monerorequest 0.2.0 → 1.0.0

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