@yongdall/user 0.1.0 → 0.1.4

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/assets/index.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import{Store as e,createStoreField as t,renderStore as n,single as r}from"@yongdall/web";import i from"@yongdall/web/plugin";var a=Object.defineProperty,o=(e,t)=>{let n={};for(var r in e)a(n,r,{get:e[r],enumerable:!0});return t||a(n,Symbol.toStringTag,{value:`Module`}),n};const s=[/[a-z]/,/[A-Z]/,/[0-9]/,/[~!@#$%^&*()_+{}|<>?,./:";'\\\[\]-]/];function*c(e){e.length<8&&(yield`密码不足 8 位`),s.filter(t=>t.test(e)).length<3&&(yield`密码至少包含小写字母、大写字母、数字、符号中的 3 种`),e.toLowerCase().includes(`admin`)&&(yield`密码不能包含admin`),[...e].find((e,t,n)=>n[t-1]===e&&n[t+1]===e)&&(yield`密码不能包含三位以上的相同的字母或数字`),[...e].find((e,t,n)=>{let r=n[t-1],i=n[t+1];if(!r||!i)return!1;let a=r.charCodeAt(0),o=e.charCodeAt(0),s=i.charCodeAt(0),c=a-o,l=o-s;if(c===l&&(l===1||l===-1))return!0})&&(yield`密码不能包含三位以上的连续的字母或数字`)}var l=o({user:()=>f});const u={password:{type:`password`,label:`您的密码`,hidden:r,validators:{blur(e){if(r)return;let t=e.value;if(!t||typeof t!=`string`)return`请填写您的密码`}}},newPassword1:{type:`password`,label:`新密码`,validators:{blur(e){let t=e.value;return!t||typeof t!=`string`?`请填写新密码`:[...c(t)]}}},newPassword2:{type:`password`,label:`重复密码`,validators:{blur(e){let t=e.value;if(!t)return`请填写重复密码`;if(t!==e.parent?.child(`newPassword1`)?.value)return`重复密码与新密码不一致`}}}},d={fields:[{field:`password`},{field:`newPassword1`},{field:`newPassword2`}]},f={documentScripts:{setPassword(r){let a=r.document?.id;if(!a)return;let o=document.createElement(`dialog`),s=document.createElement(`form`),c=s.appendChild(document.createElement(`h2`));c.textContent=`设置用户密码`,o.appendChild(s);let l=new AbortController;o.addEventListener(`close`,()=>{o.remove(),l.abort()});let f=e.create(u);f.reset();let p=n(f,(e,n)=>t(e,{},n),s,d,{editable:!0});l.signal.addEventListener(`abort`,p,{once:!0});let m=s.appendChild(document.createElement(`button`));m.type=`submit`,m.textContent=`修改密码`,s.addEventListener(`submit`,async e=>{if(e.preventDefault(),!m.disabled)try{m.disabled=!0;let{password:e,newPassword1:t}=f.value;if((await f.validate())?.length)return;let n=await i.request.clone().put(`password`).body({userId:a,password:e,newPassword:t}).result();if(!n||n===200||typeof n==`object`){o.close(),alert(`密码修改完成`);return}if(n===404){alert(`新旧密码不能相同`);return}if(n===403){alert(`密码错误`);return}if(n===400){alert(`不能修改自己的密码`);return}if(n===402){alert(`您无操作权限`);return}}catch(e){e instanceof Response&&e.status===403&&alert(`密码错误`)}finally{m.disabled=!1}}),document.body.appendChild(o),o.showModal()}}},p={password:{type:`password`,label:`当前密码`,validators:{blur(e){let t=e.value;if(!t||typeof t!=`string`)return`请填写密码`}}},newPassword1:{type:`password`,label:`新密码`,validators:{blur(e){let t=e.value;return!t||typeof t!=`string`?`请填写新密码`:[...c(t)]}}},newPassword2:{type:`password`,label:`重复密码`,validators:{blur(e){let t=e.value;if(!t)return`请填写重复密码`;if(t!==e.parent?.child(`newPassword1`)?.value)return`重复密码与新密码不一致`}}}},m={fields:[{field:`password`},{field:`newPassword1`},{field:`newPassword2`}]};function h(r){r.loading=!1,r.panel=!0,r.title=`修改密码`;let a=r.container;a.style.margin=`auto`,a.style.maxInlineSize=`300px`;let o=document.createElement(`form`),s=o.appendChild(document.createElement(`h2`));s.textContent=`修改密码`,a.appendChild(o);let c=e.create(p);if(c.reset(),r.signal.aborted)return null;let l=n(c,(e,n)=>t(e,{},n),o,m,{editable:!0});r.signal.addEventListener(`abort`,l,{once:!0});let u=o.appendChild(document.createElement(`button`));u.type=`submit`,u.textContent=`修改密码`,o.addEventListener(`submit`,async e=>{if(e.preventDefault(),!u.disabled)try{u.disabled=!0;let{password:e,newPassword1:t}=c.value;if((await c.validate())?.length)return;let n=await i.request.clone().put(`password`).body({password:e,newPassword:t}).result();if(!n||n===200||typeof n==`object`){c.reset(),alert(`密码修改完成`);return}if(n===403){alert(`密码错误`);return}}catch(e){e instanceof Response&&e.status===403&&alert(`密码错误`)}finally{u.disabled=!1}})}export{l as models,h as password,c as verifyNewPassword};
1
+ import{Store as e,renderStoreForm as t,single as n}from"@yongdall/web";import r from"@yongdall/web/plugin";var i=Object.defineProperty,a=(e,t)=>{let n={};for(var r in e)i(n,r,{get:e[r],enumerable:!0});return t||i(n,Symbol.toStringTag,{value:`Module`}),n};const o=[/[a-z]/,/[A-Z]/,/[0-9]/,/[~!@#$%^&*()_+{}|<>?,./:";'\\\[\]-]/];function*s(e){e.length<8&&(yield`密码不足 8 位`),o.filter(t=>t.test(e)).length<3&&(yield`密码至少包含小写字母、大写字母、数字、符号中的 3 种`),e.toLowerCase().includes(`admin`)&&(yield`密码不能包含admin`),[...e].find((e,t,n)=>n[t-1]===e&&n[t+1]===e)&&(yield`密码不能包含三位以上的相同的字母或数字`),[...e].find((e,t,n)=>{let r=n[t-1],i=n[t+1];if(!r||!i)return!1;let a=r.charCodeAt(0),o=e.charCodeAt(0),s=i.charCodeAt(0),c=a-o,l=o-s;if(c===l&&(l===1||l===-1))return!0})&&(yield`密码不能包含三位以上的连续的字母或数字`)}var c=a({user:()=>d});const l={password:{type:`string`,label:`您的密码`,component:`password`,hidden:n,validators:{blur(e){if(n)return;let t=e.value;if(!t||typeof t!=`string`)return`请填写您的密码`}}},newPassword1:{type:`string`,label:`新密码`,component:`password`,validators:{blur(e){let t=e.value;return!t||typeof t!=`string`?`请填写新密码`:[...s(t)]}}},newPassword2:{type:`string`,label:`重复密码`,component:`password`,validators:{blur(e){let t=e.value;if(!t)return`请填写重复密码`;if(t!==e.parent?.child(`newPassword1`)?.value)return`重复密码与新密码不一致`}}}},u={fields:[{field:`password`},{field:`newPassword1`},{field:`newPassword2`}]},d={documentScripts:{setPassword(n){let i=n.document?.id;if(!i)return;let a=document.createElement(`dialog`),o=document.createElement(`form`),s=o.appendChild(document.createElement(`h2`));s.textContent=`设置用户密码`,a.appendChild(o);let c=new AbortController;a.addEventListener(`close`,()=>{a.remove(),c.abort()});let d=e.create(l);d.reset(),t(d,o,{editable:!0,layout:u,signal:c.signal});let f=o.appendChild(document.createElement(`button`));f.type=`submit`,f.textContent=`修改密码`,o.addEventListener(`submit`,async e=>{if(e.preventDefault(),!f.disabled)try{f.disabled=!0;let{password:e,newPassword1:t}=d.value;if((await d.validate())?.length)return;let n=await r.request.clone().put(`password`).body({userId:i,password:e,newPassword:t}).result();if(!n||n===200||typeof n==`object`){a.close(),alert(`密码修改完成`);return}if(n===404){alert(`新旧密码不能相同`);return}if(n===403){alert(`密码错误`);return}if(n===400){alert(`不能修改自己的密码`);return}if(n===402){alert(`您无操作权限`);return}}catch(e){e instanceof Response&&e.status===403&&alert(`密码错误`)}finally{f.disabled=!1}}),document.body.appendChild(a),a.showModal()}}},f={password:{type:`string`,label:`当前密码`,component:`password`,validators:{blur(e){let t=e.value;if(!t||typeof t!=`string`)return`请填写密码`}}},newPassword1:{type:`string`,label:`新密码`,component:`password`,validators:{blur(e){let t=e.value;return!t||typeof t!=`string`?`请填写新密码`:[...s(t)]}}},newPassword2:{type:`string`,label:`重复密码`,component:`password`,validators:{blur(e){let t=e.value;if(!t)return`请填写重复密码`;if(t!==e.parent?.child(`newPassword1`)?.value)return`重复密码与新密码不一致`}}}},p={fields:[{field:`password`},{field:`newPassword1`},{field:`newPassword2`}]};function m(n){n.loading=!1,n.panel=!0,n.title=`修改密码`;let i=n.container;i.style.margin=`auto`,i.style.maxInlineSize=`300px`;let a=document.createElement(`form`),o=a.appendChild(document.createElement(`h2`));o.textContent=`修改密码`,i.appendChild(a);let s=e.create(f);if(s.reset(),n.signal.aborted)return null;t(s,a,{editable:!0,layout:p,signal:n.signal});let c=a.appendChild(document.createElement(`button`));c.type=`submit`,c.textContent=`修改密码`,a.addEventListener(`submit`,async e=>{if(e.preventDefault(),!c.disabled)try{c.disabled=!0;let{password:e,newPassword1:t}=s.value;if((await s.validate())?.length)return;let n=await r.request.clone().put(`password`).body({password:e,newPassword:t}).result();if(!n||n===200||typeof n==`object`){s.reset(),alert(`密码修改完成`);return}if(n===403){alert(`密码错误`);return}}catch(e){e instanceof Response&&e.status===403&&alert(`密码错误`)}finally{c.disabled=!1}})}export{c as models,m as password,s as verifyNewPassword};
2
2
  //# sourceMappingURL=index.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.mjs","names":["schema","StoreLayout"],"sources":["../../../plugins/user/common/verifyNewPassword.mjs","../../../plugins/user/assets/models.mjs","../../../plugins/user/assets/password.mjs"],"sourcesContent":["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 { ModelScript } from '@yongdall/web' */\n/** @import { Schema, StoreLayout } from '@yongdall/web' */\n\nimport { createStoreField, renderStore, single, Store } from '@yongdall/web';\nimport Plugin from '@yongdall/web/plugin';\nimport { verifyNewPassword } from './common/verifyNewPassword.mjs';\n\n/** @type {Schema} */\nconst schema = {\n\n\tpassword: {\n\t\ttype: 'password', label: '您的密码',\n\t\thidden: single,\n\t\tvalidators: {\n\t\t\tblur(store) {\n\t\t\t\tif (single) { return; }\n\t\t\t\tconst value = store.value;\n\t\t\t\tif (!value || typeof value !== 'string') { return '请填写您的密码'; }\n\t\t\t},\n\t\t}\n\t},\n\tnewPassword1: {\n\t\ttype: 'password', label: '新密码',\n\t\tvalidators: {\n\t\t\tblur(store) {\n\t\t\t\tconst value = store.value;\n\t\t\t\tif (!value || typeof value !== 'string') { return '请填写新密码'; }\n\t\t\t\treturn [...verifyNewPassword(value)];\n\t\t\t},\n\t\t},\n\t},\n\tnewPassword2: {\n\t\ttype: 'password', label: '重复密码',\n\t\tvalidators: {\n\t\t\tblur(store) {\n\t\t\t\tconst value = store.value;\n\t\t\t\tif (!value) { return '请填写重复密码'; }\n\t\t\t\tif (value !== store.parent?.child('newPassword1')?.value) {\n\t\t\t\t\treturn '重复密码与新密码不一致';\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n};\n\n/** @type {StoreLayout} */\nconst StoreLayout = {\n\tfields: [\n\t\t{ field: 'password' },\n\t\t{ field: 'newPassword1' },\n\t\t{ field: 'newPassword2' },\n\t],\n};\n/** @type {ModelScript} */\nexport const user = {\n\tdocumentScripts: {\n\t\tsetPassword(params) {\n\t\t\tconst userId = params.document?.id;\n\t\t\tif (!userId) { return; }\n\t\t\tconst dialog = document.createElement('dialog');\n\t\t\tconst form = document.createElement('form');\n\t\t\tconst title = form.appendChild(document.createElement('h2'));\n\t\t\ttitle.textContent = '设置用户密码';\n\t\t\tdialog.appendChild(form);\n\t\t\tconst ac = new AbortController();\n\t\t\tdialog.addEventListener('close', () => {\n\t\t\t\tdialog.remove();\n\t\t\t\tac.abort();\n\t\t\t});\n\t\t\tconst store = Store.create(schema);\n\t\t\tstore.reset();\n\t\t\tconst destroy = renderStore(\n\t\t\t\tstore,\n\t\t\t\t(store, options) => createStoreField(store, {}, options),\n\t\t\t\tform,\n\t\t\t\tStoreLayout,\n\t\t\t\t{ editable: true },\n\t\t\t);\n\t\t\tac.signal.addEventListener('abort', destroy, { once: true });\n\n\t\t\tconst submitButton = form.appendChild(document.createElement('button'));\n\t\t\tsubmitButton.type = 'submit';\n\t\t\tsubmitButton.textContent = '修改密码';\n\n\t\t\tform.addEventListener('submit', async event => {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tif (submitButton.disabled) { return; }\n\t\t\t\ttry {\n\t\t\t\t\tsubmitButton.disabled = true;\n\t\t\t\t\tconst { password, newPassword1 } = store.value;\n\t\t\t\t\tconst r = await store.validate();\n\t\t\t\t\tif (r?.length) { return; }\n\t\t\t\t\tconst result = await Plugin.request.clone().put('password').body({\n\t\t\t\t\t\tuserId, password, newPassword: newPassword1,\n\t\t\t\t\t}).result();\n\t\t\t\t\tif (!result || result === 200 || typeof result === 'object') {\n\t\t\t\t\t\tdialog.close();\n\t\t\t\t\t\talert('密码修改完成');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (result === 404) {\n\t\t\t\t\t\talert('新旧密码不能相同');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (result === 403) {\n\t\t\t\t\t\talert('密码错误');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (result === 400) {\n\t\t\t\t\t\talert('不能修改自己的密码');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (result === 402) {\n\t\t\t\t\t\talert('您无操作权限');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t} catch (e) {\n\t\t\t\t\tif (e instanceof Response) {\n\t\t\t\t\t\tif (e.status === 403) {\n\t\t\t\t\t\t\talert('密码错误');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tsubmitButton.disabled = false;\n\t\t\t\t}\n\t\t\t});\n\t\t\tdocument.body.appendChild(dialog);\n\t\t\tdialog.showModal();\n\t\t}\n\t}\n};\n","/** @import { PageContext, Schema, StoreLayout } from '@yongdall/web' */\n\nimport { createStoreField, renderStore, Store } from '@yongdall/web';\nimport Plugin from '@yongdall/web/plugin';\nimport { verifyNewPassword } from './common/verifyNewPassword.mjs';\n\n/** @type {Schema} */\nconst schema = {\n\n\tpassword: {\n\t\ttype: 'password', label: '当前密码',\n\t\tvalidators: {\n\t\t\tblur(store) {\n\t\t\t\tconst value = store.value;\n\t\t\t\tif (!value || typeof value !== 'string') { return '请填写密码'; }\n\t\t\t},\n\t\t}\n\t},\n\tnewPassword1: {\n\t\ttype: 'password', label: '新密码',\n\t\tvalidators: {\n\t\t\tblur(store) {\n\t\t\t\tconst value = store.value;\n\t\t\t\tif (!value || typeof value !== 'string') { return '请填写新密码'; }\n\t\t\t\treturn [...verifyNewPassword(value)];\n\t\t\t},\n\t\t},\n\t},\n\tnewPassword2: {\n\t\ttype: 'password', label: '重复密码',\n\t\tvalidators: {\n\t\t\tblur(store) {\n\t\t\t\tconst value = store.value;\n\t\t\t\tif (!value) { return '请填写重复密码'; }\n\t\t\t\tif (value !== store.parent?.child('newPassword1')?.value) {\n\t\t\t\t\treturn '重复密码与新密码不一致';\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n};\n\n/** @type {StoreLayout} */\nconst StoreLayout = {\n\tfields: [\n\t\t{ field: 'password' },\n\t\t{ field: 'newPassword1' },\n\t\t{ field: 'newPassword2' },\n\t],\n};\n/**\n * \n * @param {PageContext} ctx \n */\nexport default function(ctx) {\n\tctx.loading = false;\n\tctx.panel = true;\n\tctx.title = '修改密码';\n\tconst container = ctx.container;\n\tcontainer.style.margin = 'auto';\n\tcontainer.style.maxInlineSize = '300px';\n\n\tconst form = document.createElement('form');\n\tconst title = form.appendChild(document.createElement('h2'));\n\ttitle.textContent = '修改密码';\n\tcontainer.appendChild(form);\n\n\tconst store = Store.create(schema);\n\tstore.reset();\n\tif (ctx.signal.aborted) {\n\t\treturn null;\n\t}\n\n\n\tconst destroy = renderStore(\n\t\tstore,\n\t\t(store, options) => createStoreField(store, {}, options),\n\t\tform,\n\t\tStoreLayout,\n\t\t{ editable: true },\n\t);\n\tctx.signal.addEventListener('abort', destroy, { once: true });\n\n\n\tconst submitButton = form.appendChild(document.createElement('button'));\n\tsubmitButton.type = 'submit';\n\tsubmitButton.textContent = '修改密码';\n\n\tform.addEventListener('submit', async event => {\n\t\tevent.preventDefault();\n\t\tif (submitButton.disabled) { return; }\n\t\ttry {\n\t\t\tsubmitButton.disabled = true;\n\t\t\tconst { password, newPassword1 } = store.value;\n\t\t\tconst r = await store.validate();\n\t\t\tif (r?.length) { return; }\n\t\t\tconst result = await Plugin.request.clone().put('password').body({\n\t\t\t\tpassword, newPassword: newPassword1,\n\t\t\t}).result();\n\t\t\tif (!result || result === 200 || typeof result === 'object') {\n\t\t\t\tstore.reset();\n\t\t\t\talert('密码修改完成');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (result === 403) {\n\t\t\t\talert('密码错误');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t} catch (e) {\n\t\t\tif (e instanceof Response) {\n\t\t\t\tif (e.status === 403) {\n\t\t\t\t\talert('密码错误');\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tsubmitButton.disabled = false;\n\t\t}\n\t});\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"index.mjs","names":["schema","layout"],"sources":["../../../plugins/user/common/verifyNewPassword.mjs","../../../plugins/user/assets/models.mjs","../../../plugins/user/assets/password.mjs"],"sourcesContent":["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 { ModelScript } from '@yongdall/web' */\n/** @import { Schema, StoreLayout } from '@yongdall/web' */\n\nimport { renderStoreForm, single, Store } from '@yongdall/web';\nimport Plugin from '@yongdall/web/plugin';\nimport { verifyNewPassword } from './common/verifyNewPassword.mjs';\n\n/** @type {Schema} */\nconst schema = {\n\n\tpassword: {\n\t\ttype: 'string', label: '您的密码', component: 'password',\n\t\thidden: single,\n\t\tvalidators: {\n\t\t\tblur(store) {\n\t\t\t\tif (single) { return; }\n\t\t\t\tconst value = store.value;\n\t\t\t\tif (!value || typeof value !== 'string') { return '请填写您的密码'; }\n\t\t\t},\n\t\t}\n\t},\n\tnewPassword1: {\n\t\ttype: 'string', label: '新密码', component: 'password',\n\t\tvalidators: {\n\t\t\tblur(store) {\n\t\t\t\tconst value = store.value;\n\t\t\t\tif (!value || typeof value !== 'string') { return '请填写新密码'; }\n\t\t\t\treturn [...verifyNewPassword(value)];\n\t\t\t},\n\t\t},\n\t},\n\tnewPassword2: {\n\t\ttype: 'string', label: '重复密码', component: 'password',\n\t\tvalidators: {\n\t\t\tblur(store) {\n\t\t\t\tconst value = store.value;\n\t\t\t\tif (!value) { return '请填写重复密码'; }\n\t\t\t\tif (value !== store.parent?.child('newPassword1')?.value) {\n\t\t\t\t\treturn '重复密码与新密码不一致';\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n};\n\n/** @type {StoreLayout<any>} */\nconst layout = {\n\tfields: [\n\t\t{ field: 'password' },\n\t\t{ field: 'newPassword1' },\n\t\t{ field: 'newPassword2' },\n\t],\n};\n/** @type {ModelScript} */\nexport const user = {\n\tdocumentScripts: {\n\t\tsetPassword(params) {\n\t\t\tconst userId = params.document?.id;\n\t\t\tif (!userId) { return; }\n\t\t\tconst dialog = document.createElement('dialog');\n\t\t\tconst form = document.createElement('form');\n\t\t\tconst title = form.appendChild(document.createElement('h2'));\n\t\t\ttitle.textContent = '设置用户密码';\n\t\t\tdialog.appendChild(form);\n\t\t\tconst ac = new AbortController();\n\t\t\tdialog.addEventListener('close', () => {\n\t\t\t\tdialog.remove();\n\t\t\t\tac.abort();\n\t\t\t});\n\t\t\tconst store = Store.create(schema);\n\t\t\tstore.reset();\n\n\t\t\trenderStoreForm(store, form, { editable: true, layout, signal: ac.signal });\n\n\t\t\tconst submitButton = form.appendChild(document.createElement('button'));\n\t\t\tsubmitButton.type = 'submit';\n\t\t\tsubmitButton.textContent = '修改密码';\n\n\t\t\tform.addEventListener('submit', async event => {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tif (submitButton.disabled) { return; }\n\t\t\t\ttry {\n\t\t\t\t\tsubmitButton.disabled = true;\n\t\t\t\t\tconst { password, newPassword1 } = store.value;\n\t\t\t\t\tconst r = await store.validate();\n\t\t\t\t\tif (r?.length) { return; }\n\t\t\t\t\tconst result = await Plugin.request.clone().put('password').body({\n\t\t\t\t\t\tuserId, password, newPassword: newPassword1,\n\t\t\t\t\t}).result();\n\t\t\t\t\tif (!result || result === 200 || typeof result === 'object') {\n\t\t\t\t\t\tdialog.close();\n\t\t\t\t\t\talert('密码修改完成');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (result === 404) {\n\t\t\t\t\t\talert('新旧密码不能相同');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (result === 403) {\n\t\t\t\t\t\talert('密码错误');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (result === 400) {\n\t\t\t\t\t\talert('不能修改自己的密码');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\t\t\t\t\tif (result === 402) {\n\t\t\t\t\t\talert('您无操作权限');\n\t\t\t\t\t\treturn;\n\t\t\t\t\t}\n\n\t\t\t\t} catch (e) {\n\t\t\t\t\tif (e instanceof Response) {\n\t\t\t\t\t\tif (e.status === 403) {\n\t\t\t\t\t\t\talert('密码错误');\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t} finally {\n\t\t\t\t\tsubmitButton.disabled = false;\n\t\t\t\t}\n\t\t\t});\n\t\t\tdocument.body.appendChild(dialog);\n\t\t\tdialog.showModal();\n\t\t}\n\t}\n};\n","/** @import { PageContext, Schema, StoreLayout } from '@yongdall/web' */\n\nimport { renderStoreForm, Store } from '@yongdall/web';\nimport Plugin from '@yongdall/web/plugin';\nimport { verifyNewPassword } from './common/verifyNewPassword.mjs';\n\n/** @type {Schema} */\nconst schema = {\n\n\tpassword: {\n\t\ttype: 'string', label: '当前密码', component: 'password',\n\t\tvalidators: {\n\t\t\tblur(store) {\n\t\t\t\tconst value = store.value;\n\t\t\t\tif (!value || typeof value !== 'string') { return '请填写密码'; }\n\t\t\t},\n\t\t}\n\t},\n\tnewPassword1: {\n\t\ttype: 'string', label: '新密码', component: 'password',\n\t\tvalidators: {\n\t\t\tblur(store) {\n\t\t\t\tconst value = store.value;\n\t\t\t\tif (!value || typeof value !== 'string') { return '请填写新密码'; }\n\t\t\t\treturn [...verifyNewPassword(value)];\n\t\t\t},\n\t\t},\n\t},\n\tnewPassword2: {\n\t\ttype: 'string', label: '重复密码', component: 'password',\n\t\tvalidators: {\n\t\t\tblur(store) {\n\t\t\t\tconst value = store.value;\n\t\t\t\tif (!value) { return '请填写重复密码'; }\n\t\t\t\tif (value !== store.parent?.child('newPassword1')?.value) {\n\t\t\t\t\treturn '重复密码与新密码不一致';\n\t\t\t\t}\n\t\t\t},\n\t\t},\n\t},\n};\n\n/** @type {StoreLayout<any>} */\nconst layout = {\n\tfields: [\n\t\t{ field: 'password' },\n\t\t{ field: 'newPassword1' },\n\t\t{ field: 'newPassword2' },\n\t],\n};\n/**\n * \n * @param {PageContext} ctx \n */\nexport default function(ctx) {\n\tctx.loading = false;\n\tctx.panel = true;\n\tctx.title = '修改密码';\n\tconst container = ctx.container;\n\tcontainer.style.margin = 'auto';\n\tcontainer.style.maxInlineSize = '300px';\n\n\tconst form = document.createElement('form');\n\tconst title = form.appendChild(document.createElement('h2'));\n\ttitle.textContent = '修改密码';\n\tcontainer.appendChild(form);\n\n\tconst store = Store.create(schema);\n\tstore.reset();\n\tif (ctx.signal.aborted) {\n\t\treturn null;\n\t}\n\n\n\trenderStoreForm(store, form, { editable: true, layout, signal: ctx.signal });\n\n\n\tconst submitButton = form.appendChild(document.createElement('button'));\n\tsubmitButton.type = 'submit';\n\tsubmitButton.textContent = '修改密码';\n\n\tform.addEventListener('submit', async event => {\n\t\tevent.preventDefault();\n\t\tif (submitButton.disabled) { return; }\n\t\ttry {\n\t\t\tsubmitButton.disabled = true;\n\t\t\tconst { password, newPassword1 } = store.value;\n\t\t\tconst r = await store.validate();\n\t\t\tif (r?.length) { return; }\n\t\t\tconst result = await Plugin.request.clone().put('password').body({\n\t\t\t\tpassword, newPassword: newPassword1,\n\t\t\t}).result();\n\t\t\tif (!result || result === 200 || typeof result === 'object') {\n\t\t\t\tstore.reset();\n\t\t\t\talert('密码修改完成');\n\t\t\t\treturn;\n\t\t\t}\n\t\t\tif (result === 403) {\n\t\t\t\talert('密码错误');\n\t\t\t\treturn;\n\t\t\t}\n\n\t\t} catch (e) {\n\t\t\tif (e instanceof Response) {\n\t\t\t\tif (e.status === 403) {\n\t\t\t\t\talert('密码错误');\n\t\t\t\t}\n\t\t\t}\n\t\t} finally {\n\t\t\tsubmitButton.disabled = false;\n\t\t}\n\t});\n}\n"],"mappings":"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"}
@@ -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-KPkkrnN4.mjs";
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.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-KPkkrnN4.mjs";
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
@@ -6,7 +6,7 @@
6
6
  ".": "./index.mjs",
7
7
  "./assets": "./assets/index.mjs"
8
8
  },
9
- "version": "0.1.0",
9
+ "version": "0.1.4",
10
10
  "description": "",
11
11
  "keywords": [],
12
12
  "author": "",
@@ -1,5 +1,5 @@
1
- import { i as setPassword, o as verifyNewPassword } from "./user-KPkkrnN4.mjs";
2
- import { getUser, getUserPermissions, isSingleUser, verifyUser } from "@yongdall/core";
1
+ import { i as setPassword, o as verifyNewPassword } from "./user-DMOZK_4C.mjs";
2
+ import { getUser, hasUserPermission, isSingleUser, verifyUser } from "@yongdall/core";
3
3
  import { ApiRouter, useBody } from "@yongdall/http";
4
4
 
5
5
  //#region plugins/user/routers.yongdall.mjs
@@ -18,7 +18,7 @@ plugin.put`password`(async (ctx) => {
18
18
  if (userId === loggedUser) {
19
19
  if (newPassword === password) return 404;
20
20
  } else if (!singleUser) {
21
- if (!(await getUserPermissions()).has("system:user:password")) return 402;
21
+ if (!await hasUserPermission("system:user:password")) return 402;
22
22
  }
23
23
  if (loggedUser && password && !await verifyUser(loggedUser, password, "password")) return 403;
24
24
  if ([...verifyNewPassword(newPassword)].length) return 408;
@@ -1 +1 @@
1
- {"version":3,"file":"routers.yongdall.mjs","names":[],"sources":["../../plugins/user/routers.yongdall.mjs"],"sourcesContent":["import { ApiRouter, useBody } from '@yongdall/http';\nimport { getUser, getUserPermissions, isSingleUser, verifyUser } from '@yongdall/core';\nimport { verifyNewPassword } from './common/verifyNewPassword.mjs';\nimport { setPassword } from './index.mjs';\n\nexport const plugin = new ApiRouter();\n\nplugin.put`password`(async ctx => {\n\tconst { password, newPassword, userId } = await useBody() || {};\n\tif (!newPassword || typeof newPassword !== 'string') { return 404; }\n\tconst loggedUser = await getUser();\n\tconst singleUser = await isSingleUser();\n\tif (!singleUser && !loggedUser) { return 404; }\n\tconst targetUser = userId || loggedUser;\n\tif (!targetUser) { return 404; }\n\tif (userId === loggedUser || !singleUser) {\n\t\tif (!password || typeof password !== 'string') { return 404; }\n\t}\n\tif (userId === loggedUser) {\n\t\tif (newPassword === password) { return 404; }\n\t} else if (!singleUser) {\n\t\tconst permissions = await getUserPermissions();\n\t\tif (!permissions.has('system:user:password')) { return 402; }\n\n\t}\n\tif (loggedUser && password && !await verifyUser(loggedUser, password, 'password')) { return 403; }\n\tif ([...verifyNewPassword(newPassword)].length) { return 408; }\n\tawait setPassword(targetUser, newPassword, userId === loggedUser ? null : new Date);\n\treturn 200;\n});\n"],"mappings":";;;;;AAKA,MAAa,SAAS,IAAI,WAAW;AAErC,OAAO,GAAG,WAAW,OAAM,QAAO;CACjC,MAAM,EAAE,UAAU,aAAa,WAAW,MAAM,SAAS,IAAI,EAAE;AAC/D,KAAI,CAAC,eAAe,OAAO,gBAAgB,SAAY,QAAO;CAC9D,MAAM,aAAa,MAAM,SAAS;CAClC,MAAM,aAAa,MAAM,cAAc;AACvC,KAAI,CAAC,cAAc,CAAC,WAAc,QAAO;CACzC,MAAM,aAAa,UAAU;AAC7B,KAAI,CAAC,WAAc,QAAO;AAC1B,KAAI,WAAW,cAAc,CAAC,YAC7B;MAAI,CAAC,YAAY,OAAO,aAAa,SAAY,QAAO;;AAEzD,KAAI,WAAW,YACd;MAAI,gBAAgB,SAAY,QAAO;YAC7B,CAAC,YAEX;MAAI,EADgB,MAAM,oBAAoB,EAC7B,IAAI,uBAAuB,CAAI,QAAO;;AAGxD,KAAI,cAAc,YAAY,CAAC,MAAM,WAAW,YAAY,UAAU,WAAW,CAAI,QAAO;AAC5F,KAAI,CAAC,GAAG,kBAAkB,YAAY,CAAC,CAAC,OAAU,QAAO;AACzD,OAAM,YAAY,YAAY,aAAa,WAAW,aAAa,uBAAO,IAAI,MAAI,CAAC;AACnF,QAAO;EACN"}
1
+ {"version":3,"file":"routers.yongdall.mjs","names":[],"sources":["../../plugins/user/routers.yongdall.mjs"],"sourcesContent":["import { ApiRouter, useBody } from '@yongdall/http';\nimport { getUser, hasUserPermission, isSingleUser, verifyUser } from '@yongdall/core';\nimport { verifyNewPassword } from './common/verifyNewPassword.mjs';\nimport { setPassword } from './index.mjs';\n\nexport const plugin = new ApiRouter();\n\nplugin.put`password`(async ctx => {\n\tconst { password, newPassword, userId } = await useBody() || {};\n\tif (!newPassword || typeof newPassword !== 'string') { return 404; }\n\tconst loggedUser = await getUser();\n\tconst singleUser = await isSingleUser();\n\tif (!singleUser && !loggedUser) { return 404; }\n\tconst targetUser = userId || loggedUser;\n\tif (!targetUser) { return 404; }\n\tif (userId === loggedUser || !singleUser) {\n\t\tif (!password || typeof password !== 'string') { return 404; }\n\t}\n\tif (userId === loggedUser) {\n\t\tif (newPassword === password) { return 404; }\n\t} else if (!singleUser) {\n\t\tif (!await hasUserPermission('system:user:password')) { return 402; }\n\n\t}\n\tif (loggedUser && password && !await verifyUser(loggedUser, password, 'password')) { return 403; }\n\tif ([...verifyNewPassword(newPassword)].length) { return 408; }\n\tawait setPassword(targetUser, newPassword, userId === loggedUser ? null : new Date);\n\treturn 200;\n});\n"],"mappings":";;;;;AAKA,MAAa,SAAS,IAAI,WAAW;AAErC,OAAO,GAAG,WAAW,OAAM,QAAO;CACjC,MAAM,EAAE,UAAU,aAAa,WAAW,MAAM,SAAS,IAAI,EAAE;AAC/D,KAAI,CAAC,eAAe,OAAO,gBAAgB,SAAY,QAAO;CAC9D,MAAM,aAAa,MAAM,SAAS;CAClC,MAAM,aAAa,MAAM,cAAc;AACvC,KAAI,CAAC,cAAc,CAAC,WAAc,QAAO;CACzC,MAAM,aAAa,UAAU;AAC7B,KAAI,CAAC,WAAc,QAAO;AAC1B,KAAI,WAAW,cAAc,CAAC,YAC7B;MAAI,CAAC,YAAY,OAAO,aAAa,SAAY,QAAO;;AAEzD,KAAI,WAAW,YACd;MAAI,gBAAgB,SAAY,QAAO;YAC7B,CAAC,YACX;MAAI,CAAC,MAAM,kBAAkB,uBAAuB,CAAI,QAAO;;AAGhE,KAAI,cAAc,YAAY,CAAC,MAAM,WAAW,YAAY,UAAU,WAAW,CAAI,QAAO;AAC5F,KAAI,CAAC,GAAG,kBAAkB,YAAY,CAAC,CAAC,OAAU,QAAO;AACzD,OAAM,YAAY,YAAY,aAAa,WAAW,aAAa,uBAAO,IAAI,MAAI,CAAC;AACnF,QAAO;EACN"}
@@ -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(new Query(UserPassword_default), {
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.insert(new Query(UserPassword_default), {
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-KPkkrnN4.mjs.map
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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"}