@yongdall/user 0.1.0 → 0.1.1
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/hooks.yongdall.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { a as verifyPassword, c as User_default, i as setPassword, l as UserAccount_default, r as loadUserInfo, s as UserPassword_default, t as findUser } from "./user-
|
|
1
|
+
import { a as verifyPassword, c as User_default, i as setPassword, l as UserAccount_default, r as loadUserInfo, s as UserPassword_default, t as findUser } from "./user-DMOZK_4C.mjs";
|
|
2
2
|
import { getUser } from "@yongdall/core";
|
|
3
3
|
|
|
4
4
|
//#region plugins/user/hooks.yongdall.mjs
|
package/index.d.mts
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
import * as
|
|
1
|
+
import * as imodel2 from "imodel";
|
|
2
2
|
import * as _yongdall_model0 from "@yongdall/model";
|
|
3
3
|
|
|
4
4
|
//#region plugins/user/models/User.d.mts
|
|
5
5
|
declare const _default: _yongdall_model0.ModelTable<{
|
|
6
|
-
username:
|
|
7
|
-
account:
|
|
8
|
-
userId:
|
|
9
|
-
type:
|
|
6
|
+
username: imodel2.FieldDefine<_yongdall_model0.ModelTable<{
|
|
7
|
+
account: imodel2.FieldDefine<"string", false, false>;
|
|
8
|
+
userId: imodel2.FieldDefine<"uuid", false, false>;
|
|
9
|
+
type: imodel2.FieldDefine<"string", false, false>;
|
|
10
10
|
}, "user.account">, false, false>;
|
|
11
|
-
id:
|
|
12
|
-
name:
|
|
13
|
-
enabled:
|
|
14
|
-
createdAt:
|
|
15
|
-
updatedAt:
|
|
11
|
+
id: imodel2.FieldDefine<"uuid", false, false>;
|
|
12
|
+
name: imodel2.FieldDefine<"string", false, false>;
|
|
13
|
+
enabled: imodel2.FieldDefine<"bool", false, false>;
|
|
14
|
+
createdAt: imodel2.FieldDefine<"timestamp", false, false>;
|
|
15
|
+
updatedAt: imodel2.FieldDefine<"timestamp", false, false>;
|
|
16
16
|
}, "user">;
|
|
17
17
|
//#endregion
|
|
18
18
|
//#region plugins/user/models/UserAccount.d.mts
|
|
19
19
|
declare const _default$1: _yongdall_model0.ModelTable<{
|
|
20
|
-
account:
|
|
21
|
-
userId:
|
|
22
|
-
type:
|
|
20
|
+
account: imodel2.FieldDefine<"string", false, false>;
|
|
21
|
+
userId: imodel2.FieldDefine<"uuid", false, false>;
|
|
22
|
+
type: imodel2.FieldDefine<"string", false, false>;
|
|
23
23
|
}, "user.account">;
|
|
24
24
|
//#endregion
|
|
25
25
|
//#region plugins/user/models/UserPassword.d.mts
|
|
26
26
|
declare const _default$2: _yongdall_model0.ModelTable<{
|
|
27
|
-
userId:
|
|
28
|
-
password:
|
|
29
|
-
deadline:
|
|
30
|
-
updatedAt:
|
|
27
|
+
userId: imodel2.FieldDefine<"uuid", false, false>;
|
|
28
|
+
password: imodel2.FieldDefine<"string", false, false>;
|
|
29
|
+
deadline: imodel2.FieldDefine<"timestamp", false, true>;
|
|
30
|
+
updatedAt: imodel2.FieldDefine<"timestamp", false, false>;
|
|
31
31
|
}, "user.password">;
|
|
32
32
|
//#endregion
|
|
33
33
|
//#region plugins/user/common/verifyNewPassword.d.mts
|
package/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { a as verifyPassword, c as User_default, i as setPassword, l as UserAccount_default, n as getPasswordHash, o as verifyNewPassword, r as loadUserInfo, s as UserPassword_default, t as findUser } from "./user-
|
|
1
|
+
import { a as verifyPassword, c as User_default, i as setPassword, l as UserAccount_default, n as getPasswordHash, o as verifyNewPassword, r as loadUserInfo, s as UserPassword_default, t as findUser } from "./user-DMOZK_4C.mjs";
|
|
2
2
|
|
|
3
3
|
export { User_default as User, UserAccount_default as UserAccount, UserPassword_default as UserPassword, findUser, getPasswordHash, loadUserInfo, setPassword, verifyNewPassword, verifyPassword };
|
package/package.json
CHANGED
package/routers.yongdall.mjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as setPassword, o as verifyNewPassword } from "./user-
|
|
1
|
+
import { i as setPassword, o as verifyNewPassword } from "./user-DMOZK_4C.mjs";
|
|
2
2
|
import { getUser, getUserPermissions, isSingleUser, verifyUser } from "@yongdall/core";
|
|
3
3
|
import { ApiRouter, useBody } from "@yongdall/http";
|
|
4
4
|
|
|
@@ -232,11 +232,11 @@ async function setPassword(userId, password, deadline) {
|
|
|
232
232
|
if (!password) return false;
|
|
233
233
|
const value = await getPasswordHash(password, userId);
|
|
234
234
|
const connection = connect("rdb");
|
|
235
|
-
if (await connection.first(new Query(UserPassword_default).select("password").where({ userId }))) connection.update(
|
|
235
|
+
if (await connection.first(new Query(UserPassword_default).select("password").where({ userId }))) await connection.update(UserPassword_default, {
|
|
236
236
|
password: value,
|
|
237
237
|
deadline: deadline instanceof Date && deadline.valueOf() ? deadline : null
|
|
238
238
|
}, Where.and("userId", userId));
|
|
239
|
-
else connection.
|
|
239
|
+
else await connection.create(UserPassword_default, {
|
|
240
240
|
userId,
|
|
241
241
|
password: value,
|
|
242
242
|
deadline: deadline instanceof Date && deadline.valueOf() ? deadline : null
|
|
@@ -246,4 +246,4 @@ async function setPassword(userId, password, deadline) {
|
|
|
246
246
|
|
|
247
247
|
//#endregion
|
|
248
248
|
export { verifyPassword as a, User_default as c, setPassword as i, UserAccount_default as l, getPasswordHash as n, verifyNewPassword as o, loadUserInfo as r, UserPassword_default as s, findUser as t };
|
|
249
|
-
//# sourceMappingURL=user-
|
|
249
|
+
//# sourceMappingURL=user-DMOZK_4C.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"user-KPkkrnN4.mjs","names":["UserAccount","User","UserAccount","UserPassword"],"sources":["../../plugins/user/models/UserAccount.mjs","../../plugins/user/models/User.mjs","../../plugins/user/models/UserPassword.mjs","../../plugins/user/common/verifyNewPassword.mjs","../../plugins/user/index.mjs"],"sourcesContent":["import { createModel, createField, now } from '@yongdall/model';\n\n\nexport default createModel('user.account', {\n\taccount: createField('string', { nullable: false, label: '帐号', unique: true }),\n\tuserId: createField('uuid', { nullable: false, label: '用户', primary: 1 }),\n\ttype: createField('string', { nullable: false, default: '', primary: 2, label: '类型' }),\n});\n","import { createField, createModel, now, uuid } from '@yongdall/model';\nimport UserAccount from './UserAccount.mjs';\n\nexport default createModel('user', {\n\tusername: createField(UserAccount, { label: '登陆账号', constraints: {userId: {field: 'id'}, type: {value: 'username'}}}),\n\tid: createField('uuid', { nullable: false, default: uuid, uncreatable: true, primary: 1 }),\n\tname: createField('string', { nullable: false, default: '', label: '名称', layout: { colSpan: 6, head: 2 } }),\n\tenabled: createField('bool', { nullable: false, default: true, label: '是否启用帐号' }),\n\tcreatedAt: createField('timestamp', { nullable: false, creating: now, label: '创建日期' }),\n\tupdatedAt: createField('timestamp', { nullable: false, creating: now, updating: now, label: '最后更新日期' }),\n}, {\n\tlabel: '用户',\n\tlabelField: 'name',\n\n\tpermissions: [\n\t\t{ permission: 'system:user', fields: '*', authorizations: ['query', 'read', 'create', 'update', 'destroy', 'add', 'remove'] },\n\t],\n\tscripts: ['@yongdall/user#models.user'],\n});\n","import { createField, createModel, now } from '@yongdall/model';\n\n\nexport default createModel('user.password', {\n\tuserId: createField('uuid', { nullable: false, label: '用户', primary: 1 }),\n\tpassword: createField('string', { nullable: false, default: '', label: '新密码', renderer: 'password', layout: {colSpan: 6} }),\n\tdeadline: createField('timestamp', { nullable: true, label: '有效期', layout: {colSpan: 6} }),\n\tupdatedAt: createField('timestamp', { nullable: false, creating: now, updating: now, label: '最后更新日期', layout: {colSpan: 6} }),\n})\n","const signTypeRegex = [\n\t/[a-z]/,\n\t/[A-Z]/,\n\t/[0-9]/,\n\t/[~!@#$%^&*()_+{}|<>?,./:\";'\\\\\\[\\]-]/,\n]\n/**\n * \n * @param {string} password \n */\nexport function* verifyNewPassword(password) {\n\tif (password.length < 8) { yield '密码不足 8 位'; }\n\t\n\tif (signTypeRegex.filter(r => r.test(password)).length < 3) {\n\t\tyield `密码至少包含小写字母、大写字母、数字、符号中的 3 种`;\n\t}\n\tif (password.toLowerCase().includes('admin')) {\n\t\tyield `密码不能包含admin`;\n\t}\n\tif ([...password].find((a,index, list) => list[index - 1] === a && list[index + 1] === a)) {\n\t\tyield `密码不能包含三位以上的相同的字母或数字`;\n\t}\n\tif ([...password].find((a,index, list) => {\n\t\tconst p = list[index - 1];\n\t\tconst n = list[index + 1];\n\t\tif (!p || !n) { return false; }\n\t\tconst x = p.charCodeAt(0);\n\t\tconst y = a.charCodeAt(0);\n\t\tconst z = n.charCodeAt(0);\n\t\tconst u = x - y;\n\t\tconst v = y - z;\n\t\tif (u === v && (v === 1 || v === -1)) { return true}\n\t})) {\n\t\tyield `密码不能包含三位以上的连续的字母或数字`;\n\t}\n}\n","import { connect } from '@yongdall/connection';\nimport { Query, Where } from '@yongdall/model';\nimport { useTenant } from '@yongdall/core';\nimport { User, UserAccount, UserPassword } from './models/index.mjs';\n\nexport * from './models/index.mjs';\nexport { verifyNewPassword } from './common/verifyNewPassword.mjs'\n\nconst USER_INFO_KEY = 'user:info';\n\n/**\n * \n * @param {string} userId \n */\nexport async function loadUserInfo(userId) {\n\n\treturn connect('cache').memoize(USER_INFO_KEY, userId, async () => {\n\t\tconst rdb = connect('rdb');\n\t\tconst info = await rdb.select(new Query(User).where({ id: userId }).limit(1));\n\t\treturn info[0];\n\t});\n}\n\nconst allTypes = ['username', 'phone', 'email'];\n\n/**\n * \n * @param {string} account \n * @param {string | string[] | Set<string> | null} [types] \n */\nexport async function findUser(account, types){\n\tconst typeSet = typeof types === 'string' ? new Set(types) : new Set(types);\n\tconst t = typeSet.size ? allTypes.filter(v => typeSet.has(v)) : allTypes;\n\tif (!t.length) { return ''; }\n\tconst rdb = connect('rdb');\n\tconst info = await rdb.select(\n\t\tnew Query(UserAccount)\n\t\t\t.where('account', account.toLowerCase())\n\t\t\t.where('type', 'in', t)\n\t\t\t.limit(1),\n\t);\n\treturn info[0]?.userId || '';\n}\n/**\n * 使用 HMAC-SHA256 对一个或多个值进行哈希,使用 salt 作为密钥。\n * 输出为 base64url 格式。\n *\n * @param {string | ArrayBuffer | ArrayBufferView<ArrayBuffer>} salt\n * @param {string | number} value\n * @param {...(string | number)} values\n * @returns {Promise<string>}\n */\nasync function hash(salt, value, ...values) {\n\t// 1. 准备密钥(salt)\n\t/** @type {ArrayBuffer | ArrayBufferView<ArrayBuffer>} */\n\tlet keyBuffer;\n\tif (salt instanceof ArrayBuffer || ArrayBuffer.isView(salt)) {\n\t\tkeyBuffer = salt;\n\t} else if (typeof salt === 'string') {\n\t\tkeyBuffer = new TextEncoder().encode(salt);\n\t} else {\n\t\tthrow new Error('`salt` 参数必须为字符串或 Uint8Array');\n\t}\n\n\t// 2. 导入 HMAC 密钥\n\tconst cryptoKey = await crypto.subtle.importKey(\n\t\t'raw',\n\t\tkeyBuffer,\n\t\t{ name: 'HMAC', hash: 'SHA-256' },\n\t\tfalse,\n\t\t['sign']\n\t);\n\n\t// 3. 构造输入数据\n\t/** @type {string[]} */\n\tlet data = [];\n\n\t// 处理第一个 value\n\tif (typeof value === 'number') {\n\t\tdata.push(String(value));\n\t} else if (typeof value === 'string') {\n\t\t// JSON.stringify(value).slice(1, -1) 相当于去掉引号,等价于直接编码字符串内容\n\t\tdata.push(JSON.stringify(value).slice(1, -1));\n\t} else {\n\t\tthrow new Error('`value` 参数必须为字符串或数字');\n\t}\n\n\t// 处理后续 values\n\tfor (const v of values) {\n\t\tif (typeof v === 'number') {\n\t\t\tdata.push(String(v));\n\t\t} else if (typeof v === 'string') {\n\t\t\tdata.push(JSON.stringify(v).slice(1, -1));\n\t\t}\n\t}\n\n\t// 合并所有数据\n\tconst messageBuffer = new TextEncoder().encode(data.join('\\n'))\n\n\t// 4. 生成 HMAC\n\tconst signature = await crypto.subtle.sign('HMAC', cryptoKey, messageBuffer);\n\n\t// 5. 转为 base64url 格式\n\tconst base64 = btoa(String.fromCharCode(...new Uint8Array(signature)));\n\treturn base64\n\t\t.replace(/\\+/g, '-')\n\t\t.replace(/\\//g, '_')\n\t\t.replace(/=+$/, ''); // 移除填充\n}\n/**\n * \n * @param {string} password \n * @param {string} userId \n */\nexport async function getPasswordHash(password, userId) {\n\tconst tenant = await useTenant();\n\treturn await hash(tenant.salt, password, userId)\n\n}\n/**\n * \n * @param {string} userId \n * @param {string} password \n * @returns {Promise<-2 | -1 | 1 | 2>}\n */\nexport async function verifyPassword(userId, password) {\n\tconst item = await connect('rdb').first(\n\t\tnew Query(UserPassword)\n\t\t.select('password', 'deadline')\n\t\t.where({ userId })\n\t);\n\tif (!item) { return -2; }\n\tif (item.password !== await getPasswordHash(password, userId)) { return -1; }\n\tif (!item.deadline) { return 1; }\n\tif (Number(item.deadline) < Date.now()) { return 2; }\n\treturn 1;\n}\n/**\n * \n * @param {string} userId \n * @param {string?} password \n * @param {Date?} [deadline] \n * @returns {Promise<boolean>}\n */\n\nexport async function setPassword(userId, password, deadline) {\n\tif (!password) { return false; }\n\tconst value = await getPasswordHash(password, userId);\n\t\n\n\tconst connection = connect('rdb');\n\tconst item = await connection.first(\n\t\tnew Query(UserPassword)\n\t\t.select('password')\n\t\t.where({ userId })\n\t);\n\tif (item) {\n\t\tconnection.update(new Query(UserPassword), {\n\t\t\tpassword: value,\n\t\t\tdeadline: deadline instanceof Date && deadline.valueOf() ? deadline : null,\n\t\t}, Where.and('userId', userId));\n\t} else {\n\t\tconnection.insert(new Query(UserPassword), {\n\t\t\tuserId,\n\t\t\tpassword: value,\n\t\t\tdeadline: deadline instanceof Date && deadline.valueOf() ? deadline : null,\n\t\t});\n\n\t}\n\treturn true;\n\t\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"user-DMOZK_4C.mjs","names":["UserAccount","User","UserAccount","UserPassword"],"sources":["../../plugins/user/models/UserAccount.mjs","../../plugins/user/models/User.mjs","../../plugins/user/models/UserPassword.mjs","../../plugins/user/common/verifyNewPassword.mjs","../../plugins/user/index.mjs"],"sourcesContent":["import { createModel, createField, now } from '@yongdall/model';\n\n\nexport default createModel('user.account', {\n\taccount: createField('string', { nullable: false, label: '帐号', unique: true }),\n\tuserId: createField('uuid', { nullable: false, label: '用户', primary: 1 }),\n\ttype: createField('string', { nullable: false, default: '', primary: 2, label: '类型' }),\n});\n","import { createField, createModel, now, uuid } from '@yongdall/model';\nimport UserAccount from './UserAccount.mjs';\n\nexport default createModel('user', {\n\tusername: createField(UserAccount, { label: '登陆账号', constraints: {userId: {field: 'id'}, type: {value: 'username'}}}),\n\tid: createField('uuid', { nullable: false, default: uuid, uncreatable: true, primary: 1 }),\n\tname: createField('string', { nullable: false, default: '', label: '名称', layout: { colSpan: 6, head: 2 } }),\n\tenabled: createField('bool', { nullable: false, default: true, label: '是否启用帐号' }),\n\tcreatedAt: createField('timestamp', { nullable: false, creating: now, label: '创建日期' }),\n\tupdatedAt: createField('timestamp', { nullable: false, creating: now, updating: now, label: '最后更新日期' }),\n}, {\n\tlabel: '用户',\n\tlabelField: 'name',\n\n\tpermissions: [\n\t\t{ permission: 'system:user', fields: '*', authorizations: ['query', 'read', 'create', 'update', 'destroy', 'add', 'remove'] },\n\t],\n\tscripts: ['@yongdall/user#models.user'],\n});\n","import { createField, createModel, now } from '@yongdall/model';\n\n\nexport default createModel('user.password', {\n\tuserId: createField('uuid', { nullable: false, label: '用户', primary: 1 }),\n\tpassword: createField('string', { nullable: false, default: '', label: '新密码', renderer: 'password', layout: {colSpan: 6} }),\n\tdeadline: createField('timestamp', { nullable: true, label: '有效期', layout: {colSpan: 6} }),\n\tupdatedAt: createField('timestamp', { nullable: false, creating: now, updating: now, label: '最后更新日期', layout: {colSpan: 6} }),\n})\n","const signTypeRegex = [\n\t/[a-z]/,\n\t/[A-Z]/,\n\t/[0-9]/,\n\t/[~!@#$%^&*()_+{}|<>?,./:\";'\\\\\\[\\]-]/,\n]\n/**\n * \n * @param {string} password \n */\nexport function* verifyNewPassword(password) {\n\tif (password.length < 8) { yield '密码不足 8 位'; }\n\t\n\tif (signTypeRegex.filter(r => r.test(password)).length < 3) {\n\t\tyield `密码至少包含小写字母、大写字母、数字、符号中的 3 种`;\n\t}\n\tif (password.toLowerCase().includes('admin')) {\n\t\tyield `密码不能包含admin`;\n\t}\n\tif ([...password].find((a,index, list) => list[index - 1] === a && list[index + 1] === a)) {\n\t\tyield `密码不能包含三位以上的相同的字母或数字`;\n\t}\n\tif ([...password].find((a,index, list) => {\n\t\tconst p = list[index - 1];\n\t\tconst n = list[index + 1];\n\t\tif (!p || !n) { return false; }\n\t\tconst x = p.charCodeAt(0);\n\t\tconst y = a.charCodeAt(0);\n\t\tconst z = n.charCodeAt(0);\n\t\tconst u = x - y;\n\t\tconst v = y - z;\n\t\tif (u === v && (v === 1 || v === -1)) { return true}\n\t})) {\n\t\tyield `密码不能包含三位以上的连续的字母或数字`;\n\t}\n}\n","import { connect } from '@yongdall/connection';\nimport { Query, Where } from '@yongdall/model';\nimport { useTenant } from '@yongdall/core';\nimport { User, UserAccount, UserPassword } from './models/index.mjs';\n\nexport * from './models/index.mjs';\nexport { verifyNewPassword } from './common/verifyNewPassword.mjs'\n\nconst USER_INFO_KEY = 'user:info';\n\n/**\n * \n * @param {string} userId \n */\nexport async function loadUserInfo(userId) {\n\n\treturn connect('cache').memoize(USER_INFO_KEY, userId, async () => {\n\t\tconst rdb = connect('rdb');\n\t\tconst info = await rdb.select(new Query(User).where({ id: userId }).limit(1));\n\t\treturn info[0];\n\t});\n}\n\nconst allTypes = ['username', 'phone', 'email'];\n\n/**\n * \n * @param {string} account \n * @param {string | string[] | Set<string> | null} [types] \n */\nexport async function findUser(account, types){\n\tconst typeSet = typeof types === 'string' ? new Set(types) : new Set(types);\n\tconst t = typeSet.size ? allTypes.filter(v => typeSet.has(v)) : allTypes;\n\tif (!t.length) { return ''; }\n\tconst rdb = connect('rdb');\n\tconst info = await rdb.select(\n\t\tnew Query(UserAccount)\n\t\t\t.where('account', account.toLowerCase())\n\t\t\t.where('type', 'in', t)\n\t\t\t.limit(1),\n\t);\n\treturn info[0]?.userId || '';\n}\n/**\n * 使用 HMAC-SHA256 对一个或多个值进行哈希,使用 salt 作为密钥。\n * 输出为 base64url 格式。\n *\n * @param {string | ArrayBuffer | ArrayBufferView<ArrayBuffer>} salt\n * @param {string | number} value\n * @param {...(string | number)} values\n * @returns {Promise<string>}\n */\nasync function hash(salt, value, ...values) {\n\t// 1. 准备密钥(salt)\n\t/** @type {ArrayBuffer | ArrayBufferView<ArrayBuffer>} */\n\tlet keyBuffer;\n\tif (salt instanceof ArrayBuffer || ArrayBuffer.isView(salt)) {\n\t\tkeyBuffer = salt;\n\t} else if (typeof salt === 'string') {\n\t\tkeyBuffer = new TextEncoder().encode(salt);\n\t} else {\n\t\tthrow new Error('`salt` 参数必须为字符串或 Uint8Array');\n\t}\n\n\t// 2. 导入 HMAC 密钥\n\tconst cryptoKey = await crypto.subtle.importKey(\n\t\t'raw',\n\t\tkeyBuffer,\n\t\t{ name: 'HMAC', hash: 'SHA-256' },\n\t\tfalse,\n\t\t['sign']\n\t);\n\n\t// 3. 构造输入数据\n\t/** @type {string[]} */\n\tlet data = [];\n\n\t// 处理第一个 value\n\tif (typeof value === 'number') {\n\t\tdata.push(String(value));\n\t} else if (typeof value === 'string') {\n\t\t// JSON.stringify(value).slice(1, -1) 相当于去掉引号,等价于直接编码字符串内容\n\t\tdata.push(JSON.stringify(value).slice(1, -1));\n\t} else {\n\t\tthrow new Error('`value` 参数必须为字符串或数字');\n\t}\n\n\t// 处理后续 values\n\tfor (const v of values) {\n\t\tif (typeof v === 'number') {\n\t\t\tdata.push(String(v));\n\t\t} else if (typeof v === 'string') {\n\t\t\tdata.push(JSON.stringify(v).slice(1, -1));\n\t\t}\n\t}\n\n\t// 合并所有数据\n\tconst messageBuffer = new TextEncoder().encode(data.join('\\n'))\n\n\t// 4. 生成 HMAC\n\tconst signature = await crypto.subtle.sign('HMAC', cryptoKey, messageBuffer);\n\n\t// 5. 转为 base64url 格式\n\tconst base64 = btoa(String.fromCharCode(...new Uint8Array(signature)));\n\treturn base64\n\t\t.replace(/\\+/g, '-')\n\t\t.replace(/\\//g, '_')\n\t\t.replace(/=+$/, ''); // 移除填充\n}\n/**\n * \n * @param {string} password \n * @param {string} userId \n */\nexport async function getPasswordHash(password, userId) {\n\tconst tenant = await useTenant();\n\treturn await hash(tenant.salt, password, userId)\n\n}\n/**\n * \n * @param {string} userId \n * @param {string} password \n * @returns {Promise<-2 | -1 | 1 | 2>}\n */\nexport async function verifyPassword(userId, password) {\n\tconst item = await connect('rdb').first(\n\t\tnew Query(UserPassword)\n\t\t.select('password', 'deadline')\n\t\t.where({ userId })\n\t);\n\tif (!item) { return -2; }\n\tif (item.password !== await getPasswordHash(password, userId)) { return -1; }\n\tif (!item.deadline) { return 1; }\n\tif (Number(item.deadline) < Date.now()) { return 2; }\n\treturn 1;\n}\n/**\n * \n * @param {string} userId \n * @param {string?} password \n * @param {Date?} [deadline] \n * @returns {Promise<boolean>}\n */\n\nexport async function setPassword(userId, password, deadline) {\n\tif (!password) { return false; }\n\tconst value = await getPasswordHash(password, userId);\n\t\n\n\tconst connection = connect('rdb');\n\tconst item = await connection.first(\n\t\tnew Query(UserPassword)\n\t\t.select('password')\n\t\t.where({ userId })\n\t);\n\tif (item) {\n\t\tawait connection.update(UserPassword, {\n\t\t\tpassword: value,\n\t\t\tdeadline: deadline instanceof Date && deadline.valueOf() ? deadline : null,\n\t\t}, Where.and('userId', userId));\n\t} else {\n\t\tawait connection.create(UserPassword, {\n\t\t\tuserId,\n\t\t\tpassword: value,\n\t\t\tdeadline: deadline instanceof Date && deadline.valueOf() ? deadline : null,\n\t\t});\n\n\t}\n\treturn true;\n\t\n}\n"],"mappings":"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"}
|