Skip to content
This repository has been archived by the owner on Dec 15, 2021. It is now read-only.

Add tests for SEP10 Signer Support #9

Merged
merged 7 commits into from
Jan 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
node_modules
reports
reports
junit.xml
148 changes: 148 additions & 0 deletions cases/sep10.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,17 @@ import { fetch } from "./util/fetchShim";
import JWT from "jsonwebtoken";
import TOML from "toml";
import StellarSDK from "stellar-sdk";
import friendbot from "./util/friendbot";
import getSep10Token from "./util/sep10";

// Friendbot usage makes this very slow. Need to create an account pool at
// the beginning and reuse them.
jest.setTimeout(100000);
const url = process.env.DOMAIN;
const account = "GCQJX6WGG7SSFU2RBO5QANTFXY7C5GTTFJDCBAAO42JCCFIMZ7PEBURP";
const secret = "SAUOSXXF7ZDO5PKHRFR445DRKZ66Q5HIM2HIPQGWBTUKJZQAOP3VGH3L";
const keyPair = StellarSDK.Keypair.fromSecret(secret);
const server = new StellarSDK.Server("https://horizon-testnet.stellar.org");

describe("SEP10", () => {
let toml;
Expand Down Expand Up @@ -187,4 +193,146 @@ describe("SEP10", () => {
});
});
});

describe("signers support", () => {
afterAll(async () => {
console.log("DESTROY ALL FRIENDS");
await friendbot.destroyAllFriends();
});

/**
* Removing the masterWeight for an account means that it can
* no longer sign for itself. This should mean that it can't
* get a token with its own signature.
*/
it("fails for an account that can't sign for itself", async () => {
const accountA = StellarSDK.Keypair.random();
await friendbot(accountA);
const accountData = await server.loadAccount(accountA.publicKey());
const transaction = new StellarSDK.TransactionBuilder(accountData, {
fee: StellarSDK.BASE_FEE,
networkPassphrase: StellarSDK.Networks.TESTNET
})
.addOperation(
StellarSDK.Operation.setOptions({
masterWeight: 0
})
)
.setTimeout(30)
.build();
transaction.sign(accountA);
await server.submitTransaction(transaction);
const token = await getSep10Token(url, accountA, [accountA]);
expect(token).toBeFalsy();
});

it("succeeds for a signer of an account", async () => {
const userAccount = StellarSDK.Keypair.random();
const signerAccount = StellarSDK.Keypair.random();
await Promise.all([friendbot(userAccount), friendbot(signerAccount)]);
const accountData = await server.loadAccount(userAccount.publicKey());
const transaction = new StellarSDK.TransactionBuilder(accountData, {
fee: StellarSDK.BASE_FEE,
networkPassphrase: StellarSDK.Networks.TESTNET
})
.addOperation(
StellarSDK.Operation.setOptions({
lowThreshold: 1,
medThreshold: 1,
highThreshold: 1,
signer: {
ed25519PublicKey: signerAccount.publicKey(),
weight: 1
}
})
)
.setTimeout(30)
.build();
transaction.sign(userAccount);
await server.submitTransaction(transaction);
const token = await getSep10Token(url, userAccount, [signerAccount]);
expect(token).toBeTruthy();
});

/**
* In this test case, since we have a signer with only half the required
* weight of the thresholds, a malicious actor might try to sign twice
* with the same key hoping the server doesn't de-duplicate signers, and
* count its weight twice.
*/
it("fails when trying to reuse the same signer to gain weight", async () => {
const userAccount = StellarSDK.Keypair.random();
const signerAccount = StellarSDK.Keypair.random();
await Promise.all([friendbot(userAccount), friendbot(signerAccount)]);
const accountData = await server.loadAccount(userAccount.publicKey());
const transaction = new StellarSDK.TransactionBuilder(accountData, {
fee: StellarSDK.BASE_FEE,
networkPassphrase: StellarSDK.Networks.TESTNET
})
.addOperation(
StellarSDK.Operation.setOptions({
lowThreshold: 2,
medThreshold: 2,
highThreshold: 2,
signer: {
ed25519PublicKey: signerAccount.publicKey(),
weight: 1
}
})
)
.setTimeout(30)
.build();
transaction.sign(userAccount);
await server.submitTransaction(transaction);
const token = await getSep10Token(url, userAccount, [
signerAccount,
signerAccount
]);
expect(token).toBeFalsy();
});

it("succeeds with multiple signers", async () => {
const userAccount = StellarSDK.Keypair.random();
const signerAccount1 = StellarSDK.Keypair.random();
const signerAccount2 = StellarSDK.Keypair.random();
await Promise.all([
friendbot(userAccount),
friendbot(signerAccount1),
friendbot(signerAccount2)
]);
const accountData = await server.loadAccount(userAccount.publicKey());
const transaction = new StellarSDK.TransactionBuilder(accountData, {
fee: StellarSDK.BASE_FEE,
networkPassphrase: StellarSDK.Networks.TESTNET
})
.addOperation(
StellarSDK.Operation.setOptions({
lowThreshold: 2,
medThreshold: 2,
highThreshold: 2,
signer: {
ed25519PublicKey: signerAccount1.publicKey(),
weight: 1
}
})
)
.addOperation(
StellarSDK.Operation.setOptions({
signer: {
ed25519PublicKey: signerAccount2.publicKey(),
weight: 1
}
})
)
.setTimeout(30)
.build();
transaction.sign(userAccount);
await server.submitTransaction(transaction);
const token = await getSep10Token(url, userAccount, [
signerAccount1,
signerAccount2
]);
expect(token).toBeTruthy();
});
});
});
36 changes: 36 additions & 0 deletions cases/util/friendbot.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { fetch } from "./fetchShim";
import StellarSdk from "stellar-sdk";

const friends = [];
async function friendbot(keyPair) {
const response = await fetch(
`https://friendbot.stellar.org/?addr=${keyPair.publicKey()}`
);
friends.push(keyPair);
expect(response.status).toEqual(200);
}

friendbot.destroyAllFriends = async function() {
if (friends.length === 0) return;
const accountData = await server.loadAccount(friends[0].publicKey());
const transactionBuilder = new StellarSDK.TransactionBuilder(accountData, {
fee: StellarSDK.BASE_FEE,
networkPassphrase: StellarSDK.Networks.TESTNET
});
friends.forEach(keyPair => {
transactionBuilder.addOperation(
StellarSdk.Operations.accountMerge({
destination: "GAIH3ULLFQ4DGSECF2AR555KZ4KNDGEKN4AFI4SU2M7B43MGK3QJZNSR",
source: keyPair.publicKey()
})
);
});

const tx = transactionBuilder.setTimeout(30).build();
friends.forEach(keyPair => {
tx.sign(keyPair);
});
await server.submitTransaction(tx);
};

export default friendbot;
7 changes: 5 additions & 2 deletions cases/util/sep10.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import TOML from "toml";
import StellarSDK from "stellar-sdk";
import { fetch } from "./fetchShim";

export default async function getSep10Token(domain, keyPair) {
export default async function getSep10Token(domain, keyPair, signers) {
if (!signers) signers = [keyPair];
let response = await fetch(domain + "/.well-known/stellar.toml");
const text = await response.text();
const toml = TOML.parse(text);
Expand All @@ -14,7 +15,9 @@ export default async function getSep10Token(domain, keyPair) {
json.transaction,
json.network_passphrase
);
tx.sign(keyPair);
signers.forEach(keyPair => {
tx.sign(keyPair);
});
let resp = await fetch(toml.WEB_AUTH_ENDPOINT, {
method: "POST",
headers: {
Expand Down