nodebb-plugin-pdf-secure 1.2.1 → 1.2.3

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-pdf-secure",
3
- "version": "1.2.1",
3
+ "version": "1.2.3",
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": {
@@ -1,15 +1,11 @@
1
1
  'use strict';
2
2
 
3
- console.log('[PDF-Secure] main.js loaded');
4
-
5
- // Main plugin logic - PDF links become inline embedded viewers
3
+ // Main plugin logic - PDF links become inline embedded viewers with lazy loading
6
4
  (async function () {
7
5
  try {
8
6
  var hooks = await app.require('hooks');
9
- console.log('[PDF-Secure] Hooks loaded');
10
7
 
11
8
  hooks.on('action:ajaxify.end', function () {
12
- console.log('[PDF-Secure] ajaxify.end');
13
9
  interceptPdfLinks();
14
10
  });
15
11
  } catch (err) {
@@ -29,14 +25,13 @@ console.log('[PDF-Secure] main.js loaded');
29
25
  var href = link.getAttribute('href');
30
26
  var parts = href.split('/');
31
27
  var filename = parts[parts.length - 1];
32
- console.log('[PDF-Secure] Embedding:', filename);
33
28
 
34
- // Create inline viewer container with INLINE STYLES to ensure they work
29
+ // Create container with loading placeholder
35
30
  var container = document.createElement('div');
36
31
  container.className = 'pdf-secure-embed';
37
32
  container.style.cssText = 'margin:16px 0;border-radius:12px;overflow:hidden;background:#1f1f1f;border:1px solid rgba(255,255,255,0.1);box-shadow:0 4px 20px rgba(0,0,0,0.25);';
38
33
 
39
- // Header with filename - ALL INLINE STYLES
34
+ // Header
40
35
  var header = document.createElement('div');
41
36
  header.className = 'pdf-secure-embed-header';
42
37
  header.style.cssText = 'display:flex;align-items:center;justify-content:space-between;padding:10px 16px;background:linear-gradient(135deg,#2d2d2d 0%,#252525 100%);border-bottom:1px solid rgba(255,255,255,0.08);';
@@ -45,7 +40,6 @@ console.log('[PDF-Secure] main.js loaded');
45
40
  title.className = 'pdf-secure-embed-title';
46
41
  title.style.cssText = 'display:flex;align-items:center;gap:10px;color:#fff;font-size:14px;font-weight:500;';
47
42
 
48
- // PDF icon with INLINE SIZE
49
43
  var icon = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
50
44
  icon.setAttribute('viewBox', '0 0 24 24');
51
45
  icon.style.cssText = 'width:20px;height:20px;min-width:20px;max-width:20px;fill:#e81224;flex-shrink:0;';
@@ -58,7 +52,7 @@ console.log('[PDF-Secure] main.js loaded');
58
52
  title.appendChild(icon);
59
53
  title.appendChild(nameSpan);
60
54
 
61
- // Actions (fullscreen button)
55
+ // Actions
62
56
  var actions = document.createElement('div');
63
57
  actions.style.cssText = 'display:flex;gap:8px;';
64
58
 
@@ -78,35 +72,72 @@ console.log('[PDF-Secure] main.js loaded');
78
72
  header.appendChild(actions);
79
73
  container.appendChild(header);
80
74
 
81
- // Iframe wrapper
75
+ // Body with loading placeholder
82
76
  var iframeWrapper = document.createElement('div');
83
77
  iframeWrapper.className = 'pdf-secure-embed-body';
84
78
  iframeWrapper.style.cssText = 'position:relative;width:100%;height:600px;background:#525659;';
85
79
 
86
- var iframe = document.createElement('iframe');
87
- iframe.className = 'pdf-secure-iframe';
88
- iframe.style.cssText = 'width:100%;height:100%;border:none;display:block;';
89
- iframe.src = config.relative_path + '/plugins/pdf-secure/viewer?file=' + encodeURIComponent(filename);
90
- iframe.setAttribute('frameborder', '0');
91
- iframe.setAttribute('allowfullscreen', 'true');
92
- iframe.setAttribute('loading', 'lazy');
80
+ // Loading placeholder
81
+ var loadingPlaceholder = document.createElement('div');
82
+ loadingPlaceholder.className = 'pdf-loading-placeholder';
83
+ loadingPlaceholder.style.cssText = 'position:absolute;top:0;left:0;right:0;bottom:0;display:flex;flex-direction:column;align-items:center;justify-content:center;background:#2d2d2d;color:#fff;gap:16px;';
84
+ loadingPlaceholder.innerHTML = `
85
+ <svg viewBox="0 0 24 24" style="width:48px;height:48px;fill:#0078d4;animation:spin 1s linear infinite;">
86
+ <path d="M12 4V2A10 10 0 0 0 2 12h2a8 8 0 0 1 8-8z"/>
87
+ </svg>
88
+ <div style="font-size:14px;color:#a0a0a0;">PDF Yükleniyor...</div>
89
+ <style>@keyframes spin{from{transform:rotate(0deg)}to{transform:rotate(360deg)}}</style>
90
+ `;
91
+ iframeWrapper.appendChild(loadingPlaceholder);
93
92
 
94
- iframeWrapper.appendChild(iframe);
95
93
  container.appendChild(iframeWrapper);
96
94
 
97
- // Fullscreen button handler
95
+ // Fullscreen handler
98
96
  fullscreenBtn.addEventListener('click', function () {
99
- if (iframe.requestFullscreen) {
100
- iframe.requestFullscreen();
101
- } else if (iframe.webkitRequestFullscreen) {
102
- iframe.webkitRequestFullscreen();
103
- } else if (iframe.msRequestFullscreen) {
104
- iframe.msRequestFullscreen();
97
+ var iframe = iframeWrapper.querySelector('iframe');
98
+ if (iframe) {
99
+ if (iframe.requestFullscreen) iframe.requestFullscreen();
100
+ else if (iframe.webkitRequestFullscreen) iframe.webkitRequestFullscreen();
105
101
  }
106
102
  });
107
103
 
108
104
  link.replaceWith(container);
105
+
106
+ // LAZY LOADING with Intersection Observer
107
+ var observer = new IntersectionObserver(function (entries) {
108
+ entries.forEach(function (entry) {
109
+ if (entry.isIntersecting) {
110
+ // Load iframe only when visible
111
+ loadPdfIframe(iframeWrapper, filename, loadingPlaceholder);
112
+ observer.disconnect();
113
+ }
114
+ });
115
+ }, {
116
+ rootMargin: '200px', // Start loading 200px before visible
117
+ threshold: 0
118
+ });
119
+
120
+ observer.observe(container);
109
121
  });
110
122
  });
