Class: Syde::Vault
- Inherits:
-
Object
- Object
- Syde::Vault
- Includes:
- Errors
- Defined in:
- lib/syde/vault.rb,
lib/syde/crypto.rb,
lib/syde/storage.rb
Defined Under Namespace
Instance Attribute Summary collapse
-
#file ⇒ Object
readonly
Returns the value of attribute file.
-
#plaintext_secret_key ⇒ Object
Returns the value of attribute plaintext_secret_key.
Class Method Summary collapse
- .create(password, file = Storage::DefaultStorageFile) ⇒ Object
- .new_secret_key(password, iv) ⇒ Object
- .open(file = Storage::DefaultStorageFile) ⇒ Object
Instance Method Summary collapse
- #add(*contents) ⇒ Object (also: #<<)
- #contents ⇒ Object
- #contents=(new_content) ⇒ Object
- #data ⇒ Object
- #decrypt_secret_key(password) ⇒ Object
-
#initialize(data, file) ⇒ Vault
constructor
A new instance of Vault.
- #inspect ⇒ Object
- #iv ⇒ Object
- #lock ⇒ Object
- #locked? ⇒ Boolean
- #plaintext_contents ⇒ Object
- #public_contents ⇒ Object
- #public_data ⇒ Object
- #remove(*contents) ⇒ Object
- #secret_key_hash ⇒ Object
- #start_locking_timer(seconds) ⇒ Object
- #status ⇒ Object
- #unlock(password = nil, timeout = 5 * 60) ⇒ Object
- #unlock!(password = nil) ⇒ Object
Constructor Details
#initialize(data, file) ⇒ Vault
Returns a new instance of Vault.
44 45 46 47 48 49 50 |
# File 'lib/syde/vault.rb', line 44 def initialize(data, file) @data = data @file = file.freeze raise ArgumentError, "unable to find any stored data." if @data.empty? raise ArgumentError, "data is not valid." unless Storage.valid_format?(@data) end |
Instance Attribute Details
#file ⇒ Object (readonly)
Returns the value of attribute file.
6 7 8 |
# File 'lib/syde/vault.rb', line 6 def file @file end |
#plaintext_secret_key ⇒ Object
Returns the value of attribute plaintext_secret_key.
5 6 7 |
# File 'lib/syde/vault.rb', line 5 def plaintext_secret_key @plaintext_secret_key end |
Class Method Details
.create(password, file = Storage::DefaultStorageFile) ⇒ Object
15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
# File 'lib/syde/vault.rb', line 15 def self.create(password, file = Storage::DefaultStorageFile) file = File.(file) raise "#{file} contains content -- refusing to override." if File.exist?(file) && File.size(file) > 0 FileUtils.touch(file) unless File.exist?(file) h = {} [:plaintext, :encrypted].each { |e| h[e] = {} } h[:plaintext][:iv] = Crypto.new_iv new_secret_key = Vault.new_secret_key(password, h[:plaintext][:iv]) encrypted_key = new_secret_key[:encrypted_key] hash = new_secret_key[:plaintext_key_hash] plaintext_key = new_secret_key[:plaintext_key] h[:encrypted][:secret_key] = encrypted_key h[:plaintext][:secret_key_hash] = hash h[:encrypted][:contents] = Crypto.encrypt(plaintext_key, h[:plaintext][:iv], YAML.dump([])) h[:plaintext][:contents] = [] File.open(file, "w") do |f| f << YAML.dump(h) end Vault.new(h, file) end |
.new_secret_key(password, iv) ⇒ Object
204 205 206 207 208 209 210 211 212 |
# File 'lib/syde/vault.rb', line 204 def self.new_secret_key(password, iv) plaintext = Crypto.digest(Crypto.random_bytes(4096)) new_key = Crypto.aes(:encrypt, password, iv, plaintext) #? plaintext = nil #? GC.start { :encrypted_key => new_key, :plaintext_key_hash => Crypto.digest(plaintext), :plaintext_key => plaintext } end |
.open(file = Storage::DefaultStorageFile) ⇒ Object
8 9 10 11 12 13 |
# File 'lib/syde/vault.rb', line 8 def self.open(file = Storage::DefaultStorageFile) file = File.(file) FileUtils.touch(file) unless File.exist?(file) Vault.new(YAML.load_file(file) || "", file) end |
Instance Method Details
#add(*contents) ⇒ Object Also known as: <<
175 176 177 178 179 180 181 182 183 |
# File 'lib/syde/vault.rb', line 175 def add(*contents) raise AccessError, "vault is locked; unable to add content to vault." if locked? contents.each do |content| internal_contents << content end update_contents(internal_contents) end |
#contents ⇒ Object
141 142 143 144 145 146 147 |
# File 'lib/syde/vault.rb', line 141 def contents if locked? public_contents else plaintext_contents end end |
#contents=(new_content) ⇒ Object
167 168 169 170 171 172 173 |
# File 'lib/syde/vault.rb', line 167 def contents=(new_content) raise AccessError, "vault is locked; unable to modify vault contents." if locked? internal_contents.replace(new_content) update_contents(new_content) end |
#data ⇒ Object
52 53 54 55 56 57 58 |
# File 'lib/syde/vault.rb', line 52 def data if locked? public_data else internal_data end end |
#decrypt_secret_key(password) ⇒ Object
82 83 84 |
# File 'lib/syde/vault.rb', line 82 def decrypt_secret_key(password) Crypto.aes(:decrypt, password, iv, internal_data[:encrypted][:secret_key]) end |
#inspect ⇒ Object
200 201 202 |
# File 'lib/syde/vault.rb', line 200 def inspect %Q{#<Vault (#{status})>} end |
#iv ⇒ Object
74 75 76 |
# File 'lib/syde/vault.rb', line 74 def iv internal_data[:plaintext][:iv] end |
#lock ⇒ Object
86 87 88 89 90 |
# File 'lib/syde/vault.rb', line 86 def lock internal_data[:encrypted][:contents] = Crypto.encrypt(@plaintext_secret_key, iv, YAML.dump(internal_data[:plaintext][:contents])) internal_data[:plaintext][:contents] = nil @plaintext_secret_key = nil end |
#locked? ⇒ Boolean
119 120 121 122 123 124 125 |
# File 'lib/syde/vault.rb', line 119 def locked? if plaintext_secret_key false else true end end |
#plaintext_contents ⇒ Object
127 128 129 130 131 |
# File 'lib/syde/vault.rb', line 127 def plaintext_contents raise AccessError, "vault is locked; unable to access vault contents." if locked? YAML.load(YAML.dump(internal_contents)) end |
#public_contents ⇒ Object
149 150 151 152 153 |
# File 'lib/syde/vault.rb', line 149 def public_contents raise AccessError, "vault is locked; unable to access vault contents." if locked? public_data[:plaintext][:contents] end |
#public_data ⇒ Object
60 61 62 63 64 |
# File 'lib/syde/vault.rb', line 60 def public_data public_data = YAML.load(YAML.dump(internal_data)) public_data[:plaintext].delete(:contents) public_data end |
#remove(*contents) ⇒ Object
186 187 188 189 190 191 192 193 194 |
# File 'lib/syde/vault.rb', line 186 def remove(*contents) raise AccessError, "vault is locked; unable to remove content from vault." if locked? contents.each do |content| internal_contents.delete(content) end update_contents(internal_contents) end |
#secret_key_hash ⇒ Object
78 79 80 |
# File 'lib/syde/vault.rb', line 78 def secret_key_hash internal_data[:plaintext][:secret_key_hash] end |
#start_locking_timer(seconds) ⇒ Object
112 113 114 115 116 117 |
# File 'lib/syde/vault.rb', line 112 def start_locking_timer(seconds) Thread.new do sleep seconds self.lock end end |
#status ⇒ Object
196 197 198 |
# File 'lib/syde/vault.rb', line 196 def status locked? ? "locked" : "unlocked" end |
#unlock(password = nil, timeout = 5 * 60) ⇒ Object
105 106 107 108 109 110 |
# File 'lib/syde/vault.rb', line 105 def unlock(password = nil, timeout = 5 * 60) return false unless timeout > 0 unlock!(password) start_locking_timer(timeout) true end |
#unlock!(password = nil) ⇒ Object
92 93 94 95 96 97 98 99 100 101 102 103 |
# File 'lib/syde/vault.rb', line 92 def unlock!(password = nil) raise MissingPasswordError, "no password given." unless password plaintext_secret_key = decrypt_secret_key(password) if Crypto.digest(plaintext_secret_key) != secret_key_hash raise PasswordIncorrectError else @plaintext_secret_key = plaintext_secret_key internal_data[:encrypted][:contents] ||= Crypto.encrypt(@plaintext_secret_key, iv, YAML.dump([])) internal_data[:plaintext][:contents] = YAML.load(Crypto.decrypt(@plaintext_secret_key, iv, internal_data[:encrypted][:contents])) end end |