From b8619573422255051886b3419b264fc4a250ed25 Mon Sep 17 00:00:00 2001 From: Patrick Fic Date: Thu, 4 May 2023 11:59:39 -0700 Subject: [PATCH] Additional security hardening. --- client/.env.production | 1 + client/src/utils/RenderTemplate.js | 33 ++++++++++++++------- hasura/metadata/tables.yaml | 15 ++++++++++ server.js | 46 ++++++++++++++++------------- server/data/arms.js | 2 +- server/data/autohouse.js | 12 +++++++- server/job/job-status-transition.js | 2 +- server/opensearch/os-handler.js | 4 +++ server/utils/utils.js | 9 ++++++ 9 files changed, 89 insertions(+), 35 deletions(-) diff --git a/client/.env.production b/client/.env.production index 7a58e4591..a4cdecee5 100644 --- a/client/.env.production +++ b/client/.env.production @@ -1,3 +1,4 @@ +GENERATE_SOURCEMAP=false REACT_APP_GRAPHQL_ENDPOINT=https://db.imex.online/v1/graphql REACT_APP_GRAPHQL_ENDPOINT_WS=wss://db.imex.online/v1/graphql REACT_APP_GA_CODE=231103507 diff --git a/client/src/utils/RenderTemplate.js b/client/src/utils/RenderTemplate.js index acdfe1bf2..21ad1e30b 100644 --- a/client/src/utils/RenderTemplate.js +++ b/client/src/utils/RenderTemplate.js @@ -1,15 +1,15 @@ import { gql } from "@apollo/client"; import { notification } from "antd"; -import axios from "axios"; import jsreport from "@jsreport/browser-client"; import _ from "lodash"; import moment from "moment"; -import { auth } from "../firebase/firebase.utils"; +//import { auth } from "../firebase/firebase.utils"; import { setEmailOptions } from "../redux/email/email.actions"; import { store } from "../redux/store"; import client from "../utils/GraphQLClient"; import { TemplateList } from "./TemplateConstants"; - +import cleanAxios from "./CleanAxios"; +import axios from "axios"; const server = process.env.REACT_APP_REPORTS_SERVER_URL; jsreport.serverUrl = server; @@ -26,10 +26,14 @@ export default async function RenderTemplate( if (window.jsr3) { jsreport.serverUrl = "https://reports3.test.imex.online/"; } + const jsrAuth = (await axios.post("/utils/jsr")).data; + console.log("🚀 ~ file: RenderTemplate.js:30 ~ jsrAuth:", jsrAuth); + jsreport.headers["Authorization"] = jsrAuth; //Query assets that match the template name. Must be in format <>.query let { contextData, useShopSpecificTemplate } = await fetchContextData( - templateObject + templateObject, + jsrAuth ); const { ignoreCustomMargins } = Templates[templateObject.name]; @@ -137,11 +141,15 @@ export async function RenderTemplates( //Query assets that match the template name. Must be in format <>.query let unsortedTemplatesAndData = []; let proms = []; + const jsrAuth = (await axios.post("/utils/jsr")).data; + jsreport.headers["Authorization"] = jsrAuth; + templateObjects.forEach((template) => { proms.push( (async () => { let { contextData, useShopSpecificTemplate } = await fetchContextData( - template + template, + jsrAuth ); unsortedTemplatesAndData.push({ templateObject: template, @@ -298,19 +306,22 @@ export const GenerateDocuments = async (templates) => { await RenderTemplates(templates, bodyshop); }; -const fetchContextData = async (templateObject) => { +const fetchContextData = async (templateObject, jsrAuth) => { const bodyshop = store.getState().user.bodyshop; - jsreport.headers["Authorization"] = - "Bearer " + (await auth.currentUser.getIdToken()); + // jsreport.headers["Authorization"] = + // "Bearer " + (await auth.currentUser.getIdToken()); - const folders = await axios.get(`${server}/odata/folders`); + const folders = await cleanAxios.get(`${server}/odata/folders`, { + headers: { Authorization: jsrAuth }, + }); const shopSpecificFolder = folders.data.value.find( (f) => f.name === bodyshop.imexshopid ); - const jsReportQueries = await axios.get( - `${server}/odata/assets?$filter=name eq '${templateObject.name}.query'` + const jsReportQueries = await cleanAxios.get( + `${server}/odata/assets?$filter=name eq '${templateObject.name}.query'`, + { headers: { Authorization: jsrAuth } } ); let templateQueryToExecute; diff --git a/hasura/metadata/tables.yaml b/hasura/metadata/tables.yaml index 2d36a544e..23aefaa8e 100644 --- a/hasura/metadata/tables.yaml +++ b/hasura/metadata/tables.yaml @@ -694,6 +694,9 @@ num_retries: 3 timeout_sec: 60 webhook_from_env: HASURA_API_URL + headers: + - name: event-secret + value_from_env: EVENT_SECRET request_transform: method: POST query_params: {} @@ -4112,6 +4115,9 @@ num_retries: 3 timeout_sec: 60 webhook_from_env: HASURA_API_URL + headers: + - name: event-secret + value_from_env: EVENT_SECRET request_transform: method: POST query_params: {} @@ -4562,6 +4568,9 @@ num_retries: 3 timeout_sec: 60 webhook_from_env: HASURA_API_URL + headers: + - name: event-secret + value_from_env: EVENT_SECRET request_transform: method: POST query_params: {} @@ -5015,6 +5024,9 @@ num_retries: 3 timeout_sec: 60 webhook_from_env: HASURA_API_URL + headers: + - name: event-secret + value_from_env: EVENT_SECRET request_transform: method: POST query_params: {} @@ -5957,6 +5969,9 @@ num_retries: 3 timeout_sec: 60 webhook_from_env: HASURA_API_URL + headers: + - name: event-secret + value_from_env: EVENT_SECRET request_transform: method: POST query_params: {} diff --git a/server.js b/server.js index 273676bb9..6a0c9e20a 100644 --- a/server.js +++ b/server.js @@ -123,7 +123,11 @@ app.post( twilio.webhook({ validate: process.env.NODE_ENV === "PRODUCTION" }), smsStatus.status ); -app.post("/sms/markConversationRead", smsStatus.markConversationRead); +app.post( + "/sms/markConversationRead", + fb.validateFirebaseIdToken, + smsStatus.markConversationRead +); var job = require("./server/job/job"); app.post("/job/totals", fb.validateFirebaseIdToken, job.totals); @@ -147,11 +151,11 @@ app.post("/scheduling/job", fb.validateFirebaseIdToken, scheduling.job); var inlineCss = require("./server/render/inlinecss"); app.post("/render/inlinecss", fb.validateFirebaseIdToken, inlineCss.inlinecss); -app.post( - "/notifications/send", +// app.post( +// "/notifications/send", - fb.sendNotification -); +// fb.sendNotification +// ); app.post("/notifications/subscribe", fb.validateFirebaseIdToken, fb.subscribe); app.post( "/notifications/unsubscribe", @@ -188,13 +192,13 @@ app.post( ); //Stripe Processing -var stripe = require("./server/stripe/payment"); -app.post("/stripe/payment", fb.validateFirebaseIdToken, stripe.payment); -app.post( - "/stripe/mobilepayment", - fb.validateFirebaseIdToken, - stripe.mobile_payment -); +// var stripe = require("./server/stripe/payment"); +// app.post("/stripe/payment", fb.validateFirebaseIdToken, stripe.payment); +// app.post( +// "/stripe/mobilepayment", +// fb.validateFirebaseIdToken, +// stripe.mobile_payment +// ); //Tech Console var tech = require("./server/tech/tech"); @@ -202,7 +206,7 @@ app.post("/tech/login", fb.validateFirebaseIdToken, tech.techLogin); var utils = require("./server/utils/utils"); app.post("/utils/time", utils.servertime); - +app.post("/utils/jsr", fb.validateFirebaseIdToken, utils.jsrAuth); var qbo = require("./server/accounting/qbo/qbo"); app.post("/qbo/authorize", fb.validateFirebaseIdToken, qbo.authorize); app.get("/qbo/callback", qbo.callback); @@ -215,7 +219,7 @@ app.post("/data/ah", data.autohouse); app.post("/record-handler/arms", data.arms); var taskHandler = require("./server/tasks/tasks"); -app.post("/taskHandler", taskHandler.taskHandler); +app.post("/taskHandler", fb.validateFirebaseIdToken, taskHandler.taskHandler); var mixdataUpload = require("./server/mixdata/mixdata"); @@ -228,10 +232,10 @@ app.post( var ioevent = require("./server/ioevent/ioevent"); app.post("/ioevent", ioevent.default); -app.post("/newlog", (req, res) => { - const { message, type, user, record, object } = req.body; - logger.log(message, type, user, record, object); -}); +// app.post("/newlog", (req, res) => { +// const { message, type, user, record, object } = req.body; +// logger.log(message, type, user, record, object); +// }); var os = require("./server/opensearch/os-handler"); app.post( @@ -243,9 +247,9 @@ app.post("/search", fb.validateFirebaseIdToken, os.search); var cdkGetMake = require("./server/cdk/cdk-get-makes"); app.post("/cdk/getvehicles", fb.validateFirebaseIdToken, cdkGetMake.default); -app.get("/", async function (req, res) { - res.status(200).send("Access Forbidden."); -}); +// app.get("/", async function (req, res) { +// res.status(200).send("Access Forbidden."); +// }); server.listen(port, (error) => { if (error) throw error; diff --git a/server/data/arms.js b/server/data/arms.js index ec5f337f8..382f2437b 100644 --- a/server/data/arms.js +++ b/server/data/arms.js @@ -50,7 +50,7 @@ async function getEntegralShopData() { } exports.default = async (req, res) => { - res.sendStatus(200); + res.sendStatus(401); return; //Query for the List of Bodyshop Clients. const job = req.body.event.data.new; diff --git a/server/data/autohouse.js b/server/data/autohouse.js index 5e32c81de..bce69ec0f 100644 --- a/server/data/autohouse.js +++ b/server/data/autohouse.js @@ -40,6 +40,14 @@ exports.default = async (req, res) => { const specificShopIds = req.body.bodyshopIds; // ['uuid] const { start, end, skipUpload } = req.body; //YYYY-MM-DD + if ( + !start || + !moment(start).isValid || + req.headers["x-imex-auth"] !== process.env.AUTOHOUSE_AUTH_TOKEN + ) { + res.sendStatus(401); + return; + } const allxmlsToUpload = []; const allErrors = []; try { @@ -772,7 +780,9 @@ const CreateCosts = (job) => { billTotalsByCostCenters[ job.bodyshop.md_responsibility_centers.defaults.costs.MAPA ] = Dinero({ - amount: Math.round((job.mixdata[0] && job.mixdata[0].totalliquidcost || 0) * 100) + amount: Math.round( + ((job.mixdata[0] && job.mixdata[0].totalliquidcost) || 0) * 100 + ), }); } else { billTotalsByCostCenters[ diff --git a/server/job/job-status-transition.js b/server/job/job-status-transition.js index 4b6a7db76..fd74a2ec3 100644 --- a/server/job/job-status-transition.js +++ b/server/job/job-status-transition.js @@ -17,7 +17,7 @@ require("dotenv").config({ }); async function StatusTransition(req, res) { if (req.headers["event-secret"] !== process.env.EVENT_SECRET) { - res.status(403).send("Unauthorized"); + res.status(401).send("Unauthorized"); return; } res.sendStatus(200); diff --git a/server/opensearch/os-handler.js b/server/opensearch/os-handler.js index 6bb2adcdc..016e9530e 100644 --- a/server/opensearch/os-handler.js +++ b/server/opensearch/os-handler.js @@ -45,6 +45,10 @@ const getClient = async () => { }; async function OpenSearchUpdateHandler(req, res) { + if (req.headers["event-secret"] !== process.env.EVENT_SECRET) { + res.status(401).send("Unauthorized"); + return; + } try { var osClient = await getClient(); // const osClient = new Client({ diff --git a/server/utils/utils.js b/server/utils/utils.js index 4587106be..ad3a06d24 100644 --- a/server/utils/utils.js +++ b/server/utils/utils.js @@ -1,3 +1,12 @@ exports.servertime = (req, res) => { res.status(200).send(new Date()); }; + +exports.jsrAuth = async (req, res) => { + res.send( + "Basic " + + Buffer.from( + `${process.env.JSR_USER}:${process.env.JSR_PASSWORD}` + ).toString("base64") + ); +};