diff --git a/.env b/.env index 8f5abf1..ceeb379 100644 --- a/.env +++ b/.env @@ -1,3 +1,6 @@ +HTTPS=true +SSL_CRT_FILE=/etc/letsencrypt/live/ketrenos.com/cert.pem +SSL_KEY_FILE=/etc/letsencrypt/live/ketrenos.com/privkey.pem REACT_APP_basePath="/" NODE_CONFIG_ENV='production' -LOG_LINE=1 \ No newline at end of file +LOG_LINE=1 diff --git a/client/package.json b/client/package.json index 0e4c889..83435fe 100644 --- a/client/package.json +++ b/client/package.json @@ -32,7 +32,7 @@ "web-vitals": "^2.1.2" }, "scripts": { - "start": "HTTPS=true react-scripts start", + "start": "export $(cat ../.env | xargs) && react-scripts start", "build": "export $(cat ../.env | xargs) && react-scripts build", "test": "export $(cat ../.env | xargs) && react-scripts test", "eject": "export $(cat ../.env | xargs) && react-scripts eject" diff --git a/client/src/Group.js b/client/src/Group.js index c94ebd1..b0b8db1 100644 --- a/client/src/Group.js +++ b/client/src/Group.js @@ -8,6 +8,7 @@ import { import './Group.css'; import { GlobalContext } from "./GlobalContext.js"; import { base } from "./Common.js"; +import { Location } from "./Location.js"; function Group() { const { csrfToken, user, setUser } = useContext(GlobalContext); @@ -40,36 +41,7 @@ function Group() { if (!data) { return; } - setLocations(data.map(location => { - const fields = Object.getOwnPropertyNames(location) - .map(field =>
-
{field}
-
- {location[field]} -
-
- ); - return
{ fields }
; - })); + setLocations(data); }; effect(); }, [user, setGroup, groupId, csrfToken]); @@ -114,7 +86,8 @@ function Group() { { !error && <>
Group: {groupId}
Locations
- { locations } + { locations.map(location => + ) } } diff --git a/client/src/Location.css b/client/src/Location.css new file mode 100644 index 0000000..e8ac05b --- /dev/null +++ b/client/src/Location.css @@ -0,0 +1,4 @@ +.Location { + text-align: center; +} + diff --git a/client/src/Location.js b/client/src/Location.js new file mode 100644 index 0000000..fbcdc45 --- /dev/null +++ b/client/src/Location.js @@ -0,0 +1,94 @@ +import React, { useState, useEffect, useContext } from "react"; +import Paper from '@mui/material/Paper'; +import { + useParams, + useNavigate +} from "react-router-dom"; + +import './Location.css'; +import { GlobalContext } from "./GlobalContext.js"; +import { base } from "./Common.js"; + +function Location(props) { + const propLocation = props.location; + const { csrfToken } = useContext(GlobalContext); + const [ location, setLocation ] = useState( + typeof propLocation === 'object' ? propLocation : undefined); + const locationId = + typeof propLocation === 'number' ? propLocation : undefined; + const [ error, setError ] = useState(null); + + useEffect(() => { + if (!csrfToken && (location || !locationId)) { + return; + } + + const effect = async () => { + const res = await window.fetch( + `${base}/api/v1/locations/${locationId}`, { + method: 'GET', + cache: 'no-cache', + credentials: 'same-origin', + headers: { + 'Content-Type': 'application/json', + 'CSRF-Token': csrfToken + } + }); + const data = await res.json(); + if (res.status >= 400) { + setError(data.message ? data.message : res.statusText); + return; + } + if (!data) { + return; + } + setLocation(data); + } + effect(); + }, [locationId, csrfToken, location]); + + const createLocation = (location) => { + const fields = Object.getOwnPropertyNames(location) + .map(field =>
+
{field}
+
+ {location[field]} +
+
+ ); + return
{fields}
; + }; + + return ( + + { error &&
{error}
} + { !error && <> + { createLocation(location) } + } +
+ ); +} + +export { Location }; diff --git a/server/app.js b/server/app.js index 6341f53..227efdf 100755 --- a/server/app.js +++ b/server/app.js @@ -26,30 +26,40 @@ require('./console-line.js'); /* Monkey-patch console.log with line numbers */ app.set('trust proxy', true); app.use(session({ secret: 'm@g1x!c00k13$', - maxAge: 14 * 24 * 60 * 60 * 1000, /* 2 weeks */ - resave: true, - saveUninitialized: false, + maxAge: 30 * 24 * 60 * 60 * 1000, /* 1 month */ + resave: false, + saveUninitialized: true, cookie: { secure: true }, store: new SqliteStore({ driver: sqlite3.Database, path: config.get('sessions.db'), - ttl: 5000, + ttl: 30 * 24 * 60 * 60 * 1000, /* 1 month */ cleanupInterval: 300000 }), })); -app.use(bodyParser.urlencoded({ extended: false })); -app.use((req, res, next) => { +const csrfDebug = (req) => { console.log('CSRF debug: ', { - token: req.header('CSRF-Token'), - method: req.method + method: req.method, + path: req.path, + token: req.header('CSRF-Token'), + csrf: req.csrfToken ? req.csrfToken() : 'CSRF not initialized', + user: (req.session && req.session.userId) + ? req.session.userId + : 'Not logged in' }); - next(); -}); +}; + +app.use(bodyParser.urlencoded({ extended: false })); + app.use(cookieParser()); app.use(csrf({ cookie: true })); +app.use((req, res, next) => { + csrfDebug(req); + next(); +}); app.use(bodyParser.json()); //const ws = require('express-ws')(app, server); @@ -84,11 +94,7 @@ goodTimesDB.init().then((db) => { app.use(methodOverride()); // eslint-disable-next-line no-unused-vars app.use((err, req, res, _next) => { - console.log('CSRF debug: ', { - token: req.header('CSRF-Token'), - csrf: req.csrfToken(), - method: req.method - }); + csrfDebug(req); console.error(err); res.status(err.status || 500).json({ message: err.message, diff --git a/server/routes/locations.js b/server/routes/locations.js index 147915a..208b218 100644 --- a/server/routes/locations.js +++ b/server/routes/locations.js @@ -5,7 +5,6 @@ const router = express.Router(); const originalLocations = require('../location-data.js'); - router.put('/', (req, res) => { const location = req.body; location.id = originalLocations.length; @@ -20,9 +19,9 @@ router.get('/:locationId?', (req, res) => { item => item.id === locationId ); if (!location) { - res.status(404).send({ message: `Location ${locationId} not found.`}); + return res.status(404).send({ message: `Location ${locationId} not found.`}); } - res.status(200).send([ location ]); + return res.status(200).send([ location ]); } return res.status(200).send(originalLocations); diff --git a/server/routes/users.js b/server/routes/users.js index fa4aed2..64c6021 100755 --- a/server/routes/users.js +++ b/server/routes/users.js @@ -77,6 +77,8 @@ router.put('/password', async (req, res) => { router.get('/csrf', (req, res) => { const token = req.csrfToken(); + console.log( + `${req.method} ${req.path} - token`, token); res.json({ csrfToken: token }); });