Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Werewolf the Apocalypse 5 #116

Merged
merged 35 commits into from
Aug 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
0a35a80
Beginnings of wta 5
Daelso Aug 2, 2023
26c6efa
Working on tribe select
Daelso Aug 2, 2023
6cff1a9
Tribes, patrons and their favors/bans
Daelso Aug 3, 2023
bfcb1a6
Auspices
Daelso Aug 3, 2023
1f25ee9
Adding renown stuff
Daelso Aug 3, 2023
fc801fa
Natural gift selection, donation stuff, display better
Daelso Aug 3, 2023
1aba3aa
Some styling
Daelso Aug 3, 2023
11b2b22
Rites selection
Daelso Aug 3, 2023
4a33e37
Reorganization and auspice gifts
Daelso Aug 4, 2023
ed67259
Tribal gifts
Daelso Aug 4, 2023
d3e6441
Purchase renown
Daelso Aug 4, 2023
ed938f2
Purchasing gifts
Daelso Aug 4, 2023
c898bb4
Purchasing rites
Daelso Aug 4, 2023
f67d98c
Merit categories
Daelso Aug 4, 2023
8335820
Merit section styling
Daelso Aug 4, 2023
9747101
Cleanup
Daelso Aug 4, 2023
065df6f
Background cleanup
Daelso Aug 4, 2023
ef19021
Removes influence
Daelso Aug 4, 2023
e17b41a
Filter merits
Daelso Aug 7, 2023
e658500
talismans and some qol work to adv/flaws
Daelso Aug 7, 2023
0c1d455
Loresheet handling
Daelso Aug 7, 2023
2d3b984
Remove talismans/loresheets
Daelso Aug 7, 2023
53b3db3
Saving garou and bug fix on duped hunters
Daelso Aug 7, 2023
eaeaa97
Stop sequelize pluralizing
Daelso Aug 7, 2023
0bedde3
View saved garou!
Daelso Aug 7, 2023
bb39649
Garou cards out fronnnt
Daelso Aug 7, 2023
9a0e1af
My garou!
Daelso Aug 7, 2023
d35b683
Search setup
Daelso Aug 7, 2023
55aa656
nerdbert sheet for w5
Daelso Aug 7, 2023
f8d5a7b
good chunk of pdf exporting
Daelso Aug 7, 2023
cc0e768
renown gifts and rites
Daelso Aug 7, 2023
dd7142d
Fixes display of loresheet on homepage
Daelso Aug 7, 2023
3858eef
Garou editing, fixes an error with bonus renown application
Daelso Aug 7, 2023
2c93938
Styling, editing, pubishing raaa
Daelso Aug 7, 2023
ae57e4e
Search query fix
Daelso Aug 7, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions server.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
const helmet = require("helmet");
const app = express();
const cookieParser = require("cookie-parser");
app.use(cookieParser());

Check failure

Code scanning / CodeQL

Missing CSRF middleware High

This cookie middleware is serving a
request handler
without CSRF protection.
This cookie middleware is serving a
request handler
without CSRF protection.
This cookie middleware is serving a
request handler
without CSRF protection.
This cookie middleware is serving a
request handler
without CSRF protection.
This cookie middleware is serving a
request handler
without CSRF protection.
This cookie middleware is serving a
request handler
without CSRF protection.
This cookie middleware is serving a
request handler
without CSRF protection.
This cookie middleware is serving a
request handler
without CSRF protection.
This cookie middleware is serving a
request handler
without CSRF protection.
This cookie middleware is serving a
request handler
without CSRF protection.
This cookie middleware is serving a
request handler
without CSRF protection.
This cookie middleware is serving a
request handler
without CSRF protection.
This cookie middleware is serving a
request handler
without CSRF protection.
require("dotenv").config();
const cors = require("cors");
app.use(compression());
Expand Down Expand Up @@ -47,6 +47,8 @@
app.use("/favorites", favoriteRoutes);
const searchRoutes = require("./server/api/search");
app.use("/search", searchRoutes);
const garouRoutes = require("./server/api/garou");
app.use("/garou", garouRoutes);
//Uses userRoutes file to handle all user related endpoints

//Below are various controller links
Expand Down
290 changes: 290 additions & 0 deletions server/api/garou.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,290 @@
const express = require("express");
const cookieParser = require("cookie-parser");
require("dotenv").config();
const app = express();
const { Op } = require("sequelize");

let router = express.Router();
router.use(cookieParser());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
const Tribes = require("../models/werewolf/Tribes.js");
const Auspices = require("../models/werewolf/Auspices.js");

const lib = require("../lib");
const RenownTypes = require("../models/werewolf/RenownTypes.js");
const NativeGifts = require("../models/werewolf/NativeGifts.js");
const AuspiceGifts = require("../models/werewolf/AuspiceGifts.js");
const Rites = require("../models/werewolf/Rites.js");
const TribeGifts = require("../models/werewolf/TribeGifts.js");
const Garou = require("../models/werewolf/Garou.js");

