2016-06-09 12:39:16 +00:00
# rubocop:disable all
2016-03-21 14:11:05 +00:00
# Loops through old importer projects that kept a token/password in the import URL
# and encrypts the credentials into a separate field in project#import_data
# #down method not supported
2016-03-02 16:31:17 +00:00
class RemoveWrongImportUrlFromProjects < ActiveRecord :: Migration
2016-03-03 17:10:06 +00:00
2016-04-11 09:13:51 +00:00
class ProjectImportDataFake
2016-03-07 11:50:35 +00:00
extend AttrEncrypted
attr_accessor :credentials
2016-07-20 10:08:52 +00:00
attr_encrypted :credentials ,
2018-05-19 13:03:29 +00:00
key : Settings . attr_encrypted_db_key_base ,
2016-07-20 10:08:52 +00:00
marshal : true ,
encode : true ,
:mode = > :per_attribute_iv_and_salt ,
insecure_mode : true ,
algorithm : 'aes-256-cbc'
2016-03-03 17:10:06 +00:00
end
2016-03-02 16:31:17 +00:00
def up
2016-03-23 10:55:43 +00:00
say ( " Encrypting and migrating project import credentials... " )
2016-04-04 17:45:53 +00:00
# This should cover GitHub, GitLab, Bitbucket user:password, token@domain, and other similar URLs.
2016-04-11 09:13:51 +00:00
in_transaction ( message : " Projects including GitHub and GitLab projects with an unsecured URL. " ) { process_projects_with_wrong_url }
2016-03-23 10:55:43 +00:00
2016-04-11 09:13:51 +00:00
in_transaction ( message : " Migrating Bitbucket credentials... " ) { process_project ( import_type : 'bitbucket' , credentials_keys : [ 'bb_session' ] ) }
2016-03-23 11:52:50 +00:00
2016-04-11 09:13:51 +00:00
in_transaction ( message : " Migrating FogBugz credentials... " ) { process_project ( import_type : 'fogbugz' , credentials_keys : [ 'fb_session' ] ) }
2016-03-23 16:57:10 +00:00
2016-03-22 10:32:15 +00:00
end
def process_projects_with_wrong_url
2016-03-23 10:55:43 +00:00
projects_with_wrong_import_url . each do | project |
2016-04-14 10:03:45 +00:00
begin
2016-05-19 02:16:36 +00:00
import_url = Gitlab :: UrlSanitizer . new ( project [ " import_url " ] )
2016-03-21 12:15:51 +00:00
2016-04-14 10:03:45 +00:00
update_import_url ( import_url , project )
update_import_data ( import_url , project )
2016-05-27 15:20:15 +00:00
rescue Addressable :: URI :: InvalidURIError
2016-04-14 10:03:45 +00:00
nullify_import_url ( project )
end
2016-03-22 10:32:15 +00:00
end
end
2016-04-11 09:13:51 +00:00
def process_project ( import_type : , credentials_keys : [ ] )
2016-03-23 11:52:50 +00:00
unencrypted_import_data ( import_type : import_type ) . each do | data |
2016-04-04 16:03:55 +00:00
replace_data_credentials ( data , credentials_keys )
2016-03-23 11:52:50 +00:00
end
end
2016-04-04 16:03:55 +00:00
def replace_data_credentials ( data , credentials_keys )
2016-03-28 14:35:03 +00:00
data_hash = JSON . load ( data [ 'data' ] ) if data [ 'data' ]
2016-04-04 16:03:55 +00:00
unless data_hash . blank?
encrypted_data_hash = encrypt_data ( data_hash , credentials_keys )
unencrypted_data = data_hash . empty? ? ' NULL ' : quote ( data_hash . to_json )
update_with_encrypted_data ( encrypted_data_hash , data [ 'id' ] , unencrypted_data )
2016-03-02 16:31:17 +00:00
end
end
2016-04-04 16:03:55 +00:00
def encrypt_data ( data_hash , credentials_keys )
2016-03-28 14:35:03 +00:00
new_data_hash = { }
2016-04-04 16:03:55 +00:00
credentials_keys . each do | key |
2016-04-05 13:41:15 +00:00
new_data_hash [ key . to_sym ] = data_hash . delete ( key ) if data_hash [ key ]
2016-03-28 14:35:03 +00:00
end
2016-04-05 13:41:15 +00:00
new_data_hash . deep_symbolize_keys
2016-03-28 14:35:03 +00:00
end
2016-04-11 09:13:51 +00:00
def in_transaction ( message : )
say_with_time ( message ) do
2016-03-23 10:55:43 +00:00
ActiveRecord :: Base . transaction do
yield
end
end
end
2016-03-22 10:32:15 +00:00
def update_import_data ( import_url , project )
2016-04-11 09:13:51 +00:00
fake_import_data = ProjectImportDataFake . new
2016-03-22 10:32:15 +00:00
fake_import_data . credentials = import_url . credentials
2016-03-28 14:35:03 +00:00
import_data_id = project [ 'import_data_id' ]
if import_data_id
execute ( update_import_data_sql ( import_data_id , fake_import_data ) )
2016-03-22 10:32:15 +00:00
else
execute ( insert_import_data_sql ( project [ 'id' ] , fake_import_data ) )
end
end
2016-04-04 16:03:55 +00:00
def update_with_encrypted_data ( data_hash , import_data_id , unencrypted_data = ' NULL ' )
2016-04-11 09:13:51 +00:00
fake_import_data = ProjectImportDataFake . new
2016-03-22 10:32:15 +00:00
fake_import_data . credentials = data_hash
2016-04-04 16:03:55 +00:00
execute ( update_import_data_sql ( import_data_id , fake_import_data , unencrypted_data ) )
2016-03-22 10:32:15 +00:00
end
def update_import_url ( import_url , project )
execute ( " UPDATE projects SET import_url = #{ quote ( import_url . sanitized_url ) } WHERE id = #{ project [ 'id' ] } " )
end
2016-04-14 10:03:45 +00:00
def nullify_import_url ( project )
execute ( " UPDATE projects SET import_url = NULL WHERE id = #{ project [ 'id' ] } " )
end
2016-03-21 16:16:27 +00:00
def insert_import_data_sql ( project_id , fake_import_data )
2016-03-28 14:35:03 +00:00
%(
INSERT INTO project_import_data
( encrypted_credentials ,
project_id ,
encrypted_credentials_iv ,
encrypted_credentials_salt )
VALUES ( #{quote(fake_import_data.encrypted_credentials)},
'#{project_id}' ,
#{quote(fake_import_data.encrypted_credentials_iv)},
#{quote(fake_import_data.encrypted_credentials_salt)})
) . squish
2016-03-21 16:16:27 +00:00
end
2016-03-23 10:55:43 +00:00
def update_import_data_sql ( id , fake_import_data , data = 'NULL' )
2016-03-28 14:35:03 +00:00
%(
UPDATE project_import_data
SET encrypted_credentials = #{quote(fake_import_data.encrypted_credentials)},
encrypted_credentials_iv = #{quote(fake_import_data.encrypted_credentials_iv)},
encrypted_credentials_salt = #{quote(fake_import_data.encrypted_credentials_salt)},
data = #{data}
WHERE id = '#{id}'
) . squish
2016-03-21 16:16:27 +00:00
end
2016-04-04 17:45:53 +00:00
#GitHub projects with token, and any user:password@ based URL
2016-03-03 17:10:06 +00:00
def projects_with_wrong_import_url
2016-04-14 10:03:45 +00:00
select_all ( " SELECT p.id, p.import_url, i.id as import_data_id FROM projects p LEFT JOIN project_import_data i on p.id = i.project_id WHERE p.import_url <> '' AND p.import_url LIKE '%//%@%' " )
2016-03-22 10:32:15 +00:00
end
2016-03-23 11:52:50 +00:00
# All imports with data for import_type
def unencrypted_import_data ( import_type : )
2016-04-14 10:03:45 +00:00
select_all ( " SELECT i.id, p.import_url, i.data FROM projects p INNER JOIN project_import_data i ON p.id = i.project_id WHERE p.import_url <> '' AND p.import_type = ' #{ import_type } ' " )
2016-03-21 16:16:27 +00:00
end
2016-03-21 12:15:51 +00:00
def quote ( value )
ActiveRecord :: Base . connection . quote ( value )
2016-03-02 16:31:17 +00:00
end
end