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 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
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in ejson.gemspec
4
+ gemspec
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
@@ -0,0 +1,7 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task default: :test
4
+
5
+ task :test do
6
+ exec "ruby -I./lib test/ejson_test.rb"
7
+ end
data/bin/ejson ADDED
@@ -0,0 +1,4 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'ejson/cli'
4
+ EJSON::CLI.start
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
@@ -0,0 +1,3 @@
1
+ class Ejson
2
+ VERSION = "0.2.2"
3
+ end
@@ -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
@@ -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-----
@@ -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: