stellar-sdk 0.24.0 → 0.25.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: f79d3c2af3b2cee00a5a7fd4f7ce698bf250c349afa72f9a310b5f101326d168
4
- data.tar.gz: 85b75a06c450fb09c07383dbd0606f72d5b83e5f5ac73f51692302ab27237bd1
3
+ metadata.gz: 14f9e7a13e44b5eb83bce5faee3918a49c03cfd9d36f00b49cdec501131702bc
4
+ data.tar.gz: cbf8145d6a546359ba66f74bc868cc1f5c6bf82a0e1c077d6073ef242f3989ef
5
5
  SHA512:
6
- metadata.gz: ba9a3d5d81b4e5b55af6cb5c14f33001744feea77b706b1b7204189ac638d0c617dcab2e8364822a9a6d4bb0bb222218b4c73da35ae9e18ee649eccab0abd3dc
7
- data.tar.gz: 761d9db6452124b38568ea390ba70ddd98ad307cc4304df1bd5abb12e303398661de13ac3fd8320352db657899aef86b3ace18393254782f28ae33a1d868a138
6
+ metadata.gz: a1a999329ba74c3a0448c59c4d249c4fecdc1b0961dbc82ba985f8b3fb792b993825a1eabd2df8918566ac1b7f1ca847572a381d61c0194aa8f48cc50fdea6e4
7
+ data.tar.gz: b4c7f193cd7fef55798e4788476e30898c2b8517981ad4d05da2c9ac7a1ab4758e5287700cd017b1c62cd97e995b6f645dc15ef9cff22d0cc061aeb85375dfe7
@@ -4,12 +4,25 @@ All notable changes to this project will be documented in this file.
4
4
  The format is based on [Keep a Changelog](http://keepachangelog.com/)
5
5
  and this project adheres to [Semantic Versioning](http://semver.org/).
6
6
 
7
- ## [Unreleased]
7
+ ## [Unreleased](https://github.com/stellar/ruby-stellar-sdk/compare/v0.25.0...master)
8
8
 
9
- ## [0.23.1](https://github.com/stellar/ruby-stellar-sdk/compare/v0.23.1...v0.23.0) - 2020-06-18
9
+ ## [0.25.0](https://github.com/stellar/ruby-stellar-sdk/compare/v0.24.0...0.25.0)
10
+ ### Changed
11
+ - `Stellar::SEP10` is updated to comply with SEP10 v2.1.0
12
+ - `build_challenge_tx` now accepts `domain` instead of `anchor_name`, using the
13
+ old param name will now result in deprecation warning
14
+ - `read_challenge_tx` correctly validates multi-op challenge transactions
15
+ - `verify_challenge_tx_threshold` now expects simple `{'GA...' => weight, ... }` hash for `signers`
16
+ ### Removed:
17
+ - Deprecated `Stellar::SEP10.verify_challenge_tx` method is removed
18
+
19
+ ## [0.24.0](https://github.com/stellar/ruby-stellar-sdk/compare/v0.23.1...v0.24.0) - 2020-10-20
20
+ - Protocol 14 support
21
+
22
+ ## [0.23.1](https://github.com/stellar/ruby-stellar-sdk/compare/v0.23.0...v0.23.1) - 2020-06-18
10
23
  - Fix SEP10, considering muxed accounts
11
24
 
12
- ## [0.23.0](https://github.com/stellar/ruby-stellar-sdk/compare/v0.23.0...v0.9.0)
25
+ ## [0.23.0](https://github.com/stellar/ruby-stellar-sdk/compare/v0.9.0...v0.23.0)
13
26
  - No changes. We bumped this version to sync `stellar-sdk` and `stellar-base` versions
14
27
 
15
28
  ## [0.9.0](https://github.com/stellar/ruby-stellar-sdk/compare/v0.9.0...v0.8.0)
@@ -18,7 +31,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
18
31
  - Fee-Bump transactions ([CAP-0015](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0015.md))
19
32
  - Multiplexed accounts ([CAP-0027](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0027.md))
20
33
  - Fine-Grained control on trustline authorization ([CAP-0018](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0018.md))
21
-
34
+
22
35
  ## [0.8.0](https://github.com/stellar/ruby-stellar-sdk/compare/v0.7.0...v0.8.0)
23
36
  ### Added
24
37
  - SEP-10 Multisig Support [#69](https://github.com/stellar/ruby-stellar-sdk/pull/69)
data/README.md CHANGED
@@ -1,7 +1,7 @@
1
- # Ruby Stellar
2
-
3
- [![Build Status](https://travis-ci.org/bloom-solutions/ruby-stellar-sdk.svg)](https://travis-ci.org/bloom-solutions/ruby-stellar-sdk)
4
- [![Code Climate](https://codeclimate.com/github/bloom-solutions/ruby-stellar-sdk/badges/gpa.svg)](https://codeclimate.com/github/bloom-solutions/ruby-stellar-sdk)
1
+ # Stellar SDK for Ruby: Horizon Integration and Higher Level Abstractions
2
+ [![stellar-sdk](https://badge.fury.io/rb/stellar-sdk.svg)](https://badge.fury.io/rb/stellar-sdk)
3
+ [![Test](https://github.com/astroband/ruby-stellar-sdk/workflows/Test/badge.svg)](https://github.com/astroband/ruby-stellar-sdk/actions?query=branch%3Amaster)
4
+ [![Maintainability](https://api.codeclimate.com/v1/badges/dadfcd9396aba493cb93/maintainability)](https://codeclimate.com/github/astroband/ruby-stellar-sdk/maintainability)
5
5
 
6
6
  This library helps you to integrate your application into the [Stellar network](http://stellar.org).
7
7
 
@@ -36,7 +36,7 @@ client.send_payment({
36
36
  from: account,
37
37
  to: recipient,
38
38
  amount: Stellar::Amount.new(100_000_000)
39
- })
39
+ })
40
40
  ```
41
41
 
42
42
  Be sure to set the network when submitting to the public network (more information in [stellar-base](https://www.github.com/bloom-solutions/ruby-stellar-base)):
@@ -1,5 +1,5 @@
1
1
  module Stellar
2
2
  module SDK
3
- VERSION = "0.24.0"
3
+ VERSION = "0.25.0"
4
4
  end
5
5
  end
@@ -2,22 +2,34 @@ module Stellar
2
2
  class InvalidSep10ChallengeError < StandardError; end
3
3
 
4
4
  class SEP10
5
+ include Stellar::DSL
6
+
5
7
  # Helper method to create a valid {SEP0010}[https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0010.md]
6
8
  # challenge transaction which you can use for Stellar Web Authentication.
7
9
  #
8
- # @param server [Stellar::KeyPair] Keypair for server's signing account.
9
- # @param client [Stellar::KeyPair] Keypair for the account whishing to authenticate with the server.
10
- # @param anchor_name [String] Anchor's name to be used in the manage_data key.
11
- # @param timeout [Integer] Challenge duration (default to 5 minutes).
12
- #
13
- # @return [String] A base64 encoded string of the raw TransactionEnvelope xdr struct for the transaction.
10
+ # @example
11
+ # server = Stellar::KeyPair.random # SIGNING_KEY from your stellar.toml
12
+ # user = Stellar::KeyPair.from_address('G...')
13
+ # Stellar::SEP10.build_challenge_tx(server: server, client: user, domain: 'example.com', timeout: 300)
14
14
  #
15
- # = Example
15
+ # @param server [Stellar::KeyPair] server's signing keypair (SIGNING_KEY in service's stellar.toml)
16
+ # @param client [Stellar::KeyPair] account trying to authenticate with the server
17
+ # @param domain [String] service's domain to be used in the manage_data key
18
+ # @param timeout [Integer] challenge duration (default to 5 minutes)
16
19
  #
17
- # Stellar::SEP10.build_challenge_tx(server: server, client: user, anchor_name: anchor, timeout: timeout)
20
+ # @return [String] A base64 encoded string of the raw TransactionEnvelope xdr struct for the transaction.
18
21
  #
19
22
  # @see {SEP0010: Stellar Web Authentication}[https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0010.md]
20
- def self.build_challenge_tx(server:, client:, anchor_name:, timeout: 300)
23
+ def self.build_challenge_tx(server:, client:, domain: nil, timeout: 300, **options)
24
+ if domain.blank? && options.key?(:anchor_name)
25
+ ActiveSupport::Deprecation.new("next release", "stellar-sdk").warn <<~MSG
26
+ SEP-10 v2.0.0 requires usage of service home domain instead of anchor name in the challenge transaction.
27
+ Please update your implementation to use `Stellar::SEP10.build_challenge_tx(..., home_domain: 'example.com')`.
28
+ Using `anchor_name` parameter makes your service incompatible with SEP10-2.0 clients, support for this parameter
29
+ is deprecated and will be removed in the next major release of stellar-base.
30
+ MSG
31
+ domain = options[:anchor_name]
32
+ end
21
33
  # The value must be 64 bytes long. It contains a 48 byte
22
34
  # cryptographic-quality random string encoded using base64 (for a total of
23
35
  # 64 bytes after encoding).
@@ -35,7 +47,7 @@ module Stellar
35
47
  time_bounds: time_bounds
36
48
  ).add_operation(
37
49
  Stellar::Operation.manage_data(
38
- name: "#{anchor_name} auth",
50
+ name: "#{domain} auth",
39
51
  value: value,
40
52
  source_account: client
41
53
  )
@@ -49,76 +61,68 @@ module Stellar
49
61
  # It also verifies that transaction is signed by the server.
50
62
  #
51
63
  # It does not verify that the transaction has been signed by the client or
52
- # that any signatures other than the servers on the transaction are valid. Use
53
- # one of the following functions to completely verify the transaction:
54
- # - Stellar::SEP10.verify_challenge_tx_threshold
55
- # - Stellar::SEP10.verify_challenge_tx_signers
64
+ # that any signatures other than the servers on the transaction are valid.
65
+ # Use either {.verify_challenge_tx_threshold} or {.verify_challenge_tx_signers} to completely verify
66
+ # the signed challenge
67
+ #
68
+ # @example
69
+ # sep10 = Stellar::SEP10
70
+ # server = Stellar::KeyPair.random # this should be the SIGNING_KEY from your stellar.toml
71
+ # challenge = sep10.build_challenge_tx(server: server, client: user, home_domain: domain, timeout: timeout)
72
+ # envelope, client_address = sep10.read_challenge_tx(server: server, challenge: challenge)
56
73
  #
57
74
  # @param challenge_xdr [String] SEP0010 transaction challenge in base64.
58
75
  # @param server [Stellar::KeyPair] keypair for server where the challenge was generated.
59
76
  #
60
- # @return [Stellar::TransactionEnvelope, String]
61
- #
62
- # = Example
63
- #
64
- # sep10 = Stellar::SEP10
65
- # challenge = sep10.build_challenge_tx(server: server, client: user, anchor_name: anchor, timeout: timeout)
66
- # envelope, client_address = sep10.read_challenge_tx(challenge: challenge, server: server)
67
- #
68
- def self.read_challenge_tx(challenge_xdr:, server:)
77
+ # @return [Array(Stellar::TransactionEnvelope, String)]
78
+ def self.read_challenge_tx(server:, challenge_xdr:, **options)
69
79
  envelope = Stellar::TransactionEnvelope.from_xdr(challenge_xdr, "base64")
70
80
  transaction = envelope.tx
71
81
 
72
82
  if transaction.seq_num != 0
73
- raise InvalidSep10ChallengeError.new(
74
- "The transaction sequence number should be zero"
75
- )
83
+ raise InvalidSep10ChallengeError, "The transaction sequence number should be zero"
76
84
  end
77
85
 
78
86
  if transaction.source_account != server.muxed_account
79
- raise InvalidSep10ChallengeError.new(
80
- "The transaction source account is not equal to the server's account"
81
- )
87
+ raise InvalidSep10ChallengeError, "The transaction source account is not equal to the server's account"
82
88
  end
83
89
 
84
- if transaction.operations.size != 1
85
- raise InvalidSep10ChallengeError.new(
86
- "The transaction should contain only one operation"
87
- )
90
+ if transaction.operations.size < 1
91
+ raise InvalidSep10ChallengeError, "The transaction should contain at least one operation"
88
92
  end
89
93
 
90
- operation = transaction.operations.first
91
- client_account_id = operation.source_account
94
+ auth_op, *rest_ops = transaction.operations
95
+ client_account_id = auth_op.source_account
92
96
 
93
97
  if client_account_id.nil?
94
- raise InvalidSep10ChallengeError.new(
95
- "The transaction's operation should contain a source account"
96
- )
98
+ raise InvalidSep10ChallengeError, "The transaction's operation should contain a source account"
97
99
  end
98
100
 
99
- if operation.body.arm != :manage_data_op
100
- raise InvalidSep10ChallengeError.new(
101
- "The transaction's operation should be manageData"
102
- )
101
+ if auth_op.body.arm != :manage_data_op
102
+ raise InvalidSep10ChallengeError, "The transaction's first operation should be manageData"
103
103
  end
104
104
 
105
- if operation.body.value.data_value.unpack1("m").size != 48
106
- raise InvalidSep10ChallengeError.new(
107
- "The transaction's operation value should be a 64 bytes base64 random string"
108
- )
105
+ if auth_op.body.value.data_value.unpack1("m").size != 48
106
+ raise InvalidSep10ChallengeError, "The transaction's operation value should be a 64 bytes base64 random string"
107
+ end
108
+
109
+ rest_ops.each do |op|
110
+ if op.body.arm != :manage_data_op
111
+ raise InvalidSep10ChallengeError, "The transaction has operations that are not of type 'manageData'"
112
+ elsif op.source_account != server.muxed_account
113
+ raise InvalidSep10ChallengeError, "The transaction has operations that are unrecognized"
114
+ end
109
115
  end
110
116
 
111
117
  unless verify_tx_signed_by(tx_envelope: envelope, keypair: server)
112
- raise InvalidSep10ChallengeError.new(
113
- "The transaction is not signed by the server"
114
- )
118
+ raise InvalidSep10ChallengeError, "The transaction is not signed by the server"
115
119
  end
116
120
 
117
121
  time_bounds = transaction.time_bounds
118
122
  now = Time.now.to_i
119
123
 
120
124
  if time_bounds.nil? || !now.between?(time_bounds.min_time, time_bounds.max_time)
121
- raise InvalidSep10ChallengeError.new("The transaction has expired")
125
+ raise InvalidSep10ChallengeError, "The transaction has expired"
122
126
  end
123
127
 
124
128
  # Mirror the return type of the other SDK's and return a string
@@ -127,6 +131,36 @@ module Stellar
127
131
  [envelope, client_kp.address]
128
132
  end
129
133
 
134
+ # Verifies that for a SEP 10 challenge transaction all signatures on the transaction
135
+ # are accounted for and that the signatures meet a threshold on an account. A
136
+ # transaction is verified if it is signed by the server account, and all other
137
+ # signatures match a signer that has been provided as an argument, and those
138
+ # signatures meet a threshold on the account.
139
+ #
140
+ # @param server [Stellar::KeyPair] keypair for server's account.
141
+ # @param challenge_xdr [String] SEP0010 challenge transaction in base64.
142
+ # @param signers [{String => Integer}] The signers of client account.
143
+ # @param threshold [Integer] The medThreshold on the client account.
144
+ #
145
+ # @raise InvalidSep10ChallengeError if the transaction has unrecognized signatures (only server's
146
+ # signing key and keypairs found in the `signing` argument are recognized) or total weight of
147
+ # the signers does not meet the `threshold`
148
+ #
149
+ # @return [<String>] subset of input signers who have signed `challenge_xdr`
150
+ def self.verify_challenge_tx_threshold(server:, challenge_xdr:, signers:, threshold:)
151
+ signers_found = verify_challenge_tx_signers(
152
+ server: server, challenge_xdr: challenge_xdr, signers: signers.keys
153
+ )
154
+
155
+ total_weight = signers.values_at(*signers_found).sum
156
+
157
+ if total_weight < threshold
158
+ raise InvalidSep10ChallengeError, "signers with weight #{total_weight} do not meet threshold #{threshold}."
159
+ end
160
+
161
+ signers_found
162
+ end
163
+
130
164
  # Verifies that for a SEP 10 challenge transaction all signatures on the transaction are accounted for.
131
165
  #
132
166
  # A transaction is verified if it is signed by the server account, and all other signatures match a signer
@@ -135,211 +169,82 @@ module Stellar
135
169
  #
136
170
  # If verification succeeds a list of signers that were found is returned, excluding the server account ID.
137
171
  #
172
+ # @param server [Stellar::Keypair] server's signing key
138
173
  # @param challenge_xdr [String] SEP0010 transaction challenge transaction in base64.
139
- # @param server [Stellar::Keypair] keypair for server's account.
140
- # @param signers [SetOf[String]] The signers of client account.
174
+ # @param signers [<String>] The signers of client account.
141
175
  #
142
- # @return [SetOf[String]]
176
+ # @raise InvalidSep10ChallengeError one or more signatures in the transaction are not identifiable
177
+ # as the server account or one of the signers provided in the arguments
143
178
  #
144
- # Raises a InvalidSep10ChallengeError if:
145
- # - The transaction is invalid according to Stellar::SEP10.read_challenge_tx.
146
- # - One or more signatures in the transaction are not identifiable as the server account or one of the
147
- # signers provided in the arguments.
148
- def self.verify_challenge_tx_signers(
149
- challenge_xdr:,
150
- server:,
151
- signers:
152
- )
153
- if signers.empty?
154
- raise InvalidSep10ChallengeError.new("No signers provided.")
155
- end
179
+ # @return [<String>] subset of input signers who have signed `challenge_xdr`
180
+ def self.verify_challenge_tx_signers(server:, challenge_xdr:, signers:)
181
+ raise InvalidSep10ChallengeError, "no signers provided" if signers.empty?
156
182
 
157
- te, _ = read_challenge_tx(
158
- challenge_xdr: challenge_xdr, server: server
159
- )
183
+ te, _ = read_challenge_tx(server: server, challenge_xdr: challenge_xdr)
160
184
 
161
- # deduplicate signers and ignore non-G addresses
162
- client_signers = Set.new
163
- signers.each do |signer|
164
- # ignore server kp if passed
165
- if signer == server.address
166
- next
167
- end
168
- begin
169
- Stellar::Util::StrKey.check_decode(:account_id, signer)
170
- rescue
171
- next
172
- else
173
- client_signers.add(signer)
174
- end
175
- end
176
-
177
- if client_signers.empty?
178
- raise InvalidSep10ChallengeError.new("At least one signer with a G... address must be provied")
179
- end
185
+ # ignore non-G signers and server's own address
186
+ client_signers = signers.select { |s| s =~ /G[A-Z0-9]{55}/ && s != server.address }.to_set
187
+ raise InvalidSep10ChallengeError, "at least one regular signer must be provided" if client_signers.empty?
180
188
 
181
189
  # verify all signatures in one pass
182
- all_signers = client_signers + Set[server.address]
183
- signers_found = verify_tx_signatures(
184
- tx_envelope: te, signers: all_signers
185
- )
190
+ client_signers.add(server.address)
191
+ signers_found = verify_tx_signatures(tx_envelope: te, signers: client_signers)
186
192
 
187
193
  # ensure server signed transaction and remove it
188
194
  unless signers_found.delete?(server.address)
189
- raise InvalidSep10ChallengeError.new("Transaction not signed by server: #{server.address}")
195
+ raise InvalidSep10ChallengeError, "Transaction not signed by server: #{server.address}"
190
196
  end
191
197
 
192
198
  # Confirm we matched signatures to the client signers.
193
199
  if signers_found.empty?
194
- raise InvalidSep10ChallengeError.new("Transaction not signed by any client signer.")
200
+ raise InvalidSep10ChallengeError, "Transaction not signed by any client signer."
195
201
  end
196
202
 
197
203
  # Confirm all signatures were consumed by a signer.
198
- if signers_found.length != te.signatures.length - 1
199
- raise InvalidSep10ChallengeError.new("Transaction has unrecognized signatures.")
200
- end
201
-
202
- signers_found
203
- end
204
-
205
- # Verifies that for a SEP 10 challenge transaction all signatures on the transaction
206
- # are accounted for and that the signatures meet a threshold on an account. A
207
- # transaction is verified if it is signed by the server account, and all other
208
- # signatures match a signer that has been provided as an argument, and those
209
- # signatures meet a threshold on the account.
210
- #
211
- # @param challenge_xdr [String] SEP0010 transaction challenge transaction in base64.
212
- # @param server [Stellar::KeyPair] keypair for server's account.
213
- # @param threshold [Integer] The medThreshold on the client account.
214
- # @param signers [SetOf[::Hash]]The signers of client account.
215
- #
216
- # @return [SetOf[::Hash]]
217
- #
218
- # Raises a InvalidSep10ChallengeError if:
219
- # - The transaction is invalid according to Stellar::SEP10.read_challenge_transaction.
220
- # - One or more signatures in the transaction are not identifiable as the server
221
- # account or one of the signers provided in the arguments.
222
- # - The signatures are all valid but do not meet the threshold.
223
- def self.verify_challenge_tx_threshold(
224
- challenge_xdr:,
225
- server:,
226
- threshold:,
227
- signers:
228
- )
229
- signer_str_set = signers.map { |s| s["key"] }.to_set
230
- signer_strs_found = verify_challenge_tx_signers(
231
- challenge_xdr: challenge_xdr,
232
- server: server,
233
- signers: signer_str_set
234
- )
235
-
236
- weight = 0
237
- signers_found = Set.new
238
- signers.each do |s|
239
- unless signer_strs_found.include?(s["key"])
240
- next
241
- end
242
- signer_strs_found.delete(s["key"])
243
- signers_found.add(s)
244
- weight += s["weight"]
245
- end
246
-
247
- if weight < threshold
248
- raise InvalidSep10ChallengeError.new(
249
- "signers with weight #{weight} do not meet threshold #{threshold}."
250
- )
204
+ if signers_found.size != te.signatures.length - 1
205
+ raise InvalidSep10ChallengeError, "Transaction has unrecognized signatures."
251
206
  end
252
207
 
253
208
  signers_found
254
209
  end
255
210
 
256
- # DEPRECATED: Use verify_challenge_tx_signers instead.
257
- # This function does not support multiple client signatures.
258
- #
259
- # Verifies if a transaction is a valid per SEP-10 challenge transaction, if the validation
260
- # fails, an exception will be thrown.
261
- #
262
- # This function performs the following checks:
263
- # 1. verify that transaction sequenceNumber is equal to zero;
264
- # 2. verify that transaction source account is equal to the server's signing key;
265
- # 3. verify that transaction has time bounds set, and that current time is between the minimum and maximum bounds;
266
- # 4. verify that transaction contains a single Manage Data operation and it's source account is not null;
267
- # 5. verify that transaction envelope has a correct signature by server's signing key;
268
- # 6. verify that transaction envelope has a correct signature by the operation's source account;
269
- #
270
- # @param challenge_xdr [String] SEP0010 transaction challenge transaction in base64.
271
- # @param server [Stellar::KeyPair] keypair for server's account.
272
- #
273
- # Raises a InvalidSep10ChallengeError if the validation fails
274
- def self.verify_challenge_tx(
275
- challenge_xdr: String, server: Stellar::KeyPair
276
- )
277
- transaction_envelope, client_address = read_challenge_tx(
278
- challenge_xdr: challenge_xdr, server: server
279
- )
280
- client_keypair = Stellar::KeyPair.from_address(client_address)
281
- unless verify_tx_signed_by(tx_envelope: transaction_envelope, keypair: client_keypair)
282
- raise InvalidSep10ChallengeError.new(
283
- "Transaction not signed by client: %s" % [client_keypair.address]
284
- )
285
- end
286
- end
287
-
288
211
  # Verifies every signer passed matches a signature on the transaction exactly once,
289
212
  # returning a list of unique signers that were found to have signed the transaction.
290
213
  #
291
214
  # @param tx_envelope [Stellar::TransactionEnvelope] SEP0010 transaction challenge transaction envelope.
292
- # @param signers [SetOf[String]] The signers of client account.
215
+ # @param signers [<String>] The signers of client account.
293
216
  #
294
- # @return [SetOf[String]]
295
- def self.verify_tx_signatures(
296
- tx_envelope:,
297
- signers:
298
- )
217
+ # @return [Set<Stellar::KeyPair>]
218
+ def self.verify_tx_signatures(tx_envelope:, signers:)
299
219
  signatures = tx_envelope.signatures
300
220
  if signatures.empty?
301
- raise InvalidSep10ChallengeError.new("Transaction has no signatures.")
221
+ raise InvalidSep10ChallengeError, "Transaction has no signatures."
302
222
  end
303
223
 
304
224
  tx_hash = tx_envelope.tx.hash
305
- signatures_used = Set.new
306
- signers_found = Set.new
307
- signers.each do |signer|
308
- kp = Stellar::KeyPair.from_address(signer)
309
- tx_envelope.signatures.each_with_index do |sig, i|
310
- if signatures_used.include?(i)
311
- next
312
- end
313
- if sig.hint != kp.signature_hint
314
- next
315
- end
316
- if kp.verify(sig.signature, tx_hash)
317
- signatures_used.add(i)
318
- signers_found.add(signer)
319
- end
320
- end
321
- end
225
+ to_keypair = Stellar::DSL.method(:KeyPair)
226
+ keys_by_hint = signers.map(&to_keypair).index_by(&:signature_hint)
322
227
 
323
- signers_found
228
+ tx_envelope.signatures.each.with_object(Set.new) do |sig, result|
229
+ key = keys_by_hint.delete(sig.hint)
230
+ result.add(key.address) if key&.verify(sig.signature, tx_hash)
231
+ end
324
232
  end
325
233
 
326
234
  # Verifies if a Stellar::TransactionEnvelope was signed by the given Stellar::KeyPair
327
235
  #
236
+ # @example
237
+ # Stellar::SEP10.verify_tx_signed_by(tx_envelope: envelope, keypair: keypair)
238
+ #
328
239
  # @param tx_envelope [Stellar::TransactionEnvelope]
329
240
  # @param keypair [Stellar::KeyPair]
330
241
  #
331
242
  # @return [Boolean]
332
- #
333
- # = Example
334
- #
335
- # Stellar::SEP10.verify_tx_signed_by(tx_envelope: envelope, keypair: keypair)
336
- #
337
243
  def self.verify_tx_signed_by(tx_envelope:, keypair:)
338
244
  tx_hash = tx_envelope.tx.hash
339
245
  tx_envelope.signatures.any? do |sig|
340
- if sig.hint != keypair.signature_hint
341
- next
342
- end
246
+ next if sig.hint != keypair.signature_hint
247
+
343
248
  keypair.verify(sig.signature, tx_hash)
344
249
  end
345
250
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stellar-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.24.0
4
+ version: 0.25.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Fleckenstein
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2020-10-20 00:00:00.000000000 Z
13
+ date: 2020-10-30 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: stellar-base
@@ -18,14 +18,14 @@ dependencies:
18
18
  requirements:
19
19
  - - '='
20
20
  - !ruby/object:Gem::Version
21
- version: 0.24.0
21
+ version: 0.25.0
22
22
  type: :runtime
23
23
  prerelease: false
24
24
  version_requirements: !ruby/object:Gem::Requirement
25
25
  requirements:
26
26
  - - '='
27
27
  - !ruby/object:Gem::Version
28
- version: 0.24.0
28
+ version: 0.25.0
29
29
  - !ruby/object:Gem::Dependency
30
30
  name: activesupport
31
31
  requirement: !ruby/object:Gem::Requirement
@@ -172,9 +172,10 @@ homepage: https://github.com/stellar/ruby-stellar-sdk/tree/master/sdk
172
172
  licenses:
173
173
  - Apache-2.0
174
174
  metadata:
175
- documentation_uri: https://rubydoc.info/gems/stellar-sdk/0.24.0/
176
- changelog_uri: https://github.com/astroband/ruby-stellar-sdk/blob/v0.24.0/sdk/CHANGELOG.md
177
- source_code_uri: https://github.com/astroband/ruby-stellar-sdk/tree/v0.24.0/sdk
175
+ github_repo: ssh://github.com/astroband/ruby-stellar-sdk
176
+ documentation_uri: https://rubydoc.info/gems/stellar-sdk/0.25.0/
177
+ changelog_uri: https://github.com/astroband/ruby-stellar-sdk/blob/v0.25.0/sdk/CHANGELOG.md
178
+ source_code_uri: https://github.com/astroband/ruby-stellar-sdk/tree/v0.25.0/sdk
178
179
  post_install_message:
179
180
  rdoc_options: []
180
181
  require_paths: