diff --git a/FastGithub.HttpServer/CaCertInstallerOfLinux.cs b/FastGithub.HttpServer/CaCertInstallerOfLinux.cs new file mode 100644 index 0000000..676c519 --- /dev/null +++ b/FastGithub.HttpServer/CaCertInstallerOfLinux.cs @@ -0,0 +1,77 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Diagnostics; +using System.IO; + +namespace FastGithub.HttpServer +{ + abstract class CaCertInstallerOfLinux : ICaCertInstaller + { + const string OS_RELEASE_FILE = "/etc/os-release"; + + /// + /// 更新工具文件名 + /// + public abstract string CertUpdateFileName { get; } + + /// + /// 证书根目录 + /// + public abstract string RootCertPath { get; } + + /// + /// 是否支持 + /// + /// + public abstract bool IsSupported(); + + /// + /// 安装ca证书 + /// + /// 证书文件路径 + /// + public void Install(string caCertFilePath, ILogger logger) + { + if (Environment.UserName != "root") + { + logger.LogWarning($"无法自动安装CA证书{caCertFilePath},因为没有root权限"); + return; + } + + try + { + Directory.CreateDirectory(this.RootCertPath); + var destCertFilePath = Path.Combine(this.RootCertPath, "fastgithub.crt"); + File.Copy(caCertFilePath, destCertFilePath, overwrite: true); + Process.Start(this.CertUpdateFileName).WaitForExit(); + } + catch (Exception ex) + { + logger.LogWarning(ex.Message, "自动安装证书异常"); + } + } + + + /// + /// 是否为某个发行版 + /// + /// + /// + protected bool IsReleasName(string name) + { + if (File.Exists(OS_RELEASE_FILE) == false) + { + return false; + } + + var releaseLines = File.ReadAllLines(OS_RELEASE_FILE); + if (releaseLines.Length == 0) + { + return false; + } + + var nameLine = releaseLines[0]; + return nameLine.Contains(name); + } + } +} \ No newline at end of file diff --git a/FastGithub.HttpServer/CaCertInstallerOfLinuxCentOS.cs b/FastGithub.HttpServer/CaCertInstallerOfLinuxCentOS.cs new file mode 100644 index 0000000..69f5333 --- /dev/null +++ b/FastGithub.HttpServer/CaCertInstallerOfLinuxCentOS.cs @@ -0,0 +1,20 @@ +using System; + +namespace FastGithub.HttpServer +{ + class CaCertInstallerOfLinuxCentOS : CaCertInstallerOfLinux + { + public override string RootCertPath => "/etc/pki/ca-trust/source/anchors"; + + public override string CertUpdateFileName => "update-ca-trust"; + + /// + /// 是否支持 + /// + /// + public override bool IsSupported() + { + return OperatingSystem.IsLinux() && base.IsReleasName("CentOS"); + } + } +} \ No newline at end of file diff --git a/FastGithub.HttpServer/CaCertInstallerOfLinuxDebain.cs b/FastGithub.HttpServer/CaCertInstallerOfLinuxDebain.cs new file mode 100644 index 0000000..eb016d4 --- /dev/null +++ b/FastGithub.HttpServer/CaCertInstallerOfLinuxDebain.cs @@ -0,0 +1,20 @@ +using System; + +namespace FastGithub.HttpServer +{ + class CaCertInstallerOfLinuxDebain : CaCertInstallerOfLinux + { + public override string RootCertPath => "/usr/local/share/ca-certificates"; + + public override string CertUpdateFileName => "update-ca-certificates"; + + /// + /// 是否支持 + /// + /// + public override bool IsSupported() + { + return OperatingSystem.IsLinux() && base.IsReleasName("Debain"); + } + } +} \ No newline at end of file diff --git a/FastGithub.HttpServer/CaCertInstallerOfLinuxUbuntu.cs b/FastGithub.HttpServer/CaCertInstallerOfLinuxUbuntu.cs new file mode 100644 index 0000000..c94bd4b --- /dev/null +++ b/FastGithub.HttpServer/CaCertInstallerOfLinuxUbuntu.cs @@ -0,0 +1,16 @@ +using System; + +namespace FastGithub.HttpServer +{ + sealed class CaCertInstallerOfLinuxUbuntu : CaCertInstallerOfLinuxDebain + { + /// + /// 是否支持 + /// + /// + public override bool IsSupported() + { + return OperatingSystem.IsLinux() && base.IsReleasName("Ubuntu"); + } + } +} \ No newline at end of file diff --git a/FastGithub.HttpServer/CaCertInstallerOfMacOS.cs b/FastGithub.HttpServer/CaCertInstallerOfMacOS.cs new file mode 100644 index 0000000..580d3b5 --- /dev/null +++ b/FastGithub.HttpServer/CaCertInstallerOfMacOS.cs @@ -0,0 +1,27 @@ +using Microsoft.Extensions.Logging; +using System; + +namespace FastGithub.HttpServer +{ + sealed class CaCertInstallerOfMacOS : ICaCertInstaller + { + /// + /// 是否支持 + /// + /// + public bool IsSupported() + { + return OperatingSystem.IsMacOS(); + } + + /// + /// 安装ca证书 + /// + /// 证书文件路径 + /// + public void Install(string caCertFilePath, ILogger logger) + { + logger.LogWarning($"请手动安装CA证书然后设置信任CA证书{caCertFilePath}"); + } + } +} diff --git a/FastGithub.HttpServer/CaCertInstallerOfWindows.cs b/FastGithub.HttpServer/CaCertInstallerOfWindows.cs new file mode 100644 index 0000000..b4299e2 --- /dev/null +++ b/FastGithub.HttpServer/CaCertInstallerOfWindows.cs @@ -0,0 +1,51 @@ +using Microsoft.Extensions.Logging; +using System; +using System.Security.Cryptography.X509Certificates; + +namespace FastGithub.HttpServer +{ + sealed class CaCertInstallerOfWindows : ICaCertInstaller + { + /// + /// 是否支持 + /// + /// + public bool IsSupported() + { + return OperatingSystem.IsWindows(); + } + + /// + /// 安装ca证书 + /// + /// 证书文件路径 + /// + public void Install(string caCertFilePath, ILogger logger) + { + try + { + using var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine); + store.Open(OpenFlags.ReadWrite); + + var caCert = new X509Certificate2(caCertFilePath); + var subjectName = caCert.Subject[3..]; + foreach (var item in store.Certificates.Find(X509FindType.FindBySubjectName, subjectName, false)) + { + if (item.Thumbprint != caCert.Thumbprint) + { + store.Remove(item); + } + } + if (store.Certificates.Find(X509FindType.FindByThumbprint, caCert.Thumbprint, true).Count == 0) + { + store.Add(caCert); + } + store.Close(); + } + catch (Exception) + { + logger.LogWarning($"请手动安装CA证书{caCertFilePath}到“将所有的证书都放入下列存储”\\“受信任的根证书颁发机构”"); + } + } + } +} diff --git a/FastGithub.HttpServer/CertService.cs b/FastGithub.HttpServer/CertService.cs index 98e7852..6b66f32 100644 --- a/FastGithub.HttpServer/CertService.cs +++ b/FastGithub.HttpServer/CertService.cs @@ -18,6 +18,7 @@ namespace FastGithub.HttpServer private const string CACERT_PATH = "cacert"; private const int KEY_SIZE_BITS = 2048; private readonly IMemoryCache serverCertCache; + private readonly IEnumerable certInstallers; private readonly ILogger logger; @@ -34,12 +35,16 @@ namespace FastGithub.HttpServer /// /// 证书服务 /// + /// + /// /// public CertService( IMemoryCache serverCertCache, + IEnumerable certInstallers, ILogger logger) { this.serverCertCache = serverCertCache; + this.certInstallers = certInstallers; this.logger = logger; Directory.CreateDirectory(CACERT_PATH); } @@ -68,17 +73,10 @@ namespace FastGithub.HttpServer /// public void InstallAndTrustCaCert() { - if (OperatingSystem.IsWindows()) + var installer = this.certInstallers.FirstOrDefault(item => item.IsSupported()); + if (installer != null) { - this.InstallAndTrustCaCertAtWindows(); - } - else if (OperatingSystem.IsLinux()) - { - this.logger.LogWarning($"请根据具体linux发行版手动安装CA证书{this.CaCerFilePath}"); - } - else if (OperatingSystem.IsMacOS()) - { - this.logger.LogWarning($"请手动安装CA证书然后设置信任CA证书{this.CaCerFilePath}"); + installer.Install(this.CaCerFilePath, this.logger); } else { @@ -113,38 +111,6 @@ namespace FastGithub.HttpServer } } - /// - /// 安装CA证书 - /// - private void InstallAndTrustCaCertAtWindows() - { - try - { - using var store = new X509Store(StoreName.Root, StoreLocation.LocalMachine); - store.Open(OpenFlags.ReadWrite); - - var caCert = new X509Certificate2(this.CaCerFilePath); - var subjectName = caCert.Subject[3..]; - foreach (var item in store.Certificates.Find(X509FindType.FindBySubjectName, subjectName, false)) - { - if (item.Thumbprint != caCert.Thumbprint) - { - store.Remove(item); - } - } - if (store.Certificates.Find(X509FindType.FindByThumbprint, caCert.Thumbprint, true).Count == 0) - { - store.Add(caCert); - } - store.Close(); - } - catch (Exception) - { - this.logger.LogWarning($"请手动安装CA证书{this.CaCerFilePath}到“将所有的证书都放入下列存储”\\“受信任的根证书颁发机构”"); - } - } - - /// /// 获取颁发给指定域名的证书 /// diff --git a/FastGithub.HttpServer/ICaCertInstaller.cs b/FastGithub.HttpServer/ICaCertInstaller.cs new file mode 100644 index 0000000..9fe3fe9 --- /dev/null +++ b/FastGithub.HttpServer/ICaCertInstaller.cs @@ -0,0 +1,23 @@ +using Microsoft.Extensions.Logging; + +namespace FastGithub.HttpServer +{ + /// + /// CA证书安装器 + /// + interface ICaCertInstaller + { + /// + /// 是否支持 + /// + /// + bool IsSupported(); + + /// + /// 安装ca证书 + /// + /// 证书文件路径 + /// + void Install(string caCertFilePath,ILogger logger); + } +} diff --git a/FastGithub.HttpServer/ServiceCollectionExtensions.cs b/FastGithub.HttpServer/ServiceCollectionExtensions.cs index 4151824..1224460 100644 --- a/FastGithub.HttpServer/ServiceCollectionExtensions.cs +++ b/FastGithub.HttpServer/ServiceCollectionExtensions.cs @@ -1,6 +1,5 @@ using FastGithub.HttpServer; using Microsoft.Extensions.DependencyInjection; - namespace FastGithub { /// @@ -18,9 +17,14 @@ namespace FastGithub return services .AddMemoryCache() .AddHttpForwarder() - .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() + .AddSingleton() .AddSingleton() - .AddSingleton() + .AddSingleton() .AddSingleton(); } } diff --git a/publish.cmd b/publish.cmd index b906076..958ab82 100644 --- a/publish.cmd +++ b/publish.cmd @@ -1,7 +1,4 @@ set output=./publish if exist "%output%" rd /S /Q "%output%" -dotnet publish -c Release -o "%output%/fastgithub_win-x64" ./FastGithub.UI/FastGithub.UI.csproj -dotnet publish -c Release /p:PublishSingleFile=true /p:PublishTrimmed=true --self-contained -r win-x64 -o "%output%/fastgithub_win-x64" ./FastGithub/FastGithub.csproj -dotnet publish -c Release /p:PublishSingleFile=true /p:PublishTrimmed=true --self-contained -r linux-x64 -o "%output%/fastgithub_linux-x64" ./FastGithub/FastGithub.csproj -dotnet publish -c Release /p:PublishSingleFile=true /p:PublishTrimmed=true --self-contained -r linux-arm64 -o "%output%/fastgithub_linux-arm64" ./FastGithub/FastGithub.csproj -dotnet publish -c Release /p:PublishSingleFile=true /p:PublishTrimmed=true --self-contained -r osx-x64 -o "%output%/fastgithub_osx-x64" ./FastGithub/FastGithub.csproj \ No newline at end of file + +dotnet publish -c Release /p:PublishSingleFile=true /p:PublishTrimmed=false --self-contained -r linux-x64 -o "%output%/fastgithub_linux-x64" ./FastGithub/FastGithub.csproj \ No newline at end of file