diff --git a/gomuks b/gomuks index d750602..3c759ba 160000 --- a/gomuks +++ b/gomuks @@ -1 +1 @@ -Subproject commit d7506029a62299515356f72061d36ae35e9c9590 +Subproject commit 3c759ba03a5235deb82cb1559ebc42c36ee0e874 diff --git a/lib/controllers/auth_url.dart b/lib/controllers/auth_url.dart new file mode 100644 index 0000000..d628461 --- /dev/null +++ b/lib/controllers/auth_url.dart @@ -0,0 +1,32 @@ +import "package:flutter_riverpod/flutter_riverpod.dart"; +import "package:nexus/controllers/client.dart"; +import "package:nexus/controllers/client_id.dart"; + +class AuthUrlController extends AsyncNotifier { + static const prefString = "auth_url"; + + final Uri homeserver; + AuthUrlController(this.homeserver); + + @override + Future build() async { + final fetched = await ref + .watch(ClientController.provider.notifier) + .getAuthUrl( + .new( + homeserverUrl: homeserver, + redirectUri: Uri.https("nexus.federated.nexus"), + responseMode: .query, + scopes: .new([.clientApi]), + clientId: await ref.watch( + ClientIdController.provider(homeserver).future, + ), + ), + ); + + return fetched.url; + } + + static final provider = AsyncNotifierProvider.autoDispose + .family(AuthUrlController.new); +} diff --git a/lib/controllers/client.dart b/lib/controllers/client.dart index 6f17caa..28c4d08 100644 --- a/lib/controllers/client.dart +++ b/lib/controllers/client.dart @@ -15,12 +15,14 @@ import "package:nexus/controllers/top_level_spaces.dart"; import "package:nexus/helpers/extensions/gomuks_buffer.dart"; import "package:nexus/main.dart"; import "package:nexus/models/event.dart"; +import "package:nexus/models/oauth_auth_code_response.dart"; import "package:nexus/models/paginate.dart"; import "package:nexus/models/requests/get_event.dart"; import "package:nexus/models/requests/get_related_events.dart"; import "package:nexus/models/requests/get_room_state.dart"; import "package:nexus/models/requests/join_room.dart"; import "package:nexus/models/profile.dart"; +import "package:nexus/models/requests/oauth/get_auth_url.dart"; import "package:nexus/models/requests/oauth/register_client.dart"; import "package:nexus/models/requests/paginate.dart"; import "package:nexus/models/requests/redact_event.dart"; @@ -281,6 +283,11 @@ class ClientController extends AsyncNotifier { request.toJson(), ))["client_id"]; + Future getAuthUrl(OAuthGetAuthUrl request) async => + .fromJson( + await _sendCommand("oauth_get_authorization_url", request.toJson()), + ); + Future discoverHomeserver(Uri homeserver) async { try { final response = await _sendCommand("discover_homeserver", { diff --git a/lib/controllers/client_id_controller.dart b/lib/controllers/client_id.dart similarity index 54% rename from lib/controllers/client_id_controller.dart rename to lib/controllers/client_id.dart index 252de52..14bfe35 100644 --- a/lib/controllers/client_id_controller.dart +++ b/lib/controllers/client_id.dart @@ -5,6 +5,9 @@ import "package:nexus/controllers/shared_prefs.dart"; class ClientIdController extends AsyncNotifier { static const prefString = "client_id"; + final Uri homeserver; + ClientIdController(this.homeserver); + @override Future build() async { final prefs = await ref.watch(SharedPrefsController.provider.future); @@ -16,8 +19,17 @@ class ClientIdController extends AsyncNotifier { .watch(ClientController.provider.notifier) .registerClient( .new( - homeserverUrl: Uri.https("matrix.federated.nexus"), + clientName: "Nexus", + applicationType: .native, + grantTypes: .new([.authorizationCode, .refreshToken]), + responseTypes: .new([.code]), + logoUri: Uri.https( + "nexus.federated.nexus", + "raw/branch/main/assets/mobile.svg", + ), + homeserverUrl: homeserver, clientUri: Uri.https("nexus.federated.nexus"), + redirectUris: .new([.https("nexus.federated.nexus")]), ), ); @@ -26,8 +38,6 @@ class ClientIdController extends AsyncNotifier { return fetched; } - static final provider = - AsyncNotifierProvider.autoDispose( - ClientIdController.new, - ); + static final provider = AsyncNotifierProvider.autoDispose + .family(ClientIdController.new); } diff --git a/lib/models/oauth_auth_code_response.dart b/lib/models/oauth_auth_code_response.dart new file mode 100644 index 0000000..5bb3f3f --- /dev/null +++ b/lib/models/oauth_auth_code_response.dart @@ -0,0 +1,15 @@ +import "package:freezed_annotation/freezed_annotation.dart"; +part "oauth_auth_code_response.freezed.dart"; +part "oauth_auth_code_response.g.dart"; + +@freezed +abstract class OAuthAuthCodeResponse with _$OAuthAuthCodeResponse { + const factory OAuthAuthCodeResponse({ + required String state, + required String codeVerifier, + required Uri url, + }) = _OAuthAuthCodeResponse; + + factory OAuthAuthCodeResponse.fromJson(Map json) => + _$OAuthAuthCodeResponseFromJson(json); +} diff --git a/lib/models/requests/oauth/get_auth_url.dart b/lib/models/requests/oauth/get_auth_url.dart index e69de29..68e025a 100644 --- a/lib/models/requests/oauth/get_auth_url.dart +++ b/lib/models/requests/oauth/get_auth_url.dart @@ -0,0 +1,29 @@ +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 scopes, + required String clientId, + String? userIdHint, + }) = _OAuthGetAuthUrl; + + factory OAuthGetAuthUrl.fromJson(Map json) => + _$OAuthGetAuthUrlFromJson(json); +} + +enum Scope { + openid, + email, + @JsonValue("urn:matrix:client:api:*") + clientApi, +} + +@JsonEnum(fieldRename: .snake) +enum ResponseMode { query, fragment } diff --git a/lib/models/requests/oauth/register_client.dart b/lib/models/requests/oauth/register_client.dart index 74d9562..c4ef68f 100644 --- a/lib/models/requests/oauth/register_client.dart +++ b/lib/models/requests/oauth/register_client.dart @@ -7,7 +7,7 @@ part "register_client.g.dart"; abstract class OAuthRegisterClientRequest with _$OAuthRegisterClientRequest { const factory OAuthRegisterClientRequest({ required Uri homeserverUrl, - ApplicationType? applicationType, + @Default(ApplicationType.web) ApplicationType applicationType, String? clientName, required Uri clientUri, Uri? logoUri, diff --git a/lib/pages/login.dart b/lib/pages/login.dart deleted file mode 100644 index 0d52afd..0000000 --- a/lib/pages/login.dart +++ /dev/null @@ -1,20 +0,0 @@ -import "package:flutter/material.dart"; -import "package:flutter_hooks/flutter_hooks.dart"; -import "package:hooks_riverpod/hooks_riverpod.dart"; -import "package:nexus/controllers/client.dart"; -import "package:nexus/controllers/client_id_controller.dart"; -import "package:nexus/helpers/extensions/better_when.dart"; -import "package:nexus/widgets/appbar.dart"; -import "package:nexus/helpers/required_validator_helper.dart"; - -class LoginPage extends HookConsumerWidget { - final Uri homeserver; - const LoginPage({super.key, required this.homeserver}); - - @override - Widget build(BuildContext context, WidgetRef ref) => Scaffold( - body: ref - .watch(ClientIdController.provider) - .betterWhen(data: (value) => Text(value)), - ); -} diff --git a/lib/pages/select_server.dart b/lib/pages/select_server.dart index a05238f..d602c16 100644 --- a/lib/pages/select_server.dart +++ b/lib/pages/select_server.dart @@ -2,10 +2,11 @@ import "package:flutter/material.dart"; import "package:flutter_hooks/flutter_hooks.dart"; import "package:flutter_svg/flutter_svg.dart"; import "package:hooks_riverpod/hooks_riverpod.dart"; +import "package:nexus/controllers/auth_url.dart"; import "package:nexus/controllers/client.dart"; import "package:nexus/helpers/launch_helper.dart"; +import "package:nexus/main.dart"; import "package:nexus/models/homeserver.dart"; -import "package:nexus/pages/login.dart"; import "package:nexus/widgets/appbar.dart"; import "package:nexus/widgets/divider_text.dart"; @@ -32,7 +33,7 @@ class SelectServerPage extends HookConsumerWidget { final newUrl = newHomeserver == null ? null : await ref - .watch(ClientController.provider.notifier) + .read(ClientController.provider.notifier) .discoverHomeserver(newHomeserver); if (context.mounted) { @@ -47,11 +48,18 @@ class SelectServerPage extends HookConsumerWidget { ), ); } else { - await Navigator.of(context).push( - MaterialPageRoute(builder: (_) => LoginPage(homeserver: newUrl)), + final authUrl = await ref.read( + AuthUrlController.provider(newUrl).future, ); + + print(authUrl); + // await Navigator.of(context).push( + // MaterialPageRoute(builder: (_) => LoginPage(homeserver: newUrl)), + // ); } } + } catch (error, stackTrace) { + showError(error, stackTrace); } finally { isLoading.value = false; }