OAuth Support (#53)

Rips out the old auth method, adds OAuth support. Fixes #51.

Tested Platforms:
- [x] Linux
    - [x] Flatpak
    - [x] Native (Nix)
- [x] Android
- [ ] Windows
- [ ] MacOS

Reviewed-on: Nexus/nexus#53
This commit is contained in:
Henry Hiles 2026-07-20 19:46:18 -04:00 committed by Henry Hiles
commit 7d106ad3a2
86 changed files with 558 additions and 1344 deletions

View file

@ -2,9 +2,8 @@ import "package:freezed_annotation/freezed_annotation.dart";
part "get_event.freezed.dart";
part "get_event.g.dart";
@Freezed()
@freezed
abstract class GetEventRequest with _$GetEventRequest {
const GetEventRequest._();
const factory GetEventRequest({
required String roomId,
required String eventId,

View file

@ -1,15 +0,0 @@
import "package:freezed_annotation/freezed_annotation.dart";
part "login.freezed.dart";
part "login.g.dart";
@freezed
abstract class LoginRequest with _$LoginRequest {
const factory LoginRequest({
required String username,
required String password,
required String homeserverUrl,
}) = _LoginRequest;
factory LoginRequest.fromJson(Map<String, Object?> json) =>
_$LoginRequestFromJson(json);
}

View file

@ -0,0 +1,17 @@
import "package:freezed_annotation/freezed_annotation.dart";
part "exchange_token.freezed.dart";
part "exchange_token.g.dart";
@freezed
abstract class OAuthExchangeTokenRequest with _$OAuthExchangeTokenRequest {
const factory OAuthExchangeTokenRequest({
required Uri homeserverUrl,
required String codeVerifier,
required Uri redirectUri,
required String code,
required String clientId,
}) = _OAuthExchangeTokenRequest;
factory OAuthExchangeTokenRequest.fromJson(Map<String, Object?> json) =>
_$OAuthExchangeTokenRequestFromJson(json);
}

View file

@ -0,0 +1,43 @@
import "dart:math";
import "package:fast_immutable_collections/fast_immutable_collections.dart";
import "package:freezed_annotation/freezed_annotation.dart";
part "get_auth_url.freezed.dart";
part "get_auth_url.g.dart";
@freezed
abstract class OAuthGetAuthUrl with _$OAuthGetAuthUrl {
const factory OAuthGetAuthUrl({
required ResponseMode responseMode,
required Uri homeserverUrl,
required Uri redirectUri,
required IList<String> scopes,
required String clientId,
String? userIdHint,
}) = _OAuthGetAuthUrl;
factory OAuthGetAuthUrl.fromJson(Map<String, Object?> json) =>
_$OAuthGetAuthUrlFromJson(json);
}
abstract class Scope {
static final openid = "openid";
static final email = "email";
static final clientApi = "urn:matrix:client:api:*";
static final _deviceChars = IList(
("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
"abcdefghijklmnopqrstuvwxyz"
"0123456789"
"-._~")
.split(""),
);
static String get _deviceId =>
_deviceChars.shuffle(Random.secure()).sublist(0, 10).join();
static String get device => "urn:matrix:client:device:$_deviceId";
}
@JsonEnum(fieldRename: .snake)
enum ResponseMode { query, fragment }

View file

@ -0,0 +1,47 @@
import "package:fast_immutable_collections/fast_immutable_collections.dart";
import "package:freezed_annotation/freezed_annotation.dart";
part "register_client.freezed.dart";
part "register_client.g.dart";
@freezed
abstract class OAuthRegisterClientRequest with _$OAuthRegisterClientRequest {
const factory OAuthRegisterClientRequest({
required Uri homeserverUrl,
@Default(ApplicationType.web) ApplicationType applicationType,
String? clientName,
required Uri clientUri,
Uri? logoUri,
Uri? policyUri,
Uri? tosUri,
IList<GrantType>? grantTypes,
IList<Uri>? redirectUris,
IList<ResponseType>? responseTypes,
AuthMethod? authMethod,
}) = _OAuthRegisterClientRequest;
factory OAuthRegisterClientRequest.fromJson(Map<String, Object?> json) =>
_$OAuthRegisterClientRequestFromJson(json);
}
enum ApplicationType { native, web }
@JsonEnum(fieldRename: .snake)
enum ResponseType { code, idToken }
@JsonEnum(fieldRename: .snake)
enum AuthMethod {
clientSecretPost,
clientSecretBasic,
clientSecretJwt,
privateKeyJwt,
none,
}
@JsonEnum(fieldRename: .snake)
enum GrantType {
authorizationCode,
refreshToken,
clientCredentials,
@JsonValue("urn:ietf:params:oauth:grant-type:device_code")
deviceCode,
}