about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2016-10-22 19:38:47 +0200
committerEugen Rochko <eugen@zeonfederated.com>2016-10-22 19:39:44 +0200
commita9e40a3d80435431f689b8d19005dd77a8f50224 (patch)
tree48573a1f1ec9c14789c529de3b8fb8badfb20444 /app
parent17122df80dc7e85910a9cfa049d2e33ef84288c6 (diff)
Adding OAuth access scopes, fixing OAuth authorization UI, adding rate limiting
to the API
Diffstat (limited to 'app')
-rw-r--r--app/assets/stylesheets/forms.scss88
-rw-r--r--app/channels/public_channel.rb2
-rw-r--r--app/controllers/api/v1/accounts_controller.rb4
-rw-r--r--app/controllers/api/v1/follows_controller.rb2
-rw-r--r--app/controllers/api/v1/media_controller.rb2
-rw-r--r--app/controllers/api/v1/statuses_controller.rb4
-rw-r--r--app/controllers/api_controller.rb22
-rw-r--r--app/controllers/home_controller.rb2
-rw-r--r--app/controllers/oauth/authorizations_controller.rb9
-rw-r--r--app/models/feed.rb2
-rw-r--r--app/models/media_attachment.rb3
-rw-r--r--app/views/doorkeeper/authorizations/error.html.haml4
-rw-r--r--app/views/doorkeeper/authorizations/new.html.haml26
-rw-r--r--app/views/doorkeeper/authorizations/show.html.haml2
-rw-r--r--app/views/oauth/authorizations/error.html.haml2
-rw-r--r--app/views/oauth/authorizations/new.html.haml25
-rw-r--r--app/views/oauth/authorizations/show.html.haml1
17 files changed, 118 insertions, 82 deletions
diff --git a/app/assets/stylesheets/forms.scss b/app/assets/stylesheets/forms.scss
index 8abbbdaee..f7677ac9d 100644
--- a/app/assets/stylesheets/forms.scss
+++ b/app/assets/stylesheets/forms.scss
@@ -85,18 +85,7 @@
     }
   }
 
