bcdatabase 1.0.6 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.markdown +31 -12
- data/README.markdown +120 -25
- data/bcdatabase.gemspec +30 -0
- data/bin/bcdatabase +15 -21
- data/lib/bcdatabase/cli.rb +81 -0
- data/lib/bcdatabase/commands/encrypt.rb +47 -0
- data/lib/bcdatabase/commands/epass.rb +40 -0
- data/lib/bcdatabase/commands/gen_key.rb +48 -0
- data/lib/bcdatabase/commands.rb +7 -233
- data/lib/bcdatabase/version.rb +1 -1
- data/lib/bcdatabase.rb +108 -23
- metadata +81 -12
data/CHANGELOG.markdown
CHANGED
@@ -1,55 +1,74 @@
|
|
1
|
+
Bcdatabase history
|
2
|
+
==================
|
3
|
+
|
4
|
+
1.1.0
|
5
|
+
-----
|
6
|
+
|
7
|
+
- Introduce "transforms" -- a way to attach behavior to modify entries
|
8
|
+
on load. See {Bcdatabase.load} for details.
|
9
|
+
- Add `:datamapper` built-in transform to support sharing one set of
|
10
|
+
entries between ActiveRecord and DataMapper. (#10)
|
11
|
+
- Rework command-line interface for better testability. It's now
|
12
|
+
compatible with MRI 1.9. (#11, #7)
|
13
|
+
- Provide a better message when working with encrypted passwords and
|
14
|
+
the keyfile is not readable. (#1)
|
15
|
+
- Improve `bcdatabase encrypt` so that it will work with a wider
|
16
|
+
variety of input passwords and YAML files. The remaining limitations
|
17
|
+
are documented in its online help. (#12)
|
18
|
+
- Interpret empty stanzas as entries made up entirely of defaults. (#13)
|
19
|
+
|
1
20
|
1.0.6
|
2
|
-
|
21
|
+
-----
|
3
22
|
- Use `ENV['RAILS_ENV']` instead of the unreliable `RAILS_ENV` constant.
|
4
23
|
|
5
24
|
1.0.5
|
6
|
-
|
25
|
+
-----
|
7
26
|
- Loosen highline dependency so that bcdatabase can be used in buildr buildfiles.
|
8
27
|
|
9
28
|
1.0.4
|
10
|
-
|
29
|
+
-----
|
11
30
|
- Fix command line utilities that were broken in 1.0.3 due to
|
12
31
|
inadequate test coverage. (GH-4)
|
13
32
|
|
14
33
|
1.0.3
|
15
|
-
|
34
|
+
-----
|
16
35
|
- Support ActiveSupport 3. ActiveSupport 2 continues to work.
|
17
36
|
|
18
37
|
1.0.2
|
19
|
-
|
38
|
+
-----
|
20
39
|
- Tighten up gemspec gem deps. Bcdatabase does not currently work
|
21
40
|
with ActiveSupport 3.
|
22
41
|
|
23
42
|
1.0.1
|
24
|
-
|
43
|
+
-----
|
25
44
|
- Update some old syntax for ruby 1.9 compatibility (David Yip)
|
26
45
|
|
27
46
|
1.0.0
|
28
|
-
|
47
|
+
-----
|
29
48
|
- Split out from NUBIC internal `bcdatabase` project.
|
30
49
|
(Changelog entries below reflect the relevant changes & version numbers from that project.)
|
31
50
|
|
32
51
|
0.4.1
|
33
|
-
|
52
|
+
-----
|
34
53
|
- Fix `bcdatabase encrypt` so that it doesn't re-encrypt already encrypted
|
35
54
|
epassword entries.
|
36
55
|
|
37
56
|
0.4.0
|
38
|
-
|
57
|
+
-----
|
39
58
|
- Use the YAML entry name as the "database" value if no other value is
|
40
59
|
provided. This is to DRY up PostgreSQL configurations where the username
|
41
60
|
(already defaulted) and the database name are the same.
|
42
61
|
|
43
62
|
0.2.0
|
44
|
-
|
63
|
+
-----
|
45
64
|
- Change default encrypted secret password location
|
46
65
|
|
47
66
|
0.1.0
|
48
|
-
|
67
|
+
-----
|
49
68
|
- Support encrypted passwords
|
50
69
|
- Command-line utility (also called bcdatabase) for creating encrypted passwords
|
51
70
|
- Gem distribution
|
52
71
|
|
53
72
|
0.0.0
|
54
|
-
|
73
|
+
-----
|
55
74
|
Original release.
|
data/README.markdown
CHANGED
@@ -1,7 +1,14 @@
|
|
1
|
-
|
1
|
+
Bcdatabase
|
2
2
|
==========
|
3
3
|
|
4
|
-
*
|
4
|
+
*Bcdatabase* is a library and utility which provides database
|
5
|
+
configuration parameter management for Ruby on Rails applications. It
|
6
|
+
provides a simple mechanism for separating database configuration
|
7
|
+
attributes from application source code so that there's no temptation
|
8
|
+
to check passwords into the version control system. And it
|
9
|
+
centralizes the parameters for a single server so that they can be
|
10
|
+
easily shared among multiple applications and easily updated by a
|
11
|
+
single administrator.
|
5
12
|
|
6
13
|
## Installing bcdatabase
|
7
14
|
|
@@ -9,7 +16,7 @@ bcdatabase
|
|
9
16
|
|
10
17
|
## Using bcdatabase to configure the database for a Rails application
|
11
18
|
|
12
|
-
A bog-standard
|
19
|
+
A bog-standard Rails application's `config/database.yml` file looks like this:
|
13
20
|
|
14
21
|
development:
|
15
22
|
adapter: oracle_enhanced
|
@@ -29,7 +36,10 @@ A bog-standard rails application's `config/database.yml` file looks like this:
|
|
29
36
|
username: cfg_animal
|
30
37
|
password: very-secret
|
31
38
|
|
32
|
-
Rails allows this file to contain [ERB][]. `bcdatabase` uses ERB to
|
39
|
+
Rails allows this file to contain [ERB][]. `bcdatabase` uses ERB to
|
40
|
+
replace an entire configuration block. If you wanted to replace, say,
|
41
|
+
just the production block in this example, you would transform it like
|
42
|
+
so:
|
33
43
|
|
34
44
|
<%
|
35
45
|
require 'bcdatabase'
|
@@ -50,7 +60,9 @@ Rails allows this file to contain [ERB][]. `bcdatabase` uses ERB to replace an
|
|
50
60
|
|
51
61
|
<%= bcdb.production :prod, :cfg_animal %>
|
52
62
|
|
53
|
-
This means "create a YAML block for the *production* environment from
|
63
|
+
This means "create a YAML block for the *production* environment from
|
64
|
+
the configuration entry named *cfg_animal* in
|
65
|
+
/etc/nubic/db/*prod*.yml." The method called can be anything:
|
54
66
|
|
55
67
|
<%= bcdb.development :local, :cfg_animal %>
|
56
68
|
<%= bcdb.staging 'stage', 'cfg_animal' %>
|
@@ -60,21 +72,33 @@ This means "create a YAML block for the *production* environment from the config
|
|
60
72
|
|
61
73
|
## Directly accessing configuration parameters from bcdatabase
|
62
74
|
|
63
|
-
More rarely, you might need to access the actual configuration hash,
|
75
|
+
More rarely, you might need to access the actual configuration hash,
|
76
|
+
instead of the YAMLized version. You can access it by invoking
|
77
|
+
`Bcdatabase.load` as shown earlier, then using the bracket operator to
|
78
|
+
specify the configuration you want:
|
64
79
|
|
65
80
|
bcdb[:local, :cfg_animal]
|
66
81
|
|
67
|
-
The resulting hash is suitable for passing to
|
82
|
+
The resulting hash is suitable for passing to
|
83
|
+
`ActiveRecord::Base.establish_connection`, for instance.
|
68
84
|
|
69
85
|
## Central configuration files
|
70
86
|
|
71
|
-
The database configuration properties for all the applications on a
|
87
|
+
The database configuration properties for all the applications on a
|
88
|
+
server are stored in one or more files under `/etc/nubic/db` (by
|
89
|
+
default; see "File locations" below). Each one is a standard YAML
|
90
|
+
file, similar to Rails' `database.yml` but with a few enhancements:
|
72
91
|
|
73
|
-
* Each file can have a defaults entry which provides attributes which
|
74
|
-
|
75
|
-
* Each entry defaults its "
|
92
|
+
* Each file can have a defaults entry which provides attributes which
|
93
|
+
are shared across all configurations in the file
|
94
|
+
* Each entry defaults its "username" attribute to the name of the
|
95
|
+
entry (useful for Oracle)
|
96
|
+
* Each entry defaults its "database" attribute to the name of the
|
97
|
+
entry (useful for PostgreSQL)
|
76
98
|
|
77
|
-
Since each file can define a set of default properties which are
|
99
|
+
Since each file can define a set of default properties which are
|
100
|
+
shared by all the contained configurations, it makes sense to group
|
101
|
+
databases which have some shared configuration elements.
|
78
102
|
|
79
103
|
### Example
|
80
104
|
|
@@ -96,7 +120,7 @@ You have defined two configuration entries. `:stage, :cfg_animal`:
|
|
96
120
|
password: secret
|
97
121
|
database: //mondo/stage
|
98
122
|
|
99
|
-
and `:
|
123
|
+
and `:stage, :personnel`:
|
100
124
|
|
101
125
|
adapter: oracle_enhanced
|
102
126
|
username: pers
|
@@ -105,33 +129,104 @@ and `:bcstage, :personnel`:
|
|
105
129
|
|
106
130
|
## Obscuring passwords
|
107
131
|
|
108
|
-
|
132
|
+
Bcdatabase supports storing encrypted passwords instead of the
|
133
|
+
plaintext ones shown in the previous example. Encrypted passwords are
|
134
|
+
defined with the key `epassword` instead of `password`. The library
|
135
|
+
will decrypt the `epassword` value and expose it to the calling code
|
136
|
+
(usually Rails) unencrypted under the `password` key. The
|
137
|
+
`bcdatabase` command line utility handles encrypting passwords; see
|
138
|
+
the next section.
|
109
139
|
|
110
|
-
While the passwords are technically encrypted, the master key must be
|
140
|
+
While the passwords are technically encrypted, the master key must be
|
141
|
+
stored on the same machine so that they can be decrypted on demand.
|
142
|
+
That means this feature only obscures passwords — it will not
|
143
|
+
deter a determined attacker.
|
111
144
|
|
112
145
|
## `bcdatabase` command line utility
|
113
146
|
|
114
|
-
The gem includes a command line utility (also called `bcdatabase`)
|
147
|
+
The gem includes a command line utility (also called `bcdatabase`)
|
148
|
+
which assists with creating `epassword` entries. It has online help;
|
149
|
+
after installing the gem, try `bcdatabase help` to read it:
|
115
150
|
|
116
151
|
$ bcdatabase help
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
help List commands or display help for one
|
152
|
+
Tasks:
|
153
|
+
bcdatabase encrypt [INPUT [OUTPUT]] # Encrypt every password in a bcdatabase YAML file
|
154
|
+
bcdatabase epass [-] # Generate epasswords from database passwords
|
155
|
+
bcdatabase gen-key [-] # Generate the bcdatabase shared key
|
156
|
+
bcdatabase help [TASK] # Describe available tasks or one specific task
|
123
157
|
|
124
158
|
## File locations
|
125
159
|
|
126
|
-
`/etc/nubic/db` is the default place the library will look for the
|
160
|
+
`/etc/nubic/db` is the default place the library will look for the
|
161
|
+
central configuration files. It may be overridden with the
|
162
|
+
environment variable `BCDATABASE_PATH`. For instance, if you wanted
|
163
|
+
to keep these files in your home directory on your development machine
|
164
|
+
— perhaps so that editing them doesn't require elevated
|
165
|
+
privileges — you could add this to `~/.bashrc`:
|
127
166
|
|
128
167
|
export BCDATABASE_PATH=${HOME}/nubic/db
|
129
168
|
|
130
|
-
Similarly, the file containing the encryption password has a sensible
|
169
|
+
Similarly, the file containing the encryption password has a sensible
|
170
|
+
default location, but that location can be overridden by setting
|
171
|
+
`BCDATABASE_PASS`.
|
172
|
+
|
173
|
+
## DataMapper
|
174
|
+
|
175
|
+
Bcdatabase was originally designed for use with ActiveRecord in Rails
|
176
|
+
applications. Since [DataMapper][dm]'s programmatic configuration mechanism
|
177
|
+
(`Datamapper.setup`) accepts hashes which are very similar to
|
178
|
+
ActiveRecord configuration hashes, Bcdatabase can easily be used with
|
179
|
+
DataMapper as well. Example:
|
180
|
+
|
181
|
+
bcdb = Bcdatabase.load(:transforms => [:datamapper]))
|
182
|
+
DataMapper.setup(:default, bcdb[:stage, :personnel])
|
183
|
+
|
184
|
+
The `:datamapper` transform passed to `Bcdatabase.load` in this
|
185
|
+
example permits sharing of one set of Bcdatabase configurations
|
186
|
+
between ActiveRecord and DataMapper-based apps. Specifically, for
|
187
|
+
those cases where the ActiveRecord adapter and the DataMapper adapter
|
188
|
+
have different names, it allows you to specify a separate
|
189
|
+
`datamapper_adapter` in your Bcdatabase configuration. For example,
|
190
|
+
say you had these contents in `stage.yml`:
|
191
|
+
|
192
|
+
defaults:
|
193
|
+
adapter: postgresql
|
194
|
+
datamapper_adapter: postgres
|
195
|
+
personnel:
|
196
|
+
password: foo
|
197
|
+
|
198
|
+
When loaded without the `:datamapper` transform, the effective
|
199
|
+
database configuration hash for `:stage, :personnel` would be
|
200
|
+
|
201
|
+
adapter: postgresql
|
202
|
+
datamapper_adapter: postgres # ignored by AR
|
203
|
+
database: personnel
|
204
|
+
username: personnel
|
205
|
+
|
206
|
+
With the `:datamapper` transform, the result would be instead:
|
207
|
+
|
208
|
+
adapter: postgres
|
209
|
+
database: personnel
|
210
|
+
username: personnel
|
211
|
+
|
212
|
+
And so your DM and AR apps can live side-by-side and neither needs to
|
213
|
+
embed its own database credentials.
|
214
|
+
|
215
|
+
[dm]: http://datamapper.org/
|
216
|
+
|
217
|
+
## Platforms
|
218
|
+
|
219
|
+
Bcdatabase works on MRI 1.8.7 and MRI 1.9.2. It will also work on
|
220
|
+
JRuby (tested on 1.6+), provided that `jruby-openssl` is also
|
221
|
+
installed. It is [continuously tested][ci] on all three of these
|
222
|
+
platforms.
|
223
|
+
|
224
|
+
[ci]: https://public-ci.nubic.northwestern.edu/job/bcdatabase/
|
131
225
|
|
132
226
|
## Credits
|
133
227
|
|
134
|
-
`bcdatabase` was developed at and for the [Northwestern University
|
228
|
+
`bcdatabase` was developed at and for the [Northwestern University
|
229
|
+
Biomedical Informatics Center][NUBIC].
|
135
230
|
|
136
231
|
[NUBIC]: http://www.nucats.northwestern.edu/centers/nubic/index.html
|
137
232
|
|
data/bcdatabase.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
lib = File.expand_path('../lib/', __FILE__)
|
2
|
+
$:.unshift lib unless $:.include?(lib)
|
3
|
+
|
4
|
+
require 'bcdatabase/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'bcdatabase'
|
8
|
+
s.version = Bcdatabase::VERSION
|
9
|
+
s.summary = %Q{Server-central database configuration for rails and other ruby apps}
|
10
|
+
s.description = %Q{bcdatabase is a tool for storing passwords and other configuration information outside of your application source tree.}
|
11
|
+
s.email = "rhett@detailedbalance.net"
|
12
|
+
s.homepage = "http://github.com/NUBIC/bcdatabase"
|
13
|
+
s.authors = ["Rhett Sutphin"]
|
14
|
+
|
15
|
+
s.require_paths = ["lib"]
|
16
|
+
|
17
|
+
s.executables = ['bcdatabase']
|
18
|
+
s.files = Dir.glob("{CHANGELOG.markdown,LICENSE,README.markdown,bcdatabase.gemspec,{bin,lib}/**/*}")
|
19
|
+
|
20
|
+
s.add_dependency "activesupport", ">= 2.0"
|
21
|
+
s.add_dependency "highline", "~> 1.5"
|
22
|
+
s.add_dependency "i18n"
|
23
|
+
s.add_dependency 'thor', '~> 0.14.6'
|
24
|
+
|
25
|
+
s.add_development_dependency 'bundler', '~> 1.0.15'
|
26
|
+
s.add_development_dependency 'rake', '~> 0.9.2'
|
27
|
+
s.add_development_dependency 'rspec','~> 2.6'
|
28
|
+
s.add_development_dependency "ci_reporter", "~> 1.6"
|
29
|
+
s.add_development_dependency 'yard', '~> 0.7.2'
|
30
|
+
end
|
data/bin/bcdatabase
CHANGED
@@ -1,26 +1,20 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
1
|
+
#!/usr/bin/env ruby
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
# Allow this executable to be run directly from the source as well as
|
4
|
+
# from an installed gem.
|
5
|
+
begin
|
6
|
+
lib = File.expand_path('../../lib', __FILE__)
|
7
|
+
unless $LOAD_PATH.include?(lib)
|
8
|
+
$LOAD_PATH << lib
|
9
|
+
require 'rubygems'
|
10
|
+
end
|
8
11
|
end
|
9
12
|
|
10
|
-
|
11
|
-
|
12
|
-
command = ARGV.shift
|
13
|
-
unless command
|
14
|
-
$stderr.puts "Please specify a command."
|
15
|
-
$stderr.puts Bcdatabase::Commands.help
|
16
|
-
exit(1)
|
17
|
-
end
|
13
|
+
require 'bcdatabase'
|
18
14
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
$stderr.puts
|
23
|
-
exit
|
15
|
+
begin
|
16
|
+
Bcdatabase::CLI.start
|
17
|
+
rescue Interrupt => e
|
18
|
+
$stderr.puts "Interrupted"
|
19
|
+
exit 1
|
24
20
|
end
|
25
|
-
|
26
|
-
exit(klass.new(ARGV).main)
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'bcdatabase'
|
2
|
+
require 'thor'
|
3
|
+
|
4
|
+
module Bcdatabase
|
5
|
+
class CLI < Thor
|
6
|
+
desc "encrypt [INPUT [OUTPUT]]",
|
7
|
+
"Encrypt every password in a bcdatabase YAML file"
|
8
|
+
long_desc <<-DESC
|
9
|
+
This command finds all the keys named 'password' in the input
|
10
|
+
YAML and substitutes appropriate 'epassword' keys.
|
11
|
+
|
12
|
+
If inputfile is specified, the source will be that file. If not,
|
13
|
+
the source will be standard in.
|
14
|
+
|
15
|
+
If inputfile and outputfile are specified, the new file will be
|
16
|
+
written to the output file. Otherwise the output will go to
|
17
|
+
standard out. Input and output may be the same file.
|
18
|
+
|
19
|
+
You can't read from standard in and write to a file directly;
|
20
|
+
use shell file redirection if you need to do that.
|
21
|
+
|
22
|
+
N.b.: this command works with a subset of legal YAML
|
23
|
+
files. Specifically, it will only work if the 'password' key and
|
24
|
+
value are entirely on the same line. If for some reason you
|
25
|
+
can't arrange for your input files to meet this restriction, you
|
26
|
+
can use the epass subcommand to encrypt one password at a time.
|
27
|
+
DESC
|
28
|
+
def encrypt(inputfile=nil, outputfile=nil)
|
29
|
+
Commands::Encrypt.new(inputfile, outputfile).run
|
30
|
+
end
|
31
|
+
|
32
|
+
desc 'epass [-]', 'Generate epasswords from database passwords'
|
33
|
+
long_desc <<-DESC
|
34
|
+
With no arguments, interactively prompts for passwords and
|
35
|
+
prints the corresponding epassword entry.
|
36
|
+
|
37
|
+
If the last argument is -, reads a newline-separated list of
|
38
|
+
passwords from standard in and prints the corresponding
|
39
|
+
epasswords to standard out.
|
40
|
+
DESC
|
41
|
+
def epass(arg=nil)
|
42
|
+
Commands::Epass.new(arg == '-').run
|
43
|
+
end
|
44
|
+
|
45
|
+
desc 'gen-key [-]', 'Generate the bcdatabase shared key'
|
46
|
+
long_desc <<-DESC
|
47
|
+
Generates the key that is used to obscure epasswords. By
|
48
|
+
default, the key will be generated in
|
49
|
+
#{Bcdatabase.pass_file}. If the last argument to this command
|
50
|
+
is -, the key will be generated to standard out instead.
|
51
|
+
|
52
|
+
CAUTION: writing to #{Bcdatabase.pass_file} may overwrite an
|
53
|
+
existing bcdatabase key. If that happens, you will need to
|
54
|
+
reencrypt all the epasswords on this machine.
|
55
|
+
DESC
|
56
|
+
def gen_key(arg=nil)
|
57
|
+
Commands::GenKey.new(arg == '-').run
|
58
|
+
end
|
59
|
+
|
60
|
+
no_tasks do
|
61
|
+
# Add uniform exception handling
|
62
|
+
[:encrypt, :epass, :gen_key].each do |original|
|
63
|
+
alias_method "#{original}_without_rescue".to_sym, original
|
64
|
+
|
65
|
+
class_eval <<-RUBY
|
66
|
+
def #{original}(*args)
|
67
|
+
#{original}_without_rescue(*args)
|
68
|
+
rescue SystemCallError => e
|
69
|
+
shell.say("\#{e.class}: \#{e}", :RED)
|
70
|
+
exit(8)
|
71
|
+
rescue Bcdatabase::Error => e
|
72
|
+
shell.say(e.message, :RED)
|
73
|
+
exit(4)
|
74
|
+
rescue Commands::ForcedExit => e
|
75
|
+
exit(e.code)
|
76
|
+
end
|
77
|
+
RUBY
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'bcdatabase/commands'
|
2
|
+
|
3
|
+
module Bcdatabase::Commands
|
4
|
+
class Encrypt
|
5
|
+
def initialize(inputfile=nil, outputfile=nil)
|
6
|
+
@input = (Pathname.new(inputfile) if inputfile)
|
7
|
+
@output = (Pathname.new(outputfile) if outputfile)
|
8
|
+
end
|
9
|
+
|
10
|
+
def run
|
11
|
+
begin
|
12
|
+
# try to preserve the order by replacing everything using regexes
|
13
|
+
contents = inio.read
|
14
|
+
contents.gsub!(/\bpassword:.*?$/) { |line|
|
15
|
+
"epassword: #{Bcdatabase.encrypt(YAML.load(line)['password'])}"
|
16
|
+
}
|
17
|
+
outio.write(contents)
|
18
|
+
ensure
|
19
|
+
@inio.close if @close_in && @inio
|
20
|
+
@outio.close if @close_out && @outio
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def inio
|
27
|
+
@inio ||=
|
28
|
+
if @input
|
29
|
+
@close_in = true
|
30
|
+
@input.open('r')
|
31
|
+
else
|
32
|
+
$stdin
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def outio
|
37
|
+
@outio ||=
|
38
|
+
if @output
|
39
|
+
@output.dirname.mkpath
|
40
|
+
@close_out = true
|
41
|
+
@output.open('w')
|
42
|
+
else
|
43
|
+
$stdout
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'bcdatabase/commands'
|
2
|
+
|
3
|
+
require 'highline'
|
4
|
+
|
5
|
+
module Bcdatabase::Commands
|
6
|
+
class Epass
|
7
|
+
def initialize(streaming, opts={})
|
8
|
+
@streaming = streaming
|
9
|
+
@echo = opts[:echo].nil? ? false : opts[:echo]
|
10
|
+
@hl = HighLine.new($stdin, $stderr)
|
11
|
+
end
|
12
|
+
|
13
|
+
def run
|
14
|
+
@streaming ? streamed : interactive
|
15
|
+
end
|
16
|
+
|
17
|
+
protected
|
18
|
+
|
19
|
+
def streamed
|
20
|
+
$stdin.readlines.each do |line|
|
21
|
+
puts Bcdatabase.encrypt(line.chomp)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
def interactive
|
26
|
+
loop do
|
27
|
+
pass = @hl.ask("Password (^C to end): ") do |q|
|
28
|
+
# this is configurable because having it false hangs the
|
29
|
+
# unit tests.
|
30
|
+
q.echo = @echo
|
31
|
+
end
|
32
|
+
puts " epassword: #{Bcdatabase.encrypt(pass)}"
|
33
|
+
end
|
34
|
+
rescue Interrupt
|
35
|
+
$stderr.puts "Quit"
|
36
|
+
rescue EOFError
|
37
|
+
$stderr.puts "Quit"
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'bcdatabase/commands'
|
2
|
+
require 'highline'
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
module Bcdatabase::Commands
|
6
|
+
class GenKey
|
7
|
+
def initialize(streaming)
|
8
|
+
@streaming = streaming
|
9
|
+
@hl = HighLine.new($stdin, $stderr)
|
10
|
+
end
|
11
|
+
|
12
|
+
def run
|
13
|
+
begin
|
14
|
+
key = random_key(128)
|
15
|
+
outio.write key
|
16
|
+
ensure
|
17
|
+
@outio.close if @close_out && @outio
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def random_key(length)
|
24
|
+
(1..length).collect { rand(255) }.pack('C*')
|
25
|
+
end
|
26
|
+
|
27
|
+
def outio
|
28
|
+
@outio ||=
|
29
|
+
if @streaming
|
30
|
+
$stdout
|
31
|
+
else
|
32
|
+
open_key_file
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def open_key_file
|
37
|
+
filename = Pathname.new(Bcdatabase.pass_file)
|
38
|
+
if filename.exist?
|
39
|
+
unless @hl.agree("This operation will overwrite the existing pass file.\n Are you sure you want to do that? (y/n) ")
|
40
|
+
raise ForcedExit.new(1)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
@close_out = true
|
44
|
+
filename.dirname.mkpath
|
45
|
+
filename.open('w')
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/bcdatabase/commands.rb
CHANGED
@@ -1,241 +1,15 @@
|
|
1
|
-
require 'rubygems'
|
2
|
-
require 'fileutils'
|
3
|
-
require 'highline'
|
4
|
-
require 'active_support'
|
5
|
-
require 'active_support/core_ext/string/inflections'
|
6
1
|
require 'bcdatabase'
|
7
2
|
|
8
|
-
HL = HighLine.new
|
9
|
-
|
10
3
|
module Bcdatabase::Commands
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
def self.usage(use)
|
15
|
-
"usage: #{UTILITY_NAME} #{use}"
|
16
|
-
end
|
17
|
-
|
18
|
-
def self.help_message(use)
|
19
|
-
msg = [ "#{command_name}: #{summary}", usage(use), "" ]
|
20
|
-
yield msg if block_given?
|
21
|
-
msg.join("\n")
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
class Epass < Base
|
26
|
-
def initialize(argv)
|
27
|
-
@streaming = argv[-1] == '-'
|
28
|
-
end
|
29
|
-
|
30
|
-
def self.summary
|
31
|
-
"Generate epasswords from individual database passwords"
|
32
|
-
end
|
33
|
-
|
34
|
-
def self.help
|
35
|
-
help_message("epass [-]") do |msg|
|
36
|
-
msg << "With no arguments, interactively prompts for passwords and"
|
37
|
-
msg << " prints the corresponding epassword entry."
|
38
|
-
msg << ""
|
39
|
-
msg << "If the last argument is -, reads a newline-separated list"
|
40
|
-
msg << " of passwords from standard in and prints the corresponding "
|
41
|
-
msg << " epasswords to standard out."
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def main
|
46
|
-
@streaming ? streamed : interactive
|
47
|
-
end
|
48
|
-
|
49
|
-
private
|
50
|
-
|
51
|
-
def streamed
|
52
|
-
$stdin.readlines.each do |line|
|
53
|
-
puts Bcdatabase.encrypt(line.chomp)
|
54
|
-
end
|
55
|
-
0
|
56
|
-
end
|
57
|
-
|
58
|
-
def interactive
|
59
|
-
begin
|
60
|
-
loop do
|
61
|
-
pass = HL.ask("Password (^C to end): ") do |q|
|
62
|
-
q.echo = false
|
63
|
-
end
|
64
|
-
puts " epassword: #{Bcdatabase.encrypt(pass)}"
|
65
|
-
end
|
66
|
-
rescue Interrupt
|
67
|
-
puts "\nQuit"
|
68
|
-
end
|
69
|
-
0
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
class Encrypt < Base
|
74
|
-
def initialize(argv)
|
75
|
-
@input = argv.shift
|
76
|
-
@output = argv.shift
|
77
|
-
end
|
78
|
-
|
79
|
-
def self.summary
|
80
|
-
"Encrypts all the password entries in a bcdatabase YAML file"
|
81
|
-
end
|
82
|
-
|
83
|
-
def self.help
|
84
|
-
help_message("encrypt [inputfile [outputfile]]") do |msg|
|
85
|
-
msg << "Specifically, this command finds all the keys named 'password'"
|
86
|
-
msg << " in the input YAML and substitutes appropriate 'epassword'"
|
87
|
-
msg << " keys."
|
88
|
-
msg << ""
|
89
|
-
msg << "If inputfile is specified, the source will be that file."
|
90
|
-
msg << " If not, the source will be standard in."
|
91
|
-
msg << ""
|
92
|
-
msg << "If inputfile and outputfile are specified, the new file"
|
93
|
-
msg << " will be written to the output file. Otherwise the output"
|
94
|
-
msg << " will go to standard out. Input and output may be the same"
|
95
|
-
msg << " file."
|
96
|
-
msg << ""
|
97
|
-
msg << "You can't read from standard in and write to a file directly; "
|
98
|
-
msg << " use shell file redirection if you need to do that."
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
def main
|
103
|
-
inio =
|
104
|
-
if @input
|
105
|
-
open(@input, "r")
|
106
|
-
else
|
107
|
-
$stdin
|
108
|
-
end
|
109
|
-
# try to preserve the order by replacing everything using regexes
|
110
|
-
contents = inio.read
|
111
|
-
contents.gsub!(/\bpassword:(\s*)(\S+)\s*?$/) { "epassword:#{$1}#{Bcdatabase.encrypt($2)}" }
|
112
|
-
outio =
|
113
|
-
if @output
|
114
|
-
open(@output, "w")
|
115
|
-
else
|
116
|
-
$stdout
|
117
|
-
end
|
118
|
-
outio.write(contents)
|
119
|
-
outio.close
|
120
|
-
0
|
121
|
-
end
|
122
|
-
end
|
123
|
-
|
124
|
-
class Help < Base
|
125
|
-
def initialize(argv)
|
126
|
-
@cmd = argv.shift
|
127
|
-
end
|
128
|
-
|
129
|
-
def self.summary
|
130
|
-
"List commands or display help for one; e.g. #{UTILITY_NAME} help epass"
|
131
|
-
end
|
132
|
-
|
133
|
-
def self.help
|
134
|
-
help_message "help [command name]"
|
135
|
-
end
|
136
|
-
|
137
|
-
def main
|
138
|
-
if @cmd
|
139
|
-
klass = Bcdatabase::Commands[@cmd]
|
140
|
-
if klass
|
141
|
-
msg = klass.respond_to?(:help) ? klass.help : klass.summary
|
142
|
-
$stderr.puts msg
|
143
|
-
else
|
144
|
-
$stderr.puts "Unknown command #{@cmd}"
|
145
|
-
return 1
|
146
|
-
end
|
147
|
-
else
|
148
|
-
$stderr.puts Bcdatabase::Commands.help
|
149
|
-
end
|
150
|
-
0
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
class GenKey < Base
|
155
|
-
def initialize(argv)
|
156
|
-
@stream = argv[-1] == '-'
|
157
|
-
end
|
158
|
-
|
159
|
-
def self.summary
|
160
|
-
"Generate a key for bcdatabase to use"
|
161
|
-
end
|
4
|
+
autoload :Encrypt, 'bcdatabase/commands/encrypt'
|
5
|
+
autoload :Epass, 'bcdatabase/commands/epass'
|
6
|
+
autoload :GenKey, 'bcdatabase/commands/gen_key'
|
162
7
|
|
163
|
-
|
164
|
-
|
165
|
-
msg << "By default, the key will be generated in "
|
166
|
-
msg << " #{Bcdatabase.pass_file}. If the last argument to this"
|
167
|
-
msg << " command is -, the key will be generated to standard out"
|
168
|
-
msg << " instead."
|
169
|
-
msg << ""
|
170
|
-
msg << "CAUTION: writing to #{Bcdatabase.pass_file} may overwrite"
|
171
|
-
msg << " an existing bcdatabase key. If that happens, you will"
|
172
|
-
msg << " need to reencrypt all the epasswords on this machine."
|
173
|
-
end
|
174
|
-
end
|
175
|
-
|
176
|
-
def main
|
177
|
-
key = random_key(128)
|
178
|
-
outio =
|
179
|
-
if @stream
|
180
|
-
$stdout
|
181
|
-
else
|
182
|
-
file = Bcdatabase.pass_file
|
183
|
-
if File.exist?(file)
|
184
|
-
sure = HL.ask("This operation will overwrite the existing pass file.\n Are you sure you want to do that? ", %w{yes no}) do |q|
|
185
|
-
q.case = :down
|
186
|
-
end
|
187
|
-
unless sure == 'yes'
|
188
|
-
exit(0)
|
189
|
-
end
|
190
|
-
end
|
191
|
-
open(file, "w")
|
192
|
-
end
|
193
|
-
outio.write key
|
194
|
-
outio.close
|
195
|
-
0
|
196
|
-
end
|
197
|
-
|
198
|
-
private
|
199
|
-
|
200
|
-
def random_key(length)
|
201
|
-
k = ""
|
202
|
-
# This is probably not going to work in ruby 1.9
|
203
|
-
until k.size == length; k << rand(126 - 32) + 32; end
|
204
|
-
k
|
205
|
-
end
|
206
|
-
end
|
8
|
+
class ForcedExit < StandardError
|
9
|
+
attr_reader :code
|
207
10
|
|
208
|
-
|
209
|
-
|
210
|
-
all_help = commands.collect { |c| [c.command_name, c.summary] }.sort_by { |p| p[0] }
|
211
|
-
max_name_length = all_help.collect { |a| a[0].size }.max
|
212
|
-
msg = Base.usage "<command> [args]\n"
|
213
|
-
msg << "Utility for bcdatabase #{Bcdatabase::VERSION}\n"
|
214
|
-
msg << "Commands:\n"
|
215
|
-
msg << all_help.collect { |name, help| " %#{max_name_length + 1}s %s" % [name, help] }.join("\n")
|
11
|
+
def initialize(code)
|
12
|
+
@code = code
|
216
13
|
end
|
217
|
-
|
218
|
-
# Lists all the commands
|
219
|
-
def commands
|
220
|
-
constants.reject { |cs| cs == "Base" }.collect { |cs| const_get(cs) }.select { |c| c.kind_of? Class }
|
221
|
-
end
|
222
|
-
|
223
|
-
# Locates the command class for a user-entered command name.
|
224
|
-
# Returns nil if the name is invalid.
|
225
|
-
def command(command_name)
|
226
|
-
begin
|
227
|
-
klassname = command_name.gsub('-', '_').camelize
|
228
|
-
Bcdatabase::Commands.const_get "#{klassname}"
|
229
|
-
rescue NameError
|
230
|
-
nil
|
231
|
-
end
|
232
|
-
end
|
233
|
-
alias :[] :command
|
234
|
-
end
|
235
|
-
end
|
236
|
-
|
237
|
-
class Class
|
238
|
-
def command_name
|
239
|
-
name.gsub(Bcdatabase::Commands.name + "::", '').underscore.gsub("_", '-')
|
240
14
|
end
|
241
15
|
end
|
data/lib/bcdatabase/version.rb
CHANGED
data/lib/bcdatabase.rb
CHANGED
@@ -2,9 +2,14 @@ require 'yaml'
|
|
2
2
|
require 'openssl'
|
3
3
|
require 'digest/sha2'
|
4
4
|
require 'base64'
|
5
|
+
require 'pathname'
|
6
|
+
|
7
|
+
# Requiring just extract_options doesn't work on AS 2.3.
|
8
|
+
require 'active_support/core_ext/array'
|
5
9
|
|
6
10
|
module Bcdatabase
|
7
11
|
autoload :VERSION, 'bcdatabase/version'
|
12
|
+
autoload :CLI, 'bcdatabase/cli'
|
8
13
|
autoload :Commands, 'bcdatabase/commands'
|
9
14
|
|
10
15
|
DEFAULT_BASE_PATH = File.join('/', 'etc', 'nubic', 'db')
|
@@ -12,22 +17,51 @@ module Bcdatabase
|
|
12
17
|
CIPHER = 'aes-256-ecb'
|
13
18
|
|
14
19
|
class << self
|
15
|
-
|
16
|
-
|
20
|
+
##
|
21
|
+
# The main entry point for Bcdatabase.
|
22
|
+
#
|
23
|
+
# @overload load(options={})
|
24
|
+
# (See other alternative for option definitions.)
|
25
|
+
# @return [DatabaseConfigurations] a new instance using the
|
26
|
+
# default path.
|
27
|
+
# @overload load(path=nil, options={})
|
28
|
+
# @param [String,nil] path the directory to load from. If nil,
|
29
|
+
# will use the value in the environment variable
|
30
|
+
# `BCDATABASE_PATH`. If that's nil, too, it will use the
|
31
|
+
# default path.
|
32
|
+
# @param [Hash,nil] options additional options affecting the
|
33
|
+
# load behavior.
|
34
|
+
# @option options :transforms [Array<Symbol, #call>] ([]) Custom
|
35
|
+
# transforms. This can either be a symbol naming a
|
36
|
+
# {DatabaseConfigurations.BUILT_IN_TRANSFORMS built-in
|
37
|
+
# transform} or a callable which is the transform itself. A
|
38
|
+
# transform is a function that takes three arguments (the
|
39
|
+
# entry itself, the entry name, and the group name) and
|
40
|
+
# returns a new copy, modified as desired. It may also return
|
41
|
+
# nil to indicate that it doesn't wish to make any changes.
|
42
|
+
# @return [DatabaseConfigurations] a new instance reflecting
|
43
|
+
# the selected path.
|
44
|
+
def load(*args)
|
45
|
+
options = args.extract_options!
|
46
|
+
path ||= (args.first || base_path)
|
17
47
|
files = Dir.glob(File.join(path, "*.yml")) + Dir.glob(File.join(path, "*.yaml"))
|
18
|
-
DatabaseConfigurations.new(files)
|
48
|
+
DatabaseConfigurations.new(files, options[:transforms] || [])
|
19
49
|
end
|
20
50
|
|
51
|
+
##
|
52
|
+
# @private exposed for collaboration
|
21
53
|
def encrypt(s)
|
22
54
|
Base64.encode64(encipher(:encrypt, s)).strip
|
23
55
|
end
|
24
56
|
|
57
|
+
##
|
58
|
+
# @private exposed for collaboration
|
25
59
|
def decrypt(s)
|
26
60
|
encipher(:decrypt, Base64.decode64(s))
|
27
61
|
end
|
28
62
|
|
29
63
|
def pass_file
|
30
|
-
ENV["BCDATABASE_PASS"] || DEFAULT_PASS_FILE
|
64
|
+
Pathname.new(ENV["BCDATABASE_PASS"] || DEFAULT_PASS_FILE)
|
31
65
|
end
|
32
66
|
|
33
67
|
private
|
@@ -43,15 +77,30 @@ module Bcdatabase
|
|
43
77
|
end
|
44
78
|
|
45
79
|
def pass
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
80
|
+
@passes ||= { }
|
81
|
+
@passes[pass_file] ||=
|
82
|
+
begin
|
83
|
+
contents = read_pass_file
|
84
|
+
# This code may not work correctly on Ruby 1.9
|
85
|
+
if contents.size == 32
|
86
|
+
contents
|
87
|
+
else
|
88
|
+
Digest::SHA256.digest(contents)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def read_pass_file
|
94
|
+
unless pass_file.readable?
|
95
|
+
msg = [
|
96
|
+
"Bcdatabase keyfile #{pass_file} is not readable. Possible solutions:",
|
97
|
+
"* Use bcdatabase gen-key to generate a key",
|
98
|
+
"* Change the path by setting BCDATABASE_PASS in the environment",
|
99
|
+
"* Check the permissions on #{pass_file}"
|
100
|
+
].compact.join("\n")
|
101
|
+
raise Bcdatabase::Error, msg
|
54
102
|
end
|
103
|
+
pass_file.read
|
55
104
|
end
|
56
105
|
|
57
106
|
def base_path
|
@@ -59,8 +108,36 @@ module Bcdatabase
|
|
59
108
|
end
|
60
109
|
end
|
61
110
|
|
111
|
+
##
|
112
|
+
# The set of groups and entries returned by one call to {Bcdatabase.load}.
|
62
113
|
class DatabaseConfigurations
|
63
|
-
|
114
|
+
BUILT_IN_TRANSFORMS = {
|
115
|
+
:key_defaults => lambda { |entry, name, group|
|
116
|
+
{ 'username' => name, 'database' => name }.merge(entry)
|
117
|
+
},
|
118
|
+
:decrypt => lambda { |entry, name, group|
|
119
|
+
entry.merge({ 'password' => Bcdatabase.decrypt(entry['epassword']) }) if entry['epassword']
|
120
|
+
},
|
121
|
+
:datamapper => lambda { |entry, name, group|
|
122
|
+
entry.merge('adapter' => entry['datamapper_adapter']) if entry['datamapper_adapter']
|
123
|
+
}
|
124
|
+
}
|
125
|
+
|
126
|
+
##
|
127
|
+
# Creates a configuration from a set of YAML files.
|
128
|
+
#
|
129
|
+
# General use of the library should not use this method, but
|
130
|
+
# instead should use {Bcdatabase.load}.
|
131
|
+
def initialize(files, transforms=[])
|
132
|
+
@transforms = ([:key_defaults, :decrypt] + transforms).collect do |t|
|
133
|
+
case t
|
134
|
+
when Symbol
|
135
|
+
BUILT_IN_TRANSFORMS[t] or fail "No built-in transform named #{t.inspect}"
|
136
|
+
else
|
137
|
+
fail 'Transforms must by callable' unless t.respond_to?(:call)
|
138
|
+
t
|
139
|
+
end
|
140
|
+
end
|
64
141
|
@files = files
|
65
142
|
@map = { }
|
66
143
|
files.each do |filename|
|
@@ -69,10 +146,18 @@ module Bcdatabase
|
|
69
146
|
end
|
70
147
|
end
|
71
148
|
|
149
|
+
##
|
150
|
+
# @return [Hash] the entry for the given group and name after all
|
151
|
+
# transformation is complete.
|
72
152
|
def [](groupname, dbname)
|
73
153
|
create_entry(groupname.to_s, dbname.to_s)
|
74
154
|
end
|
75
155
|
|
156
|
+
##
|
157
|
+
# This method implements the Rails database.yml integration
|
158
|
+
# described in full in the {file:README.markdown}.
|
159
|
+
#
|
160
|
+
# @return [String] a YAMLized view of a configuration entry.
|
76
161
|
def method_missing(name, *args)
|
77
162
|
groupname = (args[0] or raise "Database configuration group not specified for #{name}")
|
78
163
|
dbname = (args[1] or raise "Database entry name not specified for #{name}")
|
@@ -94,16 +179,16 @@ module Bcdatabase
|
|
94
179
|
|
95
180
|
def create_entry(groupname, dbname)
|
96
181
|
group = @map[groupname] or raise Error.new("No database configuration group named #{groupname.inspect} found. (Found #{@map.keys.inspect}.)")
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
182
|
+
unless group.has_key?(dbname)
|
183
|
+
raise Error.new("No database entry for #{dbname.inspect} in #{groupname}.")
|
184
|
+
end
|
185
|
+
db = group[dbname] || {}
|
186
|
+
base = (group['defaults'] || {}).
|
187
|
+
merge(group['default'] || {}).
|
188
|
+
merge(db)
|
189
|
+
@transforms.inject(base) do |result, transform|
|
190
|
+
transform.call(result, dbname, groupname) || result
|
105
191
|
end
|
106
|
-
merged
|
107
192
|
end
|
108
193
|
|
109
194
|
def unseparated_yaml(arg)
|
@@ -111,5 +196,5 @@ module Bcdatabase
|
|
111
196
|
end
|
112
197
|
end
|
113
198
|
|
114
|
-
class Error <
|
199
|
+
class Error < StandardError; end
|
115
200
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bcdatabase
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 19
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 1
|
8
|
+
- 1
|
8
9
|
- 0
|
9
|
-
|
10
|
-
version: 1.0.6
|
10
|
+
version: 1.1.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Rhett Sutphin
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-
|
18
|
+
date: 2011-08-30 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -63,24 +63,72 @@ dependencies:
|
|
63
63
|
type: :runtime
|
64
64
|
version_requirements: *id003
|
65
65
|
- !ruby/object:Gem::Dependency
|
66
|
-
name:
|
66
|
+
name: thor
|
67
67
|
prerelease: false
|
68
68
|
requirement: &id004 !ruby/object:Gem::Requirement
|
69
69
|
none: false
|
70
70
|
requirements:
|
71
71
|
- - ~>
|
72
72
|
- !ruby/object:Gem::Version
|
73
|
-
hash:
|
73
|
+
hash: 43
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
- 14
|
77
|
+
- 6
|
78
|
+
version: 0.14.6
|
79
|
+
type: :runtime
|
80
|
+
version_requirements: *id004
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: bundler
|
83
|
+
prerelease: false
|
84
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ~>
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
hash: 9
|
74
90
|
segments:
|
75
91
|
- 1
|
92
|
+
- 0
|
93
|
+
- 15
|
94
|
+
version: 1.0.15
|
95
|
+
type: :development
|
96
|
+
version_requirements: *id005
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: rake
|
99
|
+
prerelease: false
|
100
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
101
|
+
none: false
|
102
|
+
requirements:
|
103
|
+
- - ~>
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
hash: 63
|
106
|
+
segments:
|
107
|
+
- 0
|
108
|
+
- 9
|
76
109
|
- 2
|
77
|
-
version:
|
110
|
+
version: 0.9.2
|
78
111
|
type: :development
|
79
|
-
version_requirements: *
|
112
|
+
version_requirements: *id006
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: rspec
|
115
|
+
prerelease: false
|
116
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ~>
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
hash: 15
|
122
|
+
segments:
|
123
|
+
- 2
|
124
|
+
- 6
|
125
|
+
version: "2.6"
|
126
|
+
type: :development
|
127
|
+
version_requirements: *id007
|
80
128
|
- !ruby/object:Gem::Dependency
|
81
129
|
name: ci_reporter
|
82
130
|
prerelease: false
|
83
|
-
requirement: &
|
131
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
84
132
|
none: false
|
85
133
|
requirements:
|
86
134
|
- - ~>
|
@@ -91,8 +139,24 @@ dependencies:
|
|
91
139
|
- 6
|
92
140
|
version: "1.6"
|
93
141
|
type: :development
|
94
|
-
version_requirements: *
|
95
|
-
|
142
|
+
version_requirements: *id008
|
143
|
+
- !ruby/object:Gem::Dependency
|
144
|
+
name: yard
|
145
|
+
prerelease: false
|
146
|
+
requirement: &id009 !ruby/object:Gem::Requirement
|
147
|
+
none: false
|
148
|
+
requirements:
|
149
|
+
- - ~>
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
hash: 7
|
152
|
+
segments:
|
153
|
+
- 0
|
154
|
+
- 7
|
155
|
+
- 2
|
156
|
+
version: 0.7.2
|
157
|
+
type: :development
|
158
|
+
version_requirements: *id009
|
159
|
+
description: bcdatabase is a tool for storing passwords and other configuration information outside of your application source tree.
|
96
160
|
email: rhett@detailedbalance.net
|
97
161
|
executables:
|
98
162
|
- bcdatabase
|
@@ -104,12 +168,17 @@ files:
|
|
104
168
|
- CHANGELOG.markdown
|
105
169
|
- LICENSE
|
106
170
|
- README.markdown
|
171
|
+
- bcdatabase.gemspec
|
107
172
|
- bin/bcdatabase
|
173
|
+
- lib/bcdatabase/cli.rb
|
174
|
+
- lib/bcdatabase/commands/encrypt.rb
|
175
|
+
- lib/bcdatabase/commands/epass.rb
|
176
|
+
- lib/bcdatabase/commands/gen_key.rb
|
108
177
|
- lib/bcdatabase/commands.rb
|
109
178
|
- lib/bcdatabase/version.rb
|
110
179
|
- lib/bcdatabase.rb
|
111
180
|
has_rdoc: true
|
112
|
-
homepage: http://github.com/
|
181
|
+
homepage: http://github.com/NUBIC/bcdatabase
|
113
182
|
licenses: []
|
114
183
|
|
115
184
|
post_install_message:
|