900c870212
Part 4 — restore: RestoreSharesScratch + PlaceSharesRestore as SIBLINGS of the
per-app scratch/place pair. Files merged missing-only (never overwriting), each
destination PREFIX-ASSERTED against registered LIVE storage roots; definitions
merged with existing-wins; ReconcileSamba via a seam (backup must not import
stacks); credential restored best-effort into the samba named volume.
New routes POST /backup/shares/{restore,place} + a restore-page entry that renders
'Megosztasok', never the raw reserved key.
Also adds scratchJoin: reconstructing an absolute captured path under a scratch
must strip the volume name rather than rely on filepath.Join.
Part 5 — liveness: EffectiveProtected gains a settings-backed dynamic extra so the
samba CONTAINER (not the stack name — they differ) is watched exactly while sharing
is on. FINDING: the issue -> health 'fail' -> existing health_critical event ->
alert -> Hungarian degradation e-mail path needs NO further change, and introduces
no new event type, so the allowlist gotcha does not apply.
Part 6 — UI: per-tier backup status lines on the Megosztas page (amber only on
deviation). Verified the two warning-prose sites (offbox_capture/tier2_capture)
only ever receive per-app stack names, so no mapping is needed there.
RED-PROOFS RUN AND REVERTED (both fired):
4. prefix-assert removed -> place-guard traversal test FAILS
5. dynamic samba extra removed -> Scenario E enabled-case FAILS
289 lines
12 KiB
HTML
289 lines
12 KiB
HTML
{{define "sharing"}}
|
|
{{template "layout_start" .}}
|
|
|
|
<div class="page-header">
|
|
<h2>Hálózati megosztás</h2>
|
|
</div>
|
|
|
|
{{if .Flash}}
|
|
<div class="alert alert-success">{{.Flash}}</div>
|
|
{{end}}
|
|
|
|
<div class="settings-card">
|
|
<p class="settings-card-desc">
|
|
A megosztott mappák a Windows Intézőben és a Mac Finderben jelennek meg, mintha egy hálózati
|
|
meghajtó lennének. A megosztás <strong>csak az otthoni hálózaton</strong> érhető el — az
|
|
internetről nem.
|
|
</p>
|
|
|
|
<form method="POST" action="/sharing/enable">
|
|
{{.CSRFField}}
|
|
<div class="form-group">
|
|
<label>
|
|
<input type="checkbox" name="enabled" {{if .SMBEnabled}}checked{{end}}>
|
|
Megosztás engedélyezése
|
|
</label>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="server_name">Kiszolgáló neve</label>
|
|
<input type="text" id="server_name" name="server_name" class="form-control mono"
|
|
value="{{.SMBServerName}}" maxlength="15" autocomplete="off">
|
|
<div class="form-hint">
|
|
Ezen a néven jelenik meg a gép a hálózaton (<span class="mono">\\{{.SMBServerName}}</span>).
|
|
Legfeljebb 15 karakter: betű, szám, kötőjel, aláhúzás.
|
|
</div>
|
|
</div>
|
|
<div class="form-actions">
|
|
<button type="submit" class="btn btn-primary">Mentés</button>
|
|
</div>
|
|
</form>
|
|
|
|
<div class="form-group">
|
|
<span>Állapot:</span>
|
|
{{if .SMBRunning}}
|
|
<span class="badge badge-ok">fut</span>
|
|
{{else}}
|
|
<span class="badge badge-neutral">áll</span>
|
|
{{end}}
|
|
{{if and .SMBEnabled (not .SMBUserSet)}}
|
|
<span class="badge badge-warn">először adj meg jelszót</span>
|
|
{{end}}
|
|
</div>
|
|
<div class="form-hint">
|
|
Egyes hálózatokon a gép késve jelenik meg az eszközlistában. A
|
|
<span class="mono">\\{{.SMBServerName}}</span> cím beírása a címsorba ilyenkor is működik.
|
|
</div>
|
|
</div>
|
|
|
|
<div class="settings-card">
|
|
<h3>Megosztási jelszó beállítása</h3>
|
|
<p class="settings-card-desc">
|
|
Egy közös jelszó tartozik a háztartáshoz. A csatlakozáskor felhasználónévnek add meg:
|
|
<span class="mono">felhom</span>.
|
|
</p>
|
|
<form method="POST" action="/sharing/password">
|
|
{{.CSRFField}}
|
|
<div class="form-group">
|
|
<label for="smb_password">Új jelszó</label>
|
|
<input type="password" id="smb_password" name="smb_password" class="form-control"
|
|
autocomplete="new-password" minlength="8" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="smb_password_confirm">Jelszó megerősítése</label>
|
|
<input type="password" id="smb_password_confirm" name="smb_password_confirm" class="form-control"
|
|
autocomplete="new-password" minlength="8" required>
|
|
</div>
|
|
<div class="form-actions">
|
|
<button type="submit" class="btn btn-primary">Jelszó mentése</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="settings-card">
|
|
<h3>Megosztott mappák</h3>
|
|
{{if .SMBShares}}
|
|
<div class="backup-table-wrap">
|
|
<table class="db-table">
|
|
<thead>
|
|
<tr>
|
|
<th>Név</th>
|
|
<th>Mappa</th>
|
|
<th>Írásvédett</th>
|
|
<th>Felhőmentés</th>
|
|
<th>Törlés</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{range .SMBShares}}
|
|
<tr>
|
|
<td class="mono">{{.Name}}</td>
|
|
<td class="mono">{{.Path}}
|
|
{{if not .Available}}<span class="badge badge-warn">A meghajtó nem elérhető.</span>{{end}}
|
|
</td>
|
|
<td>{{if .ReadOnly}}<span class="badge badge-neutral">igen</span>{{else}}nem{{end}}</td>
|
|
<td>
|
|
<form method="POST" action="/sharing/shares/offsite">
|
|
{{$.CSRFField}}
|
|
<input type="hidden" name="name" value="{{.Name}}">
|
|
<input type="hidden" name="offsite" value="{{if .Offsite}}off{{else}}on{{end}}">
|
|
<button type="submit" class="btn btn-xs btn-outline">
|
|
{{if .Offsite}}bekapcsolva{{else}}kikapcsolva{{end}}
|
|
</button>
|
|
</form>
|
|
</td>
|
|
<td>
|
|
<form method="POST" action="/sharing/shares/delete">
|
|
{{$.CSRFField}}
|
|
<input type="hidden" name="name" value="{{.Name}}">
|
|
<button type="submit" class="btn btn-xs btn-danger-outline">Törlés</button>
|
|
</form>
|
|
</td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
<div class="form-hint">
|
|
A megosztás törlésekor <strong>a mappa és a fájlok megmaradnak</strong> — csak a hálózati
|
|
elérés szűnik meg.
|
|
</div>
|
|
|
|
<div class="backup-section-card" style="margin-top:1rem">
|
|
<h3>A megosztások mentése</h3>
|
|
<p class="form-hint" style="margin:-0.25rem 0 0.75rem">
|
|
A megosztott mappák a többi adattal együtt mentésre kerülnek. A „Felhőmentés” bekapcsolva
|
|
azt jelenti, hogy a mappa a távoli tárhelyre is felkerül; kikapcsolva csak a második
|
|
meghajtóra készül másolat.
|
|
</p>
|
|
<ul class="plain-list">
|
|
<li>
|
|
<strong>2. mentés (másik meghajtó):</strong>
|
|
{{if .SharesTier2Status}}
|
|
{{if eq .SharesTier2Status "ok"}}
|
|
rendben{{if .SharesTier2LastRun}} — {{.SharesTier2LastRun}}{{end}}
|
|
{{if .SharesTier2Warning}}<span class="badge badge-warn">{{.SharesTier2Warning}}</span>{{end}}
|
|
{{else if eq .SharesTier2Status "no_target"}}
|
|
<span class="badge badge-warn">nincs cél — {{.SharesTier2Error}}</span>
|
|
{{else}}
|
|
<span class="badge badge-warn">hiba — {{.SharesTier2Error}}</span>
|
|
{{end}}
|
|
{{else}}
|
|
még nem futott
|
|
{{end}}
|
|
</li>
|
|
<li>
|
|
<strong>Távoli mentés (felhő):</strong>
|
|
{{if .SharesOffsiteStatus}}
|
|
{{if eq .SharesOffsiteStatus "ok"}}
|
|
rendben — {{.SharesOffsiteCount}} megosztás{{if .SharesOffsiteLastRun}}, {{.SharesOffsiteLastRun}}{{end}}
|
|
{{else if eq .SharesOffsiteStatus "blocked"}}
|
|
<span class="badge badge-warn">a tárhelykeret miatt csak a beállítások kerültek fel</span>
|
|
{{else if eq .SharesOffsiteStatus "skipped"}}
|
|
<span class="badge badge-warn">kimaradt</span>
|
|
{{else}}
|
|
<span class="badge badge-warn">hiba</span>
|
|
{{end}}
|
|
{{else}}
|
|
még nem futott
|
|
{{end}}
|
|
</li>
|
|
</ul>
|
|
<div class="form-hint">
|
|
Visszaállítani a <a href="/backups/restore">Visszaállítás</a> oldalon lehet.
|
|
</div>
|
|
</div>
|
|
{{else}}
|
|
<div class="backup-table-empty">Még nincs megosztott mappa.</div>
|
|
{{end}}
|
|
</div>
|
|
|
|
<div class="settings-card">
|
|
<h3>Új megosztás</h3>
|
|
<form method="POST" action="/sharing/shares" id="share-create-form">
|
|
{{.CSRFField}}
|
|
<div class="form-group">
|
|
<label for="share_name">Megosztás neve <span class="required">*</span></label>
|
|
<input type="text" id="share_name" name="name" class="form-control mono"
|
|
maxlength="15" required autocomplete="off">
|
|
<div class="form-hint">Legfeljebb 15 karakter: betű, szám, kötőjel, aláhúzás.</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>
|
|
<input type="radio" name="mode" value="new" checked onclick="shareModeSwitch()">
|
|
Új mappa a tárhelyen
|
|
</label>
|
|
<label>
|
|
<input type="radio" name="mode" value="existing" onclick="shareModeSwitch()">
|
|
Meglévő mappa kiválasztása
|
|
</label>
|
|
</div>
|
|
|
|
<div class="form-group" id="share-mode-new">
|
|
<label for="storage_root">Tárhely</label>
|
|
<select id="storage_root" name="storage_root" class="form-control">
|
|
{{range .StorageRoots}}
|
|
<option value="{{.Path}}">{{.Label}}</option>
|
|
{{end}}
|
|
</select>
|
|
<div class="form-hint">A mappa a kiválasztott tárhely <span class="mono">shares/</span> könyvtárában jön létre.</div>
|
|
</div>
|
|
|
|
<div class="form-group" id="share-mode-existing" style="display:none">
|
|
<label>Kiválasztott mappa</label>
|
|
<input type="text" id="share_path" name="path" class="form-control mono" readonly>
|
|
<div class="form-actions">
|
|
<button type="button" class="btn btn-sm btn-outline" onclick="shareBrowseOpen()">Tallózás</button>
|
|
</div>
|
|
</div>
|
|
|
|
<div class="form-group">
|
|
<label>
|
|
<input type="checkbox" name="read_only">
|
|
Írásvédett (csak olvasható)
|
|
</label>
|
|
</div>
|
|
<div class="form-actions">
|
|
<button type="submit" class="btn btn-primary">Megosztás létrehozása</button>
|
|
</div>
|
|
</form>
|
|
</div>
|
|
|
|
<div class="confirm-overlay" id="share-browse-overlay" style="display:none">
|
|
<div class="confirm-box">
|
|
<h3>Mappa kiválasztása</h3>
|
|
<div class="mono" id="share-browse-path"></div>
|
|
<div id="share-browse-list"></div>
|
|
<div class="form-actions">
|
|
<button type="button" class="btn btn-sm btn-primary" onclick="shareBrowsePick()">Ezt választom</button>
|
|
<button type="button" class="btn btn-sm btn-outline" onclick="shareBrowseClose()">Mégse</button>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
var shareBrowseCurrent = "";
|
|
function shareModeSwitch(){
|
|
var mode = document.querySelector('input[name="mode"]:checked').value;
|
|
document.getElementById('share-mode-new').style.display = (mode === 'new') ? '' : 'none';
|
|
document.getElementById('share-mode-existing').style.display = (mode === 'existing') ? '' : 'none';
|
|
}
|
|
function shareBrowseOpen(){
|
|
document.getElementById('share-browse-overlay').style.display = '';
|
|
shareBrowseLoad('');
|
|
}
|
|
function shareBrowseClose(){
|
|
document.getElementById('share-browse-overlay').style.display = 'none';
|
|
}
|
|
function shareBrowsePick(){
|
|
if(shareBrowseCurrent){ document.getElementById('share_path').value = shareBrowseCurrent; }
|
|
shareBrowseClose();
|
|
}
|
|
function shareBrowseLoad(p){
|
|
fetch('/api/sharing/browse?path=' + encodeURIComponent(p))
|
|
.then(function(r){ return r.json(); })
|
|
.then(function(d){
|
|
shareBrowseCurrent = d.path || "";
|
|
document.getElementById('share-browse-path').textContent = d.error ? d.error : (d.path || 'Tárhelyek');
|
|
var list = document.getElementById('share-browse-list');
|
|
list.innerHTML = '';
|
|
if(d.parent){
|
|
var up = document.createElement('div');
|
|
up.innerHTML = '<button type="button" class="btn btn-xs btn-outline">.. vissza</button>';
|
|
up.firstChild.onclick = function(){ shareBrowseLoad(d.parent); };
|
|
list.appendChild(up);
|
|
}
|
|
(d.entries || []).forEach(function(e){
|
|
var row = document.createElement('div');
|
|
row.innerHTML = '<button type="button" class="btn btn-xs btn-outline"></button>';
|
|
row.firstChild.textContent = e.name;
|
|
row.firstChild.onclick = function(){ shareBrowseLoad(e.path); };
|
|
list.appendChild(row);
|
|
});
|
|
});
|
|
}
|
|
</script>
|
|
|
|
{{template "layout_end" .}}
|
|
{{end}}
|