stellar-sdk 0.23.0.rc2 → 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: 0d8a8fa97989972efbe53dd536b329596c7f0eaa9769aff84ceb86f3f70c0f69
4
- data.tar.gz: 4d8e9eae54618c12ba827b62e8243a28cbe1c1dfe3b60e14b2e26394266a560b
3
+ metadata.gz: 14f9e7a13e44b5eb83bce5faee3918a49c03cfd9d36f00b49cdec501131702bc
4
+ data.tar.gz: cbf8145d6a546359ba66f74bc868cc1f5c6bf82a0e1c077d6073ef242f3989ef
5
5
  SHA512:
6
- metadata.gz: 4952c1aea1709d96d2933e9aeae95afd094c7708a95c450c385ab39cfa7ac96c725a78d9579c424d6cddc7ffad95260c2e75b2535504ee4e0031c41721b7235e
7
- data.tar.gz: 8d3e8c2f10c959c4c52c3e26a61f61f7580bc3a93797b4ac8a976c0951133a79b60bbc6b07e9eabd5383cac2d11b62e67066163c9eda0ecaa580417a7056d6c3
6
+ metadata.gz: a1a999329ba74c3a0448c59c4d249c4fecdc1b0961dbc82ba985f8b3fb792b993825a1eabd2df8918566ac1b7f1ca847572a381d61c0194aa8f48cc50fdea6e4
7
+ data.tar.gz: b4c7f193cd7fef55798e4788476e30898c2b8517981ad4d05da2c9ac7a1ab4758e5287700cd017b1c62cd97e995b6f645dc15ef9cff22d0cc061aeb85375dfe7
@@ -4,12 +4,34 @@ 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](https://github.com/stellar/ruby-stellar-sdk/compare/v0.25.0...master)
8
+
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
23
+ - Fix SEP10, considering muxed accounts
24
+
25
+ ## [0.23.0](https://github.com/stellar/ruby-stellar-sdk/compare/v0.9.0...v0.23.0)
26
+ - No changes. We bumped this version to sync `stellar-sdk` and `stellar-base` versions
27
+
7
28
  ## [0.9.0](https://github.com/stellar/ruby-stellar-sdk/compare/v0.9.0...v0.8.0)
8
29
  ### Added
9
30
  - Stellar Protocol 13 support
10
31
  - Fee-Bump transactions ([CAP-0015](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0015.md))
11
32
  - Multiplexed accounts ([CAP-0027](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0027.md))
12
33
  - Fine-Grained control on trustline authorization ([CAP-0018](https://github.com/stellar/stellar-protocol/blob/master/core/cap-0018.md))
34
+
13
35
  ## [0.8.0](https://github.com/stellar/ruby-stellar-sdk/compare/v0.7.0...v0.8.0)
14
36
  ### Added
15
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
 
@@ -11,14 +11,11 @@ Add this lines to your application's Gemfile:
11
11
 
12
12
  ```ruby
13
13
  gem 'stellar-sdk'
14
- gem 'xdr', git: 'https://github.com/stellar/ruby-xdr.git', tag: 'v3.0.1'
15
14
  ```
16
15
 
17
16
  And then execute:
18
17
 
19
18
  $ bundle
20
-
21
- **Note** we need to add such explicit `xdr` dependency, because version 3.0.1 is not on RubyGems yet. When it's published, you can remove this line
22
19
 
23
20
  Also requires libsodium. Installable via `brew install libsodium` on OS X.
24
21
 
@@ -39,7 +36,7 @@ client.send_payment({
39
36
  from: account,
40
37
  to: recipient,
41
38
  amount: Stellar::Amount.new(100_000_000)
42
- })
39
+ })
43
40
  ```
44
41
 
45
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
  require "stellar-base"
2
- require_relative "./stellar/version"
2
+ require_relative "stellar/sdk/version"
3
3
 
4
4
  module Stellar
5
5
  autoload :Account
@@ -66,6 +66,10 @@ module Stellar
66
66
  def initialize(keypair)
67
67
  @keypair = keypair
68
68
  end
69
+
70
+ def to_keypair
71
+ keypair
72
+ end
69
73
  end
70
74
 
71
75
  class AccountNotFound < StandardError
@@ -78,12 +78,11 @@ module Stellar
78
78
  destination = options[:destination]
79
79
  sequence = options[:sequence] || (account_info(account).sequence.to_i + 1)
80
80
 
81
- transaction = Stellar::TransactionBuilder.new(
81
+ transaction = Stellar::TransactionBuilder.account_merge(
82
82
  source_account: destination.keypair,
83
- sequence_number: sequence
84
- ).add_operation(
85
- Stellar::Operation.account_merge(destination: destination.keypair)
86
- ).set_timeout(0).build
83
+ sequence_number: sequence,
84
+ destination: destination.keypair
85
+ )
87
86
 
88
87
  envelope = transaction.to_envelope(account.keypair)
89
88
  submit_transaction(tx_envelope: envelope)
@@ -105,17 +104,13 @@ module Stellar
105
104
  # instead of using a hard-coded default value.
106
105
  fee = options[:fee] || DEFAULT_FEE
107
106
 
108
- payment = Stellar::TransactionBuilder.new(
107
+ payment = Stellar::TransactionBuilder.create_account(
109
108
  source_account: funder.keypair,
110
109
  sequence_number: sequence,
111
- base_fee: fee
112
- ).add_operation(
113
- Stellar::Operation.create_account({
114
- destination: options[:account].keypair,
115
- starting_balance: options[:starting_balance]
116
- })
117
- ).set_timeout(0).build
118
-
110
+ base_fee: fee,
111
+ destination: options[:account].keypair,
112
+ starting_balance: options[:starting_balance]
113
+ )
119
114
  envelope = payment.to_envelope(funder.keypair)
120
115
  submit_transaction(tx_envelope: envelope)
121
116
  end
@@ -180,14 +175,18 @@ module Stellar
180
175
  )
181
176
  sequence ||= (account_info(source).sequence.to_i + 1)
182
177
 
183
- args = {
178
+ op_args = {
184
179
  account: source.keypair,
185
180
  sequence: sequence,
186
181
  line: asset
187
182
  }
188
- args[:limit] = limit unless limit.nil?
183
+ op_args[:limit] = limit unless limit.nil?
189
184
 
190
- tx = Stellar::Transaction.change_trust(args)
185
+ tx = Stellar::TransactionBuilder.change_trust(
186
+ source_account: source.keypair,
187
+ sequence_number: sequence,
188
+ **op_args
189
+ )
191
190
 
192
191
  envelope = tx.to_envelope(source.keypair)
193
192
  submit_transaction(tx_envelope: envelope)
@@ -0,0 +1,5 @@
1
+ module Stellar
2
+ module SDK
3
+ VERSION = "0.25.0"
4
+ end
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
- if transaction.source_account != server.raw_public_key
79
- raise InvalidSep10ChallengeError.new(
80
- "The transaction source account is not equal to the server's account"
81
- )
86
+ if transaction.source_account != server.muxed_account
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,14 +1,16 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stellar-sdk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.0.rc2
4
+ version: 0.25.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Scott Fleckenstein
8
+ - Sergey Nebolsin
9
+ - Timur Ramazanov
8
10
  autorequire:
9
- bindir: bin
11
+ bindir: exe
10
12
  cert_chain: []
11
- date: 2020-06-10 00:00:00.000000000 Z
13
+ date: 2020-10-30 00:00:00.000000000 Z
12
14
  dependencies:
13
15
  - !ruby/object:Gem::Dependency
14
16
  name: stellar-base
@@ -16,82 +18,144 @@ dependencies:
16
18
  requirements:
17
19
  - - '='
18
20
  - !ruby/object:Gem::Version
19
- version: 0.23.0.rc2
21
+ version: 0.25.0
20
22
  type: :runtime
21
23
  prerelease: false
22
24
  version_requirements: !ruby/object:Gem::Requirement
23
25
  requirements:
24
26
  - - '='
25
27
  - !ruby/object:Gem::Version
26
- version: 0.23.0.rc2
28
+ version: 0.25.0
27
29
  - !ruby/object:Gem::Dependency
28
- name: hyperclient
30
+ name: activesupport
29
31
  requirement: !ruby/object:Gem::Requirement
30
32
  requirements:
31
- - - "~>"
33
+ - - ">="
32
34
  - !ruby/object:Gem::Version
33
- version: '0.7'
35
+ version: 5.0.0
36
+ - - "<"
37
+ - !ruby/object:Gem::Version
38
+ version: '7.0'
34
39
  type: :runtime
35
40
  prerelease: false
36
41
  version_requirements: !ruby/object:Gem::Requirement
37
42
  requirements:
38
- - - "~>"
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: 5.0.0
46
+ - - "<"
39
47
  - !ruby/object:Gem::Version
40
- version: '0.7'
48
+ version: '7.0'
41
49
  - !ruby/object:Gem::Dependency
42
50
  name: excon
43
51
  requirement: !ruby/object:Gem::Requirement
44
52
  requirements:
45
- - - "~>"
53
+ - - ">="
46
54
  - !ruby/object:Gem::Version
47
- version: '0.71'
55
+ version: 0.71.0
56
+ - - "<"
57
+ - !ruby/object:Gem::Version
58
+ version: '1.0'
48
59
  type: :runtime
49
60
  prerelease: false
50
61
  version_requirements: !ruby/object:Gem::Requirement
51
62
  requirements:
52
- - - "~>"
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: 0.71.0
66
+ - - "<"
53
67
  - !ruby/object:Gem::Version
54
- version: '0.71'
68
+ version: '1.0'
55
69
  - !ruby/object:Gem::Dependency
56
- name: activesupport
70
+ name: hyperclient
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - ">="
60
74
  - !ruby/object:Gem::Version
61
- version: '5.0'
75
+ version: 0.7.0
76
+ - - "<"
77
+ - !ruby/object:Gem::Version
78
+ version: '1.0'
62
79
  type: :runtime
63
80
  prerelease: false
64
81
  version_requirements: !ruby/object:Gem::Requirement
65
82
  requirements:
66
83
  - - ">="
67
84
  - !ruby/object:Gem::Version
68
- version: '5.0'
85
+ version: 0.7.0
86
+ - - "<"
87
+ - !ruby/object:Gem::Version
88
+ version: '1.0'
69
89
  - !ruby/object:Gem::Dependency
70
90
  name: toml-rb
71
91
  requirement: !ruby/object:Gem::Requirement
72
92
  requirements:
73
- - - "~>"
74
- - !ruby/object:Gem::Version
75
- version: '1.1'
76
93
  - - ">="
77
94
  - !ruby/object:Gem::Version
78
95
  version: 1.1.1
96
+ - - "<"
97
+ - !ruby/object:Gem::Version
98
+ version: '3.0'
79
99
  type: :runtime
80
100
  prerelease: false
81
101
  version_requirements: !ruby/object:Gem::Requirement
82
102
  requirements:
83
- - - "~>"
84
- - !ruby/object:Gem::Version
85
- version: '1.1'
86
103
  - - ">="
87
104
  - !ruby/object:Gem::Version
88
105
  version: 1.1.1
106
+ - - "<"
107
+ - !ruby/object:Gem::Version
108
+ version: '3.0'
109
+ - !ruby/object:Gem::Dependency
110
+ name: bundler
111
+ requirement: !ruby/object:Gem::Requirement
112
+ requirements:
113
+ - - "~>"
114
+ - !ruby/object:Gem::Version
115
+ version: '2.0'
116
+ type: :development
117
+ prerelease: false
118
+ version_requirements: !ruby/object:Gem::Requirement
119
+ requirements:
120
+ - - "~>"
121
+ - !ruby/object:Gem::Version
122
+ version: '2.0'
123
+ - !ruby/object:Gem::Dependency
124
+ name: rake
125
+ requirement: !ruby/object:Gem::Requirement
126
+ requirements:
127
+ - - "~>"
128
+ - !ruby/object:Gem::Version
129
+ version: '13'
130
+ type: :development
131
+ prerelease: false
132
+ version_requirements: !ruby/object:Gem::Requirement
133
+ requirements:
134
+ - - "~>"
135
+ - !ruby/object:Gem::Version
136
+ version: '13'
137
+ - !ruby/object:Gem::Dependency
138
+ name: rspec
139
+ requirement: !ruby/object:Gem::Requirement
140
+ requirements:
141
+ - - "~>"
142
+ - !ruby/object:Gem::Version
143
+ version: '3.9'
144
+ type: :development
145
+ prerelease: false
146
+ version_requirements: !ruby/object:Gem::Requirement
147
+ requirements:
148
+ - - "~>"
149
+ - !ruby/object:Gem::Version
150
+ version: '3.9'
89
151
  description:
90
152
  email:
91
- - scott@stellar.org
92
153
  executables: []
93
154
  extensions: []
94
- extra_rdoc_files: []
155
+ extra_rdoc_files:
156
+ - README.md
157
+ - LICENSE
158
+ - CHANGELOG.md
95
159
  files:
96
160
  - CHANGELOG.md
97
161
  - LICENSE
@@ -101,13 +165,17 @@ files:
101
165
  - lib/stellar/amount.rb
102
166
  - lib/stellar/client.rb
103
167
  - lib/stellar/horizon/problem.rb
168
+ - lib/stellar/sdk/version.rb
104
169
  - lib/stellar/sep10.rb
105
170
  - lib/stellar/transaction_page.rb
106
- - lib/stellar/version.rb
107
- homepage: http://github.com/stellar/ruby-stellar-sdk
171
+ homepage: https://github.com/stellar/ruby-stellar-sdk/tree/master/sdk
108
172
  licenses:
109
173
  - Apache-2.0
110
- metadata: {}
174
+ metadata:
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
111
179
  post_install_message:
112
180
  rdoc_options: []
113
181
  require_paths:
@@ -116,14 +184,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
116
184
  requirements:
117
185
  - - ">="
118
186
  - !ruby/object:Gem::Version
119
- version: '0'
187
+ version: 2.5.0
120
188
  required_rubygems_version: !ruby/object:Gem::Requirement
121
189
  requirements:
122
- - - ">"
190
+ - - ">="
123
191
  - !ruby/object:Gem::Version
124
- version: 1.3.1
192
+ version: '0'
125
193
  requirements: []
126
- rubygems_version: 3.1.4
194
+ rubygems_version: 3.2.0.rc.2
127
195
  signing_key:
128
196
  specification_version: 4
129
197
  summary: Stellar client library
@@ -1,3 +0,0 @@
1
- module Stellar
2
- VERSION = "0.23.0.rc2"
3
- end