Class: SecureDBFields::DBDeployment::KeyContract
- Inherits:
-
Object
- Object
- SecureDBFields::DBDeployment::KeyContract
- Defined in:
- lib/secure_db_fields/db_deployment.rb
Constant Summary collapse
- DEFAULT_PATH =
"config/secure_db_fields/keys.env"- HEX =
/\A[0-9a-fA-F]{64}\z/.freeze
- REQUIRED_HEX_KEYS =
%w[SDF_BIDX_KEY_HEX SDF_BIDX_PHONE_KEY_HEX SDF_BIDX_PHONE_P7_KEY_HEX].freeze
Instance Attribute Summary collapse
-
#path ⇒ Object
readonly
Returns the value of attribute path.
Class Method Summary collapse
- .default_path ⇒ Object
- .ensure!(path) ⇒ Object
- .hex?(value) ⇒ Boolean
- .parse(path) ⇒ Object
- .validate!(path) ⇒ Object
- .write_new!(path) ⇒ Object
Instance Method Summary collapse
- #data ⇒ Object
-
#initialize(path) ⇒ KeyContract
constructor
A new instance of KeyContract.
Constructor Details
#initialize(path) ⇒ KeyContract
Returns a new instance of KeyContract.
168 169 170 |
# File 'lib/secure_db_fields/db_deployment.rb', line 168 def initialize(path) @path = path end |
Instance Attribute Details
#path ⇒ Object (readonly)
Returns the value of attribute path.
99 100 101 |
# File 'lib/secure_db_fields/db_deployment.rb', line 99 def path @path end |
Class Method Details
.default_path ⇒ Object
101 102 103 |
# File 'lib/secure_db_fields/db_deployment.rb', line 101 def self.default_path File.(DEFAULT_PATH, Dir.pwd) end |
.ensure!(path) ⇒ Object
105 106 107 108 109 110 111 112 113 |
# File 'lib/secure_db_fields/db_deployment.rb', line 105 def self.ensure!(path) full = File.(path) if File.exist?(full) validate!(full) else write_new!(full) end new(full) end |
.hex?(value) ⇒ Boolean
164 165 166 |
# File 'lib/secure_db_fields/db_deployment.rb', line 164 def self.hex?(value) value && HEX.match?(value) end |
.parse(path) ⇒ Object
152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/secure_db_fields/db_deployment.rb', line 152 def self.parse(path) values = {} File.readlines(path, chomp: true).each do |line| text = line.strip next if text.empty? || text.start_with?("#") key, value = text.split("=", 2) next unless key && value values[key.strip] = value.strip end values end |
.validate!(path) ⇒ Object
137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/secure_db_fields/db_deployment.rb', line 137 def self.validate!(path) stat = File.stat(path) raise Error, "key contract must be a regular file: #{path}" unless stat.file? raise Error, "key contract permissions are too open: #{path}" unless (stat.mode & 0o077).zero? values = parse(path) active = values["SDF_ACTIVE_KEY_ID"] raise Error, "key contract missing SDF_ACTIVE_KEY_ID: #{path}" unless active && active.match?(/\A[1-9][0-9]*\z/) unless hex?(values["SDF_ENC_KEY_#{active}_HEX"]) || hex?(values["SDF_ENC_KEY_HEX"]) raise Error, "key contract missing SDF_ENC_KEY_#{active}_HEX or SDF_ENC_KEY_HEX: #{path}" end REQUIRED_HEX_KEYS.each do |name| raise Error, "key contract missing #{name}: #{path}" unless hex?(values[name]) end end |
.write_new!(path) ⇒ Object
115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/secure_db_fields/db_deployment.rb', line 115 def self.write_new!(path) FileUtils.mkdir_p(File.dirname(path)) enc = SecureRandom.hex(32) bidx = SecureRandom.hex(32) phone = bidx phone_p7 = bidx body = <<~ENV SDF_ACTIVE_KEY_ID=1 SDF_ENC_KEY_1_HEX=#{enc} SDF_ENC_KEY_HEX=#{enc} SDF_BIDX_KEY_HEX=#{bidx} SDF_BIDX_PHONE_KEY_HEX=#{phone} SDF_BIDX_PHONE_P7_KEY_HEX=#{phone_p7} ENV temporary = File.join(File.dirname(path), "secure-db-fields-keys-#{Process.pid}-#{SecureRandom.hex(8)}.tmp") File.open(temporary, File::WRONLY | File::CREAT | File::EXCL, 0o600) { |file| file.write(body) } File.chmod(0o600, temporary) File.rename(temporary, path) ensure File.delete(temporary) if defined?(temporary) && File.exist?(temporary) end |
Instance Method Details
#data ⇒ Object
172 173 174 |
# File 'lib/secure_db_fields/db_deployment.rb', line 172 def data File.binread(path) end |