@tachybase/plugin-password-policy 1.0.6

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.
Files changed (77) hide show
  1. package/README.md +1 -0
  2. package/client.d.ts +2 -0
  3. package/client.js +1 -0
  4. package/dist/client/IPFilterForm.d.ts +1 -0
  5. package/dist/client/PasswordAttemptForm.d.ts +1 -0
  6. package/dist/client/PasswordStrengthSettingsForm.d.ts +2 -0
  7. package/dist/client/SignInFailsTable.d.ts +2 -0
  8. package/dist/client/UserLocksTable.d.ts +2 -0
  9. package/dist/client/collections/signInFails.d.ts +2 -0
  10. package/dist/client/collections/userLocks.d.ts +2 -0
  11. package/dist/client/hooks/usePasswordStrength.d.ts +11 -0
  12. package/dist/client/hooks/usePasswordValidator.d.ts +16 -0
  13. package/dist/client/index.d.ts +5 -0
  14. package/dist/client/index.js +4 -0
  15. package/dist/client/locale.d.ts +6 -0
  16. package/dist/constants.d.ts +11 -0
  17. package/dist/constants.js +44 -0
  18. package/dist/externalVersion.js +10 -0
  19. package/dist/index.d.ts +2 -0
  20. package/dist/index.js +39 -0
  21. package/dist/locale/en-US.json +107 -0
  22. package/dist/locale/zh-CN.json +107 -0
  23. package/dist/node_modules/geoip-lite/LICENSE +50 -0
  24. package/dist/node_modules/geoip-lite/data/city.checksum +1 -0
  25. package/dist/node_modules/geoip-lite/data/country.checksum +1 -0
  26. package/dist/node_modules/geoip-lite/data/geoip-city-names.dat +0 -0
  27. package/dist/node_modules/geoip-lite/data/geoip-city.dat +0 -0
  28. package/dist/node_modules/geoip-lite/data/geoip-city6.dat +0 -0
  29. package/dist/node_modules/geoip-lite/data/geoip-country.dat +0 -0
  30. package/dist/node_modules/geoip-lite/data/geoip-country6.dat +0 -0
  31. package/dist/node_modules/geoip-lite/lib/fsWatcher.js +83 -0
  32. package/dist/node_modules/geoip-lite/lib/geoip.js +1 -0
  33. package/dist/node_modules/geoip-lite/lib/utils.js +98 -0
  34. package/dist/node_modules/geoip-lite/node_modules/.bin/rimraf +17 -0
  35. package/dist/node_modules/geoip-lite/package.json +1 -0
  36. package/dist/node_modules/geoip-lite/scripts/updatedb.js +685 -0
  37. package/dist/node_modules/geoip-lite/test/geo-lookup.js +56 -0
  38. package/dist/node_modules/geoip-lite/test/memory_usage.js +3 -0
  39. package/dist/node_modules/geoip-lite/test/tests.js +197 -0
  40. package/dist/server/actions/IpFilterController.d.ts +7 -0
  41. package/dist/server/actions/IpFilterController.js +124 -0
  42. package/dist/server/actions/PasswordAttemptController.d.ts +7 -0
  43. package/dist/server/actions/PasswordAttemptController.js +123 -0
  44. package/dist/server/actions/PasswordStrengthController.d.ts +7 -0
  45. package/dist/server/actions/PasswordStrengthController.js +123 -0
  46. package/dist/server/actions/SignInFailsController.d.ts +5 -0
  47. package/dist/server/actions/SignInFailsController.js +156 -0
  48. package/dist/server/actions/UserLocksController.d.ts +4 -0
  49. package/dist/server/actions/UserLocksController.js +102 -0
  50. package/dist/server/collections/ipFilter.d.ts +2 -0
  51. package/dist/server/collections/ipFilter.js +51 -0
  52. package/dist/server/collections/passwordAttempt.d.ts +2 -0
  53. package/dist/server/collections/passwordAttempt.js +55 -0
  54. package/dist/server/collections/passwordHistory.d.ts +2 -0
  55. package/dist/server/collections/passwordHistory.js +46 -0
  56. package/dist/server/collections/passwordStrengthConfig.d.ts +2 -0
  57. package/dist/server/collections/passwordStrengthConfig.js +59 -0
  58. package/dist/server/collections/signInFail.d.ts +2 -0
  59. package/dist/server/collections/signInFail.js +56 -0
  60. package/dist/server/collections/userLocks.d.ts +2 -0
  61. package/dist/server/collections/userLocks.js +51 -0
  62. package/dist/server/collections/users.d.ts +2 -0
  63. package/dist/server/collections/users.js +42 -0
  64. package/dist/server/index.d.ts +1 -0
  65. package/dist/server/index.js +33 -0
  66. package/dist/server/plugin.d.ts +5 -0
  67. package/dist/server/plugin.js +129 -0
  68. package/dist/server/services/IPFilterService.d.ts +49 -0
  69. package/dist/server/services/IPFilterService.js +270 -0
  70. package/dist/server/services/PasswordAttemptService.d.ts +75 -0
  71. package/dist/server/services/PasswordAttemptService.js +595 -0
  72. package/dist/server/services/PasswordStrengthService.d.ts +28 -0
  73. package/dist/server/services/PasswordStrengthService.js +313 -0
  74. package/dist/types/geoip-lite.d.js +0 -0
  75. package/package.json +25 -0
  76. package/server.d.ts +2 -0
  77. package/server.js +1 -0
package/README.md ADDED
@@ -0,0 +1 @@
1
+ # @tachybase/plugin-password-policy
package/client.d.ts ADDED
@@ -0,0 +1,2 @@
1
+ export * from './dist/client';
2
+ export { default } from './dist/client';
package/client.js ADDED
@@ -0,0 +1 @@
1
+ module.exports = require('./dist/client/index.js');
@@ -0,0 +1 @@
1
+ export declare const IPFilterForm: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare const PasswordAttemptForm: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ declare const _default: () => import("react/jsx-runtime").JSX.Element;
2
+ export default _default;
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const SignInFailsTable: React.FC;
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const UserLockTable: React.FC;
@@ -0,0 +1,2 @@
1
+ import { CollectionOptions } from '@tachybase/client';
2
+ export declare const signInFailsCollection: CollectionOptions;
@@ -0,0 +1,2 @@
1
+ import { CollectionOptions } from '@tachybase/client';
2
+ export declare const userLockCollection: CollectionOptions;
@@ -0,0 +1,11 @@
1
+ interface PasswordStrengthConfig {
2
+ minLength: number;
3
+ strengthLevel: number;
4
+ notContainUsername: boolean;
5
+ historyCount: number;
6
+ }
7
+ export declare function usePasswordStrength(): {
8
+ config: PasswordStrengthConfig;
9
+ loading: boolean;
10
+ };
11
+ export {};
@@ -0,0 +1,16 @@
1
+ import { PasswordStrengthLevel } from '../../constants';
2
+ interface PasswordConfig {
3
+ minLength: number;
4
+ strengthLevel: PasswordStrengthLevel;
5
+ notContainUsername: boolean;
6
+ historyCount: number;
7
+ }
8
+ export declare const usePasswordValidator: () => {
9
+ config: PasswordConfig;
10
+ loading: boolean;
11
+ validatePassword: (password: string, username?: string) => {
12
+ valid: boolean;
13
+ message?: string;
14
+ };
15
+ };
16
+ export {};
@@ -0,0 +1,5 @@
1
+ import { Plugin } from '@tachybase/client';
2
+ export declare class PasswordPolicyClient extends Plugin {
3
+ load(): Promise<void>;
4
+ }
5
+ export default PasswordPolicyClient;
@@ -0,0 +1,4 @@
1
+ (function(s,t){typeof exports=="object"&&typeof module!="undefined"?t(exports,require("@tachybase/client"),require("react/jsx-runtime"),require("@tachybase/schema"),require("antd")):typeof define=="function"&&define.amd?define(["exports","@tachybase/client","react/jsx-runtime","@tachybase/schema","antd"],t):(s=typeof globalThis!="undefined"?globalThis:s||self,t(s["@tachybase/plugin-password-policy"]={},s["@tachybase/client"],s.jsxRuntime,s["@tachybase/schema"],s.antd))})(this,function(s,t,n,l,a){"use strict";var j=Object.defineProperty;var g=Object.getOwnPropertySymbols;var K=Object.prototype.hasOwnProperty,$=Object.prototype.propertyIsEnumerable;var f=(s,t,n)=>t in s?j(s,t,{enumerable:!0,configurable:!0,writable:!0,value:n}):s[t]=n,h=(s,t)=>{for(var n in t||(t={}))K.call(t,n)&&f(s,n,t[n]);if(g)for(var n of g(t))$.call(t,n)&&f(s,n,t[n]);return s};var y=(s,t,n)=>new Promise((l,a)=>{var b=e=>{try{d(n.next(e))}catch(u){a(u)}},c=e=>{try{d(n.throw(e))}catch(u){a(u)}},d=e=>e.done?l(e.value):Promise.resolve(e.value).then(b,c);d((n=n.apply(s,t)).next())});const b="password-policy";var c=(o=>(o[o.None=0]="None",o[o.NumberAndLetter=1]="NumberAndLetter",o[o.NumberAndLetterAndSymbol=2]="NumberAndLetterAndSymbol",o[o.NumberAndLetterAndUpperAndLower=3]="NumberAndLetterAndUpperAndLower",o[o.NumberAndLetterAndUpperAndLowerAndSymbol=4]="NumberAndLetterAndUpperAndLowerAndSymbol",o[o.NumberAndLetterAndUpperAndLowerAndSymbol3=5]="NumberAndLetterAndUpperAndLowerAndSymbol3",o))(c||{});function d(){return{t:(r,p={})=>t.i18n.t(r,h({ns:b},p))}}const e=o=>t.tval(o,{ns:b}),u=()=>{const o=t.useAPIClient(),{data:r}=t.useRequest(()=>o.resource("ipFilter").get().then(i=>{var m;return(m=i.data)==null?void 0:m.data}));return{form:l.createForm({values:r})}},v=()=>{const o=l.useForm(),{message:r}=a.App.useApp(),p=t.useAPIClient(),{t:i}=d();return{run(){return y(this,null,function*(){yield o.submit();try{yield p.request({url:"ipFilter:put",method:"post",data:o.values}),r.success(i("Settings saved successfully"))}catch(x){throw r.error(i("Failed to save settings")),x}})}}},k={type:"object",properties:{ipFilter:{"x-component":"FormV2","x-use-component-props":"useIPFilterValues",type:"void",title:e("IP Filter Settings"),properties:{allowFirst:{type:"boolean",title:e("Filter Mode"),default:!0,description:e("Choose how to apply white and black lists"),"x-decorator":"FormItem","x-component":"Radio.Group",enum:[{label:e("Allow first (whitelist priority)"),value:!0},{label:e("Block first (blacklist priority)"),value:!1}]},allowList:{type:"string",title:e("Allow List (Whitelist)"),"x-decorator":"FormItem","x-component":"Input.TextArea","x-component-props":{rows:6,placeholder:`127.0.0.1
2
+ 192.168.0.0/16
3
+ 10.0.0.0/8`},description:e("One IP or CIDR per line. Example: 192.168.1.0/24 or 10.0.0.1")},blockList:{type:"string",title:e("Block List (Blacklist)"),"x-decorator":"FormItem","x-component":"Input.TextArea","x-component-props":{rows:6,placeholder:`1.2.3.4
4
+ 5.6.0.0/16`},description:e("One IP or CIDR per line. Example: 1.2.3.4 or 5.6.7.0/24")},footer:{type:"void","x-component":"ActionBar",properties:{submit:{title:e("Save"),"x-component":"Action","x-component-props":{type:"primary",useAction:"{{ useSaveIPFilterValues }}"}}}}}}}},w=()=>n.jsx(a.Card,{bordered:!1,children:n.jsx(t.SchemaComponent,{schema:k,scope:{useIPFilterValues:u,useSaveIPFilterValues:v}})}),C=()=>{const o=t.useAPIClient(),{data:r}=t.useRequest(()=>o.resource("passwordAttempt").get().then(i=>{var m;return(m=i.data)==null?void 0:m.data}));return{form:l.createForm({values:r})}},S=()=>{const o=l.useForm(),{message:r}=a.App.useApp(),p=t.useAPIClient(),{t:i}=d();return{run(){return y(this,null,function*(){yield o.submit();try{yield p.request({url:"passwordAttempt:put",method:"post",data:o.values}),r.success(i("Saved successfully"))}catch(x){throw r.error(i("Failed to save settings")),x}})}}},F={type:"object",properties:{passwordAttempt:{"x-component":"FormV2","x-use-component-props":"usePasswordPolicyValues",type:"void",title:e("Password policy"),properties:{maxAttempts:{type:"digit",title:e("Max invalid password sign-in attempts"),description:e("Default value is 5. Set to 0 to disable."),"x-decorator":"FormItem","x-component":"InputNumber","x-validator":{required:!0},"x-component-props":{min:0}},windowSeconds:{type:"digit",title:e("Max invalid password sign-in attempts interval (seconds)"),description:e("Default value is 300 seconds (5 minutes)."),"x-decorator":"FormItem","x-component":"InputNumber","x-validator":{required:!0},"x-component-props":{min:1}},lockSeconds:{type:"digit",title:e("Lockout duration (seconds)"),description:e("Default value is 1800 seconds (30 minutes)."),"x-decorator":"FormItem","x-component":"InputNumber","x-validator":{required:!0},"x-component-props":{min:1}},strictLock:{type:"boolean",title:e("Can not access any api after locked"),description:e("Default value is off."),"x-decorator":"FormItem","x-component":"Checkbox"},footer:{type:"void","x-component":"ActionBar",properties:{submit:{title:'{{t("Submit")}}',"x-component":"Action","x-component-props":{type:"primary",useAction:"{{ useSavePasswordPolicyValues }}"}}}}}}}},P=()=>n.jsx(a.Card,{bordered:!1,children:n.jsx(t.SchemaComponent,{schema:F,scope:{usePasswordPolicyValues:C,useSavePasswordPolicyValues:S}})}),I=()=>{const o=t.useAPIClient(),{data:r}=t.useRequest(()=>o.resource("passwordStrengthConfig").get().then(i=>{var m;return(m=i.data)==null?void 0:m.data}));return{form:l.createForm({values:r})}},L=()=>{const o=l.useForm(),{message:r}=a.App.useApp(),p=t.useAPIClient(),{t:i}=d();return{run(){return y(this,null,function*(){yield o.submit();try{yield p.request({url:"passwordStrengthConfig:put",method:"post",data:o.values}),r.success(i("Saved successfully"))}catch(x){throw r.error(i("Failed to save settings")),x}})}}},T={type:"object",properties:{passwordStrength:{"x-component":"FormV2","x-use-component-props":"usePasswordStrengthValues",type:"void",title:e("Password Strength Settings"),properties:{minLength:{type:"number",title:e("Minimum Password Length"),"x-decorator":"FormItem","x-component":"InputNumber",default:0},strengthLevel:{type:"number",title:e("Password Strength Requirements"),"x-decorator":"FormItem","x-component":"Select",enum:[{label:e("No restrictions"),value:c.None},{label:e("Must contain letters and numbers"),value:c.NumberAndLetter},{label:e("Must contain letters, numbers, and symbols"),value:c.NumberAndLetterAndSymbol},{label:e("Must contain numbers, uppercase and lowercase letters"),value:c.NumberAndLetterAndUpperAndLower},{label:e("Must contain numbers, uppercase and lowercase letters, and symbols"),value:c.NumberAndLetterAndUpperAndLowerAndSymbol},{label:e("Must contain at least 3 of the following: numbers, uppercase letters, lowercase letters, and symbols"),value:c.NumberAndLetterAndUpperAndLowerAndSymbol3}],default:0},notContainUsername:{type:"boolean",title:e("Password cannot contain username"),"x-decorator":"FormItem","x-component":"Checkbox",default:!1},historyCount:{type:"number",title:e("Remember password history (0-24)"),description:e("Number of previous passwords to remember. 0 means no restriction."),"x-decorator":"FormItem","x-component":"InputNumber","x-component-props":{min:0,max:24},default:0},footer:{type:"void","x-component":"ActionBar",properties:{submit:{title:'{{t("Submit")}}',"x-component":"Action","x-component-props":{type:"primary",useAction:"{{ useSavePasswordStrengthValues }}"}}}}}}}},V=()=>n.jsx(a.Card,{bordered:!1,children:n.jsx(t.SchemaComponent,{schema:T,scope:{usePasswordStrengthValues:I,useSavePasswordStrengthValues:L}})}),N={name:"signInFails",fields:[{type:"string",name:"username",interface:"input",uiSchema:{type:"string",title:'{{ t("Username") }}',"x-read-pretty":!0,"x-component"(){var r;return(r=t.useRecord().user)==null?void 0:r.username}}},{type:"string",name:"nickname",interface:"input",uiSchema:{type:"string",title:'{{ t("Nickname") }}',"x-read-pretty":!0,"x-component"(){var r;return(r=t.useRecord().user)==null?void 0:r.nickname}}},{type:"string",name:"ip",interface:"input",uiSchema:{type:"string",title:"IP","x-read-pretty":!0}},{type:"string",name:"address",interface:"input",uiSchema:{type:"string",title:e("Location"),"x-read-pretty":!0}},{type:"datetime",name:"createdAt",interface:"datetime",uiSchema:{type:"string",title:e("Time"),"x-component":"DatePicker","x-component-props":{showTime:!0},"x-read-pretty":!0}},{name:"user",type:"belongsTo",target:"users",targetKey:"id",foreignKey:"userId",interface:"m2o",uiSchema:{type:"object",title:'{{t("User")}}',"x-component":"AssociationField","x-component-props":{fieldNames:{value:"id",label:"nickname"}},"x-read-pretty":!0}}]},D={type:"void",properties:{signInFails:{type:"void","x-decorator":"TableBlockProvider","x-acl-action":"signInFails:list","x-use-decorator-props":"useTableBlockDecoratorProps","x-decorator-props":{dataSource:"main",collection:"signInFails",action:"list",params:{pageSize:20,appends:["user"]},rowKey:"id",showIndex:!0,dragSort:!1},"x-component":"CardItem",properties:{actions:{type:"void","x-component":"ActionBar","x-component-props":{style:{marginBottom:"var(--tb-spacing)"}},properties:{filter:{type:"void",title:'{{ t("Filter") }}',"x-action":"filter","x-component":"Filter.Action","x-use-component-props":"useFilterActionProps","x-component-props":{icon:"FilterOutlined"},"x-align":"left"},refresh:{type:"void",title:'{{ t("Refresh") }}',"x-action":"refresh","x-component":"Action","x-settings":"actionSettings:refresh","x-component-props":{icon:"ReloadOutlined"},"x-use-component-props":"useRefreshActionProps","x-align":"right"}}},table:{type:"array","x-component":"TableV2","x-use-component-props":"useTableBlockProps","x-component-props":{rowKey:"id",rowSelection:{type:"checkbox"}},properties:{username:{type:"void","x-decorator":"TableV2.Column.Decorator","x-component":"TableV2.Column",properties:{username:{type:"string","x-component":"CollectionField","x-read-pretty":!0}}},nickname:{type:"void","x-decorator":"TableV2.Column.Decorator","x-component":"TableV2.Column",properties:{nickname:{type:"string","x-component":"CollectionField","x-read-pretty":!0}}},ip:{type:"void","x-decorator":"TableV2.Column.Decorator","x-component":"CollectionField",properties:{ip:{type:"string","x-component":"CollectionField","x-read-pretty":!0}}},address:{type:"void","x-decorator":"TableV2.Column.Decorator","x-component":"CollectionField",properties:{address:{type:"string","x-component":"CollectionField","x-read-pretty":!0}}},createdAt:{type:"void","x-decorator":"TableV2.Column.Decorator","x-component":"CollectionField",properties:{createdAt:{type:"datetime","x-component":"CollectionField","x-read-pretty":!0}}}}}}}}},B=()=>n.jsx(t.ExtendCollectionsProvider,{collections:[N],children:n.jsx(t.SchemaComponent,{schema:D})}),U={name:"userLocks",fields:[{type:"string",name:"username",interface:"input",uiSchema:{type:"string",title:'{{ t("Username") }}',"x-read-pretty":!0,"x-component"(){var r;return(r=t.useRecord().user)==null?void 0:r.username}}},{type:"string",name:"nickname",interface:"input",uiSchema:{type:"string",title:'{{ t("Nickname") }}',"x-read-pretty":!0,"x-component"(){var r;return(r=t.useRecord().user)==null?void 0:r.nickname}}},{type:"datetime",name:"updatedAt",interface:"datetime",uiSchema:{type:"string",title:e("Updated At"),"x-component":"DatePicker","x-component-props":{showTime:!0},"x-read-pretty":!0}},{type:"datetime",name:"expireAt",interface:"datetime",uiSchema:{type:"string",title:e("Lock Expires At"),"x-component":"DatePicker","x-component-props":{showTime:!0},"x-read-pretty":!0}},{name:"user",type:"belongsTo",target:"users",targetKey:"id",foreignKey:"userId",interface:"m2o",uiSchema:{type:"object",title:'{{t("User")}}',"x-component":"AssociationField","x-component-props":{fieldNames:{value:"id",label:"nickname"}},"x-read-pretty":!0}}]},M={type:"void","x-acl-action-props":{skipScopeCheck:!0},"x-acl-action":"userLocks:create","x-decorator":"FormBlockProvider","x-use-decorator-props":"useCreateFormBlockDecoratorProps","x-decorator-props":{dataSource:"main",collection:"userLocks"},"x-component":"CardItem",properties:{form:{type:"void","x-component":"FormV2","x-use-component-props":"useCreateFormBlockProps",properties:{actionBar:{type:"void","x-component":"ActionBar","x-component-props":{style:{marginBottom:"var(--tb-spacing)"}},properties:{submit:{title:'{{t("Submit")}}',"x-action":"submit","x-component":"Action","x-use-component-props":"useCreateActionProps","x-component-props":{type:"primary",htmlType:"submit"},type:"void"}}},userId:{type:"string",title:e("Username or Email"),required:!0,"x-component":"RemoteSelect","x-decorator":"FormItem","x-component-props":{placeholder:e("Please enter username, nickname or email"),fieldNames:{label:"nickname",value:"id"},service:{resource:"users",action:"list",params:{filter:{$or:[{lock:{id:{$notExists:!0}}},{lock:{expireAt:{$lt:"{{ new Date() }}"}}}]},pageSize:20,sort:["-id"],appends:["lock"]}},manual:!1}},expireAt:{type:"string",title:e("Lock Until"),required:!0,"x-component":"DatePicker","x-decorator":"FormItem","x-component-props":{showTime:!0,disabledDate:"{{ (current) => current && current < new Date() }}",placeholder:e("Please select lock expiration time")}}}}}},q={type:"void","x-action":"create","x-acl-action":"create",title:e("Lock New User"),"x-component":"Action","x-decorator":"ACLActionProvider","x-component-props":{openMode:"drawer",type:"primary",icon:"PlusOutlined"},"x-align":"right","x-acl-action-props":{skipScopeCheck:!0},properties:{drawer:{type:"void",title:e("Lock New User"),"x-component":"Action.Container","x-component-props":{className:"tb-action-popup"},properties:{form:M}}}},E={type:"void",title:'{{ t("Edit") }}',"x-action":"update","x-component":"Action.Link","x-component-props":{openMode:"drawer",icon:"EditOutlined"},"x-decorator":"ACLActionProvider",properties:{drawer:{type:"void",title:'{{ t("Edit") }}',"x-component":"Action.Container","x-component-props":{className:"tb-action-popup"},properties:{form:{type:"void","x-acl-action-props":{skipScopeCheck:!1},"x-decorator":"FormBlockProvider","x-use-decorator-props":"useEditFormBlockDecoratorProps","x-decorator-props":{dataSource:"main",collection:"userLocks",action:"get",useParams:"{{ useParamsFromRecord }}",params:{appends:["user"]}},"x-component":"CardItem",properties:{form:{type:"void","x-component":"FormV2","x-use-component-props":"useEditFormBlockProps",properties:{actionBar:{type:"void","x-component":"ActionBar","x-component-props":{style:{marginBottom:"var(--tb-spacing)"}},properties:{submit:{title:'{{t("Submit")}}',"x-action":"submit","x-component":"Action","x-use-component-props":"useUpdateActionProps","x-component-props":{type:"primary",htmlType:"submit"},"x-action-settings":{triggerWorkflows:[],onSuccess:{manualClose:!1,redirecting:!1,successMessage:'{{t("Updated successfully")}}'},skipValidator:!1},type:"void"}}},expireAt:{type:"date",title:e("Lock Until"),required:!0,"x-component":"DatePicker","x-component-props":{showTime:!0,disabledDate:"{{ (current) => current && current < new Date() }}",placeholder:e("Please select lock expiration time")},"x-decorator":"FormItem"}}}}}}}}},O={type:"void",properties:{userLocks:{type:"void","x-decorator":"TableBlockProvider","x-acl-action":"userLocks:list","x-use-decorator-props":"useTableBlockDecoratorProps","x-decorator-props":{dataSource:"main",collection:"userLocks",action:"list",params:{pageSize:20,appends:["user"]},rowKey:"id",showIndex:!0,dragSort:!1},"x-component":"CardItem",properties:{actions:{type:"void","x-component":"ActionBar","x-component-props":{style:{marginBottom:"var(--tb-spacing)"}},properties:{filter:{type:"void",title:'{{ t("Filter") }}',"x-action":"filter","x-component":"Filter.Action","x-use-component-props":"useFilterActionProps","x-component-props":{icon:"FilterOutlined"},"x-align":"left"},refresh:{type:"void",title:'{{ t("Refresh") }}',"x-action":"refresh","x-component":"Action","x-settings":"actionSettings:refresh","x-component-props":{icon:"ReloadOutlined"},"x-use-component-props":"useRefreshActionProps","x-align":"right"},create:q}},table:{type:"array","x-component":"TableV2","x-use-component-props":"useTableBlockProps","x-component-props":{rowKey:"id",rowSelection:{type:"checkbox"}},properties:{username:{type:"void","x-decorator":"TableV2.Column.Decorator","x-component":"TableV2.Column",properties:{username:{type:"string","x-component":"CollectionField","x-read-pretty":!0}}},nickname:{type:"void","x-decorator":"TableV2.Column.Decorator","x-component":"TableV2.Column",properties:{nickname:{type:"string","x-component":"CollectionField","x-read-pretty":!0}}},updatedAt:{type:"void",title:e("Updated At"),"x-decorator":"TableV2.Column.Decorator","x-component":"TableV2.Column",properties:{updatedAt:{"x-collection-field":"userLocks.updatedAt","x-component":"CollectionField","x-component-props":{ellipsis:!0,showTime:!0},"x-read-pretty":!0,"x-decorator":null}}},expireAt:{type:"void",title:e("Lock Expires At"),"x-decorator":"TableV2.Column.Decorator","x-component":"TableV2.Column",properties:{expireAt:{"x-collection-field":"userLocks.expireAt","x-component":"CollectionField","x-component-props":{ellipsis:!0,showTime:!0},"x-read-pretty":!0,"x-decorator":null}}},actions:{type:"void",title:'{{ t("Actions") }}',"x-action-column":"actions","x-decorator":"TableV2.Column.ActionBar","x-component":"TableV2.Column","x-component-props":{width:200,fixed:"right"},properties:{actions:{type:"void","x-component":"Space","x-component-props":{split:"|"},properties:{edit:E,destroy:{type:"void",title:e("Unlock"),"x-action":"destroy","x-component":"Action.Link","x-component-props":{danger:!0,confirm:{title:e("Unlock User"),content:e("Are you sure you want to unlock this user?")}},"x-decorator":"ACLActionProvider","x-use-component-props":"useDestroyActionProps"}}}}}}}}}}},R=()=>n.jsx(t.ExtendCollectionsProvider,{collections:[U],children:n.jsx(t.SchemaComponent,{schema:O})});class A extends t.Plugin{load(){return y(this,null,function*(){this.app.systemSettingsManager.add("security.password-attempt",{icon:"SettingOutlined",title:e("Password policy"),Component:P,aclSnippet:"pm.security.password-attempt"}),this.app.systemSettingsManager.add("security.user-lock",{icon:"UserOutlined",title:e("User lock"),Component:R,aclSnippet:"pm.security.user-lock"}),this.app.systemSettingsManager.add("security.ip-filter",{icon:"GlobalOutlined",title:e("IP policy"),Component:w,aclSnippet:"pm.security.ip-filter"}),this.app.systemSettingsManager.add("security.password-strength",{icon:"LockOutlined",title:e("Password strength"),Component:V,aclSnippet:"pm.security.password-strength"}),this.app.systemSettingsManager.add("security.sign-in-fails",{icon:"HistoryOutlined",title:e("Sign-in fails history"),Component:B,aclSnippet:"pm.security.sign-in-fails"})})}}s.PasswordPolicyClient=A,s.default=A,Object.defineProperties(s,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})});
@@ -0,0 +1,6 @@
1
+ export declare function usePluginTranslation(): any;
2
+ export declare function useTranslation(): {
3
+ t: (key: string, options?: {}) => string;
4
+ };
5
+ export declare function lang(key: string, options?: {}): string;
6
+ export declare const tval: (key: string) => string;
@@ -0,0 +1,11 @@
1
+ export declare const NAMESPACE = "password-policy";
2
+ export declare enum PasswordStrengthLevel {
3
+ None = 0,
4
+ NumberAndLetter = 1,
5
+ NumberAndLetterAndSymbol = 2,
6
+ NumberAndLetterAndUpperAndLower = 3,
7
+ NumberAndLetterAndUpperAndLowerAndSymbol = 4,
8
+ NumberAndLetterAndUpperAndLowerAndSymbol3 = 5
9
+ }
10
+ export declare const WINDOW_SECONDS = 300;
11
+ export declare const LOCK_SECONDS = 1800;
@@ -0,0 +1,44 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __getOwnPropNames = Object.getOwnPropertyNames;
4
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
5
+ var __export = (target, all) => {
6
+ for (var name in all)
7
+ __defProp(target, name, { get: all[name], enumerable: true });
8
+ };
9
+ var __copyProps = (to, from, except, desc) => {
10
+ if (from && typeof from === "object" || typeof from === "function") {
11
+ for (let key of __getOwnPropNames(from))
12
+ if (!__hasOwnProp.call(to, key) && key !== except)
13
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
14
+ }
15
+ return to;
16
+ };
17
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
18
+ var constants_exports = {};
19
+ __export(constants_exports, {
20
+ LOCK_SECONDS: () => LOCK_SECONDS,
21
+ NAMESPACE: () => NAMESPACE,
22
+ PasswordStrengthLevel: () => PasswordStrengthLevel,
23
+ WINDOW_SECONDS: () => WINDOW_SECONDS
24
+ });
25
+ module.exports = __toCommonJS(constants_exports);
26
+ const NAMESPACE = "password-policy";
27
+ var PasswordStrengthLevel = /* @__PURE__ */ ((PasswordStrengthLevel2) => {
28
+ PasswordStrengthLevel2[PasswordStrengthLevel2["None"] = 0] = "None";
29
+ PasswordStrengthLevel2[PasswordStrengthLevel2["NumberAndLetter"] = 1] = "NumberAndLetter";
30
+ PasswordStrengthLevel2[PasswordStrengthLevel2["NumberAndLetterAndSymbol"] = 2] = "NumberAndLetterAndSymbol";
31
+ PasswordStrengthLevel2[PasswordStrengthLevel2["NumberAndLetterAndUpperAndLower"] = 3] = "NumberAndLetterAndUpperAndLower";
32
+ PasswordStrengthLevel2[PasswordStrengthLevel2["NumberAndLetterAndUpperAndLowerAndSymbol"] = 4] = "NumberAndLetterAndUpperAndLowerAndSymbol";
33
+ PasswordStrengthLevel2[PasswordStrengthLevel2["NumberAndLetterAndUpperAndLowerAndSymbol3"] = 5] = "NumberAndLetterAndUpperAndLowerAndSymbol3";
34
+ return PasswordStrengthLevel2;
35
+ })(PasswordStrengthLevel || {});
36
+ const WINDOW_SECONDS = 300;
37
+ const LOCK_SECONDS = 1800;
38
+ // Annotate the CommonJS export names for ESM import in node:
39
+ 0 && (module.exports = {
40
+ LOCK_SECONDS,
41
+ NAMESPACE,
42
+ PasswordStrengthLevel,
43
+ WINDOW_SECONDS
44
+ });
@@ -0,0 +1,10 @@
1
+ module.exports = {
2
+ "react": "18.3.1",
3
+ "@tachybase/client": "1.0.6",
4
+ "@tachybase/schema": "1.0.6",
5
+ "antd": "5.22.5",
6
+ "@tachybase/server": "1.0.6",
7
+ "@tachybase/actions": "1.0.6",
8
+ "@tachybase/utils": "1.0.6",
9
+ "@tachybase/database": "1.0.6"
10
+ };
@@ -0,0 +1,2 @@
1
+ export * from './server';
2
+ export { default } from './server';
package/dist/index.js ADDED
@@ -0,0 +1,39 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
20
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
+ // If the importer is in node compatibility mode or this is not an ESM
22
+ // file that has been converted to a CommonJS file using a Babel-
23
+ // compatible transform (i.e. "__esModule" has not been set), then set
24
+ // "default" to the CommonJS "module.exports" for node compatibility.
25
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
+ mod
27
+ ));
28
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
+ var src_exports = {};
30
+ __export(src_exports, {
31
+ default: () => import_server.default
32
+ });
33
+ module.exports = __toCommonJS(src_exports);
34
+ __reExport(src_exports, require("./server"), module.exports);
35
+ var import_server = __toESM(require("./server"));
36
+ // Annotate the CommonJS export names for ESM import in node:
37
+ 0 && (module.exports = {
38
+ ...require("./server")
39
+ });
@@ -0,0 +1,107 @@
1
+ {
2
+ "Actions": "Actions",
3
+ "Allow List (Whitelist)": "Allow List (Whitelist)",
4
+ "Allow first (whitelist priority)": "Allow first (whitelist priority)",
5
+ "Are you sure you want to unlock this user?": "Are you sure you want to unlock this user?",
6
+ "Block List (Blacklist)": "Block List (Blacklist)",
7
+ "Block first (blacklist priority)": "Block first (blacklist priority)",
8
+ "Can not access any api after locked": "Can not access any api after locked",
9
+ "Choose how to apply white and black lists": "Choose how to apply white and black lists",
10
+ "City": "City",
11
+ "Country": "Country",
12
+ "Days": "Days",
13
+ "Default value is 1800 seconds (30 minutes).": "Default value is 1800 seconds (30 minutes).",
14
+ "Default value is 30 minutes.": "Default value is 30 minutes.",
15
+ "Default value is 300 seconds (5 minutes).": "Default value is 300 seconds (5 minutes).",
16
+ "Default value is 5 minutes.": "Default value is 5 minutes.",
17
+ "Default value is 5. Set to 0 to disable.": "Default value is 5. Set to 0 to disable.",
18
+ "Default value is off.": "Default value is off.",
19
+ "Edit": "Edit",
20
+ "Edit Lock": "Edit Lock",
21
+ "Email": "Email",
22
+ "Failed to load IP filter settings": "Failed to load IP filter settings",
23
+ "Failed to load locked users": "Failed to load locked users",
24
+ "Failed to load password strength settings": "Failed to load password strength settings",
25
+ "Failed to load sign-in fail record": "Failed to load sign-in fail record",
26
+ "Failed to load sign-in fails history": "Failed to load sign-in fails history",
27
+ "Failed to save password strength settings": "Failed to save password strength settings",
28
+ "Failed to save settings": "Failed to save settings",
29
+ "Failed to unlock user": "Failed to unlock user",
30
+ "Failed to update user lock": "Failed to update user lock",
31
+ "Failed to validate password history": "Failed to validate password history",
32
+ "Failed to validate password strength": "Failed to validate password strength",
33
+ "Filter": "Filter",
34
+ "Filter Mode": "Filter Mode",
35
+ "Hours": "Hours",
36
+ "IP Filter Settings": "IP Filter Settings",
37
+ "IP policy": "IP policy",
38
+ "Location": "Location",
39
+ "Lock Expires At": "Lock Expires At",
40
+ "Lock New User": "Lock New User",
41
+ "Lock Until": "Lock Until",
42
+ "Lockout duration": "Lockout duration",
43
+ "Lockout duration (seconds)": "Lockout duration (seconds)",
44
+ "Max invalid password sign-in attempts": "Max invalid password sign-in attempts",
45
+ "Max invalid password sign-in attempts interval": "Max invalid password sign-in attempts interval",
46
+ "Max invalid password sign-in attempts interval (seconds)": "Max invalid password sign-in attempts interval (seconds)",
47
+ "Minimum Password Length": "Minimum Password Length",
48
+ "Minutes": "Minutes",
49
+ "Must contain at least 3 of the following: numbers, uppercase letters, lowercase letters, and symbols": "Must contain at least 3 of the following: numbers, uppercase letters, lowercase letters, and symbols",
50
+ "Must contain letters and numbers": "Must contain letters and numbers",
51
+ "Must contain letters, numbers, and symbols": "Must contain letters, numbers, and symbols",
52
+ "Must contain numbers, uppercase and lowercase letters": "Must contain numbers, uppercase and lowercase letters",
53
+ "Must contain numbers, uppercase and lowercase letters, and symbols": "Must contain numbers, uppercase and lowercase letters, and symbols",
54
+ "Nickname": "Nickname",
55
+ "No password strength requirements": "No password strength requirements",
56
+ "No restrictions": "No restrictions",
57
+ "Number of previous passwords to remember. 0 means no restriction.": "Number of previous passwords to remember. 0 means no restriction.",
58
+ "One IP or CIDR per line. Example: 1.2.3.4 or 5.6.7.0/24": "One IP or CIDR per line. Example: 1.2.3.4 or 5.6.7.0/24",
59
+ "One IP or CIDR per line. Example: 192.168.1.0/24 or 10.0.0.1": "One IP or CIDR per line. Example: 192.168.1.0/24 or 10.0.0.1",
60
+ "Password": "Password",
61
+ "Password Strength": "Password Strength",
62
+ "Password Strength Requirements": "Password Strength Requirements",
63
+ "Password Strength Settings": "Password Strength Settings",
64
+ "Password cannot contain username": "Password cannot contain username",
65
+ "Password has been used recently. Please choose a different password.": "Password has been used recently. Please choose a different password.",
66
+ "Password length not match minimum length": "Password length not match minimum length",
67
+ "Password must be at least {{length}} characters long": "Password must be at least {{length}} characters long",
68
+ "Password must contain at least 3 of the following: numbers, uppercase letters, lowercase letters, and symbols": "Password must contain at least 3 of the following: numbers, uppercase letters, lowercase letters, and symbols",
69
+ "Password must contain both letters and numbers": "Password must contain both letters and numbers",
70
+ "Password must contain letters, numbers, and symbols": "Password must contain letters, numbers, and symbols",
71
+ "Password must contain numbers, uppercase and lowercase letters": "Password must contain numbers, uppercase and lowercase letters",
72
+ "Password must contain numbers, uppercase and lowercase letters, and symbols": "Password must contain numbers, uppercase and lowercase letters, and symbols",
73
+ "Password policy": "Password policy",
74
+ "Password strength": "Password strength",
75
+ "Password strength settings saved successfully": "Password strength settings saved successfully",
76
+ "Password strength: Medium": "Password strength: Medium",
77
+ "Password strength: Strong": "Password strength: Strong",
78
+ "Password strength: Very Strong": "Password strength: Very Strong",
79
+ "Please enter username, nickname or email": "Please enter username, nickname or email",
80
+ "Please input minimum password length": "Please input minimum password length",
81
+ "Please input password history count": "Please input password history count",
82
+ "Please input your password": "Please input your password",
83
+ "Please select lock expiration time": "Please select lock expiration time",
84
+ "Please select password strength level": "Please select password strength level",
85
+ "Refresh": "Refresh",
86
+ "Region": "Region",
87
+ "Remember password history (0-24)": "Remember password history (0-24)",
88
+ "Save": "Save",
89
+ "Saved successfully": "Saved successfully",
90
+ "Seconds": "Seconds",
91
+ "Settings saved successfully": "Settings saved successfully",
92
+ "Sign-in fails history": "Sign-in Fails History",
93
+ "Submit": "Submit",
94
+ "Time": "Time",
95
+ "Unlock": "Unlock",
96
+ "Unlock User": "Unlock User",
97
+ "Updated At": "Updated At",
98
+ "Updated successfully": "Updated successfully",
99
+ "User Information": "User Information",
100
+ "User has been locked": "User has been locked",
101
+ "User lock": "User lock",
102
+ "User lock updated successfully": "User lock updated successfully",
103
+ "User unlocked successfully": "User unlocked successfully",
104
+ "Username": "Username",
105
+ "Username or Email": "Username or Email",
106
+ "Your IP address is not allowed to access this resource": "Your IP address is not allowed to access this resource"
107
+ }
@@ -0,0 +1,107 @@
1
+ {
2
+ "Actions": "操作",
3
+ "Allow List (Whitelist)": "允许列表(白名单)",
4
+ "Allow first (whitelist priority)": "白名单优先",
5
+ "Are you sure you want to unlock this user?": "确定要解除该用户的锁定吗?",
6
+ "Block List (Blacklist)": "禁止列表(黑名单)",
7
+ "Block first (blacklist priority)": "黑名单优先",
8
+ "Can not access any api after locked": "锁定后任意api都不能访问",
9
+ "Choose how to apply white and black lists": "选择如何应用白名单和黑名单",
10
+ "City": "城市",
11
+ "Country": "国家",
12
+ "Days": "天",
13
+ "Default value is 1800 seconds (30 minutes).": "默认值为1800秒(30分钟)。",
14
+ "Default value is 30 minutes.": "默认值为30分钟。",
15
+ "Default value is 300 seconds (5 minutes).": "默认值为300秒(5分钟)。",
16
+ "Default value is 5 minutes.": "默认值为5分钟。",
17
+ "Default value is 5. Set to 0 to disable.": "默认值为5。设置为0表示禁用。",
18
+ "Default value is off.": "默认值为关闭。",
19
+ "Edit": "编辑",
20
+ "Edit Lock": "编辑锁定",
21
+ "Email": "邮箱",
22
+ "Failed to load IP filter settings": "加载IP过滤器设置失败",
23
+ "Failed to load locked users": "加载锁定用户列表失败",
24
+ "Failed to load password strength settings": "加载密码强度设置失败",
25
+ "Failed to load sign-in fail record": "加载登录失败记录失败",
26
+ "Failed to load sign-in fails history": "加载登录失败历史记录失败",
27
+ "Failed to save password strength settings": "保存密码强度设置失败",
28
+ "Failed to save settings": "保存设置失败",
29
+ "Failed to unlock user": "解除用户锁定失败",
30
+ "Failed to update user lock": "更新用户锁定状态失败",
31
+ "Failed to validate password history": "密码历史验证失败",
32
+ "Failed to validate password strength": "密码强度验证失败",
33
+ "Filter": "筛选",
34
+ "Filter Mode": "过滤模式",
35
+ "Hours": "小时",
36
+ "IP Filter Settings": "IP过滤器设置",
37
+ "IP policy": "IP策略",
38
+ "Location": "位置",
39
+ "Lock Expires At": "锁定到期时间",
40
+ "Lock New User": "锁定新用户",
41
+ "Lock Until": "锁定至",
42
+ "Lockout duration": "锁定时间",
43
+ "Lockout duration (seconds)": "锁定时间(秒)",
44
+ "Max invalid password sign-in attempts": "登录尝试次数",
45
+ "Max invalid password sign-in attempts interval": "登录尝试最长周期",
46
+ "Max invalid password sign-in attempts interval (seconds)": "登录尝试最长周期(秒)",
47
+ "Minimum Password Length": "最小密码长度",
48
+ "Minutes": "分钟",
49
+ "Must contain at least 3 of the following: numbers, uppercase letters, lowercase letters, and symbols": "密码必须至少包含以下4种字符中的3种:数字、大写字母、小写字母和特殊符号",
50
+ "Must contain letters and numbers": "必须包含字母和数字",
51
+ "Must contain letters, numbers, and symbols": "必须包含字母、数字和符号",
52
+ "Must contain numbers, uppercase and lowercase letters": "必须包含数字、大写和小写字母",
53
+ "Must contain numbers, uppercase and lowercase letters, and symbols": "必须包含数字、大写和小写字母和符号",
54
+ "Nickname": "昵称",
55
+ "No password strength requirements": "无密码强度要求",
56
+ "No restrictions": "无限制",
57
+ "Number of previous passwords to remember. 0 means no restriction.": "记住之前使用过的密码数量,0表示不限制",
58
+ "One IP or CIDR per line. Example: 1.2.3.4 or 5.6.7.0/24": "每行一个IP或CIDR。例如:1.2.3.4 或 5.6.7.0/24",
59
+ "One IP or CIDR per line. Example: 192.168.1.0/24 or 10.0.0.1": "每行一个IP或CIDR。例如:192.168.1.0/24 或 10.0.0.1",
60
+ "Password": "密码",
61
+ "Password Strength": "密码强度",
62
+ "Password Strength Requirements": "密码强度要求",
63
+ "Password Strength Settings": "密码强度设置",
64
+ "Password cannot contain username": "密码不能包含用户名",
65
+ "Password has been used recently. Please choose a different password.": "该密码最近已使用过,请选择其他密码",
66
+ "Password length not match minimum length": "密码长度不符合最小长度要求",
67
+ "Password must be at least {{length}} characters long": "密码长度必须至少为 {{length}} 个字符",
68
+ "Password must contain at least 3 of the following: numbers, uppercase letters, lowercase letters, and symbols": "密码必须至少包含以下4种字符中的3种:数字、大写字母、小写字母和特殊符号",
69
+ "Password must contain both letters and numbers": "密码必须同时包含字母和数字",
70
+ "Password must contain letters, numbers, and symbols": "密码必须包含字母、数字和符号",
71
+ "Password must contain numbers, uppercase and lowercase letters": "密码必须包含数字、大写字母和小写字母",
72
+ "Password must contain numbers, uppercase and lowercase letters, and symbols": "密码必须包含数字、大写字母、小写字母和特殊符号",
73
+ "Password policy": "密码策略",
74
+ "Password strength": "密码强度",
75
+ "Password strength settings saved successfully": "密码强度设置保存成功",
76
+ "Password strength: Medium": "密码强度:中等",
77
+ "Password strength: Strong": "密码强度:强",
78
+ "Password strength: Very Strong": "密码强度:非常强",
79
+ "Please enter username, nickname or email": "请输入用户名、昵称或邮箱",
80
+ "Please input minimum password length": "请输入最小密码长度",
81
+ "Please input password history count": "请输入密码历史数量",
82
+ "Please input your password": "请输入密码",
83
+ "Please select lock expiration time": "请选择锁定到期时间",
84
+ "Please select password strength level": "请选择密码强度级别",
85
+ "Refresh": "刷新",
86
+ "Region": "地区",
87
+ "Remember password history (0-24)": "记住密码历史 (0-24)",
88
+ "Save": "保存",
89
+ "Saved successfully": "保存成功",
90
+ "Seconds": "秒",
91
+ "Settings saved successfully": "设置保存成功",
92
+ "Sign-in fails history": "登录失败历史记录",
93
+ "Submit": "提交",
94
+ "Time": "时间",
95
+ "Unlock": "解除锁定",
96
+ "Unlock User": "解除用户锁定",
97
+ "Updated At": "更新时间",
98
+ "Updated successfully": "更新成功",
99
+ "User Information": "用户信息",
100
+ "User has been locked": "用户已经锁定",
101
+ "User lock": "用户锁定",
102
+ "User lock updated successfully": "更新用户锁定状态成功",
103
+ "User unlocked successfully": "已成功解除用户锁定",
104
+ "Username": "用户名",
105
+ "Username or Email": "用户名或邮箱",
106
+ "Your IP address is not allowed to access this resource": "您的IP地址不允许访问此资源"
107
+ }
@@ -0,0 +1,50 @@
1
+ There are two licenses, one for the software library, and one for the data.
2
+
3
+ This product includes GeoLite data created by MaxMind, available from http://maxmind.com/
4
+
5
+ SOFTWARE LICENSE (Node JS library)
6
+
7
+ The node-geoip JavaScript library is licensed under the Apache License, Version 2.0:
8
+
9
+ Copyright 2011 Philip Tellis <philip@bluesmoon.info>
10
+
11
+ Licensed under the Apache License, Version 2.0 (the "License");
12
+ you may not use this file except in compliance with the License.
13
+ You may obtain a copy of the License at
14
+
15
+ http://www.apache.org/licenses/LICENSE-2.0
16
+
17
+ Unless required by applicable law or agreed to in writing, software
18
+ distributed under the License is distributed on an "AS IS" BASIS,
19
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20
+ See the License for the specific language governing permissions and
21
+ limitations under the License.
22
+
23
+ DATABASES LICENSE (GeoLite2 databases)
24
+
25
+ Copyright (c) 2012-2018 MaxMind, Inc. All Rights Reserved.
26
+
27
+ The GeoLite2 databases are distributed under the
28
+ Creative Commons Attribution-ShareAlike 4.0 International License (the "License");
29
+ you may not use this file except in compliance with the License.
30
+ You may obtain a copy of the License at
31
+
32
+ https://creativecommons.org/licenses/by-sa/4.0/legalcode
33
+
34
+ The attribution requirement may be met by including the following in all
35
+ advertising and documentation mentioning features of or use of this
36
+ database:
37
+
38
+ This product includes GeoLite2 data created by MaxMind, available from
39
+ <a href="http://www.maxmind.com">http://www.maxmind.com</a>.
40
+
41
+ THIS DATABASE IS PROVIDED BY MAXMIND, INC ``AS IS'' AND ANY
42
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
43
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
44
+ DISCLAIMED. IN NO EVENT SHALL MAXMIND BE LIABLE FOR ANY
45
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
46
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
47
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
48
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
49
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
50
+ DATABASE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1 @@
1
+ dfd29adec1e9a792474993c4fec3b215bbdb03327ad210f3efd8a2db63aa553c GeoLite2-City-CSV_20231115.zip
@@ -0,0 +1 @@
1
+ 9948aae1cfb8d0147f84393cd8bc5d68198e433c5a835623b8a787ba8c7dbc72 GeoLite2-Country-CSV_20231115.zip
@@ -0,0 +1,83 @@
1
+ var fs = require('fs'),
2
+ path = require('path'),
3
+ FSWatcher = {};
4
+
5
+ /**
6
+ * Takes a directory/file and watch for change. Upon change, call the
7
+ * callback.
8
+ *
9
+ * @param {String} name: name of this watcher
10
+ * @param {String} directory: path to the directory to watch
11
+ * @param {String} [filename]: (optional) specific filename to watch for,
12
+ * watches for all files in the directory if unspecified
13
+ * @param {Integer} cooldownDelay: delay to wait before triggering the callback
14
+ * @param {Function} callback: function () : called when changes are detected
15
+ **/
16
+ function makeFsWatchFilter(name, directory, filename, cooldownDelay, callback) {
17
+ var cooldownId = null;
18
+
19
+ //Delete the cooldownId and callback the outer function
20
+ function timeoutCallback() {
21
+ cooldownId = null;
22
+ callback();
23
+ }
24
+
25
+ //This function is called when there is a change in the data directory
26
+ //It sets a timer to wait for the change to be completed
27
+ function onWatchEvent(event, changedFile) {
28
+ // check to make sure changedFile is not null
29
+ if (!changedFile) {
30
+ return;
31
+ }
32
+
33
+ var filePath = path.join(directory, changedFile);
34
+
35
+ if (!filename || filename === changedFile) {
36
+ fs.exists(filePath, function onExists(exists) {
37
+ if (!exists) {
38
+ // if the changed file no longer exists, it was a deletion.
39
+ // we ignore deleted files
40
+ return;
41
+ }
42
+
43
+ //At this point, a new file system activity has been detected,
44
+ //We have to wait for file transfert to be finished before moving on.
45
+
46
+ //If a cooldownId already exists, we delete it
47
+ if (cooldownId !== null) {
48
+ clearTimeout(cooldownId);
49
+ cooldownId = null;
50
+ }
51
+
52
+ //Once the cooldownDelay has passed, the timeoutCallback function will be called
53
+ cooldownId = setTimeout(timeoutCallback, cooldownDelay);
54
+ });
55
+ }
56
+ }
57
+
58
+ //Manage the case where filename is missing (because it's optionnal)
59
+ if (typeof cooldownDelay === 'function') {
60
+ callback = cooldownDelay;
61
+ cooldownDelay = filename;
62
+ filename = null;
63
+ }
64
+
65
+ if (FSWatcher[name]) {
66
+ stopWatching(name);
67
+ }
68
+
69
+ FSWatcher[name] = fs.watch(directory, onWatchEvent);
70
+ }
71
+
72
+ /**
73
+ * Take a FSWatcher object and close it.
74
+ *
75
+ * @param {string} name: name of the watcher to close
76
+ *
77
+ **/
78
+ function stopWatching(name) {
79
+ FSWatcher[name].close();
80
+ }
81
+
82
+ module.exports.makeFsWatchFilter = makeFsWatchFilter;
83
+ module.exports.stopWatching = stopWatching;