monerorequest 0.2.0 → 1.0.0
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 +4 -4
- data/Gemfile +5 -0
- data/Gemfile.lock +11 -1
- data/README.md +12 -8
- data/lib/monerorequest/cron.rb +6 -4
- data/lib/monerorequest/decoder.rb +31 -9
- data/lib/monerorequest/encoder.rb +22 -89
- data/lib/monerorequest/pipeline/base64_decoder.rb +14 -0
- data/lib/monerorequest/pipeline/base64_encoder.rb +14 -0
- data/lib/monerorequest/pipeline/gzip_reader.rb +15 -0
- data/lib/monerorequest/pipeline/gzip_writer.rb +20 -0
- data/lib/monerorequest/pipeline/json_encoder.rb +16 -0
- data/lib/monerorequest/pipeline/json_parser.rb +14 -0
- data/lib/monerorequest/v1.rb +49 -0
- data/lib/monerorequest/v2.rb +49 -0
- data/lib/monerorequest/validator/amount.rb +16 -0
- data/lib/monerorequest/validator/change_indicator_url.rb +24 -0
- data/lib/monerorequest/validator/currency.rb +15 -0
- data/lib/monerorequest/validator/custom_label.rb +15 -0
- data/lib/monerorequest/validator/days_per_billing_cycle.rb +16 -0
- data/lib/monerorequest/validator/number_of_payments.rb +16 -0
- data/lib/monerorequest/validator/payment_id.rb +15 -0
- data/lib/monerorequest/validator/schedule.rb +15 -0
- data/lib/monerorequest/validator/sellers_wallet.rb +17 -0
- data/lib/monerorequest/validator/start_date.rb +22 -0
- data/lib/monerorequest/version.rb +1 -1
- data/lib/monerorequest.rb +18 -10
- metadata +20 -3
- data/sig/monerorequest.rbs +0 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 944c04e247c34be236e6071a5b8f384d11f12a21598b487068f8086ef9fdd7cb
|
|
4
|
+
data.tar.gz: e681abc0a5490f7fa86811a735d53f091b4ab8effd906cfa00b0737db11ba9c5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: de8f025de01a42d3a6a4cb701e40122e6c115eee4683331da0789e5886f27ce82d99e5fd81811443b5a00c5f62c811ea3d2540bd1036579404fbe869301a5b04
|
|
7
|
+
data.tar.gz: c81846b18ec909a1c7b84130a17c1b6a7d7b88d884da06aa6634ee915842b4e14d6eaaf862361fa53af48d5f22b21cf56639b07fd2800d67390e1667711602ff
|
data/Gemfile
CHANGED
|
@@ -6,6 +6,7 @@ source "https://rubygems.org"
|
|
|
6
6
|
gemspec
|
|
7
7
|
|
|
8
8
|
group :development, :test do
|
|
9
|
+
gem "byebug", "~> 11.1"
|
|
9
10
|
gem "faker", "~> 3.3"
|
|
10
11
|
gem "rake", "~> 13.0"
|
|
11
12
|
gem "rspec", "~> 3.0"
|
|
@@ -13,3 +14,7 @@ group :development, :test do
|
|
|
13
14
|
gem "rubocop-rake", "~> 0.6"
|
|
14
15
|
gem "rubocop-rspec", "~> 2.29"
|
|
15
16
|
end
|
|
17
|
+
|
|
18
|
+
group :test do
|
|
19
|
+
gem "simplecov", "~> 0.22", require: false
|
|
20
|
+
end
|
data/Gemfile.lock
CHANGED
|
@@ -1,14 +1,16 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
monerorequest (0.
|
|
4
|
+
monerorequest (1.0.0)
|
|
5
5
|
|
|
6
6
|
GEM
|
|
7
7
|
remote: https://rubygems.org/
|
|
8
8
|
specs:
|
|
9
9
|
ast (2.4.2)
|
|
10
|
+
byebug (11.1.3)
|
|
10
11
|
concurrent-ruby (1.2.3)
|
|
11
12
|
diff-lcs (1.5.1)
|
|
13
|
+
docile (1.4.1)
|
|
12
14
|
faker (3.3.1)
|
|
13
15
|
i18n (>= 1.8.11, < 2)
|
|
14
16
|
i18n (1.14.5)
|
|
@@ -64,12 +66,19 @@ GEM
|
|
|
64
66
|
rubocop-rspec_rails (2.28.3)
|
|
65
67
|
rubocop (~> 1.40)
|
|
66
68
|
ruby-progressbar (1.13.0)
|
|
69
|
+
simplecov (0.22.0)
|
|
70
|
+
docile (~> 1.1)
|
|
71
|
+
simplecov-html (~> 0.11)
|
|
72
|
+
simplecov_json_formatter (~> 0.1)
|
|
73
|
+
simplecov-html (0.13.1)
|
|
74
|
+
simplecov_json_formatter (0.1.4)
|
|
67
75
|
unicode-display_width (2.5.0)
|
|
68
76
|
|
|
69
77
|
PLATFORMS
|
|
70
78
|
x86_64-linux
|
|
71
79
|
|
|
72
80
|
DEPENDENCIES
|
|
81
|
+
byebug (~> 11.1)
|
|
73
82
|
faker (~> 3.3)
|
|
74
83
|
monerorequest!
|
|
75
84
|
rake (~> 13.0)
|
|
@@ -77,6 +86,7 @@ DEPENDENCIES
|
|
|
77
86
|
rubocop (~> 1.21)
|
|
78
87
|
rubocop-rake (~> 0.6)
|
|
79
88
|
rubocop-rspec (~> 2.29)
|
|
89
|
+
simplecov (~> 0.22)
|
|
80
90
|
|
|
81
91
|
BUNDLED WITH
|
|
82
92
|
2.4.10
|
data/README.md
CHANGED
|
@@ -31,18 +31,14 @@ req = {
|
|
|
31
31
|
"number_of_payments" => 12,
|
|
32
32
|
"change_indicator_url" => "[some url here]"
|
|
33
33
|
}
|
|
34
|
-
enc = Monerorequest::Encoder.new(req)
|
|
35
|
-
enc.encode(1)
|
|
34
|
+
enc = Monerorequest::Encoder.new(req, 1)
|
|
36
35
|
```
|
|
37
36
|
|
|
38
37
|
Decode a request:
|
|
39
38
|
```ruby
|
|
40
39
|
require 'monerorequest'
|
|
41
40
|
|
|
42
|
-
req = "monero-request:1:H4sIAAAAAAACAy2QS4vUQBSF/0qondA9XanqJJ3sZjEozGYW4kooKpWbTjmVqnQ9pjuKID7HlStxZiEo4pMBQRAcFPwvCq5c2O0fMD24utxzOR/n3FuItyZoj4o0iWm+
|
|
43
|
-
WrEIFarzvisnEGlOOG5AVaAtSNDuw4m2nYCJsuIkGd7AWtOgHx8GVgwvBedMyxUvYYtafHrz49fT13+8nb+rNnS/nm7ff3v04vb+/fvj8w/WAcQw/3z++dDnai67tbp4cP4ouRP7787M/Z69eJtF+tNycnd/bW9/9+NUN+Ir3jnVgWSmVknrORC8
|
|
44
|
-
UoCKnI6RDWw4XU7OO9y1o71BB8hH6vzFZDYFIlRFe1yTPeVblpB6YDpQC69iSD3P4DZruUtybtGxXcqZS08yrlMeYmMNF1lF+o1FULvzMxwL3C3DikAM/8jSmSpbG9NbWqll1mQtJ6jgJJqFHIe+obDQsLU22NZzn1rOKe9hGwmQ6xskYp1fjWTE
|
|
45
|
-
lBaFjnBUYo9v/ANjVPGWxAQAA"
|
|
41
|
+
req = "monero-request:1:H4sIAAAAAAACAy2QS4vUQBSF/0qondA9XanqJJ3sZjEozGYW4kooKpWbTjmVqnQ9pjuKID7HlStxZiEo4pMBQRAcFPwvCq5c2O0fMD24utxzOR/n3FuItyZoj4o0iWm+k8YjJBqu58CkrqTg3lgWrEIFarzvisnEGlOOG5AVaAtSNDuw4m2nYCJsuIkGd7AWtOgHx8GVgwvBedMyxUvYYtafHrz49fT13+8nb+rNnS/nm7ff3v04vb+/fvj8w/WAcQw/3z++dDnai67tbp4cP4ouRP7787M/Z69eJtF+tNycnd/bW9/9+NUN+Ir3jnVgWSmVknrORC8UoCKnI6RDWw4XU7OO9y1o71BB8hH6vzFZDYFIlRFe1yTPeVblpB6YDpQC69iSD3P4DZruUtybtGxXcqZS08yrlMeYmMNF1lF+o1FULvzMxwL3C3DikAM/8jSmSpbG9NbWqll1mQtJ6jgJJqFHIe+obDQsLU22NZzn1rOKe9hGwmQ6xskYp1fjWTElBaFjnBUYo9v/ANjVPGWxAQAA"
|
|
46
42
|
dec = Monerorequest::Decoder.new(req)
|
|
47
43
|
dec.decode
|
|
48
44
|
```
|
|
@@ -63,8 +59,7 @@ req = {
|
|
|
63
59
|
"number_of_payments" => 12,
|
|
64
60
|
"change_indicator_url" => "[some url here]"
|
|
65
61
|
}
|
|
66
|
-
enc = Monerorequest::Encoder.new(req)
|
|
67
|
-
enc.encode(2)
|
|
62
|
+
enc = Monerorequest::Encoder.new(req, 2)
|
|
68
63
|
```
|
|
69
64
|
|
|
70
65
|
Decode a request:
|
|
@@ -82,6 +77,15 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
|
82
77
|
|
|
83
78
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
|
84
79
|
|
|
80
|
+
## Adding a new Monerorequest version
|
|
81
|
+
|
|
82
|
+
Adding a new Monerorequest version should be simple.
|
|
83
|
+
|
|
84
|
+
1. Update SUPPORTED_MR_VERSIONS in ```lib/monerorequest.rb```.
|
|
85
|
+
2. Add any necessary pipelines and validators in their respective folders.
|
|
86
|
+
3. Define a file named "vX.rb" where X is your version that pulls in the pipelines and validators it needs.
|
|
87
|
+
4. Make sure you add spec coverage for any new code you write and run ```bundle exec rubocop``` to ensure it passes the linter.
|
|
88
|
+
|
|
85
89
|
## Contributing
|
|
86
90
|
|
|
87
91
|
Bug reports and pull requests are welcome on GitHub at https://github.com/snex/monerorequest.
|
data/lib/monerorequest/cron.rb
CHANGED
|
@@ -16,19 +16,21 @@ module Monerorequest
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def self.valid_minutes?(minutes)
|
|
19
|
-
minutes.all? { |min| ("0".."59").member?(min) } || minutes == ["*"]
|
|
19
|
+
minutes.all? { |min| ("0".."59").member?(min.to_s) } || minutes == ["*"]
|
|
20
20
|
end
|
|
21
21
|
|
|
22
22
|
def self.valid_hours?(hours)
|
|
23
|
-
hours.all? { |hr| ("0".."23").member?(hr) } || hours == ["*"]
|
|
23
|
+
hours.all? { |hr| ("0".."23").member?(hr.to_s) } || hours == ["*"]
|
|
24
24
|
end
|
|
25
25
|
|
|
26
26
|
def self.valid_days?(days)
|
|
27
|
-
days.all? { |dy| (1..31).member?(dy.
|
|
27
|
+
days.all? { |dy| ("1".."31").member?(dy.to_s) } || days == ["*"]
|
|
28
28
|
end
|
|
29
29
|
|
|
30
30
|
def self.valid_months?(months)
|
|
31
|
-
months.all?
|
|
31
|
+
months.all? do |mth|
|
|
32
|
+
("1".."12").member?(mth.to_s) || MONTH_CODES.include?(mth.to_s.downcase)
|
|
33
|
+
end || months == ["*"] || months == ["L"]
|
|
32
34
|
end
|
|
33
35
|
|
|
34
36
|
def self.valid_dow?(dow)
|
|
@@ -1,21 +1,43 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
Monerorequest::SUPPORTED_MR_VERSIONS.each do |mr_v|
|
|
4
|
+
require_relative "v#{mr_v}"
|
|
5
|
+
end
|
|
6
|
+
|
|
3
7
|
module Monerorequest
|
|
4
|
-
# class to
|
|
8
|
+
# class to choose a proper Decoder Version and then pass the encoded data to it for decoding
|
|
5
9
|
class Decoder
|
|
10
|
+
attr_reader :errors
|
|
11
|
+
|
|
6
12
|
def initialize(request)
|
|
7
13
|
@request = request
|
|
14
|
+
_, @version, @encoded_str = @request.split(":")
|
|
15
|
+
raise RequestVersionError, @version unless Monerorequest::SUPPORTED_MR_VERSIONS.include?(@version.to_i)
|
|
16
|
+
|
|
17
|
+
@decoder = Object.const_get("Monerorequest::V#{@version}")
|
|
8
18
|
end
|
|
9
19
|
|
|
10
20
|
def decode
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
21
|
+
@data = @encoded_str
|
|
22
|
+
|
|
23
|
+
@decoder::Decoder::PIPELINES.each do |pipeline|
|
|
24
|
+
@data = pipeline.call(@data)
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
@data["version"] = @version.to_i
|
|
28
|
+
validate!
|
|
29
|
+
@data
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
private
|
|
33
|
+
|
|
34
|
+
def validate!
|
|
35
|
+
@errors = []
|
|
36
|
+
@decoder::VALIDATORS.each do |validator|
|
|
37
|
+
@errors += validator.validate!(@data)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
raise InvalidRequestError, "Invalid request: #{@errors}" unless @errors.empty?
|
|
19
41
|
end
|
|
20
42
|
end
|
|
21
43
|
end
|
|
@@ -1,113 +1,46 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
require "stringio"
|
|
7
|
-
require "uri"
|
|
8
|
-
require "zlib"
|
|
3
|
+
Monerorequest::SUPPORTED_MR_VERSIONS.each do |mr_v|
|
|
4
|
+
require_relative "v#{mr_v}"
|
|
5
|
+
end
|
|
9
6
|
|
|
10
7
|
module Monerorequest
|
|
11
8
|
# class to Encode a Monerorequest hash
|
|
12
9
|
class Encoder
|
|
13
|
-
class InvalidRequest < StandardError; end
|
|
14
|
-
|
|
15
|
-
attr_accessor :request
|
|
16
10
|
attr_reader :errors
|
|
17
11
|
|
|
18
|
-
def initialize(request)
|
|
19
|
-
|
|
20
|
-
@errors = []
|
|
12
|
+
def initialize(request, version)
|
|
13
|
+
raise RequestVersionError, version unless Monerorequest::SUPPORTED_MR_VERSIONS.include?(version.to_i)
|
|
21
14
|
|
|
15
|
+
@request = request
|
|
16
|
+
@version = version.to_i
|
|
17
|
+
set_encoder_version
|
|
22
18
|
validate!
|
|
23
19
|
end
|
|
24
20
|
|
|
25
|
-
def encode
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
json_str = @request.sort.to_h.to_json.force_encoding("ascii")
|
|
29
|
-
compressed_data = StringIO.new
|
|
30
|
-
gz = Zlib::GzipWriter.new(compressed_data, 9)
|
|
31
|
-
gz.mtime = 0
|
|
32
|
-
gz.write(json_str)
|
|
33
|
-
gz.close
|
|
34
|
-
encoded_str = Base64.encode64(compressed_data.string).gsub("\n", "")
|
|
35
|
-
"monero-request:#{version}:#{encoded_str}"
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
private
|
|
39
|
-
|
|
40
|
-
def validate!
|
|
41
|
-
validate_custom_label!
|
|
42
|
-
validate_sellers_wallet!
|
|
43
|
-
validate_currency!
|
|
44
|
-
validate_amount!
|
|
45
|
-
validate_payment_id!
|
|
46
|
-
validate_start_date!
|
|
47
|
-
validate_days_per_billing_cycle! if @request["version"] == 1
|
|
48
|
-
validate_schedule! if @request["version"] == 2
|
|
49
|
-
validate_change_indicator_url!
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
def validate_custom_label!
|
|
53
|
-
@errors.push("custom_label must be present.") unless @request.key?("custom_label")
|
|
54
|
-
@errors.push("custom_label must be a String.") unless @request["custom_label"].is_a?(String)
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
def validate_sellers_wallet!
|
|
58
|
-
@errors.push("sellers_wallet must be present.") unless @request.key?("sellers_wallet")
|
|
59
|
-
return if MoneroAddress.valid?(@request["sellers_wallet"])
|
|
21
|
+
def encode
|
|
22
|
+
data = @request
|
|
60
23
|
|
|
61
|
-
@
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
def validate_currency!
|
|
65
|
-
@errors.push("currency must be present.") unless @request.key?("currency")
|
|
66
|
-
@errors.push("currency must be a String.") unless @request["currency"].is_a?(String)
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def validate_amount!
|
|
70
|
-
@errors.push("amount must be present.") unless @request.key?("amount")
|
|
71
|
-
@errors.push("amount must be a Numeric.") unless @request["amount"].is_a?(Numeric)
|
|
72
|
-
end
|
|
24
|
+
@encoder::Encoder::PIPELINES.each do |pipeline|
|
|
25
|
+
data = pipeline.call(data)
|
|
26
|
+
end
|
|
73
27
|
|
|
74
|
-
|
|
75
|
-
@errors.push("payment_id must be present.") unless @request.key?("payment_id")
|
|
76
|
-
@errors.push("payment_id must be a Monero Payment ID.") unless MoneroPaymentID.valid?(@request["payment_id"])
|
|
28
|
+
"monero-request:#{@version}:#{data}"
|
|
77
29
|
end
|
|
78
30
|
|
|
79
|
-
|
|
80
|
-
@errors.push("start_date must be present.") unless @request.key?("start_date")
|
|
81
|
-
unless @request["start_date"].is_a?(String)
|
|
82
|
-
@errors.push("start_date must be a String.") && @request["start_date"] = ""
|
|
83
|
-
end
|
|
84
|
-
begin
|
|
85
|
-
DateTime.rfc3339(@request["start_date"])
|
|
86
|
-
rescue Date::Error
|
|
87
|
-
@errors.push("start_date must be an RFC3339 timestamp.")
|
|
88
|
-
end
|
|
89
|
-
end
|
|
31
|
+
private
|
|
90
32
|
|
|
91
|
-
def
|
|
92
|
-
|
|
93
|
-
@errors.push("days_per_billing_cycle must be present.")
|
|
94
|
-
end
|
|
95
|
-
@errors.push("days_per_billing_cycle must be a Integer.") unless @request["days_per_billing_cycle"].is_a?(Integer)
|
|
33
|
+
def set_encoder_version
|
|
34
|
+
@encoder = Object.const_get("Monerorequest::V#{@version}")
|
|
96
35
|
end
|
|
97
36
|
|
|
98
|
-
def
|
|
99
|
-
@errors
|
|
100
|
-
|
|
101
|
-
@errors
|
|
37
|
+
def validate!
|
|
38
|
+
@errors = []
|
|
39
|
+
@encoder::VALIDATORS.each do |validator|
|
|
40
|
+
@errors += validator.validate!(@request)
|
|
102
41
|
end
|
|
103
|
-
return if @request["change_indicator_url"] =~ URI::DEFAULT_PARSER.make_regexp
|
|
104
|
-
|
|
105
|
-
@errors.push("change_indicator_url must be a URL.")
|
|
106
|
-
end
|
|
107
42
|
|
|
108
|
-
|
|
109
|
-
@errors.push("schedule must be present.") unless @request.key?("schedule")
|
|
110
|
-
@errors.push("schedule must be a valid Cron.") unless Cron.valid?(@request.fetch("schedule", ""))
|
|
43
|
+
raise InvalidRequestError, "Invalid request: #{@errors}" unless @errors.empty?
|
|
111
44
|
end
|
|
112
45
|
end
|
|
113
46
|
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "base64"
|
|
4
|
+
|
|
5
|
+
module Monerorequest
|
|
6
|
+
module Pipeline
|
|
7
|
+
# pipeline that takes a base64 encoded string and decodes it
|
|
8
|
+
class Base64Decoder
|
|
9
|
+
def self.call(input)
|
|
10
|
+
Base64.strict_decode64(input)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "base64"
|
|
4
|
+
|
|
5
|
+
module Monerorequest
|
|
6
|
+
module Pipeline
|
|
7
|
+
# pipeline that takes a string and base64 encodes it
|
|
8
|
+
class Base64Encoder
|
|
9
|
+
def self.call(input)
|
|
10
|
+
Base64.strict_encode64(input)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "stringio"
|
|
4
|
+
require "zlib"
|
|
5
|
+
|
|
6
|
+
module Monerorequest
|
|
7
|
+
module Pipeline
|
|
8
|
+
# pipeline that takes a gzip blob and unzips it
|
|
9
|
+
class GzipReader
|
|
10
|
+
def self.call(input)
|
|
11
|
+
Zlib::GzipReader.new(StringIO.new(input)).read
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "stringio"
|
|
4
|
+
require "zlib"
|
|
5
|
+
|
|
6
|
+
module Monerorequest
|
|
7
|
+
module Pipeline
|
|
8
|
+
# pipeline that takes a string and gzips it
|
|
9
|
+
class GzipWriter
|
|
10
|
+
def self.call(input)
|
|
11
|
+
output = StringIO.new
|
|
12
|
+
gz = Zlib::GzipWriter.new(output, 9)
|
|
13
|
+
gz.mtime = 0
|
|
14
|
+
gz.write(input)
|
|
15
|
+
gz.close
|
|
16
|
+
output.string
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Monerorequest
|
|
6
|
+
module Pipeline
|
|
7
|
+
# pipeline that takes a hash, sorts by keys, then converts to valid JSON in ASCII encoding
|
|
8
|
+
class JSONEncoder
|
|
9
|
+
def self.call(input)
|
|
10
|
+
raise InvalidRequestError, "Request must be a Hash." unless input.is_a?(Hash)
|
|
11
|
+
|
|
12
|
+
input.sort.to_h.to_json.force_encoding("ascii")
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
|
|
5
|
+
module Monerorequest
|
|
6
|
+
module Pipeline
|
|
7
|
+
# pipeline that takes a JSON string and converts it into a ruby object
|
|
8
|
+
class JSONParser
|
|
9
|
+
def self.call(input)
|
|
10
|
+
JSON.parse(input)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "pipeline/base64_decoder"
|
|
4
|
+
require_relative "pipeline/base64_encoder"
|
|
5
|
+
require_relative "pipeline/gzip_reader"
|
|
6
|
+
require_relative "pipeline/gzip_writer"
|
|
7
|
+
require_relative "pipeline/json_parser"
|
|
8
|
+
require_relative "pipeline/json_encoder"
|
|
9
|
+
require_relative "validator/custom_label"
|
|
10
|
+
require_relative "validator/sellers_wallet"
|
|
11
|
+
require_relative "validator/currency"
|
|
12
|
+
require_relative "validator/amount"
|
|
13
|
+
require_relative "validator/payment_id"
|
|
14
|
+
require_relative "validator/start_date"
|
|
15
|
+
require_relative "validator/days_per_billing_cycle"
|
|
16
|
+
require_relative "validator/number_of_payments"
|
|
17
|
+
require_relative "validator/change_indicator_url"
|
|
18
|
+
|
|
19
|
+
module Monerorequest
|
|
20
|
+
module V1
|
|
21
|
+
VALIDATORS = [
|
|
22
|
+
Monerorequest::Validator::CustomLabel,
|
|
23
|
+
Monerorequest::Validator::SellersWallet,
|
|
24
|
+
Monerorequest::Validator::Currency,
|
|
25
|
+
Monerorequest::Validator::Amount,
|
|
26
|
+
Monerorequest::Validator::PaymentID,
|
|
27
|
+
Monerorequest::Validator::StartDate,
|
|
28
|
+
Monerorequest::Validator::DaysPerBillingCycle,
|
|
29
|
+
Monerorequest::Validator::NumberOfPayments,
|
|
30
|
+
Monerorequest::Validator::ChangeIndicatorURL
|
|
31
|
+
].freeze
|
|
32
|
+
|
|
33
|
+
module Encoder
|
|
34
|
+
PIPELINES = [
|
|
35
|
+
Monerorequest::Pipeline::JSONEncoder,
|
|
36
|
+
Monerorequest::Pipeline::GzipWriter,
|
|
37
|
+
Monerorequest::Pipeline::Base64Encoder
|
|
38
|
+
].freeze
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
module Decoder
|
|
42
|
+
PIPELINES = [
|
|
43
|
+
Monerorequest::Pipeline::Base64Decoder,
|
|
44
|
+
Monerorequest::Pipeline::GzipReader,
|
|
45
|
+
Monerorequest::Pipeline::JSONParser
|
|
46
|
+
].freeze
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "pipeline/base64_decoder"
|
|
4
|
+
require_relative "pipeline/base64_encoder"
|
|
5
|
+
require_relative "pipeline/gzip_reader"
|
|
6
|
+
require_relative "pipeline/gzip_writer"
|
|
7
|
+
require_relative "pipeline/json_parser"
|
|
8
|
+
require_relative "pipeline/json_encoder"
|
|
9
|
+
require_relative "validator/custom_label"
|
|
10
|
+
require_relative "validator/sellers_wallet"
|
|
11
|
+
require_relative "validator/currency"
|
|
12
|
+
require_relative "validator/amount"
|
|
13
|
+
require_relative "validator/payment_id"
|
|
14
|
+
require_relative "validator/start_date"
|
|
15
|
+
require_relative "validator/schedule"
|
|
16
|
+
require_relative "validator/number_of_payments"
|
|
17
|
+
require_relative "validator/change_indicator_url"
|
|
18
|
+
|
|
19
|
+
module Monerorequest
|
|
20
|
+
module V2
|
|
21
|
+
VALIDATORS = [
|
|
22
|
+
Monerorequest::Validator::CustomLabel,
|
|
23
|
+
Monerorequest::Validator::SellersWallet,
|
|
24
|
+
Monerorequest::Validator::Currency,
|
|
25
|
+
Monerorequest::Validator::Amount,
|
|
26
|
+
Monerorequest::Validator::PaymentID,
|
|
27
|
+
Monerorequest::Validator::StartDate,
|
|
28
|
+
Monerorequest::Validator::Schedule,
|
|
29
|
+
Monerorequest::Validator::NumberOfPayments,
|
|
30
|
+
Monerorequest::Validator::ChangeIndicatorURL
|
|
31
|
+
].freeze
|
|
32
|
+
|
|
33
|
+
module Encoder
|
|
34
|
+
PIPELINES = [
|
|
35
|
+
Monerorequest::Pipeline::JSONEncoder,
|
|
36
|
+
Monerorequest::Pipeline::GzipWriter,
|
|
37
|
+
Monerorequest::Pipeline::Base64Encoder
|
|
38
|
+
].freeze
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
module Decoder
|
|
42
|
+
PIPELINES = [
|
|
43
|
+
Monerorequest::Pipeline::Base64Decoder,
|
|
44
|
+
Monerorequest::Pipeline::GzipReader,
|
|
45
|
+
Monerorequest::Pipeline::JSONParser
|
|
46
|
+
].freeze
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Monerorequest
|
|
4
|
+
module Validator
|
|
5
|
+
# validates the amount field
|
|
6
|
+
class Amount
|
|
7
|
+
def self.validate!(data)
|
|
8
|
+
errors = []
|
|
9
|
+
errors.push("amount must be present.") unless data.key?("amount")
|
|
10
|
+
errors.push("amount must be a Numeric.") unless data["amount"].is_a?(Numeric)
|
|
11
|
+
errors.push("amount must be positive.") unless data["amount"].to_f.positive?
|
|
12
|
+
errors
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "uri"
|
|
4
|
+
|
|
5
|
+
module Monerorequest
|
|
6
|
+
module Validator
|
|
7
|
+
# validates the change_indicator_url field
|
|
8
|
+
class ChangeIndicatorURL
|
|
9
|
+
def self.validate!(data)
|
|
10
|
+
return [] unless data.key?("change_indicator_url")
|
|
11
|
+
|
|
12
|
+
errors = []
|
|
13
|
+
unless data["change_indicator_url"].is_a?(String)
|
|
14
|
+
errors.push("change_indicator_url must be a String.")
|
|
15
|
+
data["change_indicator_url"] = ""
|
|
16
|
+
end
|
|
17
|
+
return errors if data["change_indicator_url"] =~ URI::DEFAULT_PARSER.make_regexp
|
|
18
|
+
|
|
19
|
+
errors.push("change_indicator_url must be a URL.")
|
|
20
|
+
errors
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Monerorequest
|
|
4
|
+
module Validator
|
|
5
|
+
# validates the currency field
|
|
6
|
+
class Currency
|
|
7
|
+
def self.validate!(data)
|
|
8
|
+
errors = []
|
|
9
|
+
errors.push("currency must be present.") unless data.key?("currency")
|
|
10
|
+
errors.push("currency must be a String.") unless data["currency"].is_a?(String)
|
|
11
|
+
errors
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Monerorequest
|
|
4
|
+
module Validator
|
|
5
|
+
# validates the custom_label field
|
|
6
|
+
class CustomLabel
|
|
7
|
+
def self.validate!(data)
|
|
8
|
+
errors = []
|
|
9
|
+
errors.push("custom_label must be present.") unless data.key?("custom_label")
|
|
10
|
+
errors.push("custom_label must be a String.") unless data["custom_label"].is_a?(String)
|
|
11
|
+
errors
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Monerorequest
|
|
4
|
+
module Validator
|
|
5
|
+
# validates the days_per_billing_cycle field
|
|
6
|
+
class DaysPerBillingCycle
|
|
7
|
+
def self.validate!(data)
|
|
8
|
+
errors = []
|
|
9
|
+
errors.push("days_per_billing_cycle must be present.") unless data.key?("days_per_billing_cycle")
|
|
10
|
+
errors.push("days_per_billing_cycle must be an Integer.") unless data["days_per_billing_cycle"].is_a?(Integer)
|
|
11
|
+
errors.push("days_per_billing_cycle must be positive.") unless data["days_per_billing_cycle"].to_i.positive?
|
|
12
|
+
errors
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Monerorequest
|
|
4
|
+
module Validator
|
|
5
|
+
# validates the number_of_payments field
|
|
6
|
+
class NumberOfPayments
|
|
7
|
+
def self.validate!(data)
|
|
8
|
+
errors = []
|
|
9
|
+
errors.push("number_of_payments must be present.") unless data.key?("number_of_payments")
|
|
10
|
+
errors.push("number_of_payments must be an Integer.") unless data["number_of_payments"].is_a?(Integer)
|
|
11
|
+
errors.push("number_of_payments must be 0 or positive.") if data["number_of_payments"].to_i.negative?
|
|
12
|
+
errors
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Monerorequest
|
|
4
|
+
module Validator
|
|
5
|
+
# validates the payment_id field
|
|
6
|
+
class PaymentID
|
|
7
|
+
def self.validate!(data)
|
|
8
|
+
errors = []
|
|
9
|
+
errors.push("payment_id must be present.") unless data.key?("payment_id")
|
|
10
|
+
errors.push("payment_id must be a Monero Payment ID.") unless MoneroPaymentID.valid?(data["payment_id"])
|
|
11
|
+
errors
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Monerorequest
|
|
4
|
+
module Validator
|
|
5
|
+
# validates the schedule field
|
|
6
|
+
class Schedule
|
|
7
|
+
def self.validate!(data)
|
|
8
|
+
errors = []
|
|
9
|
+
errors.push("schedule must be present.") unless data.key?("schedule")
|
|
10
|
+
errors.push("schedule must be a valid Cron.") unless Cron.valid?(data.fetch("schedule", ""))
|
|
11
|
+
errors
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Monerorequest
|
|
4
|
+
module Validator
|
|
5
|
+
# validates the sellers_wallet field
|
|
6
|
+
class SellersWallet
|
|
7
|
+
def self.validate!(data)
|
|
8
|
+
errors = []
|
|
9
|
+
errors.push("sellers_wallet must be present.") unless data.key?("sellers_wallet")
|
|
10
|
+
return errors if MoneroAddress.valid?(data["sellers_wallet"])
|
|
11
|
+
|
|
12
|
+
errors.push("sellers_wallet must be a main Monero address.")
|
|
13
|
+
errors
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "date"
|
|
4
|
+
|
|
5
|
+
module Monerorequest
|
|
6
|
+
module Validator
|
|
7
|
+
# validates the start_date field
|
|
8
|
+
class StartDate
|
|
9
|
+
def self.validate!(data)
|
|
10
|
+
errors = []
|
|
11
|
+
errors.push("start_date must be present.") unless data.key?("start_date")
|
|
12
|
+
errors.push("start_date must be a String.") && data["start_date"] = "" unless data["start_date"].is_a?(String)
|
|
13
|
+
begin
|
|
14
|
+
DateTime.rfc3339(data["start_date"])
|
|
15
|
+
rescue Date::Error
|
|
16
|
+
errors.push("start_date must be an RFC3339 timestamp.")
|
|
17
|
+
end
|
|
18
|
+
errors
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
data/lib/monerorequest.rb
CHANGED
|
@@ -1,18 +1,26 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
module Monerorequest
|
|
4
|
+
SUPPORTED_MR_VERSIONS = [1, 2].freeze
|
|
5
|
+
|
|
6
|
+
# error raised when an unsupported Monerorequest version is supplied
|
|
7
|
+
class RequestVersionError < StandardError
|
|
8
|
+
def initialize(version)
|
|
9
|
+
@version = version
|
|
10
|
+
super
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def message
|
|
14
|
+
"Unknown version: #{@version}. Allowed versions: #{Monerorequest::SUPPORTED_MR_VERSIONS}"
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
class InvalidRequestError < StandardError; end
|
|
19
|
+
end
|
|
20
|
+
|
|
9
21
|
require_relative "monerorequest/decoder"
|
|
10
22
|
require_relative "monerorequest/encoder"
|
|
11
23
|
require_relative "monerorequest/monero_address"
|
|
12
24
|
require_relative "monerorequest/monero_payment_id"
|
|
13
25
|
require_relative "monerorequest/version"
|
|
14
26
|
require_relative "monerorequest/cron"
|
|
15
|
-
|
|
16
|
-
module Monerorequest
|
|
17
|
-
class RequestVersionError < StandardError; end
|
|
18
|
-
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: monerorequest
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 1.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- David Havlicek
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2025-01-
|
|
11
|
+
date: 2025-01-13 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description:
|
|
14
14
|
email:
|
|
@@ -31,9 +31,26 @@ files:
|
|
|
31
31
|
- lib/monerorequest/encoder.rb
|
|
32
32
|
- lib/monerorequest/monero_address.rb
|
|
33
33
|
- lib/monerorequest/monero_payment_id.rb
|
|
34
|
+
- lib/monerorequest/pipeline/base64_decoder.rb
|
|
35
|
+
- lib/monerorequest/pipeline/base64_encoder.rb
|
|
36
|
+
- lib/monerorequest/pipeline/gzip_reader.rb
|
|
37
|
+
- lib/monerorequest/pipeline/gzip_writer.rb
|
|
38
|
+
- lib/monerorequest/pipeline/json_encoder.rb
|
|
39
|
+
- lib/monerorequest/pipeline/json_parser.rb
|
|
40
|
+
- lib/monerorequest/v1.rb
|
|
41
|
+
- lib/monerorequest/v2.rb
|
|
42
|
+
- lib/monerorequest/validator/amount.rb
|
|
43
|
+
- lib/monerorequest/validator/change_indicator_url.rb
|
|
44
|
+
- lib/monerorequest/validator/currency.rb
|
|
45
|
+
- lib/monerorequest/validator/custom_label.rb
|
|
46
|
+
- lib/monerorequest/validator/days_per_billing_cycle.rb
|
|
47
|
+
- lib/monerorequest/validator/number_of_payments.rb
|
|
48
|
+
- lib/monerorequest/validator/payment_id.rb
|
|
49
|
+
- lib/monerorequest/validator/schedule.rb
|
|
50
|
+
- lib/monerorequest/validator/sellers_wallet.rb
|
|
51
|
+
- lib/monerorequest/validator/start_date.rb
|
|
34
52
|
- lib/monerorequest/version.rb
|
|
35
53
|
- monerorequest.gemspec
|
|
36
|
-
- sig/monerorequest.rbs
|
|
37
54
|
homepage: https://github.com/snex/monerorequest-ruby
|
|
38
55
|
licenses:
|
|
39
56
|
- MIT
|
data/sig/monerorequest.rbs
DELETED