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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +16 -0
- data/Gemfile.lock +34 -0
- data/LICENSE.md +21 -0
- data/README.md +174 -0
- data/Rakefile +4 -0
- data/lib/ruby-common/Signature4Verifier.rb +29 -0
- data/lib/ruby-common/Signature5Verifier.rb +31 -0
- data/lib/ruby-common/common/Exceptions.rb +7 -0
- data/lib/ruby-common/common/Ipv6Utils.rb +27 -0
- data/lib/ruby-common/common/PhpUnpack.rb +96 -0
- data/lib/ruby-common/common/Utils.rb +22 -0
- data/lib/ruby-common/common/VerifierConstants.rb +9 -0
- data/lib/ruby-common/v4/AsymmetricOpenSSL.rb +11 -0
- data/lib/ruby-common/v4/Signature4VerificationResult.rb +40 -0
- data/lib/ruby-common/v4/Signature4VerifierService.rb +203 -0
- data/lib/ruby-common/v5/AbstractSymmetricCrypt.rb +25 -0
- data/lib/ruby-common/v5/CryptFactory.rb +20 -0
- data/lib/ruby-common/v5/CryptMethodConstans.rb +10 -0
- data/lib/ruby-common/v5/DecryptResult.rb +27 -0
- data/lib/ruby-common/v5/MyOpenSSL.rb +39 -0
- data/lib/ruby-common/v5/OpenSSLAEAD.rb +41 -0
- data/lib/ruby-common/v5/PhpUnserializer.rb +88 -0
- data/lib/ruby-common/v5/Secretbox.rb +14 -0
- data/lib/ruby-common/v5/Signature5VerificationResult.rb +154 -0
- data/lib/ruby-common/v5/Signature5VerifierService.rb +90 -0
- data/lib/ruby-common/v5/StructUnpacker.rb +110 -0
- data/lib/ruby-common/version.rb +7 -0
- data/lib/ruby-common.rb +7 -0
- data/sig/ruby/common.rbs +6 -0
- metadata +120 -0
@@ -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
|
data/lib/ruby-common.rb
ADDED
data/sig/ruby/common.rbs
ADDED
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: []
|