WIP - Provider refactorings

This commit is contained in:
Anton Stubenbord
2022-12-27 00:12:33 +01:00
parent 60aecb549d
commit bf0e186646
53 changed files with 434 additions and 416 deletions

View File

@@ -2,11 +2,7 @@ import 'dart:async';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:paperless_mobile/core/service/connectivity_status.service.dart';
import 'package:injectable/injectable.dart';
@prod
@test
@lazySingleton
class ConnectivityCubit extends Cubit<ConnectivityState> {
final ConnectivityStatusService connectivityStatusService;
StreamSubscription<bool>? _sub;

View File

@@ -2,27 +2,25 @@ import 'dart:developer';
import 'package:flutter/foundation.dart';
import 'package:http_interceptor/http_interceptor.dart';
import 'package:paperless_mobile/core/store/local_vault.dart';
class AuthenticationInterceptor implements InterceptorContract {
final LocalVault _localVault;
AuthenticationInterceptor(this._localVault);
String? serverUrl;
String? token;
AuthenticationInterceptor({this.serverUrl, this.token});
@override
Future<BaseRequest> interceptRequest({required BaseRequest request}) async {
final auth = await _localVault.loadAuthenticationInformation();
if (kDebugMode) {
log("Intercepted ${request.method} request to ${request.url.toString()}");
}
return request.copyWith(
//Append server Url
headers: auth?.token?.isEmpty ?? true
url: Uri.parse((serverUrl ?? '') + request.url.toString()),
headers: token?.isEmpty ?? true
? request.headers
: {
...request.headers,
'Authorization': 'Token ${auth!.token}',
'Authorization': 'Token $token',
},
);
}

View File

@@ -0,0 +1,38 @@
import 'dart:convert';
import 'package:dio/dio.dart';
import 'package:paperless_mobile/core/type/types.dart';
class DioHttpErrorInterceptor implements InterceptorsWrapper {
@override
void onError(DioError e, ErrorInterceptorHandler handler) {
//TODO: Implement and debug how error handling works, or if request has to be resolved.
if (e.response?.statusCode == 400) {
// try to parse contained error message, otherwise return response
final Map<String, dynamic> json = jsonDecode(e.response?.data);
final PaperlessValidationErrors errorMessages = {};
for (final entry in json.entries) {
if (entry.value is List) {
errorMessages.putIfAbsent(
entry.key, () => (entry.value as List).cast<String>().first);
} else if (entry.value is String) {
errorMessages.putIfAbsent(entry.key, () => entry.value);
} else {
errorMessages.putIfAbsent(entry.key, () => entry.value.toString());
}
}
throw errorMessages;
}
handler.next(e);
}
@override
void onRequest(RequestOptions options, RequestInterceptorHandler handler) {
handler.next(options);
}
@override
void onResponse(Response response, ResponseInterceptorHandler handler) {
handler.next(response);
}
}

View File

@@ -12,20 +12,16 @@ class LabelRepositoriesProvider extends StatelessWidget {
return MultiRepositoryProvider(
providers: [
RepositoryProvider(
create: (context) =>
RepositoryProvider.of<LabelRepository<Correspondent>>(context),
create: (context) => context.read<LabelRepository<Correspondent>>(),
),
RepositoryProvider(
create: (context) =>
RepositoryProvider.of<LabelRepository<DocumentType>>(context),
create: (context) => context.read<LabelRepository<DocumentType>>(),
),
RepositoryProvider(
create: (context) =>
RepositoryProvider.of<LabelRepository<StoragePath>>(context),
create: (context) => context.read<LabelRepository<StoragePath>>(),
),
RepositoryProvider(
create: (context) =>
RepositoryProvider.of<LabelRepository<Tag>>(context),
create: (context) => context.read<LabelRepository<Tag>>(),
),
],
child: child,

View File

@@ -0,0 +1,60 @@
import 'dart:async';
import 'dart:io';
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:paperless_mobile/core/interceptor/dio_http_error_interceptor.dart';
import 'package:paperless_mobile/extensions/security_context_extension.dart';
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
///
/// Convenience http client handling timeouts.
///
class AuthenticationAwareDioManager {
final Dio _dio;
/// Some dependencies require an [HttpClient], therefore this is also maintained here.
AuthenticationAwareDioManager() : _dio = _initDio();
Dio get client => _dio;
Stream<SecurityContext> get securityContextChanges =>
_securityContextStreamController.stream.asBroadcastStream();
final StreamController<SecurityContext> _securityContextStreamController =
StreamController.broadcast();
static Dio _initDio() {
//en- and decoded by utf8 by default
final Dio dio = Dio(BaseOptions());
dio.options.receiveTimeout = const Duration(seconds: 25).inMilliseconds;
dio.options.responseType = ResponseType.json;
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) => client..badCertificateCallback = (cert, host, port) => true;
dio.interceptors.add(DioHttpErrorInterceptor());
return dio;
}
void updateSettings({
String? baseUrl,
String? authToken,
ClientCertificate? clientCertificate,
}) {
if (clientCertificate != null) {
final context =
SecurityContext().withClientCertificate(clientCertificate);
(_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) => HttpClient(context: context)
..badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
_securityContextStreamController.add(context);
}
if (baseUrl != null) {
_dio.options.baseUrl = baseUrl;
}
if (authToken != null) {
_dio.options.headers.addAll({'Authorization': 'Token $authToken'});
}
}
}

View File

@@ -1,100 +0,0 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:paperless_mobile/core/type/types.dart';
import 'package:paperless_mobile/features/login/model/client_certificate.dart';
///
/// Convenience http client handling timeouts.
///
class SecurityContextAwareDioManager {
final Dio _dio;
// Some dependencies require an [HttpClient], therefore this is also maintained here.
final HttpClient _httpClient;
SecurityContextAwareDioManager()
: _dio = _initDio(),
_httpClient = HttpClient();
Dio get client => _dio;
Stream<SecurityContext> get securityContextChanges =>
_securityContextStreamController.stream.asBroadcastStream();
final StreamController<SecurityContext> _securityContextStreamController =
StreamController.broadcast();
static Dio _initDio() {
//en- and decoded by utf8 by default
final Dio dio = Dio(BaseOptions());
dio.options.receiveTimeout = const Duration(seconds: 25).inMilliseconds;
dio.options.responseType = ResponseType.json;
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) => client
..badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
dio.interceptors.add(
//TODO: Refactor, create own class...
InterceptorsWrapper(
onError: (e, handler) {
//TODO: Implement and debug how error handling works, or if request has to be resolved.
if (e.response?.statusCode == 400) {
// try to parse contained error message, otherwise return response
final JSON json = jsonDecode(e.response?.data);
final PaperlessValidationErrors errorMessages = {};
for (final entry in json.entries) {
if (entry.value is List) {
errorMessages.putIfAbsent(entry.key,
() => (entry.value as List).cast<String>().first);
} else if (entry.value is String) {
errorMessages.putIfAbsent(entry.key, () => entry.value);
} else {
errorMessages.putIfAbsent(
entry.key, () => entry.value.toString());
}
}
throw errorMessages;
}
handler.next(e);
},
),
);
return dio;
}
void updateSettings({
String? baseUrl,
String? authToken,
ClientCertificate? clientCertificate,
}) {
if (clientCertificate != null) {
final sc = SecurityContext()
..usePrivateKeyBytes(
clientCertificate.bytes,
password: clientCertificate.passphrase,
)
..useCertificateChainBytes(
clientCertificate.bytes,
password: clientCertificate.passphrase,
)
..setTrustedCertificatesBytes(
clientCertificate.bytes,
password: clientCertificate.passphrase,
);
(_dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(client) => HttpClient(
context: sc,
)..badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
_securityContextStreamController.add(sc);
}
if (baseUrl != null) {
_dio.options.baseUrl = baseUrl;
}
if (authToken != null) {
_dio.options.headers.addAll({'Authorization': 'Token $authToken'});
}
}
}