stellar-sdk 0.8.0 → 0.9.0.pre2

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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/{LICENSE.txt → LICENSE} +0 -0
  3. data/README.md +4 -5
  4. data/lib/stellar-sdk.rb +2 -3
  5. data/lib/stellar/account.rb +16 -18
  6. data/lib/stellar/amount.rb +9 -13
  7. data/lib/stellar/client.rb +153 -113
  8. data/lib/stellar/horizon/problem.rb +14 -16
  9. data/lib/stellar/sep10.rb +56 -93
  10. data/lib/stellar/transaction_page.rb +4 -6
  11. data/lib/stellar/version.rb +1 -1
  12. metadata +13 -217
  13. data/.github/CODEOWNERS +0 -2
  14. data/.gitignore +0 -17
  15. data/.travis.yml +0 -20
  16. data/.yardopts +0 -7
  17. data/CONTRIBUTING.md +0 -48
  18. data/Gemfile +0 -14
  19. data/Guardfile +0 -5
  20. data/Rakefile +0 -3
  21. data/examples/01_get_funded.rb +0 -37
  22. data/examples/02_payment.rb +0 -15
  23. data/examples/03_transaction_history.rb +0 -21
  24. data/examples/04_setting_trust.rb +0 -1
  25. data/examples/05_fiat_payment.rb +0 -13
  26. data/examples/06_fund_testnet_friendbot.rb +0 -15
  27. data/examples/07_sep10.rb +0 -125
  28. data/ruby-stellar-sdk.gemspec +0 -35
  29. data/spec/config.yml.sample +0 -12
  30. data/spec/fixtures/vcr_cassettes/Stellar_Account/_lookup/should_handle_404_request_when_performing_federation_lookup.yml +0 -133
  31. data/spec/fixtures/vcr_cassettes/Stellar_Account/_lookup/should_handle_domains_that_are_not_federation_servers.yml +0 -44
  32. data/spec/fixtures/vcr_cassettes/Stellar_Account/_lookup/should_peforms_federation_lookup.yml +0 -85
  33. data/spec/fixtures/vcr_cassettes/Stellar_Client/_account_info/returns_the_current_details_for_the_account.yml +0 -190
  34. data/spec/fixtures/vcr_cassettes/Stellar_Client/_account_merge/merges_source_account_into_destination.yml +0 -714
  35. data/spec/fixtures/vcr_cassettes/Stellar_Client/_change_trust/given_an_asset_described_as_an_array/creates_updates_or_deletes_a_trustline.yml +0 -1156
  36. data/spec/fixtures/vcr_cassettes/Stellar_Client/_create_account/creates_the_account.yml +0 -323
  37. data/spec/fixtures/vcr_cassettes/Stellar_Client/_friendbot/requests_for_XLM_from_a_friendbot.yml +0 -246
  38. data/spec/fixtures/vcr_cassettes/Stellar_Client/_load_account/loads_successfully.yml +0 -226
  39. data/spec/fixtures/vcr_cassettes/Stellar_Client/_send_payment/alphanum12_asset/sends_a_alphanum12_asset_to_the_destination.yml +0 -747
  40. data/spec/fixtures/vcr_cassettes/Stellar_Client/_send_payment/alphanum4_asset/sends_a_alphanum4_asset_to_the_destination.yml +0 -747
  41. data/spec/fixtures/vcr_cassettes/Stellar_Client/_send_payment/memo/accepts_the_memo_attribute.yml +0 -725
  42. data/spec/fixtures/vcr_cassettes/Stellar_Client/_send_payment/native_asset/sends_a_native_payment_to_the_account.yml +0 -562
  43. data/spec/fixtures/vcr_cassettes/Stellar_Client/_send_payment/using_a_payment_channel/sends_a_payment_account_through_a_channel_account.yml +0 -757
  44. data/spec/fixtures/vcr_cassettes/Stellar_Client/_send_payment/using_a_payment_channel/sends_a_payment_when_the_channel_is_the_same_as_from_.yml +0 -642
  45. data/spec/fixtures/vcr_cassettes/Stellar_Client/_transactions/account_transactions/accepts_a_cursor_to_return_less_data.yml +0 -94
  46. data/spec/fixtures/vcr_cassettes/Stellar_Client/_transactions/account_transactions/returns_a_list_of_transaction_for_an_account.yml +0 -94
  47. data/spec/fixtures/vcr_cassettes/Stellar_Client/_transactions/all_transactions/accepts_a_cursor_to_return_less_data.yml +0 -94
  48. data/spec/fixtures/vcr_cassettes/Stellar_Client/_transactions/all_transactions/returns_a_list_of_transactions.yml +0 -94
  49. data/spec/lib/stellar/account_spec.rb +0 -59
  50. data/spec/lib/stellar/amount_spec.rb +0 -70
  51. data/spec/lib/stellar/client_spec.rb +0 -430
  52. data/spec/lib/stellar/sep10_spec.rb +0 -1148
  53. data/spec/spec_helper.rb +0 -14
  54. data/spec/support/config.rb +0 -3
  55. data/spec/support/vcr.rb +0 -10
  56. data/tasks/rspec.rake +0 -6
  57. data/tasks/travis.rake +0 -1
