diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index af7d8d0..4d4ef56 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -1,5 +1,5 @@
name: "BUG反馈"
-description: LocyanFrp的部分行为不符合预期
+description: Kairo的部分行为不符合预期
title: "BUG反馈 <在此处简单描述>"
labels: ["🐛Bug"]
@@ -7,7 +7,7 @@ body:
- type: input
id: version
attributes:
- label: 当前使用的LocyanFrp版本
+ label: 当前使用的Kairo版本
description: 设置
validations:
required: true
@@ -16,7 +16,7 @@ body:
id: expectation
attributes:
label: 你的预期
- description: 预期LocyanFrp应该的反应
+ description: 预期Kairo应该的反应
placeholder: |
1. ...
validations:
diff --git a/.github/ISSUE_TEMPLATE/crash_report.yml b/.github/ISSUE_TEMPLATE/crash_report.yml
index 135e8d9..3e12f90 100644
--- a/.github/ISSUE_TEMPLATE/crash_report.yml
+++ b/.github/ISSUE_TEMPLATE/crash_report.yml
@@ -1,5 +1,5 @@
name: "崩溃反馈"
-description: LocyanFrp发生了莫名其妙的崩溃
+description: Kairo发生了莫名其妙的崩溃
title: "崩溃反馈 <在此处简单描述报错信息>"
labels: ["❗ 崩溃"]
@@ -7,7 +7,7 @@ body:
- type: input
id: version
attributes:
- label: 当前使用的LocyanFrp版本
+ label: 当前使用的Kairo版本
description: 设置
validations:
required: true
diff --git a/.github/workflows/Build.yml b/.github/workflows/Build.yml
index c5be6c7..3d4d812 100644
--- a/.github/workflows/Build.yml
+++ b/.github/workflows/Build.yml
@@ -1,4 +1,4 @@
-name: Build
+name: Build
on:
push:
@@ -19,53 +19,50 @@ jobs:
- name: Install .NET
uses: actions/setup-dotnet@v4
with:
- dotnet-version: 6.0.x
+ dotnet-version: 9.0.x
- name: Write Build info
shell: cmd
run: |
- cmd /c echo GITHUB ACTION #${{github.run_number}} >${{ github.workspace }}\LoCyanFrpDesktop\buildinfo.info
- cmd /c echo %date% %time% >>${{ github.workspace }}\LoCyanFrpDesktop\buildinfo.info
- cmd /c echo ${{github.ref}} ${{github.sha}}>>${{ github.workspace }}\LoCyanFrpDesktop\buildinfo.info
+ cmd /c echo GITHUB ACTION #${{github.run_number}} >${{ github.workspace }}\Kairo\buildinfo.info
+ cmd /c echo %date% %time% >>${{ github.workspace }}\Kairo\buildinfo.info
+ cmd /c echo ${{github.ref}} ${{github.sha}}>>${{ github.workspace }}\Kairo\buildinfo.info
- name: DotNet restore
run: dotnet restore
- name: Build the project(Release)
- run: dotnet build -p:Configuration=Release "LoCyanFrpDesktop/LoCyanFrpDesktop.csproj"
+ run: dotnet build -p:Configuration=Release "Kairo/Kairo.csproj"
- - name: Build the project(Debug)
- run: dotnet build "LoCyanFrpDesktop/LoCyanFrpDesktop.csproj"
-
- - name: Upload LocyanFrp(Release,dotnet6-windows)
+ - name: Upload Kairo(Release,dotnet9-windows)
uses: actions/upload-artifact@v4
with:
- name: LoCyanFrpDesktop_dotnet6
- path: ${{ github.workspace }}\LoCyanFrpDesktop\bin\Release\net6.0-windows
+ name: Kairo_dotnet9
+ path: ${{ github.workspace }}\Kairo\bin\Release\net9.0-windows
if-no-files-found: ignore
- name: Build the project(Publish)
run: |
dotnet clean
- dotnet publish "LoCyanFrpDesktop/LoCyanFrpDesktop.csproj" -f net6.0-windows --no-self-contained -p:PublishSingleFile=true -p:RuntimeIdentifier=win-x64 -p:IncludeContentInSingleFile=true
+ dotnet publish "Kairo/Kairo.csproj" -f net9.0-windows --no-self-contained -p:PublishSingleFile=true -p:RuntimeIdentifier=win-x64 -p:IncludeContentInSingleFile=true
- - name: Upload LocyanFrp(Publish)
+ - name: Upload Kairo(Publish)
uses: actions/upload-artifact@v4
with:
- name: LoCyanFrpDesktop_dotnet6_publish
- path: ${{ github.workspace }}\LoCyanFrpDesktop\bin\Debug\net6.0-windows\win-x64\publish
+ name: Kairo_dotnet9_publish
+ path: ${{ github.workspace }}\Kairo\bin\Debug\net9.0-windows\win-x64\publish
if-no-files-found: ignore
- name: Build the project(Publish,Single File)
run: |
dotnet clean
- dotnet publish "LoCyanFrpDesktop/LoCyanFrpDesktop.csproj" -f net6.0-windows -r win-x64 -p:PublishSingleFile=true -p:RuntimeIdentifier=win-x64 -p:IncludeContentInSingleFile=true -p:Configuration=Release --sc -p:IncludeAllContentForSelfExtract=true -p:EnableCompressionInSingleFile=true
+ dotnet publish "Kairo/Kairo.csproj" -f net9.0-windows -r win-x64 -p:PublishSingleFile=true -p:RuntimeIdentifier=win-x64 -p:IncludeContentInSingleFile=true -p:Configuration=Release --sc -p:IncludeAllContentForSelfExtract=true -p:EnableCompressionInSingleFile=true
- - name: Upload LocyanFrp(Publish,Single File)
+ - name: Upload Kairo(Publish,Single File)
uses: actions/upload-artifact@v4
with:
- name: LoCyanFrpDesktop_dotnet6_publish_SingleFile
- path: ${{ github.workspace }}\LoCyanFrpDesktop\bin\Release\net6.0-windows\win-x64\publish
+ name: Kairo_dotnet9_publish_SingleFile
+ path: ${{ github.workspace }}\Kairo\bin\Release\net9.0-windows\win-x64\publish
if-no-files-found: ignore
diff --git a/.gitignore b/.gitignore
index d0cb9b7..3490afc 100644
--- a/.gitignore
+++ b/.gitignore
@@ -361,4 +361,4 @@ MigrationBackup/
# Fody - auto-generated XML schema
FodyWeavers.xsd
-/LoCyanFrpDesktop/Output
+/Kairo/Output
diff --git a/.idea/.idea.Kairo/.idea/.gitignore b/.idea/.idea.Kairo/.idea/.gitignore
new file mode 100644
index 0000000..879431f
--- /dev/null
+++ b/.idea/.idea.Kairo/.idea/.gitignore
@@ -0,0 +1,13 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Rider ignored files
+/modules.xml
+/projectSettingsUpdater.xml
+/.idea.Kairo.iml
+/contentModel.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/.idea.Kairo/.idea/encodings.xml b/.idea/.idea.Kairo/.idea/encodings.xml
new file mode 100644
index 0000000..df87cf9
--- /dev/null
+++ b/.idea/.idea.Kairo/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Kairo/.idea/indexLayout.xml b/.idea/.idea.Kairo/.idea/indexLayout.xml
new file mode 100644
index 0000000..7b08163
--- /dev/null
+++ b/.idea/.idea.Kairo/.idea/indexLayout.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/.idea.Kairo/.idea/vcs.xml b/.idea/.idea.Kairo/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/.idea.Kairo/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/LoCyanFrpDesktop-Impl.sln b/Kairo.sln
similarity index 82%
rename from LoCyanFrpDesktop-Impl.sln
rename to Kairo.sln
index 5c3bf61..4e6eaf6 100644
--- a/LoCyanFrpDesktop-Impl.sln
+++ b/Kairo.sln
@@ -2,12 +2,10 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.6.33829.357
MinimumVisualStudioVersion = 10.0.40219.1
-Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "LoCyanFrpDesktop", "LoCyanFrpDesktop\LoCyanFrpDesktop.csproj", "{D1D59A31-105D-4B83-A49D-B9F761336995}"
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Kairo", "Kairo\Kairo.csproj", "{D1D59A31-105D-4B83-A49D-B9F761336995}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Updater", "Updater\Updater.csproj", "{1C846730-8BC3-49D4-8786-106AF8C4D160}"
EndProject
-Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "LoCyanFrp", "LoCyanFrp", "{0301C876-91BE-4AE9-92C9-254EBFA8B940}"
-EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tools", "Tools", "{7A9FD3C3-52EE-4162-B97A-6F7EB2F1821C}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{642C59C0-F62F-4AD8-9951-1625AED50385}"
@@ -37,8 +35,6 @@ Global
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{1C846730-8BC3-49D4-8786-106AF8C4D160} = {7A9FD3C3-52EE-4162-B97A-6F7EB2F1821C}
- {7A9FD3C3-52EE-4162-B97A-6F7EB2F1821C} = {0301C876-91BE-4AE9-92C9-254EBFA8B940}
- {E4C25792-97C8-4E61-B0B3-57E3ED793DC5} = {0301C876-91BE-4AE9-92C9-254EBFA8B940}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {632713F8-B531-4B56-80C3-38FD07E244FA}
diff --git a/LoCyanFrpDesktop/App.config b/Kairo/App.config
similarity index 76%
rename from LoCyanFrpDesktop/App.config
rename to Kairo/App.config
index 06d0306..98cfe07 100644
--- a/LoCyanFrpDesktop/App.config
+++ b/Kairo/App.config
@@ -2,14 +2,14 @@
-
+
-
+
null
@@ -28,6 +28,6 @@
False
-
+
\ No newline at end of file
diff --git a/LoCyanFrpDesktop/App.xaml b/Kairo/App.xaml
similarity index 88%
rename from LoCyanFrpDesktop/App.xaml
rename to Kairo/App.xaml
index 883dceb..924100a 100644
--- a/LoCyanFrpDesktop/App.xaml
+++ b/Kairo/App.xaml
@@ -1,7 +1,7 @@
-
diff --git a/LoCyanFrpDesktop/App.xaml.cs b/Kairo/App.xaml.cs
similarity index 54%
rename from LoCyanFrpDesktop/App.xaml.cs
rename to Kairo/App.xaml.cs
index f544dc9..1ce0e90 100644
--- a/LoCyanFrpDesktop/App.xaml.cs
+++ b/Kairo/App.xaml.cs
@@ -7,12 +7,19 @@
using System.Windows;
using System.Windows.Documents;
using System.IO;
-using LoCyanFrpDesktop.Utils;
+using Kairo.Utils;
using System.Windows.Threading;
using System.Runtime.InteropServices;
using System.Threading;
+using System.Security;
+using System.Runtime.ConstrainedExecution;
+using System.Diagnostics;
+using System.Security.Policy;
+using System.Text.RegularExpressions;
+using System.Text;
+using Kairo.Components.OAuth;
-namespace LoCyanFrpDesktop
+namespace Kairo
{
///
/// App.xaml 的交互逻辑
@@ -20,8 +27,10 @@ namespace LoCyanFrpDesktop
public partial class App : Application
{
- public static string? Username = null;
- public static string? Password = null;
+ private static string? Username = null;
+ private static string? Password = null;
+ private static bool DebugMode = Global.Config.DebugMode;
+ public static bool TokenMode = false;
[DllImport("kernel32.dll", SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
static extern bool AllocConsole();
@@ -34,54 +43,90 @@ public partial class App : Application
protected override void OnStartup(StartupEventArgs e)
{
- //bool openConsole = false;
CrashInterception.Init();
-
+ ConfigManager.Init();
DispatcherUnhandledException += CurrentDomain_UnhandledException;
DispatcherUnhandledException += (_, e) => CrashInterception.ShowException(e.Exception);
- int UsernameNum = 0;
- int PasswordNum = 0;
- bool DebugMode = Global.DebugMode;
- //string Username;
- //string Password;
+
+
// 处理启动参数
+
string[] args = e.Args;
-
+ OAuthCallbackHandler.Init();
+ ProcessStartupParameters(args);
base.OnStartup(e);
-
- Thread.Sleep(3000);
- //MainWindow mainWindow = new();
+ }
+ protected override void OnExit(ExitEventArgs e)
+ {
+ //Cef.Shutdown();
+ base.OnExit(e);
+ }
+ private static void CurrentDomain_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
+ {
+ e.Handled = true;
+ }
+ private static void ProcessStartupParameters(string[] args)
+ {
+ int UsernameNum = 0;
+ int PasswordNum = 0;
if (args.Length > 0)
- {
- int i = 0;
- for (int j = 0; j < args.Count(); j++) {
+ {
+
+ string pattern = @"^locyanfrp://([^/]+)/(\d+)$";
+ Regex regex = new Regex(pattern);
+
+ for (int j = 0; j < args.Count(); j++)
+ {
if (args[j] == "--user" || args[j] == "--User" || args[j] == "--Username" || args[j] == "--username")
{
UsernameNum = j;
}
- else if(args[j] == "--password" || args[j] == "--Password")
+ else if (args[j] == "--password" || args[j] == "--Password")
{
PasswordNum = j;
- }else if(args[j] == "--debug")
+ }
+ else if (args[j] == "--debug")
{
DebugMode = true;
}
+ else
+ {
+ string url = args[j];
+ Match match = regex.Match(url);
+ if (match.Success) {
+ Console.WriteLine($"Received URL: {url}");
+ string[] parsedParameters = new string[]
+ {
+ match.Groups[1].Value,
+ match.Groups[2].Value
+ };
+ TokenMode = true;
+ DashBoard_Token dashBoard_Token = new DashBoard_Token(match.Groups[1].Value, int.Parse(match.Groups[2].Value));
+ dashBoard_Token.Show();
+
+ }
+ }
}
int Num = UsernameNum - PasswordNum;
- if (Num >= 2 && Num <= -2) {
+ if (Num >= 2 && Num <= -2)
+ {
Username = args[UsernameNum + 1];
Password = args[PasswordNum + 1];
if (Password != null && Username != null)
{
- LoCyanFrpDesktop.Properties.Settings.Default.username = Username;
- LoCyanFrpDesktop.Properties.Settings.Default.password = Password;
+ Global.Config.Username = Username;
+ foreach (char c in Password.ToCharArray())
+ {
+ Global.Password.AppendChar(c);
+ }
+
Global.LoginedByConsole = true;
}
}
-
+
if (DebugMode)
{
AllocConsole(); // 打开控制台
@@ -92,39 +137,18 @@ protected override void OnStartup(StartupEventArgs e)
}
// 解析和处理参数
// 这里可以根据参数的内容执行不同的操作
- ProcessUrlParameters(args);
- for (int x = 0; x < args.Count(); x++) {
+ for (int x = 0; x < args.Count(); x++)
+ {
if (x != args.Count() - 1)
{
Console.Write(args[x]);
}
- else {
+ else
+ {
Console.WriteLine(args[x]);
}
}
}
-
- }
- private static void CurrentDomain_UnhandledException(object sender, DispatcherUnhandledExceptionEventArgs e)
- {
- e.Handled = true;
- }
- private void ProcessUrlParameters(string[] args)
- {
- string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
- string filePath = Path.Combine(documentsPath, "auto_launch.ini");
-
- string arguments = string.Join(" ", args);
-
- try
- {
- File.WriteAllText(filePath, arguments);
- }
- catch (Exception ex)
- {
- // 处理写入文件时可能发生的异常
- MessageBox.Show("写入文件时出现错误:" + ex.Message);
- }
}
}
}
diff --git a/LoCyanFrpDesktop/Utils/Download.xaml b/Kairo/Components/Download.xaml
similarity index 90%
rename from LoCyanFrpDesktop/Utils/Download.xaml
rename to Kairo/Components/Download.xaml
index b671b20..055c1a7 100644
--- a/LoCyanFrpDesktop/Utils/Download.xaml
+++ b/Kairo/Components/Download.xaml
@@ -1,16 +1,16 @@
/// Interaction logic for Downloader.xaml
@@ -43,6 +44,7 @@ public partial class Download : UiWindow
public static string DownloadPath = AppDomain.CurrentDomain.BaseDirectory;
public string DownloadUnit = "KB/s";
public static string FolderName;
+ public static bool UsingMirror;
public Download()
{
InitializeComponent();
@@ -155,7 +157,7 @@ private void OnDownloadFileCompleted(object? sender, AsyncCompletedEventArgs e)
{
Console.Error.WriteLine(e.Error);
CrashInterception.ShowException(e.Error);
- Logger.MsgBox("无法下载FRP, 请检查您的网络连接","LocyanFrp",0,48,1);
+ Logger.MsgBox("无法下载FRP, 请检查您的网络连接","Kairo",0,48,1);
this.Owner = null;
Close();
return;
@@ -203,43 +205,12 @@ public void UnpackAndAutoSetup()
{
//CrashInterception.ShowException(ex);
}
- Properties.Settings.Default.FrpcPath = path;
- var ConfigPath = Path.Combine(DownloadPath, "FrpcPath.conf");
-
- if (File.Exists(ConfigPath))
- {
- StreamReader sr = new StreamReader(ConfigPath);
- if (string.IsNullOrEmpty(sr.ReadLine()))
- {
- sr.Close();
- StreamWriter sw = new StreamWriter(ConfigPath);
- sw.WriteLine(path);
- sw.Close();
- }
- else
- {
- sr.Close();
- File.Delete(ConfigPath);
- File.Create(ConfigPath);
- StreamWriter sw = new StreamWriter(ConfigPath);
- sw.WriteLine(path);
- sw.Close();
- }
- }
- else
- {
- File.Create(ConfigPath);
- StreamWriter sw = new StreamWriter(ConfigPath);
- sw.WriteLine(path);
- sw.Close();
-
- }
-
-
-
+ Global.Config.FrpcPath = path;
+ this.Owner = null;
Close();
}
catch (Exception ex) {
+ this.Owner = null;
this.Close();
CrashInterception.ShowException(ex);
@@ -288,10 +259,10 @@ public static async Task DownloadFile(string url,string path)
}
private async void StartDownload()
{
- var a = await RequestAPIandParse("https://api-gh.1l1.icu/repos/LoCyan-Team/LoCyanFrpPureApp/releases/latest",true);
+ var a = await RequestAPIandParse("https://api-gh.1l1.icu/repos/LoCyan-Team/LocyanFrpPureApp/releases/latest",true);
if (!a)
{
- await RequestAPIandParse("https://api.github.com/repos/LoCyan-Team/LoCyanFrpPureApp/releases/latest", false);
+ await RequestAPIandParse("https://api.github.com/repos/LoCyan-Team/LocyanFrpPureApp/releases/latest", false);
}
}
private static async Task RequestAPIandParse(string url,bool mirror)
@@ -313,11 +284,13 @@ private static async Task RequestAPIandParse(string url,bool mirror)
Match match = Regex.Match(DownloadVersion, pattern);
var Version = match.Groups[1].Value;
string architecture = RuntimeInformation.OSArchitecture.ToString();
- var MirrorAddress = (mirror ? "https://proxy-gh.1l1.icu/" : "");
+ var MirrorAddress = (mirror ? "https://proxy-gh.1l1.icu/" : "https://proxy-gh.1l1.icu/https://github.com/LoCyan-Team/LocyanFrpPureApp/releases/download/");
+ var ActualAddress = (Global.Config.UsingDownloadMirror ? "https://mirrors.locyan.cn/github-release/LoCyan-Team/LoCyanFrpPureApp/LatestRelease/" : MirrorAddress + DownloadVersion);
var _architecture = (architecture == "X86" ? "386" : "amd64");
- TheFuckingLink = $"{MirrorAddress}https://github.com/LoCyan-Team/LoCyanFrpPureApp/releases/download/{DownloadVersion}/frp_LoCyanFrp-{Version}_windows_{_architecture}.zip";
+ FolderName = $"frp_LoCyanFrp-{Version}_windows_{_architecture}";
+ TheFuckingLink = $"{ActualAddress}{FolderName}.zip";
- FolderName = $"frp_LoCyanFrp-{Version}_windows_amd64";
+
Console.WriteLine(TheFuckingLink);
await DownloadFile(TheFuckingLink, DownloadPath);
diff --git a/Kairo/Components/OAuth/Controllers/MainController.cs b/Kairo/Components/OAuth/Controllers/MainController.cs
new file mode 100644
index 0000000..b90e195
--- /dev/null
+++ b/Kairo/Components/OAuth/Controllers/MainController.cs
@@ -0,0 +1,18 @@
+using Kairo.Utils;
+using Microsoft.AspNetCore.Mvc;
+using System;
+
+namespace Kairo.Components.OAuth.Controllers
+{
+ [ApiController]
+ [Route("oauth")]
+ public class MainController : Controller
+ {
+ [HttpGet("callback")]
+ public IActionResult Callback() {
+ Access.MainWindow.Login(Request.Query["refresh_token"]);
+ Console.WriteLine(Request.Query["refresh_token"]);
+ return Ok();
+ }
+ }
+}
diff --git a/Kairo/Components/OAuth/OAuthCallbackHandler.cs b/Kairo/Components/OAuth/OAuthCallbackHandler.cs
new file mode 100644
index 0000000..06cea0d
--- /dev/null
+++ b/Kairo/Components/OAuth/OAuthCallbackHandler.cs
@@ -0,0 +1,25 @@
+using Microsoft.AspNetCore.Builder;
+using Microsoft.Extensions.DependencyInjection;
+using System.Threading.Tasks;
+
+namespace Kairo.Components.OAuth
+{
+ class OAuthCallbackHandler
+ {
+ public OAuthCallbackHandler() {
+
+ }
+ public static void Init()
+ {
+ Task.Run(() => {
+ string[] a = { "--urls=http://localhost:16092" };
+ WebApplicationBuilder builder = WebApplication.CreateBuilder(a);
+ builder.Services.AddControllers();
+ WebApplication app = builder.Build();
+ app.UseRouting();
+ app.MapControllers();
+ app.RunAsync();
+ });
+ }
+ }
+}
diff --git a/Kairo/Components/ProxyCreator.xaml b/Kairo/Components/ProxyCreator.xaml
new file mode 100644
index 0000000..fdc94a7
--- /dev/null
+++ b/Kairo/Components/ProxyCreator.xaml
@@ -0,0 +1,50 @@
+
+
+
+
+
+
+
+
+
+
+ 隧道名字
+
+
+
+
+
+ 隧道类型
+
+ TCP
+ UDP
+ HTTP
+ HTTPS
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/LoCyanFrpDesktop/UserCenter.xaml.cs b/Kairo/Components/ProxyCreator.xaml.cs
similarity index 72%
rename from LoCyanFrpDesktop/UserCenter.xaml.cs
rename to Kairo/Components/ProxyCreator.xaml.cs
index 8735c0b..de52c90 100644
--- a/LoCyanFrpDesktop/UserCenter.xaml.cs
+++ b/Kairo/Components/ProxyCreator.xaml.cs
@@ -11,15 +11,16 @@
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
+using Wpf.Ui.Controls;
-namespace LoCyanFrpDesktop
+namespace Kairo.Components
{
///
- /// UserCenter.xaml 的交互逻辑
+ /// Interaction logic for ProxyCreator.xaml
///
- public partial class UserCenter : Window
+ public partial class ProxyCreator : UiWindow
{
- public UserCenter()
+ public ProxyCreator()
{
InitializeComponent();
}
diff --git a/Kairo/Components/Update.xaml b/Kairo/Components/Update.xaml
new file mode 100644
index 0000000..95996bb
--- /dev/null
+++ b/Kairo/Components/Update.xaml
@@ -0,0 +1,44 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Kairo/Components/Update.xaml.cs b/Kairo/Components/Update.xaml.cs
new file mode 100644
index 0000000..5d0d034
--- /dev/null
+++ b/Kairo/Components/Update.xaml.cs
@@ -0,0 +1,43 @@
+using Kairo.Utils;
+using System.Runtime.CompilerServices;
+using System.Windows.Threading;
+using Wpf.Ui.Controls;
+
+namespace Kairo.Components
+{
+ ///
+ /// Interaction logic for Window1.xaml
+ ///
+ public partial class Update : UiWindow
+ {
+ private UpdateInfo updateInfos;
+ public Update()
+ {
+ Access.Update = this;
+ InitializeComponent();
+ }
+ public void RefreshData(UpdateInfo updateInfo)
+ {
+ updateInfos = updateInfo;
+ Dispatcher.Invoke(() =>
+ {
+ IncomingVersion.Text = $"Ver{updateInfo.Version}-{updateInfo.Channel}.{updateInfo.Subversion}";
+ foreach(string i in updateInfo.UpdatedWhat)
+ {
+ UpdateInfos.Items.Add(i);
+ }
+
+ });
+
+ }
+ private void Confirm_Click(object sender, System.Windows.RoutedEventArgs e)
+ {
+ Utils.Update.DownloadUpdate(updateInfos);
+ }
+
+ private void Cancel_Click(object sender, System.Windows.RoutedEventArgs e)
+ {
+ Access.Update.Close();
+ }
+ }
+}
diff --git a/LoCyanFrpDesktop/DashBoard.xaml b/Kairo/DashBoard.xaml
similarity index 81%
rename from LoCyanFrpDesktop/DashBoard.xaml
rename to Kairo/DashBoard.xaml
index 09b1510..008c456 100644
--- a/LoCyanFrpDesktop/DashBoard.xaml
+++ b/Kairo/DashBoard.xaml
@@ -1,21 +1,21 @@
-
+ Icon="/Resource/favicon2.ico">
@@ -55,11 +55,17 @@
SelectedPageIndex="0">
+ Content="开始"
+ Icon="Home24"
+ PageTag="Home"
+ PageType="{x:Type Dashboard:Home}" />
+
/// DashBoard.xaml 的交互逻辑
@@ -35,18 +37,14 @@ namespace LoCyanFrpDesktop
public partial class DashBoard : UiWindow
{
public static bool isFrpcInstalled;
- //public static Snackbar Snackbar = new Snackbar();
- public static string FrpcPathConfig = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "FrpcPath.conf");
- public double originalCenterX;
- public double originalCenterY;
+ private static SolidColorBrush DarkBrush = new SolidColorBrush(Color.FromRgb(32, 32, 32));
+ private static SolidColorBrush LightBrush = new SolidColorBrush(Color.FromRgb(250, 250, 250));
///
///
///
public DashBoard()
{
InitializeComponent();
- Uri iconUri = new Uri("pack://application:,,,/LoCyanFrpDesktop;component/Resource/favicon.ico", UriKind.RelativeOrAbsolute);
- this.Icon = new BitmapImage(iconUri);
Access.DashBoard = this;
@@ -55,39 +53,9 @@ public DashBoard()
public bool CheckIfFrpcInstalled()
{
- if (!File.Exists(FrpcPathConfig))
+ if (!string.IsNullOrEmpty(Global.Config.FrpcPath))
{
- File.Create(FrpcPathConfig);
- bool isConfirmed = Logger.MsgBox("您需要我们自动为您安装frpc吗?", "未检测到您安装的frpc", 1, 47, 1);
- if(isConfirmed)
- {
- DownloadFrpc();
- }
- return false;
- }else
- {
- StreamReader PathConfig = new StreamReader(FrpcPathConfig);
- string line = PathConfig.ReadLine();
- PathConfig.Close();
- if (line != null)
- {
- if (!File.Exists(line))
- {
- bool isConfirmed = Logger.MsgBox("您需要我们自动为您安装frpc吗?", "未检测到您安装的frpc", 1, 47, 1);
- if (isConfirmed)
- {
- DownloadFrpc();
- }
- return false;
- }
- else
- {
- Properties.Settings.Default.FrpcPath = line;
- return true;
- }
-
- }
- else
+ if (!File.Exists(Global.Config.FrpcPath))
{
bool isConfirmed = Logger.MsgBox("您需要我们自动为您安装frpc吗?", "未检测到您安装的frpc", 1, 47, 1);
if (isConfirmed)
@@ -96,22 +64,24 @@ public bool CheckIfFrpcInstalled()
}
return false;
}
-
-
+ else
+ {
+ return true;
+ }
+
+ }
+ else
+ {
+ bool isConfirmed = Logger.MsgBox("您需要我们自动为您安装frpc吗?", "未检测到您安装的frpc", 1, 47, 1);
+ if (isConfirmed)
+ {
+ DownloadFrpc();
+ }
+ return false;
}
-
- return false;
}
public void DownloadFrpc()
{
- //double screenWidth = SystemParameters.WorkArea.Width;
- //double screenHeight = SystemParameters.WorkArea.Height;
-
- // 获取原窗口的中心点
- //originalCenterX = Owner.Left + Owner.Width / 2;
- //originalCenterY = Owner.Top + Owner.Height / 2;
- //Left = originalCenterX - Width / 2;
- //Top = originalCenterY - Height / 2;
Download downloader = new Download();
downloader.Owner = this;
downloader.Show();
@@ -130,9 +100,7 @@ private void UiWindow_Closing(object sender, CancelEventArgs e)
Hide();
}
public void UiWindow_StateChanged(object sender, EventArgs e)
- {/*
- MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight;
- MaxWidth = SystemParameters.MaximizedPrimaryScreenWidth; */
+ {
}
public void UiWindow_ContentRendered(object sender, EventArgs e)
{
@@ -152,10 +120,25 @@ public void Exit_Click(object sender, RoutedEventArgs e)
}
public void UiWindow_Loaded(object sender, EventArgs e)
{
- Resources["ShadowColor"] = MainWindow.DarkThemeEnabled ? Colors.White : Colors.LightGray; ;
- Resources["MainBackgroundColor"] = new SolidColorBrush(MainWindow.DarkThemeEnabled ? Colors.LightGray : Colors.WhiteSmoke);
+ ChangeColor();
+ }
+ public void ChangeColor()
+ {
+ Resources["ShadowColor"] = Global.isDarkThemeEnabled ? Colors.White : Colors.LightGray;
+ SolidColorBrush solidColorBrush = new SolidColorBrush(Global.isDarkThemeEnabled ? Colors.LightGray : Colors.WhiteSmoke);
+ Resources["MainBackgroundColor"] = solidColorBrush;
+ if (Global.isDarkThemeEnabled)
+ {
+ this.Background = DarkBrush;
+ Theme.Apply(ThemeType.Dark);
+ }
+ else {
+ this.Background = LightBrush;
+ Theme.Apply(ThemeType.Light);
+ }
+ //Theme.Apply(Global.isDarkThemeEnabled ? ThemeType.Dark : ThemeType.Light);
+ //this.Background = solidColorBrush;
}
-
}
}
diff --git a/Kairo/DashBoard_Token.xaml b/Kairo/DashBoard_Token.xaml
new file mode 100644
index 0000000..c10d94b
--- /dev/null
+++ b/Kairo/DashBoard_Token.xaml
@@ -0,0 +1,87 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Kairo/DashBoard_Token.xaml.cs b/Kairo/DashBoard_Token.xaml.cs
new file mode 100644
index 0000000..29bc0a0
--- /dev/null
+++ b/Kairo/DashBoard_Token.xaml.cs
@@ -0,0 +1,185 @@
+using Kairo.Utils;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Shapes;
+using Wpf.Ui.Appearance;
+using Wpf.Ui.Common;
+using Wpf.Ui.Controls;
+using static Kairo.Utils.PNAP;
+
+namespace Kairo
+{
+ ///
+ /// Interaction logic for DashBoard_Token.xaml
+ ///
+ public partial class DashBoard_Token : UiWindow
+ {
+
+ public static bool isFrpcInstalled;
+ private static SolidColorBrush DarkBrush = new SolidColorBrush(Color.FromRgb(32, 32, 32));
+ private static SolidColorBrush LightBrush = new SolidColorBrush(Color.FromRgb(250, 250, 250));
+ public DashBoard_Token(string Token, int Proxy)
+ {
+ InitializeComponent();
+ if (CheckIfFrpcInstalled())
+ {
+ RunCmdCommand($" -u {Token} -p ", Proxy);
+ }
+
+
+ }
+ private static void SortOutputHandler(object sender, DataReceivedEventArgs e)
+ {
+ if (!string.IsNullOrEmpty(e.Data))
+ {
+ Logger.Output(LogType.Info, e.Data);
+ }
+ }
+ private static void RunCmdCommand(string command, int ProxyID)
+ {
+ // 创建一个 ProcessStartInfo 对象
+ ProcessStartInfo psi = new ProcessStartInfo
+ {
+ FileName = Global.Config.FrpcPath, // 指定要运行的命令行程序
+ Arguments = command + ProxyID, // 使用 /k 参数保持 cmd 窗口打开,显示输出内容
+ Verb = "runas",
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false, // 设置为 true 以便在新窗口中显示命令行窗口
+ CreateNoWindow = true, // 设置为 false 以显示命令行窗口
+ StandardOutputEncoding = Encoding.UTF8
+ };
+ // 启动进程
+ Process _FrpcProcess = Process.Start(psi);
+ _FrpcProcess.BeginOutputReadLine();
+
+ _FrpcProcess.OutputDataReceived += SortOutputHandler;
+ _FrpcProcess.EnableRaisingEvents = true;
+
+ // 读取标准输出和标准错误输出
+ //string output = process.StandardOutput.ReadToEnd();
+ //string error = process.StandardError.ReadToEnd();
+
+ // 等待进程完成
+ //process.WaitForExit();
+
+ // 打印输出
+ //Console.WriteLine("Output:\n" + output);
+ //Console.WriteLine("Error:\n" + error);
+
+ // 可以将输出存储到变量中,以便后续处理
+ // string combinedOutput = output + error;
+ }
+ public bool CheckIfFrpcInstalled()
+ {
+ if (!string.IsNullOrEmpty(Global.Config.FrpcPath))
+ {
+ if (!File.Exists(Global.Config.FrpcPath))
+ {
+ bool isConfirmed = Logger.MsgBox("您需要我们自动为您安装frpc吗?", "未检测到您安装的frpc", 1, 47, 1);
+ if (isConfirmed)
+ {
+ DownloadFrpc();
+ }
+ else
+ {
+ Environment.Exit(0);
+ }
+ return false;
+ }
+ else
+ {
+ return true;
+ }
+
+ }
+ else
+ {
+ bool isConfirmed = Logger.MsgBox("您需要我们自动为您安装frpc吗?", "未检测到您安装的frpc", 1, 47, 1);
+ if (isConfirmed)
+ {
+ DownloadFrpc();
+ }
+ else
+ {
+ Environment.Exit(0);
+ }
+ return false;
+ }
+ return false;
+ }
+ public void DownloadFrpc()
+ {
+ Download downloader = new Download();
+ downloader.Owner = this;
+ downloader.Show();
+ }
+ public void OpenSnackbar(string title, string message, SymbolRegular icon)
+ {
+ Dispatcher.Invoke(() =>
+ {
+ Snackbar.Show(title, message, icon);
+ });
+ }
+ private void UiWindow_Closing(object sender, CancelEventArgs e)
+ {
+ e.Cancel = true;
+ ShowInTaskbar = false;
+ Hide();
+ }
+ public void UiWindow_StateChanged(object sender, EventArgs e)
+ {
+ }
+ public void UiWindow_ContentRendered(object sender, EventArgs e)
+ {
+
+ }
+ public void UiWindow_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
+ => ShowInTaskbar = IsVisible;
+ public void Hide_Click(object sender, RoutedEventArgs e)
+ {
+ ShowInTaskbar = false;
+ Hide();
+ }
+
+ public void Exit_Click(object sender, RoutedEventArgs e)
+ {
+ Environment.Exit(0);
+ }
+ public void UiWindow_Loaded(object sender, EventArgs e)
+ {
+ ChangeColor();
+ }
+ public void ChangeColor()
+ {
+ Resources["ShadowColor"] = Global.isDarkThemeEnabled ? Colors.White : Colors.LightGray;
+ SolidColorBrush solidColorBrush = new SolidColorBrush(Global.isDarkThemeEnabled ? Colors.LightGray : Colors.WhiteSmoke);
+ Resources["MainBackgroundColor"] = solidColorBrush;
+ if (Global.isDarkThemeEnabled)
+ {
+ this.Background = DarkBrush;
+ Theme.Apply(ThemeType.Dark);
+ }
+ else
+ {
+ this.Background = LightBrush;
+ Theme.Apply(ThemeType.Light);
+ }
+ //Theme.Apply(Global.isDarkThemeEnabled ? ThemeType.Dark : ThemeType.Light);
+ //this.Background = solidColorBrush;
+ }
+ }
+}
diff --git a/Kairo/Dashboard/Home.xaml b/Kairo/Dashboard/Home.xaml
new file mode 100644
index 0000000..897293d
--- /dev/null
+++ b/Kairo/Dashboard/Home.xaml
@@ -0,0 +1,78 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Kairo/Dashboard/Home.xaml.cs b/Kairo/Dashboard/Home.xaml.cs
new file mode 100644
index 0000000..c42c018
--- /dev/null
+++ b/Kairo/Dashboard/Home.xaml.cs
@@ -0,0 +1,235 @@
+using Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using System;
+using System.Net.Http;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using Wpf.Ui.Controls;
+using Kairo.Utils;
+using System.Windows.Threading;
+using System.IO;
+using Kairo.Extensions;
+using System.Security.Cryptography;
+using Markdig;
+using HtmlAgilityPack;
+using System.Linq;
+using System.Windows;
+using System.Threading.Tasks;
+
+
+namespace Kairo.Dashboard
+{
+ ///
+ /// Interaction logic for ProxyList.xaml
+ ///
+ public partial class Home : UiPage
+ {
+ public static ImageBrush AvatarImage;
+ public Home()
+ {
+ InitializeCustomComponents();
+ RefreshAvatar();
+ Task.Run(() => {
+
+ FetchAnnouncement();
+ CheckIsSignedTodayOrNot();
+ });
+ }
+
+ private async void CheckIsSignedTodayOrNot()
+ {
+ using (HttpClient hc = new())
+ {
+ hc.DefaultRequestHeaders.Add("Authorization",$"Bearer {Global.Config.AccessToken}");
+ var result = await hc.GetAsync($"{Global.API}/sign?user_id={Global.Config.ID}").Await().Content.ReadAsStringAsync();
+ if (result == null) return;
+ var temp = JObject.Parse(result);
+ if (int.Parse(temp["status"].ToString()) == 200)
+ {
+ if ((bool)temp["data"]["status"])
+ {
+ Dispatcher.BeginInvoke(() =>
+ {
+ ToSign.Visibility = Visibility.Hidden;
+ SignStatus.Visibility = Visibility.Visible;
+ });
+ }
+ }
+ else
+ {
+ Console.WriteLine(temp["status"].ToString() + temp["message"].ToString());
+ }
+
+ }
+ }
+
+ private void InitializeCustomComponents()
+ {
+ InitializeComponent();
+ DataContext = this;
+ title_username.Text += Global.Config.Username;
+ Resources["BorderColor"] = Global.isDarkThemeEnabled ? Colors.White : Colors.LightGray;
+ Traffic.Text += $"{(MainWindow.Traffic / 1024)}GB";
+ BandWidth.Text += $"{MainWindow.Inbound * 8 / 1024}/{MainWindow.Outbound * 8 / 1024}Mbps";
+ }
+
+ private async void FetchAnnouncement()
+ {
+ try
+ {
+ using (HttpClient client = new())
+ {
+ var result = await client.GetAsync($"{Global.API}/notice").Await().Content.ReadAsStringAsync();
+ var result2 = JObject.Parse(result);
+ if (result2 != null && int.Parse(result2["status"].ToString()) == 200) {
+ var html = Markdown.ToHtml(result2["data"]["broadcast"].ToString());
+ var htmlDoc = new HtmlDocument();
+ if (Global.isDarkThemeEnabled)
+ {
+ htmlDoc.LoadHtml(html);
+ var cssContent = "* { color: white; } a { color: aqua} html {background: none !important;}";
+ var styleNode = HtmlNode.CreateNode($"");
+ //var scriptNode = HtmlNode.CreateNode("");
+ var newHeadNode = htmlDoc.CreateElement("head");
+ newHeadNode.AppendChild(styleNode);
+ //newHeadNode.AppendChild(scriptNode);
+ htmlDoc.DocumentNode.PrependChild(newHeadNode);
+ InitializeWebView(htmlDoc.DocumentNode.OuterHtml);
+ }
+ else
+ {
+ InitializeWebView(html);
+ }
+
+
+ }
+
+ }
+ }
+ catch (Exception _) {
+ }
+ }
+ private async void InitializeWebView(string a)
+ {
+ //if (!Directory.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WebView2"))) Directory.CreateDirectory(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WebView2"));
+ //await WebViewInstaller.CheckAndInstallAsync(false, false, Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "WebView2"));
+ Dispatcher.BeginInvoke(async () =>
+ {
+ await webView.EnsureCoreWebView2Async();
+ webView.CoreWebView2.NavigateToString(a);
+ });
+
+ }
+ private async void RefreshAvatar()
+ {
+ try
+ {
+ using (var client = new HttpClient())
+ {
+ var Avatar = await client.GetAsync(MainWindow.Avatar).Await().Content.ReadAsStreamAsync();
+ var path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Avatar.png");
+ var ApplyAvatar = () =>
+ {
+ BitmapImage bitmap = new BitmapImage();
+
+ // 设置 BitmapImage 的 UriSource 属性为图片文件的路径
+ bitmap.BeginInit();
+ bitmap.UriSource = new Uri(path, UriKind.RelativeOrAbsolute);
+ bitmap.EndInit();
+ AvatarImage = new ImageBrush(bitmap)
+ {
+ Stretch = Stretch.UniformToFill,
+
+ };
+ Dispatcher.Invoke(() =>
+ {
+ this.Avatar.Background = AvatarImage;
+ });
+ };
+
+ if (File.Exists(path)){
+ MD5 md5 = MD5.Create();
+ if (md5.ComputeHash(Avatar).SequenceEqual(md5.ComputeHash(File.ReadAllBytes("Avatar.png"))))
+ {
+ ApplyAvatar();
+ return;
+ }
+
+ File.Delete(path);
+
+ }
+ using (FileStream fileStream = new(path, FileMode.Create))
+ {
+ byte[] bytes = new byte[Avatar.Length];
+ Avatar.Read(bytes, 0, bytes.Length);
+ // 设置当前流的位置为流的开始
+ Avatar.Seek(0, SeekOrigin.Begin);
+
+ // 把 byte[] 写入文件
+
+ BinaryWriter bw = new BinaryWriter(fileStream);
+ bw.Write(bytes);
+ bw.Close();
+ fileStream.Close();
+ }
+ ApplyAvatar();
+
+ }
+
+ }
+ catch (Exception ex)
+ {
+ Logger.MsgBox("无法获取您的头像, 请稍后重试", "Kairo", 0, 48, 1);
+ }
+ }
+
+ private void ToSign_Click(object sender, RoutedEventArgs e)
+ {
+ Task.Run(() => {
+ using (var hc = new HttpClient())
+ {
+ hc.DefaultRequestHeaders.Add("Authorization", $"Bearer {Global.Config.AccessToken}");
+ HttpResponseMessage responseMessage = hc.PostAsync($"{Global.API}/sign?user_id={Global.Config.ID}",null).Result;
+
+
+ var temp = JObject.Parse(responseMessage.Content.ReadAsStringAsync().Result);
+ if (!string.IsNullOrEmpty(temp.ToString()) && int.Parse(temp["status"].ToString()) == 200) {
+ int i = int.Parse(temp["data"]["get_traffic"].ToString());
+ Logger.MsgBox($"签到成功\n您获得 {i}GB 流量", "Kairo", 0, 48, 1);
+ Dispatcher.BeginInvoke(() =>
+ {
+ Traffic.Text = $"剩余流量: {(MainWindow.Traffic / 1024) + i}GB";
+ });
+ Dispatcher.BeginInvoke(() =>
+ {
+ ToSign.Visibility = Visibility.Collapsed;
+ SignStatus.Visibility = Visibility.Visible;
+ });
+ }
+ if(int.Parse(temp["status"].ToString()) == 403)
+ {
+ if (temp["message"].ToString() == "你今天已经签到过了")
+ {
+
+ Logger.MsgBox("你今天已经签到过了", "Kairo", 0, 48, 1);
+ Dispatcher.BeginInvoke(() =>
+ {
+ ToSign.Visibility = Visibility.Collapsed;
+ SignStatus.Visibility = Visibility.Visible;
+ });
+ return;
+ }
+ Logger.MsgBox("无法连接到服务器, 请检查您的网络链接", "Kairo", 0, 48, 1);
+ return;
+ }
+ if (!responseMessage.IsSuccessStatusCode)
+ {
+ Logger.MsgBox("无法连接到服务器, 请检查您的网络链接", "Kairo", 0, 48, 1);
+ return;
+ }
+ }
+ });
+ }
+ }
+}
+
diff --git a/LoCyanFrpDesktop/Dashboard/ProxyList.xaml b/Kairo/Dashboard/ProxyList.xaml
similarity index 75%
rename from LoCyanFrpDesktop/Dashboard/ProxyList.xaml
rename to Kairo/Dashboard/ProxyList.xaml
index 9c07354..39dad52 100644
--- a/LoCyanFrpDesktop/Dashboard/ProxyList.xaml
+++ b/Kairo/Dashboard/ProxyList.xaml
@@ -1,10 +1,10 @@
@@ -37,7 +37,7 @@
-
+
@@ -48,7 +48,7 @@
-
+
@@ -60,9 +60,9 @@
>
-
-
+
+
@@ -82,26 +82,10 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
diff --git a/LoCyanFrpDesktop/Dashboard/ProxyList.xaml.cs b/Kairo/Dashboard/ProxyList.xaml.cs
similarity index 68%
rename from LoCyanFrpDesktop/Dashboard/ProxyList.xaml.cs
rename to Kairo/Dashboard/ProxyList.xaml.cs
index 23730b5..9a0e650 100644
--- a/LoCyanFrpDesktop/Dashboard/ProxyList.xaml.cs
+++ b/Kairo/Dashboard/ProxyList.xaml.cs
@@ -10,52 +10,37 @@
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
using Wpf.Ui.Controls;
-using LoCyanFrpDesktop.Utils;
-using LoCyanFrpDesktop.Dashboard;
+using Kairo.Utils;
using System.Windows.Threading;
-using System.Text.RegularExpressions;
-using System.IO;
-using static LoCyanFrpDesktop.Utils.PNAP;
-using System.Drawing.Printing;
-using System.Xml.Linq;
-using HandyControl.Tools.Extension;
+using static Kairo.Utils.PNAP;
using MenuItem = Wpf.Ui.Controls.MenuItem;
-using Wpf.Ui.Appearance;
-using System.Reflection;
-using Wpf.Ui.Styles.Controls;
-using ContextMenu2 = Wpf.Ui.Styles.Controls.ContextMenu;
using ContextMenu = System.Windows.Controls.ContextMenu;
-using System.DirectoryServices.ActiveDirectory;
-using System.Printing;
-using Microsoft.Exchange.WebServices.Data;
using System.Windows.Media.Animation;
-using System.Drawing;
using System.Windows.Shapes;
using Brushes = System.Windows.Media.Brushes;
using Color = System.Windows.Media.Color;
-using Brush = System.Windows.Media.Brush;
+using Kairo.Utils.Components;
+using Kairo.Extensions;
+using Newtonsoft.Json.Serialization;
+using Application = System.Windows.Application;
+using HorizontalAlignment = System.Windows.HorizontalAlignment;
+using MouseEventArgs = System.Windows.Input.MouseEventArgs;
using System.Runtime.CompilerServices;
-using LoCyanFrpDesktop.Extensions;
-using Microsoft.Win32.SafeHandles;
-namespace LoCyanFrpDesktop.Dashboard
+namespace Kairo.Dashboard
{
///
/// Interaction logic for ProxyList.xaml
///
public partial class ProxyList : UiPage
{
- public ObservableCollection Proxies { get; set; }
+ public static ObservableCollection Proxies = new ObservableCollection();
- public static List Proxieslist { get; set; }
+ public static List Proxieslist = new List();
//public PNAPListComp ListComponents = new PNAPListComp();
public static List PNAPList = new List();
@@ -67,75 +52,26 @@ public partial class ProxyList : UiPage
public ProxyList()
{
InitializeComponent();
+ Access.ProxyList = this;
InitializeProxiesAsync();
//Wait For Rewrite.
//InitializeAutoLaunch();
DataContext = this;
- title_username.Text += Properties.Settings.Default.username;
- Resources["BorderColor"] = MainWindow.DarkThemeEnabled ? Colors.White : Colors.LightGray;
+ Resources["BorderColor"] = Global.isDarkThemeEnabled ? Colors.White : Colors.LightGray;
//BackgroundColor = Resources["ControlFillColorDefaultBrush"];
BackgroundMenu = new();
//Inbound.Text += MainWindow.Inbound;
//OutBound.Text += MainWindow.Outbound;
- Traffic.Text += (MainWindow.Traffic / 1024) + "GB";
- RefreshAvatar();
- }
- private async void RefreshAvatar()
- {
- try
- {
- using (var client = new HttpClient()) {
- client.BaseAddress = new Uri(MainWindow.Avatar);
- var Avatar = await client.GetAsync(client.BaseAddress).Await().Content.ReadAsStreamAsync();
- var path = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Avatar.png");
-
- if (File.Exists(path))
- {
- File.Delete(path);
- }
-
- using(FileStream fileStream = new(path, FileMode.Create))
- {
- byte[] bytes = new byte[Avatar.Length];
- Avatar.Read(bytes, 0, bytes.Length);
- // 设置当前流的位置为流的开始
- Avatar.Seek(0, SeekOrigin.Begin);
-
- // 把 byte[] 写入文件
-
- BinaryWriter bw = new BinaryWriter(fileStream);
- bw.Write(bytes);
- bw.Close();
- fileStream.Close();
- }
- BitmapImage bitmap = new BitmapImage();
-
- // 设置 BitmapImage 的 UriSource 属性为图片文件的路径
- bitmap.BeginInit();
- bitmap.UriSource = new Uri(path, UriKind.RelativeOrAbsolute);
- bitmap.EndInit();
- var a = new ImageBrush(bitmap)
- {
- Stretch = Stretch.UniformToFill,
-
- };
-
- Dispatcher.Invoke(() =>
- {
- this.Avatar.Background = a;
- });
-
-
- }
-
- }
- catch (Exception ex)
+ if(Home.AvatarImage != null)
{
- Logger.MsgBox("无法获取您的头像, 请稍后重试", "LocyanFrp", 0, 48, 1);
+ Dispatcher.Invoke(() =>
+ {
+ this.Avatar.Background = Home.AvatarImage;
+ });
}
}
- private async void InitializeProxiesAsync()
+ private static async void InitializeProxiesAsync()
{
await GetProxiesListAsync();
// 若返回 null,则表示无隧道或请求失败
@@ -153,30 +89,31 @@ await Dispatcher.InvokeAsync(() =>
}
// 封装隧道获取,采用异步请求防止主线程卡死
- private async Task> GetProxiesListAsync()
+ private static async Task> GetProxiesListAsync()
{
- // 获取用户名和Token
- string username = Properties.Settings.Default.username;
- string token = Properties.Settings.Default.LoginToken;
// 实例化序列
GetProxiesResponseObject responseObject;
// 创建新的 HttpClient 实例
using (var client = new HttpClient())
{
// 定义API链接
- string url = $"https://api.locyanfrp.cn/Proxies/GetProxiesList?username={username}&token={token}";
-
+ string url = $"{Global.API}/proxy/all?user_id={Global.Config.ID}";
+ client.DefaultRequestHeaders.Add("Authorization", $"Bearer {Global.Config.AccessToken}");
// 防止API报错
try
{
// 等待请求
HttpResponseMessage response = await client.GetAsync(url);
- // 确保请求完成
- response.EnsureSuccessStatusCode();
- // 结果转换为字符串
string jsonString = await response.Content.ReadAsStringAsync();
+ // 确保请求完成
+ var temp = JObject.Parse(jsonString);
// 结果序列化
- responseObject = JsonConvert.DeserializeObject(jsonString);
+ responseObject = JsonConvert.DeserializeObject(temp["data"].ToString());
+ responseObject.Status = int.Parse(temp["status"].ToString());
+
+ // 结果转换为字符串
+
+
}
catch (Exception ex)
{
@@ -186,9 +123,13 @@ private async Task> GetProxiesListAsync()
}
}
- if (responseObject.Status != 0)
+ if (responseObject.Status != 200)
{
- Logger.MsgBox("获取隧道失败,请重启软件重新登陆账号", "LocyanFrp", 0, 48, 1);
+ if(responseObject.Status == 404)
+ {
+ return null;
+ }
+ Logger.MsgBox("获取隧道失败,请重启软件重新登陆账号", "Kairo", 0, 48, 1);
return null;
}
@@ -197,19 +138,9 @@ private async Task> GetProxiesListAsync()
for (int i = 0; i < responseObject.Proxies.Count; i++)
{
Console.WriteLine(i);
- Dispatcher.Invoke(() =>
+ Application.Current.Dispatcher.Invoke(() =>
{
- ListPanel.Children.Add(new ProxyCard(responseObject.Proxies[i], i));
- /*ListPanel.Children.Add(new Card()
- {
- //Background = new SolidColorBrush(Colors.White),
- Padding = new Thickness(10),
- Margin = new Thickness(0, 0, 10, 0),
- HorizontalAlignment = HorizontalAlignment.Stretch,
- VerticalAlignment = VerticalAlignment.Stretch,
- MinHeight = 50,
- MinWidth = 100
- });*/
+ Access.ProxyList.ListPanel.Children.Add(new ProxyCard(responseObject.Proxies[i], i));
});
@@ -220,13 +151,32 @@ private async Task> GetProxiesListAsync()
return proxies;
}
+ private static async void RefreshProxyListAsync()
+ {
+ try{
+ Proxieslist.Clear();
+ PNAPList.Clear();
+ }
+ catch
+ {
+ }
+ Application.Current.Dispatcher.BeginInvoke(() => {
+ Access.ProxyList.ListPanel.Children.Clear();
+ });
+ InitializeProxiesAsync();
+ }
private static int ProxyStarter(string SelectedProxy,int SelectedIndex)
{
string proxy_name = SelectedProxy;
int proxy_id = 0;
+ if (Global.Config.FrpcPath == null)
+ {
+ Logger.MsgBox("您尚未安装Frpc,请先安装或者手动指定", "Kairo", 0, 48, 1);
+ return 0;
+ }
foreach (var item in Proxieslist)
{
if (item.ProxyName == proxy_name)
@@ -238,16 +188,16 @@ private static int ProxyStarter(string SelectedProxy,int SelectedIndex)
if (proxy_id == 0)
{
- Logger.MsgBox("无法将隧道名解析为隧道ID,请检查自己的隧道配置", "LocyanFrp", 0, 48, 1);
+ Logger.MsgBox("无法将隧道名解析为隧道ID,请检查自己的隧道配置", "Kairo", 0, 48, 1);
return 0;
}
- Access.DashBoard.Navigation.Navigate(1);
+ Access.DashBoard.Navigation.Navigate(2);
// 运行frp
try
{
if (PNAP.PNAPList.Any(prcs => prcs.ProcessName == proxy_id))
{
- Logger.MsgBox("这个隧道已经启动了哦", "LocyanFrp", 0, 48, 1);
+ Logger.MsgBox("这个隧道已经启动了哦", "Kairo", 0, 48, 1);
return 0;
}
@@ -255,9 +205,9 @@ private static int ProxyStarter(string SelectedProxy,int SelectedIndex)
catch (Exception ex)
{
- return RunCmdCommand($" -u {Properties.Settings.Default.FrpToken} -p ", proxy_id, SelectedIndex);
+ return RunCmdCommand($" -u {Global.Config.FrpToken} -p ", proxy_id, SelectedIndex);
}
- return RunCmdCommand($" -u {Properties.Settings.Default.FrpToken} -p ",proxy_id, SelectedIndex);
+ return RunCmdCommand($" -u {Global.Config.FrpToken} -p ",proxy_id, SelectedIndex);
}
@@ -280,7 +230,7 @@ private static int RunCmdCommand(string command, int ProxyID, int SelectionIndex
// 创建一个 ProcessStartInfo 对象
ProcessStartInfo psi = new ProcessStartInfo
{
- FileName = Properties.Settings.Default.FrpcPath, // 指定要运行的命令行程序
+ FileName = Global.Config.FrpcPath, // 指定要运行的命令行程序
Arguments = command + ProxyID, // 使用 /k 参数保持 cmd 窗口打开,显示输出内容
Verb = "runas",
RedirectStandardOutput = true,
@@ -338,13 +288,9 @@ private static void _FrpcProcess_Exited(object? sender, EventArgs e, int index)
{
Cards[index].IndicatorLight.Stroke = Brushes.Gray;
});
+ PNAPList[PNAPList.FindIndex(a => a.ListIndex == index)].IsRunning = false;
}
- private void NonStaticExitedEventHandler(int index) {
- Dispatcher.Invoke(() =>
- {
- Cards[index].IndicatorLight.Stroke = Brushes.Gray;
- });
- }
+
private static void SortOutputHandler(object sender, DataReceivedEventArgs e)
{
if (!string.IsNullOrEmpty(e.Data))
@@ -363,35 +309,6 @@ private void ListView_MouseDown(object sender, MouseEventArgs e)
}
-
-
-
- /*private void InitializeAutoLaunch()
-{
- string documentsPath = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
- string filePath = Path.Combine(documentsPath, "auto_launch.ini");
-
- if (File.Exists(filePath))
- {
- string url = File.ReadAllText(filePath);
-
- // 使用正则表达式提取token和id
- Match match = Regex.Match(url, @"locyanfrp://([^/]+)/([^/]+)");
-
- if (match.Success && match.Groups.Count == 3)
- {
- string token = match.Groups[1].Value;
- string id = match.Groups[2].Value;
- RunCmdCommand($" -u {token} -p {id}");
- File.Delete(filePath);
- }
- else
- {
- System.Windows.MessageBox.Show($"自动启动出错 \n url: {url} \n filepath: {filePath}", "警告");
- }
- }
-
-}*/
private void ListCardClickHandler(object sender, MouseButtonEventArgs e)
{
@@ -413,6 +330,7 @@ public class ProxyCard : Border
Stroke = new SolidColorBrush(Colors.Gray)
};
+ private ProxyMenu temp;
public ProxyCard(Proxy ProxyInfo, int CardIndex)
{
IndexID = CardIndex;
@@ -424,7 +342,7 @@ public ProxyCard(Proxy ProxyInfo, int CardIndex)
//this.OverridesDefaultStyle = true;
//this.Style = ProxyList.card.Style;
//Theme.Apply(ThemeType.Light);
- this.Background = new SolidColorBrush(MainWindow.DarkThemeEnabled ? Color.FromRgb(53, 53, 53) : Color.FromRgb(210, 210, 210));
+ this.Background = new SolidColorBrush(Global.isDarkThemeEnabled ? Color.FromRgb(53,53,53) : Color.FromRgb(245, 245, 245));
//this.Background = new SolidColorBrush(!string.IsNullOrEmpty((string)ProxyList.BackgroundColor) ? (Color)ProxyList.BackgroundColor : Colors.Gray);
//this.Background = new SolidColorBrush((Color)ProxyList.BackgroundColor);
this.BorderThickness = new Thickness(2);
@@ -465,12 +383,13 @@ public ProxyCard(Proxy ProxyInfo, int CardIndex)
//dockPanel.Children.Add();
- ProxyMenu temp = new ProxyMenu(ProxyInfo.ProxyName, CardIndex,this);
+ temp = new ProxyMenu(ProxyInfo.ProxyName, CardIndex,this);
temp.ID = ProxyInfo.Id;
this.ContextMenu = temp;
//dockPanel.Children.Add(temp);
//this.AddChild(temp);
-
+
+ this.MouseLeftButtonDown += this.OnMouseLeftButtonDown;
this.MouseRightButtonDown += this.OnMouseRightButtonDown;
this.MouseEnter += this.OnMouseEnter;
this.MouseLeave += this.OnMouseLeave;
@@ -480,9 +399,17 @@ private void OnMouseRightButtonDown(object sender, MouseButtonEventArgs e)
}
- private void ProxyCard_MouseDoubleClick(object sender, MouseButtonEventArgs e)
+ private int ClickTimestamp = 0;
+ private void OnMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
- //StartProxy_Click(sender, e);
+ Console.WriteLine(e.Timestamp);
+ if (e.Timestamp - ClickTimestamp < 500 && ClickTimestamp != 0)
+ {
+
+ temp.StartProxy_Click(sender, e);
+
+ }
+ ClickTimestamp = e.Timestamp;
}
private void OnMouseEnter(object sender, EventArgs e)
{
@@ -502,10 +429,10 @@ private void OnMouseLeave(object sender, EventArgs e)
try
{
border.BorderBrush.BeginAnimation(SolidColorBrush.ColorProperty, colorAnimation);
+
}
catch { }
-
}
}
public class ProxyMenu : ContextMenu
@@ -527,10 +454,10 @@ public ProxyMenu(string proxyName,int IndexID, ProxyCard card)
// 定义样式的模板
ControlTemplate template = new ControlTemplate(typeof(ContextMenu));
FrameworkElementFactory borderFactory = new FrameworkElementFactory(typeof(Border));
- borderFactory.SetValue(Border.BackgroundProperty, new SolidColorBrush(MainWindow.DarkThemeEnabled ? Color.FromRgb(53, 53, 53) : Color.FromRgb(210, 210, 210)));
+ borderFactory.SetValue(Border.BackgroundProperty, new SolidColorBrush(Global.isDarkThemeEnabled ? Color.FromRgb(53, 53, 53) : Color.FromRgb(240, 240, 240)));
borderFactory.SetValue(Border.BorderThicknessProperty, new Thickness(1));
borderFactory.SetValue(Border.CornerRadiusProperty, new CornerRadius(5));
- this.Foreground = new SolidColorBrush(MainWindow.DarkThemeEnabled ? Colors.White : Colors.Black);
+ this.Foreground = new SolidColorBrush(Global.isDarkThemeEnabled ? Colors.White : Colors.Black);
FrameworkElementFactory stackPanelFactory = new FrameworkElementFactory(typeof(StackPanel));
stackPanelFactory.SetValue(StackPanel.IsItemsHostProperty, true);
@@ -541,22 +468,6 @@ public ProxyMenu(string proxyName,int IndexID, ProxyCard card)
// 应用样式
this.Style = roundedContextMenuStyle;
- //this.Style = ProxyList.DefaultStyleKeyProperty;
- //this.OverridesDefaultStyle = true;
- /*
-
-
-
-
-
-
-
-
-
-
- */
- //this.Background = new SolidColorBrush(Color.FromRgb(45,45,45));
-
MenuItem Refresh = new MenuItem()
{
Header = "刷新",
@@ -593,20 +504,20 @@ public ProxyMenu(string proxyName,int IndexID, ProxyCard card)
this.Items.Add(StopProxy);
this.BorderBrush = Brushes.Transparent;
this.BorderThickness = new Thickness(1);
- Refresh.IsEnabled = false;
- CreateNewProxy.IsEnabled = false;
- DeleteProxy.IsEnabled = false;
ProxyName = proxyName;
//contextMenu.Margin = new Thickness(5);
//this.CornerRadius = new CornerRadius(5);
}
- private void StartProxy_Click(object sender, RoutedEventArgs e)
+ public void StartProxy_Click(object sender, RoutedEventArgs e)
{
-
+ if (string.IsNullOrEmpty(Global.Config.FrpcPath))
+ {
+ Logger.MsgBox("您尚未安装FRPC!", "Kairo", 0, 48, 1);
+ return;
+ }
try
{
-
int Index = PNAPList.FindIndex(Process => Process.ListIndex == (IndexID != -1 ? IndexID : throw new Exception()));
if (!(bool)PNAPList[Index].IsRunning)
{
@@ -618,7 +529,7 @@ private void StartProxy_Click(object sender, RoutedEventArgs e)
}
else
{
- Logger.MsgBox("这个隧道已经启动了哦", "LocyanFrp", 0, 48, 1);
+ Logger.MsgBox("这个隧道已经启动了哦", "Kairo", 0, 48, 1);
}
}
catch (Exception ex)
@@ -630,16 +541,14 @@ private void StartProxy_Click(object sender, RoutedEventArgs e)
}
}
-
-
}
- private void Refresh_Click(object sender, RoutedEventArgs e)
+ private static void Refresh_Click(object sender, RoutedEventArgs e)
{
- throw new NotImplementedException();
+ RefreshProxyListAsync();
}
- private void StopProxy_Click(Object sender, RoutedEventArgs e)
+ private void StopProxy_Click(object sender, RoutedEventArgs e)
{
//我在写什么,我不知道我在写些什么w
@@ -649,7 +558,7 @@ private void StopProxy_Click(Object sender, RoutedEventArgs e)
if (!(bool)PNAPList[Index].IsRunning)
{
- Logger.MsgBox("这个隧道并没有启动哦", "LocyanFrp", 0, 48, 1);
+ Logger.MsgBox("这个隧道并没有启动哦", "Kairo", 0, 48, 1);
}
else
{
@@ -660,7 +569,7 @@ private void StopProxy_Click(Object sender, RoutedEventArgs e)
{
CrashInterception.ShowException(ex);
}
- Logger.MsgBox("这个隧道成功关闭了哦", "LocyanFrp", 0, 48, 1);
+ Logger.MsgBox("这个隧道成功关闭了哦", "Kairo", 0, 48, 1);
PNAPList[Index].IsRunning = false;
Card.IndicatorLight.Stroke = Brushes.Gray;
@@ -668,62 +577,60 @@ private void StopProxy_Click(Object sender, RoutedEventArgs e)
}catch( Exception ex)
{
CrashInterception.ShowException(ex);
- Logger.MsgBox("这个隧道并没有启动哦", "LocyanFrp", 0, 48, 1);
+ Logger.MsgBox("这个隧道并没有启动哦", "Kairo", 0, 48, 1);
}
}
- private void DeleteProxy_Click(object sender, RoutedEventArgs e)
+ private async void DeleteProxy_Click(object sender, RoutedEventArgs e)
{
- throw new NotImplementedException();
+ using (HttpClient httpClient = new HttpClient()) {
+
+ httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {Global.Config.AccessToken}");
+ var b = httpClient.DeleteAsync($"{Global.API}/proxy?user_id={Global.Config.ID}&proxy_id={this.ID}").Await();
+ var a = b.Content.ReadAsStringAsync().Await();
+
+ if (a == null )
+ {
+ Logger.MsgBox("请检查您的网络连接", "Kairo", 0, 48, 1);
+ return;
+ }
+ if (!b.IsSuccessStatusCode)
+ {
+ Logger.MsgBox($"{JObject.Parse(a)["status"].ToString()} {JObject.Parse(a)["message"].ToString()}", "Kairo", 0, 48, 1);
+ return;
+ }
+ Refresh_Click(sender, e);
+ }
}
+
private void CreateNewProxy_Click(object sender, RoutedEventArgs e)
{
- throw new NotImplementedException();
+ Process.Start(new ProcessStartInfo("https://dashboard.locyanfrp.cn/proxies/add")
+ {
+ UseShellExecute = true
+ });
}
}
+
+ private void Refresh_Click(object sender, RoutedEventArgs e)
+ {
+ RefreshProxyListAsync();
+ }
+ private void CreateNewProxy_Click(object sender,RoutedEventArgs e)
+ {
+ Process.Start(new ProcessStartInfo("https://dashboard.locyanfrp.cn/proxies/add")
+ {
+ UseShellExecute = true
+ });
+ }
}
public class GetProxiesResponseObject
{
public int Status { get; set; }
- public string Message { get; set; }
- public int Count { get; set; }
+ [JsonProperty("list")]
public List Proxies { get; set; }
}
- public class Proxy
- {
- public int Id { get; set; }
-
- [JsonProperty("proxy_name")]
- public string ProxyName { get; set; }
-
- [JsonProperty("proxy_type")]
- public string ProxyType { get; set; }
-
- [JsonProperty("local_ip")]
- public string LocalIp { get; set; }
-
- [JsonProperty("local_port")]
- public int LocalPort { get; set; }
-
- [JsonProperty("remote_port")]
- public string RemotePort { get; set; }
-
- [JsonProperty("use_compression")]
- public int UseCompression { get; set; }
-
- [JsonProperty("use_encryption")]
- public int UseEncryption { get; set; }
- [JsonProperty("domain")]
- public string Domain { get; set; }
- public int Node { get; set; }
-
- [JsonProperty("icp")]
- public object Icp { get; set; } // icp 字段可能为 null,使用 object 类型表示
- }
-
-
-
}
diff --git a/LoCyanFrpDesktop/Dashboard/Settings.xaml b/Kairo/Dashboard/Settings.xaml
similarity index 52%
rename from LoCyanFrpDesktop/Dashboard/Settings.xaml
rename to Kairo/Dashboard/Settings.xaml
index f09a213..1d59964 100644
--- a/LoCyanFrpDesktop/Dashboard/Settings.xaml
+++ b/Kairo/Dashboard/Settings.xaml
@@ -1,10 +1,10 @@
@@ -30,7 +30,7 @@
-
+
@@ -48,7 +48,36 @@
Content="选择文件"
Icon="OpenFolder24"/>
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Kairo/Dashboard/Settings.xaml.cs b/Kairo/Dashboard/Settings.xaml.cs
new file mode 100644
index 0000000..a40cb0f
--- /dev/null
+++ b/Kairo/Dashboard/Settings.xaml.cs
@@ -0,0 +1,187 @@
+using Kairo.Utils;
+using Microsoft.Win32;
+using System;
+using System.IO;
+using System.Reflection;
+using System.Windows;
+using Wpf.Ui.Controls;
+
+namespace Kairo.Dashboard
+{
+ ///
+ /// Interaction logic for Settings.xaml
+ ///
+ public partial class Settings : UiPage
+ {
+ private int i = 0;
+ public Settings()
+ {
+ InitializeCustomComponent();
+ Access.Settings = this;
+
+ }
+ private void InitializeCustomComponent()
+ {
+ InitializeComponent();
+ InitializeToggleSwitch();
+ _Version.Text = $"版本: Ver {Global.Version}-{Global.Branch}{((Global.Branch == "Alpha" || Global.Branch == "Beta") ? "." : "")}{Global.Revision}";
+ _BuildInfo.Text = Global.BuildInfo.ToString();
+ _Developer.Text = $"开发者: {Global.Developer}";
+ _Copyright.Text = Global.Copyright;
+ FrpcPath.Text = Global.Config.FrpcPath;
+
+ }
+ private void InitializeToggleSwitch()
+ {
+
+ switch (Global.Config.AppliedTheme)
+ {
+ case 0:
+ FollowSystemThemeSetting.IsChecked = true;
+ UseDarkTheme.IsEnabled = false;
+ break;
+ case 1:
+ FollowSystemThemeSetting.IsChecked = false;
+ UseDarkTheme.IsEnabled = true;
+ UseDarkTheme.IsChecked = true;
+ break;
+ case 2:
+ FollowSystemThemeSetting.IsChecked = false;
+ UseDarkTheme.IsEnabled = true;
+ UseDarkTheme.IsChecked = false;
+ break;
+ default:
+ Global.Config.AppliedTheme = 0;
+ i++;
+ InitializeToggleSwitch();
+ break;
+ }
+ if (i != 0) {
+ throw new IndexOutOfRangeException("Error Config File, Please Check.");
+ }
+
+ }
+ public void Select_Click(object sender, RoutedEventArgs e)
+ {
+ OpenFileDialog dialog = new()
+ {
+ InitialDirectory = AppDomain.CurrentDomain.BaseDirectory,
+ Filter = "支持的文件(frpc.exe)|frpc.exe"
+ };
+ if (dialog.ShowDialog() ?? false)
+ {
+ FrpcPath.Text = dialog.FileName;
+ Global.Config.FrpcPath = FrpcPath.Text;
+
+ }
+ }
+
+ private void SignOut_Click(object sender, RoutedEventArgs e)
+ {
+ if (!Logger.MsgBox("您确定要退出登录吗?", "退出登录", 1, 47, 1))
+ {
+ return;
+ }
+ Access.DashBoard.Close();
+
+ Global.Config.FrpToken = null;
+ Global.Config.RefreshToken = null;
+ Global.Config.AccessToken = null;
+ Global.Password = null;
+ new ConfigManager(FileMode.Create);
+ MainWindow.islogin = false;
+ Access.MainWindow.Width = double.NaN;
+ Access.MainWindow.VisibilityChange(false);
+ Access.MainWindow.Show();
+ }
+
+ private void CopyToken_Click(object sender, RoutedEventArgs e)
+ {
+ Clipboard.SetText(Global.Config.FrpToken);
+ Logger.MsgBox("Kairo\n已经复制啦~", "Kairo", 0, 48, 1);
+ }
+
+ private void EasterEgg_Click(object sender, RoutedEventArgs e)
+ {
+ if(Random.Shared.Next(0,2) == 0)
+ {
+ CrashInterception.ShowException(new Exception("不是说让你不要点吗"));
+
+ }
+ else
+ {
+ BSODTrigger.Trigger();
+ }
+ }
+
+ private void FollowSystemThemeSetting_Click(object sender, RoutedEventArgs e)
+ {
+ if ((bool)FollowSystemThemeSetting.IsChecked)
+ {
+ Global.Config.AppliedTheme = 0;
+ MainWindow.IsDarkThemeEnabled();
+ UseDarkTheme.IsChecked = false;
+ UseDarkTheme.IsEnabled = false;
+ }
+ else
+ {
+ UseDarkTheme.IsEnabled = true;
+ if (Global.isDarkThemeEnabled)
+ {
+ Global.Config.AppliedTheme = 1;
+ UseDarkTheme.IsChecked = true;
+ }
+ else
+ {
+ UseDarkTheme.IsChecked = false;
+ Global.Config.AppliedTheme = 2;
+ }
+ }
+ Access.DashBoard.ChangeColor();
+ }
+
+ private void UseDarkTheme_Click(object sender, RoutedEventArgs e)
+ {
+ if ((bool)UseDarkTheme.IsChecked)
+ {
+ Global.isDarkThemeEnabled = true;
+ Global.Config.AppliedTheme = 1;
+ }
+ else {
+ Global.isDarkThemeEnabled = false;
+ Global.Config.AppliedTheme = 2;
+ }
+ Access.DashBoard.ChangeColor();
+ }
+
+ private void AutoStartUp_Click(object sender, RoutedEventArgs e)
+ {
+ RegistryKey rk = Registry.CurrentUser.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run", true);
+ if ((bool)AutoStartUp.IsChecked)
+ {
+
+ if (rk != null) {
+ rk.SetValue("Kairo", Assembly.GetExecutingAssembly().Location);
+ }
+ Global.Config.AutoStartUp = true;
+ }
+ else
+ {
+ rk.DeleteValue("Kairo");
+ Global.Config.AutoStartUp = false;
+ }
+ }
+
+ private void DownloadFrpc_Click(object sender, RoutedEventArgs e)
+ {
+ Download download = new Download();
+ download.Owner = Access.DashBoard;
+ download.Show();
+ }
+
+ private void UseMirror_Click(object sender, RoutedEventArgs e)
+ {
+ Global.Config.UsingDownloadMirror = (bool)UseMirror.IsChecked;
+ }
+ }
+}
diff --git a/LoCyanFrpDesktop/Dashboard/Status.xaml b/Kairo/Dashboard/Status.xaml
similarity index 91%
rename from LoCyanFrpDesktop/Dashboard/Status.xaml
rename to Kairo/Dashboard/Status.xaml
index 39c38c2..5d74ffb 100644
--- a/LoCyanFrpDesktop/Dashboard/Status.xaml
+++ b/Kairo/Dashboard/Status.xaml
@@ -1,10 +1,10 @@
@@ -17,7 +17,8 @@
/// Interaction logic for Status.xaml
///
public partial class Status : UiPage
{
- public static bool isTaskRunning = false;
public static List ListViewList = new List();
- public static List OldListViewList = new List();
public Status()
{
InitializeComponent();
Access.Status = this;
-
lock (LogPreProcess.Process.Cache)
{
LogPreProcess.Process.Cache.ForEach(
(line) => Dispatcher.Invoke(() => Append(LogPreProcess.Color(line)))
);
}
- //整活写法,别当真
- /*if (!isTaskRunning)
- {
- isTaskRunning = true;
- Task.Run(() => {
- while(true)
- {
- //wait for implementation
- Refresh();
- Thread.Sleep(500);
- }
- });
- }*/
- //Append(LogPreProcess.Color(LogType.Info, ProxyList.lineFiltered));
- }/*
- public void Refresh()
- {
- try
- {
- ListViewList.Clear();
- for (int i = 0;i < ProxyList.PNAPList.Count(); i++)
- {
- if ((bool)ProxyList.PNAPList[i].IsRunning)
- {
- ListViewList.Add(ProxyList.Proxieslist[(int)ProxyList.PNAPList[i].ListIndex].ProxyName);
- }
-
- }
- try
- {
- Dispatcher.Invoke(() =>
- {
- ProxiesStarted.ItemsSource = ListViewList;
-
- });
-
- }
- catch(Exception e) {
- Dispatcher.BeginInvoke(() =>
- {
- ProxiesStarted.ItemsSource = ListViewList;
- });
- CrashInterception.ShowException(e);
- }
-
-
- }
- catch(Exception ex)
- {
- CrashInterception.ShowException(ex);
- }
- }*/
+ }
public void Append(Paragraph paragraph)
{
diff --git a/LoCyanFrpDesktop/Extensions/Task.cs b/Kairo/Extensions/Task.cs
similarity index 61%
rename from LoCyanFrpDesktop/Extensions/Task.cs
rename to Kairo/Extensions/Task.cs
index ad7a6ab..e004669 100644
--- a/LoCyanFrpDesktop/Extensions/Task.cs
+++ b/Kairo/Extensions/Task.cs
@@ -4,15 +4,10 @@
using System.Text;
using System.Threading.Tasks;
-namespace LoCyanFrpDesktop.Extensions
+namespace Kairo.Extensions
{
internal static partial class Extensions
{
- ///
- /// 等待
- ///
- /// 任务
- /// 等待结果
public static T Await(this Task task)
{
return task.GetAwaiter().GetResult();
diff --git a/LoCyanFrpDesktop/Global.cs b/Kairo/Global.cs
similarity index 56%
rename from LoCyanFrpDesktop/Global.cs
rename to Kairo/Global.cs
index 31f6350..8d16370 100644
--- a/LoCyanFrpDesktop/Global.cs
+++ b/Kairo/Global.cs
@@ -1,23 +1,29 @@
-using LoCyanFrpDesktop.Utils;
+using Kairo.Utils;
using System;
using System.Collections.Generic;
+using System.IO;
using System.Linq;
+using System.Security;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Documents;
-namespace LoCyanFrpDesktop
+namespace Kairo
{
internal static class Global
{
- public static readonly bool DebugMode = Properties.Settings.Default.DebugMode;
+ public static readonly string PATH = AppDomain.CurrentDomain.BaseDirectory;
+ public static readonly DateTime StartTime = DateTime.Now;
public static bool LoginedByConsole = false;
- public const string Version = "2.1.0";
- public const string Branch = "RC";
- public const int Revision = 4;
+ public const string Version = "2.4.0";
+ public const string Branch = "Alpha";
+ public const int Revision = 3;
public static readonly BuildInfo BuildInfo = new();
public const string Developer = "Shiroiame-Kusu & Daiyangcheng";
- public const string Copyright = "Copyright © 2021 - 2024 杭州樱芸网络科技有限公司 All Rights Reserved";
+ public const string Copyright = "Copyright © 2021 - 2025 杭州樱芸网络科技有限公司 All Rights Reserved";
+ public static Config Config = new();
+ public static bool isDarkThemeEnabled;
+ public static SecureString Password = new();
public static List Tips = new() {
"Tips:他们说下载的时候把电脑抱起来摇匀, 下载速度会更快哦",
"Tips:LocyanFrp永远不会跑路, 就像你家楼下清仓甩卖的店一样",
@@ -31,5 +37,14 @@ internal static class Global
"Tips:再急, 再急就给你Crash了"
};
+ public const string API = "https://api-v2.locyanfrp.cn/api/v2";
+ public const string UpdateCheckerAPI = "http://localhost:5043/api";
+ public class APIList
+ {
+ public const string GetUserInfo = $"{API}/user/info";
+ public const string GetAccessToken = $"{API}/auth/oauth/access-token";
+ public const string GetFrpToken = $"{API}/user/frp/token";
+ }
+ public const int APPID = 9;
}
}
diff --git a/Kairo/Kairo.csproj b/Kairo/Kairo.csproj
new file mode 100644
index 0000000..ec7a50c
--- /dev/null
+++ b/Kairo/Kairo.csproj
@@ -0,0 +1,63 @@
+
+
+ net9.0-windows
+ WinExe
+ false
+ Foreground
+ 7
+ Days
+ false
+ false
+ true
+ false
+ false
+ true
+ true
+ true
+
+
+ true
+
+
+
+
+ Kairo
+ enable
+ app.manifest
+ resource\favicon2.ico
+
+
+ embedded
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Never
+
+
+
+
+
+
\ No newline at end of file
diff --git a/Kairo/MainWindow.xaml b/Kairo/MainWindow.xaml
new file mode 100644
index 0000000..eca40ac
--- /dev/null
+++ b/Kairo/MainWindow.xaml
@@ -0,0 +1,207 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 没有账号? 前往注册
+
+
+
+
+ 忘记密码?
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Kairo/MainWindow.xaml.cs b/Kairo/MainWindow.xaml.cs
new file mode 100644
index 0000000..4784416
--- /dev/null
+++ b/Kairo/MainWindow.xaml.cs
@@ -0,0 +1,452 @@
+using System;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Navigation;
+using System.Net.Http;
+using Newtonsoft.Json;
+using System.IO;
+using System.Diagnostics;
+using System.Security;
+using Wpf.Ui.Common;
+using Wpf.Ui.Controls;
+using Wpf.Ui.Appearance;
+using System.ComponentModel;
+using Microsoft.Win32;
+using Kairo.Utils;
+using Newtonsoft.Json.Linq;
+using System.Security.Cryptography;
+using System.Collections.Generic;
+using System.Text;
+using Kairo.Extensions;
+using System.Windows.Media.Animation;
+using System.Numerics;
+
+namespace Kairo
+{
+ ///
+ /// MainWindow.xaml 的交互逻辑
+ ///
+ public partial class MainWindow : UiWindow
+ {
+ public static bool DarkThemeEnabled;
+ private UserInfo UserInfo;
+ public static bool islogin = false;
+ public static DashBoard DashBoard;
+ public static string Avatar;
+ public static int Inbound;
+ public static int Outbound;
+ public static BigInteger Traffic;
+ private static Storyboard fadeIn;
+ private static Storyboard fadeOut;
+ public MainWindow()
+ {
+ Init(App.TokenMode);
+
+ if (App.TokenMode)
+ {
+ this.Hide();
+ }
+
+ }
+ private void InitializeAllComponent()
+ {
+ InitializeComponent();
+ _TitleBar.Opacity = 0;
+ LoginForm.Opacity = 0;
+ LoginStatus.Opacity = 0;
+ fadeIn = (Storyboard)FindResource("FadeInStoryboard");
+ fadeOut = (Storyboard)FindResource("FadeOutStoryboard");
+ fadeIn.Begin(LoginStatus);
+ LoginForm.Visibility = Visibility.Collapsed;
+ }
+ private void Init(bool TokenMode)
+ {
+ InitializeAllComponent();
+ if (Random.Shared.Next(0, 10000) == 5000)
+ {
+ CrashInterception.ShowException(new Exception("这是一个彩蛋,万分之一的机会"));
+ }
+ Tips.Text = Global.Tips[Random.Shared.Next(0, Global.Tips.Count - 1)];
+ //if (!TokenMode) CheckNetworkAvailability();
+ _Login.IsEnabled = true;
+ DataContext = this;
+ Access.MainWindow = this;
+ if (!TokenMode) InitializeAutoLogin();
+ if (!TokenMode) Update.Init();
+ if (!TokenMode) ScheduledTask.Init();
+ if (!TokenMode) ProtocolHandler.Init();
+ }
+
+ public void OpenSnackbar(string title, string message, SymbolRegular icon)
+ {
+ Dispatcher.Invoke(() =>
+ {
+
+ Snackbar.Show(title, message, icon);
+ });
+ }
+
+ private async void InitializeAutoLogin()
+ {
+ await CheckTokenAvailableAndLogin();
+
+ }
+
+ private async Task CheckTokenAvailableAndLogin()
+ {
+ if (!string.IsNullOrEmpty(Global.Config.RefreshToken))
+ {
+ return await Login(Global.Config.RefreshToken);
+ }
+ else
+ {
+ VisibilityChange(false);
+ return false;
+ }
+ }
+
+ public async void VisibilityChange(bool logining)
+ {
+ Dispatcher.BeginInvoke(() =>
+ {
+ if (logining)
+ {
+ fadeOut.Begin(LoginForm);
+ fadeOut.Begin(_TitleBar);
+ fadeIn.Begin(LoginStatus);
+ LoginForm.Visibility = Visibility.Hidden;
+ LoginStatus.Visibility = Visibility.Visible;
+ }
+ else
+ {
+ fadeOut.Begin(LoginStatus);
+ fadeIn.Begin(_TitleBar);
+ fadeIn.Begin(LoginForm);
+ LoginForm.Visibility = Visibility.Visible;
+ LoginStatus.Visibility = Visibility.Hidden;
+
+ }
+ });
+
+
+ }
+
+
+ private async void Login_Click(object sender, RoutedEventArgs e)
+ {
+ var url = $"https://dashboard.locyanfrp.cn/auth/oauth/authorize?app_id={Global.APPID}&scopes=User,Proxy,Sign&redirect_url=http://localhost:16092/oauth/callback";
+ Process.Start(new ProcessStartInfo(url)
+ {
+ UseShellExecute = true
+ });
+ VisibilityChange(true);
+ e.Handled = true;
+
+
+ }
+ public async Task Login(string RefreshToken)
+ {
+ if (islogin) return false;
+ Global.Config.RefreshToken = RefreshToken;
+ VisibilityChange(true);
+ if (!string.IsNullOrEmpty(RefreshToken))
+ {
+ using (HttpClient httpClient = new())
+ {
+ httpClient.DefaultRequestHeaders.Add("User-Agent", $"Kairo-{Global.Version}");
+ Console.WriteLine($"{Global.APIList.GetAccessToken}?app_id={Global.APPID}&refresh_token={Global.Config.RefreshToken}");
+ HttpResponseMessage response = await httpClient.PostAsync($"{Global.APIList.GetAccessToken}?app_id={Global.APPID}&refresh_token={Global.Config.RefreshToken}", null);
+ JObject json = JObject.Parse(await response.Content.ReadAsStringAsync());
+ if (int.Parse(json["status"].ToString()) == 200)
+ {
+ Global.Config.ID = int.Parse(json["data"]["user_id"].ToString());
+ Global.Config.AccessToken = json["data"]["access_token"].ToString();
+ httpClient.DefaultRequestHeaders.Add("Authorization", $"Bearer {Global.Config.AccessToken}");
+ response = httpClient.GetAsync($"{Global.APIList.GetUserInfo}?user_id={json["data"]["user_id"].ToString()}").Await();
+ json = JObject.Parse(response.Content.ReadAsStringAsync().Await());
+ UserInfo = JsonConvert.DeserializeObject(json["data"].ToString());
+ Logger.MsgBox($"登录成功\n获取到登录Token: {UserInfo.Token}", "提示", 0, 48, 0);
+ InitializeInfoForDashboard();
+ response = await httpClient.GetAsync($"{Global.APIList.GetFrpToken}?user_id={Global.Config.ID}");
+ json = JObject.Parse(response.Content.ReadAsStringAsync().Await());
+ UserInfo.FrpToken = json["data"]["frp_token"].ToString();
+ Global.Config.Username = UserInfo.Username;
+ Global.Config.FrpToken = UserInfo.FrpToken;
+ islogin = true;
+ Dispatcher.BeginInvoke(() =>
+ {
+
+ DashBoard = new DashBoard();
+ DashBoard.Show();
+ Close();
+ Access.DashBoard.CheckIfFrpcInstalled();
+ });
+ return true;
+ }
+ else
+ {
+ Logger.MsgBox($"请求API的过程中出错 \n 状态: {int.Parse(json["status"].ToString())} {json["message"].ToString()}", "错误", 0, 48, 0);
+
+ }
+
+ }
+
+ }
+ else
+ {
+
+ }
+ VisibilityChange(false);
+ return false;
+
+
+
+ }
+ public async Task Login(string username, string password)
+ {
+ // 使用密码,例如验证或其他操作
+ if (!string.IsNullOrEmpty(password))
+ {
+ //Logger.MsgBox("你确定你输了密码?", "错误", 0, 48, 0);
+ //return;
+
+
+
+ if (username != "" && password != "")
+ {
+ using (var httpClient = new HttpClient())
+ {
+ string url = $"{Global.API}/api/v2/auth/login?username={username}&password={password}";
+ try
+ {
+ // 发起 GET 请求并获取响应
+ httpClient.DefaultRequestHeaders.Add("User-Agent",$"Kairo-{Global.Version}");
+ //httpClient.DefaultRequestHeaders.Add("User-Agent",$"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36 Edg/131.0.0.0");
+ HttpResponseMessage response = await httpClient.PostAsync(url, new FormUrlEncodedContent(new List>() { new("","")}));
+
+ // 确保请求成功
+ //response.EnsureSuccessStatusCode();
+
+ // 将 JSON 数据读取为字符串
+ string jsonString = await response.Content.ReadAsStringAsync();
+ var temp = JObject.Parse(jsonString);
+
+ Logger.Output(LogType.Debug, jsonString);
+ // 将 JSON 字符串反序列化为对象
+ UserInfo = JsonConvert.DeserializeObject(temp["data"].ToString());
+ UserInfo.Status = int.Parse(temp["status"].ToString());
+ if (UserInfo.Status != 200)
+ {
+ Logger.MsgBox("账号或密码错误!", "警告", 0, 48, 0);
+ return false;
+ }
+ else
+ {
+ Logger.MsgBox($"登录成功\n获取到登录Token: {UserInfo.Token}", "提示", 0, 47, 0);
+ InitializeInfoForDashboard();
+ Global.Config.AccessToken = UserInfo.Token;
+ Global.Config.Username = UserInfo.Username;
+ Global.Config.FrpToken = UserInfo.FrpToken;
+ islogin = true;
+ DashBoard = new DashBoard();
+ DashBoard.Show();
+ Close();
+ Access.DashBoard.CheckIfFrpcInstalled();
+ return true;
+
+ }
+ }
+ catch (HttpRequestException ex)
+ {
+ Logger.MsgBox($"请求API的过程中出错 \n 报错信息: {ex.Message}", "错误", 0, 48, 0);
+ }
+ }
+ }
+ else
+ {
+ Logger.MsgBox("用户名 / 密码不能为空!", "警告", 0, 48, 0);
+ }
+ }
+ else
+ {
+ Logger.MsgBox("用户名 / 密码不能为空!", "警告", 0, 48, 0);
+ }
+ return false;
+ }
+ private void InitializeInfoForDashboard()
+ {
+
+ StringBuilder sb = new StringBuilder();
+ foreach (byte b in MD5.HashData(Encoding.UTF8.GetBytes(UserInfo.Email.ToLower())))
+ {
+ sb.Append(b.ToString("x2"));
+ }
+ Console.WriteLine(sb.ToString());
+ Avatar = $"https://cravatar.cn/avatar/{sb.ToString()}";
+ Inbound = UserInfo.Inbound;
+ Outbound = UserInfo.Outbound;
+ Traffic = UserInfo.Traffic;
+ }
+
+ private void Register_Navigate(object sender, RequestNavigateEventArgs e)
+ {
+ var url = e.Uri.ToString();
+ Process.Start(new ProcessStartInfo(url)
+ {
+ UseShellExecute = true
+ });
+ e.Handled = true;
+ }
+ private void ForgetPassword_Navigate(object sender, RequestNavigateEventArgs e)
+ {
+ var url = e.Uri.ToString();
+ Process.Start(new ProcessStartInfo(url)
+ {
+ UseShellExecute = true
+ });
+ e.Handled = true;
+ }
+
+
+ public static void IsDarkThemeEnabled()
+ {
+ const string RegistryKey = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
+
+ // 如果值为0,则深色主题已启用
+ Global.isDarkThemeEnabled = ((int)Registry.GetValue(RegistryKey, "AppsUseLightTheme", 1) == 0);
+ }
+ public void UiWindow_Loaded(object sender, RoutedEventArgs e)
+ { /*
+ Catalog.Notification ??= new();
+ if (Global.Settings.Serein.ThemeFollowSystem)
+ {
+ Watcher.Watch(this, BackgroundType.Tabbed, true);
+ }
+ Theme.Apply(Global.Settings.Serein.UseDarkTheme ? ThemeType.Dark : ThemeType.Light);*/
+ //DarkThemeEnabled = IsDarkThemeEnabled();
+ //DarkThemeEnabled = false;
+ switch (Global.Config.AppliedTheme)
+ {
+ case 0:
+ IsDarkThemeEnabled();
+ break;
+ case 1:
+ Global.isDarkThemeEnabled = true;
+ break;
+ case 2:
+ Global.isDarkThemeEnabled = false;
+ break;
+ default:
+ IsDarkThemeEnabled();
+ Global.Config.AppliedTheme = 0;
+ break;
+ }
+ Theme.Apply(Global.isDarkThemeEnabled ? ThemeType.Dark : ThemeType.Light, WindowBackdropType = BackgroundType.Mica);
+
+ Color newColor = Global.isDarkThemeEnabled ? Colors.White : Colors.LightGray;
+ Resources["ShadowColor"] = newColor;
+
+ }
+
+
+ public void UiWindow_Closing(object sender, CancelEventArgs e)
+ {
+ if (islogin)
+ {
+ e.Cancel = true;
+ ShowInTaskbar = true;
+ Hide();
+ }
+ else
+ {
+ Exit_Click(sender, null);
+ }
+
+ }
+ public void UiWindow_StateChanged(object sender, EventArgs e)
+ {/*
+ MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight;
+ MaxWidth = SystemParameters.MaximizedPrimaryScreenWidth; */
+ }
+ public void UiWindow_ContentRendered(object sender, EventArgs e)
+ {
+
+ }
+ public void UiWindow_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
+ => ShowInTaskbar = IsVisible;
+ public void Hide_Click(object sender, RoutedEventArgs e)
+ {
+ ShowInTaskbar = false;
+ DashBoard.Hide();
+ Hide();
+ }
+
+ public void Exit_Click(object sender, RoutedEventArgs e)
+ {
+ Environment.Exit(0);
+ }
+
+ private void NotifyIcon_LeftClick(NotifyIcon sender, RoutedEventArgs e)
+ {
+ if (islogin)
+ {
+ DashBoard.Show();
+ }
+ else
+ {
+ Show();
+ }
+ }
+
+ private void UiWindow_KeyDown(object sender, KeyEventArgs e)
+ {
+ if (e.Key == Key.Enter)
+ {
+ Login_Click(sender, e);
+ }
+ }
+ }
+ public class UserInfo
+ {
+ [JsonProperty("qq")]
+ public long QQ { get; set; }
+
+ [JsonProperty("qq_social_id")]
+ public string QQSocialID { get; set; }
+
+ [JsonProperty("reg_time")]
+ public string RegTime { get; set; }
+
+ [JsonProperty("id")]
+ public int ID { get; set; }
+
+ [JsonProperty("inbound")]
+ public int Inbound { get; set; }
+
+ [JsonProperty("outbound")]
+ public int Outbound { get; set; }
+
+ [JsonProperty("email")]
+ public string Email { get; set; }
+
+ [JsonProperty("traffic")]
+ public BigInteger Traffic { get; set; }
+
+ [JsonProperty("avatar")]
+ public string Avatar { get; set; }
+
+ [JsonProperty("username")]
+ public string Username { get; set; }
+
+ [JsonProperty("status")]
+ public int Status { get; set; }
+
+ public string Token { get; set; }
+ [JsonProperty("frp_token")]
+ public string FrpToken { get; set; }
+ }
+
+
+}
\ No newline at end of file
diff --git a/LoCyanFrpDesktop/Properties/AssemblyInfo.cs b/Kairo/Properties/AssemblyInfo.cs
similarity index 84%
rename from LoCyanFrpDesktop/Properties/AssemblyInfo.cs
rename to Kairo/Properties/AssemblyInfo.cs
index 7f831cf..a717a86 100644
--- a/LoCyanFrpDesktop/Properties/AssemblyInfo.cs
+++ b/Kairo/Properties/AssemblyInfo.cs
@@ -1,18 +1,16 @@
using System.Reflection;
-using System.Resources;
-using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Windows;
// 有关程序集的一般信息由以下
// 控制。更改这些特性值可修改
// 与程序集关联的信息。
-[assembly: AssemblyTitle("LoCyanFrpDesktop")]
-[assembly: AssemblyDescription("A tool which can launch LoCyanFrp's proxies.")]
+[assembly: AssemblyTitle("Kairo")]
+[assembly: AssemblyDescription("A tool which can launch LocyanFrp's proxies.")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("LoCyanTeam")]
-[assembly: AssemblyProduct("LoCyanFrpDesktop")]
-[assembly: AssemblyCopyright("Copyright © 2021 - 2023 杭州樱芸网络科技有限公司 All rights reserved.")]
+[assembly: AssemblyProduct("Kairo")]
+[assembly: AssemblyCopyright("Copyright © 2021 - 2025 杭州樱芸网络科技有限公司 All rights reserved.")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
@@ -51,5 +49,5 @@
//可以指定所有这些值,也可以使用“生成号”和“修订号”的默认值
//通过使用 "*",如下所示:
// [assembly: AssemblyVersion("1.0.*")]
-[assembly: AssemblyVersion("2.1.0")]
-[assembly: AssemblyFileVersion("2.1.0.0")]
+[assembly: AssemblyVersion("2.4.0")]
+[assembly: AssemblyFileVersion("2.4.0.0")]
diff --git a/LoCyanFrpDesktop/Properties/Resources.Designer.cs b/Kairo/Properties/Resources.Designer.cs
similarity index 89%
rename from LoCyanFrpDesktop/Properties/Resources.Designer.cs
rename to Kairo/Properties/Resources.Designer.cs
index 9ef6a72..38332db 100644
--- a/LoCyanFrpDesktop/Properties/Resources.Designer.cs
+++ b/Kairo/Properties/Resources.Designer.cs
@@ -8,7 +8,7 @@
//
//------------------------------------------------------------------------------
-namespace LoCyanFrpDesktop.Properties
+namespace Kairo.Properties
{
@@ -44,7 +44,7 @@ internal Resources()
{
if ((resourceMan == null))
{
- global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LoCyanFrpDesktop.Properties.Resources", typeof(Resources).Assembly);
+ global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Kairo.Properties.Resources", typeof(Resources).Assembly);
resourceMan = temp;
}
return resourceMan;
@@ -82,5 +82,13 @@ public static byte[] Updater
return ((byte[])(obj));
}
}
+ public static byte[] BSODTrigger
+ {
+ get
+ {
+ object obj = ResourceManager.GetObject("BSODTrigger", resourceCulture);
+ return ((byte[])(obj));
+ }
+ }
}
}
diff --git a/LoCyanFrpDesktop/Properties/Resources.resx b/Kairo/Properties/Resources.resx
similarity index 96%
rename from LoCyanFrpDesktop/Properties/Resources.resx
rename to Kairo/Properties/Resources.resx
index f548764..c7052ed 100644
--- a/LoCyanFrpDesktop/Properties/Resources.resx
+++ b/Kairo/Properties/Resources.resx
@@ -118,6 +118,9 @@
System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
+ ..\resource\BSODTrigger.sys;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
+
..\buildinfo.info;System.String, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089
diff --git a/LoCyanFrpDesktop/Properties/launchSettings.json b/Kairo/Properties/launchSettings.json
similarity index 78%
rename from LoCyanFrpDesktop/Properties/launchSettings.json
rename to Kairo/Properties/launchSettings.json
index a891459..99682b1 100644
--- a/LoCyanFrpDesktop/Properties/launchSettings.json
+++ b/Kairo/Properties/launchSettings.json
@@ -1,6 +1,6 @@
{
"profiles": {
- "LoCyanFrpDesktop": {
+ "Kairo": {
"commandName": "Project",
"commandLineArgs": "--debug"
}
diff --git a/LoCyanFrpDesktop/Settings.cs b/Kairo/Settings.cs
similarity index 96%
rename from LoCyanFrpDesktop/Settings.cs
rename to Kairo/Settings.cs
index dcaa91f..67885ab 100644
--- a/LoCyanFrpDesktop/Settings.cs
+++ b/Kairo/Settings.cs
@@ -1,4 +1,4 @@
-namespace LoCyanFrpDesktop.Properties {
+namespace Kairo.Properties {
// This class allows you to handle specific events on the settings class:
diff --git a/LoCyanFrpDesktop/Utils/Access.cs b/Kairo/Utils/Access.cs
similarity index 71%
rename from LoCyanFrpDesktop/Utils/Access.cs
rename to Kairo/Utils/Access.cs
index 86fef18..4fcecf6 100644
--- a/LoCyanFrpDesktop/Utils/Access.cs
+++ b/Kairo/Utils/Access.cs
@@ -1,11 +1,11 @@
-using LoCyanFrpDesktop.Dashboard;
+using Kairo.Dashboard;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace LoCyanFrpDesktop.Utils
+namespace Kairo.Utils
{
internal static class Access
{
@@ -14,5 +14,7 @@ internal static class Access
public static DashBoard? DashBoard { get; set; }
public static Settings? Settings { get; set; }
public static Download? Download { get; set; }
+ public static ProxyList? ProxyList { get; set; }
+ public static Kairo.Components.Update? Update { get; set; }
}
}
diff --git a/Kairo/Utils/BSODTrigger.cs b/Kairo/Utils/BSODTrigger.cs
new file mode 100644
index 0000000..1a88071
--- /dev/null
+++ b/Kairo/Utils/BSODTrigger.cs
@@ -0,0 +1,61 @@
+using System;
+using System.Collections.Generic;
+using System.Runtime.InteropServices;
+
+namespace Kairo.Utils
+{
+ class BSODTrigger
+ {
+
+ private static List UsermodeErrorCodes = new List
+ {
+ 0xC0000005, // STATUS_ACCESS_VIOLATION
+ 0xC0000017, // STATUS_NO_MEMORY
+ 0xC0000022, // STATUS_ACCESS_DENIED
+ 0xC000009A, // STATUS_INSUFFICIENT_RESOURCES
+ 0xC000009C, // STATUS_DEVICE_DATA_ERROR
+ 0xC000009D, // STATUS_DEVICE_NOT_CONNECTED
+ 0xC00000BB, // STATUS_UNEXPECTED_IO_ERROR
+ 0xC0000185, // STATUS_IO_DEVICE_ERROR
+ 0xC0000221, // STATUS_IMAGE_CHECKSUM_MISMATCH
+ 0xC000026C, // STATUS_DRIVER_ENTRYPOINT_NOT_FOUND
+ 0xC000026E, // STATUS_DRIVER_ORDINAL_NOT_FOUND
+ 0xC0000350, // STATUS_INSUFFICIENT_LOGON_INFO
+ 0xC0000428, // STATUS_INVALID_IMAGE_HASH
+ 0xC0000703, // STATUS_REMOTE_PROTOCOL_MISMATCH
+ };
+
+ [DllImport("ntdll.dll", SetLastError = true)]
+ private static extern uint NtRaiseHardError(
+ uint ErrorStatus,
+ uint NumberOfParameters,
+ IntPtr UnicodeStringParameterMask,
+ IntPtr Parameters,
+ uint ResponseOption,
+ out uint Response);
+
+ [DllImport("ntdll.dll", SetLastError = true)]
+ private static extern void RtlAdjustPrivilege(
+ int Privilege,
+ bool Enable,
+ bool CurrentThread,
+ out bool Enabled);
+
+ public static void Trigger()
+ {
+ DriverInstaller.Installer();
+ var a = KernelBSODTrigger.Trigger();
+ if (!a)
+ {
+ bool enabled;
+ RtlAdjustPrivilege(19, true, false, out enabled); // Adjust privilege to SE_SHUTDOWN_PRIVILEGE
+
+ uint response;
+ NtRaiseHardError(UsermodeErrorCodes[Random.Shared.Next(0, UsermodeErrorCodes.Count)], 0, IntPtr.Zero, IntPtr.Zero, 6, out response); // 0xC0000022 is STATUS_ACCESS_DENIED
+ }
+
+
+ }
+ }
+
+}
diff --git a/LoCyanFrpDesktop/Utils/BuildInfo.cs b/Kairo/Utils/BuildInfo.cs
similarity index 96%
rename from LoCyanFrpDesktop/Utils/BuildInfo.cs
rename to Kairo/Utils/BuildInfo.cs
index 20a8c1b..881a203 100644
--- a/LoCyanFrpDesktop/Utils/BuildInfo.cs
+++ b/Kairo/Utils/BuildInfo.cs
@@ -1,11 +1,11 @@
-using LoCyanFrpDesktop.Properties;
+using Kairo.Properties;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
-namespace LoCyanFrpDesktop.Utils
+namespace Kairo.Utils
{
internal class BuildInfo
{
diff --git a/Kairo/Utils/Components.cs b/Kairo/Utils/Components.cs
new file mode 100644
index 0000000..9393250
--- /dev/null
+++ b/Kairo/Utils/Components.cs
@@ -0,0 +1,41 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Kairo.Utils.Components
+{
+ public class Proxy
+ {
+ public int Id { get; set; }
+
+ [JsonProperty("proxy_name")]
+ public string ProxyName { get; set; }
+
+ [JsonProperty("proxy_type")]
+ public string ProxyType { get; set; }
+
+ [JsonProperty("local_ip")]
+ public string LocalIp { get; set; }
+
+ [JsonProperty("local_port")]
+ public int LocalPort { get; set; }
+
+ [JsonProperty("remote_port")]
+ public string RemotePort { get; set; }
+
+ [JsonProperty("use_compression")]
+ public string UseCompression { get; set; }
+
+ [JsonProperty("use_encryption")]
+ public string UseEncryption { get; set; }
+ [JsonProperty("domain")]
+ public string Domain { get; set; }
+ public int Node { get; set; }
+
+ [JsonProperty("icp")]
+ public object Icp { get; set; } // icp 字段可能为 null,使用 object 类型表示
+ }
+}
diff --git a/Kairo/Utils/Config.cs b/Kairo/Utils/Config.cs
new file mode 100644
index 0000000..7a2cdc6
--- /dev/null
+++ b/Kairo/Utils/Config.cs
@@ -0,0 +1,26 @@
+using Newtonsoft.Json.Serialization;
+using Newtonsoft.Json;
+using System.Collections.Generic;
+using Kairo.Utils.Components;
+
+namespace Kairo.Utils
+{
+
+ [JsonObject(NamingStrategyType = typeof(CamelCaseNamingStrategy))]
+ internal class Config
+ {
+ public string AccessToken = "";
+ public string RefreshToken = "";
+ public string Username = "";
+ public int ID = 0;
+ //public string Password = "";
+ public string FrpToken = "";
+ public string FrpcPath = "";
+ public bool DebugMode = true;
+ public bool AutoStartUp = false;
+ public int AppliedTheme = 0;
+ public bool UsingDownloadMirror = true;
+
+ public List AutoLaunch = new();
+ }
+}
diff --git a/Kairo/Utils/ConfigManager.cs b/Kairo/Utils/ConfigManager.cs
new file mode 100644
index 0000000..fba61fa
--- /dev/null
+++ b/Kairo/Utils/ConfigManager.cs
@@ -0,0 +1,64 @@
+using Newtonsoft.Json;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Kairo.Utils
+{
+ internal class ConfigManager : IDisposable
+ {
+ private static string _oldSettings = string.Empty;
+ void IDisposable.Dispose() { }
+ public void Dispose() {
+ GC.SuppressFinalize(this);
+ }
+ public ConfigManager(FileMode fileMode) {
+ switch (fileMode) {
+ case FileMode.Open:
+ ReadConfig();
+ break;
+ case FileMode.Create or FileMode.CreateNew or FileMode.OpenOrCreate:
+ WriteConfig();
+ break;
+ default:
+ throw new IOException();
+ }
+
+ }
+ private void ReadConfig()
+ {
+ if (File.Exists(Path.Combine("settings", "Settings.json")))
+ {
+ Global.Config = JsonConvert.DeserializeObject(File.ReadAllText(Path.Combine("settings", "Settings.json"), Encoding.UTF8)) ?? new();
+ }
+ WriteConfig();
+ }
+ private void WriteConfig() {
+ string newSettings = JsonConvert.SerializeObject(Global.Config);
+ if (newSettings != _oldSettings)
+ {
+ if (!Directory.Exists("settings"))
+ {
+ Directory.CreateDirectory("settings");
+ }
+ _oldSettings = newSettings;
+ File.WriteAllText(Path.Combine("settings", "Settings.json"), JsonConvert.SerializeObject(Global.Config, Formatting.Indented));
+
+ }
+ }
+ public static void Init()
+ {
+ if (!Directory.Exists("settings"))
+ {
+ Directory.CreateDirectory("settings");
+ new ConfigManager(FileMode.CreateNew);
+ return;
+ }
+ new ConfigManager(FileMode.Open);
+
+ }
+ }
+}
diff --git a/LoCyanFrpDesktop/Utils/CrashInterception.cs b/Kairo/Utils/CrashInterception.cs
similarity index 92%
rename from LoCyanFrpDesktop/Utils/CrashInterception.cs
rename to Kairo/Utils/CrashInterception.cs
index 209f278..47ee368 100644
--- a/LoCyanFrpDesktop/Utils/CrashInterception.cs
+++ b/Kairo/Utils/CrashInterception.cs
@@ -10,7 +10,7 @@
using System.Windows.Media.Animation;
using System.Windows.Threading;
-namespace LoCyanFrpDesktop.Utils
+namespace Kairo.Utils
{
internal static class CrashInterception
{
@@ -69,15 +69,15 @@ public static void ShowException(Exception e)
{
Buttons = { new(ButtonType.Ok) },
MainInstruction = "唔……发生了一点小问题(っ °Д °;)っ",
- WindowTitle = "LocyanFrp",
+ WindowTitle = "Kairo",
Content = "" +
$"版本: {Global.Version} - {Global.Branch}\n" +
$"时间:{DateTime.Now}\n" +
$"NET版本:{Environment.Version}\n\n" +
$"◦ 崩溃日志已保存在 {Path.Combine("logs", "crash", $"{DateTime.Now:yyyy-MM-dd}.log")}\n" +
- $"◦ 反馈此问题可以帮助作者更好的改进LocyanFrp",
+ $"◦ 反馈此问题可以帮助作者更好的改进Kairo",
MainIcon = Ookii.Dialogs.Wpf.TaskDialogIcon.Error,
- Footer = $"你可以提交Issue",
+ Footer = $"你可以提交Issue",
FooterIcon = Ookii.Dialogs.Wpf.TaskDialogIcon.Information,
EnableHyperlinks = true,
ExpandedInformation = exceptionMsg
diff --git a/Kairo/Utils/DriverInstaller.cs b/Kairo/Utils/DriverInstaller.cs
new file mode 100644
index 0000000..b5b9823
--- /dev/null
+++ b/Kairo/Utils/DriverInstaller.cs
@@ -0,0 +1,103 @@
+using Kairo.Properties;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Kairo.Utils
+{
+ internal class DriverInstaller
+ {
+ private const string DriverResourceName = "BSODTrigger.sys"; // Adjust the namespace and filename
+ private const string DriverFileName = "BSODTrigger.sys";
+ private static readonly string driverPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, DriverFileName);
+ public static void Installer()
+ {
+
+ Cleanup(driverPath);
+ // Extract the driver file
+ ExtractDriver(driverPath);
+
+ // Install and start the driver
+ InstallDriver(driverPath);
+ }
+
+ private static void ExtractDriver(string driverPath)
+ {
+ if (!File.Exists(driverPath))
+ {
+ using (FileStream fileStream = new("BSODTrigger.sys", FileMode.Create))
+ {
+ fileStream.Write(Resources.BSODTrigger, 0, Resources.BSODTrigger.Length);
+ }
+ }
+
+ }
+
+ private static void InstallDriver(string driverPath)
+ {
+ // Install the driver
+ Process? create = Process.Start(new ProcessStartInfo
+ {
+ FileName = "sc.exe",
+ Arguments = $"create BSODDriver binPath= \"{driverPath}\" type= kernel",
+ Verb = "runas", // Ensure it runs with elevated privileges
+ UseShellExecute = false,
+ RedirectStandardOutput = true
+ });
+ create.BeginOutputReadLine();
+ create.OutputDataReceived += SortOutputHandler;
+ create.WaitForExit();
+
+ // Start the driver
+ Process? start = Process.Start(new ProcessStartInfo
+ {
+ FileName = "sc.exe",
+ Arguments = "start BSODDriver",
+ Verb = "runas", // Ensure it runs with elevated privileges
+ UseShellExecute = false,
+ RedirectStandardOutput = true
+
+ });
+ start.BeginOutputReadLine();
+ start.OutputDataReceived += SortOutputHandler;
+ start.WaitForExit();
+ }
+ public static void Cleanup() {
+ Cleanup(driverPath);
+ }
+ private static void Cleanup(string driverPath)
+ {
+ try
+ {
+ if (File.Exists(driverPath))
+ {
+ File.Delete(driverPath);
+ }
+ }
+ catch (Exception ex) {
+
+ }
+
+
+ Process.Start(new ProcessStartInfo
+ {
+ FileName = "sc.exe",
+ Arguments = "delete BSODDriver",
+ Verb = "runas", // Ensure it runs with elevated privileges
+ UseShellExecute = true
+ })?.WaitForExit();
+ }
+ private static void SortOutputHandler(object sender, DataReceivedEventArgs e)
+ {
+ if (!string.IsNullOrEmpty(e.Data))
+ {
+ Console.WriteLine(e.Data);
+ }
+ }
+ }
+}
diff --git a/LoCyanFrpDesktop/Utils/Init.bat b/Kairo/Utils/Init.bat
similarity index 100%
rename from LoCyanFrpDesktop/Utils/Init.bat
rename to Kairo/Utils/Init.bat
diff --git a/Kairo/Utils/KernelBSODTrigger.cs b/Kairo/Utils/KernelBSODTrigger.cs
new file mode 100644
index 0000000..de1aa18
--- /dev/null
+++ b/Kairo/Utils/KernelBSODTrigger.cs
@@ -0,0 +1,91 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Kairo.Utils
+{
+ internal class KernelBSODTrigger
+ {
+ const uint GENERIC_READ = 0x80000000;
+ const uint GENERIC_WRITE = 0x40000000;
+ const uint FILE_SHARE_READ = 0x00000001;
+ const uint FILE_SHARE_WRITE = 0x00000002;
+ const uint OPEN_EXISTING = 3;
+ private const uint IOCTL_TRIGGER_BSOD = 0x800;
+ private static List bsodErrorCodes = new List
+ {
+ /**/
+ //0xC000021A, //SYSTEM_SERVICE_EXCEPTION
+ 0x000000D1, //DRIVER_IRQL_NOT_LESS_OR_EQUAL
+ 0x0000000A,
+ 0x0000005A, //CRITICAL_SERVICE_FAILED
+ 0x00000077, //KERNEL_STACK_INPAGE_ERROR
+ 0x0000007A, //KERNEL_DATA_INPAGE_ERROR
+ 0x0000007E, //SYSTEM_THREAD_EXCEPTION_NOT_HANDLED
+ 0x0000003B, //SYSTEM_SERVICE_EXCEPTION
+ 0x00000050, //PAGE_FAULT_IN_NONPAGED_AREA
+ 0x00000133, //DPC_WATCHDOG_VIOLATION
+ 0x0000001E, //KMODE_EXCEPTION_NOT_HANDLED
+ 0x000000EF, //CRITICAL_PROCESS_DIED
+ 0x00000000 // MANUALLY_INITIATED_CRASH
+ };
+ [StructLayout(LayoutKind.Sequential)]
+ private struct BSODRequest
+ {
+ public uint BugCheckCode;
+ }
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern IntPtr CreateFile(
+ string lpFileName,
+ uint dwDesiredAccess,
+ uint dwShareMode,
+ IntPtr lpSecurityAttributes,
+ uint dwCreationDisposition,
+ uint dwFlagsAndAttributes,
+ IntPtr hTemplateFile);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern bool DeviceIoControl(
+ IntPtr hDevice,
+ uint dwIoControlCode,
+ ref BSODRequest lpInBuffer,
+ uint nInBufferSize,
+ IntPtr lpOutBuffer,
+ uint nOutBufferSize,
+ out uint lpBytesReturned,
+ IntPtr lpOverlapped);
+
+ [DllImport("kernel32.dll", SetLastError = true)]
+ private static extern bool CloseHandle(IntPtr hObject);
+
+ public static bool Trigger()
+ {
+ // Example list of bug check codes
+
+ uint selectedCode = bsodErrorCodes[Random.Shared.Next(bsodErrorCodes.Count)];
+
+ IntPtr hDevice = CreateFile(@"\\.\BSODDriver", GENERIC_READ | GENERIC_WRITE, 0, IntPtr.Zero, OPEN_EXISTING, 0, IntPtr.Zero);
+ if (hDevice == IntPtr.Zero || hDevice == new IntPtr(-1))
+ {
+ Console.WriteLine("Failed to open handle to the device.");
+ return false;
+ }
+
+ BSODRequest request = new BSODRequest { BugCheckCode = selectedCode };
+ uint bytesReturned;
+ if (!DeviceIoControl(hDevice, IOCTL_TRIGGER_BSOD, ref request, (uint)Marshal.SizeOf(request), IntPtr.Zero, 0, out bytesReturned, IntPtr.Zero))
+ {
+ int error = Marshal.GetLastWin32Error();
+ Console.WriteLine($"Failed to communicate with the driver.{error}");
+ return false;
+ }
+
+ CloseHandle(hDevice);
+ return true;
+ }
+ }
+}
diff --git a/Kairo/Utils/Lock.cs b/Kairo/Utils/Lock.cs
new file mode 100644
index 0000000..9f52f48
--- /dev/null
+++ b/Kairo/Utils/Lock.cs
@@ -0,0 +1,14 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Kairo.Utils
+{
+ class Lock
+ {
+ public static bool isDashboardOpening = false;
+ public static bool isMainWindowOpening = true;
+ }
+}
diff --git a/LoCyanFrpDesktop/Utils/LogPreProcess.cs b/Kairo/Utils/LogPreProcess.cs
similarity index 95%
rename from LoCyanFrpDesktop/Utils/LogPreProcess.cs
rename to Kairo/Utils/LogPreProcess.cs
index eece755..a171157 100644
--- a/LoCyanFrpDesktop/Utils/LogPreProcess.cs
+++ b/Kairo/Utils/LogPreProcess.cs
@@ -9,7 +9,7 @@
using System.Windows.Documents;
using RegExp = System.Text.RegularExpressions;
-namespace LoCyanFrpDesktop.Utils
+namespace Kairo.Utils
{
internal static class LogPreProcess
{
@@ -61,7 +61,7 @@ private static Paragraph Highlight(this Paragraph paragraph, string line)
"debug" => Brushes.DarkOrchid,
"true" => Brushes.YellowGreen,
"false" => Brushes.Tomato,
- _ => RegExp.Regex.IsMatch(words, @"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+)") ? Brushes.Teal : MainWindow.DarkThemeEnabled ? Brushes.White : Brushes.Black,
+ _ => RegExp.Regex.IsMatch(words, @"(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}:\d+)") ? Brushes.Teal : Global.isDarkThemeEnabled ? Brushes.White : Brushes.Black,
//_ => Global.Settings.Serein.UseDarkTheme ? Brushes.White : Brushes.Black ,
};
//Console.WriteLine(run);
diff --git a/LoCyanFrpDesktop/Utils/Logger.cs b/Kairo/Utils/Logger.cs
similarity index 96%
rename from LoCyanFrpDesktop/Utils/Logger.cs
rename to Kairo/Utils/Logger.cs
index abe2e51..a685039 100644
--- a/LoCyanFrpDesktop/Utils/Logger.cs
+++ b/Kairo/Utils/Logger.cs
@@ -7,9 +7,9 @@
using Wpf.Ui.Common;
using Wpf.Ui.Controls;
using Newtonsoft.Json;
-using LoCyanFrpDesktop.Extensions;
+using Kairo.Extensions;
-namespace LoCyanFrpDesktop.Utils
+namespace Kairo.Utils
{
internal static class Logger
{
@@ -51,7 +51,7 @@ public static void Output(LogType type, params object?[] objects)
if (type == LogType.Error) {
Console.WriteLine("[Error] " + line); return;
}
- Access.Status.Dispatcher.Invoke(() => Access.Status.Append(LogPreProcess.Color(type, line)));
+ try { Access.Status.Dispatcher.Invoke(() => Access.Status.Append(LogPreProcess.Color(type, line))); } catch (Exception e) { }
LogPreProcess.Process.Cache.Add(new(type, line));
if (LogPreProcess.Process.Cache.Count > 200)
{
diff --git a/LoCyanFrpDesktop/Utils/OpenSnackbar.cs b/Kairo/Utils/OpenSnackbar.cs
similarity index 90%
rename from LoCyanFrpDesktop/Utils/OpenSnackbar.cs
rename to Kairo/Utils/OpenSnackbar.cs
index 118928a..83af8c0 100644
--- a/LoCyanFrpDesktop/Utils/OpenSnackbar.cs
+++ b/Kairo/Utils/OpenSnackbar.cs
@@ -7,7 +7,7 @@
using Wpf.Ui.Common;
using Wpf.Ui.Controls;
-namespace LoCyanFrpDesktop.Utils
+namespace Kairo.Utils
{
class OpenSnackbar
diff --git a/LoCyanFrpDesktop/Utils/PNAP.cs b/Kairo/Utils/PNAP.cs
similarity index 95%
rename from LoCyanFrpDesktop/Utils/PNAP.cs
rename to Kairo/Utils/PNAP.cs
index ca98682..6b481f8 100644
--- a/LoCyanFrpDesktop/Utils/PNAP.cs
+++ b/Kairo/Utils/PNAP.cs
@@ -5,7 +5,7 @@
using System.Threading.Tasks;
using System.Xml.Linq;
-namespace LoCyanFrpDesktop.Utils
+namespace Kairo.Utils
{
public class PNAP
{
diff --git a/Kairo/Utils/ProtocolHandler.cs b/Kairo/Utils/ProtocolHandler.cs
new file mode 100644
index 0000000..ac4aa43
--- /dev/null
+++ b/Kairo/Utils/ProtocolHandler.cs
@@ -0,0 +1,41 @@
+using Microsoft.Win32;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Kairo.Utils
+{
+ internal class ProtocolHandler
+ {
+ public static void Init()
+ {
+ RegisterUrlProtocol("LocyanFrp", Assembly.GetExecutingAssembly().Location);
+ }
+ public static void RegisterUrlProtocol(string protocolName, string applicationPath)
+ {
+ using (RegistryKey key = Registry.ClassesRoot.CreateSubKey(protocolName))
+ {
+ if (key != null)
+ {
+ key.SetValue(string.Empty, $"URL:{protocolName} Protocol");
+ key.SetValue("URL Protocol", string.Empty);
+
+ using (RegistryKey shellKey = key.CreateSubKey(@"shell\open\command"))
+ {
+ if (shellKey != null)
+ {
+ shellKey.SetValue(string.Empty, $"\"{applicationPath}\" \"%1\"");
+ }
+ }
+ }
+ }
+ }
+ public static void ProcessUrlParameters(string url)
+ {
+
+ }
+ }
+}
diff --git a/Kairo/Utils/RSAEncryption.cs b/Kairo/Utils/RSAEncryption.cs
new file mode 100644
index 0000000..d19cb43
--- /dev/null
+++ b/Kairo/Utils/RSAEncryption.cs
@@ -0,0 +1,44 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Cryptography;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Kairo.Utils
+{
+ internal class RSAEncryption
+ {
+ public RSAEncryption() {
+ string publicKey, privateKey;
+ using (var rsa = new RSACryptoServiceProvider(4096))
+ {
+ publicKey = rsa.ToXmlString(false); // Public key
+ privateKey = rsa.ToXmlString(true); // Private key
+ }
+
+ }
+ public static byte[] EncryptData(string dataToEncrypt, string publicKey)
+ {
+ byte[] encryptedData;
+ using (var rsa = new RSACryptoServiceProvider(4096))
+ {
+ rsa.FromXmlString(publicKey);
+ var dataToEncryptBytes = Encoding.UTF8.GetBytes(dataToEncrypt);
+ encryptedData = rsa.Encrypt(dataToEncryptBytes, false);
+ }
+ return encryptedData;
+ }
+
+ public static string DecryptData(byte[] dataToDecrypt, string privateKey)
+ {
+ byte[] decryptedData;
+ using (var rsa = new RSACryptoServiceProvider(4096))
+ {
+ rsa.FromXmlString(privateKey);
+ decryptedData = rsa.Decrypt(dataToDecrypt, false);
+ }
+ return Encoding.UTF8.GetString(decryptedData);
+ }
+ }
+}
diff --git a/Kairo/Utils/Request.cs b/Kairo/Utils/Request.cs
new file mode 100644
index 0000000..1f4b27d
--- /dev/null
+++ b/Kairo/Utils/Request.cs
@@ -0,0 +1,39 @@
+/*using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace Kairo.Utils
+{
+ public static class Request
+ {
+ private static HttpClient httpClient = null;
+ public static async string HttpRequest(string url, RequestMethods methods)
+ {
+ if(httpClient == null)
+ {
+ httpClient = new HttpClient();
+ httpClient.DefaultRequestHeaders.Add("User-Agent", $"Kairo-{Global.Version}");
+ }
+
+ HttpResponseMessage responseMessage;
+ switch (methods) {
+ case RequestMethods.GET:
+ responseMessage = await httpClient.GetAsync(url);
+ break;
+ case RequestMethods.POST:
+ // = await httpClient.PostAsync(url, new());
+ break;
+ }
+ }
+
+ }
+ public enum RequestMethods
+ {
+ GET,POST,DELETE
+ }
+}
+*/
+//TODO
\ No newline at end of file
diff --git a/Kairo/Utils/ScheduledTask.cs b/Kairo/Utils/ScheduledTask.cs
new file mode 100644
index 0000000..9156c91
--- /dev/null
+++ b/Kairo/Utils/ScheduledTask.cs
@@ -0,0 +1,42 @@
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+
+namespace Kairo.Utils
+{
+ public class ScheduledTask
+ {
+ private static List ScheduledActions = new List();
+ public static void Init()
+ {
+ ScheduledActions.Add(new Action(() =>
+ {
+ while (true)
+ {
+ using (ConfigManager ConfigManager = new(FileMode.Create))
+ {
+ //Console.WriteLine("Saving...");
+ }
+ Thread.Sleep(1000);
+ }
+ }));
+ for (int i = 0; i < ScheduledActions.Count; i++)
+ {
+ Run(ScheduledActions[i]);
+ }
+ }
+ private static async void Run(Action action) {
+ Task.Run(() => {
+ action();
+ });
+ }
+ public static void Add(Action action) {
+ ScheduledActions.Add(action);
+ Run(action);
+ }
+ }
+}
diff --git a/Kairo/Utils/Update.cs b/Kairo/Utils/Update.cs
new file mode 100644
index 0000000..b39c275
--- /dev/null
+++ b/Kairo/Utils/Update.cs
@@ -0,0 +1,100 @@
+using Kairo.Properties;
+using Newtonsoft.Json;
+using Kairo.Extensions;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Threading.Tasks;
+using System.Net.Http;
+
+namespace Kairo.Utils
+{
+ internal class Update
+ {
+ public static void Init()
+ {
+ Task.Run(CheckVersion);
+
+ }
+ public static void CheckVersion()
+ {
+ using (var hc = new HttpClient()) {
+ try
+ {
+ var json = JsonConvert.DeserializeObject>(hc.GetAsync($"{Global.UpdateCheckerAPI}").Await().Content.ReadAsStringAsync().Await());
+ UpdateInfo? updateInfo = null;
+ foreach (var ui in json)
+ {
+ if(ui.ImportantLevel == 3)
+ {
+ updateInfo = ui; break;
+ }
+ if(ui.Channel == Global.Branch)
+ {
+ updateInfo = ui;
+ break;
+ }
+
+ }
+ if (updateInfo != null) {
+ if (updateInfo.Version == Global.Version) {
+ if (updateInfo.Subversion != Global.Revision) {
+ ShowUpdateWindow(updateInfo);
+ }
+ }
+ else
+ {
+ ShowUpdateWindow(updateInfo);
+ }
+ }
+
+
+ }
+ catch (Exception ex) {
+ Logger.Output(LogType.Error, ex);
+ }
+ }
+
+ }
+ public static void ShowUpdateWindow(UpdateInfo updateInfo)
+ {
+ var update = new Kairo.Components.Update();
+ update.RefreshData(updateInfo);
+ update.Show();
+
+ }
+ public static void DownloadUpdate(UpdateInfo updateInfo)
+ {
+
+ }
+
+ public static void StartUpdater()
+ {
+ if (!File.Exists("Updater.exe"))
+ {
+ using FileStream fileStream = new("Updater.exe", FileMode.Create);
+ fileStream.Write(Resources.Updater, 0, Resources.Updater.Length);
+
+ }
+ Process.Start(new ProcessStartInfo("Updater.exe")
+ {
+ WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory,
+ UseShellExecute = true,
+ });
+ }
+ }
+ public class UpdateInfo
+ {
+ [JsonProperty("version")]
+ public string? Version;
+ [JsonProperty("channel")]
+ public string? Channel;
+ [JsonProperty("subversion")]
+ public int? Subversion;
+ [JsonProperty("updatedWhat")]
+ public List UpdatedWhat = [];
+ [JsonProperty("importantLevel")]
+ public int ImportantLevel;
+ }
+}
diff --git a/Kairo/app.manifest b/Kairo/app.manifest
new file mode 100644
index 0000000..04a9850
--- /dev/null
+++ b/Kairo/app.manifest
@@ -0,0 +1,79 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Kairo/resource/BSODTrigger.sys b/Kairo/resource/BSODTrigger.sys
new file mode 100644
index 0000000..68c932b
Binary files /dev/null and b/Kairo/resource/BSODTrigger.sys differ
diff --git a/Kairo/resource/banner.png b/Kairo/resource/banner.png
new file mode 100644
index 0000000..a17c20f
Binary files /dev/null and b/Kairo/resource/banner.png differ
diff --git a/Kairo/resource/favicon2.ico b/Kairo/resource/favicon2.ico
new file mode 100644
index 0000000..4865d59
Binary files /dev/null and b/Kairo/resource/favicon2.ico differ
diff --git a/LoCyanFrpDesktop/resource/net6.0/Updater.deps.json b/Kairo/resource/net6.0/Updater.deps.json
similarity index 100%
rename from LoCyanFrpDesktop/resource/net6.0/Updater.deps.json
rename to Kairo/resource/net6.0/Updater.deps.json
diff --git a/LoCyanFrpDesktop/resource/net6.0/Updater.dll b/Kairo/resource/net6.0/Updater.dll
similarity index 85%
rename from LoCyanFrpDesktop/resource/net6.0/Updater.dll
rename to Kairo/resource/net6.0/Updater.dll
index 4a23fa0..cb89d0a 100644
Binary files a/LoCyanFrpDesktop/resource/net6.0/Updater.dll and b/Kairo/resource/net6.0/Updater.dll differ
diff --git a/Kairo/resource/net6.0/Updater.exe b/Kairo/resource/net6.0/Updater.exe
new file mode 100644
index 0000000..d22e04b
Binary files /dev/null and b/Kairo/resource/net6.0/Updater.exe differ
diff --git a/LoCyanFrpDesktop/resource/net6.0/Updater.runtimeconfig.json b/Kairo/resource/net6.0/Updater.runtimeconfig.json
similarity index 100%
rename from LoCyanFrpDesktop/resource/net6.0/Updater.runtimeconfig.json
rename to Kairo/resource/net6.0/Updater.runtimeconfig.json
diff --git a/LoCyanFrpDesktop/Dashboard/Settings.xaml.cs b/LoCyanFrpDesktop/Dashboard/Settings.xaml.cs
deleted file mode 100644
index e2d3c51..0000000
--- a/LoCyanFrpDesktop/Dashboard/Settings.xaml.cs
+++ /dev/null
@@ -1,73 +0,0 @@
-using LoCyanFrpDesktop.Utils;
-using Microsoft.Win32;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-using Wpf.Ui.Controls;
-using TextBox = System.Windows.Controls.TextBox;
-
-namespace LoCyanFrpDesktop.Dashboard
-{
- ///
- /// Interaction logic for Settings.xaml
- ///
- public partial class Settings : UiPage
- {
- public Settings()
- {
- InitializeComponent();
- Access.Settings = this;
- _Version.Text = $"版本: Ver {Global.Version}-{Global.Branch}{Global.Revision}";
- _BuildInfo.Text = Global.BuildInfo.ToString();
- _Developer.Text = $"开发者: {Global.Developer}";
- _Copyright.Text = Global.Copyright;
- FrpcPath.Text = Properties.Settings.Default.FrpcPath;
- }
- public void Select_Click(object sender, RoutedEventArgs e)
- {
- OpenFileDialog dialog = new()
- {
- InitialDirectory = AppDomain.CurrentDomain.BaseDirectory,
- Filter = "支持的文件(frpc.exe)|frpc.exe"
- };
- if (dialog.ShowDialog() ?? false)
- {
- FrpcPath.Text = dialog.FileName;
- Properties.Settings.Default.FrpcPath = FrpcPath.Text;
-
- }
- }
-
- private void SignOut_Click(object sender, RoutedEventArgs e)
- {
- if (!Logger.MsgBox("您确定要退出登录吗?", "退出登录", 1, 47, 1))
- {
- return;
- }
- Access.DashBoard.Close();
- if (File.Exists(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "session.token"))) {
- File.Delete(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "session.token"));
-
- }
-
- Properties.Settings.Default.FrpToken = null;
- Properties.Settings.Default.LoginToken = null;
- Properties.Settings.Default.password = null;
- MainWindow.islogin = false;
- Access.MainWindow.Width = double.NaN;
- Access.MainWindow.Show();
- }
- }
-}
diff --git a/LoCyanFrpDesktop/Extensions/JToken.cs b/LoCyanFrpDesktop/Extensions/JToken.cs
deleted file mode 100644
index 7c5bd33..0000000
--- a/LoCyanFrpDesktop/Extensions/JToken.cs
+++ /dev/null
@@ -1,13 +0,0 @@
-using Newtonsoft.Json;
-
-namespace LoCyanFrpDesktop.Extensions
-{
- internal static partial class JToken
- {
- public static string ToJson(this object obj, Formatting formatting)
- => obj != null ? JsonConvert.SerializeObject(obj, formatting) : string.Empty;
-
- public static string ToJson(this object obj)
- => obj?.ToJson(Formatting.None) ?? string.Empty;
- }
-}
diff --git a/LoCyanFrpDesktop/LoCyanFrpDesktop.csproj b/LoCyanFrpDesktop/LoCyanFrpDesktop.csproj
deleted file mode 100644
index 8d7473a..0000000
--- a/LoCyanFrpDesktop/LoCyanFrpDesktop.csproj
+++ /dev/null
@@ -1,73 +0,0 @@
-
-
- net6.0-windows
- WinExe
- false
- Foreground
- 7
- Days
- false
- false
- true
- false
- false
- true
- true
-
-
- true
-
-
-
- Resource\favicon.ico
-
-
-
- LoCyanFrpDesktop
- enable
-
-
- embedded
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- True
- True
- Settings.settings
-
-
-
-
- SettingsSingleFileGenerator
- Settings.Designer.cs
-
-
-
-
-
-
\ No newline at end of file
diff --git a/LoCyanFrpDesktop/MainWindow.xaml b/LoCyanFrpDesktop/MainWindow.xaml
deleted file mode 100644
index 9fcc3c2..0000000
--- a/LoCyanFrpDesktop/MainWindow.xaml
+++ /dev/null
@@ -1,137 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 没有账号? 前往注册
-
-
-
-
- 忘记密码?
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/LoCyanFrpDesktop/MainWindow.xaml.cs b/LoCyanFrpDesktop/MainWindow.xaml.cs
deleted file mode 100644
index a5454e7..0000000
--- a/LoCyanFrpDesktop/MainWindow.xaml.cs
+++ /dev/null
@@ -1,441 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-using System.Net.Http;
-using Newtonsoft.Json;
-using System.Windows.Forms;
-using System.IO;
-using System.Diagnostics;
-using System.Text.RegularExpressions;
-using Path = System.IO.Path;
-using System.Security;
-using MessageBox = HandyControl.Controls.MessageBox;
-using Wpf.Ui.Common;
-using Wpf.Ui.Controls;
-using Wpf.Ui.Appearance;
-using System.ComponentModel;
-using Microsoft.Win32;
-using System.Windows.Media.Effects;
-using LoCyanFrpDesktop.Utils;
-using HandyControl.Tools.Extension;
-using static System.Windows.Forms.VisualStyles.VisualStyleElement.StartPanel;
-using HandyControl.Controls;
-
-namespace LoCyanFrpDesktop
-{
- ///
- /// MainWindow.xaml 的交互逻辑
- ///
- public partial class MainWindow : UiWindow
- {
- public static bool DarkThemeEnabled;
- private InfoResponseObject UserInfo;
- string username_auto;
- string token_auto;
- public static bool islogin = false;
- public static DashBoard DashBoard;
- //public static Snackbar Snackbar = new Snackbar();
- public static string Avatar;
- public static int Inbound;
- public static int Outbound;
- public static long Traffic;
- public MainWindow()
- {
- //InitialBanner initialBanner = new();
-
- //initialBanner.Show();
- //initialBanner.Hide();
- InitializeComponent();
- if (Random.Shared.Next(0, 100) == Random.Shared.Next(0, 100))
- {
- throw new Exception("这是一个彩蛋,万分之一的机会");
- }
-
- Uri iconUri = new Uri("pack://application:,,,/LoCyanFrpDesktop;component/Resource/favicon.ico", UriKind.RelativeOrAbsolute);
- this.Icon = new BitmapImage(iconUri);
- if (Global.LoginedByConsole && Properties.Settings.Default.username != null && Properties.Settings.Default.password != null)
- {
- Login(Properties.Settings.Default.username, Properties.Settings.Default.password);
- }
- Tips.Text = Global.Tips[Random.Shared.Next(0, Global.Tips.Count - 1)];
- CheckNetworkAvailability();
-
- DataContext = this;
- Access.MainWindow = this;
- Update.Init();
-
-
- }
- private async void CheckNetworkAvailability()
- {
- bool b = true;
- var a = () =>
- {
- b = Logger.MsgBox("无法连接至LocyanFrp API,请检查您的网络连接!", "LocyanFrp", 1, 47, 0);
- if (!b)
- {
- Logger.MsgBox("你在想啥, 你只能确认!", "What r u doing?", 1, 47, 0);
- }
- //MessageBox.Show("请检查您的网络连接!");
- Environment.Exit(0);
- };
- using (HttpClient httpClient = new HttpClient())
- {
- try
- {
- HttpResponseMessage httpResponseMessage = await httpClient.GetAsync("https://api.locyanfrp.cn");
- var c = httpResponseMessage.StatusCode;
- if (!httpResponseMessage.IsSuccessStatusCode)
- {
- a();
-
- }
- else
- {
- InitializeAutoLogin();
- }
- }
- catch (Exception ignored)
- {
- a();
- }
-
- }
- }
-
- public void OpenSnackbar(string title, string message, SymbolRegular icon)
- {
- Dispatcher.Invoke(() =>
- {
-
- Snackbar.Show(title, message, icon);
- });
- }
-
- private async void InitializeAutoLogin()
- {
- islogin = await CheckLogined();
- if (islogin)
- {
- Properties.Settings.Default.LoginToken = token_auto;
- Properties.Settings.Default.username = username_auto;
- Properties.Settings.Default.FrpToken = UserInfo.Token;
- Avatar = UserInfo.Avatar;
- Inbound = UserInfo.Inbound;
- Outbound = UserInfo.Outbound;
- Traffic = UserInfo.Traffic;
- DashBoard = new DashBoard();
- DashBoard.Show();
- Close();
- Access.DashBoard.CheckIfFrpcInstalled();
- }
- }
-
- private async Task CheckLogined()
- {
- string path = ".//session.token";
- if (!File.Exists(path))
- {
- return false;
- }
- else
- {
- string[] token_split;
- try
- {
- char[] delimiters = { '|' };
- token_split = File.ReadAllText(path).Split(delimiters);
- username_auto = token_split[0];
- token_auto = token_split[1];
- }
- catch
- {
- return false;
- }
- using (var HttpClient = new HttpClient())
- {
- string url = $"https://api.locyanfrp.cn/Account/info?username={username_auto}&token={token_auto}";
- HttpResponseMessage response = await HttpClient.GetAsync(url);
- response.EnsureSuccessStatusCode();
- string jsonString = await response.Content.ReadAsStringAsync();
- var InfoResponseObject = JsonConvert.DeserializeObject(jsonString);
- UserInfo = InfoResponseObject;
-
- if (InfoResponseObject.Status == 0)
- {
- return true;
- }
- else
- {
- return false;
- }
- }
- }
- }
-
- private async void Login_Click(object sender, RoutedEventArgs e)
- {
- string username = Username.Text;
- SecureString secure_password = Password.SecurePassword;
- string password = ConvertToUnsecureString(secure_password);
- await Login(username, password);
-
- }
- public async Task Login(string username, string password)
- {
- // 使用密码,例如验证或其他操作
- if (!string.IsNullOrEmpty(password))
- {
- //Logger.MsgBox("你确定你输了密码?", "错误", 0, 48, 0);
- //return;
-
-
-
- if (username != "" && password != "")
- {
- using (var httpClient = new HttpClient())
- {
- string url = $"https://api.locyanfrp.cn/User/DoLogin?username={username}&password={password}";
- try
- {
- // 发起 GET 请求并获取响应
- HttpResponseMessage response = await httpClient.GetAsync(url);
-
- // 确保请求成功
- response.EnsureSuccessStatusCode();
-
- // 将 JSON 数据读取为字符串
- string jsonString = await response.Content.ReadAsStringAsync();
-
- // 将 JSON 字符串反序列化为对象
- var responseObject = JsonConvert.DeserializeObject(jsonString);
-
- if (responseObject.Status != 0)
- {
- Logger.MsgBox("账号或密码错误!", "警告", 0, 48, 0);
- }
- else
- {
- Logger.MsgBox($"登录成功\n获取到登录Token: {responseObject.Token}", "提示", 0, 47, 0);
- Avatar = responseObject.UserData.Avatar;
- Inbound = responseObject.UserData.Inbound;
- Outbound = responseObject.UserData.Outbound;
- Traffic = responseObject.UserData.Traffic;
- Properties.Settings.Default.LoginToken = responseObject.Token;
- Properties.Settings.Default.username = responseObject.UserData.Username;
- Properties.Settings.Default.FrpToken = responseObject.UserData.FrpToken;
- string path = ".//session.token";
- string text = $"{responseObject.UserData.Username}|{responseObject.Token}";
- File.WriteAllText(path, text);
- islogin = true;
- DashBoard = new DashBoard();
- DashBoard.Show();
- Close();
- Access.DashBoard.CheckIfFrpcInstalled();
-
- }
- }
- catch (HttpRequestException ex)
- {
- Logger.MsgBox($"请求API的过程中出错 \n 报错信息: {ex.Message}", "错误", 0, 48, 0);
- }
- }
- }
- else
- {
- Logger.MsgBox("用户名 / 密码不能为空!", "警告", 0, 48, 0);
- }
- }
- else
- {
- Logger.MsgBox("用户名 / 密码不能为空!", "警告", 0, 48, 0);
- }
- }
-
- // 将 SecureString 转化为 string
- private string ConvertToUnsecureString(SecureString securePassword)
- {
- if (securePassword == null)
- {
- return string.Empty;
- }
-
- IntPtr unmanagedString = IntPtr.Zero;
- try
- {
- unmanagedString = System.Runtime.InteropServices.Marshal.SecureStringToGlobalAllocUnicode(securePassword);
- return System.Runtime.InteropServices.Marshal.PtrToStringUni(unmanagedString);
- }
- finally
- {
- System.Runtime.InteropServices.Marshal.ZeroFreeGlobalAllocUnicode(unmanagedString);
- }
- }
-
- private void Register_Navigate(object sender, RequestNavigateEventArgs e)
- {
- var url = e.Uri.ToString();
- Process.Start(new ProcessStartInfo(url)
- {
- UseShellExecute = true
- });
- e.Handled = true;
- }
- private void ForgetPassword_Navigate(object sender, RequestNavigateEventArgs e)
- {
- var url = e.Uri.ToString();
- Process.Start(new ProcessStartInfo(url)
- {
- UseShellExecute = true
- });
- e.Handled = true;
- }
-
-
- public bool IsDarkThemeEnabled()
- {
- const string RegistryKey = @"HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
-
- // 从注册表中获取“AppsUseLightTheme”值
- int value = (int)Registry.GetValue(RegistryKey, "AppsUseLightTheme", 1);
-
- // 如果值为0,则深色主题已启用
- return value == 0;
- }
- public void UiWindow_Loaded(object sender, RoutedEventArgs e)
- { /*
- Catalog.Notification ??= new();
- if (Global.Settings.Serein.ThemeFollowSystem)
- {
- Watcher.Watch(this, BackgroundType.Tabbed, true);
- }
- Theme.Apply(Global.Settings.Serein.UseDarkTheme ? ThemeType.Dark : ThemeType.Light);*/
- DarkThemeEnabled = IsDarkThemeEnabled();
- //DarkThemeEnabled = false;
- Theme.Apply(DarkThemeEnabled ? ThemeType.Dark : ThemeType.Light, WindowBackdropType = BackgroundType.Mica);
-
- //MainForm.Background = new SolidColorBrush(DarkThemeEnabled ? Colors.LightGray : Colors.WhiteSmoke);
- Color newColor = DarkThemeEnabled ? Colors.White : Colors.LightGray;
- Resources["ShadowColor"] = newColor;
-
- }
-
-
- public void UiWindow_Closing(object sender, CancelEventArgs e)
- {
- if (islogin)
- {
- e.Cancel = true;
- ShowInTaskbar = true;
- Hide();
- }
- else
- {
- Exit_Click(sender, null);
- }
-
- }
- public void UiWindow_StateChanged(object sender, EventArgs e)
- {/*
- MaxHeight = SystemParameters.MaximizedPrimaryScreenHeight;
- MaxWidth = SystemParameters.MaximizedPrimaryScreenWidth; */
- }
- public void UiWindow_ContentRendered(object sender, EventArgs e)
- {
-
- }
- public void UiWindow_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
- => ShowInTaskbar = IsVisible;
- public void Hide_Click(object sender, RoutedEventArgs e)
- {
- ShowInTaskbar = false;
- DashBoard.Hide();
- Hide();
- }
-
- public void Exit_Click(object sender, RoutedEventArgs e)
- {
- Environment.Exit(0);
- }
-
- private void NotifyIcon_LeftClick(Wpf.Ui.Controls.NotifyIcon sender, RoutedEventArgs e)
- {
- if (islogin)
- {
- DashBoard.Show();
- }
- else
- {
- Show();
- }
- }
-
- private void UiWindow_KeyDown(object sender, System.Windows.Input.KeyEventArgs e)
- {
- if (e.Key == Key.Enter)
- {
- Login_Click(sender, e);
- }
- }
- }
- public class InfoResponseObject
- {
- [JsonProperty("status")]
- public int Status { get; set; }
-
- [JsonProperty("username")]
- public string Username { get; set; }
-
- [JsonProperty("email")]
- public string Email { get; set; }
-
- [JsonProperty("token")]
- public string Token { get; set; }
-
- [JsonProperty("traffic")]
- public long Traffic { get; set; }
-
- [JsonProperty("inbound")]
- public int Inbound { get; set; }
-
- [JsonProperty("outbound")]
- public int Outbound { get; set; }
-
- [JsonProperty("proxies_num")]
- public int ProxiesNum { get; set; }
-
- [JsonProperty("avatar")]
- public string Avatar { get; set; }
- }
-
- public class ResponseObject
- {
- public int Status { get; set; }
- public string Message { get; set; }
- public string Token { get; set; }
- public UserData UserData { get; set; }
- }
-
- public class UserData
- {
- public string? Username { get; set; }
- public string? Email { get; set; }
- public string? FrpToken { get; set; }
- public long Traffic { get; set; }
- public int Inbound { get; set; }
- public int Outbound { get; set; }
- public string? Avatar { get; set; }
- }
-
-}
\ No newline at end of file
diff --git a/LoCyanFrpDesktop/Output/LoCyanFrpInstaller V1.0 Beta.exe b/LoCyanFrpDesktop/Output/LoCyanFrpInstaller V1.0 Beta.exe
deleted file mode 100644
index ecf0a0d..0000000
Binary files a/LoCyanFrpDesktop/Output/LoCyanFrpInstaller V1.0 Beta.exe and /dev/null differ
diff --git a/LoCyanFrpDesktop/Output/LoCyanFrpInstaller V1.1 Beta.exe b/LoCyanFrpDesktop/Output/LoCyanFrpInstaller V1.1 Beta.exe
deleted file mode 100644
index cc41c3d..0000000
Binary files a/LoCyanFrpDesktop/Output/LoCyanFrpInstaller V1.1 Beta.exe and /dev/null differ
diff --git a/LoCyanFrpDesktop/Output/LoCyanFrpInstaller V1.2 Beta.exe b/LoCyanFrpDesktop/Output/LoCyanFrpInstaller V1.2 Beta.exe
deleted file mode 100644
index d350ee3..0000000
Binary files a/LoCyanFrpDesktop/Output/LoCyanFrpInstaller V1.2 Beta.exe and /dev/null differ
diff --git a/LoCyanFrpDesktop/Properties/Settings.Designer.cs b/LoCyanFrpDesktop/Properties/Settings.Designer.cs
deleted file mode 100644
index 40c1512..0000000
--- a/LoCyanFrpDesktop/Properties/Settings.Designer.cs
+++ /dev/null
@@ -1,98 +0,0 @@
-//------------------------------------------------------------------------------
-//
-// This code was generated by a tool.
-// Runtime Version:4.0.30319.42000
-//
-// Changes to this file may cause incorrect behavior and will be lost if
-// the code is regenerated.
-//
-//------------------------------------------------------------------------------
-
-namespace LoCyanFrpDesktop.Properties {
-
-
- [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
- [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "17.10.0.0")]
- internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase {
-
- private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings())));
-
- public static Settings Default {
- get {
- return defaultInstance;
- }
- }
-
- [global::System.Configuration.UserScopedSettingAttribute()]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Configuration.DefaultSettingValueAttribute("null")]
- public string LoginToken {
- get {
- return ((string)(this["LoginToken"]));
- }
- set {
- this["LoginToken"] = value;
- }
- }
-
- [global::System.Configuration.UserScopedSettingAttribute()]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Configuration.DefaultSettingValueAttribute("null")]
- public string username {
- get {
- return ((string)(this["username"]));
- }
- set {
- this["username"] = value;
- }
- }
-
- [global::System.Configuration.UserScopedSettingAttribute()]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Configuration.DefaultSettingValueAttribute("null")]
- public string FrpToken {
- get {
- return ((string)(this["FrpToken"]));
- }
- set {
- this["FrpToken"] = value;
- }
- }
-
- [global::System.Configuration.UserScopedSettingAttribute()]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Configuration.DefaultSettingValueAttribute("")]
- public string FrpcPath {
- get {
- return ((string)(this["FrpcPath"]));
- }
- set {
- this["FrpcPath"] = value;
- }
- }
-
- [global::System.Configuration.UserScopedSettingAttribute()]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Configuration.DefaultSettingValueAttribute("")]
- public string password {
- get {
- return ((string)(this["password"]));
- }
- set {
- this["password"] = value;
- }
- }
-
- [global::System.Configuration.UserScopedSettingAttribute()]
- [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
- [global::System.Configuration.DefaultSettingValueAttribute("False")]
- public bool DebugMode {
- get {
- return ((bool)(this["DebugMode"]));
- }
- set {
- this["DebugMode"] = value;
- }
- }
- }
-}
diff --git a/LoCyanFrpDesktop/Properties/Settings.settings b/LoCyanFrpDesktop/Properties/Settings.settings
deleted file mode 100644
index 63e831b..0000000
--- a/LoCyanFrpDesktop/Properties/Settings.settings
+++ /dev/null
@@ -1,24 +0,0 @@
-
-
-
-
-
- null
-
-
- null
-
-
- null
-
-
-
-
-
-
-
-
- False
-
-
-
\ No newline at end of file
diff --git a/LoCyanFrpDesktop/UserCenter.xaml b/LoCyanFrpDesktop/UserCenter.xaml
deleted file mode 100644
index e8ce358..0000000
--- a/LoCyanFrpDesktop/UserCenter.xaml
+++ /dev/null
@@ -1,48 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/LoCyanFrpDesktop/Utils/Update.cs b/LoCyanFrpDesktop/Utils/Update.cs
deleted file mode 100644
index 10601bb..0000000
--- a/LoCyanFrpDesktop/Utils/Update.cs
+++ /dev/null
@@ -1,258 +0,0 @@
-using LoCyanFrpDesktop.Properties;
-using Newtonsoft.Json.Linq;
-using Newtonsoft.Json;
-using LoCyanFrpDesktop.Extensions;
-using System;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.IO.Compression;
-using System.IO;
-using System.Linq;
-using System.Reflection;
-using System.Text;
-using System.Threading.Tasks;
-using System.Net.Http.Headers;
-using System.Net.Http;
-using System.Windows.Shapes;
-using System.Timers;
-using JToken = Newtonsoft.Json.Linq.JToken;
-
-namespace LoCyanFrpDesktop.Utils
-{
- internal static class Update
- {
- ///
- /// 检查更新计时器
- ///
- //private static readonly Timer _checkTimer = new(200000) { AutoReset = true };
-
- ///
- /// 更新初始化
- ///
- public static void Init()
- {
- Task.Run(CheckVersion);
- AppDomain.CurrentDomain.ProcessExit += (_, _) => StartUpdater();
-
- }
-
- ///
- /// 更新准备
- ///
- public static bool IsReadyToUpdate { get; private set; }
-
- ///
- /// 上一个获取到的版本
- ///
- public static string? LastVersion { get; private set; }
- public static string? CurrentVersion;
- private static HttpClient _httpClient = new();
- public static async Task Get(string url, string? accept = null, string userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.33")
- {
- if (!string.IsNullOrEmpty(accept))
- {
- _httpClient.DefaultRequestHeaders.Accept.Clear();
- _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(accept));
- }
- _httpClient.DefaultRequestHeaders.AcceptCharset.Clear();
- _httpClient.DefaultRequestHeaders.AcceptCharset.Add(new StringWithQualityHeaderValue("UTF-8"));
- _httpClient.DefaultRequestHeaders.Remove("user-agent");
- _httpClient.DefaultRequestHeaders.Add("user-agent", userAgent);
- HttpResponseMessage response = await _httpClient.GetAsync(url);
- Logger.Output(LogType.DetailDebug, "Response Headers\n", response.Headers.ToString());
- Logger.Output(LogType.DetailDebug, "Content\n", await response.Content.ReadAsStringAsync());
- return response;
- }
- ///
- /// 检查更新
- ///
- public static void CheckVersion()
- {
- var InterruptReason = "";
- var isProgramHasNewerVersion = false;
- if (!Global.Branch.Equals("Release") && !Global.Branch.Equals("RC"))
- {
- InterruptReason = "You Are On Preview Branch!!!";
- return;
- }
-
-
- try
- {
-
- JObject? jsonObject = JsonConvert.DeserializeObject(Net.Get("https://api.github.com/repos/LoCyan-Team/LoCyanFrpCSDesktop/releases/latest", "application/vnd.github.v3+json", "LoCyanFrpCSDesktop").Await().Content.ReadAsStringAsync().Await());
- if (jsonObject is null)
- {
- InterruptReason = "无法检测更新, 请检查网络连接";
- return;
- }
-
- string? version = jsonObject["tag_name"]?.ToString();
- if (LastVersion != version && !string.IsNullOrEmpty(version))
- {
- LastVersion = version;
- CurrentVersion = "v" + Global.Version + "-" + Global.Branch + Global.Revision;
- if (version != CurrentVersion)
- {
- isProgramHasNewerVersion = true;
-
- Console.WriteLine("Downloading...");
- DownloadNewVersion(jsonObject);
-
-
-
- }
- }
- }
- catch (Exception e)
- {
- InterruptReason = "请带着崩溃日志和截图去见开发者";
- CrashInterception.ShowException(e);
- Logger.Output(LogType.Error, e.Message);
- Logger.Output(LogType.Debug, e);
-
- }
- }
-
-
- ///
- /// 下载新版本
- ///
- private static void DownloadNewVersion(JObject jobject)
- {
- if (!Directory.Exists("update"))
- {
- Directory.CreateDirectory("update");
- }
- foreach (string file in Directory.GetFiles("update", "*.*", SearchOption.AllDirectories))
- {
- if (System.IO.Path.GetExtension(file.ToLowerInvariant()) != ".zip")
- {
- File.Delete(file);
- }
- }
- foreach (JToken asset in jobject["assets"]!)
- {
- string? filename = asset["name"]?.ToString();
- string? url = asset["browser_download_url"]?.ToString();
-
- if (string.IsNullOrEmpty(filename) ||
- //!IdentifyFile(filename?.ToLowerInvariant()) ||
- string.IsNullOrEmpty(url))
- {
- continue;
- }
-
- try
- {
- if (File.Exists($"update/{filename}"))
- {
- IsReadyToUpdate = false;
- Logger.Output(LogType.Debug, "文件已存在,自动跳过下载");
- }
- else if (IsReadyToUpdate)
- {
- break;
- }
- else
- {
- IsReadyToUpdate = false;
- Logger.Output(LogType.Info, url);
- Logger.Output(LogType.Debug, $"正在从[{url}]下载[{asset["name"]}]");
- using (Stream stream = Net.Get(url!).Await().Content.ReadAsStreamAsync().Await())
- using (FileStream fileStream = new($"update/{filename}", FileMode.Create))
- {
- byte[] bytes = new byte[stream.Length];
- _ = stream.Read(bytes, 0, bytes.Length);
- fileStream.Write(bytes, 0, bytes.Length);
- }
- Logger.Output(LogType.Debug, "下载成功");
- }
-
- ZipFile.ExtractToDirectory($"update/{filename}", "update");
- Logger.Output(LogType.Debug, "解压成功");
- Console.WriteLine("解压成功");
- IsReadyToUpdate = true;
- Logger.Output(LogType.Debug, "新版本已下载完毕\n" + (Environment.OSVersion.Platform == PlatformID.Win32NT ? "重启即可自动更新" : "你可以自行打开“update”文件夹复制替换"));
- Console.WriteLine("新版本已下载完毕\n" + (Environment.OSVersion.Platform == PlatformID.Win32NT ? "重启即可自动更新" : "你可以自行打开“update”文件夹复制替换"));
- }
- catch (Exception e)
- {
- Logger.Output(LogType.Error, e.Message);
- Logger.Output(LogType.Debug, e);
- }
- break;
- }
- }
-
- ///
- /// 识别文件
- ///
- /*private static bool IdentifyFile(string? name)
- {
- if (name?.Contains("wpf") ?? false)
- {
- string netVer = Environment.Version.Major.ToString();
- return
- !(Environment.OSVersion.Platform == PlatformID.Unix ^ name.Contains("unix")) &&
- !(netVer == "4" ^ name.Contains("dotnetframework472")) &&
- !(netVer == "6" ^ name.Contains("dotnet6"));
- }
- return false;
- }*/
-
- ///
- /// 启动 Updater.exe
- ///
- public static void StartUpdater()
- {
- if ( !IsReadyToUpdate || Environment.OSVersion.Platform != PlatformID.Win32NT)
- {
- return;
- }
- if (!File.Exists("Updater.exe"))
- {
- using FileStream fileStream = new("Updater.exe", FileMode.Create);
- fileStream.Write(Resources.Updater, 0, Resources.Updater.Length);
-
- }
- Process.Start(new ProcessStartInfo("Updater.exe")
- {
- WorkingDirectory = AppDomain.CurrentDomain.BaseDirectory,
- UseShellExecute = true,
- });
- }
- }
- internal static class Net
- {
- ///
- /// Http客户端
- ///
- private static HttpClient _httpClient = new();
-
- ///
- /// 异步Get
- ///
- /// 链接
- /// Header - Accept
- /// Header - UserAgent
- /// 正文
- public static async Task Get(string url, string? accept = null, string userAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.63 Safari/537.36 Edg/102.0.1245.33")
- {
- if (!string.IsNullOrEmpty(accept))
- {
- _httpClient.DefaultRequestHeaders.Accept.Clear();
- _httpClient.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue(accept));
- }
- _httpClient.DefaultRequestHeaders.AcceptCharset.Clear();
- _httpClient.DefaultRequestHeaders.AcceptCharset.Add(new StringWithQualityHeaderValue("UTF-8"));
- _httpClient.DefaultRequestHeaders.Remove("user-agent");
- _httpClient.DefaultRequestHeaders.Add("user-agent", userAgent);;
- HttpResponseMessage response = await _httpClient.GetAsync(url);
- Logger.Output(LogType.DetailDebug, "Response Headers\n", response.Headers.ToString());
- var content = await response.Content.ReadAsStringAsync();
- //Logger.Output(LogType.DetailDebug, "Content\n", content);
- return response;
- }
- }
-}
diff --git a/LoCyanFrpDesktop/install.iss b/LoCyanFrpDesktop/install.iss
deleted file mode 100644
index efeed5f..0000000
--- a/LoCyanFrpDesktop/install.iss
+++ /dev/null
@@ -1,38 +0,0 @@
-[Setup]
-AppName=LoCyanFrp
-AppVerName=LoCyanFrp - 1.2
-DefaultDirName={pf}\LoCyanFrp
-DefaultGroupName=LoCyanFrp
-UninstallDisplayIcon={app}\LoCyanFrpDesktop.exe
-Compression=lzma2
-SolidCompression=yes
-OutputDir=Output
-AppPublisher=ӣܿƼ˾
-AppPublisherURL=https://www.locyanfrp.cn
-PrivilegesRequired=admin
-
-[Files]
-Source: "D:\Frp\LoCyanFrpDesktop-Impl\LoCyanFrpDesktop\bin\Release\LoCyanFrpDesktop.exe"; DestDir: "{app}"; Flags: ignoreversion
-Source: "D:\Frp\LoCyanFrpDesktop-Impl\LoCyanFrpDesktop\bin\Release\Microsoft.Exchange.WebServices.Auth.dll"; DestDir: "{app}"; Flags: ignoreversion
-Source: "D:\Frp\LoCyanFrpDesktop-Impl\LoCyanFrpDesktop\bin\Release\Microsoft.Exchange.WebServices.dll"; DestDir: "{app}"; Flags: ignoreversion
-Source: "D:\Frp\LoCyanFrpDesktop-Impl\LoCyanFrpDesktop\bin\Release\Newtonsoft.Json.dll"; DestDir: "{app}"; Flags: ignoreversion
-Source: "D:\Frp\LoCyanFrpDesktop-Impl\LoCyanFrpDesktop\bin\Release\frpc.exe"; DestDir: "{app}"; Flags: ignoreversion
-Source: "D:\Frp\LoCyanFrpDesktop-Impl\LoCyanFrpDesktop\bin\Release\HandyControl.dll"; DestDir: "{app}"; Flags: ignoreversion
-Source: "D:\Frp\LoCyanFrpDesktop-Impl\LoCyanFrpDesktop\resource\*"; DestDir: "{app}\resource"; Flags: ignoreversion recursesubdirs
-
-[Icons]
-Name: "{group}\LoCyanFrp"; Filename: "{app}\LoCyanFrpDesktop.exe"; IconFilename: "{app}\resource\favicon.ico"
-; Add other shortcuts you want to create here
-
-[Icons]
-Name: "{commondesktop}\LoCyanFrp"; Filename: "{app}\LoCyanFrpDesktop.exe"; IconFilename: "{app}\resource\favicon.ico";
-
-
-[Run]
-Filename: "{app}\LoCyanFrpDesktop.exe"; Description: "ֱ LoCyanFrp"; Flags: postinstall nowait runascurrentuser
-
-[Registry]
-Root: HKCR; Subkey: "locyanfrp"; ValueType: string; ValueName: ""; ValueData: "LoCyanFrp Desktop Application Custom URL Scheme."
-Root: HKCR; Subkey: "locyanfrp"; ValueType: string; ValueName: "URL Protocol"; ValueData: ""
-Root: HKCR; Subkey: "locyanfrp\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\resource\favicon.ico"
-Root: HKCR; Subkey: "locyanfrp\shell\open\command"; ValueType: string; ValueName: ""; ValueData: """{app}\LoCyanFrpDesktop.exe"" ""%1"""
\ No newline at end of file
diff --git a/LoCyanFrpDesktop/resource/favicon.ico b/LoCyanFrpDesktop/resource/favicon.ico
deleted file mode 100644
index 14d4e37..0000000
Binary files a/LoCyanFrpDesktop/resource/favicon.ico and /dev/null differ
diff --git a/LoCyanFrpDesktop/resource/net6.0/Updater.exe b/LoCyanFrpDesktop/resource/net6.0/Updater.exe
deleted file mode 100644
index 7d2abdd..0000000
Binary files a/LoCyanFrpDesktop/resource/net6.0/Updater.exe and /dev/null differ
diff --git a/README.md b/README.md
index cff048a..f49a1df 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,16 @@
-# LoCyanFrpDesktop-Impl
+# Kairo
+
+A New Generation of LocyanFrp Desktop Application.
+基于 CSharp(C#)打造的新一代 LoCyanFrp 客户端。
-基于 CSharp(C#)打造的 LoCyanFrp 客户端。
+## 功能
+**~~*其实问题在于我自己都不记得写了些什么功能了*~~**
+
+- [x] 登录
+- [x] 签到
+- [x] 流量查询
+- [x] 隧道查询/启动/停止
+- [x] 自动下载frpc
+- [x] 暗黑/明亮主题
+- [x] 啥
+- [ ] 隧道创建/删除
\ No newline at end of file
diff --git a/Updater/Updater.csproj b/Updater/Updater.csproj
index b8bedda..a5e54ce 100644
--- a/Updater/Updater.csproj
+++ b/Updater/Updater.csproj
@@ -5,7 +5,7 @@
net6.0
enable
enable
- ..\LocyanFrpDesktop\resource
+ ..\Kairo\resource