Adding OAuth access scopes, fixing OAuth authorization UI, adding rate limiting
to the API
This commit is contained in:
		
							
								
								
									
										54
									
								
								.rubocop.yml
									
									
									
									
									
								
							
							
						
						
									
										54
									
								
								.rubocop.yml
									
									
									
									
									
								
							@@ -1,14 +1,60 @@
 | 
				
			|||||||
Rails:
 | 
					Rails:
 | 
				
			||||||
  Enabled: true
 | 
					  Enabled: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Metrics/LineLength:
 | 
					 | 
				
			||||||
  Enabled: false
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Style/PerlBackrefs:
 | 
					Style/PerlBackrefs:
 | 
				
			||||||
  AutoCorrect: false
 | 
					  AutoCorrect: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Style/ClassAndModuleChildren:
 | 
					Style/ClassAndModuleChildren:
 | 
				
			||||||
  Enabled: false
 | 
					  Enabled: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
Documentation:
 | 
					Metrics/BlockNesting:
 | 
				
			||||||
 | 
					  Max: 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Metrics/LineLength:
 | 
				
			||||||
 | 
					  AllowURI: true
 | 
				
			||||||
  Enabled: false
 | 
					  Enabled: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Metrics/MethodLength:
 | 
				
			||||||
 | 
					  CountComments: false
 | 
				
			||||||
 | 
					  Max: 10
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Metrics/ModuleLength:
 | 
				
			||||||
 | 
					  Max: 100
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Metrics/ParameterLists:
 | 
				
			||||||
 | 
					  Max: 4
 | 
				
			||||||
 | 
					  CountKeywordArgs: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Style/AccessModifierIndentation:
 | 
				
			||||||
 | 
					  EnforcedStyle: indent
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Style/CollectionMethods:
 | 
				
			||||||
 | 
					  Enabled: true
 | 
				
			||||||
 | 
					  PreferredMethods:
 | 
				
			||||||
 | 
					    find_all: 'select'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Style/Documentation:
 | 
				
			||||||
 | 
					  Enabled: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Style/DoubleNegation:
 | 
				
			||||||
 | 
					  Enabled: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Style/FrozenStringLiteralComment:
 | 
				
			||||||
 | 
					  Enabled: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Style/SpaceInsideHashLiteralBraces:
 | 
				
			||||||
 | 
					  EnforcedStyle: space
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Style/TrailingCommaInLiteral:
 | 
				
			||||||
 | 
					  EnforcedStyleForMultiline: 'comma'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Style/RegexpLiteral:
 | 
				
			||||||
 | 
					  Enabled: false
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					AllCops:
 | 
				
			||||||
 | 
					  TargetRubyVersion: 2.2
 | 
				
			||||||
 | 
					  Exclude:
 | 
				
			||||||
 | 
					  - 'spec/**/*'
 | 
				
			||||||
 | 
					  - 'db/**/*'
 | 
				
			||||||
 | 
					  - 'app/views/**/*'
 | 
				
			||||||
 | 
					  - 'config/**/*'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -85,18 +85,7 @@
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  .prompt {
 | 
					  code {
 | 
				
			||||||
    font-size: 16px;
 | 
					 | 
				
			||||||
    color: #9baec8;
 | 
					 | 
				
			||||||
    text-align: center;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
    .prompt-highlight {
 | 
					 | 
				
			||||||
      font-weight: 500;
 | 
					 | 
				
			||||||
      color: #fff;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  code.copypasteable {
 | 
					 | 
				
			||||||
    display: block;
 | 
					    display: block;
 | 
				
			||||||
    font-family: 'Roboto Mono', monospace;
 | 
					    font-family: 'Roboto Mono', monospace;
 | 
				
			||||||
    font-weight: 400;
 | 
					    font-weight: 400;
 | 
				
			||||||
@@ -110,42 +99,42 @@
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  .actions {
 | 
					  .actions {
 | 
				
			||||||
    margin-top: 30px;
 | 
					    margin-top: 30px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    button {
 | 
					  button {
 | 
				
			||||||
      display: block;
 | 
					    display: block;
 | 
				
			||||||
      width: 100%;
 | 
					    width: 100%;
 | 
				
			||||||
      border: 0;
 | 
					    border: 0;
 | 
				
			||||||
      border-radius: 4px;
 | 
					    border-radius: 4px;
 | 
				
			||||||
      background: #2b90d9;
 | 
					    background: #2b90d9;
 | 
				
			||||||
      color: #fff;
 | 
					    color: #fff;
 | 
				
			||||||
      font-size: 18px;
 | 
					    font-size: 18px;
 | 
				
			||||||
      padding: 10px;
 | 
					    padding: 10px;
 | 
				
			||||||
      text-transform: uppercase;
 | 
					    text-transform: uppercase;
 | 
				
			||||||
      cursor: pointer;
 | 
					    cursor: pointer;
 | 
				
			||||||
      font-weight: 500;
 | 
					    font-weight: 500;
 | 
				
			||||||
      outline: 0;
 | 
					    outline: 0;
 | 
				
			||||||
      margin-bottom: 10px;
 | 
					    margin-bottom: 10px;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &:hover {
 | 
				
			||||||
 | 
					      background-color: lighten(#2b90d9, 5%);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &:active, &:focus {
 | 
				
			||||||
 | 
					      position: relative;
 | 
				
			||||||
 | 
					      top: 1px;
 | 
				
			||||||
 | 
					      background-color: darken(#2b90d9, 5%);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    &.negative {
 | 
				
			||||||
 | 
					      background: #df405a;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      &:hover {
 | 
					      &:hover {
 | 
				
			||||||
        background-color: lighten(#2b90d9, 5%);
 | 
					        background-color: lighten(#df405a, 5%);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      &:active, &:focus {
 | 
					      &:active, &:focus {
 | 
				
			||||||
        position: relative;
 | 
					        background-color: darken(#df405a, 5%);
 | 
				
			||||||
        top: 1px;
 | 
					 | 
				
			||||||
        background-color: darken(#2b90d9, 5%);
 | 
					 | 
				
			||||||
      }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
      &.negative {
 | 
					 | 
				
			||||||
        background: #df405a;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        &:hover {
 | 
					 | 
				
			||||||
          background-color: lighten(#df405a, 5%);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        &:active, &:focus {
 | 
					 | 
				
			||||||
          background-color: darken(#df405a, 5%);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@@ -180,3 +169,18 @@
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					.oauth-prompt {
 | 
				
			||||||
 | 
					  margin-bottom: 30px;
 | 
				
			||||||
 | 
					  text-align: center;
 | 
				
			||||||
 | 
					  color: #9baec8;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  h2 {
 | 
				
			||||||
 | 
					    font-size: 16px;
 | 
				
			||||||
 | 
					    margin-bottom: 30px;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  strong {
 | 
				
			||||||
 | 
					    color: #d9e1e8;
 | 
				
			||||||
 | 
					    font-weight: 500;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,7 @@
 | 
				
			|||||||
# Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading.
 | 
					# Be sure to restart your server when you modify this file. Action Cable runs in a loop that does not support auto reloading.
 | 
				
			||||||
class PublicChannel < ApplicationCable::Channel
 | 
					class PublicChannel < ApplicationCable::Channel
 | 
				
			||||||
  def subscribed
 | 
					  def subscribed
 | 
				
			||||||
    stream_from 'timeline:public', -> (encoded_message) do
 | 
					    stream_from 'timeline:public', lambda do |encoded_message|
 | 
				
			||||||
      message = ActiveSupport::JSON.decode(encoded_message)
 | 
					      message = ActiveSupport::JSON.decode(encoded_message)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      status = Status.find_by(id: message['id'])
 | 
					      status = Status.find_by(id: message['id'])
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
class Api::V1::AccountsController < ApiController
 | 
					class Api::V1::AccountsController < ApiController
 | 
				
			||||||
  before_action :doorkeeper_authorize!
 | 
					  before_action -> { doorkeeper_authorize! :read }, except: [:follow, :unfollow, :block, :unblock]
 | 
				
			||||||
 | 
					  before_action -> { doorkeeper_authorize! :follow }, only: [:follow, :unfollow, :block, :unblock]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  before_action :set_account, except: [:verify_credentials, :suggestions]
 | 
					  before_action :set_account, except: [:verify_credentials, :suggestions]
 | 
				
			||||||
  respond_to    :json
 | 
					  respond_to    :json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
class Api::V1::FollowsController < ApiController
 | 
					class Api::V1::FollowsController < ApiController
 | 
				
			||||||
  before_action :doorkeeper_authorize!
 | 
					  before_action -> { doorkeeper_authorize! :follow }
 | 
				
			||||||
  respond_to    :json
 | 
					  respond_to    :json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def create
 | 
					  def create
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
class Api::V1::MediaController < ApiController
 | 
					class Api::V1::MediaController < ApiController
 | 
				
			||||||
  before_action :doorkeeper_authorize!
 | 
					  before_action -> { doorkeeper_authorize! :write }
 | 
				
			||||||
  respond_to    :json
 | 
					  respond_to    :json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def create
 | 
					  def create
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,7 @@
 | 
				
			|||||||
class Api::V1::StatusesController < ApiController
 | 
					class Api::V1::StatusesController < ApiController
 | 
				
			||||||
  before_action :doorkeeper_authorize!
 | 
					  before_action -> { doorkeeper_authorize! :read }, except: [:create, :destroy, :reblog, :unreblog, :favourite, :unfavourite]
 | 
				
			||||||
 | 
					  before_action -> { doorkeeper_authorize! :write }, only:  [:create, :destroy, :reblog, :unreblog, :favourite, :unfavourite]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  respond_to    :json
 | 
					  respond_to    :json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def show
 | 
					  def show
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,7 +1,10 @@
 | 
				
			|||||||
class ApiController < ApplicationController
 | 
					class ApiController < ApplicationController
 | 
				
			||||||
  protect_from_forgery with: :null_session
 | 
					  protect_from_forgery with: :null_session
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  skip_before_action :verify_authenticity_token
 | 
					  skip_before_action :verify_authenticity_token
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  before_action :set_rate_limit_headers
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  rescue_from ActiveRecord::RecordInvalid do |e|
 | 
					  rescue_from ActiveRecord::RecordInvalid do |e|
 | 
				
			||||||
    render json: { error: e.to_s }, status: 422
 | 
					    render json: { error: e.to_s }, status: 422
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
@@ -22,8 +25,27 @@ class ApiController < ApplicationController
 | 
				
			|||||||
    render json: { error: 'Remote SSL certificate could not be verified' }, status: 503
 | 
					    render json: { error: 'Remote SSL certificate could not be verified' }, status: 503
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def doorkeeper_unauthorized_render_options(*)
 | 
				
			||||||
 | 
					    { json: { error: 'Not authorized' } }
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def doorkeeper_forbidden_render_options(*)
 | 
				
			||||||
 | 
					    { json: { error: 'This action is outside the authorized scopes' } }
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  protected
 | 
					  protected
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def set_rate_limit_headers
 | 
				
			||||||
 | 
					    return if request.env['rack.attack.throttle_data'].nil?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    now        = Time.now.utc
 | 
				
			||||||
 | 
					    match_data = request.env['rack.attack.throttle_data']['api']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    response.headers['X-RateLimit-Limit']     = match_data[:limit].to_s
 | 
				
			||||||
 | 
					    response.headers['X-RateLimit-Remaining'] = (match_data[:limit] - match_data[:count]).to_s
 | 
				
			||||||
 | 
					    response.headers['X-RateLimit-Reset']     = (now + (match_data[:period] - now.to_i % match_data[:period])).to_s
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def current_resource_owner
 | 
					  def current_resource_owner
 | 
				
			||||||
    User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
 | 
					    User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,6 @@ class HomeController < ApplicationController
 | 
				
			|||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def find_or_create_access_token
 | 
					  def find_or_create_access_token
 | 
				
			||||||
    Doorkeeper::AccessToken.find_or_create_for(Doorkeeper::Application.where(superapp: true).first, current_user.id, nil, Doorkeeper.configuration.access_token_expires_in, Doorkeeper.configuration.refresh_token_enabled?)
 | 
					    Doorkeeper::AccessToken.find_or_create_for(Doorkeeper::Application.where(superapp: true).first, current_user.id, 'read write follow', Doorkeeper.configuration.access_token_expires_in, Doorkeeper.configuration.refresh_token_enabled?)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
							
								
								
									
										9
									
								
								app/controllers/oauth/authorizations_controller.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								app/controllers/oauth/authorizations_controller.rb
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,9 @@
 | 
				
			|||||||
 | 
					class Oauth::AuthorizationsController < Doorkeeper::AuthorizationsController
 | 
				
			||||||
 | 
					  before_action :store_current_location
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def store_current_location
 | 
				
			||||||
 | 
					    store_location_for(:user, request.url)
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@@ -7,7 +7,7 @@ class Feed
 | 
				
			|||||||
  def get(limit, max_id = nil, since_id = nil)
 | 
					  def get(limit, max_id = nil, since_id = nil)
 | 
				
			||||||
    max_id     = '+inf' if max_id.blank?
 | 
					    max_id     = '+inf' if max_id.blank?
 | 
				
			||||||
    since_id   = '-inf' if since_id.blank?
 | 
					    since_id   = '-inf' if since_id.blank?
 | 
				
			||||||
    unhydrated = redis.zrevrangebyscore(key, "(#{max_id}", "(#{since_id}", limit: [0, limit], with_scores: true).collect(&:last).map(&:to_i)
 | 
					    unhydrated = redis.zrevrangebyscore(key, "(#{max_id}", "(#{since_id}", limit: [0, limit], with_scores: true).map(&:last).map(&:to_i)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    # If we're after most recent items and none are there, we need to precompute the feed
 | 
					    # If we're after most recent items and none are there, we need to precompute the feed
 | 
				
			||||||
    if unhydrated.empty? && max_id == '+inf' && since_id == '-inf'
 | 
					    if unhydrated.empty? && max_id == '+inf' && since_id == '-inf'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -34,7 +34,8 @@ class MediaAttachment < ApplicationRecord
 | 
				
			|||||||
    image? ? 'image' : 'video'
 | 
					    image? ? 'image' : 'video'
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def self.file_styles(f)
 | 
					  def self.file_styles(f)
 | 
				
			||||||
    if f.instance.image?
 | 
					    if f.instance.image?
 | 
				
			||||||
      {
 | 
					      {
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +0,0 @@
 | 
				
			|||||||
.prompt= t('doorkeeper.authorizations.error.title')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#error_explanation
 | 
					 | 
				
			||||||
  = @pre_auth.error_response.body[:error_description]
 | 
					 | 
				
			||||||
@@ -1,26 +0,0 @@
 | 
				
			|||||||
.prompt= raw t('.prompt', client_name: "<strong class=\"prompt-highlight\">#{ @pre_auth.client.name }</strong>")
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/- if @pre_auth.scopes.count > 0
 | 
					 | 
				
			||||||
/  .scope-permission-prompt
 | 
					 | 
				
			||||||
/    %p= t('.able_to')
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/    %ul.scope-permissions
 | 
					 | 
				
			||||||
/      - @pre_auth.scopes.each do |scope|
 | 
					 | 
				
			||||||
/        %li= t scope, scope: [:doorkeeper, :scopes]
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
.actions
 | 
					 | 
				
			||||||
  = form_tag oauth_authorization_path, method: :post do
 | 
					 | 
				
			||||||
    = hidden_field_tag :client_id, @pre_auth.client.uid
 | 
					 | 
				
			||||||
    = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri
 | 
					 | 
				
			||||||
    = hidden_field_tag :state, @pre_auth.state
 | 
					 | 
				
			||||||
    = hidden_field_tag :response_type, @pre_auth.response_type
 | 
					 | 
				
			||||||
    = hidden_field_tag :scope, @pre_auth.scope
 | 
					 | 
				
			||||||
    = button_tag t('doorkeeper.authorizations.buttons.authorize'), type: :submit
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  = form_tag oauth_authorization_path, method: :delete do
 | 
					 | 
				
			||||||
    = hidden_field_tag :client_id, @pre_auth.client.uid
 | 
					 | 
				
			||||||
    = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri
 | 
					 | 
				
			||||||
    = hidden_field_tag :state, @pre_auth.state
 | 
					 | 
				
			||||||
    = hidden_field_tag :response_type, @pre_auth.response_type
 | 
					 | 
				
			||||||
    = hidden_field_tag :scope, @pre_auth.scope
 | 
					 | 
				
			||||||
    = button_tag t('doorkeeper.authorizations.buttons.deny'), type: :submit, class: 'negative'
 | 
					 | 
				
			||||||
@@ -1,2 +0,0 @@
 | 
				
			|||||||
.prompt= t('.title')
 | 
					 | 
				
			||||||
%code.copypasteable= params[:code]
 | 
					 | 
				
			||||||
							
								
								
									
										2
									
								
								app/views/oauth/authorizations/error.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										2
									
								
								app/views/oauth/authorizations/error.html.haml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,2 @@
 | 
				
			|||||||
 | 
					.flash-message#error_explanation
 | 
				
			||||||
 | 
					  = @pre_auth.error_response.body[:error_description]
 | 
				
			||||||
							
								
								
									
										25
									
								
								app/views/oauth/authorizations/new.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								app/views/oauth/authorizations/new.html.haml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,25 @@
 | 
				
			|||||||
 | 
					.oauth-prompt
 | 
				
			||||||
 | 
					  %h2
 | 
				
			||||||
 | 
					    Application
 | 
				
			||||||
 | 
					    %strong=@pre_auth.client.name
 | 
				
			||||||
 | 
					    requests access to your account
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  %p
 | 
				
			||||||
 | 
					    It will be able to
 | 
				
			||||||
 | 
					    = @pre_auth.scopes.map { |scope| t(scope, scope: [:doorkeeper, :scopes]) }.map { |s| "<strong>#{s}</strong>"}.to_sentence.html_safe
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					= form_tag oauth_authorization_path, method: :post, class: 'simple_form' do
 | 
				
			||||||
 | 
					  = hidden_field_tag :client_id, @pre_auth.client.uid
 | 
				
			||||||
 | 
					  = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri
 | 
				
			||||||
 | 
					  = hidden_field_tag :state, @pre_auth.state
 | 
				
			||||||
 | 
					  = hidden_field_tag :response_type, @pre_auth.response_type
 | 
				
			||||||
 | 
					  = hidden_field_tag :scope, @pre_auth.scope
 | 
				
			||||||
 | 
					  = button_tag t('doorkeeper.authorizations.buttons.authorize'), type: :submit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					= form_tag oauth_authorization_path, method: :delete, class: 'simple_form' do
 | 
				
			||||||
 | 
					  = hidden_field_tag :client_id, @pre_auth.client.uid
 | 
				
			||||||
 | 
					  = hidden_field_tag :redirect_uri, @pre_auth.redirect_uri
 | 
				
			||||||
 | 
					  = hidden_field_tag :state, @pre_auth.state
 | 
				
			||||||
 | 
					  = hidden_field_tag :response_type, @pre_auth.response_type
 | 
				
			||||||
 | 
					  = hidden_field_tag :scope, @pre_auth.scope
 | 
				
			||||||
 | 
					  = button_tag t('doorkeeper.authorizations.buttons.deny'), type: :submit, class: 'negative'
 | 
				
			||||||
							
								
								
									
										1
									
								
								app/views/oauth/authorizations/show.html.haml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								app/views/oauth/authorizations/show.html.haml
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1 @@
 | 
				
			|||||||
 | 
					%code= params[:code]
 | 
				
			||||||
@@ -12,7 +12,7 @@ Rails.application.configure do
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
  # Full error reports are disabled and caching is turned on.
 | 
					  # Full error reports are disabled and caching is turned on.
 | 
				
			||||||
  config.consider_all_requests_local       = false
 | 
					  config.consider_all_requests_local       = false
 | 
				
			||||||
  config.action_controller.perform_caching = false
 | 
					  config.action_controller.perform_caching = true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Disable serving static files from the `/public` folder by default since
 | 
					  # Disable serving static files from the `/public` folder by default since
 | 
				
			||||||
  # Apache or NGINX already handles this.
 | 
					  # Apache or NGINX already handles this.
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -50,8 +50,8 @@ Doorkeeper.configure do
 | 
				
			|||||||
  # Define access token scopes for your provider
 | 
					  # Define access token scopes for your provider
 | 
				
			||||||
  # 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  :public
 | 
					  default_scopes  :read
 | 
				
			||||||
  # optional_scopes :write, :follow
 | 
					  optional_scopes :write, :follow
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  # Change the way client credentials are retrieved from the request object.
 | 
					  # Change the way client credentials are retrieved from the request object.
 | 
				
			||||||
  # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
 | 
					  # By default it retrieves first from the `HTTP_AUTHORIZATION` header, then
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,5 +1,5 @@
 | 
				
			|||||||
Rabl.configure do |config|
 | 
					Rabl.configure do |config|
 | 
				
			||||||
  config.cache_all_output  = true
 | 
					  config.cache_all_output  = false
 | 
				
			||||||
  config.cache_sources     = !!Rails.env.production?
 | 
					  config.cache_sources     = !!Rails.env.production?
 | 
				
			||||||
  config.include_json_root = false
 | 
					  config.include_json_root = false
 | 
				
			||||||
  config.view_paths        = [Rails.root.join('app/views')]
 | 
					  config.view_paths        = [Rails.root.join('app/views')]
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,9 +1,19 @@
 | 
				
			|||||||
class Rack::Attack
 | 
					class Rack::Attack
 | 
				
			||||||
  throttle('get-req/ip', limit: 300, period: 5.minutes) do |req|
 | 
					  # Rate limits for the API
 | 
				
			||||||
    req.ip if req.get?
 | 
					  throttle('api', limit: 150, period: 5.minutes) do |req|
 | 
				
			||||||
 | 
					    req.ip if req.path.match(/\A\/api\//)
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  throttle('post-req/ip', limit: 100, period: 5.minutes) do |req|
 | 
					  self.throttled_response = lambda do |env|
 | 
				
			||||||
    req.ip if req.post?
 | 
					    now        = Time.now.utc
 | 
				
			||||||
 | 
					    match_data = env['rack.attack.match_data']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    headers = {
 | 
				
			||||||
 | 
					      'X-RateLimit-Limit'     => match_data[:limit].to_s,
 | 
				
			||||||
 | 
					      'X-RateLimit-Remaining' => '0',
 | 
				
			||||||
 | 
					      'X-RateLimit-Reset'     => (now + (match_data[:period] - now.to_i % match_data[:period])).to_s
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    [429, headers, [{ error: 'Throttled' }.to_json]]
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -15,6 +15,10 @@ en:
 | 
				
			|||||||
              secured_uri: 'must be an HTTPS/SSL URI.'
 | 
					              secured_uri: 'must be an HTTPS/SSL URI.'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  doorkeeper:
 | 
					  doorkeeper:
 | 
				
			||||||
 | 
					    scopes:
 | 
				
			||||||
 | 
					      read: read your account's data
 | 
				
			||||||
 | 
					      write: post on your behalf
 | 
				
			||||||
 | 
					      follow: follow, block, unblock and unfollow accounts
 | 
				
			||||||
    applications:
 | 
					    applications:
 | 
				
			||||||
      confirmations:
 | 
					      confirmations:
 | 
				
			||||||
        destroy: 'Are you sure?'
 | 
					        destroy: 'Are you sure?'
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -7,7 +7,9 @@ Rails.application.routes.draw do
 | 
				
			|||||||
    mount Sidekiq::Web => '/sidekiq'
 | 
					    mount Sidekiq::Web => '/sidekiq'
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  use_doorkeeper
 | 
					  use_doorkeeper do
 | 
				
			||||||
 | 
					    controllers authorizations: 'oauth/authorizations'
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  get '.well-known/host-meta', to: 'xrd#host_meta', as: :host_meta
 | 
					  get '.well-known/host-meta', to: 'xrd#host_meta', as: :host_meta
 | 
				
			||||||
  get '.well-known/webfinger', to: 'xrd#webfinger', as: :webfinger
 | 
					  get '.well-known/webfinger', to: 'xrd#webfinger', as: :webfinger
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,2 +1,2 @@
 | 
				
			|||||||
web_app = Doorkeeper::Application.new(name: 'Web', superapp: true, redirect_uri: Doorkeeper.configuration.native_redirect_uri)
 | 
					web_app = Doorkeeper::Application.new(name: 'Web', superapp: true, redirect_uri: Doorkeeper.configuration.native_redirect_uri, scopes: 'read write follow')
 | 
				
			||||||
web_app.save!
 | 
					web_app.save!
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,9 +2,7 @@ namespace :mastodon do
 | 
				
			|||||||
  namespace :media do
 | 
					  namespace :media do
 | 
				
			||||||
    desc 'Removes media attachments that have not been assigned to any status for longer than a day'
 | 
					    desc 'Removes media attachments that have not been assigned to any status for longer than a day'
 | 
				
			||||||
    task clear: :environment do
 | 
					    task clear: :environment do
 | 
				
			||||||
      MediaAttachment.where(status_id: nil).where('created_at < ?', 1.day.ago).find_each do |m|
 | 
					      MediaAttachment.where(status_id: nil).where('created_at < ?', 1.day.ago).find_each(&:destroy)
 | 
				
			||||||
        m.destroy
 | 
					 | 
				
			||||||
      end
 | 
					 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user