111
123
  }
124
+
125
+ function loadPdfIframe(wrapper, filename, placeholder) {
126
+ var iframe = document.createElement('iframe');
127
+ iframe.className = 'pdf-secure-iframe';
128
+ iframe.style.cssText = 'width:100%;height:100%;border:none;display:block;opacity:0;transition:opacity 0.3s;';
129
+ iframe.src = config.relative_path + '/plugins/pdf-secure/viewer?file=' + encodeURIComponent(filename);
130
+ iframe.setAttribute('frameborder', '0');
131
+ iframe.setAttribute('allowfullscreen', 'true');
132
+
133
+ // When iframe loads, fade in and remove placeholder
134
+ iframe.onload = function () {
135
+ iframe.style.opacity = '1';
136
+ if (placeholder && placeholder.parentNode) {
137
+ placeholder.remove();
138
+ }
139
+ };
140
+
141
+ wrapper.appendChild(iframe);
142
+ }
112
143
  })();
@@ -3143,14 +3143,10 @@
3143
3143
  }
3144
3144
  }, true);
3145
3145
 
3146
- // 2. Block context menu (right-click)
3146
+ // 2. Block context menu (right-click) - EVERYWHERE
3147
3147
  document.addEventListener('contextmenu', function (e) {
3148
- // Allow our custom context menu for annotations
3149
- if (e.target.closest('.annotationLayer') || e.target.closest('.pdfViewer')) {
3150
- // Keep custom context menu behavior
3151
- return;
3152
- }
3153
3148
  e.preventDefault();
3149
+ e.stopPropagation();
3154
3150
  return false;
3155
3151
  }, true);
