From 680d7fcd055d45c1f19a5e55a682aa252046a1ce Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Thu, 19 Jun 2025 17:33:50 -0400 Subject: [PATCH 01/45] slight changes --- bin/matrixoidc.dart | 8 ++-- flake.nix | 18 ++++++++ lib/models/matrix_user.freezed.dart | 14 +++--- lib/models/matrix_user.g.dart | 10 ++--- lib/models/settings.dart | 2 +- lib/models/settings.freezed.dart | 36 ++++++++-------- lib/models/settings.g.dart | 34 +++++++-------- pubspec.lock | 66 ++++++++++++++++++++++++++++- pubspec.yaml | 2 +- 9 files changed, 136 insertions(+), 54 deletions(-) diff --git a/bin/matrixoidc.dart b/bin/matrixoidc.dart index e405b09..edf5181 100644 --- a/bin/matrixoidc.dart +++ b/bin/matrixoidc.dart @@ -1,5 +1,5 @@ import "dart:io"; -import "package:args/args.dart"; +import 'package:cli_tools/config.dart'; import "package:matrixoidc/controllers/settings_controller.dart"; import "package:matrixoidc/helpers/api_helper.dart"; import "package:riverpod/riverpod.dart"; @@ -8,18 +8,18 @@ import "package:shelf/shelf_io.dart"; import "package:shelf_router/shelf_router.dart"; void main(List argsRaw) async { - final parser = ArgParser() + final parser = ConfigParser() + ..addFlag("help", abbr: "h") ..addOption("socket", abbr: "s") ..addOption("serviceDomain", abbr: "d") ..addOption("port", abbr: "p", defaultsTo: "8080") ..addOption("address", abbr: "a", defaultsTo: "127.0.0.1") ..addOption("issuer", abbr: "i", mandatory: true) - ..addOption("homeserver", abbr: "h", mandatory: true) + ..addOption("homeserver", abbr: "u", mandatory: true) ..addOption("jwtSecretFile", abbr: "j", mandatory: true) ..addOption("authorizeEndpoint", abbr: "e", mandatory: true); final container = ProviderContainer(); - container .read(SettingsController.provider.notifier) .set(parser.parse(argsRaw)); diff --git a/flake.nix b/flake.nix index ae04dfa..bcbb13c 100644 --- a/flake.nix +++ b/flake.nix @@ -13,6 +13,7 @@ flake-parts.lib.mkFlake {inherit inputs;} { systems = ["x86_64-linux" "aarch64-linux"]; perSystem = { + lib, pkgs, system, ... @@ -22,6 +23,23 @@ devShells.default = pkgs.mkShell { buildInputs = with pkgs; [just dart oauth2c watchexec]; }; + + packages.default = pkgs.buildDartApplication { + pname = "matrixoidc"; + version = "1.0.0"; + src = ./.; + + dartConfigHook = "packageRun build_runner build"; + autoPubspecLock = ./pubspec.lock; + + meta = { + homepage = "https://git.federated.nexus/Henry-Hiles/matrixoidc"; + description = "An attempt to make an OIDC provider that authenticates with matrix OAuth."; + mainProgram = "matrixoidc"; + license = lib.licenses.gpl3Plus; + maintainers = [lib.maintainers.quadradical]; + }; + }; }; }; } diff --git a/lib/models/matrix_user.freezed.dart b/lib/models/matrix_user.freezed.dart index 94504e8..0dd35c7 100644 --- a/lib/models/matrix_user.freezed.dart +++ b/lib/models/matrix_user.freezed.dart @@ -4,7 +4,7 @@ // ignore_for_file: type=lint // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark -part of "matrix_user.dart"; +part of 'matrix_user.dart'; // ************************************************************************** // FreezedGenerator @@ -20,7 +20,7 @@ mixin _$MatrixUser { /// Create a copy of MatrixUser /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) -@pragma("vm:prefer-inline") +@pragma('vm:prefer-inline') $MatrixUserCopyWith get copyWith => _$MatrixUserCopyWithImpl(this as MatrixUser, _$identity); /// Serializes this MatrixUser to a JSON map. @@ -38,7 +38,7 @@ int get hashCode => Object.hash(runtimeType,userId,matrixToken); @override String toString() { - return "MatrixUser(userId: $userId, matrixToken: $matrixToken)"; + return 'MatrixUser(userId: $userId, matrixToken: $matrixToken)'; } @@ -66,7 +66,7 @@ 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,}) { 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 @@ -90,7 +90,7 @@ class _MatrixUser implements MatrixUser { /// Create a copy of MatrixUser /// with the given fields replaced by the non-null parameter values. @override @JsonKey(includeFromJson: false, includeToJson: false) -@pragma("vm:prefer-inline") +@pragma('vm:prefer-inline') _$MatrixUserCopyWith<_MatrixUser> get copyWith => __$MatrixUserCopyWithImpl<_MatrixUser>(this, _$identity); @override @@ -109,7 +109,7 @@ int get hashCode => Object.hash(runtimeType,userId,matrixToken); @override String toString() { - return "MatrixUser(userId: $userId, matrixToken: $matrixToken)"; + return 'MatrixUser(userId: $userId, matrixToken: $matrixToken)'; } @@ -137,7 +137,7 @@ 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,}) { 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 diff --git a/lib/models/matrix_user.g.dart b/lib/models/matrix_user.g.dart index 95e855f..e3aa600 100644 --- a/lib/models/matrix_user.g.dart +++ b/lib/models/matrix_user.g.dart @@ -1,18 +1,18 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of "matrix_user.dart"; +part of 'matrix_user.dart'; // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** _MatrixUser _$MatrixUserFromJson(Map json) => _MatrixUser( - userId: json["userId"] as String, - matrixToken: json["matrixToken"] as String, + userId: json['userId'] as String, + matrixToken: json['matrixToken'] as String, ); Map _$MatrixUserToJson(_MatrixUser instance) => { - "userId": instance.userId, - "matrixToken": instance.matrixToken, + 'userId': instance.userId, + 'matrixToken': instance.matrixToken, }; diff --git a/lib/models/settings.dart b/lib/models/settings.dart index 6d7a895..dc6cf54 100644 --- a/lib/models/settings.dart +++ b/lib/models/settings.dart @@ -7,11 +7,11 @@ part "settings.g.dart"; abstract class Settings with _$Settings { const factory Settings({ required String? socket, + required String? serviceDomain, required String address, required String port, required String homeserver, required String issuer, - required String serviceDomain, required String jwtSecretFile, required String authorizeEndpoint, }) = _Settings; diff --git a/lib/models/settings.freezed.dart b/lib/models/settings.freezed.dart index 8376cab..3af7771 100644 --- a/lib/models/settings.freezed.dart +++ b/lib/models/settings.freezed.dart @@ -4,7 +4,7 @@ // ignore_for_file: type=lint // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark -part of "settings.dart"; +part of 'settings.dart'; // ************************************************************************** // FreezedGenerator @@ -16,11 +16,11 @@ T _$identity(T value) => value; /// @nodoc mixin _$Settings { - String? get socket; String get address; String get port; String get homeserver; String get issuer; String get serviceDomain; String get jwtSecretFile; String get authorizeEndpoint; + String? get socket; String? get serviceDomain; String get address; String get port; String get homeserver; String get issuer; String get jwtSecretFile; String get authorizeEndpoint; /// Create a copy of Settings /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) -@pragma("vm:prefer-inline") +@pragma('vm:prefer-inline') $SettingsCopyWith get copyWith => _$SettingsCopyWithImpl(this as Settings, _$identity); /// Serializes this Settings to a JSON map. @@ -29,16 +29,16 @@ $SettingsCopyWith get copyWith => _$SettingsCopyWithImpl(thi @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is Settings&&(identical(other.socket, socket) || other.socket == socket)&&(identical(other.address, address) || other.address == address)&&(identical(other.port, port) || other.port == port)&&(identical(other.homeserver, homeserver) || other.homeserver == homeserver)&&(identical(other.issuer, issuer) || other.issuer == issuer)&&(identical(other.serviceDomain, serviceDomain) || other.serviceDomain == serviceDomain)&&(identical(other.jwtSecretFile, jwtSecretFile) || other.jwtSecretFile == jwtSecretFile)&&(identical(other.authorizeEndpoint, authorizeEndpoint) || other.authorizeEndpoint == authorizeEndpoint)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is Settings&&(identical(other.socket, socket) || other.socket == socket)&&(identical(other.serviceDomain, serviceDomain) || other.serviceDomain == serviceDomain)&&(identical(other.address, address) || other.address == address)&&(identical(other.port, port) || other.port == port)&&(identical(other.homeserver, homeserver) || other.homeserver == homeserver)&&(identical(other.issuer, issuer) || other.issuer == issuer)&&(identical(other.jwtSecretFile, jwtSecretFile) || other.jwtSecretFile == jwtSecretFile)&&(identical(other.authorizeEndpoint, authorizeEndpoint) || other.authorizeEndpoint == authorizeEndpoint)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,socket,address,port,homeserver,issuer,serviceDomain,jwtSecretFile,authorizeEndpoint); +int get hashCode => Object.hash(runtimeType,socket,serviceDomain,address,port,homeserver,issuer,jwtSecretFile,authorizeEndpoint); @override String toString() { - return "Settings(socket: $socket, address: $address, port: $port, homeserver: $homeserver, issuer: $issuer, serviceDomain: $serviceDomain, jwtSecretFile: $jwtSecretFile, authorizeEndpoint: $authorizeEndpoint)"; + return 'Settings(socket: $socket, serviceDomain: $serviceDomain, address: $address, port: $port, homeserver: $homeserver, issuer: $issuer, jwtSecretFile: $jwtSecretFile, authorizeEndpoint: $authorizeEndpoint)'; } @@ -49,7 +49,7 @@ abstract mixin class $SettingsCopyWith<$Res> { factory $SettingsCopyWith(Settings value, $Res Function(Settings) _then) = _$SettingsCopyWithImpl; @useResult $Res call({ - String? socket, String address, String port, String homeserver, String issuer, String serviceDomain, String jwtSecretFile, String authorizeEndpoint + String? socket, String? serviceDomain, String address, String port, String homeserver, String issuer, String jwtSecretFile, String authorizeEndpoint }); @@ -66,14 +66,14 @@ class _$SettingsCopyWithImpl<$Res> /// Create a copy of Settings /// with the given fields replaced by the non-null parameter values. -@pragma("vm:prefer-inline") @override $Res call({Object? socket = freezed,Object? address = null,Object? port = null,Object? homeserver = null,Object? issuer = null,Object? serviceDomain = null,Object? jwtSecretFile = null,Object? authorizeEndpoint = null,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? socket = freezed,Object? serviceDomain = freezed,Object? address = null,Object? port = null,Object? homeserver = null,Object? issuer = null,Object? jwtSecretFile = null,Object? authorizeEndpoint = null,}) { return _then(_self.copyWith( socket: freezed == socket ? _self.socket : socket // ignore: cast_nullable_to_non_nullable +as String?,serviceDomain: freezed == serviceDomain ? _self.serviceDomain : serviceDomain // ignore: cast_nullable_to_non_nullable as String?,address: null == address ? _self.address : address // ignore: cast_nullable_to_non_nullable as String,port: null == port ? _self.port : port // ignore: cast_nullable_to_non_nullable as String,homeserver: null == homeserver ? _self.homeserver : homeserver // ignore: cast_nullable_to_non_nullable as String,issuer: null == issuer ? _self.issuer : issuer // ignore: cast_nullable_to_non_nullable -as String,serviceDomain: null == serviceDomain ? _self.serviceDomain : serviceDomain // ignore: cast_nullable_to_non_nullable as String,jwtSecretFile: null == jwtSecretFile ? _self.jwtSecretFile : jwtSecretFile // ignore: cast_nullable_to_non_nullable as String,authorizeEndpoint: null == authorizeEndpoint ? _self.authorizeEndpoint : authorizeEndpoint // ignore: cast_nullable_to_non_nullable as String, @@ -87,22 +87,22 @@ as String, @JsonSerializable() class _Settings implements Settings { - const _Settings({required this.socket, required this.address, required this.port, required this.homeserver, required this.issuer, required this.serviceDomain, required this.jwtSecretFile, required this.authorizeEndpoint}); + const _Settings({required this.socket, required this.serviceDomain, required this.address, required this.port, required this.homeserver, required this.issuer, required this.jwtSecretFile, required this.authorizeEndpoint}); factory _Settings.fromJson(Map json) => _$SettingsFromJson(json); @override final String? socket; +@override final String? serviceDomain; @override final String address; @override final String port; @override final String homeserver; @override final String issuer; -@override final String serviceDomain; @override final String jwtSecretFile; @override final String authorizeEndpoint; /// Create a copy of Settings /// with the given fields replaced by the non-null parameter values. @override @JsonKey(includeFromJson: false, includeToJson: false) -@pragma("vm:prefer-inline") +@pragma('vm:prefer-inline') _$SettingsCopyWith<_Settings> get copyWith => __$SettingsCopyWithImpl<_Settings>(this, _$identity); @override @@ -112,16 +112,16 @@ Map toJson() { @override bool operator ==(Object other) { - return identical(this, other) || (other.runtimeType == runtimeType&&other is _Settings&&(identical(other.socket, socket) || other.socket == socket)&&(identical(other.address, address) || other.address == address)&&(identical(other.port, port) || other.port == port)&&(identical(other.homeserver, homeserver) || other.homeserver == homeserver)&&(identical(other.issuer, issuer) || other.issuer == issuer)&&(identical(other.serviceDomain, serviceDomain) || other.serviceDomain == serviceDomain)&&(identical(other.jwtSecretFile, jwtSecretFile) || other.jwtSecretFile == jwtSecretFile)&&(identical(other.authorizeEndpoint, authorizeEndpoint) || other.authorizeEndpoint == authorizeEndpoint)); + return identical(this, other) || (other.runtimeType == runtimeType&&other is _Settings&&(identical(other.socket, socket) || other.socket == socket)&&(identical(other.serviceDomain, serviceDomain) || other.serviceDomain == serviceDomain)&&(identical(other.address, address) || other.address == address)&&(identical(other.port, port) || other.port == port)&&(identical(other.homeserver, homeserver) || other.homeserver == homeserver)&&(identical(other.issuer, issuer) || other.issuer == issuer)&&(identical(other.jwtSecretFile, jwtSecretFile) || other.jwtSecretFile == jwtSecretFile)&&(identical(other.authorizeEndpoint, authorizeEndpoint) || other.authorizeEndpoint == authorizeEndpoint)); } @JsonKey(includeFromJson: false, includeToJson: false) @override -int get hashCode => Object.hash(runtimeType,socket,address,port,homeserver,issuer,serviceDomain,jwtSecretFile,authorizeEndpoint); +int get hashCode => Object.hash(runtimeType,socket,serviceDomain,address,port,homeserver,issuer,jwtSecretFile,authorizeEndpoint); @override String toString() { - return "Settings(socket: $socket, address: $address, port: $port, homeserver: $homeserver, issuer: $issuer, serviceDomain: $serviceDomain, jwtSecretFile: $jwtSecretFile, authorizeEndpoint: $authorizeEndpoint)"; + return 'Settings(socket: $socket, serviceDomain: $serviceDomain, address: $address, port: $port, homeserver: $homeserver, issuer: $issuer, jwtSecretFile: $jwtSecretFile, authorizeEndpoint: $authorizeEndpoint)'; } @@ -132,7 +132,7 @@ abstract mixin class _$SettingsCopyWith<$Res> implements $SettingsCopyWith<$Res> factory _$SettingsCopyWith(_Settings value, $Res Function(_Settings) _then) = __$SettingsCopyWithImpl; @override @useResult $Res call({ - String? socket, String address, String port, String homeserver, String issuer, String serviceDomain, String jwtSecretFile, String authorizeEndpoint + String? socket, String? serviceDomain, String address, String port, String homeserver, String issuer, String jwtSecretFile, String authorizeEndpoint }); @@ -149,14 +149,14 @@ class __$SettingsCopyWithImpl<$Res> /// Create a copy of Settings /// with the given fields replaced by the non-null parameter values. -@override @pragma("vm:prefer-inline") $Res call({Object? socket = freezed,Object? address = null,Object? port = null,Object? homeserver = null,Object? issuer = null,Object? serviceDomain = null,Object? jwtSecretFile = null,Object? authorizeEndpoint = null,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? socket = freezed,Object? serviceDomain = freezed,Object? address = null,Object? port = null,Object? homeserver = null,Object? issuer = null,Object? jwtSecretFile = null,Object? authorizeEndpoint = null,}) { return _then(_Settings( socket: freezed == socket ? _self.socket : socket // ignore: cast_nullable_to_non_nullable +as String?,serviceDomain: freezed == serviceDomain ? _self.serviceDomain : serviceDomain // ignore: cast_nullable_to_non_nullable as String?,address: null == address ? _self.address : address // ignore: cast_nullable_to_non_nullable as String,port: null == port ? _self.port : port // ignore: cast_nullable_to_non_nullable as String,homeserver: null == homeserver ? _self.homeserver : homeserver // ignore: cast_nullable_to_non_nullable as String,issuer: null == issuer ? _self.issuer : issuer // ignore: cast_nullable_to_non_nullable -as String,serviceDomain: null == serviceDomain ? _self.serviceDomain : serviceDomain // ignore: cast_nullable_to_non_nullable as String,jwtSecretFile: null == jwtSecretFile ? _self.jwtSecretFile : jwtSecretFile // ignore: cast_nullable_to_non_nullable as String,authorizeEndpoint: null == authorizeEndpoint ? _self.authorizeEndpoint : authorizeEndpoint // ignore: cast_nullable_to_non_nullable as String, diff --git a/lib/models/settings.g.dart b/lib/models/settings.g.dart index 11a29e1..e9172f1 100644 --- a/lib/models/settings.g.dart +++ b/lib/models/settings.g.dart @@ -1,29 +1,29 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of "settings.dart"; +part of 'settings.dart'; // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** _Settings _$SettingsFromJson(Map json) => _Settings( - socket: json["socket"] as String?, - address: json["address"] as String, - port: json["port"] as String, - homeserver: json["homeserver"] as String, - issuer: json["issuer"] as String, - serviceDomain: json["serviceDomain"] as String, - jwtSecretFile: json["jwtSecretFile"] as String, - authorizeEndpoint: json["authorizeEndpoint"] as String, + socket: json['socket'] as String?, + serviceDomain: json['serviceDomain'] as String?, + address: json['address'] as String, + port: json['port'] as String, + homeserver: json['homeserver'] as String, + issuer: json['issuer'] as String, + jwtSecretFile: json['jwtSecretFile'] as String, + authorizeEndpoint: json['authorizeEndpoint'] as String, ); Map _$SettingsToJson(_Settings instance) => { - "socket": instance.socket, - "address": instance.address, - "port": instance.port, - "homeserver": instance.homeserver, - "issuer": instance.issuer, - "serviceDomain": instance.serviceDomain, - "jwtSecretFile": instance.jwtSecretFile, - "authorizeEndpoint": instance.authorizeEndpoint, + 'socket': instance.socket, + 'serviceDomain': instance.serviceDomain, + 'address': instance.address, + 'port': instance.port, + 'homeserver': instance.homeserver, + 'issuer': instance.issuer, + 'jwtSecretFile': instance.jwtSecretFile, + 'authorizeEndpoint': instance.authorizeEndpoint, }; diff --git a/pubspec.lock b/pubspec.lock index 84ee519..52f7e2d 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -26,7 +26,7 @@ packages: source: hosted version: "7.4.5" args: - dependency: "direct main" + dependency: transitive description: name: args sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 @@ -121,6 +121,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.4" + ci: + dependency: transitive + description: + name: ci + sha256: "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13" + url: "https://pub.dev" + source: hosted + version: "0.1.0" + cli_tools: + dependency: "direct main" + description: + name: cli_tools + sha256: ed6d1cef6e34ff3d68e7c798c3d18f497a311ac8082533340a4a914b12344717 + url: "https://pub.dev" + source: hosted + version: "0.6.0" clock: dependency: transitive description: @@ -169,6 +185,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.0" + dart_mappable: + dependency: transitive + description: + name: dart_mappable + sha256: "2255b2c00e328a65fef5a8df2dabfc0dc9c2e518c33a50051a4519b1c7a28c48" + url: "https://pub.dev" + source: hosted + version: "4.5.0" dart_style: dependency: transitive description: @@ -353,6 +377,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.0" + oauth2: + dependency: transitive + description: + name: oauth2 + sha256: c84470642cbb2bec450ccab2f8520c079cd1ca546a76ffd5c40589e07f4e8bf4 + url: "https://pub.dev" + source: hosted + version: "2.0.3" package_config: dependency: transitive description: @@ -385,6 +417,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.1" + pub_api_client: + dependency: transitive + description: + name: pub_api_client + sha256: b9c0184ce4a562d8cf2ebd7be235a25aa158b7c01bdef863cccadc5894644e26 + url: "https://pub.dev" + source: hosted + version: "3.1.1" pub_semver: dependency: transitive description: @@ -401,6 +441,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.5.0" + rfc_6901: + dependency: transitive + description: + name: rfc_6901 + sha256: df1bbfa3d023009598f19636d6114c6ac1e0b7bb7bf6a260f0e6e6ce91416820 + url: "https://pub.dev" + source: hosted + version: "0.2.0" riverpod: dependency: "direct main" description: @@ -497,6 +545,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.4.1" + super_string: + dependency: transitive + description: + name: super_string + sha256: ba41acf9fbb318b3fc0d57c9235779100394d85d83f45ab533615df1f3146ea7 + url: "https://pub.dev" + source: hosted + version: "1.0.3" term_glyph: dependency: transitive description: @@ -521,6 +577,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.2" + type_plus: + dependency: transitive + description: + name: type_plus + sha256: d5d1019471f0d38b91603adb9b5fd4ce7ab903c879d2fbf1a3f80a630a03fcc9 + url: "https://pub.dev" + source: hosted + version: "2.1.1" typed_data: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 1daf022..98f5105 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -14,8 +14,8 @@ dependencies: freezed_annotation: ^3.0.0 json_annotation: ^4.9.0 shelf_router: ^1.1.4 - args: ^2.7.0 fast_immutable_collections: ^11.0.4 + cli_tools: ^0.6.0 dev_dependencies: build_runner: ^2.4.6 From f04d073e6b2efecd8c9f2a54b37ba7b40fccc1c6 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Thu, 19 Jun 2025 22:15:05 -0400 Subject: [PATCH 02/45] Add flake, module --- flake.nix | 17 +- module.nix | 79 +++++ pubspec.lock.json | 797 ++++++++++++++++++++++++++++++++++++++++++++++ pubspec.yaml | 2 + 4 files changed, 886 insertions(+), 9 deletions(-) create mode 100644 module.nix create mode 100644 pubspec.lock.json diff --git a/flake.nix b/flake.nix index bcbb13c..2ba5e00 100644 --- a/flake.nix +++ b/flake.nix @@ -4,13 +4,8 @@ nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable"; }; - outputs = { - flake-parts, - nixpkgs, - self, - ... - } @ inputs: - flake-parts.lib.mkFlake {inherit inputs;} { + outputs = inputs: + inputs.flake-parts.lib.mkFlake {inherit inputs;} { systems = ["x86_64-linux" "aarch64-linux"]; perSystem = { lib, @@ -18,7 +13,7 @@ system, ... }: { - _module.args.pkgs = import nixpkgs {inherit system;}; + _module.args.pkgs = import inputs.nixpkgs {inherit system;}; devShells.default = pkgs.mkShell { buildInputs = with pkgs; [just dart oauth2c watchexec]; @@ -30,7 +25,9 @@ src = ./.; dartConfigHook = "packageRun build_runner build"; - autoPubspecLock = ./pubspec.lock; + pubspecLock = lib.importJSON ./pubspec.lock.json; + + preInstall = "set -x"; meta = { homepage = "https://git.federated.nexus/Henry-Hiles/matrixoidc"; @@ -40,6 +37,8 @@ maintainers = [lib.maintainers.quadradical]; }; }; + + flake.nixosModules.default = import ./module.nix; }; }; } diff --git a/module.nix b/module.nix new file mode 100644 index 0000000..1ecf0ec --- /dev/null +++ b/module.nix @@ -0,0 +1,79 @@ +{ + config, + lib, + pkgs, + utils, + ... +}: let + cfg = config.services.matrixoidc; +in { + meta.maintainers = with lib.maintainers; [quadradical]; + options.services.matrixoidc = { + enable = lib.mkEnableOption "the matrixoidc server"; + package = lib.mkPackageOption pkgs "matrixoidc" {}; + + group = lib.mkOption { + type = lib.types.string; + }; + + jwtSecretFile = lib.mkOption { + type = lib.types.path; + }; + + args = lib.mkOption { + type = lib.types.string; + }; + }; + + config = lib.mkIf cfg.enable { + systemd.services.matrixoidc = { + description = "matrixoidc server"; + documentation = ["https://git.federated.nexus/Henry-Hiles/matrixoidc"]; + wantedBy = ["multi-user.target"]; + wants = ["network-online.target"]; + after = ["network-online.target"]; + + serviceConfig = { + LoadCredential = ["matrixoidc-secrets:${cfg.jwtSecretFile}"]; + ExecStart = utils.escapeSystemdExecArgs [ + (lib.getExe cfg.package) + cfg.args + "--jwtSecretFile=/run/credentials/matrixoidc.service/matrixoidc-secrets" + ]; + DynamicUser = true; + LockPersonality = true; + MemoryDenyWriteExecute = true; + ProtectClock = true; + ProtectControlGroups = true; + ProtectHostname = true; + ProtectKernelLogs = true; + ProtectKernelModules = true; + ProtectKernelTunables = true; + PrivateDevices = true; + PrivateMounts = true; + PrivateUsers = true; + RestrictAddressFamilies = [ + "AF_INET" + "AF_INET6" + "AF_NETLINK" + ]; + RestrictNamespaces = true; + RestrictRealtime = true; + ProtectHome = true; + SystemCallArchitectures = "native"; + SystemCallFilter = [ + "@system-service" + "~@privileged" + "~@resources" + ]; + Restart = "on-failure"; + RestartSec = 5; + UMask = "077"; + + RuntimeDirectory = "matrixoidc"; + RuntimeDirectoryMode = 0770; + Group = cfg.group; + }; + }; + }; +} diff --git a/pubspec.lock.json b/pubspec.lock.json new file mode 100644 index 0000000..1037dc6 --- /dev/null +++ b/pubspec.lock.json @@ -0,0 +1,797 @@ +{ + "packages": { + "_fe_analyzer_shared": { + "dependency": "transitive", + "description": { + "name": "_fe_analyzer_shared", + "sha256": "e55636ed79578b9abca5fecf9437947798f5ef7456308b5cb85720b793eac92f", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "82.0.0" + }, + "adaptive_number": { + "dependency": "transitive", + "description": { + "name": "adaptive_number", + "sha256": "3a567544e9b5c9c803006f51140ad544aedc79604fd4f3f2c1380003f97c1d77", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.0.0" + }, + "analyzer": { + "dependency": "transitive", + "description": { + "name": "analyzer", + "sha256": "904ae5bb474d32c38fb9482e2d925d5454cda04ddd0e55d2e6826bc72f6ba8c0", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "7.4.5" + }, + "args": { + "dependency": "transitive", + "description": { + "name": "args", + "sha256": "d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.7.0" + }, + "async": { + "dependency": "transitive", + "description": { + "name": "async", + "sha256": "758e6d74e971c3e5aceb4110bfd6698efc7f501675bcfe0c775459a8140750eb", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.13.0" + }, + "boolean_selector": { + "dependency": "transitive", + "description": { + "name": "boolean_selector", + "sha256": "8aab1771e1243a5063b8b0ff68042d67334e3feab9e95b9490f9a6ebf73b42ea", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.1.2" + }, + "build": { + "dependency": "transitive", + "description": { + "name": "build", + "sha256": "486337d40a48d75049f2a01efceefc1412e3a6d6342d39624753e7d5a4e70016", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.5.1" + }, + "build_config": { + "dependency": "transitive", + "description": { + "name": "build_config", + "sha256": "4ae2de3e1e67ea270081eaee972e1bd8f027d459f249e0f1186730784c2e7e33", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.1.2" + }, + "build_daemon": { + "dependency": "transitive", + "description": { + "name": "build_daemon", + "sha256": "8e928697a82be082206edb0b9c99c5a4ad6bc31c9e9b8b2f291ae65cd4a25daa", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "4.0.4" + }, + "build_resolvers": { + "dependency": "transitive", + "description": { + "name": "build_resolvers", + "sha256": "abe6e4b5b36ce2bf01aec8f2a59424d1ecfc3cb340e7145a64359adc7233a0d1", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.5.1" + }, + "build_runner": { + "dependency": "direct dev", + "description": { + "name": "build_runner", + "sha256": "398ec7898b9b60be126067835a8202240b26dc54aa34d91d0198a539dcd5942e", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.5.1" + }, + "build_runner_core": { + "dependency": "transitive", + "description": { + "name": "build_runner_core", + "sha256": "9821dbf604ed74a6dabeaba0c33ac58190332ea238862a62cdf25fc8eba226b8", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "9.0.1" + }, + "built_collection": { + "dependency": "transitive", + "description": { + "name": "built_collection", + "sha256": "376e3dd27b51ea877c28d525560790aee2e6fbb5f20e2f85d5081027d94e2100", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "5.1.1" + }, + "built_value": { + "dependency": "transitive", + "description": { + "name": "built_value", + "sha256": "082001b5c3dc495d4a42f1d5789990505df20d8547d42507c29050af6933ee27", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "8.10.1" + }, + "checked_yaml": { + "dependency": "transitive", + "description": { + "name": "checked_yaml", + "sha256": "959525d3162f249993882720d52b7e0c833978df229be20702b33d48d91de70f", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.0.4" + }, + "ci": { + "dependency": "transitive", + "description": { + "name": "ci", + "sha256": "145d095ce05cddac4d797a158bc4cf3b6016d1fe63d8c3d2fbd7212590adca13", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "0.1.0" + }, + "cli_tools": { + "dependency": "direct main", + "description": { + "name": "cli_tools", + "sha256": "ed6d1cef6e34ff3d68e7c798c3d18f497a311ac8082533340a4a914b12344717", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "0.6.0" + }, + "clock": { + "dependency": "transitive", + "description": { + "name": "clock", + "sha256": "fddb70d9b5277016c77a80201021d40a2247104d9f4aa7bab7157b7e3f05b84b", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.1.2" + }, + "code_builder": { + "dependency": "transitive", + "description": { + "name": "code_builder", + "sha256": "0ec10bf4a89e4c613960bf1e8b42c64127021740fb21640c29c909826a5eea3e", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "4.10.1" + }, + "collection": { + "dependency": "transitive", + "description": { + "name": "collection", + "sha256": "2f5709ae4d3d59dd8f7cd309b4e023046b57d8a6c82130785d2b0e5868084e76", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.19.1" + }, + "convert": { + "dependency": "transitive", + "description": { + "name": "convert", + "sha256": "b30acd5944035672bc15c6b7a8b47d773e41e2f17de064350988c5d02adb1c68", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "3.1.2" + }, + "crypto": { + "dependency": "transitive", + "description": { + "name": "crypto", + "sha256": "1e445881f28f22d6140f181e07737b22f1e099a5e1ff94b0af2f9e4a463f4855", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "3.0.6" + }, + "dart_jsonwebtoken": { + "dependency": "direct main", + "description": { + "name": "dart_jsonwebtoken", + "sha256": "21ce9f8a8712f741e8d6876a9c82c0f8a257fe928c4378a91d8527b92a3fd413", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "3.2.0" + }, + "dart_mappable": { + "dependency": "transitive", + "description": { + "name": "dart_mappable", + "sha256": "2255b2c00e328a65fef5a8df2dabfc0dc9c2e518c33a50051a4519b1c7a28c48", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "4.5.0" + }, + "dart_style": { + "dependency": "transitive", + "description": { + "name": "dart_style", + "sha256": "5b236382b47ee411741447c1f1e111459c941ea1b3f2b540dde54c210a3662af", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "3.1.0" + }, + "ed25519_edwards": { + "dependency": "transitive", + "description": { + "name": "ed25519_edwards", + "sha256": "6ce0112d131327ec6d42beede1e5dfd526069b18ad45dcf654f15074ad9276cd", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "0.3.1" + }, + "fast_immutable_collections": { + "dependency": "direct main", + "description": { + "name": "fast_immutable_collections", + "sha256": "d1aa3d7788fab06cce7f303f4969c7a16a10c865e1bd2478291a8ebcbee084e5", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "11.0.4" + }, + "file": { + "dependency": "transitive", + "description": { + "name": "file", + "sha256": "a3b4f84adafef897088c160faf7dfffb7696046cb13ae90b508c2cbc95d3b8d4", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "7.0.1" + }, + "fixnum": { + "dependency": "transitive", + "description": { + "name": "fixnum", + "sha256": "b6dc7065e46c974bc7c5f143080a6764ec7a4be6da1285ececdc37be96de53be", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.1.1" + }, + "freezed": { + "dependency": "direct dev", + "description": { + "name": "freezed", + "sha256": "6022db4c7bfa626841b2a10f34dd1e1b68e8f8f9650db6112dcdeeca45ca793c", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "3.0.6" + }, + "freezed_annotation": { + "dependency": "direct main", + "description": { + "name": "freezed_annotation", + "sha256": "c87ff004c8aa6af2d531668b46a4ea379f7191dc6dfa066acd53d506da6e044b", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "3.0.0" + }, + "frontend_server_client": { + "dependency": "transitive", + "description": { + "name": "frontend_server_client", + "sha256": "f64a0333a82f30b0cca061bc3d143813a486dc086b574bfb233b7c1372427694", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "4.0.0" + }, + "glob": { + "dependency": "transitive", + "description": { + "name": "glob", + "sha256": "c3f1ee72c96f8f78935e18aa8cecced9ab132419e8625dc187e1c2408efc20de", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.1.3" + }, + "graphs": { + "dependency": "transitive", + "description": { + "name": "graphs", + "sha256": "741bbf84165310a68ff28fe9e727332eef1407342fca52759cb21ad8177bb8d0", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.3.2" + }, + "http": { + "dependency": "direct main", + "description": { + "name": "http", + "sha256": "2c11f3f94c687ee9bad77c171151672986360b2b001d109814ee7140b2cf261b", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.4.0" + }, + "http_methods": { + "dependency": "transitive", + "description": { + "name": "http_methods", + "sha256": "6bccce8f1ec7b5d701e7921dca35e202d425b57e317ba1a37f2638590e29e566", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.1.1" + }, + "http_multi_server": { + "dependency": "transitive", + "description": { + "name": "http_multi_server", + "sha256": "aa6199f908078bb1c5efb8d8638d4ae191aac11b311132c3ef48ce352fb52ef8", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "3.2.2" + }, + "http_parser": { + "dependency": "transitive", + "description": { + "name": "http_parser", + "sha256": "178d74305e7866013777bab2c3d8726205dc5a4dd935297175b19a23a2e66571", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "4.1.2" + }, + "io": { + "dependency": "transitive", + "description": { + "name": "io", + "sha256": "dfd5a80599cf0165756e3181807ed3e77daf6dd4137caaad72d0b7931597650b", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.0.5" + }, + "js": { + "dependency": "transitive", + "description": { + "name": "js", + "sha256": "53385261521cc4a0c4658fd0ad07a7d14591cf8fc33abbceae306ddb974888dc", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "0.7.2" + }, + "json_annotation": { + "dependency": "direct main", + "description": { + "name": "json_annotation", + "sha256": "1ce844379ca14835a50d2f019a3099f419082cfdd231cd86a142af94dd5c6bb1", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "4.9.0" + }, + "json_serializable": { + "dependency": "direct dev", + "description": { + "name": "json_serializable", + "sha256": "c50ef5fc083d5b5e12eef489503ba3bf5ccc899e487d691584699b4bdefeea8c", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "6.9.5" + }, + "lints": { + "dependency": "direct dev", + "description": { + "name": "lints", + "sha256": "a5e2b223cb7c9c8efdc663ef484fdd95bb243bff242ef5b13e26883547fce9a0", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "6.0.0" + }, + "logging": { + "dependency": "transitive", + "description": { + "name": "logging", + "sha256": "c8245ada5f1717ed44271ed1c26b8ce85ca3228fd2ffdb75468ab01979309d61", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.3.0" + }, + "matcher": { + "dependency": "transitive", + "description": { + "name": "matcher", + "sha256": "dc58c723c3c24bf8d3e2d3ad3f2f9d7bd9cf43ec6feaa64181775e60190153f2", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "0.12.17" + }, + "meta": { + "dependency": "transitive", + "description": { + "name": "meta", + "sha256": "23f08335362185a5ea2ad3a4e597f1375e78bce8a040df5c600c8d3552ef2394", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.17.0" + }, + "mime": { + "dependency": "transitive", + "description": { + "name": "mime", + "sha256": "41a20518f0cb1256669420fdba0cd90d21561e560ac240f26ef8322e45bb7ed6", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.0.0" + }, + "oauth2": { + "dependency": "transitive", + "description": { + "name": "oauth2", + "sha256": "c84470642cbb2bec450ccab2f8520c079cd1ca546a76ffd5c40589e07f4e8bf4", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.0.3" + }, + "package_config": { + "dependency": "transitive", + "description": { + "name": "package_config", + "sha256": "f096c55ebb7deb7e384101542bfba8c52696c1b56fca2eb62827989ef2353bbc", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.2.0" + }, + "path": { + "dependency": "transitive", + "description": { + "name": "path", + "sha256": "75cca69d1490965be98c73ceaea117e8a04dd21217b37b292c9ddbec0d955bc5", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.9.1" + }, + "pointycastle": { + "dependency": "transitive", + "description": { + "name": "pointycastle", + "sha256": "92aa3841d083cc4b0f4709b5c74fd6409a3e6ba833ffc7dc6a8fee096366acf5", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "4.0.0" + }, + "pool": { + "dependency": "transitive", + "description": { + "name": "pool", + "sha256": "20fe868b6314b322ea036ba325e6fc0711a22948856475e2c2b6306e8ab39c2a", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.5.1" + }, + "pub_api_client": { + "dependency": "transitive", + "description": { + "name": "pub_api_client", + "sha256": "b9c0184ce4a562d8cf2ebd7be235a25aa158b7c01bdef863cccadc5894644e26", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "3.1.1" + }, + "pub_semver": { + "dependency": "transitive", + "description": { + "name": "pub_semver", + "sha256": "5bfcf68ca79ef689f8990d1160781b4bad40a3bd5e5218ad4076ddb7f4081585", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.2.0" + }, + "pubspec_parse": { + "dependency": "transitive", + "description": { + "name": "pubspec_parse", + "sha256": "0560ba233314abbed0a48a2956f7f022cce7c3e1e73df540277da7544cad4082", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.5.0" + }, + "rfc_6901": { + "dependency": "transitive", + "description": { + "name": "rfc_6901", + "sha256": "df1bbfa3d023009598f19636d6114c6ac1e0b7bb7bf6a260f0e6e6ce91416820", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "0.2.0" + }, + "riverpod": { + "dependency": "direct main", + "description": { + "name": "riverpod", + "sha256": "59062512288d3056b2321804332a13ffdd1bf16df70dcc8e506e411280a72959", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.6.1" + }, + "shelf": { + "dependency": "direct main", + "description": { + "name": "shelf", + "sha256": "e7dd780a7ffb623c57850b33f43309312fc863fb6aa3d276a754bb299839ef12", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.4.2" + }, + "shelf_router": { + "dependency": "direct main", + "description": { + "name": "shelf_router", + "sha256": "f5e5d492440a7fb165fe1e2e1a623f31f734d3370900070b2b1e0d0428d59864", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.1.4" + }, + "shelf_web_socket": { + "dependency": "transitive", + "description": { + "name": "shelf_web_socket", + "sha256": "3632775c8e90d6c9712f883e633716432a27758216dfb61bd86a8321c0580925", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "3.0.0" + }, + "source_gen": { + "dependency": "transitive", + "description": { + "name": "source_gen", + "sha256": "35c8150ece9e8c8d263337a265153c3329667640850b9304861faea59fc98f6b", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.0.0" + }, + "source_helper": { + "dependency": "transitive", + "description": { + "name": "source_helper", + "sha256": "86d247119aedce8e63f4751bd9626fc9613255935558447569ad42f9f5b48b3c", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.3.5" + }, + "source_span": { + "dependency": "transitive", + "description": { + "name": "source_span", + "sha256": "254ee5351d6cb365c859e20ee823c3bb479bf4a293c22d17a9f1bf144ce86f7c", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.10.1" + }, + "stack_trace": { + "dependency": "transitive", + "description": { + "name": "stack_trace", + "sha256": "8b27215b45d22309b5cddda1aa2b19bdfec9df0e765f2de506401c071d38d1b1", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.12.1" + }, + "state_notifier": { + "dependency": "transitive", + "description": { + "name": "state_notifier", + "sha256": "b8677376aa54f2d7c58280d5a007f9e8774f1968d1fb1c096adcb4792fba29bb", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.0.0" + }, + "stream_channel": { + "dependency": "transitive", + "description": { + "name": "stream_channel", + "sha256": "969e04c80b8bcdf826f8f16579c7b14d780458bd97f56d107d3950fdbeef059d", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.1.4" + }, + "stream_transform": { + "dependency": "transitive", + "description": { + "name": "stream_transform", + "sha256": "ad47125e588cfd37a9a7f86c7d6356dde8dfe89d071d293f80ca9e9273a33871", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.1.1" + }, + "string_scanner": { + "dependency": "transitive", + "description": { + "name": "string_scanner", + "sha256": "921cd31725b72fe181906c6a94d987c78e3b98c2e205b397ea399d4054872b43", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.4.1" + }, + "super_string": { + "dependency": "transitive", + "description": { + "name": "super_string", + "sha256": "ba41acf9fbb318b3fc0d57c9235779100394d85d83f45ab533615df1f3146ea7", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.0.3" + }, + "term_glyph": { + "dependency": "transitive", + "description": { + "name": "term_glyph", + "sha256": "7f554798625ea768a7518313e58f83891c7f5024f88e46e7182a4558850a4b8e", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.2.2" + }, + "test_api": { + "dependency": "transitive", + "description": { + "name": "test_api", + "sha256": "522f00f556e73044315fa4585ec3270f1808a4b186c936e612cab0b565ff1e00", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "0.7.6" + }, + "timing": { + "dependency": "transitive", + "description": { + "name": "timing", + "sha256": "62ee18aca144e4a9f29d212f5a4c6a053be252b895ab14b5821996cff4ed90fe", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.0.2" + }, + "type_plus": { + "dependency": "transitive", + "description": { + "name": "type_plus", + "sha256": "d5d1019471f0d38b91603adb9b5fd4ce7ab903c879d2fbf1a3f80a630a03fcc9", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "2.1.1" + }, + "typed_data": { + "dependency": "transitive", + "description": { + "name": "typed_data", + "sha256": "f9049c039ebfeb4cf7a7104a675823cd72dba8297f264b6637062516699fa006", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.4.0" + }, + "watcher": { + "dependency": "transitive", + "description": { + "name": "watcher", + "sha256": "0b7fd4a0bbc4b92641dbf20adfd7e3fd1398fe17102d94b674234563e110088a", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.1.2" + }, + "web": { + "dependency": "transitive", + "description": { + "name": "web", + "sha256": "868d88a33d8a87b18ffc05f9f030ba328ffefba92d6c127917a2ba740f9cfe4a", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.1.1" + }, + "web_socket": { + "dependency": "transitive", + "description": { + "name": "web_socket", + "sha256": "34d64019aa8e36bf9842ac014bb5d2f5586ca73df5e4d9bf5c936975cae6982c", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "1.0.1" + }, + "web_socket_channel": { + "dependency": "transitive", + "description": { + "name": "web_socket_channel", + "sha256": "d645757fb0f4773d602444000a8131ff5d48c9e47adfe9772652dd1a4f2d45c8", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "3.0.3" + }, + "yaml": { + "dependency": "transitive", + "description": { + "name": "yaml", + "sha256": "b9da305ac7c39faa3f030eccd175340f968459dae4af175130b3fc47e40d76ce", + "url": "https://pub.dev" + }, + "source": "hosted", + "version": "3.1.3" + } + }, + "sdks": { + "dart": ">=3.8.0 <4.0.0" + } +} diff --git a/pubspec.yaml b/pubspec.yaml index 98f5105..49701af 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -2,6 +2,8 @@ name: matrixoidc description: A minimal OpenID Connect provider backed by Matrix. version: 1.0.0 publish_to: none +executables: + matrixoidc: environment: sdk: ^3.8.0 From 3ff78be71a2440ef5f72589dec163ffb8987366c Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Thu, 19 Jun 2025 22:21:57 -0400 Subject: [PATCH 03/45] try to fix package --- flake.nix | 2 +- module.nix | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index 2ba5e00..5e7245f 100644 --- a/flake.nix +++ b/flake.nix @@ -38,7 +38,7 @@ }; }; - flake.nixosModules.default = import ./module.nix; + flake.nixosModules.default = import ./module.nix inputs.self; }; }; } diff --git a/module.nix b/module.nix index 1ecf0ec..376a558 100644 --- a/module.nix +++ b/module.nix @@ -1,4 +1,4 @@ -{ +self: { config, lib, pkgs, @@ -10,7 +10,7 @@ in { meta.maintainers = with lib.maintainers; [quadradical]; options.services.matrixoidc = { enable = lib.mkEnableOption "the matrixoidc server"; - package = lib.mkPackageOption pkgs "matrixoidc" {}; + package = lib.mkPackageOption self.packages.${pkgs.stdenv.hostPlatform.system} "matrixoidc" {}; group = lib.mkOption { type = lib.types.string; From 40e61e08f872df860f34d351a356c968493b386a Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 20 Jun 2025 09:21:39 -0400 Subject: [PATCH 04/45] Move out of perSystem --- flake.nix | 3 +-- module.nix | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/flake.nix b/flake.nix index 5e7245f..76a116a 100644 --- a/flake.nix +++ b/flake.nix @@ -37,8 +37,7 @@ maintainers = [lib.maintainers.quadradical]; }; }; - - flake.nixosModules.default = import ./module.nix inputs.self; }; + flake.nixosModules.default = import ./module.nix inputs.self; }; } diff --git a/module.nix b/module.nix index 376a558..48700c0 100644 --- a/module.nix +++ b/module.nix @@ -10,7 +10,7 @@ in { meta.maintainers = with lib.maintainers; [quadradical]; options.services.matrixoidc = { enable = lib.mkEnableOption "the matrixoidc server"; - package = lib.mkPackageOption self.packages.${pkgs.stdenv.hostPlatform.system} "matrixoidc" {}; + package = lib.mkPackageOption self.packages.${pkgs.system} "default" {}; group = lib.mkOption { type = lib.types.string; From 766ce5fc8c3e17fb9dd82a95aff9aa83bc078f78 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 20 Jun 2025 09:39:09 -0400 Subject: [PATCH 05/45] Fix group --- module.nix | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/module.nix b/module.nix index 48700c0..4b6f56c 100644 --- a/module.nix +++ b/module.nix @@ -12,16 +12,18 @@ in { enable = lib.mkEnableOption "the matrixoidc server"; package = lib.mkPackageOption self.packages.${pkgs.system} "default" {}; - group = lib.mkOption { - type = lib.types.string; - }; - jwtSecretFile = lib.mkOption { type = lib.types.path; }; + group = lib.mkOption { + type = lib.types.string; + default = "matrixoidc"; + }; + args = lib.mkOption { type = lib.types.string; + default = ""; }; }; From 461e5bdfcff66af55291331563a907ee624abd4a Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 20 Jun 2025 09:41:34 -0400 Subject: [PATCH 06/45] Dont use deprecated types --- module.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/module.nix b/module.nix index 4b6f56c..a97c3c4 100644 --- a/module.nix +++ b/module.nix @@ -17,12 +17,12 @@ in { }; group = lib.mkOption { - type = lib.types.string; + type = lib.types.str; default = "matrixoidc"; }; args = lib.mkOption { - type = lib.types.string; + type = lib.types.separatedString " "; default = ""; }; }; From e07331f0524a37a110e8a12d2edb07054e20653b Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 20 Jun 2025 10:09:12 -0400 Subject: [PATCH 07/45] Use array for args --- module.nix | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/module.nix b/module.nix index a97c3c4..fa64f6e 100644 --- a/module.nix +++ b/module.nix @@ -22,8 +22,8 @@ in { }; args = lib.mkOption { - type = lib.types.separatedString " "; - default = ""; + type = with lib.types; listOf str; + default = []; }; }; @@ -37,11 +37,11 @@ in { serviceConfig = { LoadCredential = ["matrixoidc-secrets:${cfg.jwtSecretFile}"]; - ExecStart = utils.escapeSystemdExecArgs [ - (lib.getExe cfg.package) - cfg.args - "--jwtSecretFile=/run/credentials/matrixoidc.service/matrixoidc-secrets" - ]; + ExecStart = utils.escapeSystemdExecArgs ([ + (lib.getExe cfg.package) + "--jwtSecretFile=/run/credentials/matrixoidc.service/matrixoidc-secrets" + ] + ++ cfg.args); DynamicUser = true; LockPersonality = true; MemoryDenyWriteExecute = true; From 6a4c86d4369e560fe84f1e4f896ff114d1340e36 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 20 Jun 2025 10:15:45 -0400 Subject: [PATCH 08/45] RM help --- bin/matrixoidc.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/matrixoidc.dart b/bin/matrixoidc.dart index edf5181..7bd75e3 100644 --- a/bin/matrixoidc.dart +++ b/bin/matrixoidc.dart @@ -9,7 +9,6 @@ import "package:shelf_router/shelf_router.dart"; void main(List argsRaw) async { final parser = ConfigParser() - ..addFlag("help", abbr: "h") ..addOption("socket", abbr: "s") ..addOption("serviceDomain", abbr: "d") ..addOption("port", abbr: "p", defaultsTo: "8080") From b8394734d22bae308e892970e2f56e9c9061053f Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 20 Jun 2025 13:38:45 -0400 Subject: [PATCH 09/45] Add AF_UNIX --- module.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/module.nix b/module.nix index fa64f6e..d881c1c 100644 --- a/module.nix +++ b/module.nix @@ -55,6 +55,7 @@ in { PrivateMounts = true; PrivateUsers = true; RestrictAddressFamilies = [ + "AF_UNIX" "AF_INET" "AF_INET6" "AF_NETLINK" From e707ac44e285ebe7ec6062585f9210ae97772584 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 20 Jun 2025 14:02:21 -0400 Subject: [PATCH 10/45] no private users --- module.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/module.nix b/module.nix index d881c1c..1a2879e 100644 --- a/module.nix +++ b/module.nix @@ -53,7 +53,6 @@ in { ProtectKernelTunables = true; PrivateDevices = true; PrivateMounts = true; - PrivateUsers = true; RestrictAddressFamilies = [ "AF_UNIX" "AF_INET" From f076bd496fa2a9f902fd2007342a0b2a1566b90a Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 20 Jun 2025 14:07:23 -0400 Subject: [PATCH 11/45] Change UMask --- module.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module.nix b/module.nix index 1a2879e..dbc4bfd 100644 --- a/module.nix +++ b/module.nix @@ -70,7 +70,7 @@ in { ]; Restart = "on-failure"; RestartSec = 5; - UMask = "077"; + UMask = 007; RuntimeDirectory = "matrixoidc"; RuntimeDirectoryMode = 0770; From e1941308ca25f28dc7e8b90307d203ebaca0c4a8 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 20 Jun 2025 14:12:47 -0400 Subject: [PATCH 12/45] Fix test --- JUSTFILE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/JUSTFILE b/JUSTFILE index c2af145..c2d7582 100644 --- a/JUSTFILE +++ b/JUSTFILE @@ -5,4 +5,4 @@ build: dart run build_runner build test: - oauth2c http://localhost:8080 --client-id yourclientid --redirect-url http://localhost/callback --scopes openid --grant-type authorization_code --auth-method none --response-mode query \ No newline at end of file + oauth2c http://localhost:8080 --client-id yourclientid --redirect-url http://localhost:8081/callback --scopes openid --grant-type authorization_code --auth-method none --response-mode query \ No newline at end of file From 9ce1196be12534f491620ff3b45108ea2a60ab0d Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 20 Jun 2025 14:26:21 -0400 Subject: [PATCH 13/45] Quick fix for forgejo --- lib/helpers/api_helper.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 6b55c18..9c2d19e 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -85,6 +85,7 @@ class ApiHelper { return Response.ok( json.encode({ "id_token": token, + "access_token": token, // TODO: Use real access token "token_type": "Bearer", "expires_in": 600, }), From f875ef407195b12fc19e5ddd7d896278c1b98a3f Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 20 Jun 2025 15:07:34 -0400 Subject: [PATCH 14/45] rm netlink --- module.nix | 1 - 1 file changed, 1 deletion(-) diff --git a/module.nix b/module.nix index dbc4bfd..c6dc25c 100644 --- a/module.nix +++ b/module.nix @@ -57,7 +57,6 @@ in { "AF_UNIX" "AF_INET" "AF_INET6" - "AF_NETLINK" ]; RestrictNamespaces = true; RestrictRealtime = true; From a3733511b6e27b034dbc73f90d8159cd770ebcc9 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sat, 21 Jun 2025 20:06:09 -0400 Subject: [PATCH 15/45] rm jwk stuff --- bin/matrixoidc.dart | 1 - lib/helpers/api_helper.dart | 9 ++------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/bin/matrixoidc.dart b/bin/matrixoidc.dart index 7bd75e3..7bbc11d 100644 --- a/bin/matrixoidc.dart +++ b/bin/matrixoidc.dart @@ -34,7 +34,6 @@ void main(List argsRaw) async { apiHelper.openidConfiguration, ) ..get("/userinfo", apiHelper.userinfoHandler) - ..get("/jwks.json", apiHelper.jwks) ..post("/login", apiHelper.handleLogin) ..post("/token", apiHelper.tokenHandler)) .call, diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 9c2d19e..73997d1 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -81,11 +81,12 @@ class ApiHelper { ); final token = jwt.sign(SecretKey(secret), algorithm: JWTAlgorithm.HS256); + print("Token: $token"); //TODO: Remove return Response.ok( json.encode({ "id_token": token, - "access_token": token, // TODO: Use real access token + "access_token": token, "token_type": "Bearer", "expires_in": 600, }), @@ -118,11 +119,6 @@ class ApiHelper { } } - Response jwks(_) => Response.ok( - json.encode({"keys": []}), - headers: {"content-type": "application/json"}, - ); - Response openidConfiguration(_) { final settings = ref.read(SettingsController.provider)!; return Response.ok( @@ -131,7 +127,6 @@ class ApiHelper { "authorization_endpoint": settings.authorizeEndpoint, "token_endpoint": "${settings.issuer}/token", "userinfo_endpoint": "${settings.issuer}/userinfo", - "jwks_uri": "${settings.issuer}/jwks.json", "response_types_supported": ["code"], "subject_types_supported": ["public"], "id_token_signing_alg_values_supported": ["HS256"], From a19b5e1bfbdaf8e8be81502c8ae06ac09c00a151 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sat, 21 Jun 2025 20:14:30 -0400 Subject: [PATCH 16/45] rm test print --- lib/helpers/api_helper.dart | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 73997d1..76e2d3a 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -64,10 +64,6 @@ class ApiHelper { final user = codes[code]!; ref.read(AuthCodeController.provider.notifier).remove(code); - final secret = await File.fromUri( - Uri.file(settings.jwtSecretFile), - ).readAsString(); - final jwt = JWT( { "exp": @@ -80,8 +76,12 @@ class ApiHelper { audience: Audience([clientId]), ); - final token = jwt.sign(SecretKey(secret), algorithm: JWTAlgorithm.HS256); - print("Token: $token"); //TODO: Remove + final token = jwt.sign( + SecretKey( + await File.fromUri(Uri.file(settings.jwtSecretFile)).readAsString(), + ), + algorithm: JWTAlgorithm.HS256, + ); return Response.ok( json.encode({ From 7d729ccb7646a858c983e30349b2f8a4dd9f8bd9 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 22 Jun 2025 04:01:58 -0400 Subject: [PATCH 17/45] Trim secret --- lib/helpers/api_helper.dart | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 76e2d3a..70f243f 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -78,7 +78,9 @@ class ApiHelper { final token = jwt.sign( SecretKey( - await File.fromUri(Uri.file(settings.jwtSecretFile)).readAsString(), + (await File.fromUri( + Uri.file(settings.jwtSecretFile), + ).readAsString()).trim(), ), algorithm: JWTAlgorithm.HS256, ); @@ -105,9 +107,9 @@ class ApiHelper { final jwt = JWT.verify( token, SecretKey( - await File.fromUri( + (await File.fromUri( Uri.file(ref.read(SettingsController.provider)!.jwtSecretFile), - ).readAsString(), + ).readAsString()).trim(), ), ); return Response.ok( From b7bd137e16673c7d52d4a684b4bca2ba0b3f0ccf Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 22 Jun 2025 12:35:12 -0400 Subject: [PATCH 18/45] add bridge --- bin/matrixoidc.dart | 1 + lib/helpers/api_helper.dart | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/bin/matrixoidc.dart b/bin/matrixoidc.dart index 7bbc11d..a910ed7 100644 --- a/bin/matrixoidc.dart +++ b/bin/matrixoidc.dart @@ -34,6 +34,7 @@ void main(List argsRaw) async { apiHelper.openidConfiguration, ) ..get("/userinfo", apiHelper.userinfoHandler) + ..get("/bridge", apiHelper.bridgeHandler) ..post("/login", apiHelper.handleLogin) ..post("/token", apiHelper.tokenHandler)) .call, diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 70f243f..e706bbf 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -43,7 +43,13 @@ class ApiHelper { .read(AuthCodeController.provider.notifier) .set(code, MatrixUser(userId: userId, matrixToken: accessToken)); - return Response.found("$redirectUri?code=$code&state=$state"); + final uri = Uri.parse(redirectUri); + + return Response.found( + uri.replace( + queryParameters: {...uri.queryParameters, "code": code, "state": state}, + ), + ); } Future tokenHandler(Request request) async { @@ -96,6 +102,33 @@ class ApiHelper { ); } + Future bridgeHandler(Request request) async { + final query = request.url.queryParameters; + final code = query['code']; + final redirectUri = query['redirect_uri']; + + if (code == null || redirectUri == null) { + return Response(400, body: "Missing code or redirect_uri"); + } + + final tokenRes = await tokenHandler( + Request( + "POST", + Uri.base, + body: json.encode({"code": code, "client_id": "proxy"}), + ), + ); + + final uri = Uri.parse(redirectUri).replace( + queryParameters: { + ...Uri.parse(redirectUri).queryParameters, + ...json.decode(await tokenRes.readAsString()), + }, + ); + + return Response.found(uri.toString()); + } + Future userinfoHandler(Request request) async { final auth = request.headers["authorization"]; if (auth == null || !auth.startsWith("Bearer ")) { From 754ff561199b0067e99eabdd4302f10de478c6e4 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 22 Jun 2025 13:09:28 -0400 Subject: [PATCH 19/45] Attempt fix --- lib/helpers/api_helper.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index e706bbf..29d86a9 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -115,7 +115,8 @@ class ApiHelper { Request( "POST", Uri.base, - body: json.encode({"code": code, "client_id": "proxy"}), + body: utf8.encode('code=$code&client_id=proxy'), + headers: {'Content-Type': 'application/x-www-form-urlencoded'}, ), ); From a27a53b2cf6ce514507e5dda1d441735d7a4a009 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 22 Jun 2025 14:06:06 -0400 Subject: [PATCH 20/45] wait is this actually working --- lib/helpers/api_helper.dart | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 29d86a9..7654eb6 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -116,10 +116,13 @@ class ApiHelper { "POST", Uri.base, body: utf8.encode('code=$code&client_id=proxy'), - headers: {'Content-Type': 'application/x-www-form-urlencoded'}, ), ); + if (tokenRes.statusCode != 200) { + return Response(400, body: "Token post failed"); + } + final uri = Uri.parse(redirectUri).replace( queryParameters: { ...Uri.parse(redirectUri).queryParameters, From 32ec721e23606a6ce0616441b0a22a8300e59a92 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 22 Jun 2025 14:15:53 -0400 Subject: [PATCH 21/45] try to toString --- lib/helpers/api_helper.dart | 64 +++++++++++++++++++------------------ 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 7654eb6..dda1738 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -52,6 +52,39 @@ class ApiHelper { ); } + Future bridgeHandler(Request request) async { + final query = request.url.queryParameters; + final code = query['code']; + final redirectUri = query['redirect_uri']; + + if (code == null || redirectUri == null) { + return Response(400, body: "Missing code or redirect_uri"); + } + + final tokenRes = await tokenHandler( + Request( + "POST", + Uri.base, + body: utf8.encode('code=$code&client_id=proxy'), + ), + ); + + if (tokenRes.statusCode != 200) { + return Response(400, body: "Token post failed"); + } + + final uri = Uri.parse(redirectUri).replace( + queryParameters: { + ...Uri.parse(redirectUri).queryParameters, + ...(json.decode(await tokenRes.readAsString()) as Map).map( + (key, value) => MapEntry(key, value.toString()), + ), + }, + ); + + return Response.found(uri.toString()); + } + Future tokenHandler(Request request) async { final settings = ref.read(SettingsController.provider)!; final body = Uri.splitQueryString(await request.readAsString()); @@ -102,37 +135,6 @@ class ApiHelper { ); } - Future bridgeHandler(Request request) async { - final query = request.url.queryParameters; - final code = query['code']; - final redirectUri = query['redirect_uri']; - - if (code == null || redirectUri == null) { - return Response(400, body: "Missing code or redirect_uri"); - } - - final tokenRes = await tokenHandler( - Request( - "POST", - Uri.base, - body: utf8.encode('code=$code&client_id=proxy'), - ), - ); - - if (tokenRes.statusCode != 200) { - return Response(400, body: "Token post failed"); - } - - final uri = Uri.parse(redirectUri).replace( - queryParameters: { - ...Uri.parse(redirectUri).queryParameters, - ...json.decode(await tokenRes.readAsString()), - }, - ); - - return Response.found(uri.toString()); - } - Future userinfoHandler(Request request) async { final auth = request.headers["authorization"]; if (auth == null || !auth.startsWith("Bearer ")) { From fb298c98804b95fb7da7a090fa04f2ef4b3982f7 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 22 Jun 2025 14:50:24 -0400 Subject: [PATCH 22/45] Don't trim --- lib/helpers/api_helper.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index dda1738..950a97e 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -117,9 +117,7 @@ class ApiHelper { final token = jwt.sign( SecretKey( - (await File.fromUri( - Uri.file(settings.jwtSecretFile), - ).readAsString()).trim(), + (await File.fromUri(Uri.file(settings.jwtSecretFile)).readAsString()), ), algorithm: JWTAlgorithm.HS256, ); @@ -148,7 +146,7 @@ class ApiHelper { SecretKey( (await File.fromUri( Uri.file(ref.read(SettingsController.provider)!.jwtSecretFile), - ).readAsString()).trim(), + ).readAsString()), ), ); return Response.ok( From 0dfc6c96ee82e6dfbfe0004acce736d3798c5826 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 22 Jun 2025 15:04:10 -0400 Subject: [PATCH 23/45] Use cookie --- lib/helpers/api_helper.dart | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 950a97e..026be21 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -73,16 +73,13 @@ class ApiHelper { return Response(400, body: "Token post failed"); } - final uri = Uri.parse(redirectUri).replace( - queryParameters: { - ...Uri.parse(redirectUri).queryParameters, - ...(json.decode(await tokenRes.readAsString()) as Map).map( - (key, value) => MapEntry(key, value.toString()), - ), + return Response.found( + redirectUri, + headers: { + 'set-cookie': + 'id_token=${json.decode(await tokenRes.readAsString())["id_token"]}; Path=/; Secure; HttpOnly; SameSite=Lax', }, ); - - return Response.found(uri.toString()); } Future tokenHandler(Request request) async { @@ -127,7 +124,6 @@ class ApiHelper { "id_token": token, "access_token": token, "token_type": "Bearer", - "expires_in": 600, }), headers: {"Content-Type": "application/json"}, ); From 13a469ba6dfbb1ef6431570b952fb4a78471e63f Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 22 Jun 2025 15:30:51 -0400 Subject: [PATCH 24/45] serviceDomain mandatory --- bin/matrixoidc.dart | 2 +- lib/helpers/api_helper.dart | 2 +- lib/models/settings.dart | 2 +- lib/models/settings.freezed.dart | 20 ++++++++++---------- lib/models/settings.g.dart | 2 +- 5 files changed, 14 insertions(+), 14 deletions(-) diff --git a/bin/matrixoidc.dart b/bin/matrixoidc.dart index a910ed7..b462a54 100644 --- a/bin/matrixoidc.dart +++ b/bin/matrixoidc.dart @@ -10,11 +10,11 @@ import "package:shelf_router/shelf_router.dart"; void main(List argsRaw) async { final parser = ConfigParser() ..addOption("socket", abbr: "s") - ..addOption("serviceDomain", abbr: "d") ..addOption("port", abbr: "p", defaultsTo: "8080") ..addOption("address", abbr: "a", defaultsTo: "127.0.0.1") ..addOption("issuer", abbr: "i", mandatory: true) ..addOption("homeserver", abbr: "u", mandatory: true) + ..addOption("serviceDomain", abbr: "d", mandatory: true) ..addOption("jwtSecretFile", abbr: "j", mandatory: true) ..addOption("authorizeEndpoint", abbr: "e", mandatory: true); diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 026be21..a353951 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -77,7 +77,7 @@ class ApiHelper { redirectUri, headers: { 'set-cookie': - 'id_token=${json.decode(await tokenRes.readAsString())["id_token"]}; Path=/; Secure; HttpOnly; SameSite=Lax', + 'id_token=${json.decode(await tokenRes.readAsString())["id_token"]}; Path=/; Secure; HttpOnly; SameSite=Lax; Domain=.${ref.watch(SettingsController.provider)!.serviceDomain}', }, ); } diff --git a/lib/models/settings.dart b/lib/models/settings.dart index dc6cf54..87af5e9 100644 --- a/lib/models/settings.dart +++ b/lib/models/settings.dart @@ -7,7 +7,7 @@ part "settings.g.dart"; abstract class Settings with _$Settings { const factory Settings({ required String? socket, - required String? serviceDomain, + required String serviceDomain, required String address, required String port, required String homeserver, diff --git a/lib/models/settings.freezed.dart b/lib/models/settings.freezed.dart index 3af7771..0b75a21 100644 --- a/lib/models/settings.freezed.dart +++ b/lib/models/settings.freezed.dart @@ -16,7 +16,7 @@ T _$identity(T value) => value; /// @nodoc mixin _$Settings { - String? get socket; String? get serviceDomain; String get address; String get port; String get homeserver; String get issuer; String get jwtSecretFile; String get authorizeEndpoint; + String? get socket; String get serviceDomain; String get address; String get port; String get homeserver; String get issuer; String get jwtSecretFile; String get authorizeEndpoint; /// Create a copy of Settings /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) @@ -49,7 +49,7 @@ abstract mixin class $SettingsCopyWith<$Res> { factory $SettingsCopyWith(Settings value, $Res Function(Settings) _then) = _$SettingsCopyWithImpl; @useResult $Res call({ - String? socket, String? serviceDomain, String address, String port, String homeserver, String issuer, String jwtSecretFile, String authorizeEndpoint + String? socket, String serviceDomain, String address, String port, String homeserver, String issuer, String jwtSecretFile, String authorizeEndpoint }); @@ -66,11 +66,11 @@ class _$SettingsCopyWithImpl<$Res> /// Create a copy of Settings /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? socket = freezed,Object? serviceDomain = freezed,Object? address = null,Object? port = null,Object? homeserver = null,Object? issuer = null,Object? jwtSecretFile = null,Object? authorizeEndpoint = null,}) { +@pragma('vm:prefer-inline') @override $Res call({Object? socket = freezed,Object? serviceDomain = null,Object? address = null,Object? port = null,Object? homeserver = null,Object? issuer = null,Object? jwtSecretFile = null,Object? authorizeEndpoint = null,}) { return _then(_self.copyWith( socket: freezed == socket ? _self.socket : socket // ignore: cast_nullable_to_non_nullable -as String?,serviceDomain: freezed == serviceDomain ? _self.serviceDomain : serviceDomain // ignore: cast_nullable_to_non_nullable -as String?,address: null == address ? _self.address : address // ignore: cast_nullable_to_non_nullable +as String?,serviceDomain: null == serviceDomain ? _self.serviceDomain : serviceDomain // ignore: cast_nullable_to_non_nullable +as String,address: null == address ? _self.address : address // ignore: cast_nullable_to_non_nullable as String,port: null == port ? _self.port : port // ignore: cast_nullable_to_non_nullable as String,homeserver: null == homeserver ? _self.homeserver : homeserver // ignore: cast_nullable_to_non_nullable as String,issuer: null == issuer ? _self.issuer : issuer // ignore: cast_nullable_to_non_nullable @@ -91,7 +91,7 @@ class _Settings implements Settings { factory _Settings.fromJson(Map json) => _$SettingsFromJson(json); @override final String? socket; -@override final String? serviceDomain; +@override final String serviceDomain; @override final String address; @override final String port; @override final String homeserver; @@ -132,7 +132,7 @@ abstract mixin class _$SettingsCopyWith<$Res> implements $SettingsCopyWith<$Res> factory _$SettingsCopyWith(_Settings value, $Res Function(_Settings) _then) = __$SettingsCopyWithImpl; @override @useResult $Res call({ - String? socket, String? serviceDomain, String address, String port, String homeserver, String issuer, String jwtSecretFile, String authorizeEndpoint + String? socket, String serviceDomain, String address, String port, String homeserver, String issuer, String jwtSecretFile, String authorizeEndpoint }); @@ -149,11 +149,11 @@ class __$SettingsCopyWithImpl<$Res> /// Create a copy of Settings /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? socket = freezed,Object? serviceDomain = freezed,Object? address = null,Object? port = null,Object? homeserver = null,Object? issuer = null,Object? jwtSecretFile = null,Object? authorizeEndpoint = null,}) { +@override @pragma('vm:prefer-inline') $Res call({Object? socket = freezed,Object? serviceDomain = null,Object? address = null,Object? port = null,Object? homeserver = null,Object? issuer = null,Object? jwtSecretFile = null,Object? authorizeEndpoint = null,}) { return _then(_Settings( socket: freezed == socket ? _self.socket : socket // ignore: cast_nullable_to_non_nullable -as String?,serviceDomain: freezed == serviceDomain ? _self.serviceDomain : serviceDomain // ignore: cast_nullable_to_non_nullable -as String?,address: null == address ? _self.address : address // ignore: cast_nullable_to_non_nullable +as String?,serviceDomain: null == serviceDomain ? _self.serviceDomain : serviceDomain // ignore: cast_nullable_to_non_nullable +as String,address: null == address ? _self.address : address // ignore: cast_nullable_to_non_nullable as String,port: null == port ? _self.port : port // ignore: cast_nullable_to_non_nullable as String,homeserver: null == homeserver ? _self.homeserver : homeserver // ignore: cast_nullable_to_non_nullable as String,issuer: null == issuer ? _self.issuer : issuer // ignore: cast_nullable_to_non_nullable diff --git a/lib/models/settings.g.dart b/lib/models/settings.g.dart index e9172f1..d00bb6f 100644 --- a/lib/models/settings.g.dart +++ b/lib/models/settings.g.dart @@ -8,7 +8,7 @@ part of 'settings.dart'; _Settings _$SettingsFromJson(Map json) => _Settings( socket: json['socket'] as String?, - serviceDomain: json['serviceDomain'] as String?, + serviceDomain: json['serviceDomain'] as String, address: json['address'] as String, port: json['port'] as String, homeserver: json['homeserver'] as String, From 8e2df0703d71eb04dd497e78b24920797ce6eae6 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 20 Jul 2025 14:29:03 -0400 Subject: [PATCH 25/45] Add email --- lib/helpers/api_helper.dart | 2 ++ pubspec.lock | 2 +- pubspec.yaml | 1 + 3 files changed, 4 insertions(+), 1 deletion(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index a353951..9c2564e 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -105,6 +105,8 @@ class ApiHelper { "exp": DateTime.now().add(Duration(days: 7)).millisecondsSinceEpoch ~/ 1000, + "email": + "${user.userId.split(':').first.replaceFirst('@', '')}@federated.nexus", "iat": DateTime.now().millisecondsSinceEpoch ~/ 1000, }, subject: user.userId, diff --git a/pubspec.lock b/pubspec.lock index 52f7e2d..b066feb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -26,7 +26,7 @@ packages: source: hosted version: "7.4.5" args: - dependency: transitive + dependency: "direct main" description: name: args sha256: d0481093c50b1da8910eb0bb301626d4d8eb7284aa739614d2b394ee09e3ea04 diff --git a/pubspec.yaml b/pubspec.yaml index 49701af..8867bc5 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -18,6 +18,7 @@ dependencies: shelf_router: ^1.1.4 fast_immutable_collections: ^11.0.4 cli_tools: ^0.6.0 + args: ^2.7.0 dev_dependencies: build_runner: ^2.4.6 From 53df67a4ceecade3892894e06ac6f50fa23418b0 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 20 Jul 2025 14:34:24 -0400 Subject: [PATCH 26/45] Add name field --- lib/helpers/api_helper.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 9c2564e..78bf0d9 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -99,14 +99,15 @@ class ApiHelper { final user = codes[code]!; ref.read(AuthCodeController.provider.notifier).remove(code); + final name = user.userId.split(':').first.replaceFirst('@', ''); final jwt = JWT( { "exp": DateTime.now().add(Duration(days: 7)).millisecondsSinceEpoch ~/ 1000, - "email": - "${user.userId.split(':').first.replaceFirst('@', '')}@federated.nexus", + "email": "$name@federated.nexus", + "name": name, "iat": DateTime.now().millisecondsSinceEpoch ~/ 1000, }, subject: user.userId, From 8efb087cdd98fd76c860cb2b4b2735f4f03c46fd Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 20 Jul 2025 15:47:52 -0400 Subject: [PATCH 27/45] Add dummy logout endpoint --- bin/matrixoidc.dart | 3 ++- lib/helpers/api_helper.dart | 6 +++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/bin/matrixoidc.dart b/bin/matrixoidc.dart index b462a54..6ab2aa0 100644 --- a/bin/matrixoidc.dart +++ b/bin/matrixoidc.dart @@ -35,7 +35,8 @@ void main(List argsRaw) async { ) ..get("/userinfo", apiHelper.userinfoHandler) ..get("/bridge", apiHelper.bridgeHandler) - ..post("/login", apiHelper.handleLogin) + ..post("/login", apiHelper.loginHandler) + ..post("/logout", apiHelper.logoutHandler) ..post("/token", apiHelper.tokenHandler)) .call, ); diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 78bf0d9..84fb562 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -12,7 +12,7 @@ class ApiHelper { final Ref ref; ApiHelper(this.ref); - Future handleLogin(Request request) async { + Future loginHandler(Request request) async { final body = await request.readAsString(); final data = Uri.splitQueryString(body); @@ -157,6 +157,9 @@ class ApiHelper { } } + Future logoutHandler(Request request) async => + Response.ok("Log out is not currently implemented"); + Response openidConfiguration(_) { final settings = ref.read(SettingsController.provider)!; return Response.ok( @@ -165,6 +168,7 @@ class ApiHelper { "authorization_endpoint": settings.authorizeEndpoint, "token_endpoint": "${settings.issuer}/token", "userinfo_endpoint": "${settings.issuer}/userinfo", + "end_session_endpoint": "${settings.issuer}/logout", "response_types_supported": ["code"], "subject_types_supported": ["public"], "id_token_signing_alg_values_supported": ["HS256"], From 53867e273b34ad04e846d970fd81c63dfd2910f7 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 20 Jul 2025 16:27:53 -0400 Subject: [PATCH 28/45] Add introspection endpoint --- bin/matrixoidc.dart | 1 + lib/helpers/api_helper.dart | 26 ++++++++++++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/bin/matrixoidc.dart b/bin/matrixoidc.dart index 6ab2aa0..dabc347 100644 --- a/bin/matrixoidc.dart +++ b/bin/matrixoidc.dart @@ -36,6 +36,7 @@ void main(List argsRaw) async { ..get("/userinfo", apiHelper.userinfoHandler) ..get("/bridge", apiHelper.bridgeHandler) ..post("/login", apiHelper.loginHandler) + ..post('/introspect', apiHelper.introspectionHandler) ..post("/logout", apiHelper.logoutHandler) ..post("/token", apiHelper.tokenHandler)) .call, diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 84fb562..8dc4362 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -157,6 +157,31 @@ class ApiHelper { } } + Future introspectionHandler(Request request) async { + final token = Uri.splitQueryString(await request.readAsString())['token']; + if (token == null) return Response(400, body: "Missing token"); + + try { + JWT.verify( + token, + SecretKey( + (await File.fromUri( + Uri.file(ref.read(SettingsController.provider)!.jwtSecretFile), + ).readAsString()), + ), + ); + return Response.ok( + json.encode({'active': true}), + headers: {'content-type': 'application/json'}, + ); + } catch (_) { + return Response.ok( + json.encode({'active': false}), + headers: {'content-type': 'application/json'}, + ); + } + } + Future logoutHandler(Request request) async => Response.ok("Log out is not currently implemented"); @@ -168,6 +193,7 @@ class ApiHelper { "authorization_endpoint": settings.authorizeEndpoint, "token_endpoint": "${settings.issuer}/token", "userinfo_endpoint": "${settings.issuer}/userinfo", + "introspection_endpoint": "${settings.issuer}/introspect", "end_session_endpoint": "${settings.issuer}/logout", "response_types_supported": ["code"], "subject_types_supported": ["public"], From 43ad7937f9be93c93379d5adb0878b8e98cdfd3f Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 20 Jul 2025 16:31:03 -0400 Subject: [PATCH 29/45] Use double quotes --- bin/matrixoidc.dart | 4 ++-- lib/helpers/api_helper.dart | 22 +++++++++---------- lib/models/matrix_user.freezed.dart | 14 ++++++------ lib/models/matrix_user.g.dart | 10 ++++----- lib/models/settings.freezed.dart | 14 ++++++------ lib/models/settings.g.dart | 34 ++++++++++++++--------------- 6 files changed, 49 insertions(+), 49 deletions(-) diff --git a/bin/matrixoidc.dart b/bin/matrixoidc.dart index dabc347..28ba002 100644 --- a/bin/matrixoidc.dart +++ b/bin/matrixoidc.dart @@ -1,5 +1,5 @@ import "dart:io"; -import 'package:cli_tools/config.dart'; +import "package:cli_tools/config.dart"; import "package:matrixoidc/controllers/settings_controller.dart"; import "package:matrixoidc/helpers/api_helper.dart"; import "package:riverpod/riverpod.dart"; @@ -36,7 +36,7 @@ void main(List argsRaw) async { ..get("/userinfo", apiHelper.userinfoHandler) ..get("/bridge", apiHelper.bridgeHandler) ..post("/login", apiHelper.loginHandler) - ..post('/introspect', apiHelper.introspectionHandler) + ..post("/introspect", apiHelper.introspectionHandler) ..post("/logout", apiHelper.logoutHandler) ..post("/token", apiHelper.tokenHandler)) .call, diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 8dc4362..d0c5ce3 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -54,8 +54,8 @@ class ApiHelper { Future bridgeHandler(Request request) async { final query = request.url.queryParameters; - final code = query['code']; - final redirectUri = query['redirect_uri']; + final code = query["code"]; + final redirectUri = query["redirect_uri"]; if (code == null || redirectUri == null) { return Response(400, body: "Missing code or redirect_uri"); @@ -65,7 +65,7 @@ class ApiHelper { Request( "POST", Uri.base, - body: utf8.encode('code=$code&client_id=proxy'), + body: utf8.encode("code=$code&client_id=proxy"), ), ); @@ -76,8 +76,8 @@ class ApiHelper { return Response.found( redirectUri, headers: { - 'set-cookie': - 'id_token=${json.decode(await tokenRes.readAsString())["id_token"]}; Path=/; Secure; HttpOnly; SameSite=Lax; Domain=.${ref.watch(SettingsController.provider)!.serviceDomain}', + "set-cookie": + "id_token=${json.decode(await tokenRes.readAsString())["id_token"]}; Path=/; Secure; HttpOnly; SameSite=Lax; Domain=.${ref.watch(SettingsController.provider)!.serviceDomain}", }, ); } @@ -99,7 +99,7 @@ class ApiHelper { final user = codes[code]!; ref.read(AuthCodeController.provider.notifier).remove(code); - final name = user.userId.split(':').first.replaceFirst('@', ''); + final name = user.userId.split(":").first.replaceFirst("@", ""); final jwt = JWT( { @@ -158,7 +158,7 @@ class ApiHelper { } Future introspectionHandler(Request request) async { - final token = Uri.splitQueryString(await request.readAsString())['token']; + final token = Uri.splitQueryString(await request.readAsString())["token"]; if (token == null) return Response(400, body: "Missing token"); try { @@ -171,13 +171,13 @@ class ApiHelper { ), ); return Response.ok( - json.encode({'active': true}), - headers: {'content-type': 'application/json'}, + json.encode({"active": true}), + headers: {"content-type": "application/json"}, ); } catch (_) { return Response.ok( - json.encode({'active': false}), - headers: {'content-type': 'application/json'}, + json.encode({"active": false}), + headers: {"content-type": "application/json"}, ); } } diff --git a/lib/models/matrix_user.freezed.dart b/lib/models/matrix_user.freezed.dart index 0dd35c7..94504e8 100644 --- a/lib/models/matrix_user.freezed.dart +++ b/lib/models/matrix_user.freezed.dart @@ -4,7 +4,7 @@ // ignore_for_file: type=lint // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark -part of 'matrix_user.dart'; +part of "matrix_user.dart"; // ************************************************************************** // FreezedGenerator @@ -20,7 +20,7 @@ mixin _$MatrixUser { /// Create a copy of MatrixUser /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) -@pragma('vm:prefer-inline') +@pragma("vm:prefer-inline") $MatrixUserCopyWith get copyWith => _$MatrixUserCopyWithImpl(this as MatrixUser, _$identity); /// Serializes this MatrixUser to a JSON map. @@ -38,7 +38,7 @@ int get hashCode => Object.hash(runtimeType,userId,matrixToken); @override String toString() { - return 'MatrixUser(userId: $userId, matrixToken: $matrixToken)'; + return "MatrixUser(userId: $userId, matrixToken: $matrixToken)"; } @@ -66,7 +66,7 @@ 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,}) { 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 @@ -90,7 +90,7 @@ class _MatrixUser implements MatrixUser { /// Create a copy of MatrixUser /// with the given fields replaced by the non-null parameter values. @override @JsonKey(includeFromJson: false, includeToJson: false) -@pragma('vm:prefer-inline') +@pragma("vm:prefer-inline") _$MatrixUserCopyWith<_MatrixUser> get copyWith => __$MatrixUserCopyWithImpl<_MatrixUser>(this, _$identity); @override @@ -109,7 +109,7 @@ int get hashCode => Object.hash(runtimeType,userId,matrixToken); @override String toString() { - return 'MatrixUser(userId: $userId, matrixToken: $matrixToken)'; + return "MatrixUser(userId: $userId, matrixToken: $matrixToken)"; } @@ -137,7 +137,7 @@ 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,}) { 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 diff --git a/lib/models/matrix_user.g.dart b/lib/models/matrix_user.g.dart index e3aa600..95e855f 100644 --- a/lib/models/matrix_user.g.dart +++ b/lib/models/matrix_user.g.dart @@ -1,18 +1,18 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of 'matrix_user.dart'; +part of "matrix_user.dart"; // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** _MatrixUser _$MatrixUserFromJson(Map json) => _MatrixUser( - userId: json['userId'] as String, - matrixToken: json['matrixToken'] as String, + userId: json["userId"] as String, + matrixToken: json["matrixToken"] as String, ); Map _$MatrixUserToJson(_MatrixUser instance) => { - 'userId': instance.userId, - 'matrixToken': instance.matrixToken, + "userId": instance.userId, + "matrixToken": instance.matrixToken, }; diff --git a/lib/models/settings.freezed.dart b/lib/models/settings.freezed.dart index 0b75a21..a88af64 100644 --- a/lib/models/settings.freezed.dart +++ b/lib/models/settings.freezed.dart @@ -4,7 +4,7 @@ // ignore_for_file: type=lint // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark -part of 'settings.dart'; +part of "settings.dart"; // ************************************************************************** // FreezedGenerator @@ -20,7 +20,7 @@ mixin _$Settings { /// Create a copy of Settings /// with the given fields replaced by the non-null parameter values. @JsonKey(includeFromJson: false, includeToJson: false) -@pragma('vm:prefer-inline') +@pragma("vm:prefer-inline") $SettingsCopyWith get copyWith => _$SettingsCopyWithImpl(this as Settings, _$identity); /// Serializes this Settings to a JSON map. @@ -38,7 +38,7 @@ int get hashCode => Object.hash(runtimeType,socket,serviceDomain,address,port,ho @override String toString() { - return 'Settings(socket: $socket, serviceDomain: $serviceDomain, address: $address, port: $port, homeserver: $homeserver, issuer: $issuer, jwtSecretFile: $jwtSecretFile, authorizeEndpoint: $authorizeEndpoint)'; + return "Settings(socket: $socket, serviceDomain: $serviceDomain, address: $address, port: $port, homeserver: $homeserver, issuer: $issuer, jwtSecretFile: $jwtSecretFile, authorizeEndpoint: $authorizeEndpoint)"; } @@ -66,7 +66,7 @@ class _$SettingsCopyWithImpl<$Res> /// Create a copy of Settings /// with the given fields replaced by the non-null parameter values. -@pragma('vm:prefer-inline') @override $Res call({Object? socket = freezed,Object? serviceDomain = null,Object? address = null,Object? port = null,Object? homeserver = null,Object? issuer = null,Object? jwtSecretFile = null,Object? authorizeEndpoint = null,}) { +@pragma("vm:prefer-inline") @override $Res call({Object? socket = freezed,Object? serviceDomain = null,Object? address = null,Object? port = null,Object? homeserver = null,Object? issuer = null,Object? jwtSecretFile = null,Object? authorizeEndpoint = null,}) { return _then(_self.copyWith( socket: freezed == socket ? _self.socket : socket // ignore: cast_nullable_to_non_nullable as String?,serviceDomain: null == serviceDomain ? _self.serviceDomain : serviceDomain // ignore: cast_nullable_to_non_nullable @@ -102,7 +102,7 @@ class _Settings implements Settings { /// Create a copy of Settings /// with the given fields replaced by the non-null parameter values. @override @JsonKey(includeFromJson: false, includeToJson: false) -@pragma('vm:prefer-inline') +@pragma("vm:prefer-inline") _$SettingsCopyWith<_Settings> get copyWith => __$SettingsCopyWithImpl<_Settings>(this, _$identity); @override @@ -121,7 +121,7 @@ int get hashCode => Object.hash(runtimeType,socket,serviceDomain,address,port,ho @override String toString() { - return 'Settings(socket: $socket, serviceDomain: $serviceDomain, address: $address, port: $port, homeserver: $homeserver, issuer: $issuer, jwtSecretFile: $jwtSecretFile, authorizeEndpoint: $authorizeEndpoint)'; + return "Settings(socket: $socket, serviceDomain: $serviceDomain, address: $address, port: $port, homeserver: $homeserver, issuer: $issuer, jwtSecretFile: $jwtSecretFile, authorizeEndpoint: $authorizeEndpoint)"; } @@ -149,7 +149,7 @@ class __$SettingsCopyWithImpl<$Res> /// Create a copy of Settings /// with the given fields replaced by the non-null parameter values. -@override @pragma('vm:prefer-inline') $Res call({Object? socket = freezed,Object? serviceDomain = null,Object? address = null,Object? port = null,Object? homeserver = null,Object? issuer = null,Object? jwtSecretFile = null,Object? authorizeEndpoint = null,}) { +@override @pragma("vm:prefer-inline") $Res call({Object? socket = freezed,Object? serviceDomain = null,Object? address = null,Object? port = null,Object? homeserver = null,Object? issuer = null,Object? jwtSecretFile = null,Object? authorizeEndpoint = null,}) { return _then(_Settings( socket: freezed == socket ? _self.socket : socket // ignore: cast_nullable_to_non_nullable as String?,serviceDomain: null == serviceDomain ? _self.serviceDomain : serviceDomain // ignore: cast_nullable_to_non_nullable diff --git a/lib/models/settings.g.dart b/lib/models/settings.g.dart index d00bb6f..ed4b6ed 100644 --- a/lib/models/settings.g.dart +++ b/lib/models/settings.g.dart @@ -1,29 +1,29 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of 'settings.dart'; +part of "settings.dart"; // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** _Settings _$SettingsFromJson(Map json) => _Settings( - socket: json['socket'] as String?, - serviceDomain: json['serviceDomain'] as String, - address: json['address'] as String, - port: json['port'] as String, - homeserver: json['homeserver'] as String, - issuer: json['issuer'] as String, - jwtSecretFile: json['jwtSecretFile'] as String, - authorizeEndpoint: json['authorizeEndpoint'] as String, + socket: json["socket"] as String?, + serviceDomain: json["serviceDomain"] as String, + address: json["address"] as String, + port: json["port"] as String, + homeserver: json["homeserver"] as String, + issuer: json["issuer"] as String, + jwtSecretFile: json["jwtSecretFile"] as String, + authorizeEndpoint: json["authorizeEndpoint"] as String, ); Map _$SettingsToJson(_Settings instance) => { - 'socket': instance.socket, - 'serviceDomain': instance.serviceDomain, - 'address': instance.address, - 'port': instance.port, - 'homeserver': instance.homeserver, - 'issuer': instance.issuer, - 'jwtSecretFile': instance.jwtSecretFile, - 'authorizeEndpoint': instance.authorizeEndpoint, + "socket": instance.socket, + "serviceDomain": instance.serviceDomain, + "address": instance.address, + "port": instance.port, + "homeserver": instance.homeserver, + "issuer": instance.issuer, + "jwtSecretFile": instance.jwtSecretFile, + "authorizeEndpoint": instance.authorizeEndpoint, }; From 05e1a4aab1204163a57d8948d85b42aaabb683a9 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Mon, 21 Jul 2025 21:43:04 -0400 Subject: [PATCH 30/45] Add nonce support --- lib/helpers/api_helper.dart | 10 +++++++- lib/models/matrix_user.dart | 1 + lib/models/matrix_user.freezed.dart | 37 ++++++++++++++++------------- lib/models/matrix_user.g.dart | 12 ++++++---- 4 files changed, 37 insertions(+), 23 deletions(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index d0c5ce3..c3fa10e 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -41,7 +41,14 @@ class ApiHelper { ref .read(AuthCodeController.provider.notifier) - .set(code, MatrixUser(userId: userId, matrixToken: accessToken)); + .set( + code, + MatrixUser( + userId: userId, + matrixToken: accessToken, + nonce: data["nonce"], + ), + ); final uri = Uri.parse(redirectUri); @@ -108,6 +115,7 @@ class ApiHelper { 1000, "email": "$name@federated.nexus", "name": name, + "nonce": user.nonce, "iat": DateTime.now().millisecondsSinceEpoch ~/ 1000, }, subject: user.userId, diff --git a/lib/models/matrix_user.dart b/lib/models/matrix_user.dart index 805fb3f..d763865 100644 --- a/lib/models/matrix_user.dart +++ b/lib/models/matrix_user.dart @@ -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 json) => diff --git a/lib/models/matrix_user.freezed.dart b/lib/models/matrix_user.freezed.dart index 94504e8..e9eaf24 100644 --- a/lib/models/matrix_user.freezed.dart +++ b/lib/models/matrix_user.freezed.dart @@ -4,7 +4,7 @@ // ignore_for_file: type=lint // ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target, unnecessary_question_mark -part of "matrix_user.dart"; +part of 'matrix_user.dart'; // ************************************************************************** // FreezedGenerator @@ -16,11 +16,11 @@ T _$identity(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) -@pragma("vm:prefer-inline") +@pragma('vm:prefer-inline') $MatrixUserCopyWith get copyWith => _$MatrixUserCopyWithImpl(this as MatrixUser, _$identity); /// Serializes this MatrixUser to a JSON map. @@ -29,16 +29,16 @@ $MatrixUserCopyWith get copyWith => _$MatrixUserCopyWithImpl 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,11 +66,12 @@ 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 = freezed,}) { 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, +as String,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable +as String?, )); } @@ -81,16 +82,17 @@ 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 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. @override @JsonKey(includeFromJson: false, includeToJson: false) -@pragma("vm:prefer-inline") +@pragma('vm:prefer-inline') _$MatrixUserCopyWith<_MatrixUser> get copyWith => __$MatrixUserCopyWithImpl<_MatrixUser>(this, _$identity); @override @@ -100,16 +102,16 @@ Map 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,11 +139,12 @@ 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 = freezed,}) { 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, +as String,nonce: freezed == nonce ? _self.nonce : nonce // ignore: cast_nullable_to_non_nullable +as String?, )); } diff --git a/lib/models/matrix_user.g.dart b/lib/models/matrix_user.g.dart index 95e855f..d9f38c8 100644 --- a/lib/models/matrix_user.g.dart +++ b/lib/models/matrix_user.g.dart @@ -1,18 +1,20 @@ // GENERATED CODE - DO NOT MODIFY BY HAND -part of "matrix_user.dart"; +part of 'matrix_user.dart'; // ************************************************************************** // JsonSerializableGenerator // ************************************************************************** _MatrixUser _$MatrixUserFromJson(Map json) => _MatrixUser( - userId: json["userId"] as String, - matrixToken: json["matrixToken"] as String, + userId: json['userId'] as String, + matrixToken: json['matrixToken'] as String, + nonce: json['nonce'] as String?, ); Map _$MatrixUserToJson(_MatrixUser instance) => { - "userId": instance.userId, - "matrixToken": instance.matrixToken, + 'userId': instance.userId, + 'matrixToken': instance.matrixToken, + 'nonce': instance.nonce, }; From c7a014f0b39c4d2bf91c93479bd945b5f19aee12 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Tue, 22 Jul 2025 10:30:15 -0400 Subject: [PATCH 31/45] add nonce --- lib/helpers/api_helper.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index c3fa10e..d52d5cd 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -54,7 +54,12 @@ class ApiHelper { return Response.found( uri.replace( - queryParameters: {...uri.queryParameters, "code": code, "state": state}, + queryParameters: { + ...uri.queryParameters, + "code": code, + "state": state, + "nonce": data["nonce"], + }, ), ); } From 444fff5b6264bfb382aaaf1dc58f2a7d7e685392 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Tue, 22 Jul 2025 11:46:38 -0400 Subject: [PATCH 32/45] Add more info to introspection --- lib/helpers/api_helper.dart | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index d52d5cd..bf4b4b5 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -183,8 +183,24 @@ class ApiHelper { ).readAsString()), ), ); + + final jwt = JWT.verify( + token, + SecretKey( + (await File.fromUri( + Uri.file(ref.read(SettingsController.provider)!.jwtSecretFile), + ).readAsString()), + ), + ); + + final name = jwt.issuer!.split(":").first.replaceFirst("@", ""); + return Response.ok( - json.encode({"active": true}), + json.encode({ + "active": true, + "email": "$name@federated.nexus", + "name": name, + }), headers: {"content-type": "application/json"}, ); } catch (_) { From afc555e66ed68fc3055910a8f4314cf1e8843f6b Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Tue, 22 Jul 2025 13:51:10 -0400 Subject: [PATCH 33/45] Fix name --- lib/helpers/api_helper.dart | 5 +++-- lib/helpers/name_helper.dart | 3 +++ 2 files changed, 6 insertions(+), 2 deletions(-) create mode 100644 lib/helpers/name_helper.dart diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index bf4b4b5..b59d73b 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -3,6 +3,7 @@ import "dart:convert"; import "package:dart_jsonwebtoken/dart_jsonwebtoken.dart"; import "package:matrixoidc/controllers/auth_code_controller.dart"; import "package:matrixoidc/controllers/settings_controller.dart"; +import "package:matrixoidc/helpers/name_helper.dart"; import "package:shelf/shelf.dart"; import "package:http/http.dart" as http; import "package:matrixoidc/models/matrix_user.dart"; @@ -111,7 +112,7 @@ class ApiHelper { final user = codes[code]!; ref.read(AuthCodeController.provider.notifier).remove(code); - final name = user.userId.split(":").first.replaceFirst("@", ""); + final name = user.userId.getName(); final jwt = JWT( { @@ -193,7 +194,7 @@ class ApiHelper { ), ); - final name = jwt.issuer!.split(":").first.replaceFirst("@", ""); + final name = jwt.subject!.getName(); return Response.ok( json.encode({ diff --git a/lib/helpers/name_helper.dart b/lib/helpers/name_helper.dart new file mode 100644 index 0000000..79a70d2 --- /dev/null +++ b/lib/helpers/name_helper.dart @@ -0,0 +1,3 @@ +extension GetName on String { + String getName() => split(":")[1].replaceFirst("@", ""); +} From 43f59851b80740a1dc5509eb0790ac665ba1d54a Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Tue, 22 Jul 2025 14:15:13 -0400 Subject: [PATCH 34/45] Some fixes --- .vscode/launch.json | 2 +- JUSTFILE | 2 +- lib/helpers/api_helper.dart | 26 ++++++++++++++++++-------- lib/helpers/name_helper.dart | 2 +- 4 files changed, 21 insertions(+), 11 deletions(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 380f43f..280503b 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -13,7 +13,7 @@ "--jwtSecretFile", "secret", "--issuer", - "http://localhost:8080/", + "http://localhost:8080", "--authorizeEndpoint", "http://localhost:4321/login", "--serviceDomain", diff --git a/JUSTFILE b/JUSTFILE index c2d7582..0a86649 100644 --- a/JUSTFILE +++ b/JUSTFILE @@ -5,4 +5,4 @@ build: dart run build_runner build test: - oauth2c http://localhost:8080 --client-id yourclientid --redirect-url http://localhost:8081/callback --scopes openid --grant-type authorization_code --auth-method none --response-mode query \ No newline at end of file + oauth2c http://localhost:8080 --client-id yourclientid --scopes openid --grant-type authorization_code --auth-method none --response-mode query \ No newline at end of file diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index b59d73b..256dc3d 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -23,7 +23,7 @@ class ApiHelper { final state = data["state"] ?? ""; if (userId == null || accessToken == null || redirectUri == null) { - return Response(400, body: "Missing parameters"); + return Response(400, body: json.encode({"error": "Missing parameters"})); } final settings = ref.read(SettingsController.provider)!; @@ -33,7 +33,9 @@ class ApiHelper { ); if (whoamiRes.statusCode != 200) { - return Response.forbidden("Access token validation failed"); + return Response.forbidden( + json.encode({"error": "Access token validation failed"}), + ); } final code = base64Url.encode( @@ -71,7 +73,10 @@ class ApiHelper { final redirectUri = query["redirect_uri"]; if (code == null || redirectUri == null) { - return Response(400, body: "Missing code or redirect_uri"); + return Response( + 400, + body: json.encode({"error": "Missing code or redirect_uri"}), + ); } final tokenRes = await tokenHandler( @@ -83,7 +88,7 @@ class ApiHelper { ); if (tokenRes.statusCode != 200) { - return Response(400, body: "Token post failed"); + return Response(400, body: json.encode({"error": "Token post failed"})); } return Response.found( @@ -102,12 +107,15 @@ class ApiHelper { final clientId = body["client_id"]; if (code == null || clientId == null) { - return Response(400, body: "Missing code or client_id"); + return Response( + 400, + body: json.encode({"error": "Missing code or client_id"}), + ); } final codes = ref.read(AuthCodeController.provider); if (!codes.containsKey(code)) { - return Response(400, body: "Invalid code"); + return Response(400, body: json.encode({"error": "Invalid code"})); } final user = codes[code]!; @@ -173,7 +181,9 @@ class ApiHelper { Future introspectionHandler(Request request) async { final token = Uri.splitQueryString(await request.readAsString())["token"]; - if (token == null) return Response(400, body: "Missing token"); + if (token == null) { + return Response(400, body: json.encode({"error": "Missing token"})); + } try { JWT.verify( @@ -213,7 +223,7 @@ class ApiHelper { } Future logoutHandler(Request request) async => - Response.ok("Log out is not currently implemented"); + Response.ok(json.encode("Log out is not currently implemented")); Response openidConfiguration(_) { final settings = ref.read(SettingsController.provider)!; diff --git a/lib/helpers/name_helper.dart b/lib/helpers/name_helper.dart index 79a70d2..76c0460 100644 --- a/lib/helpers/name_helper.dart +++ b/lib/helpers/name_helper.dart @@ -1,3 +1,3 @@ extension GetName on String { - String getName() => split(":")[1].replaceFirst("@", ""); + String getName() => split(":").first.replaceFirst("@", ""); } From 55bd5b934b956a88af884522dbfab4a89464af3a Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 25 Jul 2025 12:24:22 -0400 Subject: [PATCH 35/45] rm email --- lib/helpers/api_helper.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 256dc3d..ec2af2a 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -127,7 +127,6 @@ class ApiHelper { "exp": DateTime.now().add(Duration(days: 7)).millisecondsSinceEpoch ~/ 1000, - "email": "$name@federated.nexus", "name": name, "nonce": user.nonce, "iat": DateTime.now().millisecondsSinceEpoch ~/ 1000, @@ -209,7 +208,6 @@ class ApiHelper { return Response.ok( json.encode({ "active": true, - "email": "$name@federated.nexus", "name": name, }), headers: {"content-type": "application/json"}, From 864fcad6315f5611b13ff31e5af106f82c24a245 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 25 Jul 2025 12:24:38 -0400 Subject: [PATCH 36/45] simplify --- lib/helpers/api_helper.dart | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index ec2af2a..2a24140 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -120,14 +120,13 @@ class ApiHelper { final user = codes[code]!; ref.read(AuthCodeController.provider.notifier).remove(code); - final name = user.userId.getName(); final jwt = JWT( { "exp": DateTime.now().add(Duration(days: 7)).millisecondsSinceEpoch ~/ 1000, - "name": name, + "name": user.userId.getName(), "nonce": user.nonce, "iat": DateTime.now().millisecondsSinceEpoch ~/ 1000, }, @@ -203,12 +202,10 @@ class ApiHelper { ), ); - final name = jwt.subject!.getName(); - return Response.ok( json.encode({ "active": true, - "name": name, + "name": jwt.subject!.getName(), }), headers: {"content-type": "application/json"}, ); From 957a6c6c97df642866c039ef586d1c52293ad552 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 25 Jul 2025 19:51:10 -0400 Subject: [PATCH 37/45] Trim files --- lib/controllers/key_controller.dart | 18 ++++++++++++++++ lib/helpers/api_helper.dart | 32 +++++------------------------ 2 files changed, 23 insertions(+), 27 deletions(-) create mode 100644 lib/controllers/key_controller.dart diff --git a/lib/controllers/key_controller.dart b/lib/controllers/key_controller.dart new file mode 100644 index 0000000..f11bdee --- /dev/null +++ b/lib/controllers/key_controller.dart @@ -0,0 +1,18 @@ +import "dart:io"; + +import "package:dart_jsonwebtoken/dart_jsonwebtoken.dart"; +import "package:matrixoidc/controllers/settings_controller.dart"; +import "package:riverpod/riverpod.dart"; + +class KeyController extends AsyncNotifier { + @override + Future build() async => SecretKey( + (await File.fromUri( + Uri.file(ref.read(SettingsController.provider)!.jwtSecretFile), + ).readAsString()).trim(), + ); + + static final provider = AsyncNotifierProvider( + KeyController.new, + ); +} diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 2a24140..787adb7 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -1,7 +1,7 @@ -import "dart:io"; import "dart:convert"; import "package:dart_jsonwebtoken/dart_jsonwebtoken.dart"; import "package:matrixoidc/controllers/auth_code_controller.dart"; +import "package:matrixoidc/controllers/key_controller.dart"; import "package:matrixoidc/controllers/settings_controller.dart"; import "package:matrixoidc/helpers/name_helper.dart"; import "package:shelf/shelf.dart"; @@ -136,9 +136,7 @@ class ApiHelper { ); final token = jwt.sign( - SecretKey( - (await File.fromUri(Uri.file(settings.jwtSecretFile)).readAsString()), - ), + await ref.read(KeyController.provider.future), algorithm: JWTAlgorithm.HS256, ); @@ -162,11 +160,7 @@ class ApiHelper { final token = auth.substring(7); final jwt = JWT.verify( token, - SecretKey( - (await File.fromUri( - Uri.file(ref.read(SettingsController.provider)!.jwtSecretFile), - ).readAsString()), - ), + await ref.read(KeyController.provider.future), ); return Response.ok( jsonEncode({"sub": jwt.subject}), @@ -184,29 +178,13 @@ class ApiHelper { } try { - JWT.verify( - token, - SecretKey( - (await File.fromUri( - Uri.file(ref.read(SettingsController.provider)!.jwtSecretFile), - ).readAsString()), - ), - ); - final jwt = JWT.verify( token, - SecretKey( - (await File.fromUri( - Uri.file(ref.read(SettingsController.provider)!.jwtSecretFile), - ).readAsString()), - ), + await ref.read(KeyController.provider.future), ); return Response.ok( - json.encode({ - "active": true, - "name": jwt.subject!.getName(), - }), + json.encode({"active": true, "name": jwt.subject!.getName()}), headers: {"content-type": "application/json"}, ); } catch (_) { From a86c8e2b26a6d12eaf6fd74f79111a08fc2768d6 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sat, 26 Jul 2025 10:08:10 -0400 Subject: [PATCH 38/45] Add name to userinfo --- lib/helpers/api_helper.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 787adb7..805e158 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -163,7 +163,7 @@ class ApiHelper { await ref.read(KeyController.provider.future), ); return Response.ok( - jsonEncode({"sub": jwt.subject}), + jsonEncode({"sub": jwt.subject, "name": jwt.subject!.getName()}), headers: {"Content-Type": "application/json"}, ); } catch (e) { @@ -207,7 +207,7 @@ class ApiHelper { "token_endpoint": "${settings.issuer}/token", "userinfo_endpoint": "${settings.issuer}/userinfo", "introspection_endpoint": "${settings.issuer}/introspect", - "end_session_endpoint": "${settings.issuer}/logout", + "end_session_endpoint": "#", "response_types_supported": ["code"], "subject_types_supported": ["public"], "id_token_signing_alg_values_supported": ["HS256"], From 644d065ec916be0213c2ef656d9c82da6d29bbfd Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 27 Jul 2025 15:13:17 -0400 Subject: [PATCH 39/45] Add fake name fields --- lib/helpers/api_helper.dart | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 805e158..e8652b4 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -162,8 +162,15 @@ class ApiHelper { token, await ref.read(KeyController.provider.future), ); + + final name = jwt.subject!.getName(); return Response.ok( - jsonEncode({"sub": jwt.subject, "name": jwt.subject!.getName()}), + jsonEncode({ + "sub": jwt.subject, + "name": name, + "first_name": name, + "last_name": "", + }), headers: {"Content-Type": "application/json"}, ); } catch (e) { From 8cb223e8624edae8ea2652e4f5aa7d810e7c1bce Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 27 Jul 2025 15:29:43 -0400 Subject: [PATCH 40/45] Change naming --- bin/matrixoidc.dart | 1 - lib/helpers/api_helper.dart | 25 +++++++++++++++++-------- lib/helpers/name_helper.dart | 3 --- 3 files changed, 17 insertions(+), 12 deletions(-) delete mode 100644 lib/helpers/name_helper.dart diff --git a/bin/matrixoidc.dart b/bin/matrixoidc.dart index 28ba002..1484caf 100644 --- a/bin/matrixoidc.dart +++ b/bin/matrixoidc.dart @@ -36,7 +36,6 @@ void main(List argsRaw) async { ..get("/userinfo", apiHelper.userinfoHandler) ..get("/bridge", apiHelper.bridgeHandler) ..post("/login", apiHelper.loginHandler) - ..post("/introspect", apiHelper.introspectionHandler) ..post("/logout", apiHelper.logoutHandler) ..post("/token", apiHelper.tokenHandler)) .call, diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index e8652b4..67836bf 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -3,7 +3,6 @@ import "package:dart_jsonwebtoken/dart_jsonwebtoken.dart"; import "package:matrixoidc/controllers/auth_code_controller.dart"; import "package:matrixoidc/controllers/key_controller.dart"; import "package:matrixoidc/controllers/settings_controller.dart"; -import "package:matrixoidc/helpers/name_helper.dart"; import "package:shelf/shelf.dart"; import "package:http/http.dart" as http; import "package:matrixoidc/models/matrix_user.dart"; @@ -126,7 +125,6 @@ class ApiHelper { "exp": DateTime.now().add(Duration(days: 7)).millisecondsSinceEpoch ~/ 1000, - "name": user.userId.getName(), "nonce": user.nonce, "iat": DateTime.now().millisecondsSinceEpoch ~/ 1000, }, @@ -163,7 +161,21 @@ class ApiHelper { await ref.read(KeyController.provider.future), ); - final name = jwt.subject!.getName(); + final settings = ref.read(SettingsController.provider)!; + final profile = await http.get( + Uri.parse( + "${settings.homeserver}/_matrix/client/v3/profile/${jwt.subject}", + ), + ); + + if (profile.statusCode != 200) { + return Response.forbidden( + json.encode({"error": "Access token validation failed"}), + ); + } + + final name = json.decode(profile.body)["displayname"]; + return Response.ok( jsonEncode({ "sub": jwt.subject, @@ -185,13 +197,10 @@ class ApiHelper { } try { - final jwt = JWT.verify( - token, - await ref.read(KeyController.provider.future), - ); + JWT.verify(token, await ref.read(KeyController.provider.future)); return Response.ok( - json.encode({"active": true, "name": jwt.subject!.getName()}), + json.encode({"active": true}), headers: {"content-type": "application/json"}, ); } catch (_) { diff --git a/lib/helpers/name_helper.dart b/lib/helpers/name_helper.dart deleted file mode 100644 index 76c0460..0000000 --- a/lib/helpers/name_helper.dart +++ /dev/null @@ -1,3 +0,0 @@ -extension GetName on String { - String getName() => split(":").first.replaceFirst("@", ""); -} From a5c4f900a279868f4d504914b53f27929ddc430c Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 27 Jul 2025 15:53:06 -0400 Subject: [PATCH 41/45] Trim name --- lib/helpers/api_helper.dart | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 67836bf..5ae65bd 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -174,7 +174,8 @@ class ApiHelper { ); } - final name = json.decode(profile.body)["displayname"]; + final fullName = (json.decode(profile.body)["displayname"] as String); + final name = fullName.length <= 20 ? fullName : fullName.substring(0, 20); return Response.ok( jsonEncode({ From 3703c97e09abad1d9860ddd2a51705bf9e45a0d3 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Wed, 30 Jul 2025 12:22:31 -0400 Subject: [PATCH 42/45] Add nickname --- lib/helpers/api_helper.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index 5ae65bd..e2ecdfa 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -183,6 +183,7 @@ class ApiHelper { "name": name, "first_name": name, "last_name": "", + "nickname": name, }), headers: {"Content-Type": "application/json"}, ); From ff95c709614c07e9a549f29ba1c4fcb77fb8fdc5 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Fri, 1 Aug 2025 16:23:56 -0400 Subject: [PATCH 43/45] Change launch name --- .vscode/launch.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.vscode/launch.json b/.vscode/launch.json index 280503b..1c64f63 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -5,7 +5,7 @@ "version": "0.2.0", "configurations": [ { - "name": "matrix-oauth2oidc", + "name": "matrixoidc", "program": "bin/matrixoidc.dart", "args": [ "--homeserver", From a48c2fcd42b1133a5163eb283f6f307f0148fbdc Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Mon, 18 Aug 2025 14:14:30 -0400 Subject: [PATCH 44/45] add max age --- lib/helpers/api_helper.dart | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/helpers/api_helper.dart b/lib/helpers/api_helper.dart index e2ecdfa..fe0dad2 100644 --- a/lib/helpers/api_helper.dart +++ b/lib/helpers/api_helper.dart @@ -94,7 +94,7 @@ class ApiHelper { redirectUri, headers: { "set-cookie": - "id_token=${json.decode(await tokenRes.readAsString())["id_token"]}; Path=/; Secure; HttpOnly; SameSite=Lax; Domain=.${ref.watch(SettingsController.provider)!.serviceDomain}", + "id_token=${json.decode(await tokenRes.readAsString())["id_token"]}; Path=/; Secure; HttpOnly; SameSite=Lax; Domain=.${ref.watch(SettingsController.provider)!.serviceDomain}; Max-Age=604800", }, ); } @@ -183,7 +183,7 @@ class ApiHelper { "name": name, "first_name": name, "last_name": "", - "nickname": name, + "nickname": name, }), headers: {"Content-Type": "application/json"}, ); From 424e9b7b029c6d386fee190cbb3ff2750dfa0a90 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sat, 23 Aug 2025 10:39:30 -0400 Subject: [PATCH 45/45] Always restart --- module.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module.nix b/module.nix index c6dc25c..dd3d9de 100644 --- a/module.nix +++ b/module.nix @@ -67,7 +67,7 @@ in { "~@privileged" "~@resources" ]; - Restart = "on-failure"; + Restart = "aslways"; RestartSec = 5; UMask = 007;