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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 291427781e97ac0ab65b8613c8e0f5255244c72ec826fb7cb0dc787c0931624f
4
- data.tar.gz: bc8bae94e62c9ffb65bb81bd14e1d3bc576c6f083e37c4f23bb6a0bf20ef1d4b
3
+ metadata.gz: c750c2a56b880d7ef8c5c0cef1bb856476d8fa88bf2cc06c72be2e45b14935dd
4
+ data.tar.gz: f162eb3e45b0d907642753b9f387cece1f49e3f3531b7cfb6570bcf6a00eba66
5
5
  SHA512:
6
- metadata.gz: 913ed8d651d680952deff0d635f4b3fc304b1154100093b7f8c40a8314fbcbfae4a1a5b1ae575cbc4e01f144917adf989601b45d81544835c9d28344ea66cac6
7
- data.tar.gz: 658289523da203f6b7cac915bc410efe6e107b736badf548367bc05183c89dd3a2c0d7f168f14842bc298b833bfd831efe0ae3bfebbc43821c52607f37d8deff
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.5, 2.6, 2.7, 3.1, truffleruby]
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
- - 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
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.5, 2.6, 2.7, 3.1, truffleruby]
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
- - 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
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
@@ -6,6 +6,7 @@
6
6
  /pkg/
7
7
  /spec/reports/
8
8
  /tmp/
9
+ Gemfile.lock
9
10
 
10
11
  # rspec failure tracking
11
12
  .rspec_status
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 team's API key
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({ hello: 'World!' })
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 | Description |
83
- | --------- | ---- | ----------- |
84
- | data | `String`, `Number`, `Boolean`, `Hash`, `Array` | Data to be encrypted |
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)
@@ -8,23 +8,25 @@ require_relative "crypto/client"
8
8
  module Evervault
9
9
  class Client
10
10
 
11
- attr_accessor :api_key, :base_url, :cage_run_url, :request_timeout
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
- cage_run_url: "https://run.evervault.com/",
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
- @request = Evervault::Http::Request.new(timeout: request_timeout, api_key: api_key)
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, cage_run_url: cage_run_url, cert: @intercept
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 run(function_name, encrypted_data, options = {})
38
- @request_handler.post(function_name, encrypted_data, options: options, cage_run: true)
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, params, optional_headers = {})
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)
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 def build_headers(optional_headers)
27
- optional_headers.merge({
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
- "Api-Key": @api_key,
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:, cage_run_url:, cert:)
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, params = nil)
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), params)
19
+ resp = @request.execute(:get, build_url(path))
21
20
  parse_json_body(resp.body)
22
21
  end
23
22
 
24
- def put(path, params)
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), params)
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, params)
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), params)
35
+ resp = @request.execute(:delete, build_url(path))
37
36
  parse_json_body(resp.body)
38
37
  end
39
38
 
40
- def post(path, params, options: {}, cage_run: false)
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, cage_run), params, build_cage_run_headers(options, cage_run))
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, cage_run = false)
53
- return "#{@base_url}#{path}" unless cage_run
54
- "#{@cage_run_url}#{path}"
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 connect
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
- super
57
+ connect_without_intercept
58
58
  end
59
59
 
60
- def request(req, body = nil, &block)
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
- super
65
+ request_without_intercept(req, body, &block)
66
66
  end
67
67
  end
68
68
 
69
- Net::HTTP.send :prepend, NetHTTPOverride
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
@@ -1,4 +1,4 @@
1
1
  module Evervault
2
- VERSION = "1.3.1"
2
+ VERSION = "2.0.0"
3
3
  EV_VERSION = {"prime256v1" => "NOC", "secp256k1" => "DUB"}
4
4
  end
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
- if api_key.nil?
27
- raise Evervault::Errors::AuthenticationError.new(
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: 1.3.1
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-03-28 00:00:00.000000000 Z
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