evervault 2.0.0 → 3.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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