LibreChat/api/server/controllers/auth.controller.js
Dan Orlando dac19038a3
feat: Auth and User System (#205)
* server-side JWT auth implementation

* move oauth routes and strategies, fix bugs

* backend modifications for wiring up the frontend login and reg forms

* Add frontend data services for login and registration

* Add login and registration forms

* Implment auth context, functional client side auth

* protect routes with jwt auth

* finish local strategy (using local storage)

* Start setting up google auth

* disable token refresh, remove old auth middleware

* refactor client, add ApiErrorBoundary context

* disable google and facebook strategies

* fix: fix presets not displaying specific to user

* fix: fix issue with browser refresh

* fix: casing issue with User.js (#11)

* delete user.js to be renamed

* fix: fix casing issue with User.js

* comment out api error watcher temporarily

* fix: issue with api error watcher (#12)

* delete user.js to be renamed

* fix: fix casing issue with User.js

* comment out api error watcher temporarily

* feat: add google auth social login

* fix: make google login url dynamic based on dev/prod

* fix: bug where UI is briefly displayed before redirecting to login

* fix: fix cookie expires value for local auth

* Update README.md

* Update LOCAL_INSTALL structure

* Add local testing instructions

* Only load google strategy if client id and secret are provided

* Update .env.example files with new params

* fix issue with not redirecting to register form

* only show google login button if value is set in .env

* cleanup log messages

* Add label to button for google login on login form

* doc: fix client/server url values in .env.example

* feat: add error message details to registration failure

* Restore preventing paste on confirm password

* auto-login user after registering

* feat: forgot password (#24)

* make login/reg pages look like openai's

* add password reset data services

* new form designs similar to openai, add password reset pages

* add api's for password reset

* email utils for password reset

* remove bcrypt salt rounds from process.env

* refactor: restructure api auth code, consolidate routes (#25)

* add api's for password reset

* remove bcrypt salt rounds from process.env

* refactor: consolidate auth routes, use controller pattern

* refactor: code cleanup

* feat: migrate data to first user (#26)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes after refactor (#27)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes

* fix: issue with auto-login when logging out then logging in with new browser window (#28)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes

* fix: fix issue with auto-login in new tab

* doc: Update README and .env.example files with user system information (#29)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes

* fix: fix issue with auto-login in new tab

* doc: update README and .env.example files

* Fixup: LOCAL_INSTALL.md PS instructions (#200) (#30)

Co-authored-by: alfredo-f <alfredo.fomitchenko@mail.polimi.it>

* feat: send user with completion to protect against abuse (#31)

* Fixup: LOCAL_INSTALL.md PS instructions (#200)

* server-side JWT auth implementation

* move oauth routes and strategies, fix bugs

* backend modifications for wiring up the frontend login and reg forms

* Add frontend data services for login and registration

* Add login and registration forms

* Implment auth context, functional client side auth

* protect routes with jwt auth

* finish local strategy (using local storage)

* Start setting up google auth

* disable token refresh, remove old auth middleware

* refactor client, add ApiErrorBoundary context

* disable google and facebook strategies

* fix: fix presets not displaying specific to user

* fix: fix issue with browser refresh

* fix: casing issue with User.js (#11)

* delete user.js to be renamed

* fix: fix casing issue with User.js

* comment out api error watcher temporarily

* feat: add google auth social login

* fix: make google login url dynamic based on dev/prod

* fix: bug where UI is briefly displayed before redirecting to login

* fix: fix cookie expires value for local auth

* Only load google strategy if client id and secret are provided

* Update .env.example files with new params

* fix issue with not redirecting to register form

* only show google login button if value is set in .env

* cleanup log messages

* Add label to button for google login on login form

* doc: fix client/server url values in .env.example

* feat: add error message details to registration failure

* Restore preventing paste on confirm password

* auto-login user after registering

* feat: forgot password (#24)

* make login/reg pages look like openai's

* add password reset data services

* new form designs similar to openai, add password reset pages

* add api's for password reset

* email utils for password reset

* remove bcrypt salt rounds from process.env

* refactor: restructure api auth code, consolidate routes (#25)

* add api's for password reset

* remove bcrypt salt rounds from process.env

* refactor: consolidate auth routes, use controller pattern

* refactor: code cleanup

* feat: migrate data to first user (#26)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes after refactor (#27)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes

* fix: issue with auto-login when logging out then logging in with new browser window (#28)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes

* fix: fix issue with auto-login in new tab

* doc: Update README and .env.example files with user system information (#29)

* refactor: use /api for auth routes

* fix: use user id instead of username

* feat: migrate data to first user on register

* fix: fix social login routes

* fix: fix issue with auto-login in new tab

* doc: update README and .env.example files

* Send user id to openai to protect against abuse

* add meilisearch to gitignore

* Remove webpack

---------

Co-authored-by: alfredo-f <alfredo.fomitchenko@mail.polimi.it>

---------

Co-authored-by: Danny Avila <110412045+danny-avila@users.noreply.github.com>
Co-authored-by: Alfredo Fomitchenko <alfredo.fomitchenko@mail.polimi.it>
2023-05-07 10:04:51 -07:00

180 lines
No EOL
4.9 KiB
JavaScript

const {
loginUser,
logoutUser,
registerUser,
requestPasswordReset,
resetPassword,
} = require("../services/auth.service");
const isProduction = process.env.NODE_ENV === 'production';
const loginController = async (req, res) => {
try {
const token = req.user.generateToken();
const user = await loginUser(req.user)
if(user) {
res.cookie('token', token, {
expires: new Date(Date.now() + eval(process.env.SESSION_EXPIRY)),
httpOnly: false,
secure: isProduction
});
res.status(200).send({ token, user });
}
else {
return res.status(400).json({ message: 'Invalid credentials' });
}
}
catch (err) {
console.log(err);
return res.status(500).json({ message: err.message });
}
};
const logoutController = async (req, res) => {
const { signedCookies = {} } = req;
const { refreshToken } = signedCookies;
try {
const logout = await logoutUser(req.user, refreshToken);
console.log(logout)
const { status, message } = logout;
if (status === 200) {
res.clearCookie('token');
res.clearCookie('refreshToken');
res.status(status).send({ message });
}
else {
res.status(status).send({ message });
}
}
catch (err) {
console.log(err);
return res.status(500).json({ message: err.message });
}
}
const registrationController = async (req, res) => {
try {
const response = await registerUser(req.body);
if (response.status === 200) {
const { status, user } = response;
const token = user.generateToken();
//send token for automatic login
res.cookie('token', token, {
expires: new Date(Date.now() + eval(process.env.SESSION_EXPIRY)),
httpOnly: false,
secure: isProduction
});
res.status(status).send({ user });
}
else {
const { status, message } = response;
res.status(status).send({ message });
}
}
catch (err) {
console.log(err);
return res.status(500).json({ message: err.message });
}
};
const getUserController = async (req, res) => {
return res.status(200).send(req.user);
};
const resetPasswordRequestController = async (req, res) => {
try {
const resetService = await requestPasswordReset(
req.body.email
);
if (resetService.link) {
return res.status(200).json(resetService);
}
else {
return res.status(400).json(resetService);
}
}
catch (e) {
console.log(e);
return res.status(400).json({ message: e.message });
}
};
const resetPasswordController = async (req, res) => {
try {
const resetPasswordService = await resetPassword(
req.body.userId,
req.body.token,
req.body.password
);
if(resetPasswordService instanceof Error) {
return res.status(400).json(resetPasswordService);
}
else {
return res.status(200).json(resetPasswordService);
}
}
catch (e) {
console.log(e);
return res.status(400).json({ message: e.message });
}
};
const refreshController = async (req, res, next) => {
const { signedCookies = {} } = req;
const { refreshToken } = signedCookies;
//TODO
// if (refreshToken) {
// try {
// const payload = jwt.verify(refreshToken, process.env.REFRESH_TOKEN_SECRET);
// const userId = payload._id;
// User.findOne({ _id: userId }).then(
// (user) => {
// if (user) {
// // Find the refresh token against the user record in database
// const tokenIndex = user.refreshToken.findIndex(item => item.refreshToken === refreshToken);
// if (tokenIndex === -1) {
// res.statusCode = 401;
// res.send('Unauthorized');
// } else {
// const token = req.user.generateToken();
// // If the refresh token exists, then create new one and replace it.
// const newRefreshToken = req.user.generateRefreshToken();
// user.refreshToken[tokenIndex] = { refreshToken: newRefreshToken };
// user.save((err) => {
// if (err) {
// res.statusCode = 500;
// res.send(err);
// } else {
// // setTokenCookie(res, newRefreshToken);
// const user = req.user.toJSON();
// res.status(200).send({ token, user });
// }
// });
// }
// } else {
// res.statusCode = 401;
// res.send('Unauthorized');
// }
// },
// err => next(err)
// );
// } catch (err) {
// res.statusCode = 401;
// res.send('Unauthorized');
// }
// } else {
// res.statusCode = 401;
// res.send('Unauthorized');
// }
};
module.exports = {
getUserController,
loginController,
logoutController,
refreshController,
registrationController,
resetPasswordRequestController,
resetPasswordController,
};