nodebb-plugin-pdf-secure 1.2.5 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/library.js +39 -0
- package/package.json +1 -1
- package/plugin.json +4 -0
- package/static/viewer.html +32 -0
package/library.js
CHANGED
|
@@ -26,6 +26,14 @@ plugin.init = async (params) => {
|
|
|
26
26
|
console.error('[PDF-Secure] Failed to cache viewer template:', err.message);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
+
// Double slash bypass protection - catches /uploads//files/ attempts
|
|
30
|
+
router.use((req, res, next) => {
|
|
31
|
+
if (req.path.includes('//') && req.path.toLowerCase().includes('.pdf')) {
|
|
32
|
+
return res.status(403).json({ error: 'Invalid path' });
|
|
33
|
+
}
|
|
34
|
+
next();
|
|
35
|
+
});
|
|
36
|
+
|
|
29
37
|
// PDF direct access blocker middleware
|
|
30
38
|
// Intercepts requests to uploaded PDF files and returns 403
|
|
31
39
|
router.get('/assets/uploads/files/:filename', (req, res, next) => {
|
|
@@ -115,4 +123,35 @@ plugin.addAdminNavigation = (header) => {
|
|
|
115
123
|
return header;
|
|
116
124
|
};
|
|
117
125
|
|
|
126
|
+
// Filter meta tags to hide PDF URLs and filenames
|
|
127
|
+
plugin.filterMetaTags = async (hookData) => {
|
|
128
|
+
if (!hookData || !hookData.tags) {
|
|
129
|
+
return hookData;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Filter out PDF-related meta tags
|
|
133
|
+
hookData.tags = hookData.tags.filter(tag => {
|
|
134
|
+
// Remove og:image if it contains .pdf
|
|
135
|
+
if (tag.property === 'og:image' && tag.content && tag.content.toLowerCase().includes('.pdf')) {
|
|
136
|
+
return false;
|
|
137
|
+
}
|
|
138
|
+
// Remove twitter:image if it contains .pdf
|
|
139
|
+
if (tag.name === 'twitter:image' && tag.content && tag.content.toLowerCase().includes('.pdf')) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
return true;
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
// Sanitize description to hide .pdf extensions
|
|
146
|
+
hookData.tags = hookData.tags.map(tag => {
|
|
147
|
+
if ((tag.name === 'description' || tag.property === 'og:description') && tag.content) {
|
|
148
|
+
// Replace .pdf extension with empty string in description
|
|
149
|
+
tag.content = tag.content.replace(/\.pdf/gi, '');
|
|
150
|
+
}
|
|
151
|
+
return tag;
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
return hookData;
|
|
155
|
+
};
|
|
156
|
+
|
|
118
157
|
module.exports = plugin;
|
package/package.json
CHANGED
package/plugin.json
CHANGED
package/static/viewer.html
CHANGED
|
@@ -1334,6 +1334,34 @@
|
|
|
1334
1334
|
(function () {
|
|
1335
1335
|
'use strict';
|
|
1336
1336
|
|
|
1337
|
+
// ============================================
|
|
1338
|
+
// CANVAS EXPORT PROTECTION
|
|
1339
|
+
// Block toDataURL/toBlob for PDF render canvas only
|
|
1340
|
+
// Allows: thumbnails, annotations, other canvases
|
|
1341
|
+
// ============================================
|
|
1342
|
+
const originalToDataURL = HTMLCanvasElement.prototype.toDataURL;
|
|
1343
|
+
const originalToBlob = HTMLCanvasElement.prototype.toBlob;
|
|
1344
|
+
|
|
1345
|
+
HTMLCanvasElement.prototype.toDataURL = function () {
|
|
1346
|
+
// Block only main PDF page canvases (inside .page elements in #viewerContainer)
|
|
1347
|
+
if (this.closest && this.closest('.page') && this.closest('#viewerContainer')) {
|
|
1348
|
+
console.warn('[Security] Canvas toDataURL blocked for PDF page');
|
|
1349
|
+
return 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='; // 1x1 transparent
|
|
1350
|
+
}
|
|
1351
|
+
return originalToDataURL.apply(this, arguments);
|
|
1352
|
+
};
|
|
1353
|
+
|
|
1354
|
+
HTMLCanvasElement.prototype.toBlob = function (callback) {
|
|
1355
|
+
// Block only main PDF page canvases
|
|
1356
|
+
if (this.closest && this.closest('.page') && this.closest('#viewerContainer')) {
|
|
1357
|
+
console.warn('[Security] Canvas toBlob blocked for PDF page');
|
|
1358
|
+
// Return empty blob
|
|
1359
|
+
if (callback) callback(new Blob([], { type: 'image/png' }));
|
|
1360
|
+
return;
|
|
1361
|
+
}
|
|
1362
|
+
return originalToBlob.apply(this, arguments);
|
|
1363
|
+
};
|
|
1364
|
+
|
|
1337
1365
|
pdfjsLib.GlobalWorkerOptions.workerSrc = '';
|
|
1338
1366
|
|
|
1339
1367
|
// State - now private, not accessible from console
|
|
@@ -1520,6 +1548,10 @@
|
|
|
1520
1548
|
// Security: Delete config containing sensitive data (nonce, key)
|
|
1521
1549
|
delete window.PDF_SECURE_CONFIG;
|
|
1522
1550
|
|
|
1551
|
+
// Security: Remove PDF.js globals to prevent console manipulation
|
|
1552
|
+
delete window.pdfjsLib;
|
|
1553
|
+
delete window.pdfjsViewer;
|
|
1554
|
+
|
|
1523
1555
|
// Security: Block dangerous PDF.js methods
|
|
1524
1556
|
if (pdfDoc) {
|
|
1525
1557
|
pdfDoc.getData = function () {
|