Skip to content
Snippets Groups Projects
Commit 93a39d94 authored by Dominik Hebeler's avatar Dominik Hebeler
Browse files

invoices

parent 3fd2100a
No related branches found
No related tags found
No related merge requests found
......@@ -28,11 +28,21 @@ app.use(express.urlencoded({ extended: false, limit: "1mb" }));
app.use(cookieParser());
app.use((req, res, next) => {
res.locals.baseDir = "";
let subPath = req.url.match(/^((\/.*)?\/keys)/);
if (subPath) {
res.locals.baseDir = subPath[1];
} else {
res.locals.baseDir = "";
let allowed_hosts = [
"localhost",
"metager.de",
"metager.org"
];
if (subPath && "x-forwarded-proto" in req.headers && "x-forwarded-host" in req.headers && "x-forwarded-port" in req.headers) {
if (allowed_hosts.includes(req.hostname) || (process.env.NODE_ENV === "development" && req.hostname.match(/^(localhost|.*\.ngrok\.io|.*\.review\.metager\.de)$/))) {
res.locals.baseDir = req.headers["x-forwarded-proto"] + "://" + req.headers["x-forwarded-host"];
if (!["80", "443"].includes(req.headers["x-forwarded-port"])) {
res.locals.baseDir += ":" + req.headers["x-forwarded-port"];
}
res.locals.baseDir += subPath[1];
}
}
next();
});
......
......@@ -30,6 +30,7 @@
"multer": "^1.4.5-lts.1",
"node-forge": "^1.3.1",
"pdfkit": "^0.13.0",
"qr-scanner": "^1.4.2",
"qrcode": "^1.5.1",
"qrcode-reader": "^1.0.4",
"uuid": "^9.0.0"
......@@ -588,6 +589,11 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
"integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng=="
},
"node_modules/@types/offscreencanvas": {
"version": "2019.7.0",
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz",
"integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg=="
},
"node_modules/@types/responselike": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
......@@ -5086,6 +5092,14 @@
"integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
"optional": true
},
"node_modules/qr-scanner": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/qr-scanner/-/qr-scanner-1.4.2.tgz",
"integrity": "sha512-kV1yQUe2FENvn59tMZW6mOVfpq9mGxGf8l6+EGaXUOd4RBOLg7tRC83OrirM5AtDvZRpdjdlXURsHreAOSPOUw==",
"dependencies": {
"@types/offscreencanvas": "^2019.6.4"
}
},
"node_modules/qrcode": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.1.tgz",
......@@ -7010,6 +7024,11 @@
"resolved": "https://registry.npmjs.org/@types/node/-/node-18.11.17.tgz",
"integrity": "sha512-HJSUJmni4BeDHhfzn6nF0sVmd1SMezP7/4F0Lq+aXzmp2xm9O7WXrUtHW/CHlYVtZUbByEvWidHqRtcJXGF2Ng=="
},
"@types/offscreencanvas": {
"version": "2019.7.0",
"resolved": "https://registry.npmjs.org/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz",
"integrity": "sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg=="
},
"@types/responselike": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/responselike/-/responselike-1.0.0.tgz",
......@@ -10551,6 +10570,14 @@
"integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
"optional": true
},
"qr-scanner": {
"version": "1.4.2",
"resolved": "https://registry.npmjs.org/qr-scanner/-/qr-scanner-1.4.2.tgz",
"integrity": "sha512-kV1yQUe2FENvn59tMZW6mOVfpq9mGxGf8l6+EGaXUOd4RBOLg7tRC83OrirM5AtDvZRpdjdlXURsHreAOSPOUw==",
"requires": {
"@types/offscreencanvas": "^2019.6.4"
}
},
"qrcode": {
"version": "1.5.1",
"resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.1.tgz",
......
......@@ -29,6 +29,7 @@
"multer": "^1.4.5-lts.1",
"node-forge": "^1.3.1",
"pdfkit": "^0.13.0",
"qr-scanner": "^1.4.2",
"qrcode": "^1.5.1",
"qrcode-reader": "^1.0.4",
"uuid": "^9.0.0"
......@@ -36,4 +37,4 @@
"devDependencies": {
"nodemon": "^2.0.20"
}
}
\ No newline at end of file
}
......@@ -17,18 +17,20 @@ router.use(
// General Optional authorization for every page
// It will not require login or start a session by default
// Only when a route uses the middleware requireAuth
auth({
issuerBaseURL: `${config.get("app.openid_auth.url")}`,
baseURL: config.get("app.url"),
clientID: config.get("app.openid_auth.app_id"),
clientSecret: config.get("app.openid_auth.app_secret"),
secret: config.get("app.secret"),
session: {
rollingDuration: auth_session_expiration_seconds,
signSessionStoreCookie: true,
},
authRequired: false,
}),
(req, res, next) => {
auth({
issuerBaseURL: `${config.get("app.openid_auth.url")}`,
baseURL: res.locals.baseDir,
clientID: config.get("app.openid_auth.app_id"),
clientSecret: config.get("app.openid_auth.app_secret"),
secret: config.get("app.secret"),
session: {
rollingDuration: auth_session_expiration_seconds,
signSessionStoreCookie: true,
},
authRequired: false,
})(req, res, next);
},
/**
* If the user is already authenticated this middleware will check
* if the user inherits the required role in his oidc token to use this app
......@@ -68,7 +70,7 @@ router.use(
} else {
let params = req.query;
delete params.moderation;
let redirect_url = `${req.path}?${new URLSearchParams(
let redirect_url = `${res.locals.baseDir}${req.path}?${new URLSearchParams(
params
).toString()}`;
res.redirect(redirect_url);
......
......@@ -36,21 +36,21 @@ router.get("/:funding_source", async (req, res) => {
}
req.data.change_url.funding_source =
"/key/" +
`${res.locals.baseDir}/key/` +
encodeURIComponent(req.data.key.key) +
"/checkout/" +
encodeURIComponent(req.data.checkout.amount) +
"#payment";
req.data.change_url.funding_source_not_eligible =
"/key/" +
`${res.locals.baseDir}/key/` +
encodeURIComponent(req.data.key.key) +
"/checkout/" +
encodeURIComponent(req.data.checkout.amount) +
"?error=funding_source_not_eligible";
req.data.change_url.order_base_url =
"/key/" +
`${res.locals.baseDir}/key/` +
encodeURIComponent(req.data.key.key) +
"/checkout/" +
encodeURIComponent(req.data.checkout.amount) +
......@@ -142,7 +142,7 @@ router.post("/:funding_source/order/capture", async (req, res) => {
.then(() => loaded_order.chargeKey())
.then(() => {
let redirect_url =
"/key/" + req.data.key.key + "/orders/" + loaded_order.getOrderID();
`${res.locals.baseDir}/key/` + req.data.key.key + "/orders/" + loaded_order.getOrderID();
res.status(200).json({
redirect_url: redirect_url,
order: {
......
......@@ -101,7 +101,7 @@ router.use("/:key", param("key").isUUID(4), async (req, res, next) => {
encodeURIComponent(req.params.key);
let QRCode = require("qrcode");
let qr_data_uri = await QRCode.toDataURL(metager_url);
let qr_data_uri = await QRCode.toDataURL(metager_url, { errorCorrectionLevel: 'H', scale: 8 });
req.data = Object.assign(req.data, {
created_new: req.query.new === "true" ? true : false,
......@@ -122,18 +122,19 @@ router.use("/:key", param("key").isUUID(4), async (req, res, next) => {
css: [`${res.locals.baseDir}/styles/key/key.css`],
});
if (!req.data.admin && (!req.cookies.key || req.cookies.key !== req.data.key.key)) {
res.cookie("key", req.data.key.key, {
sameSite: "lax"
});
}
next("route");
});
// Basic account page
router.get("/:key", async (req, res) => {
res.render("key", req.data);
if (!req.data.admin && (!req.cookies.key || req.cookies.key !== req.data.key.key)) {
res.cookie("key", req.data.key.key, {
sameSite: "lax"
});
res.render("key", req.data);
} else {
res.redirect(`${res.locals.baseDir}/logout`);
}
});
router.use("/:key/orders", orderRouter);
......
......@@ -12,9 +12,8 @@ router.get("/", (req, res) => {
email: req.query.email || "",
address: req.query.address || "",
},
create_invoice_url: `/key/${
req.data.key.key
}/orders/${req.data.order.order.getOrderID()}/invoice/create`,
create_invoice_url: `${res.locals.baseDir}/key/${req.data.key.key
}/orders/${req.data.order.order.getOrderID()}/invoice/create`,
errors: {},
};
......@@ -72,11 +71,10 @@ router.post(
address: req.data.order.invoice.params.address,
};
req.data.order.invoice.moderation_url = `${config.get("app.url")}/key/${
req.data.key.key
}/orders/${req.data.order.order.getOrderID()}/invoice?${new URLSearchParams(
moderation_params
).toString()}#invoice-form`;
req.data.order.invoice.moderation_url = `${res.locals.baseDir}/key/${req.data.key.key
}/orders/${req.data.order.order.getOrderID()}/invoice?${new URLSearchParams(
moderation_params
).toString()}#invoice-form`;
// Render the message
let ejs = require("ejs"),
......@@ -157,8 +155,7 @@ router.post(
.then(() => {
// Added receipt. We can redirect to download page
res.redirect(
`/key/${
req.data.key.key
`${res.locals.baseDir}/key/${req.data.key.key
}/orders/${req.data.order.order.getOrderID()}/invoice/download`
);
})
......
......@@ -16,16 +16,15 @@ router.use("/", (req, res, next) => {
});
router.get("/", (req, res, next) => {
req.data.page = "order";
req.data.css.push("/styles/orders/orders.css");
req.data.css.push(`${res.locals.baseDir}/styles/orders/orders.css`);
res.render("key", req.data);
});
router.post("/", (req, res, next) => {
console.log(req.body["order-id"]);
let matches = req.body["order-id"].match(/^(INV_)?(\d{14})$/);
let matches = req.body["order-id"].match(/^(INV_)?(\d+)$/);
if (!matches) {
req.data.page = "order";
req.data.css.push("/styles/orders/orders.css");
req.data.css.push(`${res.locals.baseDir}/styles/orders/orders.css`);
req.data.error = 400;
req.data.form = {
"order-id": req.body["order-id"],
......@@ -34,16 +33,16 @@ router.post("/", (req, res, next) => {
} else {
let order_id = matches[2];
Order.LOAD_ORDER_FROM_ID(order_id)
.then(/** @param {Order} order */ (order) => order.getKeyFromOrderLink())
.then(/** @param {Order} order */(order) => order.getKeyFromOrderLink())
.then((key) => {
if (key !== req.data.key.key) {
throw "Order is not connected to this key";
}
res.redirect(`/key/${req.data.key.key}/orders/${order_id}`);
res.redirect(`${res.locals.baseDir}/key/${req.data.key.key}/orders/${order_id}`);
})
.catch((reason) => {
req.data.page = "order";
req.data.css.push("/styles/orders/orders.css");
req.data.css.push(`${res.locals.baseDir}/styles/orders/orders.css`);
req.data.error = 404;
req.data.form = {
"order-id": req.body["order-id"],
......@@ -67,16 +66,15 @@ router.use("/:order_id", param("order_id").isInt(), (req, res, next) => {
.then((order) => {
res.cookie("order", order.getOrderID());
req.data.page = "order";
req.data.css.push("/styles/orders/order.css");
req.data.css.push(`${res.locals.baseDir}/styles/orders/order.css`);
req.data.order = { order: order };
req.data.links.order_url = `/key/${req.data.key.key}/orders/${req.params.order_id}#order`;
req.data.links.receipt_url = `/key/${req.data.key.key}/orders/${req.params.order_id}/pdf`;
req.data.links.invoice_url = `/key/${req.data.key.key}/orders/${req.params.order_id}/invoice#invoice-form`;
req.data.links.refund_url = `/key/${req.data.key.key}/orders/${req.params.order_id}/refund#refund-form`;
req.data.links.order_url = `${res.locals.baseDir}/key/${req.data.key.key}/orders/${req.params.order_id}#order`;
req.data.links.receipt_url = `${res.locals.baseDir}/key/${req.data.key.key}/orders/${req.params.order_id}/pdf`;
req.data.links.invoice_url = `${res.locals.baseDir}/key/${req.data.key.key}/orders/${req.params.order_id}/invoice#invoice-form`;
req.data.links.refund_url = `${res.locals.baseDir}/key/${req.data.key.key}/orders/${req.params.order_id}/refund#refund-form`;
if (req.data.order.order.isReceiptCreated()) {
req.data.order.download_invoice_url = `/key/${
req.data.key.key
}/orders/${req.data.order.order.getOrderID()}/invoice/download`;
req.data.order.download_invoice_url = `${res.locals.baseDir}/key/${req.data.key.key
}/orders/${req.data.order.order.getOrderID()}/invoice/download`;
}
next("route");
})
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment