summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar Piotr Russ <mail@pruss.it> 2020-11-26 22:20:54 +0100
committerGravatar Piotr Russ <mail@pruss.it> 2020-11-26 22:20:54 +0100
commitf2fcc41cb17ece1fc5acf57809c5e3d61c236133 (patch)
treea103a0dd371c5f7fd5d7e3105fef0730c8594827
parent627239499c7c9fb5e7af68b2e79e01d0523f5d8f (diff)
downloadwebsite_creator-f2fcc41cb17ece1fc5acf57809c5e3d61c236133.tar.gz
website_creator-f2fcc41cb17ece1fc5acf57809c5e3d61c236133.tar.bz2
website_creator-f2fcc41cb17ece1fc5acf57809c5e3d61c236133.zip
completed jwt token login with refresh token, reduced db calls
-rw-r--r--.env.example1
-rwxr-xr-xapp.js2
-rw-r--r--client/admin/out.js6
-rw-r--r--client/login/out.js8
-rw-r--r--client/public/favicon.icobin0 -> 2360 bytes
-rw-r--r--client/src/admin/api/getUser.js2
-rw-r--r--client/src/admin/jsx/App.jsx4
-rw-r--r--client/src/admin/jsx/User.jsx2
-rw-r--r--client/src/login/api/login.js4
-rw-r--r--client/src/login/jsx/LoginPanel.jsx2
-rw-r--r--server/helpers/setCookie.js2
-rw-r--r--server/middleware/auth.js29
-rw-r--r--server/middleware/redirectLogged.js39
-rw-r--r--server/models/Session.js23
-rw-r--r--server/models/User.js33
-rw-r--r--server/routes/user.js33
16 files changed, 101 insertions, 89 deletions
diff --git a/.env.example b/.env.example
index 3ca9069..ecc31fd 100644
--- a/.env.example
+++ b/.env.example
@@ -1,5 +1,6 @@
DB_CONNECT =
PORT =
COOKIE_MAX_AGE =
+DB_SESSION_MAX_AGE =
JWT_TOKEN_MAX_AGE =
JWT_SECRET =
diff --git a/app.js b/app.js
index 0ee7cf7..edacd2e 100755
--- a/app.js
+++ b/app.js
@@ -31,7 +31,7 @@ app.use('/', express.static(
path.join(__dirname, 'client/public')
));
-app.get('*', (req, res) => res.redirect('/'));
+// app.get('*', (req, res) => res.redirect('/'));
app.listen(port, () => {
console.log("Server is up on port " + port + ".");
diff --git a/client/admin/out.js b/client/admin/out.js
index c89fbde..2c675d3 100644
--- a/client/admin/out.js
+++ b/client/admin/out.js
@@ -94,7 +94,7 @@
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__[\"default\"] = ((setUser) => (\n fetch('/api/user/me')\n .then(res => res.json())\n .then(data => setUser(data.email))\n .catch(() => {})\n));\n\n\n//# sourceURL=webpack:///./client/src/admin/api/getUser.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__[\"default\"] = ((setUser) => (\n fetch('/api/user/me')\n .then(res => res.json())\n .then(data => setUser(data))\n .catch(() => {})\n));\n\n\n//# sourceURL=webpack:///./client/src/admin/api/getUser.js?");
/***/ }),
@@ -190,7 +190,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Wit
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-eval("\n\nvar _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"]) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); } }; }();\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _react2 = _interopRequireDefault(_react);\n\nvar _reactDom = __webpack_require__(/*! react-dom */ \"./node_modules/react-dom/index.js\");\n\nvar _reactDom2 = _interopRequireDefault(_reactDom);\n\n__webpack_require__(/*! ../scss/index.scss */ \"./client/src/admin/scss/index.scss\");\n\nvar _TopBar = __webpack_require__(/*! ./TopBar.jsx */ \"./client/src/admin/jsx/TopBar.jsx\");\n\nvar _TopBar2 = _interopRequireDefault(_TopBar);\n\nvar _Info = __webpack_require__(/*! ./Info.jsx */ \"./client/src/admin/jsx/Info.jsx\");\n\nvar _Info2 = _interopRequireDefault(_Info);\n\nvar _MainScreen = __webpack_require__(/*! ./MainScreen.jsx */ \"./client/src/admin/jsx/MainScreen.jsx\");\n\nvar _MainScreen2 = _interopRequireDefault(_MainScreen);\n\nvar _context = __webpack_require__(/*! ../context */ \"./client/src/admin/context/index.js\");\n\nvar _context2 = _interopRequireDefault(_context);\n\nvar _translations = __webpack_require__(/*! ../data/translations */ \"./client/src/admin/data/translations.js\");\n\nvar _api = __webpack_require__(/*! ../api */ \"./client/src/admin/api/index.js\");\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar App = function App() {\n var _useState = (0, _react.useState)(_translations.defaultLanguage),\n _useState2 = _slicedToArray(_useState, 2),\n lang = _useState2[0],\n setLang = _useState2[1];\n\n var _useState3 = (0, _react.useState)([]),\n _useState4 = _slicedToArray(_useState3, 2),\n projects = _useState4[0],\n setProjects = _useState4[1];\n\n var _useState5 = (0, _react.useState)(''),\n _useState6 = _slicedToArray(_useState5, 2),\n info = _useState6[0],\n setInfo = _useState6[1];\n\n var _useState7 = (0, _react.useState)(''),\n _useState8 = _slicedToArray(_useState7, 2),\n hover = _useState8[0],\n setHover = _useState8[1];\n\n var _useState9 = (0, _react.useState)('main'),\n _useState10 = _slicedToArray(_useState9, 2),\n view = _useState10[0],\n setView = _useState10[1];\n\n var _useState11 = (0, _react.useState)(null),\n _useState12 = _slicedToArray(_useState11, 2),\n user = _useState12[0],\n setUser = _useState12[1];\n\n (0, _react.useEffect)(function () {\n (0, _api.getUser)(setUser);\n setInfo('no-saved-websites');\n }, []);\n\n return _react2.default.createElement(\n _context2.default.Provider,\n { value: { lang: lang, setHover: setHover, setInfo: setInfo } },\n _react2.default.createElement(\n 'div',\n { className: 'main' },\n _react2.default.createElement(_TopBar2.default, { lang: lang, setLang: setLang, user: user, setUser: setUser }),\n _react2.default.createElement(\n 'div',\n { className: 'main__content' },\n view === 'main' && _react2.default.createElement(_MainScreen2.default, { projects: projects })\n ),\n _react2.default.createElement(_Info2.default, { info: info, hover: hover })\n )\n );\n};\n\n_reactDom2.default.render(_react2.default.createElement(App, null), document.getElementById('app'));\n\n//# sourceURL=webpack:///./client/src/admin/jsx/App.jsx?");
+eval("\n\nvar _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"]) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); } }; }();\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _react2 = _interopRequireDefault(_react);\n\nvar _reactDom = __webpack_require__(/*! react-dom */ \"./node_modules/react-dom/index.js\");\n\nvar _reactDom2 = _interopRequireDefault(_reactDom);\n\n__webpack_require__(/*! ../scss/index.scss */ \"./client/src/admin/scss/index.scss\");\n\nvar _TopBar = __webpack_require__(/*! ./TopBar.jsx */ \"./client/src/admin/jsx/TopBar.jsx\");\n\nvar _TopBar2 = _interopRequireDefault(_TopBar);\n\nvar _Info = __webpack_require__(/*! ./Info.jsx */ \"./client/src/admin/jsx/Info.jsx\");\n\nvar _Info2 = _interopRequireDefault(_Info);\n\nvar _MainScreen = __webpack_require__(/*! ./MainScreen.jsx */ \"./client/src/admin/jsx/MainScreen.jsx\");\n\nvar _MainScreen2 = _interopRequireDefault(_MainScreen);\n\nvar _context = __webpack_require__(/*! ../context */ \"./client/src/admin/context/index.js\");\n\nvar _context2 = _interopRequireDefault(_context);\n\nvar _translations = __webpack_require__(/*! ../data/translations */ \"./client/src/admin/data/translations.js\");\n\nvar _api = __webpack_require__(/*! ../api */ \"./client/src/admin/api/index.js\");\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar App = function App() {\n var _useState = (0, _react.useState)(_translations.defaultLanguage),\n _useState2 = _slicedToArray(_useState, 2),\n lang = _useState2[0],\n setLang = _useState2[1];\n\n var _useState3 = (0, _react.useState)([]),\n _useState4 = _slicedToArray(_useState3, 2),\n projects = _useState4[0],\n setProjects = _useState4[1];\n\n var _useState5 = (0, _react.useState)(''),\n _useState6 = _slicedToArray(_useState5, 2),\n info = _useState6[0],\n setInfo = _useState6[1];\n\n var _useState7 = (0, _react.useState)(''),\n _useState8 = _slicedToArray(_useState7, 2),\n hover = _useState8[0],\n setHover = _useState8[1];\n\n var _useState9 = (0, _react.useState)('main'),\n _useState10 = _slicedToArray(_useState9, 2),\n view = _useState10[0],\n setView = _useState10[1];\n\n var _useState11 = (0, _react.useState)(null),\n _useState12 = _slicedToArray(_useState11, 2),\n user = _useState12[0],\n setUser = _useState12[1];\n\n (0, _react.useEffect)(function () {\n (0, _api.getUser)(setUser);\n setInfo('no-saved-websites');\n }, []);\n\n (0, _react.useEffect)(function () {\n user && setLang(user.language);\n }, [user]);\n\n return _react2.default.createElement(\n _context2.default.Provider,\n { value: { lang: lang, setHover: setHover, setInfo: setInfo } },\n _react2.default.createElement(\n 'div',\n { className: 'main' },\n _react2.default.createElement(_TopBar2.default, { lang: lang, setLang: setLang, user: user, setUser: setUser }),\n _react2.default.createElement(\n 'div',\n { className: 'main__content' },\n view === 'main' && _react2.default.createElement(_MainScreen2.default, { projects: projects })\n ),\n _react2.default.createElement(_Info2.default, { info: info, hover: hover })\n )\n );\n};\n\n_reactDom2.default.render(_react2.default.createElement(App, null), document.getElementById('app'));\n\n//# sourceURL=webpack:///./client/src/admin/jsx/App.jsx?");
/***/ }),
@@ -250,7 +250,7 @@ eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _react2 = _interopRequireDefault(_react);\n\nvar _hocs = __webpack_require__(/*! ../hocs */ \"./client/src/admin/hocs/index.js\");\n\nvar _api = __webpack_require__(/*! ../api */ \"./client/src/admin/api/index.js\");\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar User = function User(_ref) {\n var user = _ref.user,\n setUser = _ref.setUser,\n opened = _ref.opened,\n setOpened = _ref.setOpened;\n\n var handleLogout = function handleLogout() {\n setOpened(false);\n (0, _api.logout)();\n };\n var handleChangePass = function handleChangePass() {\n setOpened(false);\n };\n var handleRemoveUser = function handleRemoveUser() {\n setOpened(false);\n };\n\n return _react2.default.createElement(\n 'div',\n { className: 'user' },\n _react2.default.createElement(\n _hocs.WithHover,\n { message: 'click-to-change-user' },\n _react2.default.createElement(\n 'span',\n {\n className: 'user__main-item' + (opened === 'user' ? ' user__main-item--active' : ''),\n onClick: function onClick() {\n return setOpened(opened !== 'user' ? 'user' : false);\n }\n },\n user\n ),\n opened === 'user' && _react2.default.createElement(\n 'div',\n { className: 'user__list' },\n _react2.default.createElement(\n _hocs.WithHover,\n { message: 'click-to-logout' },\n _react2.default.createElement(\n 'span',\n { className: 'user__item', onClick: handleLogout },\n (0, _hocs.t)('logout')\n )\n ),\n _react2.default.createElement(\n _hocs.WithHover,\n { message: 'click-to-change-user-settings' },\n _react2.default.createElement(\n 'span',\n { className: 'user__item', onClick: handleChangePass },\n (0, _hocs.t)('user-settings')\n )\n )\n )\n )\n );\n};\n\nexports.default = User;\n\n//# sourceURL=webpack:///./client/src/admin/jsx/User.jsx?");
+eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _react2 = _interopRequireDefault(_react);\n\nvar _hocs = __webpack_require__(/*! ../hocs */ \"./client/src/admin/hocs/index.js\");\n\nvar _api = __webpack_require__(/*! ../api */ \"./client/src/admin/api/index.js\");\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar User = function User(_ref) {\n var user = _ref.user,\n setUser = _ref.setUser,\n opened = _ref.opened,\n setOpened = _ref.setOpened;\n\n var handleLogout = function handleLogout() {\n setOpened(false);\n (0, _api.logout)();\n };\n var handleChangePass = function handleChangePass() {\n setOpened(false);\n };\n var handleRemoveUser = function handleRemoveUser() {\n setOpened(false);\n };\n\n return _react2.default.createElement(\n 'div',\n { className: 'user' },\n _react2.default.createElement(\n _hocs.WithHover,\n { message: 'click-to-change-user' },\n _react2.default.createElement(\n 'span',\n {\n className: 'user__main-item' + (opened === 'user' ? ' user__main-item--active' : ''),\n onClick: function onClick() {\n return setOpened(opened !== 'user' ? 'user' : false);\n }\n },\n user.email\n ),\n opened === 'user' && _react2.default.createElement(\n 'div',\n { className: 'user__list' },\n _react2.default.createElement(\n _hocs.WithHover,\n { message: 'click-to-logout' },\n _react2.default.createElement(\n 'span',\n { className: 'user__item', onClick: handleLogout },\n (0, _hocs.t)('logout')\n )\n ),\n _react2.default.createElement(\n _hocs.WithHover,\n { message: 'click-to-change-user-settings' },\n _react2.default.createElement(\n 'span',\n { className: 'user__item', onClick: handleChangePass },\n (0, _hocs.t)('user-settings')\n )\n )\n )\n )\n );\n};\n\nexports.default = User;\n\n//# sourceURL=webpack:///./client/src/admin/jsx/User.jsx?");
/***/ }),
diff --git a/client/login/out.js b/client/login/out.js
index b2651d2..b491bc3 100644
--- a/client/login/out.js
+++ b/client/login/out.js
@@ -94,7 +94,7 @@
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__[\"default\"] = ((setUser) => (\n fetch('/api/user/me')\n .then(res => res.json())\n .then(data => setUser(data.email))\n .catch(() => {})\n));\n\n\n//# sourceURL=webpack:///./client/src/admin/api/getUser.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__[\"default\"] = ((setUser) => (\n fetch('/api/user/me')\n .then(res => res.json())\n .then(data => setUser(data))\n .catch(() => {})\n));\n\n\n//# sourceURL=webpack:///./client/src/admin/api/getUser.js?");
/***/ }),
@@ -226,7 +226,7 @@ eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _react2 = _interopRequireDefault(_react);\n\nvar _hocs = __webpack_require__(/*! ../hocs */ \"./client/src/admin/hocs/index.js\");\n\nvar _api = __webpack_require__(/*! ../api */ \"./client/src/admin/api/index.js\");\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar User = function User(_ref) {\n var user = _ref.user,\n setUser = _ref.setUser,\n opened = _ref.opened,\n setOpened = _ref.setOpened;\n\n var handleLogout = function handleLogout() {\n setOpened(false);\n (0, _api.logout)();\n };\n var handleChangePass = function handleChangePass() {\n setOpened(false);\n };\n var handleRemoveUser = function handleRemoveUser() {\n setOpened(false);\n };\n\n return _react2.default.createElement(\n 'div',\n { className: 'user' },\n _react2.default.createElement(\n _hocs.WithHover,\n { message: 'click-to-change-user' },\n _react2.default.createElement(\n 'span',\n {\n className: 'user__main-item' + (opened === 'user' ? ' user__main-item--active' : ''),\n onClick: function onClick() {\n return setOpened(opened !== 'user' ? 'user' : false);\n }\n },\n user\n ),\n opened === 'user' && _react2.default.createElement(\n 'div',\n { className: 'user__list' },\n _react2.default.createElement(\n _hocs.WithHover,\n { message: 'click-to-logout' },\n _react2.default.createElement(\n 'span',\n { className: 'user__item', onClick: handleLogout },\n (0, _hocs.t)('logout')\n )\n ),\n _react2.default.createElement(\n _hocs.WithHover,\n { message: 'click-to-change-user-settings' },\n _react2.default.createElement(\n 'span',\n { className: 'user__item', onClick: handleChangePass },\n (0, _hocs.t)('user-settings')\n )\n )\n )\n )\n );\n};\n\nexports.default = User;\n\n//# sourceURL=webpack:///./client/src/admin/jsx/User.jsx?");
+eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _react2 = _interopRequireDefault(_react);\n\nvar _hocs = __webpack_require__(/*! ../hocs */ \"./client/src/admin/hocs/index.js\");\n\nvar _api = __webpack_require__(/*! ../api */ \"./client/src/admin/api/index.js\");\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar User = function User(_ref) {\n var user = _ref.user,\n setUser = _ref.setUser,\n opened = _ref.opened,\n setOpened = _ref.setOpened;\n\n var handleLogout = function handleLogout() {\n setOpened(false);\n (0, _api.logout)();\n };\n var handleChangePass = function handleChangePass() {\n setOpened(false);\n };\n var handleRemoveUser = function handleRemoveUser() {\n setOpened(false);\n };\n\n return _react2.default.createElement(\n 'div',\n { className: 'user' },\n _react2.default.createElement(\n _hocs.WithHover,\n { message: 'click-to-change-user' },\n _react2.default.createElement(\n 'span',\n {\n className: 'user__main-item' + (opened === 'user' ? ' user__main-item--active' : ''),\n onClick: function onClick() {\n return setOpened(opened !== 'user' ? 'user' : false);\n }\n },\n user.email\n ),\n opened === 'user' && _react2.default.createElement(\n 'div',\n { className: 'user__list' },\n _react2.default.createElement(\n _hocs.WithHover,\n { message: 'click-to-logout' },\n _react2.default.createElement(\n 'span',\n { className: 'user__item', onClick: handleLogout },\n (0, _hocs.t)('logout')\n )\n ),\n _react2.default.createElement(\n _hocs.WithHover,\n { message: 'click-to-change-user-settings' },\n _react2.default.createElement(\n 'span',\n { className: 'user__item', onClick: handleChangePass },\n (0, _hocs.t)('user-settings')\n )\n )\n )\n )\n );\n};\n\nexports.default = User;\n\n//# sourceURL=webpack:///./client/src/admin/jsx/User.jsx?");
/***/ }),
@@ -238,7 +238,7 @@ eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__[\"default\"] = ((email, password) => (\n fetch('/api/user/login', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json;charset=utf-8'\n },\n body: JSON.stringify({ email, password }),\n })\n .then(() => window.location.href = \"/admin\")\n .catch(() => {})\n));\n\n\n//# sourceURL=webpack:///./client/src/login/api/login.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony default export */ __webpack_exports__[\"default\"] = ((loginData) => (\n fetch('/api/user/login', {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json;charset=utf-8'\n },\n body: JSON.stringify(loginData),\n })\n .then(() => window.location.href = \"/admin\")\n .catch(() => {})\n));\n\n\n//# sourceURL=webpack:///./client/src/login/api/login.js?");
/***/ }),
@@ -262,7 +262,7 @@ eval("\n\nvar _slicedToArray = function () { function sliceIterator(arr, i) { va
/***/ (function(module, exports, __webpack_require__) {
"use strict";
-eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"]) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); } }; }();\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _react2 = _interopRequireDefault(_react);\n\nvar _login = __webpack_require__(/*! ../api/login */ \"./client/src/login/api/login.js\");\n\nvar _login2 = _interopRequireDefault(_login);\n\nvar _hocs = __webpack_require__(/*! ../../admin/hocs */ \"./client/src/admin/hocs/index.js\");\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar LoginPanel = function LoginPanel(_ref) {\n var setUser = _ref.setUser;\n\n var _useState = (0, _react.useState)(''),\n _useState2 = _slicedToArray(_useState, 2),\n email = _useState2[0],\n setEmail = _useState2[1];\n\n var _useState3 = (0, _react.useState)(''),\n _useState4 = _slicedToArray(_useState3, 2),\n password = _useState4[0],\n setPassword = _useState4[1];\n\n var _useState5 = (0, _react.useState)(false),\n _useState6 = _slicedToArray(_useState5, 2),\n active = _useState6[0],\n setActive = _useState6[1];\n\n (0, _react.useEffect)(function () {\n var emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n emailRegex.test(email) && password.length > 5 ? setActive(true) : setActive(false);\n }, [email, password]);\n\n var submit = function submit(e) {\n e.preventDefault();\n (0, _login2.default)(email, password);\n };\n\n return _react2.default.createElement(\n 'div',\n { className: 'login-panel' },\n _react2.default.createElement(\n 'form',\n { className: 'login-panel__form', onSubmit: submit },\n _react2.default.createElement(\n 'p',\n { className: 'login-panel__header' },\n (0, _hocs.t)('login-to-admin')\n ),\n _react2.default.createElement(\n 'div',\n { className: 'text-input' },\n _react2.default.createElement('input', {\n onChange: function onChange(e) {\n return setEmail(e.target.value);\n },\n placeholder: (0, _hocs.t)('user'),\n id: 'admin-user-name',\n name: 'admin-user-name',\n type: 'text',\n className: 'text-input-field',\n value: email\n }),\n _react2.default.createElement(\n 'label',\n { htmlFor: 'admin-user-name', className: 'text-input-label' },\n (0, _hocs.t)('user')\n )\n ),\n _react2.default.createElement(\n 'div',\n { className: 'text-input' },\n _react2.default.createElement('input', {\n onChange: function onChange(e) {\n return setPassword(e.target.value);\n },\n placeholder: (0, _hocs.t)('password'),\n id: 'admin-password',\n name: 'admin-password',\n type: 'password',\n className: 'text-input-field',\n value: password\n }),\n _react2.default.createElement(\n 'label',\n { htmlFor: 'admin-password', className: 'text-input-label' },\n (0, _hocs.t)('password')\n )\n ),\n _react2.default.createElement(\n 'div',\n null,\n _react2.default.createElement('input', {\n type: 'submit',\n className: 'login-panel__button' + (active ? ' active' : ''),\n value: (0, _hocs.t)('login')\n })\n )\n )\n );\n};\n\nexports.default = LoginPanel;\n\n//# sourceURL=webpack:///./client/src/login/jsx/LoginPanel.jsx?");
+eval("\n\nObject.defineProperty(exports, \"__esModule\", {\n value: true\n});\n\nvar _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i[\"return\"]) _i[\"return\"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError(\"Invalid attempt to destructure non-iterable instance\"); } }; }();\n\nvar _react = __webpack_require__(/*! react */ \"./node_modules/react/index.js\");\n\nvar _react2 = _interopRequireDefault(_react);\n\nvar _login = __webpack_require__(/*! ../api/login */ \"./client/src/login/api/login.js\");\n\nvar _login2 = _interopRequireDefault(_login);\n\nvar _hocs = __webpack_require__(/*! ../../admin/hocs */ \"./client/src/admin/hocs/index.js\");\n\nfunction _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }\n\nvar LoginPanel = function LoginPanel(_ref) {\n var setUser = _ref.setUser;\n\n var _useState = (0, _react.useState)(''),\n _useState2 = _slicedToArray(_useState, 2),\n email = _useState2[0],\n setEmail = _useState2[1];\n\n var _useState3 = (0, _react.useState)(''),\n _useState4 = _slicedToArray(_useState3, 2),\n password = _useState4[0],\n setPassword = _useState4[1];\n\n var _useState5 = (0, _react.useState)(false),\n _useState6 = _slicedToArray(_useState5, 2),\n active = _useState6[0],\n setActive = _useState6[1];\n\n (0, _react.useEffect)(function () {\n var emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/;\n emailRegex.test(email) && password.length > 5 ? setActive(true) : setActive(false);\n }, [email, password]);\n\n var submit = function submit(e) {\n e.preventDefault();\n (0, _login2.default)({ email: email, password: password });\n };\n\n return _react2.default.createElement(\n 'div',\n { className: 'login-panel' },\n _react2.default.createElement(\n 'form',\n { className: 'login-panel__form', onSubmit: submit },\n _react2.default.createElement(\n 'p',\n { className: 'login-panel__header' },\n (0, _hocs.t)('login-to-admin')\n ),\n _react2.default.createElement(\n 'div',\n { className: 'text-input' },\n _react2.default.createElement('input', {\n onChange: function onChange(e) {\n return setEmail(e.target.value);\n },\n placeholder: (0, _hocs.t)('user'),\n id: 'admin-user-name',\n name: 'admin-user-name',\n type: 'text',\n className: 'text-input-field',\n value: email\n }),\n _react2.default.createElement(\n 'label',\n { htmlFor: 'admin-user-name', className: 'text-input-label' },\n (0, _hocs.t)('user')\n )\n ),\n _react2.default.createElement(\n 'div',\n { className: 'text-input' },\n _react2.default.createElement('input', {\n onChange: function onChange(e) {\n return setPassword(e.target.value);\n },\n placeholder: (0, _hocs.t)('password'),\n id: 'admin-password',\n name: 'admin-password',\n type: 'password',\n className: 'text-input-field',\n value: password\n }),\n _react2.default.createElement(\n 'label',\n { htmlFor: 'admin-password', className: 'text-input-label' },\n (0, _hocs.t)('password')\n )\n ),\n _react2.default.createElement(\n 'div',\n null,\n _react2.default.createElement('input', {\n type: 'submit',\n className: 'login-panel__button' + (active ? ' active' : ''),\n value: (0, _hocs.t)('login')\n })\n )\n )\n );\n};\n\nexports.default = LoginPanel;\n\n//# sourceURL=webpack:///./client/src/login/jsx/LoginPanel.jsx?");
/***/ }),
diff --git a/client/public/favicon.ico b/client/public/favicon.ico
new file mode 100644
index 0000000..31c3448
--- /dev/null
+++ b/client/public/favicon.ico
Binary files differ
diff --git a/client/src/admin/api/getUser.js b/client/src/admin/api/getUser.js
index 930ed3b..697702d 100644
--- a/client/src/admin/api/getUser.js
+++ b/client/src/admin/api/getUser.js
@@ -1,6 +1,6 @@
export default (setUser) => (
fetch('/api/user/me')
.then(res => res.json())
- .then(data => setUser(data.email))
+ .then(data => setUser(data))
.catch(() => {})
);
diff --git a/client/src/admin/jsx/App.jsx b/client/src/admin/jsx/App.jsx
index 93b6a33..3a4da84 100644
--- a/client/src/admin/jsx/App.jsx
+++ b/client/src/admin/jsx/App.jsx
@@ -23,6 +23,10 @@ const App = () => {
setInfo('no-saved-websites');
}, []);
+ useEffect(() => {
+ user && setLang(user.language);
+ }, [user]);
+
return (
<Context.Provider value={{ lang, setHover, setInfo }}>
<div className="main">
diff --git a/client/src/admin/jsx/User.jsx b/client/src/admin/jsx/User.jsx
index 131251e..eb596bf 100644
--- a/client/src/admin/jsx/User.jsx
+++ b/client/src/admin/jsx/User.jsx
@@ -17,7 +17,7 @@ const User = ({ user, setUser, opened, setOpened }) => {
className={`user__main-item${opened === 'user' ? ' user__main-item--active' : ''}`}
onClick={() => setOpened(opened !== 'user' ? 'user' : false)}
>
- {user}
+ {user.email}
</span>
{
opened === 'user' && (
diff --git a/client/src/login/api/login.js b/client/src/login/api/login.js
index 4ed36a7..576f16e 100644
--- a/client/src/login/api/login.js
+++ b/client/src/login/api/login.js
@@ -1,10 +1,10 @@
-export default (email, password) => (
+export default (loginData) => (
fetch('/api/user/login', {
method: 'POST',
headers: {
'Content-Type': 'application/json;charset=utf-8'
},
- body: JSON.stringify({ email, password }),
+ body: JSON.stringify(loginData),
})
.then(() => window.location.href = "/admin")
.catch(() => {})
diff --git a/client/src/login/jsx/LoginPanel.jsx b/client/src/login/jsx/LoginPanel.jsx
index e90a5c4..96b118f 100644
--- a/client/src/login/jsx/LoginPanel.jsx
+++ b/client/src/login/jsx/LoginPanel.jsx
@@ -16,7 +16,7 @@ const LoginPanel = ({setUser}) => {
const submit = (e) => {
e.preventDefault();
- login(email, password);
+ login({email, password});
}
return (
diff --git a/server/helpers/setCookie.js b/server/helpers/setCookie.js
index bb3580c..6d6e7e8 100644
--- a/server/helpers/setCookie.js
+++ b/server/helpers/setCookie.js
@@ -2,7 +2,7 @@ const setCookie = function (res, path, stat) {
if (res.req.newToken){
res.set(
'Set-Cookie',
- 'token='+res.req.newToken+';httpOnly;MaxAge='+process.env.COOKIE_MAX_AGE+';Path=/'
+ 'token='+res.req.newToken+';httpOnly;Max-Age='+process.env.COOKIE_MAX_AGE+';SameSite=Strict;Path=/'
);
}
}
diff --git a/server/middleware/auth.js b/server/middleware/auth.js
index 5c77830..f012054 100644
--- a/server/middleware/auth.js
+++ b/server/middleware/auth.js
@@ -1,5 +1,5 @@
const jwt = require('jsonwebtoken');
-const User = require('../models/User');
+const Session = require('../models/Session');
const auth = async (req, res, next) => {
try {
@@ -10,27 +10,26 @@ const auth = async (req, res, next) => {
}
try {
- const decoded = jwt.verify(token, process.env.JWT_SECRET);
- req.userId = decoded._id;
- req.refreshToken = decoded.ref;
+ const {sessionId, user} = jwt.verify(token, process.env.JWT_SECRET);
+ req.sessionId = sessionId;
+ req.loggedUser = JSON.parse(user);
return next();
+
} catch(er) {
if (er.message && er.message === 'jwt expired') {
- const { _id, ref } = jwt.decode(token, process.env.JWT_SECRET);
- const user = await User.findById(_id);
+ const {sessionId, user} = jwt.decode(token);
+ const userData = JSON.parse(user);
+ const session = await Session.findById(sessionId);
- if (!user) {
+ if (!session || session.userId.toString() !== userData.userId) {
throw new Error();
}
- if (user.sessions.filter(s => s.ref === ref).length > 0) {
- req.userId = _id;
- req.refreshToken = ref;
- req.newToken = await user.generateJwtToken(ref);;
- return next();
- }
-
- throw new Error();
+ session.setAccessDate();
+ req.newToken = session.generateJwtToken(userData);;
+ req.sessionId = sessionId;
+ req.loggedUser = userData;
+ return next();
}
throw new Error();
diff --git a/server/middleware/redirectLogged.js b/server/middleware/redirectLogged.js
index 40a5657..7d06ece 100644
--- a/server/middleware/redirectLogged.js
+++ b/server/middleware/redirectLogged.js
@@ -1,37 +1,42 @@
const jwt = require('jsonwebtoken');
const User = require('../models/User');
+const Session = require('../models/Session');
const redirectLogged = async (req, res, next) => {
+ console.log('redirectLogged')
try {
const token = req.cookies.token || '';
-
if (!token) {
throw new Error();
}
try {
- const decoded = jwt.verify(token, process.env.JWT_SECRET);
- res.redirect('/admin');
+ const token = jwt.verify(token, process.env.JWT_SECRET);
+ if (!token.user || !token.user.userId){
+ throw new Error();
+ }
+ return res.redirect('/admin');
} catch(er) {
if (er.message && er.message === 'jwt expired') {
- const { _id, ref } = jwt.decode(token, process.env.JWT_SECRET);
- const user = await User.findById(_id);
+ const {sessionId, user} = jwt.decode(token);
+ const userData = JSON.parse(user);
+ const session = await Session.findById(sessionId);
- if (!user) {
+ if (!session || session.userId.toString() !== userData.userId) {
throw new Error();
}
- if (user.sessions.filter(s => s.ref === ref).length > 0) {
- const newToken = await user.generateJwtToken(ref);;
- res
- .cookie('token', token, {
- maxAge: parseInt(process.env.COOKIE_MAX_AGE),
- secure: false,
- httpOnly: true,
- })
- .redirect('/admin');
- }
-
+ session.setAccessDate();
+ const newToken = session.generateJwtToken(userData);
+
+ return res
+ .cookie('token', newToken, {
+ maxAge: parseInt(process.env.COOKIE_MAX_AGE),
+ secure: false,
+ SameSite: 'Strict',
+ httpOnly: true,
+ })
+ .redirect('/admin');
throw new Error();
}
diff --git a/server/models/Session.js b/server/models/Session.js
index c410bb9..06a4369 100644
--- a/server/models/Session.js
+++ b/server/models/Session.js
@@ -1,20 +1,31 @@
const mongoose = require("mongoose");
+const jwt = require('jsonwebtoken');
const sessionSchema = new mongoose.Schema({
- user: {
+ userId: {
type : mongoose.Schema.Types.ObjectId,
ref : 'User'
},
- refreshToken: {
- type: String,
- required: true
- },
lastAccess: {
type: Date,
default: Date.now(),
- index: { expires: 90 }
+ index: { expires: parseInt(process.env.DB_SESSION_MAX_AGE) }
}
});
+sessionSchema.methods.setAccessDate = function (user) {
+ this.lastAccess = Date.now();
+ console.log('refreshing time in db')
+ this.save();
+}
+
+sessionSchema.methods.generateJwtToken = function (user) {
+ return jwt.sign(
+ { sessionId: this._id.toString(), user: JSON.stringify(user) },
+ process.env.JWT_SECRET,
+ { expiresIn: parseInt(process.env.JWT_TOKEN_MAX_AGE) }
+ );
+};
+
module.exports = mongoose.model('Session', sessionSchema);
diff --git a/server/models/User.js b/server/models/User.js
index ef3d94e..02cfe25 100644
--- a/server/models/User.js
+++ b/server/models/User.js
@@ -1,8 +1,5 @@
const mongoose = require("mongoose");
const bcrypt = require('bcryptjs');
-const randtoken = require('rand-token');
-const jwt = require('jsonwebtoken');
-const Session = require('./Session');
const userSchema = new mongoose.Schema({
email: {
@@ -25,31 +22,13 @@ const userSchema = new mongoose.Schema({
min: 4,
max: 1024,
},
-});
-
-userSchema.methods.generateJwtToken = async function (currentRefToken) {
- const refreshToken = currentRefToken ? currentRefToken : randtoken.uid(256);
-
- if (!currentRefToken) {
- const session = new Session({ user: this, refreshToken });
- await session.save();
+ language: {
+ type: String,
+ required: true,
+ min: 2,
+ max: 2,
}
-
- return jwt.sign(
- { _id: this._id.toString(), refreshToken },
- process.env.JWT_SECRET,
- { expiresIn: parseInt(process.env.JWT_TOKEN_MAX_AGE) }
- );
-}
-
-userSchema.methods.endSession = async function (ref) {
- this.sessions = this.sessions.filter((session) => {
- return session.ref !== ref;
- });
-
- await this.save();
- return null;
-}
+});
userSchema.statics.findByCredentials = async (email, password) => {
const user = await User.findOne({ email });
diff --git a/server/routes/user.js b/server/routes/user.js
index f2420ab..ee216ac 100644
--- a/server/routes/user.js
+++ b/server/routes/user.js
@@ -1,16 +1,16 @@
const router = require('express').Router();
const User = require('../models/User');
+const Session = require('../models/Session');
const auth = require('../middleware/auth');
const jwt = require('jsonwebtoken');
-router.get('/me', auth, async (req, res) => {
- const user = await User.findById(req.userId);
-
- if (!user) {
- res.clearCookie('token').redirect('/login');
+router.get('/me', auth, (req, res) => {
+ if (req.loggedUser) {
+ console.log(req.loggedUser)
+ return res.json(req.loggedUser);
}
- res.json({ email: user.email });
+ return res.clearCookie('token').redirect('/login');
})
router.post('/register', async (req, res) => {
@@ -33,10 +33,24 @@ router.post('/register', async (req, res) => {
router.post('/login', async (req, res) => {
try {
const user = await User.findByCredentials(req.body.email, req.body.password);
- const token = await user.generateJwtToken();
+ if (!user) {
+ throw new Error();
+ }
+
+ const session = new Session({ userId: user._id });
+ await session.save();
+
+ const publicUserData = {
+ userId: user.id,
+ email: user.email,
+ language: user.language
+ };
+
+ const token = session.generateJwtToken(publicUserData);
+
res
.cookie('token', token, {
- maxAge: parseInt(process.env.COOKIE_MAX_AGE),
+ maxAge: (1000 * parseInt(process.env.COOKIE_MAX_AGE)),
secure: false,
httpOnly: true,
})
@@ -49,8 +63,7 @@ router.post('/login', async (req, res) => {
router.post('/logout', auth, async (req, res) => {
try {
- const user = await User.findById(req.userId);
- await user.endSession(req.refreshToken);
+ await Session.findByIdAndRemove(req.sessionId);
res
.clearCookie('token')
.status(204)