stellar-sdk 0.8.0 → 0.9.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
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