evervault 2.0.0 → 3.0.1

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.
@@ -1,74 +1,91 @@
1
- require_relative "http/request"
2
- require_relative "http/request_handler"
3
- require_relative "http/request_intercept"
4
- require_relative "http/relay_outbound_config"
5
- require_relative "threading/repeated_timer"
6
- require_relative "crypto/client"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'http/request'
4
+ require_relative 'http/request_handler'
5
+ require_relative 'http/request_intercept'
6
+ require_relative 'http/relay_outbound_config'
7
+ require_relative 'threading/repeated_timer'
8
+ require_relative 'crypto/client'
7
9
 
8
10
  module Evervault
9
11
  class Client
12
+ attr_accessor :config
10
13
 
11
- attr_accessor :function_run_url
12
- def initialize(
13
- app_uuid:,
14
- api_key:,
15
- base_url: "https://api.evervault.com/",
16
- function_run_url: "https://run.evervault.com/",
17
- relay_url: "https://relay.evervault.com:8443",
18
- ca_host: "https://ca.evervault.com",
19
- request_timeout: 30,
20
- curve: 'prime256v1'
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)
24
- @intercept = Evervault::Http::RequestIntercept.new(
25
- request: @request, ca_host: ca_host, api_key: api_key, base_url: base_url, relay_url: relay_url
26
- )
27
- @request_handler =
28
- Evervault::Http::RequestHandler.new(
29
- request: @request, base_url: base_url, cert: @intercept
30
- )
31
- @crypto_client = Evervault::Crypto::Client.new(request_handler: @request_handler, curve: curve)
32
- @intercept.setup()
14
+ def initialize(app_uuid:, api_key:, **options, &block)
15
+ @config = Evervault::Config.new(app_id: app_uuid, api_key: api_key)
16
+ configure_via_options(**options) if options.any?
17
+ intercept.setup
18
+ configure(&block) if block_given?
33
19
  end
34
20
 
35
- def encrypt(data)
36
- @crypto_client.encrypt(data)
21
+ def encrypt(data, role = nil)
22
+ crypto_client.encrypt(data, role)
37
23
  end
38
24
 
39
25
  def decrypt(data)
40
26
  unless data.is_a?(String) || data.is_a?(Array) || data.is_a?(Hash)
41
- raise Evervault::Errors::ArgumentError.new("data is of invalid type")
27
+ raise Evervault::Errors::EvervaultError, 'data is of invalid type'
42
28
  end
29
+
43
30
  payload = { data: data }
44
- response = @request_handler.post("decrypt", payload, nil, nil, true)
45
- response["data"]
31
+ response = request_handler.post('decrypt', payload, true, Evervault::Errors::ErrorMap)
32
+ response['data']
46
33
  end
47
34
 
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)
35
+ def create_token(action, data, expiry = nil)
36
+ payload = { payload: data, expiry: expiry, action: action }
37
+ request_handler.post('client-side-tokens', payload, true, Evervault::Errors::ErrorMap)
38
+ end
39
+
40
+ def run(function_name, payload)
41
+ payload = { payload: payload }
42
+ res = request_handler.post("functions/#{function_name}/runs", payload, true, Evervault::Errors::ErrorMap)
43
+
44
+ return res if res['status'] == 'success'
45
+
46
+ Evervault::Errors::ErrorMap.raise_function_error_on_failure(res)
61
47
  end
62
48
 
63
49
  def create_run_token(function_name, data = {})
64
- @request_handler.post("v2/functions/#{function_name}/run-token", data)
50
+ request_handler.post("v2/functions/#{function_name}/run-token", data)
65
51
  end
66
52
 
67
53
  def enable_outbound_relay(decryption_domains = nil)
68
54
  if decryption_domains.nil?
69
- @intercept.setup_outbound_relay_config
55
+ intercept.setup_outbound_relay_config
70
56
  else
