class RocketJob::Jobs::ReEncrypt::RelationalJob

Public Class Methods

connection() click to toggle source

Returns a database connection.

Override this method to support other ways of obtaining a thread specific database connection.

# File lib/rocket_job/jobs/re_encrypt/relational_job.rb, line 104
def self.connection
  ActiveRecord::Base.connection
end
start(**args) click to toggle source

Re-encrypt all `encrypted_` columns in the relational database. Queues a Job for each table that needs re-encryption.

# File lib/rocket_job/jobs/re_encrypt/relational_job.rb, line 55
def self.start(**args)
  encrypted_columns.keys.collect do |table|
    create!(table_name: table, description: table, **args)
  end
end

Public Instance Methods

perform(range) click to toggle source

Re-encrypt all encrypted columns for the named table. Does not use AR models since we do not have models for all tables.

# File lib/rocket_job/jobs/re_encrypt/relational_job.rb, line 63
def perform(range)
  start_id, end_id = range

  columns = self.class.encrypted_columns[table_name]
  unless columns&.size&.positive?
    logger.error "No columns for table: #{table_name} from #{start_id} to #{end_id}"
    return
  end

  logger.info "Processing: #{table_name} from #{start_id} to #{end_id}"
  sql = "select id, #{columns.join(',')} from #{quoted_table_name} where id >= #{start_id} and id <= #{end_id}"

  # Use AR to fetch all the records
  self.class.connection.select_rows(sql).each do |row|
    row.unshift(nil)
    index   = 1
    sql     = "update #{quoted_table_name} set "
    updates = []
    columns.collect do |column|
      index += 1
      value = row[index]
      # Prevent re-encryption
      unless value.blank?
        new_value = re_encrypt(value)
        updates << "#{column} = \"#{new_value}\"" if new_value != value
      end
    end
    if updates.size.positive?
      sql << updates.join(", ")
      sql << " where id=#{row[1]}"
      logger.trace sql
      self.class.connection.execute sql
    else
      logger.trace { "Skipping empty values #{table_name}:#{row[1]}" }
    end
  end
end

Private Instance Methods

quoted_table_name() click to toggle source
# File lib/rocket_job/jobs/re_encrypt/relational_job.rb, line 110
def quoted_table_name
  @quoted_table_name ||= self.class.connection.quote_table_name(table_name)
end
re_encrypt(encrypted_value) click to toggle source
# File lib/rocket_job/jobs/re_encrypt/relational_job.rb, line 114
def re_encrypt(encrypted_value)
  return encrypted_value if (encrypted_value == "") || encrypted_value.nil?

  SymmetricEncryption.encrypt(SymmetricEncryption.decrypt(encrypted_value))
end
upload_records() click to toggle source

Upload range to re-encrypt all rows in the specified table.

# File lib/rocket_job/jobs/re_encrypt/relational_job.rb, line 121
def upload_records
  start_id          = self.class.connection.select_value("select min(id) from #{quoted_table_name}").to_i
  last_id           = self.class.connection.select_value("select max(id) from #{quoted_table_name}").to_i
  self.record_count =
    if last_id.positive?
      input.upload_integer_range_in_reverse_order(start_id, last_id) * input_category.slice_size
    else
      0
    end
end