evervault 1.3.2 → 2.1.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/workflows/release.yml +7 -7
- data/.github/workflows/run-tests.yml +7 -7
- data/README.md +41 -6
- data/lib/evervault/client.rb +37 -10
- data/lib/evervault/http/request.rb +30 -9
- data/lib/evervault/http/request_handler.rb +13 -32
- data/lib/evervault/utils/validation_utils.rb +31 -0
- data/lib/evervault/version.rb +1 -1
- data/lib/evervault.rb +16 -6
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d24159a979aa8a8a684447e804ce5280bb03946ff7b81847d3ca34cdc794c488
|
4
|
+
data.tar.gz: 5b5c762a8abab38f848c506acf3674a8b39357d06f4d57c2fd4d71e8949c2886
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e4b9c709918dd7623c7c5209d7b0848a9eef6f1c80c016234f266eb9ecca3994229f298e5001b2a14341fe687b52b37672705971366f7d027a2e91f2639528f
|
7
|
+
data.tar.gz: f11ad2a4010f1aaf6f1c11efe6e5fb1fe9db8f4efae07e581de4eaef7af41b8f78adf3e348182c8b65cbad694fe85009786da9da6d5ea7fc4d05fe7142942cae
|
@@ -11,16 +11,16 @@ jobs:
|
|
11
11
|
fail-fast: false
|
12
12
|
matrix:
|
13
13
|
os: [ubuntu, macos]
|
14
|
-
ruby: [2.
|
14
|
+
ruby: [2.6, 2.7, 3.1, truffleruby]
|
15
15
|
runs-on: ${{ matrix.os }}-latest
|
16
16
|
continue-on-error: ${{ endsWith(matrix.ruby, 'head') || matrix.ruby == 'debug' }}
|
17
17
|
steps:
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
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
24
|
|
25
25
|
build:
|
26
26
|
runs-on: ubuntu-latest
|
@@ -7,13 +7,13 @@ jobs:
|
|
7
7
|
fail-fast: false
|
8
8
|
matrix:
|
9
9
|
os: [ubuntu, macos]
|
10
|
-
ruby: [2.
|
10
|
+
ruby: [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:
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
- uses: actions/checkout@v2
|
15
|
+
- uses: ruby/setup-ruby@v1
|
16
|
+
with:
|
17
|
+
ruby-version: ${{ matrix.ruby }}
|
18
|
+
- run: bundle install
|
19
|
+
- run: bundle exec rake
|
data/README.md
CHANGED
@@ -48,11 +48,15 @@ To make Evervault available for use in your app:
|
|
48
48
|
```ruby
|
49
49
|
require "evervault"
|
50
50
|
|
51
|
-
# Initialize the client with your
|
51
|
+
# Initialize the client with your App's ID and App's API key
|
52
|
+
Evervault.app_id = <YOUR-APP-ID>
|
52
53
|
Evervault.api_key = <YOUR-API-KEY>
|
53
54
|
|
54
55
|
# Encrypt your data
|
55
|
-
encrypted_data = Evervault.encrypt(
|
56
|
+
encrypted_data = Evervault.encrypt('Hello World!')
|
57
|
+
|
58
|
+
# Decrypt your data
|
59
|
+
decrypted = Evervault.decrypt(encrypted_data)
|
56
60
|
|
57
61
|
# Process the encrypted data using a Function
|
58
62
|
result = Evervault.run(<FUNCTION-NAME>, encrypted_data)
|
@@ -65,6 +69,7 @@ req.body = encrypted_data.to_json
|
|
65
69
|
http = Net::HTTP.new(uri.host, uri.port)
|
66
70
|
http.use_ssl = true
|
67
71
|
res = http.request(req)
|
72
|
+
|
68
73
|
```
|
69
74
|
|
70
75
|
## Reference
|
@@ -79,13 +84,41 @@ The Evervault Ruby SDK exposes four methods.
|
|
79
84
|
Evervault.encrypt(data = String | Number | Boolean | Hash | Array)
|
80
85
|
```
|
81
86
|
|
82
|
-
| Parameter | Type
|
83
|
-
| --------- |
|
84
|
-
| data
|
87
|
+
| Parameter | Type | Description |
|
88
|
+
| --------- | ---------------------------------------------- | -------------------- |
|
89
|
+
| data | `String`, `Number`, `Boolean`, `Hash`, `Array` | Data to be encrypted |
|
90
|
+
|
91
|
+
### Evervault.decrypt
|
92
|
+
|
93
|
+
`Evervault.decrypt` decrypts data previously encrypted with the `encrypt()` function or through Evervault's Relay (Evervault's encryption proxy).
|
94
|
+
An API Key with the `decrypt` permission must be used to perform this operation.
|
95
|
+
|
96
|
+
```ruby
|
97
|
+
Evervault.decrypt(data = String | Array | Hash)
|
98
|
+
```
|
99
|
+
|
100
|
+
| Parameter | Type | Description |
|
101
|
+
| --------- | ------------------------- | -------------------- |
|
102
|
+
| data | `String`, `Array`, `Hash` | Data to be decrypted |
|
103
|
+
|
104
|
+
### Evervault.create_client_side_decrypt_token
|
105
|
+
`Evervault.create_client_side_token` is used to generate a time-bound token that can be used by front-end applications to decrypt Evervault encrypted data.
|
106
|
+
|
107
|
+
```ruby
|
108
|
+
time_now = Time.now
|
109
|
+
time_in_five_minutes = time_now + 300
|
110
|
+
Evervault.create_client_side_decrypt_token(encrypted_data, time_in_five_minutes)
|
111
|
+
```
|
112
|
+
|
113
|
+
| Parameter | Type | Description |
|
114
|
+
| --------- | ------------------------- | ---------------------------------------------------------------------------------------------------------------------------------- |
|
115
|
+
| data | `String`, `Array`, `Hash` | The payload the token can be used to decrypt. |
|
116
|
+
| expiry | `Time` | Optional -- The time the token should expire. The max expiry is 10 minutes in the future. If not supplied it defaults to 5 minutes |
|
117
|
+
|
85
118
|
|
86
119
|
### Evervault.enable_outbound_relay
|
87
120
|
|
88
|
-
`Evervault.enable_outbound_relay` configures your application to proxy HTTP requests using Outbound Relay based on the configuration created in the Evervault UI. See [Outbound Relay](https://docs.evervault.com/concepts/outbound-relay/overview) to learn more.
|
121
|
+
`Evervault.enable_outbound_relay` configures your application to proxy HTTP requests using Outbound Relay based on the configuration created in the Evervault UI. See [Outbound Relay](https://docs.evervault.com/concepts/outbound-relay/overview) to learn more.
|
89
122
|
|
90
123
|
```ruby
|
91
124
|
Evervault.enable_outbound_relay([decryption_domains = Array])
|
@@ -98,6 +131,7 @@ Evervault.enable_outbound_relay([decryption_domains = Array])
|
|
98
131
|
### Evervault.run
|
99
132
|
|
100
133
|
`Evervault.run` invokes a Function with a given payload.
|
134
|
+
An API Key with the `run Function` permission must be used to perform this operation.
|
101
135
|
|
102
136
|
```ruby
|
103
137
|
Evervault.run(function_name = String, data = Hash[, options = Hash])
|
@@ -119,6 +153,7 @@ Evervault.run(function_name = String, data = Hash[, options = Hash])
|
|
119
153
|
### Evervault.create_run_token
|
120
154
|
|
121
155
|
`Evervault.create_run_token` creates a single use, time bound token for invoking a Function.
|
156
|
+
An API Key with the `create Run Token` permission must be used to perform this operation.
|
122
157
|
|
123
158
|
```ruby
|
124
159
|
Evervault.create_run_token(function_name = String, data = Hash)
|
data/lib/evervault/client.rb
CHANGED
@@ -8,23 +8,25 @@ require_relative "crypto/client"
|
|
8
8
|
module Evervault
|
9
9
|
class Client
|
10
10
|
|
11
|
-
attr_accessor :
|
11
|
+
attr_accessor :function_run_url
|
12
12
|
def initialize(
|
13
|
+
app_uuid:,
|
13
14
|
api_key:,
|
14
15
|
base_url: "https://api.evervault.com/",
|
15
|
-
|
16
|
+
function_run_url: "https://run.evervault.com/",
|
16
17
|
relay_url: "https://relay.evervault.com:8443",
|
17
18
|
ca_host: "https://ca.evervault.com",
|
18
19
|
request_timeout: 30,
|
19
20
|
curve: 'prime256v1'
|
20
21
|
)
|
21
|
-
@
|
22
|
+
@function_run_url = function_run_url
|
23
|
+
@request = Evervault::Http::Request.new(timeout: request_timeout, app_uuid: app_uuid, api_key: api_key)
|
22
24
|
@intercept = Evervault::Http::RequestIntercept.new(
|
23
25
|
request: @request, ca_host: ca_host, api_key: api_key, base_url: base_url, relay_url: relay_url
|
24
26
|
)
|
25
27
|
@request_handler =
|
26
28
|
Evervault::Http::RequestHandler.new(
|
27
|
-
request: @request, base_url: base_url,
|
29
|
+
request: @request, base_url: base_url, cert: @intercept
|
28
30
|
)
|
29
31
|
@crypto_client = Evervault::Crypto::Client.new(request_handler: @request_handler, curve: curve)
|
30
32
|
@intercept.setup()
|
@@ -34,8 +36,37 @@ module Evervault
|
|
34
36
|
@crypto_client.encrypt(data)
|
35
37
|
end
|
36
38
|
|
37
|
-
def
|
38
|
-
|
39
|
+
def decrypt(data)
|
40
|
+
unless data.is_a?(String) || data.is_a?(Array) || data.is_a?(Hash)
|
41
|
+
raise Evervault::Errors::ArgumentError.new("data is of invalid type")
|
42
|
+
end
|
43
|
+
payload = { data: data }
|
44
|
+
response = @request_handler.post("decrypt", payload, nil, nil, true)
|
45
|
+
response["data"]
|
46
|
+
end
|
47
|
+
|
48
|
+
def create_token(action, data, expiry = nil)
|
49
|
+
payload = { payload: data, expiry: expiry, action: action }
|
50
|
+
@request_handler.post("client-side-tokens", payload, nil, nil, true)
|
51
|
+
end
|
52
|
+
|
53
|
+
def run(function_name, payload, options = {})
|
54
|
+
optional_headers = {}
|
55
|
+
if options.key?(:async)
|
56
|
+
if options[:async]
|
57
|
+
optional_headers["x-async"] = "true"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
if options.key?(:version)
|
61
|
+
if options[:version].is_a? Integer
|
62
|
+
optional_headers["x-version-id"] = options[:version].to_s
|
63
|
+
end
|
64
|
+
end
|
65
|
+
@request_handler.post(function_name, payload, optional_headers, @function_run_url)
|
66
|
+
end
|
67
|
+
|
68
|
+
def create_run_token(function_name, data = {})
|
69
|
+
@request_handler.post("v2/functions/#{function_name}/run-token", data)
|
39
70
|
end
|
40
71
|
|
41
72
|
def enable_outbound_relay(decryption_domains = nil)
|
@@ -45,9 +76,5 @@ module Evervault
|
|
45
76
|
@intercept.setup_decryption_domains(decryption_domains)
|
46
77
|
end
|
47
78
|
end
|
48
|
-
|
49
|
-
def create_run_token(function_name, data = {})
|
50
|
-
@request_handler.post("v2/functions/#{function_name}/run-token", data)
|
51
|
-
end
|
52
79
|
end
|
53
80
|
end
|
@@ -6,31 +6,52 @@ require_relative "../errors/error_map"
|
|
6
6
|
module Evervault
|
7
7
|
module Http
|
8
8
|
class Request
|
9
|
-
def initialize(timeout:, api_key:)
|
9
|
+
def initialize(timeout:, app_uuid:, api_key:)
|
10
10
|
@timeout = timeout
|
11
|
+
@app_uuid = app_uuid
|
11
12
|
@api_key = api_key
|
12
13
|
end
|
13
14
|
|
14
|
-
def execute(method, url,
|
15
|
-
resp =
|
16
|
-
req.body =
|
17
|
-
req.headers = build_headers(optional_headers)
|
15
|
+
def execute(method, url, body = nil, optional_headers = {}, basic_auth = false)
|
16
|
+
resp = faraday(basic_auth).public_send(method, url) do |req, url|
|
17
|
+
req.body = body.nil? || body.empty? ? nil : body.to_json
|
18
|
+
req.headers = build_headers(optional_headers, basic_auth)
|
18
19
|
req.options.timeout = @timeout
|
19
20
|
end
|
21
|
+
|
20
22
|
if resp.status >= 200 && resp.status <= 300
|
21
23
|
return resp
|
22
24
|
end
|
25
|
+
|
23
26
|
Evervault::Errors::ErrorMap.raise_errors_on_failure(resp.status, resp.body, resp.headers)
|
24
27
|
end
|
25
28
|
|
26
|
-
private
|
27
|
-
|
29
|
+
private
|
30
|
+
|
31
|
+
def faraday(basic_auth = false)
|
32
|
+
Faraday.new do |conn|
|
33
|
+
if basic_auth
|
34
|
+
conn.request :authorization, :basic, @app_uuid, @api_key
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_headers(optional_headers = {}, basic_auth = false)
|
40
|
+
headers = {
|
28
41
|
"AcceptEncoding": "gzip, deflate",
|
29
42
|
"Accept": "application/json",
|
30
43
|
"Content-Type": "application/json",
|
31
44
|
"User-Agent": "evervault-ruby/#{VERSION}",
|
32
|
-
|
33
|
-
|
45
|
+
}
|
46
|
+
unless optional_headers.nil? || optional_headers.empty?
|
47
|
+
headers = headers.merge(optional_headers)
|
48
|
+
end
|
49
|
+
if !basic_auth
|
50
|
+
headers = headers.merge({
|
51
|
+
"Api-Key": @api_key,
|
52
|
+
})
|
53
|
+
end
|
54
|
+
headers
|
34
55
|
end
|
35
56
|
end
|
36
57
|
end
|
@@ -6,70 +6,51 @@ require_relative "../errors/error_map"
|
|
6
6
|
module Evervault
|
7
7
|
module Http
|
8
8
|
class RequestHandler
|
9
|
-
def initialize(request:, base_url:,
|
9
|
+
def initialize(request:, base_url:, cert:)
|
10
10
|
@request = request
|
11
11
|
@base_url = base_url
|
12
|
-
@cage_run_url = cage_run_url
|
13
12
|
@cert = cert
|
14
13
|
end
|
15
14
|
|
16
|
-
def get(path
|
15
|
+
def get(path)
|
17
16
|
if @cert.is_certificate_expired()
|
18
17
|
@cert.setup()
|
19
18
|
end
|
20
|
-
resp = @request.execute(:get, build_url(path)
|
19
|
+
resp = @request.execute(:get, build_url(path))
|
21
20
|
parse_json_body(resp.body)
|
22
21
|
end
|
23
22
|
|
24
|
-
def put(path,
|
23
|
+
def put(path, body)
|
25
24
|
if @cert.is_certificate_expired()
|
26
25
|
@cert.setup()
|
27
26
|
end
|
28
|
-
resp = @request.execute(:put, build_url(path),
|
27
|
+
resp = @request.execute(:put, build_url(path), body)
|
29
28
|
parse_json_body(resp.body)
|
30
29
|
end
|
31
30
|
|
32
|
-
def delete(path
|
31
|
+
def delete(path)
|
33
32
|
if @cert.is_certificate_expired()
|
34
33
|
@cert.setup()
|
35
34
|
end
|
36
|
-
resp = @request.execute(:delete, build_url(path)
|
35
|
+
resp = @request.execute(:delete, build_url(path))
|
37
36
|
parse_json_body(resp.body)
|
38
37
|
end
|
39
38
|
|
40
|
-
def post(path,
|
39
|
+
def post(path, body, optional_headers = {}, alternative_base_url = nil, basic_auth = false)
|
41
40
|
if @cert.is_certificate_expired()
|
42
41
|
@cert.setup()
|
43
42
|
end
|
44
|
-
resp = @request.execute(:post, build_url(path,
|
45
|
-
parse_json_body(resp.body)
|
43
|
+
resp = @request.execute(:post, build_url(path, alternative_base_url), body, optional_headers, basic_auth)
|
44
|
+
return parse_json_body(resp.body) unless resp.body.empty?
|
46
45
|
end
|
47
46
|
|
48
47
|
private def parse_json_body(body)
|
49
48
|
JSON.parse(body)
|
50
49
|
end
|
51
50
|
|
52
|
-
private def build_url(path,
|
53
|
-
return "#{@base_url}#{path}" unless
|
54
|
-
"#{
|
55
|
-
end
|
56
|
-
|
57
|
-
private def build_cage_run_headers(options, cage_run = false)
|
58
|
-
optional_headers = {}
|
59
|
-
return optional_headers unless cage_run
|
60
|
-
if options.key?(:async)
|
61
|
-
if options[:async]
|
62
|
-
optional_headers["x-async"] = "true"
|
63
|
-
end
|
64
|
-
options.delete(:async)
|
65
|
-
end
|
66
|
-
if options.key?(:version)
|
67
|
-
if options[:version].is_a? Integer
|
68
|
-
optional_headers["x-version-id"] = options[:version].to_s
|
69
|
-
end
|
70
|
-
options.delete(:version)
|
71
|
-
end
|
72
|
-
optional_headers.merge(options)
|
51
|
+
private def build_url(path, alternative_base_url = nil)
|
52
|
+
return "#{@base_url}#{path}" unless alternative_base_url
|
53
|
+
"#{alternative_base_url}#{path}"
|
73
54
|
end
|
74
55
|
end
|
75
56
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'digest'
|
2
|
+
|
3
|
+
module Evervault
|
4
|
+
module Utils
|
5
|
+
class ValidationUtils
|
6
|
+
|
7
|
+
def self.validate_app_uuid_and_api_key(app_uuid, api_key)
|
8
|
+
if app_uuid.nil?
|
9
|
+
raise Evervault::Errors::AuthenticationError.new(
|
10
|
+
"No App ID provided. The App ID can be retrieved in the Evervault dashboard (App Settings)."
|
11
|
+
)
|
12
|
+
end
|
13
|
+
if api_key.nil?
|
14
|
+
raise Evervault::Errors::AuthenticationError.new(
|
15
|
+
"The provided App ID is invalid. The App ID can be retrieved in the Evervault dashboard (App Settings)."
|
16
|
+
)
|
17
|
+
end
|
18
|
+
if api_key.start_with?('ev:key')
|
19
|
+
# Scoped API key
|
20
|
+
app_uuid_hash = Digest::SHA512.base64digest(app_uuid)[0, 6]
|
21
|
+
app_uuid_hash_from_api_key = api_key.split(':')[4]
|
22
|
+
if app_uuid_hash != app_uuid_hash_from_api_key
|
23
|
+
raise Evervault::Errors::AuthenticationError.new(
|
24
|
+
"The API key is not valid for app #{app_uuid}. Make sure to use an API key belonging to the app #{app_uuid}."
|
25
|
+
)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/evervault/version.rb
CHANGED
data/lib/evervault.rb
CHANGED
@@ -1,15 +1,22 @@
|
|
1
|
+
require "time"
|
1
2
|
require_relative "evervault/version"
|
2
3
|
require_relative "evervault/client"
|
3
4
|
require_relative "evervault/errors/errors"
|
5
|
+
require_relative "evervault/utils/validation_utils"
|
4
6
|
|
5
7
|
module Evervault
|
6
8
|
class << self
|
9
|
+
attr_accessor :app_id
|
7
10
|
attr_accessor :api_key
|
8
11
|
|
9
12
|
def encrypt(data)
|
10
13
|
client.encrypt(data)
|
11
14
|
end
|
12
15
|
|
16
|
+
def decrypt(data)
|
17
|
+
client.decrypt(data)
|
18
|
+
end
|
19
|
+
|
13
20
|
def run(function_name, encrypted_data, options = {})
|
14
21
|
client.run(function_name, encrypted_data, options)
|
15
22
|
end
|
@@ -22,13 +29,16 @@ module Evervault
|
|
22
29
|
client.create_run_token(function_name, data)
|
23
30
|
end
|
24
31
|
|
25
|
-
|
26
|
-
if
|
27
|
-
|
28
|
-
"Please enter your team's API Key"
|
29
|
-
)
|
32
|
+
def create_client_side_decrypt_token(data, expiry = nil)
|
33
|
+
if expiry != nil
|
34
|
+
expiry = (expiry.to_f * 1000).to_i
|
30
35
|
end
|
31
|
-
|
36
|
+
client.create_token("api:decrypt", data, expiry)
|
37
|
+
end
|
38
|
+
|
39
|
+
private def client
|
40
|
+
Evervault::Utils::ValidationUtils.validate_app_uuid_and_api_key(app_id, api_key)
|
41
|
+
@client ||= Evervault::Client.new(app_uuid: app_id, api_key: api_key)
|
32
42
|
end
|
33
43
|
end
|
34
44
|
end
|
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: 1.
|
4
|
+
version: 2.1.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: 2023-
|
11
|
+
date: 2023-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description:
|
14
14
|
email:
|
@@ -42,6 +42,7 @@ files:
|
|
42
42
|
- lib/evervault/http/request_handler.rb
|
43
43
|
- lib/evervault/http/request_intercept.rb
|
44
44
|
- lib/evervault/threading/repeated_timer.rb
|
45
|
+
- lib/evervault/utils/validation_utils.rb
|
45
46
|
- lib/evervault/version.rb
|
46
47
|
- res/logo.svg
|
47
48
|
- res/logo512.png
|