71
- @intercept.setup_decryption_domains(decryption_domains)
57
+ intercept.setup_decryption_domains(decryption_domains)
58
+ end
59
+ end
60
+
61
+ def configure
62
+ yield(config)
63
+ end
64
+
65
+ private
66
+
67
+ def request
68
+ @request || Evervault::Http::Request.new(config: config)
69
+ end
70
+
71
+ def intercept
72
+ @intercept || Evervault::Http::RequestIntercept.new(request: request, config: config)
73
+ end
74
+
75
+ def request_handler
76
+ @request_handler || Evervault::Http::RequestHandler.new(request: request, config: config, cert: intercept)
77
+ end
78
+
79
+ def crypto_client
80
+ @crypto_client || Evervault::Crypto::Client.new(request_handler: request_handler, config: config)
81
+ end
82
+
83
+ def configure_via_options(**options)
84
+ warn '[DEPRECATION] configuration via Evervault::Client.new arguments is deprecated. Pass a block or use the'\
85
+ '`.configure` instead.'
86
+
87
+ options.each do |key, value|
88
+ config.send("#{key}=", value)
72
89
  end
73
90
  end
74
91
  end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Evervault
4
+ class Config
5
+ attr_accessor :app_id, :api_key, :base_url, :relay_url, :ca_host, :request_timeout, :curve
6
+
7
+ def initialize(app_id:, api_key:)
8
+ @app_id = app_id
9
+ @api_key = api_key
10
+ @base_url = 'https://api.evervault.com/'
11
+ @relay_url = 'https://relay.evervault.com:8443'
12
+ @ca_host = 'https://ca.evervault.com'
13
+ @request_timeout = 30
14
+ @curve = 'prime256v1'
15
+ end
16
+ end
17
+ end
@@ -1,126 +1,196 @@
1
- require_relative "../errors/errors"
2
- require_relative "curves/p256"
3
- require_relative "../version"
4
- require "openssl"
5
- require "base64"
6
- require "json"
7
- require "securerandom"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../errors/errors'
4
+ require_relative 'curves/p256'
5
+ require_relative 'curves/koblitz'
6
+ require_relative '../version'
7
+ require 'openssl'
8
+ require 'base64'
9
+ require 'json'
10
+ require 'securerandom'
11
+ require 'time'
8
12
 
9
13
  module Evervault
10
14
  module Crypto
11
15
  class Client
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'
16
+ attr_reader :config
17
+
18
+ def initialize(request_handler:, config: ::Evervault::Config.new)
19
+ @config = config
20
+ @p256 = Evervault::Crypto::Curves::P256.new
21
+ @koblitz = Evervault::Crypto::Curves::Koblitz.new
22
+ @ev_version = EV_VERSION[config.curve]
23
+ response = request_handler.get('cages/key')
24
+ key = config.curve == 'secp256k1' ? 'ecdhKey' : 'ecdhP256Key'
21
25
  @team_key = response[key]
22
26
  end
23
27
 
