mirror of
https://github.com/danny-avila/LibreChat.git
synced 2025-12-17 00:40:14 +01:00
* docs: make_your_own.md formatting fix for mkdocs * feat: add express-mongo-sanitize feat: add login/registration rate limiting * chore: remove unnecessary console log * wip: remove token handling from localStorage to encrypted DB solution * refactor: minor change to UserService * fix mongo query and add keys route to server * fix backend controllers and simplify schema/crud * refactor: rename token to key to separate from access/refresh tokens, setTokenDialog -> setKeyDialog * refactor(schemas): TEndpointOption token -> key * refactor(api): use new encrypted key retrieval system * fix(SetKeyDialog): fix key prop error * fix(abortMiddleware): pass random UUID if messageId is not generated yet for proper error display on frontend * fix(getUserKey): wrong prop passed in arg, adds error handling * fix: prevent message without conversationId from saving to DB, prevents branching on the frontend to a new top-level branch * refactor: change wording of multiple display messages * refactor(checkExpiry -> checkUserKeyExpiry): move to UserService file * fix: type imports from common * refactor(SubmitButton): convert to TS * refactor(key.ts): change localStorage map key name * refactor: add new custom tailwind classes to better match openAI colors * chore: remove unnecessary warning and catch ScreenShot error * refactor: move userKey frontend logic to hooks and remove use of localStorage and instead query the DB * refactor: invalidate correct query key, memoize userKey hook, conditionally render SetKeyDialog to avoid unnecessary calls, refactor SubmitButton props and useEffect for showing 'provide key first' * fix(SetKeyDialog): use enum-like object for expiry values feat(Dropdown): add optionsClassName to dynamically change dropdown options container classes * fix: handle edge case where user had provided a key but the server changes to env variable for keys * refactor(OpenAI/titleConvo): move titling to client to retain authorized credentials in message lifecycle for titling * fix(azure): handle user_provided keys correctly for azure * feat: send user Id to OpenAI to differentiate users in completion requests * refactor(OpenAI/titleConvo): adding tokens helps minimize LLM from using the language in title response * feat: add delete endpoint for keys * chore: remove throttling of title * feat: add 'Data controls' to Settings, add 'Revoke' keys feature in Key Dialog and Data controls * refactor: reorganize PluginsClient files in langchain format * feat: use langchain for titling convos * chore: cleanup titling convo, with fallback to original method, escape braces, use only snippet for language detection * refactor: move helper functions to appropriate langchain folders for reusability * fix: userProvidesKey handling for gptPlugins * fix: frontend handling of plugins key * chore: cleanup logging and ts-ignore SSE * fix: forwardRef misuse in DangerButton * fix(GoogleConfig/FileUpload): localize errors and simplify validation with zod * fix: cleanup google logging and fix user provided key handling * chore: remove titling from google * chore: removing logging from browser endpoint * wip: fix menu flicker * feat: useLocalStorage hook * feat: add Tooltip for UI * refactor(EndpointMenu): utilize Tooltip and useLocalStorage, remove old 'New Chat' slide-over * fix(e2e): use testId for endpoint menu trigger * chore: final touches to EndpointMenu before future refactor to declutter component * refactor(localization): change select endpoint to open menu and add translations * chore: add final prop to error message response * ci: minor edits to facilitate testing * ci: new e2e test which tests for new key setting/revoking features
110 lines
2.5 KiB
JavaScript
110 lines
2.5 KiB
JavaScript
const mongoose = require('mongoose');
|
|
const bcrypt = require('bcryptjs');
|
|
const jwt = require('jsonwebtoken');
|
|
const Joi = require('joi');
|
|
const DebugControl = require('../utils/debug.js');
|
|
const userSchema = require('./schema/userSchema.js');
|
|
|
|
function log({ title, parameters }) {
|
|
DebugControl.log.functionName(title);
|
|
DebugControl.log.parameters(parameters);
|
|
}
|
|
|
|
//Remove refreshToken from the response
|
|
userSchema.set('toJSON', {
|
|
transform: function (_doc, ret) {
|
|
delete ret.refreshToken;
|
|
return ret;
|
|
},
|
|
});
|
|
|
|
userSchema.methods.toJSON = function () {
|
|
return {
|
|
id: this._id,
|
|
provider: this.provider,
|
|
email: this.email,
|
|
name: this.name,
|
|
username: this.username,
|
|
avatar: this.avatar,
|
|
role: this.role,
|
|
emailVerified: this.emailVerified,
|
|
plugins: this.plugins,
|
|
createdAt: this.createdAt,
|
|
updatedAt: this.updatedAt,
|
|
};
|
|
};
|
|
|
|
userSchema.methods.generateToken = function () {
|
|
const token = jwt.sign(
|
|
{
|
|
id: this._id,
|
|
username: this.username,
|
|
provider: this.provider,
|
|
email: this.email,
|
|
},
|
|
process.env.JWT_SECRET,
|
|
{ expiresIn: eval(process.env.SESSION_EXPIRY) },
|
|
);
|
|
return token;
|
|
};
|
|
|
|
userSchema.methods.generateRefreshToken = function () {
|
|
const refreshToken = jwt.sign(
|
|
{
|
|
id: this._id,
|
|
username: this.username,
|
|
provider: this.provider,
|
|
email: this.email,
|
|
},
|
|
process.env.JWT_REFRESH_SECRET,
|
|
{ expiresIn: eval(process.env.REFRESH_TOKEN_EXPIRY) },
|
|
);
|
|
return refreshToken;
|
|
};
|
|
|
|
userSchema.methods.comparePassword = function (candidatePassword, callback) {
|
|
bcrypt.compare(candidatePassword, this.password, (err, isMatch) => {
|
|
if (err) {
|
|
return callback(err);
|
|
}
|
|
callback(null, isMatch);
|
|
});
|
|
};
|
|
|
|
module.exports.hashPassword = async (password) => {
|
|
const hashedPassword = await new Promise((resolve, reject) => {
|
|
bcrypt.hash(password, 10, function (err, hash) {
|
|
if (err) {
|
|
reject(err);
|
|
} else {
|
|
resolve(hash);
|
|
}
|
|
});
|
|
});
|
|
|
|
return hashedPassword;
|
|
};
|
|
|
|
module.exports.validateUser = (user) => {
|
|
log({
|
|
title: 'Validate User',
|
|
parameters: [{ name: 'Validate User', value: user }],
|
|
});
|
|
const schema = {
|
|
avatar: Joi.any(),
|
|
name: Joi.string().min(3).max(80).required(),
|
|
username: Joi.string()
|
|
.trim()
|
|
.allow('')
|
|
.min(2)
|
|
.max(80)
|
|
.regex(/^[a-zA-Z0-9_.-@#$%&*() ]+$/),
|
|
password: Joi.string().min(8).max(128).allow('').allow(null),
|
|
};
|
|
|
|
return schema.validate(user);
|
|
};
|
|
|
|
const User = mongoose.model('User', userSchema);
|
|
|
|
module.exports = User;
|