nodebb-plugin-pdf-secure 1.0.9 → 1.1.1

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 CHANGED
@@ -1,5 +1,7 @@
1
1
  'use strict';
2
2
 
3
+ const path = require('path');
4
+ const fs = require('fs');
3
5
  const meta = require.main.require('./src/meta');
4
6
  const groups = require.main.require('./src/groups');
5
7
  const routeHelpers = require.main.require('./src/routes/helpers');
@@ -26,6 +28,50 @@ plugin.init = async (params) => {
26
28
 
27
29
  // Admin page route
28
30
  routeHelpers.setupAdminPageRoute(router, '/admin/plugins/pdf-secure', controllers.renderAdminPage);
31
+
32
+ // Viewer page route (fullscreen Mozilla PDF.js viewer)
33
+ router.get('/plugins/pdf-secure/viewer', middleware.ensureLoggedIn, (req, res) => {
34
+ const { file } = req.query;
35
+ if (!file) {
36
+ return res.status(400).send('Missing file parameter');
37
+ }
38
+
39
+ // Sanitize filename
40
+ const safeName = path.basename(file);
41
+ if (!safeName || !safeName.toLowerCase().endsWith('.pdf')) {
42
+ return res.status(400).send('Invalid file');
43
+ }
44
+
45
+ // Serve the viewer template with security headers
46
+ res.set({
47
+ 'X-Frame-Options': 'SAMEORIGIN',
48
+ 'X-Content-Type-Options': 'nosniff',
49
+ 'Cache-Control': 'no-store, no-cache, must-revalidate, private',
50
+ });
51
+
52
+ // Read and send the viewer HTML
53
+ const viewerPath = path.join(__dirname, 'static', 'viewer.html');
54
+ fs.readFile(viewerPath, 'utf8', (err, html) => {
55
+ if (err) {
56
+ return res.status(500).send('Viewer not found');
57
+ }
58
+
59
+ // Inject the filename and config into the viewer
60
+ const injectedHtml = html
61
+ .replace('</head>', `
62
+ <script>
63
+ window.PDF_SECURE_CONFIG = {
64
+ filename: ${JSON.stringify(safeName)},
65
+ relativePath: ${JSON.stringify(req.app.get('relative_path') || '')},
66
+ csrfToken: ${JSON.stringify(req.csrfToken ? req.csrfToken() : '')}
67
+ };
68
+ </script>
69
+ </head>`)
70
+ .replace('id="uploadOverlay">', 'id="uploadOverlay" class="hidden">');
71
+
72
+ res.type('html').send(injectedHtml);
73
+ });
74
+ });
29
75
  };
30
76
 
31
77
  plugin.addRoutes = async ({ router, middleware, helpers }) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "nodebb-plugin-pdf-secure",
3
- "version": "1.0.9",
3
+ "version": "1.1.1",
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": {
@@ -2,22 +2,7 @@
2
2
 
3
3
  console.log('[PDF-Secure] main.js loaded');
4
4
 
