feat: import/export login info

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2024-12-24 11:28:18 +08:00
parent 94c077a4fe
commit c23f15b195
5 changed files with 194 additions and 71 deletions

View File

@@ -18,6 +18,7 @@ import 'api.dart';
import 'constants.dart';
import 'interceptor.dart';
import 'interceptor_anonymity.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart' as web;
class Request {
static final Request _instance = Request._internal();
@@ -43,8 +44,19 @@ class Request {
cookieManager = CookieManager(cookieJar);
dio.interceptors.add(cookieManager);
dio.interceptors.add(AnonymityInterceptor());
// final List<Cookie> cookie = await cookieManager.cookieJar
// .loadForRequest(Uri.parse(HttpString.baseUrl));
final List<Cookie> cookies = await cookieManager.cookieJar
.loadForRequest(Uri.parse(HttpString.baseUrl));
for (Cookie item in cookies) {
await web.CookieManager().setCookie(
url: web.WebUri(item.domain ?? ''),
name: item.name,
value: item.value,
path: item.path ?? '',
domain: item.domain,
isSecure: item.secure,
isHttpOnly: item.httpOnly,
);
}
final userInfo = userInfoCache.get('userInfoCache');
if (userInfo != null && userInfo.mid != null) {
final List<Cookie> cookie2 = await cookieManager.cookieJar
@@ -65,7 +77,7 @@ class Request {
log("setCookie, ${e.toString()}");
}
// final String cookieString = cookie
// final String cookieString = cookies
// .map((Cookie cookie) => '${cookie.name}=${cookie.value}')
// .join('; ');
// dio.options.headers['cookie'] = cookieString;

View File

@@ -1,4 +1,9 @@
import 'dart:convert';
import 'package:PiliPalaX/http/constants.dart';
import 'package:PiliPalaX/services/loggeer.dart';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
@@ -189,12 +194,104 @@ class _AboutPageState extends State<AboutPage> {
),
),
),
ListTile(
title: const Text('导入/导出登录信息'),
leading: const Icon(Icons.import_export_outlined),
onTap: () {
showDialog(
context: context,
builder: (context) => SimpleDialog(
clipBehavior: Clip.hardEdge,
children: [
ListTile(
title: const Text('导出'),
onTap: () async {
dynamic accessKey = GStorage.localCache
.get(LocalCacheKey.accessKey, defaultValue: {});
dynamic cookies = (await CookieManager(PersistCookieJar(
ignoreExpires: true,
storage: FileStorage(await Utils.getCookiePath()),
))
.cookieJar
.loadForRequest(Uri.parse(HttpString.baseUrl)))
.map(
(Cookie cookie) => {
'name': cookie.name,
'value': cookie.value,
},
)
.toList();
dynamic res = jsonEncode({
'accessKey': accessKey,
'cookies': cookies,
});
Utils.copyText('$res');
if (context.mounted) {
showDialog(
context: context,
builder: (context) => AlertDialog(
content: SelectableText('$res'),
),
);
}
},
),
ListTile(
title: const Text('导入'),
onTap: () async {
Get.back();
ClipboardData? data =
await Clipboard.getData('text/plain');
if (data == null ||
data.text == null ||
data.text!.isEmpty) {
SmartDialog.showToast('剪贴板无数据');
return;
}
if (!context.mounted) return;
await showDialog(
context: context,
builder: (context) {
return AlertDialog(
title: const Text('是否导入以下登录信息?'),
content: Text(data.text!),
actions: [
TextButton(
onPressed: Get.back,
child: const Text('取消'),
),
TextButton(
onPressed: () async {
Get.back();
try {
dynamic res = jsonDecode(data.text!);
Utils.afterLoginByApp(
res['accessKey'],
{'cookies': res['cookies']},
);
} catch (e) {
SmartDialog.showToast('导入失败:$e');
}
},
child: const Text('确定'),
),
],
);
},
);
},
),
],
),
);
},
),
ListTile(
title: const Text('导入/导出设置'),
dense: false,
leading: const Icon(Icons.import_export_outlined),
onTap: () async {
await showDialog(
onTap: () {
showDialog(
context: context,
builder: (context) {
return SimpleDialog(

View File

@@ -2,22 +2,13 @@ import 'dart:async';
import 'dart:io';
import 'package:PiliPalaX/common/constants.dart';
import 'package:PiliPalaX/utils/utils.dart';
import 'package:flutter/material.dart';
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:PiliPalaX/http/login.dart';
import 'package:gt3_flutter_plugin/gt3_flutter_plugin.dart';
import 'package:PiliPalaX/models/login/index.dart';
import '../../utils/login.dart';
import 'package:hive/hive.dart';
import 'package:webview_cookie_manager/webview_cookie_manager.dart';
import '../../http/constants.dart';
import '../../http/init.dart';
import '../../http/user.dart';
import '../../utils/storage.dart';
import '../home/controller.dart';
import '../media/controller.dart';
class LoginPageController extends GetxController
with GetSingleTickerProviderStateMixin {
@@ -86,7 +77,7 @@ class LoginPageController extends GetxController
if (value['status']) {
t.cancel();
statusQRCode.value = '扫码成功';
await afterLoginByApp(
await Utils.afterLoginByApp(
value['data'], value['data']['cookie_info']);
Get.back();
} else if (value['code'] == 86038) {
@@ -111,58 +102,6 @@ class LoginPageController extends GetxController
}
}
Future afterLoginByApp(Map<String, dynamic> token_info, cookie_info) async {
try {
Box localCache = GStorage.localCache;
localCache.put(LocalCacheKey.accessKey, {
'mid': token_info['mid'],
'value': token_info['access_token'],
'refresh': token_info['refresh_token']
});
List<dynamic> cookieInfo = cookie_info['cookies'];
List<Cookie> cookies = [];
String cookieStrings = cookieInfo.map((cookie) {
String cstr =
'${cookie['name']}=${cookie['value']};Domain=.bilibili.com;Path=/;';
cookies.add(Cookie.fromSetCookieValue(cstr));
return cstr;
}).join('');
List<String> Urls = [
HttpString.baseUrl,
HttpString.apiBaseUrl,
HttpString.tUrl
];
for (var url in Urls) {
await Request.cookieManager.cookieJar
.saveFromResponse(Uri.parse(url), cookies);
}
Request.dio.options.headers['cookie'] = cookieStrings;
await WebviewCookieManager().setCookies(cookies);
} catch (e) {
SmartDialog.showToast('设置登录态失败,$e');
}
final result = await UserHttp.userInfo();
if (result['status'] && result['data'].isLogin) {
SmartDialog.showToast('登录成功,当前采用「'
'${GStorage.setting.get(SettingBoxKey.defaultRcmdType, defaultValue: 'web')}'
'端」推荐');
await GStorage.userInfo.put('userInfoCache', result['data']);
try {
final HomeController homeCtr = Get.find<HomeController>();
homeCtr.updateLoginStatus(true);
homeCtr.userFace.value = result['data'].face;
final MediaController mediaCtr = Get.find<MediaController>();
mediaCtr.mid = result['data'].mid;
} catch (_) {}
await LoginUtils.refreshLoginStatus(true);
} else {
// 获取用户信息失败
SmartDialog.showNotify(
msg: '登录失败请检查cookie是否正确${result['message']}',
notifyType: NotifyType.warning);
}
}
// 申请极验验证码
Future getCaptcha(geeGt, geeChallenge, onSuccess) async {
var registerData = Gt3RegisterData(
@@ -415,7 +354,8 @@ class LoginPageController extends GetxController
return;
}
SmartDialog.showToast('正在保存身份信息');
await afterLoginByApp(data['token_info'], data['cookie_info']);
await Utils.afterLoginByApp(
data['token_info'], data['cookie_info']);
Get.back();
Get.back();
},
@@ -432,7 +372,7 @@ class LoginPageController extends GetxController
return;
}
SmartDialog.showToast('正在保存身份信息');
await afterLoginByApp(data['token_info'], data['cookie_info']);
await Utils.afterLoginByApp(data['token_info'], data['cookie_info']);
Get.back();
} else {
// handle login result
@@ -495,7 +435,7 @@ class LoginPageController extends GetxController
if (res['status']) {
SmartDialog.showToast('登录成功');
var data = res['data'];
await afterLoginByApp(data['token_info'], data['cookie_info']);
await Utils.afterLoginByApp(data['token_info'], data['cookie_info']);
Get.back();
} else {
SmartDialog.showToast(res['msg']);

View File

@@ -22,6 +22,8 @@ class GStorage {
static late final Box<dynamic> setting;
static late final Box<dynamic> video;
static bool get isLogin => userInfo.get('userInfoCache') != null;
static List<double> get speedList => List<double>.from(
video.get(
VideoBoxKey.speedsList,

View File

@@ -3,13 +3,20 @@ import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:PiliPalaX/grpc/app/main/community/reply/v1/reply.pb.dart';
import 'package:PiliPalaX/http/constants.dart';
import 'package:PiliPalaX/http/init.dart';
import 'package:PiliPalaX/http/member.dart';
import 'package:PiliPalaX/http/search.dart';
import 'package:PiliPalaX/http/user.dart';
import 'package:PiliPalaX/http/video.dart';
import 'package:PiliPalaX/models/bangumi/info.dart';
import 'package:PiliPalaX/models/common/search_type.dart';
import 'package:PiliPalaX/pages/home/controller.dart';
import 'package:PiliPalaX/pages/media/controller.dart';
import 'package:PiliPalaX/pages/video/detail/introduction/widgets/group_panel.dart';
import 'package:PiliPalaX/utils/feed_back.dart';
import 'package:PiliPalaX/utils/login.dart';
import 'package:PiliPalaX/utils/storage.dart';
import 'package:crypto/crypto.dart';
import 'package:device_info_plus/device_info_plus.dart';
import 'package:flutter/material.dart';
@@ -18,10 +25,75 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
import 'package:get/get.dart';
import 'package:path_provider/path_provider.dart';
import 'package:url_launcher/url_launcher.dart';
import 'package:webview_cookie_manager/webview_cookie_manager.dart';
import 'package:flutter_inappwebview/flutter_inappwebview.dart' as web;
class Utils {
static final Random random = Random();
static Future afterLoginByApp(
Map<String, dynamic> token_info, cookie_info) async {
try {
GStorage.localCache.put(LocalCacheKey.accessKey, {
'mid': token_info['mid'],
'value': token_info['access_token'] ?? token_info['value'],
'refresh': token_info['refresh_token'] ?? token_info['refresh']
});
List<dynamic> cookieInfo = cookie_info['cookies'];
List<Cookie> cookies = [];
String cookieStrings = cookieInfo.map((cookie) {
String cstr =
'${cookie['name']}=${cookie['value']};Domain=.bilibili.com;Path=/;';
cookies.add(Cookie.fromSetCookieValue(cstr));
return cstr;
}).join('');
List<String> urls = [
HttpString.baseUrl,
HttpString.apiBaseUrl,
HttpString.tUrl
];
for (var url in urls) {
await Request.cookieManager.cookieJar
.saveFromResponse(Uri.parse(url), cookies);
}
Request.dio.options.headers['cookie'] = cookieStrings;
await WebviewCookieManager().setCookies(cookies);
for (Cookie item in cookies) {
await web.CookieManager().setCookie(
url: web.WebUri(item.domain ?? ''),
name: item.name,
value: item.value,
path: item.path ?? '',
domain: item.domain,
isSecure: item.secure,
isHttpOnly: item.httpOnly,
);
}
} catch (e) {
SmartDialog.showToast('设置登录态失败,$e');
}
final result = await UserHttp.userInfo();
if (result['status'] && result['data'].isLogin) {
SmartDialog.showToast('登录成功,当前采用「'
'${GStorage.setting.get(SettingBoxKey.defaultRcmdType, defaultValue: 'web')}'
'端」推荐');
await GStorage.userInfo.put('userInfoCache', result['data']);
try {
final HomeController homeCtr = Get.find<HomeController>();
homeCtr.updateLoginStatus(true);
homeCtr.userFace.value = result['data'].face;
final MediaController mediaCtr = Get.find<MediaController>();
mediaCtr.mid = result['data'].mid;
} catch (_) {}
await LoginUtils.refreshLoginStatus(true);
} else {
// 获取用户信息失败
SmartDialog.showNotify(
msg: '登录失败请检查cookie是否正确${result['message']}',
notifyType: NotifyType.warning);
}
}
static bool isStringNumeric(str) {
RegExp numericRegex = RegExp(r'^[\d\.]+$');
return numericRegex.hasMatch(str.toString());