Store per-device user agent for remoteStorage authorizations
CI / Test (pull_request) Successful in 2m11s
CI / Test (pull_request) Successful in 2m11s
- Add user_agent to remote_storage_authorizations and rs_authorization_codes - Capture the browser's user agent at consent, carry it on the authorization code, and store it on the authorization when the code is exchanged - Store it directly for the implicit flow too With the reuse shortcut gone, each authorization is already a distinct per-device token; this adds the metadata needed to label and display them. Part of #254
This commit is contained in:
1 parent
0ab0412bb3
commit
25856a7ca7
8 files changed
+28
-5
No files matched your search
@@ -104,6 +104,7 @@ class Rs::OauthController < ApplicationController
|
||||
redirect_uri: redirect_uri,
|
||||
permissions: permissions,
|
||||
expire_at: expire_at,
|
||||
user_agent: request.user_agent,
|
||||
code_challenge: challenge,
|
||||
code_challenge_method: method
|
||||
)
|
||||
@@ -116,7 +117,8 @@ class Rs::OauthController < ApplicationController
|
||||
client_id: client_id,
|
||||
redirect_uri: redirect_uri,
|
||||
app_name: client_id,
|
||||
expire_at: expire_at
|
||||
expire_at: expire_at,
|
||||
user_agent: request.user_agent
|
||||
)
|
||||
|
||||
redirect_to url_with_state("#{redirect_uri}#access_token=#{auth.token}", state),
|
||||
|
||||
@@ -25,7 +25,8 @@ module RsOauthManager
|
||||
client_id: auth_code.client_id,
|
||||
redirect_uri: auth_code.redirect_uri,
|
||||
app_name: auth_code.client_id,
|
||||
expire_at: auth_code.permission_expire_at
|
||||
expire_at: auth_code.permission_expire_at,
|
||||
user_agent: auth_code.user_agent
|
||||
)
|
||||
|
||||
auth_code.consume!
|
||||
|
||||
@@ -2,7 +2,7 @@ module RsOauthManager
|
||||
class IssueCode < RsOauthManagerService
|
||||
def initialize(user:, client_id:, redirect_uri:, permissions:,
|
||||
code_challenge:, code_challenge_method: "S256",
|
||||
expire_at: nil)
|
||||
expire_at: nil, user_agent: nil)
|
||||
@user = user
|
||||
@client_id = client_id
|
||||
@redirect_uri = redirect_uri
|
||||
@@ -10,6 +10,7 @@ module RsOauthManager
|
||||
@code_challenge = code_challenge
|
||||
@code_challenge_method = code_challenge_method
|
||||
@expire_at = expire_at
|
||||
@user_agent = user_agent
|
||||
end
|
||||
|
||||
def call
|
||||
@@ -19,6 +20,7 @@ module RsOauthManager
|
||||
redirect_uri: @redirect_uri,
|
||||
permissions: @permissions,
|
||||
permission_expire_at: @expire_at,
|
||||
user_agent: @user_agent,
|
||||
code_challenge: @code_challenge,
|
||||
code_challenge_method: @code_challenge_method
|
||||
)
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
class AddUserAgentToRsAuthorizations < ActiveRecord::Migration[8.1]
|
||||
def change
|
||||
add_column :remote_storage_authorizations, :user_agent, :string
|
||||
add_column :rs_authorization_codes, :user_agent, :string
|
||||
end
|
||||
end
|
||||
+3
-1
@@ -10,7 +10,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema[8.1].define(version: 2026_11_02_120000) do
|
||||
ActiveRecord::Schema[8.1].define(version: 2026_11_02_130000) do
|
||||
create_table "active_storage_attachments", force: :cascade do |t|
|
||||
t.bigint "blob_id", null: false
|
||||
t.datetime "created_at", null: false
|
||||
@@ -110,6 +110,7 @@ ActiveRecord::Schema[8.1].define(version: 2026_11_02_120000) do
|
||||
t.string "redirect_uri"
|
||||
t.string "token"
|
||||
t.datetime "updated_at", null: false
|
||||
t.string "user_agent"
|
||||
t.integer "user_id", null: false
|
||||
t.integer "web_app_id"
|
||||
t.index ["permissions"], name: "index_remote_storage_authorizations_on_permissions"
|
||||
@@ -128,6 +129,7 @@ ActiveRecord::Schema[8.1].define(version: 2026_11_02_120000) do
|
||||
t.text "permissions", default: "--- []\n"
|
||||
t.string "redirect_uri", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.string "user_agent"
|
||||
t.integer "user_id", null: false
|
||||
t.index ["code_digest"], name: "index_rs_authorization_codes_on_code_digest", unique: true
|
||||
t.index ["user_id"], name: "index_rs_authorization_codes_on_user_id"
|
||||
|
||||
@@ -310,6 +310,7 @@ RSpec.describe Rs::OauthController, type: :controller do
|
||||
context "when user is signed in" do
|
||||
before do
|
||||
sign_in user
|
||||
request.user_agent = "RSpec Device"
|
||||
end
|
||||
|
||||
after do
|
||||
@@ -334,6 +335,10 @@ RSpec.describe Rs::OauthController, type: :controller do
|
||||
expect(@auth.permissions).to eq(%w(documents photos contacts:rw videos:r tasks/work:r))
|
||||
end
|
||||
|
||||
it "stores the device's user agent" do
|
||||
expect(@auth.user_agent).to eq("RSpec Device")
|
||||
end
|
||||
|
||||
it "redirects to the redirect_uri" do
|
||||
expect(response).to redirect_to("https://example.com#access_token=#{@auth.token}&state=foobar123")
|
||||
end
|
||||
@@ -463,6 +468,7 @@ RSpec.describe Rs::OauthController, type: :controller do
|
||||
expect(@code.permissions).to eq(%w(documents photos contacts:rw))
|
||||
expect(@code.code_challenge).to eq("challenge123")
|
||||
expect(@code.code_challenge_method).to eq("S256")
|
||||
expect(@code.user_agent).to eq("RSpec Device")
|
||||
end
|
||||
|
||||
it "does not create a remote storage authorization" do
|
||||
|
||||
@@ -20,6 +20,7 @@ RSpec.describe RsOauthManager::ExchangeCode do
|
||||
permissions: %w(documents:rw),
|
||||
code_challenge: code_challenge,
|
||||
code_challenge_method: "S256",
|
||||
user_agent: "RSpec Device",
|
||||
**overrides
|
||||
)
|
||||
end
|
||||
@@ -43,6 +44,7 @@ RSpec.describe RsOauthManager::ExchangeCode do
|
||||
expect(auth.permissions).to eq(%w(documents:rw))
|
||||
expect(auth.client_id).to eq("example.com")
|
||||
expect(auth.token).to be_present
|
||||
expect(auth.user_agent).to eq("RSpec Device")
|
||||
expect(RsAuthorizationCode.exists?(code.id)).to be(false)
|
||||
end
|
||||
|
||||
|
||||
@@ -11,7 +11,8 @@ RSpec.describe RsOauthManager::IssueCode do
|
||||
permissions: %w(documents:rw),
|
||||
code_challenge: "challenge",
|
||||
code_challenge_method: "S256",
|
||||
expire_at: 1.month.from_now
|
||||
expire_at: 1.month.from_now,
|
||||
user_agent: "RSpec Device"
|
||||
)
|
||||
end
|
||||
|
||||
@@ -21,6 +22,7 @@ RSpec.describe RsOauthManager::IssueCode do
|
||||
expect(subject.client_id).to eq("example.com")
|
||||
expect(subject.permissions).to eq(%w(documents:rw))
|
||||
expect(subject.code_challenge).to eq("challenge")
|
||||
expect(subject.user_agent).to eq("RSpec Device")
|
||||
end
|
||||
|
||||
it "does not create a remote storage authorization" do
|
||||
|
||||
Reference in new issue
Block a user