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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1eb8bfed0d690a9ea26e823821d01f213036b54f72dbf0f4b860c81b46860092
4
- data.tar.gz: 6ff77765db25d97e72f8cdb156bb3077587608bed69a66c947cce6433ffbd717
3
+ metadata.gz: 944c04e247c34be236e6071a5b8f384d11f12a21598b487068f8086ef9fdd7cb
4
+ data.tar.gz: e681abc0a5490f7fa86811a735d53f091b4ab8effd906cfa00b0737db11ba9c5
5
5
  SHA512:
6
- metadata.gz: ade67de2f1881fa4e46309c0e0a6187a55c7b965199f1e0fa8e1990845d6a28f6217459185e2b3c3026a2334a107f71734c6692a0805ba2995dfac76f630869b
7
- data.tar.gz: 7f50f46fb99f008027789bf5a528e98cd32d960eaebc9cc8c32dc8a72e124aaa386c89126d216c00f5685c82303253ef562d7fe07904ecfcc8b982a31b499957
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.2.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+k8YjJBqu58CkrqTg3lg
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.
@@ -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.to_i) } || days == ["*"]
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? { |mth| (1..12).member?(mth.to_i) || MONTH_CODES.include?(mth.downcase) } || months == ["*"]
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 Decode an encoded Monerorequest
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
- _, version, encoded_str = @request.split(":")
12
- raise RequestVersionError, "Request Versions 1 and 2 are supported." unless [1, 2].include?(version.to_i)
13
-
14
- compressed_data = Base64.decode64(encoded_str)
15
- json_str = Zlib::GzipReader.new(StringIO.new(compressed_data)).read
16
- decoded_hash = JSON.parse(json_str)
17
- decoded_hash["version"] = version.to_i
18
- decoded_hash
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
- require "base64"
4
- require "date"
5
- require "json"
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
- @request = request
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(version)
26
- raise RequestVersionError, "Request Versions 1 and 2 are supported." unless [1, 2].include?(version.to_i)
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
- @errors.push("sellers_wallet must be a main Monero address.")
62
- end
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
- def validate_payment_id!
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
- def validate_start_date!
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 validate_days_per_billing_cycle!
92
- unless @request.key?("days_per_billing_cycle") && @request["version"] == "1"
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 validate_change_indicator_url!
99
- @errors.push("change_indicator_url must be present.") unless @request.key?("change_indicator_url")
100
- unless @request["change_indicator_url"].is_a?(String)
101
- @errors.push("change_indicator_url must be a String.") && @request["change_indicator_url"] = ""
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
- def validate_schedule!
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Monerorequest
4
- VERSION = "0.2.0"
4
+ VERSION = "1.0.0"
5
5
  end
data/lib/monerorequest.rb CHANGED
@@ -1,18 +1,26 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "base64"
4
- require "date"
5
- require "json"
6
- require "stringio"
7
- require "uri"
8
- require "zlib"
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.2.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-10 00:00:00.000000000 Z
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
@@ -1,4 +0,0 @@
1
- module Monerorequest
2
- VERSION: String
3
- # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
- end