Skip to content
This repository has been archived by the owner on Mar 29, 2022. It is now read-only.

Migration Path from unecrypted to encrypted #1

Closed
hundredwatt opened this issue Oct 17, 2014 · 3 comments · Fixed by #7
Closed

Migration Path from unecrypted to encrypted #1

hundredwatt opened this issue Oct 17, 2014 · 3 comments · Fixed by #7
Assignees

Comments

@hundredwatt
Copy link
Contributor

We need a way to encrypted an previously unencrypted column and keep the data intact. Ideally, there would be a way to detected if a value is encrypted or not so that the accessor can return the correct value regardless AND then run a migration to encrypt all unencrypted values.

@ebababi
Copy link
Member

ebababi commented Oct 20, 2014

Let's just extend the migration generator for the time being. Generator should contain something like:

require 'openssl'
require 'base64'

class ChangeSecretInModel < ActiveRecord::Migration
  def up
    public_key = OpenSSL::PKey::RSA.new(File.read(ENV['PUBLIC_KEY_FILE']))

    change_column :models, :secret, :text, limit: 4096

    say_with_time "encrypt_model_secrets" do
      encrypt_model_secrets(public_key)
    end
  end

  def down
    private_key = OpenSSL::PKey::RSA.new(File.read(ENV['PRIVATE_KEY_FILE']), ENV['PRIVATE_KEY_PASSWORD'])

    say_with_time "decrypt_model_secrets" do
      decrypt_model_secrets(private_key)
    end

    change_column :models, :secret, :string
  end

  private
    def encrypt_model_secrets(public_key)
      Model.reset_column_information

      Model.find_each do |model|
        secret = model.instance_variable_get(:@attributes).send(:fetch, 'secret')

        model.update_columns(
          secret: secret.nil? ? secret : Base64.encode64(public_key.public_encrypt(secret))
        )
      end

      Model.count
    end

    def decrypt_model_secrets(private_key)
      Model.reset_column_information

      Model.find_each do |model|
        secret = model.instance_variable_get(:@attributes).send(:fetch, 'secret')

        model.update_columns(
          secret: secret.nil? ? secret : private_key.private_decrypt(Base64.decode64(secret)),
        )
      end

      Model.count
    end
end

@hundredwatt
Copy link
Contributor Author

@ebababi This generator isn't working for me (Rails 4.1.9):

Amplify $ ./bin/rake db:migrate
== 20150113181325 ChangeTokenSecretInUsers: migrating =========================
-- change_column(:users, :token, :text, {:limit=>4096})
   -> 0.0098s
-- change_column(:users, :secret, :text, {:limit=>4096})
   -> 0.0089s
-- encrypt_user_tokens_and_secrets
rake aborted!
StandardError: An error has occurred, all later migrations canceled:

no implicit conversion of ActiveRecord::AttributeMethods::Serialization::Attribute into String/Users/jason/Dropbox (Personal)/Current/Amplify/db/migrate/20150113181325_change_token_secret_in_users.rb:36:in `public_encrypt'
/Users/jason/Dropbox (Personal)/Current/Amplify/db/migrate/20150113181325_change_token_secret_in_users.rb:36:in `block in encrypt_user_tokens_and_secrets'
/Users/jason/Dropbox (Personal)/Current/Amplify/db/migrate/20150113181325_change_token_secret_in_users.rb:31:in `encrypt_user_tokens_and_secrets'
/Users/jason/Dropbox (Personal)/Current/Amplify/db/migrate/20150113181325_change_token_secret_in_users.rb:12:in `block in up'
/Users/jason/Dropbox (Personal)/Current/Amplify/db/migrate/20150113181325_change_token_secret_in_users.rb:11:in `up'
-e:1:in `<main>'
TypeError: no implicit conversion of ActiveRecord::AttributeMethods::Serialization::Attribute into String
/Users/jason/Dropbox (Personal)/Current/Amplify/db/migrate/20150113181325_change_token_secret_in_users.rb:36:in `public_encrypt'
/Users/jason/Dropbox (Personal)/Current/Amplify/db/migrate/20150113181325_change_token_secret_in_users.rb:36:in `block in encrypt_user_tokens_and_secrets'
/Users/jason/Dropbox (Personal)/Current/Amplify/db/migrate/20150113181325_change_token_secret_in_users.rb:31:in `encrypt_user_tokens_and_secrets'
/Users/jason/Dropbox (Personal)/Current/Amplify/db/migrate/20150113181325_change_token_secret_in_users.rb:12:in `block in up'
/Users/jason/Dropbox (Personal)/Current/Amplify/db/migrate/20150113181325_change_token_secret_in_users.rb:11:in `up'
-e:1:in `<main>'
Tasks: TOP => db:migrate
(See full trace by running task with --trace)

@hundredwatt
Copy link
Contributor Author

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Development

Successfully merging a pull request may close this issue.

2 participants