Change read:me scope to profile scope (#30357)

Co-authored-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
Emelia Smith 2024-06-06 09:30:10 +02:00 committed by GitHub
parent 569b7d2f25
commit e02d23b549
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 68 additions and 9 deletions

View file

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class Api::V1::Accounts::CredentialsController < Api::BaseController class Api::V1::Accounts::CredentialsController < Api::BaseController
before_action -> { doorkeeper_authorize! :read, :'read:accounts', :'read:me' }, except: [:update] before_action -> { doorkeeper_authorize! :profile, :read, :'read:accounts' }, except: [:update]
before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:update] before_action -> { doorkeeper_authorize! :write, :'write:accounts' }, only: [:update]
before_action :require_user! before_action :require_user!

View file

@ -13,7 +13,7 @@ class Settings::ApplicationsController < Settings::BaseController
def new def new
@application = Doorkeeper::Application.new( @application = Doorkeeper::Application.new(
redirect_uri: Doorkeeper.configuration.native_redirect_uri, redirect_uri: Doorkeeper.configuration.native_redirect_uri,
scopes: 'read:me' scopes: 'profile'
) )
end end

View file

@ -11,6 +11,9 @@ class ScopeTransformer < Parslet::Transform
@namespace = scope[:namespace]&.to_s @namespace = scope[:namespace]&.to_s
@access = scope[:access] ? [scope[:access].to_s] : DEFAULT_ACCESS.dup @access = scope[:access] ? [scope[:access].to_s] : DEFAULT_ACCESS.dup
@term = scope[:term]&.to_s || DEFAULT_TERM @term = scope[:term]&.to_s || DEFAULT_TERM
# # override for profile scope which is read only
@access = %w(read) if @term == 'profile'
end end
def key def key

View file

@ -74,7 +74,8 @@ Doorkeeper.configure do
# For more information go to # For more information go to
# https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes # https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes
default_scopes :read default_scopes :read
optional_scopes :write, optional_scopes :profile,
:write,
:'write:accounts', :'write:accounts',
:'write:blocks', :'write:blocks',
:'write:bookmarks', :'write:bookmarks',
@ -89,7 +90,6 @@ Doorkeeper.configure do
:'write:reports', :'write:reports',
:'write:statuses', :'write:statuses',
:read, :read,
:'read:me',
:'read:accounts', :'read:accounts',
:'read:blocks', :'read:blocks',
:'read:bookmarks', :'read:bookmarks',

View file

@ -135,6 +135,7 @@ en:
media: Media attachments media: Media attachments
mutes: Mutes mutes: Mutes
notifications: Notifications notifications: Notifications
profile: Your Mastodon profile
push: Push notifications push: Push notifications
reports: Reports reports: Reports
search: Search search: Search
@ -165,6 +166,7 @@ en:
admin:write:reports: perform moderation actions on reports admin:write:reports: perform moderation actions on reports
crypto: use end-to-end encryption crypto: use end-to-end encryption
follow: modify account relationships follow: modify account relationships
profile: read only your account's profile information
push: receive your push notifications push: receive your push notifications
read: read all your account's data read: read all your account's data
read:accounts: see accounts information read:accounts: see accounts information
@ -174,7 +176,6 @@ en:
read:filters: see your filters read:filters: see your filters
read:follows: see your follows read:follows: see your follows
read:lists: see your lists read:lists: see your lists
read:me: read only your account's basic information
read:mutes: see your mutes read:mutes: see your mutes
read:notifications: see your notifications read:notifications: see your notifications
read:reports: see your reports read:reports: see your reports

View file

