cryptograpi_ruby 0.0.1 → 0.0.1.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 29da0fd4bd9d3261e0c0b62a530543a528383b3e801a896954e5d212610e59d4
4
- data.tar.gz: a102a68abeef683afab3d1ebc32bf04e749c4cab891075b689aa3224fa0fff4e
3
+ metadata.gz: ba7b04c4eda2c473ba5f06e06780b132d253e2306102e0a6e06d7f13d3731a4c
4
+ data.tar.gz: 99bbff7d24a71953d31348b21f41fb58378d64aaebf73cbbb35f4531d250eac7
5
5
  SHA512:
6
- metadata.gz: 362abb4b8d8f63b60ddece6f51ef0a2149264a5e9d33a10a00f38a01b8ed1ed5ad15e0c71da050fbee384376760ae7230df62a00b3a37dc179f9cbb24166df93
7
- data.tar.gz: ab8f9a4791ffe18c341b380536b0df48bc5d8d42de48021c87cc88ee779162206a85eac9a3a708b2079f3cb9f64f74d86cf3af6359d20053c077160c13d3135e
6
+ metadata.gz: 183e28010a0cd233dda749e7998470a89b0707fdfc58115d26ee9a9377ddc4c5b611aa5a6df27ff02a3f05146687254cf35a142c3f7e61173e845e1872ab00e7
7
+ data.tar.gz: '0971e1bd891126004b3233a972152f94ea86cf4020ee79451d44ceca174b42ad619db7f3126a6f0d2c425dba145a5f957d3401bd22ebceaed31cd42bbe39d6bf'
data/Gemfile CHANGED
@@ -1,7 +1,10 @@
1
1
  # frozen_string_literal: true
2
-
3
2
  # cryptograpi_ruby/Gemfile
4
3
 
5
4
  source 'https://rubygems.org'
6
5
 
7
6
  gemspec
7
+
8
+ group :test do
9
+ gem 'tzinfo-data', platforms: %i[mingw mswin x64_mingw jruby]
10
+ end
data/Rakefile CHANGED
@@ -1,8 +1,20 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'rake'
4
- require 'rubocop/rake_task'
5
4
 
5
+ begin
6
+ require 'bundler/setup'
7
+ Bundler::GemHelper.install_tasks
8
+ rescue LoadError
9
+ puts 'it is recommended to run bundler for running the tests'
10
+ end
11
+
12
+ task default: :spec
13
+
14
+ require 'rspec/core/rake_task'
15
+ RSpec::Core::RakeTask.new(:spec)
16
+
17
+ require 'rubocop/rake_task'
6
18
  RuboCop::RakeTask.new do |task|
7
19
  task.requires << 'rubocop-performance'
8
20
  task.requires << 'rubocop-rspec'
@@ -22,8 +22,23 @@ Gem::Specification.new do |spec|
22
22
  spec.add_development_dependency 'rubocop', '~> 1.18'
23
23
  spec.add_development_dependency 'rubocop-performance', '~> 1.11'
24
24
  spec.add_development_dependency 'rubocop-rspec', '~> 2.4'
25
+ spec.add_development_dependency 'codecov', '~> 0.1'
26
+ spec.add_development_dependency 'dotenv', '~> 2.5'
27
+ spec.add_development_dependency 'rake', '~> 13.0'
28
+ spec.add_development_dependency 'rspec', '~> 3.6'
29
+ spec.add_development_dependency 'simplecov', '~> 0.16'
30
+ spec.add_development_dependency 'vcr', '~> 6.0'
31
+
32
+ # Use an embedded rails app for testing
33
+ spec.add_development_dependency 'rails', '~> 6.1'
34
+ spec.add_development_dependency 'rspec-rails', '~> 4.0'
35
+
36
+
37
+
25
38
  spec.add_runtime_dependency 'activesupport', '~> 6.1'
39
+ spec.add_runtime_dependency 'configparser', '>=0.1'
26
40
  spec.add_runtime_dependency 'httparty', '~> 0.18'
