From 23abc091ea09280fda60b2cfcbe59db97775b9d7 Mon Sep 17 00:00:00 2001 From: lifegpc Date: Fri, 2 Feb 2024 13:14:25 +0800 Subject: [PATCH] add login client type --- lib/api/client.dart | 25 +++++ lib/api/client.g.dart | 98 +++++++++++++++++++ lib/api/token.dart | 13 +++ lib/api/token.g.dart | 10 ++ lib/login.dart | 16 ++- lib/platform/device.dart | 1 + lib/platform/device_other.dart | 12 +++ lib/platform/device_web.dart | 17 ++++ macos/Flutter/GeneratedPluginRegistrant.swift | 2 + pubspec.lock | 26 ++++- pubspec.yaml | 2 + web/index.html | 1 + 12 files changed, 221 insertions(+), 2 deletions(-) create mode 100644 lib/platform/device.dart create mode 100644 lib/platform/device_other.dart create mode 100644 lib/platform/device_web.dart diff --git a/lib/api/client.dart b/lib/api/client.dart index 587db5b..02a5ca8 100644 --- a/lib/api/client.dart +++ b/lib/api/client.dart @@ -98,6 +98,23 @@ abstract class _EHApi { // ignore: unused_element @Part(name: "secure") bool? secure, // ignore: unused_element + @Part(name: "client") String? client, + // ignore: unused_element + @Part(name: "device") String? device, + // ignore: unused_element + @Part(name: "client_version") String? clientVersion, + // ignore: unused_element + @Part(name: "client_platform") String? clientPlatform, + // ignore: unused_element + @CancelRequest() CancelToken? cancel}); + @PATCH('/token') + @MultiPart() + Future> updateToken( + {@Part(name: "token") String? token, + @Part(name: "client") String? client, + @Part(name: "device") String? device, + @Part(name: "client_version") String? clientVersion, + @Part(name: "client_platform") String? clientPlatform, @CancelRequest() CancelToken? cancel}); @DELETE('/token') @MultiPart() @@ -210,6 +227,10 @@ class EHApi extends __EHApi { bool? setCookie, bool? httpOnly, bool? secure, + String? client, + String? device, + String? clientVersion, + String? clientPlatform, CancelToken? cancel}) async { int t = DateTime.now().millisecondsSinceEpoch; final p = @@ -224,6 +245,10 @@ class EHApi extends __EHApi { setCookie: setCookie, httpOnly: httpOnly, secure: secure, + client: client, + device: device, + clientVersion: clientVersion, + clientPlatform: clientPlatform, cancel: cancel); } diff --git a/lib/api/client.g.dart b/lib/api/client.g.dart index 43b77b9..18320bd 100644 --- a/lib/api/client.g.dart +++ b/lib/api/client.g.dart @@ -156,6 +156,10 @@ class __EHApi implements _EHApi { bool? setCookie, bool? httpOnly, bool? secure, + String? client, + String? device, + String? clientVersion, + String? clientPlatform, CancelToken? cancel, }) async { const _extra = {}; @@ -193,6 +197,30 @@ class __EHApi implements _EHApi { secure.toString(), )); } + if (client != null) { + _data.fields.add(MapEntry( + 'client', + client, + )); + } + if (device != null) { + _data.fields.add(MapEntry( + 'device', + device, + )); + } + if (clientVersion != null) { + _data.fields.add(MapEntry( + 'client_version', + clientVersion, + )); + } + if (clientPlatform != null) { + _data.fields.add(MapEntry( + 'client_platform', + clientPlatform, + )); + } final _result = await _dio .fetch>(_setStreamType>(Options( method: 'PUT', @@ -219,6 +247,76 @@ class __EHApi implements _EHApi { return value; } + @override + Future> updateToken({ + String? token, + String? client, + String? device, + String? clientVersion, + String? clientPlatform, + CancelToken? cancel, + }) async { + const _extra = {}; + final queryParameters = {}; + queryParameters.removeWhere((k, v) => v == null); + final _headers = {}; + final _data = FormData(); + if (token != null) { + _data.fields.add(MapEntry( + 'token', + token, + )); + } + if (client != null) { + _data.fields.add(MapEntry( + 'client', + client, + )); + } + if (device != null) { + _data.fields.add(MapEntry( + 'device', + device, + )); + } + if (clientVersion != null) { + _data.fields.add(MapEntry( + 'client_version', + clientVersion, + )); + } + if (clientPlatform != null) { + _data.fields.add(MapEntry( + 'client_platform', + clientPlatform, + )); + } + final _result = await _dio + .fetch>(_setStreamType>(Options( + method: 'PATCH', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/token', + queryParameters: queryParameters, + data: _data, + cancelToken: cancel, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final value = ApiResult.fromJson( + _result.data!, + (json) => Token.fromJson(json as Map), + ); + return value; + } + @override Future> deleteToken({ String? token, diff --git a/lib/api/token.dart b/lib/api/token.dart index a13f79e..e393519 100644 --- a/lib/api/token.dart +++ b/lib/api/token.dart @@ -12,6 +12,11 @@ class Token { required this.expired, required this.httpOnly, required this.secure, + required this.lastUsed, + this.client, + this.device, + this.clientVersion, + this.clientPlatform, }); final int id; final int uid; @@ -21,6 +26,14 @@ class Token { @JsonKey(name: 'http_only') final bool httpOnly; final bool secure; + @JsonKey(fromJson: _fromJson, toJson: _toJson, name: 'last_used') + final DateTime lastUsed; + final String? client; + final String? device; + @JsonKey(name: 'client_version') + final String? clientVersion; + @JsonKey(name: 'client_platform') + final String? clientPlatform; static DateTime _fromJson(String d) => DateTime.parse(d); static String _toJson(DateTime d) => d.toIso8601String(); factory Token.fromJson(Map json) => _$TokenFromJson(json); diff --git a/lib/api/token.g.dart b/lib/api/token.g.dart index 24987b7..4bb4265 100644 --- a/lib/api/token.g.dart +++ b/lib/api/token.g.dart @@ -13,6 +13,11 @@ Token _$TokenFromJson(Map json) => Token( expired: Token._fromJson(json['expired'] as String), httpOnly: json['http_only'] as bool, secure: json['secure'] as bool, + lastUsed: Token._fromJson(json['last_used'] as String), + client: json['client'] as String?, + device: json['device'] as String?, + clientVersion: json['client_version'] as String?, + clientPlatform: json['client_platform'] as String?, ); Map _$TokenToJson(Token instance) => { @@ -22,6 +27,11 @@ Map _$TokenToJson(Token instance) => { 'expired': Token._toJson(instance.expired), 'http_only': instance.httpOnly, 'secure': instance.secure, + 'last_used': Token._toJson(instance.lastUsed), + 'client': instance.client, + 'device': instance.device, + 'client_version': instance.clientVersion, + 'client_platform': instance.clientPlatform, }; TokenWithUserInfo _$TokenWithUserInfoFromJson(Map json) => diff --git a/lib/login.dart b/lib/login.dart index 25f20a2..a2c60b4 100644 --- a/lib/login.dart +++ b/lib/login.dart @@ -3,7 +3,9 @@ import 'package:flutter/scheduler.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; import 'package:go_router/go_router.dart'; import 'package:logging/logging.dart'; +import 'package:package_info_plus/package_info_plus.dart'; import 'globals.dart'; +import 'platform/device.dart'; final _log = Logger("LoginPage"); @@ -16,6 +18,14 @@ class LoginPage extends StatefulWidget { State createState() => _LoginPageState(); } +Future get clientVersion async { + try { + return (await PackageInfo.fromPlatform()).version; + } catch (_) { + return null; + } +} + Future login(String username, String password) async { String baseUrl = api.baseUrl!; final u = Uri.parse(baseUrl); @@ -25,7 +35,11 @@ Future login(String username, String password) async { password: password, setCookie: true, httpOnly: true, - secure: u.scheme == 'https'); + secure: u.scheme == 'https', + client: "flutter", + device: device, + clientVersion: await clientVersion, + clientPlatform: clientPlatform); if (re.ok) return true; if (re.status == 4) return false; throw re.unwrapErr(); diff --git a/lib/platform/device.dart b/lib/platform/device.dart new file mode 100644 index 0000000..bf17b73 --- /dev/null +++ b/lib/platform/device.dart @@ -0,0 +1 @@ +export './device_other.dart' if (dart.library.html) './device_web.dart'; diff --git a/lib/platform/device_other.dart b/lib/platform/device_other.dart new file mode 100644 index 0000000..49409ea --- /dev/null +++ b/lib/platform/device_other.dart @@ -0,0 +1,12 @@ +import 'dart:io'; + +String? get device => null; + +String? get clientPlatform { + if (Platform.isAndroid) return "android"; + if (Platform.isIOS) return "ios"; + if (Platform.isLinux) return "linux"; + if (Platform.isMacOS) return "macos"; + if (Platform.isWindows) return "windows"; + return null; +} diff --git a/lib/platform/device_web.dart b/lib/platform/device_web.dart new file mode 100644 index 0000000..fb54513 --- /dev/null +++ b/lib/platform/device_web.dart @@ -0,0 +1,17 @@ +import 'package:ua_parser_js/ua_parser_js.dart'; + +final _uaParser = UAParser(); +String? _device; + +String? get device { + if (_device == null) { + final ua = _uaParser.getResult(); + _device = ua.browser.name; + if (_device != null && _device!.isNotEmpty) { + _device = "$_device ${ua.browser.version}"; + } + } + return _device; +} + +String? get clientPlatform => "web"; diff --git a/macos/Flutter/GeneratedPluginRegistrant.swift b/macos/Flutter/GeneratedPluginRegistrant.swift index 6a5d0a8..21336e7 100644 --- a/macos/Flutter/GeneratedPluginRegistrant.swift +++ b/macos/Flutter/GeneratedPluginRegistrant.swift @@ -8,6 +8,7 @@ import Foundation import cryptography_flutter import device_info_plus import irondash_engine_context +import package_info_plus import path_provider_foundation import screen_retriever import shared_preferences_foundation @@ -18,6 +19,7 @@ func RegisterGeneratedPlugins(registry: FlutterPluginRegistry) { CryptographyFlutterPlugin.register(with: registry.registrar(forPlugin: "CryptographyFlutterPlugin")) DeviceInfoPlusMacosPlugin.register(with: registry.registrar(forPlugin: "DeviceInfoPlusMacosPlugin")) IrondashEngineContextPlugin.register(with: registry.registrar(forPlugin: "IrondashEngineContextPlugin")) + FPPPackageInfoPlusPlugin.register(with: registry.registrar(forPlugin: "FPPPackageInfoPlusPlugin")) PathProviderPlugin.register(with: registry.registrar(forPlugin: "PathProviderPlugin")) ScreenRetrieverPlugin.register(with: registry.registrar(forPlugin: "ScreenRetrieverPlugin")) SharedPreferencesPlugin.register(with: registry.registrar(forPlugin: "SharedPreferencesPlugin")) diff --git a/pubspec.lock b/pubspec.lock index 6053d20..7ee88a7 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -550,6 +550,22 @@ packages: url: "https://pub.dev" source: hosted version: "2.1.0" + package_info_plus: + dependency: "direct main" + description: + name: package_info_plus + sha256: "88bc797f44a94814f2213db1c9bd5badebafdfb8290ca9f78d4b9ee2a3db4d79" + url: "https://pub.dev" + source: hosted + version: "5.0.1" + package_info_plus_platform_interface: + dependency: transitive + description: + name: package_info_plus_platform_interface + sha256: "9bc8ba46813a4cc42c66ab781470711781940780fd8beddd0c3da62506d3a6c6" + url: "https://pub.dev" + source: hosted + version: "2.0.1" palette_generator: dependency: "direct main" description: @@ -915,6 +931,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.2" + ua_parser_js: + dependency: "direct main" + description: + name: ua_parser_js + sha256: "5b0df2978a81800391bd5bf73987b7bb06171556af9fc1ceec02c157c366a212" + url: "https://pub.dev" + source: hosted + version: "1.0.1" universal_io: dependency: transitive description: @@ -1020,5 +1044,5 @@ packages: source: hosted version: "3.1.2" sdks: - dart: ">=3.2.0-194.0.dev <4.0.0" + dart: ">=3.2.0 <4.0.0" flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index c219d56..0fc847d 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -30,6 +30,7 @@ dependencies: json_annotation: ^4.8.1 keymap: ^0.0.92 logging: ^1.2.0 + package_info_plus: ^5.0.1 palette_generator: ^0.3.3+3 path: ^1.8.3 path_provider: ^2.1.0 @@ -38,6 +39,7 @@ dependencies: shared_preferences: ^2.2.0 super_clipboard: ^0.6.4 super_context_menu: ^0.6.4 + ua_parser_js: ^1.0.1 user_agent_analyzer: ^5.0.0 window_manager: ^0.3.6 diff --git a/web/index.html b/web/index.html index c670175..570ba41 100644 --- a/web/index.html +++ b/web/index.html @@ -31,6 +31,7 @@ E-Hentai Downloader Dashboard +