70 lines
2.3 KiB
Ruby
70 lines
2.3 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
module Gitlab
|
|
module BackgroundMigration
|
|
# Populates "static_object_token_encrypted" field with encrypted versions
|
|
# of values from "static_object_token" field
|
|
class EncryptStaticObjectToken
|
|
# rubocop:disable Style/Documentation
|
|
class User < ActiveRecord::Base
|
|
include ::EachBatch
|
|
self.table_name = 'users'
|
|
scope :with_static_object_token, -> { where.not(static_object_token: nil) }
|
|
scope :without_static_object_token_encrypted, -> { where(static_object_token_encrypted: nil) }
|
|
end
|
|
# rubocop:enable Style/Documentation
|
|
|
|
BATCH_SIZE = 100
|
|
|
|
def perform(start_id, end_id)
|
|
ranged_query = User
|
|
.where(id: start_id..end_id)
|
|
.with_static_object_token
|
|
.without_static_object_token_encrypted
|
|
|
|
ranged_query.each_batch(of: BATCH_SIZE) do |sub_batch|
|
|
first, last = sub_batch.pick(Arel.sql('min(id), max(id)'))
|
|
|
|
batch_query = User.unscoped
|
|
.where(id: first..last)
|
|
.with_static_object_token
|
|
.without_static_object_token_encrypted
|
|
|
|
user_tokens = batch_query.pluck(:id, :static_object_token)
|
|
|
|
user_encrypted_tokens = user_tokens.map do |(id, plaintext_token)|
|
|
next if plaintext_token.blank?
|
|
|
|
[id, Gitlab::CryptoHelper.aes256_gcm_encrypt(plaintext_token)]
|
|
end
|
|
|
|
encrypted_tokens_sql = user_encrypted_tokens.compact.map { |(id, token)| "(#{id}, '#{token}')" }.join(',')
|
|
|
|
next unless user_encrypted_tokens.present?
|
|
|
|
User.connection.execute(<<~SQL)
|
|
WITH cte(cte_id, cte_token) AS #{::Gitlab::Database::AsWithMaterialized.materialized_if_supported} (
|
|
SELECT *
|
|
FROM (VALUES #{encrypted_tokens_sql}) AS t (id, token)
|
|
)
|
|
UPDATE #{User.table_name}
|
|
SET static_object_token_encrypted = cte_token
|
|
FROM cte
|
|
WHERE cte_id = id
|
|
SQL
|
|
end
|
|
|
|
mark_job_as_succeeded(start_id, end_id)
|
|
end
|
|
|
|
private
|
|
|
|
def mark_job_as_succeeded(*arguments)
|
|
Gitlab::Database::BackgroundMigrationJob.mark_all_as_succeeded(
|
|
self.class.name.demodulize,
|
|
arguments
|
|
)
|
|
end
|
|
end
|
|
end
|
|
end
|