I will hereby not claim any legal responsibility or liability for and the jokes it serves (especially those from the "Dark" category).
Whether it is used maliciously or breaks something in your project or someone gets offended by a joke, I can't be held accountable.
- Additionally, I will only be able to provide security updates for a small selection of versions, a list of which you can find
here.
+ Additionally, I will only be able to provide security updates for a small selection of versions, a list of which you can find
here.
I am doing my best to ensure security and stability but there's only so much a single developer can do.
Please report any issue that may arise to
the GitHub issue tracker and I will try my best to fix it as soon as possible.
If you want to contact me, you can
join my Discord server (fastest way to contact me) or send me an E-Mail at
sven.fehler@web.de
diff --git a/docs/raw/index.js b/docs/raw/index.js
index 267f1514..834624d4 100644
--- a/docs/raw/index.js
+++ b/docs/raw/index.js
@@ -744,7 +744,18 @@ function buildSubmission()
}
var subDisp = document.getElementById("submissionDisplay");
- subDisp.innerHTML = JSON.stringify(submission, null, 4);
+
+ var escapedSubmission = JSON.parse(JSON.stringify(submission)); // copy value without reference
+ if(type == "single")
+ {
+ escapedSubmission.joke = htmlEscape(submission.joke);
+ }
+ else if(type == "twopart")
+ {
+ escapedSubmission.setup = htmlEscape(submission.setup);
+ escapedSubmission.delivery = htmlEscape(submission.delivery);
+ }
+ subDisp.innerHTML = JSON.stringify(escapedSubmission, null, 4);
var subCodeElem = document.getElementById("submissionCodeElement");
@@ -770,6 +781,19 @@ function buildSubmission()
}, 5);
}
+/**
+ * Escapes unsafe HTML
+ * @param {String} unsafeHTML
+ * @returns {String}
+ */
+function htmlEscape(unsafeHTML)
+{
+ unsafeHTML = unsafeHTML.replace(//g, ">");
+
+ return unsafeHTML;
+}
+
//#MARKER privacy policy
function privPolMoreInfo()
{
diff --git a/package-lock.json b/package-lock.json
index 3ef166c0..d10ff67d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,6 +1,6 @@
{
"name": "@sv443/jokeapi",
- "version": "2.1.2",
+ "version": "2.1.3",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
@@ -4098,9 +4098,9 @@
}
},
"svjsl": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/svjsl/-/svjsl-1.9.0.tgz",
- "integrity": "sha512-aDa2/CDW3rrktILZ16TwieRkkaa25SHb9GgLTiQlYkBSA2VUpH8wvup4dop1juhPGWvtf61vQIz5/xHl2+dFgQ=="
+ "version": "1.9.4",
+ "resolved": "https://registry.npmjs.org/svjsl/-/svjsl-1.9.4.tgz",
+ "integrity": "sha512-W3TItJKVKo8W8MO7S+Of88sX4agS4sXS7EXR/6terUBtvuKgciXNK0w/Sf8xc4CAJwb/V33QQgH6/qEVdpYTMw=="
},
"tapable": {
"version": "1.1.3",
diff --git a/package.json b/package.json
index a2eb1901..46a5effd 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "@sv443/jokeapi",
- "version": "2.1.2",
+ "version": "2.1.3",
"description": "A RESTful API that serves jokes from many categories while also offering a lot of filtering methods",
"main": "JokeAPI.js",
"homepage": "https://sv443.net/jokeapi/v2",
@@ -50,7 +50,7 @@
"json-to-pretty-yaml": "^1.2.2",
"mysql": "^2.18.1",
"node-wrap": "^0.2.0",
- "svjsl": "^1.9.0",
+ "svjsl": "^1.9.4",
"xss": "^1.0.6",
"snyk": "^1.316.1"
},
diff --git a/settings.js b/settings.js
index 86ab56da..8ad1e119 100644
--- a/settings.js
+++ b/settings.js
@@ -7,6 +7,7 @@ const settings = {
debug: {
verboseLogging: false, // set to true to enable extra debug output
progressBarDisabled: true, // set to true to disable the progress bar - greatly improves readability of verbose debug output
+ onlyLogErrors: true, // set to true to disable sending any console logs but error messages
},
info: {
name: "JokeAPI", // the name of JokeAPI
@@ -24,6 +25,18 @@ const settings = {
infoMsg: "If you want to be updated on the status and future updates of JokeAPI or need some help, please consider joining my Discord server: https://sv443.net/discord",
privacyPolicyUrl: "https://sv443.net/privacypolicy/en"
},
+ wrapper: {
+ mainFilePath: "./src/main.js", // main script file
+ skipWrapping: true, // whether or not to skip the wrapping through node-wrap
+ wrapperSettings: {
+ console: true, // whether Node-Wrap should log to the console
+ crashTimeout: 2000, // timeout (in ms) until the process should be restarted after a crash
+ logFile: "./data/logs/wrapper.log", // Node-Wrap log file
+ logTimestamp: true, // whether to add a timestamp to the log
+ restartOnCrash: true, // whether to restart the process after a crash
+ restartTimeout: 0, // timeout (in ms) until the process should be started again after a restart has been requested
+ },
+ },
init: {
initDirs: [ // directories that should be generated if they don't exist - paths relative to root of project - doesn't necessarily need trailing slash
"./data/logs",
@@ -41,18 +54,6 @@ const settings = {
disableLogging: false, // set to true to disable logging a character on each request
blacklistLoggingEnabled: true, // whether or not to log the character when an IP is on the blacklist
},
- wrapper: {
- mainFilePath: "./src/main.js", // main script file
- skipWrapping: false, // whether or not to skip the wrapping through node-wrap
- wrapperSettings: {
- console: true, // whether Node-Wrap should log to the console
- crashTimeout: 2000, // timeout (in ms) until the process should be restarted after a crash
- logFile: "./data/logs/wrapper.log", // Node-Wrap log file
- logTimestamp: true, // whether to add a timestamp to the log
- restartOnCrash: true, // whether to restart the process after a crash
- restartTimeout: 0, // timeout (in ms) until the process should be started again after a restart has been requested
- },
- },
jokes: {
jokesFormatVersion: 2, // current joke format version
jokesFilePath: "./data/jokes.json", // path to the jokes file
@@ -182,4 +183,4 @@ const settings = {
}
}
-module.exports = settings;
\ No newline at end of file
+module.exports = settings;
diff --git a/src/classes/FilteredJoke.js b/src/classes/FilteredJoke.js
index b54bb717..f6a0fd99 100644
--- a/src/classes/FilteredJoke.js
+++ b/src/classes/FilteredJoke.js
@@ -156,8 +156,16 @@ class FilteredJoke
return false;
}
- this._searchString = decodeURIComponent(searchString);
- return true;
+ try
+ {
+ this._searchString = decodeURIComponent(searchString);
+ return true;
+ }
+ catch(err)
+ {
+ this._errors.push("The URI is malformatted or the \"contains\" parameter isn't correctly percent-encoded");
+ return false;
+ }
}
/**
diff --git a/src/logRequest.js b/src/logRequest.js
index ce5dba26..7b8ff4a3 100644
--- a/src/logRequest.js
+++ b/src/logRequest.js
@@ -26,6 +26,9 @@ const logRequest = (type, additionalInfo, analyticsData) => {
let spacerDisabled = false;
let logChar = settings.logging.logChar;
+ if(settings.debug.onlyLogErrors)
+ logDisabled = true;
+
switch(type)
{
case "success":
@@ -75,6 +78,9 @@ const logRequest = (type, additionalInfo, analyticsData) => {
}
break;
case "error":
+ if(settings.debug.onlyLogErrors)
+ logDisabled = false;
+
color = settings.colors.ratelimit;
logType = "error";
@@ -93,7 +99,7 @@ const logRequest = (type, additionalInfo, analyticsData) => {
break;
case "docsrecompiled":
color = settings.colors.docsrecompiled;
- logChar = `r${jsl.colors.rst} `;
+ logChar = "r ";
break;
case "submission":
logChar = `\n\n${jsl.colors.fg.blue}⯈ Got a submission${!jsl.isEmpty(additionalInfo) ? ` from ${jsl.colors.fg.yellow}${additionalInfo.substring(0, 8)}` : ""}${jsl.colors.rst}\n\n`;
@@ -147,11 +153,16 @@ const initMsg = (initTimestamp) => {
console.log(` ├─ Analytics database ${jsl.colors.fg.red}not connected${jsl.colors.rst}`);
console.log(` ├─ ${settings.info.name} is listening at ${jsl.colors.fg.green}0.0.0.0:${settings.httpServer.port}${jsl.colors.rst}`);
console.log(` └─ Initialization took ${jsl.colors.fg.green}${(new Date().getTime() - initTimestamp).toFixed(0)}ms${jsl.colors.rst}`);
- console.log(`\n\n ${settings.colors.success}${settings.logging.logChar} Success ${settings.colors.docs}${settings.logging.logChar} Docs ${settings.colors.ratelimit}${settings.logging.logChar} RateLimited ${settings.colors.error}${settings.logging.logChar} Error${jsl.colors.rst}`);
- process.stdout.write("\x1b[2m");
- process.stdout.write("└┬───────────────────────────────────────┘\n");
- process.stdout.write(" └─► ");
- process.stdout.write("\x1b[0m");
+ process.stdout.write("\n");
+
+ if(!settings.debug.onlyLogErrors)
+ {
+ console.log(`\n ${settings.colors.success}${settings.logging.logChar} Success ${settings.colors.docs}${settings.logging.logChar} Docs ${settings.colors.ratelimit}${settings.logging.logChar} RateLimited ${settings.colors.error}${settings.logging.logChar} Error${jsl.colors.rst}`);
+ process.stdout.write("\x1b[2m");
+ process.stdout.write("└┬───────────────────────────────────────┘\n");
+ process.stdout.write(" └─► ");
+ process.stdout.write(jsl.colors.rst);
+ }
}
module.exports = logRequest;
diff --git a/tools/submissions.js b/tools/submissions.js
index 5540bb5e..718560c4 100644
--- a/tools/submissions.js
+++ b/tools/submissions.js
@@ -16,7 +16,7 @@ const run = () => {
return process.exit(0);
}
- pause(`Do you want to go through them all now? (Y/n):${jsl.colors.rst}`).then(key => {
+ jsl.pause(`Do you want to go through them all now? (Y/n):${jsl.colors.rst}`).then(key => {
if(key.toLowerCase && key.toLowerCase() == "n")
process.exit(0);
else
@@ -52,13 +52,13 @@ const run = () => {
}
else console.error(`${jsl.colors.fg.red}Error: Unsuppoted joke type "${submission.type}"${jsl.colors.rst}`);
- pause("Do you want to add this joke? (y/N):").then(key => {
+ jsl.pause("Do you want to add this joke? (y/N):").then(key => {
if(key.toLowerCase() === "y")
{
addJoke(submissions[idx]);
- process.stdout.write(`${jsl.colors.fg.green}Adding joke.${jsl.colors.rst}\n\n`);
+ process.stdout.write(`${jsl.colors.fg.green}Adding joke.${jsl.colors.rst}\n\n\n\n`);
}
- else process.stdout.write(`${jsl.colors.fg.red}Not adding joke.${jsl.colors.rst}\n\n`);
+ else process.stdout.write(`${jsl.colors.fg.red}Not adding joke.${jsl.colors.rst}\n\n\n\n`);
goThroughSubmission(++idx);
});
@@ -119,7 +119,7 @@ const getFlags = joke => {
});
if(flags.length == 0)
- return "";
+ return "(none)";
return jsl.readableArray(flags);
};
@@ -136,38 +136,4 @@ const getSubmissions = () => {
return submissions;
};
-/**
- * Waits for the user to press a key and then resolves a Promise
- * @param {String} text The text to display
- * @returns {Promise} Passes the pressed key in the resolution or the error message in the rejection
- */
-function pause(text = "Press any key to continue...")
-{
- if(!process.stdin.isRaw)
- process.stdin.setRawMode(true);
-
- return new Promise((resolve, reject) => {
- process.stdout.write(`${text} `);
- process.stdin.resume();
-
- let onData = function(chunk)
- {
- if(/\u0003/gu.test(chunk)) // eslint-disable-line no-control-regex
- process.exit(0);
-
- process.stdout.write("\n");
- process.stdin.pause();
-
- process.stdin.removeListener("data", onData);
- return resolve(chunk.toString());
- }
-
- process.stdin.on("data", onData);
-
- process.stdin.on("error", err => {
- return reject(err);
- });
- });
-}
-
run();
\ No newline at end of file