rs_yettings 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +186 -0
- data/Rakefile +38 -0
- data/lib/tasks/yettings.rake +17 -0
- data/lib/yettings.rb +79 -0
- data/lib/yettings/base.rb +41 -0
- data/lib/yettings/encryption.rb +124 -0
- data/lib/yettings/railtie.rb +15 -0
- data/lib/yettings/version.rb +3 -0
- data/spec/dummy/Guardfile +228 -0
- data/spec/dummy/README.rdoc +261 -0
- data/spec/dummy/Rakefile +7 -0
- data/spec/dummy/app/assets/javascripts/application.js +15 -0
- data/spec/dummy/app/assets/stylesheets/application.css +13 -0
- data/spec/dummy/app/controllers/application_controller.rb +3 -0
- data/spec/dummy/app/helpers/application_helper.rb +2 -0
- data/spec/dummy/app/views/layouts/application.html.erb +14 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/config/application.rb +59 -0
- data/spec/dummy/config/boot.rb +10 -0
- data/spec/dummy/config/database.yml +25 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +37 -0
- data/spec/dummy/config/environments/production.rb +67 -0
- data/spec/dummy/config/environments/test.rb +37 -0
- data/spec/dummy/config/ignored.yml +17 -0
- data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/spec/dummy/config/initializers/inflections.rb +15 -0
- data/spec/dummy/config/initializers/mime_types.rb +5 -0
- data/spec/dummy/config/initializers/secret_token.rb +7 -0
- data/spec/dummy/config/initializers/session_store.rb +8 -0
- data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/spec/dummy/config/locales/en.yml +5 -0
- data/spec/dummy/config/routes.rb +58 -0
- data/spec/dummy/config/yetting.yml +17 -0
- data/spec/dummy/config/yetting.yml.pub +0 -0
- data/spec/dummy/config/yettings/blank.yml +0 -0
- data/spec/dummy/config/yettings/defaults.yml +6 -0
- data/spec/dummy/config/yettings/hendrix.yml +11 -0
- data/spec/dummy/config/yettings/jimi.yml +11 -0
- data/spec/dummy/config/yettings/secret.yml.pub +1 -0
- data/spec/dummy/db/test.sqlite3 +0 -0
- data/spec/dummy/log/development.log +1 -0
- data/spec/dummy/log/test.log +141 -0
- data/spec/dummy/public/404.html +26 -0
- data/spec/dummy/public/422.html +26 -0
- data/spec/dummy/public/500.html +25 -0
- data/spec/dummy/public/favicon.ico +0 -0
- data/spec/dummy/script/rails +6 -0
- data/spec/spec_helper.rb +28 -0
- data/spec/yettings/base_spec.rb +66 -0
- data/spec/yettings/encryption_spec.rb +104 -0
- data/spec/yettings_spec.rb +90 -0
- metadata +320 -0
data/README.md
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
# yettings
|
2
|
+
|
3
|
+
YAML settings for your Rails 3 app.
|
4
|
+
|
5
|
+
## What does it do?
|
6
|
+
|
7
|
+
Yettings allows you to add a yml file to your "config" directory and you can access the values defined in the YAML in your Rails app. You can
|
8
|
+
use this to store API keys, constants, and other key/value pairs. This plugin was heavily inspired by settingslogic, with a few differences... You don't
|
9
|
+
have to add a class and point to the YML file. The Yetting class will be created dynamically and will be available to your Rails app. This plugin is also
|
10
|
+
more basic than settingslogic. It does not have support for dynamic setting creation... only the values in the yetting.yml will be available.
|
11
|
+
|
12
|
+
|
13
|
+
## This project only supports Rails 3 and Ruby >= 1.9.2
|
14
|
+
|
15
|
+
There is a branch for 1.8.7, but it has not been merged into master. If you want to use it, you can reference the github location and branch in your Gemfile. See the issue tracker for more details
|
16
|
+
|
17
|
+
## Known bug in YAML psych parser (Ruby < 1.9.2-p271)
|
18
|
+
This bug can cause issues loading the YAML keys when using Yettings. The workaround is to set your YAML parser to sych if your environment is currently using psych:
|
19
|
+
|
20
|
+
YAML::ENGINE.yamler = "syck"
|
21
|
+
|
22
|
+
More info here: http://pivotallabs.com/users/mkocher/blog/articles/1692-yaml-psych-and-ruby-1-9-2-p180-here-there-be-dragons
|
23
|
+
|
24
|
+
This issue is fixed in ruby-1.9.2-p271.
|
25
|
+
|
26
|
+
## Usage
|
27
|
+
|
28
|
+
###Install the gem
|
29
|
+
|
30
|
+
Add this to your Gemfile
|
31
|
+
gem "yettings"
|
32
|
+
|
33
|
+
Install with Bundler
|
34
|
+
bundle install
|
35
|
+
|
36
|
+
###Adding the YAML file with your key/value pairs
|
37
|
+
|
38
|
+
1. Create a YAML file inside /your_rails_app/config called yetting.yml
|
39
|
+
2. If you want to namespace your Yettings, create a YAML file inside /your_rails_app/config/yettings/ and call it whatever you want.
|
40
|
+
|
41
|
+
###YAML file content
|
42
|
+
You can define key/value pairs in the YAML file and these will be available in your app. You can set the defaults and any environment specific values.
|
43
|
+
The file must contain each environment that you will use in your Rails app. Here is a sample:
|
44
|
+
|
45
|
+
defaults: &defaults
|
46
|
+
api_key: asdf12345lkj
|
47
|
+
some_number: 999
|
48
|
+
an_erb_yetting: <%= "erb stuff works" %>
|
49
|
+
some_array:
|
50
|
+
- element1
|
51
|
+
- element2
|
52
|
+
|
53
|
+
development:
|
54
|
+
<<: *defaults
|
55
|
+
api_key: api key for dev
|
56
|
+
|
57
|
+
test:
|
58
|
+
<<: *defaults
|
59
|
+
|
60
|
+
production:
|
61
|
+
<<: *defaults
|
62
|
+
|
63
|
+
In the above example, you can define the key/value pair using strings, numbers, erb code, or arrays. Notice that the "api_key" in the development
|
64
|
+
environment will override the "api_key" from defaults.
|
65
|
+
|
66
|
+
|
67
|
+
###Accessing the values in your Rails app
|
68
|
+
|
69
|
+
You simply call the Yetting class or the namespaced class and the key as a class method. For namespaced yml files, Yettings will convert the filename in
|
70
|
+
/your_rails_app/config/yettings/ to a class name and append Yetting. So if you have main.yml, then it will use MainYetting as the class name.
|
71
|
+
Then you can call the key that you put in the YAML as a class method. Here are 2 examples:
|
72
|
+
|
73
|
+
#/your_rails_app/config/yetting.yml in production
|
74
|
+
Yetting.some_number #=> 999
|
75
|
+
Yetting.api_key #=> "asdf12345lkj"
|
76
|
+
|
77
|
+
#/your_rails_app/config/yettings/main.yml
|
78
|
+
MainYetting.some_number #=> 999
|
79
|
+
MainYetting.some_array #=> ["element1","element2"]
|
80
|
+
|
81
|
+
|
82
|
+
###Default settings
|
83
|
+
The above YAML content explicitly specifies settings for each environment using
|
84
|
+
YAML splats. In case you'd rather not write all those out, settings in the
|
85
|
+
'defaults' section will be used to populate each environment. So, the above file
|
86
|
+
could be written as
|
87
|
+
|
88
|
+
defaults:
|
89
|
+
api_key: asdf12345lkj
|
90
|
+
some_number: 999
|
91
|
+
an_erb_yetting: <%= "erb stuff works" %>
|
92
|
+
some_array:
|
93
|
+
- element1
|
94
|
+
- element2
|
95
|
+
|
96
|
+
development:
|
97
|
+
api_key: api key for dev
|
98
|
+
|
99
|
+
|
100
|
+
## Encryption
|
101
|
+
|
102
|
+
You may be tempted to store sensitive information in your settings
|
103
|
+
files. For example, you may have places in your app where you use secret API
|
104
|
+
keys, passwords or other credentials that are a liability to keep in revision
|
105
|
+
control.
|
106
|
+
|
107
|
+
With version 0.2.0, Yettings supports encrypted values. To use this feature,
|
108
|
+
you'll need to generate a public/private keypair:
|
109
|
+
|
110
|
+
rake yettings:gen_keys
|
111
|
+
|
112
|
+
Now you'll find the following files and directories in your project:
|
113
|
+
|
114
|
+
config/yettings/.private_key
|
115
|
+
config/yettings/.public_key
|
116
|
+
config/yettings/.private/
|
117
|
+
|
118
|
+
You'll also automatically have the private key and private directory added to
|
119
|
+
the .gitignore file to avoid checking these into git. Now create a file in the
|
120
|
+
.private directory, let's call it secret.yml, and put something in there you
|
121
|
+
don't ever want anyone else to know about:
|
122
|
+
|
123
|
+
# config/yettings/.private/secret.yml
|
124
|
+
defaults:
|
125
|
+
guilty_pleasure: singing into hairbrush
|
126
|
+
|
127
|
+
Whenever you run rails, you'll see a warning like this:
|
128
|
+
|
129
|
+
$ ./bin/rails c
|
130
|
+
WARNING: overwriting config/yettings/secret.yml.pub with contents of config/yettings/.private/secret.yml
|
131
|
+
|
132
|
+
Take a look at the secret.yml.pub file in that location and you'll see the contents are now encrypted:
|
133
|
+
|
134
|
+
# config/yettings/secret.yml.pub
|
135
|
+
---
|
136
|
+
defaults:
|
137
|
+
guilty_pleasure: !binary |-
|
138
|
+
YSgVHF+rhhBSRRaHIyOZwkd99ovrTvnfvsEdXjUXmbm2RdZTkBLzP+Ha275r
|
139
|
+
gAwfY2P7AtkluGQmEpmr6f1C9XLI6hs3AHpkIE4OSJmOQAD2AU8lmw6oOg1j
|
140
|
+
SJBX7F+v1i8WS+rhxF3y5uNtAh+Fv4w+N/d9w6iDed0wywLq1e3jXjbQv8KL
|
141
|
+
rCf9FRpW2WTUYa+tntalaAQkNcp2Es3bWODfkZYOnsMm2POi5mtaCQR0/O8E
|
142
|
+
1k1sToOqvt/vL1g24NeSTGXLndqo1pRkdhREkj7TiY6fFj3CXQtk+4JTJGGs
|
143
|
+
bex7be+v9eEk5rJc7gu6uq1F9ymuWx+LUNHczppw4g==
|
144
|
+
|
145
|
+
Check this into git, then edit your private file again:
|
146
|
+
|
147
|
+
# config/yettings/.private/secret.yml
|
148
|
+
defaults:
|
149
|
+
guilty_pleasure: singing into hairbrush
|
150
|
+
specifically: '"Only in My Dreams" by Debbie Gibson'
|
151
|
+
|
152
|
+
Next time you run rails, your public file will be appended to, and you'll see
|
153
|
+
which key was updated when you commit to git again. This will help you if you
|
154
|
+
ever need to roll back your credentials.
|
155
|
+
|
156
|
+
diff --git a/test_app/config/yettings/secret.yml.pub b/test_app/config/yettings/
|
157
|
+
index 3c0e462..8d9555d 100644
|
158
|
+
--- a/test_app/config/yettings/secret.yml.pub
|
159
|
+
+++ b/test_app/config/yettings/secret.yml.pub
|
160
|
+
@@ -7,3 +7,10 @@ defaults:
|
161
|
+
rCf9FRpW2WTUYa+tntalaAQkNcp2Es3bWODfkZYOnsMm2POi5mtaCQR0/O8E
|
162
|
+
1k1sToOqvt/vL1g24NeSTGXLndqo1pRkdhREkj7TiY6fFj3CXQtk+4JTJGGs
|
163
|
+
bex7be+v9eEk5rJc7gu6uq1F9ymuWx+LUNHczppw4g==
|
164
|
+
+ specifically: !binary |-
|
165
|
+
+ A5M0/A3AbzkJaIXP3Ehtx0jPQtq2p8Y4SOqWN6OobkStjwSB6t9oHPDxA/jB
|
166
|
+
+ mnzkyH6Hwsq0MMQjvJrRoDDNU7lTPnVSxGkwkHBD37I09X9JEim0qTC4M1Q3
|
167
|
+
+ /VQEHtdEF8NfG9ZJs1b3iQNzu1CA2KNzUywmVpMJuwDNx4mSGdqpE37EeWMZ
|
168
|
+
+ iuY/F+nfi6pJYktlmuis2uy8IDrAdEQ7k0x2i3dGs9KotiNAmCkRvq5jwH9a
|
169
|
+
+ FXf30fXLX2cjWHQd3Ru3XurSOiN4LoYvAQBdgLyfX2ipapY8W+vcP8RmDBQR
|
170
|
+
+ vu9miVub5T1xndclETuL97JTO6Yg8PU98Pv42289GQ==
|
171
|
+
|
172
|
+
|
173
|
+
## Contributing to yettings
|
174
|
+
|
175
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
176
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
177
|
+
* Fork the project
|
178
|
+
* Start a feature/bugfix branch
|
179
|
+
* Commit and push until you are happy with your contribution
|
180
|
+
* Make sure to add tests for it. I will not even look at patches without a test included.
|
181
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
182
|
+
|
183
|
+
## Copyright
|
184
|
+
|
185
|
+
Copyright (c) 2011 mc-2
|
186
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'Yettings'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
|
26
|
+
Bundler::GemHelper.install_tasks
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
|
30
|
+
Rake::TestTask.new(:test) do |t|
|
31
|
+
t.libs << 'lib'
|
32
|
+
t.libs << 'test'
|
33
|
+
t.pattern = 'test/**/*_test.rb'
|
34
|
+
t.verbose = false
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
task :default => :test
|
@@ -0,0 +1,17 @@
|
|
1
|
+
namespace :yettings do
|
2
|
+
desc "generate public/private key pair for encrypting sensitive yetting files"
|
3
|
+
task :gen_keys => :environment do
|
4
|
+
Yettings.gen_keys
|
5
|
+
end
|
6
|
+
|
7
|
+
desc "encrypt sensitive yetting files for checking into revision control"
|
8
|
+
task :encrypt => :environment do
|
9
|
+
Yettings.encrypt_files!
|
10
|
+
end
|
11
|
+
|
12
|
+
desc "decrypt sensitive yetting files for editing"
|
13
|
+
task :decrypt => :environment do
|
14
|
+
Yettings.decrypt_files!
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
data/lib/yettings.rb
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'erb'
|
3
|
+
require 'openssl'
|
4
|
+
require "yettings/railtie.rb"
|
5
|
+
require "yettings/base.rb"
|
6
|
+
require "yettings/encryption.rb"
|
7
|
+
|
8
|
+
module Yettings
|
9
|
+
include Yettings::Encryption
|
10
|
+
|
11
|
+
class UndefinedYettingError < StandardError; end
|
12
|
+
class NameConflictError < StandardError; end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
def setup!
|
16
|
+
EncryptedStrings::SymmetricCipher.default_algorithm = 'DES-EDE3-CBC'
|
17
|
+
find_yml_files.each do |yml_file|
|
18
|
+
create_yetting_class yml_file
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_yetting_class(yml_file)
|
23
|
+
name = klass_name(yml_file)
|
24
|
+
klass = Object.const_set(name, Class.new(Yettings::Base))
|
25
|
+
klass.load_yml_erb yaml_erb(yml_file)
|
26
|
+
end
|
27
|
+
|
28
|
+
def yaml_erb(yml_file)
|
29
|
+
yaml_erb = File.read(yml_file)
|
30
|
+
yaml_erb = decrypt_string(yaml_erb) if pub?(yml_file)
|
31
|
+
yaml_erb
|
32
|
+
end
|
33
|
+
|
34
|
+
def pub?(yml_file)
|
35
|
+
yml_file.end_with? ".pub"
|
36
|
+
end
|
37
|
+
|
38
|
+
def klass_name(yml_file)
|
39
|
+
basename = File.basename(yml_file)
|
40
|
+
if basename == "yetting.yml"
|
41
|
+
name = "Yetting"
|
42
|
+
else
|
43
|
+
name = basename.gsub(/\.pub$/,"").gsub(/\.yml$/,"").camelize + "Yetting"
|
44
|
+
end
|
45
|
+
return name unless Object.const_defined?(name)
|
46
|
+
if name.constantize.ancestors.include? Yettings::Base
|
47
|
+
Object.module_eval { remove_const name }
|
48
|
+
return name
|
49
|
+
else
|
50
|
+
raise NameConflictError, "#{name} is already defined"
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def rails_config
|
55
|
+
"#{Rails.root}/config"
|
56
|
+
end
|
57
|
+
|
58
|
+
def root
|
59
|
+
"#{rails_config}/yettings"
|
60
|
+
end
|
61
|
+
|
62
|
+
def private_root
|
63
|
+
"#{root}/\.private"
|
64
|
+
end
|
65
|
+
|
66
|
+
def find_yml_files
|
67
|
+
Dir.glob("#{rails_config}/yetting.yml") + Dir.glob("#{root}/**/*.yml") + Dir.glob("#{root}/**/*.yml.pub")
|
68
|
+
end
|
69
|
+
|
70
|
+
def find_public_yml_files
|
71
|
+
Dir.glob("#{root}/**/*.yml.pub")
|
72
|
+
end
|
73
|
+
|
74
|
+
def find_private_yml_files
|
75
|
+
Dir.glob("#{private_root}/**/*.yml")
|
76
|
+
end
|
77
|
+
end # class << self
|
78
|
+
end
|
79
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
require 'erb'
|
3
|
+
require 'openssl'
|
4
|
+
|
5
|
+
class Yettings::Base
|
6
|
+
class UndefinedYettingError < StandardError; end
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def method_missing(method_id, *args)
|
10
|
+
raise UndefinedYettingError, "#{method_id} is not defined in #{self}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def [](key)
|
14
|
+
send key
|
15
|
+
end
|
16
|
+
|
17
|
+
def load_yml_erb(yml_erb)
|
18
|
+
yml = ERB.new(yml_erb).result
|
19
|
+
full_hash = build_hash yml
|
20
|
+
defaults = full_hash.delete('defaults') || {}
|
21
|
+
env_hash = full_hash[Rails.env] || {}
|
22
|
+
define_methods defaults.merge(env_hash)
|
23
|
+
end
|
24
|
+
|
25
|
+
def define_methods(hash)
|
26
|
+
hash.each do |key, value|
|
27
|
+
class_attribute key
|
28
|
+
if value.is_a? Hash
|
29
|
+
send "#{key}=", Class.new(Yettings::Base)
|
30
|
+
send(key).define_methods(value)
|
31
|
+
else
|
32
|
+
define_singleton_method(key) { value }
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def build_hash(yml)
|
38
|
+
yml.present? ? YAML.load(yml).to_hash : {}
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'base64'
|
2
|
+
|
3
|
+
module Yettings
|
4
|
+
module Encryption
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def decrypt_string(encrypted)
|
9
|
+
if key_and_iv_exists?
|
10
|
+
decipher = OpenSSL::Cipher::AES.new(256, :CBC)
|
11
|
+
decipher.decrypt
|
12
|
+
decipher.key = key
|
13
|
+
decipher.iv = iv
|
14
|
+
encrypted = Base64.strict_decode64(encrypted)
|
15
|
+
plain = decipher.update(encrypted) + decipher.final
|
16
|
+
else
|
17
|
+
"access denied (no key file and/or IV file found)"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def encrypt_string(data)
|
22
|
+
cipher = OpenSSL::Cipher::AES.new(256, :CBC)
|
23
|
+
cipher.encrypt
|
24
|
+
cipher.key = key
|
25
|
+
cipher.iv = iv
|
26
|
+
encrypted = cipher.update(data) + cipher.final
|
27
|
+
encrypted = Base64.strict_encode64(encrypted)
|
28
|
+
end
|
29
|
+
|
30
|
+
def encrypt_file(private_file)
|
31
|
+
return unless key_and_iv_exists? # Don't overwrite encrypted file without key
|
32
|
+
public_file = public_path(private_file)
|
33
|
+
public_yml = encrypt_string File.read(private_file)
|
34
|
+
return unless check_overwrite(public_file, private_file, public_yml)
|
35
|
+
File.open(public_file, 'w') { |f| f.write public_yml }
|
36
|
+
end
|
37
|
+
|
38
|
+
def encrypt_files!
|
39
|
+
find_private_yml_files.each do |yml_file|
|
40
|
+
encrypt_file yml_file
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def decrypt_file(public_file)
|
45
|
+
private_file = private_path(public_file)
|
46
|
+
private_yml = decrypt_string File.read(public_file)
|
47
|
+
return unless check_overwrite(private_file, public_file, private_yml)
|
48
|
+
File.open(private_file, 'w') { |f| f.write private_yml }
|
49
|
+
end
|
50
|
+
|
51
|
+
def decrypt_files!
|
52
|
+
find_public_yml_files.each do |yml_file|
|
53
|
+
decrypt_file yml_file
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def private_path(path)
|
58
|
+
path.gsub(/^#{root}/, "#{private_root}").gsub(/.pub$/, "")
|
59
|
+
end
|
60
|
+
|
61
|
+
def public_path(path)
|
62
|
+
path.gsub(/^#{private_root}/, root) + '.pub'
|
63
|
+
end
|
64
|
+
|
65
|
+
def check_overwrite(dest, source, content)
|
66
|
+
unless File.exists?(dest)
|
67
|
+
STDERR.puts "WARNING: creating #{dest} with contents of #{source}"
|
68
|
+
FileUtils.mkpath File.dirname(dest)
|
69
|
+
return true
|
70
|
+
end
|
71
|
+
return false if File.read(dest) == content
|
72
|
+
if File.mtime(source) > File.mtime(dest)
|
73
|
+
STDERR.puts "WARNING: overwriting #{dest} with contents of #{source}"
|
74
|
+
true
|
75
|
+
else
|
76
|
+
false
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
def key_and_iv_exists?
|
81
|
+
File.exists?(key_path) && File.exists?(iv_path)
|
82
|
+
end
|
83
|
+
|
84
|
+
def key_path
|
85
|
+
ENV["YETTINGS_KEY"] || "#{root}/.key"
|
86
|
+
end
|
87
|
+
|
88
|
+
def iv_path
|
89
|
+
ENV["YETTINGS_IV"] || "#{root}/.iv"
|
90
|
+
end
|
91
|
+
|
92
|
+
def key
|
93
|
+
file = File.open(key_path, "rb")
|
94
|
+
b64_key = file.read
|
95
|
+
file.close
|
96
|
+
key = Base64.strict_decode64(b64_key)
|
97
|
+
end
|
98
|
+
|
99
|
+
def iv
|
100
|
+
file = File.open(iv_path, "rb")
|
101
|
+
b64_iv = file.read
|
102
|
+
file.close
|
103
|
+
iv = Base64.strict_decode64(b64_iv)
|
104
|
+
end
|
105
|
+
|
106
|
+
def gen_keys
|
107
|
+
cipher = OpenSSL::Cipher::AES.new(256, :CBC)
|
108
|
+
key = cipher.random_key
|
109
|
+
b64_key = Base64.strict_encode64(key)
|
110
|
+
iv = cipher.random_iv
|
111
|
+
b64_iv = Base64.strict_encode64(iv)
|
112
|
+
|
113
|
+
private_path = "#{root}/.private"
|
114
|
+
FileUtils.mkpath private_path
|
115
|
+
|
116
|
+
key_file = "#{root}/.key"
|
117
|
+
File.open(key_file, 'w') { |f| f.write b64_key }
|
118
|
+
|
119
|
+
iv_file = "#{root}/.iv"
|
120
|
+
File.open(iv_file, 'w') { |f| f.write b64_iv }
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|