Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions app/models/api_token.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#
# id :bigint not null, primary key
# expires_in :integer
# ip_address :inet
# refresh_token :string
# revoked_at :datetime
# scopes :string
Expand All @@ -19,6 +20,7 @@
# Indexes
#
# index_api_tokens_on_application_id (application_id)
# index_api_tokens_on_ip_address (ip_address)
# index_api_tokens_on_token_bidx (token_bidx) UNIQUE
# index_api_tokens_on_user_id (user_id)
#
Expand Down Expand Up @@ -53,4 +55,19 @@ def self.generate(options = {})

def abbreviated = "#{token[..7]}...#{token[-3..]}"

def geocode_result
return nil unless ip_address.present?
return @geocode_result if defined?(@geocode_result)

@geocode_result = Geocoder.search(ip_address.to_s)&.first
end

def latitude
geocode_result&.latitude
end

def longitude
geocode_result&.longitude
end

end
14 changes: 14 additions & 0 deletions app/views/users/_oauth_authorization.erb
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@
</tbody>
</table>
<% end %>
<% latest_token_with_ip = authorization.tokens.where.not(ip_address: nil).order(created_at: :desc).first %>
<% if latest_token_with_ip.present? %>
<% if latest_token_with_ip.latitude.present? && latest_token_with_ip.longitude.present? %>
<img class="w-full rounded mt-3 aspect-square" src="https://maps.hackclub.com/api/shipping?latitude=<%= latest_token_with_ip.latitude %>&longitude=<%= latest_token_with_ip.longitude %>">
<% else %>
<div class="w-full rounded mt-3 aspect-square bg-smoke dark:bg-black opacity-50 flex items-center justify-center text-xl">
Location unavailable
</div>
<% end %>
<% if latest_token_with_ip.ip_address.present? %>
<div class="flex items-center mt-2">
<%= inline_icon "web", size: 20 %>&nbsp;<code class="mr1 tooltipped tooltipped--n" aria-label="<%= latest_token_with_ip.ip_address %>"><%= latest_token_with_ip.ip_address %></code>
</div>
<% end %>
<p class="regular italic muted text-sm m-0 mt-1">
<%= authorization.authorization_count == 1 ? "Authorized" : "Last authorized" %> <%= local_time_ago authorization.created_at %>
</p>
Expand Down
11 changes: 7 additions & 4 deletions config/initializers/doorkeeper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -357,7 +357,7 @@
# tokens, you can check that the requested data belongs to the specified tenant.
#
# Default value is an empty Array: []
# custom_access_token_attributes [:tenant_id]
custom_access_token_attributes [:ip_address]

# Hook into the strategies' request & response life-cycle in case your
# application needs advanced customization or logging:
Expand All @@ -366,9 +366,12 @@
# puts "BEFORE HOOK FIRED! #{request}"
# end
#
# after_successful_strategy_response do |request, response|
# puts "AFTER HOOK FIRED! #{request}, #{response}"
# end
after_successful_strategy_response do |request, response|
if response.respond_to?(:token) && response.token.is_a?(ApiToken)
ip = request.remote_ip
response.token.update(ip_address: ip) if ip.present?
end
end

# Hook into Authorization flow in order to implement Single Sign Out
# or add any other functionality. Inside the block you have an access
Expand Down
12 changes: 12 additions & 0 deletions db/migrate/20251117030308_add_ip_address_to_api_tokens.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# frozen_string_literal: true

class AddIpAddressToApiTokens < ActiveRecord::Migration[8.0]
disable_ddl_transaction!

def change
safety_assured do
add_column :api_tokens, :ip_address, :inet
add_index :api_tokens, :ip_address, algorithm: :concurrently
end
end
end
4 changes: 3 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema[8.0].define(version: 2025_11_15_104532) do
ActiveRecord::Schema[8.0].define(version: 2025_11_17_030308) do
create_schema "google_sheets"

# These are extensions that must be enabled in order to support this database
Expand Down Expand Up @@ -227,7 +227,9 @@
t.string "refresh_token"
t.integer "expires_in"
t.string "scopes"
t.inet "ip_address"
t.index ["application_id"], name: "index_api_tokens_on_application_id"
t.index ["ip_address"], name: "index_api_tokens_on_ip_address"
t.index ["token_bidx"], name: "index_api_tokens_on_token_bidx", unique: true
t.index ["user_id"], name: "index_api_tokens_on_user_id"
end
Expand Down
Loading