//Route is base/garou/

router.route("/new").post(lib.postLimiter, async (req, res) => {
try {
let currentUser = lib.getCurrentUser(req, res);

if (currentUser !== null) {
currentUser = currentUser.id;
}

const newGarou = await Garou.create({
charName: req.body.name,
tribe: req.body.tribe,
concept: req.body.concept,
auspice: req.body.auspice,
chronicle: req.body.chronicle,
touchstones: req.body.touchstones,
attributes: req.body.attributes,
skills: req.body.skills,
bonus_renown: req.body.bonus_renown,
health: req.body.health,
willpower: req.body.willpower,
remaining_specialties: req.body.remainingSpecialties,
xp: req.body.xp,
spent_xp: req.body.spent_xp,
specialties: req.body.specialties,
advantages: req.body.advantages,
advantages_remaining: req.body.advantages_remaining,
flaws_remaining: req.body.flaws_remaining,
tribe_gifts: req.body.tribe_gifts,
purchased_gifts: req.body.purchased_gifts,
tribe_renown: req.body.tribe_renown,
purchased_renown: req.body.purchased_renown,
created_by: currentUser,
createdAt: Date.now(),
updatedAt: Date.now(),
});

res.status(200).json(newGarou.id);
} catch (err) {
res.status(403).send(err);
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed
Fixed Show fixed Hide fixed

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.

Check warning

Code scanning / CodeQL

Exception text reinterpreted as HTML Medium

Exception text
is reinterpreted as HTML without escaping meta-characters.
Exception text
is reinterpreted as HTML without escaping meta-characters.
}
});

router.route("/edit/:id").put(lib.postLimiter, async (req, res) => {
try {
const currentUser = lib.getCurrentUser(req, res);

const garou = await Garou.findByPk(req.params.id);

if (currentUser.id !== garou.created_by) {
res.status(403).send("Access Denied");
return;
}

await garou.update({
charName: req.body.name,
tribe: req.body.tribe,
concept: req.body.concept,
auspice: req.body.auspice,
chronicle: req.body.chronicle,
touchstones: req.body.touchstones,
attributes: req.body.attributes,
skills: req.body.skills,
bonus_renown: req.body.bonus_renown,
health: req.body.health,
willpower: req.body.willpower,
remaining_specialties: req.body.remainingSpecialties,
xp: req.body.xp,
spent_xp: req.body.spent_xp,
specialties: req.body.specialties,
advantages: req.body.advantages,
advantages_remaining: req.body.advantages_remaining,
flaws_remaining: req.body.flaws_remaining,
tribe_gifts: req.body.tribe_gifts,
purchased_gifts: req.body.purchased_gifts,
tribe_renown: req.body.tribe_renown,
purchased_renown: req.body.purchased_renown,
updatedAt: Date.now(),
updatedBy: currentUser,
});

res.status(200).send("Garou updated!");
} catch (err) {
res.status(404).send(err);

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.

Check warning

Code scanning / CodeQL

Exception text reinterpreted as HTML Medium

Exception text
is reinterpreted as HTML without escaping meta-characters.
Exception text
is reinterpreted as HTML without escaping meta-characters.
Exception text
is reinterpreted as HTML without escaping meta-characters.
}
});

router.route("/garou/:id").get(lib.getLimiter, async (req, res) => {
try {
const garou = await Garou.findByPk(req.params.id);
res.json(garou);
} catch (err) {
res.status(404).send(err);

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.
Fixed Show fixed Hide fixed

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.

Check warning

Code scanning / CodeQL

Exception text reinterpreted as HTML Medium

Exception text
is reinterpreted as HTML without escaping meta-characters.
}
});

router.route("/myGarou/:id").get(async (req, res) => {
try {
const garou = await Garou.findAll({
where: {
created_by: req.params.id,
},
});
res.status(200).send(garou);
} catch (err) {
res.status(404).send(err);
}
});

router.route("/tribes").get(lib.getLimiter, async (req, res) => {
try {
const tribes = await Tribes.findAll({
include: [
{
model: RenownTypes,
as: "renownTypeId",
},
],
});
res.json(tribes);
} catch (err) {
res.status(404).send(err);

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.
}
});

router.route("/auspices").get(lib.getLimiter, async (req, res) => {
try {
const auspices = await Auspices.findAll();
res.json(auspices);
} catch (err) {
res.status(404).send(err);

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.
}
});

router.route("/renown_types").get(lib.getLimiter, async (req, res) => {
try {
const renown_types = await RenownTypes.findAll();
res.json(renown_types);
} catch (err) {
res.status(404).send(err);
Fixed Show fixed Hide fixed

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.
}
});

