evervault 0.1.1 → 1.0.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/.github/CODEOWNERS +6 -0
- data/.github/pull_request_template.md +6 -0
- data/.github/workflows/release.yml +23 -4
- data/.github/workflows/run-tests.yml +1 -1
- data/Gemfile +2 -1
- data/README.md +68 -43
- data/lib/evervault/client.rb +25 -17
- data/lib/evervault/crypto/client.rb +74 -47
- data/lib/evervault/crypto/curves/base.rb +38 -0
- data/lib/evervault/crypto/curves/p256.rb +25 -0
- data/lib/evervault/errors/error_map.rb +6 -2
- data/lib/evervault/errors/errors.rb +6 -0
- data/lib/evervault/http/request.rb +19 -48
- data/lib/evervault/http/request_handler.rb +68 -0
- data/lib/evervault/http/request_intercept.rb +135 -0
- data/lib/evervault/models/cage.rb +2 -2
- data/lib/evervault/version.rb +2 -1
- data/lib/evervault.rb +2 -18
- metadata +9 -5
- data/Gemfile.lock +0 -58
- data/lib/evervault/crypto/key.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7382a19b6a9fa82b2d37caa8f3e440f7bfce74bc18a237f13bdbd598dbb0d855
|
4
|
+
data.tar.gz: 78d8c04663caeca5ec0ff9336f403ec496b69fa61b25f134c9fae66eff91ab78
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f0154d3c18eaa8685e6f1d26069c286609eaeb0bf8cc56049f53870ea3d374d0c7f45aeb855e47094dfc30b8a55d54d1122fac2ffc008e8a252ca843e711081e
|
7
|
+
data.tar.gz: 3915f0582de2f85ca71e9769f1cb4bf2bdd3013f50903beb8ae1946a39d9dd87733e340159aaf5c5192872ab1685ab39d6decd43d45487bd56dc8a4ea1914b4c
|
data/.github/CODEOWNERS
ADDED
@@ -0,0 +1,6 @@
|
|
1
|
+
# This file is used to automatically request reviews on PRs.
|
2
|
+
|
3
|
+
# These owners will be the default owners for everything in
|
4
|
+
# the repo, unless a match on a later line takes precedence.
|
5
|
+
# "@evervault/product-engineering" below requests review from all members of Product Engineering.
|
6
|
+
* @evervault/product-engineering
|
@@ -1,19 +1,38 @@
|
|
1
1
|
name: Publish Gem
|
2
2
|
|
3
|
-
on:
|
4
|
-
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
tags:
|
6
|
+
- v*
|
5
7
|
|
6
8
|
jobs:
|
7
|
-
|
9
|
+
test:
|
10
|
+
strategy:
|
11
|
+
fail-fast: false
|
12
|
+
matrix:
|
13
|
+
os: [ubuntu, macos]
|
14
|
+
ruby: [2.5, 2.6, 2.7, 3.1, truffleruby]
|
15
|
+
runs-on: ${{ matrix.os }}-latest
|
16
|
+
continue-on-error: ${{ endsWith(matrix.ruby, 'head') || matrix.ruby == 'debug' }}
|
17
|
+
steps:
|
18
|
+
- uses: actions/checkout@v2
|
19
|
+
- uses: ruby/setup-ruby@v1
|
20
|
+
with:
|
21
|
+
ruby-version: ${{ matrix.ruby }}
|
22
|
+
- run: bundle install
|
23
|
+
- run: bundle exec rake
|
24
|
+
|
8
25
|
build:
|
9
26
|
runs-on: ubuntu-latest
|
10
|
-
|
27
|
+
needs: test
|
28
|
+
|
11
29
|
steps:
|
12
30
|
- uses: actions/checkout@v2
|
13
31
|
- uses: ruby/setup-ruby@v1
|
14
32
|
with:
|
15
33
|
ruby-version: 2.7
|
16
34
|
- name: Release Gem
|
35
|
+
if: contains(github.ref, 'refs/tags/v')
|
17
36
|
run: ./scripts/release.sh
|
18
37
|
env:
|
19
38
|
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
@@ -7,7 +7,7 @@ jobs:
|
|
7
7
|
fail-fast: false
|
8
8
|
matrix:
|
9
9
|
os: [ubuntu, macos]
|
10
|
-
ruby: [2.5, 2.6, 2.7,
|
10
|
+
ruby: [2.5, 2.6, 2.7, 3.1, truffleruby]
|
11
11
|
runs-on: ${{ matrix.os }}-latest
|
12
12
|
continue-on-error: ${{ endsWith(matrix.ruby, 'head') || matrix.ruby == 'debug' }}
|
13
13
|
steps:
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,94 +1,115 @@
|
|
1
|
-
|
2
|
-
<p align="center">
|
3
|
-
<img src="res/logo.svg">
|
4
|
-
</p>
|
1
|
+
[](https://evervault.com/)
|
5
2
|
|
6
|
-
|
7
|
-
<a href="https://github.com/evervault/evervault-ruby/actions?query=workflow%3Aevervault-unit-tests"><img alt="Evervault unit tests status" src="https://github.com/evervault/evervault-ruby/workflows/evervault-unit-tests/badge.svg"></a>
|
8
|
-
</p>
|
3
|
+
[](https://github.com/evervault/evervault-ruby/actions?query=workflow%3Aevervault-unit-tests)
|
9
4
|
|
5
|
+
# Evervault Ruby SDK
|
6
|
+
|
7
|
+
The [Evervault](https://evervault.com) Ruby SDK is a toolkit for encrypting data as it enters your server, working with Cages, and proxying your outbound API requests to specific domains through [Outbound Relay](https://docs.evervault.com/concepts/relay/outbound-interception) to allow them to be decrypted before reaching their target.
|
10
8
|
|
11
9
|
## Getting Started
|
12
|
-
Ruby SDK for [Evervault](https://evervault.com)
|
13
|
-
### Prerequisites
|
14
10
|
|
15
|
-
|
11
|
+
Before starting with the Evervault Ruby SDK, you will need to [create an account](https://app.evervault.com/register) and a team.
|
12
|
+
|
13
|
+
For full installation support, [book time here](https://calendly.com/evervault/cages-onboarding).
|
14
|
+
|
15
|
+
## Documentation
|
16
16
|
|
17
|
-
|
17
|
+
See the Evervault [Ruby SDK documentation](https://docs.evervault.com/ruby).
|
18
18
|
|
19
19
|
## Installation
|
20
20
|
|
21
|
-
|
21
|
+
There are two ways to install the Ruby SDK.
|
22
|
+
|
23
|
+
#### 1. With Gemfile
|
24
|
+
|
25
|
+
Add this line to your application's `Gemfile`:
|
22
26
|
|
23
27
|
```ruby
|
24
28
|
gem 'evervault'
|
25
29
|
```
|
26
30
|
|
27
|
-
|
31
|
+
Then, run:
|
32
|
+
|
28
33
|
```sh
|
29
|
-
|
34
|
+
bundle install
|
30
35
|
```
|
31
|
-
|
36
|
+
#### 2. By yourself
|
37
|
+
|
38
|
+
Just run:
|
39
|
+
|
32
40
|
```sh
|
33
|
-
|
41
|
+
gem install evervault
|
34
42
|
```
|
35
43
|
|
36
44
|
## Setup
|
37
45
|
|
38
|
-
|
46
|
+
To make Evervault available for use in your app:
|
47
|
+
|
39
48
|
```ruby
|
40
49
|
require "evervault"
|
41
50
|
|
42
|
-
# Initialize the client with your team's
|
51
|
+
# Initialize the client with your team's API key
|
43
52
|
Evervault.api_key = <YOUR-API-KEY>
|
44
53
|
|
45
54
|
# Encrypt your data and run a cage
|
46
|
-
|
55
|
+
encrypted_data = Evervault.encrypt({ hello: 'World!' })
|
56
|
+
|
57
|
+
# Process the encrypted data in a Cage
|
58
|
+
result = Evervault.run(<CAGE-NAME>, encrypted_data)
|
47
59
|
```
|
48
60
|
|
49
|
-
|
61
|
+
## Reference
|
50
62
|
|
51
|
-
|
52
|
-
```ruby
|
53
|
-
require "evervault"
|
63
|
+
The Evervault Ruby SDK exposes eight methods.
|
54
64
|
|
55
|
-
|
56
|
-
evervault = Evervault::Client.new(api_key: <YOUR-API-KEY>)
|
65
|
+
### Evervault.encrypt
|
57
66
|
|
58
|
-
|
59
|
-
|
67
|
+
`Evervault.encrypt` encrypts data for use in your [Evervault Cages](https://docs.evervault.com/tutorial). To encrypt data on your server, simply pass a supported value into the `Evervault.encrypt` method and then you can store the encrypted data in your database as normal.
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
Evervault.encrypt(data = String | Number | Boolean | Hash | Array)
|
60
71
|
```
|
61
72
|
|
62
|
-
|
73
|
+
| Parameter | Type | Description |
|
74
|
+
| --------- | ---- | ----------- |
|
75
|
+
| data | `String`, `Number`, `Boolean`, `Hash`, `Array` | Data to be encrypted |
|
63
76
|
|
64
|
-
### Evervault.
|
77
|
+
### Evervault.relay
|
65
78
|
|
66
|
-
|
79
|
+
`Evervault.relay` specifies which domains should be proxied through outbound relay. See [Outbound Relay](https://docs.evervault.com/concepts/relay/outbound-interception) to learn more.
|
67
80
|
|
68
81
|
```ruby
|
69
|
-
Evervault.
|
82
|
+
Evervault.relay(decryption_domains = Array)
|
70
83
|
```
|
71
84
|
|
72
85
|
| Parameter | Type | Description |
|
73
86
|
| --------- | ---- | ----------- |
|
74
|
-
|
|
87
|
+
| decryption_domains | `Array` | Requests sent to any of the domains listed will be proxied through outbound relay |
|
75
88
|
|
76
89
|
### Evervault.run
|
77
90
|
|
78
|
-
|
91
|
+
`Evervault.run` invokes a Cage with a given payload.
|
79
92
|
|
80
93
|
```ruby
|
81
|
-
Evervault.run(cage_name = String, data = Hash)
|
94
|
+
Evervault.run(cage_name = String, data = Hash[, options = Hash])
|
82
95
|
```
|
83
96
|
|
84
97
|
| Parameter | Type | Description |
|
85
98
|
| --------- | ---- | ----------- |
|
86
|
-
| cageName | String | Name of the
|
87
|
-
| data | Hash | Payload for the
|
99
|
+
| cageName | String | Name of the Cage to be run |
|
100
|
+
| data | Hash | Payload for the Cage |
|
101
|
+
| options | Hash | [Options for the Cage run](#Cage-Run-Options) |
|
102
|
+
|
103
|
+
#### Cage Run Options
|
104
|
+
|
105
|
+
| Option | Type | Default | Description |
|
106
|
+
| ------ | ---- | ------- | ----------- |
|
107
|
+
| `async` | `Boolean` | `false` | Run your Cage in async mode. Async Cage runs will be queued for processing. |
|
108
|
+
| `version` | `Integer` | `nil` | Specify the version of your Cage to run. By default, the latest version will be run. |
|
88
109
|
|
89
110
|
### Evervault.encrypt_and_run
|
90
111
|
|
91
|
-
Encrypt your data and use it as the payload to invoke the
|
112
|
+
Encrypt your data and use it as the payload to invoke the Cage.
|
92
113
|
|
93
114
|
```ruby
|
94
115
|
Evervault.encrypt_and_run(cage_name = String, data = Hash)
|
@@ -96,7 +117,7 @@ Evervault.encrypt_and_run(cage_name = String, data = Hash)
|
|
96
117
|
|
97
118
|
| Parameter | Type | Description |
|
98
119
|
| --------- | ---- | ----------- |
|
99
|
-
| cageName | String | Name of the
|
120
|
+
| cageName | String | Name of the Cage to be run |
|
100
121
|
| data | dict | Data to be encrypted |
|
101
122
|
|
102
123
|
### Evervault.cages
|
@@ -129,7 +150,7 @@ Evervault.cages
|
|
129
150
|
|
130
151
|
### Evervault.cage_list
|
131
152
|
|
132
|
-
Return a `CageList` object, containing a list of your team's
|
153
|
+
Return a `CageList` object, containing a list of your team's Cages
|
133
154
|
|
134
155
|
```ruby
|
135
156
|
Evervault.cage_list
|
@@ -167,7 +188,7 @@ Evervault.cage_list
|
|
167
188
|
|
168
189
|
#### CageList.to_hash
|
169
190
|
|
170
|
-
Converts a list of
|
191
|
+
Converts a list of Cages to a hash with keys of CageName => Cage Model
|
171
192
|
|
172
193
|
```ruby
|
173
194
|
Evervault.cage_list.to_hash
|
@@ -210,9 +231,9 @@ Evervault.cage_list.to_hash
|
|
210
231
|
|
211
232
|
### Evervault::Models::Cage.run
|
212
233
|
|
213
|
-
Each Cage model exposes a `run` method, which allows you to run that particular
|
234
|
+
Each Cage model exposes a `run` method, which allows you to run that particular Cage.
|
214
235
|
|
215
|
-
*Note*: this does not encrypt data before running the
|
236
|
+
*Note*: this does not encrypt data before running the Cage.
|
216
237
|
```ruby
|
217
238
|
cage = Evervault.cage_list.cages[0]
|
218
239
|
cage.run({'name': 'testing'})
|
@@ -221,7 +242,8 @@ cage.run({'name': 'testing'})
|
|
221
242
|
|
222
243
|
| Parameter | Type | Description |
|
223
244
|
| --------- | ---- | ----------- |
|
224
|
-
| data | Hash | Payload for the
|
245
|
+
| data | Hash | Payload for the Cage |
|
246
|
+
| options | Hash | [Options for the Cage run](#Cage-Run-Options) |
|
225
247
|
|
226
248
|
## Development
|
227
249
|
|
@@ -233,6 +255,9 @@ To install this gem onto your local machine, run `bundle exec rake install`. To
|
|
233
255
|
|
234
256
|
Bug reports and pull requests are welcome on GitHub at https://github.com/evervault/evervault-ruby.
|
235
257
|
|
258
|
+
## Feedback
|
259
|
+
|
260
|
+
Questions or feedback? [Let us know](mailto:support@evervault.com).
|
236
261
|
|
237
262
|
## License
|
238
263
|
|
data/lib/evervault/client.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
require_relative "http/request"
|
2
|
+
require_relative "http/request_handler"
|
3
|
+
require_relative "http/request_intercept"
|
2
4
|
require_relative "crypto/client"
|
3
5
|
require_relative "models/cage_list"
|
4
6
|
|
@@ -9,33 +11,35 @@ module Evervault
|
|
9
11
|
def initialize(
|
10
12
|
api_key:,
|
11
13
|
base_url: "https://api.evervault.com/",
|
12
|
-
cage_run_url: "https://
|
13
|
-
|
14
|
+
cage_run_url: "https://run.evervault.com/",
|
15
|
+
relay_url: "https://relay.evervault.com:8443",
|
16
|
+
ca_host: "https://ca.evervault.com",
|
17
|
+
request_timeout: 30,
|
18
|
+
curve: 'prime256v1'
|
14
19
|
)
|
15
|
-
@
|
16
|
-
@
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
base_url: base_url,
|
23
|
-
cage_run_url: cage_run_url
|
20
|
+
@request = Evervault::Http::Request.new(timeout: request_timeout, api_key: api_key)
|
21
|
+
@intercept = Evervault::Http::RequestIntercept.new(
|
22
|
+
request: @request, ca_host: ca_host, api_key: api_key, relay_url: relay_url
|
23
|
+
)
|
24
|
+
@request_handler =
|
25
|
+
Evervault::Http::RequestHandler.new(
|
26
|
+
request: @request, base_url: base_url, cage_run_url: cage_run_url, cert: @intercept
|
24
27
|
)
|
25
|
-
@crypto_client = Evervault::Crypto::Client.new(
|
28
|
+
@crypto_client = Evervault::Crypto::Client.new(request_handler: @request_handler, curve: curve)
|
29
|
+
@intercept.setup()
|
26
30
|
end
|
27
31
|
|
28
32
|
def encrypt(data)
|
29
33
|
@crypto_client.encrypt(data)
|
30
34
|
end
|
31
35
|
|
32
|
-
def run(cage_name, encrypted_data)
|
33
|
-
@
|
36
|
+
def run(cage_name, encrypted_data, options = {})
|
37
|
+
@request_handler.post(cage_name, encrypted_data, options: options, cage_run: true)
|
34
38
|
end
|
35
39
|
|
36
|
-
def encrypt_and_run(cage_name, data)
|
40
|
+
def encrypt_and_run(cage_name, data, options = {})
|
37
41
|
encrypted_data = encrypt(data)
|
38
|
-
run(cage_name, encrypted_data)
|
42
|
+
run(cage_name, encrypted_data, options)
|
39
43
|
end
|
40
44
|
|
41
45
|
def cages
|
@@ -43,8 +47,12 @@ module Evervault
|
|
43
47
|
end
|
44
48
|
|
45
49
|
def cage_list
|
46
|
-
cages = @
|
50
|
+
cages = @request_handler.get("cages")
|
47
51
|
@cage_list ||= Evervault::Models::CageList.new(cages: cages["cages"], request: @request)
|
48
52
|
end
|
53
|
+
|
54
|
+
def relay(decryption_domains=[])
|
55
|
+
@intercept.setup_domains(decryption_domains)
|
56
|
+
end
|
49
57
|
end
|
50
58
|
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require_relative "../errors/errors"
|
2
|
-
require_relative "
|
2
|
+
require_relative "curves/p256"
|
3
|
+
require_relative "../version"
|
3
4
|
require "openssl"
|
4
5
|
require "base64"
|
5
6
|
require "json"
|
@@ -8,80 +9,106 @@ require "securerandom"
|
|
8
9
|
module Evervault
|
9
10
|
module Crypto
|
10
11
|
class Client
|
11
|
-
attr_reader :
|
12
|
-
def initialize(
|
13
|
-
@
|
12
|
+
attr_reader :request_handler
|
13
|
+
def initialize(request_handler:, curve:)
|
14
|
+
@curve = curve
|
15
|
+
@p256 = Evervault::Crypto::Curves::P256.new()
|
16
|
+
@ev_version = base_64_remove_padding(
|
17
|
+
Base64.strict_encode64(EV_VERSION[curve])
|
18
|
+
)
|
19
|
+
response = request_handler.get("cages/key")
|
20
|
+
key = @curve == 'secp256k1' ? 'ecdhKey' : 'ecdhP256Key'
|
21
|
+
@team_key = response[key]
|
14
22
|
end
|
15
23
|
|
16
24
|
def encrypt(data)
|
17
25
|
raise Evervault::Errors::UndefinedDataError.new(
|
18
26
|
"Data is required for encryption"
|
19
|
-
) if data.nil? || data.empty?
|
27
|
+
) if data.nil? || (data.instance_of?(String) && data.empty?)
|
28
|
+
|
29
|
+
raise Evervault::Errors::UnsupportedEncryptType.new(
|
30
|
+
"Encryption is not supported for #{data.class}"
|
31
|
+
) if !(encryptable_data?(data) || data.instance_of?(Hash) || data.instance_of?(Array))
|
20
32
|
|
21
|
-
|
22
|
-
encrypt_hash(data)
|
23
|
-
elsif encryptable_data?(data)
|
24
|
-
encrypt_string(data)
|
25
|
-
end
|
33
|
+
traverse_and_encrypt(data)
|
26
34
|
end
|
27
35
|
|
28
|
-
private def encrypt_string(
|
29
|
-
cipher = OpenSSL::Cipher
|
36
|
+
private def encrypt_string(data_to_encrypt)
|
37
|
+
cipher = OpenSSL::Cipher.new('aes-256-gcm').encrypt
|
38
|
+
|
39
|
+
shared_key = generate_shared_key()
|
40
|
+
cipher.key = shared_key
|
41
|
+
|
30
42
|
iv = cipher.random_iv
|
31
|
-
root_key = cipher.random_key
|
32
|
-
cipher.key = root_key
|
33
43
|
cipher.iv = iv
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
44
|
+
|
45
|
+
if (@curve == 'prime256v1')
|
46
|
+
cipher.auth_data = Base64.strict_decode64(@team_key)
|
47
|
+
end
|
48
|
+
|
49
|
+
encrypted_data = cipher.update(data_to_encrypt.to_s) + cipher.final + cipher.auth_tag
|
50
|
+
|
51
|
+
ephemeral_key_compressed_string = @ephemeral_public_key.to_octet_string(:compressed)
|
52
|
+
|
53
|
+
format(header_type(data_to_encrypt), Base64.strict_encode64(iv), Base64.strict_encode64(ephemeral_key_compressed_string), Base64.strict_encode64(encrypted_data))
|
43
54
|
end
|
44
55
|
|
45
|
-
private def
|
56
|
+
private def traverse_and_encrypt(data)
|
46
57
|
if encryptable_data?(data)
|
47
58
|
return encrypt_string(data)
|
48
59
|
elsif data.instance_of?(Hash)
|
49
60
|
encrypted_data = {}
|
50
|
-
data.each { |key, value| encrypted_data[key] =
|
61
|
+
data.each { |key, value| encrypted_data[key] = traverse_and_encrypt(value) }
|
62
|
+
return encrypted_data
|
63
|
+
elsif data.instance_of?(Array)
|
64
|
+
encrypted_data = data.map { |value| traverse_and_encrypt(value) }
|
51
65
|
return encrypted_data
|
66
|
+
else
|
67
|
+
raise Evervault::Errors::UnsupportedEncryptType.new(
|
68
|
+
"Encryption is not supported for #{data.class}"
|
69
|
+
)
|
52
70
|
end
|
53
71
|
data
|
54
72
|
end
|
55
73
|
|
56
74
|
private def encryptable_data?(data)
|
57
|
-
data.instance_of?(String) ||
|
58
|
-
|
59
|
-
data.instance_of?(Float)
|
75
|
+
data.instance_of?(String) || [true, false].include?(data) ||
|
76
|
+
data.instance_of?(Integer) || data.instance_of?(Float)
|
60
77
|
end
|
61
78
|
|
62
|
-
private def
|
63
|
-
|
79
|
+
private def generate_shared_key()
|
80
|
+
ec = OpenSSL::PKey::EC.new(@curve)
|
81
|
+
ec.generate_key
|
82
|
+
@ephemeral_public_key = ec.public_key
|
83
|
+
|
84
|
+
decoded_team_key = OpenSSL::BN.new(Base64.strict_decode64(@team_key), 2)
|
85
|
+
group_for_team_key = OpenSSL::PKey::EC::Group.new(@curve)
|
86
|
+
team_key_point = OpenSSL::PKey::EC::Point.new(group_for_team_key, decoded_team_key)
|
87
|
+
|
88
|
+
shared_key = ec.dh_compute_key(team_key_point)
|
89
|
+
|
90
|
+
if @curve == 'prime256v1'
|
91
|
+
# Perform KDF
|
92
|
+
encoded_ephemeral_key = @p256.encode(decompressed_key: @ephemeral_public_key.to_bn(:uncompressed).to_s(16)).to_der
|
93
|
+
hash_input = shared_key + [00, 00, 00, 01].pack('C*') + encoded_ephemeral_key
|
94
|
+
hash = OpenSSL::Digest::SHA256.new()
|
95
|
+
digest = hash.digest(hash_input)
|
96
|
+
return digest
|
97
|
+
end
|
98
|
+
|
99
|
+
shared_key
|
64
100
|
end
|
65
101
|
|
66
|
-
private def format(
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
utf8_to_base_64_url(
|
73
|
-
{
|
74
|
-
cageData: encrypted_key,
|
75
|
-
keyIv: iv,
|
76
|
-
sharedEncryptedData: encrypted_data
|
77
|
-
}.to_json
|
78
|
-
)
|
79
|
-
"#{header}.#{payload}.#{SecureRandom.uuid}"
|
102
|
+
private def format(datatype, iv, team_key, encrypted_data)
|
103
|
+
"ev:#{@ev_version}#{
|
104
|
+
datatype != 'string' ? ':' + datatype : ''
|
105
|
+
}:#{base_64_remove_padding(iv)}:#{base_64_remove_padding(
|
106
|
+
team_key
|
107
|
+
)}:#{base_64_remove_padding(encrypted_data)}:$"
|
80
108
|
end
|
81
109
|
|
82
|
-
private def
|
83
|
-
|
84
|
-
b64_string.gsub("+", "-").gsub("/", "_")
|
110
|
+
private def base_64_remove_padding(str)
|
111
|
+
str.gsub(/={1,2}$/, '');
|
85
112
|
end
|
86
113
|
|
87
114
|
private def header_type(data)
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require "openssl"
|
2
|
+
|
3
|
+
module Evervault
|
4
|
+
module Crypto
|
5
|
+
class CurveBase
|
6
|
+
|
7
|
+
def initialize(curve_name:, curve_values:)
|
8
|
+
@asn1Encoder = buildEncoder(curve_values: curve_values)
|
9
|
+
end
|
10
|
+
|
11
|
+
def encode(decompressed_key:)
|
12
|
+
@asn1Encoder.call(decompressed_key)
|
13
|
+
end
|
14
|
+
|
15
|
+
private def buildEncoder(curve_values:)
|
16
|
+
a = OpenSSL::ASN1::OctetString.new([curve_values::A].pack('H*'))
|
17
|
+
b = OpenSSL::ASN1::OctetString.new([curve_values::B].pack('H*'))
|
18
|
+
seed = OpenSSL::ASN1::BitString.new([curve_values::SEED].pack('H*'))
|
19
|
+
curve = OpenSSL::ASN1::Sequence.new([a, b, seed])
|
20
|
+
|
21
|
+
field_type = OpenSSL::ASN1::ObjectId.new("1.2.840.10045.1.1")
|
22
|
+
parameters = OpenSSL::ASN1::Integer.new(curve_values::P.to_i(16))
|
23
|
+
field_id = OpenSSL::ASN1::Sequence.new([field_type, parameters])
|
24
|
+
|
25
|
+
version = OpenSSL::ASN1::Integer.new(1)
|
26
|
+
base = OpenSSL::ASN1::OctetString.new([curve_values::GENERATOR].pack('H*'))
|
27
|
+
order = OpenSSL::ASN1::Integer.new(curve_values::N.to_i(16))
|
28
|
+
cofactor = OpenSSL::ASN1::Integer.new(curve_values::H.to_i(16))
|
29
|
+
ec_parameters = OpenSSL::ASN1::Sequence.new([version, field_id, curve, base, order, cofactor])
|
30
|
+
|
31
|
+
algorithm = OpenSSL::ASN1::ObjectId.new("1.2.840.10045.2.1")
|
32
|
+
algorithm_identifier = OpenSSL::ASN1::Sequence.new([algorithm, ec_parameters])
|
33
|
+
|
34
|
+
return lambda {|public_key| OpenSSL::ASN1::Sequence.new([algorithm_identifier, OpenSSL::ASN1::BitString.new([public_key].pack('H*'))])}
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require_relative "base"
|
2
|
+
|
3
|
+
# https://neuromancer.sk/std/x962/prime256v1
|
4
|
+
|
5
|
+
module P256_CONSTANTS
|
6
|
+
A = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"
|
7
|
+
B = "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"
|
8
|
+
SEED = "C49D360886E704936A6678E1139D26B7819F7E90"
|
9
|
+
P = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"
|
10
|
+
GENERATOR = "046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"
|
11
|
+
N = "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"
|
12
|
+
H = "01"
|
13
|
+
end
|
14
|
+
|
15
|
+
module Evervault
|
16
|
+
module Crypto
|
17
|
+
module Curves
|
18
|
+
class P256 < CurveBase
|
19
|
+
def initialize()
|
20
|
+
super(curve_name: 'prime256v1', curve_values: P256_CONSTANTS)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -3,7 +3,7 @@ require_relative "errors"
|
|
3
3
|
module Evervault
|
4
4
|
module Errors
|
5
5
|
class ErrorMap
|
6
|
-
def self.raise_errors_on_failure(status_code, body)
|
6
|
+
def self.raise_errors_on_failure(status_code, body, headers)
|
7
7
|
return if status_code < 400
|
8
8
|
case status_code
|
9
9
|
when 404
|
@@ -13,7 +13,11 @@ module Evervault
|
|
13
13
|
when 401
|
14
14
|
raise AuthenticationError.new("Unauthorized")
|
15
15
|
when 403
|
16
|
-
|
16
|
+
if (headers.include? "x-evervault-error-code") && (headers["x-evervault-error-code"] == "forbidden-ip-error")
|
17
|
+
raise ForbiddenIPError.new("IP is not present in Cage whitelist")
|
18
|
+
else
|
19
|
+
raise AuthenticationError.new("Forbidden")
|
20
|
+
end
|
17
21
|
when 500
|
18
22
|
raise ServerError.new("Server Error")
|
19
23
|
when 502
|
@@ -23,5 +23,11 @@ module Evervault
|
|
23
23
|
class InvalidPublicKeyError < EvervaultError; end
|
24
24
|
|
25
25
|
class UnexpectedError < EvervaultError; end
|
26
|
+
|
27
|
+
class CertDownloadError < EvervaultError; end
|
28
|
+
|
29
|
+
class UnsupportedEncryptType < EvervaultError; end
|
30
|
+
|
31
|
+
class ForbiddenIPError < EvervaultError; end
|
26
32
|
end
|
27
33
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
require "
|
1
|
+
require "faraday"
|
2
2
|
require "json"
|
3
3
|
require_relative "../version"
|
4
4
|
require_relative "../errors/error_map"
|
@@ -6,63 +6,34 @@ require_relative "../errors/error_map"
|
|
6
6
|
module Evervault
|
7
7
|
module Http
|
8
8
|
class Request
|
9
|
-
def initialize(
|
10
|
-
@api_key = api_key
|
9
|
+
def initialize(timeout:, api_key:)
|
11
10
|
@timeout = timeout
|
12
|
-
@
|
13
|
-
@cage_run_url = cage_run_url
|
14
|
-
end
|
15
|
-
|
16
|
-
def get(path, params = nil)
|
17
|
-
execute(:get, build_url(path), params)
|
18
|
-
end
|
19
|
-
|
20
|
-
def put(path, params)
|
21
|
-
execute(:put, build_url(path), params)
|
22
|
-
end
|
23
|
-
|
24
|
-
def delete(path, params)
|
25
|
-
execute(:delete, build_url(path), params)
|
26
|
-
end
|
27
|
-
|
28
|
-
def post(path, params, cage_run: false)
|
29
|
-
execute(:post, build_url(path, cage_run), params)
|
30
|
-
end
|
31
|
-
|
32
|
-
private def build_url(path, cage_run = false)
|
33
|
-
return "#{@base_url}#{path}" unless cage_run
|
34
|
-
"#{@cage_run_url}#{path}"
|
11
|
+
@api_key = api_key
|
35
12
|
end
|
36
13
|
|
37
|
-
def execute(method, url, params)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
req.on_complete do |response|
|
47
|
-
if response.success?
|
48
|
-
return JSON.parse(response.body)
|
49
|
-
else
|
50
|
-
Evervault::Errors::ErrorMap.raise_errors_on_failure(
|
51
|
-
response.code,
|
52
|
-
response.body
|
53
|
-
)
|
14
|
+
def execute(method, url, params, optional_headers = {}, is_ca = false)
|
15
|
+
resp = Faraday.send(method, url) do |req|
|
16
|
+
req.body = params.nil? || params.empty? ? nil : params.to_json
|
17
|
+
req.headers = build_headers(optional_headers)
|
18
|
+
req.options.timeout = @timeout
|
19
|
+
end
|
20
|
+
if resp.status >= 200 && resp.status <= 300
|
21
|
+
if is_ca
|
22
|
+
return resp.body
|
54
23
|
end
|
24
|
+
return JSON.parse(resp.body)
|
55
25
|
end
|
56
|
-
resp
|
26
|
+
Evervault::Errors::ErrorMap.raise_errors_on_failure(resp.status, resp.body, resp.headers)
|
57
27
|
end
|
58
28
|
|
59
|
-
private def build_headers
|
60
|
-
{
|
29
|
+
private def build_headers(optional_headers)
|
30
|
+
optional_headers.merge({
|
61
31
|
"AcceptEncoding": "gzip, deflate",
|
62
32
|
"Accept": "application/json",
|
63
33
|
"Content-Type": "application/json",
|
64
|
-
"
|
65
|
-
|
34
|
+
"User-Agent": "evervault-ruby/#{VERSION}",
|
35
|
+
"Api-Key": @api_key,
|
36
|
+
})
|
66
37
|
end
|
67
38
|
end
|
68
39
|
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "json"
|
3
|
+
require_relative "../version"
|
4
|
+
require_relative "../errors/error_map"
|
5
|
+
|
6
|
+
module Evervault
|
7
|
+
module Http
|
8
|
+
class RequestHandler
|
9
|
+
def initialize(request:, base_url:, cage_run_url:, cert:)
|
10
|
+
@request = request
|
11
|
+
@base_url = base_url
|
12
|
+
@cage_run_url = cage_run_url
|
13
|
+
@cert = cert
|
14
|
+
end
|
15
|
+
|
16
|
+
def get(path, params = nil)
|
17
|
+
if @cert.is_certificate_expired()
|
18
|
+
@cert.setup()
|
19
|
+
end
|
20
|
+
@request.execute(:get, build_url(path), params)
|
21
|
+
end
|
22
|
+
|
23
|
+
def put(path, params)
|
24
|
+
if @cert.is_certificate_expired()
|
25
|
+
@cert.setup()
|
26
|
+
end
|
27
|
+
@request.execute(:put, build_url(path), params)
|
28
|
+
end
|
29
|
+
|
30
|
+
def delete(path, params)
|
31
|
+
if @cert.is_certificate_expired()
|
32
|
+
@cert.setup()
|
33
|
+
end
|
34
|
+
@request.execute(:delete, build_url(path), params)
|
35
|
+
end
|
36
|
+
|
37
|
+
def post(path, params, options: {}, cage_run: false)
|
38
|
+
if @cert.is_certificate_expired()
|
39
|
+
@cert.setup()
|
40
|
+
end
|
41
|
+
@request.execute(:post, build_url(path, cage_run), params, build_cage_run_headers(options, cage_run))
|
42
|
+
end
|
43
|
+
|
44
|
+
private def build_url(path, cage_run = false)
|
45
|
+
return "#{@base_url}#{path}" unless cage_run
|
46
|
+
"#{@cage_run_url}#{path}"
|
47
|
+
end
|
48
|
+
|
49
|
+
private def build_cage_run_headers(options, cage_run = false)
|
50
|
+
optional_headers = {}
|
51
|
+
return optional_headers unless cage_run
|
52
|
+
if options.key?(:async)
|
53
|
+
if options[:async]
|
54
|
+
optional_headers["x-async"] = "true"
|
55
|
+
end
|
56
|
+
options.delete(:async)
|
57
|
+
end
|
58
|
+
if options.key?(:version)
|
59
|
+
if options[:version].is_a? Integer
|
60
|
+
optional_headers["x-version-id"] = options[:version].to_s
|
61
|
+
end
|
62
|
+
options.delete(:version)
|
63
|
+
end
|
64
|
+
optional_headers.merge(options)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require "faraday"
|
2
|
+
require "json"
|
3
|
+
require "tempfile"
|
4
|
+
require "openssl"
|
5
|
+
require 'net/http'
|
6
|
+
require_relative "../version"
|
7
|
+
require_relative "../errors/errors"
|
8
|
+
|
9
|
+
module NetHTTPOverride
|
10
|
+
@@api_key = nil
|
11
|
+
@@relay_url = nil
|
12
|
+
@@relay_port = nil
|
13
|
+
@@cert = nil
|
14
|
+
@@decrypt_if_exact = []
|
15
|
+
@@decrypt_if_ends_with = []
|
16
|
+
|
17
|
+
def self.set_api_key(value)
|
18
|
+
@@api_key = value
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.set_relay_url(value)
|
22
|
+
relay_address_and_port = value.gsub(/(^\w+:|^)\/\//, '').split(":")
|
23
|
+
@@relay_url = relay_address_and_port[0]
|
24
|
+
@@relay_port = relay_address_and_port[1]
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.set_cert(value)
|
28
|
+
@@cert = value
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.add_to_decrypt_if_exact(value)
|
32
|
+
@@decrypt_if_exact.append(value)
|
33
|
+
end
|
34
|
+
|
35
|
+
def self.add_to_decrypt_if_ends_with(value)
|
36
|
+
@@decrypt_if_ends_with.append(value)
|
37
|
+
end
|
38
|
+
|
39
|
+
def should_decrypt(domain)
|
40
|
+
return (@@decrypt_if_exact.include? domain) || (@@decrypt_if_ends_with.any? { |suffix| domain.end_with? suffix })
|
41
|
+
end
|
42
|
+
|
43
|
+
def connect
|
44
|
+
if should_decrypt(conn_address)
|
45
|
+
@cert_store = OpenSSL::X509::Store.new
|
46
|
+
@cert_store.add_cert(@@cert)
|
47
|
+
@proxy_from_env = false
|
48
|
+
@proxy_address = @@relay_url
|
49
|
+
@proxy_port = @@relay_port
|
50
|
+
end
|
51
|
+
super
|
52
|
+
end
|
53
|
+
|
54
|
+
def request(req, body = nil, &block)
|
55
|
+
should_decrypt = should_decrypt(@address)
|
56
|
+
if should_decrypt
|
57
|
+
req["Proxy-Authorization"] = @@api_key
|
58
|
+
end
|
59
|
+
super
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
Net::HTTP.send :prepend, NetHTTPOverride
|
64
|
+
|
65
|
+
module Evervault
|
66
|
+
module Http
|
67
|
+
class RequestIntercept
|
68
|
+
def initialize(request:, ca_host:, api_key:, relay_url:)
|
69
|
+
NetHTTPOverride.set_api_key(api_key)
|
70
|
+
NetHTTPOverride.set_relay_url(relay_url)
|
71
|
+
|
72
|
+
@request = request
|
73
|
+
@ca_host = ca_host
|
74
|
+
@expire_date = nil
|
75
|
+
@initial_date = nil
|
76
|
+
end
|
77
|
+
|
78
|
+
def is_certificate_expired()
|
79
|
+
if @expire_date
|
80
|
+
now = Time.now
|
81
|
+
if now > @expire_date || now < @initial_date
|
82
|
+
return true
|
83
|
+
end
|
84
|
+
end
|
85
|
+
return false
|
86
|
+
end
|
87
|
+
|
88
|
+
def setup_domains(decrypt_domains=[])
|
89
|
+
for domain in decrypt_domains
|
90
|
+
if domain.start_with?("www.")
|
91
|
+
domain = domain[4..-1]
|
92
|
+
end
|
93
|
+
NetHTTPOverride.add_to_decrypt_if_exact(domain)
|
94
|
+
NetHTTPOverride.add_to_decrypt_if_ends_with("." + domain)
|
95
|
+
NetHTTPOverride.add_to_decrypt_if_ends_with("@" + domain)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def setup
|
100
|
+
get_cert()
|
101
|
+
end
|
102
|
+
|
103
|
+
def get_cert()
|
104
|
+
ca_content = nil
|
105
|
+
i = 0
|
106
|
+
|
107
|
+
while !ca_content && i < 1
|
108
|
+
i += 1
|
109
|
+
begin
|
110
|
+
ca_content = @request.execute("get", @ca_host, nil, {}, is_ca: true)
|
111
|
+
rescue;
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
if !ca_content || ca_content == ""
|
116
|
+
raise Evervault::Errors::CertDownloadError.new("Unable to install the Evervault root certificate from #{@ca_host}")
|
117
|
+
end
|
118
|
+
|
119
|
+
cert = OpenSSL::X509::Certificate.new ca_content
|
120
|
+
set_cert_expire_date(cert)
|
121
|
+
NetHTTPOverride.set_cert(cert)
|
122
|
+
end
|
123
|
+
|
124
|
+
def set_cert_expire_date(cert)
|
125
|
+
begin
|
126
|
+
@expire_date = cert.not_after
|
127
|
+
@initial_date = cert.not_before
|
128
|
+
rescue => exception
|
129
|
+
@expire_date = nil
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
data/lib/evervault/version.rb
CHANGED
data/lib/evervault.rb
CHANGED
@@ -6,24 +6,8 @@ module Evervault
|
|
6
6
|
class << self
|
7
7
|
attr_accessor :api_key
|
8
8
|
|
9
|
-
def
|
10
|
-
client.
|
11
|
-
end
|
12
|
-
|
13
|
-
def encrypt_and_run(cage_name, data)
|
14
|
-
client.encrypt_and_run(cage_name, data)
|
15
|
-
end
|
16
|
-
|
17
|
-
def encrypt(data)
|
18
|
-
client.encrypt(data)
|
19
|
-
end
|
20
|
-
|
21
|
-
def cages
|
22
|
-
client.cages
|
23
|
-
end
|
24
|
-
|
25
|
-
def cage_list
|
26
|
-
client.cage_list
|
9
|
+
def method_missing(method, *args, &block)
|
10
|
+
client.send(method, *args, &block)
|
27
11
|
end
|
28
12
|
|
29
13
|
private def client
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: evervault
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jonny O'Mahony
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-07-08 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -17,12 +17,13 @@ executables: []
|
|
17
17
|
extensions: []
|
18
18
|
extra_rdoc_files: []
|
19
19
|
files:
|
20
|
+
- ".github/CODEOWNERS"
|
21
|
+
- ".github/pull_request_template.md"
|
20
22
|
- ".github/workflows/release.yml"
|
21
23
|
- ".github/workflows/run-tests.yml"
|
22
24
|
- ".gitignore"
|
23
25
|
- ".rspec"
|
24
26
|
- Gemfile
|
25
|
-
- Gemfile.lock
|
26
27
|
- LICENSE.txt
|
27
28
|
- README.md
|
28
29
|
- Rakefile
|
@@ -32,10 +33,13 @@ files:
|
|
32
33
|
- lib/evervault.rb
|
33
34
|
- lib/evervault/client.rb
|
34
35
|
- lib/evervault/crypto/client.rb
|
35
|
-
- lib/evervault/crypto/
|
36
|
+
- lib/evervault/crypto/curves/base.rb
|
37
|
+
- lib/evervault/crypto/curves/p256.rb
|
36
38
|
- lib/evervault/errors/error_map.rb
|
37
39
|
- lib/evervault/errors/errors.rb
|
38
40
|
- lib/evervault/http/request.rb
|
41
|
+
- lib/evervault/http/request_handler.rb
|
42
|
+
- lib/evervault/http/request_intercept.rb
|
39
43
|
- lib/evervault/models/cage.rb
|
40
44
|
- lib/evervault/models/cage_list.rb
|
41
45
|
- lib/evervault/version.rb
|
@@ -63,7 +67,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
63
67
|
- !ruby/object:Gem::Version
|
64
68
|
version: '0'
|
65
69
|
requirements: []
|
66
|
-
rubygems_version: 3.1.
|
70
|
+
rubygems_version: 3.1.6
|
67
71
|
signing_key:
|
68
72
|
specification_version: 4
|
69
73
|
summary: Ruby SDK to run Evervault Cages
|
data/Gemfile.lock
DELETED
@@ -1,58 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
evervault (0.1.1)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: https://rubygems.org/
|
8
|
-
specs:
|
9
|
-
addressable (2.7.0)
|
10
|
-
public_suffix (>= 2.0.2, < 5.0)
|
11
|
-
coderay (1.1.3)
|
12
|
-
crack (0.4.4)
|
13
|
-
diff-lcs (1.4.4)
|
14
|
-
ethon (0.12.0)
|
15
|
-
ffi (>= 1.3.0)
|
16
|
-
ffi (1.13.1)
|
17
|
-
gem-release (2.2.0)
|
18
|
-
hashdiff (1.0.1)
|
19
|
-
method_source (1.0.0)
|
20
|
-
pry (0.13.1)
|
21
|
-
coderay (~> 1.1)
|
22
|
-
method_source (~> 1.0)
|
23
|
-
public_suffix (4.0.6)
|
24
|
-
rake (12.3.3)
|
25
|
-
rspec (3.9.0)
|
26
|
-
rspec-core (~> 3.9.0)
|
27
|
-
rspec-expectations (~> 3.9.0)
|
28
|
-
rspec-mocks (~> 3.9.0)
|
29
|
-
rspec-core (3.9.3)
|
30
|
-
rspec-support (~> 3.9.3)
|
31
|
-
rspec-expectations (3.9.2)
|
32
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
33
|
-
rspec-support (~> 3.9.0)
|
34
|
-
rspec-mocks (3.9.1)
|
35
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
36
|
-
rspec-support (~> 3.9.0)
|
37
|
-
rspec-support (3.9.3)
|
38
|
-
typhoeus (1.4.0)
|
39
|
-
ethon (>= 0.9.0)
|
40
|
-
webmock (3.9.3)
|
41
|
-
addressable (>= 2.3.6)
|
42
|
-
crack (>= 0.3.2)
|
43
|
-
hashdiff (>= 0.4.0, < 2.0.0)
|
44
|
-
|
45
|
-
PLATFORMS
|
46
|
-
ruby
|
47
|
-
|
48
|
-
DEPENDENCIES
|
49
|
-
evervault!
|
50
|
-
gem-release
|
51
|
-
pry
|
52
|
-
rake (~> 12.0)
|
53
|
-
rspec (~> 3.0)
|
54
|
-
typhoeus
|
55
|
-
webmock
|
56
|
-
|
57
|
-
BUNDLED WITH
|
58
|
-
2.1.4
|
data/lib/evervault/crypto/key.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
require "openssl"
|
2
|
-
|
3
|
-
module Evervault
|
4
|
-
module Crypto
|
5
|
-
class Key
|
6
|
-
attr_reader :public_key
|
7
|
-
def initialize(public_key:)
|
8
|
-
@public_key = OpenSSL::PKey::RSA.new(format_key(public_key))
|
9
|
-
end
|
10
|
-
|
11
|
-
private def format_key(key)
|
12
|
-
key_header = "-----BEGIN PUBLIC KEY-----\n"
|
13
|
-
key_footer = "-----END PUBLIC KEY-----"
|
14
|
-
return key if key.include?(key_header) && key.include?(key_footer)
|
15
|
-
"#{key_header}#{key.scan(/.{0,64}/).join("\n")}#{key_footer}"
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|