mirror of
https://github.com/mastodon/mastodon.git
synced 2025-07-12 15:33:14 +00:00
Compare commits
17 Commits
be36da649d
...
45fe1bd1df
Author | SHA1 | Date | |
---|---|---|---|
![]() |
45fe1bd1df | ||
![]() |
94bceb8683 | ||
![]() |
88b0f3a172 | ||
![]() |
b69b5ba775 | ||
![]() |
a2a34fbadd | ||
![]() |
677e0b8a37 | ||
![]() |
81b79fefb7 | ||
![]() |
9e0eb99747 | ||
![]() |
fcd238cb4b | ||
![]() |
463d5dd4d5 | ||
![]() |
1af6ae19b9 | ||
![]() |
7898619d74 | ||
![]() |
2250aead46 | ||
![]() |
47e4f8478f | ||
![]() |
fad8f7b148 | ||
![]() |
b21e7d8fdb | ||
![]() |
5c6ad1a0e5 |
|
@ -2,6 +2,9 @@
|
|||
|
||||
class Api::V1::AppsController < Api::BaseController
|
||||
skip_before_action :require_authenticated_user!
|
||||
before_action :validate_token_endpoint_auth_method!
|
||||
|
||||
TOKEN_ENDPOINT_AUTH_METHODS = %w(none client_secret_basic client_secret_post).freeze
|
||||
|
||||
def create
|
||||
@app = Doorkeeper::Application.create!(application_options)
|
||||
|
@ -16,14 +19,25 @@ class Api::V1::AppsController < Api::BaseController
|
|||
redirect_uri: app_params[:redirect_uris],
|
||||
scopes: app_scopes_or_default,
|
||||
website: app_params[:website],
|
||||
confidential: !app_public?,
|
||||
}
|
||||
end
|
||||
|
||||
def validate_token_endpoint_auth_method!
|
||||
return unless app_params.include? :token_endpoint_auth_method
|
||||
|
||||
bad_request unless TOKEN_ENDPOINT_AUTH_METHODS.include? app_params[:token_endpoint_auth_method]
|
||||
end
|
||||
|
||||
def app_public?
|
||||
app_params[:token_endpoint_auth_method] == 'none'
|
||||
end
|
||||
|
||||
def app_scopes_or_default
|
||||
app_params[:scopes] || Doorkeeper.configuration.default_scopes
|
||||
end
|
||||
|
||||
def app_params
|
||||
params.permit(:client_name, :scopes, :website, :redirect_uris, redirect_uris: [])
|
||||
params.permit(:client_name, :scopes, :website, :token_endpoint_auth_method, :redirect_uris, redirect_uris: [])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -21,7 +21,13 @@ class OAuth::AuthorizationsController < Doorkeeper::AuthorizationsController
|
|||
end
|
||||
|
||||
def render_success
|
||||
if skip_authorization? || (matching_token? && !truthy_param?('force_login'))
|
||||
# FIXME: Find a better way to apply this validation: if the scopes only
|
||||
# includes offline_access, then it's not valid, since offline_access doesn't
|
||||
# actually give access to resources:
|
||||
if pre_auth.scopes.all?('offline_access')
|
||||
error = Doorkeeper::OAuth::InvalidRequestResponse.new(reason: :offline_access_only, missing_param: nil)
|
||||
render :error, locals: { error_response: error }, status: 400
|
||||
elsif skip_authorization? || (matching_token? && !truthy_param?('force_login'))
|
||||
redirect_or_render authorize_response
|
||||
elsif Doorkeeper.configuration.api_only
|
||||
render json: pre_auth
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
// @ts-check
|
||||
|
||||
|
||||
/**
|
||||
* @typedef {[code: string, name: string, localName: string]} InitialStateLanguage
|
||||
*/
|
||||
|
@ -64,6 +63,7 @@
|
|||
* @property {boolean=} critical_updates_pending
|
||||
* @property {InitialStateMeta} meta
|
||||
* @property {Role?} role
|
||||
* @property {string[]} features
|
||||
*/
|
||||
|
||||
const element = document.getElementById('initial-state');
|
||||
|
@ -140,4 +140,12 @@ export function getAccessToken() {
|
|||
return getMeta('access_token');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {string} feature
|
||||
* @returns {boolean}
|
||||
*/
|
||||
export function isFeatureEnabled(feature) {
|
||||
return initialState?.features?.includes(feature) || false;
|
||||
}
|
||||
|
||||
export default initialState;
|
||||
|
|
|
@ -219,6 +219,9 @@
|
|||
"confirmations.delete_list.confirm": "Elimina",
|
||||
"confirmations.delete_list.message": "Segur que vols suprimir permanentment aquesta llista?",
|
||||
"confirmations.delete_list.title": "Eliminar la llista?",
|
||||
"confirmations.discard_draft.confirm": "Descarta i continua",
|
||||
"confirmations.discard_draft.edit.cancel": "Continua l'edició",
|
||||
"confirmations.discard_draft.post.cancel": "Reprendre l'esborrany",
|
||||
"confirmations.discard_edit_media.confirm": "Descarta",
|
||||
"confirmations.discard_edit_media.message": "Tens canvis no desats en la descripció del contingut o en la previsualització, els vols descartar?",
|
||||
"confirmations.follow_to_list.confirm": "Seguir i afegir a una llista",
|
||||
|
@ -792,6 +795,7 @@
|
|||
"report_notification.categories.violation": "Violació de norma",
|
||||
"report_notification.categories.violation_sentence": "violació de normes",
|
||||
"report_notification.open": "Obre l'informe",
|
||||
"search.clear": "Esborra la cerca",
|
||||
"search.no_recent_searches": "No hi ha cerques recents",
|
||||
"search.placeholder": "Cerca",
|
||||
"search.quick_action.account_search": "Perfils coincidint amb {x}",
|
||||
|
|
|
@ -572,7 +572,7 @@
|
|||
"navigation_bar.mutes": "Skjulte brugere",
|
||||
"navigation_bar.opened_in_classic_interface": "Indlæg, konti og visse andre sider åbnes som standard i den klassiske webgrænseflade.",
|
||||
"navigation_bar.preferences": "Præferencer",
|
||||
"navigation_bar.privacy_and_reach": "Fortrolighed og udbredelse",
|
||||
"navigation_bar.privacy_and_reach": "Fortrolighed og rækkevidde",
|
||||
"navigation_bar.search": "Søg",
|
||||
"navigation_bar.search_trends": "Søg/Trender",
|
||||
"navigation_panel.collapse_followed_tags": "Sammenfold menuen Fulgte hashtags",
|
||||
|
|
|
@ -14,6 +14,8 @@ class ScopeTransformer < Parslet::Transform
|
|||
|
||||
# # override for profile scope which is read only
|
||||
@access = %w(read) if @term == 'profile'
|
||||
# Override offline_access since it doesn't imply read or write access:
|
||||
@access = %w(offline) if @term == 'offline_access'
|
||||
end
|
||||
|
||||
def key
|
||||
|
|
|
@ -10,12 +10,6 @@ module DatabaseViewRecord
|
|||
concurrently: true,
|
||||
cascade: false
|
||||
)
|
||||
rescue ActiveRecord::StatementInvalid
|
||||
Scenic.database.refresh_materialized_view(
|
||||
table_name,
|
||||
concurrently: false,
|
||||
cascade: false
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -65,12 +65,22 @@ class SessionActivation < ApplicationRecord
|
|||
end
|
||||
|
||||
def access_token_attributes
|
||||
app = Doorkeeper::Application.find_by(superapp: true)
|
||||
scopes = Doorkeeper::OAuth::Scopes.from_array(DEFAULT_SCOPES)
|
||||
|
||||
context = Doorkeeper::OAuth::Authorization::Token.build_context(
|
||||
app,
|
||||
Doorkeeper::OAuth::AUTHORIZATION_CODE,
|
||||
scopes,
|
||||
user_id
|
||||
)
|
||||
|
||||
{
|
||||
application_id: Doorkeeper::Application.find_by(superapp: true)&.id,
|
||||
resource_owner_id: user_id,
|
||||
scopes: DEFAULT_SCOPES.join(' '),
|
||||
expires_in: Doorkeeper.configuration.access_token_expires_in,
|
||||
use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?,
|
||||
application_id: context.client.id,
|
||||
resource_owner_id: context.resource_owner,
|
||||
scopes: context.scopes,
|
||||
expires_in: Doorkeeper::OAuth::Authorization::Token.access_token_expires_in(Doorkeeper.config, context),
|
||||
use_refresh_token: Doorkeeper::OAuth::Authorization::Token.refresh_token_enabled?(Doorkeeper.config, context),
|
||||
}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -314,10 +314,12 @@ class User < ApplicationRecord
|
|||
def token_for_app(app)
|
||||
return nil if app.nil? || app.owner != self
|
||||
|
||||
Doorkeeper::AccessToken.find_or_create_by(application_id: app.id, resource_owner_id: id) do |t|
|
||||
t.scopes = app.scopes
|
||||
t.expires_in = Doorkeeper.configuration.access_token_expires_in
|
||||
t.use_refresh_token = Doorkeeper.configuration.refresh_token_enabled?
|
||||
context = Doorkeeper::OAuth::Authorization::Token.build_context(app, Doorkeeper::OAuth::AUTHORIZATION_CODE, app.scopes, app.owner.id)
|
||||
|
||||
Doorkeeper::AccessToken.find_or_create_by(application_id: context.client.id, resource_owner_id: context.resource_owner) do |t|
|
||||
t.scopes = context.scopes
|
||||
t.expires_in = Doorkeeper::OAuth::Authorization::Token.access_token_expires_in(Doorkeeper.config, context)
|
||||
t.use_refresh_token = Doorkeeper::OAuth::Authorization::Token.refresh_token_enabled?(Doorkeeper.config, context)
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -61,7 +61,7 @@ class OAuthMetadataPresenter < ActiveModelSerializers::Model
|
|||
end
|
||||
|
||||
def token_endpoint_auth_methods_supported
|
||||
%w(client_secret_basic client_secret_post)
|
||||
%w(none client_secret_basic client_secret_post)
|
||||
end
|
||||
|
||||
def code_challenge_methods_supported
|
||||
|
|
|
@ -5,7 +5,7 @@ class InitialStateSerializer < ActiveModel::Serializer
|
|||
|
||||
attributes :meta, :compose, :accounts,
|
||||
:media_attachments, :settings,
|
||||
:languages
|
||||
:languages, :features
|
||||
|
||||
attribute :critical_updates_pending, if: -> { object&.role&.can?(:view_devops) && SoftwareUpdate.check_enabled? }
|
||||
|
||||
|
@ -85,6 +85,10 @@ class InitialStateSerializer < ActiveModel::Serializer
|
|||
LanguagesHelper::SUPPORTED_LOCALES.map { |(key, value)| [key, value[0], value[1]] }
|
||||
end
|
||||
|
||||
def features
|
||||
Mastodon::Feature.enabled_features
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def default_meta_store
|
||||
|
|
|
@ -8,7 +8,7 @@ class REST::CredentialApplicationSerializer < REST::ApplicationSerializer
|
|||
end
|
||||
|
||||
def client_secret
|
||||
object.secret
|
||||
object.secret if object.confidential?
|
||||
end
|
||||
|
||||
# Added for future forwards compatibility when we may decide to expire OAuth
|
||||
|
|
|
@ -27,12 +27,14 @@ class AppSignUpService < BaseService
|
|||
end
|
||||
|
||||
def create_access_token!
|
||||
context = Doorkeeper::OAuth::Authorization::Token.build_context(@app, Doorkeeper::OAuth::AUTHORIZATION_CODE, @app.scopes, @user.id)
|
||||
|
||||
@access_token = Doorkeeper::AccessToken.create!(
|
||||
application: @app,
|
||||
resource_owner_id: @user.id,
|
||||
scopes: @app.scopes,
|
||||
expires_in: Doorkeeper.configuration.access_token_expires_in,
|
||||
use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?
|
||||
application: context.client,
|
||||
resource_owner_id: context.resource_owner,
|
||||
scopes: context.scopes,
|
||||
expires_in: Doorkeeper::OAuth::Authorization::Token.access_token_expires_in(Doorkeeper.config, context),
|
||||
use_refresh_token: Doorkeeper::OAuth::Authorization::Token.refresh_token_enabled?(Doorkeeper.config, context)
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -31,10 +31,30 @@ Doorkeeper.configure do
|
|||
# If you want to disable expiration, set this to nil.
|
||||
access_token_expires_in nil
|
||||
|
||||
# Assign a custom TTL for implicit grants.
|
||||
# custom_access_token_expires_in do |oauth_client|
|
||||
# oauth_client.application.additional_settings.implicit_oauth_expiration
|
||||
# end
|
||||
# context.grant_type to compare with Doorkeeper::OAUTH grant type constants
|
||||
# context.client for client (Doorkeeper::Application)
|
||||
# context.scopes for scopes
|
||||
custom_access_token_expires_in do |context|
|
||||
# If the client is confidential (all clients pre 4.3) and it hasn't
|
||||
# requested offline_access, then we don't want to expire access tokens.
|
||||
# Applications created by users are also considered confidential.
|
||||
if context.client.confidential? && !context.scopes.exists?('offline_access')
|
||||
nil
|
||||
else
|
||||
15.minutes.to_i
|
||||
end
|
||||
end
|
||||
|
||||
use_refresh_token do |context|
|
||||
context.scopes.exists?('offline_access')
|
||||
end
|
||||
|
||||
after_successful_strategy_response do |request, _response|
|
||||
if request.is_a? Doorkeeper::OAuth::RefreshTokenRequest
|
||||
Web::PushSubscription.where(access_token_id: request.refresh_token.id).update!(access_token_id: request.access_token.id)
|
||||
SessionActivation.where(access_token_id: request.refresh_token.id).update!(access_token_id: request.access_token.id)
|
||||
end
|
||||
end
|
||||
|
||||
# Use a custom class for generating the access token.
|
||||
# https://github.com/doorkeeper-gem/doorkeeper#custom-access-token-generator
|
||||
|
@ -71,6 +91,7 @@ Doorkeeper.configure do
|
|||
# https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes
|
||||
default_scopes :read
|
||||
optional_scopes :profile,
|
||||
:offline_access,
|
||||
:write,
|
||||
:'write:accounts',
|
||||
:'write:blocks',
|
||||
|
@ -120,7 +141,9 @@ Doorkeeper.configure do
|
|||
# By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
|
||||
# falls back to the `:client_id` and `:client_secret` params from the `params` object.
|
||||
# Check out the wiki for more information on customization
|
||||
# client_credentials :from_basic, :from_params
|
||||
#
|
||||
# This is the default value:
|
||||
client_credentials :from_basic, :from_params
|
||||
|
||||
# Change the way access token is authenticated from the request object.
|
||||
# By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
|
||||
|
@ -165,7 +188,17 @@ Doorkeeper.configure do
|
|||
# http://tools.ietf.org/html/rfc6819#section-4.4.3
|
||||
#
|
||||
|
||||
grant_flows %w(authorization_code client_credentials)
|
||||
grant_flows %w(authorization_code client_credentials refresh_token)
|
||||
|
||||
# If the client is not a confidential client, it should not be able to use the
|
||||
# client_credentials grant flow, since it cannot keep a secret.
|
||||
allow_grant_flow_for_client do |grant_flow, client|
|
||||
if grant_flow == Doorkeeper::OAuth::CLIENT_CREDENTIALS
|
||||
client.confidential?
|
||||
else
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
# Under some circumstances you might want to have applications auto-approved,
|
||||
# so that the user skips the authorization step.
|
||||
|
|
|
@ -578,6 +578,11 @@ ca:
|
|||
all: Totes
|
||||
limited: Limitades
|
||||
title: Moderació
|
||||
moderation_notes:
|
||||
create: Afegeix una nota de moderació
|
||||
created_msg: S'ha creat la nota de moderació d'instància.
|
||||
destroyed_msg: S'ha esborrat la nota de moderació d'instància.
|
||||
title: Notes de moderació
|
||||
private_comment: Comentari privat
|
||||
public_comment: Comentari públic
|
||||
purge: Purga
|
||||
|
@ -1339,6 +1344,10 @@ ca:
|
|||
basic_information: Informació bàsica
|
||||
hint_html: "<strong>Personalitza el que la gent veu en el teu perfil públic i a prop dels teus tuts..</strong> És més probable que altres persones et segueixin i interaccionin amb tu quan tens emplenat el teu perfil i amb la teva imatge."
|
||||
other: Altres
|
||||
emoji_styles:
|
||||
auto: Automàtic
|
||||
native: Nadiu
|
||||
twemoji: Twemoji
|
||||
errors:
|
||||
'400': La sol·licitud que vas emetre no era vàlida o no era correcta.
|
||||
'403': No tens permís per a veure aquesta pàgina.
|
||||
|
|
|
@ -653,7 +653,7 @@ da:
|
|||
mark_as_sensitive_description_html: Medierne i det anmeldte indlæg markeres som sensitive, og en advarsel (strike) registreres mhp. eskalering ved evt. fremtidige overtrædelser fra samme konto.
|
||||
other_description_html: Se flere muligheder for at kontrollere kontoens adfærd og tilpasse kommunikationen til den anmeldte konto.
|
||||
resolve_description_html: Ingen foranstaltninger træffes mod den anmeldte konto, ingen advarsel (strike) registreres og anmeldelsen lukkes.
|
||||
silence_description_html: Kontoen vil kun være synlig for følgerene eller dem, som manuelt slå den op, hvilket markant begrænser dens udbredelse. Kan altid omgøres. Lukker alle indrapporteringer af kontoen.
|
||||
silence_description_html: Kontoen vil kun være synlig for dem, der allerede følger den eller manuelt slår den op, hvilket alvorligt begrænser dens rækkevidde. Kan altid omgøres. Lukker alle indrapporteringer af denne konto.
|
||||
suspend_description_html: Kontoen inkl. alt indhold utilgængeliggøres og interaktion umuliggøres, og den slettes på et tidspunkt. Kan omgøres inden for 30 dage. Lukker alle indrapporteringer af kontoen.
|
||||
actions_description_html: Afgør, hvilke foranstaltning, der skal træffes for at løse denne anmeldelse. Ved en straffende foranstaltning mod den anmeldte konto, fremsendes en e-mailnotifikation, undtagen når kategorien <strong>Spam</strong> er valgt.
|
||||
actions_description_remote_html: Fastslå en nødvendig handling mhp. at løse denne anmeldelse. Dette vil kun påvirke <strong>din</strong> servers kommunikation med, og indholdshåndtering for, fjernkontoen.
|
||||
|
@ -1266,8 +1266,8 @@ da:
|
|||
user_privacy_agreement_html: Jeg accepterer <a href="%{privacy_policy_path}" target="_blank">fortrolighedspolitikken</a>
|
||||
author_attribution:
|
||||
example_title: Eksempeltekst
|
||||
hint_html: Skriver du nyheder eller blogartikler uden for Mastodon? Styr, hvordan man bliver krediteret, når disse deles på Mastodon.
|
||||
instructions: 'Sørg for, at denne kode er i artikelens HTML:'
|
||||
hint_html: Skriver du nyheder eller blogartikler uden for Mastodon? Styr, hvordan du bliver krediteret, når de bliver delt på Mastodon.
|
||||
instructions: 'Sørg for, at denne kode er i din artikels HTML:'
|
||||
more_from_html: Flere fra %{name}
|
||||
s_blog: "%{name}s blog"
|
||||
then_instructions: Tilføj dernæst publikationsdomænenavnet i feltet nedenfor.
|
||||
|
@ -1718,11 +1718,11 @@ da:
|
|||
hint_html: "<strong>Tilpas hvordan din profil og dine indlæg kan findes.</strong> En række funktioner i Mastodon kan hjælpe dig med at nå ud til et bredere publikum, hvis du aktiverer dem. Tjek indstillingerne herunder for at sikre, at de passer til dit brugsscenarie."
|
||||
privacy: Privatliv
|
||||
privacy_hint_html: Styr, hvor meget der ønskes synliggjort til gavn for andre. Folk finder interessante profiler og apps ved at tjekke andres følgere ud, samt se hvilke apps de sender fra, men dine præferencer ønskes muligvis ikke synliggjort.
|
||||
reach: Udbredelse
|
||||
reach: Rækkevidde
|
||||
reach_hint_html: Indstil om du vil blive opdaget og fulgt af nye mennesker. Ønsker du, at dine indlæg skal vises på Udforsk-siden? Ønsker du, at andre skal se dig i deres følg-anbefalinger? Ønsker du at acceptere alle nye følgere automatisk, eller vil du have detaljeret kontrol over hver og en?
|
||||
search: Søg
|
||||
search: Søgning
|
||||
search_hint_html: Indstil hvordan du vil findes. Ønsker du, at folk skal finde dig gennem hvad du har skrevet offentligt? Vil du have folk udenfor Mastodon til at finde din profil, når de søger på nettet? Vær opmærksom på, at det ikke kan garanteres at dine offentlige indlæg er udelukket fra alle søgemaskiner.
|
||||
title: Fortrolighed og udbredelse
|
||||
title: Fortrolighed og rækkevidde
|
||||
privacy_policy:
|
||||
title: Privatlivspolitik
|
||||
reactions:
|
||||
|
@ -1923,7 +1923,7 @@ da:
|
|||
'7889238': 3 måneder
|
||||
min_age_label: Alderstærskel
|
||||
min_favs: Behold indlæg favoritmarkeret mindst
|
||||
min_favs_hint: Sletter ingen dine egne indlæg, som har modtaget minimum dette antal favoritmarkeringer. Lad stå tomt for at slette indlæg uanset antal favoritmarkeringer
|
||||
min_favs_hint: Sletter ingen af dine egne indlæg, som har modtaget minimum dette antal favoritmarkeringer. Lad stå tom for at slette indlæg uanset antal favoritmarkeringer
|
||||
min_reblogs: Behold indlæg fremhævet mindst
|
||||
min_reblogs_hint: Sletter ingen af dine egne indlæg, som er fremhævet flere end dette antal gange. Lad stå tom for at slette indlæg uanset antallet af fremhævelser
|
||||
stream_entries:
|
||||
|
@ -2095,7 +2095,7 @@ da:
|
|||
verification:
|
||||
extra_instructions_html: <strong>Tip:</strong> Linket på din hjemmeside kan være usynligt. Den vigtige del er <code>rel="me"</code> , som forhindrer impersonation på websteder med brugergenereret indhold. Du kan endda bruge et <code>link</code> tag i overskriften på siden i stedet for <code>a</code>, men HTML skal være tilgængelig uden at udføre JavaScript.
|
||||
here_is_how: Sådan gør du
|
||||
hint_html: "<strong>Bekræftelse af din identitet på Mastodon er for alle.</strong> Baseret på åbne webstandarder, nu og for evigt gratis. Alt du behøver er en personlig hjemmeside, som folk genkende dig ved. Når du linker til denne hjemmeside fra din profil, vi vil kontrollere, at hjemmesiden linker tilbage til din profil og vise en visuel indikator på det."
|
||||
hint_html: "<strong>Verificering af din identitet på Mastodon er for alle.</strong> Baseret på åbne webstandarder, nu og for altid gratis. Alt, hvad du behøver, er en personlig hjemmeside, som folk kender dig fra. Når du linker til denne hjemmeside fra din profil, kontrollerer vi, at hjemmesiden linker tilbage til din profil, og viser en visuel indikator på den."
|
||||
instructions_html: Kopier og indsæt koden nedenfor i HTML på din hjemmeside. Tilføj derefter adressen på din hjemmeside i et af de ekstra felter på din profil på fanen "Redigér profil" og gem ændringer.
|
||||
verification: Bekræftelse
|
||||
verified_links: Dine bekræftede links
|
||||
|
|
|
@ -89,6 +89,7 @@ en:
|
|||
invalid_request:
|
||||
missing_param: 'Missing required parameter: %{value}.'
|
||||
request_not_authorized: Request need to be authorized. Required parameter for authorizing request is missing or invalid.
|
||||
offline_access_only: The offline_access scope can only be used with other scopes.
|
||||
unknown: The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.
|
||||
invalid_resource_owner: The provided resource owner credentials are not valid, or resource owner cannot be found
|
||||
invalid_scope: The requested scope is invalid, unknown, or malformed.
|
||||
|
@ -118,6 +119,7 @@ en:
|
|||
read: Read-only access
|
||||
read/write: Read and write access
|
||||
write: Write-only access
|
||||
offline: Access for an extended period of time
|
||||
title:
|
||||
accounts: Accounts
|
||||
admin/accounts: Administration of accounts
|
||||
|
@ -138,6 +140,7 @@ en:
|
|||
notifications: Notifications
|
||||
profile: Your Mastodon profile
|
||||
push: Push notifications
|
||||
offline_access: Offline access
|
||||
reports: Reports
|
||||
search: Search
|
||||
statuses: Posts
|
||||
|
|
|
@ -1349,6 +1349,10 @@ hu:
|
|||
basic_information: Általános információk
|
||||
hint_html: "<strong>Tedd egyedivé, mi látnak mások a profilodon és a bejegyzéseid mellett.</strong> Mások nagyobb eséllyel követnek vissza és lépnek veled kapcsolatba, ha van kitöltött profilod és profilképed."
|
||||
other: Egyéb
|
||||
emoji_styles:
|
||||
auto: Automatikus
|
||||
native: Natív
|
||||
twemoji: Twemoji
|
||||
errors:
|
||||
'400': A küldött kérés érvénytelen vagy hibás volt.
|
||||
'403': Nincs jogosultságod az oldal megtekintéséhez.
|
||||
|
|
|
@ -61,6 +61,7 @@ ca:
|
|||
setting_display_media_default: Amaga el contingut gràfic marcat com a sensible
|
||||
setting_display_media_hide_all: Oculta sempre tot el contingut multimèdia
|
||||
setting_display_media_show_all: Mostra sempre el contingut gràfic
|
||||
setting_emoji_style: Com mostrar els emojis. "Automàtic" provarà de fer servir els emojis nadius, però revertirà a twemojis en els navegadors antics.
|
||||
setting_system_scrollbars_ui: S'aplica només als navegadors d'escriptori basats en Safari i Chrome
|
||||
setting_use_blurhash: Els degradats es basen en els colors de les imatges ocultes, però n'enfosqueixen els detalls
|
||||
setting_use_pending_items: Amaga les actualitzacions de la línia de temps després de fer un clic, en lloc de desplaçar-les automàticament
|
||||
|
@ -240,6 +241,7 @@ ca:
|
|||
setting_display_media_default: Per defecte
|
||||
setting_display_media_hide_all: Amaga-ho tot
|
||||
setting_display_media_show_all: Mostra-ho tot
|
||||
setting_emoji_style: Estil d'emojis
|
||||
setting_expand_spoilers: Desplega sempre els tuts marcats amb advertències de contingut
|
||||
setting_hide_network: Amaga la teva xarxa
|
||||
setting_missing_alt_text_modal: Mostra un diàleg de confirmació abans de publicar contingut sense text alternatiu
|
||||
|
|
|
@ -61,6 +61,7 @@ hu:
|
|||
setting_display_media_default: Kényes tartalomnak jelölt média elrejtése
|
||||
setting_display_media_hide_all: Média elrejtése mindig
|
||||
setting_display_media_show_all: Média megjelenítése mindig
|
||||
setting_emoji_style: Az emodzsik megjelenítési módja. Az „Automatikus” megpróbálja a natív emodzsikat használni, de az örökölt böngészők esetén a Twemojira vált vissza.
|
||||
setting_system_scrollbars_ui: Csak Chrome és Safari alapú asztali böngészőkre vonatkozik
|
||||
setting_use_blurhash: A kihomályosítás az eredeti képből történik, de minden részletet elrejt
|
||||
setting_use_pending_items: Idővonal frissítése csak kattintásra automatikus görgetés helyett
|
||||
|
@ -241,6 +242,7 @@ hu:
|
|||
setting_display_media_default: Alapértelmezés
|
||||
setting_display_media_hide_all: Mindent elrejt
|
||||
setting_display_media_show_all: Mindent mutat
|
||||
setting_emoji_style: Emodzsistílus
|
||||
setting_expand_spoilers: Tartalmi figyelmeztetéssel ellátott bejegyzések automatikus kinyitása
|
||||
setting_hide_network: Hálózatod elrejtése
|
||||
setting_missing_alt_text_modal: Megerősítési párbeszédablak megjelenítése a helyettesítő szöveg nélküli média közzététele előtt
|
||||
|
|
|
@ -34,12 +34,19 @@ RSpec.describe OAuth::AuthorizationsController do
|
|||
|
||||
context 'when app is already authorized' do
|
||||
before do
|
||||
context = Doorkeeper::OAuth::Authorization::Token.build_context(
|
||||
app,
|
||||
Doorkeeper::OAuth::AUTHORIZATION_CODE,
|
||||
app.scopes,
|
||||
user.id
|
||||
)
|
||||
|
||||
Doorkeeper::AccessToken.find_or_create_for(
|
||||
application: app,
|
||||
resource_owner: user.id,
|
||||
scopes: app.scopes,
|
||||
expires_in: Doorkeeper.configuration.access_token_expires_in,
|
||||
use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?
|
||||
application: context.client,
|
||||
resource_owner: context.resource_owner,
|
||||
scopes: context.scopes,
|
||||
expires_in: Doorkeeper::OAuth::Authorization::Token.access_token_expires_in(Doorkeeper.config, context),
|
||||
use_refresh_token: Doorkeeper::OAuth::Authorization::Token.refresh_token_enabled?(Doorkeeper.config, context)
|
||||
)
|
||||
end
|
||||
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
Fabricator(:application, from: Doorkeeper::Application) do
|
||||
name 'Example'
|
||||
website 'http://example.com'
|
||||
redirect_uri 'http://example.com/callback'
|
||||
redirect_uri 'urn:ietf:wg:oauth:2.0:oob'
|
||||
end
|
||||
|
|
|
@ -23,6 +23,12 @@ RSpec.describe ScopeTransformer do
|
|||
it_behaves_like 'a scope', nil, 'profile', 'read'
|
||||
end
|
||||
|
||||
context 'with scope "offline_access"' do
|
||||
let(:input) { 'offline_access' }
|
||||
|
||||
it_behaves_like 'a scope', nil, 'offline_access', 'offline'
|
||||
end
|
||||
|
||||
context 'with scope "read"' do
|
||||
let(:input) { 'read' }
|
||||
|
||||
|
|
|
@ -36,6 +36,7 @@ RSpec.describe 'Apps' do
|
|||
expect(app).to be_present
|
||||
expect(app.scopes.to_s).to eq scopes
|
||||
expect(app.redirect_uris).to eq redirect_uris
|
||||
expect(app.confidential).to be true
|
||||
|
||||
expect(response.parsed_body).to match(
|
||||
a_hash_including(
|
||||
|
@ -55,6 +56,76 @@ RSpec.describe 'Apps' do
|
|||
end
|
||||
end
|
||||
|
||||
context 'without being a confidential application' do
|
||||
let(:client_name) { 'Test confidential app' }
|
||||
let(:params) do
|
||||
{
|
||||
client_name: client_name,
|
||||
redirect_uris: redirect_uris,
|
||||
scopes: scopes,
|
||||
website: website,
|
||||
token_endpoint_auth_method: 'none',
|
||||
}
|
||||
end
|
||||
|
||||
it 'creates an public OAuth app', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
expect(response.content_type)
|
||||
.to start_with('application/json')
|
||||
|
||||
app = Doorkeeper::Application.find_by(name: client_name)
|
||||
|
||||
expect(app).to be_present
|
||||
expect(app.scopes.to_s).to eq scopes
|
||||
expect(app.redirect_uris).to eq redirect_uris
|
||||
expect(app.confidential).to be false
|
||||
|
||||
expect(response.parsed_body).to match(
|
||||
a_hash_including(
|
||||
id: app.id.to_s,
|
||||
client_id: app.uid,
|
||||
client_secret: nil,
|
||||
client_secret_expires_at: 0,
|
||||
name: client_name,
|
||||
website: website,
|
||||
scopes: ['read', 'write'],
|
||||
redirect_uris: redirect_uris,
|
||||
# Deprecated properties as of 4.3:
|
||||
redirect_uri: redirect_uri,
|
||||
vapid_key: Rails.configuration.x.vapid_public_key
|
||||
)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context 'when token_endpoint_auth_method is unknown' do
|
||||
let(:client_name) { 'Test unknown auth app' }
|
||||
let(:params) do
|
||||
{
|
||||
client_name: client_name,
|
||||
redirect_uris: redirect_uris,
|
||||
scopes: scopes,
|
||||
website: website,
|
||||
# Not yet supported:
|
||||
token_endpoint_auth_method: 'private_key_jwt',
|
||||
}
|
||||
end
|
||||
|
||||
it 'does not create an OAuth app', :aggregate_failures do
|
||||
subject
|
||||
|
||||
expect(response).to have_http_status(400)
|
||||
expect(response.content_type)
|
||||
.to start_with('application/json')
|
||||
|
||||
app = Doorkeeper::Application.find_by(name: client_name)
|
||||
|
||||
expect(app).to_not be_present
|
||||
end
|
||||
end
|
||||
|
||||
context 'without scopes being supplied' do
|
||||
let(:scopes) { nil }
|
||||
|
||||
|
|
|
@ -5,17 +5,19 @@ require 'rails_helper'
|
|||
RSpec.describe 'Managing OAuth Tokens' do
|
||||
describe 'POST /oauth/token' do
|
||||
subject do
|
||||
post '/oauth/token', params: params
|
||||
post '/oauth/token', params: params, headers: {
|
||||
# This is using the OAuth client_secret_basic client authentication method
|
||||
Authorization: ActionController::HttpAuthentication::Basic.encode_credentials(application.uid, application.secret),
|
||||
}
|
||||
end
|
||||
|
||||
let(:application) do
|
||||
Fabricate(:application, scopes: 'read write follow', redirect_uri: 'urn:ietf:wg:oauth:2.0:oob')
|
||||
end
|
||||
|
||||
let(:params) do
|
||||
{
|
||||
grant_type: grant_type,
|
||||
client_id: application.uid,
|
||||
client_secret: application.secret,
|
||||
redirect_uri: 'urn:ietf:wg:oauth:2.0:oob',
|
||||
code: code,
|
||||
scope: scope,
|
||||
|
@ -103,6 +105,53 @@ RSpec.describe 'Managing OAuth Tokens' do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
context "with grant_type 'refresh_token'" do
|
||||
let(:grant_type) { 'refresh_token' }
|
||||
|
||||
let!(:user) { Fabricate(:user) }
|
||||
let!(:application) { Fabricate(:application, scopes: 'read offline_access') }
|
||||
let!(:access_token) do
|
||||
Fabricate(
|
||||
:accessible_access_token,
|
||||
resource_owner_id: user.id,
|
||||
application: application,
|
||||
# Even though the `application` uses the `offline_access` scope, the
|
||||
# generation of a refresh token only happens when the model is created
|
||||
# with `use_refresh_token: true`.
|
||||
#
|
||||
# This is normally determined from the request to create the access
|
||||
# token, but here we are just creating the access token model, so we
|
||||
# need to force the `access_token` to have `use_refresh_token: true`
|
||||
use_refresh_token: true
|
||||
)
|
||||
end
|
||||
|
||||
let!(:web_push_subscription) { Fabricate(:web_push_subscription, user: user, access_token: access_token) }
|
||||
|
||||
let(:params) do
|
||||
{
|
||||
grant_type: grant_type,
|
||||
refresh_token: access_token.refresh_token,
|
||||
}
|
||||
end
|
||||
|
||||
it 'updates the Web::PushSubscription when refreshed' do
|
||||
expect { subject }
|
||||
.to change { access_token.reload.revoked_at }.from(nil).to(be_present)
|
||||
|
||||
expect(response).to have_http_status(200)
|
||||
|
||||
new_token = Doorkeeper::AccessToken.by_token(response.parsed_body[:access_token])
|
||||
|
||||
expect(web_push_subscription.reload.access_token_id).to eq(new_token.id)
|
||||
|
||||
# Assert that there are definitely no subscriptions left for the
|
||||
# previous access token:
|
||||
expect(Web::PushSubscription.where(access_token: access_token.id).count)
|
||||
.to eq(0)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'POST /oauth/revoke' do
|
||||
|
|
|
@ -25,7 +25,7 @@ RSpec.describe 'The /.well-known/oauth-authorization-server request' do
|
|||
scopes_supported: Doorkeeper.configuration.scopes.map(&:to_s),
|
||||
response_types_supported: Doorkeeper.configuration.authorization_response_types,
|
||||
response_modes_supported: Doorkeeper.configuration.authorization_response_flows.flat_map(&:response_mode_matches).uniq,
|
||||
token_endpoint_auth_methods_supported: %w(client_secret_basic client_secret_post),
|
||||
token_endpoint_auth_methods_supported: %w(none client_secret_basic client_secret_post),
|
||||
grant_types_supported: grant_types_supported,
|
||||
code_challenge_methods_supported: Doorkeeper.configuration.pkce_code_challenge_methods_supported,
|
||||
# non-standard extension:
|
||||
|
|
Loading…
Reference in New Issue
Block a user