@arcblock/did-connect-js 1.29.23 → 4.0.0-beta.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/{lib/adapters/detect.d.cts → dist/adapters/detect.d.ts} +3 -5
- package/dist/adapters/detect.d.ts.map +1 -0
- package/dist/adapters/detect.js +13 -0
- package/dist/adapters/detect.js.map +1 -0
- package/dist/adapters/express.d.ts +40 -0
- package/dist/adapters/express.d.ts.map +1 -0
- package/dist/adapters/express.js +30 -0
- package/dist/adapters/express.js.map +1 -0
- package/dist/adapters/hono.d.ts +49 -0
- package/dist/adapters/hono.d.ts.map +1 -0
- package/dist/adapters/hono.js +176 -0
- package/dist/adapters/hono.js.map +1 -0
- package/dist/authenticator/base.d.ts +21 -0
- package/dist/authenticator/base.d.ts.map +1 -0
- package/dist/authenticator/base.js +109 -0
- package/dist/authenticator/base.js.map +1 -0
- package/dist/authenticator/wallet.d.ts +221 -0
- package/dist/authenticator/wallet.d.ts.map +1 -0
- package/dist/authenticator/wallet.js +588 -0
- package/dist/authenticator/wallet.js.map +1 -0
- package/dist/handlers/base.d.ts +25 -0
- package/dist/handlers/base.d.ts.map +1 -0
- package/dist/handlers/base.js +48 -0
- package/dist/handlers/base.js.map +1 -0
- package/dist/handlers/util.d.ts +48 -0
- package/dist/handlers/util.d.ts.map +1 -0
- package/dist/handlers/util.js +812 -0
- package/dist/handlers/util.js.map +1 -0
- package/dist/handlers/wallet.d.ts +96 -0
- package/dist/handlers/wallet.d.ts.map +1 -0
- package/dist/handlers/wallet.js +129 -0
- package/dist/handlers/wallet.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/protocol.d.ts +14 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +37 -0
- package/dist/protocol.js.map +1 -0
- package/dist/schema/claims.d.ts +17 -0
- package/dist/schema/claims.d.ts.map +1 -0
- package/dist/schema/claims.js +205 -0
- package/dist/schema/claims.js.map +1 -0
- package/dist/schema/index.d.ts +7 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +49 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/storage/kv.d.ts +31 -0
- package/dist/storage/kv.d.ts.map +1 -0
- package/dist/storage/kv.js +54 -0
- package/dist/storage/kv.js.map +1 -0
- package/dist/types.d.ts +53 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +48 -104
- package/LICENSE +0 -13
- package/README.md +0 -210
- package/esm/_virtual/rolldown_runtime.mjs +0 -8
- package/esm/adapters/detect.d.mts +0 -11
- package/esm/adapters/detect.mjs +0 -16
- package/esm/adapters/express.d.mts +0 -48
- package/esm/adapters/express.mjs +0 -39
- package/esm/adapters/hono.d.mts +0 -57
- package/esm/adapters/hono.mjs +0 -164
- package/esm/authenticator/base.d.mts +0 -23
- package/esm/authenticator/base.mjs +0 -88
- package/esm/authenticator/wallet.d.mts +0 -270
- package/esm/authenticator/wallet.mjs +0 -556
- package/esm/handlers/base.d.mts +0 -32
- package/esm/handlers/base.mjs +0 -37
- package/esm/handlers/util.d.mts +0 -70
- package/esm/handlers/util.mjs +0 -739
- package/esm/handlers/wallet.d.mts +0 -120
- package/esm/handlers/wallet.mjs +0 -139
- package/esm/index.d.mts +0 -8
- package/esm/index.mjs +0 -8
- package/esm/package.mjs +0 -118
- package/esm/protocol.d.mts +0 -15
- package/esm/protocol.mjs +0 -40
- package/esm/schema/claims.d.mts +0 -18
- package/esm/schema/claims.mjs +0 -154
- package/esm/schema/index.d.mts +0 -9
- package/esm/schema/index.mjs +0 -49
- package/esm/storage/kv.d.mts +0 -33
- package/esm/storage/kv.mjs +0 -55
- package/esm/types.d.mts +0 -55
- package/esm/types.mjs +0 -1
- package/lib/_virtual/rolldown_runtime.cjs +0 -31
- package/lib/adapters/detect.cjs +0 -18
- package/lib/adapters/express.cjs +0 -41
- package/lib/adapters/express.d.cts +0 -48
- package/lib/adapters/hono.cjs +0 -167
- package/lib/adapters/hono.d.cts +0 -57
- package/lib/authenticator/base.cjs +0 -91
- package/lib/authenticator/base.d.cts +0 -23
- package/lib/authenticator/wallet.cjs +0 -564
- package/lib/authenticator/wallet.d.cts +0 -270
- package/lib/handlers/base.cjs +0 -40
- package/lib/handlers/base.d.cts +0 -32
- package/lib/handlers/util.cjs +0 -759
- package/lib/handlers/util.d.cts +0 -70
- package/lib/handlers/wallet.cjs +0 -139
- package/lib/handlers/wallet.d.cts +0 -119
- package/lib/index.cjs +0 -16
- package/lib/index.d.cts +0 -8
- package/lib/package.cjs +0 -121
- package/lib/protocol.cjs +0 -46
- package/lib/protocol.d.cts +0 -15
- package/lib/schema/claims.cjs +0 -156
- package/lib/schema/claims.d.cts +0 -18
- package/lib/schema/index.cjs +0 -52
- package/lib/schema/index.d.cts +0 -9
- package/lib/storage/kv.cjs +0 -57
- package/lib/storage/kv.d.cts +0 -33
- package/lib/types.cjs +0 -0
- package/lib/types.d.cts +0 -55
package/esm/handlers/util.mjs
DELETED
|
@@ -1,739 +0,0 @@
|
|
|
1
|
-
import { __require } from "../_virtual/rolldown_runtime.mjs";
|
|
2
|
-
import { require_package } from "../package.mjs";
|
|
3
|
-
import { PROTECTED_KEYS, SESSION_STATUS, decrypt, encrypt } from "../protocol.mjs";
|
|
4
|
-
import { isValid } from "@arcblock/did";
|
|
5
|
-
import { fromBase64, stripHexPrefix, toBase64 } from "@ocap/util";
|
|
6
|
-
import isEqual from "lodash/isEqual.js";
|
|
7
|
-
import pick from "lodash/pick.js";
|
|
8
|
-
import random from "lodash/random.js";
|
|
9
|
-
import * as Mcrypto from "@ocap/mcrypto";
|
|
10
|
-
import omit from "lodash/omit.js";
|
|
11
|
-
import url from "url";
|
|
12
|
-
import stringify from "json-stable-stringify";
|
|
13
|
-
import cloneDeep from "lodash/cloneDeep.js";
|
|
14
|
-
import get from "lodash/get.js";
|
|
15
|
-
import isPlainObject from "lodash/isPlainObject.js";
|
|
16
|
-
import set from "lodash/set.js";
|
|
17
|
-
import SealedBox from "tweetnacl-sealedbox-js";
|
|
18
|
-
|
|
19
|
-
//#region src/handlers/util.ts
|
|
20
|
-
const ABSOLUTE_URL_REGEX = /^[a-zA-Z][a-zA-Z\d+\-.]*?:/;
|
|
21
|
-
const WINDOWS_PATH_REGEX = /^[a-zA-Z]:\\/;
|
|
22
|
-
const isUrl = (input) => {
|
|
23
|
-
if (typeof input !== "string") return false;
|
|
24
|
-
if (WINDOWS_PATH_REGEX.test(input)) return false;
|
|
25
|
-
return ABSOLUTE_URL_REGEX.test(input);
|
|
26
|
-
};
|
|
27
|
-
__require("debug")(`${require_package().name}:handlers:util`);
|
|
28
|
-
const sha3 = Mcrypto.Hasher.SHA3.hash256;
|
|
29
|
-
const getLocale = (req) => (req.acceptsLanguages("en-US", "zh-CN") || "en-US").split("-").shift();
|
|
30
|
-
const getSessionId = () => Date.now().toString();
|
|
31
|
-
const noop = () => ({});
|
|
32
|
-
const noTouch = (x) => x;
|
|
33
|
-
const errors = {
|
|
34
|
-
tokenMissing: {
|
|
35
|
-
en: "Session Id is required to check status",
|
|
36
|
-
zh: "缺少会话 ID 参数"
|
|
37
|
-
},
|
|
38
|
-
didMismatch: {
|
|
39
|
-
en: "Login user and wallet user mismatch, please relogin and try again",
|
|
40
|
-
zh: "登录用户和扫码用户不匹配,为保障安全,请重新登录应用"
|
|
41
|
-
},
|
|
42
|
-
mfaMismatch: {
|
|
43
|
-
en: "Dynamic verification code mismatch, please try again later",
|
|
44
|
-
zh: "动态验证码不匹配,请重试"
|
|
45
|
-
},
|
|
46
|
-
challengeMismatch: {
|
|
47
|
-
en: "Challenge mismatch",
|
|
48
|
-
zh: "随机校验码不匹配"
|
|
49
|
-
},
|
|
50
|
-
token404: {
|
|
51
|
-
en: "Session not found or expired",
|
|
52
|
-
zh: "会话不存在或已过期"
|
|
53
|
-
},
|
|
54
|
-
didMissing: {
|
|
55
|
-
en: "userDid is required to start auth",
|
|
56
|
-
zh: "userDid 参数缺失,请勿尝试连接多个不同的钱包"
|
|
57
|
-
},
|
|
58
|
-
pkMissing: {
|
|
59
|
-
en: "userPk is required to start auth",
|
|
60
|
-
zh: "userPk 参数缺失,请勿尝试连接多个不同的钱包"
|
|
61
|
-
},
|
|
62
|
-
authClaim: {
|
|
63
|
-
en: "authPrincipal claim is not configured correctly",
|
|
64
|
-
zh: "authPrincipal 声明配置不正确"
|
|
65
|
-
},
|
|
66
|
-
userDeclined: {
|
|
67
|
-
en: "You have declined the authentication request",
|
|
68
|
-
zh: "授权请求被拒绝"
|
|
69
|
-
},
|
|
70
|
-
userBusy: {
|
|
71
|
-
en: "Busy processing another DID Connect request",
|
|
72
|
-
zh: "正在处理其他请求"
|
|
73
|
-
}
|
|
74
|
-
};
|
|
75
|
-
const preparePathname = (path, req) => {
|
|
76
|
-
const delimiter = path.replace(/\/retrieve$/, "").replace(/\/auth$/, "");
|
|
77
|
-
const [prefix] = url.parse(req.originalUrl).pathname.split(delimiter);
|
|
78
|
-
return [prefix, path].join("/").replace(/\/+/g, "/");
|
|
79
|
-
};
|
|
80
|
-
const getBaseUrl = (req) => {
|
|
81
|
-
if (req.headers["x-path-prefix"]) return `/${req.headers["x-path-prefix"]}/`.replace(/\/+/g, "/");
|
|
82
|
-
return "/";
|
|
83
|
-
};
|
|
84
|
-
const prepareBaseUrl = (req, params) => {
|
|
85
|
-
const pathPrefix = getBaseUrl(req).replace(/\/$/, "");
|
|
86
|
-
const [hostname = "", port = 80] = (req.get("x-forwarded-host") || req.get("x-real-hostname") || req.get("host") || "").split(":");
|
|
87
|
-
const finalPort = get(params, "x-real-port", null) || req.get("X-Real-Port") || port || "";
|
|
88
|
-
return url.format({
|
|
89
|
-
protocol: get(params, "x-real-protocol") || req.get("X-Real-protocol") || req.get("X-Forwarded-Proto") || req.protocol,
|
|
90
|
-
hostname,
|
|
91
|
-
port: Number(finalPort) === 80 ? "" : finalPort,
|
|
92
|
-
pathname: pathPrefix
|
|
93
|
-
});
|
|
94
|
-
};
|
|
95
|
-
const unescape = (str) => (str + "===".slice((str.length + 3) % 4)).replace(/-/g, "+").replace(/_/g, "/");
|
|
96
|
-
const decodeEncKey = (str) => new Uint8Array(Buffer.from(unescape(str), "base64"));
|
|
97
|
-
const getStepChallenge = () => stripHexPrefix(Mcrypto.getRandomBytes(16)).toUpperCase();
|
|
98
|
-
const parseWalletUA = (userAgent) => {
|
|
99
|
-
const ua = (userAgent || "").toString().toLowerCase();
|
|
100
|
-
let os = "";
|
|
101
|
-
let version = "";
|
|
102
|
-
if (ua.indexOf("android") > -1) os = "android";
|
|
103
|
-
else if (ua.indexOf("iphone") > -1) os = "ios";
|
|
104
|
-
else if (ua.indexOf("ipad") > -1) os = "ios";
|
|
105
|
-
else if (ua.indexOf("ipod") > -1) os = "ios";
|
|
106
|
-
else if (ua.indexOf("arcwallet") === 0) os = "web";
|
|
107
|
-
else if (ua.indexOf("abtwallet") === 0) os = "web";
|
|
108
|
-
const match = ua.split(/\s+/).find((x) => x.startsWith("arcwallet/") || x.startsWith("abtwallet/"));
|
|
109
|
-
if (match) {
|
|
110
|
-
const tmp = match.split("/");
|
|
111
|
-
const coerced = tmp.length > 1 ? (tmp[1].match(/(\d+\.\d+\.\d+)/) || [])[1] : void 0;
|
|
112
|
-
if (coerced) version = coerced;
|
|
113
|
-
}
|
|
114
|
-
return {
|
|
115
|
-
os,
|
|
116
|
-
version,
|
|
117
|
-
jwt: "1.1.0"
|
|
118
|
-
};
|
|
119
|
-
};
|
|
120
|
-
const isDeepLink = (str) => str.startsWith("https://abtwallet.io/i/") || str.startsWith("https://didwallet.io/i/");
|
|
121
|
-
const isConnectedOnly = (params, sessionUserDid = "") => {
|
|
122
|
-
if (typeof params.forceConnected === "string" && isValid(params.forceConnected)) return params.forceConnected;
|
|
123
|
-
if (!sessionUserDid) return false;
|
|
124
|
-
if (isValid(sessionUserDid) === false) return false;
|
|
125
|
-
if (params.connectedDid !== sessionUserDid) return false;
|
|
126
|
-
if (typeof params.forceConnected === "undefined") return true;
|
|
127
|
-
if (typeof params.forceConnected === "string") try {
|
|
128
|
-
return !!JSON.parse(params.forceConnected);
|
|
129
|
-
} catch {
|
|
130
|
-
return false;
|
|
131
|
-
}
|
|
132
|
-
return !!params.forceConnected;
|
|
133
|
-
};
|
|
134
|
-
function createHandlers({ action, pathname, claims, onStart, onConnect, onAuth, onDecline, onComplete, onExpire, onError, pathTransformer, tokenStorage, authenticator, authPrincipal, persistentDynamicClaims = false, getSignParams = noop, getPathName = noTouch, options }) {
|
|
135
|
-
const { tokenKey, encKey, versionKey, cleanupDelay } = options;
|
|
136
|
-
const defaultSteps = (Array.isArray(claims) ? claims : [claims]).filter(Boolean);
|
|
137
|
-
if (defaultSteps.length > 0) {
|
|
138
|
-
const keys = Object.keys(defaultSteps[0]);
|
|
139
|
-
const firstClaim = defaultSteps[0][keys[0]];
|
|
140
|
-
if (Array.isArray(firstClaim)) {
|
|
141
|
-
if (firstClaim[0] === "authPrincipal") authPrincipal = false;
|
|
142
|
-
} else if (keys[0] === "authPrincipal") authPrincipal = false;
|
|
143
|
-
}
|
|
144
|
-
if (authPrincipal) {
|
|
145
|
-
let target = "";
|
|
146
|
-
let description = "Please continue with your account";
|
|
147
|
-
let chainInfo;
|
|
148
|
-
let targetType;
|
|
149
|
-
if (typeof authPrincipal === "string") if (isValid(authPrincipal)) target = authPrincipal;
|
|
150
|
-
else description = authPrincipal;
|
|
151
|
-
if (typeof authPrincipal === "object") {
|
|
152
|
-
target = get(authPrincipal, "target", target);
|
|
153
|
-
description = get(authPrincipal, "description", description);
|
|
154
|
-
targetType = get(authPrincipal, "targetType", targetType);
|
|
155
|
-
if (authPrincipal.chainInfo && authenticator._isValidChainInfo(authPrincipal.chainInfo)) chainInfo = authPrincipal.chainInfo;
|
|
156
|
-
}
|
|
157
|
-
const supervised = defaultSteps.length === 0;
|
|
158
|
-
defaultSteps.unshift({ authPrincipal: {
|
|
159
|
-
skippable: true,
|
|
160
|
-
description,
|
|
161
|
-
target,
|
|
162
|
-
chainInfo,
|
|
163
|
-
targetType,
|
|
164
|
-
supervised
|
|
165
|
-
} });
|
|
166
|
-
}
|
|
167
|
-
const canSkipConnect = defaultSteps[0]?.authPrincipal?.skippable;
|
|
168
|
-
const createExtraParams = (locale, params, extra = {}) => {
|
|
169
|
-
const finalParams = {
|
|
170
|
-
...params,
|
|
171
|
-
...extra || {}
|
|
172
|
-
};
|
|
173
|
-
return {
|
|
174
|
-
locale,
|
|
175
|
-
action,
|
|
176
|
-
...Object.keys(finalParams).filter((x) => ![
|
|
177
|
-
"userDid",
|
|
178
|
-
"userInfo",
|
|
179
|
-
"userSession",
|
|
180
|
-
"appSession",
|
|
181
|
-
"userPk",
|
|
182
|
-
"token"
|
|
183
|
-
].includes(x)).reduce((obj, x) => {
|
|
184
|
-
obj[x] = finalParams[x];
|
|
185
|
-
return obj;
|
|
186
|
-
}, {})
|
|
187
|
-
};
|
|
188
|
-
};
|
|
189
|
-
const createSessionUpdater = (token, params) => async (key, value, secure = false) => {
|
|
190
|
-
const getUpdate = (k, v) => {
|
|
191
|
-
if (secure && params[encKey]) {
|
|
192
|
-
const encrypted = SealedBox.seal(Buffer.from(stringify(v)), decodeEncKey(params[encKey]));
|
|
193
|
-
return { [k]: Buffer.from(encrypted).toString("base64") };
|
|
194
|
-
}
|
|
195
|
-
return { [k]: v };
|
|
196
|
-
};
|
|
197
|
-
if (typeof key === "object") {
|
|
198
|
-
secure = value;
|
|
199
|
-
const keys = Object.keys(key);
|
|
200
|
-
const updates = Object.assign({}, ...keys.map((k) => getUpdate(k, key[k])));
|
|
201
|
-
return tokenStorage.update(token, updates);
|
|
202
|
-
}
|
|
203
|
-
return tokenStorage.update(token, omit(getUpdate(key, value), PROTECTED_KEYS));
|
|
204
|
-
};
|
|
205
|
-
const createMfaCodeGenerator = (token) => async () => {
|
|
206
|
-
const mfaCode = random(10, 99);
|
|
207
|
-
await tokenStorage.update(token, { mfaCode });
|
|
208
|
-
return mfaCode;
|
|
209
|
-
};
|
|
210
|
-
const onProcessError = ({ req, res, stage, err }) => {
|
|
211
|
-
const { token, store } = req.context || {};
|
|
212
|
-
if (token) tokenStorage.update(token, {
|
|
213
|
-
status: SESSION_STATUS.ERROR,
|
|
214
|
-
error: err.message,
|
|
215
|
-
mfaCode: 0
|
|
216
|
-
});
|
|
217
|
-
res.jsonp({ error: err.message });
|
|
218
|
-
onError({
|
|
219
|
-
token,
|
|
220
|
-
extraParams: get(store, "extraParams", {}),
|
|
221
|
-
stage,
|
|
222
|
-
err
|
|
223
|
-
});
|
|
224
|
-
};
|
|
225
|
-
const _preparePathname = (str, req) => {
|
|
226
|
-
return pathTransformer(preparePathname(str, req));
|
|
227
|
-
};
|
|
228
|
-
const generateSession = async (req, res) => {
|
|
229
|
-
try {
|
|
230
|
-
const params = {
|
|
231
|
-
"x-real-port": req.get("x-real-port"),
|
|
232
|
-
"x-real-protocol": req.get("x-real-protocol"),
|
|
233
|
-
deviceDid: req.get("x-device-did"),
|
|
234
|
-
connectedDid: get(req, "cookies.connected_did", ""),
|
|
235
|
-
connectedPk: get(req, "cookies.connected_pk", ""),
|
|
236
|
-
...req.body,
|
|
237
|
-
...req.query,
|
|
238
|
-
...req.params
|
|
239
|
-
};
|
|
240
|
-
params.forceConnected = isConnectedOnly(params, req.get("x-user-did"));
|
|
241
|
-
const token = sha3(getSessionId()).replace(/^0x/, "").slice(0, 8);
|
|
242
|
-
await tokenStorage.create(token, SESSION_STATUS.CREATED);
|
|
243
|
-
let sourceToken = params.sourceToken || "";
|
|
244
|
-
const sourceTokenState = sourceToken ? await tokenStorage.read(sourceToken) : null;
|
|
245
|
-
if (sourceTokenState) if ([SESSION_STATUS.SUCCEED].includes(sourceTokenState.status)) sourceToken = "";
|
|
246
|
-
else await tokenStorage.update(sourceToken, { destToken: token });
|
|
247
|
-
const finalPath = _preparePathname(getPathName(pathname, req), req);
|
|
248
|
-
const baseUrl = prepareBaseUrl(req, params);
|
|
249
|
-
const uri = await authenticator.uri({
|
|
250
|
-
token,
|
|
251
|
-
pathname: finalPath,
|
|
252
|
-
baseUrl,
|
|
253
|
-
query: {}
|
|
254
|
-
});
|
|
255
|
-
const challenge = getStepChallenge();
|
|
256
|
-
const didwallet = parseWalletUA(req.query["user-agent"] || req.headers["user-agent"]);
|
|
257
|
-
const extraParams = createExtraParams(getLocale(req), params);
|
|
258
|
-
const hookParams = {
|
|
259
|
-
req,
|
|
260
|
-
request: req,
|
|
261
|
-
challenge,
|
|
262
|
-
baseUrl,
|
|
263
|
-
deepLink: uri,
|
|
264
|
-
extraParams,
|
|
265
|
-
updateSession: createSessionUpdater(token, extraParams),
|
|
266
|
-
didwallet
|
|
267
|
-
};
|
|
268
|
-
const [wallet, delegator] = await Promise.all([authenticator.getWalletInfo({
|
|
269
|
-
baseUrl,
|
|
270
|
-
request: req,
|
|
271
|
-
extraParams
|
|
272
|
-
}), authenticator.getDelegator({
|
|
273
|
-
baseUrl,
|
|
274
|
-
request: req,
|
|
275
|
-
extraParams
|
|
276
|
-
})]);
|
|
277
|
-
const [appInfo, memberAppInfo] = await Promise.all([authenticator.getAppInfo({
|
|
278
|
-
baseUrl,
|
|
279
|
-
request: req,
|
|
280
|
-
wallet,
|
|
281
|
-
delegator,
|
|
282
|
-
extraParams
|
|
283
|
-
}, "appInfo"), authenticator.getAppInfo({
|
|
284
|
-
baseUrl,
|
|
285
|
-
request: req,
|
|
286
|
-
wallet,
|
|
287
|
-
delegator,
|
|
288
|
-
extraParams
|
|
289
|
-
}, "memberAppInfo")]);
|
|
290
|
-
await tokenStorage.update(token, {
|
|
291
|
-
currentStep: 0,
|
|
292
|
-
mfaSupported: !didwallet.os,
|
|
293
|
-
challenge,
|
|
294
|
-
sharedKey: getStepChallenge(),
|
|
295
|
-
extraParams: params,
|
|
296
|
-
appInfo,
|
|
297
|
-
memberAppInfo,
|
|
298
|
-
sourceToken
|
|
299
|
-
});
|
|
300
|
-
const extra = await onStart(hookParams);
|
|
301
|
-
res.jsonp({
|
|
302
|
-
token,
|
|
303
|
-
status: SESSION_STATUS.CREATED,
|
|
304
|
-
url: uri,
|
|
305
|
-
appInfo,
|
|
306
|
-
memberAppInfo,
|
|
307
|
-
extra: extra || {}
|
|
308
|
-
});
|
|
309
|
-
} catch (err) {
|
|
310
|
-
onProcessError({
|
|
311
|
-
req,
|
|
312
|
-
res,
|
|
313
|
-
stage: "generate-token",
|
|
314
|
-
err
|
|
315
|
-
});
|
|
316
|
-
}
|
|
317
|
-
};
|
|
318
|
-
const checkSession = async (req, res) => {
|
|
319
|
-
try {
|
|
320
|
-
const { locale, token, store, params } = req.context;
|
|
321
|
-
if (!token) {
|
|
322
|
-
res.status(400).json({ error: errors.tokenMissing[locale] });
|
|
323
|
-
return;
|
|
324
|
-
}
|
|
325
|
-
if (!store) {
|
|
326
|
-
res.status(400).json({ error: errors.token404[locale] });
|
|
327
|
-
return;
|
|
328
|
-
}
|
|
329
|
-
if (store.status === SESSION_STATUS.FORBIDDEN) {
|
|
330
|
-
res.status(403).json({ error: errors.didMismatch[locale] });
|
|
331
|
-
return;
|
|
332
|
-
}
|
|
333
|
-
if (store.status === SESSION_STATUS.SUCCEED) {
|
|
334
|
-
setTimeout(() => {
|
|
335
|
-
tokenStorage.delete(token).catch(console.error);
|
|
336
|
-
}, cleanupDelay);
|
|
337
|
-
const extraParams = createExtraParams(locale, params, get(store, "extraParams", {}));
|
|
338
|
-
await onComplete({
|
|
339
|
-
req,
|
|
340
|
-
request: req,
|
|
341
|
-
userDid: store.did,
|
|
342
|
-
userPk: store.pk,
|
|
343
|
-
extraParams,
|
|
344
|
-
updateSession: createSessionUpdater(token, extraParams)
|
|
345
|
-
});
|
|
346
|
-
}
|
|
347
|
-
res.status(200).json(Object.keys(store).filter((x) => PROTECTED_KEYS.includes(x) === false).reduce((acc, key) => {
|
|
348
|
-
acc[key] = store[key];
|
|
349
|
-
return acc;
|
|
350
|
-
}, {}));
|
|
351
|
-
} catch (err) {
|
|
352
|
-
onProcessError({
|
|
353
|
-
req,
|
|
354
|
-
res,
|
|
355
|
-
stage: "check-token-status",
|
|
356
|
-
err
|
|
357
|
-
});
|
|
358
|
-
}
|
|
359
|
-
};
|
|
360
|
-
const expireSession = async (req, res) => {
|
|
361
|
-
try {
|
|
362
|
-
const { locale, token, store } = req.context;
|
|
363
|
-
if (!token) {
|
|
364
|
-
res.status(400).json({ error: errors.tokenMissing[locale] });
|
|
365
|
-
return;
|
|
366
|
-
}
|
|
367
|
-
if (!store) {
|
|
368
|
-
res.status(400).json({ error: errors.token404[locale] });
|
|
369
|
-
return;
|
|
370
|
-
}
|
|
371
|
-
onExpire({
|
|
372
|
-
token,
|
|
373
|
-
extraParams: get(store, "extraParams", {}),
|
|
374
|
-
status: "expired"
|
|
375
|
-
});
|
|
376
|
-
if (store.status !== SESSION_STATUS.SCANNED) await tokenStorage.delete(token);
|
|
377
|
-
res.status(200).json({ token });
|
|
378
|
-
} catch (err) {
|
|
379
|
-
onProcessError({
|
|
380
|
-
req,
|
|
381
|
-
res,
|
|
382
|
-
stage: "mark-token-timeout",
|
|
383
|
-
err
|
|
384
|
-
});
|
|
385
|
-
}
|
|
386
|
-
};
|
|
387
|
-
const checkUser = async ({ context, userDid, userPk }) => {
|
|
388
|
-
const { locale, token, store } = context;
|
|
389
|
-
if (store.currentStep > 0) {
|
|
390
|
-
if (!userDid) return errors.didMissing[locale];
|
|
391
|
-
if (!userPk) return errors.pkMissing[locale];
|
|
392
|
-
if (userDid !== store.did) {
|
|
393
|
-
await tokenStorage.update(token, { status: SESSION_STATUS.FORBIDDEN });
|
|
394
|
-
return errors.didMismatch[locale];
|
|
395
|
-
}
|
|
396
|
-
}
|
|
397
|
-
return false;
|
|
398
|
-
};
|
|
399
|
-
const onAuthRequest = async (req, res) => {
|
|
400
|
-
const { locale, token, store, params, didwallet } = req.context;
|
|
401
|
-
const extraParams = createExtraParams(locale, params, get(store, "extraParams", {}));
|
|
402
|
-
const userDid = params.userDid || store.did || extraParams.connectedDid;
|
|
403
|
-
const userPk = params.userPk || store.pk || extraParams.connectedPk;
|
|
404
|
-
const error = await checkUser({
|
|
405
|
-
context: req.context,
|
|
406
|
-
userDid,
|
|
407
|
-
userPk
|
|
408
|
-
});
|
|
409
|
-
if (error) return res.jsonp({ error });
|
|
410
|
-
if (params[versionKey] && store.clientVersion !== params[versionKey]) {
|
|
411
|
-
store.clientVersion = params[versionKey];
|
|
412
|
-
store.encryptionKey = params[encKey];
|
|
413
|
-
await tokenStorage.update(token, {
|
|
414
|
-
clientVersion: params[versionKey],
|
|
415
|
-
encryptionKey: params[encKey]
|
|
416
|
-
});
|
|
417
|
-
}
|
|
418
|
-
try {
|
|
419
|
-
const steps = [...cloneDeep(defaultSteps)];
|
|
420
|
-
const shouldSkipConnect = canSkipConnect && !!extraParams.connectedDid;
|
|
421
|
-
if (shouldSkipConnect) set(steps, "[0].authPrincipal.supervised", false);
|
|
422
|
-
if (extraParams.forceConnected) {
|
|
423
|
-
let target = extraParams.connectedDid;
|
|
424
|
-
if (typeof extraParams.forceConnected === "string" && isValid(extraParams.forceConnected)) target = extraParams.forceConnected;
|
|
425
|
-
if (isValid(target)) set(steps, "[0].authPrincipal.target", target);
|
|
426
|
-
}
|
|
427
|
-
if (store.status !== SESSION_STATUS.SCANNED) await tokenStorage.update(token, {
|
|
428
|
-
status: SESSION_STATUS.SCANNED,
|
|
429
|
-
connectedWallet: didwallet
|
|
430
|
-
});
|
|
431
|
-
if (store.dynamic || shouldSkipConnect) {
|
|
432
|
-
const newClaims = await onConnect({
|
|
433
|
-
req,
|
|
434
|
-
request: req,
|
|
435
|
-
userDid,
|
|
436
|
-
userPk,
|
|
437
|
-
didwallet,
|
|
438
|
-
challenge: store.challenge,
|
|
439
|
-
pathname: _preparePathname(getPathName(pathname, req), req),
|
|
440
|
-
baseUrl: prepareBaseUrl(req, extraParams),
|
|
441
|
-
extraParams,
|
|
442
|
-
updateSession: createSessionUpdater(token, extraParams)
|
|
443
|
-
});
|
|
444
|
-
if (newClaims) if (Array.isArray(newClaims)) steps.push(...newClaims);
|
|
445
|
-
else steps.push(newClaims);
|
|
446
|
-
}
|
|
447
|
-
const signParams = await getSignParams(req);
|
|
448
|
-
const signedClaim = await authenticator.sign(Object.assign(signParams, {
|
|
449
|
-
context: {
|
|
450
|
-
token,
|
|
451
|
-
userDid,
|
|
452
|
-
userPk,
|
|
453
|
-
didwallet,
|
|
454
|
-
...pick(store, [
|
|
455
|
-
"currentStep",
|
|
456
|
-
"sharedKey",
|
|
457
|
-
"encryptionKey"
|
|
458
|
-
]),
|
|
459
|
-
mfaCode: store.mfaSupported ? createMfaCodeGenerator(token) : void 0
|
|
460
|
-
},
|
|
461
|
-
claims: steps[store.currentStep],
|
|
462
|
-
pathname: _preparePathname(getPathName(pathname, req), req),
|
|
463
|
-
baseUrl: prepareBaseUrl(req, extraParams),
|
|
464
|
-
extraParams,
|
|
465
|
-
challenge: store.challenge,
|
|
466
|
-
appInfo: store.appInfo,
|
|
467
|
-
memberAppInfo: store.memberAppInfo,
|
|
468
|
-
request: req
|
|
469
|
-
}));
|
|
470
|
-
res.jsonp(encrypt(signedClaim, store));
|
|
471
|
-
} catch (err) {
|
|
472
|
-
onProcessError({
|
|
473
|
-
req,
|
|
474
|
-
res,
|
|
475
|
-
stage: "send-auth-claim",
|
|
476
|
-
err
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
};
|
|
480
|
-
const onAuthResponse = async (req, res) => {
|
|
481
|
-
const { locale, token, store, params, didwallet } = req.context;
|
|
482
|
-
try {
|
|
483
|
-
const { userDid, userPk, action: userAction, challenge: userChallenge, claims: claimResponse, timestamp } = await authenticator.verify(decrypt(params, store), locale);
|
|
484
|
-
if (!store.did || !store.pk) await tokenStorage.update(token, {
|
|
485
|
-
did: userDid,
|
|
486
|
-
pk: userPk
|
|
487
|
-
});
|
|
488
|
-
const extraParams = createExtraParams(locale, params, get(store, "extraParams", {}));
|
|
489
|
-
const cbParams = {
|
|
490
|
-
step: store.currentStep,
|
|
491
|
-
req,
|
|
492
|
-
request: req,
|
|
493
|
-
userDid,
|
|
494
|
-
userPk,
|
|
495
|
-
challenge: store.challenge,
|
|
496
|
-
didwallet,
|
|
497
|
-
claims: claimResponse,
|
|
498
|
-
baseUrl: prepareBaseUrl(req, extraParams),
|
|
499
|
-
extraParams,
|
|
500
|
-
updateSession: createSessionUpdater(token, extraParams),
|
|
501
|
-
timestamp
|
|
502
|
-
};
|
|
503
|
-
const steps = [...defaultSteps];
|
|
504
|
-
const shouldSkipConnect = canSkipConnect && !!extraParams.connectedDid;
|
|
505
|
-
if (store.dynamic || shouldSkipConnect) {
|
|
506
|
-
const newClaims = await onConnect(cbParams);
|
|
507
|
-
if (newClaims) if (Array.isArray(newClaims)) steps.push(...newClaims);
|
|
508
|
-
else steps.push(newClaims);
|
|
509
|
-
} else if (persistentDynamicClaims && Array.isArray(store.dynamicClaims)) steps.push(...store.dynamicClaims);
|
|
510
|
-
if (userAction === "declineAuth") {
|
|
511
|
-
await tokenStorage.update(token, {
|
|
512
|
-
status: SESSION_STATUS.ERROR,
|
|
513
|
-
error: errors.userDeclined[locale],
|
|
514
|
-
mfaCode: 0,
|
|
515
|
-
currentStep: steps.length - 1
|
|
516
|
-
});
|
|
517
|
-
const result = await onDecline(cbParams);
|
|
518
|
-
return res.jsonp({ ...result || {} });
|
|
519
|
-
}
|
|
520
|
-
if (userAction === "busy") {
|
|
521
|
-
await tokenStorage.update(token, {
|
|
522
|
-
status: SESSION_STATUS.BUSY,
|
|
523
|
-
error: errors.userBusy[locale],
|
|
524
|
-
mfaCode: 0,
|
|
525
|
-
currentStep: steps.length - 1
|
|
526
|
-
});
|
|
527
|
-
return res.jsonp({});
|
|
528
|
-
}
|
|
529
|
-
if (store.mfaCode && !claimResponse.some((x) => isEqual(x.mfaCode, [store.mfaCode]))) return onProcessError({
|
|
530
|
-
req,
|
|
531
|
-
res,
|
|
532
|
-
stage: "verify-mfa-code",
|
|
533
|
-
err: new Error(errors.mfaMismatch[locale])
|
|
534
|
-
});
|
|
535
|
-
if (!userChallenge) return res.jsonp({ error: errors.challengeMismatch[locale] });
|
|
536
|
-
if (userChallenge !== store.challenge) return res.jsonp({ error: errors.challengeMismatch[locale] });
|
|
537
|
-
const error = await checkUser({
|
|
538
|
-
context: req.context,
|
|
539
|
-
userDid,
|
|
540
|
-
userPk
|
|
541
|
-
});
|
|
542
|
-
if (error) return res.jsonp({ error });
|
|
543
|
-
const isConnected = store.currentStep > 0;
|
|
544
|
-
if (isConnected === false) {
|
|
545
|
-
const newClaims = await onConnect(cbParams);
|
|
546
|
-
if (newClaims) {
|
|
547
|
-
await tokenStorage.update(token, {
|
|
548
|
-
dynamic: !persistentDynamicClaims,
|
|
549
|
-
dynamicClaims: persistentDynamicClaims ? newClaims : void 0
|
|
550
|
-
});
|
|
551
|
-
if (Array.isArray(newClaims)) steps.push(...newClaims);
|
|
552
|
-
else steps.push(newClaims);
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
const onLastStep = async (result) => {
|
|
556
|
-
let nextWorkflow = isUrl(extraParams.nw) ? extraParams.nw : "";
|
|
557
|
-
if (nextWorkflow && result && result.nextWorkflowData) {
|
|
558
|
-
if (isPlainObject(result.nextWorkflowData) === false) return onProcessError({
|
|
559
|
-
req,
|
|
560
|
-
res,
|
|
561
|
-
stage: "validate-next-workflow-data",
|
|
562
|
-
err: /* @__PURE__ */ new Error(`expect nextWorkflowData should be a plain object, got: ${result.nextWorkflowData}`)
|
|
563
|
-
});
|
|
564
|
-
const tmp = new URL(nextWorkflow);
|
|
565
|
-
const merged = Object.assign(extraParams.previousWorkflowData || {}, result.nextWorkflowData);
|
|
566
|
-
const previousWorkflowData = toBase64(JSON.stringify(merged));
|
|
567
|
-
if (previousWorkflowData.length > 8192) return onProcessError({
|
|
568
|
-
req,
|
|
569
|
-
res,
|
|
570
|
-
stage: "append-next-workflow",
|
|
571
|
-
err: /* @__PURE__ */ new Error("base64 encoded nextWorkflowData should be less than 8192 characters")
|
|
572
|
-
});
|
|
573
|
-
if (isDeepLink(nextWorkflow)) {
|
|
574
|
-
const actualUrl = decodeURIComponent(tmp.searchParams.get("url"));
|
|
575
|
-
const obj = new URL(actualUrl);
|
|
576
|
-
obj.searchParams.set("previousWorkflowData", previousWorkflowData);
|
|
577
|
-
tmp.searchParams.set("url", obj.href);
|
|
578
|
-
} else tmp.searchParams.set("previousWorkflowData", previousWorkflowData);
|
|
579
|
-
nextWorkflow = tmp.href;
|
|
580
|
-
}
|
|
581
|
-
const updates = {};
|
|
582
|
-
let actualNw = nextWorkflow || result?.nextWorkflow || "";
|
|
583
|
-
if (actualNw) {
|
|
584
|
-
if (isDeepLink(actualNw)) actualNw = new URL(actualNw).searchParams.get("url");
|
|
585
|
-
if (actualNw) updates.nextWorkflow = decodeURIComponent(actualNw);
|
|
586
|
-
}
|
|
587
|
-
if (result?.nextToken && result.nextWorkflow) try {
|
|
588
|
-
await tokenStorage.update(result.nextToken, { prevToken: token });
|
|
589
|
-
} catch (err) {
|
|
590
|
-
console.error("DIDAuth: failed to to update nextToken", err);
|
|
591
|
-
updates.status = SESSION_STATUS.SUCCEED;
|
|
592
|
-
}
|
|
593
|
-
else {
|
|
594
|
-
if (store.prevToken) try {
|
|
595
|
-
await tokenStorage.update(store.prevToken, { status: SESSION_STATUS.SUCCEED });
|
|
596
|
-
} catch (err) {
|
|
597
|
-
console.error("DIDAuth: failed to to update prevToken", err);
|
|
598
|
-
}
|
|
599
|
-
updates.status = SESSION_STATUS.SUCCEED;
|
|
600
|
-
}
|
|
601
|
-
await tokenStorage.update(token, updates);
|
|
602
|
-
return res.jsonp({ ...Object.assign({ nextWorkflow }, result || {}) });
|
|
603
|
-
};
|
|
604
|
-
if (steps.length === 1) return onLastStep(await onAuth(cbParams));
|
|
605
|
-
if (isConnected && store.currentStep < steps.length) {
|
|
606
|
-
const result = await onAuth(cbParams);
|
|
607
|
-
if (store.currentStep === steps.length - 1) return onLastStep(result);
|
|
608
|
-
}
|
|
609
|
-
const nextStep = store.currentStep + 1;
|
|
610
|
-
const nextChallenge = getStepChallenge();
|
|
611
|
-
await tokenStorage.update(token, {
|
|
612
|
-
currentStep: nextStep,
|
|
613
|
-
challenge: nextChallenge,
|
|
614
|
-
mfaCode: 0
|
|
615
|
-
});
|
|
616
|
-
const signParams = await getSignParams(req);
|
|
617
|
-
try {
|
|
618
|
-
const nextSignedClaim = await authenticator.sign(Object.assign(signParams, {
|
|
619
|
-
context: {
|
|
620
|
-
token,
|
|
621
|
-
userDid,
|
|
622
|
-
userPk,
|
|
623
|
-
didwallet,
|
|
624
|
-
...pick(store, [
|
|
625
|
-
"currentStep",
|
|
626
|
-
"sharedKey",
|
|
627
|
-
"encryptionKey"
|
|
628
|
-
]),
|
|
629
|
-
mfaCode: store.mfaSupported ? createMfaCodeGenerator(token) : void 0
|
|
630
|
-
},
|
|
631
|
-
claims: steps[nextStep],
|
|
632
|
-
pathname: _preparePathname(getPathName(pathname, req), req),
|
|
633
|
-
baseUrl: prepareBaseUrl(req, extraParams),
|
|
634
|
-
extraParams,
|
|
635
|
-
challenge: nextChallenge,
|
|
636
|
-
appInfo: store.appInfo,
|
|
637
|
-
memberAppInfo: store.memberAppInfo,
|
|
638
|
-
request: req
|
|
639
|
-
}));
|
|
640
|
-
return res.jsonp(encrypt(nextSignedClaim, store));
|
|
641
|
-
} catch (err) {
|
|
642
|
-
return onProcessError({
|
|
643
|
-
req,
|
|
644
|
-
res,
|
|
645
|
-
stage: "next-auth-claim",
|
|
646
|
-
err
|
|
647
|
-
});
|
|
648
|
-
}
|
|
649
|
-
} catch (err) {
|
|
650
|
-
onProcessError({
|
|
651
|
-
req,
|
|
652
|
-
res,
|
|
653
|
-
stage: "verify-auth-claim",
|
|
654
|
-
err
|
|
655
|
-
});
|
|
656
|
-
}
|
|
657
|
-
};
|
|
658
|
-
const ensureContext = async (req, _res, next) => {
|
|
659
|
-
const didwallet = parseWalletUA(req.query["user-agent"] || req.headers["user-agent"]);
|
|
660
|
-
const params = {
|
|
661
|
-
...req.body,
|
|
662
|
-
...req.query,
|
|
663
|
-
...req.params
|
|
664
|
-
};
|
|
665
|
-
const token = params[tokenKey];
|
|
666
|
-
const locale = getLocale(req);
|
|
667
|
-
let store = null;
|
|
668
|
-
if (token) {
|
|
669
|
-
store = await tokenStorage.read(token);
|
|
670
|
-
if (params.previousWorkflowData) try {
|
|
671
|
-
store.extraParams.previousWorkflowData = JSON.parse(fromBase64(params.previousWorkflowData).toString());
|
|
672
|
-
await tokenStorage.update(token, { extraParams: store.extraParams });
|
|
673
|
-
} catch (e) {
|
|
674
|
-
console.warn("Could not parse previousWorkflowData", params.previousWorkflowData, e);
|
|
675
|
-
}
|
|
676
|
-
if (store?.destToken && typeof params.notrace === "undefined") {
|
|
677
|
-
const result = await tokenStorage.read(store.destToken);
|
|
678
|
-
if (result) store = result;
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
req.context = {
|
|
682
|
-
locale,
|
|
683
|
-
token,
|
|
684
|
-
didwallet,
|
|
685
|
-
params,
|
|
686
|
-
store
|
|
687
|
-
};
|
|
688
|
-
return next();
|
|
689
|
-
};
|
|
690
|
-
const ensureSignedJson = (req, res, next) => {
|
|
691
|
-
if (req.ensureSignedJson === void 0) {
|
|
692
|
-
req.ensureSignedJson = true;
|
|
693
|
-
const originJsonp = res.jsonp;
|
|
694
|
-
res.jsonp = async (payload) => {
|
|
695
|
-
if (payload.appPk && payload.authInfo) return originJsonp.call(res, payload);
|
|
696
|
-
const data = payload.response ? { response: payload.response } : { response: payload };
|
|
697
|
-
const fields = [
|
|
698
|
-
"error",
|
|
699
|
-
"errorMessage",
|
|
700
|
-
"successMessage",
|
|
701
|
-
"nextWorkflow",
|
|
702
|
-
"nextUrl",
|
|
703
|
-
"cookies",
|
|
704
|
-
"storages"
|
|
705
|
-
];
|
|
706
|
-
fields.forEach((x) => {
|
|
707
|
-
if (payload[x]) data[x] = payload[x];
|
|
708
|
-
});
|
|
709
|
-
data.errorMessage = data.error || data.errorMessage || "";
|
|
710
|
-
if (typeof data.response === "object") data.response = omit(data.response, fields);
|
|
711
|
-
const token$1 = {
|
|
712
|
-
...req.body,
|
|
713
|
-
...req.query,
|
|
714
|
-
...req.params
|
|
715
|
-
}[tokenKey];
|
|
716
|
-
const store$1 = token$1 ? await tokenStorage.read(token$1) : null;
|
|
717
|
-
const extraParams = get(store$1, "extraParams", {});
|
|
718
|
-
const signedData = await authenticator.signResponse(data, prepareBaseUrl(req, extraParams), req, extraParams);
|
|
719
|
-
originJsonp.call(res, encrypt(signedData, store$1));
|
|
720
|
-
};
|
|
721
|
-
}
|
|
722
|
-
const { token, store, locale } = req.context;
|
|
723
|
-
if (!token || !store) return res.jsonp({ error: errors.token404[locale] });
|
|
724
|
-
next();
|
|
725
|
-
};
|
|
726
|
-
return {
|
|
727
|
-
generateSession,
|
|
728
|
-
expireSession,
|
|
729
|
-
checkSession,
|
|
730
|
-
onAuthRequest,
|
|
731
|
-
onAuthResponse,
|
|
732
|
-
ensureContext,
|
|
733
|
-
ensureSignedJson,
|
|
734
|
-
createExtraParams
|
|
735
|
-
};
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
//#endregion
|
|
739
|
-
export { createHandlers as default, errors, getStepChallenge, isConnectedOnly, isDeepLink, parseWalletUA, prepareBaseUrl, preparePathname };
|