coy 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +5 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +7 -0
- data/README.md +102 -0
- data/Rakefile +15 -0
- data/bin/coy +58 -0
- data/coy.gemspec +30 -0
- data/features/ignore_file.feature +138 -0
- data/features/step_definitions/coy_steps.rb +20 -0
- data/features/step_definitions/ignore_steps.rb +17 -0
- data/features/support/cleanup_truecrypt.rb +21 -0
- data/features/support/env.rb +12 -0
- data/features/truecrypt.feature +41 -0
- data/lib/coy.rb +2 -0
- data/lib/coy/operation.rb +115 -0
- data/lib/coy/random_source.rb +31 -0
- data/lib/coy/version.rb +3 -0
- data/lib/truecrypt.rb +50 -0
- data/spec/io_helpers.rb +32 -0
- data/spec/lib/coy/operation_spec.rb +201 -0
- data/spec/lib/coy/random_source_spec.rb +47 -0
- data/spec/spec_helper.rb +10 -0
- metadata +216 -0
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
Copyright (c) 2013 Joel Helbling
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
+
|
5
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
+
|
7
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
[![Build Status](https://travis-ci.org/joelhelbling/coy.png)](https://travis-ci.org/joelhelbling/coy)
|
2
|
+
|
3
|
+
# Coy
|
4
|
+
|
5
|
+
/koi/ Adjective: *reluctant to give details, esp. about something regarded as
|
6
|
+
sensitive.*
|
7
|
+
|
8
|
+
A utility for protecting shy data, Coy uses TrueCrypt to set up a vcs-ignored\*,
|
9
|
+
encrypted volume within your project project for storing sensitive
|
10
|
+
information. This allows access to that sensitive material _while
|
11
|
+
you're developing or running your application_ but after you close it,
|
12
|
+
the data is inaccessible\*\*.
|
13
|
+
|
14
|
+
You probably don't want to store a whole project in there; usually the
|
15
|
+
sensitive bits are just a few bytes of stuff, such as passwords, personally
|
16
|
+
identifying information, etc. Accordingly, Coy's protected directories have
|
17
|
+
a 2Mb capacity.
|
18
|
+
|
19
|
+
\* _Git, Mercurial and SVN (See [Ignorance](http://github.com/joelhelbling/ignorance).)_
|
20
|
+
|
21
|
+
\*\* _Encrypted with AES and a Whirlpool hash algorithm._
|
22
|
+
|
23
|
+
## Installation
|
24
|
+
|
25
|
+
First, you'll need to [install TrueCrypt](http://www.truecrypt.org/downloads) and ensure
|
26
|
+
its command-line utility is visible in your path:
|
27
|
+
|
28
|
+
$ which truecrypt
|
29
|
+
|
30
|
+
Now you can add this line to your application's Gemfile:
|
31
|
+
|
32
|
+
gem 'coy'
|
33
|
+
|
34
|
+
And then execute:
|
35
|
+
|
36
|
+
$ bundle
|
37
|
+
|
38
|
+
Or install it yourself as:
|
39
|
+
|
40
|
+
$ gem install coy
|
41
|
+
|
42
|
+
|
43
|
+
## Usage
|
44
|
+
|
45
|
+
This would create a new protected directory called "secret":
|
46
|
+
|
47
|
+
$ coy create secret
|
48
|
+
|
49
|
+
This mounts the newly created TrueCrypt volume:
|
50
|
+
|
51
|
+
$ coy open secret
|
52
|
+
|
53
|
+
Now you can slip on in there:
|
54
|
+
|
55
|
+
$ cd secret/
|
56
|
+
|
57
|
+
And stash some top-secret tidbits that your program will need:
|
58
|
+
|
59
|
+
$ echo "---\n - :santas_little_helper: me" > hush-hush.yaml
|
60
|
+
|
61
|
+
And then, in your ruby code:
|
62
|
+
|
63
|
+
```ruby
|
64
|
+
File.exists? './secret/hush-hush.yaml' #=> true
|
65
|
+
```
|
66
|
+
|
67
|
+
Once you're done developing or delivering toys and whatnot, you can
|
68
|
+
close up shop:
|
69
|
+
|
70
|
+
```
|
71
|
+
$ cd ..
|
72
|
+
$ coy close secret
|
73
|
+
```
|
74
|
+
|
75
|
+
And at this point, the `secret/` directory is inaccessible (unmounted).
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
Dir.exists? './secret/' #=> false
|
79
|
+
```
|
80
|
+
|
81
|
+
Now your secret identity is protected by AES encryption, a Whirlpool hash,
|
82
|
+
your awesome password, and whatever other measures TrueCrypt uses. Dobermans,
|
83
|
+
probably.
|
84
|
+
|
85
|
+
### Password
|
86
|
+
|
87
|
+
The `create` and `open` commands require a password. Coy will prompt you,
|
88
|
+
and mask the input. On the other hand, if you're safe in the batcave, you
|
89
|
+
can include the password as a command-line argument:
|
90
|
+
|
91
|
+
$ coy create secret --password l33tp@55w0rd
|
92
|
+
$ coy open secret -p l33tp@55w0rd
|
93
|
+
|
94
|
+
## Contributing
|
95
|
+
|
96
|
+
1. Fork it
|
97
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
98
|
+
3. Write tests!
|
99
|
+
4. Commit your changes (`git commit -am 'Add some feature'`)
|
100
|
+
5. Push to the branch (`git push origin my-new-feature`)
|
101
|
+
6. Create new Pull Request
|
102
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rspec/core/rake_task'
|
3
|
+
require 'cucumber/rake/task'
|
4
|
+
|
5
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
6
|
+
t.verbose = false
|
7
|
+
t.pattern = 'spec/lib/**/*_spec.rb'
|
8
|
+
t.rspec_opts = " --format doc"
|
9
|
+
end
|
10
|
+
|
11
|
+
Cucumber::Rake::Task.new(:cukes) do |t|
|
12
|
+
t.cucumber_opts = "features --format pretty"
|
13
|
+
end
|
14
|
+
|
15
|
+
task default: :spec
|
data/bin/coy
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib'))
|
4
|
+
|
5
|
+
require 'main'
|
6
|
+
require 'coy'
|
7
|
+
|
8
|
+
Main {
|
9
|
+
description <<-DESC
|
10
|
+
Coy uses TrueCrypt (installed separately) to create and manage
|
11
|
+
a protected, git-ignored directory within your project.
|
12
|
+
|
13
|
+
For help with individual operations (create|open|close) type
|
14
|
+
`coy <operation> -h`
|
15
|
+
DESC
|
16
|
+
|
17
|
+
mode 'create' do
|
18
|
+
argument('name') {
|
19
|
+
description "...of the protected directory."
|
20
|
+
default "secret"
|
21
|
+
}
|
22
|
+
option('password=[PASSWORD]', 'p') {
|
23
|
+
cast :string
|
24
|
+
description "set a password for the new protected directory"
|
25
|
+
}
|
26
|
+
|
27
|
+
def run()
|
28
|
+
puts Coy::Operation.new(:create, params.to_options).go
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
mode 'open' do
|
33
|
+
argument('name') {
|
34
|
+
description "...of the protected directory."
|
35
|
+
default "secret"
|
36
|
+
}
|
37
|
+
option('password=[PASSWORD]', 'p') {
|
38
|
+
cast :string
|
39
|
+
description "password to unlock the protected directory"
|
40
|
+
}
|
41
|
+
def run()
|
42
|
+
puts Coy::Operation.new(:open, params.to_options).go
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
mode 'close' do
|
47
|
+
argument('name') {
|
48
|
+
description "...of the protected directory."
|
49
|
+
default "secret"
|
50
|
+
}
|
51
|
+
def run()
|
52
|
+
puts Coy::Operation.new(:close, params.to_options).go
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
run { puts params.to_options.inspect }
|
57
|
+
}
|
58
|
+
|
data/coy.gemspec
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'coy/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = "coy"
|
8
|
+
gem.version = Coy::VERSION
|
9
|
+
gem.authors = ["Joel Helbling"]
|
10
|
+
gem.email = ["joel@joelhelbling.com"]
|
11
|
+
gem.description = %q{Protects sensitive file artifacts in a project, e.g. a yaml file with passwords in it.}
|
12
|
+
gem.summary = %q{Easily create AES-encrypted directories within a project to protect sensitive information. Uses TrueCrypt (required to install) and uses Ignorance to prevent contents of protected directories from being inadvertently being added to a version control repository (Git, Hg, SVN).}
|
13
|
+
gem.homepage = "http://github.com/joelhelbling/coy"
|
14
|
+
|
15
|
+
gem.files = `git ls-files`.split($/)
|
16
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
18
|
+
gem.require_paths = ["lib"]
|
19
|
+
|
20
|
+
gem.add_dependency 'ignorance', '>= 0.0.1'
|
21
|
+
gem.add_dependency 'highline', '~> 1.6.15'
|
22
|
+
gem.add_dependency 'main', '~> 5.1.1'
|
23
|
+
|
24
|
+
gem.add_development_dependency 'rspec', '~> 2.12.0'
|
25
|
+
gem.add_development_dependency 'fakefs', '~> 0.4.2'
|
26
|
+
gem.add_development_dependency 'cucumber', '~> 1.2.1'
|
27
|
+
gem.add_development_dependency 'aruba', '~> 0.5.1'
|
28
|
+
gem.add_development_dependency 'rake', '~> 10.0.3'
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,138 @@
|
|
1
|
+
@ignore
|
2
|
+
Feature: Check the project's .gitignore file to ensure
|
3
|
+
coy assets will not be inadvertently committed/pushed/published.
|
4
|
+
|
5
|
+
@not-ignored @auto-add @git
|
6
|
+
Scenario: no ignore file, but we agree to automatic add (Git)
|
7
|
+
Given the current directory is a git repo
|
8
|
+
And a file named ".gitignore" should not exist
|
9
|
+
And I run `coy create secret --password fuzz` interactively
|
10
|
+
When I type "Y"
|
11
|
+
And I type "Y"
|
12
|
+
Then the output should contain:
|
13
|
+
"""
|
14
|
+
add .coy to this project's .gitignore file automatically?
|
15
|
+
"""
|
16
|
+
And the output should contain:
|
17
|
+
"""
|
18
|
+
add secret to this project's .gitignore file automatically?
|
19
|
+
"""
|
20
|
+
And the output should contain:
|
21
|
+
"""
|
22
|
+
Protected directory "secret" successfully created.
|
23
|
+
"""
|
24
|
+
And the file ".gitignore" should contain ".coy"
|
25
|
+
And the file ".gitignore" should contain "secret"
|
26
|
+
|
27
|
+
@not-ignored @auto-add @hg
|
28
|
+
Scenario: no ignore file, but we agree to automatic add (Hg)
|
29
|
+
Given I have an appropriate .gitignore file
|
30
|
+
Given the current directory is a mercurial repo
|
31
|
+
And a file named ".hgignore" should not exist
|
32
|
+
And I run `coy create secret --password fuzz` interactively
|
33
|
+
When I type "Y"
|
34
|
+
And I type "Y"
|
35
|
+
Then the output should contain:
|
36
|
+
"""
|
37
|
+
add .coy to this project's .hgignore file automatically?
|
38
|
+
"""
|
39
|
+
And the output should contain:
|
40
|
+
"""
|
41
|
+
add secret to this project's .hgignore file automatically?
|
42
|
+
"""
|
43
|
+
And the output should contain:
|
44
|
+
"""
|
45
|
+
Protected directory "secret" successfully created.
|
46
|
+
"""
|
47
|
+
And the file ".hgignore" should contain ".coy"
|
48
|
+
And the file ".hgignore" should contain "secret"
|
49
|
+
|
50
|
+
@not-ignored @auto-add @svn
|
51
|
+
Scenario: no ignore file, but we agree to automatic add (SVN)
|
52
|
+
Given I have an appropriate .gitignore file
|
53
|
+
Given the current directory is a svn repo
|
54
|
+
And a file named ".svnignore" should not exist
|
55
|
+
And I run `coy create secret --password fuzz` interactively
|
56
|
+
When I type "Y"
|
57
|
+
And I type "Y"
|
58
|
+
Then the output should contain:
|
59
|
+
"""
|
60
|
+
add .coy to this project's .svnignore file automatically?
|
61
|
+
"""
|
62
|
+
And the output should contain:
|
63
|
+
"""
|
64
|
+
add secret to this project's .svnignore file automatically?
|
65
|
+
"""
|
66
|
+
And the output should contain:
|
67
|
+
"""
|
68
|
+
Protected directory "secret" successfully created.
|
69
|
+
"""
|
70
|
+
And the file ".svnignore" should contain ".coy"
|
71
|
+
And the file ".svnignore" should contain "secret"
|
72
|
+
|
73
|
+
@no-auto-add @git
|
74
|
+
Scenario: volume not in ignore file, and we decline auto-add (Git)
|
75
|
+
Given we ignore coy with git
|
76
|
+
And I run `coy create secret --password fuzz` interactively
|
77
|
+
When I type "n"
|
78
|
+
Then the output should contain:
|
79
|
+
"""
|
80
|
+
WARNING: please add "secret" to this project's .gitignore file!
|
81
|
+
"""
|
82
|
+
|
83
|
+
@no-auto-add @hg
|
84
|
+
Scenario: volume not in ignore file, and we decline auto-add (Hg)
|
85
|
+
Given I have an appropriate .gitignore file
|
86
|
+
And the current directory is a mercurial repo
|
87
|
+
And we ignore coy with hg
|
88
|
+
And I run `coy create secret --password fuzz` interactively
|
89
|
+
When I type "n"
|
90
|
+
Then the output should contain:
|
91
|
+
"""
|
92
|
+
WARNING: please add "secret" to this project's .hgignore file!
|
93
|
+
"""
|
94
|
+
|
95
|
+
@no-auto-add @svn
|
96
|
+
Scenario: volume not in ignore file, and we decline auto-add (Git)
|
97
|
+
Given I have an appropriate .gitignore file
|
98
|
+
And the current directory is a svn repo
|
99
|
+
And we ignore coy with svn
|
100
|
+
And I run `coy create secret --password fuzz` interactively
|
101
|
+
When I type "n"
|
102
|
+
Then the output should contain:
|
103
|
+
"""
|
104
|
+
WARNING: please add "secret" to this project's .svnignore file!
|
105
|
+
"""
|
106
|
+
|
107
|
+
@already-ignored @git
|
108
|
+
Scenario: ignore file includes both .coy and "secret" (Git)
|
109
|
+
Given a .gitignore with:
|
110
|
+
"""
|
111
|
+
.coy
|
112
|
+
secret
|
113
|
+
"""
|
114
|
+
When I run `coy create secret -p fuzz`
|
115
|
+
Then the output should contain "success"
|
116
|
+
|
117
|
+
@already-ignored @hg
|
118
|
+
Scenario: ignore file includes both .coy and "secret" (Hg)
|
119
|
+
Given I have an appropriate .gitignore file
|
120
|
+
And the current directory is a mercurial repo
|
121
|
+
Given a .hgignore with:
|
122
|
+
"""
|
123
|
+
.coy
|
124
|
+
secret
|
125
|
+
"""
|
126
|
+
When I run `coy create secret -p fuzz`
|
127
|
+
Then the output should contain "success"
|
128
|
+
@already-ignored @svn
|
129
|
+
Scenario: ignore file includes both .coy and "secret" (SVN)
|
130
|
+
Given I have an appropriate .gitignore file
|
131
|
+
And the current directory is a svn repo
|
132
|
+
Given a .svnignore with:
|
133
|
+
"""
|
134
|
+
.coy
|
135
|
+
secret
|
136
|
+
"""
|
137
|
+
When I run `coy create secret -p fuzz`
|
138
|
+
Then the output should contain "success"
|
@@ -0,0 +1,20 @@
|
|
1
|
+
Given /^I have a protected directory named "(.*?)" with password "(.*?)"$/ do |vol_name, password|
|
2
|
+
@password = password
|
3
|
+
step "I run `coy create #{vol_name} --password #{password}`"
|
4
|
+
end
|
5
|
+
|
6
|
+
Given /^protected directory "(.*?)" is open$/ do |vol_name|
|
7
|
+
step "I run `truecrypt .coy/#{vol_name}.tc --password=#@password #{vol_name}`"
|
8
|
+
remember_we_opened vol_name
|
9
|
+
step "a directory named \"#{vol_name}\" should exist"
|
10
|
+
end
|
11
|
+
|
12
|
+
Then /^a protected directory named "(.*?)" should exist/ do |vol_name|
|
13
|
+
step "a directory named \"#{vol_name}\" should exist"
|
14
|
+
remember_we_opened vol_name
|
15
|
+
end
|
16
|
+
|
17
|
+
Then /^let's cleanup "(.*?)"$/ do |vol_name|
|
18
|
+
step "I run `truecrypt -d .coy/#{vol_name}.tc`"
|
19
|
+
end
|
20
|
+
|
@@ -0,0 +1,17 @@
|
|
1
|
+
Given /I have an appropriate \.gitignore file/ do
|
2
|
+
step "a file named \".gitignore\" with:", ".coy\nfoo\nbar\nsecret"
|
3
|
+
end
|
4
|
+
|
5
|
+
Given /^the current directory is a (.*?) repo$/ do |vcs|
|
6
|
+
repo_dir = {'git' => '.git', 'mercurial' => '.hg', 'svn' => '.svn'}[vcs.downcase]
|
7
|
+
step "a directory named \"#{repo_dir}\""
|
8
|
+
end
|
9
|
+
|
10
|
+
Given /^a ([^ ]+) with:$/ do |ignore_file, string|
|
11
|
+
step "a file named \"#{ignore_file}\" with:", string
|
12
|
+
end
|
13
|
+
|
14
|
+
Given /^we ignore coy with (.*?)$/ do |vcs|
|
15
|
+
ignore_file = {:git => '.gitignore', :hg => '.hgignore', :svn => '.svnignore'}[vcs.downcase.to_sym]
|
16
|
+
step "a file named \"#{ignore_file}\" with:", ".coy\n"
|
17
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module CleanupTruecrypt
|
2
|
+
def remember_we_opened(vol_name)
|
3
|
+
@opened_tc_volumes ||= []
|
4
|
+
@opened_tc_volumes << vol_name
|
5
|
+
end
|
6
|
+
|
7
|
+
def close_all_opened_tc_volumes
|
8
|
+
@opened_tc_volumes && @opened_tc_volumes.each do |vol|
|
9
|
+
print " # CLEANUP: was truecrypt volume \"#{vol}\" closed? "
|
10
|
+
if File.directory? File.join('tmp', 'aruba', vol)
|
11
|
+
print "No, shutting it down now..."
|
12
|
+
step "let's cleanup \"#{vol}\""
|
13
|
+
else
|
14
|
+
print "Yes."
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
World CleanupTruecrypt
|
21
|
+
|
@@ -0,0 +1,41 @@
|
|
1
|
+
@truecrypt
|
2
|
+
Feature: Interact with truecrypt volumes
|
3
|
+
|
4
|
+
Background:
|
5
|
+
Given I have an appropriate .gitignore file
|
6
|
+
|
7
|
+
@create
|
8
|
+
Scenario Outline: create a plain 'ole volume with the name provided
|
9
|
+
Given a file named ".coy/secret.tc" should not exist
|
10
|
+
When I run `coy create secret <password_flag> fuzz`
|
11
|
+
Then the output should contain:
|
12
|
+
"""
|
13
|
+
Protected directory "secret" successfully created
|
14
|
+
"""
|
15
|
+
And a directory named ".coy" should exist
|
16
|
+
And a file named ".coy/secret.tc" should exist
|
17
|
+
|
18
|
+
Examples:
|
19
|
+
| password_flag |
|
20
|
+
| --password |
|
21
|
+
| -p |
|
22
|
+
|
23
|
+
@open
|
24
|
+
Scenario Outline: open a protected directory
|
25
|
+
Given a directory named "foo" should not exist
|
26
|
+
And I have a protected directory named "foo" with password "fuzz"
|
27
|
+
When I run `coy open foo <password_flag> fuzz`
|
28
|
+
Then a protected directory named "foo" should exist
|
29
|
+
|
30
|
+
Examples:
|
31
|
+
| password_flag |
|
32
|
+
| --password |
|
33
|
+
| -p |
|
34
|
+
|
35
|
+
@close
|
36
|
+
Scenario: close an opened protected directory
|
37
|
+
Given I have a protected directory named "bar" with password "fuzz"
|
38
|
+
And protected directory "bar" is open
|
39
|
+
When I run `coy close bar`
|
40
|
+
Then a directory named "bar" should not exist
|
41
|
+
|
data/lib/coy.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'highline'
|
2
|
+
require 'ignorance'
|
3
|
+
require 'truecrypt'
|
4
|
+
require 'coy/random_source'
|
5
|
+
|
6
|
+
module Coy
|
7
|
+
class Operation
|
8
|
+
|
9
|
+
COY_DIR = '.coy'
|
10
|
+
COY_COMMENT = "added by coy"
|
11
|
+
|
12
|
+
def initialize(action, p={})
|
13
|
+
|
14
|
+
guard_truecrypt_installed
|
15
|
+
|
16
|
+
@action = action
|
17
|
+
p[:short_name] ||= (p[:name] || p['name'])
|
18
|
+
p[:file_name] = format_name(p[:short_name])
|
19
|
+
p[:password] ||= p['password']
|
20
|
+
@parameters = p
|
21
|
+
send("parameters_for_#{@action}".to_sym)
|
22
|
+
Ignorance.negotiate COY_DIR, COY_COMMENT
|
23
|
+
Ignorance.negotiate @parameters[:short_name], COY_COMMENT
|
24
|
+
end
|
25
|
+
|
26
|
+
def parameters_for_create
|
27
|
+
@parameters[:size_in_bytes] ||= 2_000_000
|
28
|
+
@parameters[:encryption] ||= 'AES'
|
29
|
+
@parameters[:hash] ||= 'Whirlpool'
|
30
|
+
@parameters[:keyfiles] ||= '""'
|
31
|
+
|
32
|
+
# truecrypt bug: Mac OS Extended filesystem
|
33
|
+
# doesn't work with the --text interface
|
34
|
+
@parameters[:filesystem] = 'FAT'
|
35
|
+
end
|
36
|
+
|
37
|
+
def parameters_for_open
|
38
|
+
# no special parameters for open
|
39
|
+
end
|
40
|
+
|
41
|
+
def parameters_for_close
|
42
|
+
# no special parameters for close
|
43
|
+
end
|
44
|
+
|
45
|
+
def go
|
46
|
+
send @action
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def create
|
52
|
+
ensure_coy_directory_exists
|
53
|
+
guard_password_provided "Please provide a password for protected directory"
|
54
|
+
RandomSource.generate("./#{COY_DIR}/#{@parameters[:short_name]}.random") do |random_source|
|
55
|
+
@parameters[:random_source] = random_source
|
56
|
+
TrueCrypt.create_volume(@parameters) &&
|
57
|
+
puts("Protected directory \"#{@parameters[:short_name]}\" successfully created.")
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def open
|
62
|
+
if guard_volume_exists
|
63
|
+
guard_password_provided
|
64
|
+
TrueCrypt.open(@parameters)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def close
|
69
|
+
if guard_volume_exists
|
70
|
+
TrueCrypt.close(@parameters)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def format_name(name='secrets')
|
75
|
+
"#{COY_DIR}/#{name.gsub(/\.tc$/,'')}.tc"
|
76
|
+
end
|
77
|
+
|
78
|
+
def guard_truecrypt_installed
|
79
|
+
message = <<-ERROR
|
80
|
+
Coy requires TrueCrypt, but TrueCrypt is not installed! (Or at least it's not in the path.)
|
81
|
+
|
82
|
+
You can download TrueCrypt here: http://www.truecrypt.org/downloads
|
83
|
+
|
84
|
+
ERROR
|
85
|
+
raise message unless TrueCrypt.installed?
|
86
|
+
end
|
87
|
+
def ensure_coy_directory_exists
|
88
|
+
unless File.directory?('./.coy')
|
89
|
+
puts "Creating .coy subdirectory..."
|
90
|
+
Dir.mkdir COY_DIR
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def guard_volume_exists
|
95
|
+
volume_name = @parameters[:short_name]
|
96
|
+
File.exists?("#{COY_DIR}/#{volume_name}.tc").tap do |volume_exists|
|
97
|
+
unless volume_exists
|
98
|
+
warn <<-WARN
|
99
|
+
There is no protected directory called "#{volume_name}" here.
|
100
|
+
|
101
|
+
You can create one by typing `coy create #{volume_name}`
|
102
|
+
WARN
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def guard_password_provided(msg_preamble="Please enter password for protected directory")
|
108
|
+
unless @parameters[:password]
|
109
|
+
@parameters[:password] = HighLine.new.ask("#{msg_preamble} \"#{@parameters[:short_name]}\": ") {|x| x.echo = "*" }
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Coy
|
4
|
+
class RandomSource
|
5
|
+
|
6
|
+
DEFAULT_FILE = "./random_source"
|
7
|
+
|
8
|
+
def self.generate(file_name=DEFAULT_FILE)
|
9
|
+
if block_given?
|
10
|
+
File.open(file_name, 'w') { |fh| fh.write rand_strategy }
|
11
|
+
yield file_name
|
12
|
+
File.unlink(file_name)
|
13
|
+
else
|
14
|
+
rand_strategy
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.rand_strategy
|
19
|
+
some_random_bytes.inject("") do |accumulator, random_bytes|
|
20
|
+
accumulator.tap do |acc|
|
21
|
+
acc << random_bytes.crypt(@prev.to_s.rjust(2, random_bytes))
|
22
|
+
@prev = random_bytes.hash.to_s
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.some_random_bytes
|
28
|
+
(1500..2000).map{|number| rand(number).to_s }
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/coy/version.rb
ADDED
data/lib/truecrypt.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
class TrueCrypt
|
2
|
+
|
3
|
+
def self.create_volume(p={})
|
4
|
+
|
5
|
+
volume_name = p[:file_name]
|
6
|
+
mount_point = p[:short_name]
|
7
|
+
volume_type = p[:volume_type] || 'normal'
|
8
|
+
size = p[:size_in_bytes] || 5_000_000 # 5Mb
|
9
|
+
encryption = p[:encryption] || 'AES'
|
10
|
+
hash = p[:hash] || 'Whirlpool'
|
11
|
+
keyfiles = p[:keyfiles] || '""'
|
12
|
+
random_source = p[:random_source] || __FILE__
|
13
|
+
password = p[:password] || raise("Please provide a password")
|
14
|
+
filesystem = p[:filesystem] || 'FAT'
|
15
|
+
|
16
|
+
command = <<-TC
|
17
|
+
truecrypt --text \
|
18
|
+
--create #{volume_name} \
|
19
|
+
--volume-type=#{volume_type} \
|
20
|
+
--size=#{size} \
|
21
|
+
--encryption=#{encryption} \
|
22
|
+
--hash=#{hash} \
|
23
|
+
--filesystem=#{filesystem} \
|
24
|
+
--password=#{password} \
|
25
|
+
--keyfiles=#{keyfiles} \
|
26
|
+
--random-source=#{random_source}
|
27
|
+
TC
|
28
|
+
|
29
|
+
`#{command}`
|
30
|
+
end
|
31
|
+
|
32
|
+
# if no password provided, gui window will pop up
|
33
|
+
def self.open(p={})
|
34
|
+
file_name = p[:file_name] || raise("You must provide the name of the volume you wish to open")
|
35
|
+
short_name = p[:short_name]
|
36
|
+
pwd_param = p[:password] && "--password=#{p[:password]}"
|
37
|
+
`truecrypt #{file_name} #{pwd_param} #{short_name}`
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.close(p={})
|
41
|
+
file_name = p[:file_name] || raise("You must provide the name of the volume you wish to close")
|
42
|
+
`truecrypt -d #{file_name}`
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.installed?
|
46
|
+
!! `which truecrypt`.chomp.match(/truecrypt$/i)
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
data/spec/io_helpers.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'stringio'
|
2
|
+
|
3
|
+
module IOHelpers
|
4
|
+
|
5
|
+
def output_from
|
6
|
+
$stdout = $stderr = fake_io
|
7
|
+
yield
|
8
|
+
fake_io.string
|
9
|
+
ensure
|
10
|
+
$stdout = STDOUT; $stderr = STDERR
|
11
|
+
end
|
12
|
+
|
13
|
+
def user_types(input, &block)
|
14
|
+
$stdin = StringIO.new input
|
15
|
+
output_from &block
|
16
|
+
ensure
|
17
|
+
$stdin = STDIN
|
18
|
+
end
|
19
|
+
|
20
|
+
def stdout_from(&block)
|
21
|
+
output_from &block
|
22
|
+
end
|
23
|
+
|
24
|
+
def stderr_from(&block)
|
25
|
+
output_from &block
|
26
|
+
end
|
27
|
+
|
28
|
+
def fake_io
|
29
|
+
@fake_io ||= StringIO.new
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
@@ -0,0 +1,201 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'coy/operation'
|
3
|
+
|
4
|
+
module Coy
|
5
|
+
describe Operation do
|
6
|
+
before do
|
7
|
+
Ignorance.stub(:negotiate)
|
8
|
+
TrueCrypt.stub(:create_volume)
|
9
|
+
TrueCrypt.stub(:open)
|
10
|
+
TrueCrypt.stub(:close)
|
11
|
+
TrueCrypt.stub(:installed?).and_return(true)
|
12
|
+
end
|
13
|
+
|
14
|
+
let(:volume) { 'foo' }
|
15
|
+
subject { Operation.new coy_action, coy_params }
|
16
|
+
|
17
|
+
context "when TrueCrypt is not installed" do
|
18
|
+
let(:coy_action) { :doesnt_matter }
|
19
|
+
let(:coy_params) { { name: volume } }
|
20
|
+
|
21
|
+
before { TrueCrypt.stub(:installed?).and_return(false) }
|
22
|
+
|
23
|
+
specify do
|
24
|
+
expect { subject }.to raise_error /truecrypt.*?not installed/i
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ":create" do
|
29
|
+
|
30
|
+
context "required params only" do
|
31
|
+
let(:coy_action) { :create }
|
32
|
+
|
33
|
+
let(:coy_params) do
|
34
|
+
{
|
35
|
+
name: volume,
|
36
|
+
password: 'b@r'
|
37
|
+
}
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:tc_params) do
|
41
|
+
{
|
42
|
+
name: volume,
|
43
|
+
short_name: volume,
|
44
|
+
file_name: ".coy/#{volume}.tc",
|
45
|
+
size_in_bytes: 2_000_000,
|
46
|
+
encryption: 'AES',
|
47
|
+
hash: 'Whirlpool',
|
48
|
+
filesystem: 'FAT',
|
49
|
+
password: 'b@r',
|
50
|
+
keyfiles: '""',
|
51
|
+
random_source: "./.coy/#{volume}.random"
|
52
|
+
}
|
53
|
+
end
|
54
|
+
|
55
|
+
it "creates a volume" do
|
56
|
+
TrueCrypt.should_receive(:create_volume).with(tc_params)
|
57
|
+
subject.go
|
58
|
+
end
|
59
|
+
|
60
|
+
it "negotiates adding the coy directory to ignore file" do
|
61
|
+
Ignorance.should_receive(:negotiate).with('.coy', Operation::COY_COMMENT)
|
62
|
+
subject.go
|
63
|
+
end
|
64
|
+
|
65
|
+
it "negotiates adding volume to ignore files" do
|
66
|
+
Ignorance.should_receive(:negotiate).with(volume, Operation::COY_COMMENT)
|
67
|
+
subject.go
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
describe ":open", :fakefs do
|
74
|
+
let(:coy_action) { :open }
|
75
|
+
|
76
|
+
let(:coy_params) do
|
77
|
+
{
|
78
|
+
name: 'foo',
|
79
|
+
password: 'b@r'
|
80
|
+
}
|
81
|
+
end
|
82
|
+
|
83
|
+
let(:tc_params) do
|
84
|
+
{
|
85
|
+
name: 'foo',
|
86
|
+
short_name: 'foo',
|
87
|
+
file_name: '.coy/foo.tc',
|
88
|
+
password: 'b@r'
|
89
|
+
}
|
90
|
+
end
|
91
|
+
|
92
|
+
before do
|
93
|
+
Dir.mkdir '.coy'
|
94
|
+
File.open(".coy/#{volume}.tc", 'w') {|fh| fh.write "whatnot" }
|
95
|
+
end
|
96
|
+
|
97
|
+
it "opens a volume" do
|
98
|
+
TrueCrypt.should_receive(:open).with(tc_params)
|
99
|
+
subject.go
|
100
|
+
end
|
101
|
+
|
102
|
+
it "negotiates adding the coy directory to ignore file" do
|
103
|
+
Ignorance.should_receive(:negotiate).with('.coy', Operation::COY_COMMENT)
|
104
|
+
subject.go
|
105
|
+
end
|
106
|
+
|
107
|
+
it "negotiates adding volume to ignore files" do
|
108
|
+
Ignorance.should_receive(:negotiate).with(volume, Operation::COY_COMMENT)
|
109
|
+
subject.go
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
describe ":close", :fakefs do
|
114
|
+
let(:coy_action) { :close }
|
115
|
+
|
116
|
+
let(:coy_params) do
|
117
|
+
{
|
118
|
+
name: 'foo'
|
119
|
+
}
|
120
|
+
end
|
121
|
+
|
122
|
+
let(:tc_params) do
|
123
|
+
{
|
124
|
+
name: 'foo',
|
125
|
+
short_name: 'foo',
|
126
|
+
file_name: '.coy/foo.tc',
|
127
|
+
password: nil
|
128
|
+
}
|
129
|
+
end
|
130
|
+
|
131
|
+
before do
|
132
|
+
Dir.mkdir '.coy'
|
133
|
+
File.open(".coy/#{volume}.tc", 'w') {|fh| fh.write "whatnot" }
|
134
|
+
end
|
135
|
+
|
136
|
+
it "closes a volume" do
|
137
|
+
TrueCrypt.should_receive(:close).with(tc_params)
|
138
|
+
subject.go
|
139
|
+
end
|
140
|
+
|
141
|
+
it "negotiates adding the coy directory to ignore file" do
|
142
|
+
Ignorance.should_receive(:negotiate).with('.coy', Operation::COY_COMMENT)
|
143
|
+
subject.go
|
144
|
+
end
|
145
|
+
|
146
|
+
it "negotiates adding volume to ignore files" do
|
147
|
+
Ignorance.should_receive(:negotiate).with(volume, Operation::COY_COMMENT)
|
148
|
+
subject.go
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe "guarding against non-existant volume", :fakefs, :capture_io do
|
153
|
+
context "volume doesn't exist" do
|
154
|
+
let(:volume_name) { 'foo' }
|
155
|
+
let(:coy_params) { { name: volume_name } }
|
156
|
+
|
157
|
+
describe ":open" do
|
158
|
+
let(:coy_action) { :open }
|
159
|
+
|
160
|
+
it "advises user to create volume" do
|
161
|
+
expect( output_from { subject.go } ).to match /create.*?#{volume_name}/i
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe ":close" do
|
166
|
+
let(:coy_action) { :close }
|
167
|
+
|
168
|
+
it "advises user to create volume" do
|
169
|
+
expect( output_from { subject.go } ).to match /create.*?#{volume_name}/i
|
170
|
+
end
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
context "when user omits password in command-line", :fakefs, :capture_io do
|
176
|
+
let(:coy_params) { { name: volume } }
|
177
|
+
|
178
|
+
before do
|
179
|
+
Dir.mkdir '.coy'
|
180
|
+
File.open(".coy/#{volume}.tc", 'w') { |fh| fh.write "whatnot" }
|
181
|
+
end
|
182
|
+
|
183
|
+
describe ":create" do
|
184
|
+
let(:coy_action) { :create }
|
185
|
+
|
186
|
+
it "asks user to provide a password" do
|
187
|
+
expect( user_types("p@55w0rd") { subject.go } ).to match /provide.*?password.*?#{volume}/i
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
describe ":open" do
|
192
|
+
let(:coy_action) { :open }
|
193
|
+
|
194
|
+
it "prompts user for volume password" do
|
195
|
+
expect( user_types("p@55w0rd") { subject.go } ).to match /enter.*?password.*?#{volume}/i
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
end
|
201
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'coy/random_source'
|
3
|
+
|
4
|
+
module Coy
|
5
|
+
describe RandomSource do
|
6
|
+
subject { described_class }
|
7
|
+
|
8
|
+
its(:generate) { should_not be_empty }
|
9
|
+
|
10
|
+
specify "each run should be different" do
|
11
|
+
subject.generate.should_not == subject.generate
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "::generate" do
|
15
|
+
context "with a code block", :fakefs do
|
16
|
+
let(:file_name) { './foo.random' }
|
17
|
+
context "but no file name" do
|
18
|
+
it "provides a default file name" do
|
19
|
+
expect { |b| subject.generate(&b) }.to yield_with_args(Coy::RandomSource::DEFAULT_FILE)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
context "with file name provided" do
|
23
|
+
it "uses the provided file name" do
|
24
|
+
expect { |b| subject.generate(file_name, &b) }.to yield_with_args(file_name)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe "generating random source file" do
|
29
|
+
it "writes the file to the hard drive" do
|
30
|
+
subject.generate(file_name) do |f_name|
|
31
|
+
File.new(f_name).should exist
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it "deletes the file after yielding to the block" do
|
36
|
+
subject.generate(file_name) do |f_name|
|
37
|
+
File.new(f_name).should exist
|
38
|
+
end
|
39
|
+
File.exists?(file_name).should be_false
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'fakefs/spec_helpers'
|
2
|
+
require File.join(File.dirname(__FILE__), 'io_helpers')
|
3
|
+
|
4
|
+
$LOAD_PATH.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'lib')))
|
5
|
+
|
6
|
+
RSpec.configure do |cfg|
|
7
|
+
cfg.treat_symbols_as_metadata_keys_with_true_values = true
|
8
|
+
cfg.include FakeFS::SpecHelpers, fakefs: true
|
9
|
+
cfg.include IOHelpers, capture_io: true
|
10
|
+
end
|
metadata
ADDED
@@ -0,0 +1,216 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: coy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Joel Helbling
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2013-02-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: ignorance
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 0.0.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.0.1
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: highline
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ~>
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: 1.6.15
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 1.6.15
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: main
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ~>
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 5.1.1
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 5.1.1
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ~>
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 2.12.0
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 2.12.0
|
78
|
+
- !ruby/object:Gem::Dependency
|
79
|
+
name: fakefs
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ~>
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 0.4.2
|
86
|
+
type: :development
|
87
|
+
prerelease: false
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ~>
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.4.2
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: cucumber
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ~>
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 1.2.1
|
102
|
+
type: :development
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ~>
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.2.1
|
110
|
+
- !ruby/object:Gem::Dependency
|
111
|
+
name: aruba
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
113
|
+
none: false
|
114
|
+
requirements:
|
115
|
+
- - ~>
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: 0.5.1
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - ~>
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 0.5.1
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: rake
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ~>
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: 10.0.3
|
134
|
+
type: :development
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ~>
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 10.0.3
|
142
|
+
description: Protects sensitive file artifacts in a project, e.g. a yaml file with
|
143
|
+
passwords in it.
|
144
|
+
email:
|
145
|
+
- joel@joelhelbling.com
|
146
|
+
executables:
|
147
|
+
- coy
|
148
|
+
extensions: []
|
149
|
+
extra_rdoc_files: []
|
150
|
+
files:
|
151
|
+
- .gitignore
|
152
|
+
- Gemfile
|
153
|
+
- LICENSE.txt
|
154
|
+
- README.md
|
155
|
+
- Rakefile
|
156
|
+
- bin/coy
|
157
|
+
- coy.gemspec
|
158
|
+
- features/ignore_file.feature
|
159
|
+
- features/step_definitions/coy_steps.rb
|
160
|
+
- features/step_definitions/ignore_steps.rb
|
161
|
+
- features/support/cleanup_truecrypt.rb
|
162
|
+
- features/support/env.rb
|
163
|
+
- features/truecrypt.feature
|
164
|
+
- lib/coy.rb
|
165
|
+
- lib/coy/operation.rb
|
166
|
+
- lib/coy/random_source.rb
|
167
|
+
- lib/coy/version.rb
|
168
|
+
- lib/truecrypt.rb
|
169
|
+
- spec/io_helpers.rb
|
170
|
+
- spec/lib/coy/operation_spec.rb
|
171
|
+
- spec/lib/coy/random_source_spec.rb
|
172
|
+
- spec/spec_helper.rb
|
173
|
+
homepage: http://github.com/joelhelbling/coy
|
174
|
+
licenses: []
|
175
|
+
post_install_message:
|
176
|
+
rdoc_options: []
|
177
|
+
require_paths:
|
178
|
+
- lib
|
179
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
180
|
+
none: false
|
181
|
+
requirements:
|
182
|
+
- - ! '>='
|
183
|
+
- !ruby/object:Gem::Version
|
184
|
+
version: '0'
|
185
|
+
segments:
|
186
|
+
- 0
|
187
|
+
hash: 1409079959630218355
|
188
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
189
|
+
none: false
|
190
|
+
requirements:
|
191
|
+
- - ! '>='
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
version: '0'
|
194
|
+
segments:
|
195
|
+
- 0
|
196
|
+
hash: 1409079959630218355
|
197
|
+
requirements: []
|
198
|
+
rubyforge_project:
|
199
|
+
rubygems_version: 1.8.24
|
200
|
+
signing_key:
|
201
|
+
specification_version: 3
|
202
|
+
summary: Easily create AES-encrypted directories within a project to protect sensitive
|
203
|
+
information. Uses TrueCrypt (required to install) and uses Ignorance to prevent
|
204
|
+
contents of protected directories from being inadvertently being added to a version
|
205
|
+
control repository (Git, Hg, SVN).
|
206
|
+
test_files:
|
207
|
+
- features/ignore_file.feature
|
208
|
+
- features/step_definitions/coy_steps.rb
|
209
|
+
- features/step_definitions/ignore_steps.rb
|
210
|
+
- features/support/cleanup_truecrypt.rb
|
211
|
+
- features/support/env.rb
|
212
|
+
- features/truecrypt.feature
|
213
|
+
- spec/io_helpers.rb
|
214
|
+
- spec/lib/coy/operation_spec.rb
|
215
|
+
- spec/lib/coy/random_source_spec.rb
|
216
|
+
- spec/spec_helper.rb
|