From ab6696e855b58cdb2b6264c9acb0397dd7384e25 Mon Sep 17 00:00:00 2001 From: Eugen Rochko Date: Mon, 7 Mar 2016 12:42:33 +0100 Subject: Adding doorkeeper, adding a REST API POST /api/statuses Params: status (text contents), in_reply_to_id (optional) GET /api/statuses/:id POST /api/statuses/:id/reblog GET /api/accounts/:id GET /api/accounts/:id/following GET /api/accounts/:id/followers POST /api/accounts/:id/follow POST /api/accounts/:id/unfollow POST /api/follows Params: uri (e.g. user@domain) OAuth authentication is currently disabled, but the API can be used with HTTP Auth. --- config/application.rb | 5 ++ config/initializers/devise.rb | 2 +- config/initializers/doorkeeper.rb | 104 ++++++++++++++++++++++++++++++++ config/initializers/rabl_init.rb | 3 + config/initializers/reload_api.rb | 13 ---- config/locales/doorkeeper.en.yml | 123 ++++++++++++++++++++++++++++++++++++++ config/routes.rb | 37 ++++++++---- 7 files changed, 262 insertions(+), 25 deletions(-) create mode 100644 config/initializers/doorkeeper.rb create mode 100644 config/initializers/rabl_init.rb delete mode 100644 config/initializers/reload_api.rb create mode 100644 config/locales/doorkeeper.en.yml (limited to 'config') diff --git a/config/application.rb b/config/application.rb index dddf4905b..3f23b0a94 100644 --- a/config/application.rb +++ b/config/application.rb @@ -27,5 +27,10 @@ module Mastodon config.paths.add File.join('app', 'api'), glob: File.join('**', '*.rb') config.autoload_paths += Dir[Rails.root.join('app', 'api', '*')] + + config.to_prepare do + Doorkeeper::AuthorizationsController.layout 'auth' + Doorkeeper::AuthorizedApplicationsController.layout 'auth' + end end end diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 23352eac0..89747999a 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -61,7 +61,7 @@ Devise.setup do |config| # given strategies, for example, `config.http_authenticatable = [:database]` will # enable it only for database authentication. The supported strategies are: # :database = Support basic authentication with authentication key + password - # config.http_authenticatable = false + config.http_authenticatable = [:database] # If 401 status code should be returned for AJAX requests. True by default. # config.http_authenticatable_on_xhr = true diff --git a/config/initializers/doorkeeper.rb b/config/initializers/doorkeeper.rb new file mode 100644 index 000000000..10b9980b4 --- /dev/null +++ b/config/initializers/doorkeeper.rb @@ -0,0 +1,104 @@ +Doorkeeper.configure do + # Change the ORM that doorkeeper will use (needs plugins) + orm :active_record + + # This block will be called to check whether the resource owner is authenticated or not. + resource_owner_authenticator do + current_user || redirect_to(new_user_session_url) + end + + # If you want to restrict access to the web interface for adding oauth authorized applications, you need to declare the block below. + # admin_authenticator do + # # Put your admin authentication logic here. + # # Example implementation: + # Admin.find_by_id(session[:admin_id]) || redirect_to(new_admin_session_url) + # end + + # Authorization Code expiration time (default 10 minutes). + # authorization_code_expires_in 10.minutes + + # Access token expiration time (default 2 hours). + # If you want to disable expiration, set this to nil. + # access_token_expires_in 2.hours + + # Assign a custom TTL for implicit grants. + # custom_access_token_expires_in do |oauth_client| + # oauth_client.application.additional_settings.implicit_oauth_expiration + # end + + # Use a custom class for generating the access token. + # https://github.com/doorkeeper-gem/doorkeeper#custom-access-token-generator + # access_token_generator "::Doorkeeper::JWT" + + # Reuse access token for the same resource owner within an application (disabled by default) + # Rationale: https://github.com/doorkeeper-gem/doorkeeper/issues/383 + # reuse_access_token + + # Issue access tokens with refresh token (disabled by default) + # use_refresh_token + + # Provide support for an owner to be assigned to each registered application (disabled by default) + # Optional parameter :confirmation => true (default false) if you want to enforce ownership of + # a registered application + # Note: you must also run the rails g doorkeeper:application_owner generator to provide the necessary support + # enable_application_owner :confirmation => false + + # Define access token scopes for your provider + # For more information go to + # https://github.com/doorkeeper-gem/doorkeeper/wiki/Using-Scopes + # default_scopes :public + # optional_scopes :write, :update + + # Change the way client credentials are retrieved from the request object. + # 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 + + # Change the way access token is authenticated from the request object. + # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then + # falls back to the `:access_token` or `:bearer_token` params from the `params` object. + # Check out the wiki for more information on customization + # access_token_methods :from_bearer_authorization, :from_access_token_param, :from_bearer_param + + # Change the native redirect uri for client apps + # When clients register with the following redirect uri, they won't be redirected to any server and the authorization code will be displayed within the provider + # The value can be any string. Use nil to disable this feature. When disabled, clients must provide a valid URL + # (Similar behaviour: https://developers.google.com/accounts/docs/OAuth2InstalledApp#choosingredirecturi) + # + # native_redirect_uri 'urn:ietf:wg:oauth:2.0:oob' + + # Forces the usage of the HTTPS protocol in non-native redirect uris (enabled + # by default in non-development environments). OAuth2 delegates security in + # communication to the HTTPS protocol so it is wise to keep this enabled. + # + # force_ssl_in_redirect_uri !Rails.env.development? + + # Specify what grant flows are enabled in array of Strings. The valid + # strings and the flows they enable are: + # + # "authorization_code" => Authorization Code Grant Flow + # "implicit" => Implicit Grant Flow + # "password" => Resource Owner Password Credentials Grant Flow + # "client_credentials" => Client Credentials Grant Flow + # + # If not specified, Doorkeeper enables authorization_code and + # client_credentials. + # + # implicit and password grant flows have risks that you should understand + # before enabling: + # http://tools.ietf.org/html/rfc6819#section-4.4.2 + # http://tools.ietf.org/html/rfc6819#section-4.4.3 + # + # grant_flows %w(authorization_code client_credentials) + + # Under some circumstances you might want to have applications auto-approved, + # so that the user skips the authorization step. + # For example if dealing with a trusted application. + # skip_authorization do |resource_owner, client| + # client.superapp? or resource_owner.admin? + # end + + # WWW-Authenticate Realm (default "Doorkeeper"). + # realm "Doorkeeper" +end diff --git a/config/initializers/rabl_init.rb b/config/initializers/rabl_init.rb new file mode 100644 index 000000000..f11eb190d --- /dev/null +++ b/config/initializers/rabl_init.rb @@ -0,0 +1,3 @@ +Rabl.configure do |config| + config.include_json_root = false +end diff --git a/config/initializers/reload_api.rb b/config/initializers/reload_api.rb deleted file mode 100644 index c6b599d80..000000000 --- a/config/initializers/reload_api.rb +++ /dev/null @@ -1,13 +0,0 @@ -if Rails.env.development? - ActiveSupport::Dependencies.explicitly_unloadable_constants << 'Twitter::API' - - api_files = Dir[Rails.root.join('app', 'api', '**', '*.rb')] - - api_reloader = ActiveSupport::FileUpdateChecker.new(api_files) do - Rails.application.reload_routes! - end - - ActionDispatch::Callbacks.to_prepare do - api_reloader.execute_if_updated - end -end diff --git a/config/locales/doorkeeper.en.yml b/config/locales/doorkeeper.en.yml new file mode 100644 index 000000000..7d2d215da --- /dev/null +++ b/config/locales/doorkeeper.en.yml @@ -0,0 +1,123 @@ +en: + activerecord: + attributes: + doorkeeper/application: + name: 'Name' + redirect_uri: 'Redirect URI' + errors: + models: + doorkeeper/application: + attributes: + redirect_uri: + fragment_present: 'cannot contain a fragment.' + invalid_uri: 'must be a valid URI.' + relative_uri: 'must be an absolute URI.' + secured_uri: 'must be an HTTPS/SSL URI.' + + doorkeeper: + applications: + confirmations: + destroy: 'Are you sure?' + buttons: + edit: 'Edit' + destroy: 'Destroy' + submit: 'Submit' + cancel: 'Cancel' + authorize: 'Authorize' + form: + error: 'Whoops! Check your form for possible errors' + help: + redirect_uri: 'Use one line per URI' + native_redirect_uri: 'Use %{native_redirect_uri} for local tests' + scopes: 'Separate scopes with spaces. Leave blank to use the default scopes.' + edit: + title: 'Edit application' + index: + title: 'Your applications' + new: 'New Application' + name: 'Name' + callback_url: 'Callback URL' + new: + title: 'New Application' + show: + title: 'Application: %{name}' + application_id: 'Application Id' + secret: 'Secret' + scopes: 'Scopes' + callback_urls: 'Callback urls' + actions: 'Actions' + + authorizations: + buttons: + authorize: 'Authorize' + deny: 'Deny' + error: + title: 'An error has occurred' + new: + title: 'Authorization required' + prompt: 'Authorize %{client_name} to use your account?' + able_to: 'This application will be able to' + show: + title: 'Authorization code' + + authorized_applications: + confirmations: + revoke: 'Are you sure?' + buttons: + revoke: 'Revoke' + index: + title: 'Your authorized applications' + application: 'Application' + created_at: 'Created At' + date_format: '%Y-%m-%d %H:%M:%S' + + errors: + messages: + # Common error messages + invalid_request: 'The request is missing a required parameter, includes an unsupported parameter value, or is otherwise malformed.' + invalid_redirect_uri: 'The redirect uri included is not valid.' + unauthorized_client: 'The client is not authorized to perform this request using this method.' + access_denied: 'The resource owner or authorization server denied the request.' + invalid_scope: 'The requested scope is invalid, unknown, or malformed.' + server_error: 'The authorization server encountered an unexpected condition which prevented it from fulfilling the request.' + temporarily_unavailable: 'The authorization server is currently unable to handle the request due to a temporary overloading or maintenance of the server.' + + #configuration error messages + credential_flow_not_configured: 'Resource Owner Password Credentials flow failed due to Doorkeeper.configure.resource_owner_from_credentials being unconfigured.' + resource_owner_authenticator_not_configured: 'Resource Owner find failed due to Doorkeeper.configure.resource_owner_authenticator being unconfiged.' + + # Access grant errors + unsupported_response_type: 'The authorization server does not support this response type.' + + # Access token errors + invalid_client: 'Client authentication failed due to unknown client, no client authentication included, or unsupported authentication method.' + invalid_grant: 'The provided authorization grant is invalid, expired, revoked, does not match the redirection URI used in the authorization request, or was issued to another client.' + unsupported_grant_type: 'The authorization grant type is not supported by the authorization server.' + + # Password Access token errors + invalid_resource_owner: 'The provided resource owner credentials are not valid, or resource owner cannot be found' + + invalid_token: + revoked: "The access token was revoked" + expired: "The access token expired" + unknown: "The access token is invalid" + + flash: + applications: + create: + notice: 'Application created.' + destroy: + notice: 'Application deleted.' + update: + notice: 'Application updated.' + authorized_applications: + destroy: + notice: 'Application revoked.' + + layouts: + admin: + nav: + oauth2_provider: 'OAuth2 Provider' + applications: 'Applications' + application: + title: 'OAuth authorization required' diff --git a/config/routes.rb b/config/routes.rb index 3167cbdeb..b34837711 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,6 @@ Rails.application.routes.draw do + use_doorkeeper + get '.well-known/host-meta', to: 'xrd#host_meta', as: :host_meta get '.well-known/webfinger', to: 'xrd#webfinger', as: :webfinger @@ -9,23 +11,36 @@ Rails.application.routes.draw do } resources :accounts, path: 'users', only: [:show], param: :username do - member do - post :follow - post :unfollow - end - - resources :stream_entries, path: 'updates', only: [:show] do - member do - post :reblog - post :favourite - end - end + resources :stream_entries, path: 'updates', only: [:show] end namespace :api do + # PubSubHubbub resources :subscriptions, only: [:show] post '/subscriptions/:id', to: 'subscriptions#update' + + # Salmon post '/salmon/:id', to: 'salmon#update', as: :salmon + + # JSON / REST API + resources :statuses, only: [:create, :show] do + member do + post :reblog + end + end + + resources :follows, only: [:create] + + resources :accounts, only: [:show] do + member do + get :statuses + get :followers + get :following + + post :follow + post :unfollow + end + end end root 'home#index' -- cgit