Browse Source

Merge pull request #127 from provokateurin/feature/cookie-jar

dynamite,nextcloud,neon: Implement CookieJar
pull/130/head
Kate 2 years ago committed by GitHub
parent
commit
4d046a918a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 88
      packages/dynamite/lib/src/openapi_builder.dart
  2. 4
      packages/neon/integration_test/screenshot_test.dart
  3. 4
      packages/neon/lib/main.dart
  4. 2
      packages/neon/lib/src/apps/files/app.dart
  5. 2
      packages/neon/lib/src/apps/news/app.dart
  6. 2
      packages/neon/lib/src/apps/notes/app.dart
  7. 2
      packages/neon/lib/src/apps/notifications/app.dart
  8. 4
      packages/neon/lib/src/blocs/accounts.dart
  9. 2
      packages/neon/lib/src/blocs/push_notifications.dart
  10. 2
      packages/neon/lib/src/utils/account_options.dart
  11. 4
      packages/neon/lib/src/utils/app_implementation.dart
  12. 2
      packages/neon/lib/src/utils/global_options.dart
  13. 2
      packages/neon/lib/src/utils/nextcloud_app_specific_options.dart
  14. 4
      packages/neon/lib/src/utils/push_utils.dart
  15. 4
      packages/neon/lib/src/utils/storage.dart
  16. 7
      packages/neon/pubspec.lock
  17. 44
      packages/nextcloud/lib/src/nextcloud.openapi.dart
  18. 2
      packages/nextcloud/pubspec.yaml

88
packages/dynamite/lib/src/openapi_builder.dart