-  .prompt {
-    font-size: 16px;
-    color: #9baec8;
-    text-align: center;
-
-    .prompt-highlight {
-      font-weight: 500;
-      color: #fff;
-    }
-  }
-
-  code.copypasteable {
+  code {
     display: block;
     font-family: 'Roboto Mono', monospace;
     font-weight: 400;
@@ -110,42 +99,42 @@
 
   .actions {
     margin-top: 30px;
+  }
 
-    button {
-      display: block;
-      width: 100%;
-      border: 0;
-      border-radius: 4px;
-      background: #2b90d9;
-      color: #fff;
-      font-size: 18px;
-      padding: 10px;
-      text-transform: uppercase;
-      cursor: pointer;
-      font-weight: 500;
-      outline: 0;
-      margin-bottom: 10px;
+  button {
+    display: block;
+    width: 100%;
+    border: 0;
+    border-radius: 4px;
+    background: #2b90d9;
+    color: #fff;
+    font-size: 18px;
+    padding: 10px;
+    text-transform: uppercase;
+    cursor: pointer;
+    font-weight: 500;
+    outline: 0;
+    margin-bottom: 10px;
 
-      &:hover {
-        background-color: lighten(#2b90d9, 5%);
-      }
+    &:hover {
+      background-color: lighten(#2b90d9, 5%);
+    }
 
-      &:active, &:focus {
-        position: relative;
-        top: 1px;
-        background-color: darken(#2b90d9, 5%);
-      }
+    &:active, &:focus {
+      position: relative;
+      top: 1px;
+      background-color: darken(#2b90d9, 5%);
+    }
 
-      &.negative {
-        background: #df405a;
+    &.negative {
+      background: #df405a;
 
-        &:hover {
-          background-color: lighten(#df405a, 5%);
-        }
+      &:hover {
+        background-color: lighten(#df405a, 5%);
+      }
 
-        &:active, &:focus {
-          background-color: darken(#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;
+  }
+}
diff --git a/app/channels/public_channel.rb b/app/channels/public_channel.rb
index 5d7fadc1d..578cdc001 100644
--- a/app/channels/public_channel.rb
+++ b/app/channels/public_channel.rb
@@ -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.
 class PublicChannel < ApplicationCable::Channel
   def subscribed
-    stream_from 'timeline:public', -> (encoded_message) do
+    stream_from 'timeline:public', lambda do |encoded_message|
       message = ActiveSupport::JSON.decode(encoded_message)
 
       status = Status.find_by(id: message['id'])
diff --git a/app/controllers/api/v1/accounts_controller.rb b/app/controllers/api/v1/accounts_controller.rb
index 2669315e2..bb3e54a89 100644
--- a/app/controllers/api/v1/accounts_controller.rb
+++ b/app/controllers/api/v1/accounts_controller.rb
@@ -1,5 +1,7 @@
 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]
   respond_to    :json
 
diff --git a/app/controllers/api/v1/follows_controller.rb b/app/controllers/api/v1/follows_controller.rb
index 739ac1fb1..9181cd077 100644
--- a/app/controllers/api/v1/follows_controller.rb
+++ b/app/controllers/api/v1/follows_controller.rb
@@ -1,5 +1,5 @@
 class Api::V1::FollowsController < ApiController
-  before_action :doorkeeper_authorize!
+  before_action -> { doorkeeper_authorize! :follow }
   respond_to    :json
 
   def create
diff --git a/app/controllers/api/v1/media_controller.rb b/app/controllers/api/v1/media_controller.rb
index 7efe38bd8..dffc797fe 100644
--- a/app/controllers/api/v1/media_controller.rb
+++ b/app/controllers/api/v1/media_controller.rb
@@ -1,5 +1,5 @@
 class Api::V1::MediaController < ApiController
-  before_action :doorkeeper_authorize!
+  before_action -> { doorkeeper_authorize! :write }
   respond_to    :json
 
   def create
diff --git a/app/controllers/api/v1/statuses_controller.rb b/app/controllers/api/v1/statuses_controller.rb
index a7305233e..b02b7bb57 100644
--- a/app/controllers/api/v1/statuses_controller.rb
+++ b/app/controllers/api/v1/statuses_controller.rb
@@ -1,5 +1,7 @@
 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
 
   def show
diff --git a/app/controllers/api_controller.rb b/app/controllers/api_controller.rb
index e29892cbe..0776f4ce8 100644
--- a/app/controllers/api_controller.rb
+++ b/app/controllers/api_controller.rb
@@ -1,7 +1,10 @@
 class ApiController < ApplicationController
   protect_from_forgery with: :null_session
+
   skip_before_action :verify_authenticity_token
 
+  before_action :set_rate_limit_headers
+
   rescue_from ActiveRecord::RecordInvalid do |e|
     render json: { error: e.to_s }, status: 422
   end
@@ -22,8 +25,27 @@ class ApiController < ApplicationController
     render json: { error: 'Remote SSL certificate could not be verified' }, status: 503
   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
 
+  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
     User.find(doorkeeper_token.resource_owner_id) if doorkeeper_token
   end
diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb
index 4e6b2a879..8ed88d074 100644
--- a/app/controllers/home_controller.rb
+++ b/app/controllers/home_controller.rb
@@ -15,6 +15,6 @@ class HomeController < ApplicationController
   end
 
   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
diff --git a/app/controllers/oauth/authorizations_controller.rb b/app/controllers/oauth/authorizations_controller.rb
new file mode 100644
index 000000000..f5f05814e
--- /dev/null
+++ b/app/controllers/oauth/authorizations_controller.rb
@@ -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
diff --git a/app/models/feed.rb b/app/models/feed.rb
index 2bc9e980a..211d64638 100644
--- a/app/models/feed.rb
+++ b/app/models/feed.rb
@@ -7,7 +7,7 @@ class Feed
   def get(limit, max_id = nil, since_id = nil)
     max_id     = '+inf' if max_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 unhydrated.empty? && max_id == '+inf' && since_id == '-inf'
diff --git a/app/models/media_attachment.rb b/app/models/media_attachment.rb
index ab6c91efb..008147a08 100644
--- a/app/models/media_attachment.rb
+++ b/app/models/media_attachment.rb
@@ -34,7 +34,8 @@ class MediaAttachment < ApplicationRecord
     image? ? 'image' : 'video'
   end
 
-private
+  private
+
   def self.file_styles(f)
     if f.instance.image?
       {
diff --git a/app/views/doorkeeper/authorizations/error.html.haml b/app/views/doorkeeper/authorizations/error.html.haml
deleted file mode 100644
index cb97ae170..000000000
--- a/app/views/doorkeeper/authorizations/error.html.haml
+++ /dev/null
@@ -1,4 +0,0 @@
-.prompt= t('doorkeeper.authorizations.error.title')
-
-#error_explanation
-  = @pre_auth.error_response.body[:error_description]
diff --git a/app/views/doorkeeper/authorizations/new.html.haml b/app/views/doorkeeper/authorizations/new.html.haml
deleted file mode 100644
index 91d71cc01..000000000
--- a/app/views/doorkeeper/authorizations/new.html.haml
+++ /dev/null
@@ -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'
diff --git a/app/views/doorkeeper/authorizations/show.html.haml b/app/views/doorkeeper/authorizations/show.html.haml
deleted file mode 100644
index 44638318b..000000000
--- a/app/views/doorkeeper/authorizations/show.html.haml
+++ /dev/null
@@ -1,2 +0,0 @@
-.prompt= t('.title')
-%code.copypasteable= params[:code]
diff --git a/app/views/oauth/authorizations/error.html.haml b/app/views/oauth/authorizations/error.html.haml
new file mode 100644
index 000000000..ee72d9740
--- /dev/null
+++ b/app/views/oauth/authorizations/error.html.haml
@@ -0,0 +1,2 @@
+.flash-message#error_explanation
+  = @pre_auth.error_response.body[:error_description]
diff --git a/app/views/oauth/authorizations/new.html.haml b/app/views/oauth/authorizations/new.html.haml
new file mode 100644
index 000000000..ba5d426f5
--- /dev/null
+++ b/app/views/oauth/authorizations/new.html.haml
@@ -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'
diff --git a/app/views/oauth/authorizations/show.html.haml b/app/views/oauth/authorizations/show.html.haml
new file mode 100644
index 000000000..d1a3e1f81
--- /dev/null
+++ b/app/views/oauth/authorizations/show.html.haml
@@ -0,0 +1 @@
+%code= params[:code]