stellar-sdk 0.24.0 → 0.25.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 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: