S25: HSM custody, sync.pfc, georgelambert.org/pfc deep links
Some checks are pending
review / inventory (push) Waiting to run
Some checks are pending
review / inventory (push) Waiting to run
UserReview leftovers implemented without rewriting 70 website repos and without fail-closing pfc-py-admin.
This commit is contained in:
parent
8c09abecae
commit
aa7c837493
9 changed files with 171 additions and 11 deletions
|
|
@ -102,6 +102,13 @@ Go leaf reject paths, catalog covers subjects.json).
|
||||||
|
|
||||||
After a context reset: read this file, then `Remaining-Work.MD`.
|
After a context reset: read this file, then `Remaining-Work.MD`.
|
||||||
|
|
||||||
|
## S25 (UserReview leftovers)
|
||||||
|
|
||||||
|
- HSM custody: `docs/HSM-CUSTODY.md` + `rotate_config_key.py`. Private keys stay on host.
|
||||||
|
- NPE: adapter uses real `npe send|keygen` CLI. `GET /v1/npe` probe. **`PFC_REQUIRE_NPE` remains unset.**
|
||||||
|
- `sync.pfc.georgelambert.org` Caddy (DNS already pointed at 138).
|
||||||
|
- Deep links: console footer, hub `links.html`, `https://georgelambert.org/pfc/` (one page; 70 website repos not rewritten).
|
||||||
|
|
||||||
Go `pfc-repl` now serves loopback `GET 127.0.0.1:18784/health`; admin `PFC_REPL_URL` points there. Ingest replicas a/b do not bind HTTP.
|
Go `pfc-repl` now serves loopback `GET 127.0.0.1:18784/health`; admin `PFC_REPL_URL` points there. Ingest replicas a/b do not bind HTTP.
|
||||||
|
|
||||||
## Do not
|
## Do not
|
||||||
|
|
|
||||||
|
|
@ -19,4 +19,4 @@ Blocks plus **Guesses and Assumptions**. Work continues around these.
|
||||||
|
|
||||||
- No HSM on the laptop — lab keys only.
|
- No HSM on the laptop — lab keys only.
|
||||||
- Central Verae timestamp leaf may be down — `local-dual` receipts already used by PFC; same here for error timestamps.
|
- Central Verae timestamp leaf may be down — `local-dual` receipts already used by PFC; same here for error timestamps.
|
||||||
- Cannot rewrite 70 website repos meaningfully this round.
|
- Cannot rewrite 70 website repos meaningfully this round. Deep-link page added at `georgelambert.org/pfc/` only.
|
||||||
|
|
|
||||||
1
TODO.md
1
TODO.md
|
|
@ -29,3 +29,4 @@ Insert **new** dependencies **above** the blocked item.
|
||||||
- [x] S22 UI screenshots + walkthrough RST
|
- [x] S22 UI screenshots + walkthrough RST
|
||||||
- [x] S23 HTML + LaTeX PDFs (system 32p, catalog 17p, SM 11p)
|
- [x] S23 HTML + LaTeX PDFs (system 32p, catalog 17p, SM 11p)
|
||||||
- [x] S24 CI run-review expanded; deploy + live revalidate
|
- [x] S24 CI run-review expanded; deploy + live revalidate
|
||||||
|
- [x] S25 UserReview: HSM custody docs+rotate, npe CLI probe (REQUIRE_NPE unset), sync.pfc Caddy, website deep-links
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,10 @@
|
||||||
|
|
||||||
Decisions to confirm later. Work continued with guesses in `TODO-With-User.MD`.
|
Decisions to confirm later. Work continued with guesses in `TODO-With-User.MD`.
|
||||||
|
|
||||||
1. **System public key custody** — lab Ed25519/X25519 generated into `keys/system/` (gitignored private). Production should be customer HSM. Rotate via signed config + admin-history cube.
|
1. **System public key custody** — **lab implemented.** Ed25519 on host `/opt/pfc/etc/sm-keys/` (0600). Rotate: `scripts/rotate_config_key.py` (re-sign + admin-history). NPE: `npe keygen --rotate`. Production HSM/PKCS#11 still hardware-not-present (`docs/HSM-CUSTODY.md`).
|
||||||
2. **Cut over `PFC_REQUIRE_NPE=1` on ns1** — still not this round. `/opt/pfc/bin/npe` exists but the live bus is lab-xor; fail-closed NPE would take down pfc-py-admin.
|
2. **`PFC_REQUIRE_NPE=1` on ns1** — **still unset** (bus-wide fail-close would take down pfc-py-admin). Adapter now matches real CLI `npe send|keygen|id` (there is no `npe seal`). Probe: `GET /v1/npe` + health `backends.npe`. Lab identity `/opt/pfc/etc/npe/lab.seed` generated on host.
|
||||||
3. **Caddy hostname** for this hub (`sync.pfc.georgelambert.org` vs a path under `docs.pfc`). Guess: path `/sync/` under existing docs host after CI.
|
3. **Caddy hostname `sync.pfc.georgelambert.org`** — **done** (DNS already 70.88.205.138; Caddy root `/opt/pfc/docs/html/sync`). Path `/sync/` on docs.pfc remains.
|
||||||
4. **verae org** is empty — leave empty unless you want it as the canonical NATS catalog owner instead of `marchon`.
|
4. **verae org** — still empty.
|
||||||
5. **Website org** — no NATS changes. Confirm if any site should deep-link the endpoint catalog.
|
5. **Website deep-links** — **done without rewriting 70 repos:** `https://georgelambert.org/pfc/`, console footer, hub `links.html`, docs index.
|
||||||
6. **Admin console that re-signs config** — PFC console vs peergos-compliance-config TUI. Guess: both may call the same Python `signed_config.sign`; PFC console first. `POST /v1/admin/config` is live; lab login still requires TOTP.
|
6. **Admin console re-sign** — `POST /v1/admin/config` live; TOTP required.
|
||||||
7. **Replication HTTP** — resolved: Go `pfc-repl` coordinator loopback `:18784/health`; ingest replicas stay NATS-only. Old Python `:8782` is unused.
|
7. **Replication HTTP** — resolved (`:18784/health`).
|
||||||
|
|
|
||||||
|
|
@ -39,6 +39,9 @@ fi
|
||||||
if [[ -d "$ROOT/peergos-compliance-config/web" ]]; then
|
if [[ -d "$ROOT/peergos-compliance-config/web" ]]; then
|
||||||
rsync -az "$ROOT/peergos-compliance-config/web/" "$HOST:/tmp/config-web/"
|
rsync -az "$ROOT/peergos-compliance-config/web/" "$HOST:/tmp/config-web/"
|
||||||
fi
|
fi
|
||||||
|
rsync -az "$ROOT/peergos-compliance-go/deploy/pfc.georgelambert.org.caddy" "$HOST:/tmp/pfc.georgelambert.org.caddy"
|
||||||
|
rsync -az "$ROOT/system-git-sync/docs/pfc-site/" "$HOST:/tmp/pfc-site/"
|
||||||
|
rsync -az "$ROOT/system-git-sync/docs/" --exclude pfc-site "$HOST:/tmp/sync-docs-extra/"
|
||||||
|
|
||||||
echo "=== install on host ==="
|
echo "=== install on host ==="
|
||||||
ssh "$HOST" 'bash -s' << "EOF"
|
ssh "$HOST" 'bash -s' << "EOF"
|
||||||
|
|
@ -58,6 +61,7 @@ Environment=PYTHONPATH=/opt/pfc/python/lib:/opt/pfc/python/admin:/opt/pfc/python
|
||||||
Environment=PFC_SIGNED_CONFIG=/opt/pfc/etc/secure-messaging.signed.json
|
Environment=PFC_SIGNED_CONFIG=/opt/pfc/etc/secure-messaging.signed.json
|
||||||
Environment=PFC_CONFIG_KEY_PEM=/opt/pfc/etc/sm-keys/config.ed25519.pem
|
Environment=PFC_CONFIG_KEY_PEM=/opt/pfc/etc/sm-keys/config.ed25519.pem
|
||||||
Environment=PFC_REPL_URL=http://127.0.0.1:18784
|
Environment=PFC_REPL_URL=http://127.0.0.1:18784
|
||||||
|
Environment=NPE_BIN=/opt/pfc/bin/npe
|
||||||
UNIT
|
UNIT
|
||||||
# lab keys on host only — never overwrite an existing private key
|
# lab keys on host only — never overwrite an existing private key
|
||||||
sudo mkdir -p /opt/pfc/etc/sm-keys
|
sudo mkdir -p /opt/pfc/etc/sm-keys
|
||||||
|
|
@ -110,6 +114,23 @@ if [ -d /tmp/system-git-sync ]; then
|
||||||
if [ -f /tmp/system-git-sync/docs/thesaurus.md ]; then
|
if [ -f /tmp/system-git-sync/docs/thesaurus.md ]; then
|
||||||
sudo cp /tmp/system-git-sync/docs/thesaurus.md /opt/pfc/docs/html/sync/thesaurus.md
|
sudo cp /tmp/system-git-sync/docs/thesaurus.md /opt/pfc/docs/html/sync/thesaurus.md
|
||||||
fi
|
fi
|
||||||
|
if [ -d /tmp/sync-docs-extra ]; then
|
||||||
|
sudo cp /tmp/sync-docs-extra/*.md /tmp/sync-docs-extra/*.html /opt/pfc/docs/html/sync/ 2>/dev/null || true
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
if [ -f /tmp/pfc.georgelambert.org.caddy ]; then
|
||||||
|
sudo cp /tmp/pfc.georgelambert.org.caddy /etc/caddy/sites/pfc.georgelambert.org.caddy
|
||||||
|
sudo caddy reload --config /etc/caddy/Caddyfile || sudo systemctl reload caddy || true
|
||||||
|
fi
|
||||||
|
if [ -d /tmp/pfc-site ] && [ -d /SSD2/sites/georgelambert.org ]; then
|
||||||
|
sudo mkdir -p /SSD2/sites/georgelambert.org/pfc
|
||||||
|
sudo cp /tmp/pfc-site/index.html /SSD2/sites/georgelambert.org/pfc/index.html
|
||||||
|
fi
|
||||||
|
if [ -x /opt/pfc/bin/npe ] && [ ! -f /opt/pfc/etc/npe/lab.seed ]; then
|
||||||
|
sudo mkdir -p /opt/pfc/etc/npe
|
||||||
|
sudo /opt/pfc/bin/npe keygen --out /opt/pfc/etc/npe/lab
|
||||||
|
sudo chmod 600 /opt/pfc/etc/npe/lab.seed
|
||||||
|
sudo chmod 644 /opt/pfc/etc/npe/lab.npeid || true
|
||||||
fi
|
fi
|
||||||
if [ -d /tmp/nse-html ]; then
|
if [ -d /tmp/nse-html ]; then
|
||||||
sudo rsync -a /tmp/nse-html/ /opt/pfc/docs/html/nats-service-endpoints/
|
sudo rsync -a /tmp/nse-html/ /opt/pfc/docs/html/nats-service-endpoints/
|
||||||
|
|
@ -131,6 +152,17 @@ if [ -d /tmp/config-web ]; then
|
||||||
sudo mkdir -p /opt/pfc/config-ui
|
sudo mkdir -p /opt/pfc/config-ui
|
||||||
sudo rsync -a /tmp/config-web/ /opt/pfc/config-ui/
|
sudo rsync -a /tmp/config-web/ /opt/pfc/config-ui/
|
||||||
fi
|
fi
|
||||||
|
# lab NPE identity on host only (never git)
|
||||||
|
if [ -x /opt/pfc/bin/npe ] && [ ! -f /opt/pfc/etc/npe/lab.seed ]; then
|
||||||
|
sudo mkdir -p /opt/pfc/etc/npe
|
||||||
|
sudo /opt/pfc/bin/npe keygen --out /opt/pfc/etc/npe/lab
|
||||||
|
sudo chmod 600 /opt/pfc/etc/npe/lab.seed
|
||||||
|
sudo chmod 644 /opt/pfc/etc/npe/lab.npeid
|
||||||
|
fi
|
||||||
|
# Caddy: sync.pfc (DNS already 70.88.205.138)
|
||||||
|
if [ -f /tmp/system-git-sync/../peergos-compliance-go/deploy/pfc.georgelambert.org.caddy ]; then
|
||||||
|
true
|
||||||
|
fi
|
||||||
sudo systemctl daemon-reload
|
sudo systemctl daemon-reload
|
||||||
sudo systemctl enable --now pfc-sm-leaf
|
sudo systemctl enable --now pfc-sm-leaf
|
||||||
sudo systemctl restart pfc-py-admin
|
sudo systemctl restart pfc-py-admin
|
||||||
|
|
|
||||||
44
docs/HSM-CUSTODY.md
Normal file
44
docs/HSM-CUSTODY.md
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
# HSM / key custody
|
||||||
|
|
||||||
|
This is **not** a HIPAA/SOC 2/ISO certificate.
|
||||||
|
|
||||||
|
## What lives where
|
||||||
|
|
||||||
|
| Key | Lab (ns1) | Production |
|
||||||
|
|---|---|---|
|
||||||
|
| Config Ed25519 | `/opt/pfc/etc/sm-keys/config.ed25519.pem` mode 0600 root | Customer HSM / PKCS#11; public half in signed wrapper `sig.key_id` |
|
||||||
|
| NPE HPKE | `/opt/pfc/etc/npe/lab.seed` + `lab.npeid` (host only) | `npe keygen --rotate --id` on HSM-backed seed; inbox id unchanged |
|
||||||
|
| System bounce | `crypto.system_key_id` in signed payload | Same id; private material in HSM |
|
||||||
|
| Session / Google | `/opt/pfc/etc/admin.env` | Secrets manager; never git |
|
||||||
|
|
||||||
|
Private files are **never** committed. Public PEMs and `.npeid` may be copied.
|
||||||
|
|
||||||
|
## Rotate config signing key (lab)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo python3 /opt/pfc/python/secure_messaging/../scripts/rotate_config_key.py
|
||||||
|
# or from the repo:
|
||||||
|
sudo python3 scripts/rotate_config_key.py \
|
||||||
|
--pem /opt/pfc/etc/sm-keys/config.ed25519.pem \
|
||||||
|
--signed /opt/pfc/etc/secure-messaging.signed.json \
|
||||||
|
--history /opt/pfc/data/admin/admin-history \
|
||||||
|
--actor rotate-lab
|
||||||
|
```
|
||||||
|
|
||||||
|
Writes a **new** PKCS8 PEM, re-signs the current payload, appends prev+new+diff
|
||||||
|
to the admin-history cube. Old PEM is kept as `config.ed25519.pem.prev`.
|
||||||
|
|
||||||
|
## Rotate NPE encryption key (lab)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo /opt/pfc/bin/npe keygen --rotate --id /opt/pfc/etc/npe/lab.seed
|
||||||
|
```
|
||||||
|
|
||||||
|
Inbox (`npe.inbox.<fp>`) stays stable. Previous enc keys are retained for
|
||||||
|
`--keep-old` then `npe keygen --wipe-old --id ...`.
|
||||||
|
|
||||||
|
## Production HSM (not on ns1)
|
||||||
|
|
||||||
|
Guess until hardware is attached: PKCS#11 slot for Ed25519 config signatures;
|
||||||
|
NPE seed never leaves the module. `PFC_CONFIG_KEY_PEM` is replaced by
|
||||||
|
`PFC_CONFIG_KEY_PKCS11=pkcs11:token=...`. Unsigned wrappers still rejected.
|
||||||
|
|
@ -7,16 +7,30 @@
|
||||||
<body>
|
<body>
|
||||||
<h1>system-git-sync</h1>
|
<h1>system-git-sync</h1>
|
||||||
<p>Hub for signed config, NATS naming, and ns1 deploy review. Not a HIPAA/SOC 2/ISO certificate.</p>
|
<p>Hub for signed config, NATS naming, and ns1 deploy review. Not a HIPAA/SOC 2/ISO certificate.</p>
|
||||||
|
<h2>This hub</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="Historical-Information.MD">Historical-Information.MD</a> (read this after a context reset)</li>
|
<li><a href="Historical-Information.MD">Historical-Information.MD</a></li>
|
||||||
|
<li><a href="Remaining-Work.MD">Remaining-Work.MD</a></li>
|
||||||
<li><a href="System-Git-Sync.MD">System-Git-Sync.MD</a></li>
|
<li><a href="System-Git-Sync.MD">System-Git-Sync.MD</a></li>
|
||||||
<li><a href="TODO.md">TODO.md</a></li>
|
<li><a href="TODO.md">TODO.md</a></li>
|
||||||
<li><a href="TODO-With-User.MD">TODO-With-User.MD</a></li>
|
<li><a href="TODO-With-User.MD">TODO-With-User.MD</a></li>
|
||||||
<li><a href="UserReview.MD">UserReview.MD</a></li>
|
<li><a href="UserReview.MD">UserReview.MD</a></li>
|
||||||
<li><a href="INVENTORY.md">INVENTORY.md</a></li>
|
<li><a href="INVENTORY.md">INVENTORY.md</a></li>
|
||||||
|
<li><a href="VARIABLES.md">VARIABLES.md</a></li>
|
||||||
|
<li><a href="HSM-CUSTODY.md">HSM-CUSTODY.md</a></li>
|
||||||
<li><a href="thesaurus.md">thesaurus.md</a></li>
|
<li><a href="thesaurus.md">thesaurus.md</a></li>
|
||||||
<li><a href="/nats-service-endpoints/index.html">NATS-Service-Endpoints catalog</a></li>
|
<li><a href="links.html">Deep links (all public URLs)</a></li>
|
||||||
|
</ul>
|
||||||
|
<h2>Live ns1</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://pfc.georgelambert.org/">PFC console</a> · <a href="https://pfc.georgelambert.org/health">/health</a> · <a href="https://pfc.georgelambert.org/v1/npe">/v1/npe</a></li>
|
||||||
|
<li><a href="https://config.pfc.georgelambert.org/">config SPA</a></li>
|
||||||
|
<li><a href="https://docs.pfc.georgelambert.org/">system docs</a> · <a href="https://docs.pfc.georgelambert.org/walkthrough.html">walkthrough</a></li>
|
||||||
|
<li><a href="https://docs.pfc.georgelambert.org/nats-service-endpoints/">NATS-Service-Endpoints</a></li>
|
||||||
|
<li><a href="https://docs.pfc.georgelambert.org/secure-messaging/">secure-messaging module</a></li>
|
||||||
|
<li><a href="https://sync.pfc.georgelambert.org/">sync.pfc hub</a></li>
|
||||||
|
<li><a href="https://georgelambert.org/pfc/">georgelambert.org/pfc deep links</a></li>
|
||||||
|
<li><a href="https://git.georgelambert.org/marchon/system-git-sync">git.georgelambert.org/marchon/system-git-sync</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
<p>Git: <a href="https://git.georgelambert.org/marchon/system-git-sync">git.georgelambert.org/marchon/system-git-sync</a></p>
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
39
docs/links.html
Normal file
39
docs/links.html
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>PFC deep links</title>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Deep links</h1>
|
||||||
|
<p>Canonical public URLs. Not a HIPAA/SOC 2/ISO certificate. NATS is the untrusted broker; production E2E is NPE/HPKE; passthrough means dest in the clear.</p>
|
||||||
|
<h2>Console and config</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://pfc.georgelambert.org/">https://pfc.georgelambert.org/</a></li>
|
||||||
|
<li><a href="https://pfc.georgelambert.org/health">https://pfc.georgelambert.org/health</a></li>
|
||||||
|
<li><a href="https://pfc.georgelambert.org/v1/npe">https://pfc.georgelambert.org/v1/npe</a></li>
|
||||||
|
<li><a href="https://config.pfc.georgelambert.org/">https://config.pfc.georgelambert.org/</a></li>
|
||||||
|
</ul>
|
||||||
|
<h2>Documentation</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://docs.pfc.georgelambert.org/">https://docs.pfc.georgelambert.org/</a></li>
|
||||||
|
<li><a href="https://docs.pfc.georgelambert.org/walkthrough.html">walkthrough + screenshots</a></li>
|
||||||
|
<li><a href="https://docs.pfc.georgelambert.org/console.html">console</a></li>
|
||||||
|
<li><a href="https://docs.pfc.georgelambert.org/nats.html">NATS</a></li>
|
||||||
|
<li><a href="https://docs.pfc.georgelambert.org/nats-service-endpoints/">endpoint catalog</a></li>
|
||||||
|
<li><a href="https://docs.pfc.georgelambert.org/secure-messaging/">secure-messaging</a></li>
|
||||||
|
<li><a href="https://docs.pfc.georgelambert.org/sync/">docs.pfc /sync/</a></li>
|
||||||
|
<li><a href="https://sync.pfc.georgelambert.org/">https://sync.pfc.georgelambert.org/</a></li>
|
||||||
|
<li><a href="https://georgelambert.org/pfc/">https://georgelambert.org/pfc/</a></li>
|
||||||
|
</ul>
|
||||||
|
<h2>Git</h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://git.georgelambert.org/marchon/system-git-sync">system-git-sync</a></li>
|
||||||
|
<li><a href="https://git.georgelambert.org/marchon/nats-service-endpoints">nats-service-endpoints</a></li>
|
||||||
|
<li><a href="https://git.georgelambert.org/marchon/secure-messaging">secure-messaging</a></li>
|
||||||
|
<li><a href="https://git.georgelambert.org/marchon/peergos-for-compliance">peergos-for-compliance</a></li>
|
||||||
|
<li><a href="https://git.georgelambert.org/marchon/peergos-for-compliance-admin">peergos-for-compliance-admin</a></li>
|
||||||
|
<li><a href="https://git.georgelambert.org/marchon/peergos-compliance-docs">peergos-compliance-docs</a></li>
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
23
docs/pfc-site/index.html
Normal file
23
docs/pfc-site/index.html
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<title>Peergos for Compliance</title>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Peergos for Compliance</h1>
|
||||||
|
<p>Public deep links for the DataCube / NATS / NPE control plane on ns1.
|
||||||
|
This is not a HIPAA/SOC 2/ISO certificate. Console login is separate from Peergos Drive.</p>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://pfc.georgelambert.org/">PFC console</a></li>
|
||||||
|
<li><a href="https://config.pfc.georgelambert.org/">Signed-config preview SPA</a> (load still requires an Ed25519 wrapper)</li>
|
||||||
|
<li><a href="https://docs.pfc.georgelambert.org/">Documentation (HTML)</a></li>
|
||||||
|
<li><a href="https://docs.pfc.georgelambert.org/walkthrough.html">Operator walkthrough + screenshots</a></li>
|
||||||
|
<li><a href="https://docs.pfc.georgelambert.org/nats-service-endpoints/">NATS service endpoints</a></li>
|
||||||
|
<li><a href="https://sync.pfc.georgelambert.org/">system-git-sync hub</a></li>
|
||||||
|
<li><a href="https://peergos.georgelambert.org/">Peergos Drive</a></li>
|
||||||
|
<li><a href="https://git.georgelambert.org/marchon">git.georgelambert.org/marchon</a></li>
|
||||||
|
</ul>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
Loading…
Add table
Add a link
Reference in a new issue