router
.route("/native_gifts/:max_level")
.get(lib.getLimiter, async (req, res) => {
try {
const maxLevel = parseInt(req.params.max_level);

if (isNaN(maxLevel) || maxLevel < 0) {
return res.status(400).json({ error: "Invalid max_level." });
}

const native_gifts = await NativeGifts.findAll({
where: {
renown_level: {
[Op.lte]: maxLevel,
},
},
});
res.json(native_gifts);
} catch (err) {
res.status(404).send(err);

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.
}
});

router
.route("/auspice_gifts/:max_level/:auspice_id")
.get(lib.getLimiter, async (req, res) => {
try {
const maxLevel = parseInt(req.params.max_level);
const auspiceId = parseInt(req.params.auspice_id);

if (
isNaN(maxLevel) ||
isNaN(auspiceId) ||
maxLevel < 0 ||
auspiceId < 1
) {
return res
.status(400)
.json({ error: "Invalid max_level or auspice_id." });
}

const gifts = await AuspiceGifts.findAll({
where: {
renown_level: {
[Op.lte]: maxLevel,
},
auspice_id: {
[Op.eq]: auspiceId,
},
},
});
res.json(gifts);
} catch (err) {
res.status(404).send(err);

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.
}
});

router
.route("/tribe_gifts/:max_level/:tribe_id")
.get(lib.getLimiter, async (req, res) => {
try {
const maxLevel = parseInt(req.params.max_level);
const tribeId = parseInt(req.params.tribe_id);

if (isNaN(maxLevel) || isNaN(tribeId) || maxLevel < 0 || tribeId < 1) {
return res
.status(400)
.json({ error: "Invalid max_level or tribe_id." });
}

const gifts = await TribeGifts.findAll({
where: {
renown_level: {
[Op.lte]: maxLevel,
},
tribe_id: {
[Op.eq]: tribeId,
},
},
});

res.status(200).json(gifts);
} catch (err) {
res.status(404).send(err);
}
});

router.route("/rites").get(lib.getLimiter, async (req, res) => {
try {
const rites = await Rites.findAll();
res.json(rites);
} catch (err) {
res.status(404).send(err);

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.
}
});

router.route("/card").get(async (req, res) => {
try {
const garou = await Garou.findAll({
limit: 3,
order: [["createdAt", "DESC"]],
});
res.json(garou);
} catch (err) {
res.status(404).send(err);
Fixed Show fixed Hide fixed
}
});

router.route("/delete/:id").delete(lib.postLimiter, async (req, res) => {
try {
let currentUser = lib.getCurrentUser(req, res);

const garou = await Garou.findByPk(req.params.id);

if (currentUser.id !== garou.created_by) {
return;
}
garou.destroy();
res.status(200).send("Deletion successful");
} catch (err) {
res.status(404).send(err);

Check warning

Code scanning / CodeQL

Exception text reinterpreted as HTML Medium

Exception text
is reinterpreted as HTML without escaping meta-characters.
Exception text
is reinterpreted as HTML without escaping meta-characters.
Exception text
is reinterpreted as HTML without escaping meta-characters.
}
});

module.exports = router; //Exports our routes
22 changes: 22 additions & 0 deletions server/api/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,26 @@
}
});

router.route("/garou").post(async (req, res) => {
try {
const params = req.body.searchParams;
let baseQuery = "SELECT * FROM ey140u9j4rs9xcib.garou WHERE 1=1";
if (params.user) {
baseQuery += ` AND created_by = ${params.user}`;
}
if (params.tribe) {
baseQuery += ` AND tribe->"$.tribe_id" = "${params.tribe.tribe_id}"`;
}
if (params.auspice) {
baseQuery += ` AND auspice->"$.auspice_id" = "${params.auspice.auspice_id}"`;
}

const [results, metadata] = await sequelize.sequelize.query(baseQuery);
Dismissed Show dismissed Hide dismissed

res.status(200).send(results);
} catch (err) {
res.status(404).send(err);

Check warning

Code scanning / CodeQL

Exception text reinterpreted as HTML Medium

Exception text
is reinterpreted as HTML without escaping meta-characters.

Check warning

Code scanning / CodeQL

Information exposure through a stack trace Medium

This information exposed to the user depends on
stack trace information
.
}
});

module.exports = router; //Exports our routes
14 changes: 13 additions & 1 deletion server/lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,12 @@ const postLimiter = rateLimit({
message: "Rate limit exceeded, please wait 15 minutes and try again!",
});

const getLimiter = rateLimit({
windowMs: 300000, //5 min
max: 250, //attempts
message: "Rate limit exceeded, please wait 5 minutes and try again!",
});

const authenticateToken = (req, res, next) => {
let token = req.cookies.access;

Expand Down Expand Up @@ -104,4 +110,10 @@ const getCurrentUser = (req, res) => {
return currentUser;
};

module.exports = { authenticateToken, getCurrentUser, limiter, postLimiter };
module.exports = {
authenticateToken,
getCurrentUser,
limiter,
postLimiter,
getLimiter,
};
Loading
Loading