1
0

Sign In is plumbed

Signed-off-by: James Ketrenos <james_eikona@ketrenos.com>
This commit is contained in:
James Ketrenos 2022-04-06 12:28:36 -07:00
parent 3793107597
commit b6a62c7de2
18 changed files with 918 additions and 95 deletions

View File

@ -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"
]
}

View File

@ -1 +1 @@
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Goodtimes"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>Good Times</title><script defer="defer" src="/static/js/main.17eef588.js"></script><link href="/static/css/main.97dfe1d2.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
<!doctype html><html lang="en"><head><meta charset="utf-8"/><link rel="icon" href="/favicon.ico"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><meta name="description" content="Goodtimes"/><link rel="apple-touch-icon" href="/logo192.png"/><link rel="manifest" href="/manifest.json"/><title>Good Times</title><script defer="defer" src="/static/js/main.fe56e574.js"></script><link href="/static/css/main.97dfe1d2.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>

View File

@ -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 (
<div className="App">
<GlobalContext.Provider value={{user, setUser}}>
<GlobalContext.Provider value={{user, setUser, csrfToken }}>
<GoodTimesBar />
<Container className="Content">
<Routes>
@ -31,6 +49,7 @@ function App() {
<Route path="/password" element={
<Paper>Not implemented... yet.</Paper>
}/>
<Route path="/:group" element={<Group />}/>
<Route path="/" element={
<Paper style={{
flexDirection: 'column',
@ -40,7 +59,7 @@ function App() {
<div>The eventual new site for the legacy Beer Tuesday... coming soon...
</div>
{ user && <div>
Logged in as {user.email}
Logged in as {user.email}
</div> }
</Paper>
}/>
@ -49,6 +68,6 @@ function App() {
</GlobalContext.Provider>
</div>
);
}
};
export default App;

5
client/src/Common.js Normal file
View File

@ -0,0 +1,5 @@
const base = process.env.PUBLIC_URL;
export {
base
};

View File

@ -0,0 +1,10 @@
import { createContext } from "react";
const global = {
user: undefined,
ws: undefined,
};
const GlobalContext = createContext(global);
export { GlobalContext, global };

View File

@ -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'

23
client/src/Group.js Normal file
View File

@ -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 (
<div className="Group">
<GlobalContext.Provider value={{user, setUser}}>
Group: {group}
</GlobalContext.Provider>
</div>
);
}
export default Group;

153
client/src/SignIn.js Normal file
View File

@ -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 (
<Typography variant="body2" color="text.secondary" align="center" {...props}>
{'Copyright © '}
<Link color="inherit" href="https://ketrenos.com/">
ketrenos.com
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
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 (
<ThemeProvider theme={theme}>
<Container component="main" maxWidth="xs">
<CssBaseline />
<Box
sx={{
marginTop: 8,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign in
</Typography>
<Box component="form" onSubmit={handleSubmit} noValidate sx={{ mt: 1 }}>
<TextField
margin="normal"
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
autoFocus
/>
<TextField
margin="normal"
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="current-password"
/>
{error &&
<Typography component="h2" sx={{ color: 'red' }} >
{error}
</Typography>
}
<FormControlLabel
control={<Checkbox value="remember" color="primary" />}
label="Remember me"
/>
<Button
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
>
Sign In
</Button>
<Grid container>
<Grid item xs>
<Link component={ReactLink} to="/password" variant="body2">
Forgot password?
</Link>
</Grid>
<Grid item>
<Link component={ReactLink} to="/signup" variant="body2">
{"Don't have an account? Sign Up"}
</Link>
</Grid>
</Grid>
</Box>
</Box>
<Copyright sx={{ mt: 8, mb: 4 }} />
</Container>
</ThemeProvider>
);
}

126
client/src/SignUp.js Normal file
View File

@ -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 (
<Typography variant="body2" color="text.secondary" align="center" {...props}>
{'Copyright © '}
<Link color="inherit" href="https://ketrenos.com/">
ketrenos.com
</Link>{' '}
{new Date().getFullYear()}
{'.'}
</Typography>
);
}
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 (
<ThemeProvider theme={theme}>
<Container component="main" maxWidth="xs">
<CssBaseline />
<Box
sx={{
marginTop: 8,
display: 'flex',
flexDirection: 'column',
alignItems: 'center',
}}
>
<Avatar sx={{ m: 1, bgcolor: 'secondary.main' }}>
<LockOutlinedIcon />
</Avatar>
<Typography component="h1" variant="h5">
Sign up
</Typography>
<Box component="form" noValidate onSubmit={handleSubmit} sx={{ mt: 3 }}>
<Grid container spacing={2}>
<Grid item xs={12} sm={6}>
<TextField
autoComplete="given-name"
name="firstName"
required
fullWidth
id="firstName"
label="First Name"
autoFocus
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
required
fullWidth
id="lastName"
label="Last Name"
name="lastName"
autoComplete="family-name"
/>
</Grid>
<Grid item xs={12}>
<TextField
required
fullWidth
id="email"
label="Email Address"
name="email"
autoComplete="email"
/>
</Grid>
<Grid item xs={12}>
<TextField
required
fullWidth
name="password"
label="Password"
type="password"
id="password"
autoComplete="new-password"
/>
</Grid>
</Grid>
<Button
type="submit"
fullWidth
variant="contained"
sx={{ mt: 3, mb: 2 }}
>
Sign Up
</Button>
<Grid container justifyContent="flex-end">
<Grid item>
<Link component={ReactLink} to="/signin" variant="body2">
Already have an account? Sign in
</Link>
</Grid>
</Grid>
</Box>
</Box>
<Copyright sx={{ mt: 5 }} />
</Container>
</ThemeProvider>
);
}

Binary file not shown.

1
server/.dockerignore Normal file
View File

@ -0,0 +1 @@
node_modules

View File

@ -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);

View File

@ -18,7 +18,6 @@ function init() {
primaryKey: true,
autoIncrement: true
},
path: Sequelize.STRING,
name: Sequelize.STRING,
}, {
timestamps: false,

View File

@ -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,

View File

@ -9,7 +9,7 @@ const templates = {
"html": [
"<p>Hello {{username}},</p>",
"",
"<p>Welcome to <b>ketrenos.com</b>. You are almost done creating your account. ",
"<p>Welcome to <b>goodtimes.ketrenos.com</b>. You are almost done creating your account. ",
"Before you can access the system, you must verify your email address.</p>",
"",
"<p>To do so, simply access this link:</p>",
@ -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:",

501
server/package-lock.json generated
View File

@ -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",

View File

@ -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",

View File

@ -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);
});