mirror of
https://github.com/Mintplex-Labs/anything-llm.git
synced 2025-05-02 17:07:13 +00:00
401-Password Complexity Check Capability (#402)
* Added improved password complexity checking capability. * Move password complexity checker as User.util dynamically import required libraries depending on code execution flow lint * Ensure persistence of password requirements on restarts via env-dump Copy example schema to docker env as well --------- Co-authored-by: timothycarambat <rambat1010@gmail.com>
This commit is contained in:
parent
7b30dd041b
commit
732d07829f
8 changed files with 128 additions and 6 deletions
docker
frontend/src/pages/Admin/Users
server
|
@ -79,3 +79,17 @@ VECTOR_DB="lancedb"
|
|||
STORAGE_DIR="/app/server/storage"
|
||||
UID='1000'
|
||||
GID='1000'
|
||||
|
||||
###########################################
|
||||
######## PASSWORD COMPLEXITY ##############
|
||||
###########################################
|
||||
# Enforce a password schema for your organization users.
|
||||
# Documentation on how to use https://github.com/kamronbatman/joi-password-complexity
|
||||
# Default is only 8 char minimum
|
||||
# PASSWORDMINCHAR=8
|
||||
# PASSWORDMAXCHAR=250
|
||||
# PASSWORDLOWERCASE=1
|
||||
# PASSWORDUPPERCASE=1
|
||||
# PASSWORDNUMERIC=1
|
||||
# PASSWORDSYMBOL=1
|
||||
# PASSWORDREQUIREMENTS=4
|
|
@ -77,7 +77,6 @@ export default function NewUserModal() {
|
|||
className="bg-zinc-900 border border-gray-500 text-white text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
|
||||
placeholder="User's initial password"
|
||||
required={true}
|
||||
minLength={8}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -77,7 +77,6 @@ export default function EditUserModal({ currentUser, user }) {
|
|||
type="text"
|
||||
className="bg-zinc-900 border border-gray-500 text-white text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5"
|
||||
placeholder={`${user.username}'s new password`}
|
||||
minLength={8}
|
||||
autoComplete="off"
|
||||
/>
|
||||
</div>
|
||||
|
|
|
@ -78,3 +78,16 @@ VECTOR_DB="lancedb"
|
|||
# AUTH_TOKEN="hunter2" # This is the password to your application if remote hosting.
|
||||
# STORAGE_DIR= # absolute filesystem path with no trailing slash
|
||||
# NO_DEBUG="true"
|
||||
|
||||
###########################################
|
||||
######## PASSWORD COMPLEXITY ##############
|
||||
###########################################
|
||||
# Enforce a password schema for your organization users.
|
||||
# Documentation on how to use https://github.com/kamronbatman/joi-password-complexity
|
||||
#PASSWORDMINCHAR=8
|
||||
#PASSWORDMAXCHAR=250
|
||||
#PASSWORDLOWERCASE=1
|
||||
#PASSWORDUPPERCASE=1
|
||||
#PASSWORDNUMERIC=1
|
||||
#PASSWORDSYMBOL=1
|
||||
#PASSWORDREQUIREMENTS=4
|
||||
|
|
|
@ -1,9 +1,14 @@
|
|||
const prisma = require("../utils/prisma");
|
||||
const bcrypt = require("bcrypt");
|
||||
|
||||
const User = {
|
||||
create: async function ({ username, password, role = "default" }) {
|
||||
const passwordCheck = this.checkPasswordComplexity(password);
|
||||
if (!passwordCheck.checkedOK) {
|
||||
return { user: null, error: passwordCheck.error };
|
||||
}
|
||||
|
||||
try {
|
||||
const bcrypt = require("bcrypt");
|
||||
const hashedPassword = bcrypt.hashSync(password, 10);
|
||||
const user = await prisma.users.create({
|
||||
data: {
|
||||
|
@ -21,9 +26,14 @@ const User = {
|
|||
|
||||
update: async function (userId, updates = {}) {
|
||||
try {
|
||||
// Rehash new password if it exists as update
|
||||
// will be given to us as plaintext.
|
||||
if (updates.hasOwnProperty("password") && updates.password.length >= 8) {
|
||||
// Rehash new password if it exists as update field
|
||||
if (updates.hasOwnProperty("password")) {
|
||||
const passwordCheck = this.checkPasswordComplexity(updates.password);
|
||||
if (!passwordCheck.checkedOK) {
|
||||
return { success: false, error: passwordCheck.error };
|
||||
}
|
||||
|
||||
const bcrypt = require("bcrypt");
|
||||
updates.password = bcrypt.hashSync(updates.password, 10);
|
||||
} else {
|
||||
delete updates.password;
|
||||
|
@ -82,6 +92,38 @@ const User = {
|
|||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
checkPasswordComplexity: function (passwordInput = "") {
|
||||
const passwordComplexity = require("joi-password-complexity");
|
||||
// Can be set via ENV variable on boot. No frontend config at this time.
|
||||
// Docs: https://www.npmjs.com/package/joi-password-complexity
|
||||
const complexityOptions = {
|
||||
min: process.env.PASSWORDMINCHAR || 8,
|
||||
max: process.env.PASSWORDMAXCHAR || 250,
|
||||
lowerCase: process.env.PASSWORDLOWERCASE || 0,
|
||||
upperCase: process.env.PASSWORDUPPERCASE || 0,
|
||||
numeric: process.env.PASSWORDNUMERIC || 0,
|
||||
symbol: process.env.PASSWORDSYMBOL || 0,
|
||||
// reqCount should be equal to how many conditions you are testing for (1-4)
|
||||
requirementCount: process.env.PASSWORDREQUIREMENTS || 0,
|
||||
};
|
||||
|
||||
const complexityCheck = passwordComplexity(
|
||||
complexityOptions,
|
||||
"password"
|
||||
).validate(passwordInput);
|
||||
if (complexityCheck.hasOwnProperty("error")) {
|
||||
let myError = "";
|
||||
let prepend = "";
|
||||
for (let i = 0; i < complexityCheck.error.details.length; i++) {
|
||||
myError += prepend + complexityCheck.error.details[i].message;
|
||||
prepend = ", ";
|
||||
}
|
||||
return { checkedOK: false, error: myError };
|
||||
}
|
||||
|
||||
return { checkedOK: true, error: "No error." };
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = { User };
|
||||
|
|
|
@ -36,6 +36,8 @@
|
|||
"express": "^4.18.2",
|
||||
"extract-zip": "^2.0.1",
|
||||
"graphql": "^16.7.1",
|
||||
"joi": "^17.11.0",
|
||||
"joi-password-complexity": "^5.2.0",
|
||||
"js-tiktoken": "^1.0.7",
|
||||
"jsonwebtoken": "^8.5.1",
|
||||
"langchain": "^0.0.90",
|
||||
|
|
|
@ -286,6 +286,14 @@ async function dumpENV() {
|
|||
"CACHE_VECTORS",
|
||||
"STORAGE_DIR",
|
||||
"SERVER_PORT",
|
||||
// Password Schema Keys if present.
|
||||
"PASSWORDMINCHAR",
|
||||
"PASSWORDMAXCHAR",
|
||||
"PASSWORDLOWERCASE",
|
||||
"PASSWORDUPPERCASE",
|
||||
"PASSWORDNUMERIC",
|
||||
"PASSWORDSYMBOL",
|
||||
"PASSWORDREQUIREMENTS",
|
||||
];
|
||||
|
||||
for (const key of protectedKeys) {
|
||||
|
|
|
@ -150,6 +150,18 @@
|
|||
resolved "https://registry.yarnpkg.com/@graphql-typed-document-node/core/-/core-3.2.0.tgz#5f3d96ec6b2354ad6d8a28bf216a1d97b5426861"
|
||||
integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==
|
||||
|
||||
"@hapi/hoek@^9.0.0":
|
||||
version "9.3.0"
|
||||
resolved "https://registry.yarnpkg.com/@hapi/hoek/-/hoek-9.3.0.tgz#8368869dcb735be2e7f5cb7647de78e167a251fb"
|
||||
integrity sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==
|
||||
|
||||
"@hapi/topo@^5.0.0":
|
||||
version "5.1.0"
|
||||
resolved "https://registry.yarnpkg.com/@hapi/topo/-/topo-5.1.0.tgz#dc448e332c6c6e37a4dc02fd84ba8d44b9afb012"
|
||||
integrity sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==
|
||||
dependencies:
|
||||
"@hapi/hoek" "^9.0.0"
|
||||
|
||||
"@mapbox/node-pre-gyp@^1.0.0", "@mapbox/node-pre-gyp@^1.0.10":
|
||||
version "1.0.11"
|
||||
resolved "https://registry.yarnpkg.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz#417db42b7f5323d79e93b34a6d7a2a12c0df43fa"
|
||||
|
@ -224,6 +236,23 @@
|
|||
resolved "https://registry.yarnpkg.com/@sevinf/maybe/-/maybe-0.5.0.tgz#e59fcea028df615fe87d708bb30e1f338e46bb44"
|
||||
integrity sha512-ARhyoYDnY1LES3vYI0fiG6e9esWfTNcXcO6+MPJJXcnyMV3bim4lnFt45VXouV7y82F4x3YH8nOQ6VztuvUiWg==
|
||||
|
||||
"@sideway/address@^4.1.3":
|
||||
version "4.1.4"
|
||||
resolved "https://registry.yarnpkg.com/@sideway/address/-/address-4.1.4.tgz#03dccebc6ea47fdc226f7d3d1ad512955d4783f0"
|
||||
integrity sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==
|
||||
dependencies:
|
||||
"@hapi/hoek" "^9.0.0"
|
||||
|
||||
"@sideway/formula@^3.0.1":
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/@sideway/formula/-/formula-3.0.1.tgz#80fcbcbaf7ce031e0ef2dd29b1bfc7c3f583611f"
|
||||
integrity sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==
|
||||
|
||||
"@sideway/pinpoint@^2.0.0":
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/@sideway/pinpoint/-/pinpoint-2.0.0.tgz#cff8ffadc372ad29fd3f78277aeb29e632cc70df"
|
||||
integrity sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==
|
||||
|
||||
"@tootallnate/once@1":
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82"
|
||||
|
@ -1556,6 +1585,22 @@ isomorphic-fetch@^3.0.0:
|
|||
node-fetch "^2.6.1"
|
||||
whatwg-fetch "^3.4.1"
|
||||
|
||||
joi-password-complexity@^5.2.0:
|
||||
version "5.2.0"
|
||||
resolved "https://registry.yarnpkg.com/joi-password-complexity/-/joi-password-complexity-5.2.0.tgz#5308f4e7c6c39ce0a6a050597883d5fd7f2800b4"
|
||||
integrity sha512-exQOcaKC4EuZwwNVQ/5/FcnCzdwdzjA2RPIrRgZXTjzkFhY5NUtP83SlcNSUK3OvbRFpjUq1FCzhHg/uqPg90g==
|
||||
|
||||
joi@^17.11.0:
|
||||
version "17.11.0"
|
||||
resolved "https://registry.yarnpkg.com/joi/-/joi-17.11.0.tgz#aa9da753578ec7720e6f0ca2c7046996ed04fc1a"
|
||||
integrity sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==
|
||||
dependencies:
|
||||
"@hapi/hoek" "^9.0.0"
|
||||
"@hapi/topo" "^5.0.0"
|
||||
"@sideway/address" "^4.1.3"
|
||||
"@sideway/formula" "^3.0.1"
|
||||
"@sideway/pinpoint" "^2.0.0"
|
||||
|
||||
js-tiktoken@^1.0.6, js-tiktoken@^1.0.7:
|
||||
version "1.0.7"
|
||||
resolved "https://registry.yarnpkg.com/js-tiktoken/-/js-tiktoken-1.0.7.tgz#56933fcd2093e8304060dfde3071bda91812e6f5"
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue