saltcorn-samba 0.3.8 → 0.3.10

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/CHANGELOG.md CHANGED
@@ -4,6 +4,110 @@ 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.10] – 2026-07-05
8
+
9
+ ### Fixed – **DNS-Fehler: `getaddrinfo ENOTFOUND "host:445"`**
10
+
11
+ Nachdem 0.3.9 den Callback-Signatur-Bug behoben hatte und der Test-Button
12
+ endlich echt gegen den SMB-Server lief, kam bei der Verbindung ein neuer
13
+ Fehler zum Vorschein:
14
+
15
+ ```
16
+ getaddrinfo ENOTFOUND 192.168.110.10:445 (ENOTFOUND)
17
+ ```
18
+
19
+ **Ursache:** In `smb-client.js` wurde der UNC-Share-String so gebaut:
20
+
21
+ ```js
22
+ const shareStr = `\\\\${server}${port ? ":" + port : ""}\\${share}`;
23
+ // => "\\\\192.168.110.10:445\\buero"
24
+ ```
25
+
26
+ `@marsaud/smb2` interpretiert alles zwischen den führenden `\\` und dem
27
+ nächsten `\` als **Hostnamen** und reicht das direkt an
28
+ `net.connect()` / `dns.lookup()` weiter. Node versucht dann
29
+ `"192.168.110.10:445"` als Hostnamen aufzulösen — was natürlich
30
+ fehlschlägt.
31
+
32
+ **Fix:** Host und Port sauber trennen.
33
+
34
+ - Der `share`-UNC-Pfad enthält jetzt **nur den Host**:
35
+ `\\192.168.110.10\buero`
36
+ - Der Port wird über die separate `port`-Option an `SMB2` übergeben
37
+ (Default 445).
38
+ - Zusätzlich tolerant: falls jemand versehentlich `host:445` ins
39
+ Server-Feld einträgt, wird der Port dort herausgezogen.
40
+ - IPv6-Adressen in eckigen Klammern (`[::1]:445`) werden unterstützt.
41
+
42
+ ### Notes
43
+ - Keine Konfig-Migration nötig. Wer bisher Host **ohne** Port eingetragen
44
+ hat, bekommt jetzt genau die gleiche Verbindung wie vorher — nur
45
+ funktionierend.
46
+ - Wer aus Verzweiflung `IP:445` ins Server-Feld getippt hatte: das wird
47
+ jetzt automatisch aufgesplittet. Sauberer ist trotzdem: Host im
48
+ Server-Feld, Port im Port-Feld.
49
+
50
+ ## [0.3.9] – 2026-07-05
51
+
52
+ ### Fixed – **Root-Cause-Fix: Falsche Callback-Signatur in allen Routen**
53
+
54
+ Die Diagnose-Ausgabe aus 0.3.8 hat gezeigt, dass in den Route-Handlern
55
+ **alle** Felder von `req` leer waren (`has_req_user: false`,
56
+ `has_session: false`, `referer: null` usw.). Ursache war eine falsche
57
+ Callback-Signatur, die seit 0.1 in **allen 8 Routen** verwendet wurde.
58
+
59
+ Saltcorn registriert Plugin-Routen so
60
+ (`packages/server/plugin_routes_handler.js`, Zeilen 40–52):
61
+
62
+ ```js
63
+ tenantRouter.post(url, error_catcher(route.callback));
64
+ ```
65
+
66
+ und `error_catcher` ist definiert als
67
+ (`packages/server/routes/utils.ts`, Zeile 427):
68
+
69
+ ```js
70
+ const error_catcher = (fn) => (request, response, next) => {
71
+ ...; fn(request, response, next);
72
+ };
73
+ ```
74
+
75
+ Die Callbacks werden also mit der klassischen Express-Signatur
76
+ `(req, res, next)` aufgerufen — **nicht** mit einem Objekt `{ req, res }`.
77
+
78
+ Bisher stand in `index.js` überall:
79
+
80
+ ```js
81
+ callback: async ({ req, res }) => { ... }
82
+ ```
83
+
84
+ Dadurch wurde aus dem echten Express-`request`-Objekt versucht, `req.req`
85
+ und `req.res` per Destructuring zu holen — beides `undefined`. Effekt:
86
+
87
+ - `req.user`, `req.session`, `req.headers`, `req.body`, `req.query`,
88
+ `req.csrfToken()` waren alle unerreichbar.
89
+ - Der Admin-Check konnte niemals erfolgreich sein.
90
+ - Der Samba-Verbindungstest hat *nie* funktioniert.
91
+ - Datei-Listing, Upload, Rename, Delete, Mkdir waren ebenfalls betroffen.
92
+
93
+ **Fix:** Alle 8 Routen (`/sambadir`, `/sambafile`, `/sambalink`,
94
+ `/sambatest`, `/sambaupload`, `/sambadelete`, `/sambarename`,
95
+ `/sambamkdir`) auf die korrekte Signatur umgestellt:
96
+
97
+ ```js
98
+ callback: async (req, res) => { ... }
99
+ ```
100
+
101
+ Damit erhält jeder Handler das echte Express-`req`-Objekt mit
102
+ `req.user`, `req.session`, `req.headers`, `req.body`, `req.csrfToken()`,
103
+ usw. — und die gesamte Admin- und Berechtigungslogik aus 0.3.7/0.3.8
104
+ greift jetzt so, wie sie gedacht war.
105
+
106
+ ### Notes
107
+ - Kein Funktionsverlust, keine Konfig-Migration nötig.
108
+ - Wer 0.3.8 installiert hat und den Test-Button nicht zum Laufen bekommen
109
+ hat: **Update auf 0.3.9 einspielen, Server neu starten, erneut testen.**
110
+
7
111
  ## [0.3.8] – 2026-07-05
8
112
 
9
113
  ### Changed
package/index.js CHANGED
@@ -480,7 +480,7 @@ const routes = [
480
480
  {
481
481
  url: "/sambadir",
482
482
  method: "get",
483
- callback: async ({ req, res }) => {
483
+ callback: async (req, res) => {
484
484
  const cfg = getConfig();
485
485
  if (!cfg.server) return jsonError(res, 500, "Samba plugin not configured");
486
486
  if (!canRead(req, cfg)) return jsonError(res, 403, "Forbidden");
@@ -528,7 +528,7 @@ const routes = [
528
528
  {
529
529
  url: "/sambafile",
530
530
  method: "get",
531
- callback: async ({ req, res }) => {
531
+ callback: async (req, res) => {
532
532
  const cfg = getConfig();
533
533
  if (!cfg.server) return res.status(500).send("Samba plugin not configured");
534
534
  if (!canRead(req, cfg)) return res.status(403).send("Forbidden");
@@ -561,7 +561,7 @@ const routes = [
561
561
  {
562
562
  url: "/sambalink",
563
563
  method: "get",
564
- callback: async ({ req, res }) => {
564
+ callback: async (req, res) => {
565
565
  const cfg = getConfig();
566
566
  if (!cfg.server) return res.status(500).send("Samba plugin not configured");
567
567
  if (!canRead(req, cfg)) return res.status(403).send("Forbidden");
@@ -617,7 +617,7 @@ code{background:#f4f4f4;padding:2px 6px;border-radius:3px;word-break:break-all}<
617
617
  // when the config-page CSRF token has already been consumed by the
618
618
  // save-workflow or when a stricter CSRF policy is applied.
619
619
  noCsrf: true,
620
- callback: async ({ req, res }) => {
620
+ callback: async (req, res) => {
621
621
  // -----------------------------------------------------------------
622
622
  // Admin gate — komplett neu in 0.3.8:
623
623
  //
@@ -822,7 +822,7 @@ code{background:#f4f4f4;padding:2px 6px;border-radius:3px;word-break:break-all}<
822
822
  {
823
823
  url: "/sambaupload",
824
824
  method: "post",
825
- callback: async ({ req, res }) => {
825
+ callback: async (req, res) => {
826
826
  const cfg = getConfig();
827
827
  if (!cfg.server) return jsonError(res, 500, "Samba plugin not configured");
828
828
  if (!canWrite(req, cfg)) return jsonError(res, 403, "Forbidden");
@@ -893,7 +893,7 @@ code{background:#f4f4f4;padding:2px 6px;border-radius:3px;word-break:break-all}<
893
893
  {
894
894
  url: "/sambadelete",
895
895
  method: "post",
896
- callback: async ({ req, res }) => {
896
+ callback: async (req, res) => {
897
897
  const cfg = getConfig();
898
898
  if (!cfg.server) return jsonError(res, 500, "Samba plugin not configured");
899
899
  if (!canWrite(req, cfg)) return jsonError(res, 403, "Forbidden");
@@ -924,7 +924,7 @@ code{background:#f4f4f4;padding:2px 6px;border-radius:3px;word-break:break-all}<
924
924
  {
925
925
  url: "/sambarename",
926
926
  method: "post",
927
- callback: async ({ req, res }) => {
927
+ callback: async (req, res) => {
928
928
  const cfg = getConfig();
929
929
  if (!cfg.server) return jsonError(res, 500, "Samba plugin not configured");
930
930
  if (!canWrite(req, cfg)) return jsonError(res, 403, "Forbidden");
@@ -987,7 +987,7 @@ code{background:#f4f4f4;padding:2px 6px;border-radius:3px;word-break:break-all}<
987
987
  {
988
988
  url: "/sambamkdir",
989
989
  method: "post",
990
- callback: async ({ req, res }) => {
990
+ callback: async (req, res) => {
991
991
  const cfg = getConfig();
992
992
  if (!cfg.server) return jsonError(res, 500, "Samba plugin not configured");
993
993
  if (!canWrite(req, cfg)) return jsonError(res, 403, "Forbidden");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "saltcorn-samba",
3
- "version": "0.3.8",
3
+ "version": "0.3.10",
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": {
package/smb-client.js CHANGED
@@ -116,13 +116,41 @@ function buildClient(config) {
116
116
  if (!share) throw new Error("Samba: share missing");
117
117
  if (/[\\/]/.test(share)) throw new Error("Samba: share must not contain slashes");
118
118
 
119
- const shareStr = `\\\\${server}${port ? ":" + port : ""}\\${share}`;
119
+ // Host und Port sauber trennen. Der Server-String darf NICHT im share-UNC-
120
+ // Pfad landen, sonst versucht Node's DNS "host:port" als Hostnamen aufzulösen
121
+ // (getaddrinfo ENOTFOUND "1.2.3.4:445"). @marsaud/smb2 nimmt den Port über
122
+ // die separate `port`-Option entgegen; der share-String enthält nur den Host.
123
+ //
124
+ // Zusätzlich tolerant sein, falls jemand versehentlich "host:445" ins
125
+ // Server-Feld getippt hat — dann Port dort rausziehen.
126
+ let hostOnly = String(server).trim();
127
+ let portFromServer;
128
+ // IPv6-Adressen in eckigen Klammern zulassen: [::1]:445
129
+ const v6 = hostOnly.match(/^\[([^\]]+)\](?::(\d+))?$/);
130
+ if (v6) {
131
+ hostOnly = v6[1];
132
+ if (v6[2]) portFromServer = Number(v6[2]);
133
+ } else {
134
+ // Nur splitten, wenn genau EIN Doppelpunkt — sonst IPv6 ohne Klammern
135
+ const colonCount = (hostOnly.match(/:/g) || []).length;
136
+ if (colonCount === 1) {
137
+ const [h, p] = hostOnly.split(":");
138
+ if (h && /^\d+$/.test(p)) {
139
+ hostOnly = h;
140
+ portFromServer = Number(p);
141
+ }
142
+ }
143
+ }
144
+
145
+ const effectivePort = Number(port) || portFromServer || 445;
146
+ const shareStr = `\\\\${hostOnly}\\${share}`;
120
147
  const SMB2 = getSMB2();
121
148
  const smb = new SMB2({
122
149
  share: shareStr,
123
150
  domain: domain || "WORKGROUP",
124
151
  username: username || "guest",
125
152
  password: password || "",
153
+ port: effectivePort,
126
154
  autoCloseTimeout: 10000,
127
155
  });
128
156