streetcreds 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -2
- data/Gemfile.lock +9 -5
- data/LICENSE.txt +1 -1
- data/README.md +32 -26
- data/lib/streetcreds.rb +9 -101
- data/lib/streetcreds/cred_file.rb +84 -0
- data/lib/streetcreds/patches/openssl_cipher_patch.rb +12 -0
- data/lib/streetcreds/patches/yaml_patch.rb +9 -0
- data/lib/streetcreds/version.rb +1 -1
- data/streetcreds.gemspec +20 -16
- metadata +49 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0573e55f19dd3630b82109a083f349004e918ecb
|
4
|
+
data.tar.gz: 7b1de8a55c673746ffcbef42cfa49631484406e5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a7acd91f79ac3c1a2cce59706f80b8abade9d088f951caee78f6c4883630deeee8a7b9afe6e67282c0ee9f963783204dcf8bf41f0189fb1598479170ad292046
|
7
|
+
data.tar.gz: 8506e8b4cea0e388d30c913c22afde738412f9b83ed98a72ef5c997ce1a6e104c394454170ddf39aa9eb21d241af586eba16187fea04a9c168da0c7528e0efae
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,20 +1,24 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
streetcreds (0.
|
5
|
-
|
4
|
+
streetcreds (0.2.0)
|
5
|
+
encrypted_strings
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
|
10
|
+
byebug (9.0.6)
|
11
|
+
encrypted_strings (0.3.3)
|
12
|
+
rake (10.5.0)
|
11
13
|
|
12
14
|
PLATFORMS
|
13
15
|
ruby
|
14
16
|
|
15
17
|
DEPENDENCIES
|
16
|
-
bundler (~> 1.
|
18
|
+
bundler (~> 1.15)
|
19
|
+
byebug
|
20
|
+
rake (~> 10.0)
|
17
21
|
streetcreds!
|
18
22
|
|
19
23
|
BUNDLED WITH
|
20
|
-
1.
|
24
|
+
1.15.1
|
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
@@ -1,38 +1,44 @@
|
|
1
1
|
# StreetCreds
|
2
2
|
|
3
|
-
|
3
|
+
This is a gem that manages encrypted YAML files that can be used to store credentials and stuff you might just not want to leave lying around on your system.
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
It's not in rubygems yet.
|
5
|
+
It doesn't use a strong or unique IV or anything like that. It's not top-notch security. It's just a quick-and-dirty way to obfuscate things you might be using locally to enable your code to access resources, short of using a local deployment of a secret manager like Hashicorp Vault.
|
6
|
+
|
7
|
+
It uses ruby 2.0 hash-syntax for many of its methods, allowing you to leave some things un-filled and asking for them if it needs them. If you don't want your code being interrupted to ask for a password, provide one programatically.
|
8
|
+
|
9
|
+
This is a complete rewrite of StreetCreds 0.1 and is definitely not backwards-compatible. It's barely the same thing.
|
11
10
|
|
12
11
|
## Usage
|
13
12
|
|
14
|
-
|
13
|
+
Use it like this:
|
14
|
+
```ruby
|
15
|
+
# #convert_on_valid is false by default and will assume you want to encrypt a valid YAML file
|
16
|
+
# if it hasn't been encrypted already.
|
17
|
+
cf = StreetCreds::CredFile.new(filepath: '~/mycreds.yml', convert_on_valid: true)
|
15
18
|
|
16
|
-
|
19
|
+
# Add a cred via code:
|
20
|
+
cf['github'] = {'username' => 'wwboynton', password: 'xxxxxxxxxxxxxx'}
|
21
|
+
# Worth noting, all your keys will be recursively symbolized. Hope that's okay.
|
22
|
+
|
23
|
+
# #inspect is overridden and will #inspect the internal hash.
|
24
|
+
# This will show all values, including passwords and sensitive data!
|
25
|
+
puts cf.inspect
|
17
26
|
|
18
|
-
|
27
|
+
# Save back to the file. This will always be encrypted.
|
28
|
+
cf.save
|
19
29
|
|
20
|
-
|
30
|
+
# Decrypt a file in-place
|
31
|
+
StreetCreds::CredFile.decrypt_existing_file(filepath: '~/mycreds.yml')
|
32
|
+
|
33
|
+
# You can encrypt-in-place too, but you could also just use #convert_on_valid
|
34
|
+
StreetCreds::CredFile.encrypt_existing_file(filepath: '~/mycreds.yml')
|
35
|
+
|
36
|
+
```
|
37
|
+
|
38
|
+
## License
|
21
39
|
|
22
|
-
|
23
|
-
of this software and associated documentation files (the "Software"), to deal
|
24
|
-
in the Software without restriction, including without limitation the rights
|
25
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
26
|
-
copies of the Software, and to permit persons to whom the Software is
|
27
|
-
furnished to do so, subject to the following conditions:
|
40
|
+
It's MIT. Do whatever.
|
28
41
|
|
29
|
-
|
30
|
-
all copies or substantial portions of the Software.
|
42
|
+
## Contributing
|
31
43
|
|
32
|
-
|
33
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
34
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
35
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
36
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
37
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
38
|
-
THE SOFTWARE.
|
44
|
+
I guess you can PR if you really want to. I'd probably look at it.
|
data/lib/streetcreds.rb
CHANGED
@@ -1,101 +1,9 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
attr_accessor :credentials
|
11
|
-
|
12
|
-
def initialize
|
13
|
-
end
|
14
|
-
|
15
|
-
def set_up(cred_file)
|
16
|
-
@cred_file = cred_file
|
17
|
-
@sample_file = "#{cred_file}.sample"
|
18
|
-
check_dir
|
19
|
-
check_file
|
20
|
-
@credentials = YAML.load_file(@cred_file) || {}
|
21
|
-
end
|
22
|
-
|
23
|
-
def check_dir
|
24
|
-
cred_path = get_cred_path
|
25
|
-
unless File.exist?(cred_path)
|
26
|
-
puts "Creating credentials directory at '#{cred_path}'"
|
27
|
-
FileUtils.mkdir_p(cred_path)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def check_file
|
32
|
-
unless File.exist?(@cred_file)
|
33
|
-
puts "There is no credentials.yml file at '#{@cred_file.yellow}'".red
|
34
|
-
puts "Please fill out the sample file at '#{@sample_file.yellow}' and copy it to '#{@cred_file.yellow}'".red
|
35
|
-
if !File.exist?(@cred_file) && !File.exist?(@sample_file)
|
36
|
-
File.open(@sample_file, 'w') { |f| f.write(sample) }
|
37
|
-
end
|
38
|
-
raise StandardError
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
|
43
|
-
def get_cred_path
|
44
|
-
@cred_file.split('/')[0..-2].join('/')
|
45
|
-
end
|
46
|
-
|
47
|
-
def save
|
48
|
-
File.open(@cred_file, 'w') { |f| f.write(@credentials.to_yaml) }
|
49
|
-
end
|
50
|
-
|
51
|
-
def [](key)
|
52
|
-
@credentials[key]
|
53
|
-
end
|
54
|
-
|
55
|
-
def []=(key, val)
|
56
|
-
@credentials[key] = val
|
57
|
-
end
|
58
|
-
|
59
|
-
def has_key?(key)
|
60
|
-
@credentials.has_key?(key)
|
61
|
-
end
|
62
|
-
|
63
|
-
def self.has_key?(key)
|
64
|
-
Credentials.instance.has_key?(key)
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.[](key)
|
68
|
-
Credentials.instance[key]
|
69
|
-
end
|
70
|
-
|
71
|
-
def self.[]=(key, val)
|
72
|
-
Credentials.instance[key] = val
|
73
|
-
end
|
74
|
-
|
75
|
-
def self.save
|
76
|
-
Credentials.instance.save
|
77
|
-
end
|
78
|
-
|
79
|
-
def self.credentials
|
80
|
-
Credentials.instance.credentials
|
81
|
-
end
|
82
|
-
|
83
|
-
def sample
|
84
|
-
<<EOS
|
85
|
-
---
|
86
|
-
:google:
|
87
|
-
:username:
|
88
|
-
:password:
|
89
|
-
:google_drive:
|
90
|
-
:client_id:
|
91
|
-
:client_secret:
|
92
|
-
:github:
|
93
|
-
:username:
|
94
|
-
:password:
|
95
|
-
:hipchat:
|
96
|
-
:token:
|
97
|
-
EOS
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
1
|
+
require 'streetcred/version'
|
2
|
+
require 'streetcred/cred_file'
|
3
|
+
require 'encrypted_strings'
|
4
|
+
require 'streetcred/patches/openssl_cipher_patch'
|
5
|
+
require 'yaml'
|
6
|
+
require 'streetcred/patches/yaml_patch'
|
7
|
+
require 'fileutils'
|
8
|
+
require 'pp'
|
9
|
+
# require 'byebug'
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module StreetCred
|
2
|
+
class CredFile
|
3
|
+
def self.encrypt_existing_file(filepath:)
|
4
|
+
filepath = full_path(filepath)
|
5
|
+
hash = YAML.load(File.open(filepath))
|
6
|
+
new(filepath: filepath, hash: hash)
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.decrypt_existing_file(filepath:)
|
10
|
+
filepath = full_path(filepath)
|
11
|
+
decrypted_contents = new(filepath: filepath).decrypt_file
|
12
|
+
File.open(filepath, 'w+') { |f| f.write(decrypted_contents) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(filepath:, hash: nil, convert_on_valid: false)
|
16
|
+
@filepath = self.class.full_path(filepath)
|
17
|
+
load_file(hash: hash, convert_on_valid: convert_on_valid)
|
18
|
+
end
|
19
|
+
|
20
|
+
def load_file(convert_on_valid:, hash: nil)
|
21
|
+
if hash.nil?
|
22
|
+
begin
|
23
|
+
file_contents = File.read(@filepath)
|
24
|
+
return @hash = {} if file_contents.empty?
|
25
|
+
@hash = YAMLHelper.load_if_valid(file_contents) if convert_on_valid
|
26
|
+
@hash = YAMLHelper.load_if_valid(decrypt_file) unless @hash
|
27
|
+
rescue Errno::ENOENT
|
28
|
+
@hash = {}
|
29
|
+
end
|
30
|
+
end
|
31
|
+
@hash = self.class.symbolize_keys(@hash)
|
32
|
+
end
|
33
|
+
|
34
|
+
def decrypt_file(contents: nil, password: nil)
|
35
|
+
contents = File.read(@filepath) unless contents
|
36
|
+
password = ask_password if password.nil?
|
37
|
+
contents.decrypt(:symmetric, :password => password)
|
38
|
+
end
|
39
|
+
|
40
|
+
def save
|
41
|
+
FileUtils.mkdir_p(File.dirname(@filepath))
|
42
|
+
yaml = self.class.symbolize_keys(@hash).to_yaml
|
43
|
+
if yaml.empty?
|
44
|
+
File.delete(@filepath)
|
45
|
+
else
|
46
|
+
encrypted_yaml = encrypt_file(contents: yaml)
|
47
|
+
File.open(@filepath, 'w+') { |f| f.write(encrypted_yaml) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def encrypt_file(contents:, password: nil)
|
52
|
+
password = ask_password if password.nil?
|
53
|
+
contents.encrypt(:symmetric, :password => password)
|
54
|
+
end
|
55
|
+
|
56
|
+
def ask_password
|
57
|
+
return @password if @password
|
58
|
+
print "Password?\n> "
|
59
|
+
@password = $stdin.noecho(&:gets).chomp
|
60
|
+
puts ''
|
61
|
+
@password
|
62
|
+
end
|
63
|
+
|
64
|
+
def inspect
|
65
|
+
@hash.inspect
|
66
|
+
end
|
67
|
+
|
68
|
+
# Act like a hash
|
69
|
+
def method_missing(meth, *args)
|
70
|
+
@hash.send(meth, *args)
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.full_path(filepath)
|
74
|
+
Pathname.new(filepath).expand_path.to_s
|
75
|
+
end
|
76
|
+
|
77
|
+
# Adapted from https://stackoverflow.com/a/8379653/5637619
|
78
|
+
def self.symbolize_keys(hash)
|
79
|
+
Hash[hash.map do |k, v|
|
80
|
+
[k.to_sym, (v.is_a?(Hash) ? symbolize_keys(v) : v)]
|
81
|
+
end]
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'encrypted_strings'
|
2
|
+
|
3
|
+
# I know monkey patches are bad, but this warning is annoying and the encrypted_strings guys haven't accepted that PR.
|
4
|
+
module EncryptedStrings
|
5
|
+
class SymmetricCipher
|
6
|
+
def build_cipher(type) #:nodoc:
|
7
|
+
cipher = OpenSSL::Cipher.new(algorithm).send(type)
|
8
|
+
cipher.pkcs5_keyivgen(password)
|
9
|
+
cipher
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
data/lib/streetcreds/version.rb
CHANGED
data/streetcreds.gemspec
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
lib = File.expand_path(
|
2
|
+
lib = File.expand_path("../lib", __FILE__)
|
3
3
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
-
require
|
4
|
+
require "streetcreds/version"
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
7
|
spec.name = "streetcreds"
|
@@ -9,24 +9,28 @@ Gem::Specification.new do |spec|
|
|
9
9
|
spec.authors = ["Wesley Boynton"]
|
10
10
|
spec.email = ["wes@boynton.io"]
|
11
11
|
|
12
|
-
spec.summary = %q{
|
13
|
-
spec.homepage = "https://www.github.com/wwboynton/streetcreds"
|
12
|
+
spec.summary = %q{Dead-simple password-based encryption and decryption of some yaml configuration files}
|
14
13
|
spec.license = "MIT"
|
15
14
|
|
16
|
-
# Prevent pushing this gem to RubyGems.org
|
17
|
-
# delete this section to allow pushing
|
18
|
-
if spec.respond_to?(:metadata)
|
19
|
-
|
20
|
-
else
|
21
|
-
|
22
|
-
|
15
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
16
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
17
|
+
# if spec.respond_to?(:metadata)
|
18
|
+
# spec.metadata["allowed_push_host"] = "TODO: Set to 'http://mygemserver.com'"
|
19
|
+
# else
|
20
|
+
# raise "RubyGems 2.0 or newer is required to protect against " \
|
21
|
+
# "public gem pushes."
|
22
|
+
# end
|
23
23
|
|
24
|
-
spec.files = `git ls-files -z`.split("\x0").reject
|
25
|
-
|
26
|
-
|
24
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
25
|
+
f.match(%r{^(test|spec|features)/})
|
26
|
+
end
|
27
|
+
spec.bindir = "exe"
|
28
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
27
29
|
spec.require_paths = ["lib"]
|
28
30
|
|
29
|
-
spec.add_runtime_dependency
|
31
|
+
spec.add_runtime_dependency "encrypted_strings"
|
30
32
|
|
31
|
-
spec.add_development_dependency "bundler", "~> 1.
|
33
|
+
spec.add_development_dependency "bundler", "~> 1.15"
|
34
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
35
|
+
spec.add_development_dependency "byebug"
|
32
36
|
end
|
metadata
CHANGED
@@ -1,43 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: streetcreds
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Wesley Boynton
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-06-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
14
|
+
name: encrypted_strings
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- -
|
24
|
+
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - ~>
|
31
|
+
- - "~>"
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '1.
|
33
|
+
version: '1.15'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '1.
|
40
|
+
version: '1.15'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '10.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '10.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: byebug
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
41
69
|
description:
|
42
70
|
email:
|
43
71
|
- wes@boynton.io
|
@@ -45,37 +73,40 @@ executables: []
|
|
45
73
|
extensions: []
|
46
74
|
extra_rdoc_files: []
|
47
75
|
files:
|
48
|
-
- .gitignore
|
76
|
+
- ".gitignore"
|
49
77
|
- Gemfile
|
50
78
|
- Gemfile.lock
|
51
79
|
- LICENSE.txt
|
52
80
|
- README.md
|
53
81
|
- lib/streetcreds.rb
|
82
|
+
- lib/streetcreds/cred_file.rb
|
83
|
+
- lib/streetcreds/patches/openssl_cipher_patch.rb
|
84
|
+
- lib/streetcreds/patches/yaml_patch.rb
|
54
85
|
- lib/streetcreds/version.rb
|
55
86
|
- streetcreds.gemspec
|
56
|
-
homepage:
|
87
|
+
homepage:
|
57
88
|
licenses:
|
58
89
|
- MIT
|
59
|
-
metadata:
|
60
|
-
allowed_push_host: 'TODO: Set to ''http://mygemserver.com'''
|
90
|
+
metadata: {}
|
61
91
|
post_install_message:
|
62
92
|
rdoc_options: []
|
63
93
|
require_paths:
|
64
94
|
- lib
|
65
95
|
required_ruby_version: !ruby/object:Gem::Requirement
|
66
96
|
requirements:
|
67
|
-
- -
|
97
|
+
- - ">="
|
68
98
|
- !ruby/object:Gem::Version
|
69
99
|
version: '0'
|
70
100
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
71
101
|
requirements:
|
72
|
-
- -
|
102
|
+
- - ">="
|
73
103
|
- !ruby/object:Gem::Version
|
74
104
|
version: '0'
|
75
105
|
requirements: []
|
76
106
|
rubyforge_project:
|
77
|
-
rubygems_version: 2.
|
107
|
+
rubygems_version: 2.6.11
|
78
108
|
signing_key:
|
79
109
|
specification_version: 4
|
80
|
-
summary:
|
110
|
+
summary: Dead-simple password-based encryption and decryption of some yaml configuration
|
111
|
+
files
|
81
112
|
test_files: []
|