@stellar/typescript-wallet-sdk 1.4.1 → 1.6.0-beta.1719865729038
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/CHANGELOG.MD +98 -0
- package/examples/sep24/sep24.ts +4 -9
- package/jest.e2e.config.js +9 -0
- package/lib/bundle.js +47445 -43024
- package/lib/bundle.js.map +1 -1
- package/lib/bundle_browser.js +45409 -41445
- package/lib/bundle_browser.js.map +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/walletSdk/Anchor/index.d.ts +1 -1
- package/lib/walletSdk/Auth/AuthHeaderSigner.d.ts +61 -0
- package/lib/walletSdk/Auth/index.d.ts +2 -2
- package/lib/walletSdk/Exceptions/index.d.ts +21 -0
- package/lib/walletSdk/Horizon/AccountService.d.ts +1 -1
- package/lib/walletSdk/Horizon/Stellar.d.ts +1 -1
- package/lib/walletSdk/Horizon/Transaction/TransactionBuilder.d.ts +1 -1
- package/lib/walletSdk/Recovery/AccountRecover.d.ts +1 -1
- package/lib/walletSdk/Recovery/index.d.ts +2 -2
- package/lib/walletSdk/Types/anchor.d.ts +5 -1
- package/lib/walletSdk/Types/auth.d.ts +17 -0
- package/lib/walletSdk/Types/horizon.d.ts +1 -1
- package/lib/walletSdk/Types/index.d.ts +2 -1
- package/lib/walletSdk/Types/recovery.d.ts +2 -2
- package/lib/walletSdk/Types/sep7.d.ts +15 -0
- package/lib/walletSdk/Uri/Sep7Base.d.ts +187 -0
- package/lib/walletSdk/Uri/Sep7Pay.d.ts +121 -0
- package/lib/walletSdk/Uri/Sep7Tx.d.ts +133 -0
- package/lib/walletSdk/Uri/index.d.ts +4 -0
- package/lib/walletSdk/Uri/sep7Parser.d.ts +60 -0
- package/lib/walletSdk/Utils/index.d.ts +2 -1
- package/package.json +8 -3
- package/src/index.ts +14 -0
- package/src/walletSdk/Anchor/index.ts +1 -1
- package/src/walletSdk/Auth/AuthHeaderSigner.ts +162 -0
- package/src/walletSdk/Auth/WalletSigner.ts +3 -3
- package/src/walletSdk/Auth/index.ts +48 -2
- package/src/walletSdk/Customer/index.ts +7 -7
- package/src/walletSdk/Exceptions/index.ts +56 -0
- package/src/walletSdk/Horizon/Account.ts +2 -1
- package/src/walletSdk/Horizon/AccountService.ts +1 -1
- package/src/walletSdk/Horizon/Stellar.ts +1 -1
- package/src/walletSdk/Horizon/Transaction/TransactionBuilder.ts +1 -1
- package/src/walletSdk/Recovery/AccountRecover.ts +1 -1
- package/src/walletSdk/Recovery/index.ts +2 -2
- package/src/walletSdk/Types/anchor.ts +4 -0
- package/src/walletSdk/Types/auth.ts +19 -0
- package/src/walletSdk/Types/horizon.ts +1 -1
- package/src/walletSdk/Types/index.ts +2 -1
- package/src/walletSdk/Types/recovery.ts +2 -2
- package/src/walletSdk/Types/sep7.ts +19 -0
- package/src/walletSdk/Uri/Sep7Base.ts +311 -0
- package/src/walletSdk/Uri/Sep7Pay.ts +169 -0
- package/src/walletSdk/Uri/Sep7Tx.ts +193 -0
- package/src/walletSdk/Uri/index.ts +9 -0
- package/src/walletSdk/Uri/sep7Parser.ts +220 -0
- package/src/walletSdk/Utils/index.ts +2 -1
- package/src/walletSdk/Watcher/index.ts +3 -1
- package/test/customer.test.ts +7 -7
- package/test/e2e/README.md +11 -0
- package/test/e2e/browser.test.ts +52 -0
- package/test/integration/README.md +38 -0
- package/test/integration/anchorplatform.test.ts +11 -2
- package/test/sep7.test.ts +825 -0
- package/test/server.test.ts +13 -0
- package/test/wallet.test.ts +85 -0
- package/webpack.config.js +4 -0
- package/test/README.md +0 -18
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Transaction } from "@stellar/stellar-sdk";
|
|
2
|
+
import { Sep7Base } from "../Uri";
|
|
3
|
+
import { Sep7Replacement } from "../Types";
|
|
4
|
+
/**
|
|
5
|
+
* The Sep-7 'tx' operation represents a request to sign
|
|
6
|
+
* a specific XDR TransactionEnvelope.
|
|
7
|
+
*
|
|
8
|
+
* @see https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0007.md#operation-tx
|
|
9
|
+
*/
|
|
10
|
+
export declare class Sep7Tx extends Sep7Base {
|
|
11
|
+
/**
|
|
12
|
+
* Creates a Sep7Tx instance with given transaction.
|
|
13
|
+
*
|
|
14
|
+
* Sets the 'xdr' param as a Stellar TransactionEnvelope in XDR format that
|
|
15
|
+
* is base64 encoded and then URL-encoded.
|
|
16
|
+
*
|
|
17
|
+
* @param {Transaction} transaction a transaction which will be used to set the
|
|
18
|
+
* URI 'xdr' and 'network_passphrase' query params.
|
|
19
|
+
*
|
|
20
|
+
* @returns {Sep7Tx} the Sep7Tx instance.
|
|
21
|
+
*/
|
|
22
|
+
static forTransaction(transaction: Transaction): Sep7Tx;
|
|
23
|
+
/**
|
|
24
|
+
* Creates a new instance of the Sep7Tx class.
|
|
25
|
+
*
|
|
26
|
+
* @constructor
|
|
27
|
+
* @param {URL | string} [uri] - uri to initialize the Sep7 instance.
|
|
28
|
+
*/
|
|
29
|
+
constructor(uri?: URL | string);
|
|
30
|
+
/**
|
|
31
|
+
* Returns a deep clone of this instance.
|
|
32
|
+
*
|
|
33
|
+
* @returns {Sep7Tx} a deep clone of this Sep7Tx instance.
|
|
34
|
+
*/
|
|
35
|
+
clone(): Sep7Tx;
|
|
36
|
+
/**
|
|
37
|
+
* Returns a URL-decoded version of the uri 'xdr' param.
|
|
38
|
+
*
|
|
39
|
+
* @returns {string | undefined} URL-decoded 'xdr' param if present.
|
|
40
|
+
*/
|
|
41
|
+
get xdr(): string | undefined;
|
|
42
|
+
/**
|
|
43
|
+
* Sets and URL-encodes the uri 'xdr' param.
|
|
44
|
+
*
|
|
45
|
+
* Deletes the uri 'xdr' param if set as 'undefined'.
|
|
46
|
+
*
|
|
47
|
+
* @param {string | undefined} xdr the uri 'xdr' param to be set.
|
|
48
|
+
*/
|
|
49
|
+
set xdr(xdr: string | undefined);
|
|
50
|
+
/**
|
|
51
|
+
* Returns the uri 'pubkey' param.
|
|
52
|
+
*
|
|
53
|
+
* This param specifies which public key the URI handler should sign for.
|
|
54
|
+
*
|
|
55
|
+
* @returns {string | undefined} URL-decoded 'pubkey' param if present.
|
|
56
|
+
*/
|
|
57
|
+
get pubkey(): string | undefined;
|
|
58
|
+
/**
|
|
59
|
+
* Sets the uri 'pubkey' param.
|
|
60
|
+
*
|
|
61
|
+
* Deletes the uri 'pubkey' param if set as 'undefined'.
|
|
62
|
+
*
|
|
63
|
+
* This param should specify which public key you want the URI handler
|
|
64
|
+
* to sign for.
|
|
65
|
+
*
|
|
66
|
+
* @param {string | undefined} pubkey the uri 'pubkey' param to be set.
|
|
67
|
+
*/
|
|
68
|
+
set pubkey(pubkey: string | undefined);
|
|
69
|
+
/**
|
|
70
|
+
* Returns a URL-decoded version of the uri 'chain' param.
|
|
71
|
+
*
|
|
72
|
+
* There can be an optional chain query param to include a single SEP-0007
|
|
73
|
+
* request that spawned or triggered the creation of this SEP-0007 request.
|
|
74
|
+
* This will be a URL-encoded value. The goal of this field is to be
|
|
75
|
+
* informational only and can be used to forward SEP-0007 requests.
|
|
76
|
+
*
|
|
77
|
+
* @returns {string | undefined} URL-decoded 'chain' param if present.
|
|
78
|
+
*/
|
|
79
|
+
get chain(): string | undefined;
|
|
80
|
+
/**
|
|
81
|
+
* Sets and URL-encodes the uri 'chain' param.
|
|
82
|
+
*
|
|
83
|
+
* Deletes the uri 'chain' param if set as 'undefined'.
|
|
84
|
+
*
|
|
85
|
+
* There can be an optional chain query param to include a single SEP-0007
|
|
86
|
+
* request that spawned or triggered the creation of this SEP-0007 request.
|
|
87
|
+
* This will be a URL-encoded value. The goal of this field is to be
|
|
88
|
+
* informational only and can be used to forward SEP-0007 requests.
|
|
89
|
+
*
|
|
90
|
+
* @param {string | undefined} chain the 'chain' param to be set.
|
|
91
|
+
*/
|
|
92
|
+
set chain(chain: string | undefined);
|
|
93
|
+
/**
|
|
94
|
+
* Gets a list of fields in the transaction that need to be replaced.
|
|
95
|
+
*
|
|
96
|
+
* @returns {Sep7Replacement[]} list of fields that need to be replaced.
|
|
97
|
+
*/
|
|
98
|
+
getReplacements(): Sep7Replacement[];
|
|
99
|
+
/**
|
|
100
|
+
* Sets and URL-encodes the uri 'replace' param, which is a list of fields in
|
|
101
|
+
* the transaction that needs to be replaced.
|
|
102
|
+
*
|
|
103
|
+
* Deletes the uri 'replace' param if set as empty array '[]' or 'undefined'.
|
|
104
|
+
*
|
|
105
|
+
* This 'replace' param should be a URL-encoded value that identifies the
|
|
106
|
+
* fields to be replaced in the XDR using the 'Txrep (SEP-0011)' representation.
|
|
107
|
+
* This will be specified in the format of:
|
|
108
|
+
* txrep_tx_field_name_1:reference_identifier_1,txrep_tx_field_name_2:reference_identifier_2;reference_identifier_1:hint_1,reference_identifier_2:hint_2
|
|
109
|
+
*
|
|
110
|
+
* @see https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0011.md
|
|
111
|
+
*
|
|
112
|
+
* @param {Sep7Replacement[]} replacements a list of replacements to set.
|
|
113
|
+
*/
|
|
114
|
+
setReplacements(replacements: Sep7Replacement[] | undefined): void;
|
|
115
|
+
/**
|
|
116
|
+
* Adds an additional replacement.
|
|
117
|
+
*
|
|
118
|
+
* @param {Sep7Replacement} replacement the replacement to add.
|
|
119
|
+
*/
|
|
120
|
+
addReplacement(replacement: Sep7Replacement): void;
|
|
121
|
+
/**
|
|
122
|
+
* Removes all replacements with the given identifier.
|
|
123
|
+
*
|
|
124
|
+
* @param {string} id the identifier to remove.
|
|
125
|
+
*/
|
|
126
|
+
removeReplacement(id: string): void;
|
|
127
|
+
/**
|
|
128
|
+
* Creates a Stellar Transaction from the URI's XDR and networkPassphrase.
|
|
129
|
+
*
|
|
130
|
+
* @returns {Transaction} the Stellar Transaction.
|
|
131
|
+
*/
|
|
132
|
+
getTransaction(): Transaction;
|
|
133
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { Sep7Pay, Sep7Tx } from "../Uri";
|
|
2
|
+
import { Sep7Replacement, IsValidSep7UriResult } from "../Types";
|
|
3
|
+
/**
|
|
4
|
+
* Returns true if the given URI is a SEP-7 compliant URI, false otherwise.
|
|
5
|
+
*
|
|
6
|
+
* Currently this checks whether it starts with 'web+stellar:tx' or 'web+stellar:pay'
|
|
7
|
+
* and has its required parameters: 'xdr=' and 'destination=' respectively.
|
|
8
|
+
*
|
|
9
|
+
* @param {string} uri The URI string to check.
|
|
10
|
+
*
|
|
11
|
+
* @returns {IsValidSep7UriResult} returns '{ result: true }' if it's a valid Sep-7
|
|
12
|
+
* uri, returns '{ result: false, reason: "<reason>" }' containing a 'reason' message
|
|
13
|
+
* in case the verification fails.
|
|
14
|
+
*/
|
|
15
|
+
export declare const isValidSep7Uri: (uri: string) => IsValidSep7UriResult;
|
|
16
|
+
/**
|
|
17
|
+
* Try parsing a SEP-7 URI string and returns a Sep7Tx or Sep7Pay instance,
|
|
18
|
+
* depending on the type.
|
|
19
|
+
*
|
|
20
|
+
* @param {string} uri The URI string to parse.
|
|
21
|
+
*
|
|
22
|
+
* @returns {Sep7Tx | Sep7Pay} a uri parsed Sep7Tx or Sep7Pay instance.
|
|
23
|
+
*
|
|
24
|
+
* @throws {Sep7InvalidUriError} if the inputted uri is not a valid SEP-7 URI.
|
|
25
|
+
* @throws {Sep7UriTypeNotSupportedError} if the inputted uri does not have a
|
|
26
|
+
* supported SEP-7 type.
|
|
27
|
+
*/
|
|
28
|
+
export declare const parseSep7Uri: (uri: string) => Sep7Tx | Sep7Pay;
|
|
29
|
+
/**
|
|
30
|
+
* Takes a Sep-7 URL-decoded 'replace' string param and parses it to a list of
|
|
31
|
+
* Sep7Replacement objects for easy of use.
|
|
32
|
+
*
|
|
33
|
+
* This string identifies the fields to be replaced in the XDR using
|
|
34
|
+
* the 'Txrep (SEP-0011)' representation, which should be specified in the format of:
|
|
35
|
+
* txrep_tx_field_name_1:reference_identifier_1,txrep_tx_field_name_2:reference_identifier_2;reference_identifier_1:hint_1,reference_identifier_2:hint_2
|
|
36
|
+
*
|
|
37
|
+
* @see https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0011.md
|
|
38
|
+
*
|
|
39
|
+
* @param {string} [replacements] a replacements string in the
|
|
40
|
+
* 'Txrep (SEP-0011)' representation.
|
|
41
|
+
*
|
|
42
|
+
* @returns {Sep7Replacement[]} a list of parsed Sep7Replacement objects.
|
|
43
|
+
*/
|
|
44
|
+
export declare const sep7ReplacementsFromString: (replacements?: string) => Sep7Replacement[];
|
|
45
|
+
/**
|
|
46
|
+
* Takes a list of Sep7Replacement objects and parses it to a string that
|
|
47
|
+
* could be URL-encoded and used as a Sep-7 URI 'replace' param.
|
|
48
|
+
*
|
|
49
|
+
* This string identifies the fields to be replaced in the XDR using
|
|
50
|
+
* the 'Txrep (SEP-0011)' representation, which should be specified in the format of:
|
|
51
|
+
* txrep_tx_field_name_1:reference_identifier_1,txrep_tx_field_name_2:reference_identifier_2;reference_identifier_1:hint_1,reference_identifier_2:hint_2
|
|
52
|
+
*
|
|
53
|
+
* @see https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0011.md
|
|
54
|
+
*
|
|
55
|
+
* @param {Sep7Replacement[]} [replacements] a list of Sep7Replacement objects.
|
|
56
|
+
*
|
|
57
|
+
* @returns {string} a string that identifies the fields to be replaced in the
|
|
58
|
+
* XDR using the 'Txrep (SEP-0011)' representation.
|
|
59
|
+
*/
|
|
60
|
+
export declare const sep7ReplacementsToString: (replacements?: Sep7Replacement[]) => string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@stellar/typescript-wallet-sdk",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0-beta.1719865729038",
|
|
4
4
|
"engines": {
|
|
5
5
|
"node": ">=18"
|
|
6
6
|
},
|
|
@@ -29,6 +29,7 @@
|
|
|
29
29
|
"jest": "^29.4.1",
|
|
30
30
|
"lint-staged": "^14.0.1",
|
|
31
31
|
"npm-run-all": "^4.1.5",
|
|
32
|
+
"playwright": "^1.43.1",
|
|
32
33
|
"prettier": "^2.0.5",
|
|
33
34
|
"pretty-quick": "^2.0.1",
|
|
34
35
|
"process": "^0.11.10",
|
|
@@ -43,13 +44,16 @@
|
|
|
43
44
|
"webpack-cli": "^5.1.1"
|
|
44
45
|
},
|
|
45
46
|
"dependencies": {
|
|
46
|
-
"@stellar/stellar-sdk": "
|
|
47
|
+
"@stellar/stellar-sdk": "12.1.0",
|
|
47
48
|
"axios": "^1.4.0",
|
|
49
|
+
"base64url": "^3.0.1",
|
|
48
50
|
"https-browserify": "^1.0.0",
|
|
49
51
|
"jws": "^4.0.0",
|
|
50
52
|
"lodash": "^4.17.21",
|
|
51
53
|
"query-string": "^7.1.3",
|
|
52
54
|
"stream-http": "^3.2.0",
|
|
55
|
+
"tweetnacl": "^1.0.3",
|
|
56
|
+
"tweetnacl-util": "^0.15.1",
|
|
53
57
|
"url": "^0.11.0",
|
|
54
58
|
"util": "^0.12.5",
|
|
55
59
|
"utility-types": "^3.10.0",
|
|
@@ -58,6 +62,7 @@
|
|
|
58
62
|
"scripts": {
|
|
59
63
|
"test": "jest --watchAll",
|
|
60
64
|
"test:ci": "jest --ci",
|
|
65
|
+
"test:e2e:ci": "jest --config jest.e2e.config.js --ci",
|
|
61
66
|
"test:recovery:ci": "jest --config jest.integration.config.js recovery.test.ts --ci",
|
|
62
67
|
"test:anchorplatform:ci": "yarn jest --config jest.integration.config.js anchorplatform.test.ts --ci",
|
|
63
68
|
"build:web": "webpack --config webpack.config.js",
|
|
@@ -65,4 +70,4 @@
|
|
|
65
70
|
"build": "run-p build:web build:node",
|
|
66
71
|
"example:sep24": "ts-node examples/sep24/sep24.ts"
|
|
67
72
|
}
|
|
68
|
-
}
|
|
73
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -17,6 +17,11 @@ export { Anchor } from "./walletSdk/Anchor";
|
|
|
17
17
|
export { Sep24 } from "./walletSdk/Anchor/Sep24";
|
|
18
18
|
export { IssuedAssetId, NativeAssetId, FiatAssetId } from "./walletSdk/Asset";
|
|
19
19
|
export { Sep10, WalletSigner, DefaultSigner } from "./walletSdk/Auth";
|
|
20
|
+
export {
|
|
21
|
+
AuthHeaderSigner,
|
|
22
|
+
DefaultAuthHeaderSigner,
|
|
23
|
+
DomainAuthHeaderSigner,
|
|
24
|
+
} from "./walletSdk/Auth/AuthHeaderSigner";
|
|
20
25
|
export {
|
|
21
26
|
AccountKeypair,
|
|
22
27
|
PublicKeypair,
|
|
@@ -28,6 +33,15 @@ export {
|
|
|
28
33
|
SponsoringBuilder,
|
|
29
34
|
} from "./walletSdk/Horizon";
|
|
30
35
|
export { Recovery } from "./walletSdk/Recovery";
|
|
36
|
+
export {
|
|
37
|
+
Sep7Base,
|
|
38
|
+
Sep7Pay,
|
|
39
|
+
Sep7Tx,
|
|
40
|
+
isValidSep7Uri,
|
|
41
|
+
parseSep7Uri,
|
|
42
|
+
sep7ReplacementsFromString,
|
|
43
|
+
sep7ReplacementsToString,
|
|
44
|
+
} from "./walletSdk/Uri";
|
|
31
45
|
export { Watcher } from "./walletSdk/Watcher";
|
|
32
46
|
|
|
33
47
|
/**
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { AxiosInstance } from "axios";
|
|
2
|
+
import { StrKey } from "@stellar/stellar-sdk";
|
|
3
|
+
import nacl from "tweetnacl";
|
|
4
|
+
import naclUtil from "tweetnacl-util";
|
|
5
|
+
import base64url from "base64url";
|
|
6
|
+
|
|
7
|
+
import { SigningKeypair } from "../Horizon/Account";
|
|
8
|
+
import { DefaultClient } from "../";
|
|
9
|
+
import { AuthHeaderClaims, AuthHeaderCreateTokenParams } from "../Types";
|
|
10
|
+
import {
|
|
11
|
+
AuthHeaderSigningKeypairRequiredError,
|
|
12
|
+
AuthHeaderClientDomainRequiredError,
|
|
13
|
+
} from "../Exceptions";
|
|
14
|
+
|
|
15
|
+
export interface AuthHeaderSigner {
|
|
16
|
+
createToken({
|
|
17
|
+
claims,
|
|
18
|
+
clientDomain,
|
|
19
|
+
issuer,
|
|
20
|
+
}: AuthHeaderCreateTokenParams): Promise<string>;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Signer for signing JWT for GET /Auth with a custodial private key
|
|
25
|
+
*
|
|
26
|
+
* @class
|
|
27
|
+
*/
|
|
28
|
+
export class DefaultAuthHeaderSigner implements AuthHeaderSigner {
|
|
29
|
+
expiration: number;
|
|
30
|
+
|
|
31
|
+
constructor(expiration: number = 900) {
|
|
32
|
+
this.expiration = expiration;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Create a signed JWT for the auth header
|
|
37
|
+
* @constructor
|
|
38
|
+
* @param {AuthHeaderCreateTokenParams} params - The create token parameters
|
|
39
|
+
* @param {AuthHeaderClaims} params.claims - the data to be signed in the JWT
|
|
40
|
+
* @param {string} [params.clientDomain] - the client domain hosting SEP-1 toml
|
|
41
|
+
* @param {AccountKeypair} [params.issuer] - the account signing the JWT
|
|
42
|
+
* @returns {Promise<string>} The signed JWT
|
|
43
|
+
*/
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/require-await
|
|
45
|
+
async createToken({
|
|
46
|
+
claims,
|
|
47
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
48
|
+
clientDomain,
|
|
49
|
+
issuer,
|
|
50
|
+
}: AuthHeaderCreateTokenParams): Promise<string> {
|
|
51
|
+
if (!(issuer instanceof SigningKeypair)) {
|
|
52
|
+
throw new AuthHeaderSigningKeypairRequiredError();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const issuedAt = claims.iat || Math.floor(Date.now() / 1000);
|
|
56
|
+
const timeExp =
|
|
57
|
+
claims.exp || Math.floor(Date.now() / 1000) + this.expiration;
|
|
58
|
+
|
|
59
|
+
// turn stellar kp into nacl kp for creating JWT
|
|
60
|
+
const rawSeed = StrKey.decodeEd25519SecretSeed(issuer.secretKey);
|
|
61
|
+
const naclKP = nacl.sign.keyPair.fromSeed(rawSeed);
|
|
62
|
+
|
|
63
|
+
// encode JWT message
|
|
64
|
+
const header = { alg: "EdDSA" };
|
|
65
|
+
const encodedHeader = base64url(JSON.stringify(header));
|
|
66
|
+
const encodedPayload = base64url(
|
|
67
|
+
JSON.stringify({ ...claims, exp: timeExp, iat: issuedAt }),
|
|
68
|
+
);
|
|
69
|
+
|
|
70
|
+
// sign JWT and create signature
|
|
71
|
+
const signature = nacl.sign.detached(
|
|
72
|
+
naclUtil.decodeUTF8(`${encodedHeader}.${encodedPayload}`),
|
|
73
|
+
naclKP.secretKey,
|
|
74
|
+
);
|
|
75
|
+
const encodedSignature = base64url(Buffer.from(signature));
|
|
76
|
+
|
|
77
|
+
const jwt = `${encodedHeader}.${encodedPayload}.${encodedSignature}`;
|
|
78
|
+
return jwt;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Signer for signing JWT for GET /Auth using a remote server to sign.
|
|
84
|
+
*
|
|
85
|
+
* @class
|
|
86
|
+
*/
|
|
87
|
+
export class DomainAuthHeaderSigner implements AuthHeaderSigner {
|
|
88
|
+
signerUrl: string;
|
|
89
|
+
expiration: number;
|
|
90
|
+
httpClient: AxiosInstance;
|
|
91
|
+
|
|
92
|
+
constructor(
|
|
93
|
+
signerUrl: string,
|
|
94
|
+
expiration: number = 900,
|
|
95
|
+
httpClient?: AxiosInstance,
|
|
96
|
+
) {
|
|
97
|
+
this.signerUrl = signerUrl;
|
|
98
|
+
this.expiration = expiration;
|
|
99
|
+
this.httpClient = httpClient || DefaultClient;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Create a signed JWT for the auth header by using a remote server to sign the JWT
|
|
104
|
+
* @constructor
|
|
105
|
+
* @param {AuthHeaderCreateTokenParams} params - The create token parameters
|
|
106
|
+
* @param {AuthHeaderClaims} params.claims - the data to be signed in the JWT
|
|
107
|
+
* @param {string} [params.clientDomain] - the client domain hosting SEP-1 toml
|
|
108
|
+
* @param {AccountKeypair} [params.issuer] - unused, will not be used to sign
|
|
109
|
+
* @returns {Promise<string>} The signed JWT
|
|
110
|
+
*/
|
|
111
|
+
async createToken({
|
|
112
|
+
claims,
|
|
113
|
+
clientDomain,
|
|
114
|
+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
115
|
+
issuer,
|
|
116
|
+
}: AuthHeaderCreateTokenParams): Promise<string> {
|
|
117
|
+
if (!clientDomain) {
|
|
118
|
+
throw new AuthHeaderClientDomainRequiredError();
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const issuedAt = Math.floor(Date.now() / 1000);
|
|
122
|
+
const expiration = Math.floor(Date.now() / 1000) + this.expiration;
|
|
123
|
+
|
|
124
|
+
return await this.signTokenRemote({
|
|
125
|
+
claims,
|
|
126
|
+
clientDomain,
|
|
127
|
+
expiration,
|
|
128
|
+
issuedAt,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Sign JWT by calling a remote server
|
|
134
|
+
* @constructor
|
|
135
|
+
* @param {SignTokenRemoteParams} params - the sign token params
|
|
136
|
+
* @param {AuthHeaderClaims} params.claims - the data to be signed in the JWT
|
|
137
|
+
* @param {string} params.clientDomain - the client domain hosting SEP-1 toml
|
|
138
|
+
* @param {number} params.expiration - when the token should expire
|
|
139
|
+
* @param {number} params.issuedAt - when the token was created
|
|
140
|
+
* @returns {Promise<string>} The signed JWT
|
|
141
|
+
*/
|
|
142
|
+
async signTokenRemote({
|
|
143
|
+
claims,
|
|
144
|
+
clientDomain,
|
|
145
|
+
expiration,
|
|
146
|
+
issuedAt,
|
|
147
|
+
}: {
|
|
148
|
+
claims: AuthHeaderClaims;
|
|
149
|
+
clientDomain: string;
|
|
150
|
+
expiration: number;
|
|
151
|
+
issuedAt: number;
|
|
152
|
+
}): Promise<string> {
|
|
153
|
+
const resp = await this.httpClient.post(this.signerUrl, {
|
|
154
|
+
clientDomain,
|
|
155
|
+
expiration,
|
|
156
|
+
issuedAt,
|
|
157
|
+
...claims,
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return resp.data.token;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
HttpHeaders,
|
|
11
11
|
} from "../Types";
|
|
12
12
|
import { DefaultClient } from "../";
|
|
13
|
+
import { DefaultSignerDomainAccountError } from "../Exceptions";
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* A Wallet Signer for signing Stellar transactions.
|
|
@@ -51,9 +52,8 @@ export const DefaultSigner: WalletSigner = {
|
|
|
51
52
|
},
|
|
52
53
|
// eslint-disable-next-line @typescript-eslint/require-await
|
|
53
54
|
signWithDomainAccount: async () => {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
);
|
|
55
|
+
// The DefaultSigner can't sign transactions with domain account
|
|
56
|
+
throw new DefaultSignerDomainAccountError();
|
|
57
57
|
},
|
|
58
58
|
};
|
|
59
59
|
|
|
@@ -2,7 +2,7 @@ import { AxiosInstance } from "axios";
|
|
|
2
2
|
import { TransactionBuilder, Transaction } from "@stellar/stellar-sdk";
|
|
3
3
|
import { decode } from "jws";
|
|
4
4
|
|
|
5
|
-
import { Config } from "
|
|
5
|
+
import { Config } from "../";
|
|
6
6
|
import {
|
|
7
7
|
InvalidMemoError,
|
|
8
8
|
ClientDomainWithMemoError,
|
|
@@ -17,7 +17,10 @@ import {
|
|
|
17
17
|
ChallengeParams,
|
|
18
18
|
ChallengeResponse,
|
|
19
19
|
SignParams,
|
|
20
|
+
AuthHeaderClaims,
|
|
20
21
|
} from "../Types";
|
|
22
|
+
import { AccountKeypair } from "../Horizon/Account";
|
|
23
|
+
import { AuthHeaderSigner } from "./AuthHeaderSigner";
|
|
21
24
|
|
|
22
25
|
export { WalletSigner, DefaultSigner } from "./WalletSigner";
|
|
23
26
|
|
|
@@ -71,11 +74,13 @@ export class Sep10 {
|
|
|
71
74
|
walletSigner,
|
|
72
75
|
memoId,
|
|
73
76
|
clientDomain,
|
|
77
|
+
authHeaderSigner,
|
|
74
78
|
}: AuthenticateParams): Promise<AuthToken> {
|
|
75
79
|
const challengeResponse = await this.challenge({
|
|
76
80
|
accountKp,
|
|
77
81
|
memoId,
|
|
78
82
|
clientDomain: clientDomain || this.cfg.app.defaultClientDomain,
|
|
83
|
+
authHeaderSigner,
|
|
79
84
|
});
|
|
80
85
|
const signedTransaction = await this.sign({
|
|
81
86
|
accountKp,
|
|
@@ -90,6 +95,7 @@ export class Sep10 {
|
|
|
90
95
|
accountKp,
|
|
91
96
|
memoId,
|
|
92
97
|
clientDomain,
|
|
98
|
+
authHeaderSigner,
|
|
93
99
|
}: ChallengeParams): Promise<ChallengeResponse> {
|
|
94
100
|
if (memoId && parseInt(memoId) < 0) {
|
|
95
101
|
throw new InvalidMemoError();
|
|
@@ -104,8 +110,29 @@ export class Sep10 {
|
|
|
104
110
|
}${clientDomain ? `&client_domain=${clientDomain}` : ""}${
|
|
105
111
|
this.homeDomain ? `&home_domain=${this.homeDomain}` : ""
|
|
106
112
|
}`;
|
|
113
|
+
|
|
114
|
+
const claims = {
|
|
115
|
+
account: accountKp.publicKey,
|
|
116
|
+
home_domain: this.homeDomain,
|
|
117
|
+
memo: memoId,
|
|
118
|
+
client_domain: clientDomain,
|
|
119
|
+
web_auth_endpoint: this.webAuthEndpoint,
|
|
120
|
+
};
|
|
121
|
+
|
|
122
|
+
const token = await createAuthSignToken(
|
|
123
|
+
accountKp,
|
|
124
|
+
claims,
|
|
125
|
+
clientDomain,
|
|
126
|
+
authHeaderSigner,
|
|
127
|
+
);
|
|
128
|
+
|
|
129
|
+
let headers = {};
|
|
130
|
+
if (token) {
|
|
131
|
+
headers = { Authorization: `Bearer ${token}` };
|
|
132
|
+
}
|
|
133
|
+
|
|
107
134
|
try {
|
|
108
|
-
const resp = await this.httpClient.get(url);
|
|
135
|
+
const resp = await this.httpClient.get(url, { headers });
|
|
109
136
|
const challengeResponse: ChallengeResponse = resp.data;
|
|
110
137
|
return challengeResponse;
|
|
111
138
|
} catch (e) {
|
|
@@ -165,3 +192,22 @@ const validateToken = (token: string) => {
|
|
|
165
192
|
throw new ExpiredTokenError(parsedToken.expiresAt);
|
|
166
193
|
}
|
|
167
194
|
};
|
|
195
|
+
|
|
196
|
+
const createAuthSignToken = async (
|
|
197
|
+
account: AccountKeypair,
|
|
198
|
+
claims: AuthHeaderClaims,
|
|
199
|
+
clientDomain?: string,
|
|
200
|
+
authHeaderSigner?: AuthHeaderSigner,
|
|
201
|
+
) => {
|
|
202
|
+
if (!authHeaderSigner) {
|
|
203
|
+
return null;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
const issuer = clientDomain ? null : account;
|
|
207
|
+
|
|
208
|
+
return authHeaderSigner.createToken({
|
|
209
|
+
claims,
|
|
210
|
+
clientDomain,
|
|
211
|
+
issuer,
|
|
212
|
+
});
|
|
213
|
+
};
|
|
@@ -17,10 +17,10 @@ import {
|
|
|
17
17
|
* @class
|
|
18
18
|
*/
|
|
19
19
|
export class Sep12 {
|
|
20
|
-
private authToken;
|
|
21
|
-
private baseUrl;
|
|
22
|
-
private httpClient;
|
|
23
|
-
private headers;
|
|
20
|
+
private authToken: AuthToken;
|
|
21
|
+
private baseUrl: string;
|
|
22
|
+
private httpClient: AxiosInstance;
|
|
23
|
+
private headers: { [key: string]: string };
|
|
24
24
|
|
|
25
25
|
/**
|
|
26
26
|
* Creates a new instance of the Sep12 class.
|
|
@@ -64,7 +64,7 @@ export class Sep12 {
|
|
|
64
64
|
if (!resp.data.id) {
|
|
65
65
|
throw new CustomerNotFoundError(params);
|
|
66
66
|
}
|
|
67
|
-
return resp;
|
|
67
|
+
return resp.data;
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
/**
|
|
@@ -104,7 +104,7 @@ export class Sep12 {
|
|
|
104
104
|
: this.headers,
|
|
105
105
|
},
|
|
106
106
|
);
|
|
107
|
-
return resp;
|
|
107
|
+
return resp.data;
|
|
108
108
|
}
|
|
109
109
|
|
|
110
110
|
/**
|
|
@@ -154,7 +154,7 @@ export class Sep12 {
|
|
|
154
154
|
: this.headers,
|
|
155
155
|
},
|
|
156
156
|
);
|
|
157
|
-
return resp;
|
|
157
|
+
return resp.data;
|
|
158
158
|
}
|
|
159
159
|
|
|
160
160
|
/**
|
|
@@ -305,3 +305,59 @@ export class InvalidJsonError extends Error {
|
|
|
305
305
|
Object.setPrototypeOf(this, InvalidJsonError.prototype);
|
|
306
306
|
}
|
|
307
307
|
}
|
|
308
|
+
|
|
309
|
+
export class SigningKeypairMissingSecretError extends Error {
|
|
310
|
+
constructor() {
|
|
311
|
+
super("This keypair doesn't have a secret key and can't sign");
|
|
312
|
+
Object.setPrototypeOf(this, SigningKeypairMissingSecretError.prototype);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
export class DefaultSignerDomainAccountError extends Error {
|
|
317
|
+
constructor() {
|
|
318
|
+
super("The DefaultSigner can't sign transactions with domain account");
|
|
319
|
+
Object.setPrototypeOf(this, DefaultSignerDomainAccountError.prototype);
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
export class AuthHeaderSigningKeypairRequiredError extends Error {
|
|
324
|
+
constructor() {
|
|
325
|
+
super("Must be SigningKeypair to sign auth header");
|
|
326
|
+
Object.setPrototypeOf(
|
|
327
|
+
this,
|
|
328
|
+
AuthHeaderSigningKeypairRequiredError.prototype,
|
|
329
|
+
);
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
export class AuthHeaderClientDomainRequiredError extends Error {
|
|
334
|
+
constructor() {
|
|
335
|
+
super(
|
|
336
|
+
"This class should only be used for remote signing. For local signing use DefaultAuthHeaderSigner",
|
|
337
|
+
);
|
|
338
|
+
Object.setPrototypeOf(this, AuthHeaderClientDomainRequiredError.prototype);
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
export class Sep7InvalidUriError extends Error {
|
|
343
|
+
constructor(reason: string) {
|
|
344
|
+
super(`Invalid Stellar Sep-7 URI, reason: ${reason}`);
|
|
345
|
+
Object.setPrototypeOf(this, Sep7InvalidUriError.prototype);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
export class Sep7LongMsgError extends Error {
|
|
350
|
+
constructor(msgMaxLength: number) {
|
|
351
|
+
super(`'msg' should be no longer than ${msgMaxLength} characters`);
|
|
352
|
+
Object.setPrototypeOf(this, Sep7LongMsgError.prototype);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
export class Sep7UriTypeNotSupportedError extends Error {
|
|
357
|
+
constructor(type: string) {
|
|
358
|
+
super(
|
|
359
|
+
`Stellar Sep-7 URI operation type '${type}' is not currently supported`,
|
|
360
|
+
);
|
|
361
|
+
Object.setPrototypeOf(this, Sep7UriTypeNotSupportedError.prototype);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { Keypair, Transaction, FeeBumpTransaction } from "@stellar/stellar-sdk";
|
|
2
|
+
import { SigningKeypairMissingSecretError } from "../Exceptions";
|
|
2
3
|
|
|
3
4
|
export class AccountKeypair {
|
|
4
5
|
keypair: Keypair;
|
|
@@ -28,7 +29,7 @@ export class PublicKeypair extends AccountKeypair {
|
|
|
28
29
|
export class SigningKeypair extends AccountKeypair {
|
|
29
30
|
constructor(keypair: Keypair) {
|
|
30
31
|
if (!keypair.canSign()) {
|
|
31
|
-
throw new
|
|
32
|
+
throw new SigningKeypairMissingSecretError();
|
|
32
33
|
}
|
|
33
34
|
super(keypair);
|
|
34
35
|
}
|