saltcorn-samba 0.4.1 → 0.4.2
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 +35 -0
- package/index.js +33 -16
- package/package.json +1 -1
- package/smb-client.js +24 -28
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,41 @@ 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.4.2] – 2026-07-05
|
|
8
|
+
|
|
9
|
+
### Fixed – **Dropdown-Felder zeigen `[object Object]` statt Optionen**
|
|
10
|
+
|
|
11
|
+
Die neuen Felder `signing_mode` und `encryption_mode` wurden in der
|
|
12
|
+
Saltcorn-UI mit `[object Object]` als einzige Auswahl gerendert.
|
|
13
|
+
|
|
14
|
+
**Ursache:** In der genutzten Saltcorn-Version werden `attributes.options`
|
|
15
|
+
als einfaches String-Array erwartet (`["a", "b", "c"]`), nicht als
|
|
16
|
+
`{value, label}`-Objekt. Die Objekt-Form ist erst in neueren Builds
|
|
17
|
+
vollständig unterstützt; sonst castet das UI die Objekte zu Strings.
|
|
18
|
+
|
|
19
|
+
**Fix:** `options` auf String-Array umgestellt —
|
|
20
|
+
`["if-offered", "required", "disabled"]`. Die Beschriftung bleibt in
|
|
21
|
+
der `sublabel` erhalten (der Config-Wizard erklärt jeden Wert dort).
|
|
22
|
+
|
|
23
|
+
### Fixed – **`STATUS_OBJECT_NAME_NOT_FOUND` durch fehlgeleiteten Root-Fallback**
|
|
24
|
+
|
|
25
|
+
Der 0.4.1-Fallback `share/.` triggerte auf Samba einen anderen NT-Status:
|
|
26
|
+
`STATUS_OBJECT_NAME_NOT_FOUND` (0xC0000034 / `ENOENT`), weil Samba `.` als
|
|
27
|
+
literalen Dateinamen sucht statt als Current-Directory-Marker (das ist im
|
|
28
|
+
POSIX-Layer, nicht im SMB2-Protokoll). Der zweite Fallback `share/*` ist
|
|
29
|
+
protokoll-illegal (Wildcard im CREATE) und wird ebenfalls abgelehnt.
|
|
30
|
+
|
|
31
|
+
**Neuer Ansatz:** Wir versuchen den Fallback erst gar nicht. Statt zu
|
|
32
|
+
raten geben wir eine klare deutsche Fehlermeldung aus: **einen Basispfad
|
|
33
|
+
setzen**. Das ist die einzige zuverlässige Lösung, solange `smb3-client`
|
|
34
|
+
die `FileInformationClass` nicht konfigurierbar macht.
|
|
35
|
+
|
|
36
|
+
Die Test-Route bleibt weiterhin nachsichtig: bei `OBJECT_NAME_INVALID`
|
|
37
|
+
auf dem Root fällt sie auf `stat("")` zurück und meldet ein Erfolg mit
|
|
38
|
+
Hinweis („Verbindung + Anmeldung erfolgreich, aber Share-Root nicht
|
|
39
|
+
direkt auflistbar — bitte Basispfad setzen“). Der Hinweis wird als gelbe
|
|
40
|
+
Box im Test-Ergebnis angezeigt.
|
|
41
|
+
|
|
7
42
|
## [0.4.1] – 2026-07-05
|
|
8
43
|
|
|
9
44
|
### Fixed – **`QUERY_DIRECTORY failed: 0xC0000033` auf Share-Root (Samba 4.20+/4.23+)**
|
package/index.js
CHANGED
|
@@ -160,6 +160,9 @@ window.sambaTestConn = async function(btn) {
|
|
|
160
160
|
var rows = (data.entries||[]).map(function(e){
|
|
161
161
|
return '<li>'+ (e.isDirectory?'📁 ':'📄 ') + String(e.name).replace(/[<>&]/g,'?') +'</li>';
|
|
162
162
|
}).join('');
|
|
163
|
+
var noteHtml = data.note
|
|
164
|
+
? '<div style="margin-top:.5rem;padding:.4rem .6rem;background:#fff3cd;border:1px solid #ffeeba;border-radius:.25rem"><b>Hinweis:</b> ' + String(data.note).replace(/[<>&]/g,'?') + '</div>'
|
|
165
|
+
: '';
|
|
163
166
|
out.innerHTML =
|
|
164
167
|
'<div class="alert alert-success">' +
|
|
165
168
|
'<b>✓ Verbindung erfolgreich</b> (' + data.duration_ms + ' ms)<br>' +
|
|
@@ -167,6 +170,7 @@ window.sambaTestConn = async function(btn) {
|
|
|
167
170
|
'Basispfad: <code>' + data.base_path + '</code>, Benutzer: <code>' + data.username + '</code><br>' +
|
|
168
171
|
'Einträge gefunden: <b>' + data.entry_count + '</b>' + (data.truncated ? ' (erste 20 unten)' : '') +
|
|
169
172
|
(rows ? '<ul style="margin:.5rem 0 0 1rem">' + rows + '</ul>' : '') +
|
|
173
|
+
noteHtml +
|
|
170
174
|
'</div>';
|
|
171
175
|
} else {
|
|
172
176
|
var a = data && data.attempted || {};
|
|
@@ -301,11 +305,7 @@ const configuration_workflow = () =>
|
|
|
301
305
|
type: "String",
|
|
302
306
|
required: true,
|
|
303
307
|
attributes: {
|
|
304
|
-
options: [
|
|
305
|
-
{ value: "if-offered", label: "if-offered (Standard)" },
|
|
306
|
-
{ value: "required", label: "required (strikt)" },
|
|
307
|
-
{ value: "disabled", label: "disabled (aus)" },
|
|
308
|
-
],
|
|
308
|
+
options: ["if-offered", "required", "disabled"],
|
|
309
309
|
},
|
|
310
310
|
default: "if-offered",
|
|
311
311
|
}),
|
|
@@ -321,11 +321,7 @@ const configuration_workflow = () =>
|
|
|
321
321
|
type: "String",
|
|
322
322
|
required: true,
|
|
323
323
|
attributes: {
|
|
324
|
-
options: [
|
|
325
|
-
{ value: "if-offered", label: "if-offered (Standard)" },
|
|
326
|
-
{ value: "required", label: "required (strikt)" },
|
|
327
|
-
{ value: "disabled", label: "disabled (aus)" },
|
|
328
|
-
],
|
|
324
|
+
options: ["if-offered", "required", "disabled"],
|
|
329
325
|
},
|
|
330
326
|
default: "if-offered",
|
|
331
327
|
}),
|
|
@@ -804,18 +800,32 @@ code{background:#f4f4f4;padding:2px 6px;border-radius:3px;word-break:break-all}<
|
|
|
804
800
|
try {
|
|
805
801
|
return await client.readdir(rel);
|
|
806
802
|
} catch (err) {
|
|
807
|
-
|
|
803
|
+
// Look at both the wrapper error and its underlying cause.
|
|
804
|
+
const causeMsg = String((err && err.cause && err.cause.message) || "");
|
|
805
|
+
const msg = String((err && err.message) || err || "") + " " + causeMsg;
|
|
808
806
|
const isRootProbe = !rel;
|
|
809
|
-
const
|
|
810
|
-
if (isRootProbe &&
|
|
811
|
-
// Fall back: proof-of-life via stat on share root.
|
|
812
|
-
|
|
813
|
-
|
|
807
|
+
const isRootEnumBug = /0xC0000033|OBJECT_NAME_INVALID|Share-Root/i.test(msg);
|
|
808
|
+
if (isRootProbe && isRootEnumBug) {
|
|
809
|
+
// Fall back: proof-of-life via stat on share root. This
|
|
810
|
+
// confirms TCP + Negotiate + Session + Auth + TREE_CONNECT
|
|
811
|
+
// without hitting the broken QUERY_DIRECTORY path.
|
|
812
|
+
try {
|
|
813
|
+
await client.stat("");
|
|
814
|
+
// Signal to the caller that the connection works, but
|
|
815
|
+
// the share root cannot be enumerated on this server.
|
|
816
|
+
const marker = [];
|
|
817
|
+
marker._rootNotEnumerable = true;
|
|
818
|
+
return marker;
|
|
819
|
+
} catch (statErr) {
|
|
820
|
+
// stat also failed — surface the original error.
|
|
821
|
+
throw err;
|
|
822
|
+
}
|
|
814
823
|
}
|
|
815
824
|
throw err;
|
|
816
825
|
}
|
|
817
826
|
});
|
|
818
827
|
const took = Date.now() - started;
|
|
828
|
+
const rootNotEnum = Array.isArray(listing) && listing._rootNotEnumerable === true;
|
|
819
829
|
return res.json({
|
|
820
830
|
ok: true,
|
|
821
831
|
server: testCfg.server,
|
|
@@ -831,6 +841,13 @@ code{background:#f4f4f4;padding:2px 6px;border-radius:3px;word-break:break-all}<
|
|
|
831
841
|
isDirectory: !!(e && (e.isDirectory === true || (e.stats && e.stats.isDirectory && e.stats.isDirectory()))),
|
|
832
842
|
})),
|
|
833
843
|
truncated: Array.isArray(listing) && listing.length > 20,
|
|
844
|
+
note: rootNotEnum
|
|
845
|
+
? "Verbindung + Anmeldung erfolgreich. Der Server erlaubt jedoch " +
|
|
846
|
+
"kein direktes Auflisten des Share-Roots (bekanntes Samba-" +
|
|
847
|
+
"Verhalten mit smb3-client). Bitte setzen Sie einen Basispfad " +
|
|
848
|
+
"in der Plugin-Config (z.\u202fB. einen Unterordner der " +
|
|
849
|
+
"Freigabe) — dann funktioniert der File-Manager vollständig."
|
|
850
|
+
: undefined,
|
|
834
851
|
});
|
|
835
852
|
} catch (err) {
|
|
836
853
|
// Turn opaque SMB / socket errors into actionable hints.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "saltcorn-samba",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.2",
|
|
4
4
|
"description": "Saltcorn plugin: browse, upload, rename and delete files on a Samba/CIFS share via SMB 3.1.1 (AES-CMAC signing, optional encryption). 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
|
@@ -279,36 +279,32 @@ async function buildClient(config) {
|
|
|
279
279
|
} catch (err) {
|
|
280
280
|
// Some Samba builds (observed on 4.20+/4.23+) reject
|
|
281
281
|
// SMB2 QUERY_DIRECTORY on the *share root* with
|
|
282
|
-
// STATUS_OBJECT_NAME_INVALID (0xC0000033) because
|
|
283
|
-
//
|
|
284
|
-
//
|
|
285
|
-
//
|
|
286
|
-
|
|
287
|
-
|
|
282
|
+
// STATUS_OBJECT_NAME_INVALID (0xC0000033) because smb3-client
|
|
283
|
+
// asks for FileIdBothDirectoryInformation (class 37) on a
|
|
284
|
+
// handle opened with an empty filename. We cannot swap the
|
|
285
|
+
// information class from userland, and Samba refuses both
|
|
286
|
+
// "." (→ STATUS_OBJECT_NAME_NOT_FOUND) and "*" (→ CREATE with
|
|
287
|
+
// wildcard is protocol-illegal). The clean way out is:
|
|
288
|
+
// require the caller to configure a real base_path so every
|
|
289
|
+
// readdir happens inside a directory the server can enumerate.
|
|
290
|
+
const msg = String((err && err.message) || err || "");
|
|
288
291
|
const isRoot = !rel && !basePath;
|
|
289
|
-
const
|
|
290
|
-
/0xC0000033|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
"Setzen Sie einen Basispfad im Plugin-Konfig oder prüfen Sie die Share-Definition auf dem Server."
|
|
304
|
-
);
|
|
305
|
-
e.cause = err;
|
|
306
|
-
throw e;
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
} else {
|
|
310
|
-
throw err;
|
|
292
|
+
const isRootEnumBug =
|
|
293
|
+
/0xC0000033|OBJECT_NAME_INVALID|QUERY_DIRECTORY/i.test(msg);
|
|
294
|
+
if (isRoot && isRootEnumBug) {
|
|
295
|
+
const e = new Error(
|
|
296
|
+
"Das Share-Root lässt sich auf diesem Samba-Server nicht " +
|
|
297
|
+
"direkt auflisten (" + (msg || "QUERY_DIRECTORY failed") + "). " +
|
|
298
|
+
"Bitte in der Plugin-Config einen Basispfad setzen (z.\u202fB. " +
|
|
299
|
+
"einen Unterordner der Freigabe wie „daten“ oder „projekte“) — " +
|
|
300
|
+
"dann funktionieren alle Directory-Listings innerhalb dieses " +
|
|
301
|
+
"Unterordners. Details siehe README, Abschnitt „Troubleshooting → " +
|
|
302
|
+
"QUERY_DIRECTORY auf Share-Root“."
|
|
303
|
+
);
|
|
304
|
+
e.cause = err;
|
|
305
|
+
throw e;
|
|
311
306
|
}
|
|
307
|
+
throw err;
|
|
312
308
|
}
|
|
313
309
|
// Parallel enrichment. Bounded to a reasonable concurrency to avoid
|
|
314
310
|
// saturating the SMB session on huge directories.
|