-
Notifications
You must be signed in to change notification settings - Fork 21.4k
/
credentials_command.rb
135 lines (110 loc) · 4.61 KB
/
credentials_command.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
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
131
132
133
134
135
# frozen_string_literal: true
require "pathname"
require "active_support"
require "rails/command/helpers/editor"
require "rails/command/environment_argument"
module Rails
module Command
class CredentialsCommand < Rails::Command::Base # :nodoc:
include Helpers::Editor
include EnvironmentArgument
require_relative "credentials_command/diffing"
include Diffing
desc "edit", "Open the decrypted credentials in `$VISUAL` or `$EDITOR` for editing"
def edit
load_environment_config!
load_generators
if environment_specified?
@content_path = "config/credentials/#{environment}.yml.enc" unless config.key?(:content_path)
@key_path = "config/credentials/#{environment}.key" unless config.key?(:key_path)
end
ensure_encryption_key_has_been_added
ensure_credentials_have_been_added
ensure_diffing_driver_is_configured
change_credentials_in_system_editor
end
desc "show", "Show the decrypted credentials"
def show
load_environment_config!
say credentials.read.presence || missing_credentials_message
end
desc "diff", "Enroll/disenroll in decrypted diffs of credentials using git"
option :enroll, type: :boolean, default: false,
desc: "Enroll project in credentials file diffing with `git diff`"
option :disenroll, type: :boolean, default: false,
desc: "Disenroll project from credentials file diffing"
def diff(content_path = nil)
if @content_path = content_path
self.environment = extract_environment_from_path(content_path)
load_environment_config!
say credentials.read.presence || credentials.content_path.read
else
disenroll_project_from_credentials_diffing if options[:disenroll]
enroll_project_in_credentials_diffing if options[:enroll]
end
rescue ActiveSupport::MessageEncryptor::InvalidMessage
say credentials.content_path.read
end
private
def config
Rails.application.config.credentials
end
def content_path
@content_path ||= relative_path(config.content_path)
end
def key_path
@key_path ||= relative_path(config.key_path)
end
def credentials
@credentials ||= Rails.application.encrypted(content_path, key_path: key_path)
end
def ensure_encryption_key_has_been_added
return if credentials.key?
require "rails/generators/rails/encryption_key_file/encryption_key_file_generator"
encryption_key_file_generator = Rails::Generators::EncryptionKeyFileGenerator.new
encryption_key_file_generator.add_key_file(key_path)
encryption_key_file_generator.ignore_key_file(key_path)
end
def ensure_credentials_have_been_added
require "rails/generators/rails/credentials/credentials_generator"
Rails::Generators::CredentialsGenerator.new(
[content_path, key_path],
skip_secret_key_base: environment_specified? && %w[development test].include?(environment),
quiet: true
).invoke_all
end
def change_credentials_in_system_editor
using_system_editor do
say "Editing #{content_path}..."
credentials.change { |tmp_path| system_editor(tmp_path) }
say "File encrypted and saved."
warn_if_credentials_are_invalid
end
rescue ActiveSupport::EncryptedFile::MissingKeyError => error
say error.message
rescue ActiveSupport::MessageEncryptor::InvalidMessage
say "Couldn't decrypt #{content_path}. Perhaps you passed the wrong key?"
end
def warn_if_credentials_are_invalid
credentials.validate!
rescue ActiveSupport::EncryptedConfiguration::InvalidContentError => error
say "WARNING: #{error.message}", :red
say ""
say "Your application will not be able to load '#{content_path}' until the error has been fixed.", :red
end
def missing_credentials_message
if !credentials.key?
"Missing '#{key_path}' to decrypt credentials. See `#{executable(:help)}`."
else
"File '#{content_path}' does not exist. Use `#{executable(:edit)}` to change that."
end
end
def relative_path(path)
Rails.root.join(path).relative_path_from(Rails.root).to_s
end
def extract_environment_from_path(path)
available_environments.find { |env| path.end_with?("#{env}.yml.enc") }
end
end
end
end