24
- def encrypt(data)
25
- raise Evervault::Errors::UndefinedDataError.new(
26
- "Data is required for encryption"
27
- ) if data.nil? || (data.instance_of?(String) && data.empty?)
28
+ def encrypt(data, role = nil)
29
+ if data.nil? || (data.instance_of?(String) && data.empty?)
30
+ raise Evervault::Errors::EvervaultError, 'Data is required for encryption'
31
+ end
32
+
33
+ unless encryptable_data?(data) || data.instance_of?(Hash) || data.instance_of?(Array)
34
+ raise Evervault::Errors::EvervaultError, "Encryption is not supported for #{data.class}"
35
+ end
36
+
37
+ traverse_and_encrypt(data, role)
38
+ end
39
+
40
+ def generate_metadata(role)
41
+ buffer = []
42
+
43
+ # Binary representation of a fixed map with 2 or 3 items, followed by the key-value pairs
44
+ buffer.push(0x80 | (role.nil? ? 2 : 3))
45
+
46
+ if role
47
+ # Binary representation for a fixed string of length 2, followed by `dr` (for "data role")
48
+ buffer.push(0xA2)
49
+ buffer.push(*'dr'.bytes)
50
+ # Binary representation for a fixed string of role name length, followed by the role name itself
51
+ buffer.push(0xA0 | role.length)
52
+ buffer.push(*role.bytes)
53
+ end
54
+
55
+ # Binary representation for a fixed string of length 2, followed by `eo` (for "encryption origin")
56
+ buffer.push(0xA2)
57
+ buffer.push(*'eo'.bytes)
58
+ # Binary representation for the integer 8 (Ruby SDK)
59
+ buffer.push(8)
60
+
61
+ # Binary representation for a fixed string of length 2, followed by `et` (for "encryption timestamp")
62
+ buffer.push(0xA2)
63
+ buffer.push(*'et'.bytes)
64
+ # Binary representation for a 4-byte unsigned integer (uint 32), followed by the epoch time (big-endian)
65
+ buffer.push(0xCE)
66
+ buffer.push(*[Time.now.to_i].pack('I!>').bytes)
67
+
68
+ buffer.pack('C*')
69
+ end
70
+
71
+ private
72
+
73
+ def create_v2_aad(data_type, ephemeral_public_key_bytes, app_public_key_bytes)
74
+ data_type_number = case data_type
75
+ when 'number' then 1
76
+ when 'boolean' then 2
77
+ else 0 # Default to String
78
+ end
79
+
80
+ version_number = case @ev_version
81
+ when 'S0lS' then 0
82
+ when 'QkTC' then 1
83
+ end
84
+
85
+ raise 'This encryption version does not have a version number for AAD' if version_number.nil?
86
+
87
+ config_byte_size = 1
88
+ total_size = config_byte_size + ephemeral_public_key_bytes.bytesize + app_public_key_bytes.bytesize
89
+ aad = "\x00" * total_size # Create a binary string of zeros
90
+
91
+ # Set the configuration byte
92
+ b = 0x00 | (data_type_number << 4) | version_number
93
+ aad.setbyte(0, b)
94
+
95
+ # Copy ephemeral public key bytes into aad
96
+ aad[config_byte_size, ephemeral_public_key_bytes.bytesize] = ephemeral_public_key_bytes
97
+
98
+ # Copy application public key bytes into aad
99
+ start_index = config_byte_size + ephemeral_public_key_bytes.bytesize
100
+ aad[start_index, app_public_key_bytes.bytesize] = app_public_key_bytes
101
+
102
+ aad
103
+ end
104
+
105
+ def encryptable_data?(data)
106
+ data.instance_of?(String) || [true, false].include?(data) ||
107
+ data.instance_of?(Integer) || data.instance_of?(Float)
108
+ end
109
+
110
+ def generate_shared_key
111
+ ec = OpenSSL::PKey::EC.generate(@config.curve)
112
+ @ephemeral_public_key = ec.public_key
113
+
114
+ decoded_team_key = OpenSSL::BN.new(Base64.strict_decode64(@team_key), 2)
115
+ group_for_team_key = OpenSSL::PKey::EC::Group.new(config.curve)
116
+ team_key_point = OpenSSL::PKey::EC::Point.new(group_for_team_key, decoded_team_key)
117
+
118
+ shared_key = ec.dh_compute_key(team_key_point)
119
+
120
+ # Perform KDF
121
+ encoded_ephemeral_key = if config.curve == 'prime256v1'
122
+ @p256.encode(decompressed_key: @ephemeral_public_key
123
+ .to_bn(:uncompressed).to_s(16)).to_der
124
+ else
125
+ @koblitz.encode(decompressed_key: @ephemeral_public_key
126
+ .to_bn(:uncompressed).to_s(16)).to_der
127
+ end
128
+ hash_input = shared_key + [0o0, 0o0, 0o0, 0o1].pack('C*') + encoded_ephemeral_key
129
+ hash = OpenSSL::Digest.new('SHA256')
130
+ hash.digest(hash_input)
131
+ end
28
132
 
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))
32
-
33
- traverse_and_encrypt(data)
133
+ def base_64_remove_padding(str)
134
+ str.gsub(/={1,2}$/, '')
34
135
  end
35
136
 
36
- private def encrypt_string(data_to_encrypt)
137
+ def encrypt_string(data_to_encrypt, role)
37
138
  cipher = OpenSSL::Cipher.new('aes-256-gcm').encrypt
38
139
 
39
- shared_key = generate_shared_key()
140
+ shared_key = generate_shared_key
40
141
  cipher.key = shared_key
