starkinfra 0.0.1

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