Module: EasyCreds::Generators

Defined in:
lib/easy_creds/generators.rb

Constant Summary collapse

KNOWN =
{
  /\bsecret_key_base\b/ => :secret_key_base,
  /\bdevise_secret_key\b/ => :devise_secret_key,
  /\bcrypt_secret\b/ => :crypt_secret,
  /active_record_encryption\./ => :ar_encryption
}.freeze

Class Method Summary collapse

Class Method Details

.alternative_for(hint) ⇒ Object



93
94
95
96
97
98
99
# File 'lib/easy_creds/generators.rb', line 93

def self.alternative_for(hint)
  case hint
  when :secret_key_base, :devise_secret_key then random_hex(64)
  when :crypt_secret then random_hex(32)
  else random_alpha(32)
  end
end

.ar_encryption_keys(root = nil) ⇒ Object

Rails-derived Active Record Encryption keys via ‘rails db:encryption:init`. Falls back to independent SecureRandom keys when run outside a Rails project (nil root) or when the shell-out fails.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/easy_creds/generators.rb', line 30

def self.ar_encryption_keys(root = nil)
  return random_ar_encryption_keys if root.nil?

  stdout, _stderr, status = Open3.capture3(
    'bundle', 'exec', 'rails', 'db:encryption:init',
    chdir: root.to_s
  )
  return random_ar_encryption_keys unless status.success?

  # Output looks like:
  #   active_record_encryption:
  #     primary_key: ...
  #     deterministic_key: ...
  #     key_derivation_salt: ...
  section = stdout[/active_record_encryption:.*\z/m]
  return random_ar_encryption_keys unless section

  data  = YAML.safe_load(section)
  inner = data&.dig('active_record_encryption') || {}
  return random_ar_encryption_keys if inner.empty?

  inner.transform_keys { |k| "active_record_encryption.#{k}" }
rescue StandardError => e
  warn "⚠️  db:encryption:init failed: #{e.message}"
  random_ar_encryption_keys
end

.bulk_for(hint) ⇒ Object



101
102
103
104
105
106
107
# File 'lib/easy_creds/generators.rb', line 101

def self.bulk_for(hint)
  case hint
  when :secret_key_base, :devise_secret_key then random_hex(64)
  when :ar_encryption then nil
  else random_hex(32)
  end
end

.crypt_secretObject



23
# File 'lib/easy_creds/generators.rb', line 23

def self.crypt_secret      = SecureRandom.hex(32)

.default_for(hint, root: nil) ⇒ Object



82
83
84
85
86
87
88
89
90
91
# File 'lib/easy_creds/generators.rb', line 82

def self.default_for(hint, root: nil)
  case hint
  when :secret_key_base, :devise_secret_key, :crypt_secret
    rails_secret(root: root)
  when :ar_encryption
    ar_encryption_keys(root)
  else
    random_hex(32)
  end
end

.devise_secret_keyObject



22
# File 'lib/easy_creds/generators.rb', line 22

def self.devise_secret_key = SecureRandom.hex(64)

.generate(hint, root: nil) ⇒ Object



109
110
111
# File 'lib/easy_creds/generators.rb', line 109

def self.generate(hint, root: nil)
  default_for(hint, root: root)
end

.hint_for(key) ⇒ Object



16
17
18
19
# File 'lib/easy_creds/generators.rb', line 16

def self.hint_for(key)
  KNOWN.each { |pattern, name| return name if key.match?(pattern) }
  nil
end

.rails_secret(root: nil) ⇒ Object

Shells out to ‘rails secret` (canonical secret_key_base style). Falls back to SecureRandom on a nil root or any failure.



67
68
69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/easy_creds/generators.rb', line 67

def self.rails_secret(root: nil)
  return SecureRandom.hex(64) if root.nil?

  stdout, _err, status = Open3.capture3(
    'bundle', 'exec', 'rails', 'secret',
    chdir: root.to_s
  )
  return SecureRandom.hex(64) unless status.success?

  line = stdout.lines.find { |l| l.strip =~ /\A[0-9a-f]{64,}\z/ }
  line ? line.strip : SecureRandom.hex(64)
rescue StandardError
  SecureRandom.hex(64)
end

.random_alpha(len = 32) ⇒ Object



25
# File 'lib/easy_creds/generators.rb', line 25

def self.random_alpha(len = 32) = SecureRandom.alphanumeric(len)

.random_ar_encryption_keysObject



57
58
59
60
61
62
63
# File 'lib/easy_creds/generators.rb', line 57

def self.random_ar_encryption_keys
  {
    'active_record_encryption.primary_key' => SecureRandom.hex(32),
    'active_record_encryption.deterministic_key' => SecureRandom.hex(32),
    'active_record_encryption.key_derivation_salt' => SecureRandom.hex(32)
  }
end

.random_hex(len = 32) ⇒ Object



24
# File 'lib/easy_creds/generators.rb', line 24

def self.random_hex(len = 32)   = SecureRandom.hex(len)

.secret_key_baseObject



21
# File 'lib/easy_creds/generators.rb', line 21

def self.secret_key_base = SecureRandom.hex(64)