working a bit

This commit is contained in:
Henry Hiles 2025-06-19 13:03:18 -04:00
commit 93b6f180f6
No known key found for this signature in database
7 changed files with 61 additions and 23 deletions

View file

@ -21,9 +21,26 @@ class ApiHelper {
final password = data["password"];
final redirectUri = data["redirect_uri"];
final state = data["state"] ?? "";
final clientId = data["client_id"];
final scope = data["scope"];
final nonce = data["nonce"];
// Basic validation
if ([
username,
password,
redirectUri,
clientId,
nonce,
scope,
].any((v) => v == null)) {
return Response(400, body: "Missing required field(s)");
}
// Matrix login
final loginRes = await http.post(
Uri.https(settings.homeserver, "_matrix/client/v3/login"),
headers: {"Content-Type": "application/json"},
body: json.encode({
"type": "m.login.password",
"identifier": {"type": "m.id.user", "user": username},
@ -39,10 +56,11 @@ class ApiHelper {
final userId = loginData["user_id"];
final accessToken = loginData["access_token"];
// Request OpenID token from Matrix
final openidRes = await http.post(
Uri.https(
settings.homeserver,
"_matrix/client/v3/user/$userId/openid/request",
"_matrix/client/v3/user/${Uri.encodeComponent(userId)}/openid/request",
),
headers: {"Authorization": "Bearer $accessToken"},
);
@ -55,13 +73,19 @@ class ApiHelper {
final openidToken = json.decode(openidRes.body)["access_token"];
// Generate and store authorization code
final code = base64Url.encode(
List<int>.generate(16, (_) => DateTime.now().millisecond % 256),
);
ref
.read(AuthCodeController.provider.notifier)
.set(code, MatrixUser(userId: userId, matrixToken: openidToken));
.set(
code,
MatrixUser(userId: userId, matrixToken: openidToken, nonce: nonce!),
);
// Redirect back to client
return Response.found("$redirectUri?code=$code&state=$state");
}
@ -133,10 +157,16 @@ class ApiHelper {
);
}
return Response.ok(matrixResp.body);
return Response.ok(
matrixResp.body,
headers: {"content-type": "application/json"},
);
}
Response jwks(_) => Response.ok(json.encode({"keys": []}));
Response jwks(_) => Response.ok(
json.encode({"keys": []}),
headers: {"content-type": "application/json"},
);
Response openidConfiguration(_) {
final settings = ref.read(SettingsController.provider)!;
@ -145,7 +175,7 @@ class ApiHelper {
"issuer": settings.issuer,
"authorization_endpoint": settings.authorizeEndpoint,
"token_endpoint": "${settings.issuer}/token",
"userinfo_endpoint": "${settings.issuer}/userInfo",
"userinfo_endpoint": "${settings.issuer}/userinfo",
"jwks_uri": "${settings.issuer}/jwks.json",
"response_types_supported": ["code"],
"subject_types_supported": ["public"],

View file

@ -8,6 +8,7 @@ abstract class MatrixUser with _$MatrixUser {
const factory MatrixUser({
required String userId,
required String matrixToken,
required String nonce,
}) = _MatrixUser;
factory MatrixUser.fromJson(Map<String, dynamic> json) =>

View file

@ -16,7 +16,7 @@ T _$identity<T>(T value) => value;
/// @nodoc
mixin _$MatrixUser {
String get userId; String get matrixToken;
String get userId; String get matrixToken; String get nonce;
/// Create a copy of MatrixUser
/// with the given fields replaced by the non-null parameter values.
@JsonKey(includeFromJson: false, includeToJson: false)
@ -29,16 +29,16 @@ $MatrixUserCopyWith<MatrixUser> get copyWith => _$MatrixUserCopyWithImpl<MatrixU
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is MatrixUser&&(identical(other.userId, userId) || other.userId == userId)&&(identical(other.matrixToken, matrixToken) || other.matrixToken == matrixToken));
return identical(this, other) || (other.runtimeType == runtimeType&&other is MatrixUser&&(identical(other.userId, userId) || other.userId == userId)&&(identical(other.matrixToken, matrixToken) || other.matrixToken == matrixToken)&&(identical(other.nonce, nonce) || other.nonce == nonce));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,userId,matrixToken);
int get hashCode => Object.hash(runtimeType,userId,matrixToken,nonce);
@override
String toString() {
return 'MatrixUser(userId: $userId, matrixToken: $matrixToken)';
return 'MatrixUser(userId: $userId, matrixToken: $matrixToken, nonce: $nonce)';
}
@ -49,7 +49,7 @@ abstract mixin class $MatrixUserCopyWith<$Res> {
factory $MatrixUserCopyWith(MatrixUser value, $Res Function(MatrixUser) _then) = _$MatrixUserCopyWithImpl;
@useResult
$Res call({
String userId, String matrixToken
String userId, String matrixToken, String nonce
});
@ -66,10 +66,11 @@ class _$MatrixUserCopyWithImpl<$Res>
/// Create a copy of MatrixUser
/// with the given fields replaced by the non-null parameter values.
@pragma('vm:prefer-inline') @override $Res call({Object? userId = null,Object? matrixToken = null,}) {
@pragma('vm:prefer-inline') @override $Res call({Object? userId = null,Object? matrixToken = null,Object? nonce = null,}) {
return _then(_self.copyWith(
userId: null == userId ? _self.userId : userId // ignore: cast_nullable_to_non_nullable
as String,matrixToken: null == matrixToken ? _self.matrixToken : matrixToken // ignore: cast_nullable_to_non_nullable
as String,nonce: null == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable
as String,
));
}
@ -81,11 +82,12 @@ as String,
@JsonSerializable()
class _MatrixUser implements MatrixUser {
const _MatrixUser({required this.userId, required this.matrixToken});
const _MatrixUser({required this.userId, required this.matrixToken, required this.nonce});
factory _MatrixUser.fromJson(Map<String, dynamic> json) => _$MatrixUserFromJson(json);
@override final String userId;
@override final String matrixToken;
@override final String nonce;
/// Create a copy of MatrixUser
/// with the given fields replaced by the non-null parameter values.
@ -100,16 +102,16 @@ Map<String, dynamic> toJson() {
@override
bool operator ==(Object other) {
return identical(this, other) || (other.runtimeType == runtimeType&&other is _MatrixUser&&(identical(other.userId, userId) || other.userId == userId)&&(identical(other.matrixToken, matrixToken) || other.matrixToken == matrixToken));
return identical(this, other) || (other.runtimeType == runtimeType&&other is _MatrixUser&&(identical(other.userId, userId) || other.userId == userId)&&(identical(other.matrixToken, matrixToken) || other.matrixToken == matrixToken)&&(identical(other.nonce, nonce) || other.nonce == nonce));
}
@JsonKey(includeFromJson: false, includeToJson: false)
@override
int get hashCode => Object.hash(runtimeType,userId,matrixToken);
int get hashCode => Object.hash(runtimeType,userId,matrixToken,nonce);
@override
String toString() {
return 'MatrixUser(userId: $userId, matrixToken: $matrixToken)';
return 'MatrixUser(userId: $userId, matrixToken: $matrixToken, nonce: $nonce)';
}
@ -120,7 +122,7 @@ abstract mixin class _$MatrixUserCopyWith<$Res> implements $MatrixUserCopyWith<$
factory _$MatrixUserCopyWith(_MatrixUser value, $Res Function(_MatrixUser) _then) = __$MatrixUserCopyWithImpl;
@override @useResult
$Res call({
String userId, String matrixToken
String userId, String matrixToken, String nonce
});
@ -137,10 +139,11 @@ class __$MatrixUserCopyWithImpl<$Res>
/// Create a copy of MatrixUser
/// with the given fields replaced by the non-null parameter values.
@override @pragma('vm:prefer-inline') $Res call({Object? userId = null,Object? matrixToken = null,}) {
@override @pragma('vm:prefer-inline') $Res call({Object? userId = null,Object? matrixToken = null,Object? nonce = null,}) {
return _then(_MatrixUser(
userId: null == userId ? _self.userId : userId // ignore: cast_nullable_to_non_nullable
as String,matrixToken: null == matrixToken ? _self.matrixToken : matrixToken // ignore: cast_nullable_to_non_nullable
as String,nonce: null == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable
as String,
));
}

View file

@ -9,10 +9,12 @@ part of 'matrix_user.dart';
_MatrixUser _$MatrixUserFromJson(Map<String, dynamic> json) => _MatrixUser(
userId: json['userId'] as String,
matrixToken: json['matrixToken'] as String,
nonce: json['nonce'] as String,
);
Map<String, dynamic> _$MatrixUserToJson(_MatrixUser instance) =>
<String, dynamic>{
'userId': instance.userId,
'matrixToken': instance.matrixToken,
'nonce': instance.nonce,
};