3156
3152
 
@@ -3172,41 +3168,14 @@
3172
3168
  return false;
3173
3169
  }, true);
3174
3170
 
3175
- // 5. DevTools detection (basic)
3176
- let devToolsOpen = false;
3177
- const threshold = 160;
3178
-
3179
- function checkDevTools() {
3180
- const widthThreshold = window.outerWidth - window.innerWidth > threshold;
3181
- const heightThreshold = window.outerHeight - window.innerHeight > threshold;
3182
-
3183
- if (widthThreshold || heightThreshold) {
3184
- if (!devToolsOpen) {
3185
- devToolsOpen = true;
3186
- console.log('[Security] DevTools detected');
3187
- // Optional: blur content when devtools open
3188
- document.body.classList.add('devtools-open');
3189
- }
3190
- } else {
3191
- if (devToolsOpen) {
3192
- devToolsOpen = false;
3193
- document.body.classList.remove('devtools-open');
3194
- }
3195
- }
3196
- }
3197
-
3198
- // Check periodically
3199
- setInterval(checkDevTools, 1000);
3200
- window.addEventListener('resize', checkDevTools);
3201
-
3202
- // 6. Block Print via window.print override
3171
+ // 5. Block Print via window.print override
3203
3172
  window.print = function () {
3204
3173
  console.log('[Security] Print function blocked');
3205
3174
  alert('Yazdırma bu belgede engellenmiştir.');
3206
3175
  return false;
3207
3176
  };
3208
3177
 
3209
- // 7. Disable beforeprint event
3178
+ // 6. Disable beforeprint event
3210
3179
  window.addEventListener('beforeprint', function (e) {
3211
3180
  e.preventDefault();
3212
3181
  document.body.style.display = 'none';
@@ -3216,7 +3185,7 @@
3216
3185
  document.body.style.display = '';
3217
3186
  });
3218
3187
 
3219
- // 8. Block screenshot keyboard shortcuts
3188
+ // 7. Block screenshot keyboard shortcuts
3220
3189
  document.addEventListener('keyup', function (e) {
3221
3190
  // PrintScreen key
3222
3191
  if (e.key === 'PrintScreen') {
@@ -3225,10 +3194,9 @@
3225
3194
  }
3226
3195
  }, true);
3227
3196
 
3228
- // 9. Visibility change detection (tab switching for screenshots)
3197
+ // 8. Visibility change detection (tab switching for screenshots)
3229
3198
  document.addEventListener('visibilitychange', function () {
3230
3199
  if (document.hidden) {
3231
- // User switched tabs - could be for screenshot tools
3232
3200
  console.log('[Security] Tab hidden');
3233
3201
  }
3234
3202
  });
@@ -3236,30 +3204,6 @@
3236
3204
  console.log('[Security] All protection features initialized');
3237
3205
  })();
3238
3206
  </script>
3239
-
3240
- <!-- Security CSS for DevTools detection -->
3241
- <style>
3242
- .devtools-open #viewerContainer,
3243
- .devtools-open #viewer,
3244
- .devtools-open .pdfViewer {
3245
- filter: blur(20px) !important;
3246
- pointer-events: none !important;
3247
- }
3248
-
3249
- .devtools-open::after {
3250
- content: 'Geliştirici araçları açıkken içerik görüntülenemez.';
3251
- position: fixed;
3252
- top: 50%;
3253
- left: 50%;
3254
- transform: translate(-50%, -50%);
3255
- background: rgba(0, 0, 0, 0.9);
3256
- color: #fff;
3257
- padding: 30px 50px;
3258
- border-radius: 10px;
3259
- font-size: 18px;
3260
- z-index: 99999;
3261
- }
3262
- </style>
3263
3207
  </body>
3264
3208
 
3265
3209
  </html>