41
142
 
42
143
  iv = cipher.random_iv
43
144
  cipher.iv = iv
44
145
 
45
- if (@curve == 'prime256v1')
46
- cipher.auth_data = Base64.strict_decode64(@team_key)
47
- end
146
+ header_type = header_type(data_to_encrypt)
147
+ cipher.auth_data = create_v2_aad(header_type, @ephemeral_public_key.to_octet_string(:compressed),
148
+ Base64.decode64(@team_key))
48
149
 
49
- encrypted_data = cipher.update(data_to_encrypt.to_s) + cipher.final + cipher.auth_tag
150
+ metadata = generate_metadata(role)
151
+ metadata_offset = [metadata.length].pack('v') # 'v' specifies 16-bit unsigned little-endian
152
+ payload = metadata_offset + metadata + data_to_encrypt.to_s
153
+
154
+ encrypted_data = cipher.update(payload.to_s) + cipher.final + cipher.auth_tag
50
155
 
51
156
  ephemeral_key_compressed_string = @ephemeral_public_key.to_octet_string(:compressed)
52
157
 
53
- format(header_type(data_to_encrypt), Base64.strict_encode64(iv), Base64.strict_encode64(ephemeral_key_compressed_string), Base64.strict_encode64(encrypted_data))
158
+ format(header_type(data_to_encrypt), Base64.strict_encode64(iv),
159
+ Base64.strict_encode64(ephemeral_key_compressed_string), Base64.strict_encode64(encrypted_data))
54
160
  end
55
161
 
56
- private def traverse_and_encrypt(data)
162
+ def traverse_and_encrypt(data, role)
57
163
  if encryptable_data?(data)
58
- return encrypt_string(data)
164
+ return encrypt_string(data, role)
59
165
  elsif data.instance_of?(Hash)
60
166
  encrypted_data = {}
61
- data.each { |key, value| encrypted_data[key] = traverse_and_encrypt(value) }
167
+ data.each { |key, value| encrypted_data[key] = traverse_and_encrypt(value, role) }
62
168
  return encrypted_data
63
169
  elsif data.instance_of?(Array)
64
- encrypted_data = data.map { |value| traverse_and_encrypt(value) }
170
+ encrypted_data = data.map { |value| traverse_and_encrypt(value, role) }
65
171
  return encrypted_data
66
172
  else
67
- raise Evervault::Errors::UnsupportedEncryptType.new(
68
- "Encryption is not supported for #{data.class}"
69
- )
173
+ raise Evervault::Errors::EvervaultError, "Encryption is not supported for #{data.class}"
70
174
  end
71
- data
72
- end
73
175
 
74
- private def encryptable_data?(data)
75
- data.instance_of?(String) || [true, false].include?(data) ||
76
- data.instance_of?(Integer) || data.instance_of?(Float)
77
- end
78
-
79
- private def generate_shared_key()
80
- ec = OpenSSL::PKey::EC.generate(@curve)
81
- @ephemeral_public_key = ec.public_key
82
-
83
- decoded_team_key = OpenSSL::BN.new(Base64.strict_decode64(@team_key), 2)
84
- group_for_team_key = OpenSSL::PKey::EC::Group.new(@curve)
85
- team_key_point = OpenSSL::PKey::EC::Point.new(group_for_team_key, decoded_team_key)
86
-
87
- shared_key = ec.dh_compute_key(team_key_point)
88
-
89
- if @curve == 'prime256v1'
90
- # Perform KDF
91
- encoded_ephemeral_key = @p256.encode(decompressed_key: @ephemeral_public_key.to_bn(:uncompressed).to_s(16)).to_der
92
- hash_input = shared_key + [00, 00, 00, 01].pack('C*') + encoded_ephemeral_key
93
- hash = OpenSSL::Digest::SHA256.new()
94
- digest = hash.digest(hash_input)
95
- return digest
96
- end
97
-
98
- shared_key
176
+ data
99
177
  end
100
178
 
101
- private def format(datatype, iv, team_key, encrypted_data)
179
+ def format(datatype, iv, team_key, encrypted_data)
102
180
  "ev:#{@ev_version}#{
