evervault 1.3.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/release.yml +7 -7
- data/.github/workflows/run-tests.yml +7 -7
- data/.gitignore +1 -0
- data/README.md +26 -6
- data/lib/evervault/client.rb +32 -10
- data/lib/evervault/http/request.rb +30 -9
- data/lib/evervault/http/request_handler.rb +13 -32
- data/lib/evervault/http/request_intercept.rb +11 -5
- data/lib/evervault/utils/validation_utils.rb +31 -0
- data/lib/evervault/version.rb +1 -1
- data/lib/evervault.rb +8 -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: c750c2a56b880d7ef8c5c0cef1bb856476d8fa88bf2cc06c72be2e45b14935dd
|
4
|
+
data.tar.gz: f162eb3e45b0d907642753b9f387cece1f49e3f3531b7cfb6570bcf6a00eba66
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 322cc850f1d240e09ce26069af576efe8d588b2a939e67fb4bc4402cffc32a8eaaecc98abc4ced0f18ce6e912c52bab801f0b08197fb695a9e115edc8b5fc04d
|
7
|
+
data.tar.gz: fb7e6f187bdda3f361da65f6192424a6e09e20a97be40e486b29b9396d58a05a7d61f7df6d60338dce5133acecf3917091fa89f65005da93d29e69bb3c02a5ef
|
@@ -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/.gitignore
CHANGED
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,26 @@ 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 |
|
85
103
|
|
86
104
|
### Evervault.enable_outbound_relay
|
87
105
|
|
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.
|
106
|
+
`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
107
|
|
90
108
|
```ruby
|
91
109
|
Evervault.enable_outbound_relay([decryption_domains = Array])
|
@@ -98,6 +116,7 @@ Evervault.enable_outbound_relay([decryption_domains = Array])
|
|
98
116
|
### Evervault.run
|
99
117
|
|
100
118
|
`Evervault.run` invokes a Function with a given payload.
|
119
|
+
An API Key with the `run Function` permission must be used to perform this operation.
|
101
120
|
|
102
121
|
```ruby
|
103
122
|
Evervault.run(function_name = String, data = Hash[, options = Hash])
|
@@ -119,6 +138,7 @@ Evervault.run(function_name = String, data = Hash[, options = Hash])
|
|
119
138
|
### Evervault.create_run_token
|
120
139
|
|
121
140
|
`Evervault.create_run_token` creates a single use, time bound token for invoking a Function.
|
141
|
+
An API Key with the `create Run Token` permission must be used to perform this operation.
|
122
142
|
|
123
143
|
```ruby
|
124
144
|
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,32 @@ 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 run(function_name, payload, options = {})
|
49
|
+
optional_headers = {}
|
50
|
+
if options.key?(:async)
|
51
|
+
if options[:async]
|
52
|
+
optional_headers["x-async"] = "true"
|
53
|
+
end
|
54
|
+
end
|
55
|
+
if options.key?(:version)
|
56
|
+
if options[:version].is_a? Integer
|
57
|
+
optional_headers["x-version-id"] = options[:version].to_s
|
58
|
+
end
|
59
|
+
end
|
60
|
+
@request_handler.post(function_name, payload, optional_headers, @function_run_url)
|
61
|
+
end
|
62
|
+
|
63
|
+
def create_run_token(function_name, data = {})
|
64
|
+
@request_handler.post("v2/functions/#{function_name}/run-token", data)
|
39
65
|
end
|
40
66
|
|
41
67
|
def enable_outbound_relay(decryption_domains = nil)
|
@@ -45,9 +71,5 @@ module Evervault
|
|
45
71
|
@intercept.setup_decryption_domains(decryption_domains)
|
46
72
|
end
|
47
73
|
end
|
48
|
-
|
49
|
-
def create_run_token(function_name, data = {})
|
50
|
-
@request_handler.post("v2/functions/#{function_name}/run-token", data)
|
51
|
-
end
|
52
74
|
end
|
53
75
|
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
|
@@ -46,7 +46,7 @@ module NetHTTPOverride
|
|
46
46
|
end
|
47
47
|
end
|
48
48
|
|
49
|
-
def
|
49
|
+
def connect_with_intercept
|
50
50
|
if NetHTTPOverride.should_decrypt(conn_address)
|
51
51
|
@cert_store = OpenSSL::X509::Store.new
|
52
52
|
@cert_store.add_cert(@@cert)
|
@@ -54,19 +54,25 @@ module NetHTTPOverride
|
|
54
54
|
@proxy_address = @@relay_url
|
55
55
|
@proxy_port = @@relay_port
|
56
56
|
end
|
57
|
-
|
57
|
+
connect_without_intercept
|
58
58
|
end
|
59
59
|
|
60
|
-
def
|
60
|
+
def request_with_intercept(req, body = nil, &block)
|
61
61
|
should_decrypt = NetHTTPOverride.should_decrypt(@address)
|
62
62
|
if should_decrypt
|
63
63
|
req["Proxy-Authorization"] = @@api_key
|
64
64
|
end
|
65
|
-
|
65
|
+
request_without_intercept(req, body, &block)
|
66
66
|
end
|
67
67
|
end
|
68
68
|
|
69
|
-
Net::HTTP.
|
69
|
+
Net::HTTP.class_eval do
|
70
|
+
include NetHTTPOverride
|
71
|
+
alias_method :request_without_intercept, :request
|
72
|
+
alias_method :request, :request_with_intercept
|
73
|
+
alias_method :connect_without_intercept, :connect
|
74
|
+
alias_method :connect, :connect_with_intercept
|
75
|
+
end
|
70
76
|
|
71
77
|
module Evervault
|
72
78
|
module Http
|
@@ -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,21 @@
|
|
1
1
|
require_relative "evervault/version"
|
2
2
|
require_relative "evervault/client"
|
3
3
|
require_relative "evervault/errors/errors"
|
4
|
+
require_relative "evervault/utils/validation_utils"
|
4
5
|
|
5
6
|
module Evervault
|
6
7
|
class << self
|
8
|
+
attr_accessor :app_id
|
7
9
|
attr_accessor :api_key
|
8
10
|
|
9
11
|
def encrypt(data)
|
10
12
|
client.encrypt(data)
|
11
13
|
end
|
12
14
|
|
15
|
+
def decrypt(data)
|
16
|
+
client.decrypt(data)
|
17
|
+
end
|
18
|
+
|
13
19
|
def run(function_name, encrypted_data, options = {})
|
14
20
|
client.run(function_name, encrypted_data, options)
|
15
21
|
end
|
@@ -23,12 +29,8 @@ module Evervault
|
|
23
29
|
end
|
24
30
|
|
25
31
|
private def client
|
26
|
-
|
27
|
-
|
28
|
-
"Please enter your team's API Key"
|
29
|
-
)
|
30
|
-
end
|
31
|
-
@client ||= Evervault::Client.new(api_key: api_key)
|
32
|
+
Evervault::Utils::ValidationUtils.validate_app_uuid_and_api_key(app_id, api_key)
|
33
|
+
@client ||= Evervault::Client.new(app_uuid: app_id, api_key: api_key)
|
32
34
|
end
|
33
35
|
end
|
34
36
|
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:
|
4
|
+
version: 2.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: 2023-
|
11
|
+
date: 2023-07-21 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
|