nodebb-plugin-pdf-secure 1.2.7 → 1.2.8
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 +11 -0
- package/package.json +1 -1
- package/static/lib/main.js +51 -27
- package/static/viewer-app.js +2641 -0
- package/static/viewer.css +1484 -0
- package/static/viewer.html +78 -3006
package/library.js
CHANGED
|
@@ -129,6 +129,17 @@ plugin.filterMetaTags = async (hookData) => {
|
|
|
129
129
|
return hookData;
|
|
130
130
|
}
|
|
131
131
|
|
|
132
|
+
// Admin/Global Moderator bypass - no filtering for privileged users
|
|
133
|
+
if (hookData.req && hookData.req.uid) {
|
|
134
|
+
const [isAdmin, isGlobalMod] = await Promise.all([
|
|
135
|
+
groups.isMember(hookData.req.uid, 'administrators'),
|
|
136
|
+
groups.isMember(hookData.req.uid, 'Global Moderators'),
|
|
137
|
+
]);
|
|
138
|
+
if (isAdmin || isGlobalMod) {
|
|
139
|
+
return hookData;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
|
|
132
143
|
// Filter out PDF-related meta tags
|
|
133
144
|
hookData.tags = hookData.tags.filter(tag => {
|
|
134
145
|
// Remove og:image and og:image:url if it contains .pdf
|
package/package.json
CHANGED
package/static/lib/main.js
CHANGED
|
@@ -27,11 +27,30 @@
|
|
|
27
27
|
let isLoading = false;
|
|
28
28
|
let currentResolver = null;
|
|
29
29
|
|
|
30
|
-
//
|
|
30
|
+
// ============================================
|
|
31
|
+
// SPA MEMORY CACHE - Cache decoded PDF buffers
|
|
32
|
+
// ============================================
|
|
33
|
+
const pdfBufferCache = new Map(); // filename -> ArrayBuffer
|
|
34
|
+
const CACHE_MAX_SIZE = 5; // ~50MB limit (avg 10MB per PDF)
|
|
35
|
+
let currentLoadingFilename = null;
|
|
36
|
+
|
|
37
|
+
function setCachedBuffer(filename, buffer) {
|
|
38
|
+
// Evict oldest if cache is full
|
|
39
|
+
if (pdfBufferCache.size >= CACHE_MAX_SIZE) {
|
|
40
|
+
const firstKey = pdfBufferCache.keys().next().value;
|
|
41
|
+
pdfBufferCache.delete(firstKey);
|
|
42
|
+
console.log('[PDF-Secure] Cache: Evicted', firstKey);
|
|
43
|
+
}
|
|
44
|
+
pdfBufferCache.set(filename, buffer);
|
|
45
|
+
console.log('[PDF-Secure] Cache: Stored', filename, '(', (buffer.byteLength / 1024 / 1024).toFixed(2), 'MB)');
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
// Listen for postMessage from iframe
|
|
31
49
|
window.addEventListener('message', function (event) {
|
|
32
50
|
// Security: Only accept messages from same origin
|
|
33
51
|
if (event.origin !== window.location.origin) return;
|
|
34
52
|
|
|
53
|
+
// PDF ready - resolve queue
|
|
35
54
|
if (event.data && event.data.type === 'pdf-secure-ready') {
|
|
36
55
|
console.log('[PDF-Secure] Queue: PDF ready -', event.data.filename);
|
|
37
56
|
if (currentResolver) {
|
|
@@ -39,6 +58,37 @@
|
|
|
39
58
|
currentResolver = null;
|
|
40
59
|
}
|
|
41
60
|
}
|
|
61
|
+
|
|
62
|
+
// PDF buffer from viewer - cache it
|
|
63
|
+
if (event.data && event.data.type === 'pdf-secure-buffer') {
|
|
64
|
+
const { filename, buffer } = event.data;
|
|
65
|
+
if (filename && buffer) {
|
|
66
|
+
setCachedBuffer(filename, buffer);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Viewer asking for cached buffer
|
|
71
|
+
if (event.data && event.data.type === 'pdf-secure-cache-request') {
|
|
72
|
+
const { filename } = event.data;
|
|
73
|
+
const cached = pdfBufferCache.get(filename);
|
|
74
|
+
if (cached && event.source) {
|
|
75
|
+
// Send cached buffer to viewer (transferable for 0-copy)
|
|
76
|
+
event.source.postMessage({
|
|
77
|
+
type: 'pdf-secure-cache-response',
|
|
78
|
+
filename: filename,
|
|
79
|
+
buffer: cached
|
|
80
|
+
}, event.origin, [cached.slice(0)]); // Clone buffer since we keep original
|
|
81
|
+
console.log('[PDF-Secure] Cache: Hit -', filename);
|
|
82
|
+
} else if (event.source) {
|
|
83
|
+
// No cache, viewer will fetch normally
|
|
84
|
+
event.source.postMessage({
|
|
85
|
+
type: 'pdf-secure-cache-response',
|
|
86
|
+
filename: filename,
|
|
87
|
+
buffer: null
|
|
88
|
+
}, event.origin);
|
|
89
|
+
console.log('[PDF-Secure] Cache: Miss -', filename);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
42
92
|
});
|
|
43
93
|
|
|
44
94
|
async function processQueue() {
|
|
@@ -139,24 +189,7 @@
|
|
|
139
189
|
title.appendChild(icon);
|
|
140
190
|
title.appendChild(nameSpan);
|
|
141
191
|
|
|
142
|
-
// Actions
|
|
143
|
-
var actions = document.createElement('div');
|
|
144
|
-
actions.style.cssText = 'display:flex;gap:8px;';
|
|
145
|
-
|
|
146
|
-
var fullscreenBtn = document.createElement('button');
|
|
147
|
-
fullscreenBtn.className = 'pdf-secure-fullscreen-btn';
|
|
148
|
-
fullscreenBtn.title = 'Tam Ekran';
|
|
149
|
-
fullscreenBtn.style.cssText = 'display:flex;align-items:center;justify-content:center;width:32px;height:32px;background:rgba(255,255,255,0.08);border:none;border-radius:6px;cursor:pointer;';
|
|
150
|
-
|
|
151
|
-
var fullscreenIcon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
|
|
152
|
-
fullscreenIcon.setAttribute('viewBox', '0 0 24 24');
|
|
153
|
-
fullscreenIcon.style.cssText = 'width:18px;height:18px;min-width:18px;max-width:18px;fill:#fff;';
|
|
154
|
-
fullscreenIcon.innerHTML = '<path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z"/>';
|
|
155
|
-
fullscreenBtn.appendChild(fullscreenIcon);
|
|
156
|
-
actions.appendChild(fullscreenBtn);
|
|
157
|
-
|
|
158
192
|
header.appendChild(title);
|
|
159
|
-
header.appendChild(actions);
|
|
160
193
|
container.appendChild(header);
|
|
161
194
|
|
|
162
195
|
// Body with loading placeholder
|
|
@@ -179,15 +212,6 @@
|
|
|
179
212
|
|
|
180
213
|
container.appendChild(iframeWrapper);
|
|
181
214
|
|
|
182
|
-
// Fullscreen handler
|
|
183
|
-
fullscreenBtn.addEventListener('click', function () {
|
|
184
|
-
var iframe = iframeWrapper.querySelector('iframe');
|
|
185
|
-
if (iframe) {
|
|
186
|
-
if (iframe.requestFullscreen) iframe.requestFullscreen();
|
|
187
|
-
else if (iframe.webkitRequestFullscreen) iframe.webkitRequestFullscreen();
|
|
188
|
-
}
|
|
189
|
-
});
|
|
190
|
-
|
|
191
215
|
targetElement.replaceWith(container);
|
|
192
216
|
|
|
193
217
|
// LAZY LOADING with Intersection Observer + Queue
|