@yongdall/user-cookie 0.6.0 → 0.6.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/package.json +4 -3
- package/yongdall/user.mjs +12 -83
- package/yongdall/user.mjs.map +1 -1
package/package.json
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yongdall/user-cookie",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.2",
|
|
4
4
|
"dependencies": {
|
|
5
|
-
"@yongdall/http": "^0.
|
|
6
|
-
"@yongdall/core": "^0.
|
|
5
|
+
"@yongdall/http": "^0.6.2",
|
|
6
|
+
"@yongdall/core": "^0.6.2",
|
|
7
|
+
"@yongdall/user-status-token": "^0.6.2"
|
|
7
8
|
}
|
|
8
9
|
}
|
package/yongdall/user.mjs
CHANGED
|
@@ -1,76 +1,17 @@
|
|
|
1
|
-
import { existUser
|
|
1
|
+
import { existUser } from "@yongdall/core";
|
|
2
|
+
import * as UserStatusToken from "@yongdall/user-status-token";
|
|
2
3
|
import { k99Context } from "@yongdall/http";
|
|
3
4
|
|
|
4
|
-
//#region plugins/user-cookie/yongdall/user.
|
|
5
|
-
/** @import { UserManager } from '@yongdall/core' */
|
|
5
|
+
//#region plugins/user-cookie/yongdall/user.mts
|
|
6
6
|
const userLoggedCookie = "user-logged-token";
|
|
7
7
|
const cookieTime = 1440 * 60 * 1e3;
|
|
8
|
-
/**
|
|
9
|
-
* 使用 HMAC-SHA256 对一个或多个值进行哈希,使用 salt 作为密钥。
|
|
10
|
-
* 输出为 base64url 格式。
|
|
11
|
-
*
|
|
12
|
-
* @param {string | ArrayBuffer | ArrayBufferView<ArrayBuffer>} salt
|
|
13
|
-
* @param {string | number} value
|
|
14
|
-
* @param {...(string | number)} values
|
|
15
|
-
* @returns {Promise<string>}
|
|
16
|
-
*/
|
|
17
|
-
async function hash(salt, value, ...values) {
|
|
18
|
-
/** @type {ArrayBuffer | ArrayBufferView<ArrayBuffer>} */
|
|
19
|
-
let keyBuffer;
|
|
20
|
-
if (salt instanceof ArrayBuffer || ArrayBuffer.isView(salt)) keyBuffer = salt;
|
|
21
|
-
else if (typeof salt === "string") keyBuffer = new TextEncoder().encode(salt);
|
|
22
|
-
else throw new Error("`salt` 参数必须为字符串或 Uint8Array");
|
|
23
|
-
const cryptoKey = await crypto.subtle.importKey("raw", keyBuffer, {
|
|
24
|
-
name: "HMAC",
|
|
25
|
-
hash: "SHA-256"
|
|
26
|
-
}, false, ["sign"]);
|
|
27
|
-
/** @type {string[]} */
|
|
28
|
-
let data = [];
|
|
29
|
-
if (typeof value === "number") data.push(String(value));
|
|
30
|
-
else if (typeof value === "string") data.push(JSON.stringify(value).slice(1, -1));
|
|
31
|
-
else throw new Error("`value` 参数必须为字符串或数字");
|
|
32
|
-
for (const v of values) if (typeof v === "number") data.push(String(v));
|
|
33
|
-
else if (typeof v === "string") data.push(JSON.stringify(v).slice(1, -1));
|
|
34
|
-
const messageBuffer = new TextEncoder().encode(data.join("\n"));
|
|
35
|
-
const signature = await crypto.subtle.sign("HMAC", cryptoKey, messageBuffer);
|
|
36
|
-
return btoa(String.fromCharCode(...new Uint8Array(signature))).replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
|
|
37
|
-
}
|
|
38
|
-
/**
|
|
39
|
-
*
|
|
40
|
-
* @param {string} cookie
|
|
41
|
-
* @returns {Promise<[string, boolean]?>}
|
|
42
|
-
*/
|
|
43
|
-
async function parseUserCookie(cookie) {
|
|
44
|
-
if (typeof cookie !== "string") return null;
|
|
45
|
-
const list = cookie.split(".");
|
|
46
|
-
if (list.length !== 3) return null;
|
|
47
|
-
const timestamp = Number(list[0]);
|
|
48
|
-
if (!Number.isSafeInteger(timestamp)) return null;
|
|
49
|
-
const time = Date.now() - timestamp;
|
|
50
|
-
if (time > cookieTime) return null;
|
|
51
|
-
if (await hash(await useSalt(), list[1], list[0]) !== list[2]) return null;
|
|
52
|
-
return [list[1], time > cookieTime * 2 / 3];
|
|
53
|
-
}
|
|
54
|
-
/**
|
|
55
|
-
*
|
|
56
|
-
* @param {string} user
|
|
57
|
-
* @returns {Promise<string>}
|
|
58
|
-
*/
|
|
59
|
-
async function toUserCookie(user) {
|
|
60
|
-
const timestamp = Date.now();
|
|
61
|
-
return [
|
|
62
|
-
timestamp,
|
|
63
|
-
user,
|
|
64
|
-
await hash(await useSalt(), user, timestamp)
|
|
65
|
-
].join(".");
|
|
66
|
-
}
|
|
67
|
-
/** @type {UserManager['get']} */
|
|
68
8
|
const get = async () => {
|
|
69
9
|
const ctx = k99Context();
|
|
70
10
|
if (!ctx) return null;
|
|
11
|
+
if (ctx.requestHeaders.get("X-Cookie-Auth")?.trim().toLowerCase() === "disabled") return null;
|
|
71
12
|
const cookie = ctx.cookies[userLoggedCookie];
|
|
72
13
|
if (!cookie) return null;
|
|
73
|
-
const userInfo = await
|
|
14
|
+
const userInfo = await UserStatusToken.parse(cookie, cookieTime);
|
|
74
15
|
if (!userInfo) {
|
|
75
16
|
ctx.clearCookie(userLoggedCookie, {
|
|
76
17
|
httpOnly: true,
|
|
@@ -78,47 +19,35 @@ const get = async () => {
|
|
|
78
19
|
});
|
|
79
20
|
return null;
|
|
80
21
|
}
|
|
81
|
-
const [userId,
|
|
22
|
+
const [userId, percent] = userInfo;
|
|
82
23
|
if (!existUser(userId)) return null;
|
|
83
|
-
if (
|
|
24
|
+
if (percent > 2 / 3) ctx.setCookie(userLoggedCookie, await UserStatusToken.create(userId), {
|
|
84
25
|
httpOnly: true,
|
|
85
26
|
path: "/"
|
|
86
27
|
});
|
|
87
28
|
return userId;
|
|
88
29
|
};
|
|
89
|
-
/**
|
|
90
|
-
*
|
|
91
|
-
* @param {string} userId
|
|
92
|
-
* @returns
|
|
93
|
-
*/
|
|
94
|
-
/** @type {UserManager['set']} */
|
|
95
30
|
const set = async (userId) => {
|
|
96
31
|
if (!userId) return null;
|
|
97
32
|
const ctx = k99Context();
|
|
98
33
|
if (!ctx) return null;
|
|
99
|
-
ctx.setCookie(userLoggedCookie, await
|
|
34
|
+
ctx.setCookie(userLoggedCookie, await UserStatusToken.create(userId), {
|
|
100
35
|
httpOnly: true,
|
|
101
36
|
path: "/"
|
|
102
37
|
});
|
|
103
|
-
return
|
|
38
|
+
return true;
|
|
104
39
|
};
|
|
105
|
-
/**
|
|
106
|
-
*
|
|
107
|
-
* @param {string} userId
|
|
108
|
-
* @returns
|
|
109
|
-
*/
|
|
110
|
-
/** @type {UserManager['login']} */
|
|
111
40
|
const login = async (userId) => {
|
|
112
41
|
if (!userId) return null;
|
|
113
42
|
const ctx = k99Context();
|
|
114
43
|
if (!ctx) return null;
|
|
115
|
-
ctx.
|
|
44
|
+
if (ctx.requestHeaders.get("X-Cookie-Auth")?.trim().toLowerCase() === "disabled") return null;
|
|
45
|
+
ctx.setCookie(userLoggedCookie, await UserStatusToken.create(userId), {
|
|
116
46
|
httpOnly: true,
|
|
117
47
|
path: "/"
|
|
118
48
|
});
|
|
119
|
-
return
|
|
49
|
+
return true;
|
|
120
50
|
};
|
|
121
|
-
/** @type {UserManager['exit']} */
|
|
122
51
|
const exit = () => {
|
|
123
52
|
const ctx = k99Context();
|
|
124
53
|
if (!ctx) return null;
|
package/yongdall/user.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user.mjs","names":[],"sources":["../../../plugins/user-cookie/yongdall/user.
|
|
1
|
+
{"version":3,"file":"user.mjs","names":[],"sources":["../../../plugins/user-cookie/yongdall/user.mts"],"sourcesContent":["import type { UserManager } from '@yongdall/core'\n\nimport { existUser } from '@yongdall/core';\nimport * as UserStatusToken from '@yongdall/user-status-token';\n\nimport { k99Context } from '@yongdall/http';\n\nconst userLoggedCookie = 'user-logged-token';\nconst cookieTime = 24 * 60 * 60 * 1000;\n\nexport const get: UserManager['get'] = async () => {\n\tconst ctx = k99Context();\n\tif (!ctx) { return null; }\n\tconst cookieAuth = ctx.requestHeaders.get('X-Cookie-Auth')?.trim().toLowerCase()\n\tif (cookieAuth === 'disabled') { return null; }\n\tconst cookie = ctx.cookies[userLoggedCookie];\n\tif (!cookie) { return null; }\n\tconst userInfo = await UserStatusToken.parse(cookie, cookieTime);\n\tif (!userInfo) { ctx.clearCookie(userLoggedCookie, { httpOnly: true, path: '/' }); return null; }\n\tconst [userId, percent] = userInfo;\n\tif (!existUser(userId)) { return null; }\n\tif (percent > 2 / 3) { ctx.setCookie(userLoggedCookie, await UserStatusToken.create(userId), { httpOnly: true, path: '/' }); }\n\treturn userId;\n};\n\nexport const set: UserManager['set'] = async (userId) => {\n\tif (!userId) { return null; }\n\tconst ctx = k99Context();\n\tif (!ctx) { return null; }\n\tctx.setCookie(userLoggedCookie, await UserStatusToken.create(userId), { httpOnly: true, path: '/' });\n\treturn true;\n};\n\nexport const login: UserManager['login'] = async (userId) => {\n\tif (!userId) { return null; }\n\tconst ctx = k99Context();\n\tif (!ctx) { return null; }\n\tconst cookieAuth = ctx.requestHeaders.get('X-Cookie-Auth')?.trim().toLowerCase()\n\tif (cookieAuth === 'disabled') { return null; }\n\tctx.setCookie(userLoggedCookie, await UserStatusToken.create(userId), { httpOnly: true, path: '/' });\n\treturn true;\n};\n\nexport const exit: UserManager['exit'] = () => {\n\tconst ctx = k99Context();\n\tif (!ctx) { return null; }\n\tctx.clearCookie(userLoggedCookie, { httpOnly: true, path: '/' });\n\treturn null;\n};\n"],"mappings":";;;;;AAOA,MAAM,mBAAmB;AACzB,MAAM,aAAa,OAAU,KAAK;AAElC,MAAa,MAA0B,YAAY;CAClD,MAAM,MAAM,YAAY;AACxB,KAAI,CAAC,IAAO,QAAO;AAEnB,KADmB,IAAI,eAAe,IAAI,gBAAgB,EAAE,MAAM,CAAC,aAAa,KAC7D,WAAc,QAAO;CACxC,MAAM,SAAS,IAAI,QAAQ;AAC3B,KAAI,CAAC,OAAU,QAAO;CACtB,MAAM,WAAW,MAAM,gBAAgB,MAAM,QAAQ,WAAW;AAChE,KAAI,CAAC,UAAU;AAAE,MAAI,YAAY,kBAAkB;GAAE,UAAU;GAAM,MAAM;GAAK,CAAC;AAAE,SAAO;;CAC1F,MAAM,CAAC,QAAQ,WAAW;AAC1B,KAAI,CAAC,UAAU,OAAO,CAAI,QAAO;AACjC,KAAI,UAAU,IAAI,EAAK,KAAI,UAAU,kBAAkB,MAAM,gBAAgB,OAAO,OAAO,EAAE;EAAE,UAAU;EAAM,MAAM;EAAK,CAAC;AAC3H,QAAO;;AAGR,MAAa,MAA0B,OAAO,WAAW;AACxD,KAAI,CAAC,OAAU,QAAO;CACtB,MAAM,MAAM,YAAY;AACxB,KAAI,CAAC,IAAO,QAAO;AACnB,KAAI,UAAU,kBAAkB,MAAM,gBAAgB,OAAO,OAAO,EAAE;EAAE,UAAU;EAAM,MAAM;EAAK,CAAC;AACpG,QAAO;;AAGR,MAAa,QAA8B,OAAO,WAAW;AAC5D,KAAI,CAAC,OAAU,QAAO;CACtB,MAAM,MAAM,YAAY;AACxB,KAAI,CAAC,IAAO,QAAO;AAEnB,KADmB,IAAI,eAAe,IAAI,gBAAgB,EAAE,MAAM,CAAC,aAAa,KAC7D,WAAc,QAAO;AACxC,KAAI,UAAU,kBAAkB,MAAM,gBAAgB,OAAO,OAAO,EAAE;EAAE,UAAU;EAAM,MAAM;EAAK,CAAC;AACpG,QAAO;;AAGR,MAAa,aAAkC;CAC9C,MAAM,MAAM,YAAY;AACxB,KAAI,CAAC,IAAO,QAAO;AACnB,KAAI,YAAY,kBAAkB;EAAE,UAAU;EAAM,MAAM;EAAK,CAAC;AAChE,QAAO"}
|