103
- datatype != 'string' ? ':' + datatype : ''
181
+ datatype != 'string' ? ":#{datatype}" : ''
104
182
  }:#{base_64_remove_padding(iv)}:#{base_64_remove_padding(
105
183
  team_key
106
184
  )}:#{base_64_remove_padding(encrypted_data)}:$"
107
185
  end
108
186
 
109
- private def base_64_remove_padding(str)
110
- str.gsub(/={1,2}$/, '');
111
- end
112
-
113
- private def header_type(data)
114
- if data.instance_of?(Array)
115
- return "Array"
116
- elsif [true, false].include?(data)
117
- return "boolean"
118
- elsif data.instance_of?(Hash)
119
- return "object"
187
+ def header_type(data)
188
+ if [true, false].include?(data)
189
+ 'boolean'
120
190
  elsif data.instance_of?(Float) || data.instance_of?(Integer)
121
- return "number"
191
+ 'number'
122
192
  elsif data.instance_of?(String)
123
- return "string"
193
+ 'string'
124
194
  end
125
195
  end
126
196
  end
@@ -1,9 +1,10 @@
1
- require "openssl"
1
+ # frozen_string_literal: true
2
+
3
+ require 'openssl'
2
4
 
3
5
  module Evervault
4
6
  module Crypto
5
7
  class CurveBase
6
-
7
8
  def initialize(curve_name:, curve_values:)
8
9
  @asn1Encoder = buildEncoder(curve_values: curve_values)
9
10
  end
@@ -12,13 +13,19 @@ module Evervault
12
13
  @asn1Encoder.call(decompressed_key)
13
14
  end
14
15
 
15
- private def buildEncoder(curve_values:)
16
+ private
17
+
18
+ def buildEncoder(curve_values:)
16
19
  a = OpenSSL::ASN1::OctetString.new([curve_values::A].pack('H*'))
17
20
  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")
21
+ if !curve_values::SEED.nil?
22
+ seed = OpenSSL::ASN1::BitString.new([curve_values::SEED].pack('H*'))
23
+ curve = OpenSSL::ASN1::Sequence.new([a, b, seed])
24
+ else
25
+ curve = OpenSSL::ASN1::Sequence.new([a, b])
26
+ end
27
+
28
+ field_type = OpenSSL::ASN1::ObjectId.new('1.2.840.10045.1.1')
22
29
  parameters = OpenSSL::ASN1::Integer.new(curve_values::P.to_i(16))
23
30
  field_id = OpenSSL::ASN1::Sequence.new([field_type, parameters])
24
31
 
@@ -28,11 +35,14 @@ module Evervault
28
35
  cofactor = OpenSSL::ASN1::Integer.new(curve_values::H.to_i(16))
29
36
  ec_parameters = OpenSSL::ASN1::Sequence.new([version, field_id, curve, base, order, cofactor])
30
37
 
31
- algorithm = OpenSSL::ASN1::ObjectId.new("1.2.840.10045.2.1")
38
+ algorithm = OpenSSL::ASN1::ObjectId.new('1.2.840.10045.2.1')
32
39
  algorithm_identifier = OpenSSL::ASN1::Sequence.new([algorithm, ec_parameters])
33
40
 
34
- return lambda {|public_key| OpenSSL::ASN1::Sequence.new([algorithm_identifier, OpenSSL::ASN1::BitString.new([public_key].pack('H*'))])}
41
+ lambda { |public_key|
42
+ OpenSSL::ASN1::Sequence.new([algorithm_identifier,
43
+ OpenSSL::ASN1::BitString.new([public_key].pack('H*'))])
44
+ }
35
45
  end
36
46
  end
37
47
  end
