Class: Xshellz::Keystore
- Inherits:
-
Object
- Object
- Xshellz::Keystore
- Defined in:
- lib/xshellz/keystore.rb
Overview
Local on-disk private-key store backing Sandbox.get_or_create.
One file per sandbox name (sanitized), OpenSSH private key inside,
0600 permissions, in ~/.xshellz/keys/ by default.
Security note: keys are stored in PLAINTEXT on disk, protected only by
file permissions (0600, directory 0700). Anyone who can read the file can
SSH into the sandbox. Delete the file (+delete+) and kill the box to
revoke; pass keystore: false to get_or_create to keep keys purely
in-memory instead.
Constant Summary collapse
- SAFE_NAME =
Characters allowed to survive sanitization into a key file name.
/[^A-Za-z0-9._-]+/
Instance Attribute Summary collapse
-
#dir ⇒ Object
readonly
Returns the value of attribute dir.
Class Method Summary collapse
- .default_dir ⇒ Object
-
.sanitize(name) ⇒ Object
Turn a sandbox name into a safe file basename (no separators, no leading dots - so no traversal and no hidden files).
Instance Method Summary collapse
-
#delete(name) ⇒ Object
Remove the stored key for
name. -
#initialize(dir: self.class.default_dir) ⇒ Keystore
constructor
A new instance of Keystore.
-
#load(name) ⇒ Object
The stored key for
name, or nil when none exists. -
#path_for(name) ⇒ Object
The absolute path where +name+'s key lives (whether or not it exists).
-
#save(name, private_key_openssh) ⇒ Object
Persist an OpenSSH private key for
name(0600).
Constructor Details
#initialize(dir: self.class.default_dir) ⇒ Keystore
Returns a new instance of Keystore.
35 36 37 |
# File 'lib/xshellz/keystore.rb', line 35 def initialize(dir: self.class.default_dir) @dir = File.(dir) end |
Instance Attribute Details
#dir ⇒ Object (readonly)
Returns the value of attribute dir.
20 21 22 |
# File 'lib/xshellz/keystore.rb', line 20 def dir @dir end |
Class Method Details
.default_dir ⇒ Object
22 23 24 |
# File 'lib/xshellz/keystore.rb', line 22 def self.default_dir File.join(Dir.home, ".xshellz", "keys") end |
.sanitize(name) ⇒ Object
Turn a sandbox name into a safe file basename (no separators, no leading dots - so no traversal and no hidden files).
28 29 30 31 32 33 |
# File 'lib/xshellz/keystore.rb', line 28 def self.sanitize(name) cleaned = name.to_s.gsub(SAFE_NAME, "_").sub(/\A\.+/, "_") raise ArgumentError, "Cannot derive a key file name from #{name.inspect}" if cleaned.empty? cleaned end |
Instance Method Details
#delete(name) ⇒ Object
Remove the stored key for name. Returns true when a file was deleted.
60 61 62 63 64 65 66 |
# File 'lib/xshellz/keystore.rb', line 60 def delete(name) path = path_for(name) return false unless File.file?(path) File.delete(path) true end |
#load(name) ⇒ Object
The stored key for name, or nil when none exists.
54 55 56 57 |
# File 'lib/xshellz/keystore.rb', line 54 def load(name) path = path_for(name) File.file?(path) ? File.read(path) : nil end |
#path_for(name) ⇒ Object
The absolute path where +name+'s key lives (whether or not it exists).
40 41 42 |
# File 'lib/xshellz/keystore.rb', line 40 def path_for(name) File.join(dir, "#{self.class.sanitize(name)}.key") end |
#save(name, private_key_openssh) ⇒ Object
Persist an OpenSSH private key for name (0600). Returns the path.
45 46 47 48 49 50 51 |
# File 'lib/xshellz/keystore.rb', line 45 def save(name, private_key_openssh) FileUtils.mkdir_p(dir, mode: 0o700) path = path_for(name) File.write(path, private_key_openssh, perm: 0o600) File.chmod(0o600, path) path end |