@veridex/sdk 1.1.0 → 1.1.2
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/dist/{EVMClient-DtqvdfUP.d.mts → EVMClient-Bmy9czkE.d.mts} +2 -0
- package/dist/auth/prepareAuth.js +107 -32
- package/dist/auth/prepareAuth.js.map +1 -1
- package/dist/auth/prepareAuth.mjs +6 -6
- package/dist/chains/aptos/index.js.map +1 -1
- package/dist/chains/aptos/index.mjs +3 -3
- package/dist/chains/avalanche/index.d.mts +1 -1
- package/dist/chains/avalanche/index.js +59 -11
- package/dist/chains/avalanche/index.js.map +1 -1
- package/dist/chains/avalanche/index.mjs +4 -4
- package/dist/chains/evm/index.d.mts +3 -3
- package/dist/chains/evm/index.js +59 -11
- package/dist/chains/evm/index.js.map +1 -1
- package/dist/chains/evm/index.mjs +3 -3
- package/dist/chains/solana/index.js.map +1 -1
- package/dist/chains/solana/index.mjs +3 -3
- package/dist/chains/stacks/index.d.mts +1 -1
- package/dist/chains/stacks/index.js.map +1 -1
- package/dist/chains/stacks/index.mjs +3 -3
- package/dist/chains/starknet/index.d.mts +1 -1
- package/dist/chains/starknet/index.js.map +1 -1
- package/dist/chains/starknet/index.mjs +3 -3
- package/dist/chains/stellar/index.d.mts +312 -0
- package/dist/chains/stellar/index.js +300 -0
- package/dist/chains/stellar/index.js.map +1 -0
- package/dist/chains/stellar/index.mjs +260 -0
- package/dist/chains/stellar/index.mjs.map +1 -0
- package/dist/chains/sui/index.d.mts +1 -1
- package/dist/chains/sui/index.js.map +1 -1
- package/dist/chains/sui/index.mjs +3 -3
- package/dist/{chunk-Q5O3M5LP.mjs → chunk-2TS375ET.mjs} +2 -2
- package/dist/{chunk-QT4ZZ4GM.mjs → chunk-5FDOTI5G.mjs} +2 -2
- package/dist/{chunk-N4A2RMUN.mjs → chunk-AFHWA4CZ.mjs} +2 -2
- package/dist/{chunk-5T6KPH7A.mjs → chunk-CSU4IV2F.mjs} +2 -2
- package/dist/{chunk-YCUJZ6Z7.mjs → chunk-CTYDGO6E.mjs} +63 -6
- package/dist/chunk-CTYDGO6E.mjs.map +1 -0
- package/dist/{chunk-USDA5JTN.mjs → chunk-DZUNCSI5.mjs} +61 -13
- package/dist/chunk-DZUNCSI5.mjs.map +1 -0
- package/dist/{chunk-SXXGTQIR.mjs → chunk-E3SU36C2.mjs} +2 -2
- package/dist/{chunk-NUWSMJFJ.mjs → chunk-EFIXFA6V.mjs} +2 -2
- package/dist/{chunk-MLXQHIH2.mjs → chunk-GM5DKEHD.mjs} +2 -2
- package/dist/{chunk-GWJRKDSA.mjs → chunk-GOWXQPTW.mjs} +3 -3
- package/dist/{chunk-OVMMTL6H.mjs → chunk-ICGB3AHI.mjs} +2 -2
- package/dist/{chunk-QDO6NQ7P.mjs → chunk-M3GUNREX.mjs} +20 -3
- package/dist/{chunk-QDO6NQ7P.mjs.map → chunk-M3GUNREX.mjs.map} +1 -1
- package/dist/{chunk-X7BZMSPQ.mjs → chunk-RD6ZYUVG.mjs} +52 -30
- package/dist/chunk-RD6ZYUVG.mjs.map +1 -0
- package/dist/{chunk-F3YAGZSW.mjs → chunk-TPEP6XUA.mjs} +2 -2
- package/dist/{chunk-M3MM4YMF.mjs → chunk-UPO55SBK.mjs} +2 -2
- package/dist/{chunk-PDHZ5X5O.mjs → chunk-YYT3V7CI.mjs} +2 -2
- package/dist/constants.d.mts +2 -2
- package/dist/constants.js +51 -29
- package/dist/constants.js.map +1 -1
- package/dist/constants.mjs +1 -1
- package/dist/{index-DDalBhAm.d.mts → index-CKKUV4J7.d.mts} +10 -7
- package/dist/index.d.mts +43 -14
- package/dist/index.js +512 -159
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +335 -128
- package/dist/index.mjs.map +1 -1
- package/dist/passkey.js +57 -4
- package/dist/passkey.js.map +1 -1
- package/dist/passkey.mjs +3 -3
- package/dist/payload.js.map +1 -1
- package/dist/payload.mjs +2 -2
- package/dist/portfolio-JA4OTF7Y.mjs +13 -0
- package/dist/queries/index.js +49 -27
- package/dist/queries/index.js.map +1 -1
- package/dist/queries/index.mjs +5 -5
- package/dist/{types-B7V5VNbO.d.mts → types-C564CfsE.d.mts} +33 -4
- package/dist/utils.js +49 -27
- package/dist/utils.js.map +1 -1
- package/dist/utils.mjs +2 -2
- package/dist/wormhole.js.map +1 -1
- package/dist/wormhole.mjs +2 -2
- package/package.json +8 -1
- package/dist/chunk-USDA5JTN.mjs.map +0 -1
- package/dist/chunk-X7BZMSPQ.mjs.map +0 -1
- package/dist/chunk-YCUJZ6Z7.mjs.map +0 -1
- package/dist/portfolio-V347KZOL.mjs +0 -13
- /package/dist/{chunk-Q5O3M5LP.mjs.map → chunk-2TS375ET.mjs.map} +0 -0
- /package/dist/{chunk-QT4ZZ4GM.mjs.map → chunk-5FDOTI5G.mjs.map} +0 -0
- /package/dist/{chunk-N4A2RMUN.mjs.map → chunk-AFHWA4CZ.mjs.map} +0 -0
- /package/dist/{chunk-5T6KPH7A.mjs.map → chunk-CSU4IV2F.mjs.map} +0 -0
- /package/dist/{chunk-SXXGTQIR.mjs.map → chunk-E3SU36C2.mjs.map} +0 -0
- /package/dist/{chunk-NUWSMJFJ.mjs.map → chunk-EFIXFA6V.mjs.map} +0 -0
- /package/dist/{chunk-MLXQHIH2.mjs.map → chunk-GM5DKEHD.mjs.map} +0 -0
- /package/dist/{chunk-GWJRKDSA.mjs.map → chunk-GOWXQPTW.mjs.map} +0 -0
- /package/dist/{chunk-OVMMTL6H.mjs.map → chunk-ICGB3AHI.mjs.map} +0 -0
- /package/dist/{chunk-F3YAGZSW.mjs.map → chunk-TPEP6XUA.mjs.map} +0 -0
- /package/dist/{chunk-M3MM4YMF.mjs.map → chunk-UPO55SBK.mjs.map} +0 -0
- /package/dist/{chunk-PDHZ5X5O.mjs.map → chunk-YYT3V7CI.mjs.map} +0 -0
- /package/dist/{portfolio-V347KZOL.mjs.map → portfolio-JA4OTF7Y.mjs.map} +0 -0
package/dist/index.mjs
CHANGED
|
@@ -1,34 +1,36 @@
|
|
|
1
1
|
import {
|
|
2
2
|
CHAIN_NAMES,
|
|
3
3
|
CHAIN_PRESETS,
|
|
4
|
+
configureDefaultRpcUrls,
|
|
4
5
|
getChainConfig,
|
|
5
6
|
getChainPreset,
|
|
6
7
|
getDefaultHub,
|
|
7
8
|
getEffectivePrimaryHub,
|
|
8
9
|
getFeatureFlags,
|
|
9
10
|
getHubChains,
|
|
11
|
+
getRpcUrlOverride,
|
|
10
12
|
getSupportedChains,
|
|
11
13
|
isChainSupported,
|
|
12
14
|
isHubChain,
|
|
13
15
|
isMultiHubEnabled,
|
|
14
16
|
resetFeatureFlags,
|
|
15
17
|
setFeatureFlags
|
|
16
|
-
} from "./chunk-
|
|
18
|
+
} from "./chunk-M3GUNREX.mjs";
|
|
17
19
|
import {
|
|
18
20
|
EVMHubClientAdapter
|
|
19
21
|
} from "./chunk-V636MIV3.mjs";
|
|
20
22
|
import {
|
|
21
23
|
SolanaClient
|
|
22
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-2TS375ET.mjs";
|
|
23
25
|
import {
|
|
24
26
|
AptosClient
|
|
25
|
-
} from "./chunk-
|
|
27
|
+
} from "./chunk-5FDOTI5G.mjs";
|
|
26
28
|
import {
|
|
27
29
|
SuiClient
|
|
28
|
-
} from "./chunk-
|
|
30
|
+
} from "./chunk-E3SU36C2.mjs";
|
|
29
31
|
import {
|
|
30
32
|
StarknetClient
|
|
31
|
-
} from "./chunk-
|
|
33
|
+
} from "./chunk-GM5DKEHD.mjs";
|
|
32
34
|
import {
|
|
33
35
|
STACKS_ACTION_TYPES,
|
|
34
36
|
StacksClient,
|
|
@@ -56,13 +58,13 @@ import {
|
|
|
56
58
|
parseContractPrincipal,
|
|
57
59
|
rsToCompactSignature,
|
|
58
60
|
validatePostConditions
|
|
59
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-CSU4IV2F.mjs";
|
|
60
62
|
import {
|
|
61
63
|
AvalancheClient
|
|
62
|
-
} from "./chunk-
|
|
64
|
+
} from "./chunk-AFHWA4CZ.mjs";
|
|
63
65
|
import {
|
|
64
66
|
EVMClient
|
|
65
|
-
} from "./chunk-
|
|
67
|
+
} from "./chunk-DZUNCSI5.mjs";
|
|
66
68
|
import {
|
|
67
69
|
CONSISTENCY_LEVELS,
|
|
68
70
|
GUARDIAN_CONFIG,
|
|
@@ -85,7 +87,7 @@ import {
|
|
|
85
87
|
supportsRelayer,
|
|
86
88
|
validateEmitter,
|
|
87
89
|
waitForGuardianSignatures
|
|
88
|
-
} from "./chunk-
|
|
90
|
+
} from "./chunk-UPO55SBK.mjs";
|
|
89
91
|
import {
|
|
90
92
|
buildChallenge,
|
|
91
93
|
buildGaslessChallenge,
|
|
@@ -109,7 +111,7 @@ import {
|
|
|
109
111
|
parseAmount,
|
|
110
112
|
solanaAddressToBytes32,
|
|
111
113
|
trimTo20Bytes
|
|
112
|
-
} from "./chunk-
|
|
114
|
+
} from "./chunk-TPEP6XUA.mjs";
|
|
113
115
|
import {
|
|
114
116
|
ARBITRUM_SEPOLIA_TOKENS,
|
|
115
117
|
BASE_SEPOLIA_TOKENS,
|
|
@@ -127,13 +129,15 @@ import {
|
|
|
127
129
|
getTokenBySymbol,
|
|
128
130
|
getTokenList,
|
|
129
131
|
isNativeToken
|
|
130
|
-
} from "./chunk-
|
|
132
|
+
} from "./chunk-YYT3V7CI.mjs";
|
|
131
133
|
import {
|
|
132
134
|
PasskeyManager,
|
|
133
135
|
VERIDEX_RP_ID,
|
|
136
|
+
buildRelayerApiUrl,
|
|
134
137
|
detectRpId,
|
|
138
|
+
normalizeRelayerOrigin,
|
|
135
139
|
supportsRelatedOrigins
|
|
136
|
-
} from "./chunk-
|
|
140
|
+
} from "./chunk-CTYDGO6E.mjs";
|
|
137
141
|
import {
|
|
138
142
|
base64URLDecode,
|
|
139
143
|
base64URLEncode,
|
|
@@ -149,7 +153,7 @@ import {
|
|
|
149
153
|
isValidWormholeChainId,
|
|
150
154
|
parseDERSignature,
|
|
151
155
|
retryWithBackoff
|
|
152
|
-
} from "./chunk-
|
|
156
|
+
} from "./chunk-EFIXFA6V.mjs";
|
|
153
157
|
import {
|
|
154
158
|
ACTION_BRIDGE,
|
|
155
159
|
ACTION_CONFIG,
|
|
@@ -165,7 +169,7 @@ import {
|
|
|
165
169
|
WORMHOLE_API,
|
|
166
170
|
WORMHOLE_CHAIN_IDS,
|
|
167
171
|
WORMHOLE_CHAIN_IDS_FLAT
|
|
168
|
-
} from "./chunk-
|
|
172
|
+
} from "./chunk-RD6ZYUVG.mjs";
|
|
169
173
|
|
|
170
174
|
// src/core/BalanceManager.ts
|
|
171
175
|
import { ethers } from "ethers";
|
|
@@ -1014,7 +1018,7 @@ var RelayerClient = class _RelayerClient {
|
|
|
1014
1018
|
baseUrl;
|
|
1015
1019
|
config;
|
|
1016
1020
|
constructor(config) {
|
|
1017
|
-
this.baseUrl = config.baseUrl
|
|
1021
|
+
this.baseUrl = normalizeRelayerOrigin(config.baseUrl);
|
|
1018
1022
|
this.config = { ...DEFAULT_CONFIG2, ...config };
|
|
1019
1023
|
}
|
|
1020
1024
|
// ========================================================================
|
|
@@ -1281,6 +1285,7 @@ var RelayerClient = class _RelayerClient {
|
|
|
1281
1285
|
* Make an HTTP request to the relayer
|
|
1282
1286
|
*/
|
|
1283
1287
|
async fetch(path, options = {}) {
|
|
1288
|
+
const resolvedUrl = path.startsWith("/api/v1/") ? buildRelayerApiUrl(this.baseUrl, path.replace(/^\/api\/v1/, "")) : `${this.baseUrl}${path}`;
|
|
1284
1289
|
const headers = {
|
|
1285
1290
|
"Content-Type": "application/json",
|
|
1286
1291
|
"User-Agent": `@veridex/sdk/${_RelayerClient.SDK_VERSION}`,
|
|
@@ -1294,7 +1299,7 @@ var RelayerClient = class _RelayerClient {
|
|
|
1294
1299
|
let lastError = null;
|
|
1295
1300
|
for (let attempt = 0; attempt <= this.config.maxRetries; attempt++) {
|
|
1296
1301
|
try {
|
|
1297
|
-
const response = await fetch(
|
|
1302
|
+
const response = await fetch(resolvedUrl, {
|
|
1298
1303
|
...options,
|
|
1299
1304
|
headers,
|
|
1300
1305
|
signal: controller.signal
|
|
@@ -5300,7 +5305,7 @@ var VeridexSDK = class {
|
|
|
5300
5305
|
const wormholeChainId = chainConfig.wormholeChainId;
|
|
5301
5306
|
const tokenList = getAllTokens(wormholeChainId);
|
|
5302
5307
|
const erc20Tokens = tokenList.filter((t) => !isNativeToken(t.address)).map((t) => t.address);
|
|
5303
|
-
const { queryPortfolio } = await import("./portfolio-
|
|
5308
|
+
const { queryPortfolio } = await import("./portfolio-JA4OTF7Y.mjs");
|
|
5304
5309
|
const result = await queryPortfolio(credential.keyHash, this.queryApiKey, {
|
|
5305
5310
|
network: this.testnet ? "testnet" : "mainnet",
|
|
5306
5311
|
vaultAddresses: { [wormholeChainId]: vaultAddress },
|
|
@@ -5663,7 +5668,7 @@ var VeridexSDK = class {
|
|
|
5663
5668
|
const tokenList = getAllTokens(wormholeChainId);
|
|
5664
5669
|
const erc20Tokens = tokenList.filter((t) => !isNativeToken(t.address)).map((t) => t.address);
|
|
5665
5670
|
const rpcUrl = this.chainRpcUrls?.[wormholeChainId] ?? chainConfig.rpcUrl;
|
|
5666
|
-
const { queryPortfolio } = await import("./portfolio-
|
|
5671
|
+
const { queryPortfolio } = await import("./portfolio-JA4OTF7Y.mjs");
|
|
5667
5672
|
const result = await queryPortfolio(credential.keyHash, this.queryApiKey, {
|
|
5668
5673
|
network: this.testnet ? "testnet" : "mainnet",
|
|
5669
5674
|
vaultAddresses: { [wormholeChainId]: vaultAddress },
|
|
@@ -6657,7 +6662,7 @@ var CredentialManager = class {
|
|
|
6657
6662
|
constructor(config = {}) {
|
|
6658
6663
|
this.config = {
|
|
6659
6664
|
storageKey: config.storageKey ?? DEFAULT_STORAGE_KEY,
|
|
6660
|
-
relayerUrl: config.relayerUrl ?? ""
|
|
6665
|
+
relayerUrl: normalizeRelayerOrigin(config.relayerUrl ?? "")
|
|
6661
6666
|
};
|
|
6662
6667
|
}
|
|
6663
6668
|
// ========================================================================
|
|
@@ -6805,7 +6810,7 @@ var CredentialManager = class {
|
|
|
6805
6810
|
const managed = this.getCredential(credentialId);
|
|
6806
6811
|
if (!managed) return false;
|
|
6807
6812
|
try {
|
|
6808
|
-
const response = await fetch(
|
|
6813
|
+
const response = await fetch(buildRelayerApiUrl(this.config.relayerUrl, "/credential/metadata"), {
|
|
6809
6814
|
method: "PUT",
|
|
6810
6815
|
headers: { "Content-Type": "application/json" },
|
|
6811
6816
|
body: JSON.stringify({
|
|
@@ -6831,7 +6836,10 @@ var CredentialManager = class {
|
|
|
6831
6836
|
if (!this.config.relayerUrl) return null;
|
|
6832
6837
|
try {
|
|
6833
6838
|
const response = await fetch(
|
|
6834
|
-
|
|
6839
|
+
buildRelayerApiUrl(
|
|
6840
|
+
this.config.relayerUrl,
|
|
6841
|
+
`/credential/metadata?keyHash=${encodeURIComponent(keyHash)}`
|
|
6842
|
+
)
|
|
6835
6843
|
);
|
|
6836
6844
|
if (!response.ok) return null;
|
|
6837
6845
|
const data = await response.json();
|
|
@@ -6953,7 +6961,7 @@ var CredentialManager = class {
|
|
|
6953
6961
|
|
|
6954
6962
|
// src/core/CrossOriginAuth.ts
|
|
6955
6963
|
var DEFAULT_AUTH_PORTAL_URL = "https://auth.veridex.network";
|
|
6956
|
-
var DEFAULT_RELAYER_URL = "https://
|
|
6964
|
+
var DEFAULT_RELAYER_URL = "https://relayer.veridex.network";
|
|
6957
6965
|
var AUTH_MESSAGE_TYPES = {
|
|
6958
6966
|
AUTH_REQUEST: "VERIDEX_AUTH_REQUEST",
|
|
6959
6967
|
AUTH_RESPONSE: "VERIDEX_AUTH_RESPONSE",
|
|
@@ -6965,7 +6973,7 @@ var CrossOriginAuth = class {
|
|
|
6965
6973
|
this.config = {
|
|
6966
6974
|
rpId: config.rpId ?? VERIDEX_RP_ID,
|
|
6967
6975
|
authPortalUrl: config.authPortalUrl ?? DEFAULT_AUTH_PORTAL_URL,
|
|
6968
|
-
relayerUrl: config.relayerUrl ?? DEFAULT_RELAYER_URL,
|
|
6976
|
+
relayerUrl: normalizeRelayerOrigin(config.relayerUrl ?? DEFAULT_RELAYER_URL),
|
|
6969
6977
|
mode: config.mode ?? "popup",
|
|
6970
6978
|
popupFeatures: config.popupFeatures ?? "width=500,height=600,left=100,top=100",
|
|
6971
6979
|
timeout: config.timeout ?? 12e4,
|
|
@@ -7182,7 +7190,8 @@ var CrossOriginAuth = class {
|
|
|
7182
7190
|
return bytes;
|
|
7183
7191
|
}
|
|
7184
7192
|
async requestServerSessionChallenge(options) {
|
|
7185
|
-
const
|
|
7193
|
+
const challengeUrl = buildRelayerApiUrl(this.config.relayerUrl, "/session/challenge");
|
|
7194
|
+
const response = await fetch(challengeUrl, {
|
|
7186
7195
|
method: "POST",
|
|
7187
7196
|
headers: { "Content-Type": "application/json" },
|
|
7188
7197
|
body: JSON.stringify({
|
|
@@ -7228,7 +7237,7 @@ var CrossOriginAuth = class {
|
|
|
7228
7237
|
if (!session.serverChallengeId) {
|
|
7229
7238
|
throw new Error("Session must include a relayer-issued serverChallengeId");
|
|
7230
7239
|
}
|
|
7231
|
-
const response = await fetch(
|
|
7240
|
+
const response = await fetch(buildRelayerApiUrl(this.config.relayerUrl, "/session/create"), {
|
|
7232
7241
|
method: "POST",
|
|
7233
7242
|
headers: { "Content-Type": "application/json" },
|
|
7234
7243
|
body: JSON.stringify({
|
|
@@ -7251,7 +7260,9 @@ var CrossOriginAuth = class {
|
|
|
7251
7260
|
* Returns the session details if valid, null if expired/revoked.
|
|
7252
7261
|
*/
|
|
7253
7262
|
async validateServerSession(sessionId) {
|
|
7254
|
-
const response = await fetch(
|
|
7263
|
+
const response = await fetch(
|
|
7264
|
+
buildRelayerApiUrl(this.config.relayerUrl, `/session/${encodeURIComponent(sessionId)}`)
|
|
7265
|
+
);
|
|
7255
7266
|
if (!response.ok) {
|
|
7256
7267
|
return null;
|
|
7257
7268
|
}
|
|
@@ -7265,9 +7276,12 @@ var CrossOriginAuth = class {
|
|
|
7265
7276
|
* Revoke a server session token.
|
|
7266
7277
|
*/
|
|
7267
7278
|
async revokeServerSession(sessionId) {
|
|
7268
|
-
const response = await fetch(
|
|
7269
|
-
|
|
7270
|
-
|
|
7279
|
+
const response = await fetch(
|
|
7280
|
+
buildRelayerApiUrl(this.config.relayerUrl, `/session/${encodeURIComponent(sessionId)}`),
|
|
7281
|
+
{
|
|
7282
|
+
method: "DELETE"
|
|
7283
|
+
}
|
|
7284
|
+
);
|
|
7271
7285
|
return response.ok;
|
|
7272
7286
|
}
|
|
7273
7287
|
/**
|
|
@@ -7716,6 +7730,12 @@ function validateSessionConfig(config) {
|
|
|
7716
7730
|
"INVALID_CONFIG" /* INVALID_CONFIG */
|
|
7717
7731
|
);
|
|
7718
7732
|
}
|
|
7733
|
+
if (config.maxValue === 0n && config.allowUnboundedMaxValue !== true) {
|
|
7734
|
+
throw new SessionError(
|
|
7735
|
+
'Session maxValue=0 means "no per-tx limit" \u2014 the vault daily cap is then the only bound. This is a foot-gun: a compromised session key can drain the vault up to that cap. Pass a non-zero maxValue, or set allowUnboundedMaxValue:true if you have verified the vault daily cap and accept the residual risk.',
|
|
7736
|
+
"INVALID_CONFIG" /* INVALID_CONFIG */
|
|
7737
|
+
);
|
|
7738
|
+
}
|
|
7719
7739
|
}
|
|
7720
7740
|
|
|
7721
7741
|
// src/sessions/storage.ts
|
|
@@ -7824,39 +7844,44 @@ var IndexedDBSessionStorage = class {
|
|
|
7824
7844
|
);
|
|
7825
7845
|
}
|
|
7826
7846
|
}
|
|
7847
|
+
async decryptSession(stored) {
|
|
7848
|
+
const key = await this.getEncryptionKey();
|
|
7849
|
+
const encryptedPrivateKey = new Uint8Array(stored.encryptedPrivateKey);
|
|
7850
|
+
const privateKey = await decrypt(encryptedPrivateKey, key);
|
|
7851
|
+
return {
|
|
7852
|
+
keyHash: stored.keyHash,
|
|
7853
|
+
publicKey: new Uint8Array(stored.publicKey),
|
|
7854
|
+
privateKey,
|
|
7855
|
+
expiry: stored.expiry,
|
|
7856
|
+
maxValue: BigInt(stored.maxValue),
|
|
7857
|
+
chainScopes: stored.chainScopes ?? [],
|
|
7858
|
+
userKeyHash: stored.userKeyHash
|
|
7859
|
+
};
|
|
7860
|
+
}
|
|
7861
|
+
async pruneExpiredSessions(records) {
|
|
7862
|
+
const now = Date.now();
|
|
7863
|
+
const validRecords = records.filter((record) => record.expiry > now);
|
|
7864
|
+
const expiredRecords = records.filter((record) => record.expiry <= now);
|
|
7865
|
+
if (expiredRecords.length > 0) {
|
|
7866
|
+
await Promise.all(expiredRecords.map((record) => this.remove(record.keyHash)));
|
|
7867
|
+
}
|
|
7868
|
+
return validRecords.sort((left, right) => right.savedAt - left.savedAt);
|
|
7869
|
+
}
|
|
7827
7870
|
/**
|
|
7828
|
-
* Load
|
|
7871
|
+
* Load a session (decrypts private key)
|
|
7829
7872
|
*/
|
|
7830
|
-
async load() {
|
|
7873
|
+
async load(keyHash) {
|
|
7831
7874
|
try {
|
|
7832
7875
|
await this.initialize();
|
|
7833
7876
|
if (!this.db) {
|
|
7834
7877
|
throw new Error("Database not initialized");
|
|
7835
7878
|
}
|
|
7836
|
-
const
|
|
7837
|
-
|
|
7838
|
-
return null;
|
|
7839
|
-
}
|
|
7840
|
-
const now = Date.now();
|
|
7841
|
-
const validSessions = allSessions.filter((s) => s.expiry > now).sort((a, b) => b.savedAt - a.savedAt);
|
|
7879
|
+
const sessions = keyHash ? await this.getSessionByKeyHash(keyHash) : await this.getAllSessions();
|
|
7880
|
+
const validSessions = await this.pruneExpiredSessions(sessions);
|
|
7842
7881
|
if (validSessions.length === 0) {
|
|
7843
|
-
await this.clear();
|
|
7844
7882
|
return null;
|
|
7845
7883
|
}
|
|
7846
|
-
|
|
7847
|
-
const key = await this.getEncryptionKey();
|
|
7848
|
-
const encryptedPrivateKey = new Uint8Array(stored.encryptedPrivateKey);
|
|
7849
|
-
const privateKey = await decrypt(encryptedPrivateKey, key);
|
|
7850
|
-
const session = {
|
|
7851
|
-
keyHash: stored.keyHash,
|
|
7852
|
-
publicKey: new Uint8Array(stored.publicKey),
|
|
7853
|
-
privateKey,
|
|
7854
|
-
expiry: stored.expiry,
|
|
7855
|
-
maxValue: BigInt(stored.maxValue),
|
|
7856
|
-
chainScopes: stored.chainScopes,
|
|
7857
|
-
userKeyHash: stored.userKeyHash
|
|
7858
|
-
};
|
|
7859
|
-
return session;
|
|
7884
|
+
return this.decryptSession(validSessions[0]);
|
|
7860
7885
|
} catch (error) {
|
|
7861
7886
|
if (error instanceof SessionError) {
|
|
7862
7887
|
throw error;
|
|
@@ -7889,6 +7914,75 @@ var IndexedDBSessionStorage = class {
|
|
|
7889
7914
|
};
|
|
7890
7915
|
});
|
|
7891
7916
|
}
|
|
7917
|
+
async getSessionByKeyHash(keyHash) {
|
|
7918
|
+
if (!this.db) {
|
|
7919
|
+
return [];
|
|
7920
|
+
}
|
|
7921
|
+
return new Promise((resolve, reject) => {
|
|
7922
|
+
const transaction = this.db.transaction([STORE_NAME], "readonly");
|
|
7923
|
+
const store = transaction.objectStore(STORE_NAME);
|
|
7924
|
+
const request = store.get(keyHash);
|
|
7925
|
+
request.onsuccess = () => {
|
|
7926
|
+
resolve(request.result ? [request.result] : []);
|
|
7927
|
+
};
|
|
7928
|
+
request.onerror = () => {
|
|
7929
|
+
reject(new SessionError(
|
|
7930
|
+
"Failed to get session",
|
|
7931
|
+
"STORAGE_ERROR" /* STORAGE_ERROR */,
|
|
7932
|
+
request.error
|
|
7933
|
+
));
|
|
7934
|
+
};
|
|
7935
|
+
});
|
|
7936
|
+
}
|
|
7937
|
+
async loadAll() {
|
|
7938
|
+
try {
|
|
7939
|
+
await this.initialize();
|
|
7940
|
+
if (!this.db) {
|
|
7941
|
+
return [];
|
|
7942
|
+
}
|
|
7943
|
+
const records = await this.pruneExpiredSessions(await this.getAllSessions());
|
|
7944
|
+
return Promise.all(records.map((record) => this.decryptSession(record)));
|
|
7945
|
+
} catch (error) {
|
|
7946
|
+
if (error instanceof SessionError) {
|
|
7947
|
+
throw error;
|
|
7948
|
+
}
|
|
7949
|
+
throw new SessionError(
|
|
7950
|
+
"Failed to load sessions",
|
|
7951
|
+
"STORAGE_ERROR" /* STORAGE_ERROR */,
|
|
7952
|
+
error
|
|
7953
|
+
);
|
|
7954
|
+
}
|
|
7955
|
+
}
|
|
7956
|
+
async remove(keyHash) {
|
|
7957
|
+
try {
|
|
7958
|
+
await this.initialize();
|
|
7959
|
+
if (!this.db) {
|
|
7960
|
+
return;
|
|
7961
|
+
}
|
|
7962
|
+
return new Promise((resolve, reject) => {
|
|
7963
|
+
const transaction = this.db.transaction([STORE_NAME], "readwrite");
|
|
7964
|
+
const store = transaction.objectStore(STORE_NAME);
|
|
7965
|
+
const request = store.delete(keyHash);
|
|
7966
|
+
request.onsuccess = () => resolve();
|
|
7967
|
+
request.onerror = () => {
|
|
7968
|
+
reject(new SessionError(
|
|
7969
|
+
"Failed to remove session",
|
|
7970
|
+
"STORAGE_ERROR" /* STORAGE_ERROR */,
|
|
7971
|
+
request.error
|
|
7972
|
+
));
|
|
7973
|
+
};
|
|
7974
|
+
});
|
|
7975
|
+
} catch (error) {
|
|
7976
|
+
if (error instanceof SessionError) {
|
|
7977
|
+
throw error;
|
|
7978
|
+
}
|
|
7979
|
+
throw new SessionError(
|
|
7980
|
+
"Failed to remove session",
|
|
7981
|
+
"STORAGE_ERROR" /* STORAGE_ERROR */,
|
|
7982
|
+
error
|
|
7983
|
+
);
|
|
7984
|
+
}
|
|
7985
|
+
}
|
|
7892
7986
|
/**
|
|
7893
7987
|
* Clear all sessions
|
|
7894
7988
|
*/
|
|
@@ -7925,14 +8019,9 @@ var IndexedDBSessionStorage = class {
|
|
|
7925
8019
|
/**
|
|
7926
8020
|
* Check if any session exists
|
|
7927
8021
|
*/
|
|
7928
|
-
async exists() {
|
|
8022
|
+
async exists(keyHash) {
|
|
7929
8023
|
try {
|
|
7930
|
-
await this.
|
|
7931
|
-
if (!this.db) {
|
|
7932
|
-
return false;
|
|
7933
|
-
}
|
|
7934
|
-
const sessions = await this.getAllSessions();
|
|
7935
|
-
return sessions.length > 0;
|
|
8024
|
+
return await this.load(keyHash) !== null;
|
|
7936
8025
|
} catch {
|
|
7937
8026
|
return false;
|
|
7938
8027
|
}
|
|
@@ -7951,7 +8040,8 @@ var STORAGE_KEY_PREFIX = "veridex-session-";
|
|
|
7951
8040
|
var LocalStorageSessionStorage = class {
|
|
7952
8041
|
encryptionKey = null;
|
|
7953
8042
|
credentialId;
|
|
7954
|
-
|
|
8043
|
+
credentialHash;
|
|
8044
|
+
legacyStorageKey;
|
|
7955
8045
|
/**
|
|
7956
8046
|
* @param credentialId User's Passkey credential ID (for key derivation)
|
|
7957
8047
|
*/
|
|
@@ -7963,7 +8053,60 @@ var LocalStorageSessionStorage = class {
|
|
|
7963
8053
|
);
|
|
7964
8054
|
}
|
|
7965
8055
|
this.credentialId = credentialId;
|
|
7966
|
-
this.
|
|
8056
|
+
this.credentialHash = ethers10.keccak256(ethers10.toUtf8Bytes(credentialId));
|
|
8057
|
+
this.legacyStorageKey = STORAGE_KEY_PREFIX + this.credentialHash;
|
|
8058
|
+
}
|
|
8059
|
+
getSessionStorageKey(keyHash) {
|
|
8060
|
+
return `${STORAGE_KEY_PREFIX}${this.credentialHash}:${keyHash}`;
|
|
8061
|
+
}
|
|
8062
|
+
getSessionStoragePrefix() {
|
|
8063
|
+
return `${STORAGE_KEY_PREFIX}${this.credentialHash}:`;
|
|
8064
|
+
}
|
|
8065
|
+
async deserializeSession(stored) {
|
|
8066
|
+
const key = await this.getEncryptionKey();
|
|
8067
|
+
const encryptedPrivateKey = typeof stored.encryptedPrivateKey === "string" ? ethers10.getBytes(stored.encryptedPrivateKey) : new Uint8Array(stored.encryptedPrivateKey);
|
|
8068
|
+
const privateKey = await decrypt(encryptedPrivateKey, key);
|
|
8069
|
+
return {
|
|
8070
|
+
keyHash: stored.keyHash,
|
|
8071
|
+
publicKey: typeof stored.publicKey === "string" ? ethers10.getBytes(stored.publicKey) : new Uint8Array(stored.publicKey),
|
|
8072
|
+
privateKey,
|
|
8073
|
+
expiry: stored.expiry,
|
|
8074
|
+
maxValue: BigInt(stored.maxValue),
|
|
8075
|
+
chainScopes: stored.chainScopes ?? [],
|
|
8076
|
+
userKeyHash: stored.userKeyHash
|
|
8077
|
+
};
|
|
8078
|
+
}
|
|
8079
|
+
getRawRecords() {
|
|
8080
|
+
const records = [];
|
|
8081
|
+
const prefix = this.getSessionStoragePrefix();
|
|
8082
|
+
for (let index = 0; index < localStorage.length; index++) {
|
|
8083
|
+
const key = localStorage.key(index);
|
|
8084
|
+
if (!key || !key.startsWith(prefix)) {
|
|
8085
|
+
continue;
|
|
8086
|
+
}
|
|
8087
|
+
const value = localStorage.getItem(key);
|
|
8088
|
+
if (!value) {
|
|
8089
|
+
continue;
|
|
8090
|
+
}
|
|
8091
|
+
records.push(JSON.parse(value));
|
|
8092
|
+
}
|
|
8093
|
+
const legacyValue = localStorage.getItem(this.legacyStorageKey);
|
|
8094
|
+
if (legacyValue) {
|
|
8095
|
+
records.push(JSON.parse(legacyValue));
|
|
8096
|
+
}
|
|
8097
|
+
return records;
|
|
8098
|
+
}
|
|
8099
|
+
async getValidRecords() {
|
|
8100
|
+
const now = Date.now();
|
|
8101
|
+
const validRecords = [];
|
|
8102
|
+
for (const record of this.getRawRecords()) {
|
|
8103
|
+
if (record.expiry <= now) {
|
|
8104
|
+
await this.remove(record.keyHash);
|
|
8105
|
+
continue;
|
|
8106
|
+
}
|
|
8107
|
+
validRecords.push(record);
|
|
8108
|
+
}
|
|
8109
|
+
return validRecords.sort((left, right) => right.savedAt - left.savedAt);
|
|
7967
8110
|
}
|
|
7968
8111
|
/**
|
|
7969
8112
|
* Get or derive encryption key
|
|
@@ -7992,7 +8135,7 @@ var LocalStorageSessionStorage = class {
|
|
|
7992
8135
|
userKeyHash: session.userKeyHash,
|
|
7993
8136
|
savedAt: Date.now()
|
|
7994
8137
|
};
|
|
7995
|
-
localStorage.setItem(this.
|
|
8138
|
+
localStorage.setItem(this.getSessionStorageKey(session.keyHash), JSON.stringify(storageObject));
|
|
7996
8139
|
} catch (error) {
|
|
7997
8140
|
if (error instanceof SessionError) {
|
|
7998
8141
|
throw error;
|
|
@@ -8005,32 +8148,15 @@ var LocalStorageSessionStorage = class {
|
|
|
8005
8148
|
}
|
|
8006
8149
|
}
|
|
8007
8150
|
/**
|
|
8008
|
-
* Load
|
|
8151
|
+
* Load a session (decrypts private key)
|
|
8009
8152
|
*/
|
|
8010
|
-
async load() {
|
|
8153
|
+
async load(keyHash) {
|
|
8011
8154
|
try {
|
|
8012
|
-
const
|
|
8013
|
-
if (
|
|
8014
|
-
return null;
|
|
8015
|
-
}
|
|
8016
|
-
const stored = JSON.parse(data);
|
|
8017
|
-
if (stored.expiry <= Date.now()) {
|
|
8018
|
-
await this.clear();
|
|
8155
|
+
const records = keyHash ? (await this.getValidRecords()).filter((record) => record.keyHash === keyHash) : await this.getValidRecords();
|
|
8156
|
+
if (records.length === 0) {
|
|
8019
8157
|
return null;
|
|
8020
8158
|
}
|
|
8021
|
-
|
|
8022
|
-
const encryptedPrivateKey = ethers10.getBytes(stored.encryptedPrivateKey);
|
|
8023
|
-
const privateKey = await decrypt(encryptedPrivateKey, key);
|
|
8024
|
-
const session = {
|
|
8025
|
-
keyHash: stored.keyHash,
|
|
8026
|
-
publicKey: ethers10.getBytes(stored.publicKey),
|
|
8027
|
-
privateKey,
|
|
8028
|
-
expiry: stored.expiry,
|
|
8029
|
-
maxValue: BigInt(stored.maxValue),
|
|
8030
|
-
chainScopes: stored.chainScopes,
|
|
8031
|
-
userKeyHash: stored.userKeyHash
|
|
8032
|
-
};
|
|
8033
|
-
return session;
|
|
8159
|
+
return this.deserializeSession(records[0]);
|
|
8034
8160
|
} catch (error) {
|
|
8035
8161
|
await this.clear();
|
|
8036
8162
|
if (error instanceof SessionError) {
|
|
@@ -8043,12 +8169,55 @@ var LocalStorageSessionStorage = class {
|
|
|
8043
8169
|
);
|
|
8044
8170
|
}
|
|
8045
8171
|
}
|
|
8172
|
+
async loadAll() {
|
|
8173
|
+
try {
|
|
8174
|
+
const records = await this.getValidRecords();
|
|
8175
|
+
return Promise.all(records.map((record) => this.deserializeSession(record)));
|
|
8176
|
+
} catch (error) {
|
|
8177
|
+
await this.clear();
|
|
8178
|
+
if (error instanceof SessionError) {
|
|
8179
|
+
throw error;
|
|
8180
|
+
}
|
|
8181
|
+
throw new SessionError(
|
|
8182
|
+
"Failed to load sessions",
|
|
8183
|
+
"STORAGE_ERROR" /* STORAGE_ERROR */,
|
|
8184
|
+
error
|
|
8185
|
+
);
|
|
8186
|
+
}
|
|
8187
|
+
}
|
|
8188
|
+
async remove(keyHash) {
|
|
8189
|
+
try {
|
|
8190
|
+
localStorage.removeItem(this.getSessionStorageKey(keyHash));
|
|
8191
|
+
const legacyValue = localStorage.getItem(this.legacyStorageKey);
|
|
8192
|
+
if (legacyValue) {
|
|
8193
|
+
const legacyRecord = JSON.parse(legacyValue);
|
|
8194
|
+
if (legacyRecord.keyHash === keyHash) {
|
|
8195
|
+
localStorage.removeItem(this.legacyStorageKey);
|
|
8196
|
+
}
|
|
8197
|
+
}
|
|
8198
|
+
} catch (error) {
|
|
8199
|
+
throw new SessionError(
|
|
8200
|
+
"Failed to remove session",
|
|
8201
|
+
"STORAGE_ERROR" /* STORAGE_ERROR */,
|
|
8202
|
+
error
|
|
8203
|
+
);
|
|
8204
|
+
}
|
|
8205
|
+
}
|
|
8046
8206
|
/**
|
|
8047
8207
|
* Clear all sessions
|
|
8048
8208
|
*/
|
|
8049
8209
|
async clear() {
|
|
8050
8210
|
try {
|
|
8051
|
-
|
|
8211
|
+
const keysToRemove = [];
|
|
8212
|
+
const prefix = this.getSessionStoragePrefix();
|
|
8213
|
+
for (let index = 0; index < localStorage.length; index++) {
|
|
8214
|
+
const key = localStorage.key(index);
|
|
8215
|
+
if (key && key.startsWith(prefix)) {
|
|
8216
|
+
keysToRemove.push(key);
|
|
8217
|
+
}
|
|
8218
|
+
}
|
|
8219
|
+
keysToRemove.forEach((key) => localStorage.removeItem(key));
|
|
8220
|
+
localStorage.removeItem(this.legacyStorageKey);
|
|
8052
8221
|
} catch (error) {
|
|
8053
8222
|
throw new SessionError(
|
|
8054
8223
|
"Failed to clear sessions",
|
|
@@ -8060,9 +8229,9 @@ var LocalStorageSessionStorage = class {
|
|
|
8060
8229
|
/**
|
|
8061
8230
|
* Check if any session exists
|
|
8062
8231
|
*/
|
|
8063
|
-
async exists() {
|
|
8232
|
+
async exists(keyHash) {
|
|
8064
8233
|
try {
|
|
8065
|
-
return
|
|
8234
|
+
return await this.load(keyHash) !== null;
|
|
8066
8235
|
} catch {
|
|
8067
8236
|
return false;
|
|
8068
8237
|
}
|
|
@@ -8112,7 +8281,8 @@ var SessionManager = class {
|
|
|
8112
8281
|
maxValue: config.maxValue ?? 0n,
|
|
8113
8282
|
autoRefresh: config.autoRefresh ?? true,
|
|
8114
8283
|
refreshBuffer: config.refreshBuffer ?? DEFAULT_REFRESH_BUFFER,
|
|
8115
|
-
chainScopes: config.chainScopes ?? []
|
|
8284
|
+
chainScopes: config.chainScopes ?? [],
|
|
8285
|
+
allowUnboundedMaxValue: config.allowUnboundedMaxValue ?? false
|
|
8116
8286
|
};
|
|
8117
8287
|
validateSessionConfig(this.config);
|
|
8118
8288
|
this.debug = managerConfig?.debug ?? false;
|
|
@@ -8127,6 +8297,14 @@ var SessionManager = class {
|
|
|
8127
8297
|
refreshTimer = null;
|
|
8128
8298
|
eventCallbacks = [];
|
|
8129
8299
|
debug;
|
|
8300
|
+
resolveConfig(configOverride) {
|
|
8301
|
+
const resolvedConfig = {
|
|
8302
|
+
...this.config,
|
|
8303
|
+
...configOverride
|
|
8304
|
+
};
|
|
8305
|
+
validateSessionConfig(resolvedConfig);
|
|
8306
|
+
return resolvedConfig;
|
|
8307
|
+
}
|
|
8130
8308
|
// ========================================================================
|
|
8131
8309
|
// Session Lifecycle
|
|
8132
8310
|
// ========================================================================
|
|
@@ -8143,15 +8321,16 @@ var SessionManager = class {
|
|
|
8143
8321
|
* @returns Created session key
|
|
8144
8322
|
* @throws SessionError if registration fails
|
|
8145
8323
|
*/
|
|
8146
|
-
async createSession() {
|
|
8324
|
+
async createSession(configOverride) {
|
|
8147
8325
|
try {
|
|
8148
8326
|
this.log("Creating new session...");
|
|
8327
|
+
const sessionConfig = this.resolveConfig(configOverride);
|
|
8149
8328
|
const keyPair = generateSecp256k1KeyPair();
|
|
8150
8329
|
const keyHash = computeSessionKeyHash(keyPair.publicKey);
|
|
8151
8330
|
this.log("Generated session key:", keyHash);
|
|
8152
8331
|
const challenge = ethers11.solidityPacked(
|
|
8153
8332
|
["string", "bytes32", "uint256", "uint256"],
|
|
8154
|
-
["registerSession", keyHash,
|
|
8333
|
+
["registerSession", keyHash, sessionConfig.duration, sessionConfig.maxValue]
|
|
8155
8334
|
);
|
|
8156
8335
|
this.log("Challenge prepared, requesting Passkey signature...");
|
|
8157
8336
|
const signature = await this.passkeySign(ethers11.getBytes(challenge));
|
|
@@ -8161,20 +8340,20 @@ var SessionManager = class {
|
|
|
8161
8340
|
publicKeyX: this.credential.publicKeyX,
|
|
8162
8341
|
publicKeyY: this.credential.publicKeyY,
|
|
8163
8342
|
sessionKeyHash: keyHash,
|
|
8164
|
-
duration:
|
|
8165
|
-
maxValue:
|
|
8343
|
+
duration: sessionConfig.duration,
|
|
8344
|
+
maxValue: sessionConfig.maxValue,
|
|
8166
8345
|
requireUV: true
|
|
8167
8346
|
};
|
|
8168
8347
|
await this.hubClient.registerSession(registerParams);
|
|
8169
8348
|
this.log("Session registered on Hub");
|
|
8170
|
-
const expiry = Date.now() +
|
|
8349
|
+
const expiry = Date.now() + sessionConfig.duration * 1e3;
|
|
8171
8350
|
this.currentSession = {
|
|
8172
8351
|
publicKey: keyPair.publicKey,
|
|
8173
8352
|
privateKey: keyPair.privateKey,
|
|
8174
8353
|
keyHash,
|
|
8175
8354
|
expiry,
|
|
8176
|
-
maxValue:
|
|
8177
|
-
chainScopes:
|
|
8355
|
+
maxValue: sessionConfig.maxValue,
|
|
8356
|
+
chainScopes: sessionConfig.chainScopes,
|
|
8178
8357
|
userKeyHash: this.credential.keyHash
|
|
8179
8358
|
};
|
|
8180
8359
|
await this.storage.save(this.currentSession);
|
|
@@ -8199,12 +8378,15 @@ var SessionManager = class {
|
|
|
8199
8378
|
*
|
|
8200
8379
|
* @returns Loaded session or null if no valid session exists
|
|
8201
8380
|
*/
|
|
8202
|
-
async loadSession() {
|
|
8381
|
+
async loadSession(keyHash) {
|
|
8203
8382
|
try {
|
|
8204
|
-
this.log("Loading session from storage...");
|
|
8205
|
-
const session = await this.storage.load();
|
|
8383
|
+
this.log("Loading session from storage...", keyHash ?? "latest");
|
|
8384
|
+
const session = await this.storage.load(keyHash);
|
|
8206
8385
|
if (!session) {
|
|
8207
8386
|
this.log("No session found in storage");
|
|
8387
|
+
if (!keyHash) {
|
|
8388
|
+
this.currentSession = null;
|
|
8389
|
+
}
|
|
8208
8390
|
return null;
|
|
8209
8391
|
}
|
|
8210
8392
|
if (session.expiry <= Date.now()) {
|
|
@@ -8221,27 +8403,43 @@ var SessionManager = class {
|
|
|
8221
8403
|
return session;
|
|
8222
8404
|
} catch (error) {
|
|
8223
8405
|
this.log("Failed to load session:", error);
|
|
8224
|
-
|
|
8406
|
+
if (!keyHash) {
|
|
8407
|
+
await this.storage.clear();
|
|
8408
|
+
}
|
|
8225
8409
|
return null;
|
|
8226
8410
|
}
|
|
8227
8411
|
}
|
|
8412
|
+
async listSessions() {
|
|
8413
|
+
return this.storage.loadAll();
|
|
8414
|
+
}
|
|
8415
|
+
async selectSession(keyHash) {
|
|
8416
|
+
const session = await this.loadSession(keyHash);
|
|
8417
|
+
if (!session) {
|
|
8418
|
+
throw new SessionError(
|
|
8419
|
+
`Session ${keyHash} not found`,
|
|
8420
|
+
"SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */
|
|
8421
|
+
);
|
|
8422
|
+
}
|
|
8423
|
+
return session;
|
|
8424
|
+
}
|
|
8228
8425
|
/**
|
|
8229
8426
|
* Revoke the current session (requires biometric authentication)
|
|
8230
8427
|
*
|
|
8231
8428
|
* @throws SessionError if no active session or revocation fails
|
|
8232
8429
|
*/
|
|
8233
|
-
async revokeSession() {
|
|
8234
|
-
|
|
8430
|
+
async revokeSession(keyHash) {
|
|
8431
|
+
const targetSession = keyHash ? await this.storage.load(keyHash) : this.currentSession;
|
|
8432
|
+
if (!targetSession) {
|
|
8235
8433
|
throw new SessionError(
|
|
8236
|
-
"No active session to revoke",
|
|
8237
|
-
"NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
|
|
8434
|
+
keyHash ? `Session ${keyHash} not found` : "No active session to revoke",
|
|
8435
|
+
keyHash ? "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ : "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
|
|
8238
8436
|
);
|
|
8239
8437
|
}
|
|
8240
8438
|
try {
|
|
8241
|
-
this.log("Revoking session:",
|
|
8439
|
+
this.log("Revoking session:", targetSession.keyHash);
|
|
8242
8440
|
const challenge = ethers11.solidityPacked(
|
|
8243
8441
|
["string", "bytes32"],
|
|
8244
|
-
["revokeSession",
|
|
8442
|
+
["revokeSession", targetSession.keyHash]
|
|
8245
8443
|
);
|
|
8246
8444
|
const signature = await this.passkeySign(ethers11.getBytes(challenge));
|
|
8247
8445
|
this.log("Passkey signature obtained, revoking on Hub...");
|
|
@@ -8249,18 +8447,24 @@ var SessionManager = class {
|
|
|
8249
8447
|
signature,
|
|
8250
8448
|
publicKeyX: this.credential.publicKeyX,
|
|
8251
8449
|
publicKeyY: this.credential.publicKeyY,
|
|
8252
|
-
sessionKeyHash:
|
|
8450
|
+
sessionKeyHash: targetSession.keyHash,
|
|
8253
8451
|
requireUV: true
|
|
8254
8452
|
};
|
|
8255
8453
|
await this.hubClient.revokeSession(revokeParams);
|
|
8256
8454
|
this.log("Session revoked on Hub");
|
|
8257
|
-
await this.storage.
|
|
8258
|
-
|
|
8259
|
-
|
|
8260
|
-
|
|
8455
|
+
await this.storage.remove(targetSession.keyHash);
|
|
8456
|
+
const revokedKeyHash = targetSession.keyHash;
|
|
8457
|
+
const revokedCurrentSession = this.currentSession?.keyHash === revokedKeyHash;
|
|
8458
|
+
if (revokedCurrentSession) {
|
|
8459
|
+
if (this.refreshTimer) {
|
|
8460
|
+
clearTimeout(this.refreshTimer);
|
|
8461
|
+
this.refreshTimer = null;
|
|
8462
|
+
}
|
|
8463
|
+
this.currentSession = await this.storage.load();
|
|
8464
|
+
if (this.currentSession && this.config.autoRefresh) {
|
|
8465
|
+
this.scheduleRefresh();
|
|
8466
|
+
}
|
|
8261
8467
|
}
|
|
8262
|
-
const revokedKeyHash = this.currentSession.keyHash;
|
|
8263
|
-
this.currentSession = null;
|
|
8264
8468
|
this.emit({ type: "session-revoked", keyHash: revokedKeyHash });
|
|
8265
8469
|
this.log("Session revoked successfully");
|
|
8266
8470
|
} catch (error) {
|
|
@@ -8338,45 +8542,46 @@ var SessionManager = class {
|
|
|
8338
8542
|
* @returns Session signature
|
|
8339
8543
|
* @throws SessionError if no active session, expired, or value exceeds limit
|
|
8340
8544
|
*/
|
|
8341
|
-
async signWithSession(action) {
|
|
8342
|
-
|
|
8545
|
+
async signWithSession(action, keyHash) {
|
|
8546
|
+
const session = keyHash ? await this.storage.load(keyHash) : this.currentSession;
|
|
8547
|
+
if (!session) {
|
|
8343
8548
|
throw new SessionError(
|
|
8344
|
-
"No active session available",
|
|
8345
|
-
"NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
|
|
8549
|
+
keyHash ? `Session ${keyHash} not found` : "No active session available",
|
|
8550
|
+
keyHash ? "SESSION_NOT_FOUND" /* SESSION_NOT_FOUND */ : "NO_ACTIVE_SESSION" /* NO_ACTIVE_SESSION */
|
|
8346
8551
|
);
|
|
8347
8552
|
}
|
|
8348
8553
|
const now = Date.now();
|
|
8349
|
-
if (now >=
|
|
8350
|
-
this.emit({ type: "session-expired", keyHash:
|
|
8554
|
+
if (now >= session.expiry) {
|
|
8555
|
+
this.emit({ type: "session-expired", keyHash: session.keyHash });
|
|
8351
8556
|
throw new SessionError(
|
|
8352
8557
|
"Session has expired",
|
|
8353
8558
|
"SESSION_EXPIRED" /* SESSION_EXPIRED */
|
|
8354
8559
|
);
|
|
8355
8560
|
}
|
|
8356
|
-
if (
|
|
8561
|
+
if (session.maxValue > 0n && action.value > session.maxValue) {
|
|
8357
8562
|
throw new SessionError(
|
|
8358
|
-
`Transaction value (${action.value}) exceeds session limit (${
|
|
8563
|
+
`Transaction value (${action.value}) exceeds session limit (${session.maxValue})`,
|
|
8359
8564
|
"VALUE_EXCEEDS_LIMIT" /* VALUE_EXCEEDS_LIMIT */,
|
|
8360
|
-
{ value: action.value, limit:
|
|
8565
|
+
{ value: action.value, limit: session.maxValue }
|
|
8361
8566
|
);
|
|
8362
8567
|
}
|
|
8363
|
-
if (
|
|
8568
|
+
if (session.chainScopes.length > 0 && !session.chainScopes.includes(action.targetChain)) {
|
|
8364
8569
|
throw new SessionError(
|
|
8365
8570
|
`Chain ${action.targetChain} not in session scope`,
|
|
8366
8571
|
"CHAIN_NOT_ALLOWED" /* CHAIN_NOT_ALLOWED */,
|
|
8367
|
-
{ chain: action.targetChain, allowedChains:
|
|
8572
|
+
{ chain: action.targetChain, allowedChains: session.chainScopes }
|
|
8368
8573
|
);
|
|
8369
8574
|
}
|
|
8370
8575
|
this.log("Signing action with session key...");
|
|
8371
8576
|
const messageHash = hashAction(action);
|
|
8372
8577
|
const { signature } = signWithSessionKey(
|
|
8373
|
-
|
|
8578
|
+
session.privateKey,
|
|
8374
8579
|
messageHash
|
|
8375
8580
|
);
|
|
8376
8581
|
const sessionSignature = {
|
|
8377
8582
|
signature,
|
|
8378
|
-
sessionKeyHash:
|
|
8379
|
-
userKeyHash:
|
|
8583
|
+
sessionKeyHash: session.keyHash,
|
|
8584
|
+
userKeyHash: session.userKeyHash,
|
|
8380
8585
|
timestamp: now,
|
|
8381
8586
|
nonce: action.nonce
|
|
8382
8587
|
};
|
|
@@ -8389,8 +8594,8 @@ var SessionManager = class {
|
|
|
8389
8594
|
* @param action Action parameters
|
|
8390
8595
|
* @returns Session-signed action ready for submission
|
|
8391
8596
|
*/
|
|
8392
|
-
async signAction(action) {
|
|
8393
|
-
const signature = await this.signWithSession(action);
|
|
8597
|
+
async signAction(action, keyHash) {
|
|
8598
|
+
const signature = await this.signWithSession(action, keyHash);
|
|
8394
8599
|
return {
|
|
8395
8600
|
action,
|
|
8396
8601
|
signature,
|
|
@@ -9253,6 +9458,7 @@ export {
|
|
|
9253
9458
|
calculatePercentage,
|
|
9254
9459
|
computeKeyHash,
|
|
9255
9460
|
computeSessionKeyHash,
|
|
9461
|
+
configureDefaultRpcUrls,
|
|
9256
9462
|
createAuditEntry,
|
|
9257
9463
|
createChainClient,
|
|
9258
9464
|
createChainDetector,
|
|
@@ -9323,6 +9529,7 @@ export {
|
|
|
9323
9529
|
getExplorerUrl,
|
|
9324
9530
|
getFeatureFlags,
|
|
9325
9531
|
getHubChains,
|
|
9532
|
+
getRpcUrlOverride,
|
|
9326
9533
|
getSequenceFromTxReceipt,
|
|
9327
9534
|
getContractPrincipal as getStacksContractPrincipal,
|
|
9328
9535
|
getStacksExplorerAddressUrl,
|