27
41
  spec.add_runtime_dependency 'rb-readline', '~> 0.5'
42
+ spec.add_runtime_dependency 'tzinfo-data', '>= 1'
28
43
  spec.add_runtime_dependency 'webrick', '~> 1.7'
29
44
  end
@@ -0,0 +1,71 @@
1
+ require 'active_support/all'
2
+ require 'openssl'
3
+
4
+ module Cryptograpi
5
+ class Cipher
6
+
7
+ CRYPTOFLAG = 0b0000001
8
+
9
+ def set_algorithm
10
+ @algorithm = {
11
+ 'aes-128-gcm' => {
12
+ id: 0,
13
+ algorithm: OpenSSL::Cipher::AES128,
14
+ mode: OpenSSL::Cipher.new('aes-128-gcm'),
15
+ key_length: 16,
16
+ iv_length: 12,
17
+ tag_length: 16
18
+ },
19
+ 'aes-256-gcm' => {
20
+ id: 1,
21
+ algorithm: OpenSSL::Cipher::AES256,
22
+ mode: OpenSSL::Cipher.new('aes-256-gcm'),
23
+ key_length: 32,
24
+ iv_length: 12,
25
+ tag_length: 16
26
+ }
27
+ }
28
+ end
29
+
30
+ def find_algorithm(id)
31
+ set_algorithm.each do |k, v|
32
+ return k if v[:id] == id
33
+ end
34
+ 'unknown'
35
+ end
36
+
37
+ def get_algorithm(name)
38
+ set_algorithm[name]
39
+ end
40
+
41
+ def encryptor(obj, key, init_vector = nil)
42
+ # The 'key' parameter is a byte string that contains the key
43
+ # for this encryption operation.
44
+ # If there is an, correct length, initialization vector (init_vector)
45
+ # then it is used. If not, the function generates one.
46
+ raise 'Invalid key length' if key.length != obj[:key_length]
47
+
48
+ raise 'Invalid initialization vector length' if !init_vector.nil? && init_vector.length != obj[:init_vector_length]
49
+
50
+ cipher = obj[:mode]
51
+ cipher.encrypt
52
+ cipher.key = key
53
+ init_vector = cipher.random_init_vector
54
+
55
+ [cipher, init_vector]
56
+ end
57
+
58
+ def decryptor(obj, key, init_vector)
59
+ raise 'Invalid key length' if key.length != obj[:key_length]
60
+
61
+ raise 'Invalid initialization vector length' if !init_vector.nil? && init_vector.length != obj[:init_vector_length]
62
+
63
+ cipher = obj[:mode]
64
+ cipher.decrypt
65
+ cipher.key = key
66
+ cipher.init_vector = init_vector
67
+
68
+ cipher
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,87 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'configparser'
4
+ require 'rb-readline'
5
+ require_relative './host'
6
+
7
+ module Cryptograpi
8
+ class Info
9
+ def initialize(access_key_id, secret_access_key, signing_key, host)
10
+ @access_key_id = access_key_id
11
+ @secret_access_key = secret_access_key
12
+ @signing_key = signing_key
13
+ @host = host
14
+ end
15
+
16
+ def set_attrs
17
+ OpenStruct.new(
18
+ access_key_id: @access_key_id,
19
+ secret_access_key: @secret_access_key,
20
+ signing_key: @signing_key,
21
+ host: @host
22
+ )
23
+ end
24
+ end
25
+
26
+ # Loads and reads a credential file or uses default info
27
+ class ConfigCredentials < Info
28
+ def initialize(configuration_file, profile)
29
+ # Check if the file exists
30
+ raise "There is an error finding or reading the #{configuration_file} file" if !configuration_file.nil? && !File.exist?(configuration_file)
31
+
32
+ configuration_file = '~/.cryptograpi/credentials' if configuration_file.nil?
33
+
34
+ @credentials = load_configuration_file(configuration_file, profile) if File.exist?(File.expand_path(configuration_file))
35
+ end
36
+
37
+ def attrs
38
+ @credentials
39
+ end
40
+
41
+ def load_configuration_file(file, profile)
42
+ config = ConfigParser.new(File.expand_path(file))
43
+
44
+ # Dict for profiles
45
+ p = {}
46
+ d = {}
47
+
48
+ # If there is a default profile, get it
49
+ d = config['default'] if config['default'].present?
50
+
51
+ d['SERVER'] = Cryptograpi::CRYPTOGRAPI_HOST unless d.key?('SERVER')
52
+
53
+ # If there is a supplied profile, get it
54
+ p = config[profile] if config[profile].present?
55
+
56
+ # Use the supplied profile. Otherwise use default
57
+ access_key_id = p.key?('ACCESS_KEY_ID') ? p['ACCESS_KEY_ID'] : d['ACCESS_KEY_ID']
58
+ secret_access_key = p.key?('SECRET_ACCESS_KEY') ? p['SECRET_ACCESS_KEY'] : d['SECRET_ACCESS_KEY']
59
+ signing_key = p.key?('SIGNING_KEY') ? p['SIGNING_KEY'] : d['SIGNING_KEY']
60
+ host = p.key?('SERVER') ? p['SERVER'] : d['SERVER']
61
+
62
+ # Sanitizing the host variable to always include https
63
+ host = "https://#{host}" if !host.include?('http://') && !host.include?('https://')
64
+
65
+ Info.new(access_key_id, secret_access_key, signing_key, host).set_attrs
66
+ end
67
+ end
68
+
69
+ # Credentials can be explicitly set or
70
+ # use info from ENV Variables
71
+ class Credentials < Info
72
+ def initialize(papi, sapi, srsa, host)
73
+ super
74
+ @access_key_id = papi.present? ? papi : ENV['CRYPTOGRAPI_ACCESS_KEY_ID']
75
+ @secret_access_key = sapi.present? ? sapi : ENV['CRYPTOGRAPI_SECRET_ACCESS_KEY']
76
+ @signing_key = srsa.present? ? srsa : ENV['CRYPTOGRAPI_SIGNING_KEY']
77
+ @host = host.present? ? host : ENV['CRYPTOGRAPI_SERVER']
78
+ end
79
+
80
+ @creds = Info.new(@access_key_id, @secret_access_key, @signing_key, @host).set_attrs
81
+
82
+ def attrs
83
+ @creds
84
+ end
85
+ end
86
+ end
87
+
@@ -0,0 +1,200 @@
1
+ require 'active_support/all'
2
+ require 'httparty'
3
+ require 'rb-readline'
4
+ require 'webrick'
5
+ require_relative './cipher'
6
+ require_relative './encrypt'
7
+ require_relative './signature'
8
+
9
+ module Cryptograpi
10
+ class Decryption
11
+ def initialize(creds)
12
+ raise 'Some credentials are missing' unless validate_credentials(creds)
13
+
14
+ @papi = creds.access_key_id
15
+ @sapi = creds.signing_key
16
+ @srsa = creds.secret_access_key
17
+ @host = creds.host.blank? ? CRYPTOGRAPI_HOST : creds.host
18
+
19
+ @decryption_started = false
20
+ @decryption_ready = true
21
+ end
22
+
23
+ def begin_decryption
24
+ raise ' Decryption is not ready' unless @decryption_ready
25
+
26
+ raise ' Decryption already started' if @decryption_started
27
+
28
+ raise 'Decryption already in progress' if @key.present? && @key.key?('dec')
29
+
30
+ @decryption_started = true
31
+ @data = ''
32
+ end
33
+
34
+ def update_decryption(data)
35
+ raise ' Decryption is not started' unless @decryption_started
36
+
37
+ # Act as a buffer for data
38
+ @data += data
39
+
40
+ # If there is no key or dec member of key, a header is still being built
41
+ if !@key.present? || !@key.key?('dec')
42
+ struct_length = [1, 1, 1, 1, 1].pack('CCCCn').length
43
+ packed_struct = @data[0...struct_length]
44
+
45
+ # Does the buffer contain enough of the header to determine
46
+ # the lengths of the initialization vector and the key?
47
+ if @data.length > struct_length
48
+ version, flags, algorithm_id, iv_length, key_length = packed_struct.unpack('CCCCn')
49
+
50
+ raise 'Invalid encryption header' if (version != 0) || ((flags & ~Cipher::CRYPTOFLAG) != 0)
51
+
52
+ if @data.length > struct_length + iv_length + key_length
53
+ # Extract the initialization vector
54
+ iv = @data[struct_length...iv_length + struct_length]
55
+ # Extract the encrypted key
56
+ enc_key = @data[struct_length + iv_length..key_length + struct_length + iv_length]
57
+ # Remove the header from the buffer
58
+ @data = @data[struct_length + iv_length + key_length..-1]
59
+
60
+ # Generate a key identifier
61
+ hash_sha512 = OpenSSL::Digest.new('SHA512')
62
+ hash_sha512 << enc_key
63
+ client_id = hash_sha512.digest
64
+
65
+ if @key.present?
66
+ close if @key['client_id'] != client_id
67
+ end
68
+
69
+ unless @key.present?
70
+ url = endpoint_base + '/decrypt/key'
71
+ query = { encrypted_data_key: Base64.strict_encode64(enc_key) }
72
+ headers = Signature.headers(endpoint, @host, 'post', @papi, query, @sapi)
73
+
74
+ response = HTTParty.post(
75
+ url,
76
+ body: query.to_json,
77
+ headers: headers
78
+ )
79
+
80
+ if response.code == WEBrick::HTTPStatus::RC_OK
81
+ @key = {}
82
+ @key['finger_print'] = response[key_fingerprint]
83
+ @key['client_id'] = client_id
84
+ @key['session'] = response['encryption_session']
85
+
86
+ # Get the cipher name
87
+ @key['algorithm'] = Cipher.new.find_algorithm(algorithm_id)
88
+
89
+ encrypted_private_key = response['encrypted_private_key']
90
+ # Decrypt WDK from base64
91
+ wdk = Base64.strict_decode64(wrapped_data_key)
92
+ # Use private key to decrypt the wdk
93
+ dk = private_key.private_decrypt(wdk, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
94
+
95
+ @key['raw'] = dk
96
+ @key['uses'] = 0
97
+ else
98
+ raise "HTTPError response: Expected 201 got #{response.code}"
99
+ end
100
+ end
101
+
102
+ # If the key object exists, create a new decryptor.
103
+ # Increment the key usage
104
+ if @key.present?
105
+ @cipher = Cipher.new.get_algorithm(@key['algorithm'])
106
+ @key['dec'] = Cipher.new.decryptor(@cipher, @key['raw'], iv)
107
+
108
+ if (flags & Cipher::CRYPTOFLAG) != 0
109
+ @key['dec'].auth_data = packed_struct + iv + enc_key
110
+ end
111
+ @key['uses'] += 1
112
+ end
113
+ end
114
+ end
115
+ end
116
+
117
+ plain_text = ''
118
+ if @key.present? && @key.key?('dec')
119
+ size = @data.length - @cipher[:tag_length]
120
+ if size.positive?
121
+ plain_text = @key['dec'].update(@data[0..size - 1])
122
+ @data = @data[size..-1]
123
+ end
124
+ plain_text
125
+ end
126
+ end
127
+
128
+ def finish_decryption
129
+ raise 'Decryption is not started' unless @decryption_started
130
+
131
+ # Update maintains tag-size bytes in the buffer
132
+ # When this function is called, all data must already be
133
+ # in the decryption object
134
+ sz = @data.length - @cipher[:tag_length]
135
+
136
+ raise 'Invalid Tag!' if sz.negative?
137
+
138
+ if sz.zero?
139
+ @key['dec'].auth_tag = @data
140
+ begin
141
+ plain_text = @key['dec'].final
142
+ # Delete the context
143
+ @key.delete('dec')
144
+ # Return the plain text
145
+ @decryption_started = false
146
+ plain_text
147
+ rescue Exception
148
+ print 'Invalid cipher data or tag!'
149
+ ''
150
+ end
151
+ end
152
+ end
153
+
154
+ def close_decryption
155
+ raise 'Decryption currently running' if @decryption_started
156
+
157
+ # Reset the decryption object
158
+ if @key.present?
159
+ if @key['uses'].positive?
160
+ query_url = "#{endpoint}/#{@key['finger_print']}/#{@key['session']}"
161
+ url = "#{endpoint_base}/decryption/key/#{@key['finger_print']}/#{@key['session']}"
162
+ query = { uses: @key['uses'] }
163
+ headers = Signature.headers(query_url, @host, 'patch', @papi, query, @sapi)
164
+
165
+ response = HTTParty.patch(
166
+ url,
167
+ body: query.to_json,
168
+ headers: headers
169
+ )
170
+
171
+ remove_instance_variable(:@data)
172
+ remove_instance_variable(:@key)
173
+ end
174
+ end
175
+ end
176
+
177
+ def endpoint
178
+ '/api/v0/encryption/key'
179
+ end
180
+
181
+ def endpoint_base
182
+ "#{@host}/api/v0"
183
+ end
184
+
185
+ end
186
+
187
+ def decrypt(creds, data)
188
+ begin
189
+ dec = Decryption.new(creds)
190
+ res = dec.begin_decryption + dec.update_decryption(data) + dec.finish_decryption
191
+ dec.close_decryption
192
+ rescue StandardError
193
+ dec&.close_decryption
194
+ raise
195
+ end
196
+
197
+ res
198
+ end
199
+
200
+ end
@@ -0,0 +1,165 @@
1
+ require 'active_support/all'
2
+ require 'httparty'
3
+ require 'rb-readline'
4
+ require 'webrick'
5
+ require_relative './cipher'
6
+ require_relative './signature'
7
+
8
+ module Cryptograpi
9
+ class Encryption
10
+ def initialize(creds, uses)
11
+ raise 'Some credentials are missing' unless validate_credentials(creds)
12
+
13
+ @papi = creds.access_key_id
14
+ @sapi = creds.signing_key
15
+ @srsa = creds.secret_access_key
16
+ @host = creds.host.blank? ? CRYPTOGRAPI_HOST : creds.host
17
+ url = "#{endpoint_base}/encryption/key"
18
+ query = { uses: uses }
19
+ headers = Signature.headers(endpoint, @host, 'post', @papi, query, @sapi)
20
+
21
+ @encryption_started = false
22
+ @encryption_ready = true
23
+
24
+ # First, ask for a key from the server.
25
+ # If the request fails, raise a HTTPError.
26
+
27
+ begin
28
+ response = HTTParty.post(
29
+ url,
30
+ body: query.to_json,
31
+ headers: headers
32
+ )
33
+ rescue HTTParty::Error
34
+ raise 'Server Unreachable'
35
+ end
36
+
37
+ if response.code == WEBrick::HTTPStatus::RC_CREATED
38
+ # Builds the key object
39
+ @key = {}
40
+ @key['id'] = response['key_fingerprint']
41
+ @key['session'] = response['encryption_session']
42
+ @key['security_model'] = response['security_model']
43
+ @key['algorithm'] = response['security_model']['algorithm'].downcase
44
+ @key['max_uses'] = response['max_uses']
45
+ @key['uses'] = 0
46
+ @key['encrypted'] = Base64.strict_decode64(response['encrypted_data_key'])
47
+
48
+ # get the encrypted private key from response body
49
+ encrypted_pk = response['encrypted_private_key']
50
+ # Data key from response body
51
+ wrapped_data_key = response['wrapped_data_key']
52
+ # decrypt the encrypted private key using @srsa
53
+ pk = OpenSSL::PKey::RSA.new(encrypted_pk, @srsa)
54
+ # Decode WDK from base64 format
55
+ wdk = Base64.strict_decode64(wrapped_data_key)
56
+ # Use private key to decrypt the wrapped data key
57
+ dk = pk.private_decrypt(wdk, OpenSSL::PKey::RSA::PKCS1_OAEP_PADDING)
58
+ @key['raw'] = dk
59
+ @cipher = Cipher.new.get_algorithm(@key['algorithm'])
60
+ else
61
+ raise "HTTPError Response: Expected 201, got #{response.code}"
62
+ end
63
+ end
64
+
65
+ def begin_encryption
66
+ # Begins the encryption process
67
+ # Each time this function is called, uses increments by 1
68
+ raise 'Encryption not ready' unless @encryption_ready
69
+ # cipher already exists
70
+ raise 'Encryption in progress' if @encryption_started
71
+ # Check for max uses flag
72
+ raise 'Maximum usage exceeded' if @key['uses'] >= @key["max_uses"]
73
+
74
+ # Increase the uses counter
75
+ @key['uses'] += 1
76
+ # New context and initialization vector
77
+ @enc, @iv = Cipher.new.encryptor(@cipher, @key['raw'])
78
+ # Pack and create a byte string
79
+ struct = [0, Cipher::CRYPTOFLAG, @cipher[:id], @iv.length, @key['encrypted'].length].pack('CCCCn')
80
+
81
+ @enc.auth_data = struct + @iv + @key['encrypted']
82
+ @encryption_started = true
83
+
84
+ # Return the encrypted object
85
+ struct + @iv + @key['encrypted']
86
+ end
87
+
88
+ def update_encryption(data)
89
+ raise 'Encryption has not started yet' unless @encryption_started
90
+
91
+ @enc.update(data)
92
+ end
93
+
94
+ def finish_encryption
95
+ raise 'Encryption not started' unless @encryption_started
96
+
97
+ # Finalizes the encryption and adds any auth info required by the algorithm
98
+ res = @enc.final
99
+ if @cipher[:tag_length] != 0
100
+ # Add the tag to the cipher text
101
+ res += @enc.auth_tag
102
+ end
103
+
104
+ @encryption_started = false
105
+ # return the encrypted result
106
+ res
107
+ end
108
+
109
+ def close_encryption
110
+ raise 'Encryption currently running' if @encryption_started
111
+
112
+ if @key['uses'] < @key['max_uses']
113
+ query_url = "#{endpoint}/#{@key['id']}/#{@key['session']}"
114
+ url = "#{endpoint_base}/encryption/key/#{@key['id']}/#{@key['session']}"
115
+ query = { actual: @key['uses'], requested: @key['max_uses'] }
116
+ headers = Signature.headers(query_url, @host, 'patch', @papi, query, @sapi)
117
+
118
+ response = HTTParty.patch(
119
+ url,
120
+ body: query.to_json,
121
+ headers: headers
122
+ )
123
+ remove_instance_variable(:@key)
124
+ @encryption_ready = false
125
+ end
126
+ end
127
+
128
+ def endpoint
129
+ '/api/v0/encryption/key'
130
+ end
131
+
132
+ def endpoint_base
133
+ "#{@host}/api/v0"
134
+ end
135
+
136
+ def validate_credentials(credentials)
137
+ !credentials.access_key_id.blank? &&
138
+ !credentials.secret_access_key.blank? &&
139
+ !credentials.signing_key.blank?
140
+ end
141
+ end
142
+
143
+ # Check credentials are present and valid
144
+ def validate_credentials(credentials)
145
+ !credentials.access_key_id.blank? &&
146
+ !credentials.secret_access_key.blank? &&
147
+ !credentials.signing_key.blank?
148
+ end
149
+
150
+ # Qui e!
151
+ def encrypt(credentials, data)
152
+ begin
153
+ enc = Encryption.new(credentials, 1)
154
+ res =
155
+ enc.begin_encryption +
156
+ enc.update_encryption(data) +
157
+ enc.finish_encryption
158
+ enc.close_encryption
159
+ rescue StandardError
160
+ enc&.close_encryption
161
+ raise
162
+ end
163
+ res
164
+ end
165
+ end
@@ -0,0 +1,3 @@
1
+ module CryptograpiRuby
2
+ CRYPTOGRAPI_HOST = 'api.cryptograpi.com'.freeze
3
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/all'
4
+
5
+ module Cryptograpi
6
+ # HTTP authentication for our platform
7
+ class Signature
8
+ def self.headers(endpoint, host, http_method, papi, query, sapi)
9
+
10
+ # Request Target (http_method path?query)
11
+ req_target = "#{http_method} #{endpoint}"
12
+
13
+ # Unix time for signature creation
14
+ created_at = Time.now.to_i
15
+
16
+ # We hash the body of the HTTP message. Even if it's empty
17
+ ha_sha512 = OpenSSL::Digest.new('SHA512')
18
+ ha_sha512 << JSON.dump(query)
19
+ digest = "SHA-512=#{Base64.strict_encode64(ha_sha512.digest)}"
20
+
21
+ # Initialize headers
22
+ header_signature = {}
23
+ header_signature['user-agent'] = "cryptograpi_ruby/#{Cryptograpi::VERSION}"
24
+ header_signature['content-type'] = 'application/json'
25
+ header_signature['(request-target'] = req_target
26
+ header_signature['date'] = sign_date
27
+ header_signature['host'] = get_host(host)
28
+ header_signature['(created)'] = created_at
29
+ header_signature['digest'] = digest
30
+ headers = %w[content-type date host (created) (request-target) digest]
31
+
32
+ # Calculate HMAC including the headers
33
+ hmac = OpenSSL::HMAC.new(sapi, OpenSSL::Digest.new('SHA512'))
34
+ headers.each do |header|
35
+ hmac << "#{header}: #{header_signature[header]}\n" if header_signature.key?(header)
36
+ end
37
+
38
+ header_signature.delete('(created)')
39
+ header_signature.delete('(request-target)')
40
+ header_signature.delete('(host)')
41
+
42
+ # Build the final signature
43
+ header_signature['signature'] = "keyId=\"#{papi}\""
44
+ header_signature['signature'] += ', algorithm="hmac-sha512"'
45
+ header_signature['signature'] += ", created=#{created_at}"
46
+ header_signature['signature'] += ", headers=#{headers.join(' ')}\""
47
+ header_signature['signature'] += ', signature='
48
+ header_signature['signature'] += Base64.strict_encode64(hmac.digest)
49
+ header_signature['signature'] += '"'
50
+
51
+ header_signature
52
+ end
53
+
54
+ def self.sign_date
55
+ "#{DateTime.now.in_time_zone('GMT').strftime('%a, %d %b %Y')} #{DateTime.now.in_time_zone('GMT').strftime('%H:%M:%S')} GMT"
56
+ end
57
+
58
+ def self.get_host(host)
59
+ uri = URI(host)
60
+ ret = uri.hostname.to_s
61
+ ret += ":#{uri.port}" if /:[0-9]/.match?(host)
62
+ ret
63
+ end
64
+ end
65
+
66
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module CryptograpiRuby
4
- VERSION = '0.0.1'
4
+ VERSION = '0.0.1.1'
5
5
  end
@@ -1,2 +1,18 @@
1
1
  # frozen_string_literal: true
2
- # TBC
2
+
3
+ module CryptograpiRuby
4
+ class << self
5
+ attr_accessor :api_token, :project_id
6
+ # attr_writer :locales_path
7
+
8
+ # Let's provide a straightforward way
9
+ # to provide options, like
10
+ # CryptograpiRuby.config do |c|
11
+ # c.api_token = '123'
12
+ # c.project_id = '345'
13
+ # end
14
+ def config
15
+ yield self
16
+ end
17
+ end
18
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cryptograpi_ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Cryptograpi
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-03 00:00:00.000000000 Z
11
+ date: 2021-09-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rubyzip
@@ -66,6 +66,118 @@ dependencies:
66
66
  - - "~>"
67
67
  - !ruby/object:Gem::Version
68
68
  version: '2.4'
69
+ - !ruby/object:Gem::Dependency
70
+ name: codecov
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.1'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.1'
83
+ - !ruby/object:Gem::Dependency
84
+ name: dotenv
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.5'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.5'
97
+ - !ruby/object:Gem::Dependency
98
+ name: rake
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '13.0'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '13.0'
111
+ - !ruby/object:Gem::Dependency
112
+ name: rspec
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '3.6'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '3.6'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.16'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.16'
139
+ - !ruby/object:Gem::Dependency
140
+ name: vcr
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - "~>"
144
+ - !ruby/object:Gem::Version
145
+ version: '6.0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - "~>"
151
+ - !ruby/object:Gem::Version
152
+ version: '6.0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: rails
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - "~>"
158
+ - !ruby/object:Gem::Version
159
+ version: '6.1'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - "~>"
165
+ - !ruby/object:Gem::Version
166
+ version: '6.1'
167
+ - !ruby/object:Gem::Dependency
168
+ name: rspec-rails
169
+ requirement: !ruby/object:Gem::Requirement
170
+ requirements:
171
+ - - "~>"
172
+ - !ruby/object:Gem::Version
173
+ version: '4.0'
174
+ type: :development
175
+ prerelease: false
176
+ version_requirements: !ruby/object:Gem::Requirement
177
+ requirements:
178
+ - - "~>"
179
+ - !ruby/object:Gem::Version
180
+ version: '4.0'
69
181
  - !ruby/object:Gem::Dependency
70
182
  name: activesupport
71
183
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +192,20 @@ dependencies:
80
192
  - - "~>"
81
193
  - !ruby/object:Gem::Version
82
194
  version: '6.1'
195
+ - !ruby/object:Gem::Dependency
196
+ name: configparser
197
+ requirement: !ruby/object:Gem::Requirement
198
+ requirements:
199
+ - - ">="
200
+ - !ruby/object:Gem::Version
201
+ version: '0.1'
202
+ type: :runtime
203
+ prerelease: false
204
+ version_requirements: !ruby/object:Gem::Requirement
205
+ requirements:
206
+ - - ">="
207
+ - !ruby/object:Gem::Version
208
+ version: '0.1'
83
209
  - !ruby/object:Gem::Dependency
84
210
  name: httparty
85
211
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +234,20 @@ dependencies:
108
234
  - - "~>"
109
235
  - !ruby/object:Gem::Version
110
236
  version: '0.5'
237
+ - !ruby/object:Gem::Dependency
238
+ name: tzinfo-data
239
+ requirement: !ruby/object:Gem::Requirement
240
+ requirements:
241
+ - - ">="
242
+ - !ruby/object:Gem::Version
243
+ version: '1'
244
+ type: :runtime
245
+ prerelease: false
246
+ version_requirements: !ruby/object:Gem::Requirement
247
+ requirements:
248
+ - - ">="
249
+ - !ruby/object:Gem::Version
250
+ version: '1'
111
251
  - !ruby/object:Gem::Dependency
112
252
  name: webrick
113
253
  requirement: !ruby/object:Gem::Requirement
@@ -137,6 +277,12 @@ files:
137
277
  - Rakefile
138
278
  - cryptograpi_ruby.gemspec
139
279
  - lib/cryptograpi_ruby.rb
280
+ - lib/cryptograpi_ruby/cipher.rb
281
+ - lib/cryptograpi_ruby/credentials.rb
282
+ - lib/cryptograpi_ruby/decrypt.rb
283
+ - lib/cryptograpi_ruby/encrypt.rb
284
+ - lib/cryptograpi_ruby/host.rb
285
+ - lib/cryptograpi_ruby/signature.rb
140
286
  - lib/cryptograpi_ruby/version.rb
141
287
  homepage: https://cryptograpi.com
142
288
  licenses:
@@ -157,7 +303,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
157
303
  - !ruby/object:Gem::Version
158
304
  version: '0'
159
305
  requirements: []
160
- rubygems_version: 3.2.25
306
+ rubygems_version: 3.2.26
161
307
  signing_key:
162
308
  specification_version: 4
163
309
  summary: Cryptograpi library for ruby apps