5
- // Load PDF.js via inline <script type="module"> expose globally
6
- (function () {
7
- var base = (window.config ? config.relative_path : '') + '/plugins/nodebb-plugin-pdf-secure/static/lib';
8
- var s = document.createElement('script');
9
- s.type = 'module';
10
- s.textContent =
11
- 'import { getDocument, GlobalWorkerOptions } from "' + base + '/pdf.min.mjs";\n' +
12
- 'GlobalWorkerOptions.workerSrc = "' + base + '/pdf.worker.min.mjs";\n' +
13
- 'window.__pdfSecureLib = { getDocument: getDocument };\n' +
14
- 'window.dispatchEvent(new CustomEvent("pdf-secure-lib-ready"));\n' +
15
- 'console.log("[PDF-Secure] PDF.js library ready");';
16
- document.head.appendChild(s);
17
- console.log('[PDF-Secure] PDF.js module injected');
18
- })();
19
-
20
- // Main plugin logic
5
+ // Main plugin logic - PDF links become inline embedded viewers
21
6
  (async function () {
22
7
  try {
23
8
  var hooks = await app.require('hooks');
@@ -34,7 +19,7 @@ console.log('[PDF-Secure] main.js loaded');
34
19
  function interceptPdfLinks() {
35
20
  var postContents = document.querySelectorAll('[component="post/content"]');
36
21
 
37
- postContents.forEach(function (content, idx) {
22
+ postContents.forEach(function (content) {
38
23
  var pdfLinks = content.querySelectorAll('a[href$=".pdf"], a[href$=".PDF"]');
39
24
 
40
25
  pdfLinks.forEach(function (link) {
@@ -44,156 +29,55 @@ console.log('[PDF-Secure] main.js loaded');
44
29
  var href = link.getAttribute('href');
45
30
  var parts = href.split('/');
46
31
  var filename = parts[parts.length - 1];
47
- console.log('[PDF-Secure] Processing:', filename);
32
+ console.log('[PDF-Secure] Embedding:', filename);
48
33
 
34
+ // Create inline viewer container
49
35
  var container = document.createElement('div');
50
- container.className = 'pdf-secure-inline';
51
- container.innerHTML =
52
- '<div class="pdf-secure-toolbar">' +
53
- '<div class="pdf-secure-toolbar-left">' +
54
- '<svg class="pdf-secure-icon" viewBox="0 0 24 24"><path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z" fill="currentColor"/></svg>' +
55
- '<span class="pdf-secure-filename">' + escapeHtml(link.textContent || filename) + '</span>' +
56
- '</div>' +
57
- '<div class="pdf-secure-toolbar-right">' +
58
- '<span class="pdf-secure-pagecount"></span>' +
59
- '</div>' +
36
+ container.className = 'pdf-secure-embed';
37
+
38
+ // Header with filename
39
+ var header = document.createElement('div');
40
+ header.className = 'pdf-secure-embed-header';
41
+ header.innerHTML =
42
+ '<div class="pdf-secure-embed-title">' +
43
+ '<svg viewBox="0 0 24 24"><path d="M14 2H6c-1.1 0-2 .9-2 2v16c0 1.1.9 2 2 2h12c1.1 0 2-.9 2-2V8l-6-6zm4 18H6V4h7v5h5v11z" fill="currentColor"/></svg>' +
44
+ '<span>' + escapeHtml(link.textContent || filename) + '</span>' +
60
45
  '</div>' +
61
- '<div class="pdf-secure-viewer-area">' +
62
- '<div class="pdf-secure-loading">' +
63
- '<div class="pdf-secure-spinner"></div>' +
64
- '<span>Loading PDF...</span>' +
65
- '</div>' +
66
- '<div class="pdf-secure-error"></div>' +
67
- '<div class="pdf-secure-pages"></div>' +
46
+ '<div class="pdf-secure-embed-actions">' +
47
+ '<button class="pdf-secure-fullscreen-btn" title="Tam Ekran">' +
48
+ '<svg viewBox="0 0 24 24"><path d="M7 14H5v5h5v-2H7v-3zm-2-4h2V7h3V5H5v5zm12 7h-3v2h5v-5h-2v3zM14 5v2h3v3h2V5h-5z" fill="currentColor"/></svg>' +
49
+ '</button>' +
68
50
  '</div>';
69
-
70
- link.replaceWith(container);
71
- loadPdf(container, filename);
72
- });
73
- });
74
- }
75
-
76
- function getPdfLib() {
77
- if (window.__pdfSecureLib) return Promise.resolve(window.__pdfSecureLib);
78
- return new Promise(function (resolve) {
79
- window.addEventListener('pdf-secure-lib-ready', function () {
80
- resolve(window.__pdfSecureLib);
81
- }, { once: true });
82
- });
83
- }
84
-
85
- async function loadPdf(container, filename) {
86
- var loadingEl = container.querySelector('.pdf-secure-loading');
87
- var errorEl = container.querySelector('.pdf-secure-error');
88
- var pagesEl = container.querySelector('.pdf-secure-pages');
89
- var pagecountEl = container.querySelector('.pdf-secure-pagecount');
90
-
91
- function showError(msg) {
92
- console.error('[PDF-Secure] ERROR ' + filename + ':', msg);
93
- loadingEl.style.display = 'none';
94
- errorEl.style.display = 'flex';
95
- errorEl.textContent = msg;
96
- }
97
-
98
- try {
99
- // 1. Nonce
100
- var nonceRes = await fetch(
101
- config.relative_path + '/api/v3/plugins/pdf-secure/nonce?file=' + encodeURIComponent(filename),
102
- { credentials: 'same-origin', headers: { 'x-csrf-token': config.csrf_token } }
103
- );
104
- if (!nonceRes.ok) {
105
- showError(nonceRes.status === 401 ? 'Log in to view this PDF.' : 'Failed to load PDF (' + nonceRes.status + ')');
106
- return;
107
- }
108
- var result = await nonceRes.json();
109
- var nonce = result.response.nonce;
110
- console.log('[PDF-Secure] Nonce OK:', nonce);
111
-
112
- // 2. PDF binary
113
- var pdfRes = await fetch(
114
- config.relative_path + '/api/v3/plugins/pdf-secure/pdf-data?nonce=' + encodeURIComponent(nonce),
115
- { credentials: 'same-origin' }
116
- );
117
- if (!pdfRes.ok) { showError('Failed to load PDF data (' + pdfRes.status + ')'); return; }
118
- var pdfArrayBuffer = await pdfRes.arrayBuffer();
119
- console.log('[PDF-Secure] PDF loaded:', pdfArrayBuffer.byteLength, 'bytes');
120
-
121
- // 3. PDF.js
122
- var lib = await getPdfLib();
123
- if (!lib || !lib.getDocument) { showError('PDF.js library failed to load.'); return; }
124
-
125
- var pdfDoc = await lib.getDocument({ data: new Uint8Array(pdfArrayBuffer) }).promise;
126
- var totalPages = pdfDoc.numPages;
127
- console.log('[PDF-Secure] Pages:', totalPages);
128
-
129
- loadingEl.style.display = 'none';
130
- pagecountEl.textContent = totalPages + ' page' + (totalPages > 1 ? 's' : '');
131
-
132
- // Security
133
- container.addEventListener('contextmenu', function (e) { e.preventDefault(); });
134
- container.addEventListener('dragstart', function (e) { e.preventDefault(); });
135
- container.addEventListener('selectstart', function (e) { e.preventDefault(); });
136
-
137
- // 4. Render ALL pages
138
- var viewerArea = container.querySelector('.pdf-secure-viewer-area');
139
- var pageCanvases = [];
140
-
141
- for (var i = 1; i <= totalPages; i++) {
142
- var pageWrapper = document.createElement('div');
143
- pageWrapper.className = 'pdf-secure-page';
144
- var canvas = document.createElement('canvas');
145
- pageWrapper.appendChild(canvas);
146
- pagesEl.appendChild(pageWrapper);
147
- pageCanvases.push({ canvas: canvas, pageNum: i, rendered: false });
148
- }
149
-
150
- // Render visible pages (IntersectionObserver for performance)
151
- var observer = new IntersectionObserver(function (entries) {
152
- entries.forEach(function (entry) {
153
- if (entry.isIntersecting) {
154
- var idx = parseInt(entry.target.dataset.pageIdx, 10);
155
- var item = pageCanvases[idx];
156
- if (item && !item.rendered) {
157
- item.rendered = true;
158
- renderPage(pdfDoc, item.canvas, item.pageNum, viewerArea.clientWidth);
159
- }
51
+ container.appendChild(header);
52
+
53
+ // Iframe for viewer
54
+ var iframeWrapper = document.createElement('div');
55
+ iframeWrapper.className = 'pdf-secure-embed-body';
56
+
57
+ var iframe = document.createElement('iframe');
58
+ iframe.className = 'pdf-secure-iframe';
59
+ iframe.src = config.relative_path + '/plugins/pdf-secure/viewer?file=' + encodeURIComponent(filename);
60
+ iframe.setAttribute('frameborder', '0');
61
+ iframe.setAttribute('allowfullscreen', 'true');
62
+ iframe.setAttribute('loading', 'lazy');
63
+
64
+ iframeWrapper.appendChild(iframe);
65
+ container.appendChild(iframeWrapper);
66
+
67
+ // Fullscreen button handler
68
+ header.querySelector('.pdf-secure-fullscreen-btn').addEventListener('click', function () {
69
+ if (iframe.requestFullscreen) {
70
+ iframe.requestFullscreen();
71
+ } else if (iframe.webkitRequestFullscreen) {
72
+ iframe.webkitRequestFullscreen();
73
+ } else if (iframe.msRequestFullscreen) {
74
+ iframe.msRequestFullscreen();
160
75
  }
161
76
  });
162
- }, { root: viewerArea, rootMargin: '200px' });
163
77
 
164
- pageCanvases.forEach(function (item, idx) {
165
- item.canvas.parentElement.dataset.pageIdx = idx;
166
- observer.observe(item.canvas.parentElement);
78
+ link.replaceWith(container);
167
79
  });
168
-
169
- console.log('[PDF-Secure] DONE:', filename);
170
- } catch (err) {
171
- console.error('[PDF-Secure] CATCH:', err);
172
- showError('Failed to load PDF.');
173
- }
174
- }
175
-
176
- async function renderPage(pdfDoc, canvas, pageNum, containerWidth) {
177
- try {
178
- var page = await pdfDoc.getPage(pageNum);
179
- var vp = page.getViewport({ scale: 1 });
180
- // Use container width minus padding for scale
181
- var availableWidth = containerWidth - 40;
182
- var scale = Math.min(availableWidth / vp.width, 2.5);
183
- var scaled = page.getViewport({ scale: scale });
184
-
185
- canvas.width = scaled.width;
186
- canvas.height = scaled.height;
187
-
188
- await page.render({
189
- canvasContext: canvas.getContext('2d'),
190
- viewport: scaled,
191
- }).promise;
192
-
193
- console.log('[PDF-Secure] Rendered page', pageNum);
194
- } catch (err) {
195
- console.error('[PDF-Secure] Render error page ' + pageNum + ':', err);
196
- }
80
+ });
197
81
  }
198
82
 
199
83
  function escapeHtml(str) {
package/static/style.less CHANGED
@@ -1,169 +1,123 @@
1
- /* PDF Secure Viewer — Inline Preview (Edge-style dark theme) */
1
+ /* PDF Secure Viewer — Inline Embed Styles for NodeBB */
2
2
 
3
- .pdf-secure-inline {
4
- border-radius: 8px;
3
+ /* Embedded PDF Container */
4
+ .pdf-secure-embed {
5
+ margin: 16px 0;
6
+ border-radius: 12px;
5
7
  overflow: hidden;
6
- margin: 12px 0;
7
- max-width: 100%;
8
- user-select: none;
9
- -webkit-user-select: none;
10
- box-shadow: 0 2px 12px rgba(0, 0, 0, 0.25);
11
- border: 1px solid #404040;
8
+ background: #1f1f1f;
9
+ border: 1px solid rgba(255, 255, 255, 0.1);
10
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.25);
12
11
  }
13
12
 
14
- /* Toolbar — matches viewer.html */
15
- .pdf-secure-toolbar {
13
+ /* Header */
14
+ .pdf-secure-embed-header {
16
15
  display: flex;
17
16
  align-items: center;
18
17
  justify-content: space-between;
19
- padding: 0 12px;
20
- height: 42px;
21
- background: #2d2d2d;
22
- border-bottom: 1px solid #404040;
23
- color: #fff;
24
- font-family: "Segoe UI", system-ui, -apple-system, sans-serif;
25
- font-size: 13px;
26
- }
27
-
28
- .pdf-secure-toolbar-left {
29
- display: flex;
30
- align-items: center;
31
- gap: 8px;
32
- min-width: 0;
18
+ padding: 10px 16px;
19
+ background: linear-gradient(135deg, #2d2d2d 0%, #252525 100%);
20
+ border-bottom: 1px solid rgba(255, 255, 255, 0.08);
33
21
  }
34
22
 
35
- .pdf-secure-toolbar-right {
23
+ .pdf-secure-embed-title {
36
24
  display: flex;
37
25
  align-items: center;
38
- gap: 8px;
39
- flex-shrink: 0;
26
+ gap: 10px;
27
+ color: #fff;
28
+ font-size: 14px;
29
+ font-weight: 500;
40
30
  }
41
31
 
42
- .pdf-secure-icon {
43
- width: 18px;
44
- height: 18px;
45
- color: #a0a0a0;
32
+ .pdf-secure-embed-title svg {
33
+ width: 20px;
34
+ height: 20px;
35
+ fill: #e81224;
46
36
  flex-shrink: 0;
47
37
  }
48
38
 
49
- .pdf-secure-filename {
39
+ .pdf-secure-embed-title span {
50
40
  white-space: nowrap;
51
41
  overflow: hidden;
52
42
  text-overflow: ellipsis;
53
- font-weight: 500;
54
- }
55
-
56
- .pdf-secure-pagecount {
57
- color: #a0a0a0;
58
- font-size: 12px;
59
- white-space: nowrap;
43
+ max-width: 400px;
60
44
  }
61
45
 
62
- /* Viewer area — matches viewer.html #viewerContainer */
63
- .pdf-secure-viewer-area {
64
- background: #525659;
65
- max-height: 700px;
66
- overflow-y: auto;
67
- overflow-x: hidden;
68
- position: relative;
69
-
70
- /* Scrollbar styling */
71
- &::-webkit-scrollbar {
72
- width: 8px;
73
- }
74
- &::-webkit-scrollbar-track {
75
- background: #2d2d2d;
76
- }
77
- &::-webkit-scrollbar-thumb {
78
- background: #3d3d3d;
79
- border-radius: 4px;
80
- }
81
- &::-webkit-scrollbar-thumb:hover {
82
- background: #555;
83
- }
84
- }
85
-
86
- /* Each page — matches viewer.html .pdfViewer .page */
87
- .pdf-secure-page {
88
- margin: 8px auto;
89
- box-shadow: 0 2px 8px rgba(0, 0, 0, 0.3);
46
+ .pdf-secure-embed-actions {
90
47
  display: flex;
91
- justify-content: center;
92
- width: fit-content;
93
-
94
- canvas {
95
- display: block;
96
- max-width: 100%;
97
- pointer-events: none;
98
- }
99
- }
100
-
101
- /* Pages container */
102
- .pdf-secure-pages {
103
- padding: 4px 0;
48
+ gap: 8px;
104
49
  }
105
50
 
106
- /* Loading spinner */
107
- .pdf-secure-loading {
51
+ .pdf-secure-fullscreen-btn {
108
52
  display: flex;
109
- flex-direction: column;
110
53
  align-items: center;
111
54
  justify-content: center;
112
- gap: 12px;
113
- min-height: 300px;
114
- color: #a0a0a0;
115
- font-size: 14px;
116
- font-family: "Segoe UI", system-ui, sans-serif;
117
- }
118
-
119
- .pdf-secure-spinner {
120
55
  width: 32px;
121
56
  height: 32px;
122
- border: 3px solid #3d3d3d;
123
- border-top-color: #0078d4;
124
- border-radius: 50%;
125
- animation: pdf-secure-spin 0.8s linear infinite;
57
+ background: rgba(255, 255, 255, 0.08);
58
+ border: none;
59
+ border-radius: 6px;
60
+ cursor: pointer;
61
+ transition: all 0.2s;
126
62
  }
127
63
 
128
- @keyframes pdf-secure-spin {
129
- to { transform: rotate(360deg); }
64
+ .pdf-secure-fullscreen-btn:hover {
65
+ background: rgba(255, 255, 255, 0.15);
130
66
  }
131
67
 
132
- /* Error */
133
- .pdf-secure-error {
134
- display: none;
135
- align-items: center;
136
- justify-content: center;
137
- min-height: 200px;
138
- color: #e81224;
139
- font-size: 14px;
140
- text-align: center;
141
- padding: 20px;
142
- font-family: "Segoe UI", system-ui, sans-serif;
68
+ .pdf-secure-fullscreen-btn svg {
69
+ width: 18px;
70
+ height: 18px;
71
+ fill: #fff;
143
72
  }
144
73
 
145
- /* Anti-print */
146
- @media print {
147
- .pdf-secure-inline {
148
- display: none !important;
149
- }
74
+ /* Viewer Body */
75
+ .pdf-secure-embed-body {
76
+ position: relative;
77
+ width: 100%;
78
+ height: 600px;
79
+ background: #525659;
80
+ }
81
+
82
+ .pdf-secure-iframe {
83
+ width: 100%;
84
+ height: 100%;
85
+ border: none;
86
+ display: block;
150
87
  }
151
88
 
152
89
  /* Responsive */
153
90
  @media (max-width: 768px) {
154
- .pdf-secure-viewer-area {
155
- max-height: 500px;
91
+ .pdf-secure-embed-body {
92
+ height: 450px;
156
93
  }
157
94
 
158
- .pdf-secure-toolbar {
159
- height: 38px;
160
- padding: 0 8px;
161
- font-size: 12px;
95
+ .pdf-secure-embed-title span {
96
+ max-width: 200px;
162
97
  }
163
98
  }
164
99
 
165
100
  @media (max-width: 480px) {
166
- .pdf-secure-viewer-area {
167
- max-height: 400px;
101
+ .pdf-secure-embed-body {
102
+ height: 350px;
103
+ }
104
+
105
+ .pdf-secure-embed-header {
106
+ padding: 8px 12px;
107
+ }
108
+
109
+ .pdf-secure-embed-title {
110
+ font-size: 13px;
111
+ }
112
+
113
+ .pdf-secure-embed-title span {
114
+ max-width: 150px;
168
115
  }
169
116
  }
117
+
118
+ /* Anti-print */
119
+ @media print {
120
+ .pdf-secure-embed {
121
+ display: none !important;
122
+ }
123
+ }
@@ -40,6 +40,53 @@
40
40
  font-size: 14px;
41
41
  overflow: hidden;
42
42
  color: var(--text-primary);
43
+ /* Security: prevent text selection globally */
44
+ -webkit-user-select: none;
45
+ -moz-user-select: none;
46
+ -ms-user-select: none;
47
+ user-select: none;
48
+ }
49
+
50
+ /* Print Protection - hide everything when printing */
51
+ @media print {
52
+
53
+ html,
54
+ body,
55
+ #viewerContainer,
56
+ #viewer,
57
+ .pdfViewer,
58
+ .page {
59
+ display: none !important;
60
+ visibility: hidden !important;
61
+ }
62
+
63
+ body::before {
64
+ content: 'Bu içeriğin yazdırılması engellenmiştir.' !important;
65
+ display: block !important;
66
+ font-size: 24px;
67
+ padding: 50px;
68
+ text-align: center;
69
+ color: #666;
70
+ }
71
+ }
72
+
73
+ /* Loading Spinner Animation */
74
+ @keyframes spin {
75
+ from {
76
+ transform: rotate(0deg);
77
+ }
78
+
79
+ to {
80
+ transform: rotate(360deg);
81
+ }
82
+ }
83
+
84
+ .spin {
85
+ animation: spin 1s linear infinite;
86
+ }
87
+
88
+ .dropzone svg.spin {
89
+ fill: var(--accent);
43
90
  }
44
91
 
45
92
  /* Toolbar - Edge Style */
@@ -1357,6 +1404,90 @@
1357
1404
  generateThumbnails();
1358
1405
  }
1359
1406
 
1407
+ // Load PDF from ArrayBuffer (for secure nonce-based loading)
1408
+ async function loadPDFFromBuffer(arrayBuffer) {
1409
+ uploadOverlay.classList.add('hidden');
1410
+
1411
+ pdfDoc = await pdfjsLib.getDocument({ data: arrayBuffer }).promise;
1412
+
1413
+ pdfViewer.setDocument(pdfDoc);
1414
+ linkService.setDocument(pdfDoc);
1415
+
1416
+ ['zoomIn', 'zoomOut', 'pageInput', 'rotateLeft', 'rotateRight'].forEach(id => {
1417
+ document.getElementById(id).disabled = false;
1418
+ });
1419
+
1420
+ generateThumbnails();
1421
+ }
1422
+
1423
+ // Auto-load PDF if config is present (injected by NodeBB plugin)
1424
+ async function autoLoadSecurePDF() {
1425
+ if (!window.PDF_SECURE_CONFIG || !window.PDF_SECURE_CONFIG.filename) {
1426
+ console.log('[PDF-Secure] No config found, showing file picker');
1427
+ return;
1428
+ }
1429
+
1430
+ const config = window.PDF_SECURE_CONFIG;
1431
+ console.log('[PDF-Secure] Auto-loading:', config.filename);
1432
+
1433
+ // Show loading state
1434
+ const dropzone = document.getElementById('dropzone');
1435
+ if (dropzone) {
1436
+ dropzone.innerHTML = `
1437
+ <svg viewBox="0 0 24 24" class="spin">
1438
+ <path d="M12 4V2A10 10 0 0 0 2 12h2a8 8 0 0 1 8-8z" />
1439
+ </svg>
1440
+ <h2>PDF Yükleniyor...</h2>
1441
+ <p>${config.filename}</p>
1442
+ `;
1443
+ }
1444
+
1445
+ try {
1446
+ // Step 1: Get nonce
1447
+ const nonceUrl = config.relativePath + '/api/v3/plugins/pdf-secure/nonce?file=' + encodeURIComponent(config.filename);
1448
+ const nonceRes = await fetch(nonceUrl, {
1449
+ credentials: 'same-origin',
1450
+ headers: { 'x-csrf-token': config.csrfToken }
1451
+ });
1452
+
1453
+ if (!nonceRes.ok) {
1454
+ throw new Error(nonceRes.status === 401 ? 'Giriş yapmanız gerekiyor' : 'Nonce alınamadı');
1455
+ }
1456
+
1457
+ const nonceData = await nonceRes.json();
1458
+ const nonce = nonceData.response.nonce;
1459
+
1460
+ // Step 2: Fetch PDF binary
1461
+ const pdfUrl = config.relativePath + '/api/v3/plugins/pdf-secure/pdf-data?nonce=' + encodeURIComponent(nonce);
1462
+ const pdfRes = await fetch(pdfUrl, { credentials: 'same-origin' });
1463
+
1464
+ if (!pdfRes.ok) {
1465
+ throw new Error('PDF yüklenemedi (' + pdfRes.status + ')');
1466
+ }
1467
+
1468
+ const pdfBuffer = await pdfRes.arrayBuffer();
1469
+ console.log('[PDF-Secure] PDF loaded:', pdfBuffer.byteLength, 'bytes');
1470
+
1471
+ // Load into viewer
1472
+ await loadPDFFromBuffer(pdfBuffer);
1473
+
1474
+ } catch (err) {
1475
+ console.error('[PDF-Secure] Auto-load error:', err);
1476
+ if (dropzone) {
1477
+ dropzone.innerHTML = `
1478
+ <svg viewBox="0 0 24 24" style="fill: #e81224;">
1479
+ <path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"/>
1480
+ </svg>
1481
+ <h2>Hata</h2>
1482
+ <p>${err.message}</p>
1483
+ `;
1484
+ }
1485
+ }
1486
+ }
1487
+
1488
+ // Run auto-load on page ready
1489
+ autoLoadSecurePDF();
1490
+
1360
1491
  // Generate Thumbnails
1361
1492
  async function generateThumbnails() {
1362
1493
  thumbnailContainer.innerHTML = '';