@stellar/stellar-sdk 16.0.1 → 16.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +41 -2
- package/dist/stellar-sdk-axios.js +5401 -3690
- package/dist/stellar-sdk-axios.js.map +1 -1
- package/dist/stellar-sdk-axios.min.js +12 -11
- package/dist/stellar-sdk-axios.min.js.map +1 -1
- package/dist/stellar-sdk.js +4850 -3681
- package/dist/stellar-sdk.js.map +1 -1
- package/dist/stellar-sdk.min.js +17 -17
- package/dist/stellar-sdk.min.js.map +1 -1
- package/lib/axios/cjs/base/auth.js +147 -30
- package/lib/axios/cjs/base/auth.js.map +1 -1
- package/lib/axios/cjs/base/index.js +113 -0
- package/lib/axios/cjs/base/index.js.map +1 -0
- package/lib/axios/cjs/base/keypair.js +39 -0
- package/lib/axios/cjs/base/keypair.js.map +1 -1
- package/lib/axios/cjs/base/scval.js +34 -0
- package/lib/axios/cjs/base/scval.js.map +1 -1
- package/lib/axios/cjs/bindings/client.js +170 -0
- package/lib/axios/cjs/bindings/client.js.map +1 -1
- package/lib/axios/cjs/bindings/config.js +1 -1
- package/lib/axios/cjs/bindings/generator.js +45 -16
- package/lib/axios/cjs/bindings/generator.js.map +1 -1
- package/lib/axios/cjs/bindings/types.js +151 -1
- package/lib/axios/cjs/bindings/types.js.map +1 -1
- package/lib/axios/cjs/bindings/utils.js +10 -0
- package/lib/axios/cjs/bindings/utils.js.map +1 -1
- package/lib/axios/cjs/cli/index.js +19 -22
- package/lib/axios/cjs/cli/index.js.map +1 -1
- package/lib/axios/cjs/cli/util.js +1 -20
- package/lib/axios/cjs/cli/util.js.map +1 -1
- package/lib/axios/cjs/contract/assembled_transaction.js +39 -17
- package/lib/axios/cjs/contract/assembled_transaction.js.map +1 -1
- package/lib/axios/cjs/contract/basic_node_signer.js +8 -42
- package/lib/axios/cjs/contract/basic_node_signer.js.map +1 -1
- package/lib/axios/cjs/contract/client.js +56 -3
- package/lib/axios/cjs/contract/client.js.map +1 -1
- package/lib/axios/cjs/contract/event_spec.js +164 -0
- package/lib/axios/cjs/contract/event_spec.js.map +1 -0
- package/lib/axios/cjs/contract/index.js +2 -0
- package/lib/axios/cjs/contract/index.js.map +1 -1
- package/lib/axios/cjs/contract/sent_transaction.js +0 -20
- package/lib/axios/cjs/contract/sent_transaction.js.map +1 -1
- package/lib/axios/cjs/contract/signer.js +96 -0
- package/lib/axios/cjs/contract/signer.js.map +1 -0
- package/lib/axios/cjs/contract/spec.js +107 -3
- package/lib/axios/cjs/contract/spec.js.map +1 -1
- package/lib/axios/cjs/contract/types.js.map +1 -1
- package/lib/axios/cjs/errors/transaction_failed.js +62 -0
- package/lib/axios/cjs/errors/transaction_failed.js.map +1 -0
- package/lib/axios/cjs/errors/wrap_http_error.js +20 -0
- package/lib/axios/cjs/errors/wrap_http_error.js.map +1 -0
- package/lib/axios/cjs/federation/server.js +15 -35
- package/lib/axios/cjs/federation/server.js.map +1 -1
- package/lib/axios/cjs/horizon/account_response.js +0 -20
- package/lib/axios/cjs/horizon/account_response.js.map +1 -1
- package/lib/axios/cjs/horizon/horizon_api.js +5 -0
- package/lib/axios/cjs/horizon/horizon_api.js.map +1 -1
- package/lib/axios/cjs/horizon/horizon_axios_client.js +1 -1
- package/lib/axios/cjs/horizon/server.js +20 -26
- package/lib/axios/cjs/horizon/server.js.map +1 -1
- package/lib/axios/cjs/index.js +66 -65
- package/lib/axios/cjs/index.js.map +1 -1
- package/lib/axios/cjs/rpc/api.js.map +1 -1
- package/lib/axios/cjs/rpc/axios.js +1 -1
- package/lib/axios/cjs/rpc/server.js +181 -13
- package/lib/axios/cjs/rpc/server.js.map +1 -1
- package/lib/axios/cjs/rpc/transaction.js +2 -20
- package/lib/axios/cjs/rpc/transaction.js.map +1 -1
- package/lib/axios/cjs/webauth/challenge_transaction.js +7 -22
- package/lib/axios/cjs/webauth/challenge_transaction.js.map +1 -1
- package/lib/axios/cjs/webauth/utils.js +1 -20
- package/lib/axios/cjs/webauth/utils.js.map +1 -1
- package/lib/axios/esm/base/auth.d.ts +181 -13
- package/lib/axios/esm/base/auth.js +146 -31
- package/lib/axios/esm/base/auth.js.map +1 -1
- package/lib/axios/esm/base/index.d.ts +2 -2
- package/lib/axios/esm/base/index.js +44 -0
- package/lib/axios/esm/base/index.js.map +1 -0
- package/lib/axios/esm/base/keypair.d.ts +27 -0
- package/lib/axios/esm/base/keypair.js +39 -0
- package/lib/axios/esm/base/keypair.js.map +1 -1
- package/lib/axios/esm/base/scval.d.ts +4 -0
- package/lib/axios/esm/base/scval.js +34 -0
- package/lib/axios/esm/base/scval.js.map +1 -1
- package/lib/axios/esm/bindings/client.d.ts +39 -0
- package/lib/axios/esm/bindings/client.js +171 -1
- package/lib/axios/esm/bindings/client.js.map +1 -1
- package/lib/axios/esm/bindings/config.js +1 -1
- package/lib/axios/esm/bindings/generator.d.ts +34 -0
- package/lib/axios/esm/bindings/generator.js +45 -16
- package/lib/axios/esm/bindings/generator.js.map +1 -1
- package/lib/axios/esm/bindings/types.d.ts +42 -0
- package/lib/axios/esm/bindings/types.js +153 -3
- package/lib/axios/esm/bindings/types.js.map +1 -1
- package/lib/axios/esm/bindings/utils.d.ts +10 -0
- package/lib/axios/esm/bindings/utils.js +9 -1
- package/lib/axios/esm/bindings/utils.js.map +1 -1
- package/lib/axios/esm/cli/index.js +19 -22
- package/lib/axios/esm/cli/index.js.map +1 -1
- package/lib/axios/esm/cli/util.d.ts +1 -1
- package/lib/axios/esm/cli/util.js +1 -20
- package/lib/axios/esm/cli/util.js.map +1 -1
- package/lib/axios/esm/contract/assembled_transaction.d.ts +7 -5
- package/lib/axios/esm/contract/assembled_transaction.js +39 -17
- package/lib/axios/esm/contract/assembled_transaction.js.map +1 -1
- package/lib/axios/esm/contract/basic_node_signer.d.ts +3 -0
- package/lib/axios/esm/contract/basic_node_signer.js +8 -42
- package/lib/axios/esm/contract/basic_node_signer.js.map +1 -1
- package/lib/axios/esm/contract/client.d.ts +49 -3
- package/lib/axios/esm/contract/client.js +56 -3
- package/lib/axios/esm/contract/client.js.map +1 -1
- package/lib/axios/esm/contract/event_spec.d.ts +78 -0
- package/lib/axios/esm/contract/event_spec.js +159 -0
- package/lib/axios/esm/contract/event_spec.js.map +1 -0
- package/lib/axios/esm/contract/index.d.ts +3 -0
- package/lib/axios/esm/contract/index.js +1 -0
- package/lib/axios/esm/contract/index.js.map +1 -1
- package/lib/axios/esm/contract/sent_transaction.js +0 -20
- package/lib/axios/esm/contract/sent_transaction.js.map +1 -1
- package/lib/axios/esm/contract/signer.d.ts +104 -0
- package/lib/axios/esm/contract/signer.js +91 -0
- package/lib/axios/esm/contract/signer.js.map +1 -0
- package/lib/axios/esm/contract/spec.d.ts +84 -0
- package/lib/axios/esm/contract/spec.js +107 -3
- package/lib/axios/esm/contract/spec.js.map +1 -1
- package/lib/axios/esm/contract/types.d.ts +25 -8
- package/lib/axios/esm/contract/types.js.map +1 -1
- package/lib/axios/esm/errors/index.d.ts +1 -0
- package/lib/axios/esm/errors/transaction_failed.d.ts +55 -0
- package/lib/axios/esm/errors/transaction_failed.js +60 -0
- package/lib/axios/esm/errors/transaction_failed.js.map +1 -0
- package/lib/axios/esm/errors/wrap_http_error.d.ts +20 -0
- package/lib/axios/esm/errors/wrap_http_error.js +18 -0
- package/lib/axios/esm/errors/wrap_http_error.js.map +1 -0
- package/lib/axios/esm/federation/server.js +15 -35
- package/lib/axios/esm/federation/server.js.map +1 -1
- package/lib/axios/esm/horizon/account_response.js +0 -20
- package/lib/axios/esm/horizon/account_response.js.map +1 -1
- package/lib/axios/esm/horizon/horizon_api.d.ts +12 -1
- package/lib/axios/esm/horizon/horizon_api.js +5 -0
- package/lib/axios/esm/horizon/horizon_api.js.map +1 -1
- package/lib/axios/esm/horizon/horizon_axios_client.js +1 -1
- package/lib/axios/esm/horizon/server.d.ts +10 -4
- package/lib/axios/esm/horizon/server.js +20 -26
- package/lib/axios/esm/horizon/server.js.map +1 -1
- package/lib/axios/esm/index.js +27 -29
- package/lib/axios/esm/index.js.map +1 -1
- package/lib/axios/esm/rpc/api.d.ts +21 -0
- package/lib/axios/esm/rpc/api.js.map +1 -1
- package/lib/axios/esm/rpc/axios.js +1 -1
- package/lib/axios/esm/rpc/server.d.ts +115 -3
- package/lib/axios/esm/rpc/server.js +181 -13
- package/lib/axios/esm/rpc/server.js.map +1 -1
- package/lib/axios/esm/rpc/transaction.js +2 -20
- package/lib/axios/esm/rpc/transaction.js.map +1 -1
- package/lib/axios/esm/webauth/challenge_transaction.js +7 -22
- package/lib/axios/esm/webauth/challenge_transaction.js.map +1 -1
- package/lib/axios/esm/webauth/utils.js +1 -20
- package/lib/axios/esm/webauth/utils.js.map +1 -1
- package/lib/cjs/base/auth.js +147 -30
- package/lib/cjs/base/auth.js.map +1 -1
- package/lib/cjs/base/index.js +113 -0
- package/lib/cjs/base/index.js.map +1 -0
- package/lib/cjs/base/keypair.js +39 -0
- package/lib/cjs/base/keypair.js.map +1 -1
- package/lib/cjs/base/scval.js +34 -0
- package/lib/cjs/base/scval.js.map +1 -1
- package/lib/cjs/bindings/client.js +170 -0
- package/lib/cjs/bindings/client.js.map +1 -1
- package/lib/cjs/bindings/config.js +1 -1
- package/lib/cjs/bindings/generator.js +45 -16
- package/lib/cjs/bindings/generator.js.map +1 -1
- package/lib/cjs/bindings/types.js +151 -1
- package/lib/cjs/bindings/types.js.map +1 -1
- package/lib/cjs/bindings/utils.js +10 -0
- package/lib/cjs/bindings/utils.js.map +1 -1
- package/lib/cjs/cli/index.js +19 -22
- package/lib/cjs/cli/index.js.map +1 -1
- package/lib/cjs/cli/util.js +1 -20
- package/lib/cjs/cli/util.js.map +1 -1
- package/lib/cjs/contract/assembled_transaction.js +39 -17
- package/lib/cjs/contract/assembled_transaction.js.map +1 -1
- package/lib/cjs/contract/basic_node_signer.js +8 -42
- package/lib/cjs/contract/basic_node_signer.js.map +1 -1
- package/lib/cjs/contract/client.js +56 -3
- package/lib/cjs/contract/client.js.map +1 -1
- package/lib/cjs/contract/event_spec.js +164 -0
- package/lib/cjs/contract/event_spec.js.map +1 -0
- package/lib/cjs/contract/index.js +2 -0
- package/lib/cjs/contract/index.js.map +1 -1
- package/lib/cjs/contract/sent_transaction.js +0 -20
- package/lib/cjs/contract/sent_transaction.js.map +1 -1
- package/lib/cjs/contract/signer.js +96 -0
- package/lib/cjs/contract/signer.js.map +1 -0
- package/lib/cjs/contract/spec.js +107 -3
- package/lib/cjs/contract/spec.js.map +1 -1
- package/lib/cjs/contract/types.js.map +1 -1
- package/lib/cjs/errors/transaction_failed.js +62 -0
- package/lib/cjs/errors/transaction_failed.js.map +1 -0
- package/lib/cjs/errors/wrap_http_error.js +20 -0
- package/lib/cjs/errors/wrap_http_error.js.map +1 -0
- package/lib/cjs/federation/server.js +15 -35
- package/lib/cjs/federation/server.js.map +1 -1
- package/lib/cjs/horizon/account_response.js +0 -20
- package/lib/cjs/horizon/account_response.js.map +1 -1
- package/lib/cjs/horizon/horizon_api.js +5 -0
- package/lib/cjs/horizon/horizon_api.js.map +1 -1
- package/lib/cjs/horizon/horizon_axios_client.js +1 -1
- package/lib/cjs/horizon/server.js +20 -26
- package/lib/cjs/horizon/server.js.map +1 -1
- package/lib/cjs/index.js +66 -65
- package/lib/cjs/index.js.map +1 -1
- package/lib/cjs/rpc/api.js.map +1 -1
- package/lib/cjs/rpc/axios.js +1 -1
- package/lib/cjs/rpc/server.js +181 -13
- package/lib/cjs/rpc/server.js.map +1 -1
- package/lib/cjs/rpc/transaction.js +2 -20
- package/lib/cjs/rpc/transaction.js.map +1 -1
- package/lib/cjs/webauth/challenge_transaction.js +7 -22
- package/lib/cjs/webauth/challenge_transaction.js.map +1 -1
- package/lib/cjs/webauth/utils.js +1 -20
- package/lib/cjs/webauth/utils.js.map +1 -1
- package/lib/esm/base/auth.d.ts +181 -13
- package/lib/esm/base/auth.js +146 -31
- package/lib/esm/base/auth.js.map +1 -1
- package/lib/esm/base/index.d.ts +2 -2
- package/lib/esm/base/index.js +44 -0
- package/lib/esm/base/index.js.map +1 -0
- package/lib/esm/base/keypair.d.ts +27 -0
- package/lib/esm/base/keypair.js +39 -0
- package/lib/esm/base/keypair.js.map +1 -1
- package/lib/esm/base/scval.d.ts +4 -0
- package/lib/esm/base/scval.js +34 -0
- package/lib/esm/base/scval.js.map +1 -1
- package/lib/esm/bindings/client.d.ts +39 -0
- package/lib/esm/bindings/client.js +171 -1
- package/lib/esm/bindings/client.js.map +1 -1
- package/lib/esm/bindings/config.js +1 -1
- package/lib/esm/bindings/generator.d.ts +34 -0
- package/lib/esm/bindings/generator.js +45 -16
- package/lib/esm/bindings/generator.js.map +1 -1
- package/lib/esm/bindings/types.d.ts +42 -0
- package/lib/esm/bindings/types.js +153 -3
- package/lib/esm/bindings/types.js.map +1 -1
- package/lib/esm/bindings/utils.d.ts +10 -0
- package/lib/esm/bindings/utils.js +9 -1
- package/lib/esm/bindings/utils.js.map +1 -1
- package/lib/esm/cli/index.js +19 -22
- package/lib/esm/cli/index.js.map +1 -1
- package/lib/esm/cli/util.d.ts +1 -1
- package/lib/esm/cli/util.js +1 -20
- package/lib/esm/cli/util.js.map +1 -1
- package/lib/esm/contract/assembled_transaction.d.ts +7 -5
- package/lib/esm/contract/assembled_transaction.js +39 -17
- package/lib/esm/contract/assembled_transaction.js.map +1 -1
- package/lib/esm/contract/basic_node_signer.d.ts +3 -0
- package/lib/esm/contract/basic_node_signer.js +8 -42
- package/lib/esm/contract/basic_node_signer.js.map +1 -1
- package/lib/esm/contract/client.d.ts +49 -3
- package/lib/esm/contract/client.js +56 -3
- package/lib/esm/contract/client.js.map +1 -1
- package/lib/esm/contract/event_spec.d.ts +78 -0
- package/lib/esm/contract/event_spec.js +159 -0
- package/lib/esm/contract/event_spec.js.map +1 -0
- package/lib/esm/contract/index.d.ts +3 -0
- package/lib/esm/contract/index.js +1 -0
- package/lib/esm/contract/index.js.map +1 -1
- package/lib/esm/contract/sent_transaction.js +0 -20
- package/lib/esm/contract/sent_transaction.js.map +1 -1
- package/lib/esm/contract/signer.d.ts +104 -0
- package/lib/esm/contract/signer.js +91 -0
- package/lib/esm/contract/signer.js.map +1 -0
- package/lib/esm/contract/spec.d.ts +84 -0
- package/lib/esm/contract/spec.js +107 -3
- package/lib/esm/contract/spec.js.map +1 -1
- package/lib/esm/contract/types.d.ts +25 -8
- package/lib/esm/contract/types.js.map +1 -1
- package/lib/esm/errors/index.d.ts +1 -0
- package/lib/esm/errors/transaction_failed.d.ts +55 -0
- package/lib/esm/errors/transaction_failed.js +60 -0
- package/lib/esm/errors/transaction_failed.js.map +1 -0
- package/lib/esm/errors/wrap_http_error.d.ts +20 -0
- package/lib/esm/errors/wrap_http_error.js +18 -0
- package/lib/esm/errors/wrap_http_error.js.map +1 -0
- package/lib/esm/federation/server.js +15 -35
- package/lib/esm/federation/server.js.map +1 -1
- package/lib/esm/horizon/account_response.js +0 -20
- package/lib/esm/horizon/account_response.js.map +1 -1
- package/lib/esm/horizon/horizon_api.d.ts +12 -1
- package/lib/esm/horizon/horizon_api.js +5 -0
- package/lib/esm/horizon/horizon_api.js.map +1 -1
- package/lib/esm/horizon/horizon_axios_client.js +1 -1
- package/lib/esm/horizon/server.d.ts +10 -4
- package/lib/esm/horizon/server.js +20 -26
- package/lib/esm/horizon/server.js.map +1 -1
- package/lib/esm/index.js +27 -29
- package/lib/esm/index.js.map +1 -1
- package/lib/esm/rpc/api.d.ts +21 -0
- package/lib/esm/rpc/api.js.map +1 -1
- package/lib/esm/rpc/axios.js +1 -1
- package/lib/esm/rpc/server.d.ts +115 -3
- package/lib/esm/rpc/server.js +181 -13
- package/lib/esm/rpc/server.js.map +1 -1
- package/lib/esm/rpc/transaction.js +2 -20
- package/lib/esm/rpc/transaction.js.map +1 -1
- package/lib/esm/webauth/challenge_transaction.js +7 -22
- package/lib/esm/webauth/challenge_transaction.js.map +1 -1
- package/lib/esm/webauth/utils.js +1 -20
- package/lib/esm/webauth/utils.js.map +1 -1
- package/package.json +35 -30
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"challenge_transaction.js","sources":["../../../src/webauth/challenge_transaction.ts"],"sourcesContent":["import {\n Keypair,\n Account,\n TransactionBuilder,\n BASE_FEE,\n Operation,\n Memo,\n MemoNone,\n MemoID,\n FeeBumpTransaction,\n TimeoutInfinite,\n Transaction,\n Networks,\n} from \"../base/index.js\";\nimport { InvalidChallengeError } from \"./errors.js\";\nimport { gatherTxSigners, verifyTxSignedBy } from \"./utils.js\";\nimport { Utils } from \"../utils.js\";\nimport { ServerApi } from \"../horizon/server_api.js\";\nimport { uint8ArrayToBase64 } from \"uint8array-extras\";\n\n/**\n * Returns a valid {@link https://stellar.org/protocol/sep-10 | SEP-10}\n * challenge transaction which you can use for Stellar Web Authentication.\n * @param serverKeypair - Keypair for server's signing account.\n * @param clientAccountID - The stellar account (G...) or muxed account\n * (M...) that the wallet wishes to authenticate with the server.\n * @param homeDomain - The fully qualified domain name of the service\n * requiring authentication\n * @param timeout - Challenge duration (default to 5 minutes).\n * @param networkPassphrase - The network passphrase. If you pass this\n * argument then timeout is required.\n * @param webAuthDomain - The fully qualified domain name of the service\n * issuing the challenge.\n * @param memo - The memo to attach to the challenge transaction. The\n * memo must be of type `id`. If the `clientaccountID` is a muxed account,\n * memos cannot be used.\n * @param clientDomain - The fully qualified domain of the client\n * requesting the challenge. Only necessary when the 'client_domain'\n * parameter is passed.\n * @param clientSigningKey - The public key assigned to the SIGNING_KEY\n * attribute specified on the stellar.toml hosted on the client domain. Only\n * necessary when the 'client_domain' parameter is passed.\n * @returns A base64 encoded string of the raw TransactionEnvelope xdr\n * struct for the transaction.\n * @throws Will throw if `clientAccountID` is a muxed account, and `memo`\n * is present.\n * @throws Will throw if `clientDomain` is provided, but\n * `clientSigningKey` is missing\n * @see {@link https://stellar.org/protocol/sep-10 | SEP-10: Stellar Web Auth}\n * @example\n * ```ts\n * import { Keypair, Networks, WebAuth } from 'stellar-sdk'\n *\n * let serverKeyPair = Keypair.fromSecret(\"server-secret\")\n * let challenge = WebAuth.buildChallengeTx(\n * serverKeyPair,\n * \"client-stellar-account-id\",\n * \"stellar.org\",\n * 300,\n * Networks.TESTNET);\n * ```\n */\nexport function buildChallengeTx(\n serverKeypair: Keypair,\n clientAccountID: string,\n homeDomain: string,\n\n timeout: number = 300,\n networkPassphrase: string,\n webAuthDomain: string,\n memo: string | null = null,\n clientDomain: string | null = null,\n clientSigningKey: string | null = null,\n): string {\n if (clientAccountID.startsWith(\"M\") && memo) {\n throw Error(\"memo cannot be used if clientAccountID is a muxed account\");\n }\n\n const account = new Account(serverKeypair.publicKey(), \"-1\");\n const now = Math.floor(Date.now() / 1000);\n\n // A Base64 digit represents 6 bits, to generate a random 64 bytes\n // base64 string, we need 48 random bytes = (64 * 6)/8\n //\n // Each Base64 digit is in ASCII and each ASCII characters when\n // turned into binary represents 8 bits = 1 bytes.\n const value = uint8ArrayToBase64(crypto.getRandomValues(new Uint8Array(48)));\n\n const builder = new TransactionBuilder(account, {\n fee: BASE_FEE,\n networkPassphrase,\n timebounds: {\n minTime: now,\n maxTime: now + timeout,\n },\n })\n .addOperation(\n Operation.manageData({\n name: `${homeDomain} auth`,\n value,\n source: clientAccountID,\n }),\n )\n .addOperation(\n Operation.manageData({\n name: \"web_auth_domain\",\n value: webAuthDomain,\n source: account.accountId(),\n }),\n );\n\n if (clientDomain) {\n if (!clientSigningKey) {\n throw Error(\"clientSigningKey is required if clientDomain is provided\");\n }\n builder.addOperation(\n Operation.manageData({\n name: `client_domain`,\n value: clientDomain,\n source: clientSigningKey,\n }),\n );\n }\n\n if (memo) {\n builder.addMemo(Memo.id(memo));\n }\n\n const transaction = builder.build();\n transaction.sign(serverKeypair);\n\n return transaction.toEnvelope().toXDR(\"base64\").toString();\n}\n\n/**\n * Reads a SEP-10 challenge transaction and returns the decoded transaction and\n * client account ID contained within.\n *\n * It also verifies that the transaction has been signed by the server.\n *\n * It does not verify that the transaction has been signed by the client or that\n * any signatures other than the server's on the transaction are valid. Use one\n * of the following functions to completely verify the transaction:\n *\n * - {@link WebAuth.verifyChallengeTxThreshold}\n * - {@link WebAuth.verifyChallengeTxSigners}\n * @param challengeTx - SEP0010 challenge transaction in base64.\n * @param serverAccountID - The server's stellar account (public key).\n * @param networkPassphrase - The network passphrase, e.g.: 'Test SDF\n * Network ; September 2015' (see {@link Networks})\n * @param homeDomains - The home domain that is expected\n * to be included in the first Manage Data operation's string key. If an\n * array is provided, one of the domain names in the array must match.\n * @param webAuthDomain - The home domain that is expected to be included\n * as the value of the Manage Data operation with the 'web_auth_domain' key.\n * If no such operation is included, this parameter is not used.\n * @returns The actual transaction and the\n * Stellar public key (master key) used to sign the Manage Data operation,\n * the matched home domain, and the memo attached to the transaction, which\n * will be null if not present.\n * @see {@link https://stellar.org/protocol/sep-10 | SEP-10: Stellar Web Auth}\n */\nexport function readChallengeTx(\n challengeTx: string,\n serverAccountID: string,\n networkPassphrase: string,\n homeDomains: string | string[],\n webAuthDomain: string,\n): {\n tx: Transaction;\n clientAccountID: string;\n matchedHomeDomain: string;\n memo: string | null;\n} {\n if (serverAccountID.startsWith(\"M\")) {\n throw Error(\n \"Invalid serverAccountID: multiplexed accounts are not supported.\",\n );\n }\n\n let transaction;\n try {\n transaction = new Transaction(challengeTx, networkPassphrase);\n } catch {\n try {\n transaction = new FeeBumpTransaction(challengeTx, networkPassphrase);\n } catch {\n throw new InvalidChallengeError(\n \"Invalid challenge: unable to deserialize challengeTx transaction string\",\n );\n }\n throw new InvalidChallengeError(\n \"Invalid challenge: expected a Transaction but received a FeeBumpTransaction\",\n );\n }\n\n // verify sequence number\n const sequence = Number.parseInt(transaction.sequence, 10);\n\n if (sequence !== 0) {\n throw new InvalidChallengeError(\n \"The transaction sequence number should be zero\",\n );\n }\n\n // verify transaction source\n if (transaction.source !== serverAccountID) {\n throw new InvalidChallengeError(\n \"The transaction source account is not equal to the server's account\",\n );\n }\n\n // verify operation\n if (transaction.operations.length < 1) {\n throw new InvalidChallengeError(\n \"The transaction should contain at least one operation\",\n );\n }\n\n const [operation, ...subsequentOperations] = transaction.operations;\n\n if (!operation.source) {\n throw new InvalidChallengeError(\n \"The transaction's operation should contain a source account\",\n );\n }\n const clientAccountID: string = operation.source!;\n\n let memo: string | null = null;\n if (transaction.memo.type !== MemoNone) {\n if (clientAccountID.startsWith(\"M\")) {\n throw new InvalidChallengeError(\n \"The transaction has a memo but the client account ID is a muxed account\",\n );\n }\n if (transaction.memo.type !== MemoID) {\n throw new InvalidChallengeError(\n \"The transaction's memo must be of type `id`\",\n );\n }\n memo = transaction.memo.value as string;\n }\n\n if (operation.type !== \"manageData\") {\n throw new InvalidChallengeError(\n \"The transaction's operation type should be 'manageData'\",\n );\n }\n\n // verify timebounds\n if (\n transaction.timeBounds &&\n Number.parseInt(transaction.timeBounds?.maxTime, 10) === TimeoutInfinite\n ) {\n throw new InvalidChallengeError(\n \"The transaction requires non-infinite timebounds\",\n );\n }\n\n // give a small grace period for the transaction time to account for clock drift\n if (!Utils.validateTimebounds(transaction, 60 * 5)) {\n throw new InvalidChallengeError(\"The transaction has expired\");\n }\n\n if (operation.value === undefined) {\n throw new InvalidChallengeError(\n \"The transaction's operation values should not be null\",\n );\n }\n\n // verify base64\n if (!operation.value) {\n throw new InvalidChallengeError(\n \"The transaction's operation value should not be null\",\n );\n }\n\n if (Buffer.from(operation.value.toString(), \"base64\").length !== 48) {\n throw new InvalidChallengeError(\n \"The transaction's operation value should be a 64 bytes base64 random string\",\n );\n }\n\n // verify homeDomains\n if (!homeDomains) {\n throw new InvalidChallengeError(\n \"Invalid homeDomains: a home domain must be provided for verification\",\n );\n }\n\n let matchedHomeDomain;\n\n if (typeof homeDomains === \"string\") {\n if (`${homeDomains} auth` === operation.name) {\n matchedHomeDomain = homeDomains;\n }\n } else if (Array.isArray(homeDomains)) {\n matchedHomeDomain = homeDomains.find(\n (domain) => `${domain} auth` === operation.name,\n );\n } else {\n throw new InvalidChallengeError(\n `Invalid homeDomains: homeDomains type is ${typeof homeDomains} but should be a string or an array`,\n );\n }\n\n if (!matchedHomeDomain) {\n throw new InvalidChallengeError(\n \"Invalid homeDomains: the transaction's operation key name does not match the expected home domain\",\n );\n }\n\n // verify any subsequent operations are manage data ops and source account is the server\n for (const op of subsequentOperations) {\n if (op.type !== \"manageData\") {\n throw new InvalidChallengeError(\n \"The transaction has operations that are not of type 'manageData'\",\n );\n }\n if (op.source !== serverAccountID && op.name !== \"client_domain\") {\n throw new InvalidChallengeError(\n \"The transaction has operations that are unrecognized\",\n );\n }\n if (op.name === \"web_auth_domain\") {\n if (op.value === undefined) {\n throw new InvalidChallengeError(\n \"'web_auth_domain' operation value should not be null\",\n );\n }\n if (op.value.compare(Buffer.from(webAuthDomain))) {\n throw new InvalidChallengeError(\n `'web_auth_domain' operation value does not match ${webAuthDomain}`,\n );\n }\n }\n }\n\n if (!verifyTxSignedBy(transaction, serverAccountID)) {\n throw new InvalidChallengeError(\n `Transaction not signed by server: '${serverAccountID}'`,\n );\n }\n\n return { tx: transaction, clientAccountID, matchedHomeDomain, memo };\n}\n\n/**\n * Verifies that for a SEP 10 challenge transaction all signatures on the\n * transaction are accounted for. A transaction is verified if it is signed by\n * the server account, and all other signatures match a signer that has been\n * provided as an argument (as the accountIDs list). Additional signers can be\n * provided that do not have a signature, but all signatures must be matched to\n * a signer (accountIDs) for verification to succeed. If verification succeeds,\n * a list of signers that were found is returned, not including the server\n * account ID.\n *\n * Signers that are not prefixed as an address/account ID strkey (G...) will be\n * ignored.\n *\n * Errors will be raised if:\n * - The transaction is invalid according to\n * {@link WebAuth.readChallengeTx}.\n * - No client signatures are found on the transaction.\n * - One or more signatures in the transaction are not identifiable as the\n * server account or one of the signers provided in the arguments.\n * @param challengeTx - SEP0010 challenge transaction in base64.\n * @param serverAccountID - The server's stellar account (public key).\n * @param networkPassphrase - The network passphrase, e.g.: 'Test SDF\n * Network ; September 2015' (see {@link Networks}).\n * @param signers - The signers public keys. This list should\n * contain the public keys for all signers that have signed the transaction.\n * @param homeDomains - The home domain(s) that should\n * be included in the first Manage Data operation's string key. Required in\n * readChallengeTx().\n * @param webAuthDomain - The home domain that is expected to be included\n * as the value of the Manage Data operation with the 'web_auth_domain' key,\n * if present. Used in readChallengeTx().\n * @returns The list of signers public keys that have signed\n * the transaction, excluding the server account ID.\n * @see {@link https://stellar.org/protocol/sep-10 | SEP-10: Stellar Web Auth}\n * @example\n * ```ts\n * import { Networks, TransactionBuilder, WebAuth } from 'stellar-sdk';\n *\n * const serverKP = Keypair.random();\n * const clientKP1 = Keypair.random();\n * const clientKP2 = Keypair.random();\n *\n * // Challenge, possibly built in the server side\n * const challenge = WebAuth.buildChallengeTx(\n * serverKP,\n * clientKP1.publicKey(),\n * \"SDF\",\n * 300,\n * Networks.TESTNET\n * );\n *\n * // clock.tick(200); // Simulates a 200 ms delay when communicating from server to client\n *\n * // Transaction gathered from a challenge, possibly from the client side\n * const transaction = TransactionBuilder.fromXDR(challenge, Networks.TESTNET);\n * transaction.sign(clientKP1, clientKP2);\n * const signedChallenge = transaction\n * .toEnvelope()\n * .toXDR(\"base64\")\n * .toString();\n *\n * // The result below should be equal to [clientKP1.publicKey(), clientKP2.publicKey()]\n * WebAuth.verifyChallengeTxSigners(\n * signedChallenge,\n * serverKP.publicKey(),\n * Networks.TESTNET,\n * threshold,\n * [clientKP1.publicKey(), clientKP2.publicKey()]\n * );\n * ```\n */\nexport function verifyChallengeTxSigners(\n challengeTx: string,\n serverAccountID: string,\n networkPassphrase: string,\n signers: string[],\n homeDomains: string | string[],\n webAuthDomain: string,\n): string[] {\n // Read the transaction which validates its structure.\n const { tx } = readChallengeTx(\n challengeTx,\n serverAccountID,\n networkPassphrase,\n homeDomains,\n webAuthDomain,\n );\n\n // Ensure the server account ID is an address and not a seed.\n let serverKP: Keypair;\n try {\n serverKP = Keypair.fromPublicKey(serverAccountID); // can throw 'Invalid Stellar public key'\n } catch (err: any) {\n throw new Error(\n `Couldn't infer keypair from the provided 'serverAccountID': ${\n err.message\n }`,\n );\n }\n\n // Deduplicate the client signers and ensure the server is not included\n // anywhere we check or output the list of signers.\n const clientSigners = new Set<string>();\n for (const signer of signers) {\n // Ignore the server signer if it is in the signers list. It's\n // important when verifying signers of a challenge transaction that we\n // only verify and return client signers. If an account has the server\n // as a signer the server should not play a part in the authentication\n // of the client.\n if (signer === serverKP.publicKey()) {\n continue;\n }\n\n // Ignore non-G... account/address signers.\n if (signer.charAt(0) !== \"G\") {\n continue;\n }\n\n clientSigners.add(signer);\n }\n\n // Don't continue if none of the signers provided are in the final list.\n if (clientSigners.size === 0) {\n throw new InvalidChallengeError(\n \"No verifiable client signers provided, at least one G... address must be provided\",\n );\n }\n\n let clientSigningKey;\n for (const op of tx.operations) {\n if (op.type === \"manageData\" && op.name === \"client_domain\") {\n if (clientSigningKey) {\n throw new InvalidChallengeError(\n \"Found more than one client_domain operation\",\n );\n }\n clientSigningKey = op.source;\n }\n }\n\n // Verify all the transaction's signers (server and client) in one\n // hit. We do this in one hit here even though the server signature was\n // checked in the ReadChallengeTx to ensure that every signature and signer\n // are consumed only once on the transaction.\n const allSigners: string[] = [\n serverKP.publicKey(),\n ...Array.from(clientSigners),\n ];\n if (clientSigningKey) {\n allSigners.push(clientSigningKey);\n }\n\n const signersFound: string[] = gatherTxSigners(tx, allSigners);\n\n let serverSignatureFound = false;\n let clientSigningKeySignatureFound = false;\n for (const signer of signersFound) {\n if (signer === serverKP.publicKey()) {\n serverSignatureFound = true;\n }\n if (signer === clientSigningKey) {\n clientSigningKeySignatureFound = true;\n }\n }\n\n // Confirm we matched a signature to the server signer.\n if (!serverSignatureFound) {\n throw new InvalidChallengeError(\n `Transaction not signed by server: '${serverKP.publicKey()}'`,\n );\n }\n\n // Confirm we matched a signature to the client domain's signer\n if (clientSigningKey && !clientSigningKeySignatureFound) {\n throw new InvalidChallengeError(\n \"Transaction not signed by the source account of the 'client_domain' \" +\n \"ManageData operation\",\n );\n }\n\n // Confirm we matched at least one given signer with the transaction signatures\n if (signersFound.length === 1) {\n throw new InvalidChallengeError(\n \"None of the given signers match the transaction signatures\",\n );\n }\n\n // Confirm all signatures, including the server signature, were consumed by a signer:\n if (signersFound.length !== tx.signatures.length) {\n throw new InvalidChallengeError(\"Transaction has unrecognized signatures\");\n }\n\n // Remove the server public key before returning\n signersFound.splice(signersFound.indexOf(serverKP.publicKey()), 1);\n if (clientSigningKey) {\n // Remove the client domain public key public key before returning\n signersFound.splice(signersFound.indexOf(clientSigningKey), 1);\n }\n\n if (signersFound.length === 0) {\n throw new InvalidChallengeError(\n \"None of the given signers match the transaction signatures\",\n );\n }\n\n return signersFound;\n}\n\n/**\n * Verifies that for a SEP-10 challenge transaction all signatures on the\n * transaction are accounted for and that the signatures meet a threshold on an\n * account. A transaction is verified if it is signed by the server account, and\n * all other signatures match a signer that has been provided as an argument,\n * and those signatures meet a threshold on the account.\n *\n * Signers that are not prefixed as an address/account ID strkey (G...) will be\n * ignored.\n *\n * Errors will be raised if:\n * - The transaction is invalid according to\n * {@link WebAuth.readChallengeTx}.\n * - No client signatures are found on the transaction.\n * - One or more signatures in the transaction are not identifiable as the\n * server account or one of the signers provided in the arguments.\n * - The signatures are all valid but do not meet the threshold.\n * @param challengeTx - SEP0010 challenge transaction in base64.\n * @param serverAccountID - The server's stellar account (public key).\n * @param networkPassphrase - The network passphrase, e.g.: 'Test SDF\n * Network ; September 2015' (see {@link Networks}).\n * @param threshold - The required signatures threshold for verifying\n * this transaction.\n * @param signerSummary - a map of all\n * authorized signers to their weights. It's used to validate if the\n * transaction signatures have met the given threshold.\n * @param homeDomains - The home domain(s) that should\n * be included in the first Manage Data operation's string key. Required in\n * `verifyChallengeTxSigners() => readChallengeTx()`.\n * @param webAuthDomain - The home domain that is expected to be included\n * as the value of the Manage Data operation with the 'web_auth_domain' key,\n * if present. Used in `verifyChallengeTxSigners() => readChallengeTx()`.\n * @returns The list of signers public keys that have signed\n * the transaction, excluding the server account ID, given that the threshold\n * was met.\n * @throws Will throw if the collective\n * weight of the transaction's signers does not meet the necessary threshold\n * to verify this transaction.\n * @see {@link https://stellar.org/protocol/sep-10 | SEP-10: Stellar Web Auth}\n * @example\n * ```ts\n * import { Networks, TransactionBuilder, WebAuth } from 'stellar-sdk';\n *\n * const serverKP = Keypair.random();\n * const clientKP1 = Keypair.random();\n * const clientKP2 = Keypair.random();\n *\n * // Challenge, possibly built in the server side\n * const challenge = WebAuth.buildChallengeTx(\n * serverKP,\n * clientKP1.publicKey(),\n * \"SDF\",\n * 300,\n * Networks.TESTNET\n * );\n *\n * // clock.tick(200); // Simulates a 200 ms delay when communicating from server to client\n *\n * // Transaction gathered from a challenge, possibly from the client side\n * const transaction = TransactionBuilder.fromXDR(challenge, Networks.TESTNET);\n * transaction.sign(clientKP1, clientKP2);\n * const signedChallenge = transaction\n * .toEnvelope()\n * .toXDR(\"base64\")\n * .toString();\n *\n * // Defining the threshold and signerSummary\n * const threshold = 3;\n * const signerSummary = [\n * {\n * key: this.clientKP1.publicKey(),\n * weight: 1,\n * },\n * {\n * key: this.clientKP2.publicKey(),\n * weight: 2,\n * },\n * ];\n *\n * // The result below should be equal to [clientKP1.publicKey(), clientKP2.publicKey()]\n * WebAuth.verifyChallengeTxThreshold(\n * signedChallenge,\n * serverKP.publicKey(),\n * Networks.TESTNET,\n * threshold,\n * signerSummary\n * );\n * ```\n */\nexport function verifyChallengeTxThreshold(\n challengeTx: string,\n serverAccountID: string,\n networkPassphrase: string,\n threshold: number,\n signerSummary: ServerApi.AccountRecordSigners[],\n homeDomains: string | string[],\n webAuthDomain: string,\n): string[] {\n const signers = signerSummary.map((signer) => signer.key);\n\n const signersFound = verifyChallengeTxSigners(\n challengeTx,\n serverAccountID,\n networkPassphrase,\n signers,\n homeDomains,\n webAuthDomain,\n );\n\n let weight = 0;\n for (const signer of signersFound) {\n const sigWeight = signerSummary.find((s) => s.key === signer)?.weight || 0;\n weight += sigWeight;\n }\n\n if (weight < threshold) {\n throw new InvalidChallengeError(\n `signers with weight ${weight} do not meet threshold ${threshold}\"`,\n );\n }\n\n return signersFound;\n}\n"],"names":["memo","account","Account","uint8ArrayToBase64","TransactionBuilder","BASE_FEE","Operation","Memo","transaction","Transaction","FeeBumpTransaction","InvalidChallengeError","MemoNone","MemoID","TimeoutInfinite","Utils","Buffer","verifyTxSignedBy","Keypair","gatherTxSigners"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"challenge_transaction.js","sources":["../../../src/webauth/challenge_transaction.ts"],"sourcesContent":["import {\n Keypair,\n Account,\n TransactionBuilder,\n BASE_FEE,\n Operation,\n Memo,\n MemoNone,\n MemoID,\n FeeBumpTransaction,\n TimeoutInfinite,\n Transaction,\n Networks,\n} from \"../base/index.js\";\nimport { InvalidChallengeError } from \"./errors.js\";\nimport { gatherTxSigners, verifyTxSignedBy } from \"./utils.js\";\nimport { Utils } from \"../utils.js\";\nimport { ServerApi } from \"../horizon/server_api.js\";\nimport { uint8ArrayToBase64 } from \"uint8array-extras\";\n\n/**\n * Returns a valid {@link https://stellar.org/protocol/sep-10 | SEP-10}\n * challenge transaction which you can use for Stellar Web Authentication.\n * @param serverKeypair - Keypair for server's signing account.\n * @param clientAccountID - The stellar account (G...) or muxed account\n * (M...) that the wallet wishes to authenticate with the server.\n * @param homeDomain - The fully qualified domain name of the service\n * requiring authentication\n * @param timeout - Challenge duration (default to 5 minutes).\n * @param networkPassphrase - The network passphrase. If you pass this\n * argument then timeout is required.\n * @param webAuthDomain - The fully qualified domain name of the service\n * issuing the challenge.\n * @param memo - The memo to attach to the challenge transaction. The\n * memo must be of type `id`. If the `clientaccountID` is a muxed account,\n * memos cannot be used.\n * @param clientDomain - The fully qualified domain of the client\n * requesting the challenge. Only necessary when the 'client_domain'\n * parameter is passed.\n * @param clientSigningKey - The public key assigned to the SIGNING_KEY\n * attribute specified on the stellar.toml hosted on the client domain. Only\n * necessary when the 'client_domain' parameter is passed.\n * @returns A base64 encoded string of the raw TransactionEnvelope xdr\n * struct for the transaction.\n * @throws Will throw if `clientAccountID` is a muxed account, and `memo`\n * is present.\n * @throws Will throw if `clientDomain` is provided, but\n * `clientSigningKey` is missing\n * @see {@link https://stellar.org/protocol/sep-10 | SEP-10: Stellar Web Auth}\n * @example\n * ```ts\n * import { Keypair, Networks, WebAuth } from 'stellar-sdk'\n *\n * let serverKeyPair = Keypair.fromSecret(\"server-secret\")\n * let challenge = WebAuth.buildChallengeTx(\n * serverKeyPair,\n * \"client-stellar-account-id\",\n * \"stellar.org\",\n * 300,\n * Networks.TESTNET);\n * ```\n */\nexport function buildChallengeTx(\n serverKeypair: Keypair,\n clientAccountID: string,\n homeDomain: string,\n\n timeout: number = 300,\n networkPassphrase: string,\n webAuthDomain: string,\n memo: string | null = null,\n clientDomain: string | null = null,\n clientSigningKey: string | null = null,\n): string {\n if (clientAccountID.startsWith(\"M\") && memo) {\n throw Error(\"memo cannot be used if clientAccountID is a muxed account\");\n }\n\n const account = new Account(serverKeypair.publicKey(), \"-1\");\n const now = Math.floor(Date.now() / 1000);\n\n // A Base64 digit represents 6 bits, to generate a random 64 bytes\n // base64 string, we need 48 random bytes = (64 * 6)/8\n //\n // Each Base64 digit is in ASCII and each ASCII characters when\n // turned into binary represents 8 bits = 1 bytes.\n const value = uint8ArrayToBase64(crypto.getRandomValues(new Uint8Array(48)));\n\n const builder = new TransactionBuilder(account, {\n fee: BASE_FEE,\n networkPassphrase,\n timebounds: {\n minTime: now,\n maxTime: now + timeout,\n },\n })\n .addOperation(\n Operation.manageData({\n name: `${homeDomain} auth`,\n value,\n source: clientAccountID,\n }),\n )\n .addOperation(\n Operation.manageData({\n name: \"web_auth_domain\",\n value: webAuthDomain,\n source: account.accountId(),\n }),\n );\n\n if (clientDomain) {\n if (!clientSigningKey) {\n throw Error(\"clientSigningKey is required if clientDomain is provided\");\n }\n builder.addOperation(\n Operation.manageData({\n name: `client_domain`,\n value: clientDomain,\n source: clientSigningKey,\n }),\n );\n }\n\n if (memo) {\n builder.addMemo(Memo.id(memo));\n }\n\n const transaction = builder.build();\n transaction.sign(serverKeypair);\n\n return transaction.toEnvelope().toXDR(\"base64\").toString();\n}\n\n/**\n * Reads a SEP-10 challenge transaction and returns the decoded transaction and\n * client account ID contained within.\n *\n * It also verifies that the transaction has been signed by the server.\n *\n * It does not verify that the transaction has been signed by the client or that\n * any signatures other than the server's on the transaction are valid. Use one\n * of the following functions to completely verify the transaction:\n *\n * - {@link WebAuth.verifyChallengeTxThreshold}\n * - {@link WebAuth.verifyChallengeTxSigners}\n * @param challengeTx - SEP0010 challenge transaction in base64.\n * @param serverAccountID - The server's stellar account (public key).\n * @param networkPassphrase - The network passphrase, e.g.: 'Test SDF\n * Network ; September 2015' (see {@link Networks})\n * @param homeDomains - The home domain that is expected\n * to be included in the first Manage Data operation's string key. If an\n * array is provided, one of the domain names in the array must match.\n * @param webAuthDomain - The home domain that is expected to be included\n * as the value of the Manage Data operation with the 'web_auth_domain' key.\n * If no such operation is included, this parameter is not used.\n * @returns The actual transaction and the\n * Stellar public key (master key) used to sign the Manage Data operation,\n * the matched home domain, and the memo attached to the transaction, which\n * will be null if not present.\n * @see {@link https://stellar.org/protocol/sep-10 | SEP-10: Stellar Web Auth}\n */\nexport function readChallengeTx(\n challengeTx: string,\n serverAccountID: string,\n networkPassphrase: string,\n homeDomains: string | string[],\n webAuthDomain: string,\n): {\n tx: Transaction;\n clientAccountID: string;\n matchedHomeDomain: string;\n memo: string | null;\n} {\n if (serverAccountID.startsWith(\"M\")) {\n throw Error(\n \"Invalid serverAccountID: multiplexed accounts are not supported.\",\n );\n }\n\n let transaction;\n try {\n transaction = new Transaction(challengeTx, networkPassphrase);\n } catch {\n try {\n transaction = new FeeBumpTransaction(challengeTx, networkPassphrase);\n } catch {\n throw new InvalidChallengeError(\n \"Invalid challenge: unable to deserialize challengeTx transaction string\",\n );\n }\n throw new InvalidChallengeError(\n \"Invalid challenge: expected a Transaction but received a FeeBumpTransaction\",\n );\n }\n\n // verify sequence number\n const sequence = Number.parseInt(transaction.sequence, 10);\n\n if (sequence !== 0) {\n throw new InvalidChallengeError(\n \"The transaction sequence number should be zero\",\n );\n }\n\n // verify transaction source\n if (transaction.source !== serverAccountID) {\n throw new InvalidChallengeError(\n \"The transaction source account is not equal to the server's account\",\n );\n }\n\n // verify operation\n if (transaction.operations.length < 1) {\n throw new InvalidChallengeError(\n \"The transaction should contain at least one operation\",\n );\n }\n\n const [operation, ...subsequentOperations] = transaction.operations;\n\n if (!operation.source) {\n throw new InvalidChallengeError(\n \"The transaction's operation should contain a source account\",\n );\n }\n const clientAccountID: string = operation.source!;\n\n let memo: string | null = null;\n if (transaction.memo.type !== MemoNone) {\n if (clientAccountID.startsWith(\"M\")) {\n throw new InvalidChallengeError(\n \"The transaction has a memo but the client account ID is a muxed account\",\n );\n }\n if (transaction.memo.type !== MemoID) {\n throw new InvalidChallengeError(\n \"The transaction's memo must be of type `id`\",\n );\n }\n memo = transaction.memo.value as string;\n }\n\n if (operation.type !== \"manageData\") {\n throw new InvalidChallengeError(\n \"The transaction's operation type should be 'manageData'\",\n );\n }\n\n // verify timebounds\n if (\n transaction.timeBounds &&\n Number.parseInt(transaction.timeBounds?.maxTime, 10) === TimeoutInfinite\n ) {\n throw new InvalidChallengeError(\n \"The transaction requires non-infinite timebounds\",\n );\n }\n\n // give a small grace period for the transaction time to account for clock drift\n if (!Utils.validateTimebounds(transaction, 60 * 5)) {\n throw new InvalidChallengeError(\"The transaction has expired\");\n }\n\n if (operation.value === undefined) {\n throw new InvalidChallengeError(\n \"The transaction's operation values should not be null\",\n );\n }\n\n // verify base64\n if (!operation.value) {\n throw new InvalidChallengeError(\n \"The transaction's operation value should not be null\",\n );\n }\n\n if (Buffer.from(operation.value.toString(), \"base64\").length !== 48) {\n throw new InvalidChallengeError(\n \"The transaction's operation value should be a 64 bytes base64 random string\",\n );\n }\n\n // verify homeDomains\n if (!homeDomains) {\n throw new InvalidChallengeError(\n \"Invalid homeDomains: a home domain must be provided for verification\",\n );\n }\n\n let matchedHomeDomain;\n\n if (typeof homeDomains === \"string\") {\n if (`${homeDomains} auth` === operation.name) {\n matchedHomeDomain = homeDomains;\n }\n } else if (Array.isArray(homeDomains)) {\n matchedHomeDomain = homeDomains.find(\n (domain) => `${domain} auth` === operation.name,\n );\n } else {\n throw new InvalidChallengeError(\n `Invalid homeDomains: homeDomains type is ${typeof homeDomains} but should be a string or an array`,\n );\n }\n\n if (!matchedHomeDomain) {\n throw new InvalidChallengeError(\n \"Invalid homeDomains: the transaction's operation key name does not match the expected home domain\",\n );\n }\n\n // verify any subsequent operations are manage data ops and source account is the server\n for (const op of subsequentOperations) {\n if (op.type !== \"manageData\") {\n throw new InvalidChallengeError(\n \"The transaction has operations that are not of type 'manageData'\",\n );\n }\n if (op.source !== serverAccountID && op.name !== \"client_domain\") {\n throw new InvalidChallengeError(\n \"The transaction has operations that are unrecognized\",\n );\n }\n if (op.name === \"web_auth_domain\") {\n if (op.value === undefined) {\n throw new InvalidChallengeError(\n \"'web_auth_domain' operation value should not be null\",\n );\n }\n if (op.value.compare(Buffer.from(webAuthDomain))) {\n throw new InvalidChallengeError(\n `'web_auth_domain' operation value does not match ${webAuthDomain}`,\n );\n }\n }\n }\n\n if (!verifyTxSignedBy(transaction, serverAccountID)) {\n throw new InvalidChallengeError(\n `Transaction not signed by server: '${serverAccountID}'`,\n );\n }\n\n return { tx: transaction, clientAccountID, matchedHomeDomain, memo };\n}\n\n/**\n * Verifies that for a SEP 10 challenge transaction all signatures on the\n * transaction are accounted for. A transaction is verified if it is signed by\n * the server account, and all other signatures match a signer that has been\n * provided as an argument (as the accountIDs list). Additional signers can be\n * provided that do not have a signature, but all signatures must be matched to\n * a signer (accountIDs) for verification to succeed. If verification succeeds,\n * a list of signers that were found is returned, not including the server\n * account ID.\n *\n * Signers that are not prefixed as an address/account ID strkey (G...) will be\n * ignored.\n *\n * Errors will be raised if:\n * - The transaction is invalid according to\n * {@link WebAuth.readChallengeTx}.\n * - No client signatures are found on the transaction.\n * - One or more signatures in the transaction are not identifiable as the\n * server account or one of the signers provided in the arguments.\n * @param challengeTx - SEP0010 challenge transaction in base64.\n * @param serverAccountID - The server's stellar account (public key).\n * @param networkPassphrase - The network passphrase, e.g.: 'Test SDF\n * Network ; September 2015' (see {@link Networks}).\n * @param signers - The signers public keys. This list should\n * contain the public keys for all signers that have signed the transaction.\n * @param homeDomains - The home domain(s) that should\n * be included in the first Manage Data operation's string key. Required in\n * readChallengeTx().\n * @param webAuthDomain - The home domain that is expected to be included\n * as the value of the Manage Data operation with the 'web_auth_domain' key,\n * if present. Used in readChallengeTx().\n * @returns The list of signers public keys that have signed\n * the transaction, excluding the server account ID.\n * @see {@link https://stellar.org/protocol/sep-10 | SEP-10: Stellar Web Auth}\n * @example\n * ```ts\n * import { Networks, TransactionBuilder, WebAuth } from 'stellar-sdk';\n *\n * const serverKP = Keypair.random();\n * const clientKP1 = Keypair.random();\n * const clientKP2 = Keypair.random();\n *\n * // Challenge, possibly built in the server side\n * const challenge = WebAuth.buildChallengeTx(\n * serverKP,\n * clientKP1.publicKey(),\n * \"SDF\",\n * 300,\n * Networks.TESTNET\n * );\n *\n * // clock.tick(200); // Simulates a 200 ms delay when communicating from server to client\n *\n * // Transaction gathered from a challenge, possibly from the client side\n * const transaction = TransactionBuilder.fromXDR(challenge, Networks.TESTNET);\n * transaction.sign(clientKP1, clientKP2);\n * const signedChallenge = transaction\n * .toEnvelope()\n * .toXDR(\"base64\")\n * .toString();\n *\n * // The result below should be equal to [clientKP1.publicKey(), clientKP2.publicKey()]\n * WebAuth.verifyChallengeTxSigners(\n * signedChallenge,\n * serverKP.publicKey(),\n * Networks.TESTNET,\n * threshold,\n * [clientKP1.publicKey(), clientKP2.publicKey()]\n * );\n * ```\n */\nexport function verifyChallengeTxSigners(\n challengeTx: string,\n serverAccountID: string,\n networkPassphrase: string,\n signers: string[],\n homeDomains: string | string[],\n webAuthDomain: string,\n): string[] {\n // Read the transaction which validates its structure.\n const { tx } = readChallengeTx(\n challengeTx,\n serverAccountID,\n networkPassphrase,\n homeDomains,\n webAuthDomain,\n );\n\n // Ensure the server account ID is an address and not a seed.\n let serverKP: Keypair;\n try {\n serverKP = Keypair.fromPublicKey(serverAccountID); // can throw 'Invalid Stellar public key'\n } catch (err: any) {\n throw new Error(\n `Couldn't infer keypair from the provided 'serverAccountID': ${\n err.message\n }`,\n );\n }\n\n // Deduplicate the client signers and ensure the server is not included\n // anywhere we check or output the list of signers.\n const clientSigners = new Set<string>();\n for (const signer of signers) {\n // Ignore the server signer if it is in the signers list. It's\n // important when verifying signers of a challenge transaction that we\n // only verify and return client signers. If an account has the server\n // as a signer the server should not play a part in the authentication\n // of the client.\n if (signer === serverKP.publicKey()) {\n continue;\n }\n\n // Ignore non-G... account/address signers.\n if (signer.charAt(0) !== \"G\") {\n continue;\n }\n\n clientSigners.add(signer);\n }\n\n // Don't continue if none of the signers provided are in the final list.\n if (clientSigners.size === 0) {\n throw new InvalidChallengeError(\n \"No verifiable client signers provided, at least one G... address must be provided\",\n );\n }\n\n let clientSigningKey;\n for (const op of tx.operations) {\n if (op.type === \"manageData\" && op.name === \"client_domain\") {\n if (clientSigningKey) {\n throw new InvalidChallengeError(\n \"Found more than one client_domain operation\",\n );\n }\n clientSigningKey = op.source;\n }\n }\n\n // Verify all the transaction's signers (server and client) in one\n // hit. We do this in one hit here even though the server signature was\n // checked in the ReadChallengeTx to ensure that every signature and signer\n // are consumed only once on the transaction.\n const allSigners: string[] = [\n serverKP.publicKey(),\n ...Array.from(clientSigners),\n ];\n if (clientSigningKey) {\n allSigners.push(clientSigningKey);\n }\n\n const signersFound: string[] = gatherTxSigners(tx, allSigners);\n\n let serverSignatureFound = false;\n let clientSigningKeySignatureFound = false;\n for (const signer of signersFound) {\n if (signer === serverKP.publicKey()) {\n serverSignatureFound = true;\n }\n if (signer === clientSigningKey) {\n clientSigningKeySignatureFound = true;\n }\n }\n\n // Confirm we matched a signature to the server signer.\n if (!serverSignatureFound) {\n throw new InvalidChallengeError(\n `Transaction not signed by server: '${serverKP.publicKey()}'`,\n );\n }\n\n // Confirm we matched a signature to the client domain's signer\n if (clientSigningKey && !clientSigningKeySignatureFound) {\n throw new InvalidChallengeError(\n \"Transaction not signed by the source account of the 'client_domain' \" +\n \"ManageData operation\",\n );\n }\n\n // Confirm we matched at least one given signer with the transaction signatures\n if (signersFound.length === 1) {\n throw new InvalidChallengeError(\n \"None of the given signers match the transaction signatures\",\n );\n }\n\n // Confirm all signatures, including the server signature, were consumed by a signer:\n if (signersFound.length !== tx.signatures.length) {\n throw new InvalidChallengeError(\"Transaction has unrecognized signatures\");\n }\n\n // Remove the server public key before returning\n signersFound.splice(signersFound.indexOf(serverKP.publicKey()), 1);\n if (clientSigningKey) {\n // Remove the client domain public key public key before returning\n signersFound.splice(signersFound.indexOf(clientSigningKey), 1);\n }\n\n if (signersFound.length === 0) {\n throw new InvalidChallengeError(\n \"None of the given signers match the transaction signatures\",\n );\n }\n\n return signersFound;\n}\n\n/**\n * Verifies that for a SEP-10 challenge transaction all signatures on the\n * transaction are accounted for and that the signatures meet a threshold on an\n * account. A transaction is verified if it is signed by the server account, and\n * all other signatures match a signer that has been provided as an argument,\n * and those signatures meet a threshold on the account.\n *\n * Signers that are not prefixed as an address/account ID strkey (G...) will be\n * ignored.\n *\n * Errors will be raised if:\n * - The transaction is invalid according to\n * {@link WebAuth.readChallengeTx}.\n * - No client signatures are found on the transaction.\n * - One or more signatures in the transaction are not identifiable as the\n * server account or one of the signers provided in the arguments.\n * - The signatures are all valid but do not meet the threshold.\n * @param challengeTx - SEP0010 challenge transaction in base64.\n * @param serverAccountID - The server's stellar account (public key).\n * @param networkPassphrase - The network passphrase, e.g.: 'Test SDF\n * Network ; September 2015' (see {@link Networks}).\n * @param threshold - The required signatures threshold for verifying\n * this transaction.\n * @param signerSummary - a map of all\n * authorized signers to their weights. It's used to validate if the\n * transaction signatures have met the given threshold.\n * @param homeDomains - The home domain(s) that should\n * be included in the first Manage Data operation's string key. Required in\n * `verifyChallengeTxSigners() => readChallengeTx()`.\n * @param webAuthDomain - The home domain that is expected to be included\n * as the value of the Manage Data operation with the 'web_auth_domain' key,\n * if present. Used in `verifyChallengeTxSigners() => readChallengeTx()`.\n * @returns The list of signers public keys that have signed\n * the transaction, excluding the server account ID, given that the threshold\n * was met.\n * @throws Will throw if the collective\n * weight of the transaction's signers does not meet the necessary threshold\n * to verify this transaction.\n * @see {@link https://stellar.org/protocol/sep-10 | SEP-10: Stellar Web Auth}\n * @example\n * ```ts\n * import { Networks, TransactionBuilder, WebAuth } from 'stellar-sdk';\n *\n * const serverKP = Keypair.random();\n * const clientKP1 = Keypair.random();\n * const clientKP2 = Keypair.random();\n *\n * // Challenge, possibly built in the server side\n * const challenge = WebAuth.buildChallengeTx(\n * serverKP,\n * clientKP1.publicKey(),\n * \"SDF\",\n * 300,\n * Networks.TESTNET\n * );\n *\n * // clock.tick(200); // Simulates a 200 ms delay when communicating from server to client\n *\n * // Transaction gathered from a challenge, possibly from the client side\n * const transaction = TransactionBuilder.fromXDR(challenge, Networks.TESTNET);\n * transaction.sign(clientKP1, clientKP2);\n * const signedChallenge = transaction\n * .toEnvelope()\n * .toXDR(\"base64\")\n * .toString();\n *\n * // Defining the threshold and signerSummary\n * const threshold = 3;\n * const signerSummary = [\n * {\n * key: this.clientKP1.publicKey(),\n * weight: 1,\n * },\n * {\n * key: this.clientKP2.publicKey(),\n * weight: 2,\n * },\n * ];\n *\n * // The result below should be equal to [clientKP1.publicKey(), clientKP2.publicKey()]\n * WebAuth.verifyChallengeTxThreshold(\n * signedChallenge,\n * serverKP.publicKey(),\n * Networks.TESTNET,\n * threshold,\n * signerSummary\n * );\n * ```\n */\nexport function verifyChallengeTxThreshold(\n challengeTx: string,\n serverAccountID: string,\n networkPassphrase: string,\n threshold: number,\n signerSummary: ServerApi.AccountRecordSigners[],\n homeDomains: string | string[],\n webAuthDomain: string,\n): string[] {\n const signers = signerSummary.map((signer) => signer.key);\n\n const signersFound = verifyChallengeTxSigners(\n challengeTx,\n serverAccountID,\n networkPassphrase,\n signers,\n homeDomains,\n webAuthDomain,\n );\n\n let weight = 0;\n for (const signer of signersFound) {\n const sigWeight = signerSummary.find((s) => s.key === signer)?.weight || 0;\n weight += sigWeight;\n }\n\n if (weight < threshold) {\n throw new InvalidChallengeError(\n `signers with weight ${weight} do not meet threshold ${threshold}\"`,\n );\n }\n\n return signersFound;\n}\n"],"names":["memo","account","Account","uint8ArrayToBase64","TransactionBuilder","BASE_FEE","Operation","Memo","transaction","Transaction","FeeBumpTransaction","InvalidChallengeError","MemoNone","MemoID","TimeoutInfinite","Utils","Buffer","verifyTxSignedBy","Keypair","gatherTxSigners"],"mappings":"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"}
|
package/lib/cjs/webauth/utils.js
CHANGED
|
@@ -1,26 +1,7 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
require('../node_modules/.pnpm/@stellar_js-xdr@4.0.0/node_modules/@stellar/js-xdr/src/int.js');
|
|
4
|
-
require('../node_modules/.pnpm/@stellar_js-xdr@4.0.0/node_modules/@stellar/js-xdr/src/hyper.js');
|
|
5
|
-
require('../node_modules/.pnpm/@stellar_js-xdr@4.0.0/node_modules/@stellar/js-xdr/src/unsigned-int.js');
|
|
6
|
-
require('../node_modules/.pnpm/@stellar_js-xdr@4.0.0/node_modules/@stellar/js-xdr/src/unsigned-hyper.js');
|
|
7
|
-
require('../node_modules/.pnpm/@stellar_js-xdr@4.0.0/node_modules/@stellar/js-xdr/src/xdr-type.js');
|
|
8
|
-
require('buffer');
|
|
9
|
-
require('../base/generated/curr_generated.js');
|
|
10
|
-
require('@noble/hashes/sha2.js');
|
|
11
|
-
require('../base/signing.js');
|
|
12
|
-
var keypair = require('../base/keypair.js');
|
|
13
|
-
require('base32.js');
|
|
14
|
-
require('../base/util/continued_fraction.js');
|
|
15
|
-
require('../base/util/bignumber.js');
|
|
16
|
-
require('../base/transaction_builder.js');
|
|
17
|
-
require('../base/muxed_account.js');
|
|
18
|
-
require('../base/scval.js');
|
|
19
|
-
require('../base/numbers/uint128.js');
|
|
20
|
-
require('../base/numbers/uint256.js');
|
|
21
|
-
require('../base/numbers/int128.js');
|
|
22
|
-
require('../base/numbers/int256.js');
|
|
23
3
|
var errors = require('./errors.js');
|
|
4
|
+
var keypair = require('../base/keypair.js');
|
|
24
5
|
|
|
25
6
|
function gatherTxSigners(transaction, signers) {
|
|
26
7
|
const hashedSignatureBase = transaction.hash();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utils.js","sources":["../../../src/webauth/utils.ts"],"sourcesContent":["/**\n * Stellar Web Authentication\n * @see {@link https://stellar.org/protocol-10 | SEP-10 Specification}\n */\n\nimport { FeeBumpTransaction, Keypair, Transaction } from \"../base/index.js\";\nimport { InvalidChallengeError } from \"./errors.js\";\n/**\n * Checks if a transaction has been signed by one or more of the given signers,\n * returning a list of non-repeated signers that were found to have signed the\n * given transaction.\n *\n * @param transaction - The signed transaction.\n * @param signers - The signer's public keys.\n * @returns A list of signers that were found to have signed\n * the transaction.\n *\n * @example\n * ```ts\n * let keypair1 = Keypair.random();\n * let keypair2 = Keypair.random();\n * const account = new StellarSdk.Account(keypair1.publicKey(), \"-1\");\n *\n * const transaction = new TransactionBuilder(account, { fee: 100 })\n * .setTimeout(30)\n * .build();\n *\n * transaction.sign(keypair1, keypair2)\n * WebAuth.gatherTxSigners(transaction, [keypair1.publicKey(), keypair2.publicKey()])\n * ```\n */\nexport function gatherTxSigners(\n transaction: FeeBumpTransaction | Transaction,\n signers: string[],\n): string[] {\n const hashedSignatureBase = transaction.hash();\n\n const txSignatures = [...transaction.signatures]; // shallow copy for safe splicing\n const signersFound = new Set<string>();\n\n for (const signer of signers) {\n if (txSignatures.length === 0) {\n break;\n }\n\n let keypair: Keypair;\n try {\n keypair = Keypair.fromPublicKey(signer); // This can throw a few different errors\n } catch (err: any) {\n throw new InvalidChallengeError(\n `Signer is not a valid address: ${err.message}`,\n );\n }\n\n for (let i = 0; i < txSignatures.length; i++) {\n const decSig = txSignatures[i];\n\n if (!decSig.hint().equals(keypair.signatureHint())) {\n continue;\n }\n\n if (keypair.verify(hashedSignatureBase, decSig.signature())) {\n signersFound.add(signer);\n txSignatures.splice(i, 1);\n break;\n }\n }\n }\n\n return Array.from(signersFound);\n}\n\n/**\n * Verifies if a transaction was signed by the given account id.\n *\n * @param transaction - The signed transaction.\n * @param accountID - The signer's public key.\n * @returns Whether or not `accountID` was found to have signed the\n * transaction.\n *\n * @example\n * ```ts\n * let keypair = Keypair.random();\n * const account = new StellarSdk.Account(keypair.publicKey(), \"-1\");\n *\n * const transaction = new TransactionBuilder(account, { fee: 100 })\n * .setTimeout(30)\n * .build();\n *\n * transaction.sign(keypair)\n * WebAuth.verifyTxSignedBy(transaction, keypair.publicKey())\n * ```\n */\nexport function verifyTxSignedBy(\n transaction: FeeBumpTransaction | Transaction,\n accountID: string,\n): boolean {\n return gatherTxSigners(transaction, [accountID]).length !== 0;\n}\n\n/**\n * A parsed and validated challenge transaction, and some of its constituent details.\n */\nexport type ChallengeTxDetails = {\n /** The challenge transaction. */\n tx: Transaction;\n /** The Stellar public key (master key) used to sign the Manage Data operation. */\n clientAccountId: string;\n /** The matched home domain. */\n matchedHomeDomain: string;\n /** The memo attached to the transaction, which will be null if not present */\n memo?: string;\n};\n"],"names":["keypair","Keypair","InvalidChallengeError"],"mappings":"
|
|
1
|
+
{"version":3,"file":"utils.js","sources":["../../../src/webauth/utils.ts"],"sourcesContent":["/**\n * Stellar Web Authentication\n * @see {@link https://stellar.org/protocol-10 | SEP-10 Specification}\n */\n\nimport { FeeBumpTransaction, Keypair, Transaction } from \"../base/index.js\";\nimport { InvalidChallengeError } from \"./errors.js\";\n/**\n * Checks if a transaction has been signed by one or more of the given signers,\n * returning a list of non-repeated signers that were found to have signed the\n * given transaction.\n *\n * @param transaction - The signed transaction.\n * @param signers - The signer's public keys.\n * @returns A list of signers that were found to have signed\n * the transaction.\n *\n * @example\n * ```ts\n * let keypair1 = Keypair.random();\n * let keypair2 = Keypair.random();\n * const account = new StellarSdk.Account(keypair1.publicKey(), \"-1\");\n *\n * const transaction = new TransactionBuilder(account, { fee: 100 })\n * .setTimeout(30)\n * .build();\n *\n * transaction.sign(keypair1, keypair2)\n * WebAuth.gatherTxSigners(transaction, [keypair1.publicKey(), keypair2.publicKey()])\n * ```\n */\nexport function gatherTxSigners(\n transaction: FeeBumpTransaction | Transaction,\n signers: string[],\n): string[] {\n const hashedSignatureBase = transaction.hash();\n\n const txSignatures = [...transaction.signatures]; // shallow copy for safe splicing\n const signersFound = new Set<string>();\n\n for (const signer of signers) {\n if (txSignatures.length === 0) {\n break;\n }\n\n let keypair: Keypair;\n try {\n keypair = Keypair.fromPublicKey(signer); // This can throw a few different errors\n } catch (err: any) {\n throw new InvalidChallengeError(\n `Signer is not a valid address: ${err.message}`,\n );\n }\n\n for (let i = 0; i < txSignatures.length; i++) {\n const decSig = txSignatures[i];\n\n if (!decSig.hint().equals(keypair.signatureHint())) {\n continue;\n }\n\n if (keypair.verify(hashedSignatureBase, decSig.signature())) {\n signersFound.add(signer);\n txSignatures.splice(i, 1);\n break;\n }\n }\n }\n\n return Array.from(signersFound);\n}\n\n/**\n * Verifies if a transaction was signed by the given account id.\n *\n * @param transaction - The signed transaction.\n * @param accountID - The signer's public key.\n * @returns Whether or not `accountID` was found to have signed the\n * transaction.\n *\n * @example\n * ```ts\n * let keypair = Keypair.random();\n * const account = new StellarSdk.Account(keypair.publicKey(), \"-1\");\n *\n * const transaction = new TransactionBuilder(account, { fee: 100 })\n * .setTimeout(30)\n * .build();\n *\n * transaction.sign(keypair)\n * WebAuth.verifyTxSignedBy(transaction, keypair.publicKey())\n * ```\n */\nexport function verifyTxSignedBy(\n transaction: FeeBumpTransaction | Transaction,\n accountID: string,\n): boolean {\n return gatherTxSigners(transaction, [accountID]).length !== 0;\n}\n\n/**\n * A parsed and validated challenge transaction, and some of its constituent details.\n */\nexport type ChallengeTxDetails = {\n /** The challenge transaction. */\n tx: Transaction;\n /** The Stellar public key (master key) used to sign the Manage Data operation. */\n clientAccountId: string;\n /** The matched home domain. */\n matchedHomeDomain: string;\n /** The memo attached to the transaction, which will be null if not present */\n memo?: string;\n};\n"],"names":["keypair","Keypair","InvalidChallengeError"],"mappings":";;;;;AA+BO,SAAS,eAAA,CACd,aACA,OAAA,EACU;AACV,EAAA,MAAM,mBAAA,GAAsB,YAAY,IAAA,EAAK;AAE7C,EAAA,MAAM,YAAA,GAAe,CAAC,GAAG,WAAA,CAAY,UAAU,CAAA;AAC/C,EAAA,MAAM,YAAA,uBAAmB,GAAA,EAAY;AAErC,EAAA,KAAA,MAAW,UAAU,OAAA,EAAS;AAC5B,IAAA,IAAI,YAAA,CAAa,WAAW,CAAA,EAAG;AAC7B,MAAA;AAAA,IACF;AAEA,IAAA,IAAIA,SAAA;AACJ,IAAA,IAAI;AACF,MAAAA,SAAA,GAAUC,eAAA,CAAQ,cAAc,MAAM,CAAA;AAAA,IACxC,SAAS,GAAA,EAAU;AACjB,MAAA,MAAM,IAAIC,4BAAA;AAAA,QACR,CAAA,+BAAA,EAAkC,IAAI,OAAO,CAAA;AAAA,OAC/C;AAAA,IACF;AAEA,IAAA,KAAA,IAAS,CAAA,GAAI,CAAA,EAAG,CAAA,GAAI,YAAA,CAAa,QAAQ,CAAA,EAAA,EAAK;AAC5C,MAAA,MAAM,MAAA,GAAS,aAAa,CAAC,CAAA;AAE7B,MAAA,IAAI,CAAC,OAAO,IAAA,EAAK,CAAE,OAAOF,SAAA,CAAQ,aAAA,EAAe,CAAA,EAAG;AAClD,QAAA;AAAA,MACF;AAEA,MAAA,IAAIA,UAAQ,MAAA,CAAO,mBAAA,EAAqB,MAAA,CAAO,SAAA,EAAW,CAAA,EAAG;AAC3D,QAAA,YAAA,CAAa,IAAI,MAAM,CAAA;AACvB,QAAA,YAAA,CAAa,MAAA,CAAO,GAAG,CAAC,CAAA;AACxB,QAAA;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,KAAA,CAAM,KAAK,YAAY,CAAA;AAChC;AAuBO,SAAS,gBAAA,CACd,aACA,SAAA,EACS;AACT,EAAA,OAAO,gBAAgB,WAAA,EAAa,CAAC,SAAS,CAAC,EAAE,MAAA,KAAW,CAAA;AAC9D;;;;;"}
|
package/lib/esm/base/auth.d.ts
CHANGED
|
@@ -8,16 +8,36 @@ type BufferLike = ArrayBuffer | Buffer | Uint8Array;
|
|
|
8
8
|
* @param preimage - the entire authorization envelope whose hash you should
|
|
9
9
|
* sign, so that you can inspect the entire structure if necessary (rather
|
|
10
10
|
* than blindly signing a hash)
|
|
11
|
+
* @param payload - the 32-byte signing payload, i.e. the sha256 hash of the
|
|
12
|
+
* preimage bytes (`hash(preimage.toXDR())`), provided as a convenience so
|
|
13
|
+
* you never have to re-derive it (e.g. for HSMs or remote signers that only
|
|
14
|
+
* accept a digest)
|
|
11
15
|
*
|
|
12
|
-
* @returns
|
|
13
|
-
*
|
|
14
|
-
*
|
|
16
|
+
* @returns one of the following:
|
|
17
|
+
*
|
|
18
|
+
* - the signature of the payload as a naked buffer, implying it is signed by
|
|
19
|
+
* the key corresponding to the public key in the entry you pass to
|
|
15
20
|
* {@link authorizeEntry} (decipherable from its
|
|
16
|
-
* `credentials().address().address()`),
|
|
21
|
+
* `credentials().address().address()`),
|
|
22
|
+
* - an object with the `signature` alongside an explicit `publicKey` string
|
|
23
|
+
* identifying the Ed25519 signer, or
|
|
24
|
+
* - an object with a `signatureScVal`: an arbitrary, caller-built
|
|
25
|
+
* {@link xdr.ScVal} that is placed verbatim into the credentials'
|
|
26
|
+
* `signature` field. Use this for custom account contracts (smart wallets,
|
|
27
|
+
* passkey/WebAuthn signers, etc.) whose `__check_auth` expects a signature
|
|
28
|
+
* structure other than the built-in Stellar account
|
|
29
|
+
* `{public_key, signature}` vector. No Ed25519 verification is performed on
|
|
30
|
+
* this variant, and no `scvVec` wrapping is applied — you own the exact
|
|
31
|
+
* shape. The optional `address` selects which credential node receives the
|
|
32
|
+
* signature (like `forAddress` on {@link authorizeEntry}, which takes
|
|
33
|
+
* precedence if both are given).
|
|
17
34
|
*/
|
|
18
|
-
export type SigningCallback = (preimage: xdr.HashIdPreimage) => Promise<BufferLike | {
|
|
35
|
+
export type SigningCallback = (preimage: xdr.HashIdPreimage, payload: Buffer) => Promise<BufferLike | {
|
|
19
36
|
signature: BufferLike;
|
|
20
37
|
publicKey: string;
|
|
38
|
+
} | {
|
|
39
|
+
signatureScVal: xdr.ScVal;
|
|
40
|
+
address?: string;
|
|
21
41
|
}>;
|
|
22
42
|
/**
|
|
23
43
|
* Actually authorizes an existing authorization entry using the given
|
|
@@ -37,17 +57,22 @@ export type SigningCallback = (preimage: xdr.HashIdPreimage) => Promise<BufferLi
|
|
|
37
57
|
* {@link SigningCallback}) to handle signing the envelope hash.
|
|
38
58
|
*
|
|
39
59
|
* @param entry - an unsigned authorization entry
|
|
40
|
-
* @param signer - either a {@link Keypair} instance or a function
|
|
41
|
-
* {@link
|
|
42
|
-
*
|
|
60
|
+
* @param signer - either a {@link Keypair} instance or a function (see
|
|
61
|
+
* {@link SigningCallback}) which receives the
|
|
62
|
+
* {@link xdr.HashIdPreimage} input payload plus its 32-byte signing hash
|
|
63
|
+
* and returns EITHER
|
|
43
64
|
*
|
|
44
65
|
* (a) an object containing a `signature` of the hash of the raw payload
|
|
45
66
|
* bytes as a Buffer-like and a `publicKey` string representing who just
|
|
46
|
-
* created this signature,
|
|
67
|
+
* created this signature,
|
|
47
68
|
* (b) just the naked signature of the hash of the raw payload bytes (where
|
|
48
|
-
* the signing key is implied to be the address in the `entry`)
|
|
69
|
+
* the signing key is implied to be the address in the `entry`), or
|
|
70
|
+
* (c) an object containing a `signatureScVal` — an arbitrary, caller-built
|
|
71
|
+
* {@link xdr.ScVal} written verbatim as the credentials' signature,
|
|
72
|
+
* for custom account contracts (smart wallets, passkey/WebAuthn
|
|
73
|
+
* signers) whose `__check_auth` expects a non-Ed25519 signature shape.
|
|
49
74
|
*
|
|
50
|
-
*
|
|
75
|
+
* Option (b) is JUST for backwards compatibility and will be
|
|
51
76
|
* removed in the future.
|
|
52
77
|
* @param validUntilLedgerSeq - the (exclusive) future ledger sequence number
|
|
53
78
|
* until which this authorization entry should be valid (if
|
|
@@ -85,8 +110,10 @@ export type SigningCallback = (preimage: xdr.HashIdPreimage) => Promise<BufferLi
|
|
|
85
110
|
* // It might, for example, pop up a modal from a browser extension, send the
|
|
86
111
|
* // transaction to a third-party service for signing, or just do simple
|
|
87
112
|
* // signing via Keypair like it does here:
|
|
88
|
-
* function signPayloadCallback(payload) {
|
|
89
|
-
*
|
|
113
|
+
* function signPayloadCallback(preimage, payload) {
|
|
114
|
+
* // `payload` is hash(preimage.toXDR()) — inspect `preimage` if you want
|
|
115
|
+
* // to display/verify what is being authorized before signing.
|
|
116
|
+
* return signer.sign(payload);
|
|
90
117
|
* }
|
|
91
118
|
*
|
|
92
119
|
* function multiPartyAuth(
|
|
@@ -270,4 +297,145 @@ export declare function buildWithDelegatesEntry(params: BuildWithDelegatesParams
|
|
|
270
297
|
* credentials (which carry no address payload)
|
|
271
298
|
*/
|
|
272
299
|
export declare function getAddressCredentials(credentials: xdr.SorobanCredentials): xdr.SorobanAddressCredentials | null;
|
|
300
|
+
/** The credential arm of a {@link xdr.SorobanAuthorizationEntry}. */
|
|
301
|
+
export type AuthEntryCredentialType = "sourceAccount" | "address" | "addressV2" | "addressWithDelegates";
|
|
302
|
+
/**
|
|
303
|
+
* A single ed25519 signature parsed out of a credential node's signature
|
|
304
|
+
* value, in the map format written by {@link authorizeEntry}.
|
|
305
|
+
*/
|
|
306
|
+
export interface AuthEntrySignature {
|
|
307
|
+
/** the signer's public key, as a `G…` strkey. */
|
|
308
|
+
publicKey: string;
|
|
309
|
+
/** the raw 64-byte ed25519 signature. */
|
|
310
|
+
signature: Buffer;
|
|
311
|
+
}
|
|
312
|
+
/**
|
|
313
|
+
* One node of an authorization entry that can carry a signature: the top-level
|
|
314
|
+
* address credentials and, for `SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES`,
|
|
315
|
+
* each (possibly nested) delegate.
|
|
316
|
+
*/
|
|
317
|
+
export interface AuthEntrySigner {
|
|
318
|
+
/** the node's address (`G…` account or `C…` contract). */
|
|
319
|
+
address: string;
|
|
320
|
+
/**
|
|
321
|
+
* whether a signature payload is present on this node (i.e. its signature is
|
|
322
|
+
* neither `scvVoid` nor an empty `scvVec`). For contract (`C…`) addresses
|
|
323
|
+
* this only means *something* is attached — whether it satisfies the
|
|
324
|
+
* contract's `__check_auth` cannot be verified client-side.
|
|
325
|
+
*/
|
|
326
|
+
signed: boolean;
|
|
327
|
+
/**
|
|
328
|
+
* the signature payload parsed as the SDK's standard ed25519 format (a vec
|
|
329
|
+
* of `{public_key, signature}` maps, see {@link authorizeEntry}), or `null`
|
|
330
|
+
* when the payload has some other, signer-defined shape (as custom accounts
|
|
331
|
+
* such as WebAuthn/passkey wallets use). Of the two unsigned placeholder
|
|
332
|
+
* forms, an empty `scvVec` parses as `[]` while `scvVoid` (not a vec at all)
|
|
333
|
+
* parses as `null` — check `signed` rather than this field to tell whether a
|
|
334
|
+
* node is unsigned.
|
|
335
|
+
*/
|
|
336
|
+
signatures: AuthEntrySignature[] | null;
|
|
337
|
+
/** the raw signature value, whatever its shape. */
|
|
338
|
+
rawSignature: xdr.ScVal;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* A structured, read-only view of a {@link xdr.SorobanAuthorizationEntry},
|
|
342
|
+
* returned by {@link inspectAuthEntry}.
|
|
343
|
+
*/
|
|
344
|
+
export interface AuthEntryInfo {
|
|
345
|
+
credentialType: AuthEntryCredentialType;
|
|
346
|
+
/** the authorizing address, or `null` for source-account credentials. */
|
|
347
|
+
address: string | null;
|
|
348
|
+
/** the credential nonce, or `null` for source-account credentials. */
|
|
349
|
+
nonce: bigint | null;
|
|
350
|
+
/**
|
|
351
|
+
* the (exclusive) ledger sequence until which the signature is valid, or
|
|
352
|
+
* `null` for source-account credentials. Note that unsigned entries commonly
|
|
353
|
+
* carry a placeholder (often `0`) until {@link authorizeEntry} sets it.
|
|
354
|
+
*/
|
|
355
|
+
signatureExpirationLedger: number | null;
|
|
356
|
+
/**
|
|
357
|
+
* every node that can carry a signature: the top-level credentials first,
|
|
358
|
+
* then (for the delegates variant) each delegate, depth-first. Empty for
|
|
359
|
+
* source-account credentials.
|
|
360
|
+
*/
|
|
361
|
+
signers: AuthEntrySigner[];
|
|
362
|
+
/**
|
|
363
|
+
* whether every signer node carries a signature payload. Always `false` for
|
|
364
|
+
* source-account credentials (which have no signature nodes — they are
|
|
365
|
+
* instead covered by the transaction envelope signature; use
|
|
366
|
+
* {@link checkAuthEntryReadiness} for a submit check). For the delegates
|
|
367
|
+
* variant note that an account's policy may accept an unsigned top-level
|
|
368
|
+
* node when its delegates have signed (CAP-71-01) — consult `signers` if you
|
|
369
|
+
* support that.
|
|
370
|
+
*/
|
|
371
|
+
signed: boolean;
|
|
372
|
+
/** the invocation tree this entry authorizes. */
|
|
373
|
+
invocation: xdr.SorobanAuthorizedInvocation;
|
|
374
|
+
}
|
|
375
|
+
/** The result of {@link checkAuthEntryReadiness}. */
|
|
376
|
+
export interface AuthEntryReadiness {
|
|
377
|
+
/** `true` when the entry is fully signed and not expired. */
|
|
378
|
+
ready: boolean;
|
|
379
|
+
/**
|
|
380
|
+
* `true` when `currentLedgerSeq >= signatureExpirationLedger` (expiration is
|
|
381
|
+
* exclusive). Always `false` for source-account credentials.
|
|
382
|
+
*/
|
|
383
|
+
expired: boolean;
|
|
384
|
+
/** addresses of signer nodes that carry no signature payload. */
|
|
385
|
+
unsignedBy: string[];
|
|
386
|
+
}
|
|
387
|
+
/**
|
|
388
|
+
* Decodes a {@link xdr.SorobanAuthorizationEntry} into a plain, typed summary:
|
|
389
|
+
* which credential variant it uses, which address authorizes it, its nonce and
|
|
390
|
+
* expiration ledger, and — for every node that can carry a signature (the
|
|
391
|
+
* top-level credentials plus any CAP-71 delegates) — whether it is signed and,
|
|
392
|
+
* when the payload uses the SDK's standard ed25519 format, by which keys.
|
|
393
|
+
*
|
|
394
|
+
* This is the read-side complement to {@link authorizeEntry} /
|
|
395
|
+
* {@link authorizeInvocation}: those fill entries with signatures, this
|
|
396
|
+
* inspects what an entry (e.g. one returned by transaction simulation, or
|
|
397
|
+
* received from a counterparty in a multi-party signing flow) requires and
|
|
398
|
+
* already carries, without reaching into raw XDR accessors.
|
|
399
|
+
*
|
|
400
|
+
* @param entry - the authorization entry to inspect
|
|
401
|
+
* @returns a {@link AuthEntryInfo} summary of the entry
|
|
402
|
+
*
|
|
403
|
+
* @see checkAuthEntryReadiness
|
|
404
|
+
* @example
|
|
405
|
+
* ```ts
|
|
406
|
+
* const info = inspectAuthEntry(entry);
|
|
407
|
+
* if (!info.signed && info.address !== null) {
|
|
408
|
+
* console.log(`${info.address} still needs to sign`, info.signers);
|
|
409
|
+
* }
|
|
410
|
+
* ```
|
|
411
|
+
*/
|
|
412
|
+
export declare function inspectAuthEntry(entry: xdr.SorobanAuthorizationEntry): AuthEntryInfo;
|
|
413
|
+
/**
|
|
414
|
+
* Reports whether an authorization entry is ready to submit at a given ledger:
|
|
415
|
+
* fully signed and not yet expired.
|
|
416
|
+
*
|
|
417
|
+
* Source-account entries are always ready — they carry no signature or
|
|
418
|
+
* expiration of their own and are instead covered by the transaction envelope
|
|
419
|
+
* signature.
|
|
420
|
+
*
|
|
421
|
+
* The current ledger sequence is taken as a parameter (fetch it from a source
|
|
422
|
+
* you trust, e.g. `rpc.Server.getLatestLedger`) rather than looked up here, so
|
|
423
|
+
* this stays a pure decode with no network dependency.
|
|
424
|
+
*
|
|
425
|
+
* For `SOROBAN_CREDENTIALS_ADDRESS_WITH_DELEGATES`, this conservatively
|
|
426
|
+
* requires *every* node (top-level and all delegates) to be signed. An
|
|
427
|
+
* account's policy may accept an unsigned top-level node when its delegates
|
|
428
|
+
* have signed (CAP-71-01); if you support that, check
|
|
429
|
+
* {@link inspectAuthEntry}'s `signers` yourself.
|
|
430
|
+
*
|
|
431
|
+
* @param entry - the authorization entry to check
|
|
432
|
+
* @param currentLedgerSeq - the network's current ledger sequence, compared
|
|
433
|
+
* (exclusively) against the entry's `signatureExpirationLedger`
|
|
434
|
+
* @returns a {@link AuthEntryReadiness}: `ready`, `expired`, and which
|
|
435
|
+
* addresses are still `unsignedBy`
|
|
436
|
+
* @throws `Error` if `currentLedgerSeq` cannot represent a uint32 ledger
|
|
437
|
+
* sequence (non-integer, negative, or above 2^32 - 1), which would make the
|
|
438
|
+
* expiration comparison unreliable
|
|
439
|
+
*/
|
|
440
|
+
export declare function checkAuthEntryReadiness(entry: xdr.SorobanAuthorizationEntry, currentLedgerSeq: number): AuthEntryReadiness;
|
|
273
441
|
export {};
|
package/lib/esm/base/auth.js
CHANGED
|
@@ -29,43 +29,53 @@ async function authorizeEntry(entry, signer, validUntilLedgerSeq, networkPassphr
|
|
|
29
29
|
networkPassphrase
|
|
30
30
|
);
|
|
31
31
|
const payload = hash(preimage.toXDR());
|
|
32
|
-
let
|
|
33
|
-
let
|
|
32
|
+
let signatureScVal;
|
|
33
|
+
let targetAddress = forAddress;
|
|
34
|
+
let sigResult = null;
|
|
34
35
|
if (typeof signer === "function") {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
signature = toBuffer(sigResult);
|
|
41
|
-
publicKey = Address.fromScAddress(addrAuth.address()).toString();
|
|
42
|
-
}
|
|
36
|
+
sigResult = await signer(preimage, Buffer.from(payload));
|
|
37
|
+
}
|
|
38
|
+
if (sigResult !== null && typeof sigResult === "object" && "signatureScVal" in sigResult) {
|
|
39
|
+
signatureScVal = sigResult.signatureScVal;
|
|
40
|
+
targetAddress ??= sigResult.address;
|
|
43
41
|
} else {
|
|
44
|
-
signature
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
signature
|
|
54
|
-
},
|
|
55
|
-
{
|
|
56
|
-
type: {
|
|
57
|
-
public_key: ["symbol", null],
|
|
58
|
-
signature: ["symbol", null]
|
|
42
|
+
let signature;
|
|
43
|
+
let publicKey;
|
|
44
|
+
if (typeof signer === "function") {
|
|
45
|
+
if (sigResult !== null && typeof sigResult === "object" && "signature" in sigResult) {
|
|
46
|
+
signature = toBuffer(sigResult.signature);
|
|
47
|
+
publicKey = sigResult.publicKey;
|
|
48
|
+
} else {
|
|
49
|
+
signature = toBuffer(sigResult);
|
|
50
|
+
publicKey = Address.fromScAddress(addrAuth.address()).toString();
|
|
59
51
|
}
|
|
52
|
+
} else {
|
|
53
|
+
signature = toBuffer(signer.sign(payload));
|
|
54
|
+
publicKey = signer.publicKey();
|
|
60
55
|
}
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
56
|
+
if (!Keypair.fromPublicKey(publicKey).verify(payload, signature)) {
|
|
57
|
+
throw new Error(`signature doesn't match payload`);
|
|
58
|
+
}
|
|
59
|
+
const sigScVal = nativeToScVal(
|
|
60
|
+
{
|
|
61
|
+
public_key: StrKey.decodeEd25519PublicKey(publicKey),
|
|
62
|
+
signature
|
|
63
|
+
},
|
|
64
|
+
{
|
|
65
|
+
type: {
|
|
66
|
+
public_key: ["symbol", null],
|
|
67
|
+
signature: ["symbol", null]
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
);
|
|
71
|
+
signatureScVal = types.ScVal.scvVec([sigScVal]);
|
|
72
|
+
}
|
|
73
|
+
const targets = targetAddress === void 0 ? [addrAuth] : collectSignatureNodes(credentials).filter(
|
|
74
|
+
(node) => Address.fromScAddress(node.address()).toString() === targetAddress
|
|
65
75
|
);
|
|
66
76
|
if (targets.length === 0) {
|
|
67
77
|
throw new Error(
|
|
68
|
-
`the authorization entry has no credential node for address ${
|
|
78
|
+
`the authorization entry has no credential node for address ${targetAddress}`
|
|
69
79
|
);
|
|
70
80
|
}
|
|
71
81
|
targets.forEach((node) => node.signature(signatureScVal));
|
|
@@ -222,6 +232,111 @@ function collectSignatureNodes(credentials) {
|
|
|
222
232
|
return [];
|
|
223
233
|
}
|
|
224
234
|
}
|
|
235
|
+
function inspectAuthEntry(entry) {
|
|
236
|
+
const credentials = entry.credentials();
|
|
237
|
+
const addrAuth = getAddressCredentials(credentials);
|
|
238
|
+
let credentialType;
|
|
239
|
+
switch (credentials.switch().value) {
|
|
240
|
+
case types.SorobanCredentialsType.sorobanCredentialsSourceAccount().value:
|
|
241
|
+
credentialType = "sourceAccount";
|
|
242
|
+
break;
|
|
243
|
+
case types.SorobanCredentialsType.sorobanCredentialsAddress().value:
|
|
244
|
+
credentialType = "address";
|
|
245
|
+
break;
|
|
246
|
+
case types.SorobanCredentialsType.sorobanCredentialsAddressV2().value:
|
|
247
|
+
credentialType = "addressV2";
|
|
248
|
+
break;
|
|
249
|
+
case types.SorobanCredentialsType.sorobanCredentialsAddressWithDelegates().value:
|
|
250
|
+
credentialType = "addressWithDelegates";
|
|
251
|
+
break;
|
|
252
|
+
default:
|
|
253
|
+
throw new Error(
|
|
254
|
+
`unsupported credential type ${credentials.switch().name}`
|
|
255
|
+
);
|
|
256
|
+
}
|
|
257
|
+
const signers = collectSignatureNodes(credentials).map(
|
|
258
|
+
(node) => {
|
|
259
|
+
const rawSignature = node.signature();
|
|
260
|
+
return {
|
|
261
|
+
address: Address.fromScAddress(node.address()).toString(),
|
|
262
|
+
signed: signaturePresent(rawSignature),
|
|
263
|
+
signatures: parseEd25519Signatures(rawSignature),
|
|
264
|
+
rawSignature
|
|
265
|
+
};
|
|
266
|
+
}
|
|
267
|
+
);
|
|
268
|
+
return {
|
|
269
|
+
credentialType,
|
|
270
|
+
address: addrAuth === null ? null : Address.fromScAddress(addrAuth.address()).toString(),
|
|
271
|
+
nonce: addrAuth === null ? null : addrAuth.nonce().toBigInt(),
|
|
272
|
+
signatureExpirationLedger: addrAuth === null ? null : addrAuth.signatureExpirationLedger(),
|
|
273
|
+
signers,
|
|
274
|
+
signed: signers.length > 0 && signers.every((signer) => signer.signed),
|
|
275
|
+
invocation: entry.rootInvocation()
|
|
276
|
+
};
|
|
277
|
+
}
|
|
278
|
+
function checkAuthEntryReadiness(entry, currentLedgerSeq) {
|
|
279
|
+
if (!Number.isInteger(currentLedgerSeq) || currentLedgerSeq < 0 || currentLedgerSeq > 4294967295) {
|
|
280
|
+
throw new Error(
|
|
281
|
+
`currentLedgerSeq must be a uint32 ledger sequence, got ${currentLedgerSeq}`
|
|
282
|
+
);
|
|
283
|
+
}
|
|
284
|
+
const info = inspectAuthEntry(entry);
|
|
285
|
+
if (info.credentialType === "sourceAccount") {
|
|
286
|
+
return { ready: true, expired: false, unsignedBy: [] };
|
|
287
|
+
}
|
|
288
|
+
const expired = currentLedgerSeq >= (info.signatureExpirationLedger ?? 0);
|
|
289
|
+
const unsignedBy = info.signers.filter((signer) => !signer.signed).map((signer) => signer.address);
|
|
290
|
+
return { ready: !expired && unsignedBy.length === 0, expired, unsignedBy };
|
|
291
|
+
}
|
|
292
|
+
function signaturePresent(signature) {
|
|
293
|
+
switch (signature.switch().value) {
|
|
294
|
+
case types.ScValType.scvVoid().value:
|
|
295
|
+
return false;
|
|
296
|
+
case types.ScValType.scvVec().value:
|
|
297
|
+
return (signature.vec() ?? []).length > 0;
|
|
298
|
+
default:
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
function parseEd25519Signatures(signature) {
|
|
303
|
+
if (signature.switch().value !== types.ScValType.scvVec().value) {
|
|
304
|
+
return null;
|
|
305
|
+
}
|
|
306
|
+
const parsed = [];
|
|
307
|
+
for (const element of signature.vec() ?? []) {
|
|
308
|
+
if (element.switch().value !== types.ScValType.scvMap().value) {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
let publicKey = null;
|
|
312
|
+
let sig = null;
|
|
313
|
+
for (const mapEntry of element.map() ?? []) {
|
|
314
|
+
const key = mapEntry.key();
|
|
315
|
+
const val = mapEntry.val();
|
|
316
|
+
if (key.switch().value !== types.ScValType.scvSymbol().value || val.switch().value !== types.ScValType.scvBytes().value) {
|
|
317
|
+
return null;
|
|
318
|
+
}
|
|
319
|
+
switch (key.sym().toString()) {
|
|
320
|
+
case "public_key":
|
|
321
|
+
publicKey = val.bytes();
|
|
322
|
+
break;
|
|
323
|
+
case "signature":
|
|
324
|
+
sig = val.bytes();
|
|
325
|
+
break;
|
|
326
|
+
default:
|
|
327
|
+
return null;
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (publicKey === null || sig === null || publicKey.length !== 32 || sig.length !== 64) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
parsed.push({
|
|
334
|
+
publicKey: StrKey.encodeEd25519PublicKey(publicKey),
|
|
335
|
+
signature: sig
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
return parsed;
|
|
339
|
+
}
|
|
225
340
|
function bytesToInt64(bytes) {
|
|
226
341
|
const buf = bytes.subarray(0, 8);
|
|
227
342
|
if (buf.length < 8) {
|
|
@@ -234,5 +349,5 @@ function bytesToInt64(bytes) {
|
|
|
234
349
|
return value;
|
|
235
350
|
}
|
|
236
351
|
|
|
237
|
-
export { authorizeEntry, authorizeInvocation, buildAuthorizationEntryPreimage, buildWithDelegatesEntry, getAddressCredentials };
|
|
352
|
+
export { authorizeEntry, authorizeInvocation, buildAuthorizationEntryPreimage, buildWithDelegatesEntry, checkAuthEntryReadiness, getAddressCredentials, inspectAuthEntry };
|
|
238
353
|
//# sourceMappingURL=auth.js.map
|