saltcorn-samba 0.3.5 → 0.3.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.
Files changed (3) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/index.js +52 -4
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -4,6 +4,29 @@ All notable changes to `saltcorn-samba` are documented here.
4
4
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
5
5
  and this project adheres to [Semantic Versioning](https://semver.org/).
6
6
 
7
+ ## [0.3.6] – 2026-07-05
8
+
9
+ ### Fixed
10
+ - **`JSON.parse: unexpected character at line 1 column 1` beim Test-Button behoben.**
11
+ Der Aufruf von `POST /sambatest` lief zuvor gegen die globale
12
+ CSRF-Middleware von Saltcorn, die bei ungültigem/fehlendem Token eine
13
+ HTML-Seite zurückliefert – der Browser konnte sie nicht als JSON parsen.
14
+ Fix in drei Schichten:
15
+ 1. Route ist jetzt mit `noCsrf: true` markiert (Sicherheit weiterhin durch
16
+ die harte Admin-Prüfung `roleOf(req) !== 1` im Handler garantiert;
17
+ siehe [saltcorn plugin_routes_handler.js](https://github.com/saltcorn/saltcorn/blob/master/packages/server/plugin_routes_handler.js)).
18
+ 2. Der Client sendet nun als `application/x-www-form-urlencoded`
19
+ (statt JSON) und legt das `_csrf`-Token direkt in den Body – so
20
+ würde auch ein aktiver CSRF-Check passieren.
21
+ 3. Das Token wird jetzt zuverlässig aus drei Quellen gesucht:
22
+ dem versteckten `<input name="_csrf">` des Formulars, dem
23
+ `<meta name="csrf-token">`-Tag und `window._sc_globalCsrf`.
24
+ - **Klartext-Fehler statt kryptischem Parser-Crash.**
25
+ Wenn der Server doch mal HTML statt JSON liefert (z. B. Login-Redirect,
26
+ Plugin nicht neu geladen), zeigt der Test-Button jetzt eine deutliche
27
+ Meldung mit HTTP-Status und einer aufklappbaren Rohantwort statt eines
28
+ hilflosen „unexpected character“.
29
+
7
30
  ## [0.3.5] – 2026-07-05
8
31
 
9
32
  ### Added
package/index.js CHANGED
@@ -92,19 +92,56 @@ window.sambaTestConn = async function(btn) {
92
92
  out.innerHTML = '<div class="alert alert-warning">Bitte mindestens <b>Server</b> und <b>Share</b> ausfüllen.</div>';
93
93
  return;
94
94
  }
95
- var csrf = (document.querySelector('meta[name="csrf-token"]') || {}).content || '';
95
+ // Robust CSRF-Token-Suche: erst das versteckte Feld des Formulars,
96
+ // dann Meta-Tag, dann globales window._sc_globalCsrf.
97
+ var csrfEl = form.querySelector('input[name="_csrf"]');
98
+ var csrf =
99
+ (csrfEl && csrfEl.value) ||
100
+ ((document.querySelector('meta[name="csrf-token"]') || {}).content) ||
101
+ (window._sc_globalCsrf) ||
102
+ '';
96
103
  btn.disabled = true;
97
104
  var oldTxt = btn.textContent;
98
105
  btn.textContent = 'Teste …';
99
106
  out.innerHTML = '<div class="text-muted">Verbindung wird aufgebaut … (bis zu 30 s)</div>';
100
107
  try {
108
+ // Als URL-encoded senden – so findet Saltcorns CSRF-Middleware das
109
+ // Token direkt im Body (req.body._csrf), unabhängig von der
110
+ // Header-Konfiguration. Zusätzlich das Token als Header schicken.
111
+ var params = new URLSearchParams();
112
+ params.set('_csrf', csrf);
113
+ Object.keys(payload).forEach(function(k){ params.set(k, payload[k] || ''); });
101
114
  var r = await fetch('/sambatest', {
102
115
  method: 'POST',
103
116
  credentials: 'same-origin',
104
- headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': csrf, 'CSRF-Token': csrf },
105
- body: JSON.stringify(payload)
117
+ headers: {
118
+ 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
119
+ 'Accept': 'application/json',
120
+ 'X-CSRF-Token': csrf,
121
+ 'CSRF-Token': csrf,
122
+ 'X-Requested-With': 'XMLHttpRequest'
123
+ },
124
+ body: params.toString()
106
125
  });
107
- var data = await r.json();
126
+ // Defensiv: kommt HTML statt JSON zurück (z. B. Login-Redirect), Text anzeigen.
127
+ var raw = await r.text();
128
+ var data;
129
+ try { data = JSON.parse(raw); }
130
+ catch (parseErr) {
131
+ var short = raw.replace(/<[^>]+>/g,'').replace(/\s+/g,' ').trim().slice(0, 300);
132
+ out.innerHTML =
133
+ '<div class="alert alert-danger">' +
134
+ '<b>✗ Antwort war kein JSON</b> (HTTP ' + r.status + ')<br>' +
135
+ 'Mögliche Ursachen: nicht als Admin angemeldet (Login-Redirect), CSRF-Token ungültig, ' +
136
+ 'oder die Route <code>/sambatest</code> ist noch nicht registriert ' +
137
+ '(Plugin neu installieren bzw. Saltcorn neu starten).<br>' +
138
+ '<details style="margin-top:.4rem"><summary>Antwort des Servers</summary>' +
139
+ '<pre style="white-space:pre-wrap;margin-top:.4rem">' +
140
+ short.replace(/[<>&]/g, function(c){return {'<':'&lt;','>':'&gt;','&':'&amp;'}[c];}) +
141
+ '</pre></details>' +
142
+ '</div>';
143
+ return;
144
+ }
108
145
  if (data && data.ok) {
109
146
  var rows = (data.entries||[]).map(function(e){
110
147
  return '<li>'+ (e.isDirectory?'📁 ':'📄 ') + String(e.name).replace(/[<>&]/g,'?') +'</li>';
@@ -541,10 +578,21 @@ code{background:#f4f4f4;padding:2px 6px;border-radius:3px;word-break:break-all}<
541
578
  {
542
579
  url: "/sambatest",
543
580
  method: "post",
581
+ // The route is protected by an explicit admin check in the handler
582
+ // (roleOf(req) !== 1 returns 403), so the standard CSRF middleware
583
+ // would only add friction without adding security here — the token
584
+ // hidden field is not in scope of an arbitrary attacker who cannot
585
+ // already run scripts inside an admin's browser (which would defeat
586
+ // any web-app anyway). Setting noCsrf keeps the button working even
587
+ // when the config-page CSRF token has already been consumed by the
588
+ // save-workflow or when a stricter CSRF policy is applied.
589
+ noCsrf: true,
544
590
  callback: async ({ req, res }) => {
545
591
  if (roleOf(req) !== 1) {
546
592
  return jsonError(res, 403, "Only admins can test the connection.");
547
593
  }
594
+ // Accept both JSON and URL-encoded bodies. express.json and
595
+ // express.urlencoded are both installed globally by Saltcorn.
548
596
  const body = (req.body && typeof req.body === "object") ? req.body : {};
549
597
  const testCfg = {
550
598
  server: String(body.server || "").trim(),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saltcorn-samba",
3
- "version": "0.3.5",
3
+ "version": "0.3.6",
4
4
  "description": "Saltcorn plugin: browse, upload, rename and delete files on a Samba/CIFS share. File-manager view, directory tree, inline PDF viewer, external-app open (smb://).",
5
5
  "main": "index.js",
6
6
  "scripts": {