@@ -1,430 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Stellar::Client do
4
-
5
- subject(:client) { Stellar::Client.default_testnet }
6
-
7
- describe "headers" do
8
- let(:headers) { client.horizon.headers }
9
-
10
- it "has 'Accept'" do
11
- expect(headers["Accept"]).
12
- to eq "application/hal+json,application/problem+json,application/json"
13
- end
14
-
15
- it "has 'X-Client-Name'" do
16
- expect(headers["X-Client-Name"]).to eq "ruby-stellar-sdk"
17
- end
18
-
19
- it "has 'X-Client-Version'" do
20
- expect(headers["X-Client-Version"]).to eq Stellar::VERSION
21
- end
22
- end
23
-
24
- describe "#default_testnet" do
25
- it 'instantiates a client pointing to horizon testnet' do
26
- client = described_class.default_testnet
27
- expect(client.horizon._url).to eq(described_class::HORIZON_TESTNET_URL)
28
- end
29
- end
30
-
31
- describe "#default" do
32
- it 'instantiates a client pointing to horizon mainnet' do
33
- client = described_class.default
34
- expect(client.horizon._url).to eq(described_class::HORIZON_MAINNET_URL)
35
- end
36
- end
37
-
38
- describe "#localhost" do
39
- it 'instantiates a client pointing to localhost horizon' do
40
- client = described_class.localhost
41
- expect(client.horizon._url).to eq(described_class::HORIZON_LOCALHOST_URL)
42
- end
43
- end
44
-
45
- describe "#initialize" do
46
- let(:custom_horizon_url) { 'https://horizon.domain.com' }
47
- it 'instantiates a client accepting custom options' do
48
- client = described_class.new(horizon: custom_horizon_url)
49
- expect(client.horizon._url).to eq(custom_horizon_url)
50
- end
51
- end
52
-
53
- describe "#friendbot" do
54
- let(:client) { Stellar::Client.default_testnet }
55
- let(:account) { Stellar::Account.random }
56
-
57
- it("requests for XLM from a friendbot", {
58
- vcr: {record: :once, match_requests_on: [:method]}
59
- }) do
60
- response = client.friendbot(account)
61
-
62
- expect(response).to be_success
63
-
64
- destination_info = client.account_info(account)
65
- balances = destination_info.balances
66
- expect(balances).to_not be_empty
67
- native_asset_balance_info = balances.find do |b|
68
- b["asset_type"] == "native"
69
- end
70
- expect(native_asset_balance_info["balance"].to_f).to be > 0
71
- end
72
- end
73
-
74
- describe "#create_account" do
75
- let(:source) { Stellar::Account.from_seed(CONFIG[:source_seed]) }
76
- let(:destination) { Stellar::Account.random }
77
-
78
- it "creates the account", vcr: {record: :once, match_requests_on: [:method]} do
79
- client.create_account(
80
- funder: source,
81
- account: destination,
82
- starting_balance: 100,
83
- )
84
-
85
- destination_info = client.account_info(destination)
86
- balances = destination_info.balances
87
- expect(balances).to_not be_empty
88
- native_asset_balance_info = balances.find do |b|
89
- b["asset_type"] == "native"
90
- end
91
- expect(native_asset_balance_info["balance"].to_f).to eq 100.0
92
- end
93
- end
94
-
95
- describe "#account_info" do
96
- let(:account) { Stellar::Account.from_seed(CONFIG[:source_seed]) }
97
- let(:client) { Stellar::Client.default_testnet }
98
-
99
- it "returns the current details for the account", vcr: { record: :once, match_requests_on: [:method]} do
100
- response = client.account_info(account)
101
-
102
- expect(response.id).to eq CONFIG[:source_address]
103
- expect(response.paging_token).to be_empty
104
- expect(response.sequence).to eq "346973227974715"
105
- expect(response.subentry_count).to eq 0
106
- expect(response.thresholds).to include("low_threshold" => 0, "med_threshold" => 0, "high_threshold" => 0)
107
- expect(response.flags).to include("auth_required" => false, "auth_revocable" => false)
108
- expect(response.balances).to include("balance" => "3494.9997500", "asset_type" => "native")
109
- expect(response.signers).to include(
110
- "public_key" => CONFIG[:source_address],
111
- "weight" => 1,
112
- "type" => "ed25519_public_key",
113
- "key" => CONFIG[:source_address]
114
- )
115
- expect(response.data).to be_empty
116
- end
117
- end
118
-
119
- describe "#account_merge" do
120
- let(:funder) { Stellar::Account.from_seed(CONFIG[:source_seed]) }
121
- let(:client) { Stellar::Client.default_testnet }
122
- let(:source) { Stellar::Account.random }
123
- let(:destination) { Stellar::Account.random }
124
-
125
- it "merges source account into destination", vcr: { record: :once, match_requests_on: [:method]} do
126
- [source, destination].each do |account|
127
- account = client.create_account(
128
- funder: funder,
129
- account: account,
130
- starting_balance: 100,
131
- )
132
- end
133
-
134
- client.account_merge(
135
- account: source,
136
- destination: destination
137
- )
138
-
139
- destination_info = client.account_info(destination)
140
- native_asset_balance_info = destination_info.balances.find do |b|
141
- b["asset_type"] == "native"
142
- end
143
- # balance of merged account is the balance of both accounts minus transaction fee for merge
144
- expect(native_asset_balance_info["balance"].to_f).to eq 199.99999
145
- end
146
- end
147
-
148
- describe "#send_payment" do
149
- let(:source) { Stellar::Account.from_seed(CONFIG[:source_seed]) }
150
-
151
- context "native asset" do
152
- let(:destination) { Stellar::Account.random }
153
-
154
- it "sends a native payment to the account", vcr: {record: :once, match_requests_on: [:method]} do
155
- client.create_account(
156
- funder: source,
157
- account: destination,
158
- starting_balance: 100,
159
- )
160
-
161
- amount = Stellar::Amount.new(150)
162
-
163
- client.send_payment(
164
- from: source,
165
- to: destination,
166
- amount: amount,
167
- )
168
-
169
- destination_info = client.account_info(destination)
170
- balances = destination_info.balances
171
- expect(balances).to_not be_empty
172
- native_asset_balance_info = balances.find do |b|
173
- b["asset_type"] == "native"
174
- end
175
- expect(native_asset_balance_info["balance"].to_f).to eq 250.0
176
- end
177
- end
178
-
179
- context "alphanum4 asset" do
180
- let(:issuer) { Stellar::Account.from_seed(CONFIG[:source_seed]) }
181
- let(:destination) { Stellar::Account.random }
182
-
183
- it("sends a alphanum4 asset to the destination", {
184
- vcr: {record: :once, match_requests_on: [:method]},
185
- }) do
186
- client.create_account(
187
- funder: issuer,
188
- account: destination,
189
- starting_balance: 2,
190
- )
191
-
192
- client.change_trust(
193
- asset: [:alphanum4, "BTC", issuer.keypair],
194
- source: destination,
195
- )
196
-
197
- asset = Stellar::Asset.alphanum4("BTC", source.keypair)
198
- amount = Stellar::Amount.new(150, asset)
199
- client.send_payment(
200
- from: source,
201
- to: destination,
202
- amount: amount,
203
- )
204
-
205
- destination_info = client.account_info(destination)
206
- btc_balance = destination_info.balances.find do |b|
207
- b["asset_code"] == "BTC"
208
- end["balance"].to_f
209
-
210
- expect(btc_balance).to eq 150.0
211
- end
212
- end
213
-
214
- context "alphanum12 asset" do
215
- let(:issuer) { Stellar::Account.from_seed(CONFIG[:source_seed]) }
216
- let(:destination) { Stellar::Account.random }
217
-
218
- it("sends a alphanum12 asset to the destination", {
219
- vcr: {record: :once, match_requests_on: [:method]},
220
- }) do
221
- client.create_account(
222
- funder: issuer,
223
- account: destination,
224
- starting_balance: 2,
225
- )
226
-
227
- client.change_trust(
228
- asset: [:alphanum12, "LONGNAME", issuer.keypair],
229
- source: destination,
230
- )
231
-
232
- asset = Stellar::Asset.alphanum12("LONGNAME", source.keypair)
233
- amount = Stellar::Amount.new(150, asset)
234
-
235
- client.send_payment(
236
- from: source,
237
- to: destination,
238
- amount: amount,
239
- )
240
-
241
- destination_info = client.account_info(destination)
242
- btc_balance = destination_info.balances.find do |b|
243
- b["asset_code"] == "LONGNAME"
244
- end["balance"].to_f
245
-
246
- expect(btc_balance).to eq 150.0
247
- end
248
- end
249
-
250
- context "memo" do
251
- let(:destination) { Stellar::Account.random }
252
-
253
- it("accepts the memo attribute", {
254
- vcr: {record: :once, match_requests_on: [:method]}
255
- }) do
256
- client.create_account(
257
- funder: source,
258
- account: destination,
259
- starting_balance: 100,
260
- )
261
-
262
- amount = Stellar::Amount.new(150)
263
-
264
- client.send_payment(
265
- from: source,
266
- to: destination,
267
- amount: amount,
268
- memo: "DESUKA",
269
- )
270
-
271
- last_tx = client.account_info(destination).
272
- transactions(order: "desc")._get._embedded.records.first
273
- expect(last_tx.memo).to eq "DESUKA"
274
- end
275
- end
276
-
277
- context "using a payment channel" do
278
- let(:transaction_source) { Stellar::Account.from_seed(CONFIG[:channel_seed]) }
279
- let(:destination) { Stellar::Account.random }
280
-
281
- it("sends a payment account through a channel account", {
282
- vcr: {record: :once, match_requests_on: [:method]},
283
- }) do
284
- client.create_account(
285
- funder: source,
286
- account: destination,
287
- starting_balance: 1,
288
- )
289
-
290
- tx = client.send_payment(
291
- from: source,
292
- to: destination,
293
- amount: Stellar::Amount.new(0.55),
294
- transaction_source: transaction_source,
295
- )
296
-
297
- tx_hash = tx._attributes["hash"]
298
-
299
- tx = client.horizon.transaction(hash: tx_hash)
300
- expect(tx.source_account).to eq transaction_source.address
301
-
302
- operation = tx.operations.records.first
303
- expect(operation.from).to eq source.address
304
-
305
- destination_info = client.account_info(destination)
306
- balances = destination_info.balances
307
- expect(balances).to_not be_empty
308
- native_asset_balance_info = balances.find do |b|
309
- b["asset_type"] == "native"
310
- end
311
- expect(native_asset_balance_info["balance"].to_f).to eq 1.55
312
- end
313
-
314
- it("sends a payment when the channel is the same as `from`", {
315
- vcr: {record: :once, match_requests_on: [:method]},
316
- }) do
317
- client.create_account(
318
- funder: source,
319
- account: destination,
320
- starting_balance: 1,
321
- )
322
-
323
- tx = client.send_payment(
324
- from: source,
325
- to: destination,
326
- amount: Stellar::Amount.new(0.55),
327
- transaction_source: source,
328
- )
329
-
330
- tx_hash = tx._attributes["hash"]
331
-
332
- tx = client.horizon.transaction(hash: tx_hash)
333
- expect(tx.source_account).to eq source.address
334
-
335
- operation = tx.operations.records.first
336
- expect(operation.from).to eq source.address
337
- end
338
- end
339
- end
340
-
341
- describe "#transactions" do
342
- let(:cursor) { '348403452088320' }
343
-
344
- context "account transactions" do
345
- let(:account) { Stellar::Account.from_seed(CONFIG[:source_seed]) }
346
-
347
- it "returns a list of transaction for an account", vcr: {record: :once, match_requests_on: [:method]} do
348
- response = client.transactions(account: account)
349
- expect(response).to be_a(Stellar::TransactionPage)
350
- end
351
-
352
- it "accepts a cursor to return less data", vcr: {record: :once, match_requests_on: [:method]} do
353
- response = client.transactions(account: account,
354
- cursor: cursor)
355
- expect(response).to be_a(Stellar::TransactionPage)
356
- end
357
- end
358
-
359
- context "all transactions" do
360
- it "returns a list of transactions", vcr: {record: :once, match_requests_on: [:method]} do
361
- response = client.transactions
362
- expect(response).to be_a(Stellar::TransactionPage)
363
- end
364
-
365
- it "accepts a cursor to return less data", vcr: {record: :once, match_requests_on: [:method]} do
366
- response = client.transactions(cursor: cursor)
367
- expect(response).to be_a(Stellar::TransactionPage)
368
- end
369
- end
370
- end
371
-
372
- describe "#change_trust" do
373
- context "given an asset described as an array" do
374
- let(:issuer) { Stellar::Account.from_seed(CONFIG[:source_seed]) }
375
- let(:truster) { Stellar::Account.random }
376
-
377
- it("creates, updates, or deletes a trustline", {
378
- vcr: {record: :once, match_requests_on: [:method]},
379
- }) do
380
- client.create_account(
381
- funder: issuer,
382
- account: truster,
383
- starting_balance: 2,
384
- )
385
-
386
- # Create trustline
387
- client.change_trust(
388
- asset: [:alphanum4, "BTC", issuer.keypair],
389
- source: truster,
390
- )
391
-
392
- truster_info = client.account_info(truster)
393
- btc_balance = truster_info.balances.find do |b|
394
- b["asset_code"] == "BTC" && b["asset_issuer"] == issuer.address
395
- end
396
-
397
- expect(btc_balance).to_not be_nil
398
-
399
- # Update trustline
400
- client.change_trust(
401
- asset: [:alphanum4, "BTC", issuer.keypair],
402
- source: truster,
403
- limit: 100,
404
- )
405
-
406
- truster_info = client.account_info(truster)
407
- btc_balance = truster_info.balances.find do |b|
408
- b["asset_code"] == "BTC" && b["asset_issuer"] == issuer.address
409
- end
410
-
411
- expect(btc_balance["limit"].to_f).to eq 100
412
-
413
- # Delete trustline
414
- client.change_trust(
415
- asset: [:alphanum4, "BTC", issuer.keypair],
416
- source: truster,
417
- limit: 0,
418
- )
419
-
420
- truster_info = client.account_info(truster)
421
- btc_balance = truster_info.balances.find do |b|
422
- b["asset_code"] == "BTC" && b["asset_issuer"] == issuer.address
423
- end
424
-
425
- expect(btc_balance).to be_nil
426
- end
427
- end
428
- end
429
-
430
- end
@@ -1,1148 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe Stellar::SEP10 do
4
-
5
- subject(:sep10) { Stellar::SEP10 }
6
-
7
- let(:server) { Stellar::KeyPair.random }
8
- let(:user) { Stellar::KeyPair.random }
9
- let(:anchor) { "SDF" }
10
- let(:timeout) { 600 }
11
- let(:envelope) { Stellar::TransactionEnvelope.from_xdr(subject, "base64") }
12
- let(:transaction) { envelope.tx }
13
-
14
- subject do
15
- sep10.build_challenge_tx(server: server, client: user, anchor_name: anchor, timeout: timeout)
16
- end
17
-
18
- describe "#build_challenge_tx" do
19
- it "generates a valid SEP10 challenge" do
20
- expect(transaction.seq_num).to eql(0)
21
- expect(transaction.operations.size).to eql(1);
22
- expect(transaction.source_account).to eql(server.public_key);
23
-
24
- time_bounds = transaction.time_bounds
25
- expect(time_bounds.max_time - time_bounds.min_time).to eql(600)
26
- operation = transaction.operations.first
27
-
28
- expect(operation.body.arm).to eql(:manage_data_op)
29
- expect(operation.body.value.data_name).to eql("SDF auth")
30
- expect(operation.source_account).to eql(user.public_key)
31
- data_value = operation.body.value.data_value
32
- expect(data_value.bytes.size).to eql(64)
33
- expect(data_value.unpack("m")[0].size).to eql(48)
34
- end
35
-
36
- describe "defaults" do
37
- subject do
38
- sep10.build_challenge_tx(server: server, client: user, anchor_name: anchor)
39
- end
40
-
41
- it "has a default timeout of 300 seconds (5 minutes)" do
42
- time_bounds = transaction.time_bounds
43
- expect(time_bounds.max_time - time_bounds.min_time).to eql(300)
44
- end
45
- end
46
- end
47
-
48
- describe "#read_challenge_tx" do
49
- subject do
50
- challenge = super()
51
- envelope = Stellar::TransactionEnvelope.from_xdr(challenge, 'base64')
52
- envelope.tx.to_envelope(server, user).to_xdr(:base64)
53
- end
54
-
55
- it "returns the envelope and client public key if the transaction is valid" do
56
- expect(sep10.read_challenge_tx(challenge_xdr: subject, server: server)).to eql([envelope, user.address])
57
- end
58
-
59
- it "returns the envelope even if transaction signed by server but not client" do
60
- envelope = Stellar::TransactionEnvelope.from_xdr(subject, 'base64')
61
- expected_envelope = envelope.tx.to_envelope(server)
62
- expect(
63
- sep10.read_challenge_tx(challenge_xdr: expected_envelope.to_xdr(:base64), server: server)
64
- ).to eql(
65
- [expected_envelope, user.address]
66
- )
67
- end
68
-
69
- it "throws an error if there are too many operations on the transaction" do
70
- envelope = Stellar::TransactionEnvelope.from_xdr(subject, 'base64')
71
- envelope.tx.operations += [Stellar::Operation.bump_sequence({bump_to: 1})]
72
- bad_challege = envelope.tx.to_envelope(server, user).to_xdr(:base64)
73
- expect {
74
- sep10.read_challenge_tx(challenge_xdr: bad_challege, server:server)
75
- }.to raise_error(
76
- Stellar::InvalidSep10ChallengeError,
77
- /The transaction should contain only one operation/
78
- )
79
- end
80
-
81
- it "throws an error if transaction sequence number is different to zero" do
82
- envelope.tx.seq_num = 1
83
-
84
- expect {
85
- sep10.read_challenge_tx(challenge_xdr: envelope.to_xdr(:base64), server: server)
86
- }.to raise_error(Stellar::InvalidSep10ChallengeError, /The transaction sequence number should be zero/)
87
- end
88
-
89
- it "throws an error if transaction source account is different to server account id" do
90
- expect {
91
- sep10.read_challenge_tx(challenge_xdr: envelope.to_xdr(:base64), server: Stellar::KeyPair.random)
92
- }.to raise_error(Stellar::InvalidSep10ChallengeError, /The transaction source account is not equal to the server's account/)
93
- end
94
-
95
- it "throws an error if transaction doesn't contain any operation" do
96
- envelope.tx.operations = []
97
-
98
- expect {
99
- sep10.read_challenge_tx(challenge_xdr: envelope.to_xdr(:base64), server: server)
100
- }.to raise_error(Stellar::InvalidSep10ChallengeError, /The transaction should contain only one operation/)
101
- end
102
-
103
- it "throws an error if operation does not contain the source account" do
104
- op = envelope.tx.operations[0]
105
- op.source_account = nil
106
-
107
- expect {
108
- sep10.read_challenge_tx(challenge_xdr: envelope.to_xdr(:base64), server: server)
109
- }.to raise_error(Stellar::InvalidSep10ChallengeError, /The transaction's operation should contain a source account/)
110
- end
111
-
112
- it "throws an error if operation is not manage data" do
113
- envelope.tx.operations = [
114
- Stellar::Operation.payment(
115
- destination: Stellar::KeyPair.random,
116
- amount: [:native, 20],
117
- source_account: Stellar::KeyPair.random
118
- )
119
- ]
120
-
121
- expect {
122
- sep10.read_challenge_tx(challenge_xdr: envelope.to_xdr(:base64), server: server)
123
- }.to raise_error(Stellar::InvalidSep10ChallengeError, /The transaction's operation should be manageData/)
124
- end
125
-
126
- it "throws an error if operation value is not a 64 bytes base64 string" do
127
- transaction.operations[0].body.value.data_value = SecureRandom.random_bytes(64)
128
- expect {
129
- sep10.read_challenge_tx(challenge_xdr: envelope.to_xdr(:base64), server: server)
130
- }.to raise_error(
131
- Stellar::InvalidSep10ChallengeError,
132
- /The transaction's operation value should be a 64 bytes base64 random string/
133
- )
134
- end
135
-
136
- it "throws an error if transaction is not signed by the server" do
137
- envelope.signatures = envelope.signatures.slice(1, 2)
138
-
139
- expect {
140
- sep10.read_challenge_tx(challenge_xdr: envelope.to_xdr(:base64), server: server)
141
- }.to raise_error(
142
- Stellar::InvalidSep10ChallengeError,
143
- /The transaction is not signed by the server/
144
- )
145
- end
146
-
147
-
148
- it "throws an error if transaction does not contain valid timeBounds" do
149
- envelope.tx.time_bounds = nil
150
- challenge = envelope.tx.to_envelope(server, user).to_xdr(:base64)
151
-
152
- expect {
153
- sep10.read_challenge_tx(challenge_xdr: challenge, server: server)
154
- }.to raise_error(
155
- Stellar::InvalidSep10ChallengeError,
156
- /The transaction has expired/
157
- )
158
-
159
- envelope.tx.time_bounds = Stellar::TimeBounds.new(min_time: 0, max_time: 5)
160
- challenge = envelope.tx.to_envelope(server, user).to_xdr(:base64)
161
-
162
- expect {
163
- sep10.read_challenge_tx(challenge_xdr: challenge, server: server)
164
- }.to raise_error(
165
- Stellar::InvalidSep10ChallengeError,
166
- /The transaction has expired/
167
- )
168
-
169
- now = Time.now.to_i
170
- envelope.tx.time_bounds = Stellar::TimeBounds.new(
171
- min_time: now + 100,
172
- max_time: now + 500
173
- )
174
- challenge = envelope.tx.to_envelope(server, user).to_xdr(:base64)
175
-
176
- expect {
177
- sep10.read_challenge_tx(challenge_xdr: challenge, server: server)
178
- }.to raise_error(
179
- Stellar::InvalidSep10ChallengeError,
180
- /The transaction has expired/
181
- )
182
- end
183
- end
184
-
185
- describe "#verify_challenge_tx_threshold" do
186
- it "raises transaction not signed by server" do
187
- server_kp = Stellar::KeyPair.random
188
- client_kp_a = Stellar::KeyPair.random
189
- client_kp_b = Stellar::KeyPair.random
190
- client_kp_c = Stellar::KeyPair.random
191
- timeout = 600
192
- anchor_name = "SDF"
193
-
194
- challenge = sep10.build_challenge_tx(
195
- server: server_kp,
196
- client: client_kp_a,
197
- anchor_name: anchor_name,
198
- timeout: timeout,
199
- )
200
-
201
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(challenge, "base64")
202
- challenge_envelope.signatures = [client_kp_a, client_kp_b, client_kp_c].map {
203
- |kp| challenge_envelope.tx.sign_decorated(kp)
204
- }
205
-
206
- signers = Set[
207
- {'key' => client_kp_a.address, 'weight': 1},
208
- {'key' => client_kp_b.address, 'weight': 1},
209
- {'key' => client_kp_c.address, 'weight': 1}
210
- ]
211
-
212
- expect {
213
- sep10.verify_challenge_tx_threshold(
214
- challenge_xdr: challenge_envelope.to_xdr(:base64),
215
- server: server_kp,
216
- signers: signers,
217
- threshold: 3
218
- )
219
- }.to raise_error(
220
- Stellar::InvalidSep10ChallengeError,
221
- /The transaction is not signed by the server/
222
- )
223
- end
224
-
225
- it "succeeds with extra signers passed" do
226
- server_kp = Stellar::KeyPair.random
227
- client_kp_a = Stellar::KeyPair.random
228
- client_kp_b = Stellar::KeyPair.random
229
- client_kp_c = Stellar::KeyPair.random
230
-
231
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(
232
- sep10.build_challenge_tx(
233
- server: server_kp,
234
- client: client_kp_a,
235
- anchor_name: "SDF",
236
- timeout: 600,
237
- ),
238
- "base64"
239
- )
240
- challenge_envelope.signatures += [
241
- challenge_envelope.tx.sign_decorated(client_kp_a),
242
- challenge_envelope.tx.sign_decorated(client_kp_b)
243
- ]
244
- challenge = challenge_envelope.to_xdr(:base64)
245
-
246
- expect(
247
- sep10.verify_challenge_tx_threshold(
248
- challenge_xdr: challenge,
249
- server: server_kp,
250
- signers: Set[
251
- {'key' => client_kp_a.address, 'weight' => 1},
252
- {'key' => client_kp_b.address, 'weight' => 1},
253
- {'key' => client_kp_c.address, 'weight' => 1}
254
- ],
255
- threshold: 2
256
- )
257
- ).to eql(
258
- Set[
259
- {'key' => client_kp_a.address, 'weight' => 1},
260
- {'key' => client_kp_b.address, 'weight' => 1}
261
- ]
262
- )
263
- end
264
-
265
- it "rasies an error for unrecognizied signatures" do
266
- server_kp = Stellar::KeyPair.random
267
- client_kp_a = Stellar::KeyPair.random
268
- client_kp_b = Stellar::KeyPair.random
269
- client_kp_c = Stellar::KeyPair.random
270
-
271
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(
272
- sep10.build_challenge_tx(
273
- server: server_kp,
274
- client: client_kp_a,
275
- anchor_name: "SDF",
276
- timeout: 600,
277
- ),
278
- "base64"
279
- )
280
- challenge_envelope.signatures += [
281
- challenge_envelope.tx.sign_decorated(client_kp_a),
282
- challenge_envelope.tx.sign_decorated(client_kp_b),
283
- challenge_envelope.tx.sign_decorated(client_kp_c)
284
- ]
285
- challenge = challenge_envelope.to_xdr(:base64)
286
-
287
- expect {
288
- sep10.verify_challenge_tx_threshold(
289
- challenge_xdr: challenge,
290
- server: server_kp,
291
- signers: Set[
292
- {'key' => client_kp_a.address, 'weight' => 1},
293
- {'key' => client_kp_b.address, 'weight' => 1},
294
- ],
295
- threshold: 2
296
- )
297
- }.to raise_error(
298
- Stellar::InvalidSep10ChallengeError,
299
- /Transaction has unrecognized signatures./
300
- )
301
- end
302
-
303
- it "verifies proper challenge and threshold" do
304
- server_kp = Stellar::KeyPair.random
305
- client_kp_a = Stellar::KeyPair.random
306
- client_kp_b = Stellar::KeyPair.random
307
- client_kp_c = Stellar::KeyPair.random
308
- timeout = 600
309
- anchor_name = "SDF"
310
-
311
- challenge = sep10.build_challenge_tx(
312
- server: server_kp,
313
- client: client_kp_a,
314
- anchor_name: anchor_name,
315
- timeout: timeout,
316
- )
317
-
318
- transaction = Stellar::TransactionEnvelope.from_xdr(challenge, "base64")
319
- transaction.signatures += [
320
- client_kp_a, client_kp_b, client_kp_c
321
- ].map { |kp| transaction.tx.sign_decorated(kp) }
322
- challenge_tx = transaction.to_xdr(:base64)
323
-
324
- signers = Set[
325
- {"key" => client_kp_a.address, "weight" => 1},
326
- {"key" => client_kp_b.address, "weight" => 2},
327
- {"key" => client_kp_c.address, "weight" => 4},
328
- ]
329
-
330
- signers_found = sep10.verify_challenge_tx_threshold(
331
- challenge_xdr: challenge_tx,
332
- server: server_kp,
333
- threshold: 7,
334
- signers: signers,
335
- )
336
- expect(signers_found).to eql(signers)
337
- end
338
-
339
- it "raises error when signers don't meet threshold" do
340
- server_kp = Stellar::KeyPair.random
341
- client_kp_a = Stellar::KeyPair.random
342
- client_kp_b = Stellar::KeyPair.random
343
- client_kp_c = Stellar::KeyPair.random
344
- timeout = 600
345
- anchor_name = "SDF"
346
-
347
- challenge = sep10.build_challenge_tx(
348
- server: server_kp,
349
- client: client_kp_a,
350
- anchor_name: anchor_name,
351
- timeout: timeout,
352
- )
353
-
354
- transaction = Stellar::TransactionEnvelope.from_xdr(challenge, "base64")
355
- transaction.signatures.push(transaction.tx.sign_decorated(client_kp_a))
356
- challenge_tx = transaction.to_xdr(:base64)
357
-
358
- signers = Set[
359
- {"key" => client_kp_a.address, "weight" => 1},
360
- {"key" => client_kp_b.address, "weight" => 2},
361
- {"key" => client_kp_c.address, "weight" => 4},
362
- ]
363
-
364
- expect {
365
- sep10.verify_challenge_tx_threshold(
366
- challenge_xdr: challenge_tx,
367
- server: server_kp,
368
- threshold: 7,
369
- signers: signers,
370
- )
371
- }.to raise_error(
372
- Stellar::InvalidSep10ChallengeError,
373
- "signers with weight %d do not meet threshold %d." % [1, 7]
374
- )
375
- end
376
-
377
- it "ignores non-G address" do
378
- preauth_tx_hash = "TAQCSRX2RIDJNHFIFHWD63X7D7D6TRT5Y2S6E3TEMXTG5W3OECHZ2OG4"
379
- x_hash = "XDRPF6NZRR7EEVO7ESIWUDXHAOMM2QSKIQQBJK6I2FB7YKDZES5UCLWD"
380
- server_kp = Stellar::KeyPair.random
381
- client_kp = Stellar::KeyPair.random
382
-
383
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(
384
- sep10.build_challenge_tx(
385
- server: server_kp,
386
- client: client_kp,
387
- anchor_name: "SDF",
388
- timeout: 600,
389
- ),
390
- "base64"
391
- )
392
- challenge_envelope.signatures += [challenge_envelope.tx.sign_decorated(client_kp)]
393
- challenge = challenge_envelope.to_xdr(:base64)
394
-
395
- expect(
396
- sep10.verify_challenge_tx_threshold(
397
- challenge_xdr: challenge,
398
- server: server_kp,
399
- signers: Set[
400
- {'key'=> client_kp.address, 'weight' => 1},
401
- {'key'=> preauth_tx_hash, 'weight' => 1},
402
- {'key'=> x_hash, 'weight' => 1}
403
- ],
404
- threshold: 1
405
- )
406
- ).to eql(
407
- Set[
408
- {'key' => client_kp.address, 'weight' => 1}
409
- ]
410
- )
411
- end
412
-
413
- it "raises no signers error" do
414
- server_kp = Stellar::KeyPair.random
415
- client_kp_a = Stellar::KeyPair.random
416
- client_kp_b = Stellar::KeyPair.random
417
- client_kp_c = Stellar::KeyPair.random
418
- timeout = 600
419
- anchor_name = "SDF"
420
-
421
- challenge = sep10.build_challenge_tx(
422
- server: server_kp,
423
- client: client_kp_a,
424
- anchor_name: anchor_name,
425
- timeout: timeout,
426
- )
427
-
428
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(challenge, "base64")
429
- challenge_envelope.signatures += [
430
- client_kp_a, client_kp_b, client_kp_c
431
- ].map { |kp| challenge_envelope.tx.sign_decorated(kp) }
432
-
433
- expect {
434
- sep10.verify_challenge_tx_threshold(
435
- challenge_xdr: challenge_envelope.to_xdr(:base64),
436
- server: server_kp,
437
- signers: Set.new,
438
- threshold: 2
439
- )
440
- }.to raise_error(
441
- Stellar::InvalidSep10ChallengeError,
442
- /No signers provided./
443
- )
444
- end
445
-
446
- it "raises an error for no signatures" do
447
- server_kp = Stellar::KeyPair.random
448
- client_kp = Stellar::KeyPair.random
449
-
450
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(
451
- sep10.build_challenge_tx(
452
- server: server_kp,
453
- client: client_kp,
454
- anchor_name: "SDF",
455
- timeout: 600,
456
- ),
457
- "base64"
458
- )
459
- challenge_envelope.signatures.clear
460
- challenge = challenge_envelope.to_xdr(:base64)
461
-
462
- expect {
463
- sep10.verify_challenge_tx_threshold(
464
- challenge_xdr: challenge,
465
- server: server_kp,
466
- signers: Set[
467
- {'key' => client_kp.address, 'weight' => 1}
468
- ],
469
- threshold: 2
470
- )
471
- }.to raise_error(
472
- Stellar::InvalidSep10ChallengeError,
473
- /The transaction is not signed by the server/
474
- )
475
- end
476
-
477
- it "does not pass back duplicate signers or double-count weights" do
478
- server_kp = Stellar::KeyPair.random
479
- client_kp = Stellar::KeyPair.random
480
-
481
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(
482
- sep10.build_challenge_tx(
483
- server: server_kp,
484
- client: client_kp,
485
- anchor_name: "SDF",
486
- timeout: 600,
487
- ),
488
- "base64"
489
- )
490
- challenge_envelope.signatures += [challenge_envelope.tx.sign_decorated(client_kp)]
491
- challenge = challenge_envelope.to_xdr(:base64)
492
-
493
- expect(
494
- sep10.verify_challenge_tx_threshold(
495
- challenge_xdr: challenge,
496
- server: server_kp,
497
- signers: Set[
498
- {'key' => client_kp.address, 'weight' => 1},
499
- {'key' => client_kp.address, 'weight' => 2}
500
- ],
501
- threshold: 1
502
- )
503
- ).to eql(
504
- Set[{'key' => client_kp.address, 'weight' => 1}]
505
- )
506
-
507
- expect {
508
- sep10.verify_challenge_tx_threshold(
509
- challenge_xdr: challenge,
510
- server: server_kp,
511
- signers: Set[
512
- {'key' => client_kp.address, 'weight' => 1},
513
- {'key' => client_kp.address, 'weight' => 2}
514
- ],
515
- threshold: 3
516
- )
517
- }.to raise_error(
518
- Stellar::InvalidSep10ChallengeError,
519
- /signers with weight 1 do not meet threshold 3./
520
- )
521
- end
522
-
523
- it "raises an error for duplicate signatures" do
524
- server_kp = Stellar::KeyPair.random
525
- client_kp = Stellar::KeyPair.random
526
-
527
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(
528
- sep10.build_challenge_tx(
529
- server: server_kp,
530
- client: client_kp,
531
- anchor_name: "SDF",
532
- timeout: 600,
533
- ),
534
- "base64"
535
- )
536
- challenge_envelope.signatures += [
537
- challenge_envelope.tx.sign_decorated(client_kp),
538
- challenge_envelope.tx.sign_decorated(client_kp)
539
- ]
540
- challenge = challenge_envelope.to_xdr(:base64)
541
-
542
- expect {
543
- sep10.verify_challenge_tx_threshold(
544
- challenge_xdr: challenge,
545
- server: server_kp,
546
- signers: Set[{'key' => client_kp.address, 'weight' => 1}],
547
- threshold: 1
548
- )
549
- }.to raise_error(
550
- Stellar::InvalidSep10ChallengeError,
551
- /Transaction has unrecognized signatures./
552
- )
553
- end
554
-
555
- it "raises an error for duplicate signatures and signers" do
556
- server_kp = Stellar::KeyPair.random
557
- client_kp = Stellar::KeyPair.random
558
-
559
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(
560
- sep10.build_challenge_tx(
561
- server: server_kp,
562
- client: client_kp,
563
- anchor_name: "SDF",
564
- timeout: 600,
565
- ),
566
- "base64"
567
- )
568
- challenge_envelope.signatures += [
569
- challenge_envelope.tx.sign_decorated(client_kp),
570
- challenge_envelope.tx.sign_decorated(client_kp)
571
- ]
572
- challenge = challenge_envelope.to_xdr(:base64)
573
-
574
- expect {
575
- sep10.verify_challenge_tx_threshold(
576
- challenge_xdr: challenge,
577
- server: server_kp,
578
- signers: Set[
579
- {'key' => client_kp.address, 'weight' => 1},
580
- {'key' => client_kp.address, 'weight' => 2}
581
- ],
582
- threshold: 1
583
- )
584
- }.to raise_error(
585
- Stellar::InvalidSep10ChallengeError,
586
- /Transaction has unrecognized signatures./
587
- )
588
- end
589
- end
590
-
591
- describe "#verify_challenge_tx" do
592
- it "verifies proper challenge transaction" do
593
- server_kp = Stellar::KeyPair.random
594
- client_kp = Stellar::KeyPair.random
595
- timeout = 600
596
- anchor_name = "SDF"
597
-
598
- challenge = sep10.build_challenge_tx(
599
- server: server_kp,
600
- client: client_kp,
601
- anchor_name: anchor_name,
602
- timeout: timeout,
603
- )
604
-
605
- envelope = Stellar::TransactionEnvelope.from_xdr(challenge, "base64")
606
- envelope.signatures.push(envelope.tx.sign_decorated(client_kp))
607
- challenge_tx = envelope.to_xdr(:base64)
608
-
609
- sep10.verify_challenge_tx(
610
- challenge_xdr: challenge_tx,
611
- server: server_kp
612
- )
613
- end
614
-
615
- it "raises not signed by client" do
616
- server_kp = Stellar::KeyPair.random
617
- client_kp = Stellar::KeyPair.random
618
- timeout = 600
619
- anchor_name = "SDF"
620
-
621
- challenge = sep10.build_challenge_tx(
622
- server: server_kp,
623
- client: client_kp,
624
- anchor_name: anchor_name,
625
- timeout: timeout,
626
- )
627
-
628
- expect {
629
- sep10.verify_challenge_tx(
630
- challenge_xdr: challenge,
631
- server: server_kp
632
- )
633
- }.to raise_error(
634
- Stellar::InvalidSep10ChallengeError,
635
- "Transaction not signed by client: %s" % [client_kp.address]
636
- )
637
- end
638
- end
639
-
640
- describe "#verify_challenge_tx_signers" do
641
- it "returns expected signatures" do
642
- server_kp = Stellar::KeyPair.random
643
- client_kp_a = Stellar::KeyPair.random
644
- client_kp_b = Stellar::KeyPair.random
645
- client_kp_c = Stellar::KeyPair.random
646
- timeout = 600
647
- anchor_name = "SDF"
648
-
649
- challenge = sep10.build_challenge_tx(
650
- server: server_kp,
651
- client: client_kp_a,
652
- anchor_name: anchor_name,
653
- timeout: timeout,
654
- )
655
-
656
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(challenge, "base64")
657
- challenge_envelope.signatures += [
658
- client_kp_a, client_kp_b, client_kp_c
659
- ].map { |kp| challenge_envelope.tx.sign_decorated(kp) }
660
-
661
- signers = Set[
662
- client_kp_a.address,
663
- client_kp_b.address,
664
- client_kp_c.address,
665
- Stellar::KeyPair.random.address
666
- ]
667
- signers_found = sep10.verify_challenge_tx_signers(
668
- challenge_xdr: challenge_envelope.to_xdr(:base64),
669
- server: server_kp,
670
- signers: signers
671
- )
672
- expect(signers_found).to eql(Set[
673
- client_kp_a.address,
674
- client_kp_b.address,
675
- client_kp_c.address,
676
- ])
677
- end
678
-
679
- it "raises no signers error" do
680
- server_kp = Stellar::KeyPair.random
681
- client_kp_a = Stellar::KeyPair.random
682
- client_kp_b = Stellar::KeyPair.random
683
- client_kp_c = Stellar::KeyPair.random
684
- timeout = 600
685
- anchor_name = "SDF"
686
-
687
- challenge = sep10.build_challenge_tx(
688
- server: server_kp,
689
- client: client_kp_a,
690
- anchor_name: anchor_name,
691
- timeout: timeout,
692
- )
693
-
694
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(challenge, "base64")
695
- challenge_envelope.signatures += [
696
- client_kp_a, client_kp_b, client_kp_c
697
- ].map { |kp| challenge_envelope.tx.sign_decorated(kp) }
698
-
699
- expect {
700
- sep10.verify_challenge_tx_signers(
701
- challenge_xdr: challenge_envelope.to_xdr(:base64),
702
- server: server_kp,
703
- signers: Set.new
704
- )
705
- }.to raise_error(
706
- Stellar::InvalidSep10ChallengeError,
707
- /No signers provided./
708
- )
709
- end
710
-
711
- it "raises transaction not signed by server" do
712
- server_kp = Stellar::KeyPair.random
713
- client_kp_a = Stellar::KeyPair.random
714
- client_kp_b = Stellar::KeyPair.random
715
- client_kp_c = Stellar::KeyPair.random
716
- timeout = 600
717
- anchor_name = "SDF"
718
-
719
- challenge = sep10.build_challenge_tx(
720
- server: server_kp,
721
- client: client_kp_a,
722
- anchor_name: anchor_name,
723
- timeout: timeout,
724
- )
725
-
726
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(challenge, "base64")
727
- challenge_envelope.signatures = [client_kp_a, client_kp_b, client_kp_c].map {
728
- |kp| challenge_envelope.tx.sign_decorated(kp)
729
- }
730
-
731
- signers = Set[
732
- client_kp_a.address,
733
- client_kp_b.address,
734
- client_kp_c.address
735
- ]
736
-
737
- expect {
738
- sep10.verify_challenge_tx_signers(
739
- challenge_xdr: challenge_envelope.to_xdr(:base64),
740
- server: server_kp,
741
- signers: signers
742
- )
743
- }.to raise_error(
744
- Stellar::InvalidSep10ChallengeError,
745
- /The transaction is not signed by the server/
746
- )
747
- end
748
-
749
- it "raises no client signers found" do
750
- server_kp = Stellar::KeyPair.random
751
- client_kp_a = Stellar::KeyPair.random
752
- client_kp_b = Stellar::KeyPair.random
753
- client_kp_c = Stellar::KeyPair.random
754
- timeout = 600
755
- anchor_name = "SDF"
756
-
757
- challenge = sep10.build_challenge_tx(
758
- server: server_kp,
759
- client: client_kp_a,
760
- anchor_name: anchor_name,
761
- timeout: timeout,
762
- )
763
-
764
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(challenge, "base64")
765
- challenge_envelope.signatures += [
766
- client_kp_a, client_kp_b, client_kp_c
767
- ].map { |kp| challenge_envelope.tx.sign_decorated(kp) }
768
-
769
- # Different signers than those on the transaction envelope
770
- signers = Set[
771
- Stellar::KeyPair.random.address,
772
- Stellar::KeyPair.random.address,
773
- Stellar::KeyPair.random.address
774
- ]
775
-
776
- expect {
777
- sep10.verify_challenge_tx_signers(
778
- challenge_xdr: challenge_envelope.to_xdr(:base64),
779
- server: server_kp,
780
- signers: signers
781
- )
782
- }.to raise_error(
783
- Stellar::InvalidSep10ChallengeError,
784
- /Transaction not signed by any client signer./
785
- )
786
- end
787
-
788
- it "raises unrecognized signatures" do
789
- server_kp = Stellar::KeyPair.random
790
- client_kp_a = Stellar::KeyPair.random
791
- client_kp_b = Stellar::KeyPair.random
792
- client_kp_c = Stellar::KeyPair.random
793
- timeout = 600
794
- anchor_name = "SDF"
795
-
796
- challenge = sep10.build_challenge_tx(
797
- server: server_kp,
798
- client: client_kp_a,
799
- anchor_name: anchor_name,
800
- timeout: timeout,
801
- )
802
-
803
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(challenge, "base64")
804
- # Add random signature
805
- challenge_envelope.signatures += [
806
- client_kp_a, client_kp_b, client_kp_c, Stellar::KeyPair.random
807
- ].map { |kp| challenge_envelope.tx.sign_decorated(kp) }
808
-
809
- signers = Set[
810
- client_kp_a.address,
811
- client_kp_b.address,
812
- client_kp_c.address
813
- ]
814
-
815
- expect {
816
- sep10.verify_challenge_tx_signers(
817
- challenge_xdr: challenge_envelope.to_xdr(:base64),
818
- server: server_kp,
819
- signers: signers
820
- )
821
- }.to raise_error(
822
- Stellar::InvalidSep10ChallengeError,
823
- /Transaction has unrecognized signatures./
824
- )
825
- end
826
-
827
- it "raises an error when transaction only has server signature" do
828
- server_kp = Stellar::KeyPair.random
829
- client_kp = Stellar::KeyPair.random
830
-
831
- challenge = sep10.build_challenge_tx(
832
- server: server_kp,
833
- client: client_kp,
834
- anchor_name: "SDF",
835
- timeout: 600,
836
- )
837
-
838
- expect {
839
- sep10.verify_challenge_tx_signers(
840
- challenge_xdr: challenge,
841
- server: server_kp,
842
- signers: Set[server_kp.address]
843
- )
844
- }.to raise_error(
845
- Stellar::InvalidSep10ChallengeError,
846
- /At least one signer with a G... address must be provied/
847
- )
848
- end
849
-
850
- it "succeeds even when the server is included in the passed signers" do
851
- server_kp = Stellar::KeyPair.random
852
- client_kp = Stellar::KeyPair.random
853
-
854
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(
855
- sep10.build_challenge_tx(
856
- server: server_kp,
857
- client: client_kp,
858
- anchor_name: "SDF",
859
- timeout: 600,
860
- ),
861
- "base64"
862
- )
863
- challenge_envelope.signatures += [challenge_envelope.tx.sign_decorated(client_kp)]
864
- challenge = challenge_envelope.to_xdr(:base64)
865
-
866
- expect(
867
- sep10.verify_challenge_tx_signers(
868
- challenge_xdr: challenge,
869
- server: server_kp,
870
- signers: Set[server_kp.address, client_kp.address]
871
- )
872
- ).to eql(
873
- Set[client_kp.address]
874
- )
875
- end
876
-
877
- it "succeeds with extra signers passed" do
878
- server_kp = Stellar::KeyPair.random
879
- client_kp_a = Stellar::KeyPair.random
880
- client_kp_b = Stellar::KeyPair.random
881
- client_kp_c = Stellar::KeyPair.random
882
-
883
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(
884
- sep10.build_challenge_tx(
885
- server: server_kp,
886
- client: client_kp_a,
887
- anchor_name: "SDF",
888
- timeout: 600,
889
- ),
890
- "base64"
891
- )
892
- challenge_envelope.signatures += [
893
- challenge_envelope.tx.sign_decorated(client_kp_a),
894
- challenge_envelope.tx.sign_decorated(client_kp_b)
895
- ]
896
- challenge = challenge_envelope.to_xdr(:base64)
897
-
898
- expect(
899
- sep10.verify_challenge_tx_signers(
900
- challenge_xdr: challenge,
901
- server: server_kp,
902
- signers: Set[
903
- client_kp_a.address,
904
- client_kp_b.address,
905
- client_kp_c.address
906
- ]
907
- )
908
- ).to eql(
909
- Set[client_kp_a.address, client_kp_b.address]
910
- )
911
- end
912
-
913
- it "does not pass back duplicate signers" do
914
- server_kp = Stellar::KeyPair.random
915
- client_kp = Stellar::KeyPair.random
916
-
917
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(
918
- sep10.build_challenge_tx(
919
- server: server_kp,
920
- client: client_kp,
921
- anchor_name: "SDF",
922
- timeout: 600,
923
- ),
924
- "base64"
925
- )
926
- challenge_envelope.signatures += [challenge_envelope.tx.sign_decorated(client_kp)]
927
- challenge = challenge_envelope.to_xdr(:base64)
928
-
929
- expect(
930
- sep10.verify_challenge_tx_signers(
931
- challenge_xdr: challenge,
932
- server: server_kp,
933
- signers: Set[client_kp.address, client_kp.address]
934
- )
935
- ).to eql(
936
- Set[client_kp.address]
937
- )
938
- end
939
-
940
- it "raises an error for duplicate signatures" do
941
- server_kp = Stellar::KeyPair.random
942
- client_kp = Stellar::KeyPair.random
943
-
944
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(
945
- sep10.build_challenge_tx(
946
- server: server_kp,
947
- client: client_kp,
948
- anchor_name: "SDF",
949
- timeout: 600,
950
- ),
951
- "base64"
952
- )
953
- challenge_envelope.signatures += [
954
- challenge_envelope.tx.sign_decorated(client_kp),
955
- challenge_envelope.tx.sign_decorated(client_kp)
956
- ]
957
- challenge = challenge_envelope.to_xdr(:base64)
958
-
959
- expect {
960
- sep10.verify_challenge_tx_signers(
961
- challenge_xdr: challenge,
962
- server: server_kp,
963
- signers: Set[server_kp.address, client_kp.address]
964
- )
965
- }.to raise_error(
966
- Stellar::InvalidSep10ChallengeError,
967
- /Transaction has unrecognized signatures./
968
- )
969
- end
970
-
971
- it "ignores non-G address" do
972
- preauth_tx_hash = "TAQCSRX2RIDJNHFIFHWD63X7D7D6TRT5Y2S6E3TEMXTG5W3OECHZ2OG4"
973
- x_hash = "XDRPF6NZRR7EEVO7ESIWUDXHAOMM2QSKIQQBJK6I2FB7YKDZES5UCLWD"
974
- server_kp = Stellar::KeyPair.random
975
- client_kp = Stellar::KeyPair.random
976
-
977
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(
978
- sep10.build_challenge_tx(
979
- server: server_kp,
980
- client: client_kp,
981
- anchor_name: "SDF",
982
- timeout: 600,
983
- ),
984
- "base64"
985
- )
986
- challenge_envelope.signatures += [challenge_envelope.tx.sign_decorated(client_kp)]
987
- challenge = challenge_envelope.to_xdr(:base64)
988
-
989
- expect(
990
- sep10.verify_challenge_tx_signers(
991
- challenge_xdr: challenge,
992
- server: server_kp,
993
- signers: Set[client_kp.address, preauth_tx_hash, x_hash]
994
- )
995
- ).to eql(
996
- Set[client_kp.address]
997
- )
998
- end
999
-
1000
- it "raises an error for no signatures" do
1001
- server_kp = Stellar::KeyPair.random
1002
- client_kp = Stellar::KeyPair.random
1003
-
1004
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(
1005
- sep10.build_challenge_tx(
1006
- server: server_kp,
1007
- client: client_kp,
1008
- anchor_name: "SDF",
1009
- timeout: 600,
1010
- ),
1011
- "base64"
1012
- )
1013
- challenge_envelope.signatures.clear
1014
- challenge = challenge_envelope.to_xdr(:base64)
1015
-
1016
- expect {
1017
- sep10.verify_challenge_tx_signers(
1018
- challenge_xdr: challenge,
1019
- server: server_kp,
1020
- signers: Set[client_kp.address]
1021
- )
1022
- }.to raise_error(
1023
- Stellar::InvalidSep10ChallengeError,
1024
- /The transaction is not signed by the server/
1025
- )
1026
- end
1027
- end
1028
-
1029
- describe "#verify_tx_signatures" do
1030
- it "returns expected signatures" do
1031
- server_kp = Stellar::KeyPair.random
1032
- client_kp_a = Stellar::KeyPair.random
1033
- client_kp_b = Stellar::KeyPair.random
1034
- client_kp_c = Stellar::KeyPair.random
1035
- timeout = 600
1036
- anchor_name = "SDF"
1037
-
1038
- challenge = sep10.build_challenge_tx(
1039
- server: server_kp,
1040
- client: client_kp_a,
1041
- anchor_name: anchor_name,
1042
- timeout: timeout
1043
- )
1044
-
1045
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(challenge, "base64")
1046
-
1047
- challenge_envelope.signatures += [
1048
- client_kp_a, client_kp_b, client_kp_c
1049
- ].map { |kp| challenge_envelope.tx.sign_decorated(kp) }
1050
-
1051
- signers = Set[
1052
- client_kp_a.address,
1053
- client_kp_b.address,
1054
- client_kp_c.address,
1055
- Stellar::KeyPair.random.address
1056
- ]
1057
- signers_found = sep10.verify_tx_signatures(
1058
- tx_envelope: challenge_envelope, signers: signers
1059
- )
1060
- expect(signers_found).to eql(Set[
1061
- client_kp_a.address,
1062
- client_kp_b.address,
1063
- client_kp_c.address
1064
- ])
1065
- end
1066
-
1067
- it "raises no signature error" do
1068
- server_kp = Stellar::KeyPair.random
1069
- client_kp = Stellar::KeyPair.random
1070
- value = SecureRandom.base64(48)
1071
-
1072
- tx = Stellar::Transaction.manage_data({
1073
- account: server_kp,
1074
- sequence: 0,
1075
- name: "SDF auth",
1076
- value: value,
1077
- source_account: client_kp
1078
- })
1079
-
1080
- now = Time.now.to_i
1081
- tx.time_bounds = Stellar::TimeBounds.new(
1082
- min_time: now,
1083
- max_time: now + timeout
1084
- )
1085
-
1086
- signers = Set[client_kp.address]
1087
- expect{
1088
- sep10.verify_tx_signatures(
1089
- tx_envelope: tx.to_envelope(), signers: signers
1090
- )
1091
- }.to raise_error(
1092
- Stellar::InvalidSep10ChallengeError,
1093
- /Transaction has no signatures./
1094
- )
1095
- end
1096
-
1097
- it "removes duplicate signers" do
1098
- server_kp = Stellar::KeyPair.random
1099
- client_kp_a = Stellar::KeyPair.random
1100
- timeout = 600
1101
- anchor_name = "SDF"
1102
-
1103
- challenge = sep10.build_challenge_tx(
1104
- server: server_kp,
1105
- client: client_kp_a,
1106
- anchor_name: anchor_name,
1107
- timeout: timeout
1108
- )
1109
-
1110
- challenge_envelope = Stellar::TransactionEnvelope.from_xdr(challenge, "base64")
1111
-
1112
- # Sign the transaction with the same keypair twice
1113
- challenge_envelope.signatures += [
1114
- client_kp_a, client_kp_a
1115
- ].map { |kp| challenge_envelope.tx.sign_decorated(kp) }
1116
-
1117
- signers = Set[
1118
- client_kp_a.address,
1119
- client_kp_a.address,
1120
- Stellar::KeyPair.random.address
1121
- ]
1122
- signers_found = sep10.verify_tx_signatures(
1123
- tx_envelope: challenge_envelope, signers: signers
1124
- )
1125
- expect(signers_found).to eql(Set[client_kp_a.address])
1126
- end
1127
- end
1128
-
1129
- describe "#verify_tx_signed_by" do
1130
- let(:keypair) { Stellar::KeyPair.random }
1131
- let(:envelope) do
1132
- Stellar::Transaction.bump_sequence(account: keypair, bump_to: 1000, sequence: 0).to_envelope(keypair)
1133
- end
1134
-
1135
- it "returns true if transaction envelope is signed by keypair" do
1136
- result = sep10.verify_tx_signed_by(tx_envelope: envelope, keypair: keypair)
1137
- expect(result).to eql(true)
1138
- end
1139
-
1140
- it "returns false if transaction envelope is not signed by keypair" do
1141
- result = sep10.verify_tx_signed_by(
1142
- tx_envelope: envelope,
1143
- keypair: Stellar::KeyPair.random
1144
- )
1145
- expect(result).to eql(false)
1146
- end
1147
- end
1148
- end