add auth code flow support
This commit is contained in:
parent
fe59f7679c
commit
790caf1d38
9 changed files with 112 additions and 31 deletions
2
gomuks
2
gomuks
|
|
@ -1 +1 @@
|
|||
Subproject commit d7506029a62299515356f72061d36ae35e9c9590
|
||||
Subproject commit 3c759ba03a5235deb82cb1559ebc42c36ee0e874
|
||||
32
lib/controllers/auth_url.dart
Normal file
32
lib/controllers/auth_url.dart
Normal file
|
|
@ -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<Uri> {
|
||||
static const prefString = "auth_url";
|
||||
|
||||
final Uri homeserver;
|
||||
AuthUrlController(this.homeserver);
|
||||
|
||||
@override
|
||||
Future<Uri> 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, Uri, Uri>(AuthUrlController.new);
|
||||
}
|
||||
|
|
@ -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<int> {
|
|||
request.toJson(),
|
||||
))["client_id"];
|
||||
|
||||
Future<OAuthAuthCodeResponse> getAuthUrl(OAuthGetAuthUrl request) async =>
|
||||
.fromJson(
|
||||
await _sendCommand("oauth_get_authorization_url", request.toJson()),
|
||||
);
|
||||
|
||||
Future<Uri?> discoverHomeserver(Uri homeserver) async {
|
||||
try {
|
||||
final response = await _sendCommand("discover_homeserver", {
|
||||
|
|
|
|||
|
|
@ -5,6 +5,9 @@ import "package:nexus/controllers/shared_prefs.dart";
|
|||
class ClientIdController extends AsyncNotifier<String> {
|
||||
static const prefString = "client_id";
|
||||
|
||||
final Uri homeserver;
|
||||
ClientIdController(this.homeserver);
|
||||
|
||||
@override
|
||||
Future<String> build() async {
|
||||
final prefs = await ref.watch(SharedPrefsController.provider.future);
|
||||
|
|
@ -16,8 +19,17 @@ class ClientIdController extends AsyncNotifier<String> {
|
|||
.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<String> {
|
|||
return fetched;
|
||||
}
|
||||
|
||||
static final provider =
|
||||
AsyncNotifierProvider.autoDispose<ClientIdController, String>(
|
||||
ClientIdController.new,
|
||||
);
|
||||
static final provider = AsyncNotifierProvider.autoDispose
|
||||
.family<ClientIdController, String, Uri>(ClientIdController.new);
|
||||
}
|
||||
15
lib/models/oauth_auth_code_response.dart
Normal file
15
lib/models/oauth_auth_code_response.dart
Normal file
|
|
@ -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<String, Object?> json) =>
|
||||
_$OAuthAuthCodeResponseFromJson(json);
|
||||
}
|
||||
|
|
@ -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<Scope> scopes,
|
||||
required String clientId,
|
||||
String? userIdHint,
|
||||
}) = _OAuthGetAuthUrl;
|
||||
|
||||
factory OAuthGetAuthUrl.fromJson(Map<String, Object?> json) =>
|
||||
_$OAuthGetAuthUrlFromJson(json);
|
||||
}
|
||||
|
||||
enum Scope {
|
||||
openid,
|
||||
email,
|
||||
@JsonValue("urn:matrix:client:api:*")
|
||||
clientApi,
|
||||
}
|
||||
|
||||
@JsonEnum(fieldRename: .snake)
|
||||
enum ResponseMode { query, fragment }
|
||||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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)),
|
||||
);
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue