starkinfra 0.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.
@@ -0,0 +1,101 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('date')
4
+ require('starkbank-ecdsa')
5
+ require('starkbank')
6
+ require_relative('environment')
7
+
8
+ module StarkInfra
9
+ module Utils
10
+ class Checks
11
+ def self.check_user(user)
12
+ return user if user.is_a?(StarkBank::User)
13
+
14
+ user = user.nil? ? StarkInfra.user : user
15
+ raise(ArgumentError, 'A user is required to access our API. Check our README: https://github.com/starkinfra/sdk-ruby/') if user.nil?
16
+
17
+ user
18
+ end
19
+
20
+ def self.check_language
21
+ language = StarkInfra.language
22
+ accepted_languages = %w[en-US pt-BR]
23
+ raise(ArgumentError, "Select a valid language: #{accepted_languages.join(', ')}") unless accepted_languages.include?(language)
24
+
25
+ language
26
+ end
27
+
28
+ def self.check_environment(environment)
29
+ environments = StarkInfra::Utils::Environment.constants(false).map { |c| StarkInfra::Utils::Environment.const_get(c) }
30
+ raise(ArgumentError, "Select a valid environment: #{environments.join(', ')}") unless environments.include?(environment)
31
+
32
+ environment
33
+ end
34
+
35
+ def self.check_private_key(pem)
36
+ EllipticCurve::PrivateKey.fromPem(pem)
37
+ pem
38
+ rescue
39
+ raise(ArgumentError, 'Private-key must be a valid secp256k1 ECDSA string in pem format')
40
+ end
41
+
42
+ def self.check_date_or_datetime(data)
43
+ return if data.nil?
44
+
45
+ return data if data.is_a?(Time) || data.is_a?(DateTime)
46
+
47
+ return data if data.is_a?(Date)
48
+
49
+ data, type = check_datetime_string(data)
50
+ type == 'date' ? Date.new(data.year, data.month, data.day) : data
51
+ end
52
+
53
+ def self.check_datetime(data)
54
+ return if data.nil?
55
+
56
+ return data if data.is_a?(Time) || data.is_a?(DateTime)
57
+
58
+ return Time.new(data.year, data.month, data.day) if data.is_a?(Date)
59
+
60
+ data, _type = check_datetime_string(data)
61
+ data
62
+ end
63
+
64
+ def self.check_date(data)
65
+ return if data.nil?
66
+
67
+ return Date.new(data.year, data.month, data.day) if data.is_a?(Time) || data.is_a?(DateTime)
68
+
69
+ return data if data.is_a?(Date)
70
+
71
+ data, type = check_datetime_string(data)
72
+
73
+ type == 'date' ? Date.new(data.year, data.month, data.day) : data
74
+ end
75
+
76
+ class << self
77
+ private
78
+
79
+ def check_datetime_string(data)
80
+ data = data.to_s
81
+
82
+ begin
83
+ return [DateTime.strptime(data, '%Y-%m-%dT%H:%M:%S.%L+00:00'), 'datetime']
84
+ rescue ArgumentError
85
+ end
86
+
87
+ begin
88
+ return [DateTime.strptime(data, '%Y-%m-%dT%H:%M:%S+00:00'), 'datetime']
89
+ rescue ArgumentError
90
+ end
91
+
92
+ begin
93
+ return [DateTime.strptime(data, '%Y-%m-%d'), 'date']
94
+ rescue ArgumentError
95
+ raise(ArgumentError, 'invalid datetime string ' + data)
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module StarkInfra
4
+ module Utils
5
+ class Environment
6
+ PRODUCTION = 'production'
7
+ public_constant :PRODUCTION
8
+
9
+ SANDBOX = 'sandbox'
10
+ public_constant :SANDBOX
11
+
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('json')
4
+ require('starkbank-ecdsa')
5
+ require_relative('api')
6
+ require_relative('cache')
7
+ require_relative('request')
8
+ require_relative('../error')\
9
+
10
+
11
+ module StarkInfra
12
+ module Utils
13
+ module Parse
14
+ def self.parse_and_verify(content:, signature:, user: nil, resource:, key: nil)
15
+ event = StarkInfra::Utils::API.from_api_json(resource[:resource_maker], JSON.parse(content))
16
+ if key != nil
17
+ event = StarkInfra::Utils::API.from_api_json(resource[:resource_maker], JSON.parse(content)[key])
18
+ end
19
+
20
+ begin
21
+ signature = EllipticCurve::Signature.fromBase64(signature)
22
+ rescue
23
+ raise(StarkInfra::Error::InvalidSignatureError, 'The provided signature is not valid')
24
+ end
25
+
26
+ return event if verify_signature(content: content, signature: signature, user: user)
27
+
28
+ return event if verify_signature(content: content, signature: signature, user: user, refresh: true)
29
+
30
+ raise(StarkInfra::Error::InvalidSignatureError, 'The provided signature and content do not match the Stark Infra public key')
31
+ end
32
+
33
+ def self.verify_signature(content:, signature:, user:, refresh: false)
34
+ public_key = StarkInfra::Utils::Cache.starkinfra_public_key
35
+ if public_key.nil? || refresh
36
+ pem = get_public_key_pem(user)
37
+ public_key = EllipticCurve::PublicKey.fromPem(pem)
38
+ StarkInfra::Utils::Cache.starkinfra_public_key = public_key
39
+ end
40
+ EllipticCurve::Ecdsa.verify(content, signature, public_key)
41
+ end
42
+
43
+ def self.get_public_key_pem(user)
44
+ StarkInfra::Utils::Request.fetch(method: 'GET', path: 'public-key', query: { limit: 1 }, user: user).json['publicKeys'][0]['content']
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require('json')
4
+ require('starkbank-ecdsa')
5
+ require('net/http')
6
+ require_relative('url')
7
+ require_relative('checks')
8
+ require_relative('../error')
9
+
10
+ module StarkInfra
11
+ module Utils
12
+ module Request
13
+ class Response
14
+ attr_reader :status, :content
15
+ def initialize(status, content)
16
+ @status = status
17
+ @content = content
18
+ end
19
+
20
+ def json
21
+ JSON.parse(@content)
22
+ end
23
+ end
24
+
25
+ def self.fetch(method:, path:, payload: nil, query: nil, user: nil)
26
+ user = Checks.check_user(user)
27
+ language = Checks.check_language
28
+
29
+ base_url = {
30
+ Environment::PRODUCTION => 'https://api.starkinfra.com/',
31
+ Environment::SANDBOX => 'https://sandbox.api.starkinfra.com/',
32
+ }[user.environment] + 'v2'
33
+
34
+ url = "#{base_url}/#{path}#{StarkInfra::Utils::URL.urlencode(query)}"
35
+ uri = URI(url)
36
+
37
+ access_time = Time.now.to_i
38
+ body = payload.nil? ? '' : payload.to_json
39
+ message = "#{user.access_id}:#{access_time}:#{body}"
40
+ signature = EllipticCurve::Ecdsa.sign(message, user.private_key).toBase64
41
+
42
+ case method
43
+ when 'GET'
44
+ req = Net::HTTP::Get.new(uri)
45
+ when 'DELETE'
46
+ req = Net::HTTP::Delete.new(uri)
47
+ when 'POST'
48
+ req = Net::HTTP::Post.new(uri)
49
+ req.body = body
50
+ when 'PATCH'
51
+ req = Net::HTTP::Patch.new(uri)
52
+ req.body = body
53
+ when 'PUT'
54
+ req = Net::HTTP::Put.new(uri)
55
+ req.body = body
56
+ else
57
+ raise(ArgumentError, 'unknown HTTP method ' + method)
58
+ end
59
+
60
+ req['Access-Id'] = user.access_id
61
+ req['Access-Time'] = access_time
62
+ req['Access-Signature'] = signature
63
+ req['Content-Type'] = 'application/json'
64
+ req['User-Agent'] = "Ruby-#{RUBY_VERSION}-SDK-2.6.0"
65
+ req['Accept-Language'] = language
66
+
67
+ request = Net::HTTP.start(uri.hostname, use_ssl: true) { |http| http.request(req) }
68
+
69
+ response = Response.new(Integer(request.code, 10), request.body)
70
+
71
+ raise(StarkInfra::Error::InternalServerError) if response.status == 500
72
+ raise(StarkInfra::Error::InputErrors, response.json['errors']) if response.status == 400
73
+ raise(StarkInfra::Error::UnknownError, response.content) unless response.status == 200
74
+
75
+ response
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+ require_relative("sub_resource")
3
+
4
+ module StarkInfra
5
+ module Utils
6
+ class Resource < StarkInfra::Utils::SubResource
7
+ attr_reader :id
8
+ def initialize(id = nil)
9
+ @id = id
10
+ end
11
+ end
12
+ end
13
+ end
data/lib/utils/rest.rb ADDED
@@ -0,0 +1,136 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative('request')
4
+ require_relative('api')
5
+
6
+ module StarkInfra
7
+ module Utils
8
+ module Rest
9
+ def self.get_page(resource_name:, resource_maker:, user: nil, **query)
10
+ json = StarkInfra::Utils::Request.fetch(
11
+ method: 'GET',
12
+ path: StarkInfra::Utils::API.endpoint(resource_name),
13
+ query: query,
14
+ user: user
15
+ ).json
16
+ entities = []
17
+ json[StarkInfra::Utils::API.last_name_plural(resource_name)].each do |entity_json|
18
+ entities << StarkInfra::Utils::API.from_api_json(resource_maker, entity_json)
19
+ end
20
+ return entities, json['cursor']
21
+ end
22
+
23
+ def self.get_stream(resource_name:, resource_maker:, user: nil, **query)
24
+ limit = query[:limit]
25
+ query[:limit] = limit.nil? ? limit : [limit, 100].min
26
+
27
+ Enumerator.new do |enum|
28
+ loop do
29
+ json = StarkInfra::Utils::Request.fetch(
30
+ method: 'GET',
31
+ path: StarkInfra::Utils::API.endpoint(resource_name),
32
+ query: query,
33
+ user: user
34
+ ).json
35
+ entities = json[StarkInfra::Utils::API.last_name_plural(resource_name)]
36
+
37
+ entities.each do |entity|
38
+ enum << StarkInfra::Utils::API.from_api_json(resource_maker, entity)
39
+ end
40
+
41
+ unless limit.nil?
42
+ limit -= 100
43
+ query[:limit] = [limit, 100].min
44
+ end
45
+
46
+ cursor = json['cursor']
47
+ query['cursor'] = cursor
48
+ break if cursor.nil? || cursor.empty? || (!limit.nil? && limit <= 0)
49
+ end
50
+ end
51
+ end
52
+
53
+ def self.get_id(resource_name:, resource_maker:, id:, user: nil)
54
+ json = StarkInfra::Utils::Request.fetch(
55
+ method: 'GET',
56
+ path: "#{StarkInfra::Utils::API.endpoint(resource_name)}/#{id}",
57
+ user: user
58
+ ).json
59
+ entity = json[StarkInfra::Utils::API.last_name(resource_name)]
60
+ StarkInfra::Utils::API.from_api_json(resource_maker, entity)
61
+ end
62
+
63
+ def self.get_content(resource_name:, resource_maker:, sub_resource_name:, id:, user: nil, **query)
64
+ StarkInfra::Utils::Request.fetch(
65
+ method: 'GET',
66
+ path: "#{StarkInfra::Utils::API.endpoint(resource_name)}/#{id}/#{sub_resource_name}",
67
+ query: StarkInfra::Utils::API.cast_json_to_api_format(query),
68
+ user: user
69
+ ).content
70
+ end
71
+
72
+ def self.post(resource_name:, resource_maker:, entities:, user: nil)
73
+ jsons = []
74
+ entities.each do |entity|
75
+ jsons << StarkInfra::Utils::API.api_json(entity)
76
+ end
77
+ payload = { StarkInfra::Utils::API.last_name_plural(resource_name) => jsons }
78
+ json = StarkInfra::Utils::Request.fetch(
79
+ method: 'POST',
80
+ path: StarkInfra::Utils::API.endpoint(resource_name),
81
+ payload: payload,
82
+ user: user
83
+ ).json
84
+ returned_jsons = json[StarkInfra::Utils::API.last_name_plural(resource_name)]
85
+ entities = []
86
+ returned_jsons.each do |returned_json|
87
+ entities << StarkInfra::Utils::API.from_api_json(resource_maker, returned_json)
88
+ end
89
+ entities
90
+ end
91
+
92
+ def self.post_single(resource_name:, resource_maker:, entity:, user: nil)
93
+ json = StarkInfra::Utils::Request.fetch(
94
+ method: 'POST',
95
+ path: StarkInfra::Utils::API.endpoint(resource_name),
96
+ payload: StarkInfra::Utils::API.api_json(entity),
97
+ user: user
98
+ ).json
99
+ entity_json = json[StarkInfra::Utils::API.last_name(resource_name)]
100
+ StarkInfra::Utils::API.from_api_json(resource_maker, entity_json)
101
+ end
102
+
103
+ def self.delete_id(resource_name:, resource_maker:, id:, user: nil)
104
+ json = StarkInfra::Utils::Request.fetch(
105
+ method: 'DELETE',
106
+ path: "#{StarkInfra::Utils::API.endpoint(resource_name)}/#{id}",
107
+ user: user
108
+ ).json
109
+ entity = json[StarkInfra::Utils::API.last_name(resource_name)]
110
+ StarkInfra::Utils::API.from_api_json(resource_maker, entity)
111
+ end
112
+
113
+ def self.patch_id(resource_name:, resource_maker:, id:, user: nil, **payload)
114
+ json = StarkInfra::Utils::Request.fetch(
115
+ method: 'PATCH',
116
+ path: "#{StarkInfra::Utils::API.endpoint(resource_name)}/#{id}",
117
+ user: user,
118
+ payload: StarkInfra::Utils::API.cast_json_to_api_format(payload)
119
+ ).json
120
+ entity = json[StarkInfra::Utils::API.last_name(resource_name)]
121
+ StarkInfra::Utils::API.from_api_json(resource_maker, entity)
122
+ end
123
+
124
+ def self.get_sub_resource(resource_name:, sub_resource_maker:, sub_resource_name:, id:, user: nil, **query)
125
+ json = StarkInfra::Utils::Request.fetch(
126
+ method: 'GET',
127
+ path: "#{StarkInfra::Utils::API.endpoint(resource_name)}/#{id}/#{StarkInfra::Utils::API.endpoint(sub_resource_name)}",
128
+ user: user,
129
+ query: StarkInfra::Utils::API.cast_json_to_api_format(query)
130
+ ).json
131
+ entity = json[StarkInfra::Utils::API.last_name(sub_resource_name)]
132
+ StarkInfra::Utils::API.from_api_json(sub_resource_maker, entity)
133
+ end
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,28 @@
1
+
2
+
3
+ module StarkInfra
4
+ module Utils
5
+ class SubResource
6
+ def to_s
7
+ string_vars = []
8
+ instance_variables.each do |key|
9
+ value = instance_variable_get(key).to_s.lines.map(&:chomp).join("\n ")
10
+ string_vars << "#{key[1..-1]}: #{value}"
11
+ end
12
+ fields = string_vars.join(",\n ")
13
+ "#{class_name}(\n #{fields}\n)"
14
+ end
15
+
16
+ def inspect
17
+ "#{class_name}[#{@id}]"
18
+ end
19
+
20
+ private
21
+
22
+ def class_name
23
+ self.class.name.split('::').last.downcase
24
+ end
25
+ end
26
+ end
27
+ end
28
+
data/lib/utils/url.rb ADDED
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+ require 'erb'
3
+
4
+
5
+ module StarkInfra
6
+ module Utils
7
+ module URL
8
+ # generates query string from hash
9
+ def self.urlencode(params)
10
+ return '' if params.nil?
11
+
12
+ params = StarkInfra::Utils::API.cast_json_to_api_format(params)
13
+ return '' if params.empty?
14
+
15
+ string_params = {}
16
+ params.each do |key, value|
17
+ string_params[key] = value.is_a?(Array) ? value.join(',') : value
18
+ end
19
+
20
+ query_list = []
21
+ string_params.each do |key, value|
22
+ query_list << "#{key}=#{ERB::Util.url_encode(value)}"
23
+ end
24
+ '?' + query_list.join('&')
25
+ end
26
+ end
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,133 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: starkinfra
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - starkinfra
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-02-24 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: starkbank
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 2.6.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 2.6.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: starkbank-ecdsa
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.0.5
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.0.5
41
+ - !ruby/object:Gem::Dependency
42
+ name: minitest
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: 5.14.1
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: 5.14.1
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '13.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '13.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.81'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.81'
83
+ description:
84
+ email:
85
+ executables: []
86
+ extensions: []
87
+ extra_rdoc_files: []
88
+ files:
89
+ - lib/error.rb
90
+ - lib/event/event.rb
91
+ - lib/key.rb
92
+ - lib/pixbalance/pixbalance.rb
93
+ - lib/pixrequest/log.rb
94
+ - lib/pixrequest/pixrequest.rb
95
+ - lib/pixreversal/log.rb
96
+ - lib/pixreversal/pixreversal.rb
97
+ - lib/pixstatement/pixstatement.rb
98
+ - lib/starkinfra.rb
99
+ - lib/utils/api.rb
100
+ - lib/utils/cache.rb
101
+ - lib/utils/case.rb
102
+ - lib/utils/checks.rb
103
+ - lib/utils/environment.rb
104
+ - lib/utils/parse.rb
105
+ - lib/utils/request.rb
106
+ - lib/utils/resource.rb
107
+ - lib/utils/rest.rb
108
+ - lib/utils/sub_resource.rb
109
+ - lib/utils/url.rb
110
+ homepage: https://github.com/starkinfra/sdk-ruby
111
+ licenses:
112
+ - MIT
113
+ metadata: {}
114
+ post_install_message:
115
+ rdoc_options: []
116
+ require_paths:
117
+ - lib
118
+ required_ruby_version: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - ">="
121
+ - !ruby/object:Gem::Version
122
+ version: '2.3'
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ requirements:
125
+ - - ">="
126
+ - !ruby/object:Gem::Version
127
+ version: '0'
128
+ requirements: []
129
+ rubygems_version: 3.1.4
130
+ signing_key:
131
+ specification_version: 4
132
+ summary: SDK to facilitate Ruby integrations with Stark Infra
133
+ test_files: []