ruby-common 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.
@@ -0,0 +1,90 @@
1
+ require 'base64'
2
+ require 'date'
3
+
4
+ require_relative '../common/PhpUnpack.rb'
5
+ require_relative '../common/Ipv6Utils.rb'
6
+ require_relative '../common/Utils.rb'
7
+ require_relative '../common/Exceptions.rb'
8
+ require_relative './CryptMethodConstans.rb'
9
+ require_relative './AbstractSymmetricCrypt.rb'
10
+ require_relative './MyOpenSSL.rb'
11
+ require_relative './OpenSSLAEAD.rb'
12
+ require_relative './Secretbox.rb'
13
+ require_relative './StructUnpacker.rb'
14
+ require_relative './Secretbox.rb'
15
+ require_relative '../common/VerifierConstants.rb'
16
+ require_relative './Signature5VerificationResult.rb'
17
+ require_relative './CryptFactory.rb'
18
+
19
+
20
+ class Signature5VerifierService
21
+ VERSION = 5;
22
+ HEADER_LENGTH = 11;
23
+
24
+ def self.verifySignature(signature, user_agent, key, ip_addresses)
25
+ parsed = parse(signature, key)
26
+ verify(parsed, ip_addresses, user_agent)
27
+ return Signature5VerificationResult.new(parsed)
28
+ end
29
+
30
+ class << self
31
+ private
32
+
33
+
34
+ def parse(signature, key)
35
+ signature_decoded = SignatureVerifierUtils.base64_decode(signature)
36
+ key = SignatureVerifierUtils.base64_decode(key)
37
+
38
+ raise SignatureParseError, 'Malformed signature' if signature_decoded.bytes.length < HEADER_LENGTH;
39
+
40
+ unpack = PhpUnpack.unpack("Cversion/nlength/Jzone_id", signature_decoded);
41
+
42
+ raise SignatureParseError, 'Malformed signature' if unpack['version'].first != VERSION;
43
+
44
+ length = unpack['length'].first;
45
+ zone_id = unpack['zone_id'];
46
+
47
+ raise SignatureParseError, 'Truncated signature payload' if signature_decoded.bytes.length < length;
48
+
49
+ decrypted_payload = decrypt_payload(signature_decoded, key)
50
+ decrypted_payload['zone_id']= zone_id
51
+ return decrypted_payload
52
+ end
53
+
54
+ def decrypt_payload(signature_decoded, key)
55
+ crypt = CryptFactory.create_from_payload(signature_decoded)
56
+ decrypted_payload = crypt.decrypt_with_key(signature_decoded, key)
57
+ return StructUnpacker::parse_payload(decrypted_payload)
58
+ end
59
+
60
+ def verify(parsed, ip_addresses, user_agent)
61
+ matching_ip = nil
62
+
63
+ ip_addresses.each do |ip_address|
64
+ if parsed['ipv4.ip']
65
+ if ip_address == parsed['ipv4.ip']
66
+ matching_ip = ip_address
67
+ break
68
+ end
69
+ end
70
+
71
+ if parsed['ipv6.ip']
72
+ if IpV6Utils.abbreviate(parsed['ipv6.ip']) == IpV6Utils.abbreviate(ip_address)
73
+ matching_ip = ip_address
74
+ break
75
+ end
76
+ end
77
+ end
78
+
79
+ raise VerifyError, 'Signature IP mismatch' if matching_ip.nil?
80
+ unless parsed['b.ua'] == user_agent
81
+ raise VerifyError, 'Signature user agent mismatch'
82
+ end
83
+
84
+ unless VerifierConstants::RESULTS[parsed['result'].to_i] == parsed['verdict']
85
+ raise VerifyError, 'Result mismatch'
86
+ end
87
+ end
88
+
89
+ end
90
+ end
@@ -0,0 +1,110 @@
1
+ require_relative "../common/Exceptions.rb"
2
+ require_relative "../common/PhpUnpack.rb"
3
+ require_relative "./PhpUnserializer.rb"
4
+
5
+ require 'msgpack'
6
+ require 'json'
7
+
8
+ class StructUnpacker
9
+ SERIALIZE_HEADER = "S"
10
+ JSON_HEADER = "J"
11
+ MSG_HEADER = "M"
12
+ RFC3986_HEADER = "H"
13
+
14
+ def self.parse_payload(decrypted_payload)
15
+ header = decrypted_payload.to_s[0]
16
+
17
+ case header
18
+ when SERIALIZE_HEADER, "Serialize", "serialize"
19
+ return serialize_unpack(decrypted_payload)
20
+ when MSG_HEADER, "Msgpack", "msgpack"
21
+ return msg_unpack(decrypted_payload)
22
+ when JSON_HEADER, "StructJson", "json"
23
+ return json_unpack(decrypted_payload)
24
+ when RFC3986_HEADER, "StructRfc3986", "rfc3986"
25
+ return rfc3986_unpack(decrypted_payload)
26
+ else
27
+ raise StructParseError, "Unsupported struct class #{header}"
28
+ end
29
+ end
30
+
31
+ class << self
32
+ private
33
+
34
+ def serialize_unpack(buffer)
35
+ raise StructParseError, "Unexpected serializer type" if !buffer.to_s.start_with?(SERIALIZE_HEADER)
36
+
37
+ begin
38
+ payload = buffer.to_s[SERIALIZE_HEADER.length..-1]
39
+ return PhpUnserializer.new(payload).unserialize
40
+ rescue StandardError => e
41
+ raise StructParseError, "Error parsing Serialize struct: #{e.message}"
42
+ end
43
+ end
44
+
45
+ def json_unpack(payload)
46
+ begin
47
+ str_payload = payload.to_s[1..-1]
48
+ JSON.parse(str_payload)
49
+ rescue JSON::ParserError => e
50
+ raise StructParseError, "Error parsing StructJson struct: #{e.message}"
51
+ end
52
+ end
53
+
54
+ def msg_unpack(buffer)
55
+ begin
56
+ slice = buffer[1..-1]
57
+ return MessagePack.unpack(slice)
58
+ rescue StandardError => e
59
+ raise StructParseError, "Error parsing MsgPack struct: #{e.message}"
60
+ end
61
+ end
62
+
63
+ def rfc3986_unpack(data)
64
+ begin
65
+ query_string = data.to_s
66
+ decoded = decode_url(query_string)
67
+ pairs = decoded.split('&')
68
+ result = {}
69
+
70
+ pairs.each do |pair|
71
+ key, value = pair.split('=', 2)
72
+ result[key] = value || ""
73
+ end
74
+
75
+ result
76
+ rescue StandardError => e
77
+ raise StructParseError, "Error parsing StructRfc3986 struct: #{e.message}"
78
+ end
79
+ end
80
+
81
+ def decode_url(encoded_url)
82
+ decoded_url = ""
83
+ i = 0
84
+
85
+ while i < encoded_url.length
86
+ c = encoded_url[i]
87
+ if c == '%'
88
+ if i + 2 < encoded_url.length
89
+ hex = encoded_url[i + 1, 2]
90
+ begin
91
+ decoded_url << [hex].pack('H*')
92
+ i += 3
93
+ rescue ArgumentError
94
+ decoded_url << c
95
+ i += 1
96
+ end
97
+ else
98
+ decoded_url << c
99
+ i += 1
100
+ end
101
+ else
102
+ decoded_url << c
103
+ i += 1
104
+ end
105
+ end
106
+
107
+ decoded_url
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Ruby
4
+ module Common
5
+ VERSION = "1.0.0"
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ require_relative "./ruby-common/version.rb"
2
+ require_relative "./ruby-common/Signature4Verifier.rb"
3
+ require_relative "./ruby-common/Signature5Verifier.rb"
4
+
5
+ module RubyCommon
6
+ class Error < StandardError; end
7
+ end
@@ -0,0 +1,6 @@
1
+ module Ruby
2
+ module Common
3
+ VERSION: String
4
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
5
+ end
6
+ end
metadata ADDED
@@ -0,0 +1,120 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-common
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Adrian Parzych
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2024-10-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rbnacl
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 7.1.2
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 7.1.2
27
+ - !ruby/object:Gem::Dependency
28
+ name: msgpack
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 1.7.3
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 1.7.3
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13.0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ description:
56
+ email:
57
+ - adrian.parzych@iterative.pl
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - CHANGELOG.md
63
+ - CODE_OF_CONDUCT.md
64
+ - Gemfile
65
+ - Gemfile.lock
66
+ - LICENSE.md
67
+ - README.md
68
+ - Rakefile
69
+ - lib/ruby-common.rb
70
+ - lib/ruby-common/Signature4Verifier.rb
71
+ - lib/ruby-common/Signature5Verifier.rb
72
+ - lib/ruby-common/common/Exceptions.rb
73
+ - lib/ruby-common/common/Ipv6Utils.rb
74
+ - lib/ruby-common/common/PhpUnpack.rb
75
+ - lib/ruby-common/common/Utils.rb
76
+ - lib/ruby-common/common/VerifierConstants.rb
77
+ - lib/ruby-common/v4/AsymmetricOpenSSL.rb
78
+ - lib/ruby-common/v4/Signature4VerificationResult.rb
79
+ - lib/ruby-common/v4/Signature4VerifierService.rb
80
+ - lib/ruby-common/v5/AbstractSymmetricCrypt.rb
81
+ - lib/ruby-common/v5/CryptFactory.rb
82
+ - lib/ruby-common/v5/CryptMethodConstans.rb
83
+ - lib/ruby-common/v5/DecryptResult.rb
84
+ - lib/ruby-common/v5/MyOpenSSL.rb
85
+ - lib/ruby-common/v5/OpenSSLAEAD.rb
86
+ - lib/ruby-common/v5/PhpUnserializer.rb
87
+ - lib/ruby-common/v5/Secretbox.rb
88
+ - lib/ruby-common/v5/Signature5VerificationResult.rb
89
+ - lib/ruby-common/v5/Signature5VerifierService.rb
90
+ - lib/ruby-common/v5/StructUnpacker.rb
91
+ - lib/ruby-common/version.rb
92
+ - sig/ruby/common.rbs
93
+ homepage: https://docs.adscore.com/js-api/#signature-verification.html
94
+ licenses:
95
+ - MIT
96
+ metadata:
97
+ homepage_uri: https://www.adscore.com/
98
+ source_code_uri: https://github.com/Adscore/ruby-common
99
+ post_install_message:
100
+ rdoc_options: []
101
+ require_paths:
102
+ - lib
103
+ required_ruby_version: !ruby/object:Gem::Requirement
104
+ requirements:
105
+ - - ">="
106
+ - !ruby/object:Gem::Version
107
+ version: 2.6.0
108
+ required_rubygems_version: !ruby/object:Gem::Requirement
109
+ requirements:
110
+ - - ">="
111
+ - !ruby/object:Gem::Version
112
+ version: '0'
113
+ requirements: []
114
+ rubygems_version: 3.3.5
115
+ signing_key:
116
+ specification_version: 4
117
+ summary: This library provides various utilities for parsing [Adscore](https://adscore.com)
118
+ signatures v4 and v5, and virtually anything that might be useful for customers
119
+ doing server-side integration with the service.
120
+ test_files: []