diff --git a/lib/travis/api/app/endpoint/authorization.rb b/lib/travis/api/app/endpoint/authorization.rb index 9c53c1fe8a..8c126eab29 100644 --- a/lib/travis/api/app/endpoint/authorization.rb +++ b/lib/travis/api/app/endpoint/authorization.rb @@ -142,7 +142,9 @@ def update_first_login(user) def serialize_user(user) rendered = Travis::Api::Serialize.data(user, version: :v2) - rendered['user'].merge('token' => user.tokens.first.try(:token).to_s) + rendered['user'].merge!('token' => user.default_tokens.first.try(:token).to_s) + rendered['user'].merge!('svg_token' => user.svg_token.to_s) + rendered['user'] end def oauth_endpoint diff --git a/lib/travis/api/app/helpers/respond_with.rb b/lib/travis/api/app/helpers/respond_with.rb index 2fd5c6f32a..d7d8ce0eab 100644 --- a/lib/travis/api/app/helpers/respond_with.rb +++ b/lib/travis/api/app/helpers/respond_with.rb @@ -32,7 +32,6 @@ def body(value = nil, options = {}, &block) end private - def respond(resource, options) resource = apply_service_responder(resource, options) response = nil @@ -41,13 +40,34 @@ def respond(resource, options) acceptable_formats.find do |accept| responders.find do |const| responder = const.new(self, resource, options.dup.merge(accept: accept)) - response = responder.apply if responder.apply? + if responder.apply? + if token_proper?(responder) + response = responder.apply + else + halt 403, 'access denied' + end + end end end response || (resource ? error(406) : error(404)) end + def token_proper?(responder) + return true unless params[:token] # it means that ScopeCheck granted access basing on other proper token + + acceptable = acceptable_tokens(responder) + token = Token.find_by_token(params[:token]) + acceptable.include?(token.try(:purpose_symbol)) + end + + def acceptable_tokens(responder) + case(responder) + when Travis::Api::App::Responders::Badge then [:svg] + else [:default] + end + end + def prettify_result? !params[:pretty].nil? && (params[:pretty].downcase == 'true' || params[:pretty].to_i > 0) end diff --git a/lib/travis/model/token.rb b/lib/travis/model/token.rb index 93f45ec9dd..50ce804178 100644 --- a/lib/travis/model/token.rb +++ b/lib/travis/model/token.rb @@ -15,6 +15,10 @@ class Token < Travis::Model serialize :token, Travis::Model::EncryptedColumn.new(disable: true) + def purpose_symbol + purpose.try(:to_sym) || :default + end + protected def generate_token diff --git a/lib/travis/model/user.rb b/lib/travis/model/user.rb index 970c3c33b2..4e79d09f82 100644 --- a/lib/travis/model/user.rb +++ b/lib/travis/model/user.rb @@ -15,6 +15,7 @@ class User < Travis::Model before_create :set_as_recent after_create :create_a_token + after_create :create_svg_token before_save :track_previous_changes serialize :github_scopes @@ -40,7 +41,16 @@ def with_email(email_address) end def token - tokens.first.try(:token) + tokens.find { |t| t.try(:purpose_symbol) == :default}.try(:token) + end + + def svg_token + token = tokens.find { |t| t.try(:purpose_symbol) == :svg} || create_svg_token + token.try(:token) + end + + def default_tokens + self.tokens.select { |token| token.try(:purpose_symbol) == :default } end def to_json @@ -162,8 +172,15 @@ def inspect github_oauth_token ? super.gsub(github_oauth_token, '[REDACTED]') : super end - def create_a_token - self.tokens.create! + def create_a_token(purpose = :default) + token = self.tokens.create! + token.purpose = purpose.to_s + token.save! + token + end + + def create_svg_token + create_a_token(:svg) end protected diff --git a/spec/auth/v1/repo_status_spec.rb b/spec/auth/v1/repo_status_spec.rb index d0be340b21..696312c374 100644 --- a/spec/auth/v1/repo_status_spec.rb +++ b/spec/auth/v1/repo_status_spec.rb @@ -79,13 +79,13 @@ it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.png' } end - describe 'GET /repos/%{repo.slug}?token=%{user.token} Accept image/svg+xml' do + describe 'GET /repos/%{repo.slug}?token=%{user.svg_token} Accept image/svg+xml' do let(:accept) { 'image/svg+xml' } it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end - describe 'GET /repos/%{repo.slug}.svg?token=%{user.token}' do + describe 'GET /repos/%{repo.slug}.svg?token=%{user.svg_token}' do it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end @@ -184,13 +184,13 @@ it(:without_permission) { should auth status: 200, type: :img, file: 'passing.png' } end - describe 'GET /repos/%{repo.slug}?token=%{user.token} Accept image/svg+xml' do + describe 'GET /repos/%{repo.slug}?token=%{user.svg_token} Accept image/svg+xml' do let(:accept) { 'image/svg+xml' } it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'passing.svg' } end - describe 'GET /repos/%{repo.slug}.svg?token=%{user.token}' do + describe 'GET /repos/%{repo.slug}.svg?token=%{user.svg_token}' do it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'passing.svg' } end @@ -289,13 +289,13 @@ it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.png' } end - describe 'GET /repos/%{repo.slug}?token=%{user.token} Accept image/svg+xml' do + describe 'GET /repos/%{repo.slug}?token=%{user.svg_token} Accept image/svg+xml' do let(:accept) { 'image/svg+xml' } it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end - describe 'GET /repos/%{repo.slug}.svg?token=%{user.token}' do + describe 'GET /repos/%{repo.slug}.svg?token=%{user.svg_token}' do it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end @@ -400,13 +400,13 @@ it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.png' } end - describe 'GET /repos/%{repo.slug}?token=%{user.token} Accept image/svg+xml' do + describe 'GET /repos/%{repo.slug}?token=%{user.svg_token} Accept image/svg+xml' do let(:accept) { 'image/svg+xml' } it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end - describe 'GET /repos/%{repo.slug}.svg?token=%{user.token}' do + describe 'GET /repos/%{repo.slug}.svg?token=%{user.svg_token}' do it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end @@ -505,13 +505,13 @@ it(:without_permission) { should auth status: 200, type: :img, file: 'passing.png' } end - describe 'GET /repos/%{repo.slug}?token=%{user.token} Accept image/svg+xml' do + describe 'GET /repos/%{repo.slug}?token=%{user.svg_token} Accept image/svg+xml' do let(:accept) { 'image/svg+xml' } it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'passing.svg' } end - describe 'GET /repos/%{repo.slug}.svg?token=%{user.token}' do + describe 'GET /repos/%{repo.slug}.svg?token=%{user.svg_token}' do it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'passing.svg' } end diff --git a/spec/auth/v2.1/repo_status_spec.rb b/spec/auth/v2.1/repo_status_spec.rb index d01221709c..3b7bed1d19 100644 --- a/spec/auth/v2.1/repo_status_spec.rb +++ b/spec/auth/v2.1/repo_status_spec.rb @@ -79,13 +79,13 @@ it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.png' } end - describe 'GET /repos/%{repo.slug}?token=%{user.token} Accept image/svg+xml' do + describe 'GET /repos/%{repo.slug}?token=%{user.svg_token} Accept image/svg+xml' do let(:accept) { 'image/svg+xml' } it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end - describe 'GET /repos/%{repo.slug}.svg?token=%{user.token}' do + describe 'GET /repos/%{repo.slug}.svg?token=%{user.svg_token}' do it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end @@ -184,13 +184,13 @@ it(:without_permission) { should auth status: 200, type: :img, file: 'passing.png' } end - describe 'GET /repos/%{repo.slug}?token=%{user.token} Accept image/svg+xml' do + describe 'GET /repos/%{repo.slug}?token=%{user.svg_token} Accept image/svg+xml' do let(:accept) { 'image/svg+xml' } it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'passing.svg' } end - describe 'GET /repos/%{repo.slug}.svg?token=%{user.token}' do + describe 'GET /repos/%{repo.slug}.svg?token=%{user.svg_token}' do it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'passing.svg' } end @@ -289,13 +289,13 @@ it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.png' } end - describe 'GET /repos/%{repo.slug}?token=%{user.token} Accept image/svg+xml' do + describe 'GET /repos/%{repo.slug}?token=%{user.svg_token} Accept image/svg+xml' do let(:accept) { 'image/svg+xml' } it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end - describe 'GET /repos/%{repo.slug}.svg?token=%{user.token}' do + describe 'GET /repos/%{repo.slug}.svg?token=%{user.svg_token}' do it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end @@ -400,13 +400,13 @@ it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.png' } end - describe 'GET /repos/%{repo.slug}?token=%{user.token} Accept image/svg+xml' do + describe 'GET /repos/%{repo.slug}?token=%{user.svg_token} Accept image/svg+xml' do let(:accept) { 'image/svg+xml' } it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end - describe 'GET /repos/%{repo.slug}.svg?token=%{user.token}' do + describe 'GET /repos/%{repo.slug}.svg?token=%{user.svg_token}' do it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end @@ -505,13 +505,13 @@ it(:without_permission) { should auth status: 200, type: :img, file: 'passing.png' } end - describe 'GET /repos/%{repo.slug}?token=%{user.token} Accept image/svg+xml' do + describe 'GET /repos/%{repo.slug}?token=%{user.svg_token} Accept image/svg+xml' do let(:accept) { 'image/svg+xml' } it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'passing.svg' } end - describe 'GET /repos/%{repo.slug}.svg?token=%{user.token}' do + describe 'GET /repos/%{repo.slug}.svg?token=%{user.svg_token}' do it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'passing.svg' } end diff --git a/spec/auth/v2/repo_status_spec.rb b/spec/auth/v2/repo_status_spec.rb index e15f59b49c..75342dd26c 100644 --- a/spec/auth/v2/repo_status_spec.rb +++ b/spec/auth/v2/repo_status_spec.rb @@ -79,13 +79,13 @@ it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.png' } end - describe 'GET /repos/%{repo.slug}?token=%{user.token} Accept image/svg+xml' do + describe 'GET /repos/%{repo.slug}?token=%{user.svg_token} Accept image/svg+xml' do let(:accept) { 'image/svg+xml' } it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end - describe 'GET /repos/%{repo.slug}.svg?token=%{user.token}' do + describe 'GET /repos/%{repo.slug}.svg?token=%{user.svg_token}' do it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end @@ -184,13 +184,13 @@ it(:without_permission) { should auth status: 200, type: :img, file: 'passing.png' } end - describe 'GET /repos/%{repo.slug}?token=%{user.token} Accept image/svg+xml' do + describe 'GET /repos/%{repo.slug}?token=%{user.svg_token} Accept image/svg+xml' do let(:accept) { 'image/svg+xml' } it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'passing.svg' } end - describe 'GET /repos/%{repo.slug}.svg?token=%{user.token}' do + describe 'GET /repos/%{repo.slug}.svg?token=%{user.svg_token}' do it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'passing.svg' } end @@ -289,13 +289,13 @@ it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.png' } end - describe 'GET /repos/%{repo.slug}?token=%{user.token} Accept image/svg+xml' do + describe 'GET /repos/%{repo.slug}?token=%{user.svg_token} Accept image/svg+xml' do let(:accept) { 'image/svg+xml' } it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end - describe 'GET /repos/%{repo.slug}.svg?token=%{user.token}' do + describe 'GET /repos/%{repo.slug}.svg?token=%{user.svg_token}' do it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end @@ -400,13 +400,13 @@ it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.png' } end - describe 'GET /repos/%{repo.slug}?token=%{user.token} Accept image/svg+xml' do + describe 'GET /repos/%{repo.slug}?token=%{user.svg_token} Accept image/svg+xml' do let(:accept) { 'image/svg+xml' } it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end - describe 'GET /repos/%{repo.slug}.svg?token=%{user.token}' do + describe 'GET /repos/%{repo.slug}.svg?token=%{user.svg_token}' do it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'unknown.svg' } end @@ -505,13 +505,13 @@ it(:without_permission) { should auth status: 200, type: :img, file: 'passing.png' } end - describe 'GET /repos/%{repo.slug}?token=%{user.token} Accept image/svg+xml' do + describe 'GET /repos/%{repo.slug}?token=%{user.svg_token} Accept image/svg+xml' do let(:accept) { 'image/svg+xml' } it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'passing.svg' } end - describe 'GET /repos/%{repo.slug}.svg?token=%{user.token}' do + describe 'GET /repos/%{repo.slug}.svg?token=%{user.svg_token}' do it(:with_permission) { should auth status: 200, type: :img, file: 'passing.svg' } it(:without_permission) { should auth status: 200, type: :img, file: 'passing.svg' } end