mirror of
https://github.com/lifegpc/eh_downloader_flutter.git
synced 2026-07-08 01:30:28 +08:00
Update
This commit is contained in:
@@ -1,19 +1,75 @@
|
||||
import 'dart:convert';
|
||||
import 'package:cryptography/cryptography.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:retrofit/retrofit.dart';
|
||||
import 'api_result.dart';
|
||||
import 'status.dart';
|
||||
import 'token.dart';
|
||||
import 'user.dart';
|
||||
|
||||
part 'client.g.dart';
|
||||
|
||||
@RestApi(parser: Parser.FlutterCompute)
|
||||
final _pbkdf2a = Pbkdf2(
|
||||
macAlgorithm: Hmac.sha512(),
|
||||
iterations: 210000,
|
||||
bits: 512,
|
||||
);
|
||||
|
||||
final _pbkdf2b = Pbkdf2(
|
||||
macAlgorithm: Hmac.sha512(),
|
||||
iterations: 1000,
|
||||
bits: 512,
|
||||
);
|
||||
|
||||
const _utf8Encoder = Utf8Encoder();
|
||||
final _salt = _utf8Encoder.convert("eh-downloader-salt");
|
||||
|
||||
@RestApi()
|
||||
abstract class EHApi {
|
||||
factory EHApi(Dio dio, {String baseUrl}) = _EHApi;
|
||||
|
||||
@PUT('/user')
|
||||
Future<ApiResult<int>> createUser(
|
||||
@Query("name") String name, @Query("password") String password,
|
||||
{@Query("is_admin") bool? isAdmin,
|
||||
@Query("permissions") int? permissions});
|
||||
@GET('/user')
|
||||
Future<ApiResult<BUser>> getUser();
|
||||
@GET('/user')
|
||||
Future<ApiResult<BUser>> getUserById(@Query("id") int id);
|
||||
@GET('/user')
|
||||
Future<ApiResult<BUser>> getUserByUsername(
|
||||
@Query("username") String username);
|
||||
Future<ApiResult<BUser>> getUser(
|
||||
{@Query("id") int? id, @Query("username") String? username});
|
||||
|
||||
@GET('/status')
|
||||
Future<ApiResult<ServerStatus>> getStatus();
|
||||
|
||||
@PUT('/token')
|
||||
Future<ApiResult<Token>> _createToken(
|
||||
{@Query("username") String username,
|
||||
@Query("password") String password,
|
||||
@Query("t") int t,
|
||||
@Query("set_cookie") bool? setCookie,
|
||||
@Query("http_only") bool? httpOnly,
|
||||
@Query("secure") bool? secure});
|
||||
Future<ApiResult<Token>> createToken(
|
||||
{required String username,
|
||||
required String password,
|
||||
bool? setCookie,
|
||||
bool? httpOnly,
|
||||
bool? secure}) async {
|
||||
int t = DateTime.now().millisecondsSinceEpoch;
|
||||
final p =
|
||||
await _pbkdf2a.deriveKeyFromPassword(password: password, nonce: _salt);
|
||||
final p2 = await _pbkdf2b.deriveKey(
|
||||
secretKey: p, nonce: _utf8Encoder.convert(t.toString()));
|
||||
final p3 = base64Encode(await p2.extractBytes());
|
||||
return await _createToken(
|
||||
username: username,
|
||||
password: p3,
|
||||
t: t,
|
||||
setCookie: setCookie,
|
||||
httpOnly: httpOnly,
|
||||
secure: secure);
|
||||
}
|
||||
@DELETE('/token')
|
||||
Future<ApiResult<bool>> deleteToken({@Query("token") String? token});
|
||||
@GET('/token')
|
||||
Future<ApiResult<Token>> getToken({@Query("token") String? token});
|
||||
}
|
||||
|
||||
@@ -19,20 +19,98 @@ class _EHApi implements EHApi {
|
||||
String? baseUrl;
|
||||
|
||||
@override
|
||||
Future<ApiResult<BUser>> getUser() async {
|
||||
Future<ApiResult<int>> createUser(
|
||||
String name,
|
||||
String password, {
|
||||
bool? isAdmin,
|
||||
int? permissions,
|
||||
}) async {
|
||||
const _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{
|
||||
r'name': name,
|
||||
r'password': password,
|
||||
r'is_admin': isAdmin,
|
||||
r'permissions': permissions,
|
||||
};
|
||||
queryParameters.removeWhere((k, v) => v == null);
|
||||
final _headers = <String, dynamic>{};
|
||||
final Map<String, dynamic>? _data = null;
|
||||
final _result = await _dio
|
||||
.fetch<Map<String, dynamic>>(_setStreamType<ApiResult<int>>(Options(
|
||||
method: 'PUT',
|
||||
headers: _headers,
|
||||
extra: _extra,
|
||||
)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/user',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(
|
||||
baseUrl: _combineBaseUrls(
|
||||
_dio.options.baseUrl,
|
||||
baseUrl,
|
||||
))));
|
||||
final value = ApiResult<int>.fromJson(
|
||||
_result.data!,
|
||||
(json) => json as int,
|
||||
);
|
||||
return value;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ApiResult<BUser>> getUser({
|
||||
int? id,
|
||||
String? username,
|
||||
}) async {
|
||||
const _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{
|
||||
r'id': id,
|
||||
r'username': username,
|
||||
};
|
||||
queryParameters.removeWhere((k, v) => v == null);
|
||||
final _headers = <String, dynamic>{};
|
||||
final Map<String, dynamic>? _data = null;
|
||||
final _result = await _dio
|
||||
.fetch<Map<String, dynamic>>(_setStreamType<ApiResult<BUser>>(Options(
|
||||
method: 'GET',
|
||||
headers: _headers,
|
||||
extra: _extra,
|
||||
)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/user',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(
|
||||
baseUrl: _combineBaseUrls(
|
||||
_dio.options.baseUrl,
|
||||
baseUrl,
|
||||
))));
|
||||
final value = ApiResult<BUser>.fromJson(
|
||||
_result.data!,
|
||||
(json) => BUser.fromJson(json as Map<String, dynamic>),
|
||||
);
|
||||
return value;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ApiResult<ServerStatus>> getStatus() async {
|
||||
const _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{};
|
||||
final _headers = <String, dynamic>{};
|
||||
final Map<String, dynamic>? _data = null;
|
||||
final _result = await _dio
|
||||
.fetch<Map<String, dynamic>>(_setStreamType<ApiResult<BUser>>(Options(
|
||||
final _result = await _dio.fetch<Map<String, dynamic>>(
|
||||
_setStreamType<ApiResult<ServerStatus>>(Options(
|
||||
method: 'GET',
|
||||
headers: _headers,
|
||||
extra: _extra,
|
||||
)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/user',
|
||||
'/status',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
@@ -41,25 +119,43 @@ class _EHApi implements EHApi {
|
||||
_dio.options.baseUrl,
|
||||
baseUrl,
|
||||
))));
|
||||
final value = await compute(deserializeApiResult<BUser>, _result.data!);
|
||||
final value = ApiResult<ServerStatus>.fromJson(
|
||||
_result.data!,
|
||||
(json) => ServerStatus.fromJson(json as Map<String, dynamic>),
|
||||
);
|
||||
return value;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ApiResult<BUser>> getUserById(int id) async {
|
||||
Future<ApiResult<Token>> _createToken({
|
||||
required String username,
|
||||
required String password,
|
||||
required int t,
|
||||
bool? setCookie,
|
||||
bool? httpOnly,
|
||||
bool? secure,
|
||||
}) async {
|
||||
const _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{r'id': id};
|
||||
final queryParameters = <String, dynamic>{
|
||||
r'username': username,
|
||||
r'password': password,
|
||||
r't': t,
|
||||
r'set_cookie': setCookie,
|
||||
r'http_only': httpOnly,
|
||||
r'secure': secure,
|
||||
};
|
||||
queryParameters.removeWhere((k, v) => v == null);
|
||||
final _headers = <String, dynamic>{};
|
||||
final Map<String, dynamic>? _data = null;
|
||||
final _result = await _dio
|
||||
.fetch<Map<String, dynamic>>(_setStreamType<ApiResult<BUser>>(Options(
|
||||
method: 'GET',
|
||||
.fetch<Map<String, dynamic>>(_setStreamType<ApiResult<Token>>(Options(
|
||||
method: 'PUT',
|
||||
headers: _headers,
|
||||
extra: _extra,
|
||||
)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/user',
|
||||
'/token',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
@@ -68,25 +164,29 @@ class _EHApi implements EHApi {
|
||||
_dio.options.baseUrl,
|
||||
baseUrl,
|
||||
))));
|
||||
final value = await compute(deserializeApiResult<BUser>, _result.data!);
|
||||
final value = ApiResult<Token>.fromJson(
|
||||
_result.data!,
|
||||
(json) => Token.fromJson(json as Map<String, dynamic>),
|
||||
);
|
||||
return value;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ApiResult<BUser>> getUserByUsername(String username) async {
|
||||
Future<ApiResult<bool>> deleteToken({String? token}) async {
|
||||
const _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{r'username': username};
|
||||
final queryParameters = <String, dynamic>{r'token': token};
|
||||
queryParameters.removeWhere((k, v) => v == null);
|
||||
final _headers = <String, dynamic>{};
|
||||
final Map<String, dynamic>? _data = null;
|
||||
final _result = await _dio
|
||||
.fetch<Map<String, dynamic>>(_setStreamType<ApiResult<BUser>>(Options(
|
||||
method: 'GET',
|
||||
.fetch<Map<String, dynamic>>(_setStreamType<ApiResult<bool>>(Options(
|
||||
method: 'DELETE',
|
||||
headers: _headers,
|
||||
extra: _extra,
|
||||
)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/user',
|
||||
'/token',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
@@ -95,7 +195,41 @@ class _EHApi implements EHApi {
|
||||
_dio.options.baseUrl,
|
||||
baseUrl,
|
||||
))));
|
||||
final value = await compute(deserializeApiResult<BUser>, _result.data!);
|
||||
final value = ApiResult<bool>.fromJson(
|
||||
_result.data!,
|
||||
(json) => json as bool,
|
||||
);
|
||||
return value;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<ApiResult<Token>> getToken({String? token}) async {
|
||||
const _extra = <String, dynamic>{};
|
||||
final queryParameters = <String, dynamic>{r'token': token};
|
||||
queryParameters.removeWhere((k, v) => v == null);
|
||||
final _headers = <String, dynamic>{};
|
||||
final Map<String, dynamic>? _data = null;
|
||||
final _result = await _dio
|
||||
.fetch<Map<String, dynamic>>(_setStreamType<ApiResult<Token>>(Options(
|
||||
method: 'GET',
|
||||
headers: _headers,
|
||||
extra: _extra,
|
||||
)
|
||||
.compose(
|
||||
_dio.options,
|
||||
'/token',
|
||||
queryParameters: queryParameters,
|
||||
data: _data,
|
||||
)
|
||||
.copyWith(
|
||||
baseUrl: _combineBaseUrls(
|
||||
_dio.options.baseUrl,
|
||||
baseUrl,
|
||||
))));
|
||||
final value = ApiResult<Token>.fromJson(
|
||||
_result.data!,
|
||||
(json) => Token.fromJson(json as Map<String, dynamic>),
|
||||
);
|
||||
return value;
|
||||
}
|
||||
|
||||
|
||||
37
lib/api/status.dart
Normal file
37
lib/api/status.dart
Normal file
@@ -0,0 +1,37 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'status.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class MeilisearchInfo {
|
||||
const MeilisearchInfo({
|
||||
required this.host,
|
||||
required this.key,
|
||||
});
|
||||
final String host;
|
||||
final String key;
|
||||
factory MeilisearchInfo.fromJson(Map<String, dynamic> json) => _$MeilisearchInfoFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$MeilisearchInfoToJson(this);
|
||||
}
|
||||
|
||||
@JsonSerializable()
|
||||
class ServerStatus {
|
||||
const ServerStatus({
|
||||
required this.ffmpegApiEnabled,
|
||||
required this.ffmpegBinaryEnabled,
|
||||
required this.meilisearchEnabled,
|
||||
this.meilisearch,
|
||||
required this.noUser,
|
||||
});
|
||||
@JsonKey(name: 'ffmpeg_api_enabled')
|
||||
final bool ffmpegApiEnabled;
|
||||
@JsonKey(name: 'ffmpeg_binary_enabled')
|
||||
final bool ffmpegBinaryEnabled;
|
||||
@JsonKey(name: 'meilisearch_enabled')
|
||||
final bool meilisearchEnabled;
|
||||
final MeilisearchInfo? meilisearch;
|
||||
@JsonKey(name: 'no_user')
|
||||
final bool noUser;
|
||||
factory ServerStatus.fromJson(Map<String, dynamic> json) => _$ServerStatusFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$ServerStatusToJson(this);
|
||||
}
|
||||
39
lib/api/status.g.dart
Normal file
39
lib/api/status.g.dart
Normal file
@@ -0,0 +1,39 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'status.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
MeilisearchInfo _$MeilisearchInfoFromJson(Map<String, dynamic> json) =>
|
||||
MeilisearchInfo(
|
||||
host: json['host'] as String,
|
||||
key: json['key'] as String,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$MeilisearchInfoToJson(MeilisearchInfo instance) =>
|
||||
<String, dynamic>{
|
||||
'host': instance.host,
|
||||
'key': instance.key,
|
||||
};
|
||||
|
||||
ServerStatus _$ServerStatusFromJson(Map<String, dynamic> json) => ServerStatus(
|
||||
ffmpegApiEnabled: json['ffmpeg_api_enabled'] as bool,
|
||||
ffmpegBinaryEnabled: json['ffmpeg_binary_enabled'] as bool,
|
||||
meilisearchEnabled: json['meilisearch_enabled'] as bool,
|
||||
meilisearch: json['meilisearch'] == null
|
||||
? null
|
||||
: MeilisearchInfo.fromJson(
|
||||
json['meilisearch'] as Map<String, dynamic>),
|
||||
noUser: json['no_user'] as bool,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$ServerStatusToJson(ServerStatus instance) =>
|
||||
<String, dynamic>{
|
||||
'ffmpeg_api_enabled': instance.ffmpegApiEnabled,
|
||||
'ffmpeg_binary_enabled': instance.ffmpegBinaryEnabled,
|
||||
'meilisearch_enabled': instance.meilisearchEnabled,
|
||||
'meilisearch': instance.meilisearch,
|
||||
'no_user': instance.noUser,
|
||||
};
|
||||
27
lib/api/token.dart
Normal file
27
lib/api/token.dart
Normal file
@@ -0,0 +1,27 @@
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'token.g.dart';
|
||||
|
||||
@JsonSerializable()
|
||||
class Token {
|
||||
const Token ({
|
||||
required this.id,
|
||||
required this.uid,
|
||||
required this.token,
|
||||
required this.expired,
|
||||
required this.httpOnly,
|
||||
required this.secure,
|
||||
});
|
||||
final int id;
|
||||
final int uid;
|
||||
final String token;
|
||||
@JsonKey(fromJson: _fromJson, toJson: _toJson)
|
||||
final DateTime expired;
|
||||
@JsonKey(name: 'http_only')
|
||||
final bool httpOnly;
|
||||
final bool secure;
|
||||
static DateTime _fromJson(String d) => DateTime.parse(d);
|
||||
static String _toJson(DateTime d) => d.toIso8601String();
|
||||
factory Token.fromJson(Map<String, dynamic> json) => _$TokenFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$TokenToJson(this);
|
||||
}
|
||||
25
lib/api/token.g.dart
Normal file
25
lib/api/token.g.dart
Normal file
@@ -0,0 +1,25 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'token.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JsonSerializableGenerator
|
||||
// **************************************************************************
|
||||
|
||||
Token _$TokenFromJson(Map<String, dynamic> json) => Token(
|
||||
id: json['id'] as int,
|
||||
uid: json['uid'] as int,
|
||||
token: json['token'] as String,
|
||||
expired: Token._fromJson(json['expired'] as String),
|
||||
httpOnly: json['http_only'] as bool,
|
||||
secure: json['secure'] as bool,
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$TokenToJson(Token instance) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'uid': instance.uid,
|
||||
'token': instance.token,
|
||||
'expired': Token._toJson(instance.expired),
|
||||
'http_only': instance.httpOnly,
|
||||
'secure': instance.secure,
|
||||
};
|
||||
@@ -18,12 +18,13 @@ class BUser {
|
||||
const BUser({
|
||||
required this.id,
|
||||
required this.username,
|
||||
required this.is_admin,
|
||||
required this.isAdmin,
|
||||
required this.permissions,
|
||||
});
|
||||
final int id;
|
||||
final String username;
|
||||
final bool is_admin;
|
||||
@JsonKey(name: 'is_admin')
|
||||
final bool isAdmin;
|
||||
final UserPermission permissions;
|
||||
factory BUser.fromJson(Map<String, dynamic> json) => _$BUserFromJson(json);
|
||||
Map<String, dynamic> toJson() => _$BUserToJson(this);
|
||||
|
||||
@@ -9,14 +9,14 @@ part of 'user.dart';
|
||||
BUser _$BUserFromJson(Map<String, dynamic> json) => BUser(
|
||||
id: json['id'] as int,
|
||||
username: json['username'] as String,
|
||||
is_admin: json['is_admin'] as bool,
|
||||
isAdmin: json['is_admin'] as bool,
|
||||
permissions: $enumDecode(_$UserPermissionEnumMap, json['permissions']),
|
||||
);
|
||||
|
||||
Map<String, dynamic> _$BUserToJson(BUser instance) => <String, dynamic>{
|
||||
'id': instance.id,
|
||||
'username': instance.username,
|
||||
'is_admin': instance.is_admin,
|
||||
'is_admin': instance.isAdmin,
|
||||
'permissions': _$UserPermissionEnumMap[instance.permissions]!,
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user