diff --git a/app/models/asymmetric_key.rb b/app/models/asymmetric_key.rb index 9355c31..a4cb5a7 100644 --- a/app/models/asymmetric_key.rb +++ b/app/models/asymmetric_key.rb @@ -2,4 +2,72 @@ class AsymmetricKey < ApplicationRecord PRIVATE_KEY_CLEAR_DELAY = 1.hour.freeze + + attr_accessor :private_key_pem, :private_key_pem_secret + + ################ + # Associations # + ################ + + belongs_to :account, optional: true + + ############### + # Validations # + ############### + + validates :public_key_pem, + presence: true, + uniqueness: true + + validates :public_key_der, + presence: true, + uniqueness: true + + validates :has_password, exclusion: { in: [nil] } + + validates :bits, + numericality: { + only_integer: true, + greater_than: 0, + } + + validates :sha1, + presence: true, + uniqueness: { case_sensitive: false } + + validates :sha256, + presence: true, + uniqueness: { case_sensitive: false } + + ########### + # Methods # + ########### + + def encrypt_private_key_pem + cipher = OpenSSL::Cipher::AES256.new + cipher.encrypt + + self.private_key_pem_iv = cipher.random_iv.freeze + self.private_key_pem_secret = cipher.random_key.freeze + + self.private_key_pem_ciphertext = [ + cipher.update(private_key_pem), + cipher.final, + ].join.freeze + + private_key_pem_secret + end + + def decrypt_private_key_pem + cipher = OpenSSL::Cipher::AES256.new + cipher.decrypt + + cipher.iv = private_key_pem_iv + cipher.key = private_key_pem_secret + + self.private_key_pem = [ + cipher.update(private_key_pem_ciphertext), + cipher.final, + ].join.freeze + end end diff --git a/app/models/rsa_key.rb b/app/models/rsa_key.rb index cb9ea26..275eebc 100644 --- a/app/models/rsa_key.rb +++ b/app/models/rsa_key.rb @@ -1,67 +1,9 @@ # frozen_string_literal: true class RSAKey < AsymmetricKey - attr_accessor :private_key_pem, :private_key_pem_secret - - ################ - # Associations # - ################ - - belongs_to :account, optional: true - ############### # Validations # ############### - validates :public_key_pem, - presence: true, - uniqueness: true - - validates :public_key_der, - presence: true, - uniqueness: true - - validates :has_password, exclusion: { in: [nil] } - validates :bits, inclusion: { in: [2048, 4096] } - - validates :sha1, - presence: true, - uniqueness: { case_sensitive: false } - - validates :sha256, - presence: true, - uniqueness: { case_sensitive: false } - - ########### - # Methods # - ########### - - def encrypt_private_key_pem - cipher = OpenSSL::Cipher::AES256.new - cipher.encrypt - - self.private_key_pem_iv = cipher.random_iv.freeze - self.private_key_pem_secret = cipher.random_key.freeze - - self.private_key_pem_ciphertext = [ - cipher.update(private_key_pem), - cipher.final, - ].join.freeze - - private_key_pem_secret - end - - def decrypt_private_key_pem - cipher = OpenSSL::Cipher::AES256.new - cipher.decrypt - - cipher.iv = private_key_pem_iv - cipher.key = private_key_pem_secret - - self.private_key_pem = [ - cipher.update(private_key_pem_ciphertext), - cipher.final, - ].join.freeze - end end diff --git a/spec/models/rsa_key_spec.rb b/spec/models/rsa_key_spec.rb index 2a4056d..17fc813 100644 --- a/spec/models/rsa_key_spec.rb +++ b/spec/models/rsa_key_spec.rb @@ -27,6 +27,13 @@ RSpec.describe RSAKey do end describe '#bits' do + it do + is_expected.to \ + validate_numericality_of(:bits) + .only_integer + .is_greater_than(0) + end + it { is_expected.to validate_inclusion_of(:bits).in_array([2048, 4096]) } end