diff --git a/client/build/asset-manifest.json b/client/build/asset-manifest.json index a7a6a7e..479addf 100644 --- a/client/build/asset-manifest.json +++ b/client/build/asset-manifest.json @@ -1,7 +1,7 @@ { "files": { "main.css": "/static/css/main.97dfe1d2.css", - "main.js": "/static/js/main.17eef588.js", + "main.js": "/static/js/main.fe56e574.js", "static/js/787.0cfdad9c.chunk.js": "/static/js/787.0cfdad9c.chunk.js", "static/media/Roboto-ThinItalic-webfont.svg": "/static/media/Roboto-ThinItalic-webfont.e76f369acf2fa69edc40.svg", "static/media/Roboto-LightItalic-webfont.svg": "/static/media/Roboto-LightItalic-webfont.cc00b2543a4da739077c.svg", @@ -46,11 +46,11 @@ "static/media/logo.svg": "/static/media/logo.6ce24c58023cc2f8fd88fe9d219db6c6.svg", "index.html": "/index.html", "main.97dfe1d2.css.map": "/static/css/main.97dfe1d2.css.map", - "main.17eef588.js.map": "/static/js/main.17eef588.js.map", + "main.fe56e574.js.map": "/static/js/main.fe56e574.js.map", "787.0cfdad9c.chunk.js.map": "/static/js/787.0cfdad9c.chunk.js.map" }, "entrypoints": [ "static/css/main.97dfe1d2.css", - "static/js/main.17eef588.js" + "static/js/main.fe56e574.js" ] } \ No newline at end of file diff --git a/client/build/index.html b/client/build/index.html index a457c47..3ad7294 100644 --- a/client/build/index.html +++ b/client/build/index.html @@ -1 +1 @@ -Good Times
\ No newline at end of file +Good Times
\ No newline at end of file diff --git a/client/src/App.js b/client/src/App.js index f1b435a..83be7bc 100644 --- a/client/src/App.js +++ b/client/src/App.js @@ -1,28 +1,46 @@ -import logo from './logo.svg'; -import React, { useState } from "react"; +import React, { useEffect, useState } from "react"; import { - BrowserRouter, Routes, Route, } from "react-router-dom"; -import './App.css'; -import './fonts/index.css'; -import { GoodTimesBar } from "./GoodTimesBar.js"; -import { GlobalContext } from "./GlobalContext.js"; import Container from '@mui/material/Container'; import Paper from '@mui/material/Paper'; + +import './App.css'; +import './fonts/index.css'; + +import { GoodTimesBar } from "./GoodTimesBar.js"; +import { GlobalContext } from "./GlobalContext.js"; + import SignIn from "./SignIn.js"; import SignUp from "./SignUp.js"; +import Group from "./Group.js"; -function App() { +import { base } from "./Common.js"; + +const App = () => { const [ user, setUser ] = useState(null); + const [ csrfToken, setCsrfToken ] = useState(undefined); - console.log(user); + useEffect(() => { + window.fetch(`${base}/api/v1/users/csrf`, { + method: 'GET', + cache: 'no-cache', + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/json' + }, + }).then((res) => { + return res.json(); + }).then((data) => { + setCsrfToken(data.csrfToken); + }); + }, []); return (
- + @@ -31,6 +49,7 @@ function App() { Not implemented... yet. }/> + }/> The eventual new site for the legacy Beer Tuesday... coming soon...
{ user &&
- Logged in as {user.email} + Logged in as {user.email}
} }/> @@ -49,6 +68,6 @@ function App() { ); -} +}; export default App; diff --git a/client/src/Common.js b/client/src/Common.js new file mode 100644 index 0000000..d97ce6a --- /dev/null +++ b/client/src/Common.js @@ -0,0 +1,5 @@ + +const base = process.env.PUBLIC_URL; +export { + base +}; diff --git a/client/src/GlobalContext.js b/client/src/GlobalContext.js new file mode 100644 index 0000000..5ad2056 --- /dev/null +++ b/client/src/GlobalContext.js @@ -0,0 +1,10 @@ +import { createContext } from "react"; + +const global = { + user: undefined, + ws: undefined, +}; + +const GlobalContext = createContext(global); + +export { GlobalContext, global }; \ No newline at end of file diff --git a/client/src/GoodTimesBar.js b/client/src/GoodTimesBar.js index 5d8497e..5815146 100644 --- a/client/src/GoodTimesBar.js +++ b/client/src/GoodTimesBar.js @@ -10,11 +10,8 @@ import Container from '@mui/material/Container'; import Button from '@mui/material/Button'; import Tooltip from '@mui/material/Tooltip'; import MenuItem from '@mui/material/MenuItem'; -import { Link } from 'react-router-dom'; import { - useParams, useNavigate, - useLocation, } from "react-router-dom"; import Gravatar from 'react-gravatar' diff --git a/client/src/Group.js b/client/src/Group.js new file mode 100644 index 0000000..70c7d4f --- /dev/null +++ b/client/src/Group.js @@ -0,0 +1,23 @@ +import React, { useState } from "react"; +import { + useParams +} from "react-router-dom"; + +import './Group.css'; +import { GlobalContext } from "./GlobalContext.js"; +import Paper from '@mui/material/Paper'; + +function Group() { + const { group } = useParams(); + const [ user, setUser ] = useState(null); + + return ( +
+ + Group: {group} + +
+ ); +} + +export default Group; diff --git a/client/src/SignIn.js b/client/src/SignIn.js new file mode 100644 index 0000000..ad8a463 --- /dev/null +++ b/client/src/SignIn.js @@ -0,0 +1,153 @@ +import React, { useContext, useState } from 'react'; +import Avatar from '@mui/material/Avatar'; +import Button from '@mui/material/Button'; +import CssBaseline from '@mui/material/CssBaseline'; +import TextField from '@mui/material/TextField'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import Checkbox from '@mui/material/Checkbox'; +import Link from '@mui/material/Link'; +import Grid from '@mui/material/Grid'; +import Box from '@mui/material/Box'; +import LockOutlinedIcon from '@mui/icons-material/LockOutlined'; +import Typography from '@mui/material/Typography'; +import Container from '@mui/material/Container'; +import { createTheme, ThemeProvider } from '@mui/material/styles'; +import { Link as ReactLink, useNavigate } from "react-router-dom"; + +import { GlobalContext } from "./GlobalContext.js"; +import { base } from "./Common.js"; + +function Copyright(props) { + return ( + + {'Copyright © '} + + ketrenos.com + {' '} + {new Date().getFullYear()} + {'.'} + + ); +} + +const theme = createTheme(); + +export default function SignIn() { + const { setUser, csrfToken } = useContext(GlobalContext); + const [ error, setError ] = useState(undefined); + const navigate = useNavigate(); + + const handleSubmit = (event) => { + event.preventDefault(); + const data = new FormData(event.currentTarget); + console.log({ + email: data.get('email'), + password: data.get('password'), + }); + window.fetch(`${base}/api/v1/users/login`, { + method: 'POST', + cache: 'no-cache', + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/json', + 'CSRF-Token': csrfToken + }, + body: JSON.stringify({ + email: data.get('email'), + password: data.get('password') + }) + }) + .then(async (res) => { + return [ res.status, res.statusText, await res.json() ]; + }) + .then(([ status, statusText, data ]) => { + if (status >= 400) { + setError(data.message ? data.message : statusText); + return null; + } if (!data) { + return; + } + setUser(data); + navigate("/"); + }) + .catch((error) => { + console.error(`Error: `, error); + setError(`Error authenticating.`); + }); + }; + + return ( + + + + + + + + + Sign in + + + + + {error && + + {error} + + } + } + label="Remember me" + /> + + + + + Forgot password? + + + + + {"Don't have an account? Sign Up"} + + + + + + + + + ); +} \ No newline at end of file diff --git a/client/src/SignUp.js b/client/src/SignUp.js new file mode 100644 index 0000000..02f7288 --- /dev/null +++ b/client/src/SignUp.js @@ -0,0 +1,126 @@ +import * as React from 'react'; +import Avatar from '@mui/material/Avatar'; +import Button from '@mui/material/Button'; +import CssBaseline from '@mui/material/CssBaseline'; +import TextField from '@mui/material/TextField'; +import FormControlLabel from '@mui/material/FormControlLabel'; +import Checkbox from '@mui/material/Checkbox'; +import Link from '@mui/material/Link'; +import Grid from '@mui/material/Grid'; +import Box from '@mui/material/Box'; +import LockOutlinedIcon from '@mui/icons-material/LockOutlined'; +import Typography from '@mui/material/Typography'; +import Container from '@mui/material/Container'; +import { createTheme, ThemeProvider } from '@mui/material/styles'; +import { Link as ReactLink } from "react-router-dom"; + +function Copyright(props) { + return ( + + {'Copyright © '} + + ketrenos.com + {' '} + {new Date().getFullYear()} + {'.'} + + ); +} + +const theme = createTheme(); + +export default function SignUp() { + const handleSubmit = (event) => { + event.preventDefault(); + const data = new FormData(event.currentTarget); + console.log({ + email: data.get('email'), + password: data.get('password'), + }); + }; + + return ( + + + + + + + + + Sign up + + + + + + + + + + + + + + + + + + + + + Already have an account? Sign in + + + + + + + + + ); +} \ No newline at end of file diff --git a/db/users.db b/db/users.db index 20c0c50..5a57830 100644 Binary files a/db/users.db and b/db/users.db differ diff --git a/server/.dockerignore b/server/.dockerignore new file mode 100644 index 0000000..3c3629e --- /dev/null +++ b/server/.dockerignore @@ -0,0 +1 @@ +node_modules diff --git a/server/app.js b/server/app.js index 52d7de1..a8fe47b 100755 --- a/server/app.js +++ b/server/app.js @@ -11,11 +11,22 @@ const express = require("express"), basePath = require("./basepath"), cookieParser = require("cookie-parser"), app = express(), - fs = require('fs'); + fs = require('fs'), + csrf = require('csurf'); const server = require("http").createServer(app); -app.use(cookieParser()); +app.use(session({ + secret: 'm@g1x!', + resave: false, + saveUninitialized: false, + cookie: { secure: true } +})); +app.use(bodyParser.urlencoded({ extended: false })) +app.use(cookieParser()) +app.use(csrf({ + cookie: true +})); const ws = require('express-ws')(app, server); diff --git a/server/db/groups.js b/server/db/groups.js index e7834a0..1af9c13 100755 --- a/server/db/groups.js +++ b/server/db/groups.js @@ -18,7 +18,6 @@ function init() { primaryKey: true, autoIncrement: true }, - path: Sequelize.STRING, name: Sequelize.STRING, }, { timestamps: false, diff --git a/server/db/users.js b/server/db/users.js index 00e5dae..b9b6376 100755 --- a/server/db/users.js +++ b/server/db/users.js @@ -19,6 +19,7 @@ function init() { displayName: Sequelize.STRING, notes: Sequelize.STRING, uid: Sequelize.STRING, + md5: Sequelize.STRING, authToken: Sequelize.STRING, authDate: Sequelize.DATE, authenticated: Sequelize.BOOLEAN, diff --git a/server/lib/mail.js b/server/lib/mail.js index 3cc10c2..6098d5b 100644 --- a/server/lib/mail.js +++ b/server/lib/mail.js @@ -9,7 +9,7 @@ const templates = { "html": [ "

Hello {{username}},

", "", - "

Welcome to ketrenos.com. You are almost done creating your account. ", + "

Welcome to goodtimes.ketrenos.com. You are almost done creating your account. ", "Before you can access the system, you must verify your email address.

", "", "

To do so, simply access this link:

", @@ -21,7 +21,7 @@ const templates = { "text": [ "Hello {{username}},", "", - "Welcome to ketrenos.com. You are almost done creating your account. ", + "Welcome to goodtimes.ketrenos.com. You are almost done creating your account. ", "Before you can access the system, you must verify your email address.", "", "To do so, simply access this link:", diff --git a/server/package-lock.json b/server/package-lock.json index 01db6be..b0a0537 100644 --- a/server/package-lock.json +++ b/server/package-lock.json @@ -1,11 +1,11 @@ { - "name": "peddlers-of-ketran-server", + "name": "goodtimes-server", "version": "1.0.0", "lockfileVersion": 2, "requires": true, "packages": { "": { - "name": "peddlers-of-ketran-server", + "name": "goodtimes-server", "version": "1.0.0", "license": "MIT", "dependencies": { @@ -15,16 +15,20 @@ "connect-sqlite3": "^0.9.11", "cookie-parser": "^1.4.6", "core-js": "^3.21.1", + "csurf": "^1.11.0", "express": "^4.17.3", "express-session": "^1.17.1", "express-ws": "^5.0.2", "fast-deep-equal": "^3.1.3", - "handlebars": "^4.7.6", + "handlebars": "^4.7.7", "moment": "^2.24.0", "morgan": "^1.9.1", "node-fetch": "^2.6.0", "node-gzip": "^1.1.2", "nodemailer": "^6.3.0", + "passport": "^0.5.2", + "passport-magic-link": "^2.1.0", + "pluralize": "^8.0.0", "random-words": "^1.1.2", "sequelize": "^5.21.6", "sqlite3": "^4.1.1", @@ -32,6 +36,34 @@ "ws": "^8.5.0" } }, + "node_modules/@babel/polyfill": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.12.1.tgz", + "integrity": "sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g==", + "deprecated": "🚨 This package has been deprecated in favor of separate inclusion of a polyfill and regenerator-runtime (when needed). See the @babel/polyfill docs (https://babeljs.io/docs/en/babel-polyfill) for more information.", + "dependencies": { + "core-js": "^2.6.5", + "regenerator-runtime": "^0.13.4" + } + }, + "node_modules/@babel/polyfill/node_modules/core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==", + "deprecated": "core-js@<3.4 is no longer maintained and not recommended for usage due to the number of issues. Because of the V8 engine whims, feature detection in old core-js versions could cause a slowdown up to 100x even if nothing is polyfilled. Please, upgrade your dependencies to the actual version of core-js.", + "hasInstallScript": true + }, + "node_modules/@babel/runtime": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", + "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "dependencies": { + "regenerator-runtime": "^0.13.4" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@types/node": { "version": "17.0.23", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz", @@ -220,6 +252,11 @@ "concat-map": "0.0.1" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "node_modules/bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -392,6 +429,77 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "node_modules/csrf": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz", + "integrity": "sha512-uTqEnCvWRk042asU6JtapDTcJeeailFy4ydOQS28bj1hcLnYRiqi8SsD2jS412AY1I/4qdOwWZun774iqywf9w==", + "dependencies": { + "rndm": "1.2.0", + "tsscmp": "1.0.6", + "uid-safe": "2.1.5" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/csurf": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.11.0.tgz", + "integrity": "sha512-UCtehyEExKTxgiu8UHdGvHj4tnpE/Qctue03Giq5gPgMQ9cg/ciod5blZQ5a4uCEenNQjxyGuzygLdKUmee/bQ==", + "dependencies": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "csrf": "3.1.0", + "http-errors": "~1.7.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/csurf/node_modules/cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/csurf/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/csurf/node_modules/http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/csurf/node_modules/setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "node_modules/csurf/node_modules/toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==", + "engines": { + "node": ">=0.6" + } + }, "node_modules/dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -477,6 +585,14 @@ "safer-buffer": "^2.1.0" } }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1109,6 +1225,40 @@ "node": ">=6" } }, + "node_modules/jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=4", + "npm": ">=1.4.28" + } + }, + "node_modules/jsonwebtoken/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/jsonwebtoken/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/jsprim": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", @@ -1124,11 +1274,65 @@ "node": ">=0.6.0" } }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -1585,6 +1789,41 @@ "node": ">= 0.8" } }, + "node_modules/passport": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.5.2.tgz", + "integrity": "sha512-w9n/Ot5I7orGD4y+7V3EFJCQEznE5RxHamUxcqLT2QoJY0f2JdN8GyHonYFvN0Vz+L6lUJfVhrk2aZz2LbuREw==", + "dependencies": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + }, + "engines": { + "node": ">= 0.4.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/jaredhanson" + } + }, + "node_modules/passport-magic-link": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/passport-magic-link/-/passport-magic-link-2.1.0.tgz", + "integrity": "sha512-NzToduaRS8Qj/hHK+LsFTvlRfFwb+f+jGkLshlJSuY3kIt+c3ChrXWK4Kr0p2MStD8qMtZ9otLWn1w35UwGKIQ==", + "dependencies": { + "@babel/polyfill": "^7.0.0", + "@babel/runtime": "^7.3.1", + "jsonwebtoken": "^8.4.0", + "passport-strategy": "^1.0.0" + } + }, + "node_modules/passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=", + "engines": { + "node": ">= 0.4.0" + } + }, "node_modules/path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -1598,12 +1837,25 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "node_modules/pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, "node_modules/performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "optional": true }, + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "engines": { + "node": ">=4" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -1718,6 +1970,11 @@ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" }, + "node_modules/regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, "node_modules/request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -1788,6 +2045,11 @@ "rimraf": "bin.js" } }, + "node_modules/rndm": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz", + "integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w=" + }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -2138,6 +2400,14 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" }, + "node_modules/tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==", + "engines": { + "node": ">=0.6.x" + } + }, "node_modules/tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", @@ -2349,6 +2619,30 @@ } }, "dependencies": { + "@babel/polyfill": { + "version": "7.12.1", + "resolved": "https://registry.npmjs.org/@babel/polyfill/-/polyfill-7.12.1.tgz", + "integrity": "sha512-X0pi0V6gxLi6lFZpGmeNa4zxtwEmCs42isWLNjZZDE0Y8yVfgu0T2OAHlzBbdYlqbW/YXVvoBHpATEM+goCj8g==", + "requires": { + "core-js": "^2.6.5", + "regenerator-runtime": "^0.13.4" + }, + "dependencies": { + "core-js": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.12.tgz", + "integrity": "sha512-Kb2wC0fvsWfQrgk8HU5lW6U/Lcs8+9aaYcy4ZFc6DDlo4nZ7n70dEgE5rtR0oG6ufKDUnrwfWL1mXR5ljDatrQ==" + } + } + }, + "@babel/runtime": { + "version": "7.17.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.9.tgz", + "integrity": "sha512-lSiBBvodq29uShpWGNbgFdKYNiFDo5/HIYsaCEY9ff4sb10x9jizo2+pRrSyF4jKZCXqgzuqBOQKbUm90gQwJg==", + "requires": { + "regenerator-runtime": "^0.13.4" + } + }, "@types/node": { "version": "17.0.23", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.23.tgz", @@ -2513,6 +2807,11 @@ "concat-map": "0.0.1" } }, + "buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha1-+OcRMvf/5uAaXJaXpMbz5I1cyBk=" + }, "bytes": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", @@ -2641,6 +2940,61 @@ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" }, + "csrf": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz", + "integrity": "sha512-uTqEnCvWRk042asU6JtapDTcJeeailFy4ydOQS28bj1hcLnYRiqi8SsD2jS412AY1I/4qdOwWZun774iqywf9w==", + "requires": { + "rndm": "1.2.0", + "tsscmp": "1.0.6", + "uid-safe": "2.1.5" + } + }, + "csurf": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/csurf/-/csurf-1.11.0.tgz", + "integrity": "sha512-UCtehyEExKTxgiu8UHdGvHj4tnpE/Qctue03Giq5gPgMQ9cg/ciod5blZQ5a4uCEenNQjxyGuzygLdKUmee/bQ==", + "requires": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6", + "csrf": "3.1.0", + "http-errors": "~1.7.3" + }, + "dependencies": { + "cookie": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", + "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + } + } + }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", @@ -2704,6 +3058,14 @@ "safer-buffer": "^2.1.0" } }, + "ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "requires": { + "safe-buffer": "^5.0.1" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -3200,6 +3562,35 @@ "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz", "integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==" }, + "jsonwebtoken": { + "version": "8.5.1", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-8.5.1.tgz", + "integrity": "sha512-XjwVfRS6jTMsqYs0EsuJ4LGxXV14zQybNd4L2r0UvbVnSF9Af8x7p5MzbJ90Ioz/9TI41/hTCvznF/loiSzn8w==", + "requires": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^5.6.0" + }, + "dependencies": { + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + } + } + }, "jsprim": { "version": "1.4.2", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", @@ -3212,11 +3603,65 @@ "verror": "1.10.0" } }, + "jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "requires": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "requires": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "lodash": { "version": "4.17.21", "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" }, + "lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha1-YLuYqHy5I8aMoeUTJUgzFISfVT8=" + }, + "lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha1-bC4XHbKiV82WgC/UOwGyDV9YcPY=" + }, + "lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha1-YZwK89A/iwTDH1iChAt3sRzWg0M=" + }, + "lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha1-POdoEMWSjQM1IwGsKHMX8RwLH/w=" + }, + "lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha1-fFJqUtibRcRcxpC4gWO+BJf1UMs=" + }, + "lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha1-1SfftUVuynzJu5XV2ur4i6VKVFE=" + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=" + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -3572,6 +4017,31 @@ "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" }, + "passport": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/passport/-/passport-0.5.2.tgz", + "integrity": "sha512-w9n/Ot5I7orGD4y+7V3EFJCQEznE5RxHamUxcqLT2QoJY0f2JdN8GyHonYFvN0Vz+L6lUJfVhrk2aZz2LbuREw==", + "requires": { + "passport-strategy": "1.x.x", + "pause": "0.0.1" + } + }, + "passport-magic-link": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/passport-magic-link/-/passport-magic-link-2.1.0.tgz", + "integrity": "sha512-NzToduaRS8Qj/hHK+LsFTvlRfFwb+f+jGkLshlJSuY3kIt+c3ChrXWK4Kr0p2MStD8qMtZ9otLWn1w35UwGKIQ==", + "requires": { + "@babel/polyfill": "^7.0.0", + "@babel/runtime": "^7.3.1", + "jsonwebtoken": "^8.4.0", + "passport-strategy": "^1.0.0" + } + }, + "passport-strategy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/passport-strategy/-/passport-strategy-1.0.0.tgz", + "integrity": "sha1-tVOaqPwiWj0a0XlHbd8ja0QPUuQ=" + }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", @@ -3582,12 +4052,22 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" }, + "pause": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/pause/-/pause-0.0.1.tgz", + "integrity": "sha1-HUCLP9t2kjuVQ9lvtMnf1TXZy10=" + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", "optional": true }, + "pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==" + }, "process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -3680,6 +4160,11 @@ } } }, + "regenerator-runtime": { + "version": "0.13.9", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz", + "integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==" + }, "request": { "version": "2.88.2", "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", @@ -3738,6 +4223,11 @@ "glob": "^7.1.3" } }, + "rndm": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz", + "integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w=" + }, "safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -4011,6 +4501,11 @@ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=" }, + "tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" + }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", diff --git a/server/package.json b/server/package.json index 158858d..39a9cd5 100644 --- a/server/package.json +++ b/server/package.json @@ -15,16 +15,20 @@ "connect-sqlite3": "^0.9.11", "cookie-parser": "^1.4.6", "core-js": "^3.21.1", + "csurf": "^1.11.0", "express": "^4.17.3", "express-session": "^1.17.1", "express-ws": "^5.0.2", "fast-deep-equal": "^3.1.3", - "handlebars": "^4.7.6", + "handlebars": "^4.7.7", "moment": "^2.24.0", "morgan": "^1.9.1", "node-fetch": "^2.6.0", "node-gzip": "^1.1.2", "nodemailer": "^6.3.0", + "passport": "^0.5.2", + "passport-magic-link": "^2.1.0", + "pluralize": "^8.0.0", "random-words": "^1.1.2", "sequelize": "^5.21.6", "sqlite3": "^4.1.1", diff --git a/server/routes/users.js b/server/routes/users.js index 297f80a..35973d7 100755 --- a/server/routes/users.js +++ b/server/routes/users.js @@ -77,6 +77,11 @@ router.put("/password", function(req, res) { }); }); +router.get("/csrf", (req, res) => { + console.log("/users/csrf"); + res.json({ csrfToken: req.csrfToken() }); +}); + router.post("/create", function(req, res) { console.log("/users/create"); @@ -92,7 +97,10 @@ router.post("/create", function(req, res) { return res.status(400).send("Missing email address, password, name, and/or who you know."); } - user.password = crypto.createHash('sha256').update(user.password).digest('base64'); + user.password = crypto.createHash('sha256') + .update(user.password).digest('base64'); + user.md5 = crypto.createHash('md5') + .update(data).digest('base64'); return userDB.sequelize.query("SELECT * FROM users WHERE uid=:uid", { replacements: user, @@ -110,8 +118,8 @@ router.post("/create", function(req, res) { } }).then(function() { return userDB.sequelize.query("INSERT INTO users " + - "(uid,displayName,password,mail,memberSince,authenticated,notes) " + - "VALUES(:uid,:displayName,:password,:mail,CURRENT_TIMESTAMP,0,:notes)", { + "(uid,displayName,password,mail,memberSince,authenticated,notes,md5) " + + "VALUES(:uid,:displayName,:password,:mail,CURRENT_TIMESTAMP,0,:notes,:md5)", { replacements: user }).spread(function(results, metadata) { req.session.userId = metadata.lastID; @@ -162,42 +170,6 @@ const getSessionUser = function(req) { return user; }); - }).then(function(user) { - req.user = user; - - /* If the user already has a restriction, or there are no album user restrictions, - * return the user to the next promise */ - if (user.restriction || !config.has("restrictions")) { - return user; - } - - let allowed = config.get("restrictions"); - if (!Array.isArray(allowed)) { - allowed = [ allowed ]; - } - for (let i = 0; i < allowed.length; i++) { - if (allowed[i] == user.username) { - return user; - } - } - console.log("Unauthorized (logged in) access by user: " + user.username); - user.restriction = "Unauthorized access attempt to restricted album."; - - return user; - }).then(function(user) { - /* If there are maintainers on this album, check if this user is a maintainer */ - if (config.has("maintainers")) { - let maintainers = config.get("maintainers"); - if (maintainers.indexOf(user.username) != -1) { - user.maintainer = true; - if (user.restriction) { - console.warn("User " + user.username + " is a maintainer AND has a restriction which will be ignored: " + user.restriction); - delete user.restriction; - } - } - } - - return user; }).then(function(user) { /* Strip out any fields that shouldn't be there. The allowed fields are: */ let allowed = [ @@ -215,42 +187,48 @@ const getSessionUser = function(req) { router.post("/login", function(req, res) { console.log("/users/login"); - let username = req.query.u || req.body.u || "", - password = req.query.p || req.body.p || ""; + let { email, password } = req.body; console.log("Login attempt"); - if (!username || !password) { - return res.status(400).send("Missing username and/or password"); + if (!email || !password) { + return res.status(400).send({ + message: `Missing email and/or password` + }); } - return new Promise((reject, resolve) => { - console.log("Looking up user in DB."); - let query = "SELECT " + - "id,mailVerified,authenticated,uid AS username,displayName AS name,mail " + - "FROM users WHERE uid=:username AND password=:password"; - return userDB.sequelize.query(query, { - replacements: { - username: username, - password: crypto.createHash('sha256').update(password).digest('base64') - }, - type: userDB.Sequelize.QueryTypes.SELECT - }).then(function(users) { - if (users.length != 1) { - return resolve(null); - } - let user = users[0]; - req.session.userId = user.id; - return resolve(user); - }); - }).then(function(user) { + console.log("Looking up user in DB."); + + let query = "SELECT " + + "id,mailVerified,authenticated," + + "uid AS username," + + "displayName AS name,mail " + + "FROM users WHERE uid=:username AND password=:password"; + return userDB.sequelize.query(query, { + replacements: { + username: email, + password: crypto.createHash('sha256').update(password).digest('base64') + }, + type: userDB.Sequelize.QueryTypes.SELECT + }) + .then(function(users) { + if (users.length != 1) { + return null; + } + let user = users[0]; + req.session.userId = user.id; + return user; + }) + .then(function(user) { if (!user) { - console.log(username + " not found (or invalid password.)"); + console.log(email + " not found (or invalid password.)"); req.session.userId = null; - return res.status(401).send("Invalid login credentials"); + return res.status(401).send({ + message: `Invalid login credentials` + }); } - let message = "Logged in as " + user.username + " (" + user.id + ")"; + let message = "Logged in as " + user.displayName + " (" + user.id + ")"; if (!user.mailVerified) { console.log(message + ", who is not verified email."); } else if (!user.authenticated) { @@ -262,7 +240,8 @@ router.post("/login", function(req, res) { return getSessionUser(req).then(function(user) { return res.status(200).send(user); }); - }).catch(function(error) { + }) + .catch(function(error) { console.log(error); return res.status(403).send(error); });