saltcorn-samba 0.4.4 → 0.4.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.
- package/CHANGELOG.md +56 -0
- package/index.js +47 -20
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -4,6 +4,62 @@ 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.6] – 2026-07-05
|
|
8
|
+
|
|
9
|
+
### Fixed – **Schreibvarianten-Test verdoppelte den Basispfad**
|
|
10
|
+
|
|
11
|
+
Die Case-Probes in v0.4.4/0.4.5 riefen `client.readdir(<candidate>)` auf.
|
|
12
|
+
Der Wrapper prependiert aber automatisch den bereits konfigurierten
|
|
13
|
+
`basePath` — dadurch wurde intern nach `buero/static/static` statt
|
|
14
|
+
`buero/static` gesucht. Alle Probes scheiterten deshalb systematisch
|
|
15
|
+
mit derselben Meldung, unabhängig von der wahren Ursache.
|
|
16
|
+
|
|
17
|
+
**Fix:** Die Probes gehen jetzt direkt gegen den rohen `smb3-client`
|
|
18
|
+
(`client._raw.readdir(share/<absoluter Pfad>)`) und bauen die
|
|
19
|
+
From-Share-Root-Pfade selbst zusammen. Der Test-Endpunkt zeigt jetzt
|
|
20
|
+
zusätzlich pro Probe den tatsächlich getesteten Pfad an.
|
|
21
|
+
|
|
22
|
+
### Fixed – **Falscher „Login rejected“-Hinweis bei BASE_PATH_NOT_FOUND**
|
|
23
|
+
|
|
24
|
+
Der Fallback-Hint-Table prüfte per Substring-Match auf `access_denied`
|
|
25
|
+
u.\u00e4. — das triggerte auf den erklärenden Text in unserer eigenen
|
|
26
|
+
deutschen Fehlermeldung (wir *erwähnen* `ACCESS_DENIED` didaktisch).
|
|
27
|
+
Ein ungefundener Basispfad wurde deshalb zusätzlich mit dem irreführenden
|
|
28
|
+
Hinweis „Login rejected“ versehen.
|
|
29
|
+
|
|
30
|
+
**Fix:** Fehler mit eigenem `code` (`BASE_PATH_NOT_FOUND`,
|
|
31
|
+
`BASE_PATH_NOT_A_DIR`) überspringen den Substring-Match — die
|
|
32
|
+
Wrapper-Meldung ist bereits vollständig und braucht keinen „Hint“.
|
|
33
|
+
|
|
34
|
+
### Changed – **Bessere Basispfad-Meldung**
|
|
35
|
+
|
|
36
|
+
Wenn kein Case-Match gefunden wurde, zeigt die Meldung jetzt den
|
|
37
|
+
tatsächlich getesteten UNC-Pfad (`\\\\server\\share\\pfad`) und weist
|
|
38
|
+
explizit darauf hin, dass der Basispfad **relativ zur Freigabe** ist —
|
|
39
|
+
also `unterordner` und **nicht** `sharename/unterordner`.
|
|
40
|
+
|
|
41
|
+
## [0.4.5] – 2026-07-05
|
|
42
|
+
|
|
43
|
+
### Fixed – **Test-Verbindung-Button reagiert nicht mehr (v0.4.4-Regression)**
|
|
44
|
+
|
|
45
|
+
In v0.4.4 enthielt der neu hinzugefügte Diagnose-IIFE-Block im Inline-
|
|
46
|
+
Browser-Script eine Regex `.split(/[\r\n]/)`. Der HTML-Block ist ein
|
|
47
|
+
**Template-Literal** in `index.js`; darin werden `\r` und `\n` zu
|
|
48
|
+
**echten Steuerzeichen** aufgelöst. Das gerenderte `<script>` enthielt
|
|
49
|
+
deshalb einen literalen Zeilenumbruch mitten in der Regex — der Browser
|
|
50
|
+
konnte das Skript nicht mehr parsen, und `window.sambaTestConn` wurde
|
|
51
|
+
nie definiert. Ein Klick auf „Verbindung jetzt testen“ zeigte deshalb
|
|
52
|
+
keine Reaktion.
|
|
53
|
+
|
|
54
|
+
**Fix:** Die Escape-Sequenz im Source auf `\\r\\n` verdoppelt, damit im
|
|
55
|
+
gerenderten Skript wieder `\r\n` steht (also die Zeichenklasse, nicht
|
|
56
|
+
die literalen Zeichen). Der Skript-Parse funktioniert wieder, die
|
|
57
|
+
Test-Schaltfläche reagiert.
|
|
58
|
+
|
|
59
|
+
Zusätzlich wurde die Rendering-Pipeline mit einem Node-`--check` auf
|
|
60
|
+
dem *extrahierten* Browser-Skript verifiziert, damit dieser konkrete
|
|
61
|
+
Fehlermodus in Zukunft schon lokal auffällt.
|
|
62
|
+
|
|
7
63
|
## [0.4.4] – 2026-07-05
|
|
8
64
|
|
|
9
65
|
### Fixed – **Falscher `NAME_NOT_FOUND` durch `stat()`-Vorprüfung**
|
package/index.js
CHANGED
|
@@ -234,7 +234,7 @@ window.sambaTestConn = async function(btn) {
|
|
|
234
234
|
box += '<details style="margin-top:.3rem"><summary>Schreibvarianten-Test</summary><table class="table table-sm" style="margin-top:.3rem;font-size:.85em">';
|
|
235
235
|
box += '<thead><tr><th>Variante</th><th>Ergebnis</th></tr></thead><tbody>';
|
|
236
236
|
d.spelling_probes.forEach(function(p){
|
|
237
|
-
box += '<tr><td><code>' + esc(p.candidate) + '</code></td><td>' + (p.ok ? '✓ auflistbar' : '✗ <span class="text-muted">' + esc(String(p.error||'').split(/[
|
|
237
|
+
box += '<tr><td><code>' + esc(p.candidate) + '</code></td><td>' + (p.ok ? '✓ auflistbar' : '✗ <span class="text-muted">' + esc(String(p.error||'').split(/[\\r\\n]/)[0].slice(0,140)) + '</span>') + '</td></tr>';
|
|
238
238
|
});
|
|
239
239
|
box += '</tbody></table></details>';
|
|
240
240
|
}
|
|
@@ -901,15 +901,28 @@ code{background:#f4f4f4;padding:2px 6px;border-radius:3px;word-break:break-all}<
|
|
|
901
901
|
const missing = parts[parts.length - 1];
|
|
902
902
|
const parent = parts.slice(0, -1).join("/");
|
|
903
903
|
const parentAbs = parent || "(Share-Root)";
|
|
904
|
+
// We must probe via the *raw* smb3-client because the
|
|
905
|
+
// wrapper's readdir() automatically prepends basePath —
|
|
906
|
+
// that would double up the segment we're trying to test
|
|
907
|
+
// (e.g. readdir("static") → "buero/static/static").
|
|
908
|
+
const raw = client._raw;
|
|
909
|
+
const rawShare = client.shareName;
|
|
910
|
+
async function rawReaddir(relFromShareRoot) {
|
|
911
|
+
const full = [rawShare, relFromShareRoot].filter(Boolean).join("/");
|
|
912
|
+
return await raw.readdir(full, { withFileTypes: true });
|
|
913
|
+
}
|
|
904
914
|
let siblings = null;
|
|
905
915
|
let parent_error = null;
|
|
906
916
|
if (parent) {
|
|
907
917
|
try {
|
|
908
|
-
|
|
918
|
+
// parent here is relative to basePath — but we want
|
|
919
|
+
// absolute-from-share-root paths in the raw call.
|
|
920
|
+
const parentFromShare = [client.basePath, parent].filter(Boolean).join("/");
|
|
921
|
+
const listing = await rawReaddir(parentFromShare);
|
|
909
922
|
siblings = Array.isArray(listing)
|
|
910
923
|
? listing.map((d) => ({
|
|
911
|
-
name: d &&
|
|
912
|
-
isDirectory: !!(d &&
|
|
924
|
+
name: d && d.name,
|
|
925
|
+
isDirectory: !!(d && typeof d.isDirectory === "function" && d.isDirectory()),
|
|
913
926
|
}))
|
|
914
927
|
: null;
|
|
915
928
|
} catch (parentErr) {
|
|
@@ -932,42 +945,44 @@ code{background:#f4f4f4;padding:2px 6px;border-radius:3px;word-break:break-all}<
|
|
|
932
945
|
addProbe(missing.charAt(0).toUpperCase() + missing.slice(1).toLowerCase());
|
|
933
946
|
const probe_results = [];
|
|
934
947
|
for (const p of probes) {
|
|
935
|
-
|
|
948
|
+
// Build the *from-share-root* relative path so the probe
|
|
949
|
+
// does not accidentally get basePath prepended twice.
|
|
950
|
+
const relFromShare = [client.basePath, parent, p].filter(Boolean).join("/");
|
|
936
951
|
let ok = false;
|
|
937
952
|
let perr = null;
|
|
938
953
|
try {
|
|
939
|
-
await
|
|
954
|
+
await rawReaddir(relFromShare);
|
|
940
955
|
ok = true;
|
|
941
956
|
} catch (pErr) {
|
|
942
957
|
perr = String((pErr && pErr.message) || pErr || "");
|
|
943
958
|
}
|
|
944
|
-
probe_results.push({ candidate: p, ok, error: ok ? null : perr });
|
|
959
|
+
probe_results.push({ candidate: p, tested_path: relFromShare, ok, error: ok ? null : perr });
|
|
945
960
|
}
|
|
946
961
|
const workingAlt = probe_results.find(
|
|
947
962
|
(r) => r.ok && r.candidate !== missing
|
|
948
963
|
);
|
|
964
|
+
const testedPath = "\\\\" + testCfg.server + "\\" + testCfg.share + "\\" + rel.replace(/\//g, "\\");
|
|
949
965
|
let hintText;
|
|
950
966
|
if (workingAlt) {
|
|
951
967
|
hintText =
|
|
952
|
-
"Der Ordner
|
|
968
|
+
"Der Ordner hei\u00dft auf dem Server \u201e" +
|
|
953
969
|
workingAlt.candidate +
|
|
954
|
-
"\u201c (andere
|
|
970
|
+
"\u201c (andere Gro\u00df-/Kleinschreibung). Bitte den " +
|
|
955
971
|
"Basispfad exakt so eintragen \u2014 der Samba-Server ist " +
|
|
956
972
|
"case-sensitive (\u201ecase sensitive = yes\u201c in smb.conf).";
|
|
957
973
|
} else {
|
|
958
974
|
hintText =
|
|
959
|
-
"Der Basispfad \u201e" + rel + "\u201c
|
|
960
|
-
"
|
|
961
|
-
"
|
|
962
|
-
"
|
|
963
|
-
"
|
|
975
|
+
"Der Basispfad \u201e" + rel + "\u201c wurde auf der " +
|
|
976
|
+
"Freigabe \u201e" + testCfg.share + "\u201c nicht " +
|
|
977
|
+
"gefunden. Getestet wurde der Pfad: " + testedPath + ". " +
|
|
978
|
+
"M\u00f6gliche Ursachen: (a) Ordner existiert unter genau " +
|
|
979
|
+
"diesem Namen nicht in dieser Freigabe (Basispfad ist " +
|
|
980
|
+
"relativ zur Freigabe \u2014 also z.\u202fB. \u201eunterordner\u201c, " +
|
|
981
|
+
"nicht \u201e" + testCfg.share + "/unterordner\u201c); " +
|
|
964
982
|
"(b) der angemeldete Benutzer \u201e" +
|
|
965
983
|
(testCfg.username || "(anonymous)") +
|
|
966
|
-
"\u201c
|
|
967
|
-
"
|
|
968
|
-
"NAME_NOT_FOUND statt ACCESS_DENIED); " +
|
|
969
|
-
"(c) der Ordner ist per \u201eveto files\u201c / " +
|
|
970
|
-
"\u201ehide files\u201c auf dem Server ausgeblendet.";
|
|
984
|
+
"\u201c darf den Ordner nicht sehen; " +
|
|
985
|
+
"(c) der Ordner ist per Samba-Konfiguration ausgeblendet.";
|
|
971
986
|
}
|
|
972
987
|
const e = new Error(hintText);
|
|
973
988
|
e.cause = err;
|
|
@@ -1017,7 +1032,19 @@ code{background:#f4f4f4;padding:2px 6px;border-radius:3px;word-break:break-all}<
|
|
|
1017
1032
|
const code = (err && (err.code || err.errno)) || null;
|
|
1018
1033
|
let hint = null;
|
|
1019
1034
|
const m = msg.toLowerCase();
|
|
1020
|
-
|
|
1035
|
+
// If the wrapper already produced a well-formed, self-explanatory
|
|
1036
|
+
// error (own `code` set), skip the substring-match hint table —
|
|
1037
|
+
// it would otherwise trigger on words that appear inside our own
|
|
1038
|
+
// human-readable German explanation text (e.g. our message text
|
|
1039
|
+
// mentions "access_denied" or "path" for teaching purposes).
|
|
1040
|
+
const codesWithOwnMessage = new Set([
|
|
1041
|
+
"BASE_PATH_NOT_FOUND",
|
|
1042
|
+
"BASE_PATH_NOT_A_DIR",
|
|
1043
|
+
]);
|
|
1044
|
+
if (code && codesWithOwnMessage.has(code)) {
|
|
1045
|
+
hint = null;
|
|
1046
|
+
}
|
|
1047
|
+
else if (code === "ECONNREFUSED" || m.includes("econnrefused"))
|
|
1021
1048
|
hint = "The server refused the connection on port " + testCfg.port +
|
|
1022
1049
|
". Check that Samba is running and that a firewall (or Docker) does not block TCP/445.";
|
|
1023
1050
|
else if (code === "ETIMEDOUT" || m.includes("etimedout") || m.includes("timed out"))
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "saltcorn-samba",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.6",
|
|
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": {
|