ejson 0.4.0 → 1.0.0.rc1
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/bin/ejson +12 -2
- data/build/darwin-amd64/ejson +0 -0
- data/build/linux-amd64/ejson +0 -0
- data/ejson.gemspec +6 -9
- data/lib/ejson/version.rb +2 -2
- data/man/man1/ejson-decrypt.1.gz +0 -0
- data/man/man1/ejson-encrypt.1.gz +0 -0
- data/man/man1/ejson-keygen.1.gz +0 -0
- data/man/man1/ejson.1.gz +0 -0
- data/man/man5/ejson.5.gz +0 -0
- metadata +13 -47
- data/.gitignore +0 -17
- data/Gemfile +0 -4
- data/README.md +0 -61
- data/Rakefile +0 -7
- data/lib/ejson/cli.rb +0 -94
- data/lib/ejson/encryption.rb +0 -62
- data/lib/ejson.rb +0 -81
- data/test/ejson_test.rb +0 -124
- data/test/privatekey.pem +0 -27
- data/test/publickey.pem +0 -18
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: edf2ad7b024d89456d694953b6710bd2e6d41761
|
|
4
|
+
data.tar.gz: 2ea3452b0e34fb1401a078f1cee4b81e0b595ce4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e7801843e1f8e78e796f43ef8fe4131131351e27777c3aacd66cbba110aafc58a60268c43d91849df3b4d92356940a8493a416f638145730bac4466a92f432c8
|
|
7
|
+
data.tar.gz: 3c59e675ea9276bf587eb174cb1f62210917683f89ca3d676dd38674bb092404140f5d80034283a6fb127d6e6baffd9cb01069c7fcda0dccd69130d9d8d6d6ef
|
data/bin/ejson
CHANGED
|
@@ -1,4 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
|
+
platform = `uname -sm`
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
|
|
4
|
+
dir = case platform
|
|
5
|
+
when /^Darwin/ ; "darwin-amd64"
|
|
6
|
+
when /^Linux.*64/ ; "linux-amd64"
|
|
7
|
+
else
|
|
8
|
+
puts "Ejson is not supported on your platform."
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
bindir = File.expand_path("../../build/#{dir}", __FILE__)
|
|
12
|
+
ENV['PATH'] = "#{bindir}:#{ENV['PATH']}"
|
|
13
|
+
ENV['MANPATH'] = File.expand_path("../../man", __FILE__)
|
|
14
|
+
exec "ejson", *ARGV
|
|
Binary file
|
|
Binary file
|
data/ejson.gemspec
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# coding: utf-8
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
require File.expand_path('../lib/ejson/version', __FILE__)
|
|
3
|
+
|
|
4
|
+
files = File.read("MANIFEST").lines.map(&:chomp)
|
|
5
5
|
|
|
6
6
|
Gem::Specification.new do |spec|
|
|
7
7
|
spec.name = "ejson"
|
|
@@ -13,11 +13,8 @@ Gem::Specification.new do |spec|
|
|
|
13
13
|
spec.homepage = "https://github.com/Shopify/ejson"
|
|
14
14
|
spec.license = "MIT"
|
|
15
15
|
|
|
16
|
-
spec.files =
|
|
17
|
-
spec.executables =
|
|
18
|
-
spec.test_files =
|
|
16
|
+
spec.files = files
|
|
17
|
+
spec.executables = ["ejson"]
|
|
18
|
+
spec.test_files = []
|
|
19
19
|
spec.require_paths = ["lib"]
|
|
20
|
-
|
|
21
|
-
spec.add_runtime_dependency "thor", "~> 0.18"
|
|
22
|
-
spec.add_development_dependency "rake", "~> 10.3.2"
|
|
23
20
|
end
|
data/lib/ejson/version.rb
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
|
|
2
|
-
VERSION = "0.
|
|
1
|
+
module EJSON
|
|
2
|
+
VERSION = "1.0.0.rc1"
|
|
3
3
|
end
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/man/man1/ejson.1.gz
ADDED
|
Binary file
|
data/man/man5/ejson.5.gz
ADDED
|
Binary file
|
metadata
CHANGED
|
@@ -1,43 +1,15 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: ejson
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.0.rc1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Burke Libbey
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2014-
|
|
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
|
-
- !ruby/object:Gem::Dependency
|
|
28
|
-
name: rake
|
|
29
|
-
requirement: !ruby/object:Gem::Requirement
|
|
30
|
-
requirements:
|
|
31
|
-
- - "~>"
|
|
32
|
-
- !ruby/object:Gem::Version
|
|
33
|
-
version: 10.3.2
|
|
34
|
-
type: :development
|
|
35
|
-
prerelease: false
|
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
-
requirements:
|
|
38
|
-
- - "~>"
|
|
39
|
-
- !ruby/object:Gem::Version
|
|
40
|
-
version: 10.3.2
|
|
11
|
+
date: 2014-11-26 00:00:00.000000000 Z
|
|
12
|
+
dependencies: []
|
|
41
13
|
description: Secret management by encrypting values in a JSON hash with a public/private
|
|
42
14
|
keypair
|
|
43
15
|
email:
|
|
@@ -47,20 +19,17 @@ executables:
|
|
|
47
19
|
extensions: []
|
|
48
20
|
extra_rdoc_files: []
|
|
49
21
|
files:
|
|
50
|
-
- ".gitignore"
|
|
51
|
-
- Gemfile
|
|
52
22
|
- LICENSE.txt
|
|
53
|
-
- README.md
|
|
54
|
-
- Rakefile
|
|
55
23
|
- bin/ejson
|
|
24
|
+
- build/darwin-amd64/ejson
|
|
25
|
+
- build/linux-amd64/ejson
|
|
56
26
|
- ejson.gemspec
|
|
57
|
-
- lib/ejson.rb
|
|
58
|
-
- lib/ejson/cli.rb
|
|
59
|
-
- lib/ejson/encryption.rb
|
|
60
27
|
- lib/ejson/version.rb
|
|
61
|
-
-
|
|
62
|
-
-
|
|
63
|
-
-
|
|
28
|
+
- man/man1/ejson-decrypt.1.gz
|
|
29
|
+
- man/man1/ejson-encrypt.1.gz
|
|
30
|
+
- man/man1/ejson-keygen.1.gz
|
|
31
|
+
- man/man1/ejson.1.gz
|
|
32
|
+
- man/man5/ejson.5.gz
|
|
64
33
|
homepage: https://github.com/Shopify/ejson
|
|
65
34
|
licenses:
|
|
66
35
|
- MIT
|
|
@@ -76,16 +45,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
76
45
|
version: '0'
|
|
77
46
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
78
47
|
requirements:
|
|
79
|
-
- - "
|
|
48
|
+
- - ">"
|
|
80
49
|
- !ruby/object:Gem::Version
|
|
81
|
-
version:
|
|
50
|
+
version: 1.3.1
|
|
82
51
|
requirements: []
|
|
83
52
|
rubyforge_project:
|
|
84
53
|
rubygems_version: 2.2.2
|
|
85
54
|
signing_key:
|
|
86
55
|
specification_version: 4
|
|
87
56
|
summary: Asymmetric keywise encryption for JSON
|
|
88
|
-
test_files:
|
|
89
|
-
- test/ejson_test.rb
|
|
90
|
-
- test/privatekey.pem
|
|
91
|
-
- test/publickey.pem
|
|
57
|
+
test_files: []
|
data/.gitignore
DELETED
data/Gemfile
DELETED
data/README.md
DELETED
|
@@ -1,61 +0,0 @@
|
|
|
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
|
-
By default, it uses a public key that you won't be able to decrypt (and
|
|
28
|
-
shouldn't use because we *can* decrypt it!). You can use your own by following
|
|
29
|
-
the "Custom keypair" directions below. Feel free to fork the gem to reference
|
|
30
|
-
your own keypair by default.
|
|
31
|
-
|
|
32
|
-
#### 3) Decrypt the file:
|
|
33
|
-
|
|
34
|
-
ejson decrypt -k ~/.keys/ejson.priv.pem -p config/ejson.pub.pem secrets.production.ejson > secrets.production.json
|
|
35
|
-
# OR
|
|
36
|
-
ejson decrypt -i -k ~/.keys/ejson.priv.pem -p config/ejson.pub.pem secrets.production.ejson
|
|
37
|
-
|
|
38
|
-
Unlike encrypt, decrypt doesn't update the file in-place; it prints the
|
|
39
|
-
decrypted contents to stdout. It also requires access to the private key
|
|
40
|
-
created in step 1. By default, the secrets will be decrypted to stdout,
|
|
41
|
-
but passing the `-i` flag causes them to be overwritten to the input file.
|
|
42
|
-
|
|
43
|
-
#### See `ejson help` for more information.
|
|
44
|
-
|
|
45
|
-
## Custom keypair:
|
|
46
|
-
|
|
47
|
-
We use a single keypair internally; the default public key is fetched from S3
|
|
48
|
-
on each run. However, you can generate your own keypair like so:
|
|
49
|
-
|
|
50
|
-
openssl req -x509 -nodes -days 100000 -newkey rsa:2048 -keyout privatekey.pem -out publickey.pem -subj '/'
|
|
51
|
-
|
|
52
|
-
`publickey.pem` and `privatekey.pem` are created. Move `privatekey.pem`
|
|
53
|
-
somewhere more private, and move `publickey.pem` somewhere more public.
|
|
54
|
-
|
|
55
|
-
Then you can encrypt like:
|
|
56
|
-
|
|
57
|
-
ejson encrypt -p publickey.pem secrets.ejson
|
|
58
|
-
|
|
59
|
-
If you'd like to fork the gem to reference your own public key, that
|
|
60
|
-
information lives around line 10 of `lib/ejson/cli.rb`.
|
|
61
|
-
|
data/Rakefile
DELETED
data/lib/ejson/cli.rb
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
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
|
-
method_option :out, type: :string, default: false, aliases: "-o", desc: "Write to a file rather than stdout"
|
|
16
|
-
def decrypt(file)
|
|
17
|
-
ciphertext = File.read(file)
|
|
18
|
-
ej = EJSON.new(pubkey, options[:privkey])
|
|
19
|
-
output = JSON.pretty_generate(ej.load(ciphertext).decrypt_all)
|
|
20
|
-
if options[:out]
|
|
21
|
-
File.open(options[:out], "w") { |f| f.puts output }
|
|
22
|
-
puts "Wrote #{output.size} bytes to #{options[:out]}"
|
|
23
|
-
else
|
|
24
|
-
puts output
|
|
25
|
-
end
|
|
26
|
-
rescue EJSON::Encryption::PrivateKeyMissing => e
|
|
27
|
-
fatal("can't decrypt data without private key (specify path with -k)", e)
|
|
28
|
-
rescue EJSON::Encryption::ExpectedEncryptedString => e
|
|
29
|
-
fatal("can't decrypt data with cleartext strings (use ejson recrypt first)", e)
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
desc "encrypt [file=**/*.ejson]", "encrypt an ejson file in place (encrypt any unencrypted values)"
|
|
33
|
-
def encrypt(file="**/*.ejson")
|
|
34
|
-
ej = EJSON.new(pubkey)
|
|
35
|
-
fpaths = Dir.glob(file)
|
|
36
|
-
if fpaths.empty?
|
|
37
|
-
fatal("no ejson files found!", nil)
|
|
38
|
-
end
|
|
39
|
-
fpaths.each do |fpath|
|
|
40
|
-
data = ej.load(File.read(fpath))
|
|
41
|
-
dump = data.dump
|
|
42
|
-
File.open(fpath, "w") { |f| f.puts dump }
|
|
43
|
-
puts "Wrote #{dump.size+1} bytes to #{fpath}"
|
|
44
|
-
end
|
|
45
|
-
rescue OpenSSL::X509::CertificateError => e
|
|
46
|
-
fatal("invalid certificate", e)
|
|
47
|
-
end
|
|
48
|
-
|
|
49
|
-
desc "version", "show version information"
|
|
50
|
-
def version
|
|
51
|
-
require 'ejson/version'
|
|
52
|
-
puts "ejson version #{EJSON::VERSION}"
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
private
|
|
56
|
-
|
|
57
|
-
def fatal(str, err=str)
|
|
58
|
-
raise err if defined?(Minitest)
|
|
59
|
-
msg = $stderr.tty? ? "\x1b[31m#{str}\x1b[0m" : str
|
|
60
|
-
$stderr.puts msg
|
|
61
|
-
exit 1
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def get_input(file)
|
|
65
|
-
return File.read(file) if file
|
|
66
|
-
$stdin.read
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def pubkey
|
|
70
|
-
@pubkey ||= _pubkey
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
def _pubkey
|
|
74
|
-
if options[:pubkey] =~ %r{https://}
|
|
75
|
-
uri = URI.parse(options[:pubkey])
|
|
76
|
-
http = Net::HTTP.new(uri.host, uri.port)
|
|
77
|
-
http.use_ssl = true
|
|
78
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_PEER
|
|
79
|
-
req = Net::HTTP::Get.new(URI.parse(options[:pubkey]).request_uri)
|
|
80
|
-
resp = http.request(req)
|
|
81
|
-
resp.value # raises on code >399
|
|
82
|
-
f = Tempfile.new("pubkey")
|
|
83
|
-
f.write resp.body
|
|
84
|
-
f.close
|
|
85
|
-
at_exit { f.unlink }
|
|
86
|
-
f.path
|
|
87
|
-
else
|
|
88
|
-
options[:pubkey]
|
|
89
|
-
end
|
|
90
|
-
end
|
|
91
|
-
|
|
92
|
-
end
|
|
93
|
-
end
|
|
94
|
-
|
data/lib/ejson/encryption.rb
DELETED
|
@@ -1,62 +0,0 @@
|
|
|
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, private_key)
|
|
11
|
-
@public_key_x509 = load_public_key(public_key)
|
|
12
|
-
if private_key
|
|
13
|
-
@private_key_rsa = load_private_key(private_key)
|
|
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)
|
|
51
|
-
OpenSSL::X509::Certificate.new(get_pem(public_key))
|
|
52
|
-
end
|
|
53
|
-
|
|
54
|
-
def load_private_key(private_key)
|
|
55
|
-
OpenSSL::PKey::RSA.new(get_pem(private_key))
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
def get_pem(string)
|
|
59
|
-
string =~ /^-----BEGIN/ ? string : File.read(string)
|
|
60
|
-
end
|
|
61
|
-
end
|
|
62
|
-
end
|
data/lib/ejson.rb
DELETED
|
@@ -1,81 +0,0 @@
|
|
|
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, private_key = nil)
|
|
10
|
-
@encryption = Encryption.new(public_key, private_key)
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def load(json_text)
|
|
14
|
-
Data.new(JSON.load(json_text), @encryption)
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
def serializer
|
|
18
|
-
@serializer ||= Serializer.new(@encryption)
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
class Serializer
|
|
22
|
-
|
|
23
|
-
def initialize(encryption)
|
|
24
|
-
@encryption = encryption
|
|
25
|
-
end
|
|
26
|
-
|
|
27
|
-
def dump(data)
|
|
28
|
-
data = Data.new(data, @encryption) unless data.is_a?(Data)
|
|
29
|
-
data.dump
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
def load(data)
|
|
33
|
-
Data.new(JSON.parse(data), @encryption).decrypt_all
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
class Data
|
|
39
|
-
extend Forwardable
|
|
40
|
-
def_delegators :@data, :[]=
|
|
41
|
-
|
|
42
|
-
attr_reader :encryption
|
|
43
|
-
def initialize(data, encryption)
|
|
44
|
-
@data, @encryption = data, encryption
|
|
45
|
-
end
|
|
46
|
-
|
|
47
|
-
def dump
|
|
48
|
-
JSON.pretty_generate(encrypt_all(@data))
|
|
49
|
-
end
|
|
50
|
-
|
|
51
|
-
def encrypt_all(data=@data)
|
|
52
|
-
case data
|
|
53
|
-
when Hash
|
|
54
|
-
Hash[ data.map { |k,v| [k, encrypt_all(v)] } ]
|
|
55
|
-
when Array
|
|
56
|
-
data.map { |d| encrypt_all(d) }
|
|
57
|
-
when String
|
|
58
|
-
encryption.dump(data)
|
|
59
|
-
else
|
|
60
|
-
data
|
|
61
|
-
end
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
def decrypt_all(data=@data)
|
|
65
|
-
case data
|
|
66
|
-
when Hash
|
|
67
|
-
Hash[ data.map { |k,v| [k, decrypt_all(v)] } ]
|
|
68
|
-
when Array
|
|
69
|
-
data.map { |d| decrypt_all(d) }
|
|
70
|
-
when String
|
|
71
|
-
encryption.load(data)
|
|
72
|
-
else
|
|
73
|
-
data
|
|
74
|
-
end
|
|
75
|
-
end
|
|
76
|
-
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
end
|
|
80
|
-
|
|
81
|
-
|
data/test/ejson_test.rb
DELETED
|
@@ -1,124 +0,0 @@
|
|
|
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.new("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_inplace
|
|
37
|
-
f = Tempfile.new("encrypt")
|
|
38
|
-
|
|
39
|
-
f.puts JSON.dump({a: "b"})
|
|
40
|
-
f.close
|
|
41
|
-
|
|
42
|
-
runcli "encrypt", "-p", pubkey, f.path
|
|
43
|
-
encrypted = JSON.load(File.read(f.path))
|
|
44
|
-
assert_match(/\AENC\[MIIB.*\]\z/, encrypted["a"])
|
|
45
|
-
|
|
46
|
-
runcli "decrypt", "-o", f.path, "-p", pubkey, "-k", privkey, f.path
|
|
47
|
-
decrypted = JSON.load(File.read(f.path))
|
|
48
|
-
refute_match(/\AENC\[MIIB.*\]\z/, decrypted["a"])
|
|
49
|
-
ensure
|
|
50
|
-
File.unlink(f.path)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def test_default_key_exists
|
|
54
|
-
f = Tempfile.new("encrypt")
|
|
55
|
-
|
|
56
|
-
f.puts JSON.dump({a: "b"})
|
|
57
|
-
f.close
|
|
58
|
-
|
|
59
|
-
runcli "encrypt", f.path # no pubkey specified
|
|
60
|
-
|
|
61
|
-
first_run = JSON.load(File.read(f.path))
|
|
62
|
-
# We don't have the decryption key to this, and it may change over time,
|
|
63
|
-
# so just make sure it was encrypted.
|
|
64
|
-
assert_match(/\AENC\[MIIB.*\]\z/, first_run["a"])
|
|
65
|
-
ensure
|
|
66
|
-
File.unlink(f.path)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def test_library_is_picky
|
|
70
|
-
f = Tempfile.new("decrypt")
|
|
71
|
-
f.puts JSON.dump({a: "b"})
|
|
72
|
-
f.close
|
|
73
|
-
assert_raises(EJSON::Encryption::ExpectedEncryptedString) {
|
|
74
|
-
decrypt(f.path)
|
|
75
|
-
}
|
|
76
|
-
ensure
|
|
77
|
-
File.unlink(f.path)
|
|
78
|
-
end
|
|
79
|
-
|
|
80
|
-
def test_key_strings
|
|
81
|
-
public_key = File.read(pubkey)
|
|
82
|
-
private_key = File.read(privkey)
|
|
83
|
-
|
|
84
|
-
@enc = EJSON::Encryption.new(public_key, private_key)
|
|
85
|
-
|
|
86
|
-
assert_equal public_key, @enc.instance_variable_get(:@public_key_x509).to_s
|
|
87
|
-
assert_equal private_key, @enc.instance_variable_get(:@private_key_rsa).to_s
|
|
88
|
-
end
|
|
89
|
-
|
|
90
|
-
def test_serializer_api
|
|
91
|
-
serializer = EJSON.new(pubkey, privkey).serializer
|
|
92
|
-
data = {'foo' => 'bar'}
|
|
93
|
-
|
|
94
|
-
assert_equal data, serializer.load(serializer.dump(data))
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
def test_serializer_safety
|
|
98
|
-
serializer = EJSON.new(pubkey, privkey).serializer
|
|
99
|
-
refute serializer.dump('foo' => 'bar').include?('bar')
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
private
|
|
103
|
-
|
|
104
|
-
def encrypt(path)
|
|
105
|
-
runcli "encrypt", "-p", pubkey, path
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
def decrypt(path)
|
|
109
|
-
runcli "decrypt", "-p", pubkey, "-k", privkey, path
|
|
110
|
-
end
|
|
111
|
-
|
|
112
|
-
def runcli(*args)
|
|
113
|
-
sio = StringIO.new
|
|
114
|
-
_stdout, $stdout = $stdout, sio
|
|
115
|
-
EJSON::CLI.start(args)
|
|
116
|
-
sio.string.chomp
|
|
117
|
-
ensure
|
|
118
|
-
$stdout = _stdout
|
|
119
|
-
end
|
|
120
|
-
|
|
121
|
-
def pubkey ; File.expand_path("../publickey.pem", __FILE__); end
|
|
122
|
-
def privkey ; File.expand_path("../privatekey.pem", __FILE__); end
|
|
123
|
-
|
|
124
|
-
end
|
data/test/privatekey.pem
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
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
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
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-----
|