mirror of
https://github.com/mastodon/mastodon.git
synced 2024-11-08 08:44:27 +00:00
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
This commit is contained in:
parent
436ce03772
commit
ed7dc1704d
|
@ -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)
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
11
app/workers/scheduler/doorkeeper_cleanup_scheduler.rb
Normal file
11
app/workers/scheduler/doorkeeper_cleanup_scheduler.rb
Normal file
|
@ -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
|
|
@ -15,3 +15,6 @@
|
|||
feed_cleanup_scheduler:
|
||||
cron: '0 0 * * *'
|
||||
class: Scheduler::FeedCleanupScheduler
|
||||
doorkeeper_cleanup_scheduler:
|
||||
cron: '1 1 * * 0'
|
||||
class: Scheduler::DoorkeeperCleanupScheduler
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
class AddAccessTokenIdToSessionActivations < ActiveRecord::Migration[5.1]
|
||||
def change
|
||||
add_column :session_activations, :access_token_id, :integer
|
||||
add_foreign_key :session_activations, :oauth_access_tokens, column: :access_token_id, on_delete: :cascade
|
||||
end
|
||||
end
|
|
@ -10,7 +10,7 @@
|
|||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20170624134742) do
|
||||
ActiveRecord::Schema.define(version: 20170625140443) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
|
@ -257,6 +257,7 @@ ActiveRecord::Schema.define(version: 20170624134742) do
|
|||
t.datetime "updated_at", null: false
|
||||
t.string "user_agent", default: "", null: false
|
||||
t.inet "ip"
|
||||
t.integer "access_token_id"
|
||||
t.index ["session_id"], name: "index_session_activations_on_session_id", unique: true
|
||||
t.index ["user_id"], name: "index_session_activations_on_user_id"
|
||||
end
|
||||
|
@ -406,6 +407,7 @@ ActiveRecord::Schema.define(version: 20170624134742) do
|
|||
add_foreign_key "reports", "accounts", column: "action_taken_by_account_id", on_delete: :nullify
|
||||
add_foreign_key "reports", "accounts", column: "target_account_id", on_delete: :cascade
|
||||
add_foreign_key "reports", "accounts", on_delete: :cascade
|
||||
add_foreign_key "session_activations", "oauth_access_tokens", column: "access_token_id", on_delete: :cascade
|
||||
add_foreign_key "session_activations", "users", on_delete: :cascade
|
||||
add_foreign_key "statuses", "accounts", column: "in_reply_to_account_id", on_delete: :nullify
|
||||
add_foreign_key "statuses", "accounts", on_delete: :cascade
|
||||
|
|
Loading…
Reference in a new issue