quorum_sdk 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,134 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QuorumSdk
4
+ # Wrapper for some useful methods
5
+ module Utils
6
+ class << self
7
+ def parse_seed_url(url)
8
+ url = Addressable::URI.parse(url.gsub(/\\u([a-f0-9]{4})/i) { [::Regexp.last_match(1).hex].pack('U') })
9
+ query_values = url.query_values
10
+
11
+ group_name = query_values['a']
12
+ group_id = uuid_from_base64 query_values['g']
13
+ block_id = uuid_from_base64 query_values['b']
14
+ signature = Base64.strict_encode64 Base64.urlsafe_decode64(query_values['s'])
15
+ owner_pubkey = query_values['k']
16
+ cipher_key = Base64.urlsafe_decode64(query_values['c']).unpack1('H*')
17
+ app_key = query_values['y']
18
+ consensus_type = query_values['n'].to_s == '1' ? 'pos' : 'poa'
19
+ encryption_type = query_values['e'].to_s == '0' ? 'public' : 'private'
20
+ chain_urls = query_values['u'].split('|')
21
+
22
+ {
23
+ group_id:,
24
+ group_name:,
25
+ block_id:,
26
+ signature:,
27
+ owner_pubkey:,
28
+ cipher_key:,
29
+ app_key:,
30
+ consensus_type:,
31
+ encryption_type:,
32
+ chain_urls:
33
+ }
34
+ end
35
+
36
+ def uuid_from_base64(str)
37
+ hex = Base64.urlsafe_decode64(str).unpack1('H*')
38
+ format(
39
+ '%<first>s-%<second>s-%<third>s-%<forth>s-%<fifth>s',
40
+ first: hex[0..7],
41
+ second: hex[8..11],
42
+ third: hex[12..15],
43
+ forth: hex[16..19],
44
+ fifth: hex[20..]
45
+ )
46
+ end
47
+
48
+ ARGUMENTS_FOR_ENCRYPT_TRX = %i[private_key group_id cipher_key data].freeze
49
+ def encrypt_trx(**kwargs)
50
+ raise ArgumentError, "Keyword arguments #{ARGUMENTS_FOR_ENCRYPT_TRX} must be provided" unless ARGUMENTS_FOR_ENCRYPT_TRX.all?(&->(arg) { arg.in? kwargs.keys })
51
+ raise ArgumentError, 'data should be instance of Google::Protobuf::MessageExts' unless kwargs[:data].is_a?(Google::Protobuf::MessageExts)
52
+
53
+ data = Google::Protobuf::Any.new(
54
+ type_url: "type.googleapis.com/#{kwargs[:data].class.descriptor.name}",
55
+ value: kwargs[:data].to_proto
56
+ ).to_proto
57
+ encrypted_data = aes_encrypt data, key: kwargs[:cipher_key]
58
+
59
+ account = QuorumSdk::Account.new priv: kwargs[:private_key]
60
+
61
+ msg =
62
+ Quorum::Pb::Trx.new(
63
+ TrxId: (kwargs[:trx_id] || SecureRandom.uuid),
64
+ GroupId: kwargs[:group_id],
65
+ Data: encrypted_data,
66
+ TimeStamp: (kwargs[:timestamp].to_i || (Time.now.to_f * 1e9).to_i),
67
+ Version: (kwargs[:version] || '1.0.0'),
68
+ Expired: (kwargs[:expired].to_i || (30.seconds.from_now.to_f * 1e9).to_i),
69
+ Nonce: (kwargs[:nonce] || 1),
70
+ SenderPubkey: Base64.urlsafe_encode64(account.public_bytes_compressed, padding: false)
71
+ )
72
+
73
+ hash = Digest::SHA256.hexdigest msg.to_proto
74
+ signature = account.sign [hash].pack('H*')
75
+ msg.SenderSign = [signature].pack('H*')
76
+ trx_json = {
77
+ TrxBytes: Base64.strict_encode64(msg.to_proto)
78
+ }
79
+ encrypted = aes_encrypt trx_json.to_json, key: kwargs[:cipher_key]
80
+ Base64.strict_encode64 encrypted
81
+ end
82
+
83
+ def decrypt_trx(cipher, key:)
84
+ cipher = Base64.strict_decode64 cipher
85
+ trx_json = JSON.parse aes_decrypt(cipher, key:)
86
+ trx_bytes = Base64.strict_decode64 trx_json['TrxBytes']
87
+ trx = Quorum::Pb::Trx.decode trx_bytes
88
+
89
+ trx_without_sig = trx.dup
90
+ trx_without_sig.clear_SenderSign
91
+ hash = Digest::SHA256.hexdigest Quorum::Pb::Trx.encode(trx_without_sig)
92
+
93
+ signature = trx.SenderSign.unpack1('H*')
94
+ public_key_compressed = Base64.urlsafe_decode64(trx.SenderPubkey).unpack1('H*')
95
+ public_key_uncompressed = Eth::Signature.recover [hash].pack('H*'), signature
96
+ raise QuorumSdk::Error, 'Signature not verified' if public_key_uncompressed[2...66] != public_key_compressed[2...]
97
+
98
+ data = decrypt_trx_data(trx.Data, key:)
99
+
100
+ trx = JSON.parse Quorum::Pb::Trx.encode_json(trx)
101
+ trx['Data'] = data
102
+ trx.with_indifferent_access
103
+ end
104
+
105
+ def decrypt_trx_data(cipher, key:)
106
+ decrypted_data = aes_decrypt(cipher, key:)
107
+ obj = Google::Protobuf::Any.decode decrypted_data
108
+ msgclass = ::Google::Protobuf::DescriptorPool.generated_pool.lookup(obj.type_url.split('/').last).msgclass
109
+ JSON.parse msgclass.encode_json(msgclass.decode(obj.value))
110
+ end
111
+
112
+ def aes_encrypt(data, key:)
113
+ encipher = OpenSSL::Cipher.new('aes-256-gcm').encrypt
114
+ encipher.key = [key].pack('H*')
115
+ iv = encipher.random_iv
116
+ encipher.iv = iv
117
+ encrypted = encipher.update(data) + encipher.final
118
+ [
119
+ iv,
120
+ encrypted,
121
+ encipher.auth_tag
122
+ ].join
123
+ end
124
+
125
+ def aes_decrypt(cipher, key:)
126
+ decipher = OpenSSL::Cipher.new('aes-256-gcm').decrypt
127
+ decipher.key = [key].pack('H*')
128
+ decipher.iv = cipher[...12]
129
+ decipher.auth_tag = cipher[-16...]
130
+ decipher.update(cipher[12...-16]) + decipher.final
131
+ end
132
+ end
133
+ end
134
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module QuorumSdk
4
+ VERSION = '0.1.0'
5
+ end
data/lib/quorum_sdk.rb ADDED
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'addressable/uri'
4
+ require 'active_support/all'
5
+ require 'base64'
6
+ require 'bcrypt'
7
+ require 'eth'
8
+ require 'faraday'
9
+ require 'faraday/retry'
10
+ require 'google/protobuf/well_known_types'
11
+
12
+ require_relative 'proto/activity_stream_pb'
13
+ require_relative 'proto/chain_pb'
14
+ require_relative 'quorum_sdk/account'
15
+ require_relative 'quorum_sdk/api'
16
+ require_relative 'quorum_sdk/utils'
17
+ require_relative 'quorum_sdk/version'
18
+
19
+ module QuorumSdk
20
+ class Error < StandardError; end
21
+ class ArgumentError < Error; end
22
+ end
@@ -0,0 +1,4 @@
1
+ module QuorumSdk
2
+ VERSION: String
3
+ # See the writing guide of rbs: https://github.com/ruby/rbs#guides
4
+ end
metadata ADDED
@@ -0,0 +1,181 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: quorum_sdk
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - an-lee
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2023-01-07 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '7'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: addressable
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '2'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '2'
41
+ - !ruby/object:Gem::Dependency
42
+ name: bcrypt
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.1'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: eth
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.5'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.5'
69
+ - !ruby/object:Gem::Dependency
70
+ name: faraday
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '2'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: faraday-retry
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2'
90
+ type: :runtime
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2'
97
+ - !ruby/object:Gem::Dependency
98
+ name: google-protobuf
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '3'
104
+ type: :runtime
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '3'
111
+ - !ruby/object:Gem::Dependency
112
+ name: sha3
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '1.0'
118
+ type: :runtime
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '1.0'
125
+ description: A API wrapper for Quorum
126
+ email:
127
+ - an.lee.work@gmail.com
128
+ executables: []
129
+ extensions: []
130
+ extra_rdoc_files: []
131
+ files:
132
+ - ".rubocop.yml"
133
+ - CHANGELOG.md
134
+ - CODE_OF_CONDUCT.md
135
+ - Gemfile
136
+ - Gemfile.lock
137
+ - LICENSE.txt
138
+ - README.md
139
+ - Rakefile
140
+ - activity_stream_pb.rb
141
+ - lib/proto/activity_stream.proto
142
+ - lib/proto/activity_stream_pb.rb
143
+ - lib/proto/chain.proto
144
+ - lib/proto/chain_pb.rb
145
+ - lib/quorum_sdk.rb
146
+ - lib/quorum_sdk/account.rb
147
+ - lib/quorum_sdk/api.rb
148
+ - lib/quorum_sdk/api/chain.rb
149
+ - lib/quorum_sdk/api/light_node.rb
150
+ - lib/quorum_sdk/client.rb
151
+ - lib/quorum_sdk/utils.rb
152
+ - lib/quorum_sdk/version.rb
153
+ - sig/quorum_sdk.rbs
154
+ homepage: https://github.com/an-lee/quorum_sdk
155
+ licenses:
156
+ - MIT
157
+ metadata:
158
+ homepage_uri: https://github.com/an-lee/quorum_sdk
159
+ source_code_uri: https://github.com/an-lee/quorum_sdk
160
+ changelog_uri: https://github.com/an-lee/quorum_sdk/CHANGELOG.md
161
+ rubygems_mfa_required: 'true'
162
+ post_install_message:
163
+ rdoc_options: []
164
+ require_paths:
165
+ - lib
166
+ required_ruby_version: !ruby/object:Gem::Requirement
167
+ requirements:
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ version: '3.1'
171
+ required_rubygems_version: !ruby/object:Gem::Requirement
172
+ requirements:
173
+ - - ">="
174
+ - !ruby/object:Gem::Version
175
+ version: '0'
176
+ requirements: []
177
+ rubygems_version: 3.4.2
178
+ signing_key:
179
+ specification_version: 4
180
+ summary: A Quorum SDK implemented in Ruby
181
+ test_files: []