@phantom/embedded-provider-core 0.1.7 → 0.1.9
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/index.d.mts +25 -1
- package/dist/index.d.ts +25 -1
- package/dist/index.js +164 -22
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +162 -22
- package/dist/index.mjs.map +1 -1
- package/package.json +3 -3
package/dist/index.d.mts
CHANGED
|
@@ -10,6 +10,8 @@ interface Keypair {
|
|
|
10
10
|
interface StamperInfo {
|
|
11
11
|
keyId: string;
|
|
12
12
|
publicKey: string;
|
|
13
|
+
createdAt?: number;
|
|
14
|
+
authenticatorId?: string;
|
|
13
15
|
}
|
|
14
16
|
interface Session {
|
|
15
17
|
sessionId: string;
|
|
@@ -22,6 +24,10 @@ interface Session {
|
|
|
22
24
|
status: "pending" | "completed" | "failed";
|
|
23
25
|
createdAt: number;
|
|
24
26
|
lastUsed: number;
|
|
27
|
+
authenticatorCreatedAt: number;
|
|
28
|
+
authenticatorExpiresAt: number;
|
|
29
|
+
lastRenewalAttempt?: number;
|
|
30
|
+
username: string;
|
|
25
31
|
}
|
|
26
32
|
interface EmbeddedStorage {
|
|
27
33
|
getSession(): Promise<Session | null>;
|
|
@@ -168,6 +174,8 @@ declare class EmbeddedProvider {
|
|
|
168
174
|
private handleJWTAuth;
|
|
169
175
|
private handleRedirectAuth;
|
|
170
176
|
private completeAuthConnection;
|
|
177
|
+
private ensureValidAuthenticator;
|
|
178
|
+
private renewAuthenticator;
|
|
171
179
|
private initializeClientFromSession;
|
|
172
180
|
}
|
|
173
181
|
|
|
@@ -179,4 +187,20 @@ declare function generateSessionId(): string;
|
|
|
179
187
|
|
|
180
188
|
declare function retryWithBackoff<T>(operation: () => Promise<T>, operationName: string, logger: DebugLogger, maxRetries?: number, baseDelay?: number): Promise<T>;
|
|
181
189
|
|
|
182
|
-
|
|
190
|
+
/**
|
|
191
|
+
* Constants for authenticator lifecycle management
|
|
192
|
+
*/
|
|
193
|
+
/**
|
|
194
|
+
* How long an authenticator is valid before it expires (in milliseconds)
|
|
195
|
+
* Default: 7 days
|
|
196
|
+
* For testing: Use smaller values like 5 * 60 * 1000 (5 minutes)
|
|
197
|
+
*/
|
|
198
|
+
declare const AUTHENTICATOR_EXPIRATION_TIME_MS: number;
|
|
199
|
+
/**
|
|
200
|
+
* How long before expiration should we attempt to renew the authenticator (in milliseconds)
|
|
201
|
+
* Default: 2 days before expiration
|
|
202
|
+
* For testing: Use smaller values like 2 * 60 * 1000 (2 minutes)
|
|
203
|
+
*/
|
|
204
|
+
declare const AUTHENTICATOR_RENEWAL_WINDOW_MS: number;
|
|
205
|
+
|
|
206
|
+
export { AUTHENTICATOR_EXPIRATION_TIME_MS, AUTHENTICATOR_RENEWAL_WINDOW_MS, AuthOptions, AuthProvider, AuthResult, ConnectResult, DebugLogger, EmbeddedProvider, EmbeddedProviderConfig, EmbeddedProviderEvent, EmbeddedStorage, EventCallback, JWTAuth, JWTAuthOptions, Keypair, PhantomConnectOptions, PlatformAdapter, Session, SignAndSendTransactionParams, SignMessageParams, SignMessageResult, SignedTransaction, StamperInfo, URLParamsAccessor, WalletAddress, generateSessionId, retryWithBackoff };
|
package/dist/index.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ interface Keypair {
|
|
|
10
10
|
interface StamperInfo {
|
|
11
11
|
keyId: string;
|
|
12
12
|
publicKey: string;
|
|
13
|
+
createdAt?: number;
|
|
14
|
+
authenticatorId?: string;
|
|
13
15
|
}
|
|
14
16
|
interface Session {
|
|
15
17
|
sessionId: string;
|
|
@@ -22,6 +24,10 @@ interface Session {
|
|
|
22
24
|
status: "pending" | "completed" | "failed";
|
|
23
25
|
createdAt: number;
|
|
24
26
|
lastUsed: number;
|
|
27
|
+
authenticatorCreatedAt: number;
|
|
28
|
+
authenticatorExpiresAt: number;
|
|
29
|
+
lastRenewalAttempt?: number;
|
|
30
|
+
username: string;
|
|
25
31
|
}
|
|
26
32
|
interface EmbeddedStorage {
|
|
27
33
|
getSession(): Promise<Session | null>;
|
|
@@ -168,6 +174,8 @@ declare class EmbeddedProvider {
|
|
|
168
174
|
private handleJWTAuth;
|
|
169
175
|
private handleRedirectAuth;
|
|
170
176
|
private completeAuthConnection;
|
|
177
|
+
private ensureValidAuthenticator;
|
|
178
|
+
private renewAuthenticator;
|
|
171
179
|
private initializeClientFromSession;
|
|
172
180
|
}
|
|
173
181
|
|
|
@@ -179,4 +187,20 @@ declare function generateSessionId(): string;
|
|
|
179
187
|
|
|
180
188
|
declare function retryWithBackoff<T>(operation: () => Promise<T>, operationName: string, logger: DebugLogger, maxRetries?: number, baseDelay?: number): Promise<T>;
|
|
181
189
|
|
|
182
|
-
|
|
190
|
+
/**
|
|
191
|
+
* Constants for authenticator lifecycle management
|
|
192
|
+
*/
|
|
193
|
+
/**
|
|
194
|
+
* How long an authenticator is valid before it expires (in milliseconds)
|
|
195
|
+
* Default: 7 days
|
|
196
|
+
* For testing: Use smaller values like 5 * 60 * 1000 (5 minutes)
|
|
197
|
+
*/
|
|
198
|
+
declare const AUTHENTICATOR_EXPIRATION_TIME_MS: number;
|
|
199
|
+
/**
|
|
200
|
+
* How long before expiration should we attempt to renew the authenticator (in milliseconds)
|
|
201
|
+
* Default: 2 days before expiration
|
|
202
|
+
* For testing: Use smaller values like 2 * 60 * 1000 (2 minutes)
|
|
203
|
+
*/
|
|
204
|
+
declare const AUTHENTICATOR_RENEWAL_WINDOW_MS: number;
|
|
205
|
+
|
|
206
|
+
export { AUTHENTICATOR_EXPIRATION_TIME_MS, AUTHENTICATOR_RENEWAL_WINDOW_MS, AuthOptions, AuthProvider, AuthResult, ConnectResult, DebugLogger, EmbeddedProvider, EmbeddedProviderConfig, EmbeddedProviderEvent, EmbeddedStorage, EventCallback, JWTAuth, JWTAuthOptions, Keypair, PhantomConnectOptions, PlatformAdapter, Session, SignAndSendTransactionParams, SignMessageParams, SignMessageResult, SignedTransaction, StamperInfo, URLParamsAccessor, WalletAddress, generateSessionId, retryWithBackoff };
|
package/dist/index.js
CHANGED
|
@@ -30,6 +30,8 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var src_exports = {};
|
|
32
32
|
__export(src_exports, {
|
|
33
|
+
AUTHENTICATOR_EXPIRATION_TIME_MS: () => AUTHENTICATOR_EXPIRATION_TIME_MS,
|
|
34
|
+
AUTHENTICATOR_RENEWAL_WINDOW_MS: () => AUTHENTICATOR_RENEWAL_WINDOW_MS,
|
|
33
35
|
EmbeddedProvider: () => EmbeddedProvider,
|
|
34
36
|
JWTAuth: () => JWTAuth,
|
|
35
37
|
generateSessionId: () => generateSessionId,
|
|
@@ -43,6 +45,10 @@ var import_base64url = require("@phantom/base64url");
|
|
|
43
45
|
var import_bs58 = __toESM(require("bs58"));
|
|
44
46
|
var import_parsers = require("@phantom/parsers");
|
|
45
47
|
|
|
48
|
+
// src/constants.ts
|
|
49
|
+
var AUTHENTICATOR_EXPIRATION_TIME_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
50
|
+
var AUTHENTICATOR_RENEWAL_WINDOW_MS = 2 * 24 * 60 * 60 * 1e3;
|
|
51
|
+
|
|
46
52
|
// src/auth/jwt-auth.ts
|
|
47
53
|
var JWTAuth = class {
|
|
48
54
|
async authenticate(options) {
|
|
@@ -257,6 +263,14 @@ var EmbeddedProvider = class {
|
|
|
257
263
|
return null;
|
|
258
264
|
}
|
|
259
265
|
}
|
|
266
|
+
if (session.status === "completed" && !this.isSessionValid(session)) {
|
|
267
|
+
this.logger.warn("EMBEDDED_PROVIDER", "Session invalid due to authenticator expiration", {
|
|
268
|
+
sessionId: session.sessionId,
|
|
269
|
+
authenticatorExpiresAt: session.authenticatorExpiresAt
|
|
270
|
+
});
|
|
271
|
+
await this.storage.clearSession();
|
|
272
|
+
return null;
|
|
273
|
+
}
|
|
260
274
|
return session;
|
|
261
275
|
}
|
|
262
276
|
/*
|
|
@@ -291,6 +305,7 @@ var EmbeddedProvider = class {
|
|
|
291
305
|
walletId: this.walletId,
|
|
292
306
|
addressCount: this.addresses.length
|
|
293
307
|
});
|
|
308
|
+
await this.ensureValidAuthenticator();
|
|
294
309
|
const result = {
|
|
295
310
|
walletId: this.walletId,
|
|
296
311
|
addresses: this.addresses,
|
|
@@ -320,8 +335,9 @@ var EmbeddedProvider = class {
|
|
|
320
335
|
}
|
|
321
336
|
}
|
|
322
337
|
/*
|
|
323
|
-
* We use this method to validate if a session is still valid
|
|
324
|
-
* This checks session status,
|
|
338
|
+
* We use this method to validate if a session is still valid.
|
|
339
|
+
* This checks session status, required fields, and authenticator expiration.
|
|
340
|
+
* Sessions never expire by age - only authenticators expire.
|
|
325
341
|
*/
|
|
326
342
|
isSessionValid(session) {
|
|
327
343
|
if (!session) {
|
|
@@ -339,20 +355,23 @@ var EmbeddedProvider = class {
|
|
|
339
355
|
this.logger.log("EMBEDDED_PROVIDER", "Session not completed", { status: session.status });
|
|
340
356
|
return false;
|
|
341
357
|
}
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
358
|
+
if (!session.authenticatorExpiresAt) {
|
|
359
|
+
this.logger.log("EMBEDDED_PROVIDER", "Session invalid - missing authenticator timing", {
|
|
360
|
+
sessionId: session.sessionId
|
|
361
|
+
});
|
|
362
|
+
return false;
|
|
363
|
+
}
|
|
364
|
+
if (Date.now() >= session.authenticatorExpiresAt) {
|
|
365
|
+
this.logger.log("EMBEDDED_PROVIDER", "Authenticator expired, session invalid", {
|
|
366
|
+
authenticatorExpiresAt: new Date(session.authenticatorExpiresAt).toISOString(),
|
|
367
|
+
now: (/* @__PURE__ */ new Date()).toISOString()
|
|
349
368
|
});
|
|
350
369
|
return false;
|
|
351
370
|
}
|
|
352
371
|
this.logger.log("EMBEDDED_PROVIDER", "Session is valid", {
|
|
353
372
|
sessionId: session.sessionId,
|
|
354
373
|
walletId: session.walletId,
|
|
355
|
-
|
|
374
|
+
authenticatorExpires: new Date(session.authenticatorExpiresAt).toISOString()
|
|
356
375
|
});
|
|
357
376
|
return true;
|
|
358
377
|
}
|
|
@@ -421,9 +440,11 @@ var EmbeddedProvider = class {
|
|
|
421
440
|
platform: platformName
|
|
422
441
|
});
|
|
423
442
|
const base64urlPublicKey = (0, import_base64url.base64urlEncode)(import_bs58.default.decode(stamperInfo.publicKey));
|
|
443
|
+
const expiresAtMs = Date.now() + AUTHENTICATOR_EXPIRATION_TIME_MS;
|
|
444
|
+
const username = `user-${shortPubKey}`;
|
|
424
445
|
const { organizationId } = await tempClient.createOrganization(organizationName, [
|
|
425
446
|
{
|
|
426
|
-
username
|
|
447
|
+
username,
|
|
427
448
|
role: "ADMIN",
|
|
428
449
|
authenticators: [
|
|
429
450
|
{
|
|
@@ -431,12 +452,14 @@ var EmbeddedProvider = class {
|
|
|
431
452
|
authenticatorKind: "keypair",
|
|
432
453
|
publicKey: base64urlPublicKey,
|
|
433
454
|
algorithm: "Ed25519"
|
|
455
|
+
// Commented for now until KMS supports fully expirable organizations
|
|
456
|
+
// expiresAtMs: expiresAtMs,
|
|
434
457
|
}
|
|
435
458
|
]
|
|
436
459
|
}
|
|
437
460
|
]);
|
|
438
461
|
this.logger.info("EMBEDDED_PROVIDER", "Organization created", { organizationId });
|
|
439
|
-
return { organizationId, stamperInfo };
|
|
462
|
+
return { organizationId, stamperInfo, expiresAtMs, username };
|
|
440
463
|
}
|
|
441
464
|
async connect(authOptions) {
|
|
442
465
|
try {
|
|
@@ -465,8 +488,8 @@ var EmbeddedProvider = class {
|
|
|
465
488
|
}
|
|
466
489
|
this.validateAuthOptions(authOptions);
|
|
467
490
|
this.logger.info("EMBEDDED_PROVIDER", "No existing connection, creating new auth flow");
|
|
468
|
-
const { organizationId, stamperInfo } = await this.createOrganizationAndStamper();
|
|
469
|
-
const session = await this.handleAuthFlow(organizationId, stamperInfo, authOptions);
|
|
491
|
+
const { organizationId, stamperInfo, expiresAtMs, username } = await this.createOrganizationAndStamper();
|
|
492
|
+
const session = await this.handleAuthFlow(organizationId, stamperInfo, authOptions, expiresAtMs, username);
|
|
470
493
|
if (!session) {
|
|
471
494
|
return {
|
|
472
495
|
addresses: [],
|
|
@@ -478,6 +501,7 @@ var EmbeddedProvider = class {
|
|
|
478
501
|
await this.storage.saveSession(session);
|
|
479
502
|
}
|
|
480
503
|
await this.initializeClientFromSession(session);
|
|
504
|
+
await this.ensureValidAuthenticator();
|
|
481
505
|
const result = {
|
|
482
506
|
walletId: this.walletId,
|
|
483
507
|
addresses: this.addresses,
|
|
@@ -543,6 +567,7 @@ var EmbeddedProvider = class {
|
|
|
543
567
|
if (!this.client || !this.walletId) {
|
|
544
568
|
throw new Error("Not connected");
|
|
545
569
|
}
|
|
570
|
+
await this.ensureValidAuthenticator();
|
|
546
571
|
this.logger.info("EMBEDDED_PROVIDER", "Signing message", {
|
|
547
572
|
walletId: this.walletId,
|
|
548
573
|
message: params.message
|
|
@@ -563,6 +588,7 @@ var EmbeddedProvider = class {
|
|
|
563
588
|
if (!this.client || !this.walletId) {
|
|
564
589
|
throw new Error("Not connected");
|
|
565
590
|
}
|
|
591
|
+
await this.ensureValidAuthenticator();
|
|
566
592
|
this.logger.info("EMBEDDED_PROVIDER", "Signing and sending transaction", {
|
|
567
593
|
walletId: this.walletId,
|
|
568
594
|
networkId: params.networkId
|
|
@@ -596,20 +622,20 @@ var EmbeddedProvider = class {
|
|
|
596
622
|
* It handles app-wallet creation directly or routes to JWT/redirect authentication for user-wallets.
|
|
597
623
|
* Returns null for redirect flows since they don't complete synchronously.
|
|
598
624
|
*/
|
|
599
|
-
async handleAuthFlow(organizationId, stamperInfo, authOptions) {
|
|
625
|
+
async handleAuthFlow(organizationId, stamperInfo, authOptions, expiresAtMs, username) {
|
|
600
626
|
if (this.config.embeddedWalletType === "user-wallet") {
|
|
601
627
|
this.logger.info("EMBEDDED_PROVIDER", "Creating user-wallet, routing authentication", {
|
|
602
628
|
authProvider: authOptions?.provider || "phantom-connect"
|
|
603
629
|
});
|
|
604
630
|
if (authOptions?.provider === "jwt") {
|
|
605
|
-
return await this.handleJWTAuth(organizationId, stamperInfo, authOptions);
|
|
631
|
+
return await this.handleJWTAuth(organizationId, stamperInfo, authOptions, expiresAtMs, username);
|
|
606
632
|
} else {
|
|
607
633
|
this.logger.info("EMBEDDED_PROVIDER", "Starting redirect-based authentication flow", {
|
|
608
634
|
organizationId,
|
|
609
635
|
parentOrganizationId: this.config.organizationId,
|
|
610
636
|
provider: authOptions?.provider
|
|
611
637
|
});
|
|
612
|
-
return await this.handleRedirectAuth(organizationId, stamperInfo, authOptions);
|
|
638
|
+
return await this.handleRedirectAuth(organizationId, stamperInfo, authOptions, username);
|
|
613
639
|
}
|
|
614
640
|
} else {
|
|
615
641
|
this.logger.info("EMBEDDED_PROVIDER", "Creating app-wallet", {
|
|
@@ -634,7 +660,11 @@ var EmbeddedProvider = class {
|
|
|
634
660
|
userInfo: { embeddedWalletType: this.config.embeddedWalletType },
|
|
635
661
|
status: "completed",
|
|
636
662
|
createdAt: now,
|
|
637
|
-
lastUsed: now
|
|
663
|
+
lastUsed: now,
|
|
664
|
+
authenticatorCreatedAt: now,
|
|
665
|
+
authenticatorExpiresAt: expiresAtMs,
|
|
666
|
+
lastRenewalAttempt: void 0,
|
|
667
|
+
username
|
|
638
668
|
};
|
|
639
669
|
await this.storage.saveSession(session);
|
|
640
670
|
this.logger.info("EMBEDDED_PROVIDER", "App-wallet created successfully", { walletId, organizationId });
|
|
@@ -645,7 +675,7 @@ var EmbeddedProvider = class {
|
|
|
645
675
|
* We use this method to handle JWT-based authentication for user-wallets.
|
|
646
676
|
* It authenticates using the provided JWT token and creates a completed session.
|
|
647
677
|
*/
|
|
648
|
-
async handleJWTAuth(organizationId, stamperInfo, authOptions) {
|
|
678
|
+
async handleJWTAuth(organizationId, stamperInfo, authOptions, expiresAtMs, username) {
|
|
649
679
|
this.logger.info("EMBEDDED_PROVIDER", "Using JWT authentication flow");
|
|
650
680
|
if (!authOptions.jwtToken) {
|
|
651
681
|
this.logger.error("EMBEDDED_PROVIDER", "JWT token missing for JWT authentication");
|
|
@@ -670,7 +700,11 @@ var EmbeddedProvider = class {
|
|
|
670
700
|
userInfo: authResult.userInfo,
|
|
671
701
|
status: "completed",
|
|
672
702
|
createdAt: now,
|
|
673
|
-
lastUsed: now
|
|
703
|
+
lastUsed: now,
|
|
704
|
+
authenticatorCreatedAt: now,
|
|
705
|
+
authenticatorExpiresAt: expiresAtMs,
|
|
706
|
+
lastRenewalAttempt: void 0,
|
|
707
|
+
username
|
|
674
708
|
};
|
|
675
709
|
this.logger.log("EMBEDDED_PROVIDER", "Saving JWT session");
|
|
676
710
|
await this.storage.saveSession(session);
|
|
@@ -681,7 +715,7 @@ var EmbeddedProvider = class {
|
|
|
681
715
|
* It saves a temporary session before redirecting to prevent losing state during the redirect flow.
|
|
682
716
|
* Session timestamp is updated before redirect to prevent race conditions.
|
|
683
717
|
*/
|
|
684
|
-
async handleRedirectAuth(organizationId, stamperInfo, authOptions) {
|
|
718
|
+
async handleRedirectAuth(organizationId, stamperInfo, authOptions, username) {
|
|
685
719
|
this.logger.info("EMBEDDED_PROVIDER", "Using Phantom Connect authentication flow (redirect-based)", {
|
|
686
720
|
provider: authOptions?.provider,
|
|
687
721
|
hasRedirectUrl: !!this.config.authOptions?.redirectUrl,
|
|
@@ -699,7 +733,11 @@ var EmbeddedProvider = class {
|
|
|
699
733
|
userInfo: { provider: authOptions?.provider },
|
|
700
734
|
status: "pending",
|
|
701
735
|
createdAt: now,
|
|
702
|
-
lastUsed: now
|
|
736
|
+
lastUsed: now,
|
|
737
|
+
authenticatorCreatedAt: now,
|
|
738
|
+
authenticatorExpiresAt: now + AUTHENTICATOR_EXPIRATION_TIME_MS,
|
|
739
|
+
lastRenewalAttempt: void 0,
|
|
740
|
+
username: username || `user-${stamperInfo.keyId.substring(0, 8)}`
|
|
703
741
|
};
|
|
704
742
|
this.logger.log("EMBEDDED_PROVIDER", "Saving temporary session before redirect", {
|
|
705
743
|
sessionId: tempSession.sessionId,
|
|
@@ -750,12 +788,114 @@ var EmbeddedProvider = class {
|
|
|
750
788
|
session.lastUsed = Date.now();
|
|
751
789
|
await this.storage.saveSession(session);
|
|
752
790
|
await this.initializeClientFromSession(session);
|
|
791
|
+
await this.ensureValidAuthenticator();
|
|
753
792
|
return {
|
|
754
793
|
walletId: this.walletId,
|
|
755
794
|
addresses: this.addresses,
|
|
756
795
|
status: "completed"
|
|
757
796
|
};
|
|
758
797
|
}
|
|
798
|
+
/*
|
|
799
|
+
* Ensures the authenticator is valid and performs renewal if needed.
|
|
800
|
+
* The renewal of the authenticator can only happen meanwhile the previous authenticator is still valid.
|
|
801
|
+
*/
|
|
802
|
+
async ensureValidAuthenticator() {
|
|
803
|
+
const session = await this.storage.getSession();
|
|
804
|
+
if (!session) {
|
|
805
|
+
throw new Error("No active session found");
|
|
806
|
+
}
|
|
807
|
+
const now = Date.now();
|
|
808
|
+
if (!session.authenticatorExpiresAt) {
|
|
809
|
+
this.logger.warn("EMBEDDED_PROVIDER", "Session missing authenticator timing - treating as invalid session");
|
|
810
|
+
await this.disconnect();
|
|
811
|
+
throw new Error("Invalid session - missing authenticator timing");
|
|
812
|
+
}
|
|
813
|
+
const timeUntilExpiry = session.authenticatorExpiresAt - now;
|
|
814
|
+
this.logger.log("EMBEDDED_PROVIDER", "Checking authenticator expiration", {
|
|
815
|
+
expiresAt: new Date(session.authenticatorExpiresAt).toISOString(),
|
|
816
|
+
timeUntilExpiry
|
|
817
|
+
});
|
|
818
|
+
if (timeUntilExpiry <= 0) {
|
|
819
|
+
this.logger.error("EMBEDDED_PROVIDER", "Authenticator has expired, disconnecting");
|
|
820
|
+
await this.disconnect();
|
|
821
|
+
throw new Error("Authenticator expired");
|
|
822
|
+
}
|
|
823
|
+
const renewalWindow = AUTHENTICATOR_RENEWAL_WINDOW_MS;
|
|
824
|
+
if (timeUntilExpiry <= renewalWindow) {
|
|
825
|
+
this.logger.info("EMBEDDED_PROVIDER", "Authenticator needs renewal", {
|
|
826
|
+
expiresAt: new Date(session.authenticatorExpiresAt).toISOString(),
|
|
827
|
+
timeUntilExpiry,
|
|
828
|
+
renewalWindow
|
|
829
|
+
});
|
|
830
|
+
try {
|
|
831
|
+
await this.renewAuthenticator(session);
|
|
832
|
+
this.logger.info("EMBEDDED_PROVIDER", "Authenticator renewed successfully");
|
|
833
|
+
} catch (error) {
|
|
834
|
+
this.logger.error("EMBEDDED_PROVIDER", "Failed to renew authenticator", {
|
|
835
|
+
error: error instanceof Error ? error.message : String(error)
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
/*
|
|
841
|
+
* We use this method to perform silent authenticator renewal.
|
|
842
|
+
* It generates a new keypair, creates a new authenticator, and switches to it.
|
|
843
|
+
*/
|
|
844
|
+
async renewAuthenticator(session) {
|
|
845
|
+
if (!this.client) {
|
|
846
|
+
throw new Error("Client not initialized");
|
|
847
|
+
}
|
|
848
|
+
this.logger.info("EMBEDDED_PROVIDER", "Starting authenticator renewal");
|
|
849
|
+
try {
|
|
850
|
+
const newKeyInfo = await this.stamper.rotateKeyPair();
|
|
851
|
+
this.logger.log("EMBEDDED_PROVIDER", "Generated new keypair for renewal", {
|
|
852
|
+
newKeyId: newKeyInfo.keyId,
|
|
853
|
+
newPublicKey: newKeyInfo.publicKey
|
|
854
|
+
});
|
|
855
|
+
const base64urlPublicKey = (0, import_base64url.base64urlEncode)(import_bs58.default.decode(newKeyInfo.publicKey));
|
|
856
|
+
const expiresAtMs = Date.now() + AUTHENTICATOR_EXPIRATION_TIME_MS;
|
|
857
|
+
let authenticatorResult;
|
|
858
|
+
try {
|
|
859
|
+
authenticatorResult = await this.client.createAuthenticator({
|
|
860
|
+
organizationId: session.organizationId,
|
|
861
|
+
username: session.username,
|
|
862
|
+
authenticatorName: `auth-${newKeyInfo.keyId.substring(0, 8)}`,
|
|
863
|
+
authenticator: {
|
|
864
|
+
authenticatorName: `auth-${newKeyInfo.keyId.substring(0, 8)}`,
|
|
865
|
+
authenticatorKind: "keypair",
|
|
866
|
+
publicKey: base64urlPublicKey,
|
|
867
|
+
algorithm: "Ed25519"
|
|
868
|
+
// Commented for now until KMS supports fully expiring organizations
|
|
869
|
+
// expiresAtMs: expiresAtMs,
|
|
870
|
+
},
|
|
871
|
+
replaceExpirable: true
|
|
872
|
+
});
|
|
873
|
+
} catch (error) {
|
|
874
|
+
this.logger.error("EMBEDDED_PROVIDER", "Failed to create new authenticator", {
|
|
875
|
+
error: error instanceof Error ? error.message : String(error)
|
|
876
|
+
});
|
|
877
|
+
await this.stamper.rollbackRotation();
|
|
878
|
+
throw new Error(`Failed to create new authenticator: ${error instanceof Error ? error.message : String(error)}`);
|
|
879
|
+
}
|
|
880
|
+
this.logger.info("EMBEDDED_PROVIDER", "Created new authenticator", {
|
|
881
|
+
authenticatorId: authenticatorResult.id
|
|
882
|
+
});
|
|
883
|
+
await this.stamper.commitRotation(authenticatorResult.id || "unknown");
|
|
884
|
+
const now = Date.now();
|
|
885
|
+
session.stamperInfo = newKeyInfo;
|
|
886
|
+
session.authenticatorCreatedAt = now;
|
|
887
|
+
session.authenticatorExpiresAt = expiresAtMs;
|
|
888
|
+
session.lastRenewalAttempt = now;
|
|
889
|
+
await this.storage.saveSession(session);
|
|
890
|
+
this.logger.info("EMBEDDED_PROVIDER", "Authenticator renewal completed successfully", {
|
|
891
|
+
newKeyId: newKeyInfo.keyId,
|
|
892
|
+
expiresAt: new Date(expiresAtMs).toISOString()
|
|
893
|
+
});
|
|
894
|
+
} catch (error) {
|
|
895
|
+
await this.stamper.rollbackRotation();
|
|
896
|
+
throw error;
|
|
897
|
+
}
|
|
898
|
+
}
|
|
759
899
|
/*
|
|
760
900
|
* We use this method to initialize the PhantomClient and fetch wallet addresses from a completed session.
|
|
761
901
|
* This is the final step that sets up the provider's client state and retrieves available addresses.
|
|
@@ -781,6 +921,8 @@ var EmbeddedProvider = class {
|
|
|
781
921
|
};
|
|
782
922
|
// Annotate the CommonJS export names for ESM import in node:
|
|
783
923
|
0 && (module.exports = {
|
|
924
|
+
AUTHENTICATOR_EXPIRATION_TIME_MS,
|
|
925
|
+
AUTHENTICATOR_RENEWAL_WINDOW_MS,
|
|
784
926
|
EmbeddedProvider,
|
|
785
927
|
JWTAuth,
|
|
786
928
|
generateSessionId,
|