@ -34,13 +34,45 @@ class OpenAPIBuilder implements Builder {
final registeredJsonObjects = <String>[];
final output = <String>[
"import 'dart:convert';",
"import 'dart:io';",
"import 'dart:typed_data';",
'',
"import 'package:http/http.dart' as http;",
"import 'package:cookie_jar/cookie_jar.dart';",
"import 'package:json_annotation/json_annotation.dart';",
'',
"export 'package:cookie_jar/cookie_jar.dart';",
'',
"part '${p.basename(outputId.changeExtension('.g.dart').path)}';",
'',
Extension(
(final b) => b
..name = 'HttpClientResponseBody'
..on = refer('HttpClientResponse')
..methods.addAll([
Method(
(final b) => b
..name = 'bodyBytes'
..returns = refer('Future<Uint8List>')
..type = MethodType.getter
..modifier = MethodModifier.async
..lambda = true
..body = const Code(
'Uint8List.fromList((await toList()).reduce((final value, final element) => [...value, ...element]))',
),
),
Method(
(final b) => b
..name = 'body'
..returns = refer('Future<String>')
..type = MethodType.getter
..modifier = MethodModifier.async
..lambda = true
..body = const Code(
'utf8.decode(await bodyBytes)',
),
),
]),
).accept(emitter).toString(),
Class(
(final b) => b
..name = 'Response'
@ -707,6 +739,19 @@ class OpenAPIBuilder implements Builder {
..modifier = FieldModifier.final$
..late = true,
),
Field(
(final b) => b
..name = 'httpClient'
..type = refer('HttpClient')
..modifier = FieldModifier.final$
..late = true,
),
Field(
(final b) => b
..name = 'cookieJar'
..type = refer('CookieJar?')
..modifier = FieldModifier.final$,
),
if (hasAnySecurity) ...[
Field(
(final b) => b
@ -733,6 +778,18 @@ class OpenAPIBuilder implements Builder {
..type = refer('Map<String, String>?')
..named = true,
),
Parameter(
(final b) => b
..name = 'httpClient'
..type = refer('HttpClient?')
..named = true,
),
Parameter(
(final b) => b
..name = 'cookieJar'
..toThis = true
..named = true,
),
if (hasAnySecurity) ...[
Parameter(
(final b) => b
@ -753,6 +810,7 @@ class OpenAPIBuilder implements Builder {
},
''' : ''}
};
this.httpClient = httpClient ?? HttpClient();
'''),
),
)
@ -797,18 +855,30 @@ class OpenAPIBuilder implements Builder {
),
])
..body = const Code(r'''
final request = http.Request(method, Uri.parse('$baseURL$path'));
request.headers.addAll(baseHeaders);
request.headers.addAll(headers);
final uri = Uri.parse('$baseURL$path');
final request = await httpClient.openUrl(method, uri);
for (final header in {...baseHeaders, ...headers}.entries) {
request.headers.add(header.key, header.value);
}
if (body != null) {
request.bodyBytes = body.toList();
request.add(body.toList());
}
if (cookieJar != null) {
request.cookies.addAll(await cookieJar!.loadForRequest(uri));
}
final response = await request.close();
if (cookieJar != null) {
await cookieJar!.saveFromResponse(uri, response.cookies);
}
final response = await http.Response.fromStream(await request.send());
final responseHeaders = <String, String>{};
response.headers.forEach((final name, final values) {
responseHeaders[name] = values.last;
});
return Response(
response.statusCode,
response.headers,
response.bodyBytes,
responseHeaders,
await response.bodyBytes,
);
'''),
),

4
packages/neon/integration_test/screenshot_test.dart

@ -108,7 +108,7 @@ Future pumpAppPage(
final allAppImplementations = getAppImplementations(sharedPreferences, requestManager, platform);
final globalOptions = GlobalOptions(
Storage('global', sharedPreferences),
AppStorage('global', sharedPreferences),
packageInfo,
);
await globalOptions.pushNotificationsEnabled.set(false);
@ -116,7 +116,7 @@ Future pumpAppPage(
final accountsBloc = AccountsBloc(
requestManager,
platform,
Storage('accounts', sharedPreferences),
AppStorage('accounts', sharedPreferences),
sharedPreferences,
globalOptions,
packageInfo,

4
packages/neon/lib/main.dart

@ -36,14 +36,14 @@ Future main() async {
final packageInfo = await PackageInfo.fromPlatform();
final globalOptions = GlobalOptions(
Storage('global', sharedPreferences),
AppStorage('global', sharedPreferences),
packageInfo,
);
final accountsBloc = AccountsBloc(
requestManager,
platform,
Storage('accounts', sharedPreferences),
AppStorage('accounts', sharedPreferences),
sharedPreferences,
globalOptions,
packageInfo,

2
packages/neon/lib/src/apps/files/app.dart

@ -48,7 +48,7 @@ class FilesApp extends AppImplementation<FilesBloc, FilesAppSpecificOptions> {
String nameFromLocalization(final AppLocalizations localizations) => localizations.filesName;
@override
FilesAppSpecificOptions buildOptions(final Storage storage) => FilesAppSpecificOptions(storage);
FilesAppSpecificOptions buildOptions(final AppStorage storage) => FilesAppSpecificOptions(storage);
@override
FilesBloc buildBloc(final NextcloudClient client) => FilesBloc(

2
packages/neon/lib/src/apps/news/app.dart

@ -56,7 +56,7 @@ class NewsApp extends AppImplementation<NewsBloc, NewsAppSpecificOptions> {
String nameFromLocalization(final AppLocalizations localizations) => localizations.newsName;
@override
NewsAppSpecificOptions buildOptions(final Storage storage) => NewsAppSpecificOptions(storage, platform);
NewsAppSpecificOptions buildOptions(final AppStorage storage) => NewsAppSpecificOptions(storage, platform);
@override
NewsBloc buildBloc(final NextcloudClient client) => NewsBloc(

2
packages/neon/lib/src/apps/notes/app.dart

@ -45,7 +45,7 @@ class NotesApp extends AppImplementation<NotesBloc, NotesAppSpecificOptions> {
String nameFromLocalization(final AppLocalizations localizations) => localizations.notesName;
@override
NotesAppSpecificOptions buildOptions(final Storage storage) => NotesAppSpecificOptions(storage);
NotesAppSpecificOptions buildOptions(final AppStorage storage) => NotesAppSpecificOptions(storage);
@override
NotesBloc buildBloc(final NextcloudClient client) => NotesBloc(

2
packages/neon/lib/src/apps/notifications/app.dart

@ -25,7 +25,7 @@ class NotificationsApp extends AppImplementation<NotificationsBloc, Notification
String nameFromLocalization(final AppLocalizations localizations) => localizations.notificationsName;
@override
NotificationsAppSpecificOptions buildOptions(final Storage storage) => NotificationsAppSpecificOptions(storage);
NotificationsAppSpecificOptions buildOptions(final AppStorage storage) => NotificationsAppSpecificOptions(storage);
@override
NotificationsBloc buildBloc(final NextcloudClient client) => NotificationsBloc(

4
packages/neon/lib/src/blocs/accounts.dart

@ -123,7 +123,7 @@ class AccountsBloc extends $AccountsBloc {
}
AccountSpecificOptions getOptions(final Account account) => _accountsOptions[account.id] ??= AccountSpecificOptions(
Storage('accounts-${account.id}', _sharedPreferences),
AppStorage('accounts-${account.id}', _sharedPreferences),
getAppsBloc(account),
);
@ -177,7 +177,7 @@ class AccountsBloc extends $AccountsBloc {
final RequestManager _requestManager;
final NeonPlatform _platform;
final Storage _storage;
final AppStorage _storage;
final SharedPreferences _sharedPreferences;
final GlobalOptions _globalOptions;
final List<AppImplementation> _allAppImplementations;

2
packages/neon/lib/src/blocs/push_notifications.dart

@ -126,7 +126,7 @@ class PushNotificationsBloc extends $PushNotificationsBloc {
final AccountsBloc _accountsBloc;
final NeonPlatform _platform;
final SharedPreferences _sharedPreferences;
late final _storage = Storage('notifications', _sharedPreferences);
late final _storage = AppStorage('notifications', _sharedPreferences);
final GlobalOptions _globalOptions;
final Env? _env;
RSAKeypair? _keypair;

2
packages/neon/lib/src/utils/account_options.dart

@ -17,7 +17,7 @@ class AccountSpecificOptions {
});
}
final Storage _storage;
final AppStorage _storage;
final AppsBloc _appsBloc;
final _appIDsSubject = BehaviorSubject<Map<String?, LabelBuilder>>();

4
packages/neon/lib/src/utils/app_implementation.dart

@ -18,7 +18,7 @@ abstract class AppImplementation<T extends RxBlocBase, R extends NextcloudAppSpe
this.requestManager,
this.platform,
) {
final storage = Storage('app-$id', sharedPreferences);
final storage = AppStorage('app-$id', sharedPreferences);
options = buildOptions(storage);
}
@ -30,7 +30,7 @@ abstract class AppImplementation<T extends RxBlocBase, R extends NextcloudAppSpe
String name(final BuildContext context) => nameFromLocalization(AppLocalizations.of(context));
late final R options;
R buildOptions(final Storage storage);
R buildOptions(final AppStorage storage);
T buildBloc(final NextcloudClient client);

2
packages/neon/lib/src/utils/global_options.dart

@ -35,7 +35,7 @@ class GlobalOptions {
});
}
final Storage _storage;
final AppStorage _storage;
final PackageInfo _packageInfo;
final _themeOLEDAsDarkEnabledSubject = BehaviorSubject<bool>();
final _pushNotificationsEnabledEnabledSubject = BehaviorSubject<bool>();

2
packages/neon/lib/src/utils/nextcloud_app_specific_options.dart

@ -3,7 +3,7 @@ part of '../neon.dart';
abstract class NextcloudAppSpecificOptions {
NextcloudAppSpecificOptions(this.storage);
final Storage storage;
final AppStorage storage;
late final List<OptionsCategory> categories;
late final List<Option> options;

4
packages/neon/lib/src/utils/push_utils.dart

@ -1,7 +1,7 @@
part of '../neon.dart';
class PushUtils {
static Future<RSAKeypair> loadRSAKeypair(final Storage storage) async {
static Future<RSAKeypair> loadRSAKeypair(final AppStorage storage) async {
const keyDevicePrivateKey = 'device-private-key';
late RSAKeypair keypair;
@ -51,7 +51,7 @@ class PushUtils {
);
final sharedPreferences = await SharedPreferences.getInstance();
final keypair = await loadRSAKeypair(Storage('notifications', sharedPreferences));
final keypair = await loadRSAKeypair(AppStorage('notifications', sharedPreferences));
final data = json.decode(utf8.decode(message)) as Map<String, dynamic>;
final notification = NotificationsPushNotification(
accountID: instance,

4
packages/neon/lib/src/utils/storage.dart

@ -1,7 +1,7 @@
part of '../neon.dart';
class Storage extends SettingsStorage {
Storage(
class AppStorage extends SettingsStorage {
AppStorage(
this._id,
this._sharedPreferences,
);

7
packages/neon/pubspec.lock

@ -148,6 +148,13 @@ packages:
url: "https://pub.dartlang.org"
source: hosted
version: "3.1.1"
cookie_jar:
dependency: transitive
description:
name: cookie_jar
url: "https://pub.dartlang.org"
source: hosted
version: "3.0.1"
cross_file:
dependency: transitive
description:

44
packages/nextcloud/lib/src/nextcloud.openapi.dart

@ -1,11 +1,20 @@
import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';
import 'package:http/http.dart' as http;
import 'package:cookie_jar/cookie_jar.dart';
import 'package:json_annotation/json_annotation.dart';
export 'package:cookie_jar/cookie_jar.dart';
part 'nextcloud.openapi.g.dart';
extension HttpClientResponseBody on HttpClientResponse {
Future<Uint8List> get bodyBytes async =>
Uint8List.fromList((await toList()).reduce((final value, final element) => [...value, ...element]));
Future<String> get body async => utf8.decode(await bodyBytes);
}
class Response {
Response(
this.statusCode,
@ -64,6 +73,8 @@ class Client {
Client(
this.baseURL, {
Map<String, String>? baseHeaders,
HttpClient? httpClient,
this.cookieJar,
this.authentication,
}) {
this.baseHeaders = {
@ -74,12 +85,17 @@ class Client {
...authentication!.headers,
},
};
this.httpClient = httpClient ?? HttpClient();
}
final String baseURL;
late final Map<String, String> baseHeaders;
late final HttpClient httpClient;
final CookieJar? cookieJar;
final Authentication? authentication;
CoreClient get core => CoreClient(this);
@ -94,18 +110,30 @@ class Client {
Map<String, String> headers,
Uint8List? body,
) async {
final request = http.Request(method, Uri.parse('$baseURL$path'));
request.headers.addAll(baseHeaders);
request.headers.addAll(headers);
final uri = Uri.parse('$baseURL$path');
final request = await httpClient.openUrl(method, uri);
for (final header in {...baseHeaders, ...headers}.entries) {
request.headers.add(header.key, header.value);
}
if (body != null) {
request.bodyBytes = body.toList();
request.add(body.toList());
}
if (cookieJar != null) {
request.cookies.addAll(await cookieJar!.loadForRequest(uri));
}
final response = await http.Response.fromStream(await request.send());
final response = await request.close();
if (cookieJar != null) {
await cookieJar!.saveFromResponse(uri, response.cookies);
}
final responseHeaders = <String, String>{};
response.headers.forEach((final name, final values) {
responseHeaders[name] = values.last;
});
return Response(
response.statusCode,
response.headers,
response.bodyBytes,
responseHeaders,
await response.bodyBytes,
);
}
}

2
packages/nextcloud/pubspec.yaml

@ -5,9 +5,9 @@ environment:
sdk: '>=2.18.0 <3.0.0'
dependencies:
cookie_jar: ^3.0.1
crypto: ^3.0.1
crypton: ^2.0.5
http: ^0.13.4
intl: ^0.17.0
json_annotation: ^4.7.0
meta: ^1.7.0

Loading…
Cancel
Save