nodebb-plugin-pdf-secure 1.2.25 → 1.2.26

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.
@@ -45,12 +45,8 @@ Controllers.servePdfBinary = async function (req, res) {
45
45
  }
46
46
 
47
47
  try {
48
- let pdfBuffer;
49
- if (data.isPremium) {
50
- pdfBuffer = await pdfHandler.getFullPdf(data.file);
51
- } else {
52
- pdfBuffer = await pdfHandler.getSinglePagePdf(data.file);
53
- }
48
+ // Always send full PDF - page restriction is handled client-side
49
+ const pdfBuffer = await pdfHandler.getFullPdf(data.file);
54
50
 
55
51
  // Apply partial XOR encryption with dynamic key from nonce
56
52
  const encodedBuffer = partialXorEncode(pdfBuffer, data.xorKey);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-pdf-secure",
3
- "version": "1.2.25",
3
+ "version": "1.2.26",
4
4
  "description": "Secure PDF viewer plugin for NodeBB - prevents downloading, enables canvas-only rendering with Premium group support",
5
5
  "main": "library.js",
6
6
  "repository": {
@@ -2262,7 +2262,7 @@
2262
2262
  }
2263
2263
 
2264
2264
  function resetOverlayCSS(overlay) {
2265
- if (!isOverlayTampered(overlay)) return; // Skip if already correct (prevents observer loop)
2265
+ if (!isOverlayTampered(overlay)) return;
2266
2266
  overlay.style.cssText = 'position:absolute;top:0;left:0;right:0;bottom:0;display:flex;z-index:15;opacity:1;visibility:visible;pointer-events:auto;';
2267
2267
  }
2268
2268
 
@@ -2271,15 +2271,12 @@
2271
2271
  pages.forEach(function (page) {
2272
2272
  var pageNum = parseInt(page.dataset.pageNumber || '0', 10);
2273
2273
  if (pageNum > 1) {
2274
- // Ensure page is visible (undo any old display:none)
2275
2274
  if (page.style.display === 'none') {
2276
2275
  page.style.display = '';
2277
2276
  }
2278
2277
  injectPageLock(page);
2279
- // CSS integrity: reset overlay styles in case of tampering
2280
2278
  var existing = page.querySelector('.page-lock-overlay');
2281
2279
  if (existing) resetOverlayCSS(existing);
2282
- // Ensure blur class is present
2283
2280
  if (!page.classList.contains('page-locked-blur')) {
2284
2281
  page.classList.add('page-locked-blur');
2285
2282
  }
@@ -2326,13 +2323,11 @@
2326
2323
  for (var i = 0; i < mutations.length; i++) {
2327
2324
  var target = mutations[i].target;
2328
2325
  if (!target || !target.classList) continue;
2329
- // Overlay CSS tampered - reset only if values actually differ
2330
2326
  if (target.classList.contains('page-lock-overlay')) {
2331
2327
  if (isOverlayTampered(target)) {
2332
2328
  resetOverlayCSS(target);
2333
2329
  }
2334
2330
  }
2335
- // Blur class removed from locked page - re-add it
2336
2331
  if (target.classList.contains('page') && !target.classList.contains('page-locked-blur')) {
2337
2332
  var pageNum = parseInt(target.dataset.pageNumber || '0', 10);
2338
2333
  if (pageNum > 1) {
@@ -2343,6 +2338,47 @@
2343
2338
  }).observe(viewerEl, { subtree: true, attributes: true, attributeFilter: ['style', 'class'] });
2344
2339
  }
2345
2340
 
2341
+ // ============================================
2342
+ // LITE MODE: Hide all tools except fullscreen and zoom
2343
+ // Lite users can view full PDF but cannot use annotations,
2344
+ // sidebar, rotate, sepia, overflow menu, etc.
2345
+ // ============================================
2346
+ function applyLiteMode() {
2347
+ // Hide sidebar button
2348
+ var sidebarBtn = document.getElementById('sidebarBtn');
2349
+ if (sidebarBtn) sidebarBtn.style.display = 'none';
2350
+
2351
+ // Close sidebar if open
2352
+ var sidebarEl = document.getElementById('sidebar');
2353
+ if (sidebarEl) sidebarEl.classList.remove('open');
2354
+
2355
+ // Hide entire annotation tools group (highlight, draw, eraser, select, undo/redo, text, shapes)
2356
+ var annotationGroup = document.querySelector('#toolbar > .toolbarGroup:nth-child(3)');
2357
+ if (annotationGroup) annotationGroup.style.display = 'none';
2358
+
2359
+ // In the zoom/utility group, hide everything except zoomIn and zoomOut
2360
+ var keepIds = new Set(['zoomIn', 'zoomOut']);
2361
+ var utilityGroup = document.querySelector('#toolbar > .toolbarGroup:nth-child(5)');
2362
+ if (utilityGroup) {
2363
+ Array.from(utilityGroup.children).forEach(function (child) {
2364
+ if (!keepIds.has(child.id)) {
2365
+ child.style.display = 'none';
2366
+ }
2367
+ });
2368
+ }
2369
+
2370
+ // Hide bottom toolbar annotation tools (mobile), keep only fullscreen button
2371
+ var bottomToolbarInner = document.getElementById('bottomToolbarInner');
2372
+ if (bottomToolbarInner) bottomToolbarInner.style.display = 'none';
2373
+
2374
+ // Hide all top-level separators between groups
2375
+ document.querySelectorAll('#toolbar > .separator').forEach(function (sep) {
2376
+ sep.style.display = 'none';
2377
+ });
2378
+
2379
+ console.log('[PDF-Secure] Lite mode applied - restricted toolbar');
2380
+ }
2381
+
2346
2382
  // Auto-load PDF if config is present (injected by NodeBB plugin)
2347
2383
  async function autoLoadSecurePDF() {
2348
2384
  if (!_cfg || !_cfg.filename) {
@@ -2423,7 +2459,7 @@
2423
2459
  }
2424
2460
 
2425
2461
  // Send buffer to parent for caching (premium only - non-premium must not leak decoded buffer)
2426
- if (_cfg.isPremium !== false && window.parent && window.parent !== window) {
2462
+ if ((_cfg.isPremium !== false || _cfg.isLite) && window.parent && window.parent !== window) {
2427
2463
  // Clone buffer for parent (we keep original)
2428
2464
  const bufferCopy = pdfBuffer.slice(0);
2429
2465
  window.parent.postMessage({
@@ -2439,8 +2475,8 @@
2439
2475
  // Step 4: Load into viewer
2440
2476
  await loadPDFFromBuffer(pdfBuffer);
2441
2477
 
2442
- // Premium Gate: Client-side page restriction for non-premium users
2443
- if (config.isPremium === false && pdfDoc && pdfDoc.numPages > 1) {
2478
+ // Premium Gate: Client-side page restriction for non-premium, non-lite users
2479
+ if (config.isPremium === false && !config.isLite && pdfDoc && pdfDoc.numPages > 1) {
2444
2480
  premiumInfo = Object.freeze({ isPremium: false, totalPages: pdfDoc.numPages });
2445
2481
  applyPageLocks();
2446
2482
  startPeriodicCheck();
@@ -2449,6 +2485,11 @@
2449
2485
  premiumInfo = Object.freeze({ isPremium: true, totalPages: pdfDoc ? pdfDoc.numPages : 1 });
2450
2486
  }
2451
2487
 
2488
+ // Lite Mode: Full PDF access but restricted toolbar
2489
+ if (config.isLite) {
2490
+ applyLiteMode();
2491
+ }
2492
+
2452
2493
  // Step 5: Moved to pagerendered event for proper timing
2453
2494
 
2454
2495
  // Step 6: Security - clear references to prevent extraction