Skip to content
Open
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
02868bf
add new icon from bounty
matmanna Feb 10, 2026
36a158d
Merge branch 'hackclub:main' into main
matmanna Feb 17, 2026
5ff4402
Merge pull request #2 from hackclub/main
matmanna Mar 2, 2026
bfe6360
feat: add hackatime normal token revocation
matmanna Mar 2, 2026
1ad3835
chore: make linter not hate me (its always whitespace) <3
matmanna Mar 2, 2026
e0fdb0a
fix: combine both revocation apis into one (as requested by mahad)
matmanna Mar 2, 2026
c12f771
chore: add HKA_REVOCATION_KEY to .env.example
matmanna Mar 2, 2026
a7ba13f
chore: merge remote-tracking branch 'upstream/main'
matmanna Mar 3, 2026
707af3c
feat: add hackatime normal token revocation
matmanna Mar 2, 2026
331062f
chore: make linter not hate me (its always whitespace) <3
matmanna Mar 2, 2026
340009b
fix: combine both revocation apis into one (as requested by mahad)
matmanna Mar 2, 2026
30e5091
chore: add HKA_REVOCATION_KEY to .env.example
matmanna Mar 2, 2026
075f9c9
chore: merge branch 'revokable_api_tokens' of https://github.com/quac…
matmanna Mar 3, 2026
b8a4154
feat: add hackatime normal token revocation
matmanna Mar 2, 2026
353aa8d
chore: make linter not hate me (its always whitespace) <3
matmanna Mar 2, 2026
aaea827
fix: combine both revocation apis into one (as requested by mahad)
matmanna Mar 2, 2026
2e96e80
chore: add HKA_REVOCATION_KEY to .env.example
matmanna Mar 2, 2026
86c3bc9
feat: add hackatime normal token revocation
matmanna Mar 2, 2026
0d74f3f
chore: make linter not hate me (its always whitespace) <3
matmanna Mar 2, 2026
f588a2e
fix: combine both revocation apis into one (as requested by mahad)
matmanna Mar 2, 2026
f8d4f57
fix: stuff greptile suggested
matmanna Mar 8, 2026
bb5cfb3
chore: keep uptodate
matmanna Mar 8, 2026
2fb2aff
style: add final newline
matmanna Mar 8, 2026
766833d
Merge branch 'main' into revokable_api_tokens
matmanna Mar 11, 2026
082e7b8
docs: apply .env.example suggestion from @skyfallwastaken
matmanna Mar 12, 2026
8a842e5
refactor: move apikey rotation to user model
matmanna Mar 12, 2026
163301e
merge branch 'revokable_api_tokens' of https://github.com/quackclub/h…
matmanna Mar 12, 2026
d5d0cc2
style: remove unnecessary comment
matmanna Mar 12, 2026
64cfe45
fix: tests passing and inappropriate response codes
matmanna Mar 12, 2026
595c283
refactor: fix response codes
matmanna Mar 12, 2026
c21f28f
refactor: move key info request back into separate function
matmanna Mar 12, 2026
446cadf
Merge branch 'revokable_api_tokens' of github.com:quackclub/hackatime…
matmanna Mar 13, 2026
a8f4d4f
Merge branch 'main' into revokable_api_tokens
matmanna Mar 13, 2026
86eae94
fix: broken ci because of merge mistake :/
matmanna Mar 13, 2026
07e85a1
Merge branch 'main' into revokable_api_tokens
matmanna Mar 13, 2026
ea1f735
Merge branch 'main' into revokable_api_tokens
skyfallwastaken Mar 14, 2026
c1873d6
Merge branch 'revokable_api_tokens' of github.com:quackclub/hackatime…
matmanna Mar 14, 2026
8a005db
refactor: remove unnecessary test line and switch to report_error
matmanna Mar 14, 2026
34646e5
fix: returned name for admin & regular keys
matmanna Mar 15, 2026
54012e5
Merge branch 'main' into revokable_api_tokens
matmanna Mar 16, 2026
b624b9b
Merge branch 'main' into revokable_api_tokens
matmanna Mar 18, 2026
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
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -63,3 +63,6 @@ S3_ACCESS_KEY_ID=your_s3_access_key_id_here
S3_SECRET_ACCESS_KEY=your_s3_secret_access_key_here
S3_BUCKET=your_s3_bucket_name_here
S3_ENDPOINT=https://<ACCOUNT_ID>.r2.cloudflarestorage.com

# Revocation key for token revocation
HKA_REVOCATION_KEY=your_hka_revocation_key_here
38 changes: 32 additions & 6 deletions app/controllers/api/internal/revocations_controller.rb
Original file line number Diff line number Diff line change
@@ -1,26 +1,52 @@
module Api
module Internal
class RevocationsController < Api::Internal::ApplicationController
REGULAR_KEY_REGEX = /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/i
ADMIN_KEY_REGEX = /\Ahka_[0-9a-f]{64}\z/

def create
token = params[:token]

return head 400 unless token.present?

admin_api_key = AdminApiKey.active.find_by(token:)

return render json: { success: false } unless admin_api_key.present?
key, user = revocable_key_and_owner(token)

admin_api_key.revoke!
return render json: { success: false } unless key.present?

user = admin_api_key.user
revoke_key!(key)

render json: {
success: true,
owner_email: user.email_addresses.first&.email,
key_name: admin_api_key.name
key_name: key.name
}.compact_blank
end

private

def revocable_key_and_owner(token)
if token.match?(ADMIN_KEY_REGEX)
key = AdminApiKey.active.find_by(token:)
return [ key, key&.user ]
end

if token.match?(REGULAR_KEY_REGEX)
key = ApiKey.find_by(token:)
return [ key, key&.user ]
end

[ nil, nil ]
end

def revoke_key!(key)
return key.revoke! if key.is_a?(AdminApiKey)

key.update!(
token: SecureRandom.uuid_v4,
name: "#{key.name}_revoked_#{SecureRandom.hex(8)}"
)
end

private def authenticate!
res = authenticate_with_http_token do |token, _|
ActiveSupport::SecurityUtils.secure_compare(token, ENV["HKA_REVOCATION_KEY"])
Expand Down