about summary refs log tree commit diff
path: root/app
diff options
context:
space:
mode:
authorEugen Rochko <eugen@zeonfederated.com>2017-06-25 23:51:32 +0200
committerGitHub <noreply@github.com>2017-06-25 23:51:32 +0200
commited7dc1704dc3ce82567d9aac366b095f02ce181f (patch)
treeeb05f60470367fc111c0258e7e3bc06cc779f9d0 /app
parent436ce03772c8c87a215cdcd88020edfb8c241d38 (diff)
Bind web UI access tokens to sessions (#3940)
* Add overview of active sessions

* Better display of browser/platform name

* Improve how browser information is stored and displayed for sessions overview

* Fix test

* Fix #2347 - Bind web UI access token to session

When you logout, session also destroys the access token, so it's no longer
valid. If access token is destroyed some other way, the session is also
destroyed, requiring a re-login.

Fix #1681 - Add scheduler to remove revoked access tokens and grants

* Fix test
Diffstat (limited to 'app')
-rw-r--r--app/controllers/application_controller.rb5
-rw-r--r--app/controllers/home_controller.rb12
-rw-r--r--app/models/session_activation.rb44
-rw-r--r--app/workers/scheduler/doorkeeper_cleanup_scheduler.rb11
4 files changed, 51 insertions, 21 deletions
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
index 9cb397aa8..865fcd125 100644
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -11,6 +11,7 @@ class ApplicationController < ActionController::Base
   include UserTrackingConcern
 
   helper_method :current_account
+  helper_method :current_session
   helper_method :single_user_mode?
 
   rescue_from ActionController::RoutingError, with: :not_found
@@ -68,6 +69,10 @@ class ApplicationController < ActionController::Base
     @current_account ||= current_user.try(:account)
   end
 
+  def current_session
+    @current_session ||= SessionActivation.find_by(session_id: session['auth_id'])
+  end
+
   def cache_collection(raw, klass)
     return raw unless klass.respond_to?(:with_includes)
 
diff --git a/app/controllers/home_controller.rb b/app/controllers/home_controller.rb
index 1d41892cd..6209a3ae9 100644
--- a/app/controllers/home_controller.rb
+++ b/app/controllers/home_controller.rb
@@ -5,7 +5,7 @@ class HomeController < ApplicationController
 
   def index
     @body_classes           = 'app-body'
-    @token                  = find_or_create_access_token.token
+    @token                  = current_session.token
     @web_settings           = Web::Setting.find_by(user: current_user)&.data || {}
     @admin                  = Account.find_local(Setting.site_contact_username)
     @streaming_api_base_url = Rails.configuration.x.streaming_api_base_url
@@ -16,14 +16,4 @@ class HomeController < ApplicationController
   def authenticate_user!
     redirect_to(single_user_mode? ? account_path(Account.first) : about_path) unless user_signed_in?
   end
-
-  def find_or_create_access_token
-    Doorkeeper::AccessToken.find_or_create_for(
-      Doorkeeper::Application.where(superapp: true).first,
-      current_user.id,
-      Doorkeeper::OAuth::Scopes.from_string('read write follow'),
-      Doorkeeper.configuration.access_token_expires_in,
-      Doorkeeper.configuration.refresh_token_enabled?
-    )
-  end
 end
diff --git a/app/models/session_activation.rb b/app/models/session_activation.rb
index 75339b5f7..02a918e8a 100644
--- a/app/models/session_activation.rb
+++ b/app/models/session_activation.rb
@@ -3,16 +3,23 @@
 #
 # Table name: session_activations
 #
-#  id         :integer          not null, primary key
-#  user_id    :integer          not null
-#  session_id :string           not null
-#  created_at :datetime         not null
-#  updated_at :datetime         not null
-#  user_agent :string           default(""), not null
-#  ip         :inet
+#  id              :integer          not null, primary key
+#  user_id         :integer          not null
+#  session_id      :string           not null
+#  created_at      :datetime         not null
+#  updated_at      :datetime         not null
+#  user_agent      :string           default(""), not null
+#  ip              :inet
+#  access_token_id :integer
 #
 
 class SessionActivation < ApplicationRecord
+  belongs_to :access_token, class_name: 'Doorkeeper::AccessToken', dependent: :destroy
+
+  delegate :token,
+           to: :access_token,
+           allow_nil: true
+
   def detection
     @detection ||= Browser.new(user_agent)
   end
@@ -25,9 +32,8 @@ class SessionActivation < ApplicationRecord
     detection.platform.id
   end
 
-  before_save do
-    self.user_agent = '' if user_agent.nil?
-  end
+  before_create :assign_access_token
+  before_save   :assign_user_agent
 
   class << self
     def active?(id)
@@ -53,4 +59,22 @@ class SessionActivation < ApplicationRecord
       where('session_id != ?', id).destroy_all
     end
   end
+
+  private
+
+  def assign_user_agent
+    self.user_agent = '' if user_agent.nil?
+  end
+
+  def assign_access_token
+    superapp = Doorkeeper::Application.find_by(superapp: true)
+
+    return if superapp.nil?
+
+    self.access_token = Doorkeeper::AccessToken.create!(application_id: superapp.id,
+                                                        resource_owner_id: user_id,
+                                                        scopes: 'read write follow',
+                                                        expires_in: Doorkeeper.configuration.access_token_expires_in,
+                                                        use_refresh_token: Doorkeeper.configuration.refresh_token_enabled?)
+  end
 end
diff --git a/app/workers/scheduler/doorkeeper_cleanup_scheduler.rb b/app/workers/scheduler/doorkeeper_cleanup_scheduler.rb
new file mode 100644
index 000000000..6488798cd
--- /dev/null
+++ b/app/workers/scheduler/doorkeeper_cleanup_scheduler.rb
@@ -0,0 +1,11 @@
+# frozen_string_literal: true
+require 'sidekiq-scheduler'
+
+class Scheduler::DoorkeeperCleanupScheduler
+  include Sidekiq::Worker
+
+  def perform
+    Doorkeeper::AccessToken.where('revoked_at IS NOT NULL').where('revoked_at < NOW()').delete_all
+    Doorkeeper::AccessGrant.where('revoked_at IS NOT NULL').where('revoked_at < NOW()').delete_all
+  end
+end