@account-kit/signer 4.16.1-alpha.3 → 4.17.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/esm/base.d.ts +15 -32
- package/dist/esm/base.js +94 -122
- package/dist/esm/base.js.map +1 -1
- package/dist/esm/client/base.d.ts +2 -36
- package/dist/esm/client/base.js.map +1 -1
- package/dist/esm/client/index.d.ts +1 -40
- package/dist/esm/client/index.js +7 -164
- package/dist/esm/client/index.js.map +1 -1
- package/dist/esm/client/types.d.ts +12 -66
- package/dist/esm/client/types.js.map +1 -1
- package/dist/esm/errors.d.ts +0 -6
- package/dist/esm/errors.js +0 -18
- package/dist/esm/errors.js.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.js +1 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/session/manager.d.ts +0 -1
- package/dist/esm/session/manager.js.map +1 -1
- package/dist/esm/signer.d.ts +2 -3
- package/dist/esm/signer.js.map +1 -1
- package/dist/esm/types.d.ts +0 -8
- package/dist/esm/types.js +0 -5
- package/dist/esm/types.js.map +1 -1
- package/dist/esm/version.d.ts +1 -1
- package/dist/esm/version.js +1 -1
- package/dist/esm/version.js.map +1 -1
- package/dist/types/base.d.ts +15 -32
- package/dist/types/base.d.ts.map +1 -1
- package/dist/types/client/base.d.ts +2 -36
- package/dist/types/client/base.d.ts.map +1 -1
- package/dist/types/client/index.d.ts +1 -40
- package/dist/types/client/index.d.ts.map +1 -1
- package/dist/types/client/types.d.ts +12 -66
- package/dist/types/client/types.d.ts.map +1 -1
- package/dist/types/errors.d.ts +0 -6
- package/dist/types/errors.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/session/manager.d.ts +0 -1
- package/dist/types/session/manager.d.ts.map +1 -1
- package/dist/types/signer.d.ts +2 -3
- package/dist/types/signer.d.ts.map +1 -1
- package/dist/types/types.d.ts +0 -8
- package/dist/types/types.d.ts.map +1 -1
- package/dist/types/version.d.ts +1 -1
- package/dist/types/version.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/base.ts +87 -166
- package/src/client/base.ts +1 -43
- package/src/client/index.ts +7 -174
- package/src/client/types.ts +14 -76
- package/src/errors.ts +1 -11
- package/src/index.ts +1 -5
- package/src/session/manager.ts +1 -5
- package/src/signer.ts +2 -6
- package/src/types.ts +0 -9
- package/src/version.ts +1 -1
- package/dist/esm/utils/parseMfaError.d.ts +0 -2
- package/dist/esm/utils/parseMfaError.js +0 -15
- package/dist/esm/utils/parseMfaError.js.map +0 -1
- package/dist/types/utils/parseMfaError.d.ts +0 -3
- package/dist/types/utils/parseMfaError.d.ts.map +0 -1
- package/src/utils/parseMfaError.ts +0 -15
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@account-kit/signer",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.17.0",
|
|
4
4
|
"description": "Core interfaces and clients for interfacing with the Alchemy Signer API",
|
|
5
5
|
"author": "Alchemy",
|
|
6
6
|
"license": "MIT",
|
|
@@ -49,8 +49,8 @@
|
|
|
49
49
|
"vitest": "^2.0.4"
|
|
50
50
|
},
|
|
51
51
|
"dependencies": {
|
|
52
|
-
"@aa-sdk/core": "^4.
|
|
53
|
-
"@account-kit/logging": "^4.
|
|
52
|
+
"@aa-sdk/core": "^4.17.0",
|
|
53
|
+
"@account-kit/logging": "^4.17.0",
|
|
54
54
|
"@solana/web3.js": "^1.98.0",
|
|
55
55
|
"@turnkey/http": "^2.6.2",
|
|
56
56
|
"@turnkey/iframe-stamper": "^1.0.0",
|
|
@@ -74,5 +74,5 @@
|
|
|
74
74
|
"url": "https://github.com/alchemyplatform/aa-sdk/issues"
|
|
75
75
|
},
|
|
76
76
|
"homepage": "https://github.com/alchemyplatform/aa-sdk#readme",
|
|
77
|
-
"gitHead": "
|
|
77
|
+
"gitHead": "680b0acb112f02deaa1fa4e8b253ac3800c06cb2"
|
|
78
78
|
}
|
package/src/base.ts
CHANGED
|
@@ -21,14 +21,7 @@ import type { Mutate, StoreApi } from "zustand";
|
|
|
21
21
|
import { subscribeWithSelector } from "zustand/middleware";
|
|
22
22
|
import { createStore } from "zustand/vanilla";
|
|
23
23
|
import type { BaseSignerClient } from "./client/base";
|
|
24
|
-
import type {
|
|
25
|
-
EmailType,
|
|
26
|
-
MfaFactor,
|
|
27
|
-
OauthConfig,
|
|
28
|
-
OauthParams,
|
|
29
|
-
User,
|
|
30
|
-
VerifyMfaParams,
|
|
31
|
-
} from "./client/types";
|
|
24
|
+
import type { OauthConfig, OauthParams, User } from "./client/types";
|
|
32
25
|
import { NotAuthenticatedError } from "./errors.js";
|
|
33
26
|
import { SignerLogger } from "./metrics.js";
|
|
34
27
|
import {
|
|
@@ -58,10 +51,6 @@ type AlchemySignerStore = {
|
|
|
58
51
|
error: ErrorInfo | null;
|
|
59
52
|
otpId?: string;
|
|
60
53
|
isNewUser?: boolean;
|
|
61
|
-
mfaStatus: {
|
|
62
|
-
mfaRequired: boolean;
|
|
63
|
-
mfaFactorId?: string;
|
|
64
|
-
};
|
|
65
54
|
};
|
|
66
55
|
|
|
67
56
|
type UnpackedSignature = {
|
|
@@ -75,6 +64,14 @@ type InternalStore = Mutate<
|
|
|
75
64
|
[["zustand/subscribeWithSelector", never]]
|
|
76
65
|
>;
|
|
77
66
|
|
|
67
|
+
export type EmailConfig = {
|
|
68
|
+
mode?: "MAGIC_LINK" | "OTP";
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export type SignerConfig = {
|
|
72
|
+
email: EmailConfig;
|
|
73
|
+
};
|
|
74
|
+
|
|
78
75
|
/**
|
|
79
76
|
* Base abstract class for Alchemy Signer, providing authentication and session management for smart accounts.
|
|
80
77
|
* Implements the `SmartAccountAuthenticator` interface and handles various signer events.
|
|
@@ -86,6 +83,7 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
|
|
|
86
83
|
inner: TClient;
|
|
87
84
|
private sessionManager: SessionManager;
|
|
88
85
|
private store: InternalStore;
|
|
86
|
+
private config: Promise<SignerConfig>;
|
|
89
87
|
|
|
90
88
|
/**
|
|
91
89
|
* Initializes an instance with the provided client and session configuration.
|
|
@@ -110,10 +108,6 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
|
|
|
110
108
|
user: null,
|
|
111
109
|
status: AlchemySignerStatus.INITIALIZING,
|
|
112
110
|
error: initialError ?? null,
|
|
113
|
-
mfaStatus: {
|
|
114
|
-
mfaRequired: false,
|
|
115
|
-
mfaFactorId: undefined,
|
|
116
|
-
},
|
|
117
111
|
} satisfies AlchemySignerStore)
|
|
118
112
|
)
|
|
119
113
|
);
|
|
@@ -128,6 +122,7 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
|
|
|
128
122
|
this.registerListeners();
|
|
129
123
|
// then initialize so that we can catch those events
|
|
130
124
|
this.sessionManager.initialize();
|
|
125
|
+
this.config = this.fetchConfig();
|
|
131
126
|
}
|
|
132
127
|
|
|
133
128
|
/**
|
|
@@ -186,13 +181,6 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
|
|
|
186
181
|
},
|
|
187
182
|
{ fireImmediately: true }
|
|
188
183
|
);
|
|
189
|
-
case "mfaStatusChanged":
|
|
190
|
-
return this.store.subscribe(
|
|
191
|
-
({ mfaStatus }) => mfaStatus,
|
|
192
|
-
(mfaStatus) =>
|
|
193
|
-
(listener as AlchemySignerEvents["mfaStatusChanged"])(mfaStatus),
|
|
194
|
-
{ fireImmediately: true }
|
|
195
|
-
);
|
|
196
184
|
default:
|
|
197
185
|
assertNever(event, `Unknown event type ${event}`);
|
|
198
186
|
}
|
|
@@ -602,39 +590,6 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
|
|
|
602
590
|
}
|
|
603
591
|
);
|
|
604
592
|
|
|
605
|
-
/**
|
|
606
|
-
* Gets the current MFA status
|
|
607
|
-
*
|
|
608
|
-
* @example
|
|
609
|
-
* ```ts
|
|
610
|
-
* import { AlchemyWebSigner } from "@account-kit/signer";
|
|
611
|
-
*
|
|
612
|
-
* const signer = new AlchemyWebSigner({
|
|
613
|
-
* client: {
|
|
614
|
-
* connection: {
|
|
615
|
-
* rpcUrl: "/api/rpc",
|
|
616
|
-
* },
|
|
617
|
-
* iframeConfig: {
|
|
618
|
-
* iframeContainerId: "alchemy-signer-iframe-container",
|
|
619
|
-
* },
|
|
620
|
-
* },
|
|
621
|
-
* });
|
|
622
|
-
*
|
|
623
|
-
* const mfaStatus = signer.getMfaStatus();
|
|
624
|
-
* if (mfaStatus === AlchemyMfaStatus.REQUIRED) {
|
|
625
|
-
* // Handle MFA requirement
|
|
626
|
-
* }
|
|
627
|
-
* ```
|
|
628
|
-
*
|
|
629
|
-
* @returns {{ mfaRequired: boolean; mfaFactorId?: string }} The current MFA status
|
|
630
|
-
*/
|
|
631
|
-
getMfaStatus = (): {
|
|
632
|
-
mfaRequired: boolean;
|
|
633
|
-
mfaFactorId?: string;
|
|
634
|
-
} => {
|
|
635
|
-
return this.store.getState().mfaStatus;
|
|
636
|
-
};
|
|
637
|
-
|
|
638
593
|
private unpackSignRawMessageBytes = (
|
|
639
594
|
hex: `0x${string}`
|
|
640
595
|
): UnpackedSignature => {
|
|
@@ -824,48 +779,70 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
|
|
|
824
779
|
private authenticateWithEmail = async (
|
|
825
780
|
params: Extract<AuthParams, { type: "email" }>
|
|
826
781
|
): Promise<User> => {
|
|
827
|
-
if ("
|
|
828
|
-
|
|
829
|
-
|
|
782
|
+
if ("email" in params) {
|
|
783
|
+
const existingUser = await this.getUser(params.email);
|
|
784
|
+
const expirationSeconds = this.getExpirationSeconds();
|
|
785
|
+
|
|
786
|
+
const { orgId, otpId } = existingUser
|
|
787
|
+
? await this.inner.initEmailAuth({
|
|
788
|
+
email: params.email,
|
|
789
|
+
emailMode: params.emailMode,
|
|
790
|
+
expirationSeconds,
|
|
791
|
+
redirectParams: params.redirectParams,
|
|
792
|
+
})
|
|
793
|
+
: await this.inner.createAccount({
|
|
794
|
+
type: "email",
|
|
795
|
+
email: params.email,
|
|
796
|
+
emailMode: params.emailMode,
|
|
797
|
+
expirationSeconds,
|
|
798
|
+
redirectParams: params.redirectParams,
|
|
799
|
+
});
|
|
830
800
|
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
801
|
+
this.sessionManager.setTemporarySession({
|
|
802
|
+
orgId,
|
|
803
|
+
isNewUser: !existingUser,
|
|
804
|
+
});
|
|
805
|
+
this.store.setState({
|
|
806
|
+
status: AlchemySignerStatus.AWAITING_EMAIL_AUTH,
|
|
807
|
+
otpId,
|
|
808
|
+
error: null,
|
|
809
|
+
});
|
|
834
810
|
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
811
|
+
// We wait for the session manager to emit a connected event if
|
|
812
|
+
// cross tab sessions are permitted
|
|
813
|
+
return new Promise<User>((resolve) => {
|
|
814
|
+
const removeListener = this.sessionManager.on(
|
|
815
|
+
"connected",
|
|
816
|
+
(session) => {
|
|
817
|
+
resolve(session.user);
|
|
818
|
+
removeListener();
|
|
819
|
+
}
|
|
820
|
+
);
|
|
821
|
+
});
|
|
822
|
+
} else {
|
|
823
|
+
const temporarySession = params.orgId
|
|
824
|
+
? { orgId: params.orgId }
|
|
825
|
+
: this.sessionManager.getTemporarySession();
|
|
842
826
|
|
|
843
|
-
|
|
827
|
+
if (!temporarySession) {
|
|
828
|
+
this.store.setState({
|
|
829
|
+
status: AlchemySignerStatus.DISCONNECTED,
|
|
830
|
+
});
|
|
831
|
+
throw new Error("Could not find email auth init session!");
|
|
832
|
+
}
|
|
844
833
|
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
834
|
+
const user = await this.inner.completeAuthWithBundle({
|
|
835
|
+
bundle: params.bundle,
|
|
836
|
+
orgId: temporarySession.orgId,
|
|
837
|
+
connectedEventName: "connectedEmail",
|
|
838
|
+
authenticatingType: "email",
|
|
839
|
+
});
|
|
850
840
|
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
otpId,
|
|
854
|
-
error: null,
|
|
855
|
-
mfaStatus: {
|
|
856
|
-
mfaRequired: isMfaRequired,
|
|
857
|
-
mfaFactorId: multiFactors?.[0]?.multiFactorId,
|
|
858
|
-
},
|
|
859
|
-
});
|
|
841
|
+
// fire new user event
|
|
842
|
+
this.emitNewUserEvent(params.isNewUser);
|
|
860
843
|
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
return new Promise<User>((resolve) => {
|
|
864
|
-
const removeListener = this.sessionManager.on("connected", (session) => {
|
|
865
|
-
resolve(session.user);
|
|
866
|
-
removeListener();
|
|
867
|
-
});
|
|
868
|
-
});
|
|
844
|
+
return user;
|
|
845
|
+
}
|
|
869
846
|
};
|
|
870
847
|
|
|
871
848
|
private authenticateWithPasskey = async (
|
|
@@ -926,7 +903,7 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
|
|
|
926
903
|
args: Extract<AuthParams, { type: "otp" }>
|
|
927
904
|
): Promise<User> => {
|
|
928
905
|
const tempSession = this.sessionManager.getTemporarySession();
|
|
929
|
-
const { orgId, isNewUser
|
|
906
|
+
const { orgId, isNewUser } = tempSession ?? {};
|
|
930
907
|
const { otpId } = this.store.getState();
|
|
931
908
|
if (!orgId) {
|
|
932
909
|
throw new Error("orgId not found in session");
|
|
@@ -934,16 +911,11 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
|
|
|
934
911
|
if (!otpId) {
|
|
935
912
|
throw new Error("otpId not found in session");
|
|
936
913
|
}
|
|
937
|
-
if (isMfaRequired && !args.multiFactors) {
|
|
938
|
-
throw new Error(`MFA is required.`);
|
|
939
|
-
}
|
|
940
|
-
|
|
941
914
|
const { bundle } = await this.inner.submitOtpCode({
|
|
942
915
|
orgId,
|
|
943
916
|
otpId,
|
|
944
917
|
otpCode: args.otpCode,
|
|
945
918
|
expirationSeconds: this.getExpirationSeconds(),
|
|
946
|
-
multiFactors: args.multiFactors,
|
|
947
919
|
});
|
|
948
920
|
const user = await this.inner.completeAuthWithBundle({
|
|
949
921
|
bundle,
|
|
@@ -1050,78 +1022,27 @@ export abstract class BaseAlchemySigner<TClient extends BaseSignerClient>
|
|
|
1050
1022
|
if (isNewUser) this.store.setState({ isNewUser });
|
|
1051
1023
|
};
|
|
1052
1024
|
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
redirectParams?: URLSearchParams
|
|
1058
|
-
): Promise<{
|
|
1059
|
-
orgId: string;
|
|
1060
|
-
otpId?: string;
|
|
1061
|
-
multiFactors?: MfaFactor[];
|
|
1062
|
-
isNewUser: boolean;
|
|
1063
|
-
}> {
|
|
1064
|
-
const existingUser = await this.getUser(email);
|
|
1065
|
-
const expirationSeconds = this.getExpirationSeconds();
|
|
1066
|
-
|
|
1067
|
-
if (existingUser) {
|
|
1068
|
-
const {
|
|
1069
|
-
orgId,
|
|
1070
|
-
otpId,
|
|
1071
|
-
multiFactors: mfaFactors,
|
|
1072
|
-
} = await this.inner.initEmailAuth({
|
|
1073
|
-
email: email,
|
|
1074
|
-
emailMode: emailMode,
|
|
1075
|
-
expirationSeconds,
|
|
1076
|
-
redirectParams: redirectParams,
|
|
1077
|
-
multiFactors,
|
|
1078
|
-
});
|
|
1079
|
-
return {
|
|
1080
|
-
orgId,
|
|
1081
|
-
otpId,
|
|
1082
|
-
multiFactors: mfaFactors,
|
|
1083
|
-
isNewUser: false,
|
|
1084
|
-
};
|
|
1085
|
-
}
|
|
1086
|
-
|
|
1087
|
-
const { orgId, otpId } = await this.inner.createAccount({
|
|
1088
|
-
type: "email",
|
|
1089
|
-
email,
|
|
1090
|
-
emailMode,
|
|
1091
|
-
expirationSeconds,
|
|
1092
|
-
redirectParams,
|
|
1093
|
-
});
|
|
1094
|
-
return {
|
|
1095
|
-
orgId,
|
|
1096
|
-
otpId,
|
|
1097
|
-
isNewUser: true,
|
|
1098
|
-
};
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
private async completeEmailAuth(
|
|
1102
|
-
params: Extract<AuthParams, { type: "email"; bundle: string }>
|
|
1103
|
-
): Promise<User> {
|
|
1104
|
-
const temporarySession = params.orgId
|
|
1105
|
-
? { orgId: params.orgId }
|
|
1106
|
-
: this.sessionManager.getTemporarySession();
|
|
1025
|
+
protected initConfig = async (): Promise<SignerConfig> => {
|
|
1026
|
+
this.config = this.fetchConfig();
|
|
1027
|
+
return this.config;
|
|
1028
|
+
};
|
|
1107
1029
|
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
|
|
1030
|
+
/**
|
|
1031
|
+
* Returns the signer configuration while fetching it if it's not already initialized.
|
|
1032
|
+
*
|
|
1033
|
+
* @returns {Promise<SignerConfig>} A promise that resolves to the signer configuration
|
|
1034
|
+
*/
|
|
1035
|
+
public getConfig = async (): Promise<SignerConfig> => {
|
|
1036
|
+
if (!this.config) {
|
|
1037
|
+
return this.initConfig();
|
|
1111
1038
|
}
|
|
1112
1039
|
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
orgId: temporarySession.orgId,
|
|
1116
|
-
connectedEventName: "connectedEmail",
|
|
1117
|
-
authenticatingType: "email",
|
|
1118
|
-
});
|
|
1119
|
-
|
|
1120
|
-
// fire new user event
|
|
1121
|
-
this.emitNewUserEvent(params.isNewUser);
|
|
1040
|
+
return this.config;
|
|
1041
|
+
};
|
|
1122
1042
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1043
|
+
protected fetchConfig = async (): Promise<SignerConfig> => {
|
|
1044
|
+
return this.inner.request("/v1/signer-config", {});
|
|
1045
|
+
};
|
|
1125
1046
|
}
|
|
1126
1047
|
|
|
1127
1048
|
function toErrorInfo(error: unknown): ErrorInfo {
|
package/src/client/base.ts
CHANGED
|
@@ -14,13 +14,9 @@ import type {
|
|
|
14
14
|
AlchemySignerClientEvents,
|
|
15
15
|
AuthenticatingEventMetadata,
|
|
16
16
|
CreateAccountParams,
|
|
17
|
-
RemoveMfaParams,
|
|
18
17
|
EmailAuthParams,
|
|
19
|
-
EnableMfaParams,
|
|
20
|
-
EnableMfaResult,
|
|
21
18
|
GetOauthProviderUrlArgs,
|
|
22
19
|
GetWebAuthnAttestationResult,
|
|
23
|
-
MfaFactor,
|
|
24
20
|
OauthConfig,
|
|
25
21
|
OauthParams,
|
|
26
22
|
OauthState,
|
|
@@ -30,7 +26,6 @@ import type {
|
|
|
30
26
|
SignerRoutes,
|
|
31
27
|
SignupResponse,
|
|
32
28
|
User,
|
|
33
|
-
VerifyMfaParams,
|
|
34
29
|
} from "./types.js";
|
|
35
30
|
|
|
36
31
|
export interface BaseSignerClientParams {
|
|
@@ -136,44 +131,7 @@ export abstract class BaseSignerClient<TExportWalletParams = unknown> {
|
|
|
136
131
|
|
|
137
132
|
public abstract initEmailAuth(
|
|
138
133
|
params: Omit<EmailAuthParams, "targetPublicKey">
|
|
139
|
-
): Promise<{ orgId: string; otpId?: string
|
|
140
|
-
|
|
141
|
-
/**
|
|
142
|
-
* Retrieves the list of MFA factors configured for the current user.
|
|
143
|
-
*
|
|
144
|
-
* @returns {Promise<{ multiFactors: Array<MfaFactor> }>} A promise that resolves to an array of configured MFA factors
|
|
145
|
-
*/
|
|
146
|
-
public abstract getMfaFactors(): Promise<{
|
|
147
|
-
multiFactors: MfaFactor[];
|
|
148
|
-
}>;
|
|
149
|
-
|
|
150
|
-
/**
|
|
151
|
-
* Initiates the setup of a new MFA factor for the current user. Mfa will need to be verified before it is active.
|
|
152
|
-
*
|
|
153
|
-
* @param {EnableMfaParams} params The parameters required to enable a new MFA factor
|
|
154
|
-
* @returns {Promise<EnableMfaResult>} A promise that resolves to the factor setup information
|
|
155
|
-
*/
|
|
156
|
-
public abstract addMfa(params: EnableMfaParams): Promise<EnableMfaResult>;
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Verifies a newly created MFA factor to complete the setup process.
|
|
160
|
-
*
|
|
161
|
-
* @param {VerifyMfaParams} params The parameters required to verify the MFA factor
|
|
162
|
-
* @returns {Promise<{ multiFactors: MfaFactor[] }>} A promise that resolves to the updated list of MFA factors
|
|
163
|
-
*/
|
|
164
|
-
public abstract verifyMfa(params: VerifyMfaParams): Promise<{
|
|
165
|
-
multiFactors: MfaFactor[];
|
|
166
|
-
}>;
|
|
167
|
-
|
|
168
|
-
/**
|
|
169
|
-
* Removes existing MFA factors by ID or factor type.
|
|
170
|
-
*
|
|
171
|
-
* @param {RemoveMfaParams} params The parameters specifying which factors to disable
|
|
172
|
-
* @returns {Promise<{ multiFactors: MfaFactor[] }>} A promise that resolves to the updated list of MFA factors
|
|
173
|
-
*/
|
|
174
|
-
public abstract removeMfa(params: RemoveMfaParams): Promise<{
|
|
175
|
-
multiFactors: MfaFactor[];
|
|
176
|
-
}>;
|
|
134
|
+
): Promise<{ orgId: string; otpId?: string }>;
|
|
177
135
|
|
|
178
136
|
public abstract completeAuthWithBundle(params: {
|
|
179
137
|
bundle: string;
|
package/src/client/index.ts
CHANGED
|
@@ -17,23 +17,9 @@ import type {
|
|
|
17
17
|
OauthConfig,
|
|
18
18
|
OtpParams,
|
|
19
19
|
User,
|
|
20
|
-
MfaFactor,
|
|
21
|
-
EnableMfaParams,
|
|
22
|
-
EnableMfaResult,
|
|
23
|
-
VerifyMfaParams,
|
|
24
|
-
RemoveMfaParams,
|
|
25
20
|
} from "./types.js";
|
|
26
|
-
import { MfaRequiredError, NotAuthenticatedError } from "../errors.js";
|
|
27
|
-
import { parseMfaError } from "../utils/parseMfaError.js";
|
|
28
21
|
|
|
29
22
|
const CHECK_CLOSE_INTERVAL = 500;
|
|
30
|
-
const MFA_PAYLOAD = {
|
|
31
|
-
GET: "get_mfa",
|
|
32
|
-
ADD: "add_mfa",
|
|
33
|
-
DELETE: "delete_mfas",
|
|
34
|
-
VERIFY: "verify_mfa",
|
|
35
|
-
LIST: "list_mfas",
|
|
36
|
-
};
|
|
37
23
|
|
|
38
24
|
export const AlchemySignerClientParamsSchema = z.object({
|
|
39
25
|
connection: ConnectionConfigSchema,
|
|
@@ -212,25 +198,13 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
|
|
|
212
198
|
const { email, emailMode, expirationSeconds } = params;
|
|
213
199
|
const publicKey = await this.initIframeStamper();
|
|
214
200
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
multiFactors: params.multiFactors,
|
|
223
|
-
});
|
|
224
|
-
} catch (error) {
|
|
225
|
-
const multiFactors = parseMfaError(error);
|
|
226
|
-
|
|
227
|
-
// If MFA is required, and emailMode is Magic Link, the user must submit mfa with the request or
|
|
228
|
-
// the the server will return an error with the required mfa factors.
|
|
229
|
-
if (multiFactors) {
|
|
230
|
-
throw new MfaRequiredError(multiFactors);
|
|
231
|
-
}
|
|
232
|
-
throw error;
|
|
233
|
-
}
|
|
201
|
+
return this.request("/v1/auth", {
|
|
202
|
+
email,
|
|
203
|
+
emailMode,
|
|
204
|
+
targetPublicKey: publicKey,
|
|
205
|
+
expirationSeconds,
|
|
206
|
+
redirectParams: params.redirectParams?.toString(),
|
|
207
|
+
});
|
|
234
208
|
};
|
|
235
209
|
|
|
236
210
|
/**
|
|
@@ -268,12 +242,6 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
|
|
|
268
242
|
...args,
|
|
269
243
|
targetPublicKey,
|
|
270
244
|
});
|
|
271
|
-
|
|
272
|
-
if (!credentialBundle) {
|
|
273
|
-
throw new Error(
|
|
274
|
-
"Failed to submit OTP code. Check if multiFactor is required."
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
245
|
return { bundle: credentialBundle };
|
|
278
246
|
}
|
|
279
247
|
|
|
@@ -702,141 +670,6 @@ export class AlchemySignerWebClient extends BaseSignerClient<ExportWalletParams>
|
|
|
702
670
|
const nonce = this.getOauthNonce(publicKey);
|
|
703
671
|
return this.request("/v1/prepare-oauth", { nonce });
|
|
704
672
|
};
|
|
705
|
-
|
|
706
|
-
/**
|
|
707
|
-
* Retrieves the list of MFA factors configured for the current user.
|
|
708
|
-
*
|
|
709
|
-
* @returns {Promise<{ multiFactors: MfaFactor[] }>} A promise that resolves to an array of configured MFA factors
|
|
710
|
-
* @throws {NotAuthenticatedError} If no user is authenticated
|
|
711
|
-
*/
|
|
712
|
-
public override getMfaFactors = async (): Promise<{
|
|
713
|
-
multiFactors: MfaFactor[];
|
|
714
|
-
}> => {
|
|
715
|
-
if (!this.user) {
|
|
716
|
-
throw new NotAuthenticatedError();
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
const stampedRequest = await this.turnkeyClient.stampSignRawPayload({
|
|
720
|
-
organizationId: this.user.orgId,
|
|
721
|
-
type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2",
|
|
722
|
-
timestampMs: Date.now().toString(),
|
|
723
|
-
parameters: {
|
|
724
|
-
encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
|
|
725
|
-
hashFunction: "HASH_FUNCTION_NO_OP",
|
|
726
|
-
payload: MFA_PAYLOAD.LIST,
|
|
727
|
-
signWith: this.user.address,
|
|
728
|
-
},
|
|
729
|
-
});
|
|
730
|
-
|
|
731
|
-
return this.request("/v1/auth-list-multi-factors", {
|
|
732
|
-
stampedRequest,
|
|
733
|
-
});
|
|
734
|
-
};
|
|
735
|
-
|
|
736
|
-
/**
|
|
737
|
-
* Initiates the setup of a new MFA factor for the current user. Mfa will need to be verified before it is active.
|
|
738
|
-
*
|
|
739
|
-
* @param {EnableMfaParams} params The parameters required to enable a new MFA factor
|
|
740
|
-
* @returns {Promise<EnableMfaResult>} A promise that resolves to the factor setup information
|
|
741
|
-
* @throws {NotAuthenticatedError} If no user is authenticated
|
|
742
|
-
* @throws {Error} If an unsupported factor type is provided
|
|
743
|
-
*/
|
|
744
|
-
public override addMfa = async (
|
|
745
|
-
params: EnableMfaParams
|
|
746
|
-
): Promise<EnableMfaResult> => {
|
|
747
|
-
if (!this.user) {
|
|
748
|
-
throw new NotAuthenticatedError();
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
const stampedRequest = await this.turnkeyClient.stampSignRawPayload({
|
|
752
|
-
organizationId: this.user.orgId,
|
|
753
|
-
type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2",
|
|
754
|
-
timestampMs: Date.now().toString(),
|
|
755
|
-
parameters: {
|
|
756
|
-
encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
|
|
757
|
-
hashFunction: "HASH_FUNCTION_NO_OP",
|
|
758
|
-
payload: MFA_PAYLOAD.ADD,
|
|
759
|
-
signWith: this.user.address,
|
|
760
|
-
},
|
|
761
|
-
});
|
|
762
|
-
|
|
763
|
-
switch (params.multiFactorType) {
|
|
764
|
-
case "totp":
|
|
765
|
-
return this.request("/v1/auth-request-multi-factor", {
|
|
766
|
-
stampedRequest,
|
|
767
|
-
multiFactorType: params.multiFactorType,
|
|
768
|
-
});
|
|
769
|
-
default:
|
|
770
|
-
throw new Error(
|
|
771
|
-
`Unsupported MFA factor type: ${params.multiFactorType}`
|
|
772
|
-
);
|
|
773
|
-
}
|
|
774
|
-
};
|
|
775
|
-
|
|
776
|
-
/**
|
|
777
|
-
* Verifies a newly created MFA factor to complete the setup process.
|
|
778
|
-
*
|
|
779
|
-
* @param {VerifyMfaParams} params The parameters required to verify the MFA factor
|
|
780
|
-
* @returns {Promise<{ multiFactors: MfaFactor[] }>} A promise that resolves to the updated list of MFA factors
|
|
781
|
-
* @throws {NotAuthenticatedError} If no user is authenticated
|
|
782
|
-
*/
|
|
783
|
-
public override verifyMfa = async (
|
|
784
|
-
params: VerifyMfaParams
|
|
785
|
-
): Promise<{ multiFactors: MfaFactor[] }> => {
|
|
786
|
-
if (!this.user) {
|
|
787
|
-
throw new NotAuthenticatedError();
|
|
788
|
-
}
|
|
789
|
-
|
|
790
|
-
const stampedRequest = await this.turnkeyClient.stampSignRawPayload({
|
|
791
|
-
organizationId: this.user.orgId,
|
|
792
|
-
type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2",
|
|
793
|
-
timestampMs: Date.now().toString(),
|
|
794
|
-
parameters: {
|
|
795
|
-
encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
|
|
796
|
-
hashFunction: "HASH_FUNCTION_NO_OP",
|
|
797
|
-
payload: MFA_PAYLOAD.VERIFY,
|
|
798
|
-
signWith: this.user.address,
|
|
799
|
-
},
|
|
800
|
-
});
|
|
801
|
-
|
|
802
|
-
return this.request("/v1/auth-verify-multi-factor", {
|
|
803
|
-
stampedRequest,
|
|
804
|
-
multiFactorId: params.multiFactorId,
|
|
805
|
-
multiFactorCode: params.multiFactorCode,
|
|
806
|
-
});
|
|
807
|
-
};
|
|
808
|
-
|
|
809
|
-
/**
|
|
810
|
-
* Removes existing MFA factors by ID.
|
|
811
|
-
*
|
|
812
|
-
* @param {RemoveMfaParams} params The parameters specifying which factors to disable
|
|
813
|
-
* @returns {Promise<{ multiFactors: MfaFactor[] }>} A promise that resolves to the updated list of MFA factors
|
|
814
|
-
* @throws {NotAuthenticatedError} If no user is authenticated
|
|
815
|
-
*/
|
|
816
|
-
public override removeMfa = async (
|
|
817
|
-
params: RemoveMfaParams
|
|
818
|
-
): Promise<{ multiFactors: MfaFactor[] }> => {
|
|
819
|
-
if (!this.user) {
|
|
820
|
-
throw new NotAuthenticatedError();
|
|
821
|
-
}
|
|
822
|
-
|
|
823
|
-
const stampedRequest = await this.turnkeyClient.stampSignRawPayload({
|
|
824
|
-
organizationId: this.user.orgId,
|
|
825
|
-
type: "ACTIVITY_TYPE_SIGN_RAW_PAYLOAD_V2",
|
|
826
|
-
timestampMs: Date.now().toString(),
|
|
827
|
-
parameters: {
|
|
828
|
-
encoding: "PAYLOAD_ENCODING_HEXADECIMAL",
|
|
829
|
-
hashFunction: "HASH_FUNCTION_NO_OP",
|
|
830
|
-
payload: MFA_PAYLOAD.DELETE,
|
|
831
|
-
signWith: this.user.address,
|
|
832
|
-
},
|
|
833
|
-
});
|
|
834
|
-
|
|
835
|
-
return this.request("/v1/auth-delete-multi-factors", {
|
|
836
|
-
stampedRequest,
|
|
837
|
-
multiFactorIds: params.multiFactorIds,
|
|
838
|
-
});
|
|
839
|
-
};
|
|
840
673
|
}
|
|
841
674
|
|
|
842
675
|
/**
|