wip: Sicherungs-Commit aller Änderungen seit April + Arbeitsstruktur (CLAUDE.md, ROADMAP.md, PROGRESS.md, Autopilot)
6 Wochen uncommittete Arbeit (Voice-Channels, LiveKit-Manager, Settings-Modal u.v.m.) als ein WIP-Commit gesichert, damit nichts verloren geht und der Pi den aktuellen Stand klonen kann. Thematische Aufarbeitung: siehe ROADMAP M0. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CPrAGBxBT6GfPXzeWQ4AXb
This commit is contained in:
@@ -0,0 +1,241 @@
|
||||
# 01 — Authentifizierung & Session
|
||||
|
||||
---
|
||||
|
||||
## Inhaltsverzeichnis
|
||||
- [Login mit Passwort](#login-mit-passwort)
|
||||
- [Login mit Token](#login-mit-token)
|
||||
- [SSO / OAuth](#sso--oauth)
|
||||
- [Register](#registrierung)
|
||||
- [Session prüfen & wiederherstellen](#session-prüfen--wiederherstellen)
|
||||
- [Logout](#logout)
|
||||
- [Multi-Account / Device](#multi-account--device)
|
||||
- [Homeserver ermitteln](#homeserver-ermitteln)
|
||||
- [Flows & Login-Typen abfragen](#flows--login-typen-abfragen)
|
||||
|
||||
---
|
||||
|
||||
## Login mit Passwort
|
||||
|
||||
```dart
|
||||
await client.checkHomeserver(Uri.parse('https://matrix.example.org'));
|
||||
|
||||
final loginResponse = await client.login(
|
||||
LoginType.mLoginPassword,
|
||||
password: 'geheimesPasswort',
|
||||
identifier: AuthenticationUserIdentifier(user: '@alice:example.org'),
|
||||
// oder nur Username (ohne Server):
|
||||
// identifier: AuthenticationUserIdentifier(user: 'alice'),
|
||||
initialDeviceDisplayName: 'Pyramid Android',
|
||||
);
|
||||
// loginResponse.accessToken, .deviceId, .userId
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Login mit Token
|
||||
|
||||
```dart
|
||||
await client.checkHomeserver(Uri.parse('https://matrix.example.org'));
|
||||
|
||||
await client.login(
|
||||
LoginType.mLoginToken,
|
||||
token: 'einmaliger_login_token',
|
||||
initialDeviceDisplayName: 'Pyramid',
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## SSO / OAuth
|
||||
|
||||
```dart
|
||||
// Verfügbare Login-Flows abfragen
|
||||
final flows = await client.getLoginFlows();
|
||||
final hasSso = flows.flows?.any((f) => f.type == AuthenticationTypes.sso) ?? false;
|
||||
|
||||
// SSO-URL erzeugen (öffnet Browser/WebView)
|
||||
final redirectUri = 'io.pyramid.app://login-callback';
|
||||
final ssoUrl = client.homeserver!.toString() +
|
||||
'/_matrix/client/v3/login/sso/redirect?redirectUrl=${Uri.encodeComponent(redirectUri)}';
|
||||
// → Uri im Browser öffnen, nach Redirect den Token extrahieren
|
||||
|
||||
// Nach Redirect mit Token einloggen
|
||||
await client.login(
|
||||
LoginType.mLoginToken,
|
||||
token: tokenAusRedirectUrl,
|
||||
initialDeviceDisplayName: 'Pyramid',
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Registrierung
|
||||
|
||||
```dart
|
||||
// Homeserver-Registrierung prüfen
|
||||
await client.checkHomeserver(Uri.parse('https://matrix.example.org'));
|
||||
|
||||
// UIAA-Flow starten
|
||||
try {
|
||||
await client.uiaRequestBackground(
|
||||
(auth) => client.register(
|
||||
username: 'neuernutzer',
|
||||
password: 'sicheresPasswort',
|
||||
initialDeviceDisplayName: 'Pyramid',
|
||||
auth: auth,
|
||||
),
|
||||
);
|
||||
} on MatrixException catch (e) {
|
||||
// e.error: M_USER_IN_USE, M_INVALID_USERNAME, etc.
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Session prüfen & wiederherstellen
|
||||
|
||||
```dart
|
||||
// Nach client.init() prüfen ob Session noch gültig ist
|
||||
if (client.isLogged()) {
|
||||
print('Eingeloggt als: ${client.userID}');
|
||||
print('Homeserver: ${client.homeserver}');
|
||||
print('Device ID: ${client.deviceID}');
|
||||
print('Access Token: ${client.accessToken}');
|
||||
}
|
||||
|
||||
// Auf Login-State reagieren
|
||||
client.onLoginStateChanged.stream.listen((LoginState state) {
|
||||
switch (state) {
|
||||
case LoginState.loggedIn: // Session aktiv
|
||||
case LoginState.softLoggedOut: // Token abgelaufen, Re-Auth nötig
|
||||
case LoginState.loggedOut: // Ausgeloggt
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Logout
|
||||
|
||||
```dart
|
||||
// Nur dieses Device
|
||||
await client.logout();
|
||||
|
||||
// Alle Devices
|
||||
await client.logoutAll();
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Multi-Account / Device
|
||||
|
||||
```dart
|
||||
// Eigene Devices (Sessions) auflisten
|
||||
final devices = await client.getDevices();
|
||||
for (final device in devices ?? []) {
|
||||
print('${device.deviceId}: ${device.displayName} — ${device.lastSeenIp}');
|
||||
}
|
||||
|
||||
// Device umbenennen
|
||||
await client.updateDevice(
|
||||
deviceId: 'DEVICEID',
|
||||
displayName: 'Pyramid (Wohnzimmer)',
|
||||
);
|
||||
|
||||
// Device löschen (andere Session killen)
|
||||
await client.deleteDevice(
|
||||
'ANDERES_DEVICE_ID',
|
||||
auth: AuthenticationPassword(
|
||||
identifier: AuthenticationUserIdentifier(user: client.userID!),
|
||||
password: 'meinPasswort',
|
||||
),
|
||||
);
|
||||
|
||||
// Mehrere Devices auf einmal löschen
|
||||
await client.deleteDevices(
|
||||
['DEVICE1', 'DEVICE2'],
|
||||
auth: AuthenticationPassword(...),
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Homeserver ermitteln
|
||||
|
||||
```dart
|
||||
// .well-known auflösen (Autodiscovery)
|
||||
final discovery = await client.checkHomeserver(
|
||||
Uri.parse('https://example.org'), // Domain reicht, SDK findet Matrix-Server
|
||||
);
|
||||
// client.homeserver ist jetzt gesetzt
|
||||
|
||||
// Direkt mit bekannter HS-URL
|
||||
await client.checkHomeserver(Uri.parse('https://matrix.example.org'));
|
||||
|
||||
// Homeserver-Versioninfo
|
||||
final serverVersion = await client.getVersions();
|
||||
print(serverVersion.versions); // ['v1.1', 'v1.2', ...]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Flows & Login-Typen abfragen
|
||||
|
||||
```dart
|
||||
final response = await client.getLoginFlows();
|
||||
for (final flow in response.flows ?? []) {
|
||||
switch (flow.type) {
|
||||
case AuthenticationTypes.password: // m.login.password
|
||||
case AuthenticationTypes.sso: // m.login.sso
|
||||
case AuthenticationTypes.token: // m.login.token
|
||||
case 'm.login.cas': // Legacy-CAS
|
||||
}
|
||||
}
|
||||
|
||||
// SSO-Provider Details (für Brand-Buttons im UI)
|
||||
final ssoProviders = response.flows
|
||||
?.where((f) => f.type == AuthenticationTypes.sso)
|
||||
.expand((f) => f.identityProviders ?? [])
|
||||
.toList();
|
||||
// ssoProvider.id, .name, .brand, .icon
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## UIAA (User-Interactive Auth) Flows
|
||||
|
||||
```dart
|
||||
// Generisches UIAA-Handling (z.B. für Account-Löschung)
|
||||
await client.uiaRequestBackground(
|
||||
(auth) => client.deactivateAccount(auth: auth, eraseData: false),
|
||||
);
|
||||
|
||||
// Passwort ändern (braucht Re-Auth)
|
||||
await client.uiaRequestBackground(
|
||||
(auth) => client.changePassword(
|
||||
'neuesPasswort',
|
||||
auth: auth,
|
||||
oldPassword: 'altesPasswort', // optional, falls Server es erlaubt
|
||||
),
|
||||
);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Fehlerbehandlung
|
||||
|
||||
```dart
|
||||
try {
|
||||
await client.login(...);
|
||||
} on MatrixException catch (e) {
|
||||
switch (e.error) {
|
||||
case MatrixError.M_FORBIDDEN: // Falsches Passwort
|
||||
case MatrixError.M_USER_IN_USE: // Username vergeben
|
||||
case MatrixError.M_INVALID_USERNAME:
|
||||
case MatrixError.M_LIMIT_EXCEEDED: // Rate-Limiting
|
||||
case MatrixError.M_UNKNOWN:
|
||||
}
|
||||
print(e.errorMessage); // Menschenlesbarer Text vom Server
|
||||
}
|
||||
```
|
||||
Reference in New Issue
Block a user