336 lines
13 KiB
Markdown
336 lines
13 KiB
Markdown
|
|
# ic-web — IC-Webhosting
|
|||
|
|
|
|||
|
|
Ein IC-Hostinganbieter: er vergibt Domänen, richtet je Domäne einen Zugang
|
|||
|
|
ein, und die Domäneninhaber pflegen darauf ihre Webseite und ihre Postfächer.
|
|||
|
|
Aufgerufen werden die Seiten im Browser von **pc-live** unter `ic://domäne`.
|
|||
|
|
|
|||
|
|
## Die drei Ebenen
|
|||
|
|
|
|||
|
|
| Rolle | Zugang | Darf |
|
|||
|
|
|---|---|---|
|
|||
|
|
| **Anbieter** (`superadmin`) | `admin@liveinvader.ls` | Domänen anlegen, übertragen, sperren, löschen; überall Zugänge und Seiten |
|
|||
|
|
| **Domänenadmin** (`admin`) | `<name>@<domäne>` | Seiten der eigenen Domäne pflegen, dort Zugänge anlegen und verwalten |
|
|||
|
|
| **Redakteur** (`editor`) | `<name>@<domäne>` | nur Seiten der eigenen Domäne pflegen |
|
|||
|
|
|
|||
|
|
Job und Serverrechte spielen keine Rolle. Wer den Zugang kennt, verwaltet die
|
|||
|
|
Seite — unabhängig davon, welchen Charakter er gerade spielt.
|
|||
|
|
|
|||
|
|
## Ein Zugang ist ein Postfach
|
|||
|
|
|
|||
|
|
`presse@weazel-news.ls` ist Benutzername, Passwort **und** Mailadresse in einem.
|
|||
|
|
Beim Anmelden wird der Zugriff auf das Postfach in `ic-mail` erteilt, beim
|
|||
|
|
Abmelden wieder entzogen. Deshalb können **mehrere Personen gleichzeitig
|
|||
|
|
dasselbe Postfach offen haben** — ein Firmenpostfach gehört der Firma, nicht
|
|||
|
|
einer Person.
|
|||
|
|
|
|||
|
|
Wird ein Zugang gelöscht, bleibt das Postfach mit seinen Nachrichten bestehen.
|
|||
|
|
|
|||
|
|
Aufgeräumt wird **beim Start**, nicht beim Herunterfahren: ic-web widerruft
|
|||
|
|
dann alle Postfachzugriffe, die es je erteilt hat (`granted_by = 'ic-web'`).
|
|||
|
|
Beim Stoppen ginge das nicht — der Aufruf nach ic-mail wartet auf eine
|
|||
|
|
Datenbankantwort, und eine wartende Koroutine lässt sich während des
|
|||
|
|
Herunterfahrens nicht mehr fortsetzen; der Server meldet dann
|
|||
|
|
„Execution of function reference in script host failed". Der Umweg über den
|
|||
|
|
Start deckt außerdem den Fall ab, den ein Stop-Handler nie erwischt: den
|
|||
|
|
Absturz.
|
|||
|
|
|
|||
|
|
## Postfächer im Mailclient
|
|||
|
|
|
|||
|
|
Der Mailclient von pc-live kann weitere Postfächer aufnehmen: *Postfächer →
|
|||
|
|
**+ Postfach hinzufügen*** fragt Adresse und Passwort ab — dieselbe Prüfung
|
|||
|
|
wie die Anmeldung, aber **ohne Verwaltungsrechte**. Man kann zehn Postfächer
|
|||
|
|
offen haben (`Config.MaxOpenMailboxes`) und trotzdem nur für eines Seiten
|
|||
|
|
pflegen dürfen.
|
|||
|
|
|
|||
|
|
Freigeschaltete Postfächer tragen ein ✕ zum Entfernen; das eigene und
|
|||
|
|
dienstlich zugewiesene nicht — die gehören einem nicht. Beim Verlassen des
|
|||
|
|
Servers werden alle wieder geschlossen, ebenso beim nächsten Start von ic-web.
|
|||
|
|
|
|||
|
|
Das Abmelden von der Verwaltung nimmt ein eigenständig geöffnetes Postfach
|
|||
|
|
nicht weg.
|
|||
|
|
|
|||
|
|
## Signaturen
|
|||
|
|
|
|||
|
|
Die Signatur gehört zum **Postfach**, nicht zur Person: eine Firmenadresse
|
|||
|
|
trägt dieselbe Fußzeile, egal wer sie gerade bedient. Ändern darf sie jeder mit
|
|||
|
|
Zugriff auf das Postfach (*Signatur* im Mailclient).
|
|||
|
|
|
|||
|
|
Beim Schreiben wird sie unter den Text gesetzt, getrennt durch eine Zeile mit
|
|||
|
|
`--`. Beim Wechsel des Absenders tauscht sie sich aus, der geschriebene Text
|
|||
|
|
bleibt stehen.
|
|||
|
|
|
|||
|
|
Gespeichert wird in `ic_mail_accounts.signature` (ic-mail, Migration
|
|||
|
|
`sql/migration_signaturen.sql`).
|
|||
|
|
|
|||
|
|
## Ordner je Postfach
|
|||
|
|
|
|||
|
|
Ordner gehören zum Postfach, nicht zur Person (`pc_live_mail_folders.address`,
|
|||
|
|
Migration `pc-live/sql/migration_postfach_ordner.sql`). Ein geteiltes Postfach
|
|||
|
|
hat für alle dieselbe Struktur.
|
|||
|
|
|
|||
|
|
Eine Mail an ein geteiltes Postfach wird je Empfänger einmal gespeichert. Damit
|
|||
|
|
das Einsortieren trotzdem für alle gilt, tragen alle Kopien einer Zustellung
|
|||
|
|
dieselbe `delivery_id`: wird eine Kopie verschoben, wandern die anderen mit.
|
|||
|
|
Gelesen und gelöscht bleibt persönlich — das ist keine Eigenschaft der
|
|||
|
|
Nachricht, sondern der Person.
|
|||
|
|
|
|||
|
|
Welches Postfach gemeint ist, schickt der Client mit; der Server prüft es über
|
|||
|
|
`ic-mail:CanAccessAddress` und fällt ohne Zugriff auf das persönliche Postfach
|
|||
|
|
zurück, statt fremde Ordner herauszugeben.
|
|||
|
|
|
|||
|
|
## Kalender
|
|||
|
|
|
|||
|
|
Dieselbe Mechanik wie bei Postfächern und Ordnern
|
|||
|
|
(`pc_live_calendar.address` + `visibility`, Migration
|
|||
|
|
`pc-live/sql/migration_kalender.sql`):
|
|||
|
|
|
|||
|
|
| Sichtbarkeit | gehört | sieht | bearbeitet |
|
|||
|
|
|---|---|---|---|
|
|||
|
|
| `private` | der Person | nur sie | nur sie |
|
|||
|
|
| `shared` | einem Postfach | wer es bedient | wer es bedient |
|
|||
|
|
| `public` | einem Postfach | jeder auf dem Server | wer es bedient |
|
|||
|
|
|
|||
|
|
Ein öffentlicher Termin hängt bewusst auch an einem Postfach — sonst gäbe es
|
|||
|
|
niemanden, der ihn später ändern oder absagen könnte. Wer ein Postfach bedient,
|
|||
|
|
darf dessen Termine auch dann ändern, wenn jemand anderes sie eingetragen hat;
|
|||
|
|
genau das macht sie geteilt.
|
|||
|
|
|
|||
|
|
Änderungen erreichen alle Beteiligten sofort, sonst hätte jeder eine andere
|
|||
|
|
Vorstellung vom Dienstplan, bis er den PC neu öffnet.
|
|||
|
|
|
|||
|
|
## Ablauf
|
|||
|
|
|
|||
|
|
1. Der Anbieter meldet sich in der App **Webhosting** mit `admin@liveinvader.ls`
|
|||
|
|
an (Startpasswort siehe unten) und ändert sein Passwort.
|
|||
|
|
2. Er legt unter *Verwaltung* eine Domäne an, wählt den Besitzer-Job und den
|
|||
|
|
ersten Zugang. Benutzername und Passwort werden **einmal** angezeigt.
|
|||
|
|
3. Der Domänenadmin meldet sich damit an, ändert sein Passwort und legt unter
|
|||
|
|
*Zugänge* weitere Zugänge für seine Leute an.
|
|||
|
|
4. Alle Zugänge dieser Domäne pflegen die Seiten unter *Meine Seite* und
|
|||
|
|
veröffentlichen sie.
|
|||
|
|
|
|||
|
|
## Ersteinrichtung
|
|||
|
|
|
|||
|
|
Beim ersten Start legt ic-web den Anbieterzugang aus `Config.MainAdmin` an und
|
|||
|
|
schreibt Benutzername und Startpasswort in die Serverkonsole. Vorgabe:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
admin@liveinvader.ls / liveinvader
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Beim ersten Anmelden wird zum Ändern aufgefordert.
|
|||
|
|
|
|||
|
|
Passwort vergessen? In der Serverkonsole:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
webpasswd admin@liveinvader.ls neues-passwort
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## Inhalte sind kein HTML
|
|||
|
|
|
|||
|
|
Seiten bestehen aus **typisierten Blöcken** (`shared/blocks.lua`), nicht aus
|
|||
|
|
Markup. Der Grund: die Seiten werden im NUI von pc-live angezeigt — im selben
|
|||
|
|
Kontext wie der PC selbst. Wer dort Markup einschleusen kann, kann auch dessen
|
|||
|
|
NUI-Callbacks aufrufen. Ein Blockmodell schließt das konstruktiv aus, statt es
|
|||
|
|
filtern zu müssen; HTML zu filtern ist ein Wettlauf, den man langfristig
|
|||
|
|
verliert.
|
|||
|
|
|
|||
|
|
`B.Validate` baut jeden Block aus dem Schema **neu auf**. Was nicht im Schema
|
|||
|
|
steht, fällt weg — es wird nicht bereinigt, sondern verworfen.
|
|||
|
|
|
|||
|
|
Blocktypen: `heading`, `text`, `image`, `list`, `button`, `contact`, `divider`.
|
|||
|
|
|
|||
|
|
Der Renderer in pc-live setzt Text ausschließlich über `textContent`, niemals
|
|||
|
|
über `innerHTML`. Deshalb bleiben `<` und `>` im Text erhalten statt
|
|||
|
|
verstümmelt zu werden.
|
|||
|
|
|
|||
|
|
## Domänennamen
|
|||
|
|
|
|||
|
|
Form: `name.endung`, nur Kleinbuchstaben, Ziffern und Bindestriche, 3–30
|
|||
|
|
Zeichen, Endung aus `Config.Domain.allowedTlds` (`.ls .sa .gov .org .net`).
|
|||
|
|
|
|||
|
|
`Config.Domain.reserved` sperrt Namen **nur gegen die Selbstanmeldung** — der
|
|||
|
|
Anbieter darf `lspd.ls` sehr wohl vergeben, dafür ist er da.
|
|||
|
|
|
|||
|
|
Unabhängig davon gesperrt sind Domänen des Mailsystems: existiert der Realm
|
|||
|
|
schon in ic-mail als `is_default`, `system` oder `citizen` (etwa `mail.ls`),
|
|||
|
|
lehnt `D.EnsureRealm` ab — für alle. Sonst hinge eine Firmenwebseite an der
|
|||
|
|
Domäne sämtlicher persönlicher Postfächer. Eine herrenlose *Firmen*-Domäne
|
|||
|
|
(`type = company`) wird dagegen übernommen.
|
|||
|
|
|
|||
|
|
## Bilder und Meldungen
|
|||
|
|
|
|||
|
|
Bilder werden extern verlinkt — NUI kann keine Dateien hochladen. Erlaubt sind
|
|||
|
|
nur `https` und die Hosts aus `Config.ImageHosts` (Subdomains eingeschlossen).
|
|||
|
|
Die Hostliste ist der Rahmen, die Meldefunktion fängt den Rest — sie greift
|
|||
|
|
aber erst nachträglich.
|
|||
|
|
|
|||
|
|
Jeder Spieler kann eine Seite melden (Link unten auf jeder Seite), einmal je
|
|||
|
|
Seite und Stunde. Der Anbieter sieht die Meldungen unter *Meldungen*.
|
|||
|
|
|
|||
|
|
## Passwörter
|
|||
|
|
|
|||
|
|
Gespeichert wird `SHA2(salt || passwort)`, gerechnet in der Datenbank — das
|
|||
|
|
Passwort läuft nur als Abfrageparameter durch den Server. Fünf Fehlversuche je
|
|||
|
|
Benutzername innerhalb von fünf Minuten sperren den Namen kurzzeitig
|
|||
|
|
(`Config.Login`).
|
|||
|
|
|
|||
|
|
Das ist ein **IC-Passwort**, keine Sicherheitsgrenze gegen Serveradmins: wer
|
|||
|
|
Datenbankzugriff hat, kann jeden Zugang zurücksetzen. Es verhindert, dass
|
|||
|
|
Mitspieler fremde Seiten ändern — nicht mehr.
|
|||
|
|
|
|||
|
|
## Installation
|
|||
|
|
|
|||
|
|
### 1. Ordner
|
|||
|
|
|
|||
|
|
Der Ordner `ic-web` gehört in dein Resource-Verzeichnis, zum Beispiel:
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
resources/[haleoe]/ic-web/
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. Datenbank
|
|||
|
|
|
|||
|
|
```bash
|
|||
|
|
mysql -u BENUTZER -p DATENBANK < sql/ic_web.sql
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Legt an: `ic_web_sites`, `ic_web_pages`, `ic_web_accounts`,
|
|||
|
|
`ic_web_login_fails`, `ic_web_reports`. Wiederholt ausführbar.
|
|||
|
|
|
|||
|
|
### 3. server.cfg
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
ensure oxmysql
|
|||
|
|
ensure es_extended
|
|||
|
|
ensure ic-mail
|
|||
|
|
ensure ic-web # nach ic-mail
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
Liegt alles in einem Ordner mit eckigen Klammern, genügt `ensure [haleoe]` —
|
|||
|
|
dann startet ic-web automatisch mit. Die Reihenfolge stimmt dabei von selbst,
|
|||
|
|
weil ic-mail alphabetisch vorher kommt.
|
|||
|
|
|
|||
|
|
### 4. Anbindung an pc-live
|
|||
|
|
|
|||
|
|
ic-web bringt keine eigene Oberfläche mit — sie sitzt im PC. Diese Dateien
|
|||
|
|
gehören nach `pc-live`:
|
|||
|
|
|
|||
|
|
| Datei | Ziel in pc-live | Zweck |
|
|||
|
|
|---|---|---|
|
|||
|
|
| `client/webhosting.lua` | `client/` | Brücke zwischen NUI und Server |
|
|||
|
|
| `nui/js/apps/webhosting.js` | `nui/js/apps/` | die App selbst |
|
|||
|
|
|
|||
|
|
Dazu in pc-live eintragen:
|
|||
|
|
|
|||
|
|
**`fxmanifest.lua`**
|
|||
|
|
```lua
|
|||
|
|
client_scripts { …, 'client/webhosting.lua' }
|
|||
|
|
files { …, 'nui/js/apps/webhosting.js' }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**`nui/index.html`** — vor `desktop.js`, weil andere Apps den Dialogbaukasten
|
|||
|
|
daraus benutzen:
|
|||
|
|
```html
|
|||
|
|
<script src="js/apps/webhosting.js"></script>
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**`nui/js/desktop.js`** — App eintragen und den Antwortkanal anschließen:
|
|||
|
|
```js
|
|||
|
|
'pc.webhosting': { name: 'Webhosting', icon: '🌍', open: () => WebhostingApp.open() },
|
|||
|
|
…
|
|||
|
|
case 'icweb_response': ICWebNet.onResponse(data); break;
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**`server/apps.lua`** — damit die App auf dem Schreibtisch erscheint:
|
|||
|
|
```lua
|
|||
|
|
AppRegistry.Register({
|
|||
|
|
app_id = "pc.webhosting", name = "Webhosting", icon = "🌍",
|
|||
|
|
version = "1.0.0", category = "system", default = true,
|
|||
|
|
permissions = {}, dependencies = {}, price = 0,
|
|||
|
|
description = "IC-Domänen und Webseiten verwalten. Anmeldung erforderlich.",
|
|||
|
|
})
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**`nui/js/apps/browser.js`** — damit `ic://domäne.ls` im Browser aufgeht:
|
|||
|
|
der Zweig, der Adressen der Form `name.endung` an `ICWebNet.call('getSite', …)`
|
|||
|
|
gibt und mit `ICWebRender.renderPage` zeichnet.
|
|||
|
|
|
|||
|
|
### 5. Erste Anmeldung
|
|||
|
|
|
|||
|
|
Beim ersten Start legt ic-web den Anbieterzugang an und schreibt ihn in die
|
|||
|
|
Serverkonsole. Vorgabe: `admin@liveinvader.ls` / `liveinvader`. Beim ersten
|
|||
|
|
Anmelden wird ein eigenes Passwort verlangt.
|
|||
|
|
|
|||
|
|
## Voraussetzungen
|
|||
|
|
|
|||
|
|
| | |
|
|||
|
|
|---|---|
|
|||
|
|
| `oxmysql` | Datenbankzugriff |
|
|||
|
|
| `es_extended` | Spielername, Jobliste, Benachrichtigungen |
|
|||
|
|
| `ic-mail` | Domänen und Postfächer. Fehlt es, laufen die Webseiten trotzdem – nur ohne Mailadressen |
|
|||
|
|
| `pc-live` | die Oberfläche |
|
|||
|
|
| `fmsdk` | Protokoll. Fehlt es, wird verworfen statt zu scheitern |
|
|||
|
|
|
|||
|
|
ic-mail braucht dafür sechs Exports, die dieses Projekt voraussetzt:
|
|||
|
|
`GetRealmByName`, `CreateRealm`, `EnsureSharedAddress`, `GrantAddressAccess`,
|
|||
|
|
`RevokeAddressAccess`, `RevokeAccessGrantedBy`.
|
|||
|
|
|
|||
|
|
## Selbstanmeldung (optional, aus)
|
|||
|
|
|
|||
|
|
`Config.SelfRegistration.enabled = true` erlaubt Behörden und Unternehmen, sich
|
|||
|
|
ohne Anbieter selbst eine Domäne zu holen — Grundlage ist dann der ESX-Job ab
|
|||
|
|
`minGrade`. Der Zugang wird dabei automatisch erzeugt und einmalig angezeigt.
|
|||
|
|
Standardmäßig aus, weil die Vergabe über den Anbieter läuft.
|
|||
|
|
|
|||
|
|
## Konsolenbefehle
|
|||
|
|
|
|||
|
|
Notbremse des Serverbetreibers, kein IC-Weg. Erlaubt sind Serverkonsole sowie
|
|||
|
|
ESX-Gruppe `admin`/`superadmin` bzw. ACE `ic_web.admin` (`Config.Console`).
|
|||
|
|
|
|||
|
|
| Befehl | Wirkung |
|
|||
|
|
|---|---|
|
|||
|
|
| `webpasswd <benutzer@domäne> <passwort>` | Passwort setzen |
|
|||
|
|
| `webaccounts` | alle Zugänge auflisten |
|
|||
|
|
| `webreports` | offene Meldungen |
|
|||
|
|
| `webblock <domäne>` | Seite sperren bzw. freigeben |
|
|||
|
|
| `webreport done\|dismiss <id>` | Meldung abschließen |
|
|||
|
|
|
|||
|
|
## Exports
|
|||
|
|
|
|||
|
|
```lua
|
|||
|
|
exports['ic-web']:GetSite(domain, slug) -- (seite, nil) oder (nil, fehlertext)
|
|||
|
|
exports['ic-web']:DomainExists(domain)
|
|||
|
|
exports['ic-web']:GetSitesForJob(job)
|
|||
|
|
exports['ic-web']:GetSession(src) -- wer ist an diesem PC angemeldet
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
`ic-mail` wurde um vier Exports ergänzt, die ic-web benutzt:
|
|||
|
|
`EnsureSharedAddress`, `GrantAddressAccess`, `RevokeAddressAccess`,
|
|||
|
|
`DeleteAddress` — sowie `GetRealmByName` und `CreateRealm` für die Domänen.
|
|||
|
|
|
|||
|
|
## Netzwerkereignisse
|
|||
|
|
|
|||
|
|
Jedes Ereignis bekommt eine Anfrage-Id und antwortet über
|
|||
|
|
`ic-web:client:response` mit `{ ok, data, error }`. Alle sind gedrosselt;
|
|||
|
|
Rechte werden ausnahmslos serverseitig aus der Anmeldung abgeleitet.
|
|||
|
|
|
|||
|
|
Anmeldung: `login`, `logout`, `session`, `changePassword`.
|
|||
|
|
Seiten: `getSite`, `listMine`, `getEditable`, `savePage`, `deletePage`,
|
|||
|
|
`updateSite`, `report`.
|
|||
|
|
Zugänge: `listAccounts`, `createAccount`, `setAccountPassword`,
|
|||
|
|
`setAccountActive`, `setAccountRole`, `deleteAccount`.
|
|||
|
|
Anbieter: `adminListSites`, `adminListAccounts`, `adminListJobs`,
|
|||
|
|
`adminRegister`, `adminSetBlocked`, `adminSetOwner`, `adminDeleteSite`,
|
|||
|
|
`adminListReports`, `adminSetReportStatus`.
|
|||
|
|
|
|||
|
|
## Tabellen
|
|||
|
|
|
|||
|
|
`ic_web_sites`, `ic_web_pages`, `ic_web_accounts`, `ic_web_login_fails`,
|
|||
|
|
`ic_web_reports`.
|
|||
|
|
|
|||
|
|
Die Domäne wird über den **Namen** referenziert, nicht über einen
|
|||
|
|
Fremdschlüssel auf `ic_mail_realms` — Fremdschlüssel über Resource-Grenzen
|
|||
|
|
hinweg koppeln zwei Lebenszyklen aneinander, die unabhängig voneinander
|
|||
|
|
installiert werden.
|