Class: Secret::File
Overview
Handles file operations. Uses Ruby’s internal file locking mechanisms.
Instance Attribute Summary collapse
-
#container ⇒ Object
readonly
Returns the value of attribute container.
-
#identifier ⇒ Object
readonly
Returns the value of attribute identifier.
Instance Method Summary collapse
-
#contents ⇒ String
Gets the contents of the file in a string format.
-
#delete! ⇒ Object
Delete the contents of this file, along with any other associated files.
- #ensure_writeable! ⇒ Object
-
#exist? ⇒ Boolean
Checks whether this file actually exists or not.
-
#initialize(container, identifier) ⇒ File
constructor
Creates a new secret file.
-
#restore_backup! ⇒ Boolean
Attempts to restore a backup (i.e. if the computer crashed while doing a stash command).
-
#secure! ⇒ Object
Secures the file by chmoding it to 0700.
-
#stash(content) ⇒ Object
Stashes some content into the file! This will write a temporary backup file before stashing, in order to prevent any partial writes if the server crashes.
-
#stream(mode = 'r', &block) ⇒ IO
Gets a file stream of this file.
-
#touch! ⇒ Boolean
Creates a new file if it doesn’t exist.
Methods included from Encryption
#change_encryption_passphrase!, #decrypt!, #decrypted, #encrypt!, #encrypted, #encrypted?, #ensure_unencrypted!, #remove_encrypted_indicator, #stash_encrypted
Constructor Details
#initialize(container, identifier) ⇒ File
Creates a new secret file. The specified identifier doesn’t already need to exist.
12 13 14 15 16 17 |
# File 'lib/secret/file.rb', line 12 def initialize(container, identifier) raise ArgumentError, "Container must be a Secret::Container object" unless container.is_a?(Secret::Container) @container = container; @identifier = identifier touch! ensure_writeable! end |
Instance Attribute Details
#container ⇒ Object (readonly)
Returns the value of attribute container.
7 8 9 |
# File 'lib/secret/file.rb', line 7 def container @container end |
#identifier ⇒ Object (readonly)
Returns the value of attribute identifier.
7 8 9 |
# File 'lib/secret/file.rb', line 7 def identifier @identifier end |
Instance Method Details
#contents ⇒ String
Gets the contents of the file in a string format. Will return an empty string if the file doesn’t exist, or the file just so happens to be empty.
62 63 64 65 66 67 68 |
# File 'lib/secret/file.rb', line 62 def contents str = nil stream 'r' do |f| str = f.read end return str end |
#delete! ⇒ Object
Delete the contents of this file, along with any other associated files.
160 161 162 163 |
# File 'lib/secret/file.rb', line 160 def delete! ::File.delete(file_path) if exist? Dir[file_path + "*"].each {|f| ::File.delete f } end |
#ensure_writeable! ⇒ Object
132 133 134 135 136 |
# File 'lib/secret/file.rb', line 132 def ensure_writeable! unless ::File.writable?(file_path) raise FileUnreadableError, "File is not writeable - perhaps it was created by a different process?" end end |
#exist? ⇒ Boolean
Checks whether this file actually exists or not
21 22 23 |
# File 'lib/secret/file.rb', line 21 def exist? ::File.exist?(file_path) end |
#restore_backup! ⇒ Boolean
Attempts to restore a backup (i.e. if the computer crashed while doing a stash command)
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 |
# File 'lib/secret/file.rb', line 140 def restore_backup! return false unless ::File.exist?(backup_file_path) # We know backup exists, so let's write to the file. We want to truncate file contents. # Now copy file contents over from the backup file. We use this method to use locking. ::File.open(file_path, 'w', container.chmod_mode) do |f| begin f.flock ::File::LOCK_EX ::File.open(backup_file_path, 'r', container.chmod_mode) do |b| f.write b.read end ensure f.flock ::File::LOCK_UN end end return true end |
#secure! ⇒ Object
Secures the file by chmoding it to 0700
84 85 86 87 |
# File 'lib/secret/file.rb', line 84 def secure! raise IOError, "File doesn't exist" unless exist? ::File.chmod(container.chmod_mode, file_path) end |
#stash(content) ⇒ Object
Stashes some content into the file! This will write a temporary backup file before stashing, in order to prevent any partial writes if the server crashes. Once this finishes executing, you can be sure that contents have been written.
95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/secret/file.rb', line 95 def stash(content) raise ArgumentError, "Content must be a String (was type of type #{content.class.name})" unless content.is_a?(String) touch! ensure_writeable! # Think of this as a beginning of a transaction. ::File.open(file_path, 'a', container.chmod_mode) do |f| begin f.flock(::File::LOCK_EX) # Open a temporary file for writing, and close it immediately ::File.open(tmp_file_path, "w", container.chmod_mode){|f| f.write content } # Rename tmp file to backup file now we know contents are sane ::File.rename(tmp_file_path, backup_file_path) # Remove encryption indicator remove_encrypted_indicator # Truncate file contents to zero bytes f.truncate 0 # Write content f.write content ensure # Now unlock file! f.flock(::File::LOCK_UN) end # Delete backup file ::File.delete(backup_file_path) end # Committed! Secure it just in case secure! end |
#stream(mode = 'r', &block) ⇒ IO
Uses an exclusive lock on this file
Gets a file stream of this file. If the file doesn’t exist, then a blank file will be created. By default, this allows you to write to the file. However, please use the #stash command, as it accounts for mid-write crashes. Don’t forget to close the file stream when you’re done!
44 45 46 47 48 49 50 51 52 53 54 55 56 |
# File 'lib/secret/file.rb', line 44 def stream(mode = 'r', &block) touch! ensure_writeable! return ::File.open(file_path, mode, container.chmod_mode) unless block_given? ::File.open(file_path, mode, container.chmod_mode) do |f| begin f.flock(::File::LOCK_EX) # Lock with exclusive mode block.call(f) ensure f.flock(::File::LOCK_UN) end end end |
#touch! ⇒ Boolean
Creates a new file if it doesn’t exist. Doesn’t actually change the last updated timestamp.
73 74 75 76 77 78 79 80 |
# File 'lib/secret/file.rb', line 73 def touch! unless exist? ::File.open(file_path, 'w', container.chmod_mode) {} secure! return true end return false end |