v0.7.40-beta - beheerdersaccount en bind meteen klaarzetten
Het installatiescript kan nu allebei zelf regelen, zodat je na afloop niet meer naar de webinterface hoeft om een account te claimen en niet meer in .env hoeft te duiken om erbij te kunnen. Beheerdersaccount: - Op een terminal wordt gevraagd of je er meteen een wil, met naam en wachtwoord (twee keer, echo uit). - Automatisch via --admin NAAM plus --admin-password-file of SU_ADMIN_PASSWORD; zonder bron en zonder terminal maakt het script er zelf een van 24 tekens en toont die. - --admin-password weigert bewust: argumenten zijn zichtbaar in 'ps'. Het wachtwoord gaat via stdin naar curl, niet als argument. - Nieuw --create-admin voor een installatie die al draait. Bereikbaarheid: - Keuzemenu voor BIND (deze server / hele netwerk / eigen adres), met het gedetecteerde serveradres erbij. - Bij opnieuw installeren is de bestaande instelling het uitgangspunt, zodat enter je server niet ongemerkt terugzet op loopback. Opgeloste fouten: - Een bestaande .env bleef altijd ongemoeid, ook met --bind: de installatie leek te lukken terwijl de server op het oude adres bleef luisteren. - --update rekende met de standaardpoort in plaats van met wat er in .env staat, waardoor de wachtlus en het slotadres niet klopten. - --dry-run riep 'sudo docker' aan en vroeg dus om een wachtwoord terwijl het net beloofd had niets te doen; zonder terminal liep het daarop vast. - Ongeldig bind-adres en poort buiten 1-65535 worden nu meteen geweigerd. Getest met een pseudo-terminal voor de vragen en tegen een echt draaiende server voor het aanmaken van het account, inclusief een wachtwoord vol aanhalingstekens en backslashes, een geweigerd tweede account en een server die niet reageert. De e2e-tests slaan zichzelf over waar curl ontbreekt, zoals in het CI-image. 992 tests groen. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01C7oLCRYzY5ixJ5Sv8Y8EFb
This commit is contained in:
parent
d7cbb4f440
commit
8e53b90615
5 changed files with 865 additions and 26 deletions
49
CHANGELOG.md
49
CHANGELOG.md
|
|
@ -1,3 +1,52 @@
|
||||||
|
# v0.7.40-beta — Account en bereikbaarheid meteen goed
|
||||||
|
|
||||||
|
Na het installeren was je nog niet klaar: je moest zelf naar de webinterface om
|
||||||
|
een beheerdersaccount te claimen, en stond `BIND` op `127.0.0.1`, dan kón je daar
|
||||||
|
niet eens bij zonder eerst `.env` aan te passen. Het script regelt nu allebei.
|
||||||
|
|
||||||
|
**Beheerdersaccount.** Op een terminal vraagt het script of je er meteen één wil,
|
||||||
|
en zo ja om een naam en wachtwoord (twee keer, met de echo uit). Automatisch gaat
|
||||||
|
het met `--admin NAAM` plus `--admin-password-file PAD` of `SU_ADMIN_PASSWORD`.
|
||||||
|
Is er geen wachtwoordbron én geen terminal, dan maakt het script er zelf een van
|
||||||
|
24 tekens en zet die op het scherm.
|
||||||
|
|
||||||
|
Het wachtwoord kan bewust *niet* als optie mee: `--admin-password` weigert met
|
||||||
|
uitleg. Opdrachtregelargumenten zijn voor elke gebruiker op de server zichtbaar
|
||||||
|
met `ps` en blijven in je shell-geschiedenis staan. Onderweg naar de server gaat
|
||||||
|
het via stdin naar `curl`, niet als argument.
|
||||||
|
|
||||||
|
Nieuw is ook **`--create-admin`**: alleen het account aanmaken, bij een
|
||||||
|
installatie die al draait. Voor als het de eerste keer is misgegaan of je het
|
||||||
|
hebt overgeslagen. De poort komt daarbij uit `.env`.
|
||||||
|
|
||||||
|
**Bereikbaarheid.** Het script vraagt nu waarop de interface moet luisteren:
|
||||||
|
alleen deze server, het hele netwerk (met het gedetecteerde adres erbij), of een
|
||||||
|
adres dat je zelf opgeeft. Installeer je opnieuw over een bestaande map, dan is
|
||||||
|
je huidige instelling het uitgangspunt en houdt enter die vast.
|
||||||
|
|
||||||
|
Daarbij zat een fout die je zelf tegenkwam: een bestaande `.env` bleef *altijd*
|
||||||
|
ongemoeid, ook als je `--bind` meegaf. De installatie leek dan te lukken terwijl
|
||||||
|
de server op het oude adres bleef luisteren. Nu wordt doorgevoerd wat je
|
||||||
|
expliciet meegeeft, en blijft de rest staan. Andersom rekent het script bij
|
||||||
|
`--update` voortaan met wat er écht in `.env` staat: draaide je op poort 8080,
|
||||||
|
dan wachtte het daarvoor op poort 5000 en meldde het het verkeerde adres.
|
||||||
|
|
||||||
|
Verder: `--dry-run` riep `sudo docker` aan en vroeg dus om een wachtwoord,
|
||||||
|
terwijl het net beloofd had niets te doen — zonder terminal liep het daar vast.
|
||||||
|
Een proefdraai spreekt de Docker-daemon nu niet meer aan. En een ongeldig
|
||||||
|
bind-adres of een poort buiten 1–65535 wordt meteen geweigerd in plaats van als
|
||||||
|
een onbegrijpelijke fout uit `docker compose` terug te komen.
|
||||||
|
|
||||||
|
De vragen worden allemaal vooraf gesteld, zodat je kunt weglopen terwijl het
|
||||||
|
image gebouwd wordt.
|
||||||
|
|
||||||
|
Getest met een echte pseudo-terminal voor de vragen, en tegen een echt
|
||||||
|
draaiende server voor het aanmaken van het account — inclusief een wachtwoord
|
||||||
|
vol aanhalingstekens en backslashes, een tweede account dat geweigerd hoort te
|
||||||
|
worden, en een server die niet reageert.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
# v0.7.30 — Installeren met één regel
|
# v0.7.30 — Installeren met één regel
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
32
README.md
32
README.md
|
|
@ -37,7 +37,9 @@ curl -fsSL https://git.ramonbesselink.nl/bes-r/server-up/raw/branch/main/install
|
||||||
```
|
```
|
||||||
|
|
||||||
Dat controleert je systeem, installeert Docker als het ontbreekt, zet Server Up
|
Dat controleert je systeem, installeert Docker als het ontbreekt, zet Server Up
|
||||||
in `/opt/server-up` en start het op `http://localhost:5000`.
|
in `/opt/server-up` en start het. Onderweg vraagt het waarop de interface moet
|
||||||
|
luisteren en of het meteen een beheerdersaccount voor je aanmaakt — die twee
|
||||||
|
vragen komen vooraf, zodat je kunt weglopen terwijl het image gebouwd wordt.
|
||||||
|
|
||||||
Liever eerst lezen wat je uitvoert — verstandig, want het script gebruikt
|
Liever eerst lezen wat je uitvoert — verstandig, want het script gebruikt
|
||||||
root-rechten:
|
root-rechten:
|
||||||
|
|
@ -58,12 +60,25 @@ cp .env.example .env
|
||||||
docker compose up -d --build
|
docker compose up -d --build
|
||||||
```
|
```
|
||||||
|
|
||||||
Alle opties staan in [docs/installeren.md](docs/installeren.md):
|
Alle opties staan in [docs/installeren.md](docs/installeren.md): `--dir`,
|
||||||
`--dir`, `--port`, `--bind`, `--branch`, `--token`, `--update`, `--uninstall`.
|
`--port`, `--bind`, `--branch`, `--token`, `--admin`, `--create-admin`,
|
||||||
|
`--update`, `--uninstall`.
|
||||||
|
|
||||||
Open daarna de interface en **maak meteen een beheerdersaccount aan.**
|
### Het beheerdersaccount
|
||||||
Zolang dat niet gebeurd is, kan iedereen die de pagina bereikt het account
|
|
||||||
claimen — de container waarschuwt daar bij het opstarten ook voor.
|
Zolang er nog geen account is, kan iedereen die de pagina bereikt het claimen —
|
||||||
|
de container waarschuwt daar bij het opstarten ook voor. Laat het script het
|
||||||
|
daarom meteen aanmaken:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sh install.sh --admin ramon # vraagt om een wachtwoord
|
||||||
|
SU_ADMIN_PASSWORD='...' sh install.sh --admin ramon --yes # zonder vragen
|
||||||
|
```
|
||||||
|
|
||||||
|
Zonder wachtwoordbron en zonder terminal maakt het script er zelf een en toont
|
||||||
|
die. Overgeslagen of misgegaan? `sh /opt/server-up/install.sh --create-admin
|
||||||
|
--admin ramon` doet het achteraf. Een wachtwoord als opdrachtregeloptie wordt
|
||||||
|
geweigerd: dat is zichtbaar in `ps`.
|
||||||
|
|
||||||
### Instellingen
|
### Instellingen
|
||||||
|
|
||||||
|
|
@ -76,7 +91,10 @@ PORT=5000
|
||||||
```
|
```
|
||||||
|
|
||||||
De poort bindt standaard op `127.0.0.1`. Zet hem pas open als er een reverse
|
De poort bindt standaard op `127.0.0.1`. Zet hem pas open als er een reverse
|
||||||
proxy met TLS voor staat.
|
proxy met TLS voor staat. Achteraf wijzigen kan met
|
||||||
|
`sh /opt/server-up/install.sh --update --bind 0.0.0.0`; pas het anders aan in
|
||||||
|
`.env` en **niet** in `docker-compose.yml`, want dat bestand komt uit de repo en
|
||||||
|
wordt bij elke update overschreven.
|
||||||
|
|
||||||
## Documentatie
|
## Documentatie
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,10 @@ schrijven én `docker` aanroepen, dan blijft alles onder je eigen account.
|
||||||
--bind ADRES Waarop de poort luistert (standaard: 127.0.0.1)
|
--bind ADRES Waarop de poort luistert (standaard: 127.0.0.1)
|
||||||
--branch NAAM Branch om te installeren (standaard: main)
|
--branch NAAM Branch om te installeren (standaard: main)
|
||||||
--token TOKEN Toegangstoken, als je repo niet openbaar is
|
--token TOKEN Toegangstoken, als je repo niet openbaar is
|
||||||
|
--admin NAAM Maak meteen een beheerdersaccount met deze naam
|
||||||
|
--admin-password-file PAD
|
||||||
|
Lees het wachtwoord uit een bestand
|
||||||
|
--create-admin Alleen het account aanmaken, bij een draaiende installatie
|
||||||
--update Bijwerken naar de nieuwste versie
|
--update Bijwerken naar de nieuwste versie
|
||||||
--uninstall Stoppen en verwijderen (gegevens blijven staan)
|
--uninstall Stoppen en verwijderen (gegevens blijven staan)
|
||||||
--yes Niets vragen
|
--yes Niets vragen
|
||||||
|
|
@ -59,12 +63,15 @@ schrijven én `docker` aanroepen, dan blijft alles onder je eigen account.
|
||||||
### Voorbeelden
|
### Voorbeelden
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Standaard, alleen bereikbaar vanaf de server zelf
|
# Standaard: vraagt waarop het moet luisteren en of je een account wil
|
||||||
sh install.sh
|
sh install.sh
|
||||||
|
|
||||||
# Bereikbaar op je netwerk, andere poort
|
# Bereikbaar op je netwerk, andere poort
|
||||||
sh install.sh --bind 0.0.0.0 --port 8080
|
sh install.sh --bind 0.0.0.0 --port 8080
|
||||||
|
|
||||||
|
# Volledig automatisch, met account
|
||||||
|
SU_ADMIN_PASSWORD='een-lang-wachtwoord' sh install.sh --admin ramon --yes
|
||||||
|
|
||||||
# Ergens anders neerzetten
|
# Ergens anders neerzetten
|
||||||
sh install.sh --dir /srv/server-up
|
sh install.sh --dir /srv/server-up
|
||||||
|
|
||||||
|
|
@ -77,21 +84,65 @@ sh install.sh --token jouw-forgejo-token
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Meteen na het installeren
|
## Het beheerdersaccount
|
||||||
|
|
||||||
**Maak een beheerdersaccount aan.** Server Up beheert de Docker-daemon, en wie
|
Server Up beheert de Docker-daemon, en wie containers kan starten kan
|
||||||
containers kan starten kan willekeurige mappen van de host mounten. Zolang er
|
willekeurige mappen van de host mounten. Zolang er nog geen account is, kan
|
||||||
nog geen account is, kan iedereen die de pagina bereikt het claimen.
|
iedereen die de pagina bereikt het claimen — dus hoe korter dat venster, hoe
|
||||||
|
beter. Het script kan het account daarom meteen aanmaken.
|
||||||
|
|
||||||
De poort staat standaard op `127.0.0.1`, dus alleen bereikbaar vanaf de server
|
Op een terminal vraagt het script erom. Automatisch kan het ook:
|
||||||
zelf. Wil je er van buitenaf bij, zet dan eerst een reverse proxy met TLS ervoor
|
|
||||||
en pas daarna `BIND` aan:
|
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
sed -i 's/^BIND=.*/BIND=0.0.0.0/' /opt/server-up/.env
|
# Wachtwoord uit een bestand
|
||||||
docker compose -f /opt/server-up/docker-compose.yml up -d
|
sh install.sh --admin ramon --admin-password-file /root/su-ww --yes
|
||||||
|
|
||||||
|
# Of uit een omgevingsvariabele
|
||||||
|
SU_ADMIN_PASSWORD='een-lang-wachtwoord' sh install.sh --admin ramon --yes
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Geef je geen wachtwoord en is er geen terminal, dan maakt het script er zelf een
|
||||||
|
van 24 tekens en zet die op het scherm. Schrijf die meteen over — hij staat
|
||||||
|
nergens anders.
|
||||||
|
|
||||||
|
> Het wachtwoord kan **niet** als optie mee. Opdrachtregelargumenten zijn voor
|
||||||
|
> elke gebruiker op de server zichtbaar met `ps` en blijven in je
|
||||||
|
> shell-geschiedenis staan. `--admin-password` weigert daarom met een verwijzing
|
||||||
|
> naar de twee manieren hierboven.
|
||||||
|
|
||||||
|
Ging het aanmaken mis, of heb je het overgeslagen? Dan kan het achteraf, zolang
|
||||||
|
er nog geen account bestaat:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sh /opt/server-up/install.sh --create-admin --admin ramon
|
||||||
|
```
|
||||||
|
|
||||||
|
Eist minstens 10 tekens, net als de webinterface.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Bereikbaarheid
|
||||||
|
|
||||||
|
Het script vraagt waarop de webinterface moet luisteren:
|
||||||
|
|
||||||
|
| Keuze | `BIND` | Wanneer |
|
||||||
|
|---|---|---|
|
||||||
|
| Alleen deze server | `127.0.0.1` | Standaard en veiligst. Erbij via een SSH-tunnel of een reverse proxy op dezelfde machine. |
|
||||||
|
| Het hele netwerk | `0.0.0.0` | Direct bereikbaar op het adres van je server. Zet er een reverse proxy met TLS voor. |
|
||||||
|
| Een specifiek adres | zelf opgeven | Bijvoorbeeld alleen je beheernetwerk. |
|
||||||
|
|
||||||
|
Achteraf wijzigen kan met dezelfde optie; die wordt ook doorgevoerd in een
|
||||||
|
`.env` die er al staat:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sh /opt/server-up/install.sh --update --bind 0.0.0.0
|
||||||
|
```
|
||||||
|
|
||||||
|
Wat je *niet* expliciet meegeeft blijft staan zoals het was, zodat een `--update`
|
||||||
|
je instellingen niet terugzet. Pas `BIND` daarom aan in `.env` of via deze optie
|
||||||
|
— **niet** in `docker-compose.yml`, want dat bestand komt uit de repo en wordt
|
||||||
|
bij elke update overschreven.
|
||||||
|
|
||||||
Zie [beveiliging.md](beveiliging.md) voor de reverse proxy, rollen en SSO.
|
Zie [beveiliging.md](beveiliging.md) voor de reverse proxy, rollen en SSO.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
360
install.sh
360
install.sh
|
|
@ -13,7 +13,7 @@
|
||||||
|
|
||||||
set -eu
|
set -eu
|
||||||
|
|
||||||
SCRIPT_VERSIE="1.0"
|
SCRIPT_VERSIE="1.1"
|
||||||
GIT_HOST="git.ramonbesselink.nl"
|
GIT_HOST="git.ramonbesselink.nl"
|
||||||
GIT_PAD="bes-r/server-up"
|
GIT_PAD="bes-r/server-up"
|
||||||
BRANCH="main"
|
BRANCH="main"
|
||||||
|
|
@ -24,6 +24,13 @@ TOKEN=""
|
||||||
JA=0
|
JA=0
|
||||||
DROOG=0
|
DROOG=0
|
||||||
ACTIE="install"
|
ACTIE="install"
|
||||||
|
BEHEERDER=""
|
||||||
|
BEHEERDER_WW=""
|
||||||
|
BEHEERDER_WW_BESTAND=""
|
||||||
|
# Expliciet meegegeven waarden overschrijven wél een bestaande .env; de rest
|
||||||
|
# blijft staan, zodat een --update je instellingen niet terugzet.
|
||||||
|
BIND_EXPLICIET=0
|
||||||
|
POORT_EXPLICIET=0
|
||||||
|
|
||||||
# ── Uitvoer ──────────────────────────────────────────────────────────────────
|
# ── Uitvoer ──────────────────────────────────────────────────────────────────
|
||||||
# Kleuren alleen als we naar een terminal schrijven; in een pipe of logbestand
|
# Kleuren alleen als we naar een terminal schrijven; in een pipe of logbestand
|
||||||
|
|
@ -79,15 +86,28 @@ Gebruik: install.sh [opties]
|
||||||
maar zet er dan wel een reverse proxy met TLS voor.
|
maar zet er dan wel een reverse proxy met TLS voor.
|
||||||
--branch NAAM Branch om te installeren (standaard: ${BRANCH})
|
--branch NAAM Branch om te installeren (standaard: ${BRANCH})
|
||||||
--token TOKEN Toegangstoken, als je git-repo niet openbaar is
|
--token TOKEN Toegangstoken, als je git-repo niet openbaar is
|
||||||
|
--admin NAAM Maak meteen een beheerdersaccount met deze naam
|
||||||
|
--admin-password-file PAD
|
||||||
|
Lees het wachtwoord uit een bestand. Kan ook via de
|
||||||
|
omgevingsvariabele SU_ADMIN_PASSWORD. Geef je geen van
|
||||||
|
beide, dan wordt ernaar gevraagd; kan dat niet (geen
|
||||||
|
terminal), dan wordt er één aangemaakt en getoond.
|
||||||
|
--create-admin Alleen het beheerdersaccount aanmaken, bij een installatie
|
||||||
|
die al draait. Werkt zolang er nog geen account bestaat.
|
||||||
--update Bijwerken naar de nieuwste versie
|
--update Bijwerken naar de nieuwste versie
|
||||||
--uninstall Stoppen en verwijderen (je gegevens blijven staan)
|
--uninstall Stoppen en verwijderen (je gegevens blijven staan)
|
||||||
--yes Niets vragen, overal ja op antwoorden
|
--yes Niets vragen, overal ja op antwoorden
|
||||||
--dry-run Alleen tonen wat er zou gebeuren
|
--dry-run Alleen tonen wat er zou gebeuren
|
||||||
--help Deze uitleg
|
--help Deze uitleg
|
||||||
|
|
||||||
|
Het wachtwoord staat bewust niet als optie op de opdrachtregel: die is voor
|
||||||
|
iedereen op de server te zien met 'ps' en blijft in je shell-geschiedenis staan.
|
||||||
|
|
||||||
Voorbeelden:
|
Voorbeelden:
|
||||||
sh install.sh
|
sh install.sh
|
||||||
sh install.sh --bind 0.0.0.0 --port 8080
|
sh install.sh --bind 0.0.0.0 --port 8080
|
||||||
|
sh install.sh --admin ramon
|
||||||
|
SU_ADMIN_PASSWORD=... sh install.sh --admin ramon --yes
|
||||||
sh install.sh --update
|
sh install.sh --update
|
||||||
UITLEG
|
UITLEG
|
||||||
}
|
}
|
||||||
|
|
@ -96,12 +116,18 @@ UITLEG
|
||||||
while [ $# -gt 0 ]; do
|
while [ $# -gt 0 ]; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
--dir) DOEL="${2:?--dir vereist een pad}"; shift 2 ;;
|
--dir) DOEL="${2:?--dir vereist een pad}"; shift 2 ;;
|
||||||
--port) POORT="${2:?--port vereist een nummer}"; shift 2 ;;
|
--port) POORT="${2:?--port vereist een nummer}"; POORT_EXPLICIET=1; shift 2 ;;
|
||||||
--bind) BIND="${2:?--bind vereist een adres}"; shift 2 ;;
|
--bind) BIND="${2:?--bind vereist een adres}"; BIND_EXPLICIET=1; shift 2 ;;
|
||||||
--branch) BRANCH="${2:?--branch vereist een naam}"; shift 2 ;;
|
--branch) BRANCH="${2:?--branch vereist een naam}"; shift 2 ;;
|
||||||
--token) TOKEN="${2:?--token vereist een waarde}"; shift 2 ;;
|
--token) TOKEN="${2:?--token vereist een waarde}"; shift 2 ;;
|
||||||
|
--admin) BEHEERDER="${2:?--admin vereist een gebruikersnaam}"; shift 2 ;;
|
||||||
|
--admin-password-file)
|
||||||
|
BEHEERDER_WW_BESTAND="${2:?--admin-password-file vereist een pad}"; shift 2 ;;
|
||||||
|
--admin-password)
|
||||||
|
fout "Gebruik --admin-password-file of SU_ADMIN_PASSWORD; een wachtwoord op de opdrachtregel is voor iedereen zichtbaar met 'ps'." ;;
|
||||||
--update) ACTIE="update"; shift ;;
|
--update) ACTIE="update"; shift ;;
|
||||||
--uninstall) ACTIE="uninstall"; shift ;;
|
--uninstall) ACTIE="uninstall"; shift ;;
|
||||||
|
--create-admin) ACTIE="create-admin"; shift ;;
|
||||||
--yes|-y) JA=1; shift ;;
|
--yes|-y) JA=1; shift ;;
|
||||||
--dry-run) DROOG=1; shift ;;
|
--dry-run) DROOG=1; shift ;;
|
||||||
--help|-h) gebruik; exit 0 ;;
|
--help|-h) gebruik; exit 0 ;;
|
||||||
|
|
@ -110,6 +136,18 @@ while [ $# -gt 0 ]; do
|
||||||
done
|
done
|
||||||
|
|
||||||
case "$POORT" in ''|*[!0-9]*) fout "Ongeldige poort: $POORT" ;; esac
|
case "$POORT" in ''|*[!0-9]*) fout "Ongeldige poort: $POORT" ;; esac
|
||||||
|
[ "$POORT" -ge 1 ] && [ "$POORT" -le 65535 ] || fout "Poort buiten bereik: $POORT"
|
||||||
|
|
||||||
|
# Docker publiceert op een adres, niet op een hostnaam. Alleen cijfers, punten
|
||||||
|
# en dubbele punten (IPv6) toestaan, zodat een typefout hier opvalt en niet pas
|
||||||
|
# als 'docker compose up' er een onbegrijpelijke fout over geeft.
|
||||||
|
geldig_bind() {
|
||||||
|
case "$1" in
|
||||||
|
''|*[!0-9.:a-fA-F]*) return 1 ;;
|
||||||
|
*) return 0 ;;
|
||||||
|
esac
|
||||||
|
}
|
||||||
|
geldig_bind "$BIND" || fout "Ongeldig bind-adres: $BIND (verwacht een IP-adres, bijvoorbeeld 127.0.0.1 of 0.0.0.0)"
|
||||||
|
|
||||||
# ── Rechten ──────────────────────────────────────────────────────────────────
|
# ── Rechten ──────────────────────────────────────────────────────────────────
|
||||||
# Alleen sudo gebruiken waar het echt nodig is: kan de gebruiker zelf al in de
|
# Alleen sudo gebruiken waar het echt nodig is: kan de gebruiker zelf al in de
|
||||||
|
|
@ -146,6 +184,18 @@ controleer_systeem() {
|
||||||
}
|
}
|
||||||
|
|
||||||
controleer_docker() {
|
controleer_docker() {
|
||||||
|
# Bij een proefdraai niets aanroepen wat via sudo loopt: dan staat er
|
||||||
|
# ineens een wachtwoordvraag op het scherm terwijl we net beloofd hebben
|
||||||
|
# dat er niets gebeurt — en zonder terminal blijft hij daarop hangen.
|
||||||
|
if [ "$DROOG" -eq 1 ]; then
|
||||||
|
if heeft docker; then
|
||||||
|
goed "Docker aanwezig (de daemon wordt bij een proefdraai niet aangesproken)"
|
||||||
|
else
|
||||||
|
waarschuw "Docker is niet geïnstalleerd; het script zou aanbieden dat te doen."
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
if heeft docker; then
|
if heeft docker; then
|
||||||
if $SUDO docker info >/dev/null 2>&1; then
|
if $SUDO docker info >/dev/null 2>&1; then
|
||||||
goed "Docker draait ($($SUDO docker version --format '{{.Server.Version}}' 2>/dev/null || echo '?'))"
|
goed "Docker draait ($($SUDO docker version --format '{{.Server.Version}}' 2>/dev/null || echo '?'))"
|
||||||
|
|
@ -216,18 +266,127 @@ haal_broncode() {
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Instellingen ─────────────────────────────────────────────────────────────
|
# ── Instellingen ─────────────────────────────────────────────────────────────
|
||||||
|
server_ip() { hostname -I 2>/dev/null | awk '{print $1}'; }
|
||||||
|
|
||||||
|
kies_bind() {
|
||||||
|
# Alleen vragen als er nog iets te kiezen valt: met --bind, met --yes of
|
||||||
|
# zonder terminal is de keuze al gemaakt.
|
||||||
|
[ "$BIND_EXPLICIET" -eq 1 ] && return 0
|
||||||
|
[ "$JA" -eq 1 ] && return 0
|
||||||
|
[ "$DROOG" -eq 1 ] && return 0
|
||||||
|
[ -e /dev/tty ] || return 0
|
||||||
|
|
||||||
|
# Installeer je opnieuw over een bestaande map, dan is je huidige keuze het
|
||||||
|
# uitgangspunt — anders zet enter je server ongemerkt terug op loopback.
|
||||||
|
huidig=""
|
||||||
|
if [ -f "$DOEL/.env" ]; then
|
||||||
|
lees_env_terug "$DOEL/.env"
|
||||||
|
huidig="$BIND"
|
||||||
|
fi
|
||||||
|
|
||||||
|
ip="$(server_ip)"
|
||||||
|
stap "Bereikbaarheid"
|
||||||
|
printf ' Waarop moet de webinterface luisteren?\n\n'
|
||||||
|
printf ' 1) Alleen deze server (127.0.0.1) — veiligst\n'
|
||||||
|
printf ' Erbij via een SSH-tunnel of een reverse proxy op deze machine.\n'
|
||||||
|
printf ' 2) Het hele netwerk (0.0.0.0)\n'
|
||||||
|
printf ' Direct bereikbaar op http://%s:%s — zet er wel TLS voor.\n' "${ip:-<server-ip>}" "$POORT"
|
||||||
|
printf ' 3) Een specifiek adres\n\n'
|
||||||
|
if [ -n "$huidig" ]; then
|
||||||
|
printf ' Nu ingesteld: %s\n' "$huidig"
|
||||||
|
printf ' Keuze [enter = zo laten]: '
|
||||||
|
else
|
||||||
|
printf ' Keuze [1]: '
|
||||||
|
fi
|
||||||
|
read -r keuze </dev/tty || keuze=""
|
||||||
|
case "$keuze" in
|
||||||
|
1) BIND="127.0.0.1" ;;
|
||||||
|
2) BIND="0.0.0.0" ;;
|
||||||
|
3) printf ' Adres: '
|
||||||
|
read -r adres </dev/tty || adres=""
|
||||||
|
geldig_bind "$adres" || fout "Ongeldig bind-adres: $adres"
|
||||||
|
BIND="$adres" ;;
|
||||||
|
'') BIND="${huidig:-127.0.0.1}" ;;
|
||||||
|
*) fout "Onbekende keuze: $keuze" ;;
|
||||||
|
esac
|
||||||
|
BIND_EXPLICIET=1
|
||||||
|
goed "Luistert op $BIND"
|
||||||
|
}
|
||||||
|
|
||||||
|
zet_env_regel() {
|
||||||
|
# zet_env_regel BESTAND SLEUTEL WAARDE — vervangt de regel of voegt hem toe.
|
||||||
|
# Waarden zijn hier altijd al gevalideerd (cijfers, punten, dubbele punten).
|
||||||
|
$SUDO sh -c "sed -i '/^$2=/d' '$1' && printf '%s=%s\n' '$2' '$3' >> '$1'"
|
||||||
|
}
|
||||||
|
|
||||||
|
lees_env_terug() {
|
||||||
|
# Wat er in .env staat is de waarheid, niet wat dit script als standaard
|
||||||
|
# heeft. Zonder dit klopt bij --update de wachtlus en het slotadres niet
|
||||||
|
# meer zodra je ooit een andere poort hebt gekozen.
|
||||||
|
[ -f "$1" ] || return 0
|
||||||
|
# Lezen kan meestal zonder sudo; alleen als het bestand van root is en
|
||||||
|
# afgeschermd, is de omweg nodig.
|
||||||
|
if [ -r "$1" ]; then
|
||||||
|
_lees="cat"
|
||||||
|
elif [ -n "$SUDO" ]; then
|
||||||
|
_lees="$SUDO cat"
|
||||||
|
elif heeft sudo; then
|
||||||
|
_lees="sudo cat"
|
||||||
|
else
|
||||||
|
_lees="cat"
|
||||||
|
fi
|
||||||
|
_inhoud="$($_lees "$1" 2>/dev/null || true)"
|
||||||
|
_poort="$(printf '%s\n' "$_inhoud" | sed -n 's/^PORT=//p' | tail -1)"
|
||||||
|
_bind="$(printf '%s\n' "$_inhoud" | sed -n 's/^BIND=//p' | tail -1)"
|
||||||
|
if [ "$POORT_EXPLICIET" -eq 0 ]; then
|
||||||
|
case "$_poort" in ''|*[!0-9]*) ;; *) POORT="$_poort" ;; esac
|
||||||
|
fi
|
||||||
|
if [ "$BIND_EXPLICIET" -eq 0 ] && [ -n "$_bind" ] && geldig_bind "$_bind"; then
|
||||||
|
BIND="$_bind"
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
schrijf_env() {
|
schrijf_env() {
|
||||||
stap "Instellingen"
|
stap "Instellingen"
|
||||||
env_bestand="$DOEL/.env"
|
env_bestand="$DOEL/.env"
|
||||||
|
|
||||||
if [ -f "$env_bestand" ]; then
|
if [ -f "$env_bestand" ]; then
|
||||||
goed "Bestaande .env blijft ongemoeid"
|
# Een bestaande .env bevat jouw instellingen; die blijven staan. Alleen
|
||||||
# BIND en PORT wel bijwerken als ze expliciet zijn meegegeven.
|
# wat je nu expliciet meegeeft wordt doorgevoerd — dat is precies het
|
||||||
|
# verschil dat eerder ontbrak, waardoor --bind niets deed zodra er al
|
||||||
|
# een .env stond.
|
||||||
|
gewijzigd=0
|
||||||
|
if [ "$BIND_EXPLICIET" -eq 1 ]; then
|
||||||
|
if [ "$DROOG" -eq 1 ]; then
|
||||||
|
printf ' [droog] BIND=%s in bestaande .env zetten\n' "$BIND"
|
||||||
|
else
|
||||||
|
zet_env_regel "$env_bestand" BIND "$BIND"
|
||||||
|
fi
|
||||||
|
gewijzigd=1
|
||||||
|
fi
|
||||||
|
if [ "$POORT_EXPLICIET" -eq 1 ]; then
|
||||||
|
if [ "$DROOG" -eq 1 ]; then
|
||||||
|
printf ' [droog] PORT=%s in bestaande .env zetten\n' "$POORT"
|
||||||
|
else
|
||||||
|
zet_env_regel "$env_bestand" PORT "$POORT"
|
||||||
|
fi
|
||||||
|
gewijzigd=1
|
||||||
|
fi
|
||||||
|
if [ "$gewijzigd" -eq 1 ]; then
|
||||||
|
goed "Bestaande .env bijgewerkt (BIND=$BIND, PORT=$POORT)"
|
||||||
|
else
|
||||||
|
lees_env_terug "$env_bestand"
|
||||||
|
goed "Bestaande .env blijft ongemoeid (BIND=$BIND, PORT=$POORT)"
|
||||||
|
fi
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$DROOG" -eq 1 ]; then
|
if [ "$DROOG" -eq 1 ]; then
|
||||||
printf ' [droog] .env aanmaken met BIND=%s PORT=%s\n' "$BIND" "$POORT"
|
printf ' [droog] .env aanmaken met BIND=%s PORT=%s\n' "$BIND" "$POORT"
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ -f "$DOEL/.env.example" ]; then
|
if [ -f "$DOEL/.env.example" ]; then
|
||||||
$SUDO cp "$DOEL/.env.example" "$env_bestand"
|
$SUDO cp "$DOEL/.env.example" "$env_bestand"
|
||||||
else
|
else
|
||||||
|
|
@ -276,6 +435,148 @@ wacht_op_gereed() {
|
||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# ── Beheerdersaccount ────────────────────────────────────────────────────────
|
||||||
|
# Tussen "container draait" en "eerste account" ligt een venster waarin iedereen
|
||||||
|
# die de pagina bereikt zichzelf beheerder kan maken. Dat venster hoort zo kort
|
||||||
|
# mogelijk te zijn, dus kan het script het account meteen aanmaken.
|
||||||
|
WW_GEGENEREERD=0
|
||||||
|
BEHEERDER_WW_TOON=""
|
||||||
|
|
||||||
|
json_tekst() {
|
||||||
|
# Escapet een waarde voor gebruik tussen JSON-aanhalingstekens.
|
||||||
|
printf '%s' "$1" | sed -e 's/\\/\\\\/g' -e 's/"/\\"/g'
|
||||||
|
}
|
||||||
|
|
||||||
|
genereer_wachtwoord() {
|
||||||
|
LC_ALL=C tr -dc 'A-Za-z0-9' < /dev/urandom 2>/dev/null | head -c 24
|
||||||
|
}
|
||||||
|
|
||||||
|
vraag_wachtwoord() {
|
||||||
|
# Twee keer intypen, met de echo uit. Mislukt dat, dan valt hij terug op
|
||||||
|
# een gegenereerd wachtwoord in plaats van er een half account van te maken.
|
||||||
|
oude_stty=""
|
||||||
|
if stty -g </dev/tty >/dev/null 2>&1; then oude_stty="$(stty -g </dev/tty)"; fi
|
||||||
|
poging=0
|
||||||
|
while [ "$poging" -lt 3 ]; do
|
||||||
|
poging=$((poging + 1))
|
||||||
|
if [ -n "$oude_stty" ]; then stty -echo </dev/tty; fi
|
||||||
|
printf ' Wachtwoord voor %s (minstens 10 tekens): ' "$BEHEERDER"
|
||||||
|
read -r ww1 </dev/tty || ww1=""
|
||||||
|
printf '\n Nogmaals: '
|
||||||
|
read -r ww2 </dev/tty || ww2=""
|
||||||
|
if [ -n "$oude_stty" ]; then stty "$oude_stty" </dev/tty; fi
|
||||||
|
printf '\n'
|
||||||
|
if [ "$ww1" != "$ww2" ]; then
|
||||||
|
waarschuw "De twee invoeren verschillen."
|
||||||
|
elif [ "${#ww1}" -lt 10 ]; then
|
||||||
|
waarschuw "Minstens 10 tekens, dat is ook wat de server eist."
|
||||||
|
else
|
||||||
|
BEHEERDER_WW="$ww1"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
waarschuw "Geen bruikbaar wachtwoord ingevoerd; er wordt er een aangemaakt."
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
bepaal_wachtwoord() {
|
||||||
|
# Volgorde: bestand, omgevingsvariabele, vragen, anders zelf aanmaken.
|
||||||
|
[ -n "$BEHEERDER_WW" ] && return 0
|
||||||
|
if [ -n "$BEHEERDER_WW_BESTAND" ]; then
|
||||||
|
[ -r "$BEHEERDER_WW_BESTAND" ] || fout "Kan $BEHEERDER_WW_BESTAND niet lezen."
|
||||||
|
BEHEERDER_WW="$(head -n 1 "$BEHEERDER_WW_BESTAND")"
|
||||||
|
[ -n "$BEHEERDER_WW" ] || fout "$BEHEERDER_WW_BESTAND is leeg."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ -n "${SU_ADMIN_PASSWORD:-}" ]; then
|
||||||
|
BEHEERDER_WW="$SU_ADMIN_PASSWORD"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
if [ "$JA" -eq 0 ] && [ -e /dev/tty ]; then
|
||||||
|
vraag_wachtwoord && return 0
|
||||||
|
fi
|
||||||
|
BEHEERDER_WW="$(genereer_wachtwoord)"
|
||||||
|
[ -n "$BEHEERDER_WW" ] || fout "Kon geen wachtwoord aanmaken (/dev/urandom niet leesbaar). Gebruik --admin-password-file."
|
||||||
|
WW_GEGENEREERD=1
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
vraag_beheerder() {
|
||||||
|
# Niets meegegeven, maar wel een terminal? Dan hier aanbieden, want dit is
|
||||||
|
# het moment waarop het uitmaakt.
|
||||||
|
[ -n "$BEHEERDER" ] && return 0
|
||||||
|
[ "$JA" -eq 1 ] && return 0
|
||||||
|
[ "$DROOG" -eq 1 ] && return 0
|
||||||
|
[ -e /dev/tty ] || return 0
|
||||||
|
|
||||||
|
stap "Beheerdersaccount"
|
||||||
|
if ! vraag "Nu meteen een beheerdersaccount aanmaken?"; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
printf ' Gebruikersnaam: '
|
||||||
|
read -r naam </dev/tty || naam=""
|
||||||
|
naam="$(printf '%s' "$naam" | tr -d '[:space:]')"
|
||||||
|
if [ -z "$naam" ]; then
|
||||||
|
waarschuw "Geen naam opgegeven; overgeslagen."
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
BEHEERDER="$naam"
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
beheerder_vooraf() {
|
||||||
|
# Alles wat om invoer vraagt gebeurt vóór het bouwen, zodat je daarna kunt
|
||||||
|
# weglopen terwijl het image gebouwd wordt.
|
||||||
|
[ "$DROOG" -eq 1 ] && return 0
|
||||||
|
vraag_beheerder
|
||||||
|
[ -n "$BEHEERDER" ] || return 0
|
||||||
|
bepaal_wachtwoord
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
maak_beheerder() {
|
||||||
|
[ -n "$BEHEERDER" ] || return 0
|
||||||
|
|
||||||
|
if [ "$DROOG" -eq 1 ]; then
|
||||||
|
stap "Beheerdersaccount"
|
||||||
|
printf ' [droog] account %s aanmaken via POST /api/auth/setup\n' "$BEHEERDER"
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
bepaal_wachtwoord
|
||||||
|
|
||||||
|
# Het wachtwoord gaat via stdin naar curl, niet via de opdrachtregel:
|
||||||
|
# argumenten zijn voor elke gebruiker op de server zichtbaar in 'ps'.
|
||||||
|
antwoord="$(mktemp 2>/dev/null || echo /tmp/su-setup.$$)"
|
||||||
|
code="$(printf '{"username":"%s","password":"%s"}' \
|
||||||
|
"$(json_tekst "$BEHEERDER")" "$(json_tekst "$BEHEERDER_WW")" \
|
||||||
|
| curl -sS -o "$antwoord" -w '%{http_code}' \
|
||||||
|
-X POST -H 'Content-Type: application/json' \
|
||||||
|
--data-binary @- \
|
||||||
|
"http://127.0.0.1:${POORT}/api/auth/setup" 2>/dev/null || true)"
|
||||||
|
# Bij een mislukte verbinding schrijft curl zelf al "000"; kan curl helemaal
|
||||||
|
# niet draaien, dan blijft het leeg. Beide gevallen zijn hetzelfde verhaal.
|
||||||
|
case "$code" in ''|*[!0-9]*) code="000" ;; esac
|
||||||
|
|
||||||
|
case "$code" in
|
||||||
|
200) goed "Beheerder '$BEHEERDER' aangemaakt"
|
||||||
|
# Alleen een zelf aangemaakt wachtwoord moet nog getoond worden;
|
||||||
|
# een ingetypt of meegegeven wachtwoord kent de gebruiker al.
|
||||||
|
if [ "$WW_GEGENEREERD" -eq 1 ]; then
|
||||||
|
BEHEERDER_WW_TOON="$BEHEERDER_WW"
|
||||||
|
fi ;;
|
||||||
|
409) waarschuw "Er bestond al een account; er is niets gewijzigd."
|
||||||
|
BEHEERDER=""; WW_GEGENEREERD=0 ;;
|
||||||
|
000) waarschuw "Server Up was niet bereikbaar; account niet aangemaakt."
|
||||||
|
BEHEERDER=""; WW_GEGENEREERD=0 ;;
|
||||||
|
*) melding="$(sed -n 's/.*"msg" *: *"\([^"]*\)".*/\1/p' "$antwoord" 2>/dev/null)"
|
||||||
|
waarschuw "Aanmaken mislukt (HTTP $code)${melding:+: }${melding:-}"
|
||||||
|
BEHEERDER=""; WW_GEGENEREERD=0 ;;
|
||||||
|
esac
|
||||||
|
rm -f "$antwoord"
|
||||||
|
BEHEERDER_WW=""
|
||||||
|
}
|
||||||
|
|
||||||
afsluiting() {
|
afsluiting() {
|
||||||
if [ "$BIND" = "0.0.0.0" ]; then
|
if [ "$BIND" = "0.0.0.0" ]; then
|
||||||
ip="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
ip="$(hostname -I 2>/dev/null | awk '{print $1}')"
|
||||||
|
|
@ -288,9 +589,18 @@ afsluiting() {
|
||||||
printf '%s Server Up draait op %s%s\n' "$C_OK" "$adres" "$C_UIT"
|
printf '%s Server Up draait op %s%s\n' "$C_OK" "$adres" "$C_UIT"
|
||||||
printf '%s────────────────────────────────────────────────────────%s\n\n' "$C_KOP" "$C_UIT"
|
printf '%s────────────────────────────────────────────────────────%s\n\n' "$C_KOP" "$C_UIT"
|
||||||
|
|
||||||
printf ' %sMaak nu meteen een beheerdersaccount aan.%s\n' "$C_WAARSCHUW" "$C_UIT"
|
if [ -n "$BEHEERDER" ]; then
|
||||||
printf ' Zolang dat niet gebeurd is, kan iedereen die deze pagina\n'
|
printf ' %s✔%s Inloggen als: %s%s%s\n' "$C_OK" "$C_UIT" "$C_KOP" "$BEHEERDER" "$C_UIT"
|
||||||
printf ' bereikt het account claimen.\n\n'
|
if [ "$WW_GEGENEREERD" -eq 1 ]; then
|
||||||
|
printf ' Wachtwoord: %s%s%s\n' "$C_KOP" "$BEHEERDER_WW_TOON" "$C_UIT"
|
||||||
|
printf ' %sSchrijf dit nu over — het staat nergens anders.%s\n' "$C_WAARSCHUW" "$C_UIT"
|
||||||
|
fi
|
||||||
|
printf '\n'
|
||||||
|
else
|
||||||
|
printf ' %sMaak nu meteen een beheerdersaccount aan.%s\n' "$C_WAARSCHUW" "$C_UIT"
|
||||||
|
printf ' Zolang dat niet gebeurd is, kan iedereen die deze pagina\n'
|
||||||
|
printf ' bereikt het account claimen.\n\n'
|
||||||
|
fi
|
||||||
|
|
||||||
if [ "$BIND" = "127.0.0.1" ]; then
|
if [ "$BIND" = "127.0.0.1" ]; then
|
||||||
printf ' Alleen bereikbaar vanaf deze server zelf. Van buitenaf erbij?\n'
|
printf ' Alleen bereikbaar vanaf deze server zelf. Van buitenaf erbij?\n'
|
||||||
|
|
@ -326,6 +636,13 @@ verwijderen() {
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── Hoofdprogramma ───────────────────────────────────────────────────────────
|
# ── Hoofdprogramma ───────────────────────────────────────────────────────────
|
||||||
|
# De testsuite laadt dit bestand om losse functies te kunnen aanroepen — vooral
|
||||||
|
# de vragen die bepalen waarop de server straks luistert. Zonder deze uitgang
|
||||||
|
# zou het script bij het inladen meteen een hele installatie beginnen.
|
||||||
|
if [ -n "${SU_INSTALL_ALLEEN_FUNCTIES:-}" ]; then
|
||||||
|
return 0 2>/dev/null || exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
printf '\n%sServer Up — installatiescript %s%s\n' "$C_KOP" "$SCRIPT_VERSIE" "$C_UIT"
|
printf '\n%sServer Up — installatiescript %s%s\n' "$C_KOP" "$SCRIPT_VERSIE" "$C_UIT"
|
||||||
[ "$DROOG" -eq 1 ] && waarschuw "Proefdraai: er wordt niets gewijzigd."
|
[ "$DROOG" -eq 1 ] && waarschuw "Proefdraai: er wordt niets gewijzigd."
|
||||||
|
|
||||||
|
|
@ -339,18 +656,45 @@ case "$ACTIE" in
|
||||||
controleer_systeem
|
controleer_systeem
|
||||||
controleer_docker
|
controleer_docker
|
||||||
haal_broncode
|
haal_broncode
|
||||||
|
# Ook bij bijwerken: expliciete --bind/--port doorvoeren, en anders
|
||||||
|
# overnemen wat er al staat.
|
||||||
|
schrijf_env
|
||||||
start
|
start
|
||||||
wacht_op_gereed || true
|
wacht_op_gereed || true
|
||||||
printf '\n'
|
printf '\n'
|
||||||
goed "Bijgewerkt."
|
goed "Bijgewerkt."
|
||||||
;;
|
;;
|
||||||
|
create-admin)
|
||||||
|
# Losse actie voor een installatie die al draait: handig als het
|
||||||
|
# aanmaken tijdens de installatie is misgegaan, of overgeslagen.
|
||||||
|
# Docker en schrijfrechten zijn hier niet nodig — alleen .env lezen
|
||||||
|
# en één verzoek naar de draaiende server — dus geen bepaal_rechten.
|
||||||
|
lees_env_terug "$DOEL/.env"
|
||||||
|
if [ -z "$BEHEERDER" ]; then
|
||||||
|
if [ -e /dev/tty ] && [ "$JA" -eq 0 ]; then
|
||||||
|
printf '\n Gebruikersnaam: '
|
||||||
|
read -r naam </dev/tty || naam=""
|
||||||
|
BEHEERDER="$(printf '%s' "$naam" | tr -d '[:space:]')"
|
||||||
|
fi
|
||||||
|
[ -n "$BEHEERDER" ] || fout "Geef de gebruikersnaam op met --admin NAAM."
|
||||||
|
fi
|
||||||
|
stap "Beheerdersaccount"
|
||||||
|
maak_beheerder
|
||||||
|
if [ -n "$BEHEERDER" ] && [ "$WW_GEGENEREERD" -eq 1 ]; then
|
||||||
|
printf '\n Wachtwoord: %s%s%s\n' "$C_KOP" "$BEHEERDER_WW_TOON" "$C_UIT"
|
||||||
|
printf ' %sSchrijf dit nu over — het staat nergens anders.%s\n\n' "$C_WAARSCHUW" "$C_UIT"
|
||||||
|
fi
|
||||||
|
;;
|
||||||
install)
|
install)
|
||||||
controleer_systeem
|
controleer_systeem
|
||||||
controleer_docker
|
controleer_docker
|
||||||
|
kies_bind
|
||||||
|
beheerder_vooraf
|
||||||
haal_broncode
|
haal_broncode
|
||||||
schrijf_env
|
schrijf_env
|
||||||
start
|
start
|
||||||
wacht_op_gereed || true
|
wacht_op_gereed || true
|
||||||
|
maak_beheerder
|
||||||
afsluiting
|
afsluiting
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
||||||
|
|
@ -51,7 +51,8 @@ def test_help_werkt_en_noemt_alle_opties():
|
||||||
r = _draai("--help")
|
r = _draai("--help")
|
||||||
assert r.returncode == 0
|
assert r.returncode == 0
|
||||||
for optie in ("--dir", "--port", "--bind", "--branch", "--token",
|
for optie in ("--dir", "--port", "--bind", "--branch", "--token",
|
||||||
"--update", "--uninstall", "--yes", "--dry-run"):
|
"--update", "--uninstall", "--yes", "--dry-run",
|
||||||
|
"--admin", "--admin-password-file", "--create-admin"):
|
||||||
assert optie in r.stdout, f"{optie} niet gedocumenteerd in --help"
|
assert optie in r.stdout, f"{optie} niet gedocumenteerd in --help"
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -125,6 +126,382 @@ def test_proefdraai_werkt_zonder_curl_en_tar(tmp_path):
|
||||||
assert not (tmp_path / "su").exists()
|
assert not (tmp_path / "su").exists()
|
||||||
|
|
||||||
|
|
||||||
|
# ── Beheerdersaccount ────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def test_wachtwoord_mag_niet_op_de_opdrachtregel():
|
||||||
|
"""Argumenten zijn voor elke gebruiker op de server zichtbaar met 'ps' en
|
||||||
|
blijven in de shell-geschiedenis staan."""
|
||||||
|
r = _draai("--admin-password", "geheimgeheim")
|
||||||
|
assert r.returncode != 0
|
||||||
|
assert "ps" in r.stderr
|
||||||
|
|
||||||
|
|
||||||
|
def test_create_admin_zonder_naam_stopt(tmp_path):
|
||||||
|
r = _draai("--create-admin", "--dir", str(tmp_path), "--yes")
|
||||||
|
assert r.returncode != 0
|
||||||
|
assert "--admin" in r.stderr
|
||||||
|
|
||||||
|
|
||||||
|
def test_dry_run_toont_het_aanmaken_van_het_account(tmp_path):
|
||||||
|
r = _draai("--dry-run", "--dir", str(tmp_path / "su"), "--yes", "--admin", "ramon")
|
||||||
|
assert "/api/auth/setup" in r.stdout
|
||||||
|
assert "ramon" in r.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def test_wachtwoord_staat_niet_in_de_curl_argumenten():
|
||||||
|
"""Het wachtwoord gaat via stdin naar curl (--data-binary @-), niet als
|
||||||
|
argument. Anders is het alsnog zichtbaar in 'ps'."""
|
||||||
|
tekst = SCRIPT.read_text(encoding="utf-8")
|
||||||
|
setup = tekst[tekst.index("maak_beheerder()"):]
|
||||||
|
setup = setup[:setup.index("\nafsluiting()")]
|
||||||
|
assert "--data-binary @-" in setup
|
||||||
|
assert not re.search(r'-d\s+["\']?\{', setup), "JSON als curl-argument"
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("adres", ["localhost", "0.0.0.0;rm -rf /", "mijn server"])
|
||||||
|
def test_ongeldig_bind_adres_stopt(adres):
|
||||||
|
r = _draai("--bind", adres)
|
||||||
|
assert r.returncode != 0
|
||||||
|
assert "bind" in r.stderr.lower()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("adres", ["127.0.0.1", "0.0.0.0", "10.0.20.22", "::1"])
|
||||||
|
def test_geldig_bind_adres_wordt_geaccepteerd(adres, tmp_path):
|
||||||
|
r = _draai("--dry-run", "--dir", str(tmp_path / "su"), "--yes", "--bind", adres)
|
||||||
|
assert r.returncode == 0, r.stderr
|
||||||
|
assert f"BIND={adres}" in r.stdout
|
||||||
|
|
||||||
|
|
||||||
|
# ── De vragen die het script stelt ───────────────────────────────────────────
|
||||||
|
# Interactief is de normale manier waarop iemand dit script draait, en juist
|
||||||
|
# daar bepaalt een verkeerd antwoord waar de server straks op luistert. Daarom
|
||||||
|
# worden de vragen hier echt gesteld, via een pseudo-terminal.
|
||||||
|
|
||||||
|
def _in_terminal(fragment, invoer, tmp_path, tijdslimiet=20):
|
||||||
|
"""Draait een stukje sh dat install.sh inlaadt, met een echte terminal."""
|
||||||
|
import os
|
||||||
|
import pty
|
||||||
|
import re as _re
|
||||||
|
import select
|
||||||
|
import signal
|
||||||
|
import time
|
||||||
|
|
||||||
|
script = tmp_path / "fragment.sh"
|
||||||
|
script.write_text(f"set --\nSU_INSTALL_ALLEEN_FUNCTIES=1 . {SCRIPT}\n{fragment}\n")
|
||||||
|
|
||||||
|
pid, fd = pty.fork()
|
||||||
|
if pid == 0: # kindproces
|
||||||
|
os.execvp("sh", ["sh", str(script)])
|
||||||
|
os.write(fd, invoer.encode())
|
||||||
|
uit, einde = b"", time.time() + tijdslimiet
|
||||||
|
while time.time() < einde:
|
||||||
|
klaar, _, _ = select.select([fd], [], [], 0.5)
|
||||||
|
if klaar:
|
||||||
|
try:
|
||||||
|
blok = os.read(fd, 4096)
|
||||||
|
except OSError: # terminal dicht: proces weg
|
||||||
|
break
|
||||||
|
if not blok:
|
||||||
|
break
|
||||||
|
uit += blok
|
||||||
|
elif os.waitpid(pid, os.WNOHANG)[0]:
|
||||||
|
break
|
||||||
|
try:
|
||||||
|
os.kill(pid, signal.SIGKILL)
|
||||||
|
except ProcessLookupError:
|
||||||
|
pass
|
||||||
|
try:
|
||||||
|
os.waitpid(pid, 0)
|
||||||
|
except ChildProcessError:
|
||||||
|
pass
|
||||||
|
return _re.sub(r"\x1b\[[0-9;]*m", "", uit.decode(errors="replace").replace("\r", ""))
|
||||||
|
|
||||||
|
|
||||||
|
BIND_FRAGMENT = ('DROOG=0; JA=0; BIND_EXPLICIET=0; DOEL="$MAP"\n'
|
||||||
|
'kies_bind\n'
|
||||||
|
'printf "UITKOMST BIND=%s\\n" "$BIND"\n')
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("invoer,verwacht", [
|
||||||
|
("1\n", "127.0.0.1"),
|
||||||
|
("2\n", "0.0.0.0"),
|
||||||
|
("3\n10.0.20.99\n", "10.0.20.99"),
|
||||||
|
("\n", "127.0.0.1"), # enter zonder bestaande .env
|
||||||
|
])
|
||||||
|
def test_keuzemenu_voor_het_bind_adres(invoer, verwacht, tmp_path):
|
||||||
|
leeg = tmp_path / "leeg"
|
||||||
|
leeg.mkdir()
|
||||||
|
uit = _in_terminal(f'MAP="{leeg}"\n' + BIND_FRAGMENT, invoer, tmp_path)
|
||||||
|
assert f"UITKOMST BIND={verwacht}" in uit, uit
|
||||||
|
|
||||||
|
|
||||||
|
def test_enter_behoudt_de_bestaande_instelling(tmp_path):
|
||||||
|
"""Opnieuw installeren over een bestaande map mag je server niet ongemerkt
|
||||||
|
terugzetten op loopback."""
|
||||||
|
bestaand = tmp_path / "bestaand"
|
||||||
|
bestaand.mkdir()
|
||||||
|
(bestaand / ".env").write_text("BIND=10.0.20.5\nPORT=8080\n")
|
||||||
|
uit = _in_terminal(f'MAP="{bestaand}"\n' + BIND_FRAGMENT, "\n", tmp_path)
|
||||||
|
assert "UITKOMST BIND=10.0.20.5" in uit, uit
|
||||||
|
assert "Nu ingesteld: 10.0.20.5" in uit
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("invoer,melding", [
|
||||||
|
("9\n", "Onbekende keuze"),
|
||||||
|
("3\nlocalhost\n", "Ongeldig bind-adres"),
|
||||||
|
])
|
||||||
|
def test_menu_weigert_onzin(invoer, melding, tmp_path):
|
||||||
|
leeg = tmp_path / "leeg"
|
||||||
|
leeg.mkdir()
|
||||||
|
uit = _in_terminal(f'MAP="{leeg}"\n' + BIND_FRAGMENT, invoer, tmp_path)
|
||||||
|
assert melding in uit
|
||||||
|
assert "UITKOMST" not in uit
|
||||||
|
|
||||||
|
|
||||||
|
WW_FRAGMENT = ('DROOG=0; JA=0; BEHEERDER=""\n'
|
||||||
|
'beheerder_vooraf\n'
|
||||||
|
'printf "UITKOMST naam=%s lengte=%s zelf=%s\\n" '
|
||||||
|
'"$BEHEERDER" "${#BEHEERDER_WW}" "$WW_GEGENEREERD"\n')
|
||||||
|
|
||||||
|
|
||||||
|
def test_account_aanmaken_kan_geweigerd_worden(tmp_path):
|
||||||
|
uit = _in_terminal(WW_FRAGMENT, "n\n", tmp_path)
|
||||||
|
assert "UITKOMST naam= lengte=0 zelf=0" in uit
|
||||||
|
|
||||||
|
|
||||||
|
def test_wachtwoord_twee_keer_intypen(tmp_path):
|
||||||
|
uit = _in_terminal(WW_FRAGMENT, "j\nramon\neenlangwachtwoord\neenlangwachtwoord\n", tmp_path)
|
||||||
|
assert "UITKOMST naam=ramon lengte=17 zelf=0" in uit, uit
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize("invoer,melding", [
|
||||||
|
("j\nramon\neenlangwachtwoord\nietsanders\neenlangwachtwoord\neenlangwachtwoord\n",
|
||||||
|
"verschillen"),
|
||||||
|
("j\nramon\nkort\nkort\neenlangwachtwoord\neenlangwachtwoord\n",
|
||||||
|
"Minstens 10 tekens"),
|
||||||
|
])
|
||||||
|
def test_wachtwoord_mag_opnieuw_na_een_fout(invoer, melding, tmp_path):
|
||||||
|
uit = _in_terminal(WW_FRAGMENT, invoer, tmp_path)
|
||||||
|
assert melding in uit
|
||||||
|
assert "UITKOMST naam=ramon lengte=17 zelf=0" in uit, uit
|
||||||
|
|
||||||
|
|
||||||
|
def test_na_drie_pogingen_maakt_het_script_er_zelf_een(tmp_path):
|
||||||
|
"""Blijven hangen op een prompt is erger dan een gegenereerd wachtwoord."""
|
||||||
|
uit = _in_terminal(WW_FRAGMENT, "j\nramon\na\na\nb\nb\nc\nc\n", tmp_path)
|
||||||
|
assert "UITKOMST naam=ramon lengte=24 zelf=1" in uit, uit
|
||||||
|
|
||||||
|
|
||||||
|
def test_lege_gebruikersnaam_slaat_over(tmp_path):
|
||||||
|
uit = _in_terminal(WW_FRAGMENT, "j\n\n", tmp_path)
|
||||||
|
assert "Geen naam opgegeven" in uit
|
||||||
|
assert "UITKOMST naam= lengte=0 zelf=0" in uit
|
||||||
|
|
||||||
|
|
||||||
|
def test_proefdraai_vraagt_niets_en_gebruikt_geen_sudo(tmp_path):
|
||||||
|
"""Een proefdraai beloofde dat er niets gebeurt, maar riep wél 'sudo docker'
|
||||||
|
aan. Op een server waar sudo een wachtwoord wil, liep hij daarop vast."""
|
||||||
|
uit = _in_terminal(
|
||||||
|
f'DROOG=1; SUDO="sudo"; DOEL="{tmp_path}"\ncontroleer_docker\nprintf "KLAAR\\n"\n',
|
||||||
|
"", tmp_path, tijdslimiet=15)
|
||||||
|
assert "KLAAR" in uit, f"controleer_docker liep vast:\n{uit}"
|
||||||
|
assert "password" not in uit.lower()
|
||||||
|
|
||||||
|
|
||||||
|
# ── .env ─────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
def test_bind_wordt_doorgevoerd_in_een_bestaande_env(tmp_path):
|
||||||
|
"""Eerder bleef een bestaande .env altijd ongemoeid, ook als je --bind
|
||||||
|
meegaf. Dan leek de installatie te lukken maar bleef de server onbereikbaar
|
||||||
|
op het oude adres."""
|
||||||
|
doel = tmp_path / "su"
|
||||||
|
doel.mkdir()
|
||||||
|
(doel / ".env").write_text("BIND=127.0.0.1\nPORT=5000\nSU_TAG=0.7.30\n")
|
||||||
|
r = _draai("--dry-run", "--dir", str(doel), "--yes", "--bind", "0.0.0.0")
|
||||||
|
assert "BIND=0.0.0.0 in bestaande .env zetten" in r.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def test_env_blijft_ongemoeid_zonder_expliciete_opties(tmp_path):
|
||||||
|
"""Anders zet een --update je instellingen elke keer terug."""
|
||||||
|
doel = tmp_path / "su"
|
||||||
|
doel.mkdir()
|
||||||
|
(doel / ".env").write_text("BIND=0.0.0.0\nPORT=8080\n")
|
||||||
|
r = _draai("--dry-run", "--dir", str(doel), "--yes")
|
||||||
|
assert "ongemoeid" in r.stdout
|
||||||
|
# En hij rekent verder met wat er écht staat, niet met de standaardwaarden.
|
||||||
|
assert "BIND=0.0.0.0, PORT=8080" in r.stdout
|
||||||
|
|
||||||
|
|
||||||
|
def test_poort_uit_env_wordt_gebruikt_voor_het_slotadres(tmp_path):
|
||||||
|
doel = tmp_path / "su"
|
||||||
|
doel.mkdir()
|
||||||
|
(doel / ".env").write_text("BIND=0.0.0.0\nPORT=8080\n")
|
||||||
|
r = _draai("--dry-run", "--dir", str(doel), "--yes")
|
||||||
|
assert ":8080" in r.stdout
|
||||||
|
|
||||||
|
|
||||||
|
# ── Tegen een echt draaiende server ──────────────────────────────────────────
|
||||||
|
# Deze tests starten de app zelf en laten het script er een account op
|
||||||
|
# aanmaken. Dat is het enige wat aantoont dat de JSON-opbouw, de poortdetectie
|
||||||
|
# en de foutafhandeling in samenhang kloppen.
|
||||||
|
|
||||||
|
geen_curl = pytest.mark.skipif(not shutil.which("curl"),
|
||||||
|
reason="curl ontbreekt (o.a. in python:3.12-slim)")
|
||||||
|
|
||||||
|
|
||||||
|
def _vrije_poort():
|
||||||
|
import socket
|
||||||
|
s = socket.socket()
|
||||||
|
s.bind(("127.0.0.1", 0))
|
||||||
|
poort = s.getsockname()[1]
|
||||||
|
s.close()
|
||||||
|
return poort
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def draaiende_app(tmp_path):
|
||||||
|
"""De echte app op een vrije poort, met een lege configuratie."""
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import urllib.error
|
||||||
|
import urllib.request
|
||||||
|
|
||||||
|
poort = _vrije_poort()
|
||||||
|
data = tmp_path / "data"
|
||||||
|
data.mkdir()
|
||||||
|
omgeving = dict(os.environ,
|
||||||
|
SU_CONFIG=str(data / "config.json"),
|
||||||
|
SU_AUDIT=str(data / "audit.db"),
|
||||||
|
SU_GIT_CACHE=str(data / "git"),
|
||||||
|
SU_SECRET=str(data / "secret.key"),
|
||||||
|
LIBRARY_DIR=str(data / "lib"),
|
||||||
|
DATA_DIR=str(tmp_path / "appdata"),
|
||||||
|
BACKUP_DIR=str(tmp_path / "backups"),
|
||||||
|
PORT=str(poort))
|
||||||
|
proces = subprocess.Popen([sys.executable, str(WORTEL / "server-up" / "app.py")],
|
||||||
|
env=omgeving, stdout=subprocess.PIPE,
|
||||||
|
stderr=subprocess.STDOUT, text=True)
|
||||||
|
try:
|
||||||
|
for _ in range(80):
|
||||||
|
if proces.poll() is not None:
|
||||||
|
pytest.skip(f"app start niet: {proces.communicate()[0][-500:]}")
|
||||||
|
try:
|
||||||
|
urllib.request.urlopen(f"http://127.0.0.1:{poort}/healthz", timeout=1)
|
||||||
|
break
|
||||||
|
except (urllib.error.URLError, OSError):
|
||||||
|
time.sleep(0.25)
|
||||||
|
else:
|
||||||
|
pytest.skip("app reageerde niet op tijd")
|
||||||
|
yield poort
|
||||||
|
finally:
|
||||||
|
proces.terminate()
|
||||||
|
try:
|
||||||
|
proces.wait(timeout=10)
|
||||||
|
except subprocess.TimeoutExpired:
|
||||||
|
proces.kill()
|
||||||
|
|
||||||
|
|
||||||
|
def _inloggen(poort, naam, wachtwoord):
|
||||||
|
import json
|
||||||
|
import urllib.error
|
||||||
|
import urllib.request
|
||||||
|
verzoek = urllib.request.Request(
|
||||||
|
f"http://127.0.0.1:{poort}/api/auth/login",
|
||||||
|
data=json.dumps({"username": naam, "password": wachtwoord}).encode(),
|
||||||
|
headers={"Content-Type": "application/json"})
|
||||||
|
try:
|
||||||
|
with urllib.request.urlopen(verzoek, timeout=5) as a:
|
||||||
|
return a.status
|
||||||
|
except urllib.error.HTTPError as e:
|
||||||
|
return e.code
|
||||||
|
|
||||||
|
|
||||||
|
@geen_curl
|
||||||
|
def test_script_maakt_een_werkend_beheerdersaccount(draaiende_app, tmp_path):
|
||||||
|
poort = draaiende_app
|
||||||
|
inst = tmp_path / "inst"
|
||||||
|
inst.mkdir()
|
||||||
|
# De poort komt uit .env, niet uit een optie: zo werkt het ook als je
|
||||||
|
# destijds met --port hebt geïnstalleerd.
|
||||||
|
(inst / ".env").write_text(f"BIND=127.0.0.1\nPORT={poort}\n")
|
||||||
|
ww = tmp_path / "ww"
|
||||||
|
ww.write_text("een-heel-lang-wachtwoord\n")
|
||||||
|
|
||||||
|
r = _draai("--create-admin", "--dir", str(inst), "--admin", "ramon",
|
||||||
|
"--admin-password-file", str(ww), "--yes")
|
||||||
|
assert r.returncode == 0, r.stderr
|
||||||
|
assert "aangemaakt" in r.stdout
|
||||||
|
assert _inloggen(poort, "ramon", "een-heel-lang-wachtwoord") == 200
|
||||||
|
|
||||||
|
|
||||||
|
@geen_curl
|
||||||
|
def test_wachtwoord_met_aanhalingstekens_en_backslashes(draaiende_app, tmp_path):
|
||||||
|
"""Het wachtwoord gaat als JSON over de lijn; zonder escapen levert dit een
|
||||||
|
kapot verzoek op of — erger — een ander wachtwoord dan je denkt."""
|
||||||
|
poort = draaiende_app
|
||||||
|
inst = tmp_path / "inst"
|
||||||
|
inst.mkdir()
|
||||||
|
(inst / ".env").write_text(f"PORT={poort}\n")
|
||||||
|
lastig = 'pa"ss\\wo/rd$`{}[]&|;<>#!\'x'
|
||||||
|
ww = tmp_path / "ww"
|
||||||
|
ww.write_text(lastig + "\n")
|
||||||
|
|
||||||
|
r = _draai("--create-admin", "--dir", str(inst), "--admin", "lastig",
|
||||||
|
"--admin-password-file", str(ww), "--yes")
|
||||||
|
assert r.returncode == 0, r.stderr
|
||||||
|
assert "aangemaakt" in r.stdout
|
||||||
|
assert _inloggen(poort, "lastig", lastig) == 200
|
||||||
|
|
||||||
|
|
||||||
|
@geen_curl
|
||||||
|
def test_zelf_aangemaakt_wachtwoord_wordt_getoond_en_werkt(draaiende_app, tmp_path):
|
||||||
|
"""Zonder bestand, omgevingsvariabele of terminal maakt het script er zelf
|
||||||
|
één aan. Die moet dan wel op het scherm komen, want hij staat nergens."""
|
||||||
|
poort = draaiende_app
|
||||||
|
inst = tmp_path / "inst"
|
||||||
|
inst.mkdir()
|
||||||
|
(inst / ".env").write_text(f"PORT={poort}\n")
|
||||||
|
|
||||||
|
r = _draai("--create-admin", "--dir", str(inst), "--admin", "auto", "--yes")
|
||||||
|
assert r.returncode == 0, r.stderr
|
||||||
|
getoond = re.search(r"Wachtwoord: (\S+)", r.stdout)
|
||||||
|
assert getoond, f"geen wachtwoord getoond in:\n{r.stdout}"
|
||||||
|
assert _inloggen(poort, "auto", getoond.group(1)) == 200
|
||||||
|
|
||||||
|
|
||||||
|
@geen_curl
|
||||||
|
def test_tweede_account_wordt_netjes_geweigerd(draaiende_app, tmp_path):
|
||||||
|
poort = draaiende_app
|
||||||
|
inst = tmp_path / "inst"
|
||||||
|
inst.mkdir()
|
||||||
|
(inst / ".env").write_text(f"PORT={poort}\n")
|
||||||
|
ww = tmp_path / "ww"
|
||||||
|
ww.write_text("een-heel-lang-wachtwoord\n")
|
||||||
|
_draai("--create-admin", "--dir", str(inst), "--admin", "eerste",
|
||||||
|
"--admin-password-file", str(ww), "--yes")
|
||||||
|
|
||||||
|
r = _draai("--create-admin", "--dir", str(inst), "--admin", "tweede",
|
||||||
|
"--admin-password-file", str(ww), "--yes")
|
||||||
|
assert r.returncode == 0, r.stderr
|
||||||
|
assert "bestond al" in r.stdout
|
||||||
|
assert _inloggen(poort, "tweede", "een-heel-lang-wachtwoord") != 200
|
||||||
|
|
||||||
|
|
||||||
|
@geen_curl
|
||||||
|
def test_onbereikbare_server_meldt_dat_zonder_te_ontsporen(tmp_path):
|
||||||
|
inst = tmp_path / "inst"
|
||||||
|
inst.mkdir()
|
||||||
|
(inst / ".env").write_text(f"PORT={_vrije_poort()}\n")
|
||||||
|
ww = tmp_path / "ww"
|
||||||
|
ww.write_text("een-heel-lang-wachtwoord\n")
|
||||||
|
|
||||||
|
r = _draai("--create-admin", "--dir", str(inst), "--admin", "ramon",
|
||||||
|
"--admin-password-file", str(ww), "--yes")
|
||||||
|
assert r.returncode == 0, r.stderr
|
||||||
|
assert "niet bereikbaar" in r.stdout
|
||||||
|
|
||||||
|
|
||||||
def test_verwijst_naar_het_juiste_git_domein():
|
def test_verwijst_naar_het_juiste_git_domein():
|
||||||
tekst = SCRIPT.read_text(encoding="utf-8")
|
tekst = SCRIPT.read_text(encoding="utf-8")
|
||||||
assert 'GIT_HOST="git.ramonbesselink.nl"' in tekst
|
assert 'GIT_HOST="git.ramonbesselink.nl"' in tekst
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue