PageRenderTime 27ms CodeModel.GetById 27ms RepoModel.GetById 1ms app.codeStats 0ms

/db/migrate/20160302152808_remove_wrong_import_url_from_projects.rb

https://bitbucket.org/terrchen/gitlab-ce
Ruby | 138 lines | 108 code | 21 blank | 9 comment | 3 complexity | 6e1e82f74bed914f7b30872d8b4fafb0 MD5 | raw file
Possible License(s): Apache-2.0, CC0-1.0
  1. # rubocop:disable all
  2. # Loops through old importer projects that kept a token/password in the import URL
  3. # and encrypts the credentials into a separate field in project#import_data
  4. # #down method not supported
  5. class RemoveWrongImportUrlFromProjects < ActiveRecord::Migration
  6. class ProjectImportDataFake
  7. extend AttrEncrypted
  8. attr_accessor :credentials
  9. attr_encrypted :credentials,
  10. key: Settings.attr_encrypted_db_key_base,
  11. marshal: true,
  12. encode: true,
  13. :mode => :per_attribute_iv_and_salt,
  14. insecure_mode: true,
  15. algorithm: 'aes-256-cbc'
  16. end
  17. def up
  18. say("Encrypting and migrating project import credentials...")
  19. # This should cover GitHub, GitLab, Bitbucket user:password, token@domain, and other similar URLs.
  20. in_transaction(message: "Projects including GitHub and GitLab projects with an unsecured URL.") { process_projects_with_wrong_url }
  21. in_transaction(message: "Migrating Bitbucket credentials...") { process_project(import_type: 'bitbucket', credentials_keys: ['bb_session']) }
  22. in_transaction(message: "Migrating FogBugz credentials...") { process_project(import_type: 'fogbugz', credentials_keys: ['fb_session']) }
  23. end
  24. def process_projects_with_wrong_url
  25. projects_with_wrong_import_url.each do |project|
  26. begin
  27. import_url = Gitlab::UrlSanitizer.new(project["import_url"])
  28. update_import_url(import_url, project)
  29. update_import_data(import_url, project)
  30. rescue Addressable::URI::InvalidURIError
  31. nullify_import_url(project)
  32. end
  33. end
  34. end
  35. def process_project(import_type:, credentials_keys: [])
  36. unencrypted_import_data(import_type: import_type).each do |data|
  37. replace_data_credentials(data, credentials_keys)
  38. end
  39. end
  40. def replace_data_credentials(data, credentials_keys)
  41. data_hash = JSON.load(data['data']) if data['data']
  42. unless data_hash.blank?
  43. encrypted_data_hash = encrypt_data(data_hash, credentials_keys)
  44. unencrypted_data = data_hash.empty? ? ' NULL ' : quote(data_hash.to_json)
  45. update_with_encrypted_data(encrypted_data_hash, data['id'], unencrypted_data)
  46. end
  47. end
  48. def encrypt_data(data_hash, credentials_keys)
  49. new_data_hash = {}
  50. credentials_keys.each do |key|
  51. new_data_hash[key.to_sym] = data_hash.delete(key) if data_hash[key]
  52. end
  53. new_data_hash.deep_symbolize_keys
  54. end
  55. def in_transaction(message:)
  56. say_with_time(message) do
  57. ActiveRecord::Base.transaction do
  58. yield
  59. end
  60. end
  61. end
  62. def update_import_data(import_url, project)
  63. fake_import_data = ProjectImportDataFake.new
  64. fake_import_data.credentials = import_url.credentials
  65. import_data_id = project['import_data_id']
  66. if import_data_id
  67. execute(update_import_data_sql(import_data_id, fake_import_data))
  68. else
  69. execute(insert_import_data_sql(project['id'], fake_import_data))
  70. end
  71. end
  72. def update_with_encrypted_data(data_hash, import_data_id, unencrypted_data = ' NULL ')
  73. fake_import_data = ProjectImportDataFake.new
  74. fake_import_data.credentials = data_hash
  75. execute(update_import_data_sql(import_data_id, fake_import_data, unencrypted_data))
  76. end
  77. def update_import_url(import_url, project)
  78. execute("UPDATE projects SET import_url = #{quote(import_url.sanitized_url)} WHERE id = #{project['id']}")
  79. end
  80. def nullify_import_url(project)
  81. execute("UPDATE projects SET import_url = NULL WHERE id = #{project['id']}")
  82. end
  83. def insert_import_data_sql(project_id, fake_import_data)
  84. %(
  85. INSERT INTO project_import_data
  86. (encrypted_credentials,
  87. project_id,
  88. encrypted_credentials_iv,
  89. encrypted_credentials_salt)
  90. VALUES ( #{quote(fake_import_data.encrypted_credentials)},
  91. '#{project_id}',
  92. #{quote(fake_import_data.encrypted_credentials_iv)},
  93. #{quote(fake_import_data.encrypted_credentials_salt)})
  94. ).squish
  95. end
  96. def update_import_data_sql(id, fake_import_data, data = 'NULL')
  97. %(
  98. UPDATE project_import_data
  99. SET encrypted_credentials = #{quote(fake_import_data.encrypted_credentials)},
  100. encrypted_credentials_iv = #{quote(fake_import_data.encrypted_credentials_iv)},
  101. encrypted_credentials_salt = #{quote(fake_import_data.encrypted_credentials_salt)},
  102. data = #{data}
  103. WHERE id = '#{id}'
  104. ).squish
  105. end
  106. #GitHub projects with token, and any user:password@ based URL
  107. def projects_with_wrong_import_url
  108. 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 '%//%@%'")
  109. end
  110. # All imports with data for import_type
  111. def unencrypted_import_data(import_type: )
  112. 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}' ")
  113. end
  114. def quote(value)
  115. ActiveRecord::Base.connection.quote(value)
  116. end
  117. end