fix github scanned issues

This commit is contained in:
slynn1324 2021-10-04 15:47:42 -05:00
parent a573f4a073
commit efa93f409f
12 changed files with 293 additions and 49 deletions

View file

@ -79,6 +79,7 @@ app.addSetter('load.user', async (data) => {
data.user = await res.json(); data.user = await res.json();
window.uid = data.user.id; window.uid = data.user.id;
window.csrfToken = data.user.csrf;
dispatchSocketConnect(); dispatchSocketConnect();
store.do("loader.hide"); store.do("loader.hide");
@ -183,7 +184,10 @@ async function multipartUpload(file, boardId, newBoardName, siteUrl, description
let res = await fetch("./multiup", { let res = await fetch("./multiup", {
method: "POST", method: "POST",
body: formData body: formData,
headers: {
"x-csrf-token": window.csrfToken
}
}); });
if ( res.status == 200 ){ if ( res.status == 200 ){
@ -449,6 +453,11 @@ window.ondrop = async (evt) => {
}; };
function getCookie(name) {
const value = `; ${document.cookie}`;
const parts = value.split(`; ${name}=`);
if (parts.length === 2) return parts.pop().split(';').shift();
}

View file

@ -94,7 +94,8 @@ app.addSetter('addPinModal.save', async (data) => {
let res = await fetch('api/pins', { let res = await fetch('api/pins', {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': "application/json" 'Content-Type': "application/json",
"x-csrf-token" : window.csrfToken
}, },
body: JSON.stringify(postData) body: JSON.stringify(postData)
}); });

View file

@ -32,7 +32,10 @@ app.addSetter("brickwall.deletePin", async (data) => {
closeLightGallery(); closeLightGallery();
let res = await fetch(`api/pins/${pinId}`, { let res = await fetch(`api/pins/${pinId}`, {
method: 'DELETE' method: 'DELETE',
headers: {
'x-csrf-token': window.csrfToken
}
}); });
if ( res.status == 200 ){ if ( res.status == 200 ){
@ -63,7 +66,7 @@ async function iosShare(){
let index = getLightGalleryIndex(); let index = getLightGalleryIndex();
let pin = data.board.pins[index]; let pin = data.board.pins[index];
let result = await fetch("/api/pins/" + pin.id + "/otl", {method: 'POST'}); let result = await fetch("/api/pins/" + pin.id + "/otl", {method: 'POST', headers: {'x-csrf-token':window.csrfToken}});
let obj = await result.json(); let obj = await result.json();
let t = obj.t; let t = obj.t;

View file

@ -33,6 +33,7 @@ app.addSetter('editBoardModal.save', async (data) => {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json', 'Content-Type': 'application/json',
'x-csrf-token': window.csrfToken
}, },
body: JSON.stringify({ body: JSON.stringify({
name: name, name: name,
@ -70,7 +71,10 @@ app.addSetter('editBoardModal.delete', async (data) => {
let res = await fetch(`/api/boards/${boardId}`, { let res = await fetch(`/api/boards/${boardId}`, {
method: 'DELETE' method: 'DELETE',
headers: {
'x-csrf-token':window.csrfToken
}
}); });
if ( res.status == 200 ){ if ( res.status == 200 ){

View file

@ -56,7 +56,10 @@ app.addSetter("editPinModal.save", async (data) => {
// TODO: make a helper method // TODO: make a helper method
let res = await fetch("/api/boards", { let res = await fetch("/api/boards", {
method: 'POST', method: 'POST',
headers: {'Content-Type': 'application/json' }, headers: {
'Content-Type': 'application/json'
'x-csrf-token': window.csrfToken
},
body: JSON.stringify({ body: JSON.stringify({
"name": data.editPinModal.newBoardName "name": data.editPinModal.newBoardName
}) })
@ -79,7 +82,8 @@ app.addSetter("editPinModal.save", async (data) => {
let res = await fetch('api/pins/' + pin.id, { let res = await fetch('api/pins/' + pin.id, {
method: 'POST', method: 'POST',
headers: { headers: {
'Content-Type': 'application/json' 'Content-Type': 'application/json',
'x-csrf-token': window.csrfToken
}, },
body: JSON.stringify(postData) body: JSON.stringify(postData)
}); });

187
package-lock.json generated
View file

@ -11,11 +11,14 @@
"better-sqlite3": "^7.4.3", "better-sqlite3": "^7.4.3",
"body-parser": "^1.19.0", "body-parser": "^1.19.0",
"cookie-parser": "^1.4.5", "cookie-parser": "^1.4.5",
"csurf": "^1.11.0",
"eta": "^1.12.3", "eta": "^1.12.3",
"express": "^4.17.1", "express": "^4.17.1",
"express-rate-limit": "^5.4.0",
"express-ws": "^5.0.2", "express-ws": "^5.0.2",
"multer": "^1.4.3", "multer": "^1.4.3",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",
"sanitize-filename": "^1.6.3",
"sharp": "^0.29.1", "sharp": "^0.29.1",
"yargs": "^17.2.1" "yargs": "^17.2.1"
} }
@ -388,6 +391,48 @@
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
}, },
"node_modules/csrf": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz",
"integrity": "sha512-uTqEnCvWRk042asU6JtapDTcJeeailFy4ydOQS28bj1hcLnYRiqi8SsD2jS412AY1I/4qdOwWZun774iqywf9w==",
"dependencies": {
"rndm": "1.2.0",
"tsscmp": "1.0.6",
"uid-safe": "2.1.5"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/csurf": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/csurf/-/csurf-1.11.0.tgz",
"integrity": "sha512-UCtehyEExKTxgiu8UHdGvHj4tnpE/Qctue03Giq5gPgMQ9cg/ciod5blZQ5a4uCEenNQjxyGuzygLdKUmee/bQ==",
"dependencies": {
"cookie": "0.4.0",
"cookie-signature": "1.0.6",
"csrf": "3.1.0",
"http-errors": "~1.7.3"
},
"engines": {
"node": ">= 0.8.0"
}
},
"node_modules/csurf/node_modules/http-errors": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
"integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
"dependencies": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.0"
},
"engines": {
"node": ">= 0.6"
}
},
"node_modules/debug": { "node_modules/debug": {
"version": "2.6.9", "version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@ -583,6 +628,11 @@
"node": ">= 0.10.0" "node": ">= 0.10.0"
} }
}, },
"node_modules/express-rate-limit": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.4.0.tgz",
"integrity": "sha512-sT+rk1wvj06+0MpEiij7y3kGdB4hoMyQ+a5zcESUpDMLhbLXoYIQI6JfsvLBz1wOhmfF//ALG/Q59FKMI0x2Eg=="
},
"node_modules/express-ws": { "node_modules/express-ws": {
"version": "5.0.2", "version": "5.0.2",
"resolved": "https://registry.npmjs.org/express-ws/-/express-ws-5.0.2.tgz", "resolved": "https://registry.npmjs.org/express-ws/-/express-ws-5.0.2.tgz",
@ -1071,6 +1121,14 @@
"node": ">=0.6" "node": ">=0.6"
} }
}, },
"node_modules/random-bytes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
"integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=",
"engines": {
"node": ">= 0.8"
}
},
"node_modules/range-parser": { "node_modules/range-parser": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@ -1129,6 +1187,11 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/rndm": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz",
"integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w="
},
"node_modules/safe-buffer": { "node_modules/safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@ -1139,6 +1202,14 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
}, },
"node_modules/sanitize-filename": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz",
"integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==",
"dependencies": {
"truncate-utf8-bytes": "^1.0.0"
}
},
"node_modules/semver": { "node_modules/semver": {
"version": "5.7.1", "version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
@ -1415,6 +1486,22 @@
"node": ">=0.6" "node": ">=0.6"
} }
}, },
"node_modules/truncate-utf8-bytes": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
"integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=",
"dependencies": {
"utf8-byte-length": "^1.0.1"
}
},
"node_modules/tsscmp": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",
"integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==",
"engines": {
"node": ">=0.6.x"
}
},
"node_modules/tunnel-agent": { "node_modules/tunnel-agent": {
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@ -1443,6 +1530,17 @@
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
}, },
"node_modules/uid-safe": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
"integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
"dependencies": {
"random-bytes": "~1.0.0"
},
"engines": {
"node": ">= 0.8"
}
},
"node_modules/unpipe": { "node_modules/unpipe": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
@ -1451,6 +1549,11 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/utf8-byte-length": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",
"integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E="
},
"node_modules/util-deprecate": { "node_modules/util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
@ -1937,6 +2040,41 @@
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
}, },
"csrf": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/csrf/-/csrf-3.1.0.tgz",
"integrity": "sha512-uTqEnCvWRk042asU6JtapDTcJeeailFy4ydOQS28bj1hcLnYRiqi8SsD2jS412AY1I/4qdOwWZun774iqywf9w==",
"requires": {
"rndm": "1.2.0",
"tsscmp": "1.0.6",
"uid-safe": "2.1.5"
}
},
"csurf": {
"version": "1.11.0",
"resolved": "https://registry.npmjs.org/csurf/-/csurf-1.11.0.tgz",
"integrity": "sha512-UCtehyEExKTxgiu8UHdGvHj4tnpE/Qctue03Giq5gPgMQ9cg/ciod5blZQ5a4uCEenNQjxyGuzygLdKUmee/bQ==",
"requires": {
"cookie": "0.4.0",
"cookie-signature": "1.0.6",
"csrf": "3.1.0",
"http-errors": "~1.7.3"
},
"dependencies": {
"http-errors": {
"version": "1.7.3",
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz",
"integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==",
"requires": {
"depd": "~1.1.2",
"inherits": "2.0.4",
"setprototypeof": "1.1.1",
"statuses": ">= 1.5.0 < 2",
"toidentifier": "1.0.0"
}
}
}
},
"debug": { "debug": {
"version": "2.6.9", "version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
@ -2102,6 +2240,11 @@
} }
} }
}, },
"express-rate-limit": {
"version": "5.4.0",
"resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-5.4.0.tgz",
"integrity": "sha512-sT+rk1wvj06+0MpEiij7y3kGdB4hoMyQ+a5zcESUpDMLhbLXoYIQI6JfsvLBz1wOhmfF//ALG/Q59FKMI0x2Eg=="
},
"express-ws": { "express-ws": {
"version": "5.0.2", "version": "5.0.2",
"resolved": "https://registry.npmjs.org/express-ws/-/express-ws-5.0.2.tgz", "resolved": "https://registry.npmjs.org/express-ws/-/express-ws-5.0.2.tgz",
@ -2471,6 +2614,11 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
"integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ=="
}, },
"random-bytes": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz",
"integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs="
},
"range-parser": { "range-parser": {
"version": "1.2.1", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
@ -2517,6 +2665,11 @@
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
}, },
"rndm": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz",
"integrity": "sha1-8z/pz7Urv9UgqhgyO8ZdsRCht2w="
},
"safe-buffer": { "safe-buffer": {
"version": "5.1.2", "version": "5.1.2",
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
@ -2527,6 +2680,14 @@
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
}, },
"sanitize-filename": {
"version": "1.6.3",
"resolved": "https://registry.npmjs.org/sanitize-filename/-/sanitize-filename-1.6.3.tgz",
"integrity": "sha512-y/52Mcy7aw3gRm7IrcGDFx/bCk4AhRh2eI9luHOQM86nZsqwiRkkq2GekHXBBD+SmPidc8i2PqtYZl+pWJ8Oeg==",
"requires": {
"truncate-utf8-bytes": "^1.0.0"
}
},
"semver": { "semver": {
"version": "5.7.1", "version": "5.7.1",
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
@ -2739,6 +2900,19 @@
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
"integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw=="
}, },
"truncate-utf8-bytes": {
"version": "1.0.2",
"resolved": "https://registry.npmjs.org/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz",
"integrity": "sha1-QFkjkJWS1W94pYGENLC3hInKXys=",
"requires": {
"utf8-byte-length": "^1.0.1"
}
},
"tsscmp": {
"version": "1.0.6",
"resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz",
"integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA=="
},
"tunnel-agent": { "tunnel-agent": {
"version": "0.6.0", "version": "0.6.0",
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
@ -2761,11 +2935,24 @@
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
"integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c="
}, },
"uid-safe": {
"version": "2.1.5",
"resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz",
"integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==",
"requires": {
"random-bytes": "~1.0.0"
}
},
"unpipe": { "unpipe": {
"version": "1.0.0", "version": "1.0.0",
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
"integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
}, },
"utf8-byte-length": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz",
"integrity": "sha1-9F8VDExm7uloGGUFq5P8u4rWv2E="
},
"util-deprecate": { "util-deprecate": {
"version": "1.0.2", "version": "1.0.2",
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",

View file

@ -12,11 +12,14 @@
"better-sqlite3": "^7.4.3", "better-sqlite3": "^7.4.3",
"body-parser": "^1.19.0", "body-parser": "^1.19.0",
"cookie-parser": "^1.4.5", "cookie-parser": "^1.4.5",
"csurf": "^1.11.0",
"eta": "^1.12.3", "eta": "^1.12.3",
"express": "^4.17.1", "express": "^4.17.1",
"express-rate-limit": "^5.4.0",
"express-ws": "^5.0.2", "express-ws": "^5.0.2",
"multer": "^1.4.3", "multer": "^1.4.3",
"node-fetch": "^2.6.1", "node-fetch": "^2.6.1",
"sanitize-filename": "^1.6.3",
"sharp": "^0.29.1", "sharp": "^0.29.1",
"yargs": "^17.2.1" "yargs": "^17.2.1"
} }

