diff --git a/client/admin/brewUtils/brewLookup/brewLookup.jsx b/client/admin/brewUtils/brewLookup/brewLookup.jsx
index 50a2f2015..e5b585ced 100644
--- a/client/admin/brewUtils/brewLookup/brewLookup.jsx
+++ b/client/admin/brewUtils/brewLookup/brewLookup.jsx
@@ -1,3 +1,5 @@
+require('./brewLookup.less');
+
const React = require('react');
const createClass = require('create-react-class');
const cx = require('classnames');
@@ -12,22 +14,43 @@ const BrewLookup = createClass({
},
getInitialState() {
return {
- query : '',
- foundBrew : null,
- searching : false,
- error : null
+ query : '',
+ foundBrew : null,
+ searching : false,
+ error : null,
+ scriptCount : 0
};
},
handleChange(e){
this.setState({ query: e.target.value });
},
lookup(){
- this.setState({ searching: true, error: null });
+ this.setState({ searching: true, error: null, scriptCount: 0 });
request.get(`/admin/lookup/${this.state.query}`)
- .then((res)=>this.setState({ foundBrew: res.body }))
+ .then((res)=>{
+ const foundBrew = res.body;
+ const scriptCheck = foundBrew?.text.match(/(<\/?s)cript/g);
+ this.setState({
+ foundBrew : foundBrew,
+ scriptCount : scriptCheck?.length || 0,
+ });
+ })
.catch((err)=>this.setState({ error: err }))
- .finally(()=>this.setState({ searching: false }));
+ .finally(()=>{
+ this.setState({
+ searching : false
+ });
+ });
+ },
+
+ async cleanScript(){
+ if(!this.state.foundBrew?.shareId) return;
+
+ await request.put(`/admin/clean/script/${this.state.foundBrew.shareId}`)
+ .catch((err)=>{ this.setState({ error: err }); return; });
+
+ this.lookup();
},
renderFoundBrew(){
@@ -46,12 +69,23 @@ const BrewLookup = createClass({
Share Link
/share/{brew.shareId}
+ Created Time
+ {brew.createdAt ? Moment(brew.createdAt).toLocaleString() : 'No creation date'}
+
Last Updated
{Moment(brew.updatedAt).fromNow()}
Num of Views
{brew.views}
+
+ SCRIPT tags detected
+ {this.state.scriptCount}
+ {this.state.scriptCount > 0 &&
+
+
+
+ }
;
},
diff --git a/client/admin/brewUtils/brewLookup/brewLookup.less b/client/admin/brewUtils/brewLookup/brewLookup.less
new file mode 100644
index 000000000..da15e3a64
--- /dev/null
+++ b/client/admin/brewUtils/brewLookup/brewLookup.less
@@ -0,0 +1,6 @@
+.brewLookup {
+ .cleanButton {
+ display : inline-block;
+ width : 100%;
+ }
+}
\ No newline at end of file
diff --git a/client/homebrew/brewRenderer/brewRenderer.jsx b/client/homebrew/brewRenderer/brewRenderer.jsx
index 1c45269cf..4685775b9 100644
--- a/client/homebrew/brewRenderer/brewRenderer.jsx
+++ b/client/homebrew/brewRenderer/brewRenderer.jsx
@@ -161,7 +161,8 @@ const BrewRenderer = (props)=>{
renderedPages.length = 0;
// Render currently-edited page first so cross-page effects (variables, links) can propagate out first
- renderedPages[props.currentEditorCursorPageNum - 1] = renderPage(rawPages[props.currentEditorCursorPageNum - 1], props.currentEditorCursorPageNum - 1);
+ if(rawPages.length > props.currentEditorCursorPageNum -1)
+ renderedPages[props.currentEditorCursorPageNum - 1] = renderPage(rawPages[props.currentEditorCursorPageNum - 1], props.currentEditorCursorPageNum - 1);
_.forEach(rawPages, (page, index)=>{
if((isInView(index) || !renderedPages[index]) && typeof window !== 'undefined'){
diff --git a/package-lock.json b/package-lock.json
index ae99df672..a9b64c1d7 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -21,11 +21,11 @@
"cookie-parser": "^1.4.7",
"create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3",
- "dompurify": "^3.1.7",
+ "dompurify": "^3.2.0",
"expr-eval": "^2.0.2",
"express": "^4.21.1",
"express-async-handler": "^1.2.0",
- "express-static-gzip": "2.1.8",
+ "express-static-gzip": "2.2.0",
"fs-extra": "11.2.0",
"idb-keyval": "^6.2.1",
"js-yaml": "^4.1.0",
@@ -33,13 +33,13 @@
"less": "^3.13.1",
"lodash": "^4.17.21",
"marked": "11.2.0",
- "marked-emoji": "^1.4.2",
+ "marked-emoji": "^1.4.3",
"marked-extended-tables": "^1.0.10",
"marked-gfm-heading-id": "^3.2.0",
"marked-smartypants-lite": "^1.0.2",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1",
- "mongoose": "^8.7.3",
+ "mongoose": "^8.8.1",
"nanoid": "3.3.4",
"nconf": "^0.12.1",
"react": "^18.3.1",
@@ -4327,9 +4327,9 @@
}
},
"node_modules/bson": {
- "version": "6.8.0",
- "resolved": "https://registry.npmjs.org/bson/-/bson-6.8.0.tgz",
- "integrity": "sha512-iOJg8pr7wq2tg/zSlCCHMi3hMm5JTOxLTagf3zxhcenHsFp+c6uOs6K7W5UE7A4QIJGtqh/ZovFNMP4mOPJynQ==",
+ "version": "6.9.0",
+ "resolved": "https://registry.npmjs.org/bson/-/bson-6.9.0.tgz",
+ "integrity": "sha512-X9hJeyeM0//Fus+0pc5dSUMhhrrmWwQUtdavaQeF3Ta6m69matZkGWV/MrBcnwUeLC8W9kwwc2hfkZgUuCX3Ig==",
"engines": {
"node": ">=16.20.1"
}
@@ -5455,9 +5455,9 @@
}
},
"node_modules/dompurify": {
- "version": "3.1.7",
- "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.7.tgz",
- "integrity": "sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ=="
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.0.tgz",
+ "integrity": "sha512-AMdOzK44oFWqHEi0wpOqix/fUNY707OmoeFDnbi3Q5I8uOpy21ufUA5cDJPr0bosxrflOVD/H2DMSvuGKJGfmQ=="
},
"node_modules/duplexer2": {
"version": "0.1.4",
@@ -6290,10 +6290,11 @@
"license": "MIT"
},
"node_modules/express-static-gzip": {
- "version": "2.1.8",
- "resolved": "https://registry.npmjs.org/express-static-gzip/-/express-static-gzip-2.1.8.tgz",
- "integrity": "sha512-g8tiJuI9Y9Ffy59ehVXvqb0hhP83JwZiLxzanobPaMbkB5qBWA8nuVgd+rcd5qzH3GkgogTALlc0BaADYwnMbQ==",
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/express-static-gzip/-/express-static-gzip-2.2.0.tgz",
+ "integrity": "sha512-4ZQ0pHX0CAauxmzry2/8XFLM6aZA4NBvg9QezSlsEO1zLnl7vMFa48/WIcjzdfOiEUS4S1npPPKP2NHHYAp6qg==",
"dependencies": {
+ "parseurl": "^1.3.3",
"serve-static": "^1.16.2"
}
},
@@ -10487,11 +10488,11 @@
}
},
"node_modules/marked-emoji": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/marked-emoji/-/marked-emoji-1.4.2.tgz",
- "integrity": "sha512-2sP+bp2z76dwbILzQ7ijy2PyjjAJR3iAZCzaNGThD2UijFUBeidkn6MoCdX/j47tPIcWt9nwnjqRQPd01ZrfdA==",
+ "version": "1.4.3",
+ "resolved": "https://registry.npmjs.org/marked-emoji/-/marked-emoji-1.4.3.tgz",
+ "integrity": "sha512-HDZx1VOmzu7XT2QNKWfrHGbNRMTWKj9XD78yrcH1madD30HpGLMODPOmKr/e7CA7NKKXkpXXNdndQn++ysXmHg==",
"peerDependencies": {
- "marked": ">=4 <15"
+ "marked": ">=4 <16"
}
},
"node_modules/marked-extended-tables": {
@@ -10865,13 +10866,13 @@
}
},
"node_modules/mongoose": {
- "version": "8.7.3",
- "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.7.3.tgz",
- "integrity": "sha512-Xl6+dzU5ZpEcDoJ8/AyrIdAwTY099QwpolvV73PIytpK13XqwllLq/9XeVzzLEQgmyvwBVGVgjmMrKbuezxrIA==",
+ "version": "8.8.1",
+ "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-8.8.1.tgz",
+ "integrity": "sha512-l7DgeY1szT98+EKU8GYnga5WnyatAu+kOQ2VlVX1Mxif6A0Umt0YkSiksCiyGxzx8SPhGe9a53ND1GD4yVDrPA==",
"dependencies": {
"bson": "^6.7.0",
"kareem": "2.6.3",
- "mongodb": "6.9.0",
+ "mongodb": "~6.10.0",
"mpath": "0.9.0",
"mquery": "5.0.0",
"ms": "2.1.3",
@@ -10943,9 +10944,9 @@
}
},
"node_modules/mongoose/node_modules/mongodb": {
- "version": "6.9.0",
- "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.9.0.tgz",
- "integrity": "sha512-UMopBVx1LmEUbW/QE0Hw18u583PEDVQmUmVzzBRH0o/xtE9DBRA5ZYLOjpLIa03i8FXjzvQECJcqoMvCXftTUA==",
+ "version": "6.10.0",
+ "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-6.10.0.tgz",
+ "integrity": "sha512-gP9vduuYWb9ZkDM546M+MP2qKVk5ZG2wPF63OvSRuUbqCR+11ZCAE1mOfllhlAG0wcoJY5yDL/rV3OmYEwXIzg==",
"dependencies": {
"@mongodb-js/saslprep": "^1.1.5",
"bson": "^6.7.0",
diff --git a/package.json b/package.json
index a48423f50..08473ca05 100644
--- a/package.json
+++ b/package.json
@@ -98,11 +98,11 @@
"cookie-parser": "^1.4.7",
"create-react-class": "^15.7.0",
"dedent-tabs": "^0.10.3",
- "dompurify": "^3.1.7",
+ "dompurify": "^3.2.0",
"expr-eval": "^2.0.2",
"express": "^4.21.1",
"express-async-handler": "^1.2.0",
- "express-static-gzip": "2.1.8",
+ "express-static-gzip": "2.2.0",
"fs-extra": "11.2.0",
"idb-keyval": "^6.2.1",
"js-yaml": "^4.1.0",
@@ -110,13 +110,13 @@
"less": "^3.13.1",
"lodash": "^4.17.21",
"marked": "11.2.0",
- "marked-emoji": "^1.4.2",
+ "marked-emoji": "^1.4.3",
"marked-extended-tables": "^1.0.10",
"marked-gfm-heading-id": "^3.2.0",
"marked-smartypants-lite": "^1.0.2",
"markedLegacy": "npm:marked@^0.3.19",
"moment": "^2.30.1",
- "mongoose": "^8.7.3",
+ "mongoose": "^8.8.1",
"nanoid": "3.3.4",
"nconf": "^0.12.1",
"react": "^18.3.1",
diff --git a/server/admin.api.js b/server/admin.api.js
index fd724b9f1..bc179ff7b 100644
--- a/server/admin.api.js
+++ b/server/admin.api.js
@@ -5,6 +5,10 @@ const Moment = require('moment');
const templateFn = require('../client/template.js');
const zlib = require('zlib');
+const HomebrewAPI = require('./homebrew.api.js');
+const asyncHandler = require('express-async-handler');
+const { splitTextStyleAndMetadata } = require('../shared/helpers.js');
+
process.env.ADMIN_USER = process.env.ADMIN_USER || 'admin';
process.env.ADMIN_PASS = process.env.ADMIN_PASS || 'password3';
@@ -66,23 +70,8 @@ router.post('/admin/cleanup', mw.adminOnly, (req, res)=>{
});
/* Searches for matching edit or share id, also attempts to partial match */
-router.get('/admin/lookup/:id', mw.adminOnly, async (req, res, next)=>{
- HomebrewModel.findOne({
- $or : [
- { editId: { $regex: req.params.id, $options: 'i' } },
- { shareId: { $regex: req.params.id, $options: 'i' } },
- ]
- }).exec()
- .then((brew)=>{
- if(!brew) // No document found
- return res.status(404).json({ error: 'Document not found' });
- else
- return res.json(brew);
- })
- .catch((err)=>{
- console.error(err);
- return res.status(500).json({ error: 'Internal Server Error' });
- });
+router.get('/admin/lookup/:id', mw.adminOnly, asyncHandler(HomebrewAPI.getBrew('admin', false)), async (req, res, next)=>{
+ return res.json(req.brew);
});
/* Find 50 brews that aren't compressed yet */
@@ -100,6 +89,25 @@ router.get('/admin/finduncompressed', mw.adminOnly, (req, res)=>{
});
});
+/* Cleans `