R-970: the box's hub key opens no route; Data tab leftovers; R-1103: the install form's dead branches
gates / gates (push) Successful in 48s
gates / gates (push) Successful in 48s
R-970: /api/config, /api/config/hash, /api/config/apply removed (they read and replaced controller.yaml with every secret, reachable with the box's own hub API key, unsigned; nothing called them). The hub-key Bearer door on /api/selfupdate/ and /api/geo/ and the matching CSRF exemption are gone; the dashboard keeps using those with a session. The route table is buildMux, so a test drives the real one. Data tab: the export password field is autocomplete=new-password with a non-login name; the 2nd copy's status rows that repeated the form are gone (the no-target reason moves into the form). R-1103: app_fields.html loses its installed-only branches (no page serves them since R-1095); the tests that rendered that dead path are retired, their rules asserted on the settings tab (R-694 moved there). Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
This commit is contained in:
@@ -90,7 +90,8 @@ function appMigrate(btn,app,label){
|
||||
|
||||
{{/* „BIZTONSAGI MENTES" — ONE section (v0.321.0). The nightly backup and the 2nd copy were two sections with
|
||||
two titles for one subject, and the 2nd copy's state sat in a two-column grid of monospace values. Now: the
|
||||
nightly backup is a row, the 2nd copy's state is rows, then what it means and the form to change it. The words
|
||||
nightly backup is a row, then what the 2nd copy means and the form that shows and changes it (v0.322.0: the
|
||||
rows that repeated the form are gone). The words
|
||||
are plain: no „off-drive", no „PBS", no „DB/konfiguráció". Pinned by TestAppData_OneBackupSection. */}}
|
||||
<div class="app-section" id="app-backup-section" data-backup-section="1">
|
||||
<h3>{{T "deploy.biztonsagi_mentes"}}</h3>
|
||||
@@ -99,31 +100,8 @@ function appMigrate(btn,app,label){
|
||||
<div class="app-field-value">{{T "app_page.backup_nightly_text"}} <a href="/backups" class="app-info-link">{{T "app_page.backup_status_link"}}</a></div>
|
||||
</div>
|
||||
{{- if .Tier2}}{{with .Tier2}}
|
||||
{{- if .IsHDDApp}}
|
||||
<div class="app-field-row" data-backup-row="second">
|
||||
<div class="app-field-label">{{T "tier2_config.2_mentes"}}</div>
|
||||
<div class="app-field-value">{{if .Disabled}}{{T "tier2_config.kikapcsolva"}}{{else}}{{T "tier2_config.bekapcsolva"}}{{end}}</div>
|
||||
</div>
|
||||
{{- if .NoTarget}}
|
||||
<div class="app-field-row" data-backup-row="target">
|
||||
<div class="app-field-label">{{T "tier2_config.cel"}}</div>
|
||||
<div class="app-field-value text-error">{{T "tier2_config.nincs_elerheto_off_drive_cel"}}</div>
|
||||
</div>
|
||||
<div class="app-field-row">
|
||||
<div class="app-field-label">{{T "tier2_config.megjegyzes"}}</div>
|
||||
<div class="app-field-value">{{.NoTargetReason}}</div>
|
||||
</div>
|
||||
{{- else}}
|
||||
<div class="app-field-row" data-backup-row="target">
|
||||
<div class="app-field-label">{{T "tier2_config.cel_meghajto"}}</div>
|
||||
<div class="app-field-value">{{.EffectiveLabel}}{{if .EffectiveIsSSD}} {{T "tier2_config.csak_db_konfiguracio"}}{{end}}</div>
|
||||
</div>
|
||||
<div class="app-field-row">
|
||||
<div class="app-field-label">{{T "tier2_config.kivalasztas_modja"}}</div>
|
||||
<div class="app-field-value">{{if .Preferred}}{{T "tier2_config.kezi_valasztas"}}{{else}}{{T "tier2_config.automatikus_kisbetu"}}{{end}} — {{.EffectiveDesc}}</div>
|
||||
</div>
|
||||
{{- end}}
|
||||
{{- end}}
|
||||
{{- /* v0.322.0: the 2nd copy's state is said ONCE — by the form below (checkbox, target, hint). Its rows here
|
||||
repeated the same three facts. */}}
|
||||
<p class="app-field-hint" style="margin-top:12px">{{T "tier2_config.a_2_mentes_egy_masik"}}</p>
|
||||
|
||||
{{if not .IsHDDApp}}
|
||||
@@ -167,6 +145,9 @@ function appMigrate(btn,app,label){
|
||||
<option value="{{.Path}}" {{if eq .Path $.Tier2.Preferred}}selected{{end}}>{{.Label}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
{{if .NoTarget}}
|
||||
<div class="form-hint text-error" style="margin-top:.4rem" data-second-backup-notarget="1">{{T "tier2_config.nincs_elerheto_off_drive_cel"}} — {{.NoTargetReason}}</div>
|
||||
{{end}}
|
||||
{{if not .Alternatives}}
|
||||
<div style="font-size:.8rem;color:var(--text-3);margin-top:.4rem">
|
||||
{{T "tier2_config.nincs_masik_adatmeghajto_automatikus_cel"}}
|
||||
@@ -229,7 +210,9 @@ function appMigrate(btn,app,label){
|
||||
|
||||
<h3>{{T "app_export.jelszo_opcionalis"}}</h3>
|
||||
<div style="display:flex;gap:.5rem;margin-bottom:1rem">
|
||||
<input type="password" id="exportPassword" class="form-control" placeholder="{{T "app_export.titkositasi_jelszo"}}" style="flex:1">
|
||||
{{/* v0.322.0: autocomplete="new-password" and a name that is not a login field — the browser filled the household's
|
||||
saved dashboard password in here, and an export could be locked with it unnoticed. */}}
|
||||
<input type="password" id="fabEncryptionKey" name="fab_encryption_key" autocomplete="new-password" data-export-key="1" class="form-control" placeholder="{{T "app_export.titkositasi_jelszo"}}" style="flex:1">
|
||||
<button class="btn btn-sm btn-outline" onclick="togglePw(this)" type="button" id="exportPwToggle" aria-label="{{T "app_export.jelszo_mutatasa"}}">{{T "deploy.megjelenites"}}</button>
|
||||
</div>
|
||||
|
||||
@@ -272,7 +255,7 @@ function csrfH() {
|
||||
}
|
||||
|
||||
function togglePw(btn) {
|
||||
var inp = document.getElementById('exportPassword');
|
||||
var inp = document.getElementById('fabEncryptionKey');
|
||||
var show = inp.type === 'password';
|
||||
inp.type = show ? 'text' : 'password';
|
||||
if (btn) { btn.textContent = show ? '{{T "app_info.elrejtes"}}' : '{{T "deploy.megjelenites"}}'; }
|
||||
@@ -394,7 +377,7 @@ function esc(s) { return String(s).replace(/[&<>"]/g, function(c){ return {'&':'
|
||||
|
||||
async function startExport() {
|
||||
var drive = document.getElementById('destDrive').value;
|
||||
var password = document.getElementById('exportPassword').value;
|
||||
var password = document.getElementById('fabEncryptionKey').value;
|
||||
var stopApp = document.getElementById('stopApp').checked;
|
||||
|
||||
document.getElementById('startBtn').disabled = true;
|
||||
|
||||
@@ -1,55 +1,34 @@
|
||||
{{/* THE APP'S CONFIGURATION FIELDS — the install wizard's form (deploy.html).
|
||||
|
||||
v0.319.0: the settings tab no longer renders this — it shows the install answers as rows and
|
||||
the login as one panel (app_settings.html, app_login.go). The `.AlreadyDeployed` branches below
|
||||
are NOT dead: `/apps/{slug}/install` still answers for an app that is installed, and renders
|
||||
this form read-only. Their guards are what keep an installed app's secrets out of that page
|
||||
(TestDeployPage_DeployedApp_DoesNotCarryTheSecret, TestR709_AnInstalledAppsPasswordIsNotInThePage)
|
||||
and the parity case `deploy_installed` renders them.
|
||||
It renders ONLY for an app that is not installed (v0.322.0, R-1103): since v0.321.0 (R-1095)
|
||||
`/apps/{slug}/install` of an installed app answers 302 to its settings tab, and the settings tab
|
||||
shows the install answers as rows and the login as one panel (app_settings.html, app_login.go).
|
||||
The old read-only „installed" branches are gone; their secret rules live where the values are
|
||||
shown now — R-254/R-709 on the settings tab (TestAppPage_LoginPairPanel, TestR255_NoPlantedSecretReachesAnyPage).
|
||||
|
||||
The secret rules are unchanged and load-bearing:
|
||||
R-254 — an INSTALLED app's `type: secret` value is not in the page; the eye fetches it.
|
||||
R-709 — nor is a `type: password` one.
|
||||
The PRE-DEPLOY hidden input is deliberate: the form must carry what it submits, so the value
|
||||
saved is the one the household was shown (controller/README §318). */}}
|
||||
The PRE-DEPLOY hidden input is deliberate: the form must carry what it submits, so the value
|
||||
saved is the one the household was shown (controller/README §318). */}}
|
||||
|
||||
{{define "app_deploy_fields"}}
|
||||
{{if .AutoFields}}
|
||||
<div class="form-section">
|
||||
<h4>{{T "deploy.automatikusan_generalt_ertekek"}}</h4>
|
||||
{{if .AlreadyDeployed}}
|
||||
<p class="form-section-desc">{{T "deploy.ezek_az_ertekek_automatikusan_jottek"}}</p>
|
||||
{{else}}
|
||||
<p class="form-section-desc">{{T "deploy.ezek_az_ertekek_a_telepitessel"}}</p>
|
||||
{{end}}
|
||||
{{$autoValues := .AutoFieldValues}}
|
||||
{{$stackName := .Stack.Name}}
|
||||
{{$isDeployed := .AlreadyDeployed}}
|
||||
{{range .AutoFields}}
|
||||
{{$val := index $autoValues .EnvVar}}
|
||||
<div class="form-group form-group-auto">
|
||||
<label>{{.Label}} {{if eq .Type "secret"}}<span class="auto-generated-badge"><svg class="ico ico-sm"><use href="#i-check"/></svg> {{T "deploy.automatikusan_generalva"}}</span>{{end}}</label>
|
||||
{{if $val}}
|
||||
{{if eq .Type "secret"}}
|
||||
{{if $isDeployed}}
|
||||
<!-- R-254 site two: on an ALREADY-DEPLOYED app nothing is being submitted, so there is
|
||||
no reason for the value to be in this page at all. It is fetched on demand. The
|
||||
pre-deploy branch below is different and deliberate — the form must carry what it
|
||||
submits, so the saved value is the one the customer was shown (README §318). -->
|
||||
<div class="input-with-button">
|
||||
<input type="password" id="auto-field-{{.EnvVar}}" class="form-control" value="" placeholder="••••••••••••" readonly>
|
||||
<button type="button" class="btn btn-sm btn-outline" onclick="revealAutoField('{{$stackName}}','{{.EnvVar}}', this)">{{T "deploy.megjelenites"}}</button>
|
||||
</div>
|
||||
{{else}}
|
||||
<div class="input-with-button">
|
||||
<input type="password" id="auto-field-{{.EnvVar}}" class="form-control" value="{{$val}}" readonly>
|
||||
<button type="button" class="btn btn-sm btn-outline" onclick="toggleAutoField('auto-field-{{.EnvVar}}', this)">{{T "deploy.megjelenites"}}</button>
|
||||
</div>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<input type="text" id="auto-field-{{.EnvVar}}" class="form-control" value="{{$val}}" readonly>
|
||||
{{end}}
|
||||
{{if and (not $isDeployed) (eq .Type "secret")}}
|
||||
{{if eq .Type "secret"}}
|
||||
<input type="hidden" name="{{.EnvVar}}" value="{{$val}}">
|
||||
{{end}}
|
||||
{{end}}
|
||||
@@ -62,10 +41,6 @@
|
||||
<div class="form-section">
|
||||
<h4>{{T "deploy.beallitasok"}}</h4>
|
||||
{{range .UserFields}}
|
||||
{{/* v0.316.0: an INSTALLED app shows its address once, as the „Cim" row above these
|
||||
fields, so the disabled subdomain input saying the same thing is skipped. The
|
||||
install wizard still asks for it — this is the read-only view's duplicate only. */}}
|
||||
{{if and $.AlreadyDeployed (eq .Type "subdomain")}}{{continue}}{{end}}
|
||||
<div class="form-group">
|
||||
<label for="field-{{.EnvVar}}">
|
||||
{{.Label}}
|
||||
@@ -79,35 +54,22 @@
|
||||
class="form-control subdomain-input"
|
||||
{{/* R-351: a reinstall offers the address the customer's own backup recorded,
|
||||
ahead of the catalog default. Editable — a domain can legitimately change. */}}
|
||||
value="{{if and $.AlreadyDeployed $.DeployedFieldValues}}{{index $.DeployedFieldValues .EnvVar}}{{else if index $.RestoreFieldValues .EnvVar}}{{index $.RestoreFieldValues .EnvVar}}{{else}}{{.Default}}{{end}}"
|
||||
value="{{if index $.RestoreFieldValues .EnvVar}}{{index $.RestoreFieldValues .EnvVar}}{{else}}{{.Default}}{{end}}"
|
||||
placeholder="{{T "deploy.aldomain_placeholder"}}"
|
||||
pattern="[a-z0-9]([a-z0-9-]*[a-z0-9])?"
|
||||
required
|
||||
{{if $.AlreadyDeployed}}disabled{{end}}
|
||||
oninput="this.value=this.value.toLowerCase().replace(/[^a-z0-9-]/g,'')">
|
||||
<span class="subdomain-suffix">.{{$.Domain}}</span>
|
||||
</div>
|
||||
{{if not $.AlreadyDeployed}}
|
||||
<span class="form-hint">{{T "deploy.az_aldomain_telepites_utan_nem"}}</span>
|
||||
{{end}}
|
||||
{{else if eq .Type "select"}}
|
||||
<select id="field-{{.EnvVar}}" name="{{.EnvVar}}" class="form-control"
|
||||
{{if $.AlreadyDeployed}}disabled{{end}}>
|
||||
<select id="field-{{.EnvVar}}" name="{{.EnvVar}}" class="form-control">
|
||||
{{range .Options}}
|
||||
<option value="{{.Value}}">{{.Label}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
{{else if eq .Type "password"}}
|
||||
<div class="input-with-button">
|
||||
{{- if $.AlreadyDeployed}}
|
||||
{{- /* R-709 (v0.280.0): an installed app's password is never in this page; the eye fetches it. */}}
|
||||
<input type="password" id="field-{{.EnvVar}}" class="form-control" value="" placeholder="••••••••••••" disabled>
|
||||
{{- if not (and $.RestoredLogins (index $.RestoredLogins .EnvVar))}}
|
||||
<button type="button" class="btn btn-sm btn-outline pw-toggle-btn"
|
||||
onclick="revealPasswordField('{{$.Stack.Name}}', '{{.EnvVar}}', this)"
|
||||
title="{{T "deploy.megjelenites"}}">👁</button>
|
||||
{{- end}}
|
||||
{{- else}}
|
||||
<input type="password" id="field-{{.EnvVar}}" name="{{.EnvVar}}"
|
||||
class="form-control" value="{{.Default}}"
|
||||
placeholder="{{.Placeholder}}"
|
||||
@@ -118,27 +80,20 @@
|
||||
title="{{T "deploy.megjelenites"}}">👁</button>
|
||||
<button type="button" class="btn btn-sm btn-outline"
|
||||
onclick="generatePassword('field-{{.EnvVar}}', 'field-confirm-{{.EnvVar}}', '{{.Generate}}')">{{T "deploy.generalas"}}</button>
|
||||
{{- end}}
|
||||
</div>
|
||||
{{if $.AlreadyDeployed}}
|
||||
<span class="form-hint">{{if and $.RestoredLogins (index $.RestoredLogins .EnvVar)}}{{T "deploy.login_from_backup"}}{{else}}{{T "deploy.telepiteskor_beallitott_kezdeti_jelszo_h"}}{{end}}</span>
|
||||
{{else}}
|
||||
<div class="input-with-button" style="margin-top:.25rem">
|
||||
<input type="password" id="field-confirm-{{.EnvVar}}"
|
||||
class="form-control" placeholder="{{T "deploy.jelszo_megerositese"}}"
|
||||
data-confirm-for="field-{{.EnvVar}}">
|
||||
</div>
|
||||
{{end}}
|
||||
{{else if eq .Type "boolean"}}
|
||||
<label class="toggle">
|
||||
<input type="checkbox" id="field-{{.EnvVar}}" name="{{.EnvVar}}" value="true"
|
||||
{{if $.AlreadyDeployed}}disabled{{end}}>
|
||||
<input type="checkbox" id="field-{{.EnvVar}}" name="{{.EnvVar}}" value="true">
|
||||
<span class="toggle-label">{{T "deploy.igen"}}</span>
|
||||
</label>
|
||||
{{else if eq .Type "path"}}
|
||||
{{if $.StoragePaths}}
|
||||
<select id="field-{{.EnvVar}}" name="{{.EnvVar}}" class="form-control"
|
||||
{{if $.AlreadyDeployed}}disabled{{end}}
|
||||
onchange="checkStorageSpace(this)">
|
||||
{{range $.StoragePaths}}
|
||||
<option value="{{.Path}}" data-free-percent="{{printf "%.0f" .FreePercent}}"
|
||||
@@ -147,13 +102,10 @@
|
||||
configured default — it is where this app's data actually lived, and
|
||||
restoring into a different drive is the mismatch the restore then has
|
||||
to stop and name. The customer can still pick another. */}}
|
||||
{{if $.AlreadyDeployed}}{{if eq .Path $.CurrentHDDPath}}selected{{end}}{{else if $.RestorePrefillHDDPath}}{{if and (eq .Path $.RestorePrefillHDDPath) (not .NotAllowed)}}selected{{end}}{{else if and .IsDefault (not .NotAllowed)}}selected{{end}}>
|
||||
{{if $.RestorePrefillHDDPath}}{{if and (eq .Path $.RestorePrefillHDDPath) (not .NotAllowed)}}selected{{end}}{{else if and .IsDefault (not .NotAllowed)}}selected{{end}}>
|
||||
{{T "deploy.szabad_2"}}{{if .NotAllowed}} ({{.NotAllowedNote}}){{else if .IsDefault}} {{T "deploy.alapertelmezett"}}{{end}}
|
||||
</option>
|
||||
{{end}}
|
||||
{{if $.CurrentHDDPathMissing}}
|
||||
<option value="{{$.CurrentHDDPath}}" selected disabled>{{T "deploy.nem_elerheto"}}</option>
|
||||
{{end}}
|
||||
</select>
|
||||
<div id="storage-space-warn" class="form-hint" style="color:var(--warn);display:none">
|
||||
<svg class="ico ico-sm"><use href="#i-triangle-alert"/></svg> {{T "deploy.a_kivalasztott_tarhely_majdnem_megtelt"}}
|
||||
@@ -165,16 +117,14 @@
|
||||
<input type="text" id="field-{{.EnvVar}}" name="{{.EnvVar}}"
|
||||
class="form-control" value="{{.Default}}"
|
||||
placeholder="{{.Placeholder}}"
|
||||
{{if .Required}}required{{end}}
|
||||
{{if $.AlreadyDeployed}}disabled{{end}}>
|
||||
{{if .Required}}required{{end}}>
|
||||
<span class="form-hint" style="color:var(--warn)">{{T "deploy.nincs_regisztralt_adattarolo_adja_meg"}}</span>
|
||||
{{end}}
|
||||
{{else}}
|
||||
<input type="text" id="field-{{.EnvVar}}" name="{{.EnvVar}}"
|
||||
class="form-control" value="{{.Default}}"
|
||||
placeholder="{{.Placeholder}}"
|
||||
{{if .Required}}required{{end}}
|
||||
{{if $.AlreadyDeployed}}disabled{{end}}>
|
||||
{{if .Required}}required{{end}}>
|
||||
{{end}}
|
||||
|
||||
{{if and .Description (ne .Type "subdomain")}}
|
||||
|
||||
Reference in New Issue
Block a user