Refactor handling of auth token for pre 0.9.9 clients
This commit is contained in:
parent
a719251745
commit
47578b63b1
@ -32,12 +32,7 @@ module Api
|
||||
private
|
||||
|
||||
def asciicast_attributes
|
||||
username, token = basic_auth_credentials
|
||||
AsciicastParams.build(params[:asciicast], username, token, request.user_agent)
|
||||
end
|
||||
|
||||
def basic_auth_credentials
|
||||
authenticate_with_http_basic { |username, password| [username, password] }
|
||||
AsciicastParams.build(params[:asciicast], current_user, request.user_agent)
|
||||
end
|
||||
|
||||
def asciicast_creator
|
||||
|
25
app/middleware/api_token_registrator.rb
Normal file
25
app/middleware/api_token_registrator.rb
Normal file
@ -0,0 +1,25 @@
|
||||
class ApiTokenRegistrator
|
||||
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
auth = Rack::Auth::Basic::Request.new(env)
|
||||
|
||||
if auth.provided? && auth.basic? && auth.credentials
|
||||
ensure_user_with_token(*auth.credentials)
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def ensure_user_with_token(username, token)
|
||||
unless ApiToken.where(token: token).exists?
|
||||
ApiToken.create_with_tmp_user!(token, username)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
26
app/middleware/metadata_parser.rb
Normal file
26
app/middleware/metadata_parser.rb
Normal file
@ -0,0 +1,26 @@
|
||||
class MetadataParser
|
||||
|
||||
def initialize(app)
|
||||
@app = app
|
||||
end
|
||||
|
||||
def call(env)
|
||||
request = Rack::Request.new(env)
|
||||
auth = Rack::Auth::Basic::Request.new(env)
|
||||
|
||||
if request.post? && request.path == '/api/asciicasts'
|
||||
if request.params['asciicast']['meta'] # pre "format 1" client
|
||||
meta = JSON.parse(request.params['asciicast']['meta'][:tempfile].read)
|
||||
request.params['asciicast']['meta'] = meta
|
||||
|
||||
username, token = meta.delete('username'), meta.delete('user_token')
|
||||
if token.present? && !auth.provided? || !auth.basic?
|
||||
env['HTTP_AUTHORIZATION'] = ActionController::HttpAuthentication::Basic.encode_credentials(username, token)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@app.call(env)
|
||||
end
|
||||
|
||||
end
|
@ -8,7 +8,16 @@ class ApiToken < ActiveRecord::Base
|
||||
validates :token, uniqueness: true
|
||||
|
||||
def self.for_token(token)
|
||||
ApiToken.where(token: token).first
|
||||
where(token: token).first
|
||||
end
|
||||
|
||||
def self.create_with_tmp_user!(token, username)
|
||||
transaction do
|
||||
ApiToken.create!(
|
||||
token: token,
|
||||
user: User.create!(temporary_username: username.presence),
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def reassign_to(target_user)
|
||||
|
@ -1,18 +1,16 @@
|
||||
class AsciicastParams
|
||||
FormatError = Class.new(StandardError)
|
||||
|
||||
def self.build(asciicast_params, username, token, user_agent)
|
||||
def self.build(asciicast_params, user, user_agent)
|
||||
if asciicast_params.try(:respond_to?, :read)
|
||||
from_format_1_request(asciicast_params, username, token, user_agent)
|
||||
from_format_1_request(asciicast_params, user, user_agent)
|
||||
else
|
||||
from_format_0_request(asciicast_params, username, token, user_agent)
|
||||
from_format_0_request(asciicast_params, user, user_agent)
|
||||
end
|
||||
end
|
||||
|
||||
def self.from_format_0_request(params, username, token, user_agent)
|
||||
meta = JSON.parse(params.delete(:meta).read)
|
||||
token ||= meta.delete('user_token')
|
||||
username ||= meta.delete('username')
|
||||
def self.from_format_0_request(params, user, user_agent)
|
||||
meta = params.delete(:meta)
|
||||
|
||||
attributes = {
|
||||
command: meta['command'],
|
||||
@ -26,7 +24,7 @@ class AsciicastParams
|
||||
terminal_lines: meta['term']['lines'],
|
||||
terminal_type: meta['term']['type'],
|
||||
title: meta['title'],
|
||||
user: User.for_api_token!(token, username),
|
||||
user: user,
|
||||
version: 0,
|
||||
}
|
||||
|
||||
@ -39,7 +37,7 @@ class AsciicastParams
|
||||
attributes
|
||||
end
|
||||
|
||||
def self.from_format_1_request(asciicast_file, username, token, user_agent)
|
||||
def self.from_format_1_request(asciicast_file, user, user_agent)
|
||||
begin
|
||||
asciicast = Oj.sc_parse(AsciicastHandler.new, asciicast_file)
|
||||
rescue Oj::ParseError
|
||||
@ -63,7 +61,7 @@ class AsciicastParams
|
||||
terminal_lines: asciicast['height'],
|
||||
terminal_type: env && env['TERM'],
|
||||
title: asciicast['title'],
|
||||
user: User.for_api_token!(token, username),
|
||||
user: user,
|
||||
user_agent: user_agent,
|
||||
version: version,
|
||||
}
|
||||
|
@ -44,25 +44,10 @@ class User < ActiveRecord::Base
|
||||
joins(:api_tokens).where('api_tokens.token' => token).first
|
||||
end
|
||||
|
||||
def self.for_api_token!(token, username)
|
||||
for_api_token(token) || create_with_token(token, username)
|
||||
end
|
||||
|
||||
def self.for_auth_token(auth_token)
|
||||
where(auth_token: auth_token).first
|
||||
end
|
||||
|
||||
def self.create_with_token(token, username)
|
||||
return nil if token.blank?
|
||||
username = nil if username.blank?
|
||||
|
||||
transaction do |tx|
|
||||
user = User.create!(temporary_username: username)
|
||||
user.api_tokens.create!(token: token)
|
||||
user
|
||||
end
|
||||
end
|
||||
|
||||
def self.generate_auth_token
|
||||
SecureRandom.urlsafe_base64
|
||||
end
|
||||
|
24
app/strategies/api_token_strategy.rb
Normal file
24
app/strategies/api_token_strategy.rb
Normal file
@ -0,0 +1,24 @@
|
||||
class ApiTokenStrategy < ::Warden::Strategies::Base
|
||||
|
||||
def valid?
|
||||
auth.provided? && auth.basic? && auth.credentials
|
||||
end
|
||||
|
||||
def authenticate!
|
||||
user = User.for_api_token(auth.credentials.last)
|
||||
user.nil? ? fail!("Invalid auth token") : success!(user)
|
||||
end
|
||||
|
||||
def store?
|
||||
false
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def auth
|
||||
@auth ||= Rack::Auth::Basic::Request.new(env)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
Warden::Strategies.add(:api_token, ApiTokenStrategy)
|
@ -48,6 +48,10 @@ module Asciinema
|
||||
rewrite /%7E(.+)/i, '/~$1'
|
||||
end
|
||||
|
||||
config.middleware.use 'MetadataParser'
|
||||
config.middleware.use 'ApiTokenRegistrator'
|
||||
config.middleware.use 'Warden::Manager'
|
||||
|
||||
config.action_mailer.default_url_options = { protocol: CFG.scheme, host: CFG.host }
|
||||
|
||||
if CFG.smtp_settings
|
||||
|
@ -7,6 +7,4 @@ Warden::Manager.serialize_from_session do |id|
|
||||
end
|
||||
|
||||
require 'auth_cookie_strategy'
|
||||
|
||||
Rails.application.config.middleware.insert_after ActionDispatch::Flash, Warden::Manager do |manager|
|
||||
end
|
||||
require 'api_token_strategy'
|
||||
|
@ -97,7 +97,7 @@ describe "Asciicast creation" do
|
||||
end
|
||||
|
||||
context 'when a user with given token exists' do
|
||||
let(:user) { User.create_with_token('f33e6188-f53c-11e2-abf4-84a6c827e88b', 'kill') }
|
||||
let(:user) { ApiToken.create_with_tmp_user!('f33e6188-f53c-11e2-abf4-84a6c827e88b', 'kill').user }
|
||||
|
||||
subject do
|
||||
user
|
||||
@ -192,7 +192,7 @@ describe "Asciicast creation" do
|
||||
end
|
||||
|
||||
context 'when a user with given token exists' do
|
||||
let(:user) { User.create_with_token('f33e6188-f53c-11e2-abf4-84a6c827e88b', 'kill') }
|
||||
let(:user) { ApiToken.create_with_tmp_user!('f33e6188-f53c-11e2-abf4-84a6c827e88b', 'kill').user }
|
||||
|
||||
subject do
|
||||
user
|
||||
@ -287,7 +287,7 @@ describe "Asciicast creation" do
|
||||
end
|
||||
|
||||
context 'when a user with given token exists' do
|
||||
let(:user) { User.create_with_token('f33e6188-f53c-11e2-abf4-84a6c827e88b', 'kill') }
|
||||
let(:user) { ApiToken.create_with_tmp_user!('f33e6188-f53c-11e2-abf4-84a6c827e88b', 'kill').user }
|
||||
|
||||
subject do
|
||||
user
|
||||
@ -373,7 +373,7 @@ describe "Asciicast creation" do
|
||||
end
|
||||
|
||||
context 'when a user with given token exists' do
|
||||
let(:user) { User.create_with_token('f33e6188-f53c-11e2-abf4-84a6c827e88b', 'kill') }
|
||||
let(:user) { ApiToken.create_with_tmp_user!('f33e6188-f53c-11e2-abf4-84a6c827e88b', 'kill').user }
|
||||
|
||||
subject do
|
||||
user
|
||||
|
@ -76,55 +76,6 @@ describe User do
|
||||
end
|
||||
end
|
||||
|
||||
describe '.create_with_token' do
|
||||
subject { described_class.create_with_token(token, username) }
|
||||
|
||||
let(:token) { 'f33e6188-f53c-11e2-abf4-84a6c827e88b' }
|
||||
let(:username) { 'somerandomguy' }
|
||||
|
||||
it "returns a persisted user record" do
|
||||
expect(subject.id).not_to be(nil)
|
||||
end
|
||||
|
||||
it "assigns given username to the user as temporary_username" do
|
||||
expect(subject.temporary_username).to eq(username)
|
||||
end
|
||||
|
||||
it "assigns given api token to the user" do
|
||||
expect(subject.api_tokens.reload.first.token).to eq(token)
|
||||
end
|
||||
|
||||
context "when token is blank" do
|
||||
let(:token) { '' }
|
||||
|
||||
it { should be(nil) }
|
||||
end
|
||||
|
||||
context "when username is nil" do
|
||||
let(:username) { nil }
|
||||
|
||||
it "returns a persisted user record" do
|
||||
expect(subject.id).not_to be(nil)
|
||||
end
|
||||
|
||||
it "assigns nil as temporary_username to the user" do
|
||||
expect(subject.temporary_username).to be(nil)
|
||||
end
|
||||
end
|
||||
|
||||
context "when username is an empty string" do
|
||||
let(:username) { nil }
|
||||
|
||||
it "returns a persisted user record" do
|
||||
expect(subject.id).not_to be(nil)
|
||||
end
|
||||
|
||||
it "assigns nil as temporary_username to the user" do
|
||||
expect(subject.temporary_username).to be(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#username=' do
|
||||
it 'strips the whitespace' do
|
||||
user = described_class.new(username: ' sickill ')
|
||||
|
Loading…
Reference in New Issue
Block a user