38
- end
48
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
4
+
5
+ module KOBLITZ_CONSTANTS
6
+ A = '0000000000000000000000000000000000000000000000000000000000000000'
7
+ B = '0000000000000000000000000000000000000000000000000000000000000007'
8
+ SEED = nil
9
+ P = 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F'
10
+ GENERATOR = '0479BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798483ADA7726A3C4655DA4FBFC0E1108A8FD17B'\
11
+ '448A68554199C47D08FFB10D4B8'
12
+ N = 'FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141'
13
+ H = '01'
14
+ end
15
+
16
+ module Evervault
17
+ module Crypto
18
+ module Curves
19
+ class Koblitz < CurveBase
20
+ def initialize
21
+ super(curve_name: 'secp256k1', curve_values: KOBLITZ_CONSTANTS)
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -1,22 +1,25 @@
1
- require_relative "base"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'base'
2
4
 
3
5
  # https://neuromancer.sk/std/x962/prime256v1
4
6
 
5
7
  module P256_CONSTANTS
6
- A = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC"
7
- B = "5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B"
8
- SEED = "C49D360886E704936A6678E1139D26B7819F7E90"
9
- P = "FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF"
10
- GENERATOR = "046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"
11
- N = "FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551"
12
- H = "01"
8
+ A = 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFC'
9
+ B = '5AC635D8AA3A93E7B3EBBD55769886BC651D06B0CC53B0F63BCE3C3E27D2604B'
10
+ SEED = 'C49D360886E704936A6678E1139D26B7819F7E90'
11
+ P = 'FFFFFFFF00000001000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFF'
12
+ GENERATOR = '046B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C2964FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE3'\
13
+ '3576B315ECECBB6406837BF51F5'
14
+ N = 'FFFFFFFF00000000FFFFFFFFFFFFFFFFBCE6FAADA7179E84F3B9CAC2FC632551'
15
+ H = '01'
13
16
  end
14
17
 
15
18
  module Evervault
16
19
  module Crypto
17
20
  module Curves
18
21
  class P256 < CurveBase
19
- def initialize()
22
+ def initialize
20
23
  super(curve_name: 'prime256v1', curve_values: P256_CONSTANTS)
21
24
  end
22
25
  end
@@ -1,47 +1,35 @@
1
- require_relative "errors"
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'errors'
2
4
 
3
5
  module Evervault
4
6
  module Errors
5
7
  class ErrorMap
6
- def self.raise_errors_on_failure(status_code, body, headers)
7
- return if status_code < 400
8
- case status_code
9
- when 404
10
- raise ResourceNotFoundError.new("Resource Not Found")
11
- when 400
12
- raise BadRequestError.new("Bad request")
13
- when 401
14
- raise AuthenticationError.new("Unauthorized")
15
- when 403
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
21
- when 500
22
- raise ServerError.new("Server Error")
23
- when 502
24
- raise BadGatewayError.new("Bad Gateway Error")
25
- when 503
26
- raise ServiceUnavailableError.new("Service Unavailable")
8
+ def self.raise_errors_on_failure(_status_code, body, _headers)
9
+ parsed_body = JSON.parse(body)
10
+ code = parsed_body['code']
11
+ detail = parsed_body['detail']
12
+
13
+ case code
14
+ when 'functions/request-timeout'
15
+ raise FunctionTimeoutError, detail
16
+ when 'functions/function-not-ready'
17
+ raise FunctionNotReadyError, detail
18
+ when 'functions/forbidden-ip'
19
+ raise ForbiddenIPError, detail
27
20
  else
28
- raise UnexpectedError.new(
29
- self.message_for_unexpected_error_without_type(body)
30
- )
21
+ raise EvervaultError, detail
31
22
  end
32
23
  end
33
24
 
34
- private def message_for_unexpected_error_without_type(error_details)
35
- if error_details.nil?
36
- return(
37
- "An unexpected error occurred without message or status code. Please contact Evervault support"
38
- )
39
- end
40
- message = error_details["message"]
41
- status_code = error_details["statusCode"]
42
- "An unexpected error occured. It occurred with the message: #{
43
- message
44
- } and http_code: '#{status_code}'. Please contact Evervault support"
25
+ def self.raise_function_error_on_failure(body)
26
+ error = body['error']
27
+ raise EvervaultError, 'An unexpected error occurred. Please contact Evervault support' unless error
28
+
29
+ message = error['message']
30
+ stack = error['stack']
31
+ id = body['id']
32
+ raise FunctionRuntimeError.new(message, stack, id)
45
33
  end
46
34
  end
47
35
  end