View file

@ -99,7 +99,7 @@ module.exports = async (req, res, next) => {
console.log("login"); console.log("login");
// res.type("html").sendFile(path.resolve('./templates/login.html')); // res.type("html").sendFile(path.resolve('./templates/login.html'));
res.render("login", { registerEnabled: dao.getProperty("registerEnabled") }); res.render("login", { registerEnabled: dao.getProperty("registerEnabled"), csrfToken: req.csrfToken() });
return; return;
} else if ( req.method == "POST" && req.originalUrl == "/login" ){ } else if ( req.method == "POST" && req.originalUrl == "/login" ){
let username = req.body.username; let username = req.body.username;
@ -136,7 +136,7 @@ module.exports = async (req, res, next) => {
return; return;
} }
res.render("register", {}); res.render("register", { csrfToken: req.csrfToken() });
return; return;
} else if ( req.method == "POST" && req.originalUrl == "/register" ){ } else if ( req.method == "POST" && req.originalUrl == "/register" ){

View file

@ -2,6 +2,7 @@ const yargs = require('yargs');
const express = require('express'); const express = require('express');
const bodyParser = require('body-parser'); const bodyParser = require('body-parser');
const multer = require("multer") const multer = require("multer")
const RateLimit = require("express-rate-limit");
const path = require('path'); const path = require('path');
const cookieParser = require('cookie-parser'); const cookieParser = require('cookie-parser');
const tokenUtil = require('./token-utils.js'); const tokenUtil = require('./token-utils.js');
@ -10,10 +11,21 @@ const conf = require("./conf.js");
const imageUtils = require('./image-utils.js'); const imageUtils = require('./image-utils.js');
var eta = require("eta"); var eta = require("eta");
const tokenUtils = require('./token-utils.js'); const tokenUtils = require('./token-utils.js');
const csrf = require("csurf");
const sanitizeFilename = require("sanitize-filename");
// consider using temp files, but we're going to limit the size so should be ok // consider using temp files, but we're going to limit the size so should be ok
const upload = multer({storage:multer.memoryStorage(), limits: {fileSize: 26214400, files: 1}}); // 1 - 25MB file const upload = multer({storage:multer.memoryStorage(), limits: {fileSize: 26214400, files: 1}}); // 1 - 25MB file
// enable a rate limit so we can't swamp the server/filesystem -- 100 per second here. Pretty fast because we're likely
// running locally and want to load images fast.
// GitHub CodeQL - js/missing-rate-limiting
const rateLimiter = new RateLimit({
windowMs: 1000,
max: 100
});
module.exports = async () => { module.exports = async () => {
process.on('SIGINT', () => { process.on('SIGINT', () => {
@ -88,6 +100,8 @@ module.exports = async () => {
app.set("views", "./templates") app.set("views", "./templates")
const expressWs = require('express-ws')(app); const expressWs = require('express-ws')(app);
app.use(rateLimiter); // rate limiting
app.use(bodyParser.raw({type: 'image/jpeg', limit: '25mb'})); // accept image/jpeg files only app.use(bodyParser.raw({type: 'image/jpeg', limit: '25mb'})); // accept image/jpeg files only
app.use(bodyParser.urlencoded({ extended: false })) app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json()); app.use(bodyParser.json());
@ -96,6 +110,44 @@ module.exports = async () => {
// api method that are not subject to CSRF checks
// handle raw uploads for pin creation
app.post("/up", async (req, res) => {
try {
require("fs").writeFileSync("up.jpg", req.body);
// try to parse the image first... if this blows up we'll stop early
let image = await imageUtils.processImage(req.body);
let boardName = req.headers['board-name'].trim();
// get the board
let board = dao.findBoardByUserAndName(req.user.id, boardName);
if ( !board ){
board = dao.createBoard(req.user.id, boardName, 0);
}
let pin = dao.createPin(req.user.id, board.id, null, null, null, null, image.original.height, image.original.width, image.thumbnail.height, image.thumbnail.height);
await imageUtils.saveImage(req.user.id, pin.id, image);
broadcast(req.user.id, {updateBoard:board.id});
res.status(200).send(pin);
} catch (err){
console.log(`Error uploading pin`, err);
res.status(500).send(SERVER_ERROR);
}
});
// all other endpoints require csrf
app.use(csrf({cookie:true}));
// accept websocket connections. currently are parsing the userid from the path to // accept websocket connections. currently are parsing the userid from the path to
// map the connections to only notify on changes from the same user. // map the connections to only notify on changes from the same user.
// this simple mapping of holding all connections in memory here won't really scale beyond // this simple mapping of holding all connections in memory here won't really scale beyond
@ -145,7 +197,7 @@ module.exports = async () => {
res.sendStatus(403); res.sendStatus(403);
return; return;
} }
res.send({name: user.username, id: user.id, admin: user.admin, version: VERSION}); res.send({name: user.username, id: user.id, admin: user.admin, version: VERSION, csrf: req.csrfToken()});
}); });
// list boards // list boards
@ -227,7 +279,7 @@ module.exports = async () => {
res.status(404).send(NOT_FOUND); res.status(404).send(NOT_FOUND);
} }
} catch (err) { } catch (err) {
console.log(`Error deleting board#${req.params.boardId}:`, err); console.log('Error deleting board# %s', req.params.boardId, err);
res.status(500).send(SERVER_ERROR); res.status(500).send(SERVER_ERROR);
} }
}); });
@ -242,7 +294,7 @@ module.exports = async () => {
res.status(404).send(NOT_FOUND); res.status(404).send(NOT_FOUND);
} }
} catch (err){ } catch (err){
console.error(`Error getting pin#${req.params.pinId}: ${err.message}`, err); console.error('Error getting pin# %s', req.params.pinId, err);
res.status(500).send(SERVER_ERROR); res.status(500).send(SERVER_ERROR);
} }
}); });
@ -295,7 +347,7 @@ module.exports = async () => {
res.status(404).send(NOT_FOUND); res.status(404).send(NOT_FOUND);
} }
} catch (err) { } catch (err) {
console.log(`Error updating pin#${req.params.pinId}`, err); console.log('Error updating pin# %s', req.params.pinId, err);
res.status(500).send(SERVER_ERROR); res.status(500).send(SERVER_ERROR);
} }
@ -325,7 +377,7 @@ module.exports = async () => {
} }
} catch (err){ } catch (err){
console.log(`Error deleting pin#${req.params.pinId}`, err); console.log('Error deleting pin# %s', req.params.pinId, err);
res.status(500).send(SERVER_ERROR); res.status(500).send(SERVER_ERROR);
} }
}); });
@ -344,37 +396,7 @@ module.exports = async () => {
res.status(200).send({t: token}); res.status(200).send({t: token});
}); });
// handle raw uploads for pin creation
app.post("/up", async (req, res) => {
try {
require("fs").writeFileSync("up.jpg", req.body);
// try to parse the image first... if this blows up we'll stop early
let image = await imageUtils.processImage(req.body);
let boardName = req.headers['board-name'].trim();
// get the board
let board = dao.findBoardByUserAndName(req.user.id, boardName);
if ( !board ){
board = dao.createBoard(req.user.id, boardName, 0);
}
let pin = dao.createPin(req.user.id, board.id, null, null, null, null, image.original.height, image.original.width, image.thumbnail.height, image.thumbnail.height);
await imageUtils.saveImage(req.user.id, pin.id, image);
broadcast(req.user.id, {updateBoard:board.id});
res.status(200).send(pin);
} catch (err){
console.log(`Error uploading pin`, err);
res.status(500).send(SERVER_ERROR);
}
});
// handle multipart uploads for pin creation // handle multipart uploads for pin creation
@ -431,6 +453,7 @@ module.exports = async () => {
} }
res.render("settings", { res.render("settings", {
csrfToken: req.csrfToken(),
registerEnabled: registerEnabled, registerEnabled: registerEnabled,
users: users, users: users,
userId: req.user.id userId: req.user.id
@ -478,8 +501,6 @@ module.exports = async () => {
let password = req.body.password; let password = req.body.password;
let repeatPassword = req.body.repeatPassword; let repeatPassword = req.body.repeatPassword;
console.log(`username: ${username} password: ${password} rp: ${repeatPassword}`);
if ( password != repeatPassword ){ if ( password != repeatPassword ){
res.redirect("./settings#password-match") res.redirect("./settings#password-match")
return; return;
@ -491,7 +512,7 @@ module.exports = async () => {
try{ try{
dao.createUser(username, 0, key, salt); dao.createUser(username, 0, key, salt);
} catch (err){ } catch (err){
console.log("error creating user " + username, err); console.log("error creating user %s", username, err);
res.redirect("./settings#create-user-error"); res.redirect("./settings#create-user-error");
return; return;
} }
@ -503,11 +524,17 @@ module.exports = async () => {
let uid = req.body.uid; let uid = req.body.uid;
// uids must ONLY be integer numbers, to ensure that this is safe to use in the path below
if ( !uid.match(/^[0-9]+$/) ){
console.log("Invalid uid: %s", uid);
res.redirect("./settings#delete-user-error");
}
try { try {
dao.deleteUser(uid); dao.deleteUser(uid);
require("fs").rmdirSync(conf.getImagePath() + "/" + uid , { recursive: true }); require("fs").rmdirSync(conf.getImagePath() + "/" + uid , { recursive: true });
} catch (err){ } catch (err){
console.log("error deleting user " + uid, err); console.log("error deleting user %s", uid, err);
res.redirect("./settings#delete-user-error"); res.redirect("./settings#delete-user-error");
return; return;
} }

View file

@ -26,6 +26,7 @@
<p class="modal-card-title">tinypin &raquo; log in</p> <p class="modal-card-title">tinypin &raquo; log in</p>
</header> </header>
<form method="post" action="./login"> <form method="post" action="./login">
<input type="hidden" name="_csrf" value="<%= it.csrfToken %>" />
<section class="modal-card-body"> <section class="modal-card-body">
<div class="field"> <div class="field">

View file

@ -26,6 +26,7 @@
<p class="modal-card-title">tinypin &raquo; create account</p> <p class="modal-card-title">tinypin &raquo; create account</p>
</header> </header>
<form method="post" action="./register"> <form method="post" action="./register">
<input type="hidden" name="_csrf" value="<%= it.csrfToken %>" />
<section class="modal-card-body"> <section class="modal-card-body">
<div class="field"> <div class="field">

View file

@ -69,6 +69,7 @@
<h1 style="border-bottom: 1px solid #eee;"><strong>Settings</strong></h1> <h1 style="border-bottom: 1px solid #eee;"><strong>Settings</strong></h1>
<br /> <br />
<form method="POST" action="./settings"> <form method="POST" action="./settings">
<input type="hidden" name="_csrf" value="<%= it.csrfToken %>" />
<input type="hidden" name="action" value="updateSettings"> <input type="hidden" name="action" value="updateSettings">
<div class="field is-horizontal"> <div class="field is-horizontal">
<div class="field-label is-normal"> <div class="field-label is-normal">
@ -101,7 +102,8 @@
<br /> <br />
<form method="POST" action="./settings"> <form method="POST" action="./settings">
<input type="hidden" name="action" value="updateUsers"> <input type="hidden" name="_csrf" value="<%= it.csrfToken %>" />
<input type="hidden" name="action" value="updateUsers" />
<table class="table" style="width: 100%;"> <table class="table" style="width: 100%;">
<thead> <thead>
<tr> <tr>
@ -165,6 +167,7 @@
<p class="modal-card-title">tinypin &raquo; create account</p> <p class="modal-card-title">tinypin &raquo; create account</p>
</header> </header>
<form method="post" action="./settings" onsubmit="return submitCreateUserForm()"> <form method="post" action="./settings" onsubmit="return submitCreateUserForm()">
<input type="hidden" name="_csrf" value="<%= it.csrfToken %>" />
<input type="hidden" name="action" value="createUser" /> <input type="hidden" name="action" value="createUser" />
<section class="modal-card-body"> <section class="modal-card-body">
@ -202,6 +205,7 @@
</div> </div>
<form id="deleteUserForm" action="./settings" method="POST"> <form id="deleteUserForm" action="./settings" method="POST">
<input type="hidden" name="_csrf" value="<%= it.csrfToken %>" />
<input type="hidden" name="action" value="deleteUser" /> <input type="hidden" name="action" value="deleteUser" />
<input type="hidden" id="deleteUserUid" name="uid" value="" /> <input type="hidden" id="deleteUserUid" name="uid" value="" />
</form> </form>