ejson 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|