Merge pull request #167 from travis-ci/rkh-v3-enable-disable
v3: repo enable/disable
This commit is contained in:
commit
47c6cf1ee6
|
@ -8,5 +8,9 @@ module Travis::API::V3
|
||||||
def self.for_request(*)
|
def self.for_request(*)
|
||||||
new
|
new
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def admin_for(repository)
|
||||||
|
raise LoginRequired
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -2,12 +2,13 @@ require 'travis/api/v3/access_control/generic'
|
||||||
|
|
||||||
module Travis::API::V3
|
module Travis::API::V3
|
||||||
class AccessControl::Application < AccessControl::Generic
|
class AccessControl::Application < AccessControl::Generic
|
||||||
attr_reader :application_name, :config, :user
|
attr_reader :application_name, :config, :user, :user_control
|
||||||
|
|
||||||
def initialize(application_name, user: nil)
|
def initialize(application_name, user: nil)
|
||||||
@application_name = application_name
|
@application_name = application_name
|
||||||
@config = Travis.config.applications[application_name]
|
@config = Travis.config.applications[application_name]
|
||||||
@user = user
|
@user = user
|
||||||
|
@user_control = user ? AccessControl::User.new(user) : AccessControl::Generic.new
|
||||||
raise ArgumentError, 'unknown application %p' % application_name unless config
|
raise ArgumentError, 'unknown application %p' % application_name unless config
|
||||||
raise ArgumentError, 'cannot use %p without a user' % application_name if config.requires_user and not user
|
raise ArgumentError, 'cannot use %p without a user' % application_name if config.requires_user and not user
|
||||||
end
|
end
|
||||||
|
@ -19,5 +20,12 @@ module Travis::API::V3
|
||||||
def full_access?
|
def full_access?
|
||||||
config.full_access
|
config.full_access
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def admin_for(repository)
|
||||||
|
return user_control.admin_for(repository) unless full_access?
|
||||||
|
admin = repository.users.where('permissions.admin = true'.freeze).order('users.synced_at DESC'.freeze).first
|
||||||
|
raise AdminAccessRequired, "no admin found for #{repository.slug}" unless admin
|
||||||
|
admin
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -15,6 +15,10 @@ module Travis::API::V3
|
||||||
full_access? or dispatch(object)
|
full_access? or dispatch(object)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def admin_for(repository)
|
||||||
|
raise AdminAccessRequired, repository: repository
|
||||||
|
end
|
||||||
|
|
||||||
def user
|
def user
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,10 @@ module Travis::API::V3
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def admin_for(repository)
|
||||||
|
permission?(:admin, repository) ? user : super
|
||||||
|
end
|
||||||
|
|
||||||
protected
|
protected
|
||||||
|
|
||||||
def repository_writable?(repository)
|
def repository_writable?(repository)
|
||||||
|
|
109
lib/travis/api/v3/extensions/encrypted_column.rb
Normal file
109
lib/travis/api/v3/extensions/encrypted_column.rb
Normal file
|
@ -0,0 +1,109 @@
|
||||||
|
require 'securerandom'
|
||||||
|
require 'base64'
|
||||||
|
|
||||||
|
module Travis::API::V3
|
||||||
|
module Extensions
|
||||||
|
class EncryptedColumn
|
||||||
|
attr_reader :disable, :options
|
||||||
|
alias disabled? disable
|
||||||
|
|
||||||
|
def initialize(options = {})
|
||||||
|
@options = options || {}
|
||||||
|
@disable = self.options[:disable]
|
||||||
|
@key = self.options[:key]
|
||||||
|
end
|
||||||
|
|
||||||
|
def enabled?
|
||||||
|
!disabled?
|
||||||
|
end
|
||||||
|
|
||||||
|
def load(data)
|
||||||
|
return nil unless data
|
||||||
|
|
||||||
|
data = data.to_s
|
||||||
|
|
||||||
|
decrypt?(data) ? decrypt(data) : data
|
||||||
|
end
|
||||||
|
|
||||||
|
def dump(data)
|
||||||
|
encrypt?(data) ? encrypt(data.to_s) : data
|
||||||
|
end
|
||||||
|
|
||||||
|
def key
|
||||||
|
@key || config.key
|
||||||
|
end
|
||||||
|
|
||||||
|
def iv
|
||||||
|
SecureRandom.hex(8)
|
||||||
|
end
|
||||||
|
|
||||||
|
def prefix
|
||||||
|
'--ENCR--'
|
||||||
|
end
|
||||||
|
|
||||||
|
def decrypt?(data)
|
||||||
|
data.present? && (!use_prefix? || prefix_used?(data))
|
||||||
|
end
|
||||||
|
|
||||||
|
def encrypt?(data)
|
||||||
|
data.present? && enabled?
|
||||||
|
end
|
||||||
|
|
||||||
|
def prefix_used?(data)
|
||||||
|
data[0..7] == prefix
|
||||||
|
end
|
||||||
|
|
||||||
|
def decrypt(data)
|
||||||
|
data = data[8..-1] if prefix_used?(data)
|
||||||
|
|
||||||
|
data = decode data
|
||||||
|
|
||||||
|
iv = data[-16..-1]
|
||||||
|
data = data[0..-17]
|
||||||
|
|
||||||
|
aes = create_aes :decrypt, key.to_s, iv
|
||||||
|
|
||||||
|
result = aes.update(data) + aes.final
|
||||||
|
end
|
||||||
|
|
||||||
|
def encrypt(data)
|
||||||
|
iv = self.iv
|
||||||
|
|
||||||
|
aes = create_aes :encrypt, key.to_s, iv
|
||||||
|
|
||||||
|
encrypted = aes.update(data) + aes.final
|
||||||
|
|
||||||
|
encrypted = "#{encrypted}#{iv}"
|
||||||
|
encrypted = encode encrypted
|
||||||
|
encrypted = "#{prefix}#{encrypted}" if use_prefix?
|
||||||
|
encrypted
|
||||||
|
end
|
||||||
|
|
||||||
|
def use_prefix?
|
||||||
|
options.has_key?(:use_prefix) ? options[:use_prefix] : Travis::Features.feature_inactive?(:db_encryption_prefix)
|
||||||
|
end
|
||||||
|
|
||||||
|
def create_aes(mode = :encrypt, key, iv)
|
||||||
|
aes = OpenSSL::Cipher::AES.new(256, :CBC)
|
||||||
|
|
||||||
|
aes.send(mode)
|
||||||
|
aes.key = key
|
||||||
|
aes.iv = iv
|
||||||
|
|
||||||
|
aes
|
||||||
|
end
|
||||||
|
|
||||||
|
def config
|
||||||
|
Travis.config.encryption
|
||||||
|
end
|
||||||
|
|
||||||
|
def decode(str)
|
||||||
|
Base64.strict_decode64 str
|
||||||
|
end
|
||||||
|
|
||||||
|
def encode(str)
|
||||||
|
Base64.strict_encode64 str
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
44
lib/travis/api/v3/github.rb
Normal file
44
lib/travis/api/v3/github.rb
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
require 'gh'
|
||||||
|
|
||||||
|
|
||||||
|
module Travis::API::V3
|
||||||
|
class GitHub
|
||||||
|
DEFAULT_OPTIONS = {
|
||||||
|
client_id: Travis.config.oauth2.try(:client_id),
|
||||||
|
client_secret: Travis.config.oauth2.try(:client_secret),
|
||||||
|
user_agent: "Travis-API/3 Travis-CI/0.0.1 GH/#{GH::VERSION}",
|
||||||
|
origin: Travis.config.host,
|
||||||
|
api_url: Travis.config.github.api_url,
|
||||||
|
ssl: Travis.config.ssl.merge(Travis.config.github.ssl || {}).to_hash.compact
|
||||||
|
}
|
||||||
|
private_constant :DEFAULT_OPTIONS
|
||||||
|
|
||||||
|
attr_reader :gh, :user
|
||||||
|
|
||||||
|
def initialize(user = nil, token = nil)
|
||||||
|
if user.respond_to? :github_oauth_token
|
||||||
|
raise ServerError, 'no GitHub token for user' if user.github_oauth_token.blank?
|
||||||
|
token = user.github_oauth_token
|
||||||
|
end
|
||||||
|
|
||||||
|
@user = user
|
||||||
|
@gh = GH.with(token: token, **DEFAULT_OPTIONS)
|
||||||
|
end
|
||||||
|
|
||||||
|
def set_hook(repository, flag)
|
||||||
|
hooks_url = "repos/#{repository.slug}/hooks"
|
||||||
|
payload = {
|
||||||
|
name: 'travis'.freeze,
|
||||||
|
events: [:push, :pull_request, :issue_comment, :public, :member],
|
||||||
|
active: flag,
|
||||||
|
config: { domain: Travis.config.service_hook_url || '' }
|
||||||
|
}
|
||||||
|
|
||||||
|
if hook = gh[hooks_url].detect { |hook| hook['name'.freeze] == 'travis'.freeze }
|
||||||
|
gh.patch(hook['_links'.freeze]['self'.freeze]['href'.freeze], payload)
|
||||||
|
else
|
||||||
|
gh.post(hooks_url, payload)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
14
lib/travis/api/v3/models/token.rb
Normal file
14
lib/travis/api/v3/models/token.rb
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
module Travis::API::V3
|
||||||
|
class Models::Token < Model
|
||||||
|
belongs_to :user
|
||||||
|
validate :token, presence: true
|
||||||
|
serialize :token, Extensions::EncryptedColumn.new(disable: true)
|
||||||
|
before_validation :generate_token, on: :create
|
||||||
|
|
||||||
|
protected
|
||||||
|
|
||||||
|
def generate_token
|
||||||
|
self.token = SecureRandom.base64(15).tr('+/=lIO0', 'pqrsxyz')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -1,9 +1,17 @@
|
||||||
module Travis::API::V3
|
module Travis::API::V3
|
||||||
class Models::User < Model
|
class Models::User < Model
|
||||||
has_many :memberships, dependent: :destroy
|
has_many :memberships, dependent: :destroy
|
||||||
has_many :organizations, through: :memberships
|
|
||||||
has_many :permissions, dependent: :destroy
|
has_many :permissions, dependent: :destroy
|
||||||
has_many :repositories, through: :permissions
|
|
||||||
has_many :emails, dependent: :destroy
|
has_many :emails, dependent: :destroy
|
||||||
|
has_many :tokens, dependent: :destroy
|
||||||
|
has_many :repositories, through: :permissions
|
||||||
|
has_many :organizations, through: :memberships
|
||||||
|
|
||||||
|
|
||||||
|
serialize :github_oauth_token, Extensions::EncryptedColumn.new(disable: true)
|
||||||
|
|
||||||
|
def token
|
||||||
|
tokens.first_or_create.token
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -7,6 +7,9 @@ module Travis::API::V3
|
||||||
route '/repo/{repository.id}'
|
route '/repo/{repository.id}'
|
||||||
get :find
|
get :find
|
||||||
|
|
||||||
|
post :enable, '/enable'
|
||||||
|
post :disable, '/disable'
|
||||||
|
|
||||||
resource :requests do
|
resource :requests do
|
||||||
route '/requests'
|
route '/requests'
|
||||||
get :find
|
get :find
|
||||||
|
|
|
@ -13,12 +13,17 @@ module Travis::API::V3
|
||||||
@access_control = access_control
|
@access_control = access_control
|
||||||
@params = params
|
@params = params
|
||||||
@queries = {}
|
@queries = {}
|
||||||
|
@github = {}
|
||||||
end
|
end
|
||||||
|
|
||||||
def query(type = self.class.result_type)
|
def query(type = self.class.result_type)
|
||||||
@queries[type] ||= Queries[type].new(params, self.class.result_type)
|
@queries[type] ||= Queries[type].new(params, self.class.result_type)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def github(user = nil)
|
||||||
|
@github[user] ||= GitHub.new(user)
|
||||||
|
end
|
||||||
|
|
||||||
def find(type = self.class.result_type, *args)
|
def find(type = self.class.result_type, *args)
|
||||||
not_found(true, type) unless object = query(type).find(*args)
|
not_found(true, type) unless object = query(type).find(*args)
|
||||||
not_found(false, type) unless access_control.visible? object
|
not_found(false, type) unless access_control.visible? object
|
||||||
|
|
15
lib/travis/api/v3/services/repository/disable.rb
Normal file
15
lib/travis/api/v3/services/repository/disable.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
module Travis::API::V3
|
||||||
|
class Services::Repository::Disable < Service
|
||||||
|
def run!(activate = false)
|
||||||
|
raise LoginRequired unless access_control.logged_in? or access_control.full_access?
|
||||||
|
raise NotFound unless repository = find(:repository)
|
||||||
|
|
||||||
|
admin = access_control.admin_for(repository)
|
||||||
|
|
||||||
|
github(admin).set_hook(repository, activate)
|
||||||
|
repository.update_attributes(active: activate)
|
||||||
|
|
||||||
|
repository
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
7
lib/travis/api/v3/services/repository/enable.rb
Normal file
7
lib/travis/api/v3/services/repository/enable.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
module Travis::API::V3
|
||||||
|
class Services::Repository::Enable < Services::Repository::Disable
|
||||||
|
def run!
|
||||||
|
super(true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -9,7 +9,9 @@ describe Travis::API::V3::ServiceIndex do
|
||||||
describe "custom json entry point" do
|
describe "custom json entry point" do
|
||||||
let(:expected_resources) {{
|
let(:expected_resources) {{
|
||||||
"repository" => {
|
"repository" => {
|
||||||
"find" => [{"request-method"=>"GET", "uri-template"=>"#{path}repo/{repository.id}"}] },
|
"find" => [{"request-method"=>"GET", "uri-template"=>"#{path}repo/{repository.id}"}],
|
||||||
|
"enable" => [{"request-method"=>"POST", "uri-template"=>"#{path}repo/{repository.id}/enable"}],
|
||||||
|
"disable" => [{"request-method"=>"POST", "uri-template"=>"#{path}repo/{repository.id}/disable"}] },
|
||||||
"repositories" => {
|
"repositories" => {
|
||||||
"for_current_user" => [{"request-method"=>"GET", "uri-template"=>"#{path}repos"}] },
|
"for_current_user" => [{"request-method"=>"GET", "uri-template"=>"#{path}repos"}] },
|
||||||
"branch" => {
|
"branch" => {
|
||||||
|
|
Loading…
Reference in New Issue
Block a user