Class: Arcanus::Chest

Inherits:
Object
  • Object
show all
Defined in:
lib/arcanus/chest.rb

Overview

Encapsulates the collection of encrypted secrets managed by Arcanus.

Defined Under Namespace

Classes: Item

Constant Summary collapse

SIGNATURE_SIZE_BITS =
256
ENCRYPTION_CIPHER =
OpenSSL::Cipher.new('AES-256-CBC')

Instance Method Summary collapse

Constructor Details

#initialize(key:, chest_file_path:) ⇒ Chest

Returns a new instance of Chest.


12
13
14
15
16
17
18
# File 'lib/arcanus/chest.rb', line 12

def initialize(key:, chest_file_path:)
  @key = key
  @chest_file_path = chest_file_path
  @original_encrypted_hash = YAML.load_file(chest_file_path).to_hash
  @original_decrypted_hash = decrypt_hash(@original_encrypted_hash)
  @hash = Utils.deep_dup(@original_decrypted_hash)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method_sym, *args) ⇒ Object


39
40
41
42
43
44
45
46
# File 'lib/arcanus/chest.rb', line 39

def method_missing(method_sym, *args)
  method_name = method_sym.to_s
  if @hash.key?(method_name)
    self[method_name]
  else
    super
  end
end

Instance Method Details

#[](key) ⇒ Object

Access the chest as if it were a hash.

Parameters:

  • key (String)

Returns:

  • (Object)

24
25
26
27
28
29
30
31
32
33
34
35
36
37
# File 'lib/arcanus/chest.rb', line 24

def [](key)
  if @hash.key?(key)
    value = @hash[key]
    if value.is_a?(Hash)
      Item.new(value, [key])
    else
      value
    end
  else
    raise KeyError,
          "Key '#{key}' does not exist in this Arcanus chest",
          caller
  end
end

#fetch(*args) ⇒ Object

Fetch key from the chest as if it were a hash.


57
58
59
# File 'lib/arcanus/chest.rb', line 57

def fetch(*args)
  @hash.fetch(*args)
end

#get(key_path) ⇒ Object

Get value at the specified key path.

Parameters:

  • key_path (String)

Returns:

  • (Object)

88
89
90
91
92
93
94
# File 'lib/arcanus/chest.rb', line 88

def get(key_path)
  keys = key_path.split('.')
  keys.inject(@hash) { |hash, key| hash[key] }
rescue NoMethodError
  raise Arcanus::Errors::InvalidKeyPathError,
        "Key path '#{key_path}' does not correspond to an actual key"
end

#respond_to?(method_sym) ⇒ Boolean

Returns:

  • (Boolean)

52
53
54
# File 'lib/arcanus/chest.rb', line 52

def respond_to?(method_sym, *)
  @hash.key?(method_sym.to_s) || super
end

#respond_to_missing?(method_name, *args) ⇒ Boolean

Returns:

  • (Boolean)

48
49
50
# File 'lib/arcanus/chest.rb', line 48

def respond_to_missing?(method_name, *args)
  @hash.key?(method_name.to_s) ? true : super
end

#saveObject

For each key in the chest, encrypt the new value if it has changed.

The goal is to create a file where the only lines that differ are the keys that changed.


104
105
106
107
108
109
110
111
112
# File 'lib/arcanus/chest.rb', line 104

def save
  modified_hash =
    process_hash_changes(@original_encrypted_hash, @original_decrypted_hash, @hash)

  File.open(@chest_file_path, 'w') do |f|
    f.puts('# Do not edit this file directly! Run `arcanus edit`')
    f.write(modified_hash.to_yaml)
  end
end

#set(key_path, value) ⇒ Object

Set value for the specified key path.

Parameters:

  • key_path (String)
  • value (Object)

75
76
77
78
79
80
81
82
# File 'lib/arcanus/chest.rb', line 75

def set(key_path, value)
  keys = key_path.split('.')
  nested_hash = keys[0..-2].inject(@hash) { |hash, key| hash[key] }
  nested_hash[keys[-1]] = value
rescue NoMethodError
  raise Arcanus::Errors::InvalidKeyPathError,
        "Key path '#{key_path}' does not correspond to an actual key"
end

#to_hashObject

Returns contents of the chest as a hash.


62
63
64
# File 'lib/arcanus/chest.rb', line 62

def to_hash
  @hash.dup
end

#to_yamlObject

Returns contents of the chest as YAML.


67
68
69
# File 'lib/arcanus/chest.rb', line 67

def to_yaml
  @hash.to_yaml
end

#update(new_hash) ⇒ Object


96
97
98
# File 'lib/arcanus/chest.rb', line 96

def update(new_hash)
  @hash = new_hash
end