diff --git a/microservices/download/index.js b/microservices/download/index.js index 0b35739..14af68e 100644 --- a/microservices/download/index.js +++ b/microservices/download/index.js @@ -3,6 +3,16 @@ const utils = require("./utils.js"); const port = parseInt(process.env.PORT) || 8080; const server = http.createServer(async (req, res) => { + if (typeof req?.url !== "string"){ + // Not sure if this error condition is even possible, but handling it anyway + await utils.displayError(req, res, { + code: 500, + msg: "Internal Server Error: Misformed URL" + }); + console.log("Download Returned 500 due to the requested URL not being received as a string internally"); + return; + } + // Since req.url is our URL plus query params, lets split them first. const url = req.url.split("?"); const path = url[0]; @@ -11,21 +21,41 @@ const server = http.createServer(async (req, res) => { // Set our Request Route if (path === "/" && req.method === "GET") { - let params = { + if (typeof queryParams !== "string"){ + await utils.displayError(req, res, { + code: 400, + msg: "Missing Query Parameters" + }); + console.log("Download Returned 400 due to the requested URL having no query parameters"); + return; + } + + if (queryParams.length > 100){ + // Longest valid combo is 36 characters ("os=silicon_mac&type=mac_zip_blockmap"), + // But leaving extra room to update the parameters in the future. + await utils.displayError(req, res, { + code: 414, + msg: "Requested Parameters are Too Long" + }); + console.log("Download Returned 414 due to the provided parameters being too long"); + return; + } + + let validatedParams = { os: utils.query_os(queryParams), type: utils.query_type(queryParams) }; - if (!params.os || !params.type) { + if (!validatedParams.os || !validatedParams.type) { await utils.displayError(req, res, { - code: 503, - msg: "Missing Required Download Parameters" + code: 400, + msg: "Required Download Parameters Missing or Invalid" }); - console.log("Download Returned 503 due to missing os or type"); + console.log("Download Returned 400 due to missing or invalid os or type"); return; } - let redirLink = await utils.findLink(params.os, params.type); + let redirLink = await utils.findLink(validatedParams.os, validatedParams.type); if (!redirLink.ok) { await utils.displayError(req, res, redirLink); @@ -37,7 +67,7 @@ const server = http.createServer(async (req, res) => { Location: redirLink.content }).end(); - console.log(`Download Returned: OS: ${params.os} - TYPE: ${params.type} - URL: ${redirLink.content}`); + console.log(`Download Returned: OS: ${validatedParams.os} - TYPE: ${validatedParams.type} - URL: ${redirLink.content}`); } else { diff --git a/microservices/download/utils.js b/microservices/download/utils.js index a5df8c2..7341cba 100644 --- a/microservices/download/utils.js +++ b/microservices/download/utils.js @@ -2,29 +2,12 @@ const https = require("node:https"); const bins = require("./bins.js"); let TOKEN = process.env.GH_TOKEN_DOWNLOAD_MICROSERVICE; -const VALID_OS = [ "linux", "arm_linux", "silicon_mac", "intel_mac", "windows" ]; -const VALID_TYPE = [ - "linux_appimage", - "linux_tar", - "linux_rpm", - "linux_deb", - "windows_setup", - "windows_portable", - "windows_blockmap", - "mac_zip", - "mac_zip_blockmap", - "mac_dmg", - "mac_dmg_blockmap" -]; - // Environment Variables Check if (typeof TOKEN === "undefined") { - if (process.env.PULSAR_STATUS === "dev") { - // We are in dev mode, assign dev values - TOKEN = "123456"; - } else { - // We are not in dev mode. Our secrets are gone and the application will fail to work + if (process.env.PULSAR_STATUS !== "dev") { + // We are not in dev mode. Our auth token is gone, and the application may fail to work + // due to rate limiting by GitHub for unauthenticated API requests. console.log("Missing Required Environment Variable: 'GH_TOKEN_DOWNLOAD_MICROSERVICE'!"); process.exit(1); } @@ -43,6 +26,12 @@ function doRequest() { } }; + if (process.env.PULSAR_STATUS === "dev") { + // We don't expect to be authed in dev mode. + // Fetching releases from GitHub without authentication is fine in dev mode. + delete options.headers['Authorization']; + } + return new Promise((resolve, reject) => { let data = ''; @@ -65,52 +54,58 @@ function doRequest() { }); }; -function query_os(param) { - let raw = param; // The query string. From the URL string split by `?` - let prov = undefined; - - if (typeof raw !== "string") { +function query_os(queryString) { + if (typeof queryString !== "string") { return false; } - let full = raw.split("&"); + const allParams = queryString.split("&"); + const valid = [ "linux", "arm_linux", "silicon_mac", "intel_mac", "windows" ]; - for (const param of full) { + for (const param of allParams) { if (param.startsWith("os=")) { - prov = param.split("=")[1]; - break; + // Returning a result based on the first "os=" param we encounter. + // Users should not provide the same param twice, that would be invalid. + const prov = param.split("=")[1]; + return valid.includes(prov) ? prov : false; } } - if (prov === undefined) { - return false; - } - - return VALID_OS.includes(prov) ? prov : false; + // No "os" query param was provided, return false + return false; } -function query_type(param) { - let raw = param; - let prov = undefined; - - if (typeof raw !== "string") { +function query_type(queryString) { + if (typeof queryString !== "string") { return false; } - let full = raw.split("&"); - - for (const param of full) { + const allParams = queryString.split("&"); + const valid = [ + "linux_appimage", + "linux_tar", + "linux_rpm", + "linux_deb", + "windows_setup", + "windows_portable", + "windows_blockmap", + "mac_zip", + "mac_zip_blockmap", + "mac_dmg", + "mac_dmg_blockmap" + ]; + + for (const param of allParams) { if (param.startsWith("type=")) { - prov = param.split("=")[1]; - break; + // Returning a result based on the first "type=" param we encounter. + // Users should not provide the same param twice, that would be invalid. + const prov = param.split("=")[1]; + return valid.includes(prov) ? prov : false; } } - if (prov === undefined) { - return false; - } - - return VALID_TYPE.includes(prov) ? prov : false; + // No "type" query param was provided, return false + return false; } async function displayError(req, res, errMsg) { @@ -185,8 +180,8 @@ async function findLink(os, type) { console.log(err); return { ok: false, - code: 505, - msg: "Server Error" + code: 500, + msg: "Server Error While Finding Link" }; } }