Files
admin 977665d8c0
gates / gates (push) Successful in 27s
The family gate (decisions 63/64, R-780): family members with their own logins, a permanent forwardAuth door per family app, anchored exceptions, min_controller
- internal/family: the family list (bcrypt, generated 4x4 passwords shown once) + 30-day sessions in family.json
  (0600, atomic); a reset (generation), a removal or a logout ends sessions at the next request.
- internal/stacks/family_gate.go: family_gate / family_gate_except / min_controller in .felhom.yml; the door is written
  BEFORE the first start (install and a removed app's restore), a life record in app.yaml, reconciled by the gate loop;
  priority below the install hold, setup gate and sign-up block; every exception anchored ^/prefix(/|$) (finding F1).
- internal/web/family_gate.go: forwardAuth /__felhom_gate/family (app cookie felhom_famgate, host-only, names a store
  session); /__family/start|login|logout on the dashboard host (session cookie felhom_family, Path=/__family);
  sign-in counted per visitor (clientIP) AND per name, short windows; the household's dashboard session vouches.
  RequireAuth never reads a family cookie. The "Család" card on the security page: add / new password / remove.
Red-proofs RP-F1..RP-F7 (felhom.eu audits/family-gate-2026-10-02/A/).

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0159rPz1ZhFKsS53msqPYxtS
2026-10-02 07:42:47 +02:00

49 lines
2.2 KiB
HTML

{{define "familygate"}}
<!DOCTYPE html>
<html lang="{{T "layout.html_lang"}}">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="robots" content="noindex">
<title>{{if .AppName}}{{.AppName}} — {{end}}{{T "family_gate.page_title"}}</title>
<link rel="stylesheet" href="/static/style.css?v={{.Version}}">
</head>
<body class="login-body">
<div class="login-card">
<img src="/static/felhom-logo.svg?v={{.Version}}" alt="Felhom.eu" class="login-logo">
{{- if .AppName}}
<h1 class="login-title">{{.AppName}}</h1>
{{- end}}
{{- if .Notice}}
<p class="alert alert-info" id="family-gate-notice">{{.Notice}}</p>
{{- end}}
{{- if .SignedIn}}
<p id="family-gate-signed-in">{{T "family_gate.signed_in_note"}}</p>
<form method="post" action="/__family/logout">
<button type="submit" class="btn btn-outline btn-full">{{T "family_gate.sign_out"}}</button>
</form>
{{- else}}
<p id="family-gate-text">{{T "family_gate.page_body"}}</p>
<form method="post" action="/__family/login" class="login-form">
<input type="hidden" name="_ft" value="{{.FormToken}}">
<input type="hidden" name="rd" value="{{.RD}}">
<div class="form-group">
<label for="family-name">{{T "family_gate.name"}}</label>
<input type="text" id="family-name" name="name" autocomplete="username" autocapitalize="none" required autofocus class="form-control">
</div>
<div class="form-group">
<label for="family-password">{{T "family_gate.password"}}</label>
<input type="password" id="family-password" name="password" autocomplete="current-password" required class="form-control">
</div>
<button type="submit" class="btn btn-primary btn-full">{{T "family_gate.sign_in"}}</button>
</form>
{{- end}}
{{- if .Host}}
<p class="login-footer">{{.Host}}</p>
{{- end}}
<div class="shell-lang">{{template "lang_globe" .}}</div>
</div>
</body>
</html>
{{end}}