From 08decff829ea5a1e2a7bcbbc293919aff051ff3e Mon Sep 17 00:00:00 2001 From: wanghongenpin <178070584@qq.com> Date: Wed, 22 Nov 2023 16:20:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=AE=89=E5=8D=93=E7=AD=BE=E5=90=8D=E8=AF=81?= =?UTF-8?q?=E4=B9=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- android/app/build.gradle | 22 ++++- android/key.properties | 4 + android/keystore.jks | Bin 0 -> 2223 bytes lib/network/network.dart | 1 - lib/network/util/tls.dart | 26 ++++++ lib/ui/desktop/toolbar/setting/script.dart | 90 ++++++++++-------- lib/ui/desktop/toolbar/setting/theme.dart | 2 +- lib/ui/launch/launch.dart | 5 +- lib/ui/mobile/menu.dart | 3 +- lib/ui/mobile/setting/script.dart | 104 ++++++++++++--------- pubspec.lock | 58 ++++++++++-- pubspec.yaml | 2 +- 12 files changed, 216 insertions(+), 101 deletions(-) create mode 100644 android/key.properties create mode 100644 android/keystore.jks diff --git a/android/app/build.gradle b/android/app/build.gradle index d1f731e..135ec62 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -21,6 +21,12 @@ if (flutterVersionName == null) { flutterVersionName = '1.0' } +def keystoreProperties = new Properties() +def keystorePropertiesFile = rootProject.file('key.properties') +if (keystorePropertiesFile.exists()) { + keystoreProperties.load(new FileInputStream(keystorePropertiesFile)) +} + apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle" @@ -53,16 +59,30 @@ android { versionName flutterVersionName } + signingConfigs { + release { + keyAlias keystoreProperties['keyAlias'] + keyPassword keystoreProperties['keyPassword'] + storeFile keystoreProperties['storeFile'] ? file(keystoreProperties['storeFile']) : null + storePassword keystoreProperties['storePassword'] + } + } + buildTypes { release { // Signing with the debug keys for now, so `flutter run --release` works. - signingConfig signingConfigs.debug + signingConfig signingConfigs.release minifyEnabled true shrinkResources true proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' } + debug { + signingConfig signingConfigs.release + minifyEnabled true + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } } } diff --git a/android/key.properties b/android/key.properties new file mode 100644 index 0000000..e2eadef --- /dev/null +++ b/android/key.properties @@ -0,0 +1,4 @@ +storePassword=proxypin +keyPassword=proxypin +keyAlias=proxypin +storeFile=../keystore.jks diff --git a/android/keystore.jks b/android/keystore.jks new file mode 100644 index 0000000000000000000000000000000000000000..b32e3518ff49763402d303dc8a7bd11a79164bc2 GIT binary patch literal 2223 zcmchYc{J1u8^>p}hb-eAYlFuiLrzy!V{<|M!pQkMHL^e>~gyK0G#$4FZ86djb9#f?=0K zV`9UCLiRu^XDF^21mXh&B-jr?j9*xj9}EL)KqSCmJ`juqTXyiDVrT@*spdF%a7;yY zQ2At2w*vfl&D)}pf;varbx$deky*z6s)6SxZ%R5s^E}DQlI0&LkI_XFU7TuLL}-Rn z=spEN&>Kxm?Q!M0jmxOQD0X>=S<$Y5{C)42 zjbZsIVWUcrc>SH~Q&}$zU-;-L})A#vbj%?OfUJ_jz-U+I>WA&P_piq+i2b z?7A%wtXRnmnX;ke_0bn@NFS_TuG)kB21oh`clRR zmf8RZ%Pk@7znB-LvgYV}EL(AzDSUygUXVb@*s%4#=+Nh!%ol6TI5pHTBp;kJggk(s zJ?JLJ*s#7CEr9Hq#`8F8-7fi=@ZOgC-xBdq4z{}en z#04zIB!DAjl2dh%Dk4wKo@~^rT{{M***0Wl=-GFDty?mXET;RGeuz%;aBLoKqAlXJ zudQm;eV^qtAU1M4jp9vNx=J;_^%#HDS1bJ%b2MS9Q=LJQtXO!zs1s^Sx6W^GSX?OH z7qf3X*nigVyVQ?3?HTEE`{zpy=8Ca3Us(A__|}S6M9W#TmO=BEpk>%%)WU%8!{FX; zmyyA~!-jpquW1ABi~8q}C9)2)cRR-be|zQwYH-5&HkCq}rn+nT4}VbMA2N}O9n$vh ztgi942%hWj@30!eY0@(C=bp7@EvN3*U#q0J(a|N&RUW^MYbWE_AKj)8sZMM{M5Ph# zm%{69vRd0chpgvIYLgSxECUjo?iO1Jm%>>ZE5^BFk*YoKg7Oc95Hl^iV)Gd2;_AU^ z8O2qcNWP7e$OarEIp2jGc(ub7H+Re~;+RI6*b#;XLh_D{!K6gL8!LK^SwgaPHJUsP zWhqfT=9jEwa>H*x$yY86H&}l=gK7o{_hZ}AN7H`!Mu`huMT|zeJT_l5y8WsyjI|0q zV$koGr0dZA@kxR6_{U0}aw2-SbS7+T^@!+{w{5>cR&LR~e;?OHY#41VL@Nat8b3p* zMukJYPAvDsV=Jf+U~BGmMvGLbI|ovj$AWz4>b5>8;1j6=sPya=pg z53oc-O(ftwEJk)oN75d7zgf+F)XrX1hOeM<>w;Y3aSU;Q_L5QrW4unJd%uN??;*y6n zv5F-k7T)VrwEW(h!rbyVyd&*4sD52#Yp~x&oFHJPY;l~<+*Z0eea=UqQZ`?^TfoW9 zqT^A}IOBOZ#wR9@bC-Kd%{&H&>rwsG*)|a5-N2RMaLO=ggU0vnwf<0hMfPZ9L%*zW zyi(++=dlkyyLu97b(O8x<|4csPxg31c`s=xyKkeAveVD;O;6!gk2S(iOK@PY`{*Nd z<#@Z`TJc*KOe?acMXC}qZbRU|DtWfmLN3~zv@HtUZ^de(CKsojpI7>6jeMtcuz(Q= z1ib)|pnd=eV*3yZ0Ye}#4HwndfGEF^MzT%v7f~=+gbxIq(-Q%N_@O6Z{8EskC;k?K zQV>hKzlFe0Apwa0nIYGSS7m}0-T z{b>~aH$Oyly^;nqWNr|4MulSIeA^7@P3iTQu?ZaTjiav9A3b`rO9X!9T z<6gSoTdvmngp8)rF4j&Dh zjULwj#6_63Qbc)pw5YT3>B+Mo%>d?(rXrHeab*ip*_%4mLN=T4?VRH41y=ZXLa2Z$ zY`U}g5qJgfRB*MLbE-uq(7eSxay0n6#^p$d%Aw{tAqnex_LZkI(>4KxWd*$S?yHTH zNoW#wQ*m+);h!>Z)~p6fr#>MV8W`SzL!e*~xI`H^04VM)Sy2oo1CuVBsku{2ME|ZF zWWg)Twb+ceOYHjR5cjTUZ-`)!cy+mJz{(7NhOm{SZ{(-!h@$J?lZ5)n+{2Sfwz6yfpBZyToDrJM>!f_#f+1u} 0x03) return false; + if (data[5] != 0x01 /* client_hello */) return false; + if (data[9] != 0x03 || data[10] < 0x00 || data[10] > 0x03) return false; + return true; + } + ///从TLS Client Hello 解析域名 static String? getDomain(Uint8List data) { try { diff --git a/lib/ui/desktop/toolbar/setting/script.dart b/lib/ui/desktop/toolbar/setting/script.dart index e546112..cf258e0 100644 --- a/lib/ui/desktop/toolbar/setting/script.dart +++ b/lib/ui/desktop/toolbar/setting/script.dart @@ -321,7 +321,7 @@ class ScriptList extends StatefulWidget { } class _ScriptListState extends State { - Map selected = {}; + int selected = -1; @override Widget build(BuildContext context) { @@ -354,47 +354,9 @@ class _ScriptListState extends State { } }); }, - onSecondaryTapDown: (details) { - showContextMenu(context, details.globalPosition, items: [ - PopupMenuItem( - height: 35, - child: const Text("编辑"), - onTap: () async { - String script = await (await ScriptManager.instance).getScript(list[index]); - if (!context.mounted) { - return; - } - showDialog( - barrierDismissible: false, - context: context, - builder: (_) => ScriptEdit(scriptItem: list[index], script: script)).then((value) { - if (value != null) { - setState(() {}); - } - }); - }), - PopupMenuItem(height: 35, child: const Text("导出"), onTap: () => export(list[index])), - PopupMenuItem( - height: 35, - child: list[index].enabled ? const Text("禁用") : const Text("启用"), - onTap: () { - list[index].enabled = !list[index].enabled; - setState(() {}); - }), - const PopupMenuDivider(), - PopupMenuItem( - height: 35, - child: const Text("删除"), - onTap: () async { - (await ScriptManager.instance).removeScript(index); - _refreshScript(); - setState(() {}); - if (context.mounted) FlutterToastr.show('删除成功', context); - }), - ]); - }, + onSecondaryTapDown: (details) => showMenus(details, index), child: Container( - color: selected[index] == true + color: selected == index ? primaryColor.withOpacity(0.8) : index.isEven ? Colors.grey.withOpacity(0.1) @@ -421,6 +383,52 @@ class _ScriptListState extends State { }); } + //点击菜单 + showMenus(TapDownDetails details, int index) { + setState(() { + selected = index; + }); + showContextMenu(context, details.globalPosition, items: [ + PopupMenuItem( + height: 35, + child: const Text("编辑"), + onTap: () async { + String script = await (await ScriptManager.instance).getScript(widget.scripts[index]); + if (!context.mounted) { + return; + } + showDialog( + barrierDismissible: false, + context: context, + builder: (_) => ScriptEdit(scriptItem: widget.scripts[index], script: script)).then((value) { + if (value != null) { + setState(() {}); + } + }); + }), + PopupMenuItem(height: 35, child: const Text("导出"), onTap: () => export(widget.scripts[index])), + PopupMenuItem( + height: 35, + child: widget.scripts[index].enabled ? const Text("禁用") : const Text("启用"), + onTap: () { + widget.scripts[index].enabled = !widget.scripts[index].enabled; + }), + const PopupMenuDivider(), + PopupMenuItem( + height: 35, + child: const Text("删除"), + onTap: () async { + (await ScriptManager.instance).removeScript(index); + _refreshScript(); + if (context.mounted) FlutterToastr.show('删除成功', context); + }), + ]).then((value) { + setState(() { + selected = -1; + }); + }); + } + //导出js export(ScriptItem item) async { //文件名称 diff --git a/lib/ui/desktop/toolbar/setting/theme.dart b/lib/ui/desktop/toolbar/setting/theme.dart index 35776e6..29af605 100644 --- a/lib/ui/desktop/toolbar/setting/theme.dart +++ b/lib/ui/desktop/toolbar/setting/theme.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:network_proxy/main.dart'; class ThemeSetting extends StatelessWidget { - const ThemeSetting({Key? key}) : super(key: key); + const ThemeSetting({super.key}); @override Widget build(BuildContext context) { diff --git a/lib/ui/launch/launch.dart b/lib/ui/launch/launch.dart index ad86751..3f83611 100644 --- a/lib/ui/launch/launch.dart +++ b/lib/ui/launch/launch.dart @@ -12,7 +12,8 @@ class SocketLaunch extends StatefulWidget { final bool startup; final Function? onStart; final Function? onStop; - final bool serverLaunch; + + final bool serverLaunch; //是否启动代理服务器 const SocketLaunch( {super.key, @@ -30,7 +31,7 @@ class SocketLaunch extends StatefulWidget { } class _SocketLaunchState extends State with WindowListener, WidgetsBindingObserver { - bool started = false; + static bool started = false; @override void initState() { diff --git a/lib/ui/mobile/menu.dart b/lib/ui/mobile/menu.dart index 703585e..c19929a 100644 --- a/lib/ui/mobile/menu.dart +++ b/lib/ui/mobile/menu.dart @@ -4,6 +4,7 @@ import 'package:easy_permission/easy_permission.dart'; import 'package:flutter/material.dart'; import 'package:flutter_barcode_scanner/flutter_barcode_scanner.dart'; import 'package:flutter_toastr/flutter_toastr.dart'; +import 'package:network_proxy/native/vpn.dart'; import 'package:network_proxy/network/bin/server.dart'; import 'package:network_proxy/network/http_client.dart'; import 'package:network_proxy/network/util/host_filter.dart'; @@ -211,7 +212,7 @@ class MoreEnum extends StatelessWidget { hostname: response.headers.get("hostname")); if (context.mounted && Navigator.canPop(context)) { - FlutterToastr.show("连接成功${proxyServer.isRunning ? '' : ',手机需要开启抓包才可以抓取请求哦'}", context, duration: 3); + FlutterToastr.show("连接成功${Vpn.isVpnStarted ? '' : ',手机需要开启抓包才可以抓取请求哦'}", context, duration: 3); Navigator.pop(context); } } diff --git a/lib/ui/mobile/setting/script.dart b/lib/ui/mobile/setting/script.dart index 32b1c10..fbcd2f6 100644 --- a/lib/ui/mobile/setting/script.dart +++ b/lib/ui/mobile/setting/script.dart @@ -117,7 +117,7 @@ class _MobileScriptState extends State { } try { - var json = jsonDecode(await file.readAsString()); + var json = jsonDecode(utf8.decode(await file.readAsBytes())); var scriptItem = ScriptItem.fromJson(json); (await ScriptManager.instance).addScript(scriptItem, json['script']); _refreshScript(); @@ -148,7 +148,7 @@ class ScriptEdit extends StatefulWidget { final ScriptItem? scriptItem; final String? script; - const ScriptEdit({Key? key, this.scriptItem, this.script}) : super(key: key); + const ScriptEdit({super.key, this.scriptItem, this.script}); @override State createState() => _ScriptEditState(); @@ -230,8 +230,7 @@ class _ScriptEditState extends State { CodeTheme( data: CodeThemeData(styles: monokaiSublimeTheme), child: SingleChildScrollView( - child: CodeField( - textStyle: const TextStyle(fontSize: 14), controller: script))) + child: CodeField(textStyle: const TextStyle(fontSize: 14), controller: script))) ], )))); } @@ -271,14 +270,19 @@ class ScriptList extends StatefulWidget { } class _ScriptListState extends State { + int selected = -1; + @override Widget build(BuildContext context) { return Column(children: rows(widget.scripts)); } List rows(List list) { + var primaryColor = Theme.of(context).primaryColor; + return List.generate(list.length, (index) { return InkWell( + splashColor: primaryColor.withOpacity(0.3), onDoubleTap: () async { String script = await (await ScriptManager.instance).getScript(list[index]); if (!context.mounted) { @@ -292,47 +296,13 @@ class _ScriptListState extends State { } }); }, - onTapDown: (details) { - showContextMenu(context, details.globalPosition, items: [ - PopupMenuItem( - height: 35, - child: const Text("编辑"), - onTap: () async { - String script = await (await ScriptManager.instance).getScript(list[index]); - if (!context.mounted) { - return; - } - Navigator.of(context) - .push(MaterialPageRoute( - builder: (context) => ScriptEdit(scriptItem: list[index], script: script))) - .then((value) { - if (value != null) { - setState(() {}); - } - }); - }), - PopupMenuItem(height: 35, child: const Text("分享"), onTap: () => export(list[index])), - PopupMenuItem( - height: 35, - child: list[index].enabled ? const Text("禁用") : const Text("启用"), - onTap: () { - list[index].enabled = !list[index].enabled; - setState(() {}); - }), - const PopupMenuDivider(), - PopupMenuItem( - height: 35, - child: const Text("删除"), - onTap: () async { - (await ScriptManager.instance).removeScript(index); - _refreshScript(); - setState(() {}); - if (context.mounted) FlutterToastr.show('删除成功', context); - }), - ]); - }, + onTapDown: (details) => showMenus(details, index), child: Container( - color: index.isEven ? Colors.grey.withOpacity(0.1) : null, + color: selected == index + ? primaryColor.withOpacity(0.8) + : index.isEven + ? Colors.grey.withOpacity(0.1) + : null, height: 45, padding: const EdgeInsets.all(5), child: Row( @@ -358,6 +328,52 @@ class _ScriptListState extends State { }); } + //点击菜单 + showMenus(TapDownDetails details, int index) { + setState(() { + selected = index; + }); + showContextMenu(context, details.globalPosition, items: [ + PopupMenuItem( + height: 35, + child: const Text("编辑"), + onTap: () async { + String script = await (await ScriptManager.instance).getScript(widget.scripts[index]); + if (!context.mounted) { + return; + } + Navigator.of(context) + .push(MaterialPageRoute( + builder: (context) => ScriptEdit(scriptItem: widget.scripts[index], script: script))) + .then((value) { + if (value != null) { + setState(() {}); + } + }); + }), + PopupMenuItem(height: 35, child: const Text("分享"), onTap: () => export(widget.scripts[index])), + PopupMenuItem( + height: 35, + child: widget.scripts[index].enabled ? const Text("禁用") : const Text("启用"), + onTap: () { + widget.scripts[index].enabled = !widget.scripts[index].enabled; + }), + const PopupMenuDivider(), + PopupMenuItem( + height: 35, + child: const Text("删除"), + onTap: () async { + (await ScriptManager.instance).removeScript(index); + _refreshScript(); + if (context.mounted) FlutterToastr.show('删除成功', context); + }), + ]).then((value) { + setState(() { + selected = -1; + }); + }); + } + //导出js export(ScriptItem item) async { //文件名称 diff --git a/pubspec.lock b/pubspec.lock index 04cd7eb..fb9530a 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -267,10 +267,10 @@ packages: dependency: "direct dev" description: name: flutter_lints - sha256: ad76540d21c066228ee3f9d1dad64a9f7e46530e8bb7c85011a88bc1fd874bc5 + sha256: e2a421b7e59244faef694ba7b30562e489c2b489866e505074eb005cd7060db7 url: "https://pub.flutter-io.cn" source: hosted - version: "3.0.0" + version: "3.0.1" flutter_plugin_android_lifecycle: dependency: transitive description: @@ -337,6 +337,14 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "1.3.1" + intl: + dependency: transitive + description: + name: intl + sha256: "3bc132a9dbce73a7e4a21a17d06e1878839ffbf975568bc875c60537824b0c4d" + url: "https://pub.flutter-io.cn" + source: hosted + version: "0.18.1" js: dependency: transitive description: @@ -353,6 +361,22 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "4.8.1" + leak_tracker: + dependency: transitive + description: + name: leak_tracker + sha256: "7e108028e3d258667d079986da8c0bc32da4cb57431c2af03b1dc1038621a9dc" + url: "https://pub.flutter-io.cn" + source: hosted + version: "9.0.13" + leak_tracker_testing: + dependency: transitive + description: + name: leak_tracker_testing + sha256: b06739349ec2477e943055aea30172c5c7000225f79dad4702e2ec0eda79a6ff + url: "https://pub.flutter-io.cn" + source: hosted + version: "1.0.5" linked_scroll_controller: dependency: transitive description: @@ -397,18 +421,18 @@ packages: dependency: transitive description: name: material_color_utilities - sha256: "9528f2f296073ff54cb9fee677df673ace1218163c3bc7628093e7eed5203d41" + sha256: "0e0a020085b65b6083975e499759762399b4475f766c21668c4ecca34ea74e5a" url: "https://pub.flutter-io.cn" source: hosted - version: "0.5.0" + version: "0.8.0" meta: dependency: transitive description: name: meta - sha256: a6e590c838b18133bb482a2745ad77c5bb7715fb0451209e1a7567d416678b8e + sha256: d584fa6707a52763a52446f02cc621b077888fb63b93bbcb1143a7be5a0c0c04 url: "https://pub.flutter-io.cn" source: hosted - version: "1.10.0" + version: "1.11.0" mime: dependency: transitive description: @@ -734,14 +758,30 @@ packages: url: "https://pub.flutter-io.cn" source: hosted version: "2.1.4" + vm_service: + dependency: transitive + description: + name: vm_service + sha256: b3d56ff4341b8f182b96aceb2fa20e3dcb336b9f867bc0eafc0de10f1048e957 + url: "https://pub.flutter-io.cn" + source: hosted + version: "13.0.0" web: dependency: transitive description: name: web - sha256: "14f1f70c51119012600c5f1f60ca68efda5a9b6077748163c6af2893ec5df8fc" + sha256: afe077240a270dcfd2aafe77602b4113645af95d0ad31128cc02bce5ac5d5152 url: "https://pub.flutter-io.cn" source: hosted - version: "0.2.1-beta" + version: "0.3.0" + web_socket_channel: + dependency: transitive + description: + name: web_socket_channel + sha256: d88238e5eac9a42bb43ca4e721edba3c08c6354d4a53063afaa568516217621b + url: "https://pub.flutter-io.cn" + source: hosted + version: "2.4.0" win32: dependency: transitive description: @@ -767,5 +807,5 @@ packages: source: hosted version: "1.0.3" sdks: - dart: ">=3.2.0-157.0.dev <4.0.0" + dart: ">=3.2.0-194.0.dev <4.0.0" flutter: ">=3.13.0" diff --git a/pubspec.yaml b/pubspec.yaml index 7aee169..06305a8 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -37,7 +37,7 @@ dependencies: dev_dependencies: flutter_test: sdk: flutter - flutter_lints: ^3.0.0 + flutter_lints: ^3.0.1 # The following section is specific to Flutter packages. flutter: