ejson 0.2.2
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 +7 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +54 -0
- data/Rakefile +7 -0
- data/bin/ejson +4 -0
- data/ejson.gemspec +22 -0
- data/lib/ejson.rb +60 -0
- data/lib/ejson/cli.rb +86 -0
- data/lib/ejson/encryption.rb +61 -0
- data/lib/ejson/version.rb +3 -0
- data/test/ejson_test.rb +85 -0
- data/test/privatekey.pem +27 -0
- data/test/publickey.pem +18 -0
- metadata +78 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 45c8c29f86387553314be3e8738a55173944bdf1
|
|
4
|
+
data.tar.gz: 3353be24350564b401c3cfc631bd09d7ab98d1d1
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 52504a192b550a1d4391617b5695a87f14e974299db5760cb845f14612b36faf54e2087b0184ce7cf3556a7c5ec1d2d75ad569cc6ea18cc501c70b8a26d3145c
|
|
7
|
+
data.tar.gz: bb65c77a6500b0d550337e51fe7af6704c9c6c81b022e86dee2e968706100318427aea9f872895d0efc328bc38d4c3364299f1e496a8ddbce597dfbe2cd88904
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2014 Burke Libbey
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
# EJSON
|
|
2
|
+
|
|
3
|
+
EJSON is a small library to manage encrypted secrets using PKCS7 (asymmetric)
|
|
4
|
+
encryption. It provides a simple command interface to manage and update secrets
|
|
5
|
+
in a JSON file where keys are cleartext and values are encrypted.
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
It's on rubygems. Just `gem install ejson` or add it to your `Gemfile`.
|
|
10
|
+
|
|
11
|
+
## Usage
|
|
12
|
+
|
|
13
|
+
#### 1) Create a `secrets.ejson`:
|
|
14
|
+
|
|
15
|
+
echo '{"a": "b"}' > config/secrets.production.ejson
|
|
16
|
+
|
|
17
|
+
Keys in this file will remain in cleartext, while values will all be encrypted.
|
|
18
|
+
It can be arbitrarily nested.
|
|
19
|
+
|
|
20
|
+
#### 2) Encrypt the file:
|
|
21
|
+
|
|
22
|
+
ejson
|
|
23
|
+
|
|
24
|
+
This updates `config/secrets.ejson` in place, encrypting any newly-added or
|
|
25
|
+
modified values that are not yet encrypted. `ejson` is short-hand for `ejson encrypt`.
|
|
26
|
+
|
|
27
|
+
#### 3) Decrypt the file:
|
|
28
|
+
|
|
29
|
+
ejson decrypt -k ~/.keys/ejson.priv.pem -p config/ejson.pub.pem secrets.production.ejson > secrets.production.json
|
|
30
|
+
|
|
31
|
+
Unlike encrypt, decrypt doesn't update the file in-place; it prints the
|
|
32
|
+
decrypted contents to stdout. It also requires access to the private key
|
|
33
|
+
created in step 1.
|
|
34
|
+
|
|
35
|
+
#### See `ejson help` for more information.
|
|
36
|
+
|
|
37
|
+
## Custom keypair:
|
|
38
|
+
|
|
39
|
+
We use a single keypair internally; the default public key is fetched from S3
|
|
40
|
+
on each run. However, you can generate your own keypair like so:
|
|
41
|
+
|
|
42
|
+
mkdir config && cd config
|
|
43
|
+
openssl req -x509 -nodes -days 100000 -newkey rsa:2048 -keyout privatekey.pem -out publickey.pem -subj '/'
|
|
44
|
+
|
|
45
|
+
`publickey.pem` and `privatekey.pem` are created. Move `privatekey.pem`
|
|
46
|
+
somewhere more secure.
|
|
47
|
+
|
|
48
|
+
mkdir -p ~/.keys
|
|
49
|
+
mv config/privatekey.pem ~/.keys/ejson.pem
|
|
50
|
+
|
|
51
|
+
Then you can encrypt like:
|
|
52
|
+
|
|
53
|
+
ejson encrypt -p config/publickey.pem secrets.ejson
|
|
54
|
+
|
data/Rakefile
ADDED
data/bin/ejson
ADDED
data/ejson.gemspec
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'ejson/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = "ejson"
|
|
8
|
+
spec.version = Ejson::VERSION
|
|
9
|
+
spec.authors = ["Burke Libbey"]
|
|
10
|
+
spec.email = ["burke.libbey@shopify.com"]
|
|
11
|
+
spec.summary = %q{Asymmetric keywise encryption for JSON}
|
|
12
|
+
spec.description = %q{Secret management by encrypting values in a JSON hash with a public/private keypair}
|
|
13
|
+
spec.homepage = "https://github.com/Shopify/ejson"
|
|
14
|
+
spec.license = "MIT"
|
|
15
|
+
|
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
|
19
|
+
spec.require_paths = ["lib"]
|
|
20
|
+
|
|
21
|
+
spec.add_runtime_dependency "thor", "~> 0.18"
|
|
22
|
+
end
|
data/lib/ejson.rb
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
require 'forwardable'
|
|
3
|
+
require 'ejson/encryption'
|
|
4
|
+
|
|
5
|
+
class EJSON
|
|
6
|
+
extend Forwardable
|
|
7
|
+
def_delegators :@encryption, :load_string, :dump_string
|
|
8
|
+
|
|
9
|
+
def initialize(public_key_file, private_key_file = nil)
|
|
10
|
+
@encryption = Encryption.new(public_key_file, private_key_file)
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def load(json_text)
|
|
14
|
+
Data.new(JSON.load(json_text), @encryption)
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class Data
|
|
18
|
+
extend Forwardable
|
|
19
|
+
def_delegators :@data, :[]=
|
|
20
|
+
|
|
21
|
+
attr_reader :encryption
|
|
22
|
+
def initialize(data, encryption)
|
|
23
|
+
@data, @encryption = data, encryption
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def dump
|
|
27
|
+
JSON.pretty_generate(encrypt_all(@data))
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def encrypt_all(data=@data)
|
|
31
|
+
case data
|
|
32
|
+
when Hash
|
|
33
|
+
Hash[ data.map { |k,v| [k, encrypt_all(v)] } ]
|
|
34
|
+
when Array
|
|
35
|
+
data.map { |d| encrypt_all(d) }
|
|
36
|
+
when String
|
|
37
|
+
encryption.dump(data)
|
|
38
|
+
else
|
|
39
|
+
data
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def decrypt_all(data=@data)
|
|
44
|
+
case data
|
|
45
|
+
when Hash
|
|
46
|
+
Hash[ data.map { |k,v| [k, decrypt_all(v)] } ]
|
|
47
|
+
when Array
|
|
48
|
+
data.map { |d| decrypt_all(d) }
|
|
49
|
+
when String
|
|
50
|
+
encryption.load(data)
|
|
51
|
+
else
|
|
52
|
+
data
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
|
data/lib/ejson/cli.rb
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
require 'thor'
|
|
2
|
+
require 'json'
|
|
3
|
+
require 'ejson'
|
|
4
|
+
require 'net/http'
|
|
5
|
+
|
|
6
|
+
class EJSON
|
|
7
|
+
|
|
8
|
+
class CLI < Thor
|
|
9
|
+
class_option "privkey", type: :string, aliases: "-k", desc: "Path to PKCS7 private key in PEM format"
|
|
10
|
+
class_option "pubkey", type: :string, aliases: "-p", desc: "Path or URL to PKCS7 public key in PEM format", default: "https://s3.amazonaws.com/shopify-ops/ejson-publickey.pem"
|
|
11
|
+
|
|
12
|
+
default_task :encrypt
|
|
13
|
+
|
|
14
|
+
desc "decrypt [file]", "decrypt some data from file to stdout"
|
|
15
|
+
def decrypt(file)
|
|
16
|
+
ciphertext = File.read(file)
|
|
17
|
+
ej = EJSON.new(pubkey, options[:privkey])
|
|
18
|
+
puts JSON.pretty_generate(ej.load(ciphertext).decrypt_all)
|
|
19
|
+
rescue EJSON::Encryption::PrivateKeyMissing => e
|
|
20
|
+
fatal("can't decrypt data without private key (specify path with -k)", e)
|
|
21
|
+
rescue EJSON::Encryption::ExpectedEncryptedString => e
|
|
22
|
+
fatal("can't decrypt data with cleartext strings (use ejson recrypt first)", e)
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
desc "encrypt [file=**/*.ejson]", "encrypt an ejson file in place (encrypt any unencrypted values)"
|
|
26
|
+
def encrypt(file="**/*.ejson")
|
|
27
|
+
ej = EJSON.new(pubkey)
|
|
28
|
+
fpaths = Dir.glob(file)
|
|
29
|
+
if fpaths.empty?
|
|
30
|
+
fatal("no ejson files found!", nil)
|
|
31
|
+
end
|
|
32
|
+
fpaths.each do |fpath|
|
|
33
|
+
data = ej.load(File.read(fpath))
|
|
34
|
+
dump = data.dump
|
|
35
|
+
File.open(fpath, "w") { |f| f.puts dump }
|
|
36
|
+
puts "Wrote #{dump.size+1} bytes to #{fpath}"
|
|
37
|
+
end
|
|
38
|
+
rescue OpenSSL::X509::CertificateError => e
|
|
39
|
+
fatal("invalid certificate", e)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
desc "version", "show version information"
|
|
43
|
+
def version
|
|
44
|
+
puts "ejson version #{EJSON::VERSION}"
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
private
|
|
48
|
+
|
|
49
|
+
def fatal(str, err=str)
|
|
50
|
+
raise err if defined?(Minitest)
|
|
51
|
+
msg = $stderr.tty? ? "\x1b[31m#{str}\x1b[0m" : str
|
|
52
|
+
$stderr.puts msg
|
|
53
|
+
exit 1
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def get_input(file)
|
|
57
|
+
return File.read(file) if file
|
|
58
|
+
$stdin.read
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def pubkey
|
|
62
|
+
@pubkey ||= _pubkey
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def _pubkey
|
|
66
|
+
if options[:pubkey] =~ %r{https://}
|
|
67
|
+
uri = URI.parse(options[:pubkey])
|
|
68
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
|
69
|
+
http.use_ssl = true
|
|
70
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
71
|
+
req = Net::HTTP::Get.new(URI.parse(options[:pubkey]).request_uri)
|
|
72
|
+
resp = http.request(req)
|
|
73
|
+
resp.value # raises on code >399
|
|
74
|
+
f = Tempfile.new("pubkey")
|
|
75
|
+
f.write resp.body
|
|
76
|
+
f.close
|
|
77
|
+
at_exit { f.unlink }
|
|
78
|
+
f.path
|
|
79
|
+
else
|
|
80
|
+
options[:pubkey]
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
require 'openssl'
|
|
2
|
+
require 'base64'
|
|
3
|
+
|
|
4
|
+
class EJSON
|
|
5
|
+
|
|
6
|
+
class Encryption
|
|
7
|
+
PrivateKeyMissing = Class.new(StandardError)
|
|
8
|
+
ExpectedEncryptedString = Class.new(StandardError)
|
|
9
|
+
|
|
10
|
+
def initialize(public_key_file, private_key_file)
|
|
11
|
+
@public_key_x509 = load_public_key(public_key_file)
|
|
12
|
+
if private_key_file
|
|
13
|
+
@private_key_rsa = load_private_key(private_key_file)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
ENCRYPTED = /\AENC\[(.*)\]\n*\z/m
|
|
18
|
+
|
|
19
|
+
def load(str)
|
|
20
|
+
if str =~ ENCRYPTED
|
|
21
|
+
decrypt_string($1)
|
|
22
|
+
else
|
|
23
|
+
raise ExpectedEncryptedString
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def dump(str)
|
|
28
|
+
if str =~ ENCRYPTED
|
|
29
|
+
str
|
|
30
|
+
else
|
|
31
|
+
"ENC[#{encrypt_string(str)}]"
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
private
|
|
36
|
+
|
|
37
|
+
def encrypt_string(plaintext)
|
|
38
|
+
cipher = OpenSSL::Cipher::AES.new(256, :CBC)
|
|
39
|
+
bin = OpenSSL::PKCS7.encrypt([@public_key_x509], plaintext, cipher, OpenSSL::PKCS7::BINARY).to_der
|
|
40
|
+
Base64.encode64(bin).tr("\n",'')
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def decrypt_string(ciphertext)
|
|
44
|
+
raise PrivateKeyMissing unless @private_key_rsa
|
|
45
|
+
bin = Base64.decode64(ciphertext)
|
|
46
|
+
pkcs7 = OpenSSL::PKCS7.new(bin)
|
|
47
|
+
pkcs7.decrypt(@private_key_rsa, @public_key_x509)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def load_public_key(public_key_file)
|
|
51
|
+
public_key_pem = File.read(public_key_file)
|
|
52
|
+
OpenSSL::X509::Certificate.new(public_key_pem)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def load_private_key(private_key_file)
|
|
56
|
+
private_key_pem = File.read(private_key_file)
|
|
57
|
+
OpenSSL::PKey::RSA.new(private_key_pem)
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
end
|
data/test/ejson_test.rb
ADDED
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
require 'minitest/autorun'
|
|
2
|
+
require 'tempfile'
|
|
3
|
+
|
|
4
|
+
require 'ejson/cli'
|
|
5
|
+
|
|
6
|
+
class CLITest < Minitest::Unit::TestCase
|
|
7
|
+
|
|
8
|
+
def test_ejson
|
|
9
|
+
f = Tempfile.create("encrypt")
|
|
10
|
+
|
|
11
|
+
f.puts JSON.dump({a: "b"})
|
|
12
|
+
f.close
|
|
13
|
+
|
|
14
|
+
encrypt f.path
|
|
15
|
+
|
|
16
|
+
first_run = JSON.load(File.read(f.path))
|
|
17
|
+
assert_match(/\AENC\[MIIB.*\]\z/, first_run["a"])
|
|
18
|
+
|
|
19
|
+
File.open(f.path, "w") { |f2|
|
|
20
|
+
f2.puts JSON.dump(first_run.merge({new_key: "new_value"}))
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
encrypt f.path
|
|
24
|
+
|
|
25
|
+
second_run = JSON.load(File.read(f.path))
|
|
26
|
+
|
|
27
|
+
assert_equal first_run["a"], second_run["a"]
|
|
28
|
+
assert_match(/\AENC\[MIIB.*\]\z/, second_run["new_key"])
|
|
29
|
+
|
|
30
|
+
val = JSON.parse(decrypt(f.path))
|
|
31
|
+
assert_equal({"a" => "b", "new_key" => "new_value"}, val)
|
|
32
|
+
ensure
|
|
33
|
+
File.unlink(f.path)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def test_default_key_exists
|
|
37
|
+
f = Tempfile.create("encrypt")
|
|
38
|
+
|
|
39
|
+
f.puts JSON.dump({a: "b"})
|
|
40
|
+
f.close
|
|
41
|
+
|
|
42
|
+
runcli "encrypt", f.path # no pubkey specified
|
|
43
|
+
|
|
44
|
+
first_run = JSON.load(File.read(f.path))
|
|
45
|
+
# We don't have the decryption key to this, and it may change over time,
|
|
46
|
+
# so just make sure it was encrypted.
|
|
47
|
+
assert_match(/\AENC\[MIIB.*\]\z/, first_run["a"])
|
|
48
|
+
ensure
|
|
49
|
+
File.unlink(f.path)
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def test_library_is_picky
|
|
53
|
+
f = Tempfile.create("decrypt")
|
|
54
|
+
f.puts JSON.dump({a: "b"})
|
|
55
|
+
f.close
|
|
56
|
+
assert_raises(EJSON::Encryption::ExpectedEncryptedString) {
|
|
57
|
+
decrypt(f.path)
|
|
58
|
+
}
|
|
59
|
+
ensure
|
|
60
|
+
File.unlink(f.path)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
private
|
|
64
|
+
|
|
65
|
+
def encrypt(path)
|
|
66
|
+
runcli "encrypt", "-p", pubkey, path
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def decrypt(path)
|
|
70
|
+
runcli "decrypt", "-p", pubkey, "-k", privkey, path
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def runcli(*args)
|
|
74
|
+
sio = StringIO.new
|
|
75
|
+
_stdout, $stdout = $stdout, sio
|
|
76
|
+
EJSON::CLI.start(args)
|
|
77
|
+
sio.string.chomp
|
|
78
|
+
ensure
|
|
79
|
+
$stdout = _stdout
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def pubkey ; File.expand_path("../publickey.pem", __FILE__); end
|
|
83
|
+
def privkey ; File.expand_path("../privatekey.pem", __FILE__); end
|
|
84
|
+
|
|
85
|
+
end
|
data/test/privatekey.pem
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
-----BEGIN RSA PRIVATE KEY-----
|
|
2
|
+
MIIEogIBAAKCAQEAunMnKCNM9NRDvaANZ3wSBTM7EA4fl3ix/QjwCp3k118n7+Jf
|
|
3
|
+
1DpdBAjqbx0jWVUZHjKan4t4ZHkCTKW4BXGzdEWVkFebYtYdxCm9DAiHFV53RscI
|
|
4
|
+
gVmzrxxpC8Lxa7RApam1iGPK7TXXlkMe+2d3Jij1hZdCHCYT48/DDBRtIEcXCZRg
|
|
5
|
+
nFkoSuvGbGwMBCxVhLTnvveIF5IgBV3la3vPJFfY62Hafuinpsy/hL4108pbrQcq
|
|
6
|
+
oiyb3OgflTe6JrBmA29qqWoCLAW+6XRgcHsOUfTYiBx6XFHQ42SfzQhu+FY57a38
|
|
7
|
+
Q3TkZLOb6abE6t5lsBqnJoE+dL/2WjLkhxQ/jQIDAQABAoIBAErqjBg/nuNdCt79
|
|
8
|
+
mYU0QBVg0WGRGzaEo5fVaIYLjXDQZj6oCfM/hDJj1rbQ0WxKmi4dDS4AH17XlInx
|
|
9
|
+
qHBfkEiu0PrPiLr857bzQme8YXK/o1OIE63NujopQzgbm1+4bKVj/HISDu6jTL2u
|
|
10
|
+
uJsxpplpqcWE0mZ3ElTeHTQUXQizdz12DPn5vgXvtVS0yFFBErE7aAKorRRFoLPq
|
|
11
|
+
OcajLIMODMo6huUAJW7uYR6PT6uwbt3Phc+VLQtdXpCCfLtDJK427G/5uJ/2vnY/
|
|
12
|
+
rLVWConeNZcUDWRuc34agiXA4yjErXdKXJ/yiEdz2pKtAerf+N9VCoIBLBala3oL
|
|
13
|
+
2BeMYY0CgYEA848omruvavfp4dJimdEHj0yTsFFggGHefoJWHG8Cvgyv9avISiAk
|
|
14
|
+
T5gB01pSjpTTGL+Ba2aeSPKgKZcGNjp/F5xzeZzuP2tMxT8bs2FR3y9tGmLnhvF8
|
|
15
|
+
JkKtlHilrGLt4pWh9eF+jiLDDmJE1N3fCU8TtIva+a/M60ZORA5ZSrcCgYEAw/k3
|
|
16
|
+
sJs72xhUhjrNdpzww5dpHYxmoOxhCTyKG1H0r4sQ0Jv9w4K3mrphp/WRygA2LylO
|
|
17
|
+
iCEc+56JJ6l4A6rdSFyV+YRtcdU7TKi9sarMDVBttqWsDkr/bnIIHE+QQhsScEBH
|
|
18
|
+
e7rHE+1NP5rPfDB7ibBJ3QCOCpjHbkhUGAZIU9sCgYBa176RWAepoiY98DaOoIRt
|
|
19
|
+
UmaTkQapW9ec4Ag2OsGPGTRYMWZXH33rogqsRjgcri2+QU+IO5I2KyjJ2maau17D
|
|
20
|
+
87quVXYXeXH87/jpAxeCYzIScWlhz5g6vQv5ILbKgWuw45axGxYU9apDJyv9KXQT
|
|
21
|
+
CMeUw8U88/E+n855W9C6KQKBgGtfKU7+zl2tR+o/X4FEXXmchIAnA7fZqxTHcZek
|
|
22
|
+
YJ6pX+4b+X5cKUKCKa0/k8AMO6O9SwS0t894vgbYCCRiQlk6OQV7tAcxYAsRTNWC
|
|
23
|
+
Ecidr27p+IngN3EI0z7HrO87K/AKl9/HpvlZBAD8Tf/qBFWdG+sVOb2+lU3sHP8I
|
|
24
|
+
uioPAoGAVWyvmQsABl3ydPrvVl4zk3AHm3Bnouy1vM1RchQzXp6OD/u5mNGJ37Ks
|
|
25
|
+
zIgipj/z9xf4J3ii5w0Qnxusq9Zy/6xKO1pgIEhiJUAYcm5jHGC51n7Y+d1NUPe1
|
|
26
|
+
gnJAzuwmvbefN800tmZJtWv7dWSc7whoFsdR1rNwrlZXUoNJzPk=
|
|
27
|
+
-----END RSA PRIVATE KEY-----
|
data/test/publickey.pem
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
-----BEGIN CERTIFICATE-----
|
|
2
|
+
MIIC5jCCAc6gAwIBAgIJAKY1nRwN7afeMA0GCSqGSIb3DQEBBQUAMAAwIBcNMTQw
|
|
3
|
+
MzE0MTc1ODQzWhgPMjI4NzEyMjgxNzU4NDNaMAAwggEiMA0GCSqGSIb3DQEBAQUA
|
|
4
|
+
A4IBDwAwggEKAoIBAQC6cycoI0z01EO9oA1nfBIFMzsQDh+XeLH9CPAKneTXXyfv
|
|
5
|
+
4l/UOl0ECOpvHSNZVRkeMpqfi3hkeQJMpbgFcbN0RZWQV5ti1h3EKb0MCIcVXndG
|
|
6
|
+
xwiBWbOvHGkLwvFrtEClqbWIY8rtNdeWQx77Z3cmKPWFl0IcJhPjz8MMFG0gRxcJ
|
|
7
|
+
lGCcWShK68ZsbAwELFWEtOe+94gXkiAFXeVre88kV9jrYdp+6KemzL+EvjXTylut
|
|
8
|
+
ByqiLJvc6B+VN7omsGYDb2qpagIsBb7pdGBwew5R9NiIHHpcUdDjZJ/NCG74Vjnt
|
|
9
|
+
rfxDdORks5vppsTq3mWwGqcmgT50v/ZaMuSHFD+NAgMBAAGjYTBfMB0GA1UdDgQW
|
|
10
|
+
BBTzh5Sf8+voPm2ZI6iHFQ+gItYb6zAwBgNVHSMEKTAngBTzh5Sf8+voPm2ZI6iH
|
|
11
|
+
FQ+gItYb66EEpAIwAIIJAKY1nRwN7afeMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcN
|
|
12
|
+
AQEFBQADggEBACr61pBSpsz931OUztFcDjm07u+vatM5XE5qAH18BZeKbXzCRz4j
|
|
13
|
+
9cAEYIYrtBdJZj3RLDzKB3Hn38BeuXebb4UlbzPJwIj1klHKH90Nwl84XWBCJqPX
|
|
14
|
+
rsGv7C5EOLAR1w/hxT+K2JC2LDJz9hkuDU1hjX1MeRpnJwXzPbHBQvgYb4lIgaOb
|
|
15
|
+
ikSlcTpkdG5fGafanyZwxDeQsy4tHAUP/jRQ4/Xzkzp0GzuX+v9d+2FXJLyoh6vJ
|
|
16
|
+
Fze3kL1+RH13Fn5NkdTAHpkX9AX0BuLKWslY3I/lusn3x9kPxVQTmTF2WQTVdKDg
|
|
17
|
+
FDvqWYvyLcuiWcfNUdy3EOpKLBKyyan3DZ8=
|
|
18
|
+
-----END CERTIFICATE-----
|
metadata
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: ejson
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.2.2
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Burke Libbey
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2014-04-15 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: thor
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '0.18'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '0.18'
|
|
27
|
+
description: Secret management by encrypting values in a JSON hash with a public/private
|
|
28
|
+
keypair
|
|
29
|
+
email:
|
|
30
|
+
- burke.libbey@shopify.com
|
|
31
|
+
executables:
|
|
32
|
+
- ejson
|
|
33
|
+
extensions: []
|
|
34
|
+
extra_rdoc_files: []
|
|
35
|
+
files:
|
|
36
|
+
- ".gitignore"
|
|
37
|
+
- Gemfile
|
|
38
|
+
- LICENSE.txt
|
|
39
|
+
- README.md
|
|
40
|
+
- Rakefile
|
|
41
|
+
- bin/ejson
|
|
42
|
+
- ejson.gemspec
|
|
43
|
+
- lib/ejson.rb
|
|
44
|
+
- lib/ejson/cli.rb
|
|
45
|
+
- lib/ejson/encryption.rb
|
|
46
|
+
- lib/ejson/version.rb
|
|
47
|
+
- test/ejson_test.rb
|
|
48
|
+
- test/privatekey.pem
|
|
49
|
+
- test/publickey.pem
|
|
50
|
+
homepage: https://github.com/Shopify/ejson
|
|
51
|
+
licenses:
|
|
52
|
+
- MIT
|
|
53
|
+
metadata: {}
|
|
54
|
+
post_install_message:
|
|
55
|
+
rdoc_options: []
|
|
56
|
+
require_paths:
|
|
57
|
+
- lib
|
|
58
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - ">="
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '0'
|
|
63
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
68
|
+
requirements: []
|
|
69
|
+
rubyforge_project:
|
|
70
|
+
rubygems_version: 2.2.0
|
|
71
|
+
signing_key:
|
|
72
|
+
specification_version: 4
|
|
73
|
+
summary: Asymmetric keywise encryption for JSON
|
|
74
|
+
test_files:
|
|
75
|
+
- test/ejson_test.rb
|
|
76
|
+
- test/privatekey.pem
|
|
77
|
+
- test/publickey.pem
|
|
78
|
+
has_rdoc:
|