@ -0,0 +1,23 @@
# frozen_string_literal: true
class ChangeReadMeScopeToProfile < ActiveRecord::Migration[7.1]
def up
replace_scopes('read:me', 'profile')
end
def down
replace_scopes('profile', 'read:me')
end
private
def replace_scopes(old_scope, new_scope)
Doorkeeper::Application.where("scopes LIKE '%#{old_scope}%'").in_batches do |applications|
applications.update_all("scopes = replace(scopes, '#{old_scope}', '#{new_scope}')")
end
Doorkeeper::AccessToken.where("scopes LIKE '%#{old_scope}%'").in_batches do |access_tokens|
access_tokens.update_all("scopes = replace(scopes, '#{old_scope}', '#{new_scope}')")
end
end
end

View file

@ -10,7 +10,7 @@
# #
# It's strongly recommended that you check this file into your version control system. # It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema[7.1].define(version: 2024_05_22_041528) do ActiveRecord::Schema[7.1].define(version: 2024_06_03_195202) do
# These are extensions that must be enabled in order to support this database # These are extensions that must be enabled in order to support this database
enable_extension "plpgsql" enable_extension "plpgsql"

View file

@ -130,11 +130,20 @@ namespace :tests do
# This is checking the attribute rather than the method, to avoid the legacy fallback # This is checking the attribute rather than the method, to avoid the legacy fallback
# and ensure the data has been migrated # and ensure the data has been migrated
unless Account.find_local('qcuser').user[:otp_secret] == 'anotpsecretthatshouldbeencrypted' unless Account.find_local('qcuser').user[:otp_secret] == 'anotpsecretthatshouldbeencrypted'
puts "DEBUG: #{Account.find_local('qcuser').user.inspect}"
puts 'OTP secret for user not preserved as expected' puts 'OTP secret for user not preserved as expected'
exit(1) exit(1)
end end
unless Doorkeeper::Application.find(2)[:scopes] == 'write:accounts profile'
puts 'Application OAuth scopes not rewritten as expected'
exit(1)
end
unless Doorkeeper::Application.find(2).access_tokens.first[:scopes] == 'write:accounts profile'
puts 'OAuth access token scopes not rewritten as expected'
exit(1)
end
puts 'No errors found. Database state is consistent with a successful migration process.' puts 'No errors found. Database state is consistent with a successful migration process.'
end end
@ -152,6 +161,23 @@ namespace :tests do
VALUES VALUES
(1, 'https://example.com/users/foobar', 'foobar@example.com', now(), now()), (1, 'https://example.com/users/foobar', 'foobar@example.com', now(), now()),
(1, 'https://example.com/users/foobar', 'foobar@example.com', now(), now()); (1, 'https://example.com/users/foobar', 'foobar@example.com', now(), now());
/* Doorkeeper records
While the `read:me` scope was technically not valid in 3.3.0,
it is still useful for the purposes of testing the `ChangeReadMeScopeToProfile`
migration.
*/
INSERT INTO "oauth_applications"
(id, name, uid, secret, redirect_uri, scopes, created_at, updated_at)
VALUES
(2, 'foo', 'foo', 'foo', 'https://example.com/#foo', 'write:accounts read:me', now(), now()),
(3, 'bar', 'bar', 'bar', 'https://example.com/#bar', 'read:me', now(), now());
INSERT INTO "oauth_access_tokens"
(token, application_id, scopes, resource_owner_id, created_at)
VALUES
('secret', 2, 'write:accounts read:me', 4, now());
SQL SQL
end end

View file

@ -20,6 +20,12 @@ describe ScopeTransformer do
end end
end end
context 'with scope "profile"' do
let(:input) { 'profile' }
it_behaves_like 'a scope', nil, 'profile', 'read'
end
context 'with scope "read"' do context 'with scope "read"' do
let(:input) { 'read' } let(:input) { 'read' }

View file

@ -29,8 +29,8 @@ RSpec.describe 'credentials API' do
}) })
end end
describe 'allows the read:me scope' do describe 'allows the profile scope' do
let(:scopes) { 'read:me' } let(:scopes) { 'profile' }
it 'returns the response successfully' do it 'returns the response successfully' do
subject subject