dingcong 3 years ago
commit
0ef0c1cc9d
100 changed files with 29180 additions and 0 deletions
  1. 63 0
      .gitattributes
  2. 12 0
      backend/AuthCenter/AuthCenter/.config/dotnet-tools.json
  3. 60 0
      backend/AuthCenter/AuthCenter/AuthCenter.csproj
  4. 59 0
      backend/AuthCenter/AuthCenter/AuthConfig/AuthenticationHelpers.cs
  5. 173 0
      backend/AuthCenter/AuthCenter/AuthConfig/Config.cs
  6. 135 0
      backend/AuthCenter/AuthCenter/AuthConfig/SameSiteCookiesServiceCollectionExtensions.cs
  7. 280 0
      backend/AuthCenter/AuthCenter/Controllers/AccountController.cs
  8. 31 0
      backend/AuthCenter/AuthCenter/Controllers/HomeController.cs
  9. 202 0
      backend/AuthCenter/AuthCenter/Controllers/OAuthController.cs
  10. 25 0
      backend/AuthCenter/AuthCenter/Filters/ExceptionFilter.cs
  11. 882 0
      backend/AuthCenter/AuthCenter/Migrations/IdentityServer/ConfigurationDb/20210729013943_InitialConfigurationDb.Designer.cs
  12. 658 0
      backend/AuthCenter/AuthCenter/Migrations/IdentityServer/ConfigurationDb/20210729013943_InitialConfigurationDb.cs
  13. 880 0
      backend/AuthCenter/AuthCenter/Migrations/IdentityServer/ConfigurationDb/ConfigurationDbContextModelSnapshot.cs
  14. 127 0
      backend/AuthCenter/AuthCenter/Migrations/IdentityServer/PersistedGrantDb/20210729013922_InitialPersistedGrantDb.Designer.cs
  15. 85 0
      backend/AuthCenter/AuthCenter/Migrations/IdentityServer/PersistedGrantDb/20210729013922_InitialPersistedGrantDb.cs
  16. 125 0
      backend/AuthCenter/AuthCenter/Migrations/IdentityServer/PersistedGrantDb/PersistedGrantDbContextModelSnapshot.cs
  17. 58 0
      backend/AuthCenter/AuthCenter/NLog.config
  18. 37 0
      backend/AuthCenter/AuthCenter/Program.cs
  19. 21 0
      backend/AuthCenter/AuthCenter/Properties/PublishProfiles/FolderProfile.pubxml
  20. 27 0
      backend/AuthCenter/AuthCenter/Properties/launchSettings.json
  21. 50 0
      backend/AuthCenter/AuthCenter/Services/CustomProfileService.cs
  22. 39 0
      backend/AuthCenter/AuthCenter/Services/DiscoGenerator.cs
  23. 44 0
      backend/AuthCenter/AuthCenter/Services/EapExtensionValidator.cs
  24. 77 0
      backend/AuthCenter/AuthCenter/Services/SeedData.cs
  25. 186 0
      backend/AuthCenter/AuthCenter/Startup.cs
  26. 15 0
      backend/AuthCenter/AuthCenter/Views/Account/Error.cshtml
  27. 207 0
      backend/AuthCenter/AuthCenter/Views/Account/Login.cshtml
  28. 40 0
      backend/AuthCenter/AuthCenter/Views/Home/Error.cshtml
  29. 5 0
      backend/AuthCenter/AuthCenter/Views/Home/Index.cshtml
  30. 9 0
      backend/AuthCenter/AuthCenter/appsettings.Development.json
  31. 26 0
      backend/AuthCenter/AuthCenter/appsettings.json
  32. 30 0
      backend/AuthCenter/AuthCenter/auth.json
  33. 1 0
      backend/AuthCenter/AuthCenter/tempkey.jwk
  34. 525 0
      backend/AuthCenter/AuthCenter/wwwroot/css/login.css
  35. BIN
      backend/AuthCenter/AuthCenter/wwwroot/images/login-bg.jpg
  36. BIN
      backend/AuthCenter/AuthCenter/wwwroot/images/logo.png
  37. 3 0
      backend/AuthCenter/AuthCenter/wwwroot/js/lib/axios.js
  38. BIN
      backend/AuthCenter/AuthCenter/wwwroot/js/lib/element-ui/fonts/element-icons.ttf
  39. BIN
      backend/AuthCenter/AuthCenter/wwwroot/js/lib/element-ui/fonts/element-icons.woff
  40. 15520 0
      backend/AuthCenter/AuthCenter/wwwroot/js/lib/element-ui/index.css
  41. 1 0
      backend/AuthCenter/AuthCenter/wwwroot/js/lib/element-ui/index.js
  42. 6 0
      backend/AuthCenter/AuthCenter/wwwroot/js/lib/vue.min.js
  43. 133 0
      backend/AuthCenter/AuthorizeCenter.sln
  44. 46 0
      backend/AuthCenter/AuthorizeCenter/AuthConfig/Config.cs
  45. 23 0
      backend/AuthCenter/AuthorizeCenter/AuthorizeCenter.csproj
  46. 58 0
      backend/AuthCenter/AuthorizeCenter/Controllers/AccountController.cs
  47. 16 0
      backend/AuthCenter/AuthorizeCenter/Controllers/HomeController.cs
  48. 24 0
      backend/AuthCenter/AuthorizeCenter/Program.cs
  49. 27 0
      backend/AuthCenter/AuthorizeCenter/Properties/launchSettings.json
  50. 25 0
      backend/AuthCenter/AuthorizeCenter/Services/AccountService.cs
  51. 51 0
      backend/AuthCenter/AuthorizeCenter/Startup.cs
  52. 23 0
      backend/AuthCenter/AuthorizeCenter/Views/Account/Login.cshtml
  53. 5 0
      backend/AuthCenter/AuthorizeCenter/Views/Home/Index.cshtml
  54. 24 0
      backend/AuthCenter/AuthorizeCenter/appsettings.json
  55. 1 0
      backend/AuthCenter/AuthorizeCenter/tempkey.jwk
  56. 20 0
      backend/AutoUpdate/.gitattributes
  57. 31 0
      backend/AutoUpdate/AutoUpdate.sln
  58. 47 0
      backend/AutoUpdate/MAutoUpdate.Test/Form1.Designer.cs
  59. 18 0
      backend/AutoUpdate/MAutoUpdate.Test/Form1.cs
  60. 120 0
      backend/AutoUpdate/MAutoUpdate.Test/Form1.resx
  61. 73 0
      backend/AutoUpdate/MAutoUpdate.Test/MAutoUpdate.Test.csproj
  62. 40 0
      backend/AutoUpdate/MAutoUpdate.Test/Program.cs
  63. 36 0
      backend/AutoUpdate/MAutoUpdate.Test/Properties/AssemblyInfo.cs
  64. 71 0
      backend/AutoUpdate/MAutoUpdate.Test/Properties/Resources.Designer.cs
  65. 117 0
      backend/AutoUpdate/MAutoUpdate.Test/Properties/Resources.resx
  66. 30 0
      backend/AutoUpdate/MAutoUpdate.Test/Properties/Settings.Designer.cs
  67. 7 0
      backend/AutoUpdate/MAutoUpdate.Test/Properties/Settings.settings
  68. 12 0
      backend/AutoUpdate/MAutoUpdate/CompareVersion.cs
  69. 133 0
      backend/AutoUpdate/MAutoUpdate/EAPClock.cs
  70. 6 0
      backend/AutoUpdate/MAutoUpdate/Local.xml
  71. 98 0
      backend/AutoUpdate/MAutoUpdate/LocalInfo.cs
  72. 34 0
      backend/AutoUpdate/MAutoUpdate/LogTool.cs
  73. 257 0
      backend/AutoUpdate/MAutoUpdate/MAutoUpdate.csproj
  74. 154 0
      backend/AutoUpdate/MAutoUpdate/MainForm.Designer.cs
  75. 100 0
      backend/AutoUpdate/MAutoUpdate/MainForm.cs
  76. 197 0
      backend/AutoUpdate/MAutoUpdate/MainForm.resx
  77. 16 0
      backend/AutoUpdate/MAutoUpdate/Models/EapResponse.cs
  78. 18 0
      backend/AutoUpdate/MAutoUpdate/Models/WebAppVersion.cs
  79. 290 0
      backend/AutoUpdate/MAutoUpdate/Program.cs
  80. 36 0
      backend/AutoUpdate/MAutoUpdate/Properties/AssemblyInfo.cs
  81. 63 0
      backend/AutoUpdate/MAutoUpdate/Properties/Resources.Designer.cs
  82. 121 0
      backend/AutoUpdate/MAutoUpdate/Properties/Resources.resx
  83. 26 0
      backend/AutoUpdate/MAutoUpdate/Properties/Settings.Designer.cs
  84. 7 0
      backend/AutoUpdate/MAutoUpdate/Properties/Settings.settings
  85. 36 0
      backend/AutoUpdate/MAutoUpdate/RemoteInfo.cs
  86. 13 0
      backend/AutoUpdate/MAutoUpdate/Server.xml
  87. 92 0
      backend/AutoUpdate/MAutoUpdate/UpdateForm.Designer.cs
  88. 48 0
      backend/AutoUpdate/MAutoUpdate/UpdateForm.cs
  89. 120 0
      backend/AutoUpdate/MAutoUpdate/UpdateForm.resx
  90. 644 0
      backend/AutoUpdate/MAutoUpdate/UpdateWork.cs
  91. 101 0
      backend/AutoUpdate/MAutoUpdate/YButton.cs
  92. 829 0
      backend/AutoUpdate/MAutoUpdate/Zip DLL/CRC32.cs
  93. 116 0
      backend/AutoUpdate/MAutoUpdate/Zip DLL/ComHelper.cs
  94. 1879 0
      backend/AutoUpdate/MAutoUpdate/Zip DLL/Deflate.cs
  95. 740 0
      backend/AutoUpdate/MAutoUpdate/Zip DLL/DeflateStream.cs
  96. 135 0
      backend/AutoUpdate/MAutoUpdate/Zip DLL/EncryptionAlgorithm.cs
  97. 684 0
      backend/AutoUpdate/MAutoUpdate/Zip DLL/Events.cs
  98. 300 0
      backend/AutoUpdate/MAutoUpdate/Zip DLL/Exceptions.cs
  99. 85 0
      backend/AutoUpdate/MAutoUpdate/Zip DLL/ExtractExistingFileAction.cs
  100. 0 0
      backend/AutoUpdate/MAutoUpdate/Zip DLL/FileSelector.cs

+ 63 - 0
.gitattributes

@@ -0,0 +1,63 @@
+###############################################################################
+# Set default behavior to automatically normalize line endings.
+###############################################################################
+* text=auto
+
+###############################################################################
+# Set default behavior for command prompt diff.
+#
+# This is need for earlier builds of msysgit that does not have it on by
+# default for csharp files.
+# Note: This is only used by command line
+###############################################################################
+#*.cs     diff=csharp
+
+###############################################################################
+# Set the merge driver for project and solution files
+#
+# Merging from the command prompt will add diff markers to the files if there
+# are conflicts (Merging from VS is not affected by the settings below, in VS
+# the diff markers are never inserted). Diff markers may cause the following 
+# file extensions to fail to load in VS. An alternative would be to treat
+# these files as binary and thus will always conflict and require user
+# intervention with every merge. To do so, just uncomment the entries below
+###############################################################################
+#*.sln       merge=binary
+#*.csproj    merge=binary
+#*.vbproj    merge=binary
+#*.vcxproj   merge=binary
+#*.vcproj    merge=binary
+#*.dbproj    merge=binary
+#*.fsproj    merge=binary
+#*.lsproj    merge=binary
+#*.wixproj   merge=binary
+#*.modelproj merge=binary
+#*.sqlproj   merge=binary
+#*.wwaproj   merge=binary
+
+###############################################################################
+# behavior for image files
+#
+# image files are treated as binary by default.
+###############################################################################
+#*.jpg   binary
+#*.png   binary
+#*.gif   binary
+
+###############################################################################
+# diff behavior for common document formats
+# 
+# Convert binary document formats to text before diffing them. This feature
+# is only available from the command line. Turn it on by uncommenting the 
+# entries below.
+###############################################################################
+#*.doc   diff=astextplain
+#*.DOC   diff=astextplain
+#*.docx  diff=astextplain
+#*.DOCX  diff=astextplain
+#*.dot   diff=astextplain
+#*.DOT   diff=astextplain
+#*.pdf   diff=astextplain
+#*.PDF   diff=astextplain
+#*.rtf   diff=astextplain
+#*.RTF   diff=astextplain

+ 12 - 0
backend/AuthCenter/AuthCenter/.config/dotnet-tools.json

@@ -0,0 +1,12 @@
+{
+  "version": 1,
+  "isRoot": true,
+  "tools": {
+    "dotnet-ef": {
+      "version": "5.0.8",
+      "commands": [
+        "dotnet-ef"
+      ]
+    }
+  }
+}

+ 60 - 0
backend/AuthCenter/AuthCenter/AuthCenter.csproj

@@ -0,0 +1,60 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+    <UserSecretsId>cd7cfd24-f78c-4ae4-ab65-7c7445ef4336</UserSecretsId>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Content Remove="NLog.config" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <None Remove="C:\Users\XiangQi\.nuget\packages\nlog.config\4.7.10\contentFiles\any\any\NLog.config" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Resource Include="NLog.config">
+      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+    </Resource>
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="IdentityServer4" Version="4.1.0" />
+    <PackageReference Include="IdentityServer4.EntityFramework" Version="4.1.0" />
+    <PackageReference Include="Microsoft.AspNetCore.Mvc.Razor.RuntimeCompilation" Version="3.1.17" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore" Version="3.1.17" />
+    <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="3.1.17">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+    <PackageReference Include="Microsoft.EntityFrameworkCore.Tools" Version="3.1.17">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
+    <PackageReference Include="NLog" Version="4.7.10" />
+    <PackageReference Include="NLog.Web.AspNetCore" Version="4.13.0" />
+    <PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.2.6" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\UFP\DllUfpBll\DllUfpBll.csproj" />
+    <ProjectReference Include="..\..\UFP\DllUfpDal\DllUfpDal.csproj" />
+    <ProjectReference Include="..\..\UFP\DllUfpUtil\DllUfpUtil.csproj" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <Reference Include="Cksoft.Data">
+      <HintPath>..\..\Dll\Cksoft.Data.dll</HintPath>
+    </Reference>
+    <Reference Include="CkSoft.Data.Repository">
+      <HintPath>..\..\Dll\CkSoft.Data.Repository.dll</HintPath>
+    </Reference>
+    <Reference Include="Cksoft.Unity">
+      <HintPath>..\..\Dll\Cksoft.Unity.dll</HintPath>
+    </Reference>
+  </ItemGroup>
+
+  <ProjectExtensions><VisualStudio><UserProperties appsettings_1json__JsonSchema="" /></VisualStudio></ProjectExtensions>
+
+</Project>

+ 59 - 0
backend/AuthCenter/AuthCenter/AuthConfig/AuthenticationHelpers.cs

@@ -0,0 +1,59 @@
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace AuthCenter.AuthConfig
+{
+    public static class AuthenticationHelpers
+    {
+        public static void CheckSameSite(HttpContext httpContext, CookieOptions options)
+        {
+            if (options.SameSite == SameSiteMode.None)
+            {
+                var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
+                if (!httpContext.Request.IsHttps || DisallowsSameSiteNone(userAgent))
+                {
+                    // For .NET Core < 3.1 set SameSite = (SameSiteMode)(-1)
+                    options.SameSite = SameSiteMode.Unspecified;
+                }
+            }
+        }
+
+        public static bool DisallowsSameSiteNone(string userAgent)
+        {
+            // Cover all iOS based browsers here. This includes:
+            // - Safari on iOS 12 for iPhone, iPod Touch, iPad
+            // - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
+            // - Chrome on iOS 12 for iPhone, iPod Touch, iPad
+            // All of which are broken by SameSite=None, because they use the iOS networking stack
+            if (userAgent.Contains("CPU iPhone OS 12") || userAgent.Contains("iPad; CPU OS 12"))
+            {
+                return true;
+            }
+
+            // Cover Mac OS X based browsers that use the Mac OS networking stack. This includes:
+            // - Safari on Mac OS X.
+            // This does not include:
+            // - Chrome on Mac OS X
+            // Because they do not use the Mac OS networking stack.
+            if (userAgent.Contains("Macintosh; Intel Mac OS X 10_14") &&
+                userAgent.Contains("Version/") && userAgent.Contains("Safari"))
+            {
+                return true;
+            }
+
+            // Cover Chrome 50-69, because some versions are broken by SameSite=None,
+            // and none in this range require it.
+            // Note: this covers some pre-Chromium Edge versions,
+            // but pre-Chromium Edge does not require SameSite=None.
+            if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
+            {
+                return true;
+            }
+
+            return false;
+        }
+    }
+}

+ 173 - 0
backend/AuthCenter/AuthCenter/AuthConfig/Config.cs

@@ -0,0 +1,173 @@
+using IdentityServer4;
+using IdentityServer4.Models;
+using IdentityServer4.Test;
+using Microsoft.Extensions.Configuration;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace AuthCenter.AuthConfig
+{
+    public class Config
+    {
+        public static IEnumerable<IdentityResource> GetIdentityResources()
+        {
+            return new List<IdentityResource>
+            {
+                //必须要添加,否则报无效的scope错误
+                new IdentityResources.OpenId(),
+                new IdentityResources.Profile(),
+                new IdentityResources.Address(),
+                new IdentityResources.Phone(),
+                new IdentityResources.Email()
+            };
+        }
+
+        /// <summary>
+        /// api资源列表
+        /// </summary>
+        /// <returns></returns>
+        public static IEnumerable<ApiResource> GetApiResources()
+        {
+            //可访问的API资源(资源名,资源描述)
+            return new List<ApiResource>
+            {
+                new ApiResource("eapapi", "Web EAP API Service")
+                {
+                    Scopes = { "eapapi","eap","dashboard"},
+                    //ApiSecrets = { new Secret("secret".Sha256()) }
+                }
+            };
+        }
+
+        /// <summary>
+        /// 4.0版本需要添加apiscope
+        /// </summary>
+        /// <returns></returns>
+        public static IEnumerable<ApiScope> GetApiScopes()
+        {
+            return new ApiScope[] {
+                 new ApiScope("eap"),
+                 new ApiScope("eapapi"),
+                 new ApiScope("dashboard")
+            };
+        }
+
+        public static List<TestUser> GetUsers()
+        {
+            return new List<TestUser>()
+            {
+                new TestUser(){ SubjectId="1",Username="admin",Password="123456"}
+            };
+        }
+
+        /// <summary>
+        /// 客户端列表
+        /// </summary>
+        /// <returns></returns>
+        public static IEnumerable<Client> GetClients()
+        {
+            var builder = new ConfigurationBuilder();
+            builder.AddJsonFile("auth.json");
+            var configuration = builder.Build();
+            var lists = configuration.GetSection("Clients").Get<IEnumerable<Client>>();
+
+            return new List<Client>
+            {
+                 new Client
+                 {
+                    ClientId = lists.First().ClientId,
+                    ClientName = lists.First().ClientName,
+                    AllowedGrantTypes = GrantTypes.ClientCredentials,
+                    IncludeJwtId = false,
+                    AllowOfflineAccess = true,
+                    AccessTokenLifetime = 3600*24,
+                    IdentityTokenLifetime = 3600*24,
+                    //AccessTokenLifetime = 60,
+                    RedirectUris = lists.First().RedirectUris,
+                    ClientSecrets = new[] { new Secret("secret".Sha256()) },
+                    AllowedScopes = {
+                        "eapapi",
+                        "eap",
+                        IdentityServerConstants.StandardScopes.OpenId,
+                        IdentityServerConstants.StandardScopes.Profile
+                    }
+                 },
+                 new Client
+                {
+                    ClientId = lists.ElementAt(1).ClientId,
+                    ClientName = lists.ElementAt(1).ClientName,
+                    ClientSecrets = new [] { new Secret("secret".Sha256()) },
+                    AllowedGrantTypes = GrantTypes.Code,
+                    RedirectUris = lists.ElementAt(1).RedirectUris,
+                    PostLogoutRedirectUris = lists.ElementAt(1).PostLogoutRedirectUris,
+                    AllowedCorsOrigins = lists.ElementAt(1).AllowedCorsOrigins,
+                    //是否显示授权提示界面
+                    RequireConsent = false,
+                    RequirePkce = false,
+                    AccessTokenType = AccessTokenType.Jwt,
+                    AccessTokenLifetime = 3600*24,
+                    IdentityTokenLifetime = 3600*24,
+                    AbsoluteRefreshTokenLifetime = 0,//RefreshToken的最长生命周期,默认30天
+                    RefreshTokenExpiration = TokenExpiration.Sliding,//刷新令牌时,将刷新RefreshToken的生命周期。RefreshToken的总生命周期不会超过AbsoluteRefreshTokenLifetime。
+                    SlidingRefreshTokenLifetime = 3600*24,//以秒为单位滑动刷新令牌的生命周期。
+                    //按照现有的设置,如果3600内没有使用RefreshToken,那么RefreshToken将失效。即便是在3600内一直有使用RefreshToken,RefreshToken的总生命周期不会超过30天。所有的时间都可以按实际需求调整。
+
+                    AllowOfflineAccess = true,//如果要获取refresh_tokens ,必须把AllowOfflineAccess设置为true
+                    AllowedScopes = {
+                        "eap",
+                        "eapapi",
+                        IdentityServerConstants.StandardScopes.OpenId,
+                        IdentityServerConstants.StandardScopes.Profile,
+                        IdentityServerConstants.StandardScopes.OfflineAccess
+                    }
+                },
+                 new Client
+                 {
+                    ClientId = lists.ElementAt(2).ClientId,
+                    ClientName = lists.ElementAt(2).ClientName,
+                    AllowedGrantTypes = GrantTypes.Implicit,
+                    AllowAccessTokensViaBrowser = true,
+                    RefreshTokenUsage = TokenUsage.OneTimeOnly,
+                    //AccessTokenType = AccessTokenType.Reference,
+                    // SlidingRefreshTokenLifetime = 3600,
+                    RedirectUris =lists.ElementAt(2).RedirectUris,
+                    AllowedCorsOrigins = lists.ElementAt(2).AllowedCorsOrigins,
+                    AccessTokenLifetime = 3600 * 24,
+                    AllowOfflineAccess = true,//如果要获取refresh_tokens ,必须把AllowOfflineAccess设置为true
+                    AllowedScopes =
+                    {
+                       IdentityServerConstants.StandardScopes.OpenId,
+                       IdentityServerConstants.StandardScopes.Profile,
+                       IdentityServerConstants.StandardScopes.OfflineAccess,
+                       "eapapi"
+                    }
+                 },
+                 new Client
+                 {
+                    ClientId = lists.ElementAt(3).ClientId,
+                    ClientName = lists.ElementAt(3).ClientName,
+                    ClientSecrets = new List<Secret>()
+                    {
+                        new Secret("Mobile Secret".Sha256())
+                    },
+                    AllowedGrantTypes ={ "eap.auth" } ,
+                    AllowAccessTokensViaBrowser = true,
+                    RefreshTokenUsage = TokenUsage.OneTimeOnly,
+                    AllowedCorsOrigins = lists.ElementAt(3).AllowedCorsOrigins,
+                    AccessTokenLifetime = 3600 * 24,
+                    RequireClientSecret = true,
+                    AccessTokenType = AccessTokenType.Jwt,
+                    AllowOfflineAccess = true,
+                    AllowedScopes =
+                    {
+                       IdentityServerConstants.StandardScopes.OpenId,
+                       IdentityServerConstants.StandardScopes.Profile,
+                       IdentityServerConstants.StandardScopes.OfflineAccess,
+                       "eapapi"
+                    }
+                 },
+             };
+        }
+    }
+}

+ 135 - 0
backend/AuthCenter/AuthCenter/AuthConfig/SameSiteCookiesServiceCollectionExtensions.cs

@@ -0,0 +1,135 @@
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Http;
+
+namespace Microsoft.Extensions.DependencyInjection
+{
+    public static class SameSiteCookiesServiceCollectionExtensions
+    {
+        /// <summary>
+        /// -1 defines the unspecified value, which tells ASPNET Core to NOT
+        /// send the SameSite attribute. With ASPNET Core 3.1 the
+        /// <seealso cref="SameSiteMode" /> enum will have a definition for
+        /// Unspecified.
+        /// </summary>
+        private const SameSiteMode Unspecified = (SameSiteMode)(-1);
+
+        /// <summary>
+        /// Configures a cookie policy to properly set the SameSite attribute
+        /// for Browsers that handle unknown values as Strict. Ensure that you
+        /// add the <seealso cref="Microsoft.AspNetCore.CookiePolicy.CookiePolicyMiddleware" />
+        /// into the pipeline before sending any cookies!
+        /// </summary>
+        /// <remarks>
+        /// Minimum ASPNET Core Version required for this code:
+        ///   - 2.1.14
+        ///   - 2.2.8
+        ///   - 3.0.1
+        ///   - 3.1.0-preview1
+        /// Starting with version 80 of Chrome (to be released in February 2020)
+        /// cookies with NO SameSite attribute are treated as SameSite=Lax.
+        /// In order to always get the cookies send they need to be set to
+        /// SameSite=None. But since the current standard only defines Lax and
+        /// Strict as valid values there are some browsers that treat invalid
+        /// values as SameSite=Strict. We therefore need to check the browser
+        /// and either send SameSite=None or prevent the sending of SameSite=None.
+        /// Relevant links:
+        /// - https://tools.ietf.org/html/draft-west-first-party-cookies-07#section-4.1
+        /// - https://tools.ietf.org/html/draft-west-cookie-incrementalism-00
+        /// - https://www.chromium.org/updates/same-site
+        /// - https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/
+        /// - https://bugs.webkit.org/show_bug.cgi?id=198181
+        /// </remarks>
+        /// <param name="services">The service collection to register <see cref="CookiePolicyOptions" /> into.</param>
+        /// <returns>The modified <see cref="IServiceCollection" />.</returns>
+        public static IServiceCollection ConfigureNonBreakingSameSiteCookies(this IServiceCollection services)
+        {
+            services.Configure<CookiePolicyOptions>(options =>
+            {
+                options.MinimumSameSitePolicy = Unspecified;
+                options.OnAppendCookie = cookieContext =>
+                   CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
+                options.OnDeleteCookie = cookieContext =>
+                   CheckSameSite(cookieContext.Context, cookieContext.CookieOptions);
+            });
+
+            return services;
+        }
+
+        private static void CheckSameSite(HttpContext httpContext, CookieOptions options)
+        {
+            if (options.SameSite == SameSiteMode.None)
+            {
+                var userAgent = httpContext.Request.Headers["User-Agent"].ToString();
+
+                if (DisallowsSameSiteNone(userAgent))
+                {
+                    options.SameSite = Unspecified;
+                }
+            }
+        }
+
+        /// <summary>
+        /// Checks if the UserAgent is known to interpret an unknown value as Strict.
+        /// For those the <see cref="CookieOptions.SameSite" /> property should be
+        /// set to <see cref="Unspecified" />.
+        /// </summary>
+        /// <remarks>
+        /// This code is taken from Microsoft:
+        /// https://devblogs.microsoft.com/aspnet/upcoming-samesite-cookie-changes-in-asp-net-and-asp-net-core/
+        /// </remarks>
+        /// <param name="userAgent">The user agent string to check.</param>
+        /// <returns>Whether the specified user agent (browser) accepts SameSite=None or not.</returns>
+        private static bool DisallowsSameSiteNone(string userAgent)
+        {
+            // Cover all iOS based browsers here. This includes:
+            //   - Safari on iOS 12 for iPhone, iPod Touch, iPad
+            //   - WkWebview on iOS 12 for iPhone, iPod Touch, iPad
+            //   - Chrome on iOS 12 for iPhone, iPod Touch, iPad
+            // All of which are broken by SameSite=None, because they use the
+            // iOS networking stack.
+            // Notes from Thinktecture:
+            // Regarding https://caniuse.com/#search=samesite iOS versions lower
+            // than 12 are not supporting SameSite at all. Starting with version 13
+            // unknown values are NOT treated as strict anymore. Therefore we only
+            // need to check version 12.
+            if (userAgent.Contains("CPU iPhone OS 12")
+               || userAgent.Contains("iPad; CPU OS 12"))
+            {
+                return true;
+            }
+
+            // Cover Mac OS X based browsers that use the Mac OS networking stack.
+            // This includes:
+            //   - Safari on Mac OS X.
+            // This does not include:
+            //   - Chrome on Mac OS X
+            // because they do not use the Mac OS networking stack.
+            // Notes from Thinktecture: 
+            // Regarding https://caniuse.com/#search=samesite MacOS X versions lower
+            // than 10.14 are not supporting SameSite at all. Starting with version
+            // 10.15 unknown values are NOT treated as strict anymore. Therefore we
+            // only need to check version 10.14.
+            if (userAgent.Contains("Safari")
+               && userAgent.Contains("Macintosh; Intel Mac OS X 10_14")
+               && userAgent.Contains("Version/"))
+            {
+                return true;
+            }
+
+            // Cover Chrome 50-69, because some versions are broken by SameSite=None
+            // and none in this range require it.
+            // Note: this covers some pre-Chromium Edge versions,
+            // but pre-Chromium Edge does not require SameSite=None.
+            // Notes from Thinktecture:
+            // We can not validate this assumption, but we trust Microsofts
+            // evaluation. And overall not sending a SameSite value equals to the same
+            // behavior as SameSite=None for these old versions anyways.
+            if (userAgent.Contains("Chrome/5") || userAgent.Contains("Chrome/6"))
+            {
+                return true;
+            }
+
+            return false;
+        }
+    }
+}

+ 280 - 0
backend/AuthCenter/AuthCenter/Controllers/AccountController.cs

@@ -0,0 +1,280 @@
+using System;
+using System.Security.Claims;
+using System.Threading.Tasks;
+using AuthorizeCenter.Services;
+using DllUfpEntity;
+using DllUfpEntity.Dto;
+using IdentityServer4.Services;
+using IdentityServer4.Stores;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using IdentityServer4;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.Extensions.Configuration;
+using Cksoft.Unity;
+using IdentityServer4.Events;
+using IdentityServer4.Extensions;
+using DllUfpUtil;
+using NLog;
+using Microsoft.Extensions.Logging;
+using System.Net.Http;
+using IdentityModel.Client;
+using AuthCenter.Services;
+using AuthCenter.AuthConfig;
+using System.Linq;
+using IdentityServer4.Models;
+using System.Collections.Generic;
+
+namespace AuthorizeCenter.Controllers
+{
+    public class AccountController : Controller
+    {
+        public AccountService AccountService { get; set; }
+        private readonly IIdentityServerInteractionService _interaction;
+        private IClientStore _clientStore { get; set; }
+        private IConfiguration _configuration;
+        private IEventService eventService;
+        private ILogger<AccountController> _logger;
+        public AccountController(AccountService accountService, IIdentityServerInteractionService
+            interaction, IClientStore clientStore,
+            IConfiguration configuration, ILogger<AccountController> logger)
+        {
+            AccountService = accountService;
+            _interaction = interaction;
+            _clientStore = clientStore;
+            _configuration = configuration;
+            _logger = logger;
+        }
+
+        /// <summary>
+        /// 登录页面
+        /// </summary>
+        /// <param name="returnUrl"></param>
+        /// <returns></returns>
+        public async Task<IActionResult> Login(string returnUrl = null)
+        {
+            ViewData["ReturnUrl"] = returnUrl;
+            var appInfo = _configuration.GetSection("WebConfig").Get<AppInfoDto>();
+            var accountStr = string.Empty;
+            // 如果cookie中含有账户信息,将账户信息取出返回前端
+            if (Request.Cookies.TryGetValue("login-account-info", out accountStr))
+            {
+                var decodes = Base64Helper.DecodeBase64(accountStr);
+                if (!string.IsNullOrEmpty(decodes))
+                {
+                    var strs = decodes.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
+                    var account = strs[1];
+                    var pwd = strs[2];
+                    ViewBag.Account = account;
+                    ViewBag.Password = pwd;
+                    ViewBag.RememberMe = true;
+                }
+            }
+            return View(appInfo);
+        }
+
+        /// <summary>
+        /// 校验用户名密码
+        /// </summary>
+        /// <param name="userLoginDto"></param>
+        /// <returns></returns>
+        [HttpPost]
+        public async Task<EapResponse> CheckAccount([FromBody] UserLoginDto userLoginDto)
+        {
+            if (!ModelState.IsValid)
+            {
+                return new EapResponse { Code = -1, Msg = "数据不合法" };
+            }
+            string errorinfo = string.Empty;
+            var res = AccountService.Login(new Staff()
+            {
+                FCode = userLoginDto.Account,
+                Password = userLoginDto.Password
+            }, ref errorinfo);
+            if (res != null)
+            {
+                Response.Cookies.Delete("login-account-info");
+                if (userLoginDto.RememberMe)
+                {
+                    var str = $"Encrypt,{res.FCode},{userLoginDto.Password}";
+                    var encrypt = Base64Helper.EncodeBase64(str);
+                    Response.Cookies.Append("login-account-info", encrypt, new CookieOptions
+                    {
+                        Path = "/",
+                        Expires = new DateTimeOffset(DateTime.SpecifyKind(DateTime.Now.AddDays(7), DateTimeKind.Unspecified), new TimeSpan(0, 0, 0))
+                    });
+                }
+                return await Task.FromResult(new EapResponse { Code = 1, Msg = string.Empty });
+            }
+            return await Task.FromResult(new EapResponse { Code = -1, Msg = errorinfo });
+        }
+
+        /// <summary>
+        /// Id4认证
+        /// </summary>
+        /// <param name="userLoginDto"></param>
+        /// <returns></returns>
+        [HttpPost]
+        public async Task<IActionResult> Login(Id4SignOnDto userLoginDto)
+        {
+            _logger.LogError("开始获取token");
+            ViewData["ReturnUrl"] = userLoginDto.ReturnUrl;
+            string errorinfo = string.Empty;
+            var context = await _interaction.GetAuthorizationContextAsync(userLoginDto.ReturnUrl);
+            if (ModelState.IsValid)
+            {
+                var res = AccountService.Login(new Staff()
+                {
+                    FCode = userLoginDto.UserSuccessAccount,
+                    Password = userLoginDto.UserSuccessPassword
+                }, ref errorinfo);
+                if (res != null)
+                {
+                    var user = res;
+                    AuthenticationProperties props = null;
+                    props = new AuthenticationProperties
+                    {
+                        IsPersistent = true,
+                        ExpiresUtc = DateTimeOffset.UtcNow.AddDays(1)
+                    };
+                    var isuser = new IdentityServerUser(user.ID)
+                    {
+                        DisplayName = user.FCode
+                    };
+                    await HttpContext.SignInAsync(isuser, props);
+                    if (context != null)
+                    {
+                        if (_interaction.IsValidReturnUrl(userLoginDto.ReturnUrl))
+                        {
+                            _logger.LogError("跳转页面");
+                            _logger.LogError(userLoginDto.ReturnUrl);
+                            return Redirect(userLoginDto.ReturnUrl);
+                        }
+                    }
+                    if (Url.IsLocalUrl(userLoginDto.ReturnUrl))
+                    {
+                        return Redirect(userLoginDto.ReturnUrl);
+                    }
+                    else if (string.IsNullOrEmpty(userLoginDto.ReturnUrl))
+                    {
+                        return Redirect("~/");
+                    }
+                    else
+                    {
+                        throw new Exception("invalid return URL");
+                    }
+                }
+            }
+            var appInfo = _configuration.GetSection("WebConfig").Get<AppInfoDto>();
+            return View(appInfo);
+        }
+
+        /// <summary>
+        /// 退出登录
+        /// </summary>
+        /// <param name="logoutId"></param>
+        /// <returns></returns>
+        public async Task<IActionResult> Logout(string logoutId, string accessToken)
+        {
+            var logout = await _interaction.GetLogoutContextAsync(logoutId);
+
+            await OAuthHelper.RevokeToken(accessToken);
+            await HttpContext.SignOutAsync();
+
+            //await eventService.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(),
+            //    User.GetDisplayName()));
+
+            var refererUrl = Request.Headers["Referer"].ToString();
+            if (!string.IsNullOrWhiteSpace(refererUrl))
+            {
+                return Redirect(refererUrl);
+            }
+            else
+            {
+                if (logout.PostLogoutRedirectUri != null)
+                {
+                    return Redirect(logout.PostLogoutRedirectUri);
+                }
+            }
+            return View();
+        }
+
+        public async Task<IActionResult> Error(string errorId)
+        {
+            var errContext = await _interaction.GetErrorContextAsync(errorId);
+            var logger = LogManager.LoadConfiguration("NLog.config").GetCurrentClassLogger();
+            if (errContext != null)
+            {
+                logger.Fatal(errContext.ToString());
+            }
+            return View(errContext);
+        }
+
+        /// <summary>
+        /// 移动端登录
+        /// </summary>
+        /// <param name="userLoginDto"></param>
+        /// <returns></returns>
+        [HttpPost]
+        public async Task<EapResponse> MobileLogin([FromBody] UserLoginDto userLoginDto)
+        {
+            string errorinfo = string.Empty;
+            if (ModelState.IsValid)
+            {
+                var res = AccountService.Login(new Staff()
+                {
+                    FCode = userLoginDto.Account,
+                    Password = userLoginDto.Password
+                }, ref errorinfo);
+                if (res == null)
+                {
+                    return new EapResponse() { Code = -1, Msg = errorinfo };
+                }
+                var user = res;
+                AuthenticationProperties props = null;
+                props = new AuthenticationProperties
+                {
+                    IsPersistent = true,
+                    ExpiresUtc = DateTimeOffset.UtcNow.AddDays(1),
+                };
+                var isuser = new IdentityServerUser(user.ID)
+                {
+                    DisplayName = user.FCode
+                };
+                await HttpContext.SignInAsync(isuser, props);
+
+                var (disco, client) = await DiscoGenerator.GenerateDiscoryDocumentResponse();
+                if (disco == null)
+                    return new EapResponse { Code = -1, Msg = "配置错误" };
+                var clients = Config.GetClients();
+                var secret = "Mobile Secret";
+                var userDics = new KeyValuePair<string, string>("userId", user.ID);
+                var parameters = new List<KeyValuePair<string, string>>();
+                parameters.Add(userDics);
+                var codeRes = await client.RequestTokenAsync(new TokenRequest
+                {
+                    Address = disco.TokenEndpoint,
+                    ClientId = userLoginDto.ClientId,
+                    ClientSecret = secret,
+                    GrantType = "eap.auth",
+                    Parameters = new Parameters(parameters)
+                });
+                if (codeRes.IsError)
+                {
+                    var error = codeRes.Error;
+                    return new EapResponse { Code = -1, Msg = "登录失败" };
+                }
+                var oauthToken = new OAuthToken
+                {
+                    AccessToken = codeRes.AccessToken,
+                    ExpiresIn = codeRes.ExpiresIn,
+                    IdToken = codeRes.IdentityToken,
+                    RefreshToken = codeRes.RefreshToken,
+                    TokenType = codeRes.TokenType
+                };
+                return new EapResponse { Code = 1, Msg = "登录成功", Data = oauthToken };
+            }
+            return new EapResponse { Code = -1, Msg = "传入数据不合法" };
+        }
+    }
+}

+ 31 - 0
backend/AuthCenter/AuthCenter/Controllers/HomeController.cs

@@ -0,0 +1,31 @@
+using IdentityServer4.Services;
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace AuthorizeCenter.Controllers
+{
+    [Route("[controller]/[action]")]
+    public class HomeController : Controller
+    {
+        private readonly IIdentityServerInteractionService _interaction;
+        public HomeController(IIdentityServerInteractionService
+            interaction)
+        {
+            _interaction = interaction;
+        }
+        public IActionResult Index()
+        {
+            return Redirect("/.well-known/openid-configuration");
+        }
+
+        public async Task<IActionResult> Error(string errorId)
+        {
+            // retrieve error details from identityserver
+            var message = await _interaction.GetErrorContextAsync(errorId);
+            return View("Error", message);
+        }
+    }
+}

+ 202 - 0
backend/AuthCenter/AuthCenter/Controllers/OAuthController.cs

@@ -0,0 +1,202 @@
+using AuthCenter.AuthConfig;
+using AuthorizeCenter.Services;
+using Cksoft.Unity;
+using DllUfpEntity.Dto;
+using DllUfpUtil;
+using IdentityModel.Client;
+using IdentityServer4.Events;
+using IdentityServer4.Extensions;
+using IdentityServer4.Services;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Authorization;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.Configuration;
+using NLog;
+using System.Linq;
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace AuthorizeCenter.Controllers
+{
+    [ApiController]
+    [AllowAnonymous]
+    public class OAuthController : Controller
+    {
+        public AccountService AccountService { get; set; }
+        public IConfiguration Configuration { get; set; }
+        private Logger logger;
+        private IEventService _eventService;
+
+        public OAuthController(AccountService accountService,
+            IConfiguration configuration,
+            IEventService eventService)
+        {
+            AccountService = accountService;
+            Configuration = configuration;
+            _eventService = eventService;
+            logger = LogManager.LoadConfiguration("NLog.config").GetCurrentClassLogger();
+        }
+
+        /// <summary>
+        /// 根据授权码获取token
+        /// </summary>
+        /// <param name="code"></param>
+        /// <param name="redirectUri"></param>
+        /// <returns></returns>
+        [Route("api/oauth2/token")]
+        public async Task<IActionResult> Token(string code, string redirectUri,
+            string refreshToken,
+            string clientId = "EAP", string secret = "secret")
+        {
+            var token = new OAuthToken();
+            if (string.IsNullOrEmpty(refreshToken))
+            {
+                token = await GetOAuthToken(code, redirectUri, clientId, secret);
+            }
+            else
+            {
+                token = await GetTokenViaRefreshToken(refreshToken);
+            }
+            if (token == null)
+            {
+                return new UnauthorizedResult();
+            }
+
+            return Json(token);
+        }
+
+        [Route("api/oauth2/token/refresh")]
+        public async Task<IActionResult> Refresh(string redirectUri, string clientId,
+            string secret, string refreshToken)
+        {
+            var token = await GetTokenViaRefreshToken(refreshToken, clientId, secret);
+            if (token == null)
+                return new UnauthorizedResult();
+            return Json(token);
+        }
+
+        /// <summary>
+        /// 根据refresh_token获取access_token
+        /// </summary>
+        /// <returns></returns>
+        private async Task<OAuthToken> GetTokenViaRefreshToken(string refreshToken,
+            string clientId = "EAP", string secret = "secret")
+        {
+            var client = new HttpClient();
+            var discoRequest = new DiscoveryDocumentRequest()
+            {
+                Policy = new DiscoveryPolicy
+                {
+                    RequireHttps = false,
+                },
+                Address = AppConfigurtaionServices.Configuration["Id4:Authority"]
+            };
+            var disco = await client.GetDiscoveryDocumentAsync(discoRequest);
+            if (disco.IsError)
+            {
+                logger.Error("加载配置失败:" + disco.Error.ToString());
+                return null;
+            }
+
+            //接下来,您可以使用发现文档中的信息向IdentityServer请求令牌以访问api1
+            var tokenResponse = await client.RequestRefreshTokenAsync(new RefreshTokenRequest
+            {
+                Address = disco.TokenEndpoint,
+                ClientId = "EAP",
+                ClientSecret = "secret",
+                GrantType = "refresh_token",
+                RefreshToken = refreshToken
+            });
+
+            if (tokenResponse.IsError)
+            {
+                logger.Error("获取token失败:" + disco.Error?.ToString());
+                return null;
+            }
+
+            return new OAuthToken
+            {
+                AccessToken = tokenResponse.AccessToken,
+                ExpiresIn = tokenResponse.ExpiresIn,
+                IdToken = tokenResponse.IdentityToken,
+                RefreshToken = tokenResponse.RefreshToken,
+                TokenType = tokenResponse.TokenType
+            };
+        }
+
+        private async Task<OAuthToken> GetOAuthToken(string code,
+            string redirectUri, string clientId = "EAP", string secret = "secret")
+        {
+            logger.Fatal("开始获取TOKEN");
+            var handler = new HttpClientHandler();
+            handler.ClientCertificateOptions = ClientCertificateOption.Manual;
+            handler.ServerCertificateCustomValidationCallback =
+                (httpRequestMessage, cert, certChain, policyErrors) =>
+                {
+                    return true;
+                };
+            var client = new HttpClient(handler);
+            var discoRequest = new DiscoveryDocumentRequest()
+            {
+                Policy = new DiscoveryPolicy
+                {
+                    RequireHttps = false,
+                },
+                Address = AppConfigurtaionServices.Configuration["Id4:Authority"]
+            };
+            var disco = await client.GetDiscoveryDocumentAsync(discoRequest);
+            // var disco = await client.GetDiscoveryDocumentAsync(AppConfigurtaionServices.Configuration["Id4:Authority"]);
+            if (disco.IsError)
+            {
+                logger.Error("加载配置失败:" + disco.Error);
+                return null;
+            }
+            var tokenResponse = await client.RequestAuthorizationCodeTokenAsync(new AuthorizationCodeTokenRequest
+            {
+                Address = disco.TokenEndpoint,
+                ClientId = clientId,
+                ClientSecret = secret,
+                Code = code,
+                RedirectUri = redirectUri
+            });
+
+            if (tokenResponse.IsError)
+            {
+                logger.Error("获取Token失败:" + tokenResponse.Error.ToString());
+                return null;
+            }
+
+            return new OAuthToken
+            {
+                AccessToken = tokenResponse.AccessToken,
+                ExpiresIn = tokenResponse.ExpiresIn,
+                IdToken = tokenResponse.IdentityToken,
+                RefreshToken = tokenResponse.RefreshToken,
+                TokenType = tokenResponse.TokenType
+            };
+        }
+
+        /// <summary>
+        /// 根据token获取用户信息
+        /// </summary>
+        /// <param name="token"></param>
+        /// <returns></returns>
+        [Route("api/oauth2/userinfo")]
+        public async Task<UserInfo> GetUserInfo(string token)
+        {
+            return await OAuthHelper.GetUserInfo(token);
+        }
+
+        [Route("api/oauth2/logout")]
+        public async Task<IActionResult> Logout(string accesstoken)
+        {
+            var refererUrl = Request.Headers["Referer"].ToString();
+            await OAuthHelper.RevokeToken(accesstoken);
+            await HttpContext.SignOutAsync("idsrv");
+            await HttpContext.SignOutAsync("idsrv.external");
+            await _eventService.RaiseAsync(new UserLogoutSuccessEvent(User.GetSubjectId(),
+                User.GetDisplayName()));
+            return Redirect(refererUrl);
+        }
+    }
+}

+ 25 - 0
backend/AuthCenter/AuthCenter/Filters/ExceptionFilter.cs

@@ -0,0 +1,25 @@
+using Microsoft.AspNetCore.Mvc.Filters;
+using NLog;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace AuthCenter.Filters
+{
+    public class ExceptionFilter : ExceptionFilterAttribute
+    {
+        private Logger logger;
+
+        public override void OnException(ExceptionContext context)
+        {
+            logger = LogManager.LoadConfiguration("NLog.config").GetCurrentClassLogger();
+            var controllerName = context.ActionDescriptor.RouteValues["controller"];    // 控制器名称
+            var actionName = context.ActionDescriptor.RouteValues["action"];     // 方法名称
+            string errorinfo = $@"/{controllerName}/{actionName}请求异常:{context.Exception.Message}/{context.Exception.ToString()}";
+            var userCode = context.HttpContext.Request.Headers["usercode"];
+            logger.Error(errorinfo);
+            context.ExceptionHandled = true;
+        }
+    }
+}

+ 882 - 0
backend/AuthCenter/AuthCenter/Migrations/IdentityServer/ConfigurationDb/20210729013943_InitialConfigurationDb.Designer.cs

@@ -0,0 +1,882 @@
+// <auto-generated />
+using System;
+using IdentityServer4.EntityFramework.DbContexts;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace AuthCenter.Migrations.IdentityServer.ConfigurationDb
+{
+    [DbContext(typeof(ConfigurationDbContext))]
+    [Migration("20210729013943_InitialConfigurationDb")]
+    partial class InitialConfigurationDb
+    {
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("ProductVersion", "3.1.17")
+                .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<string>("AllowedAccessTokenSigningAlgorithms")
+                        .HasColumnType("varchar(100) CHARACTER SET utf8mb4")
+                        .HasMaxLength(100);
+
+                    b.Property<DateTime>("Created")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(1000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(1000);
+
+                    b.Property<string>("DisplayName")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<bool>("Enabled")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<DateTime?>("LastAccessed")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<bool>("NonEditable")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("ShowInDiscoveryDocument")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<DateTime?>("Updated")
+                        .HasColumnType("datetime(6)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("Name")
+                        .IsUnique();
+
+                    b.ToTable("ApiResources");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ApiResourceId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ApiResourceId");
+
+                    b.ToTable("ApiResourceClaims");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ApiResourceId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Key")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.Property<string>("Value")
+                        .IsRequired()
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ApiResourceId");
+
+                    b.ToTable("ApiResourceProperties");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ApiResourceId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Scope")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ApiResourceId");
+
+                    b.ToTable("ApiResourceScopes");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ApiResourceId")
+                        .HasColumnType("int");
+
+                    b.Property<DateTime>("Created")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(1000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(1000);
+
+                    b.Property<DateTime?>("Expiration")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.Property<string>("Value")
+                        .IsRequired()
+                        .HasColumnType("longtext CHARACTER SET utf8mb4")
+                        .HasMaxLength(4000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ApiResourceId");
+
+                    b.ToTable("ApiResourceSecrets");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(1000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(1000);
+
+                    b.Property<string>("DisplayName")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<bool>("Emphasize")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("Enabled")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<bool>("Required")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("ShowInDiscoveryDocument")
+                        .HasColumnType("tinyint(1)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("Name")
+                        .IsUnique();
+
+                    b.ToTable("ApiScopes");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ScopeId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ScopeId");
+
+                    b.ToTable("ApiScopeClaims");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<string>("Key")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.Property<int>("ScopeId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Value")
+                        .IsRequired()
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ScopeId");
+
+                    b.ToTable("ApiScopeProperties");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("AbsoluteRefreshTokenLifetime")
+                        .HasColumnType("int");
+
+                    b.Property<int>("AccessTokenLifetime")
+                        .HasColumnType("int");
+
+                    b.Property<int>("AccessTokenType")
+                        .HasColumnType("int");
+
+                    b.Property<bool>("AllowAccessTokensViaBrowser")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("AllowOfflineAccess")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("AllowPlainTextPkce")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("AllowRememberConsent")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<string>("AllowedIdentityTokenSigningAlgorithms")
+                        .HasColumnType("varchar(100) CHARACTER SET utf8mb4")
+                        .HasMaxLength(100);
+
+                    b.Property<bool>("AlwaysIncludeUserClaimsInIdToken")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("AlwaysSendClientClaims")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<int>("AuthorizationCodeLifetime")
+                        .HasColumnType("int");
+
+                    b.Property<bool>("BackChannelLogoutSessionRequired")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<string>("BackChannelLogoutUri")
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("ClientClaimsPrefix")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("ClientId")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("ClientName")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("ClientUri")
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("ConsentLifetime")
+                        .HasColumnType("int");
+
+                    b.Property<DateTime>("Created")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(1000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(1000);
+
+                    b.Property<int>("DeviceCodeLifetime")
+                        .HasColumnType("int");
+
+                    b.Property<bool>("EnableLocalLogin")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("Enabled")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("FrontChannelLogoutSessionRequired")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<string>("FrontChannelLogoutUri")
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.Property<int>("IdentityTokenLifetime")
+                        .HasColumnType("int");
+
+                    b.Property<bool>("IncludeJwtId")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<DateTime?>("LastAccessed")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("LogoUri")
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("NonEditable")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<string>("PairWiseSubjectSalt")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("ProtocolType")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<int>("RefreshTokenExpiration")
+                        .HasColumnType("int");
+
+                    b.Property<int>("RefreshTokenUsage")
+                        .HasColumnType("int");
+
+                    b.Property<bool>("RequireClientSecret")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("RequireConsent")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("RequirePkce")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("RequireRequestObject")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<int>("SlidingRefreshTokenLifetime")
+                        .HasColumnType("int");
+
+                    b.Property<bool>("UpdateAccessTokenClaimsOnRefresh")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<DateTime?>("Updated")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("UserCodeType")
+                        .HasColumnType("varchar(100) CHARACTER SET utf8mb4")
+                        .HasMaxLength(100);
+
+                    b.Property<int?>("UserSsoLifetime")
+                        .HasColumnType("int");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId")
+                        .IsUnique();
+
+                    b.ToTable("Clients");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.Property<string>("Value")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientClaims");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Origin")
+                        .IsRequired()
+                        .HasColumnType("varchar(150) CHARACTER SET utf8mb4")
+                        .HasMaxLength(150);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientCorsOrigins");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("GrantType")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientGrantTypes");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Provider")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientIdPRestrictions");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("PostLogoutRedirectUri")
+                        .IsRequired()
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientPostLogoutRedirectUris");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Key")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.Property<string>("Value")
+                        .IsRequired()
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientProperties");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("RedirectUri")
+                        .IsRequired()
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientRedirectUris");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Scope")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientScopes");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<DateTime>("Created")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime?>("Expiration")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.Property<string>("Value")
+                        .IsRequired()
+                        .HasColumnType("longtext CHARACTER SET utf8mb4")
+                        .HasMaxLength(4000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientSecrets");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<DateTime>("Created")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(1000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(1000);
+
+                    b.Property<string>("DisplayName")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<bool>("Emphasize")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("Enabled")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<bool>("NonEditable")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("Required")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("ShowInDiscoveryDocument")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<DateTime?>("Updated")
+                        .HasColumnType("datetime(6)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("Name")
+                        .IsUnique();
+
+                    b.ToTable("IdentityResources");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("IdentityResourceId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("IdentityResourceId");
+
+                    b.ToTable("IdentityResourceClaims");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("IdentityResourceId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Key")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.Property<string>("Value")
+                        .IsRequired()
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("IdentityResourceId");
+
+                    b.ToTable("IdentityResourceProperties");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
+                        .WithMany("UserClaims")
+                        .HasForeignKey("ApiResourceId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
+                        .WithMany("Properties")
+                        .HasForeignKey("ApiResourceId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
+                        .WithMany("Scopes")
+                        .HasForeignKey("ApiResourceId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
+                        .WithMany("Secrets")
+                        .HasForeignKey("ApiResourceId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope")
+                        .WithMany("UserClaims")
+                        .HasForeignKey("ScopeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope")
+                        .WithMany("Properties")
+                        .HasForeignKey("ScopeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("Claims")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("AllowedCorsOrigins")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("AllowedGrantTypes")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("IdentityProviderRestrictions")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("PostLogoutRedirectUris")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("Properties")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("RedirectUris")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("AllowedScopes")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("ClientSecrets")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource")
+                        .WithMany("UserClaims")
+                        .HasForeignKey("IdentityResourceId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource")
+                        .WithMany("Properties")
+                        .HasForeignKey("IdentityResourceId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}

+ 658 - 0
backend/AuthCenter/AuthCenter/Migrations/IdentityServer/ConfigurationDb/20210729013943_InitialConfigurationDb.cs

@@ -0,0 +1,658 @@
+using System;
+using Microsoft.EntityFrameworkCore.Metadata;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace AuthCenter.Migrations.IdentityServer.ConfigurationDb
+{
+    public partial class InitialConfigurationDb : Migration
+    {
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.CreateTable(
+                name: "ApiResources",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Enabled = table.Column<bool>(nullable: false),
+                    Name = table.Column<string>(maxLength: 200, nullable: false),
+                    DisplayName = table.Column<string>(maxLength: 200, nullable: true),
+                    Description = table.Column<string>(maxLength: 1000, nullable: true),
+                    AllowedAccessTokenSigningAlgorithms = table.Column<string>(maxLength: 100, nullable: true),
+                    ShowInDiscoveryDocument = table.Column<bool>(nullable: false),
+                    Created = table.Column<DateTime>(nullable: false),
+                    Updated = table.Column<DateTime>(nullable: true),
+                    LastAccessed = table.Column<DateTime>(nullable: true),
+                    NonEditable = table.Column<bool>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ApiResources", x => x.Id);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ApiScopes",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Enabled = table.Column<bool>(nullable: false),
+                    Name = table.Column<string>(maxLength: 200, nullable: false),
+                    DisplayName = table.Column<string>(maxLength: 200, nullable: true),
+                    Description = table.Column<string>(maxLength: 1000, nullable: true),
+                    Required = table.Column<bool>(nullable: false),
+                    Emphasize = table.Column<bool>(nullable: false),
+                    ShowInDiscoveryDocument = table.Column<bool>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ApiScopes", x => x.Id);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "Clients",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Enabled = table.Column<bool>(nullable: false),
+                    ClientId = table.Column<string>(maxLength: 200, nullable: false),
+                    ProtocolType = table.Column<string>(maxLength: 200, nullable: false),
+                    RequireClientSecret = table.Column<bool>(nullable: false),
+                    ClientName = table.Column<string>(maxLength: 200, nullable: true),
+                    Description = table.Column<string>(maxLength: 1000, nullable: true),
+                    ClientUri = table.Column<string>(maxLength: 2000, nullable: true),
+                    LogoUri = table.Column<string>(maxLength: 2000, nullable: true),
+                    RequireConsent = table.Column<bool>(nullable: false),
+                    AllowRememberConsent = table.Column<bool>(nullable: false),
+                    AlwaysIncludeUserClaimsInIdToken = table.Column<bool>(nullable: false),
+                    RequirePkce = table.Column<bool>(nullable: false),
+                    AllowPlainTextPkce = table.Column<bool>(nullable: false),
+                    RequireRequestObject = table.Column<bool>(nullable: false),
+                    AllowAccessTokensViaBrowser = table.Column<bool>(nullable: false),
+                    FrontChannelLogoutUri = table.Column<string>(maxLength: 2000, nullable: true),
+                    FrontChannelLogoutSessionRequired = table.Column<bool>(nullable: false),
+                    BackChannelLogoutUri = table.Column<string>(maxLength: 2000, nullable: true),
+                    BackChannelLogoutSessionRequired = table.Column<bool>(nullable: false),
+                    AllowOfflineAccess = table.Column<bool>(nullable: false),
+                    IdentityTokenLifetime = table.Column<int>(nullable: false),
+                    AllowedIdentityTokenSigningAlgorithms = table.Column<string>(maxLength: 100, nullable: true),
+                    AccessTokenLifetime = table.Column<int>(nullable: false),
+                    AuthorizationCodeLifetime = table.Column<int>(nullable: false),
+                    ConsentLifetime = table.Column<int>(nullable: true),
+                    AbsoluteRefreshTokenLifetime = table.Column<int>(nullable: false),
+                    SlidingRefreshTokenLifetime = table.Column<int>(nullable: false),
+                    RefreshTokenUsage = table.Column<int>(nullable: false),
+                    UpdateAccessTokenClaimsOnRefresh = table.Column<bool>(nullable: false),
+                    RefreshTokenExpiration = table.Column<int>(nullable: false),
+                    AccessTokenType = table.Column<int>(nullable: false),
+                    EnableLocalLogin = table.Column<bool>(nullable: false),
+                    IncludeJwtId = table.Column<bool>(nullable: false),
+                    AlwaysSendClientClaims = table.Column<bool>(nullable: false),
+                    ClientClaimsPrefix = table.Column<string>(maxLength: 200, nullable: true),
+                    PairWiseSubjectSalt = table.Column<string>(maxLength: 200, nullable: true),
+                    Created = table.Column<DateTime>(nullable: false),
+                    Updated = table.Column<DateTime>(nullable: true),
+                    LastAccessed = table.Column<DateTime>(nullable: true),
+                    UserSsoLifetime = table.Column<int>(nullable: true),
+                    UserCodeType = table.Column<string>(maxLength: 100, nullable: true),
+                    DeviceCodeLifetime = table.Column<int>(nullable: false),
+                    NonEditable = table.Column<bool>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_Clients", x => x.Id);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "IdentityResources",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Enabled = table.Column<bool>(nullable: false),
+                    Name = table.Column<string>(maxLength: 200, nullable: false),
+                    DisplayName = table.Column<string>(maxLength: 200, nullable: true),
+                    Description = table.Column<string>(maxLength: 1000, nullable: true),
+                    Required = table.Column<bool>(nullable: false),
+                    Emphasize = table.Column<bool>(nullable: false),
+                    ShowInDiscoveryDocument = table.Column<bool>(nullable: false),
+                    Created = table.Column<DateTime>(nullable: false),
+                    Updated = table.Column<DateTime>(nullable: true),
+                    NonEditable = table.Column<bool>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_IdentityResources", x => x.Id);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ApiResourceClaims",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Type = table.Column<string>(maxLength: 200, nullable: false),
+                    ApiResourceId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ApiResourceClaims", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_ApiResourceClaims_ApiResources_ApiResourceId",
+                        column: x => x.ApiResourceId,
+                        principalTable: "ApiResources",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ApiResourceProperties",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Key = table.Column<string>(maxLength: 250, nullable: false),
+                    Value = table.Column<string>(maxLength: 2000, nullable: false),
+                    ApiResourceId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ApiResourceProperties", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_ApiResourceProperties_ApiResources_ApiResourceId",
+                        column: x => x.ApiResourceId,
+                        principalTable: "ApiResources",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ApiResourceScopes",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Scope = table.Column<string>(maxLength: 200, nullable: false),
+                    ApiResourceId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ApiResourceScopes", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_ApiResourceScopes_ApiResources_ApiResourceId",
+                        column: x => x.ApiResourceId,
+                        principalTable: "ApiResources",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ApiResourceSecrets",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Description = table.Column<string>(maxLength: 1000, nullable: true),
+                    Value = table.Column<string>(maxLength: 4000, nullable: false),
+                    Expiration = table.Column<DateTime>(nullable: true),
+                    Type = table.Column<string>(maxLength: 250, nullable: false),
+                    Created = table.Column<DateTime>(nullable: false),
+                    ApiResourceId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ApiResourceSecrets", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_ApiResourceSecrets_ApiResources_ApiResourceId",
+                        column: x => x.ApiResourceId,
+                        principalTable: "ApiResources",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ApiScopeClaims",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Type = table.Column<string>(maxLength: 200, nullable: false),
+                    ScopeId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ApiScopeClaims", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_ApiScopeClaims_ApiScopes_ScopeId",
+                        column: x => x.ScopeId,
+                        principalTable: "ApiScopes",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ApiScopeProperties",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Key = table.Column<string>(maxLength: 250, nullable: false),
+                    Value = table.Column<string>(maxLength: 2000, nullable: false),
+                    ScopeId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ApiScopeProperties", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_ApiScopeProperties_ApiScopes_ScopeId",
+                        column: x => x.ScopeId,
+                        principalTable: "ApiScopes",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ClientClaims",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Type = table.Column<string>(maxLength: 250, nullable: false),
+                    Value = table.Column<string>(maxLength: 250, nullable: false),
+                    ClientId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ClientClaims", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_ClientClaims_Clients_ClientId",
+                        column: x => x.ClientId,
+                        principalTable: "Clients",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ClientCorsOrigins",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Origin = table.Column<string>(maxLength: 150, nullable: false),
+                    ClientId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ClientCorsOrigins", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_ClientCorsOrigins_Clients_ClientId",
+                        column: x => x.ClientId,
+                        principalTable: "Clients",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ClientGrantTypes",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    GrantType = table.Column<string>(maxLength: 250, nullable: false),
+                    ClientId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ClientGrantTypes", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_ClientGrantTypes_Clients_ClientId",
+                        column: x => x.ClientId,
+                        principalTable: "Clients",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ClientIdPRestrictions",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Provider = table.Column<string>(maxLength: 200, nullable: false),
+                    ClientId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ClientIdPRestrictions", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_ClientIdPRestrictions_Clients_ClientId",
+                        column: x => x.ClientId,
+                        principalTable: "Clients",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ClientPostLogoutRedirectUris",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    PostLogoutRedirectUri = table.Column<string>(maxLength: 2000, nullable: false),
+                    ClientId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ClientPostLogoutRedirectUris", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_ClientPostLogoutRedirectUris_Clients_ClientId",
+                        column: x => x.ClientId,
+                        principalTable: "Clients",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ClientProperties",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Key = table.Column<string>(maxLength: 250, nullable: false),
+                    Value = table.Column<string>(maxLength: 2000, nullable: false),
+                    ClientId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ClientProperties", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_ClientProperties_Clients_ClientId",
+                        column: x => x.ClientId,
+                        principalTable: "Clients",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ClientRedirectUris",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    RedirectUri = table.Column<string>(maxLength: 2000, nullable: false),
+                    ClientId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ClientRedirectUris", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_ClientRedirectUris_Clients_ClientId",
+                        column: x => x.ClientId,
+                        principalTable: "Clients",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ClientScopes",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Scope = table.Column<string>(maxLength: 200, nullable: false),
+                    ClientId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ClientScopes", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_ClientScopes_Clients_ClientId",
+                        column: x => x.ClientId,
+                        principalTable: "Clients",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "ClientSecrets",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Description = table.Column<string>(maxLength: 2000, nullable: true),
+                    Value = table.Column<string>(maxLength: 4000, nullable: false),
+                    Expiration = table.Column<DateTime>(nullable: true),
+                    Type = table.Column<string>(maxLength: 250, nullable: false),
+                    Created = table.Column<DateTime>(nullable: false),
+                    ClientId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_ClientSecrets", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_ClientSecrets_Clients_ClientId",
+                        column: x => x.ClientId,
+                        principalTable: "Clients",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "IdentityResourceClaims",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Type = table.Column<string>(maxLength: 200, nullable: false),
+                    IdentityResourceId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_IdentityResourceClaims", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_IdentityResourceClaims_IdentityResources_IdentityResourceId",
+                        column: x => x.IdentityResourceId,
+                        principalTable: "IdentityResources",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "IdentityResourceProperties",
+                columns: table => new
+                {
+                    Id = table.Column<int>(nullable: false)
+                        .Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
+                    Key = table.Column<string>(maxLength: 250, nullable: false),
+                    Value = table.Column<string>(maxLength: 2000, nullable: false),
+                    IdentityResourceId = table.Column<int>(nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_IdentityResourceProperties", x => x.Id);
+                    table.ForeignKey(
+                        name: "FK_IdentityResourceProperties_IdentityResources_IdentityResourc~",
+                        column: x => x.IdentityResourceId,
+                        principalTable: "IdentityResources",
+                        principalColumn: "Id",
+                        onDelete: ReferentialAction.Cascade);
+                });
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ApiResourceClaims_ApiResourceId",
+                table: "ApiResourceClaims",
+                column: "ApiResourceId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ApiResourceProperties_ApiResourceId",
+                table: "ApiResourceProperties",
+                column: "ApiResourceId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ApiResources_Name",
+                table: "ApiResources",
+                column: "Name",
+                unique: true);
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ApiResourceScopes_ApiResourceId",
+                table: "ApiResourceScopes",
+                column: "ApiResourceId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ApiResourceSecrets_ApiResourceId",
+                table: "ApiResourceSecrets",
+                column: "ApiResourceId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ApiScopeClaims_ScopeId",
+                table: "ApiScopeClaims",
+                column: "ScopeId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ApiScopeProperties_ScopeId",
+                table: "ApiScopeProperties",
+                column: "ScopeId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ApiScopes_Name",
+                table: "ApiScopes",
+                column: "Name",
+                unique: true);
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ClientClaims_ClientId",
+                table: "ClientClaims",
+                column: "ClientId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ClientCorsOrigins_ClientId",
+                table: "ClientCorsOrigins",
+                column: "ClientId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ClientGrantTypes_ClientId",
+                table: "ClientGrantTypes",
+                column: "ClientId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ClientIdPRestrictions_ClientId",
+                table: "ClientIdPRestrictions",
+                column: "ClientId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ClientPostLogoutRedirectUris_ClientId",
+                table: "ClientPostLogoutRedirectUris",
+                column: "ClientId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ClientProperties_ClientId",
+                table: "ClientProperties",
+                column: "ClientId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ClientRedirectUris_ClientId",
+                table: "ClientRedirectUris",
+                column: "ClientId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_Clients_ClientId",
+                table: "Clients",
+                column: "ClientId",
+                unique: true);
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ClientScopes_ClientId",
+                table: "ClientScopes",
+                column: "ClientId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_ClientSecrets_ClientId",
+                table: "ClientSecrets",
+                column: "ClientId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_IdentityResourceClaims_IdentityResourceId",
+                table: "IdentityResourceClaims",
+                column: "IdentityResourceId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_IdentityResourceProperties_IdentityResourceId",
+                table: "IdentityResourceProperties",
+                column: "IdentityResourceId");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_IdentityResources_Name",
+                table: "IdentityResources",
+                column: "Name",
+                unique: true);
+        }
+
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropTable(
+                name: "ApiResourceClaims");
+
+            migrationBuilder.DropTable(
+                name: "ApiResourceProperties");
+
+            migrationBuilder.DropTable(
+                name: "ApiResourceScopes");
+
+            migrationBuilder.DropTable(
+                name: "ApiResourceSecrets");
+
+            migrationBuilder.DropTable(
+                name: "ApiScopeClaims");
+
+            migrationBuilder.DropTable(
+                name: "ApiScopeProperties");
+
+            migrationBuilder.DropTable(
+                name: "ClientClaims");
+
+            migrationBuilder.DropTable(
+                name: "ClientCorsOrigins");
+
+            migrationBuilder.DropTable(
+                name: "ClientGrantTypes");
+
+            migrationBuilder.DropTable(
+                name: "ClientIdPRestrictions");
+
+            migrationBuilder.DropTable(
+                name: "ClientPostLogoutRedirectUris");
+
+            migrationBuilder.DropTable(
+                name: "ClientProperties");
+
+            migrationBuilder.DropTable(
+                name: "ClientRedirectUris");
+
+            migrationBuilder.DropTable(
+                name: "ClientScopes");
+
+            migrationBuilder.DropTable(
+                name: "ClientSecrets");
+
+            migrationBuilder.DropTable(
+                name: "IdentityResourceClaims");
+
+            migrationBuilder.DropTable(
+                name: "IdentityResourceProperties");
+
+            migrationBuilder.DropTable(
+                name: "ApiResources");
+
+            migrationBuilder.DropTable(
+                name: "ApiScopes");
+
+            migrationBuilder.DropTable(
+                name: "Clients");
+
+            migrationBuilder.DropTable(
+                name: "IdentityResources");
+        }
+    }
+}

+ 880 - 0
backend/AuthCenter/AuthCenter/Migrations/IdentityServer/ConfigurationDb/ConfigurationDbContextModelSnapshot.cs

@@ -0,0 +1,880 @@
+// <auto-generated />
+using System;
+using IdentityServer4.EntityFramework.DbContexts;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace AuthCenter.Migrations.IdentityServer.ConfigurationDb
+{
+    [DbContext(typeof(ConfigurationDbContext))]
+    partial class ConfigurationDbContextModelSnapshot : ModelSnapshot
+    {
+        protected override void BuildModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("ProductVersion", "3.1.17")
+                .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResource", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<string>("AllowedAccessTokenSigningAlgorithms")
+                        .HasColumnType("varchar(100) CHARACTER SET utf8mb4")
+                        .HasMaxLength(100);
+
+                    b.Property<DateTime>("Created")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(1000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(1000);
+
+                    b.Property<string>("DisplayName")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<bool>("Enabled")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<DateTime?>("LastAccessed")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<bool>("NonEditable")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("ShowInDiscoveryDocument")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<DateTime?>("Updated")
+                        .HasColumnType("datetime(6)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("Name")
+                        .IsUnique();
+
+                    b.ToTable("ApiResources");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ApiResourceId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ApiResourceId");
+
+                    b.ToTable("ApiResourceClaims");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ApiResourceId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Key")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.Property<string>("Value")
+                        .IsRequired()
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ApiResourceId");
+
+                    b.ToTable("ApiResourceProperties");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ApiResourceId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Scope")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ApiResourceId");
+
+                    b.ToTable("ApiResourceScopes");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ApiResourceId")
+                        .HasColumnType("int");
+
+                    b.Property<DateTime>("Created")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(1000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(1000);
+
+                    b.Property<DateTime?>("Expiration")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.Property<string>("Value")
+                        .IsRequired()
+                        .HasColumnType("longtext CHARACTER SET utf8mb4")
+                        .HasMaxLength(4000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ApiResourceId");
+
+                    b.ToTable("ApiResourceSecrets");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScope", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(1000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(1000);
+
+                    b.Property<string>("DisplayName")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<bool>("Emphasize")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("Enabled")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<bool>("Required")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("ShowInDiscoveryDocument")
+                        .HasColumnType("tinyint(1)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("Name")
+                        .IsUnique();
+
+                    b.ToTable("ApiScopes");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ScopeId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ScopeId");
+
+                    b.ToTable("ApiScopeClaims");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<string>("Key")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.Property<int>("ScopeId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Value")
+                        .IsRequired()
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ScopeId");
+
+                    b.ToTable("ApiScopeProperties");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.Client", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("AbsoluteRefreshTokenLifetime")
+                        .HasColumnType("int");
+
+                    b.Property<int>("AccessTokenLifetime")
+                        .HasColumnType("int");
+
+                    b.Property<int>("AccessTokenType")
+                        .HasColumnType("int");
+
+                    b.Property<bool>("AllowAccessTokensViaBrowser")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("AllowOfflineAccess")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("AllowPlainTextPkce")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("AllowRememberConsent")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<string>("AllowedIdentityTokenSigningAlgorithms")
+                        .HasColumnType("varchar(100) CHARACTER SET utf8mb4")
+                        .HasMaxLength(100);
+
+                    b.Property<bool>("AlwaysIncludeUserClaimsInIdToken")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("AlwaysSendClientClaims")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<int>("AuthorizationCodeLifetime")
+                        .HasColumnType("int");
+
+                    b.Property<bool>("BackChannelLogoutSessionRequired")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<string>("BackChannelLogoutUri")
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.Property<string>("ClientClaimsPrefix")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("ClientId")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("ClientName")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("ClientUri")
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.Property<int?>("ConsentLifetime")
+                        .HasColumnType("int");
+
+                    b.Property<DateTime>("Created")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(1000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(1000);
+
+                    b.Property<int>("DeviceCodeLifetime")
+                        .HasColumnType("int");
+
+                    b.Property<bool>("EnableLocalLogin")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("Enabled")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("FrontChannelLogoutSessionRequired")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<string>("FrontChannelLogoutUri")
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.Property<int>("IdentityTokenLifetime")
+                        .HasColumnType("int");
+
+                    b.Property<bool>("IncludeJwtId")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<DateTime?>("LastAccessed")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("LogoUri")
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.Property<bool>("NonEditable")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<string>("PairWiseSubjectSalt")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("ProtocolType")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<int>("RefreshTokenExpiration")
+                        .HasColumnType("int");
+
+                    b.Property<int>("RefreshTokenUsage")
+                        .HasColumnType("int");
+
+                    b.Property<bool>("RequireClientSecret")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("RequireConsent")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("RequirePkce")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("RequireRequestObject")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<int>("SlidingRefreshTokenLifetime")
+                        .HasColumnType("int");
+
+                    b.Property<bool>("UpdateAccessTokenClaimsOnRefresh")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<DateTime?>("Updated")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("UserCodeType")
+                        .HasColumnType("varchar(100) CHARACTER SET utf8mb4")
+                        .HasMaxLength(100);
+
+                    b.Property<int?>("UserSsoLifetime")
+                        .HasColumnType("int");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId")
+                        .IsUnique();
+
+                    b.ToTable("Clients");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.Property<string>("Value")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientClaims");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Origin")
+                        .IsRequired()
+                        .HasColumnType("varchar(150) CHARACTER SET utf8mb4")
+                        .HasMaxLength(150);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientCorsOrigins");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("GrantType")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientGrantTypes");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Provider")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientIdPRestrictions");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("PostLogoutRedirectUri")
+                        .IsRequired()
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientPostLogoutRedirectUris");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Key")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.Property<string>("Value")
+                        .IsRequired()
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientProperties");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("RedirectUri")
+                        .IsRequired()
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientRedirectUris");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Scope")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientScopes");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("ClientId")
+                        .HasColumnType("int");
+
+                    b.Property<DateTime>("Created")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.Property<DateTime?>("Expiration")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.Property<string>("Value")
+                        .IsRequired()
+                        .HasColumnType("longtext CHARACTER SET utf8mb4")
+                        .HasMaxLength(4000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("ClientId");
+
+                    b.ToTable("ClientSecrets");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResource", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<DateTime>("Created")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(1000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(1000);
+
+                    b.Property<string>("DisplayName")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<bool>("Emphasize")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("Enabled")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<string>("Name")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<bool>("NonEditable")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("Required")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<bool>("ShowInDiscoveryDocument")
+                        .HasColumnType("tinyint(1)");
+
+                    b.Property<DateTime?>("Updated")
+                        .HasColumnType("datetime(6)");
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("Name")
+                        .IsUnique();
+
+                    b.ToTable("IdentityResources");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("IdentityResourceId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("IdentityResourceId");
+
+                    b.ToTable("IdentityResourceClaims");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b =>
+                {
+                    b.Property<int>("Id")
+                        .ValueGeneratedOnAdd()
+                        .HasColumnType("int");
+
+                    b.Property<int>("IdentityResourceId")
+                        .HasColumnType("int");
+
+                    b.Property<string>("Key")
+                        .IsRequired()
+                        .HasColumnType("varchar(250) CHARACTER SET utf8mb4")
+                        .HasMaxLength(250);
+
+                    b.Property<string>("Value")
+                        .IsRequired()
+                        .HasColumnType("varchar(2000) CHARACTER SET utf8mb4")
+                        .HasMaxLength(2000);
+
+                    b.HasKey("Id");
+
+                    b.HasIndex("IdentityResourceId");
+
+                    b.ToTable("IdentityResourceProperties");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceClaim", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
+                        .WithMany("UserClaims")
+                        .HasForeignKey("ApiResourceId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceProperty", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
+                        .WithMany("Properties")
+                        .HasForeignKey("ApiResourceId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceScope", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
+                        .WithMany("Scopes")
+                        .HasForeignKey("ApiResourceId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiResourceSecret", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.ApiResource", "ApiResource")
+                        .WithMany("Secrets")
+                        .HasForeignKey("ApiResourceId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeClaim", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope")
+                        .WithMany("UserClaims")
+                        .HasForeignKey("ScopeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ApiScopeProperty", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.ApiScope", "Scope")
+                        .WithMany("Properties")
+                        .HasForeignKey("ScopeId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientClaim", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("Claims")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientCorsOrigin", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("AllowedCorsOrigins")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientGrantType", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("AllowedGrantTypes")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientIdPRestriction", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("IdentityProviderRestrictions")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientPostLogoutRedirectUri", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("PostLogoutRedirectUris")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientProperty", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("Properties")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientRedirectUri", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("RedirectUris")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientScope", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("AllowedScopes")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.ClientSecret", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.Client", "Client")
+                        .WithMany("ClientSecrets")
+                        .HasForeignKey("ClientId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceClaim", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource")
+                        .WithMany("UserClaims")
+                        .HasForeignKey("IdentityResourceId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.IdentityResourceProperty", b =>
+                {
+                    b.HasOne("IdentityServer4.EntityFramework.Entities.IdentityResource", "IdentityResource")
+                        .WithMany("Properties")
+                        .HasForeignKey("IdentityResourceId")
+                        .OnDelete(DeleteBehavior.Cascade)
+                        .IsRequired();
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}

+ 127 - 0
backend/AuthCenter/AuthCenter/Migrations/IdentityServer/PersistedGrantDb/20210729013922_InitialPersistedGrantDb.Designer.cs

@@ -0,0 +1,127 @@
+// <auto-generated />
+using System;
+using IdentityServer4.EntityFramework.DbContexts;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Migrations;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace AuthCenter.Migrations.IdentityServer.PersistedGrantDb
+{
+    [DbContext(typeof(PersistedGrantDbContext))]
+    [Migration("20210729013922_InitialPersistedGrantDb")]
+    partial class InitialPersistedGrantDb
+    {
+        protected override void BuildTargetModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("ProductVersion", "3.1.17")
+                .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b =>
+                {
+                    b.Property<string>("UserCode")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("ClientId")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<DateTime>("CreationTime")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Data")
+                        .IsRequired()
+                        .HasColumnType("longtext CHARACTER SET utf8mb4")
+                        .HasMaxLength(50000);
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("DeviceCode")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<DateTime?>("Expiration")
+                        .IsRequired()
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("SessionId")
+                        .HasColumnType("varchar(100) CHARACTER SET utf8mb4")
+                        .HasMaxLength(100);
+
+                    b.Property<string>("SubjectId")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.HasKey("UserCode");
+
+                    b.HasIndex("DeviceCode")
+                        .IsUnique();
+
+                    b.HasIndex("Expiration");
+
+                    b.ToTable("DeviceCodes");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b =>
+                {
+                    b.Property<string>("Key")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("ClientId")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<DateTime?>("ConsumedTime")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<DateTime>("CreationTime")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Data")
+                        .IsRequired()
+                        .HasColumnType("longtext CHARACTER SET utf8mb4")
+                        .HasMaxLength(50000);
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<DateTime?>("Expiration")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("SessionId")
+                        .HasColumnType("varchar(100) CHARACTER SET utf8mb4")
+                        .HasMaxLength(100);
+
+                    b.Property<string>("SubjectId")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("varchar(50) CHARACTER SET utf8mb4")
+                        .HasMaxLength(50);
+
+                    b.HasKey("Key");
+
+                    b.HasIndex("Expiration");
+
+                    b.HasIndex("SubjectId", "ClientId", "Type");
+
+                    b.HasIndex("SubjectId", "SessionId", "Type");
+
+                    b.ToTable("PersistedGrants");
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}

+ 85 - 0
backend/AuthCenter/AuthCenter/Migrations/IdentityServer/PersistedGrantDb/20210729013922_InitialPersistedGrantDb.cs

@@ -0,0 +1,85 @@
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
+
+namespace AuthCenter.Migrations.IdentityServer.PersistedGrantDb
+{
+    public partial class InitialPersistedGrantDb : Migration
+    {
+        protected override void Up(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.CreateTable(
+                name: "DeviceCodes",
+                columns: table => new
+                {
+                    UserCode = table.Column<string>(maxLength: 200, nullable: false),
+                    DeviceCode = table.Column<string>(maxLength: 200, nullable: false),
+                    SubjectId = table.Column<string>(maxLength: 200, nullable: true),
+                    SessionId = table.Column<string>(maxLength: 100, nullable: true),
+                    ClientId = table.Column<string>(maxLength: 200, nullable: false),
+                    Description = table.Column<string>(maxLength: 200, nullable: true),
+                    CreationTime = table.Column<DateTime>(nullable: false),
+                    Expiration = table.Column<DateTime>(nullable: false),
+                    Data = table.Column<string>(maxLength: 50000, nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_DeviceCodes", x => x.UserCode);
+                });
+
+            migrationBuilder.CreateTable(
+                name: "PersistedGrants",
+                columns: table => new
+                {
+                    Key = table.Column<string>(maxLength: 200, nullable: false),
+                    Type = table.Column<string>(maxLength: 50, nullable: false),
+                    SubjectId = table.Column<string>(maxLength: 200, nullable: true),
+                    SessionId = table.Column<string>(maxLength: 100, nullable: true),
+                    ClientId = table.Column<string>(maxLength: 200, nullable: false),
+                    Description = table.Column<string>(maxLength: 200, nullable: true),
+                    CreationTime = table.Column<DateTime>(nullable: false),
+                    Expiration = table.Column<DateTime>(nullable: true),
+                    ConsumedTime = table.Column<DateTime>(nullable: true),
+                    Data = table.Column<string>(maxLength: 50000, nullable: false)
+                },
+                constraints: table =>
+                {
+                    table.PrimaryKey("PK_PersistedGrants", x => x.Key);
+                });
+
+            migrationBuilder.CreateIndex(
+                name: "IX_DeviceCodes_DeviceCode",
+                table: "DeviceCodes",
+                column: "DeviceCode",
+                unique: true);
+
+            migrationBuilder.CreateIndex(
+                name: "IX_DeviceCodes_Expiration",
+                table: "DeviceCodes",
+                column: "Expiration");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_PersistedGrants_Expiration",
+                table: "PersistedGrants",
+                column: "Expiration");
+
+            migrationBuilder.CreateIndex(
+                name: "IX_PersistedGrants_SubjectId_ClientId_Type",
+                table: "PersistedGrants",
+                columns: new[] { "SubjectId", "ClientId", "Type" });
+
+            migrationBuilder.CreateIndex(
+                name: "IX_PersistedGrants_SubjectId_SessionId_Type",
+                table: "PersistedGrants",
+                columns: new[] { "SubjectId", "SessionId", "Type" });
+        }
+
+        protected override void Down(MigrationBuilder migrationBuilder)
+        {
+            migrationBuilder.DropTable(
+                name: "DeviceCodes");
+
+            migrationBuilder.DropTable(
+                name: "PersistedGrants");
+        }
+    }
+}

+ 125 - 0
backend/AuthCenter/AuthCenter/Migrations/IdentityServer/PersistedGrantDb/PersistedGrantDbContextModelSnapshot.cs

@@ -0,0 +1,125 @@
+// <auto-generated />
+using System;
+using IdentityServer4.EntityFramework.DbContexts;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.EntityFrameworkCore.Infrastructure;
+using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
+
+namespace AuthCenter.Migrations.IdentityServer.PersistedGrantDb
+{
+    [DbContext(typeof(PersistedGrantDbContext))]
+    partial class PersistedGrantDbContextModelSnapshot : ModelSnapshot
+    {
+        protected override void BuildModel(ModelBuilder modelBuilder)
+        {
+#pragma warning disable 612, 618
+            modelBuilder
+                .HasAnnotation("ProductVersion", "3.1.17")
+                .HasAnnotation("Relational:MaxIdentifierLength", 64);
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.DeviceFlowCodes", b =>
+                {
+                    b.Property<string>("UserCode")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("ClientId")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<DateTime>("CreationTime")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Data")
+                        .IsRequired()
+                        .HasColumnType("longtext CHARACTER SET utf8mb4")
+                        .HasMaxLength(50000);
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("DeviceCode")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<DateTime?>("Expiration")
+                        .IsRequired()
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("SessionId")
+                        .HasColumnType("varchar(100) CHARACTER SET utf8mb4")
+                        .HasMaxLength(100);
+
+                    b.Property<string>("SubjectId")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.HasKey("UserCode");
+
+                    b.HasIndex("DeviceCode")
+                        .IsUnique();
+
+                    b.HasIndex("Expiration");
+
+                    b.ToTable("DeviceCodes");
+                });
+
+            modelBuilder.Entity("IdentityServer4.EntityFramework.Entities.PersistedGrant", b =>
+                {
+                    b.Property<string>("Key")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("ClientId")
+                        .IsRequired()
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<DateTime?>("ConsumedTime")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<DateTime>("CreationTime")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("Data")
+                        .IsRequired()
+                        .HasColumnType("longtext CHARACTER SET utf8mb4")
+                        .HasMaxLength(50000);
+
+                    b.Property<string>("Description")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<DateTime?>("Expiration")
+                        .HasColumnType("datetime(6)");
+
+                    b.Property<string>("SessionId")
+                        .HasColumnType("varchar(100) CHARACTER SET utf8mb4")
+                        .HasMaxLength(100);
+
+                    b.Property<string>("SubjectId")
+                        .HasColumnType("varchar(200) CHARACTER SET utf8mb4")
+                        .HasMaxLength(200);
+
+                    b.Property<string>("Type")
+                        .IsRequired()
+                        .HasColumnType("varchar(50) CHARACTER SET utf8mb4")
+                        .HasMaxLength(50);
+
+                    b.HasKey("Key");
+
+                    b.HasIndex("Expiration");
+
+                    b.HasIndex("SubjectId", "ClientId", "Type");
+
+                    b.HasIndex("SubjectId", "SessionId", "Type");
+
+                    b.ToTable("PersistedGrants");
+                });
+#pragma warning restore 612, 618
+        }
+    }
+}

+ 58 - 0
backend/AuthCenter/AuthCenter/NLog.config

@@ -0,0 +1,58 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<nlog xmlns="http://www.nlog-project.org/schemas/NLog.xsd"
+      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+      xsi:schemaLocation="http://www.nlog-project.org/schemas/NLog.xsd NLog.xsd"
+      autoReload="true"
+      throwExceptions="false"
+      internalLogLevel="Warn"
+      internalLogFile="Logs/nlog-internal.log">
+
+  <!--internalLogLevel="Off"-->
+  <!-- optional, add some variables
+  https://github.com/nlog/NLog/wiki/Configuration-file#variables
+  -->
+  <variable name="myvar" value="myvalue"/>
+
+  <!--
+  See https://github.com/nlog/nlog/wiki/Configuration-file
+  for information on customizing logging rules and outputs.
+   -->
+  <targets>
+
+    <!--
+    add your targets here
+    See https://github.com/nlog/NLog/wiki/Targets for possible targets.
+    See https://github.com/nlog/NLog/wiki/Layout-Renderers for the possible layout renderers.
+    -->
+
+    <!--
+    Write events to a file with the date in the filename.
+    <target xsi:type="File" name="f" fileName="${basedir}/logs/${shortdate}.log"
+            layout="${longdate} ${uppercase:${level}} ${message}" />
+    -->
+
+    <!-- write logs to file -->
+    <target xsi:type="File" name="allfile" fileName="logs/${date:format=yyyy-MM-dd}/log.txt"
+             layout="------------------------------------------${newline}${longdate} | ${uppercase:${level}} | ${logger} ${newline}${message} ${exception} ${newline} | url: ${aspnet-request-url} | action: ${aspnet-mvc-action}" />
+
+    <target xsi:type="Null" name="blackhole" />
+
+  </targets>
+  <rules>
+    <!-- add your logging rules here -->
+
+    <!--
+    Write all events with minimal level of Debug (So Debug, Info, Warn, Error and Fatal, but not Trace)  to "f"
+    <logger name="*" minlevel="Debug" writeTo="f" />
+    -->
+
+    <!--All logs, including from Microsoft-->
+    <!--minlevel 改为Trace 跟踪全部 Error 只捕获异常-->
+    <logger name="*" minlevel="Error" maxlevel="Fatal" writeTo="allfile" />
+
+    <!--Skip Microsoft logs and so log only own logs-->
+    <logger name="Microsoft.*" minlevel="Trace" writeTo="blackhole" final="true" />
+    <!--<logger name="*" minlevel="Trace" writeTo="ownFile-web" />-->
+
+  </rules>
+</nlog>

+ 37 - 0
backend/AuthCenter/AuthCenter/Program.cs

@@ -0,0 +1,37 @@
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Logging;
+using NLog.Web;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace AuthCenter
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            CreateHostBuilder(args).Build().Run();
+        }
+
+        public static IHostBuilder CreateHostBuilder(string[] args) =>
+            Host.CreateDefaultBuilder(args)
+            .UseNLog()
+                .ConfigureWebHostDefaults(webBuilder =>
+                {
+                    webBuilder.UseStartup<Startup>();
+                    webBuilder.UseKestrel(options =>
+                    {
+                        var builder = new ConfigurationBuilder().AddJsonFile("appsettings.json");
+                        var configuration = builder.Build();
+                        int port = Convert.ToInt32(configuration["ListenPort"]);
+                        options.Limits.MaxRequestBodySize = null;
+                        options.ListenLocalhost(port);
+                    });
+                    webBuilder.UseIIS();
+                });
+    }
+}

+ 21 - 0
backend/AuthCenter/AuthCenter/Properties/PublishProfiles/FolderProfile.pubxml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+https://go.microsoft.com/fwlink/?LinkID=208121. 
+-->
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <DeleteExistingFiles>True</DeleteExistingFiles>
+    <ExcludeApp_Data>False</ExcludeApp_Data>
+    <LaunchSiteAfterPublish>True</LaunchSiteAfterPublish>
+    <LastUsedBuildConfiguration>Release</LastUsedBuildConfiguration>
+    <LastUsedPlatform>Any CPU</LastUsedPlatform>
+    <PublishProvider>FileSystem</PublishProvider>
+    <PublishUrl>D:\Projects\Publish\AuthCenter</PublishUrl>
+    <WebPublishMethod>FileSystem</WebPublishMethod>
+    <SiteUrlToLaunchAfterPublish />
+    <TargetFramework>netcoreapp3.1</TargetFramework>
+    <RuntimeIdentifier>win-x64</RuntimeIdentifier>
+    <ProjectGuid>aa098788-973d-4083-bbc4-1631d969c61c</ProjectGuid>
+    <SelfContained>false</SelfContained>
+  </PropertyGroup>
+</Project>

+ 27 - 0
backend/AuthCenter/AuthCenter/Properties/launchSettings.json

@@ -0,0 +1,27 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:5666",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "AuthCenter": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      },
+      "applicationUrl": "http://localhost:5000"
+    }
+  }
+}

+ 50 - 0
backend/AuthCenter/AuthCenter/Services/CustomProfileService.cs

@@ -0,0 +1,50 @@
+using AuthorizeCenter.Services;
+using IdentityServer4.Extensions;
+using IdentityServer4.Models;
+using IdentityServer4.Services;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Security.Claims;
+
+namespace AuthCenter.Services
+{
+    public class CustomProfileService : IProfileService
+    {
+        public AccountService AccountService { get; set; }
+        public CustomProfileService(AccountService accountService)
+        {
+            AccountService = accountService;
+        }
+
+        public virtual Task GetProfileDataAsync(ProfileDataRequestContext context)
+        {
+            var claims = context.Subject.Claims.ToList();
+            // 自定义验证
+            if (claims.Any(c => c.Type == "realName"))
+            {
+                // 设置返回的claims的值
+                context.IssuedClaims = claims.ToList();
+                return Task.CompletedTask;
+            }
+
+            var userId = context.Subject.GetSubjectId();
+            // 通过 用户id 找到用户
+            var user = AccountService.GetById(userId);
+            if (user != null)
+            {
+                context.IssuedClaims.Add(new Claim("account", user.FCode));
+                context.IssuedClaims.Add(new Claim("realName", user.FName));
+                context.IssuedClaims.Add(new Claim("isSA", user.IsSA.ToString()));
+            }
+            return Task.CompletedTask;
+        }
+
+        public async Task IsActiveAsync(IsActiveContext context)
+        {
+            context.IsActive = true;
+            await Task.CompletedTask;
+        }
+    }
+}

+ 39 - 0
backend/AuthCenter/AuthCenter/Services/DiscoGenerator.cs

@@ -0,0 +1,39 @@
+using Cksoft.Unity;
+using IdentityModel.Client;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Net.Http;
+using System.Threading.Tasks;
+
+namespace AuthCenter.Services
+{
+    public class DiscoGenerator
+    {
+        public static async Task<(DiscoveryDocumentResponse, HttpClient)> GenerateDiscoryDocumentResponse()
+        {
+            var handler = new HttpClientHandler();
+            handler.ClientCertificateOptions = ClientCertificateOption.Manual;
+            handler.ServerCertificateCustomValidationCallback =
+                (httpRequestMessage, cert, certChain, policyErrors) =>
+                {
+                    return true;
+                };
+            var client = new HttpClient(handler);
+            var discoRequest = new DiscoveryDocumentRequest()
+            {
+                Policy = new DiscoveryPolicy
+                {
+                    RequireHttps = false,
+                },
+                Address = AppConfigurtaionServices.Configuration["Id4:Authority"]
+            };
+            var disco = await client.GetDiscoveryDocumentAsync(discoRequest);
+            if (disco.IsError)
+            {
+                return (null, null);
+            }
+            return (disco, client);
+        }
+    }
+}

+ 44 - 0
backend/AuthCenter/AuthCenter/Services/EapExtensionValidator.cs

@@ -0,0 +1,44 @@
+using AuthorizeCenter.Services;
+using IdentityModel;
+using IdentityServer4.Models;
+using IdentityServer4.Validation;
+using Microsoft.AspNetCore.Http;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Security.Claims;
+using System.Threading.Tasks;
+
+namespace AuthCenter.Services
+{
+    public class EapExtensionValidator : IExtensionGrantValidator
+    {
+        public AccountService AccountService { get; set; }
+
+        public string GrantType => "eap.auth";
+
+        public EapExtensionValidator(AccountService accountService)
+        {
+            AccountService = accountService;
+        }
+
+        public Task ValidateAsync(ExtensionGrantValidationContext context)
+        {
+            var userId = context.Request.Raw["userId"];
+            var staff = AccountService.GetById(userId);
+            //if (AccountService.Login(staff, ref errorinfo) != null)
+            //{
+            context.Result = new GrantValidationResult(
+                subject: staff.FCode,
+                authenticationMethod: OidcConstants.AuthenticationMethods.Password,
+                claims: new List<Claim>
+                {
+                        new Claim("account",staff.FCode),
+                        new Claim("realName",staff.FName),
+                        new Claim("isSA",staff.IsSA.ToString())
+                });
+           
+            return Task.CompletedTask;
+        }
+    }
+}

+ 77 - 0
backend/AuthCenter/AuthCenter/Services/SeedData.cs

@@ -0,0 +1,77 @@
+using AuthCenter.AuthConfig;
+using IdentityServer4.EntityFramework.DbContexts;
+using IdentityServer4.EntityFramework.Interfaces;
+using IdentityServer4.EntityFramework.Mappers;
+using IdentityServer4.EntityFramework.Storage;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Reflection;
+using System.Threading.Tasks;
+
+namespace AuthCenter.Services
+{
+    public class SeedData
+    {
+        public static void InitData(IApplicationBuilder serviceProvider)
+        {
+            Console.WriteLine("开始创建初始化数据...");
+            using (var scope = serviceProvider.ApplicationServices.CreateScope())
+            {
+                scope.ServiceProvider.GetRequiredService<PersistedGrantDbContext>().Database.Migrate();
+                {
+                    var context = scope.ServiceProvider.GetRequiredService<ConfigurationDbContext>();
+                    context.Database.Migrate();
+                    EnsureSeedData(context);
+                }
+            }
+            Console.WriteLine("初始化数据创建完成.");
+        }
+
+        private static void EnsureSeedData(ConfigurationDbContext context)
+        {
+            if (!context.Clients.Any())
+            {
+                Console.WriteLine("Clients 正在初始化");
+                foreach (var client in Config.GetClients())
+                {
+                    context.Clients.Add(client.ToEntity());
+                }
+                context.SaveChanges();
+            }
+
+            if (!context.IdentityResources.Any())
+            {
+                Console.WriteLine("IdentityResources 正在初始化");
+                foreach (var resource in Config.GetIdentityResources())
+                {
+                    context.IdentityResources.Add(resource.ToEntity());
+                }
+                context.SaveChanges();
+            }
+
+            if (!context.ApiResources.Any())
+            {
+                Console.WriteLine("ApiResources 正在初始化");
+                foreach (var resource in Config.GetApiResources())
+                {
+                    context.ApiResources.Add(resource.ToEntity());
+                }
+                context.SaveChanges();
+            }
+
+            if (!context.ApiScopes.Any())
+            {
+                Console.WriteLine("ApiScopes 正在初始化");
+                foreach (var resource in Config.GetApiScopes())
+                {
+                    context.ApiScopes.Add(resource.ToEntity());
+                }
+                context.SaveChanges();
+            }
+        }
+    }
+}

+ 186 - 0
backend/AuthCenter/AuthCenter/Startup.cs

@@ -0,0 +1,186 @@
+using AuthCenter.AuthConfig;
+using AuthCenter.Filters;
+using AuthCenter.Services;
+using AuthorizeCenter.Services;
+using Cksoft.Unity;
+using IdentityModel.Client;
+using IdentityServer4.Extensions;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.HttpOverrides;
+using Microsoft.EntityFrameworkCore;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Microsoft.Extensions.Options;
+using System;
+using System.IdentityModel.Tokens.Jwt;
+using System.IO;
+using System.Reflection;
+using System.Security.Cryptography.X509Certificates;
+using System.Threading.Tasks;
+
+namespace AuthCenter
+{
+    public class Startup
+    {
+        readonly string corsPolicy = "Allow_Cors";
+        public IConfiguration Configuration { get; set; }
+        public bool EnableDatabase { get; set; }
+        public IWebHostEnvironment WebHostEnvironment { get; set; }
+        public Startup(IConfiguration configuration, IWebHostEnvironment webHostEnvironment)
+        {
+            Configuration = configuration;
+            WebHostEnvironment = webHostEnvironment;
+            EnableDatabase = Convert.ToBoolean(Configuration["EnableDatabase"] == null ? "false" : Configuration["EnableDatabase"]);
+        }
+        public void ConfigureServices(IServiceCollection services)
+        {
+            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
+            services.AddCors(options =>
+            {
+                options.AddPolicy(corsPolicy,
+                    builder => builder.AllowAnyOrigin()
+                    .AllowAnyMethod()
+                    .AllowAnyHeader()
+                    );
+            });
+            services.AddControllersWithViews(opts =>
+            {
+                opts.Filters.Add(typeof(ExceptionFilter));
+            })
+                .AddRazorRuntimeCompilation();
+            services.Configure<ForwardedHeadersOptions>(options =>
+            {
+                options.ForwardedHeaders =
+                    ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
+            });
+
+            services.Configure<CookiePolicyOptions>(options =>
+            {
+                options.MinimumSameSitePolicy = SameSiteMode.Strict;
+                //options.OnAppendCookie = cookieContext =>
+                //    cookieContext.CookieOptions.SameSite = SameSiteMode.Lax;
+                //options.OnDeleteCookie = cookieContext =>
+                //    cookieContext.CookieOptions.SameSite = SameSiteMode.Lax;
+            });
+
+            //services.AddTransient(sp => sp.GetRequiredService<IOptions<TokenClientOptions>>().Value);
+
+            //services.AddHttpClient<TokenClient>();
+
+            //services.AddHttpClient("auth2Client", configureClient: client =>
+            //{
+            //    client.BaseAddress = new Uri(Configuration["Id4:Authority"]);
+            //});
+
+            // 是否将id$配置持久化到数据库
+
+            if (EnableDatabase)
+            {
+                var connectionString = Configuration.GetConnectionString("id4");
+                string migrationsAssembly = Assembly.GetEntryAssembly().GetName().Name;
+                services.AddIdentityServer(opts =>
+                {
+                    opts.UserInteraction.LoginUrl = "/account/login";
+                    opts.UserInteraction.LogoutUrl = "/account/logout";
+                    opts.Events.RaiseErrorEvents = true;
+                    opts.Events.RaiseInformationEvents = true;
+                    opts.Events.RaiseFailureEvents = true;
+                    opts.Events.RaiseSuccessEvents = true;
+                    opts.UserInteraction.ErrorUrl = "/account/error";
+                })
+                        .AddDeveloperSigningCredential()
+                        .AddConfigurationStore(options =>
+                {
+                    options.ConfigureDbContext = builder =>
+                    {
+                        builder.UseMySql(connectionString, sql => sql.MigrationsAssembly("AuthCenter"));
+                    };
+                })
+                        .AddOperationalStore(options =>
+                {
+                    options.ConfigureDbContext = builder =>
+                    {
+                        builder.UseMySql(connectionString, sql => sql.MigrationsAssembly("AuthCenter"));
+                    };
+                    options.EnableTokenCleanup = true;
+                    ////token自动清理间隔:默认1H
+                    options.TokenCleanupInterval = 3600;
+                    ////token自动清理每次数量
+                    options.TokenCleanupBatchSize = 100;
+                })
+                        .AddProfileService<CustomProfileService>(); ;
+            }
+            else
+            {
+                services.AddIdentityServer(opts =>
+                {
+                    opts.UserInteraction.LoginUrl = "/account/login";
+                    opts.UserInteraction.ErrorUrl = "/account/error";
+                })
+                .AddDeveloperSigningCredential()
+                .AddInMemoryApiResources(Config.GetApiResources())
+                //4.0版本需要添加,不然调用时提示invalid_scope错误
+                .AddInMemoryApiScopes(Config.GetApiScopes())
+                .AddInMemoryIdentityResources(Config.GetIdentityResources())
+                .AddInMemoryClients(Config.GetClients())
+                .AddExtensionGrantValidator<EapExtensionValidator>()
+                .AddProfileService<CustomProfileService>();
+            }
+            services.AddTransient<AccountService>();
+        }
+
+        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+        public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
+        {
+            NLog.ILogger logger = NLog.LogManager.LoadConfiguration("NLog.config").GetCurrentClassLogger();
+            AppConfigurtaionServices.Configuration = Configuration;
+            // 初始化Id4数据
+            if (EnableDatabase)
+            {
+                SeedData.InitData(app);
+            }
+            if (env.IsDevelopment())
+            {
+                app.UseDeveloperExceptionPage();
+            }
+            else
+            {
+                app.UseHsts();
+            }
+            logger.Info("服务启动成功。");
+            app.UseRouting();
+            app.UseStaticFiles();
+
+            app.UseForwardedHeaders();
+            app.UseCookiePolicy();
+
+            app.UseIdentityServer();
+
+            app.Use(async (ctx, next) =>
+            {
+                ctx.SetIdentityServerOrigin(Configuration["Id4:Authority"]);
+                await next();
+            });
+
+            app.UseCors(corsPolicy);
+
+            app.UseAuthentication();
+            app.UseAuthorization();
+
+            app.UseEndpoints(endpoints =>
+            {
+                endpoints.Map("/", context =>
+                {
+                    context.Response.Redirect("/Home/Index");
+                    return Task.CompletedTask;
+                });
+                endpoints.MapControllerRoute(
+                        name: "default",
+                        pattern: "{controller=Home}/{action=Index}/{id?}");
+            });
+        }
+    }
+}

+ 15 - 0
backend/AuthCenter/AuthCenter/Views/Account/Error.cshtml

@@ -0,0 +1,15 @@
+@model IdentityServer4.Models.ErrorMessage
+@{
+    Layout = null;
+}
+
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+    <title>请求错误</title>
+</head>
+<body>
+    <h4>@Model.Error</h4>
+    <p>@Model.ClientId</p>
+    <p>@Model.ErrorDescription</p>
+</body>
+</html>

+ 207 - 0
backend/AuthCenter/AuthCenter/Views/Account/Login.cshtml

@@ -0,0 +1,207 @@
+@model DllUfpEntity.Dto.AppInfoDto
+@{
+    Layout = null;
+}
+
+<!DOCTYPE html>
+
+<html>
+<head>
+    <meta name="viewport" content="width=device-width" />
+    <title>@Model.AppName 登录中心</title>
+    <link rel="stylesheet" href="~/css/login.css" />
+    <script src="~/js/lib/vue.min.js"></script>
+    <script src="~/js/lib/axios.js"></script>
+    <!-- 引入样式 -->
+    <link rel="stylesheet" href="~/js/lib/element-ui/index.css">
+    <!-- 引入组件库 -->
+    <script src="~/js/lib/element-ui/index.js"></script>
+</head>
+<body>
+    <div class="container">
+        <div class="logo">
+            <img src="@Model.Logo" style="width: 100%; height: 100%;" alt="@Model.CompanyName" />
+        </div>
+        <div class="app-name">@Model.AppName</div>
+        <div class="login_box">
+            <div class="login-form">
+                <div class="login">
+                    <div class="login_name">
+                        <p>欢迎登录</p>
+                    </div>
+                    <form action="/Account/Login" method="post">
+                        <el-form ref="loginForm"
+                                 :model="loginForm"
+                                 :rules="loginRules">
+                            <el-form-item prop="userName">
+                                <el-input ref="userName"
+                                          v-model="loginForm.userName"
+                                          :size="size"
+                                          placeholder="用户名"
+                                          name="userName"
+                                          type="text">
+                                    <i slot="prefix" class="el-input__icon el-icon-user"></i>
+                                </el-input>
+                            </el-form-item>
+
+                            <el-form-item prop="password">
+                                <el-input :key="passwordType"
+                                          ref="password"
+                                          v-model="loginForm.password"
+                                          :size="size"
+                                          :type="passwordType"
+                                          placeholder="密码"
+                                          name="password"
+                                          v-on:keyup.enter.native="handleLogin">
+                                    <i slot="prefix" class="el-input__icon el-icon-lock"></i>
+                                    <i slot="sufix" v-on:click="showPwd" :class="['el-input__icon',passwordType === 'password' ? 'el-icon-eye' : 'el-icon-eye-open']"></i>
+                                </el-input>
+                            </el-form-item>
+
+                            <el-row :gutter="0" class="rememberMebar">
+                                <el-col :span="12" style="text-align:left;">
+                                    <el-checkbox v-model="loginForm.rememberMe" :size="size">记住我</el-checkbox>
+                                </el-col>
+                                <el-col :span="12" style="text-align:right;">
+                                    <el-link :type="'primary'" v-on:click="changePwd()">忘记密码</el-link>
+                                </el-col>
+                            </el-row>
+
+                            <el-button :loading="loading"
+                                       type="primary"
+                                       :size="size"
+                                       style="width: 100%; margin-top: 15px"
+                                       v-on:click.native.prevent="handleLogin">登录</el-button>
+                            <el-alert v-if="errortip" :title="errortip"
+                                      :closable="false"
+                                      type="error"
+                                      show-icon>
+                            </el-alert>
+                        </el-form>
+                        <input type="submit" value="登录" id="loginBtn" style="display:none;" />
+                        @*<input type="hidden" name="account" value="s00001" />
+                            <input type="hidden" name="password" value="123456" />*@
+                        <input type="hidden" name="userSuccessAccount" :value="loginForm.userName" />
+                        <input type="hidden" name="userSuccessPassword" :value="loginForm.password" />
+                        <input type="hidden" name="returnUrl" value="@ViewData["returnUrl"]" />
+                    </form>
+                </div>
+            </div>
+            <div class="slogon">
+                <p v-html="'@Model.Slogan'"></p>
+            </div>
+
+        </div>
+    </div>
+    <script type="text/javascript">
+        var account = '@ViewBag.Account';
+        var password = '@ViewBag.Password';
+        var rememberMe = '@ViewBag.RememberMe';
+        var loginIndex = new Vue({
+            el: ".container",
+            data() {
+                const validateUsername = (rule, value, callback) => {
+                    if (!value || value.length<1) {
+                        callback(new Error('请输入用户名'))
+                    } else {
+                        callback()
+                    }
+                }
+                const validatePassword = (rule, value, callback) => {
+                    if (value.length < 6) {
+                        callback(new Error('请输入正确的密码'))
+                    } else {
+                        callback()
+                    }
+                }
+                return {
+                    loginForm: {
+                        userName: account,
+                        password: password,
+                        rememberMe: rememberMe==="True"
+                    },
+                    loginRules: {
+                        userName: [{ required: true, trigger: 'blur', validator: validateUsername }],
+                        password: [{ required: true, trigger: 'blur', validator: validatePassword }]
+                    },
+                    loading: false,
+                    passwordType: 'password',
+                    errortip: '',
+                    size: window.outerWidth<=1366?'small':'large'
+                }
+            },
+            watch: {},
+            methods: {
+                handleLogin() {
+                    this.$refs.loginForm.validate(valid => {
+                        if (valid) {
+                            this.errortip = null
+                            this.loading = true
+                            @*var dlform = document.createElement('form');
+                            dlform.style = "display:none;";
+                            dlform.method = 'post';
+                            dlform.action = '@Url.Action("Login","Account")';
+                            var userNameInput = document.createElement('input');
+                            userNameInput.type = 'hidden';
+                            userNameInput.name = 'account';
+                            userNameInput.value = this.loginForm.userName;
+                            dlform.appendChild(userNameInput);
+                            var passwordInput = document.createElement('input');
+                            passwordInput.type = 'hidden';
+                            passwordInput.name = 'password';
+                            passwordInput.value = this.loginForm.password;
+                            dlform.appendChild(passwordInput);
+                            var returnUrlInput = document.createElement('input');
+                            returnUrlInput.type = 'hidden';
+                            returnUrlInput.name = 'returnUrl';
+                            returnUrlInput.value = "@ViewData["returnUrl"]";
+                            dlform.appendChild(returnUrlInput);
+                            document.body.appendChild(dlform);
+                            dlform.submit();
+                            document.body.removeChild(dlform);*@
+                            axios({
+                                url: '@Url.Action("CheckAccount", "Account")',
+                                method: 'post',
+                                data: {
+                                    account: this.loginForm.userName,
+                                    password: this.loginForm.password,
+                                    rememberMe: this.loginForm.rememberMe,
+                                    returnUrl: '@ViewData["returnUrl"]'
+                                }
+                            }).then(res => {
+                                const data = res.data;
+                                this.loading = false
+                                if (data.code < 0) {
+                                    this.errortip = data.msg;
+                                } else {
+                                   document.getElementById('loginBtn').click();
+                                }
+
+                            }).catch(() => {
+                                this.$message.error('网络错误,请联系管理员');
+                                this.loading = false
+                            })
+                        } else {
+                            console.log('表单不合法')
+                            return false
+                        }
+                    })
+                },
+                showPwd() {
+                    if (this.passwordType === 'password'){
+                        this.passwordType = ''
+                    } else {
+                        this.passwordType = 'password'
+                    }
+                    this.$nextTick(() => {
+                        this.$refs.password.focus()
+                    })
+                },
+                changePwd() {
+                    this.$message.info('暂不支持密码找回,请联系管理员重置密码');
+                }
+            }
+        });
+    </script>
+</body>
+</html>

+ 40 - 0
backend/AuthCenter/AuthCenter/Views/Home/Error.cshtml

@@ -0,0 +1,40 @@
+@model IdentityServer4.Models.ErrorMessage
+
+@{
+    var error = Model?.Error;
+    var errorDescription = Model?.ErrorDescription;
+    var request_id = Model?.RequestId;
+}
+
+<div class="error-page">
+    <div class="page-header">
+        <h1>Error</h1>
+    </div>
+
+    <div class="row">
+        <div class="col-sm-6">
+            <div class="alert alert-danger">
+                Sorry, there was an error
+
+                @if (error != null)
+                {
+                    <strong>
+                        <em>
+                            : @error
+                        </em>
+                    </strong>
+
+                    if (errorDescription != null)
+                    {
+                        <div>@errorDescription</div>
+                    }
+                }
+            </div>
+
+            @if (request_id != null)
+            {
+                <div class="request-id">Request Id: @request_id</div>
+            }
+        </div>
+    </div>
+</div>

+ 5 - 0
backend/AuthCenter/AuthCenter/Views/Home/Index.cshtml

@@ -0,0 +1,5 @@
+@{ 
+    Layout = null;
+}
+
+<h3>认证中心首页</h3>

+ 9 - 0
backend/AuthCenter/AuthCenter/appsettings.Development.json

@@ -0,0 +1,9 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft": "Warning",
+      "Microsoft.Hosting.Lifetime": "Information"
+    }
+  }
+}

+ 26 - 0
backend/AuthCenter/AuthCenter/appsettings.json

@@ -0,0 +1,26 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information"
+    }
+  },
+  "ListenPort": 5888, // Kestrel监听端口
+  "AllowedHosts": "*",
+  "ConnectionStrings": {
+    "id4": "Server=192.168.0.26;Port=3306;Database=identityserver4test;Uid=root;Pwd=xqrosdb20140715;Charset=utf8;Max Pool Size=100;"
+  },
+  "ufp": {
+    "DbType": "MySql",
+    "ConnectionStrings": "Server=192.168.0.26;Port=3306;Database=ufp;Uid=root;Pwd=xqrosdb20140715;Charset=utf8;Max Pool Size=100;"
+  },
+  "WebConfig": {
+    "CompanyName": "",
+    "Logo": "../images/logo.png",
+    "AppName": "EAP管理系统",
+    "Slogan": ""
+  },
+  "Id4": {
+    "Authority": "http://localhost:5666"
+  },
+  "EnableDatabase": false // 是否引入Id4数据库配置
+}

+ 30 - 0
backend/AuthCenter/AuthCenter/auth.json

@@ -0,0 +1,30 @@
+{
+  "Clients": [
+    {
+      "ClientId": "EAPAPI",
+      "ClientName": "EAPAPI Client",
+      "AccessTokenLifetime": 86400,
+      "RedirectUris": [ "http://localhost:18531" ]
+    },
+    {
+      "ClientId": "EAP",
+      "ClientName": "EAP Client",
+      "AccessTokenLifetime": 86400,
+      "RedirectUris": [ "http://localhost:4200/oauth/callback" ],
+      "PostLogoutRedirectUris": [ "http://localhost:4200" ],
+      "AllowedCorsOrigins": [ "http://localhost:4200" ]
+    },
+    {
+      "ClientId": "Dashboard",
+      "ClientName": "Dashboard Client",
+      "RedirectUris": [ "http://localhost:5500/callback.html", "http://localhost:5500/silentref.html" ],
+      "AllowedCorsOrigins": [ "http://localhost:5500" ]
+    },
+    {
+      "ClientId": "Mobile",
+      "ClientName": "Mobile Client",
+      "ClientSecrets": ["Mobile Secret"],
+      "AllowedCorsOrigins": [ "http://localhost:8100" ]
+    }
+  ]
+}

File diff suppressed because it is too large
+ 1 - 0
backend/AuthCenter/AuthCenter/tempkey.jwk


+ 525 - 0
backend/AuthCenter/AuthCenter/wwwroot/css/login.css

@@ -0,0 +1,525 @@
+*{
+    margin:0;
+    padding:0;
+}
+
+@media screen and (max-width: 1366px) {
+    html {
+        font-size: 13px !important;
+    }
+
+      .el-form-item__error{
+       padding-top:0px !important;
+    }
+         .el-form-item{
+       margin-bottom:18px !important;
+    }
+
+    .container {
+       // min-width: 1266px;
+       // min-height: 708px;
+        width: 100vw - 20px;
+        height: calc(82vh - 4px);
+        background: url(../images/login-bg.jpg) center no-repeat;
+        background-size: 100% 100%;
+        padding-top: 9.39rem;
+    }
+
+    .anticon {
+        color: #fff !important;
+    }
+
+    .ant-form-item label {
+        color: #fff;
+    }
+
+    .slogon {
+        clear: both;
+        float: right;
+        color: #fff;
+        font-size: 22px;
+        font-weight: 600;
+        margin-top: 20px;
+        margin-right: 0px;
+    }
+
+    .logo {
+        width: 110px;
+        height: 40px;
+        position: absolute;
+        left: 50px;
+        top: 50px;
+    }
+
+    .app-name {
+        float: right;
+        font-size: 24px;
+        margin-top: -40px;
+        color: #fff;
+        text-align: center;
+        font-weight: 600;
+        margin-right: 162px;
+        margin-bottom: 16px;
+    }
+
+    img {
+        border: none;
+    }
+
+    .login_box {
+        margin: 20px auto;
+        clear: both;
+        margin-right:50px;
+        margin-top:40px;
+    }
+
+    .login {
+        height: 308px;
+        width: 300px;
+        padding: 20px 50px;
+        color: #fff;
+        background: linear-gradient(to bottom, rgba(24, 121, 191, 0.6), rgba(24, 121, 191, 0.2));
+        border-radius: 6px;
+        margin: 4px;
+        position: relative;
+    }
+
+    .login_logo {
+        width: 120px;
+        height: 120px;
+        // border: 5px solid #93defe;
+        border-radius: 100px;
+        background: #fff;
+        text-align: center;
+        line-height: 110px;
+        position: absolute;
+        top: -60px;
+        right: 140px;
+    }
+
+    .login_name {
+        width: 100%;
+        float: left;
+        text-align: center;
+    }
+
+    .login_name p {
+        width: 100%;
+        text-align: center;
+        font-size: 20px;
+        font-weight: 600;
+        color: #fff;
+        padding: 10px 0 20px;
+    }
+
+    .login_logo img {
+        width: 60px;
+        height: 60px;
+        display: inline-block;
+        vertical-align: middle;
+    }
+
+    .copyright {
+        font-size: 14px;
+        color: #444;
+        display: block;
+        width: 100%;
+        float: left;
+        text-align: center;
+        margin-top: 60px;
+    }
+
+    .error {
+        color: red;
+        margin-bottom: 10px;
+        display: block;
+    }
+
+    .login-form {
+        padding: 10px;
+        // border: 4px solid rgba(1, 255, 255, 0.8);
+       /* width: 340px;
+        height: 290px;*/
+        text-align:center;
+        float: right;
+        clear:both;
+    }
+
+    .login-form-forgot {
+        float: right;
+    }
+
+    .login-form-button {
+        width: 100%;
+    }
+}
+
+@media screen and (min-width: 1920px) {
+    html {
+        font-size: 20px !important;
+    }
+
+      .el-form-item__error{
+       padding-top:5px !important;
+    }
+
+         .el-form-item{
+       margin-bottom:24px !important;
+    }
+
+         .el-form-item__content{
+         font-size:18px !important;
+         }
+
+         .el-checkbox{
+         font-size:18px !important;
+         }
+         .el-checkbox__label{
+         font-size:16px !important;
+         }
+         .el-checkbox__input{
+         margin-bottom:2px;
+         }
+
+         .el-link{
+            font-size:16px !important;
+         }
+
+    .container {
+        min-width: 1920px;
+        min-height: 681px;
+        background: url(../images/login-bg.jpg) center center no-repeat;
+        background-size: 100% 100%;
+        padding-top: 15%;
+        width: 100%;
+        height: 100%;
+    }
+
+    .anticon {
+        color: #fff !important;
+    }
+
+    .ant-form-item label {
+        color: #fff;
+    }
+
+    .slogon {
+        clear: both;
+        float: right;
+        color: #fff;
+        font-size: 25px;
+        font-weight: 600;
+        margin-top: 100px;
+        margin-right: -48px;
+    }
+
+    .logo {
+        width: 180px;
+        height: 70px;
+        position: absolute;
+        left: 80px;
+        top: 80px;
+    }
+
+    .app-name {
+        float: right;
+        font-size: 32px;
+        margin-top: -90px;
+        color: #fff;
+        font-weight: 600;
+        text-align: center;
+        margin-right: 260px;
+        margin-bottom: 60px;
+        width: 345px;
+    }
+
+    img {
+        border: none;
+    }
+
+    .login_box {
+        width: 100%;
+        margin: 0px auto;
+        clear: both;
+        float: right;
+        margin-right: 230px;
+    }
+
+    .login {
+        height: 368px;
+        width: 400px;
+        padding: 20px 50px;
+        color: #fff;
+        background: linear-gradient(to bottom, rgba(24, 121, 191, 0.6), rgba(24, 121, 191, 0.2));
+        border-radius: 6px;
+        margin: 4px;
+        position: relative;
+        // margin-top: 50px;
+    }
+
+    .login_logo {
+        width: 120px;
+        height: 120px;
+        // border: 5px solid #93defe;
+        border-radius: 100px;
+        background: #fff;
+        text-align: center;
+        line-height: 110px;
+        position: absolute;
+        top: -60px;
+        right: 140px;
+    }
+
+    .login_name {
+        width: 100%;
+        float: left;
+        text-align: center;
+    }
+
+    .login_name p {
+        width: 100%;
+        text-align: center;
+        font-size: 24px;
+        font-weight: 600;
+        color: #fff;
+        padding: 10px 0 50px;
+    }
+
+    .login_logo img {
+        width: 60px;
+        height: 60px;
+        display: inline-block;
+        vertical-align: middle;
+    }
+
+    .copyright {
+        font-size: 14px;
+        color: #444;
+        display: block;
+        width: 100%;
+        float: left;
+        text-align: center;
+        margin-top: 60px;
+    }
+
+    .error {
+        color: red;
+        margin-bottom: 10px;
+        display: block;
+    }
+
+    .login-form {
+        padding: 10px;
+        //border: 4px solid rgba(1, 255, 255, 0.8);
+        width: 440px;
+        height: 400px;
+        float: right;
+    }
+
+    .login-form-forgot {
+        float: right;
+    }
+
+    .login-form-button {
+        width: 100%;
+    }
+}
+
+@media screen and (min-width: 1367px) and (max-width: 1919px) {
+    html {
+        font-size: 20px !important;
+    }
+
+    .container {
+        width: 100%;
+        height: 100%;
+        min-width: 1536px;
+        min-height: 700px;
+        background: url(../images/login-bg.jpg) center center no-repeat;
+        background-size: 100% 100%;
+        padding-top: 12.5%;
+    }
+
+    [nz-input] {
+        background-color: rgba(28, 76, 166, 0.1) !important;
+        color: #fff;
+    }
+
+    .anticon {
+        color: #fff !important;
+    }
+
+    .ant-form-item label {
+        color: #fff;
+    }
+
+    .slogon {
+        clear: both;
+        float: right;
+        color: #fff;
+        font-size: 25px;
+        font-weight: 600;
+        margin-top: 60px;
+        margin-right: 0px;
+    }
+
+    .logo {
+        width: 140px;
+        height: 80px;
+        position: absolute;
+        left: 40px;
+        top: 50px;
+    }
+
+    .app-name {
+        float: right;
+        font-size: 28px;
+        margin-top: -100px;
+        color: #fff;
+        font-weight: 600;
+        text-align: center;
+        margin-right: 190px;
+        margin-bottom: 10px;
+        width: 345px;
+    }
+
+    img {
+        border: none;
+    }
+
+    .login_box {
+        width: 100%;
+        margin: 0px auto;
+        clear: both;
+        float: right;
+        margin-right: 130px;
+        margin-top: 0px;
+    }
+
+    .login {
+        height: 368px;
+        width: 400px;
+        padding: 20px 50px;
+        color: #fff;
+        background: linear-gradient(to bottom, rgba(24, 121, 191, 0.6), rgba(24, 121, 191, 0.2));
+        border-radius: 6px;
+        margin: 4px;
+        position: relative;
+        // margin-top: 50px;
+    }
+
+    .login_logo {
+        width: 120px;
+        height: 120px;
+        border: 5px solid #93defe;
+        border-radius: 100px;
+        background: #fff;
+        text-align: center;
+        line-height: 110px;
+        position: absolute;
+        top: -60px;
+        right: 140px;
+    }
+
+    .login_name {
+        width: 100%;
+        float: left;
+        text-align: center;
+    }
+
+    .login_name p {
+        width: 100%;
+        text-align: center;
+        font-size: 20px;
+        font-weight: 600;
+        color: #fff;
+        padding: 10px 0 20px;
+    }
+
+    .login_logo img {
+        width: 60px;
+        height: 60px;
+        display: inline-block;
+        vertical-align: middle;
+    }
+
+    .copyright {
+        font-size: 14px;
+        color: #444;
+        display: block;
+        width: 100%;
+        float: left;
+        text-align: center;
+        margin-top: 60px;
+    }
+
+    .error {
+        color: red;
+        margin-bottom: 10px;
+        display: block;
+    }
+
+    .login-form {
+        padding: 10px;
+        // border: 4px solid rgba(1, 255, 255, 0.8);
+        width: 440px;
+        height: 400px;
+        float: right;
+    }
+
+    .login-form-forgot {
+        float: right;
+    }
+
+    .login-form-button {
+        width: 100%;
+    }
+}
+
+ .el-input {
+    display: inline-block;
+   
+    width: 85%;
+  }
+
+    .el-input--small{
+        font-size:14px !important;
+    }
+
+    .el-input__inner{
+        background-color:unset !important;
+        border-radius:0px !important;
+        color:#fff !important;
+        border:2px solid #fff;
+    } 
+    .el-input__prefix,.el-input__suffix{
+        height:unset !important;
+        color:#fff !important;
+    }
+ 
+    .el-button--primary{
+       background-color:#0070cc !important;
+       border-color:#0070cc !important;
+    }
+
+    .rememberMebar{
+       margin-bottom:10px;
+    }
+
+   .el-checkbox{
+      color:#fff !important;
+   }
+   
+   .el-checkbox__input.is-checked+.el-checkbox__label{
+       color:#fff !important;
+   }
+
+   .el-checkbox__input.is-checked .el-checkbox__inner,.el-checkbox__input.is-indeterminate .el-checkbox__inner{
+       background-color:#0070cc !important;
+       border-color:#0070cc !important;                                          
+   }
+
+   .el-alert{
+     border-radius:0px !important;
+   }
+

BIN
backend/AuthCenter/AuthCenter/wwwroot/images/login-bg.jpg


BIN
backend/AuthCenter/AuthCenter/wwwroot/images/logo.png


File diff suppressed because it is too large
+ 3 - 0
backend/AuthCenter/AuthCenter/wwwroot/js/lib/axios.js


BIN
backend/AuthCenter/AuthCenter/wwwroot/js/lib/element-ui/fonts/element-icons.ttf


BIN
backend/AuthCenter/AuthCenter/wwwroot/js/lib/element-ui/fonts/element-icons.woff


File diff suppressed because it is too large
+ 15520 - 0
backend/AuthCenter/AuthCenter/wwwroot/js/lib/element-ui/index.css


File diff suppressed because it is too large
+ 1 - 0
backend/AuthCenter/AuthCenter/wwwroot/js/lib/element-ui/index.js


File diff suppressed because it is too large
+ 6 - 0
backend/AuthCenter/AuthCenter/wwwroot/js/lib/vue.min.js


+ 133 - 0
backend/AuthCenter/AuthorizeCenter.sln

@@ -0,0 +1,133 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 16
+VisualStudioVersion = 16.0.31205.134
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "UFP", "UFP", "{90D2F3F9-E8F5-4500-BEC2-8B770D9924D9}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "AuthCenter", "AuthCenter\AuthCenter.csproj", "{AA098788-973D-4083-BBC4-1631D969C61C}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DllUfpBll", "..\UFP\DllUfpBll\DllUfpBll.csproj", "{C5A2BA61-5FD2-4EC6-A250-22A9AD1F8A57}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DllUfpDal", "..\UFP\DllUfpDal\DllUfpDal.csproj", "{D03F73D4-1EC6-4453-832D-08AB2302044A}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DllUfpUtil", "..\UFP\DllUfpUtil\DllUfpUtil.csproj", "{76797372-4B3B-43F6-A004-36A2B828F3B0}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DllUfpEntity", "..\UFP\DllUfpEntity\DllUfpEntity.csproj", "{1422EF0B-C968-4D4E-AF68-87009D8785DE}"
+EndProject
+Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "EAP", "EAP", "{906C3591-79AB-4F9C-A894-B769838A74E6}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DllEapEntity", "..\DllEapEntity\DllEapEntity.csproj", "{31395810-7FA3-4490-AB09-36A1F1C95C1F}"
+EndProject
+Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "DllEapCommon", "..\DllEapCommon\DllEapCommon.csproj", "{A806E2FD-3A63-46A6-98F8-F651457D60AF}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Debug|x64 = Debug|x64
+		Debug|x86 = Debug|x86
+		Release|Any CPU = Release|Any CPU
+		Release|x64 = Release|x64
+		Release|x86 = Release|x86
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{AA098788-973D-4083-BBC4-1631D969C61C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AA098788-973D-4083-BBC4-1631D969C61C}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AA098788-973D-4083-BBC4-1631D969C61C}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{AA098788-973D-4083-BBC4-1631D969C61C}.Debug|x64.Build.0 = Debug|Any CPU
+		{AA098788-973D-4083-BBC4-1631D969C61C}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{AA098788-973D-4083-BBC4-1631D969C61C}.Debug|x86.Build.0 = Debug|Any CPU
+		{AA098788-973D-4083-BBC4-1631D969C61C}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AA098788-973D-4083-BBC4-1631D969C61C}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AA098788-973D-4083-BBC4-1631D969C61C}.Release|x64.ActiveCfg = Release|Any CPU
+		{AA098788-973D-4083-BBC4-1631D969C61C}.Release|x64.Build.0 = Release|Any CPU
+		{AA098788-973D-4083-BBC4-1631D969C61C}.Release|x86.ActiveCfg = Release|Any CPU
+		{AA098788-973D-4083-BBC4-1631D969C61C}.Release|x86.Build.0 = Release|Any CPU
+		{C5A2BA61-5FD2-4EC6-A250-22A9AD1F8A57}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{C5A2BA61-5FD2-4EC6-A250-22A9AD1F8A57}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{C5A2BA61-5FD2-4EC6-A250-22A9AD1F8A57}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{C5A2BA61-5FD2-4EC6-A250-22A9AD1F8A57}.Debug|x64.Build.0 = Debug|Any CPU
+		{C5A2BA61-5FD2-4EC6-A250-22A9AD1F8A57}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{C5A2BA61-5FD2-4EC6-A250-22A9AD1F8A57}.Debug|x86.Build.0 = Debug|Any CPU
+		{C5A2BA61-5FD2-4EC6-A250-22A9AD1F8A57}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{C5A2BA61-5FD2-4EC6-A250-22A9AD1F8A57}.Release|Any CPU.Build.0 = Release|Any CPU
+		{C5A2BA61-5FD2-4EC6-A250-22A9AD1F8A57}.Release|x64.ActiveCfg = Release|Any CPU
+		{C5A2BA61-5FD2-4EC6-A250-22A9AD1F8A57}.Release|x64.Build.0 = Release|Any CPU
+		{C5A2BA61-5FD2-4EC6-A250-22A9AD1F8A57}.Release|x86.ActiveCfg = Release|Any CPU
+		{C5A2BA61-5FD2-4EC6-A250-22A9AD1F8A57}.Release|x86.Build.0 = Release|Any CPU
+		{D03F73D4-1EC6-4453-832D-08AB2302044A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{D03F73D4-1EC6-4453-832D-08AB2302044A}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{D03F73D4-1EC6-4453-832D-08AB2302044A}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{D03F73D4-1EC6-4453-832D-08AB2302044A}.Debug|x64.Build.0 = Debug|Any CPU
+		{D03F73D4-1EC6-4453-832D-08AB2302044A}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{D03F73D4-1EC6-4453-832D-08AB2302044A}.Debug|x86.Build.0 = Debug|Any CPU
+		{D03F73D4-1EC6-4453-832D-08AB2302044A}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{D03F73D4-1EC6-4453-832D-08AB2302044A}.Release|Any CPU.Build.0 = Release|Any CPU
+		{D03F73D4-1EC6-4453-832D-08AB2302044A}.Release|x64.ActiveCfg = Release|Any CPU
+		{D03F73D4-1EC6-4453-832D-08AB2302044A}.Release|x64.Build.0 = Release|Any CPU
+		{D03F73D4-1EC6-4453-832D-08AB2302044A}.Release|x86.ActiveCfg = Release|Any CPU
+		{D03F73D4-1EC6-4453-832D-08AB2302044A}.Release|x86.Build.0 = Release|Any CPU
+		{76797372-4B3B-43F6-A004-36A2B828F3B0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{76797372-4B3B-43F6-A004-36A2B828F3B0}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{76797372-4B3B-43F6-A004-36A2B828F3B0}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{76797372-4B3B-43F6-A004-36A2B828F3B0}.Debug|x64.Build.0 = Debug|Any CPU
+		{76797372-4B3B-43F6-A004-36A2B828F3B0}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{76797372-4B3B-43F6-A004-36A2B828F3B0}.Debug|x86.Build.0 = Debug|Any CPU
+		{76797372-4B3B-43F6-A004-36A2B828F3B0}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{76797372-4B3B-43F6-A004-36A2B828F3B0}.Release|Any CPU.Build.0 = Release|Any CPU
+		{76797372-4B3B-43F6-A004-36A2B828F3B0}.Release|x64.ActiveCfg = Release|Any CPU
+		{76797372-4B3B-43F6-A004-36A2B828F3B0}.Release|x64.Build.0 = Release|Any CPU
+		{76797372-4B3B-43F6-A004-36A2B828F3B0}.Release|x86.ActiveCfg = Release|Any CPU
+		{76797372-4B3B-43F6-A004-36A2B828F3B0}.Release|x86.Build.0 = Release|Any CPU
+		{1422EF0B-C968-4D4E-AF68-87009D8785DE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{1422EF0B-C968-4D4E-AF68-87009D8785DE}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{1422EF0B-C968-4D4E-AF68-87009D8785DE}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{1422EF0B-C968-4D4E-AF68-87009D8785DE}.Debug|x64.Build.0 = Debug|Any CPU
+		{1422EF0B-C968-4D4E-AF68-87009D8785DE}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{1422EF0B-C968-4D4E-AF68-87009D8785DE}.Debug|x86.Build.0 = Debug|Any CPU
+		{1422EF0B-C968-4D4E-AF68-87009D8785DE}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{1422EF0B-C968-4D4E-AF68-87009D8785DE}.Release|Any CPU.Build.0 = Release|Any CPU
+		{1422EF0B-C968-4D4E-AF68-87009D8785DE}.Release|x64.ActiveCfg = Release|Any CPU
+		{1422EF0B-C968-4D4E-AF68-87009D8785DE}.Release|x64.Build.0 = Release|Any CPU
+		{1422EF0B-C968-4D4E-AF68-87009D8785DE}.Release|x86.ActiveCfg = Release|Any CPU
+		{1422EF0B-C968-4D4E-AF68-87009D8785DE}.Release|x86.Build.0 = Release|Any CPU
+		{31395810-7FA3-4490-AB09-36A1F1C95C1F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{31395810-7FA3-4490-AB09-36A1F1C95C1F}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{31395810-7FA3-4490-AB09-36A1F1C95C1F}.Debug|x64.ActiveCfg = Debug|x64
+		{31395810-7FA3-4490-AB09-36A1F1C95C1F}.Debug|x64.Build.0 = Debug|x64
+		{31395810-7FA3-4490-AB09-36A1F1C95C1F}.Debug|x86.ActiveCfg = Debug|x86
+		{31395810-7FA3-4490-AB09-36A1F1C95C1F}.Debug|x86.Build.0 = Debug|x86
+		{31395810-7FA3-4490-AB09-36A1F1C95C1F}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{31395810-7FA3-4490-AB09-36A1F1C95C1F}.Release|Any CPU.Build.0 = Release|Any CPU
+		{31395810-7FA3-4490-AB09-36A1F1C95C1F}.Release|x64.ActiveCfg = Release|x64
+		{31395810-7FA3-4490-AB09-36A1F1C95C1F}.Release|x64.Build.0 = Release|x64
+		{31395810-7FA3-4490-AB09-36A1F1C95C1F}.Release|x86.ActiveCfg = Release|x86
+		{31395810-7FA3-4490-AB09-36A1F1C95C1F}.Release|x86.Build.0 = Release|x86
+		{A806E2FD-3A63-46A6-98F8-F651457D60AF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A806E2FD-3A63-46A6-98F8-F651457D60AF}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A806E2FD-3A63-46A6-98F8-F651457D60AF}.Debug|x64.ActiveCfg = Debug|Any CPU
+		{A806E2FD-3A63-46A6-98F8-F651457D60AF}.Debug|x64.Build.0 = Debug|Any CPU
+		{A806E2FD-3A63-46A6-98F8-F651457D60AF}.Debug|x86.ActiveCfg = Debug|Any CPU
+		{A806E2FD-3A63-46A6-98F8-F651457D60AF}.Debug|x86.Build.0 = Debug|Any CPU
+		{A806E2FD-3A63-46A6-98F8-F651457D60AF}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A806E2FD-3A63-46A6-98F8-F651457D60AF}.Release|Any CPU.Build.0 = Release|Any CPU
+		{A806E2FD-3A63-46A6-98F8-F651457D60AF}.Release|x64.ActiveCfg = Release|Any CPU
+		{A806E2FD-3A63-46A6-98F8-F651457D60AF}.Release|x64.Build.0 = Release|Any CPU
+		{A806E2FD-3A63-46A6-98F8-F651457D60AF}.Release|x86.ActiveCfg = Release|Any CPU
+		{A806E2FD-3A63-46A6-98F8-F651457D60AF}.Release|x86.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(NestedProjects) = preSolution
+		{C5A2BA61-5FD2-4EC6-A250-22A9AD1F8A57} = {90D2F3F9-E8F5-4500-BEC2-8B770D9924D9}
+		{D03F73D4-1EC6-4453-832D-08AB2302044A} = {90D2F3F9-E8F5-4500-BEC2-8B770D9924D9}
+		{76797372-4B3B-43F6-A004-36A2B828F3B0} = {90D2F3F9-E8F5-4500-BEC2-8B770D9924D9}
+		{1422EF0B-C968-4D4E-AF68-87009D8785DE} = {90D2F3F9-E8F5-4500-BEC2-8B770D9924D9}
+		{31395810-7FA3-4490-AB09-36A1F1C95C1F} = {906C3591-79AB-4F9C-A894-B769838A74E6}
+		{A806E2FD-3A63-46A6-98F8-F651457D60AF} = {906C3591-79AB-4F9C-A894-B769838A74E6}
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {D5496645-234E-484D-864D-686E2211D332}
+	EndGlobalSection
+EndGlobal

+ 46 - 0
backend/AuthCenter/AuthorizeCenter/AuthConfig/Config.cs

@@ -0,0 +1,46 @@
+using IdentityServer4;
+using IdentityServer4.Models;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace AuthorizeCenter.AuthConfig
+{
+    public class Config
+    {
+        // scopes define the resources in your system
+        public static IEnumerable<IdentityResource> GetIdentityResources()
+        {
+            return new List<IdentityResource>
+            {
+                new IdentityResources.OpenId(),
+                new IdentityResources.Profile(),
+            };
+        }
+
+        // clients want to access resources (aka scopes)
+        public static IEnumerable<Client> GetClients()
+        {
+            return new List<Client>
+            {
+                // OpenID Connect隐式流客户端(MVC)
+                new Client
+                {
+                    ClientId = "EAP",
+                    ClientName = "EAP Web Client",
+                    AllowedGrantTypes = GrantTypes.Implicit,//隐式方式
+                    RequireConsent=false,//如果不需要显示否同意授权 页面 这里就设置为false
+                    RedirectUris = { "http://localhost:5555/signin-oidc" },//登录成功后返回的客户端地址
+                    PostLogoutRedirectUris = { "http://localhost:5555/signout-callback-oidc" },//注销登录后返回的客户端地址
+
+                    AllowedScopes =//下面这两个必须要加吧 不太明白啥意思
+                    {
+                        IdentityServerConstants.StandardScopes.OpenId,
+                        IdentityServerConstants.StandardScopes.Profile
+                    }
+                }
+            };
+        }
+    }
+}

+ 23 - 0
backend/AuthCenter/AuthorizeCenter/AuthorizeCenter.csproj

@@ -0,0 +1,23 @@
+<Project Sdk="Microsoft.NET.Sdk.Web">
+
+  <PropertyGroup>
+    <TargetFramework>netcoreapp2.1</TargetFramework>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <Folder Include="wwwroot\" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <PackageReference Include="IdentityServer4" Version="2.2.0" />
+    <PackageReference Include="Microsoft.AspNetCore.App" />
+  </ItemGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\DataAcc\CkSoft.Data.Repository\CkSoft.Data.Repository.csproj" />
+    <ProjectReference Include="..\..\DataAcc\Cksoft.Data\Cksoft.Data.csproj" />
+    <ProjectReference Include="..\..\DllUfpDal\DllUfpDal.csproj" />
+    <ProjectReference Include="..\..\DllUfpEntity\DllUfpEntity.csproj" />
+  </ItemGroup>
+
+</Project>

+ 58 - 0
backend/AuthCenter/AuthorizeCenter/Controllers/AccountController.cs

@@ -0,0 +1,58 @@
+using AuthorizeCenter.Services;
+using DllUfpEntity;
+using DllUfpEntity.Dto;
+using Microsoft.AspNetCore.Authentication;
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace AuthorizeCenter.Controllers
+{
+    public class AccountController : Controller
+    {
+        public AccountService AccountService { get; set; }
+        public AccountController(AccountService accountService)
+        {
+            AccountService = accountService;
+        }
+        public async Task<IActionResult> Login(string returnUrl = null)
+        {
+            ViewData["ReturnUrl"] = returnUrl;
+            return View();
+        }
+
+        [HttpPost]
+        public async Task<IActionResult> Login(UserLoginDto userLoginDto)
+        {
+            ViewData["ReturnUrl"] = userLoginDto.ReturnUrl;
+            string errorinfo = string.Empty;
+            var res = AccountService.Login(new Staff()
+            {
+                FCode = userLoginDto.Account,
+                Password = userLoginDto.Password
+            }, ref errorinfo);
+            if (res != null)
+            {
+                AuthenticationProperties props = new AuthenticationProperties
+                {
+                    IsPersistent = true,
+                    ExpiresUtc = DateTimeOffset.UtcNow.Add(TimeSpan.FromDays(1))
+                };
+                await HttpContext.SignInAsync(res.ID.ToString(), new System.Security.Claims.ClaimsPrincipal(new BinaryReader(new MemoryStream(Encoding.UTF8.GetBytes(res.FCode)))), props);
+                if (!string.IsNullOrEmpty(userLoginDto.ReturnUrl))
+                {
+                    return Redirect(userLoginDto.ReturnUrl);
+                }
+                return View();
+            }
+            else
+            {
+                return View();
+            }
+        }
+    }
+}

+ 16 - 0
backend/AuthCenter/AuthorizeCenter/Controllers/HomeController.cs

@@ -0,0 +1,16 @@
+using Microsoft.AspNetCore.Mvc;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace AuthorizeCenter.Controllers
+{
+    public class HomeController : Controller
+    {
+        public IActionResult Index()
+        {
+            return View();
+        }
+    }
+}

+ 24 - 0
backend/AuthCenter/AuthorizeCenter/Program.cs

@@ -0,0 +1,24 @@
+using Microsoft.AspNetCore;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.Logging;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace AuthorizeCenter
+{
+    public class Program
+    {
+        public static void Main(string[] args)
+        {
+            CreateWebHostBuilder(args).Build().Run();
+        }
+
+        public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
+            WebHost.CreateDefaultBuilder(args)
+                .UseStartup<Startup>();
+    }
+}

+ 27 - 0
backend/AuthCenter/AuthorizeCenter/Properties/launchSettings.json

@@ -0,0 +1,27 @@
+{
+  "iisSettings": {
+    "windowsAuthentication": false,
+    "anonymousAuthentication": true,
+    "iisExpress": {
+      "applicationUrl": "http://localhost:5666",
+      "sslPort": 0
+    }
+  },
+  "profiles": {
+    "IIS Express": {
+      "commandName": "IISExpress",
+      "launchBrowser": true,
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "AuthorizeCenter": {
+      "commandName": "Project",
+      "launchBrowser": true,
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      },
+      "applicationUrl": "https://localhost:5001;http://localhost:5000"
+    }
+  }
+}

+ 25 - 0
backend/AuthCenter/AuthorizeCenter/Services/AccountService.cs

@@ -0,0 +1,25 @@
+using Cksoft.Data;
+using Cksoft.Data.Repository;
+using DllUfpDal;
+using DllUfpEntity;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace AuthorizeCenter.Services
+{
+    public class AccountService
+    {
+        public IDatabase CurrDb { get; set; }
+        public Staff Login(Staff staff, ref string errorinfo)
+        {
+            using (IDatabase db = DbFactory.Base("ufp"))
+            {
+                var dal = new StaffDal(db);
+                var res = dal.Login(staff, ref errorinfo);
+                return res;
+            }
+        }
+    }
+}

+ 51 - 0
backend/AuthCenter/AuthorizeCenter/Startup.cs

@@ -0,0 +1,51 @@
+using AuthorizeCenter.AuthConfig;
+using AuthorizeCenter.Services;
+using Microsoft.AspNetCore.Builder;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Http;
+using Microsoft.AspNetCore.Mvc;
+using Microsoft.Extensions.DependencyInjection;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+
+namespace AuthorizeCenter
+{
+    public class Startup
+    {
+        // This method gets called by the runtime. Use this method to add services to the container.
+        // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
+        public void ConfigureServices(IServiceCollection services)
+        {
+            services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
+
+            services.AddIdentityServer()  //Ids4服务
+               .AddDeveloperSigningCredential()
+               .AddInMemoryIdentityResources(Config.GetIdentityResources())
+               .AddInMemoryClients(Config.GetClients());//把配置文件的Client配置资源放到内存
+
+            services.AddTransient<AccountService>();
+        }
+
+        // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
+        public void Configure(IApplicationBuilder app, IHostingEnvironment env)
+        {
+            if (env.IsDevelopment())
+            {
+                app.UseDeveloperExceptionPage();
+            }
+
+            app.UseHttpsRedirection();
+            app.UseStaticFiles();
+            app.UseCookiePolicy();
+            app.UseIdentityServer();
+            app.UseMvc(routes =>
+            {
+                routes.MapRoute(
+                    name: "default",
+                    template: "{controller=Home}/{action=Index}/{id?}");
+            });
+        }
+    }
+}

+ 23 - 0
backend/AuthCenter/AuthorizeCenter/Views/Account/Login.cshtml

@@ -0,0 +1,23 @@
+@{
+    Layout = null;
+}
+
+<!DOCTYPE html>
+
+<html>
+<head>
+    <meta name="viewport" content="width=device-width" />
+    <title>Login</title>
+</head>
+<body>
+
+    <div align="center">
+        <h1>统一认证登录中心</h1>
+        <form action="/Account/Login" method="post">
+            用户名:<input type="text" name="userName" /><br />
+            密 码:<input type="password" name="password" /><input type="hidden" name="returnUrl" value="@ViewData["returnUrl"]" /> <br />
+            <input type="submit" value="登录" />
+        </form>
+    </div>
+</body>
+</html>

+ 5 - 0
backend/AuthCenter/AuthorizeCenter/Views/Home/Index.cshtml

@@ -0,0 +1,5 @@
+@{ 
+    Layout = null;
+}
+
+<h3>认证中心首页</h3>

+ 24 - 0
backend/AuthCenter/AuthorizeCenter/appsettings.json

@@ -0,0 +1,24 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Error"
+    }
+  },
+  "ListenPort": 5555, // Kestrel监听端口
+  "AllowedHosts": "*",
+  "ConnectionStrings": {
+    "ufp": "Server=192.168.124.94;Port=3306;Database=ufp;Uid=root;Pwd=ofilmeap;Charset=utf8;"
+  },
+  "ufp": {
+    "DbType": "MySql",
+    "ConnectionStrings": "Server=192.168.124.94;Port=3306;Database=ufp;Uid=root;Pwd=ofilmeap;Charset=utf8;Max Pool Size=100;"
+  },
+  "WebConfig": {
+    "Logo": "assets/images/logo.png",
+    "AppName": "欧菲光EAP管理系统",
+    "Slogan": "一切为了客户 &nbsp;&nbsp; 一切为了胜利&nbsp;&nbsp; 一切为了结果",
+    "Index": "/data-center",
+    "VisitLog": true
+    // "Server": "http://localhost:18531/"
+  }
+}

File diff suppressed because it is too large
+ 1 - 0
backend/AuthCenter/AuthorizeCenter/tempkey.jwk


+ 20 - 0
backend/AutoUpdate/.gitattributes

@@ -0,0 +1,20 @@
+# Auto detect text files and perform LF normalization
+# Custom for Visual Studio
+*.cs     diff=csharp
+*.sln    merge=union
+*.csproj merge=union
+*.vbproj merge=union
+*.fsproj merge=union
+*.dbproj merge=union
+
+# Standard to msysgit
+*.doc	 diff=astextplain
+*.DOC	 diff=astextplain
+*.docx diff=astextplain
+*.DOCX diff=astextplain
+*.dot  diff=astextplain
+*.DOT  diff=astextplain
+*.pdf  diff=astextplain
+*.PDF	 diff=astextplain
+*.rtf	 diff=astextplain
+*.RTF	 diff=astextplain

+ 31 - 0
backend/AutoUpdate/AutoUpdate.sln

@@ -0,0 +1,31 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.27130.2036
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MAutoUpdate", "MAutoUpdate\MAutoUpdate.csproj", "{A41F9740-A368-4F0C-91CE-ACF24D0DCA60}"
+EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MAutoUpdate.Test", "MAutoUpdate.Test\MAutoUpdate.Test.csproj", "{AE611095-8EF9-419C-9D2C-A17373AA6396}"
+EndProject
+Global
+	GlobalSection(SolutionConfigurationPlatforms) = preSolution
+		Debug|Any CPU = Debug|Any CPU
+		Release|Any CPU = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(ProjectConfigurationPlatforms) = postSolution
+		{A41F9740-A368-4F0C-91CE-ACF24D0DCA60}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{A41F9740-A368-4F0C-91CE-ACF24D0DCA60}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{A41F9740-A368-4F0C-91CE-ACF24D0DCA60}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{A41F9740-A368-4F0C-91CE-ACF24D0DCA60}.Release|Any CPU.Build.0 = Release|Any CPU
+		{AE611095-8EF9-419C-9D2C-A17373AA6396}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+		{AE611095-8EF9-419C-9D2C-A17373AA6396}.Debug|Any CPU.Build.0 = Debug|Any CPU
+		{AE611095-8EF9-419C-9D2C-A17373AA6396}.Release|Any CPU.ActiveCfg = Release|Any CPU
+		{AE611095-8EF9-419C-9D2C-A17373AA6396}.Release|Any CPU.Build.0 = Release|Any CPU
+	EndGlobalSection
+	GlobalSection(SolutionProperties) = preSolution
+		HideSolutionNode = FALSE
+	EndGlobalSection
+	GlobalSection(ExtensibilityGlobals) = postSolution
+		SolutionGuid = {559C136B-D826-44B3-8A7D-7A265066C27A}
+	EndGlobalSection
+EndGlobal

+ 47 - 0
backend/AutoUpdate/MAutoUpdate.Test/Form1.Designer.cs

@@ -0,0 +1,47 @@
+namespace MAutoUpdate.Test
+{
+    partial class Form1
+    {
+        /// <summary>
+        /// 必需的设计器变量。
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// 清理所有正在使用的资源。
+        /// </summary>
+        /// <param name="disposing">如果应释放托管资源,为 true;否则为 false。</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows 窗体设计器生成的代码
+
+        /// <summary>
+        /// 设计器支持所需的方法 - 不要修改
+        /// 使用代码编辑器修改此方法的内容。
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.SuspendLayout();
+            // 
+            // Form1
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(566, 321);
+            this.Name = "Form1";
+            this.Text = "Form1";
+            this.ResumeLayout(false);
+
+        }
+
+        #endregion
+    }
+}
+

+ 18 - 0
backend/AutoUpdate/MAutoUpdate.Test/Form1.cs

@@ -0,0 +1,18 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Drawing;
+using System.Text;
+using System.Windows.Forms;
+
+namespace MAutoUpdate.Test
+{
+    public partial class Form1 : Form
+    {
+        public Form1()
+        {
+            InitializeComponent();
+        }
+    }
+}

+ 120 - 0
backend/AutoUpdate/MAutoUpdate.Test/Form1.resx

@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 73 - 0
backend/AutoUpdate/MAutoUpdate.Test/MAutoUpdate.Test.csproj

@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProjectGuid>{AE611095-8EF9-419C-9D2C-A17373AA6396}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <RootNamespace>MAutoUpdate.Test</RootNamespace>
+    <AssemblyName>MAutoUpdate.Test</AssemblyName>
+    <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <PlatformTarget>AnyCPU</PlatformTarget>
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="System" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Deployment" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Form1.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="Form1.Designer.cs">
+      <DependentUpon>Form1.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <EmbeddedResource Include="Form1.resx">
+      <DependentUpon>Form1.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+      <SubType>Designer</SubType>
+    </EmbeddedResource>
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+    </None>
+    <Compile Include="Properties\Settings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Settings.settings</DependentUpon>
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>
+    </Compile>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+</Project>

+ 40 - 0
backend/AutoUpdate/MAutoUpdate.Test/Program.cs

@@ -0,0 +1,40 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Windows.Forms;
+
+namespace MAutoUpdate.Test
+{
+    static class Program
+    {
+        /// <summary>
+        /// 应用程序的主入口点。
+        /// </summary>
+        [STAThread]
+        static void Main()
+        {
+            //启动clickonce
+            //Process.Start("iexplore.exe", "http://192.168.0.45:9923/EapForIdle.application");
+            Process.Start("rundll32.exe", "dfshim.dll,ShOpenVerbApplication " + "http://192.168.0.45:9923/EapForIdle.application");
+            string path = AppDomain.CurrentDomain.BaseDirectory + "MAutoUpdate.exe";
+            //同时启动自动更新程序
+            if (File.Exists(path))
+            {
+                ProcessStartInfo processStartInfo = new ProcessStartInfo()
+                {
+                    FileName = "MAutoUpdate.exe",
+                    Arguments = " MAutoUpdate.Test 1"
+                };
+                Process proc = Process.Start(processStartInfo);
+                if (proc != null)
+                {
+                    proc.WaitForExit();
+                }
+            }
+            Application.EnableVisualStyles();
+            Application.SetCompatibleTextRenderingDefault(false);
+            Application.Run(new Form1());
+        }
+    }
+}

+ 36 - 0
backend/AutoUpdate/MAutoUpdate.Test/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的一般信息由以下
+// 控制。更改这些特性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("MAutoUpdate.Test")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("MAutoUpdate.Test")]
+[assembly: AssemblyCopyright("Copyright ©  2018")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 会使此程序集中的类型
+//对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型
+//请将此类型的 ComVisible 特性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("ae611095-8ef9-419c-9d2c-a17373aa6396")]
+
+// 程序集的版本信息由下列四个值组成: 
+//
+//      主版本
+//      次版本
+//      生成号
+//      修订号
+//
+// 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
+// 方法是按如下所示使用“*”: :
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.0.0.0")]

+ 71 - 0
backend/AutoUpdate/MAutoUpdate.Test/Properties/Resources.Designer.cs

@@ -0,0 +1,71 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     此代码由工具生成。
+//     运行时版本: 4.0.30319.42000
+//
+//     对此文件的更改可能导致不正确的行为,如果
+//     重新生成代码,则所做更改将丢失。
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace MAutoUpdate.Test.Properties
+{
+
+
+    /// <summary>
+    ///   强类型资源类,用于查找本地化字符串等。
+    /// </summary>
+    // 此类是由 StronglyTypedResourceBuilder
+    // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
+    // 若要添加或删除成员,请编辑 .ResX 文件,然后重新运行 ResGen
+    // (以 /str 作为命令选项),或重新生成 VS 项目。
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources
+    {
+
+        private static global::System.Resources.ResourceManager resourceMan;
+
+        private static global::System.Globalization.CultureInfo resourceCulture;
+
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources()
+        {
+        }
+
+        /// <summary>
+        ///   返回此类使用的缓存 ResourceManager 实例。
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager
+        {
+            get
+            {
+                if ((resourceMan == null))
+                {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MAutoUpdate.Test.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+
+        /// <summary>
+        ///   覆盖当前线程的 CurrentUICulture 属性
+        ///   使用此强类型的资源类的资源查找。
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture
+        {
+            get
+            {
+                return resourceCulture;
+            }
+            set
+            {
+                resourceCulture = value;
+            }
+        }
+    }
+}

+ 117 - 0
backend/AutoUpdate/MAutoUpdate.Test/Properties/Resources.resx

@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 30 - 0
backend/AutoUpdate/MAutoUpdate.Test/Properties/Settings.Designer.cs

@@ -0,0 +1,30 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     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.
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace MAutoUpdate.Test.Properties
+{
+
+
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "11.0.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;
+            }
+        }
+    }
+}

+ 7 - 0
backend/AutoUpdate/MAutoUpdate.Test/Properties/Settings.settings

@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
+  <Profiles>
+    <Profile Name="(Default)" />
+  </Profiles>
+  <Settings />
+</SettingsFile>

+ 12 - 0
backend/AutoUpdate/MAutoUpdate/CompareVersion.cs

@@ -0,0 +1,12 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MAutoUpdate
+{
+    public class CompareVersion
+    {
+        public Hashtable Versions { get; set; }
+    }
+}

+ 133 - 0
backend/AutoUpdate/MAutoUpdate/EAPClock.cs

@@ -0,0 +1,133 @@
+using System;
+using System.Collections.Generic;
+using System.Configuration;
+using System.Diagnostics;
+using System.Text;
+using System.Threading;
+using System.Windows.Forms;
+
+namespace MAutoUpdate
+{
+    public class EAPClock
+    {
+        //EAP小程序的名称,可能是下面两个中的某一个
+        string eapName1 = AppDomain.CurrentDomain.BaseDirectory + "/EapForIdle.exe";
+        string eapProcessName = "EapForIdle";
+
+        string thisProgramProcessName = "MAutoUpdate";
+        int thisProgramRunCount = 0;            //判本此程序后台是否已运行。1表示没运行,大于1表示后台已运行此程序。
+
+        int checkInterval = Convert.ToInt32(ConfigurationManager.AppSettings["RunCheckInterval"]) * 60;
+
+        bool isStartOrNotEap;  //判断EAP小程序是否启动
+
+        /// <summary>
+        /// 自动定时启动小程序。先判断后台 此程序 是否已运行,如果没运行则调用 newThreadStart()
+        /// </summary>
+        public void AutoStartEap()
+        {
+            StartEapForIdle();
+            StartTimer();
+        }
+
+        public void StartTimer()
+        {
+            string errorinfo = string.Empty;
+            System.Timers.Timer timer = new System.Timers.Timer();
+            timer.Enabled = true;
+            //设置执行一次(false)还是一直执行(true)
+            timer.AutoReset = true;
+            timer.Interval = checkInterval * 1000;
+            timer.Elapsed += delegate
+            {
+                StartEapForIdle();
+            };
+            timer.Start();
+            LogTool.AddLog("**********定时检查任务开启*************");
+        }
+
+        /// <summary>
+        /// 判断此程序是否单例运行
+        /// </summary>
+        /// <returns>返回值thisProgramRunCount如果大于1,表示小程序已运行。如果等于1,表示只有当前程序在运行。</returns>
+        public int IsOrNontOnlyOneThis()
+        {
+            //通过进程名获取当前进 此程序EAP 运行的实例,存放到进程数组中。
+            Process[] processes = Process.GetProcessesByName(thisProgramProcessName);
+            thisProgramRunCount = processes.Length;
+            return thisProgramRunCount;
+        }
+
+        public bool IsRunning(string programName)
+        {
+            var processes = Process.GetProcessesByName(programName);
+            if (processes == null || processes.Length == 0)
+                return false;
+            return true;
+        }
+
+        /// <summary>
+        /// 开个新线程启动小程序.
+        /// </summary>
+        public void newThreadStart()
+        {
+            Thread thread = new Thread(AlwaysRun);       //新线程调用AlwaysRun()死循环方法
+            thread.IsBackground = true;
+            thread.Start();
+        }
+
+        /// <summary>
+        /// 循环检查是否已运行小程序,如果后台没运行小程序,就启动小程序。
+        /// </summary>
+        public void AlwaysRun()
+        {
+            int EAPRunCount;
+            while (true)
+            {
+
+                EAPRunCount = IsOrNotRunEAP();
+                if (EAPRunCount == 0)
+                {
+                    StartEapForIdle();
+                }
+                // else MessageBox.Show("小程序已在后台开启,无需再次打开");
+                Thread.Sleep(30000);              //当前线程睡眠
+            }
+        }
+
+        public void StartEapForIdle()
+        {
+            LogTool.AddLog("**********检查EAP小程序开启状态开始*************");
+            LogTool.AddLog("小程序路径:" + eapName1);
+            if (!IsRunning(eapProcessName))
+            {
+                try
+                {
+
+                    Process.Start(eapName1);
+                    LogTool.AddLog("**********小程序被关闭,已重新开启*************");
+                }
+                catch (Exception ex)
+                {
+                    LogTool.AddLog("自动重启EAP程序失败,原因为:" + ex.ToString());
+                }
+            }
+            else
+            {
+                LogTool.AddLog("**********小程序运行中*************");
+            }
+            LogTool.AddLog("**********检查EAP小程序开启状态结束*************");
+        }
+
+        /// <summary>
+        /// 判断小程序是否在进程中运行,返回值EAPRunCount如果大于0,表示小程序已运行。如果等于0,表示未运行。
+        /// </summary>
+        public int IsOrNotRunEAP()
+        {
+            //通过小程序进程名获取当前进小程序运行的实例,存放到进程数组中。
+            Process[] processes = Process.GetProcessesByName(eapProcessName);
+            int EAPRunCount = processes.Length;
+            return EAPRunCount;
+        }
+    }
+}

+ 6 - 0
backend/AutoUpdate/MAutoUpdate/Local.xml

@@ -0,0 +1,6 @@
+<LocalUpdate>
+  <LocalVersion>1.0.0.1</LocalVersion>
+  <LocalIgnoreVersion>1.0.0.0</LocalIgnoreVersion>
+  <LastUdpate>2016/9/28 9:25:24</LastUdpate>
+  <ServerUpdateUrl>http://192.168.124.93:9807/huidu/server.xml</ServerUpdateUrl>
+</LocalUpdate>

+ 98 - 0
backend/AutoUpdate/MAutoUpdate/LocalInfo.cs

@@ -0,0 +1,98 @@
+using Microsoft.Win32;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Text;
+using System.Web.Hosting;
+using System.Xml;
+
+namespace MAutoUpdate
+{
+    public class LocalInfo
+    {
+        /// <summary>
+        /// 本地版本号
+        /// </summary>
+        public string LocalVersion { get; set; }
+        /// <summary>
+        /// 最后更新时间
+        /// </summary>
+        public string LastUdpate { get; set; }
+        /// <summary>
+        /// server.xml文件地址
+        /// </summary>
+        public string ServerUpdateUrl { get; set; }
+        public string LocalIgnoreVersion { get; set; }
+
+        private string url = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Local.xml");
+        //private string url = Path.Combine(HostingEnvironment.ApplicationPhysicalPath, "Local.xml");
+
+
+        public LocalInfo(string localAddress)
+        {
+            url = Path.Combine(localAddress, "Local.xml");
+        }
+
+        public void SaveReg(string subKey)
+        {
+            RegistryKey Key;
+            Key = Registry.CurrentUser;
+            //Key = Key.OpenSubKey("SOFTWARE\\GoodMES\\Update");
+            Key = Key.OpenSubKey(subKey, true);
+
+            foreach (var item in this.GetType().GetProperties())
+            {
+                Key.SetValue(item.Name.ToString(), this.GetType().GetProperty(item.Name.ToString()).GetValue(this, null).ToString());
+            }
+        }
+        public void LoadReg(string subKey)
+        {
+            //获取本地配置文件
+            RegistryKey Key;
+            Key = Registry.CurrentUser;
+            Key = Key.OpenSubKey(subKey);
+
+            foreach (var item in this.GetType().GetProperties())
+            {
+                this.GetType().GetProperty(item.Name.ToString()).SetValue(this, Key.GetValue(item.Name.ToString()).ToString(), null);
+            }
+            Key.Close();
+        }
+        public void LoadXml(int _type)
+        {
+            XmlDocument xdoc = new XmlDocument();
+            xdoc.Load(url);
+            var root = xdoc.DocumentElement;
+            var listNodes = root.SelectNodes("/LocalUpdate");
+            foreach (XmlNode item in listNodes)
+            {
+                RemoteInfo remote = new RemoteInfo();
+                foreach (XmlNode pItem in item.ChildNodes)
+                {
+                    if (pItem.Name == "LocalVersion" && _type == 1)
+                    {
+                        GetType().GetProperty(pItem.Name).SetValue(this, "1.0.0.1", null);
+                    }
+                    else
+                        GetType().GetProperty(pItem.Name).SetValue(this, pItem.InnerText, null);
+                }
+            }
+        }
+        public void SaveXml()
+        {
+            XmlDocument xdoc = new XmlDocument();
+            xdoc.Load(url);
+            var root = xdoc.DocumentElement;
+            var listNodes = root.SelectNodes("/LocalUpdate");
+            foreach (XmlNode item in listNodes)
+            {
+                foreach (XmlNode pItem in item.ChildNodes)
+                {
+                    // Key.SetValue(item.Name.ToString(), this.GetType().GetProperty(item.Name.ToString()).GetValue(this, null).ToString());
+                    pItem.InnerText = this.GetType().GetProperty(pItem.Name.ToString()).GetValue(this, null).ToString();
+                }
+            }
+            xdoc.Save(url);
+        }
+    }
+}

+ 34 - 0
backend/AutoUpdate/MAutoUpdate/LogTool.cs

@@ -0,0 +1,34 @@
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Text;
+
+namespace MAutoUpdate
+{
+    public static class LogTool
+    {
+        static string temp = AppDomain.CurrentDomain.BaseDirectory + "/logs";
+        public static void AddLog(String value)
+        {
+            try
+            {
+                Debug.WriteLine(value);
+                if (Directory.Exists(Path.Combine(temp, @"update\")) == false)
+                {
+                    DirectoryInfo directoryInfo = new DirectoryInfo(Path.Combine(temp, @"update\"));
+                    directoryInfo.Create();
+                }
+                using (StreamWriter sw = File.AppendText(Path.Combine(temp, @"update\update.log")))
+                {
+                    sw.WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"));
+                    sw.WriteLine(value);
+                    sw.WriteLine();
+                }
+            }
+            catch
+            {
+            }
+        }
+    }
+}

+ 257 - 0
backend/AutoUpdate/MAutoUpdate/MAutoUpdate.csproj

@@ -0,0 +1,257 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+  <PropertyGroup>
+    <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+    <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+    <ProductVersion>9.0.30729</ProductVersion>
+    <SchemaVersion>2.0</SchemaVersion>
+    <ProjectGuid>{A41F9740-A368-4F0C-91CE-ACF24D0DCA60}</ProjectGuid>
+    <OutputType>WinExe</OutputType>
+    <AppDesignerFolder>Properties</AppDesignerFolder>
+    <RootNamespace>MAutoUpdate</RootNamespace>
+    <AssemblyName>MAutoUpdate</AssemblyName>
+    <TargetFrameworkVersion>v2.0</TargetFrameworkVersion>
+    <FileAlignment>512</FileAlignment>
+    <FileUpgradeFlags>
+    </FileUpgradeFlags>
+    <UpgradeBackupLocation>
+    </UpgradeBackupLocation>
+    <OldToolsVersion>3.5</OldToolsVersion>
+    <IsWebBootstrapper>false</IsWebBootstrapper>
+    <TargetFrameworkProfile />
+    <PublishUrl>D:\Projects\Publish\MAutoUpdate\</PublishUrl>
+    <Install>true</Install>
+    <InstallFrom>Disk</InstallFrom>
+    <UpdateEnabled>true</UpdateEnabled>
+    <UpdateMode>Foreground</UpdateMode>
+    <UpdateInterval>7</UpdateInterval>
+    <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+    <UpdatePeriodically>false</UpdatePeriodically>
+    <UpdateRequired>true</UpdateRequired>
+    <MapFileExtensions>true</MapFileExtensions>
+    <UpdateUrl>http://192.168.124.85:9925/</UpdateUrl>
+    <MinimumRequiredVersion>1.0.0.9</MinimumRequiredVersion>
+    <ApplicationRevision>10</ApplicationRevision>
+    <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+    <UseApplicationTrust>false</UseApplicationTrust>
+    <PublishWizardCompleted>true</PublishWizardCompleted>
+    <BootstrapperEnabled>false</BootstrapperEnabled>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
+    <DebugSymbols>true</DebugSymbols>
+    <DebugType>full</DebugType>
+    <Optimize>false</Optimize>
+    <OutputPath>bin\Debug\</OutputPath>
+    <DefineConstants>DEBUG;TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+    <UseVSHostingProcess>true</UseVSHostingProcess>
+  </PropertyGroup>
+  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
+    <DebugType>pdbonly</DebugType>
+    <Optimize>true</Optimize>
+    <OutputPath>bin\Release\</OutputPath>
+    <DefineConstants>TRACE</DefineConstants>
+    <ErrorReport>prompt</ErrorReport>
+    <WarningLevel>4</WarningLevel>
+  </PropertyGroup>
+  <PropertyGroup />
+  <PropertyGroup>
+    <ApplicationIcon>clock-32.ico</ApplicationIcon>
+  </PropertyGroup>
+  <PropertyGroup>
+    <StartupObject />
+  </PropertyGroup>
+  <PropertyGroup>
+    <ManifestCertificateThumbprint>FC0662CD8E86FE2B1C5D83F7CD6A8B21A5A103EB</ManifestCertificateThumbprint>
+  </PropertyGroup>
+  <PropertyGroup>
+    <ManifestKeyFile>MAutoUpdate_TemporaryKey.pfx</ManifestKeyFile>
+  </PropertyGroup>
+  <PropertyGroup>
+    <GenerateManifests>true</GenerateManifests>
+  </PropertyGroup>
+  <PropertyGroup>
+    <SignManifests>false</SignManifests>
+  </PropertyGroup>
+  <ItemGroup>
+    <Reference Include="Newtonsoft.Json, Version=13.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
+      <HintPath>..\packages\Newtonsoft.Json.13.0.1\lib\net20\Newtonsoft.Json.dll</HintPath>
+    </Reference>
+    <Reference Include="System" />
+    <Reference Include="System.Configuration" />
+    <Reference Include="System.Data" />
+    <Reference Include="System.Deployment" />
+    <Reference Include="System.Drawing" />
+    <Reference Include="System.Web" />
+    <Reference Include="System.Windows.Forms" />
+    <Reference Include="System.Xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="common\UntilApi.cs" />
+    <Compile Include="CompareVersion.cs" />
+    <Compile Include="EAPClock.cs" />
+    <Compile Include="Models\EapResponse.cs" />
+    <Compile Include="Models\WebAppVersion.cs" />
+    <Compile Include="UpdateWork.cs" />
+    <Compile Include="LocalInfo.cs" />
+    <Compile Include="LogTool.cs" />
+    <Compile Include="MainForm.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="MainForm.Designer.cs">
+      <DependentUpon>MainForm.cs</DependentUpon>
+    </Compile>
+    <Compile Include="Program.cs" />
+    <Compile Include="Properties\AssemblyInfo.cs" />
+    <Compile Include="Properties\Resources.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DesignTime>True</DesignTime>
+      <DependentUpon>Resources.resx</DependentUpon>
+    </Compile>
+    <Compile Include="RemoteInfo.cs" />
+    <Compile Include="UpdateForm.cs">
+      <SubType>Form</SubType>
+    </Compile>
+    <Compile Include="UpdateForm.Designer.cs">
+      <DependentUpon>UpdateForm.cs</DependentUpon>
+    </Compile>
+    <Compile Include="YButton.cs">
+      <SubType>Component</SubType>
+    </Compile>
+    <Compile Include="Zip DLL\ComHelper.cs" />
+    <Compile Include="Zip DLL\CRC32.cs" />
+    <Compile Include="Zip DLL\Deflate.cs" />
+    <Compile Include="Zip DLL\DeflateStream.cs" />
+    <Compile Include="Zip DLL\EncryptionAlgorithm.cs" />
+    <Compile Include="Zip DLL\Events.cs" />
+    <Compile Include="Zip DLL\Exceptions.cs" />
+    <Compile Include="Zip DLL\ExtractExistingFileAction.cs" />
+    <Compile Include="Zip DLL\FileSelector.cs" />
+    <Compile Include="Zip DLL\GZipStream.cs" />
+    <Compile Include="Zip DLL\Inflate.cs" />
+    <Compile Include="Zip DLL\InfTree.cs" />
+    <Compile Include="Zip DLL\OffsetStream.cs" />
+    <Compile Include="Zip DLL\ParallelDeflateOutputStream.cs" />
+    <Compile Include="Zip DLL\Shared.cs" />
+    <Compile Include="Zip DLL\Tree.cs" />
+    <Compile Include="Zip DLL\WinZipAes.cs" />
+    <Compile Include="Zip DLL\ZipConstants.cs" />
+    <Compile Include="Zip DLL\ZipCrypto.cs" />
+    <Compile Include="Zip DLL\ZipDirEntry.cs" />
+    <Compile Include="Zip DLL\ZipEntry.cs" />
+    <Compile Include="Zip DLL\ZipEntry.Extract.cs" />
+    <Compile Include="Zip DLL\ZipEntry.Read.cs" />
+    <Compile Include="Zip DLL\ZipEntry.Write.cs" />
+    <Compile Include="Zip DLL\ZipEntrySource.cs" />
+    <Compile Include="Zip DLL\ZipErrorAction.cs" />
+    <Compile Include="Zip DLL\ZipFile.AddUpdate.cs" />
+    <Compile Include="Zip DLL\ZipFile.Check.cs" />
+    <Compile Include="Zip DLL\ZipFile.cs" />
+    <Compile Include="Zip DLL\ZipFile.Events.cs" />
+    <Compile Include="Zip DLL\ZipFile.Extract.cs" />
+    <Compile Include="Zip DLL\ZipFile.Read.cs" />
+    <Compile Include="Zip DLL\ZipFile.Save.cs" />
+    <Compile Include="Zip DLL\ZipFile.SaveSelfExtractor.cs" />
+    <Compile Include="Zip DLL\ZipFile.Selector.cs" />
+    <Compile Include="Zip DLL\ZipFile.Static.cs" />
+    <Compile Include="Zip DLL\ZipFile.x-IEnumerable.cs" />
+    <Compile Include="Zip DLL\ZipInputStream.cs" />
+    <Compile Include="Zip DLL\ZipOutputStream.cs" />
+    <Compile Include="Zip DLL\ZipSegmentedStream.cs" />
+    <Compile Include="Zip DLL\Zlib.cs" />
+    <Compile Include="Zip DLL\ZlibBaseStream.cs" />
+    <Compile Include="Zip DLL\ZlibCodec.cs" />
+    <Compile Include="Zip DLL\ZlibConstants.cs" />
+    <Compile Include="Zip DLL\ZlibStream.cs" />
+    <EmbeddedResource Include="MainForm.resx">
+      <DependentUpon>MainForm.cs</DependentUpon>
+    </EmbeddedResource>
+    <EmbeddedResource Include="Properties\Resources.resx">
+      <Generator>ResXFileCodeGenerator</Generator>
+      <SubType>Designer</SubType>
+      <LastGenOutput>Resources.Designer.cs</LastGenOutput>
+    </EmbeddedResource>
+    <EmbeddedResource Include="UpdateForm.resx">
+      <DependentUpon>UpdateForm.cs</DependentUpon>
+    </EmbeddedResource>
+    <None Include="app.config" />
+    <None Include="app.manifest" />
+    <None Include="MAutoUpdate_TemporaryKey.pfx" />
+    <None Include="packages.config" />
+    <None Include="Properties\Settings.settings">
+      <Generator>SettingsSingleFileGenerator</Generator>
+      <LastGenOutput>Settings.Designer.cs</LastGenOutput>
+    </None>
+    <Compile Include="Properties\Settings.Designer.cs">
+      <AutoGen>True</AutoGen>
+      <DependentUpon>Settings.settings</DependentUpon>
+      <DesignTimeSharedInput>True</DesignTimeSharedInput>
+    </Compile>
+    <None Include="Zip DLL\Migrated rules for Zip DLL.ruleset" />
+  </ItemGroup>
+  <ItemGroup>
+    <Content Include="clock-32.ico" />
+    <Content Include="Zip DLL\msbuild.flymake.xml" />
+    <None Include="config.update" />
+    <Content Include="Local.xml">
+      <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+    </Content>
+    <Content Include="Server.xml" />
+  </ItemGroup>
+  <ItemGroup>
+    <BootstrapperPackage Include="Microsoft.Net.Client.3.5">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1 Client Profile</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+    <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+      <Visible>False</Visible>
+      <ProductName>.NET Framework 3.5 SP1</ProductName>
+      <Install>false</Install>
+    </BootstrapperPackage>
+  </ItemGroup>
+  <ItemGroup>
+    <Folder Include="Zip DLL\BZip2\" />
+  </ItemGroup>
+  <ItemGroup>
+    <PublishFile Include="Local.xml">
+      <Visible>False</Visible>
+      <Group>
+      </Group>
+      <TargetPath>
+      </TargetPath>
+      <PublishState>Include</PublishState>
+      <IncludeHash>True</IncludeHash>
+      <FileType>File</FileType>
+    </PublishFile>
+    <PublishFile Include="Server.xml">
+      <Visible>False</Visible>
+      <Group>
+      </Group>
+      <TargetPath>
+      </TargetPath>
+      <PublishState>Include</PublishState>
+      <IncludeHash>True</IncludeHash>
+      <FileType>File</FileType>
+    </PublishFile>
+    <PublishFile Include="Zip DLL\msbuild.flymake.xml">
+      <Visible>False</Visible>
+      <Group>
+      </Group>
+      <TargetPath>
+      </TargetPath>
+      <PublishState>Include</PublishState>
+      <IncludeHash>True</IncludeHash>
+      <FileType>File</FileType>
+    </PublishFile>
+  </ItemGroup>
+  <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+  <!-- To modify your build process, add your task inside one of the targets below and uncomment it. 
+       Other similar extension points exist, see Microsoft.Common.targets.
+  <Target Name="BeforeBuild">
+  </Target>
+  <Target Name="AfterBuild">
+  </Target>
+  -->
+</Project>

+ 154 - 0
backend/AutoUpdate/MAutoUpdate/MainForm.Designer.cs

@@ -0,0 +1,154 @@
+using MAutoUpdate.Control;
+
+namespace MAutoUpdate
+{
+    partial class MainForm
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(MainForm));
+            this.LBTitle = new System.Windows.Forms.Label();
+            this.lblContent = new System.Windows.Forms.Label();
+            this.btnUpdateNow = new YButton();
+            this.btnUpdateLater = new YButton();
+            this.btnIgnore = new YButton();
+            this.SuspendLayout();
+            // 
+            // LBTitle
+            // 
+            this.LBTitle.AutoSize = true;
+            this.LBTitle.BackColor = System.Drawing.Color.Transparent;
+            this.LBTitle.Font = new System.Drawing.Font("微软雅黑", 11F, System.Drawing.FontStyle.Bold);
+            this.LBTitle.ForeColor = System.Drawing.Color.DimGray;
+            this.LBTitle.Location = new System.Drawing.Point(11, 13);
+            this.LBTitle.Name = "LBTitle";
+            this.LBTitle.Size = new System.Drawing.Size(54, 19);
+            this.LBTitle.TabIndex = 22;
+            this.LBTitle.Text = "新版本";
+            // 
+            // lblContent
+            // 
+            this.lblContent.Font = new System.Drawing.Font("微软雅黑", 11F);
+            this.lblContent.ForeColor = System.Drawing.Color.DimGray;
+            this.lblContent.Location = new System.Drawing.Point(112, 103);
+            this.lblContent.Name = "lblContent";
+            this.lblContent.Size = new System.Drawing.Size(358, 159);
+            this.lblContent.TabIndex = 24;
+            // 
+            // btnUpdateNow
+            // 
+            this.btnUpdateNow.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(26)))), ((int)(((byte)(173)))), ((int)(((byte)(25)))));
+            this.btnUpdateNow.EnterImage = null;
+            this.btnUpdateNow.Font = new System.Drawing.Font("微软雅黑", 10F);
+            this.btnUpdateNow.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(240)))), ((int)(((byte)(240)))), ((int)(((byte)(240)))));
+            this.btnUpdateNow.IsColorChange = true;
+            this.btnUpdateNow.IsFontChange = false;
+            this.btnUpdateNow.Location = new System.Drawing.Point(390, 332);
+            this.btnUpdateNow.MoveColor = System.Drawing.Color.FromArgb(((int)(((byte)(26)))), ((int)(((byte)(173)))), ((int)(((byte)(25)))));
+            this.btnUpdateNow.MoveFontColor = System.Drawing.Color.White;
+            this.btnUpdateNow.Name = "btnUpdateNow";
+            this.btnUpdateNow.NormalColor = System.Drawing.Color.FromArgb(((int)(((byte)(26)))), ((int)(((byte)(173)))), ((int)(((byte)(25)))));
+            this.btnUpdateNow.NormalFontColor = System.Drawing.Color.White;
+            this.btnUpdateNow.Size = new System.Drawing.Size(141, 45);
+            this.btnUpdateNow.TabIndex = 27;
+            this.btnUpdateNow.Text = "立即更新";
+            this.btnUpdateNow.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+            this.btnUpdateNow.Click += new System.EventHandler(this.btnUpdateNow_Click);
+            // 
+            // btnUpdateLater
+            // 
+            this.btnUpdateLater.BackColor = System.Drawing.Color.White;
+            this.btnUpdateLater.EnterImage = null;
+            this.btnUpdateLater.Font = new System.Drawing.Font("微软雅黑", 10F);
+            this.btnUpdateLater.ForeColor = System.Drawing.Color.Black;
+            this.btnUpdateLater.IsColorChange = true;
+            this.btnUpdateLater.IsFontChange = false;
+            this.btnUpdateLater.Location = new System.Drawing.Point(232, 332);
+            this.btnUpdateLater.MoveColor = System.Drawing.Color.White;
+            this.btnUpdateLater.MoveFontColor = System.Drawing.Color.Black;
+            this.btnUpdateLater.Name = "btnUpdateLater";
+            this.btnUpdateLater.NormalColor = System.Drawing.Color.White;
+            this.btnUpdateLater.NormalFontColor = System.Drawing.Color.Black;
+            this.btnUpdateLater.Size = new System.Drawing.Size(141, 45);
+            this.btnUpdateLater.TabIndex = 26;
+            this.btnUpdateLater.Text = "以后提醒我";
+            this.btnUpdateLater.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+            this.btnUpdateLater.Click += new System.EventHandler(this.btnUpdateLater_Click);
+            // 
+            // btnIgnore
+            // 
+            this.btnIgnore.BackColor = System.Drawing.Color.White;
+            this.btnIgnore.EnterImage = null;
+            this.btnIgnore.Font = new System.Drawing.Font("微软雅黑", 10F);
+            this.btnIgnore.ForeColor = System.Drawing.Color.Black;
+            this.btnIgnore.IsColorChange = true;
+            this.btnIgnore.IsFontChange = false;
+            this.btnIgnore.Location = new System.Drawing.Point(76, 332);
+            this.btnIgnore.MoveColor = System.Drawing.Color.White;
+            this.btnIgnore.MoveFontColor = System.Drawing.Color.Black;
+            this.btnIgnore.Name = "btnIgnore";
+            this.btnIgnore.NormalColor = System.Drawing.Color.White;
+            this.btnIgnore.NormalFontColor = System.Drawing.Color.Black;
+            this.btnIgnore.Size = new System.Drawing.Size(141, 45);
+            this.btnIgnore.TabIndex = 25;
+            this.btnIgnore.Text = "忽略这次更新";
+            this.btnIgnore.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+            this.btnIgnore.Click += new System.EventHandler(this.btnIgnore_Click);
+            // 
+            // MainForm
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(224)))), ((int)(((byte)(224)))), ((int)(((byte)(224)))));
+            this.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Zoom;
+            this.ClientSize = new System.Drawing.Size(600, 420);
+            this.Controls.Add(this.btnUpdateNow);
+            this.Controls.Add(this.btnUpdateLater);
+            this.Controls.Add(this.btnIgnore);
+            this.Controls.Add(this.lblContent);
+            this.Controls.Add(this.LBTitle);
+            this.DoubleBuffered = true;
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+            this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
+            this.Name = "MainForm";
+            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen;
+            this.Text = "MainForm";
+            this.TopMost = true;
+            this.MouseDown += new System.Windows.Forms.MouseEventHandler(this.PNTop_MouseDown);
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+        private System.Windows.Forms.Label LBTitle;
+        private System.Windows.Forms.Label lblContent;
+        private YButton btnIgnore;
+        private YButton btnUpdateLater;
+        private YButton btnUpdateNow;
+    }
+}

+ 100 - 0
backend/AutoUpdate/MAutoUpdate/MainForm.cs

@@ -0,0 +1,100 @@
+using Ionic.Zip;
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Diagnostics;
+using System.Drawing;
+using System.IO;
+using System.IO.Compression;
+using System.Net;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading;
+using System.Windows.Forms;
+using System.Xml;
+
+namespace MAutoUpdate
+{
+    public partial class MainForm : Form
+    {
+        UpdateWork updateWork;
+        public MainForm(UpdateWork _updateWork)
+        {
+            InitializeComponent();
+            updateWork = _updateWork;
+            var res = _updateWork.UpdateVerList[_updateWork.UpdateVerList.Count - 1].VersionDesc;
+
+            var temp = WebRequest.Create(res);
+            var stream = temp.GetResponse().GetResponseStream();
+            using (StreamReader reader = new StreamReader(stream, System.Text.Encoding.Default))
+            {
+                string text = reader.ReadToEnd();
+                this.lblContent.Text = text;
+            }
+            //foreach (var item in _updateWork.UpdateVerList[_updateWork.UpdateVerList.Count - 1].VersionDesc.Split('$'))
+            //{
+            //    this.lblContent.Text = this.lblContent.Text + item + Environment.NewLine;
+            //}
+        }
+        #region 让窗体变成可移动
+        [DllImport("user32.dll")]
+        public static extern bool ReleaseCapture();
+        [DllImport("user32.dll")]
+        public static extern bool SendMessage(IntPtr hwnd, int wMsg, int wParam, int lParam);
+
+        [DllImport("user32.dll")]
+        private static extern IntPtr WindowFromPoint(Point p);
+
+        public const int WM_SYSCOMMAND = 0x0112;
+        public const int SC_MOVE = 0xF010;
+        public const int HTCAPTION = 0x0002;
+        private IntPtr moveObject = IntPtr.Zero;    //拖动窗体的句柄
+
+        private void PNTop_MouseDown(object sender, MouseEventArgs e)
+        {
+            if (moveObject == IntPtr.Zero)
+            {
+                if (this.Parent != null)
+                {
+                    moveObject = this.Parent.Handle;
+                }
+                else
+                {
+                    moveObject = this.Handle;
+                }
+            }
+            ReleaseCapture();
+            SendMessage(moveObject, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, 0);
+        }
+
+        #endregion
+
+
+        /// <summary>
+        /// 如果以后更新,则将更新程序关闭
+        /// </summary>
+        /// <param name="sender"></param>
+        /// <param name="e"></param>
+        private void btnUpdateLater_Click(object sender, EventArgs e)
+        {
+            Application.Exit();
+        }
+
+        private void btnUpdateNow_Click(object sender, EventArgs e)
+        {
+            this.Visible = false;//隐藏当前窗口
+            UpdateForm updateForm = new UpdateForm(updateWork);
+            if (updateForm.ShowDialog() == DialogResult.OK)
+            {
+                Application.Exit();
+            }
+        }
+
+        private void btnIgnore_Click(object sender, EventArgs e)
+        {
+            updateWork.IgnoreThisVersion();
+            Application.Exit();
+        }
+    }
+}

+ 197 - 0
backend/AutoUpdate/MAutoUpdate/MainForm.resx

@@ -0,0 +1,197 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <assembly alias="System.Drawing" name="System.Drawing, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
+  <data name="$this.Icon" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+    <value>
+        AAABAAEAICAAAAEAIACoEAAAFgAAACgAAAAgAAAAQAAAAAEAIAAAAAAAgBAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAMC6qBr58dmS+fHZ4Pnx2f358dn/+fHZ//nx2f/58dn/+fHZ//nx2f/58dn/+fHZ//nx
+        2f/58dn/+fHZ//nx2f/58dn/+fHZ//nx2f/58dn/+fLc//379f/79ub/+fHZ//nx2f358dnf+fHZksjC
+        rxoAAAAAAAAAAAAAAADm4Ms9+fLb7vny2//58tv/+fLb//ny2//58tv/+fLb//ny2//48Nf/8OS//+jZ
+        p//x5cL/+fLb//ny2//58tv/+fLb//ny2//58tv/+fLb//r04f/+/fr///////7+/v/8+Oz/+fLb//ny
+        2//58tv/+fLb7uzl0D0AAAAAwLurGvnz3e75893/+fPd//nz3f/5893/+fPd//nz3f/5893/+fPd/+DM
+        j/++mST/vpkk/8ioRP/48Nj/+fPd//nz3f/f0Jj/8erL//nz3f/79ub//v78///////39vX/////////
+        ///9+vL/+fPe//nz3f/5893/+fPd7s7JuBr69OCS+vTg//r04P/69OD/+vTg//r04P/48dz/+vTg//r0
+        4P/06s3/zrFX/76ZJP++mST/vpkk/8CgN//JsFj/zLZi/7KXJf+kmyv/5ePD//7+/v//////2dHO/2lI
+        Pf+bhn7/+vn5///////9/Pf/+vTi//r04P/69OD/+vPgkvr14+D69eP/+vXj//r14//69eP/59in/8Cd
+        LP/QtF7/1r1v/7+bKP++mST/vpkk/76ZJP++mST/upgm/7eYJv+2mCb/s5go/9bRnv/+/v7//v7+/7qr
+        pv9cOSv/WDQm/1g0Jv99YVb/7enn///////+/fr/+/bn//r14//69ePg+/bn/fv25//79uf/+/bn/+rc
+        sP+/myn/vpkk/76ZJP++mST/vpkk/76ZJP++mST/wZ4w/8mpR//DpkT/uZor/7qdMP/p4L7///////n4
+        9/+YgXj/WTUm/1k1Jv9ZNSb/WTUm/1k1Jv9oRzr/1s3K///////+/vz//Pjs//v25/379+r/+/fq//v3
+        6v/79+r/5dWj/72YJP+9mCT/vZgk/72YJP+9mCT/0LZh/+3hu//79uj/+/fq//v36v/69ef/9/Pn////
+        ///q5uT/e15R/1o1Jv9aNSb/WjUm/1o1Jv9aNSb/WjUm/1o1Jv9dOSr/tqag//7+/v/+/v7//Prx//z4
+        7f/8+O3//Pjt//z47f/48uL/u5Mq/7qRJv+6kSb/vJQr/+TTpP/8+O3//Pjt//z47f/8+O3//Prx//7+
+        /f//////08nF/2hGN/9bNib/WzYm/1s2Jv9bNib/WzYm/1s2Jv9bNib/WzYm/1s2Jv9bNib/lX1y//j2
+        9v/+/v7//Prx//z68f/8+vH//Prx/9i/i/+2hyj/toco/7aIKv/n17T//Prx//z68f/8+vH//Prx//37
+        9f/+/v7//v7+/7Oimv9eOin/XDcm/1w3Jv9cNyb/XDcm/1w3Jv9cNyb/XDcm/1w3Jv9cNyb/XDcm/1w3
+        Jv9cNyb/eltN/+jj4f/9+/T//fv0//379P/z6tr/toY3/7F+K/+xfiv/0LF8//379P/9+/T//fv0//X2
+        9P/5+vn//v7+///////v6+r/yr64/8q+uP/Kvrj/yr64/8q+uP96W03/Xjgm/144Jv9eOCb/Xjgm/6uY
+        j//Kvrj/yr64/8q+uP/Kvrj/1cvH//389//v5NT/vI5U/611Lv+tdS3/rXUt/612L//07N///fz3//38
+        9//9/Pf/5/D6/////////////////////////////////////////////////4ltYP9fOSb/Xzkm/185
+        Jv9fOSb/0cfB/////////////////////////////v36/9vBqP+naDD/p2gw/6doMP+naDD/u4pe//79
+        +v/+/fr//v36/8vg9/9WnfD/v9n3//79+//+/fv//fz7/62S7v/8+/v//v79////////////i25g/2E6
+        Jv9hOib/YTom/2E6Jv/Sx8H///////7+/v/+/fv//v37//79+//+/vz/y6ON/6FaNP+hWjT/oVo0/6Fa
+        NP/LpI7//v78//7+/P/+/fz/LpLt/yeN7P/8/Pz//v78/+Tf8//+/fz/nXns//79/P/+/v7/////////
+        //+Mb2D/Yzsm/2M7Jv9jOyb/Yzsm/9LHwf///////v7+//7+/P/+/vz//v78//7+/v/avbP/oVdD/5tM
+        N/+bTDf/m0w3/9CroP/+/v7//v7+//7+/v+Z0/b/N6rv//7+/v/+/v7/2sz4/7SW8//e0fn//v7+//7+
+        /v///////////41vYP9lPCb/ZTwm/2U8Jv9lPCb/08fB///////+/v7//v7+//7+/v/+/v7/////////
+        ///38fD/nExF/5ZBOf+WQTn/yJyY/////////////////3XR9f8WsO7/4fX8////////////////////
+        ////////////////////////j3Bg/2Y9Jv9nPSb/Zj0m/2Y9Jv/TyMH/////////////////////////
+        //////////////////+mXln/lkA6/5ZAOv+2enb/////////////////XMzz/xS27v9OyPL/8/v+////
+        ///////////////////3+PH///////////+QcWD/aD4m/2g+Jv9oPib/aD4m/9TIwf//////////////
+        /////////////////////////////7Z6dv+WQDr/lkA6/5tJRP/69/f////////////4/f7/xO36/xe8
+        7v8yxPD/leD1/7zo7f+z3dT/irqJ/8fXsP///////////5JyYP9qPyb/aj8m/2o/Jv9qPyb/1cjB////
+        ///////////////////////////////////59PT/pFpV/5ZAOv+WQDr/lkA6/9Sxrv//////////////
+        ////////KcLw/xS87v8Vu+3/HLng/zOyt/9Lqor/wdzG////////////k3Jg/2xAJv9sQCb/bEAm/2xA
+        Jv/VycH//////////////////////////////////////7qCfv+WQDr/lkA6/5ZAOv+WQDr/oFJN//fx
+        8P/////////////////V8/z/qOb5/9fz/P9b0PP/HLnh/4fT2f/+/v7///////////+Vc2D/bkEm/25B
+        Jv9uQSb/bkEm/9bJwf//////////////////////////////////////tXl1/5ZAOv+WQDr/lkA6/5ZA
+        Ov+WQDr/snNv//z5+f////////////////////////////D6/f/M8Pv/7vr8/////////////////5Z0
+        X/9wQib/cEIm/3BCJv9wQib/1snB/////////////////////////////v7+//7+/v/p19X/lkA6/5ZA
+        Ov+WQDr/lkA6/5ZAOv+WPzv/sXFz//fw8f/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7///7+////
+        ////////l3Vg/3JDJv9yQyb/ckMm/3JDJv/XycH///////7//v/+/v7//v7+//7+/v/+/v7//v7+//7+
+        /v+9iIT/s3Vx/7h+ev+WQDr/lkA6/5Y/O/+VPkL/nlBb/9a0vf/8+vv//v7+//7+/v/+/v7//v7+//7+
+        /v/+/v7///////////+ZdV//dEQm/3REJv90RCb/dEQm/9fKwf///////v7+//7+/v/+/v7//v7+//7+
+        /v/+/v7//v7+//7+/v/+/v7//v7+/8OTkP+WQDr/lj87/5U+Qv+UPUr/kztS/5xLaf+8hp//07DE/97D
+        1f/dw9j/07DP/+bT5f///////////5p2X/92RSb/dkUm/3ZFJv92RSb/2MrB///////+/v7//v7+//7+
+        /v/+/v7//f39//39/f/9/f3//f39//39/f/9/f3//fz8/8KRjf+WPzv/lT5C/5Q9Sv+TO1L/kjpa/5I5
+        Y/+RN2v/kDZz/480e/+OM4P/0KvP////////////m3df/3dGJv93Rib/d0Ym/3dGJv/YysH///////7+
+        /v/9/f3//f39//39/f/9/f3//f39//39/f/9/f3//f39//39/f/9/f3/38XE/5Y/O/+VPkL/lD1K/5M7
+        Uv+SOlr/kjlj/5E3a/+QNnP/jzR7/44zg//Qq8////////////+cd1//eUYm/3lGJv95Rib/eUYm/9nK
+        wf///////v7+//39/f/9/f3//f39//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/bv73/lj87/5U+
+        Qv+UPUr/kztS/5I6Wv+SOWP/kTdr/5A2c/+PNHv/jjOD/9Crz////////////514X/96Ryb/ekcm/3pH
+        Jv96Ryb/2cvB///////+/v7//Pz8//z8/P/8/Pz//Pz8/fz8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//Dm
+        5f+2enf/lT9C/5Q9Sv+VP1X/zaWz/8WXrf+wcJX/oVWJ/480e/+OM4P/0KvP////////////nnhf/3tI
+        Jv97SCb/e0gm/3tIJv/Zy8H///////7+/v/8/Pz//Pz8//z8/P37+/vg+/v7//v7+//7+/v/+/v7//v7
+        +//7+/v/+/v7//v7+//l09T/sXJ8/9vAx//7+/v/+/v7//v7+//6+Pn/qGOZ/44zg//Qq8//////////
+        //+feF//fEgm/3xIJv98SCb/fEgm/9rLwf///////v7+//v7+//7+/v/+/v74Pv7+5L7+/v/+/v7//v7
+        +//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//7+/v/+/v7//v7+//u4+z/lkGM/9Sx
+        0v/////////////////////////////////////////////////+/v7/+/v7//v7+//7+/uSycnJGvr6
+        +u76+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6
+        +v/5+Pn//f39//////////////////////////////////////////////////7+/v/6+vr/+vr67tbW
+        1hoAAAAA7e3tPfr6+u36+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6+v/6+vr/+vr6//r6
+        +v/6+vr/+vr6//r6+v/7+/v//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz//Pz8//z8/P/8/Pz/+/v7//r6
+        +u3y8vI9AAAAAAAAAAAAAAAAz8/PGvr5+ZL5+frf+vr5/Pr6+v/6+vr/+fr6//r6+v/5+fr/+vr6//r6
+        +v/5+vr/+vn6//r6+f/6+vr/+vr6//r6+f/6+vr/+vr6//r6+v/6+vn/+vr6//r6+v/6+vr/+vr6/Pn5
+        +d/6+fmS1dXVGgAAAAAAAAAAwAAAA4AAAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+        AAAAAAAAAAAAAAAAAAAAAAAAgAAAAcAAAAM=
+</value>
+  </data>
+</root>

+ 16 - 0
backend/AutoUpdate/MAutoUpdate/Models/EapResponse.cs

@@ -0,0 +1,16 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MAutoUpdate.Models
+{
+    public class EapResponse
+    {
+        public int Code { get; set; } = 1;
+        public int Id { get; set; }
+        public string Msg { get; set; } = string.Empty;
+        public object Data { get; set; }
+
+        public int IsAuthorized { get; set; }
+    }
+}

+ 18 - 0
backend/AutoUpdate/MAutoUpdate/Models/WebAppVersion.cs

@@ -0,0 +1,18 @@
+
+namespace MAutoUpdate.Models
+{
+    /// <summary>
+    /// 小程序版本信息
+    /// </summary>
+    public class WebAppVersion
+    {
+        /// <summary>
+        /// 版本号
+        /// </summary>
+        public string Version { get; set; }
+        /// <summary>
+        /// 更新日期
+        /// </summary>
+        public string UpdateTime { get; set; }
+    }
+}

+ 290 - 0
backend/AutoUpdate/MAutoUpdate/Program.cs

@@ -0,0 +1,290 @@
+using System;
+using System.Collections.Generic;
+using System.Windows.Forms;
+using System.IO;
+using System.Net;
+using System.Diagnostics;
+using System.Threading;
+using System.Xml;
+using System.Web.Hosting;
+using System.Deployment.Application;
+using System.Reflection;
+using System.Security.Cryptography;
+using System.Text;
+using System.Collections;
+using Newtonsoft.Json;
+using System.Configuration;
+using MAutoUpdate.common;
+using MAutoUpdate.Models;
+
+namespace MAutoUpdate
+{
+    static class Program
+    {
+        static bool f;
+        static Process pCurrent = Process.GetCurrentProcess();
+        static Mutex m = new Mutex(true, pCurrent.MainModule.FileName.Replace(":", "").Replace(@"\", "") + "MAutoUpdate", out f);//互斥,
+        static string ip = ConfigurationManager.AppSettings["IP"].ToString();
+        static string appPath = AppDomain.CurrentDomain.BaseDirectory;
+        static int updateCheckInterval = Convert.ToInt32(ConfigurationManager.AppSettings["UpdateCheckInterval"]) * 60;
+
+        /// <summary>
+        /// 程序主入口
+        /// </summary>
+        /// <param name="args">[0]程序名称,[1]静默更新 0:否 1:是 [3] 0:程序启动检测 1:手动点击检查更新按钮(在于忽略更新的情况下,手动检测时候还是要弹出来的) </param>
+        [STAThread]
+        static void Main(string[] args)
+        {
+            if (IsRunning())
+            {
+                LogTool.AddLog("已存在正在运行的更新程序");
+            }
+            else
+            {
+                LogTool.AddLog("正在启动定时更新程序");
+                new EAPClock().AutoStartEap();
+                DoCheckVersion();
+                StartTimer();
+                while (true)
+                {
+                    Thread.Sleep(1000 * 60*60);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 是否已启动
+        /// </summary>
+        /// <returns></returns>
+        static bool IsRunning()
+        {
+            Process[] processes = Process.GetProcesses();
+            Process currentProcess = Process.GetCurrentProcess();
+            bool processExist = false;
+            foreach (Process p in processes)
+            {
+                if (p.ProcessName == currentProcess.ProcessName && p.Id != currentProcess.Id)
+                {
+                    processExist = true;
+                }
+            }
+            return processExist;
+        }
+
+        public static int GetPidByProcessName(string processName)
+        {
+            Process[] arrayProcess = Process.GetProcessesByName(processName);
+            foreach (Process p in arrayProcess)
+            {
+                return p.Id;
+            }
+            return 0;
+        }
+
+        /// <summary>
+        /// 检查版本更新
+        /// </summary>
+        public static void DoCheckVersion()
+        {
+            if (f)
+            {
+                try
+                {
+                    if (ApplicationDeployment.IsNetworkDeployed)
+                    {
+                        LogTool.AddLog("当前版本" + ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString());
+                    }
+                    CheckVersion();
+                }
+                catch (Exception ex)
+                {
+                    MessageBox.Show(ex.Message);
+                }
+            }
+        }
+
+        /// <summary>
+        /// 启动定时器
+        /// </summary>
+        public static void StartTimer()
+        {
+            System.Timers.Timer timer = new System.Timers.Timer();
+            timer.Enabled = true;
+            //设置执行一次(false)还是一直执行(true)
+            timer.AutoReset = true;
+            timer.Interval = updateCheckInterval * 1000;
+            timer.Elapsed += delegate
+            {
+                DoCheckVersion();
+            };
+            timer.Start();
+        }
+
+        public static bool startprocess()
+        {
+            try
+            {
+                Process.Start(Path.Combine(AppDomain.CurrentDomain.BaseDirectory + @"Debug\", "EapForIdle.exe"));
+                return true;
+            }
+            catch
+            {
+                return false;
+            }
+        }
+
+        public static void CheckVersion()
+        {
+            try
+            {
+                if (!RequireUpdate())
+                    return;
+                LogTool.AddLog("*******************开始更新****************");
+                string programName = "EapForIdle";
+                string isClickUpdate = "0";
+                string localAddress = appPath;
+                if (!Directory.Exists(localAddress))
+                {
+                    Directory.CreateDirectory(localAddress);
+                }
+                var files = Directory.GetFiles(localAddress, "*.*");
+                Hashtable hashtable = new Hashtable();
+                DirectoryInfo folder = new DirectoryInfo(localAddress);
+                foreach (FileInfo file in folder.GetFiles("*.*"))
+                {
+                    hashtable[file.Name] = GetMD5HashFromFile(file.FullName);
+                }
+                CompareVersion compareVersion = new CompareVersion();
+                compareVersion.Versions = hashtable;
+                string Json = JsonConvert.SerializeObject(compareVersion);
+                string ss = ip + "CompareVersion/DownloadAppFile";
+                string result = UntilApi.HttpPost(ss, Json);
+                EapResponse response = JsonConvert.DeserializeObject<EapResponse>(result);
+                if (response != null)
+                {
+                    if (response.Code == 1)
+                    {
+                        var ht = JsonConvert.DeserializeObject<Hashtable>(response.Data.ToString());
+                        if (ht.Count > 0)
+                        {
+                            UpdateWork updateWork = new UpdateWork(programName, localAddress, isClickUpdate, 1, ht);
+                            updateWork.Do();
+                        }
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                LogTool.AddLog(ex.ToString() + ex.StackTrace);
+            }
+        }
+
+        /// <summary>
+        /// 检测APP师傅需要更新
+        /// </summary>
+        /// <returns></returns>
+        public static bool RequireUpdate()
+        {
+            var versionPath = Path.Combine(appPath, "version.json");
+            if (!File.Exists(versionPath))
+                return true;
+            WebAppVersion appVersion = null;
+            var file = new FileInfo(versionPath);
+            using (var sr = file.OpenText())
+            {
+                var str = sr.ReadToEnd();
+                appVersion = JsonConvert.DeserializeObject<WebAppVersion>(str);
+            }
+            if (appVersion == null)
+                return true;
+            try
+            {
+                string url = ip + "CompareVersion/GetAppVersion";
+                string result = UntilApi.HttpGet(url);
+                EapResponse response = JsonConvert.DeserializeObject<EapResponse>(result);
+                if (response != null && response.Code == 1)
+                {
+                    var hs = JsonConvert.DeserializeObject<Hashtable>(response.Data.ToString());
+                    var serverAppVersion = hs["version"];
+                    LogTool.AddLog("**************检查版本开始***************");
+                    LogTool.AddLog("服务端最新版本:" + serverAppVersion + ",本地版本:" + appVersion.Version);
+                    LogTool.AddLog("**************检查版本结束***************");
+
+                    if (serverAppVersion.ToString() != appVersion.Version)
+                        return true;
+                }
+                return false;
+            }
+            catch (Exception ex)
+            {
+                LogTool.AddLog(ex.ToString() + ex.StackTrace);
+                return false;
+            }
+        }
+
+        public static string GetMD5HashFromFile(string fileName)
+        {
+            try
+            {
+                FileStream file = new FileStream(fileName, System.IO.FileMode.Open, FileAccess.Read);
+                MD5 md5 = new MD5CryptoServiceProvider();
+                byte[] retVal = md5.ComputeHash(file);
+                file.Close();
+                StringBuilder sb = new StringBuilder();
+                for (int i = 0; i < retVal.Length; i++)
+                {
+                    sb.Append(retVal[i].ToString("x2"));
+                }
+                return sb.ToString();
+            }
+            catch (Exception ex)
+            {
+                throw new Exception("GetMD5HashFromFile() fail,error:" + ex.Message);
+            }
+        }
+
+        static void CheckForUpdate()
+        {
+            try
+            {
+                if (ApplicationDeployment.IsNetworkDeployed)
+                {
+                    ApplicationDeployment ad = ApplicationDeployment.CurrentDeployment;
+                    if (ad.CheckForUpdate())
+                    {
+                        LogTool.AddLog("更新版本" + ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString());
+                        //Application.ExitThread();
+                        //Restart();
+                        ad.UpdateAsync();
+                        ad.UpdateCompleted += (s, ee) =>
+                        {
+                            if (ee.Error == null)
+                            {
+                                LogTool.AddLog("更新版本成功" + ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString());
+                                //var vserson=  ApplicationDeployment.CurrentDeployment.CurrentVersion;
+                                //var vserson = Assembly.GetExecutingAssembly().GetName().Version;
+                                //ForUpdate FU = new ForUpdate(this);
+                                //FU.ShowDialog();
+                                //FU.Focus();
+                            }
+                            else
+                            {
+                                LogTool.AddLog("更新版本失败" + ApplicationDeployment.CurrentDeployment.CurrentVersion.ToString());
+                                MessageBox.Show(ee.Error.ToString());
+                            }
+                        };
+                    }
+                    else
+                    {
+                        LogTool.AddLog("不需要更新版本");
+                    }
+                }
+            }
+            catch (Exception ex)
+            {
+                LogTool.AddLog(ex.Message);
+            }
+
+        }
+    }
+}

+ 36 - 0
backend/AutoUpdate/MAutoUpdate/Properties/AssemblyInfo.cs

@@ -0,0 +1,36 @@
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+
+// 有关程序集的常规信息通过下列属性集
+// 控制。更改这些属性值可修改
+// 与程序集关联的信息。
+[assembly: AssemblyTitle("AutoUpdate")]
+[assembly: AssemblyDescription("")]
+[assembly: AssemblyConfiguration("")]
+[assembly: AssemblyCompany("")]
+[assembly: AssemblyProduct("AutoUpdate")]
+[assembly: AssemblyCopyright("Copyright ©  2012")]
+[assembly: AssemblyTrademark("")]
+[assembly: AssemblyCulture("")]
+
+// 将 ComVisible 设置为 false 使此程序集中的类型
+// 对 COM 组件不可见。如果需要从 COM 访问此程序集中的类型,
+// 则将该类型上的 ComVisible 属性设置为 true。
+[assembly: ComVisible(false)]
+
+// 如果此项目向 COM 公开,则下列 GUID 用于类型库的 ID
+[assembly: Guid("276417b2-b45c-4c7d-902e-82730c1c3399")]
+
+// 程序集的版本信息由下面四个值组成:
+//
+//      主版本
+//      次版本 
+//      内部版本号
+//      修订号
+//
+// 可以指定所有这些值,也可以使用“内部版本号”和“修订号”的默认值,
+// 方法是按如下所示使用“*”:
+// [assembly: AssemblyVersion("1.0.*")]
+[assembly: AssemblyVersion("1.0.0.0")]
+[assembly: AssemblyFileVersion("1.1.1.1")]

+ 63 - 0
backend/AutoUpdate/MAutoUpdate/Properties/Resources.Designer.cs

@@ -0,0 +1,63 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     此代码由工具生成。
+//     运行时版本:4.0.30319.42000
+//
+//     对此文件的更改可能会导致不正确的行为,并且如果
+//     重新生成代码,这些更改将会丢失。
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace MAutoUpdate.Properties {
+    using System;
+    
+    
+    /// <summary>
+    ///   一个强类型的资源类,用于查找本地化的字符串等。
+    /// </summary>
+    // 此类是由 StronglyTypedResourceBuilder
+    // 类通过类似于 ResGen 或 Visual Studio 的工具自动生成的。
+    // 若要添加或移除成员,请编辑 .ResX 文件,然后重新运行 ResGen
+    // (以 /str 作为命令选项),或重新生成 VS 项目。
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")]
+    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    internal class Resources {
+        
+        private static global::System.Resources.ResourceManager resourceMan;
+        
+        private static global::System.Globalization.CultureInfo resourceCulture;
+        
+        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
+        internal Resources() {
+        }
+        
+        /// <summary>
+        ///   返回此类使用的缓存的 ResourceManager 实例。
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Resources.ResourceManager ResourceManager {
+            get {
+                if (object.ReferenceEquals(resourceMan, null)) {
+                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("MAutoUpdate.Properties.Resources", typeof(Resources).Assembly);
+                    resourceMan = temp;
+                }
+                return resourceMan;
+            }
+        }
+        
+        /// <summary>
+        ///   重写当前线程的 CurrentUICulture 属性
+        ///   重写当前线程的 CurrentUICulture 属性。
+        /// </summary>
+        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
+        internal static global::System.Globalization.CultureInfo Culture {
+            get {
+                return resourceCulture;
+            }
+            set {
+                resourceCulture = value;
+            }
+        }
+    }
+}

+ 121 - 0
backend/AutoUpdate/MAutoUpdate/Properties/Resources.resx

@@ -0,0 +1,121 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
+</root>

+ 26 - 0
backend/AutoUpdate/MAutoUpdate/Properties/Settings.Designer.cs

@@ -0,0 +1,26 @@
+//------------------------------------------------------------------------------
+// <auto-generated>
+//     此代码由工具生成。
+//     运行时版本:4.0.30319.42000
+//
+//     对此文件的更改可能会导致不正确的行为,并且如果
+//     重新生成代码,这些更改将会丢失。
+// </auto-generated>
+//------------------------------------------------------------------------------
+
+namespace MAutoUpdate.Properties {
+    
+    
+    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
+    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.8.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;
+            }
+        }
+    }
+}

+ 7 - 0
backend/AutoUpdate/MAutoUpdate/Properties/Settings.settings

@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='utf-8'?>
+<SettingsFile xmlns="http://schemas.microsoft.com/VisualStudio/2004/01/settings" CurrentProfile="(Default)">
+  <Profiles>
+    <Profile Name="(Default)" />
+  </Profiles>
+  <Settings />
+</SettingsFile>

+ 36 - 0
backend/AutoUpdate/MAutoUpdate/RemoteInfo.cs

@@ -0,0 +1,36 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace MAutoUpdate
+{
+    public class RemoteInfo
+    {
+        /// <summary>
+        /// 更新后启动程序
+        /// </summary>
+        public String ApplicationStart { get; set; }
+        public String AppName { get; set; }
+        public String MinVersion { get; set; }
+        /// <summary>
+        /// 发布日期
+        /// </summary>
+        public String ReleaseDate { get; set; }
+        /// <summary>
+        /// 下载地址
+        /// </summary>
+        public String ReleaseUrl { get; set; }
+        /// <summary>
+        /// 发布版本号
+        /// </summary>
+        public String ReleaseVersion { get; set; }
+        /// <summary>
+        /// Cover表示覆盖更新,Increment表示增量更新
+        /// </summary>
+        public String UpdateMode { get; set; }
+        /// <summary>
+        /// 更新界面提示信息
+        /// </summary>
+        public String VersionDesc { get; set; }
+    }
+}

+ 13 - 0
backend/AutoUpdate/MAutoUpdate/Server.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<ServerUpdate>
+  <item>
+    <ApplicationStart>EapForIdle.exe</ApplicationStart>
+    <AppName>Print</AppName>
+    <MinVersion>1.0.0.0</MinVersion>
+    <ReleaseDate>2017/9/28 9:25:24</ReleaseDate>
+    <ReleaseUrl>http://localhost/WebApp/update/1.1.0.0.zip</ReleaseUrl>
+    <ReleaseVersion>1.1.0.0</ReleaseVersion>
+    <VersionDesc>1、Increment$2、hello$3、123456</VersionDesc>
+    <UpdateMode>Increment</UpdateMode>
+  </item>
+</ServerUpdate>

+ 92 - 0
backend/AutoUpdate/MAutoUpdate/UpdateForm.Designer.cs

@@ -0,0 +1,92 @@
+namespace MAutoUpdate
+{
+    partial class UpdateForm
+    {
+        /// <summary>
+        /// Required designer variable.
+        /// </summary>
+        private System.ComponentModel.IContainer components = null;
+
+        /// <summary>
+        /// Clean up any resources being used.
+        /// </summary>
+        /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing && (components != null))
+            {
+                components.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+
+        #region Windows Form Designer generated code
+
+        /// <summary>
+        /// Required method for Designer support - do not modify
+        /// the contents of this method with the code editor.
+        /// </summary>
+        private void InitializeComponent()
+        {
+            this.updateBar = new System.Windows.Forms.ProgressBar();
+            this.LBTitle = new System.Windows.Forms.Label();
+            this.label1 = new System.Windows.Forms.Label();
+            this.SuspendLayout();
+            // 
+            // updateBar
+            // 
+            this.updateBar.BackColor = System.Drawing.Color.Lime;
+            this.updateBar.Location = new System.Drawing.Point(40, 299);
+            this.updateBar.Name = "updateBar";
+            this.updateBar.Size = new System.Drawing.Size(509, 28);
+            this.updateBar.TabIndex = 24;
+            // 
+            // LBTitle
+            // 
+            this.LBTitle.AutoSize = true;
+            this.LBTitle.BackColor = System.Drawing.Color.Transparent;
+            this.LBTitle.Font = new System.Drawing.Font("微软雅黑", 11F, System.Drawing.FontStyle.Bold);
+            this.LBTitle.ForeColor = System.Drawing.Color.DimGray;
+            this.LBTitle.Location = new System.Drawing.Point(12, 9);
+            this.LBTitle.Name = "LBTitle";
+            this.LBTitle.Size = new System.Drawing.Size(54, 19);
+            this.LBTitle.TabIndex = 25;
+            this.LBTitle.Text = "新版本";
+            // 
+            // label1
+            // 
+            this.label1.BackColor = System.Drawing.Color.Transparent;
+            this.label1.Font = new System.Drawing.Font("微软雅黑", 11F, System.Drawing.FontStyle.Bold);
+            this.label1.ForeColor = System.Drawing.Color.DimGray;
+            this.label1.Location = new System.Drawing.Point(95, 243);
+            this.label1.Name = "label1";
+            this.label1.Size = new System.Drawing.Size(407, 19);
+            this.label1.TabIndex = 26;
+            this.label1.Text = "正在升级...";
+            this.label1.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+            // 
+            // UpdateForm
+            // 
+            this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
+            this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+            this.ClientSize = new System.Drawing.Size(588, 428);
+            this.Controls.Add(this.label1);
+            this.Controls.Add(this.LBTitle);
+            this.Controls.Add(this.updateBar);
+            this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.None;
+            this.Name = "UpdateForm";
+            this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent;
+            this.Text = "UpdateForm";
+            this.Load += new System.EventHandler(this.UpdateForm_Load);
+            this.ResumeLayout(false);
+            this.PerformLayout();
+
+        }
+
+        #endregion
+
+        private System.Windows.Forms.ProgressBar updateBar;
+        private System.Windows.Forms.Label LBTitle;
+        private System.Windows.Forms.Label label1;
+    }
+}

+ 48 - 0
backend/AutoUpdate/MAutoUpdate/UpdateForm.cs

@@ -0,0 +1,48 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Data;
+using System.Diagnostics;
+using System.Drawing;
+using System.Text;
+using System.Threading;
+using System.Windows.Forms;
+
+namespace MAutoUpdate
+{
+    public partial class UpdateForm : Form
+    {
+        public delegate void UpdateUI(int step);//声明一个更新主线程的委托
+        public UpdateUI UpdateUIDelegate;
+        private UpdateWork work;
+        public UpdateForm(UpdateWork _work)
+        {
+            work = _work;
+            InitializeComponent();
+            UpdateUIDelegate = new UpdateUI((obj) =>
+            {
+                this.updateBar.Value = obj;
+            });
+            work.OnUpdateProgess += new UpdateWork.UpdateProgess((obj) =>
+              {
+                  this.Invoke(UpdateUIDelegate, (int)obj);
+              });
+        }
+
+        private void UpdateForm_Load(object sender, EventArgs e)
+        {
+            ThreadPool.QueueUserWorkItem((obj) =>
+            {
+                try
+                {
+                    work.Do();
+                    this.DialogResult = DialogResult.OK;
+                }
+                catch (Exception EX)
+                {
+                    MessageBox.Show(EX.Message);
+                }
+            });
+        }
+    }
+}

+ 120 - 0
backend/AutoUpdate/MAutoUpdate/UpdateForm.resx

@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="utf-8"?>
+<root>
+  <!-- 
+    Microsoft ResX Schema 
+    
+    Version 2.0
+    
+    The primary goals of this format is to allow a simple XML format 
+    that is mostly human readable. The generation and parsing of the 
+    various data types are done through the TypeConverter classes 
+    associated with the data types.
+    
+    Example:
+    
+    ... ado.net/XML headers & schema ...
+    <resheader name="resmimetype">text/microsoft-resx</resheader>
+    <resheader name="version">2.0</resheader>
+    <resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
+    <resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
+    <data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
+    <data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
+    <data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
+        <value>[base64 mime encoded serialized .NET Framework object]</value>
+    </data>
+    <data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
+        <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
+        <comment>This is a comment</comment>
+    </data>
+                
+    There are any number of "resheader" rows that contain simple 
+    name/value pairs.
+    
+    Each data row contains a name, and value. The row also contains a 
+    type or mimetype. Type corresponds to a .NET class that support 
+    text/value conversion through the TypeConverter architecture. 
+    Classes that don't support this are serialized and stored with the 
+    mimetype set.
+    
+    The mimetype is used for serialized objects, and tells the 
+    ResXResourceReader how to depersist the object. This is currently not 
+    extensible. For a given mimetype the value must be set accordingly:
+    
+    Note - application/x-microsoft.net.object.binary.base64 is the format 
+    that the ResXResourceWriter will generate, however the reader can 
+    read any of the formats listed below.
+    
+    mimetype: application/x-microsoft.net.object.binary.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
+            : and then encoded with base64 encoding.
+    
+    mimetype: application/x-microsoft.net.object.soap.base64
+    value   : The object must be serialized with 
+            : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
+            : and then encoded with base64 encoding.
+
+    mimetype: application/x-microsoft.net.object.bytearray.base64
+    value   : The object must be serialized into a byte array 
+            : using a System.ComponentModel.TypeConverter
+            : and then encoded with base64 encoding.
+    -->
+  <xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
+    <xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
+    <xsd:element name="root" msdata:IsDataSet="true">
+      <xsd:complexType>
+        <xsd:choice maxOccurs="unbounded">
+          <xsd:element name="metadata">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" />
+              </xsd:sequence>
+              <xsd:attribute name="name" use="required" type="xsd:string" />
+              <xsd:attribute name="type" type="xsd:string" />
+              <xsd:attribute name="mimetype" type="xsd:string" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="assembly">
+            <xsd:complexType>
+              <xsd:attribute name="alias" type="xsd:string" />
+              <xsd:attribute name="name" type="xsd:string" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="data">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+                <xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
+              <xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
+              <xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
+              <xsd:attribute ref="xml:space" />
+            </xsd:complexType>
+          </xsd:element>
+          <xsd:element name="resheader">
+            <xsd:complexType>
+              <xsd:sequence>
+                <xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
+              </xsd:sequence>
+              <xsd:attribute name="name" type="xsd:string" use="required" />
+            </xsd:complexType>
+          </xsd:element>
+        </xsd:choice>
+      </xsd:complexType>
+    </xsd:element>
+  </xsd:schema>
+  <resheader name="resmimetype">
+    <value>text/microsoft-resx</value>
+  </resheader>
+  <resheader name="version">
+    <value>2.0</value>
+  </resheader>
+  <resheader name="reader">
+    <value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+  <resheader name="writer">
+    <value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
+  </resheader>
+</root>

+ 644 - 0
backend/AutoUpdate/MAutoUpdate/UpdateWork.cs

@@ -0,0 +1,644 @@
+using System;
+using System.Collections.Generic;
+using System.Text;
+using System.Net;
+using System.IO;
+using System.Diagnostics;
+using System.Windows.Forms;
+using System.Threading;
+using System.Runtime.InteropServices;
+using Microsoft.Win32;
+using System.Xml;
+using Ionic.Zip;
+using System.Net.Security;
+using System.Security.Cryptography.X509Certificates;
+using System.Collections;
+using System.Configuration;
+
+namespace MAutoUpdate
+{
+    public class UpdateWork
+    {
+        public delegate void UpdateProgess(double data);
+        public UpdateProgess OnUpdateProgess;
+        string mainName;
+        //临时目录(WIN7以及以上在C盘只有对于temp目录有操作权限)
+        //string tempPath = Path.Combine(Environment.GetEnvironmentVariable("TEMP"), @"MAutoUpdate\temp\");
+        //string bakPath = Path.Combine(Environment.GetEnvironmentVariable("TEMP"), @"MAutoUpdate\bak\");
+
+        string tempPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"MAutoUpdate\temp\");
+        string bakPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"MAutoUpdate\bak\");
+
+        string appPath = AppDomain.CurrentDomain.BaseDirectory + "/";
+
+        LocalInfo localInfo;
+        Hashtable hashTable;
+        public List<RemoteInfo> UpdateVerList { get; set; }
+        public string programName { get; set; }
+        public string subKey { get; set; }
+        public int Type { get; set; }
+        /// <summary>
+        /// 初始化配置目录信息
+        /// </summary>
+        public UpdateWork(string _programName, string localAddress, string isClickUpdate, int _type, Hashtable ht)
+        {
+            hashTable = ht;
+            Type = _type;
+            //localInfo = new LocalInfo(localAddress);
+            //Process cur = Process.GetCurrentProcess();
+            //mainName = Path.GetFileName(cur.MainModule.FileName);
+            programName = _programName;
+            //创建备份目录信息
+            //DirectoryInfo bakinfo = new DirectoryInfo(bakPath);
+            //if (bakinfo.Exists == false)
+            //{
+            //    bakinfo.Create();
+            //}
+            ////创建临时目录信息
+            //DirectoryInfo tempinfo = new DirectoryInfo(tempPath);
+            //if (tempinfo.Exists == false)
+            //{
+            //    tempinfo.Create();
+            //}
+            //localInfo.LoadXml(_type);
+            //UpdateVerList = GetServer(localInfo.ServerUpdateUrl);
+            //CheckVer(localInfo.LocalVersion, localInfo.LocalIgnoreVersion, isClickUpdate);
+        }
+
+        //public bool Do()
+        //{
+        //    KillProcessExist();
+        //    Thread.Sleep(400);
+        //    //更新之前先备份
+        //    Bak();
+        //    Thread.Sleep(400);
+        //    //备份结束开始下载东西
+        //    DownLoad();//下载更新包文件信息
+        //    Thread.Sleep(400);
+        //    //3、开始更新
+        //    Update();
+        //    Thread.Sleep(400);
+
+        //    Start();
+        //    Thread.Sleep(400);
+        //    return true;
+        //}
+        public bool Do()
+        {
+            KillProcessExist();
+            Thread.Sleep(1000);
+            //更新之前先备份
+
+            //备份结束开始下载东西
+            //DownLoad();//下载更新包文件信息
+
+            DownLoadInfo();
+            Thread.Sleep(400);
+
+            Start();
+            Thread.Sleep(400);
+            return true;
+        }
+        public void DownLoadInfo()
+        {
+            var url = appPath;
+            if (!Directory.Exists(url))
+            {
+                Directory.CreateDirectory(url);
+            }
+            foreach (var item in hashTable.Keys)
+            {
+                if (item.ToString() == "MAutoUpdate.exe")
+                {
+                    continue;
+                }
+                Stream stream = new MemoryStream();
+                try
+                {
+                    LogTool.AddLog("更新程序:下载更新包文件" + item);
+                    byte[] bs = Convert.FromBase64String(hashTable[item].ToString());
+                    stream.Read(bs, 0, bs.Length);
+                    using (FileStream fs = new FileStream(appPath + item.ToString(), FileMode.Create))
+                    {
+                        fs.Write(bs, 0, bs.Length);
+                    }
+                    //web.DownloadFile(hashTable[item].ToString(), AppDomain.CurrentDomain.BaseDirectory + @"Debug/" + item.ToString());
+                    //OnUpdateProgess?.Invoke(60 / UpdateVerList.Count);
+                }
+                catch (Exception ex)
+                {
+                    LogTool.AddLog("更新程序:更新包文件" + item + "下载失败,本次停止更新,异常信息:" + ex.Message);
+                    throw ex;
+                }
+                finally
+                {
+                    stream.Close();
+                    stream.Dispose();
+                }
+            }
+            //using (WebClient web = new WebClient())
+            //{
+            //    foreach (var item in hashTable.Keys)
+            //    {
+            //        try
+            //        {
+            //            LogTool.AddLog("更新程序:下载更新包文件" + item);
+            //            web.DownloadFile(hashTable[item].ToString(), AppDomain.CurrentDomain.BaseDirectory + @"Debug/" + item.ToString());
+            //            //OnUpdateProgess?.Invoke(60 / UpdateVerList.Count);
+            //        }
+            //        catch (Exception ex)
+            //        {
+            //            LogTool.AddLog("更新程序:更新包文件" + item + "下载失败,本次停止更新,异常信息:" + ex.Message);
+            //            throw ex;
+            //        }
+            //    }
+            //}
+        }
+
+        public static byte[] HexStrTobyte(string hexString)
+        {
+            hexString = hexString.Replace(" ", "");
+            if ((hexString.Length % 2) != 0)
+                hexString += " ";
+            byte[] returnBytes = new byte[hexString.Length / 2];
+            for (int i = 0; i < returnBytes.Length; i++)
+                returnBytes[i] = Convert.ToByte(hexString.Substring(i * 2, 2).Trim(), 16);
+            return returnBytes;
+        }
+        public void IgnoreThisVersion()
+        {
+            var item = UpdateVerList[UpdateVerList.Count - 1];
+            localInfo.LocalIgnoreVersion = item.ReleaseVersion;
+            localInfo.SaveXml();
+        }
+
+        /// <summary>
+        /// 获取更新的服务器端的数据信息
+        /// </summary>
+        /// <param name="url">自动更新的URL信息</param>
+        /// <returns></returns>
+        private static List<RemoteInfo> GetServer(string url)
+        {
+            ServicePointManager.ServerCertificateValidationCallback += RemoteCertificateValidate;
+            List<RemoteInfo> list = new List<RemoteInfo>();
+            XmlReader xml = XmlReader.Create(url);
+            XmlDocument xdoc = new XmlDocument();
+            xdoc.Load(url);
+            var root = xdoc.DocumentElement;
+            var listNodes = root.SelectNodes("/ServerUpdate/item");
+            foreach (XmlNode item in listNodes)
+            {
+                RemoteInfo remote = new RemoteInfo();
+                foreach (XmlNode pItem in item.ChildNodes)
+                {
+                    remote.GetType().GetProperty(pItem.Name).SetValue(remote, pItem.InnerText, null);
+                }
+                list.Add(remote);
+            }
+            return list;
+        }
+        private static bool RemoteCertificateValidate(
+              object sender, X509Certificate cert,
+               X509Chain chain, SslPolicyErrors error)
+        {
+            System.Console.WriteLine("Warning, trust any certificate");
+            return true;
+        }
+
+        /// <summary>
+        /// 下载方法
+        /// </summary>
+        private UpdateWork DownLoad()
+        {
+            //比如uri=http://localhost/Rabom/1.rar;iis就需要自己配置了。
+            //截取文件名
+            //构造文件完全限定名,准备将网络流下载为本地文件
+            using (WebClient web = new WebClient())
+            {
+                foreach (var item in UpdateVerList)
+                {
+                    try
+                    {
+                        LogTool.AddLog("更新程序:下载更新包文件" + item.ReleaseVersion);
+                        web.DownloadFile(item.ReleaseUrl, tempPath + item.ReleaseVersion + ".zip");
+                        OnUpdateProgess?.Invoke(60 / UpdateVerList.Count);
+                    }
+                    catch (Exception ex)
+                    {
+                        LogTool.AddLog("更新程序:更新包文件" + item.ReleaseVersion + "下载失败,本次停止更新,异常信息:" + ex.Message);
+                        throw ex;
+                    }
+                }
+                return this;
+            }
+        }
+
+        /// <summary>
+        /// 备份当前的程序目录信息
+        /// </summary>
+        private UpdateWork Bak()
+        {
+            try
+            {
+
+                LogTool.AddLog("更新程序:准备执行备份操作");
+
+                DirectoryInfo di = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);
+                foreach (var item in di.GetFiles())
+                {
+                    if (item.Name != mainName)//当前文件不需要备份
+                    {
+                        File.Copy(item.FullName, bakPath + item.Name, true);
+                    }
+                }
+                //文件夹复制
+                foreach (var item in di.GetDirectories())
+                {
+                    if (item.Name != "bak" && item.Name != "temp")
+                    {
+                        CopyDirectory(item.FullName, bakPath);
+                    }
+                }
+                LogTool.AddLog("更新程序:备份操作执行完成,开始关闭应用程序");
+                OnUpdateProgess?.Invoke(20);
+                return this;
+            }
+            catch (Exception EX)
+            {
+                throw EX;
+            }
+        }
+
+        private UpdateWork Update()
+        {
+            foreach (var item in UpdateVerList)
+            {
+                try
+                {
+                    //如果是覆盖安装的话,先删除原先的所有程序
+                    if (item.UpdateMode == "Cover")
+                    {
+                        DelLocal();
+                    }
+                    string path = tempPath + item.ReleaseVersion + ".zip";
+                    using (ZipFile zip = new ZipFile(path))
+                    {
+                        LogTool.AddLog("更新程序:解压" + item.ReleaseVersion + ".zip");
+                        zip.ExtractAll(AppDomain.CurrentDomain.BaseDirectory, ExtractExistingFileAction.OverwriteSilently);
+                        LogTool.AddLog("更新程序:" + item.ReleaseVersion + ".zip" + "解压完成");
+                        ExecuteINI();//执行注册表等更新以及删除文件
+                    }
+                    localInfo.LastUdpate = item.ReleaseDate;
+                    localInfo.LocalVersion = item.ReleaseVersion;
+                    localInfo.SaveXml();
+                }
+                catch (Exception ex)
+                {
+                    LogTool.AddLog("更新程序出现异常:异常信息:" + ex.Message);
+                    LogTool.AddLog("更新程序:更新失败,进行回滚操作");
+                    Restore();
+                    break;
+                }
+                finally
+                {
+                    //删除下载的临时文件
+                    LogTool.AddLog("更新程序:删除临时文件" + item.ReleaseVersion);
+                    DelTempFile(item.ReleaseVersion + ".zip");//删除更新包
+                    LogTool.AddLog("更新程序:临时文件删除完成" + item.ReleaseVersion);
+                }
+            }
+            OnUpdateProgess?.Invoke(98);
+            return this;
+        }
+
+        private UpdateWork Start()
+        {
+            try
+            {
+                var processPath = appPath + "EapForIdle.exe";
+                Process.Start(processPath);
+                //CopyFile();
+                //String[] StartInfo = UpdateVerList[UpdateVerList.Count - 1].ApplicationStart.Split(',');
+                //if (StartInfo.Length > 0)
+                //{
+                //    foreach (var item in StartInfo)
+                //    {
+                //        LogTool.AddLog("更新程序:启动" + item);
+                //        Process.Start(Path.Combine(AppDomain.CurrentDomain.BaseDirectory + @"Debug\", item));
+                //    }
+                //}
+                //OnUpdateProgess?.Invoke(100);
+                return this;
+            }
+            catch (Exception ex)
+            {
+                LogTool.AddLog(ex.ToString());
+                return this;
+            }
+        }
+
+        public void CopyFile()
+        {
+            try
+            {
+                string sourceName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Local.xml");
+                string folderPath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Debug");
+                if (!Directory.Exists(folderPath))
+                {
+                    Directory.CreateDirectory(folderPath);
+                }
+                string fileName = Path.GetFileName(sourceName);
+                string targetPath = Path.Combine(folderPath, fileName);
+                FileInfo file = new FileInfo(sourceName);
+                if (file.Exists)
+                {
+                    file.CopyTo(targetPath, true);
+                }
+            }
+            catch (Exception ex)
+            {
+                LogTool.AddLog(ex.ToString());
+            }
+        }
+
+        /// <summary>
+        /// 文件拷贝
+        /// </summary>
+        /// <param name="srcdir">源目录</param>
+        /// <param name="desdir">目标目录</param>
+        private UpdateWork CopyDirectory(string srcdir, string desdir)
+        {
+            string folderName = srcdir.Substring(srcdir.LastIndexOf("\\") + 1);
+
+            string desfolderdir = desdir + "\\" + folderName;
+
+            if (desdir.LastIndexOf("\\") == (desdir.Length - 1))
+            {
+                desfolderdir = desdir + folderName;
+            }
+            string[] filenames = Directory.GetFileSystemEntries(srcdir);
+            foreach (string file in filenames)// 遍历所有的文件和目录
+            {
+                if (Directory.Exists(file))// 先当作目录处理如果存在这个目录就递归Copy该目录下面的文件
+                {
+                    string currentdir = desfolderdir + "\\" + file.Substring(file.LastIndexOf("\\") + 1);
+                    if (!Directory.Exists(currentdir))
+                    {
+                        Directory.CreateDirectory(currentdir);
+                    }
+                    CopyDirectory(file, desfolderdir);
+                }
+                else // 否则直接copy文件
+                {
+                    string srcfileName = file.Substring(file.LastIndexOf("\\") + 1);
+                    srcfileName = desfolderdir + "\\" + srcfileName;
+                    if (!Directory.Exists(desfolderdir))
+                    {
+                        Directory.CreateDirectory(desfolderdir);
+                    }
+                    File.Copy(file, srcfileName, true);
+                }
+            }
+            return this;
+        }
+
+        /// <summary>
+        /// 删除临时文件
+        /// </summary>
+        private UpdateWork DelTempFile(String name)
+        {
+            FileInfo file = new FileInfo(tempPath + name);
+            file.Delete();
+            return this;
+        }
+
+        /// <summary>
+        /// 更新失败的情况下,回滚当前更新
+        /// </summary>
+        private UpdateWork Restore()
+        {
+            DelLocal();
+            CopyDirectory(bakPath, appPath);
+            return this;
+        }
+
+        /// <summary>
+        /// 删除本地文件夹的文件
+        /// </summary>
+        private UpdateWork DelLocal()
+        {
+            DirectoryInfo di = new DirectoryInfo(appPath);
+            foreach (var item in di.GetFiles())
+            {
+                if (item.Name != mainName)
+                {
+                    if (item.Name == "Local.xml")
+                    {
+                    }
+                    else
+                    {
+                        File.Delete(item.FullName);
+                    }
+                }
+            }
+            foreach (var item in di.GetDirectories())
+            {
+                if (item.Name != "bak" && item.Name != "temp")
+                {
+                    item.Delete(true);
+                }
+            }
+            return this;
+        }
+
+        /// <summary>
+        /// 校验程序版本号
+        /// </summary>
+        /// <param name="LocalVer">当前本地版本信息</param>
+        /// <returns></returns>
+        private UpdateWork CheckVer(string LocalVer, string localIgnoreVer, string isClickUpdate)
+        {
+            string[] Local = LocalVer.Split('.');
+            string[] LocalIgnore = localIgnoreVer.Split('.');
+            List<RemoteInfo> list = new List<RemoteInfo>();
+            List<RemoteInfo> listReal = new List<RemoteInfo>();
+            foreach (var item in UpdateVerList)
+            {
+                string[] Remote = item.ReleaseVersion.Split('.');
+                for (int i = 0; i < Local.Length; i++)
+                {
+                    if (int.Parse(Local[i]) < int.Parse(Remote[i]))
+                    {
+                        list.Add(item);
+                        break;
+                    }
+                    else if (int.Parse(Local[i]) == int.Parse(Remote[i]))
+                    {
+                        continue;
+                    }
+                    else
+                    {
+                        break;
+                    }
+                }
+            }
+            if (isClickUpdate == "0")
+            {
+                foreach (var item in list)
+                {
+                    string[] Remote = item.ReleaseVersion.Split('.');
+                    for (int i = 0; i < LocalIgnore.Length; i++)
+                    {
+                        if (int.Parse(LocalIgnore[i]) < int.Parse(Remote[i]))
+                        {
+                            listReal.Add(item);
+                            break;
+                        }
+                        else if (int.Parse(LocalIgnore[i]) == int.Parse(Remote[i]))
+                        {
+                            continue;
+                        }
+                        else
+                        {
+                            break;
+                        }
+                    }
+                }
+            }
+            else
+            {
+                listReal = list;
+            }
+            UpdateVerList = listReal;
+            return this;
+        }
+
+        /// <summary>
+        /// 更新配置信息
+        /// </summary>
+        private UpdateWork ExecuteINI()
+        {
+            DirectoryInfo TheFolder = new DirectoryInfo(appPath);
+
+            if (File.Exists(Path.Combine(TheFolder.FullName, "config.update")))
+            {
+                string[] ss = File.ReadAllLines(Path.Combine(TheFolder.FullName, "config.update"));
+                Int32 i = -1;//0[regedit_del] 表示注册表删除‘1[regedit_add]表示注册表新增 2[file_del] 表示删除文件
+                foreach (var s in ss)
+                {
+                    String s1 = s.Trim();
+                    if (s1 == "[regedit_del]")
+                    {
+                        i = 0;
+                    }
+                    else if (s1 == "[regedit_add]")
+                    {
+                        i = 1;
+                    }
+                    else if (s1 == "[file_del]")
+                    {
+                        i = 2;
+                    }
+                    else
+                    {
+                        if (i == 0)
+                        {
+                            string[] tempKeys = s1.Split(',');
+                            DelRegistryKey(tempKeys[0], tempKeys[1]);
+                        }
+                        else if (i == 1)
+                        {
+                            string[] values = s1.Split('=');
+                            string[] tempKeys = values[0].Split(',');
+                            SetRegistryKey(tempKeys[0], tempKeys[1], values[1]);
+                        }
+                        else if (i == 2)
+                        {
+                            DelFile(Path.Combine(appPath, s1));
+                        }
+                    }
+                }
+                DelFile(Path.Combine(TheFolder.FullName, "config.update"));
+            }
+            return this;
+        }
+
+        /// <summary>
+        /// 删除文件
+        /// </summary>
+        private UpdateWork DelFile(string name)
+        {
+            if (File.Exists(Path.Combine(appPath, name)))
+            {
+                FileInfo file = new FileInfo(Path.Combine(appPath, name));
+                file.Delete();
+            }
+            return this;
+        }
+
+        /// <summary>
+        /// 校验当前程序是否在运行
+        /// </summary>
+        /// <param name="programName"></param>
+        /// <returns></returns>
+        public bool CheckProcessExist()
+        {
+            return Process.GetProcessesByName(programName).Length > 0 ? true : false;
+        }
+
+        /// <summary>
+        /// 杀掉当前运行的程序进程
+        /// </summary>
+        /// <param name="programName">程序名称</param>
+        public void KillProcessExist()
+        {
+            Process[] processes = Process.GetProcessesByName(programName);
+            foreach (Process p in processes)
+            {
+                p.Kill();
+                p.Close();
+                p.Dispose();
+            }
+        }
+
+        #region 暂时没用,如果需要将本地版本放注册表的话 那是有用的
+        /// <summary>
+        /// 设置注册表值
+        /// </summary>
+        /// <param name="subKey"></param>
+        /// <param name="key"></param>
+        /// <param name="value"></param>
+        private void SetRegistryKey(String subKey, String key, String value)
+        {
+            RegistryKey reg;
+            RegistryKey reglocal = Registry.CurrentUser;
+
+            reg = reglocal.OpenSubKey(subKey, true);
+            if (reg == null)
+                reg = reglocal.CreateSubKey(subKey);
+            reg.SetValue(key, value, RegistryValueKind.String);
+            if (reg != null)
+            {
+                reg.Close();
+            }
+        }
+        private void DelRegistryKey(String subKey, String key)
+        {
+            RegistryKey reg;
+            RegistryKey reglocal = Registry.CurrentUser;
+
+            reg = reglocal.OpenSubKey(subKey, true);
+            if (reg != null)
+            {
+                var res = reg.GetValue(key);
+                if (res != null)
+                {
+                    reg.DeleteValue(key);
+
+                }
+            }
+            reg.Close();
+        }
+        #endregion
+    }
+}

+ 101 - 0
backend/AutoUpdate/MAutoUpdate/YButton.cs

@@ -0,0 +1,101 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Drawing;
+using System.Data;
+using System.Text;
+using System.Windows.Forms;
+
+namespace MAutoUpdate.Control
+{
+    public partial class YButton : Label
+    {
+        private Boolean isColorChange = true;
+        private Boolean isFontChange = false;
+
+        public Boolean IsFontChange
+        {
+            get { return isFontChange; }
+            set { isFontChange = value; }
+        }
+
+        public Boolean IsColorChange
+        {
+            get { return isColorChange; }
+            set { isColorChange = value; }
+        }
+        private Color normalColor = Color.FromArgb(56, 95, 170);
+
+        public Color NormalColor
+        {
+            get { return normalColor; }
+            set { normalColor = value; }
+        }
+        private Color moveColor = Color.FromArgb(128, 156, 211);
+
+        public Color MoveColor
+        {
+            get { return moveColor; }
+            set { moveColor = value; }
+        }
+        private Color moveFontColor = Color.FromArgb(128, 156, 211);
+
+        public Color MoveFontColor
+        {
+            get { return moveFontColor; }
+            set { moveFontColor = value; }
+        }
+        private Color normalFontColor = Color.FromArgb(128, 156, 211);
+
+        public Color NormalFontColor
+        {
+            get { return normalFontColor; }
+            set { normalFontColor = value; }
+        }
+        public Image EnterImage { get; set; }
+
+        public YButton()
+            : base()
+        {
+            this.Size = new Size(61, 23);
+            this.ForeColor = Color.FromArgb(240, 240, 240);
+            this.BackColor = normalColor;
+            this.TextAlign = ContentAlignment.MiddleCenter;
+            this.AutoSize = false;
+        }
+
+        protected override void OnMouseEnter(EventArgs e)
+        {
+            if (isColorChange)
+            {
+                this.BackColor = moveColor;
+            }
+            if (isFontChange)
+            {
+                this.ForeColor =this.moveFontColor;
+            }
+
+            base.OnMouseEnter(e);
+        }
+
+        protected override void OnMouseLeave(EventArgs e)
+        {
+            if (isColorChange)
+            {
+                this.BackColor = normalColor;
+            }
+            if (isFontChange)
+            {
+                this.ForeColor = this.normalFontColor;
+            }
+            base.OnMouseLeave(e);
+        }
+
+        protected override void OnPaint(PaintEventArgs e)
+        {
+            base.OnPaint(e);
+
+        }
+
+    }
+}

+ 829 - 0
backend/AutoUpdate/MAutoUpdate/Zip DLL/CRC32.cs

@@ -0,0 +1,829 @@
+// CRC32.cs
+// ------------------------------------------------------------------
+//
+// Copyright (c) 2011 Dino Chiesa.
+// All rights reserved.
+//
+// This code module is part of DotNetZip, a zipfile class library.
+//
+// ------------------------------------------------------------------
+//
+// This code is licensed under the Microsoft Public License.
+// See the file License.txt for the license details.
+// More info on: http://dotnetzip.codeplex.com
+//
+// ------------------------------------------------------------------
+//
+// Last Saved: <2011-August-02 18:25:54>
+//
+// ------------------------------------------------------------------
+//
+// This module defines the CRC32 class, which can do the CRC32 algorithm, using
+// arbitrary starting polynomials, and bit reversal. The bit reversal is what
+// distinguishes this CRC-32 used in BZip2 from the CRC-32 that is used in PKZIP
+// files, or GZIP files. This class does both.
+//
+// ------------------------------------------------------------------
+
+
+using System;
+using Interop = System.Runtime.InteropServices;
+
+namespace Ionic.Crc
+{
+    /// <summary>
+    ///   Computes a CRC-32. The CRC-32 algorithm is parameterized - you
+    ///   can set the polynomial and enable or disable bit
+    ///   reversal. This can be used for GZIP, BZip2, or ZIP.
+    /// </summary>
+    /// <remarks>
+    ///   This type is used internally by DotNetZip; it is generally not used
+    ///   directly by applications wishing to create, read, or manipulate zip
+    ///   archive files.
+    /// </remarks>
+
+#if !PCL
+    [Interop.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000C")]
+    [Interop.ComVisible(true)]
+#if !NETCF
+    [Interop.ClassInterface(Interop.ClassInterfaceType.AutoDispatch)]
+#endif
+#endif
+    public class CRC32
+    {
+        /// <summary>
+        ///   Indicates the total number of bytes applied to the CRC.
+        /// </summary>
+        public Int64 TotalBytesRead
+        {
+            get
+            {
+                return _TotalBytesRead;
+            }
+        }
+
+        /// <summary>
+        /// Indicates the current CRC for all blocks slurped in.
+        /// </summary>
+        public Int32 Crc32Result
+        {
+            get
+            {
+                return unchecked((Int32)(~_register));
+            }
+        }
+
+        /// <summary>
+        /// Returns the CRC32 for the specified stream.
+        /// </summary>
+        /// <param name="input">The stream over which to calculate the CRC32</param>
+        /// <returns>the CRC32 calculation</returns>
+        public Int32 GetCrc32(System.IO.Stream input)
+        {
+            return GetCrc32AndCopy(input, null);
+        }
+
+        /// <summary>
+        /// Returns the CRC32 for the specified stream, and writes the input into the
+        /// output stream.
+        /// </summary>
+        /// <param name="input">The stream over which to calculate the CRC32</param>
+        /// <param name="output">The stream into which to deflate the input</param>
+        /// <returns>the CRC32 calculation</returns>
+        public Int32 GetCrc32AndCopy(System.IO.Stream input, System.IO.Stream output)
+        {
+            if (input == null)
+                throw new Exception("The input stream must not be null.");
+
+            unchecked
+            {
+                byte[] buffer = new byte[BUFFER_SIZE];
+                int readSize = BUFFER_SIZE;
+
+                _TotalBytesRead = 0;
+                int count = input.Read(buffer, 0, readSize);
+                if (output != null) output.Write(buffer, 0, count);
+                _TotalBytesRead += count;
+                while (count > 0)
+                {
+                    SlurpBlock(buffer, 0, count);
+                    count = input.Read(buffer, 0, readSize);
+                    if (output != null) output.Write(buffer, 0, count);
+                    _TotalBytesRead += count;
+                }
+
+                return (Int32)(~_register);
+            }
+        }
+
+
+        /// <summary>
+        ///   Get the CRC32 for the given (word,byte) combo.  This is a
+        ///   computation defined by PKzip for PKZIP 2.0 (weak) encryption.
+        /// </summary>
+        /// <param name="W">The word to start with.</param>
+        /// <param name="B">The byte to combine it with.</param>
+        /// <returns>The CRC-ized result.</returns>
+        public Int32 ComputeCrc32(Int32 W, byte B)
+        {
+            return _InternalComputeCrc32((UInt32)W, B);
+        }
+
+        internal Int32 _InternalComputeCrc32(UInt32 W, byte B)
+        {
+            return (Int32)(crc32Table[(W ^ B) & 0xFF] ^ (W >> 8));
+        }
+
+
+        /// <summary>
+        /// Update the value for the running CRC32 using the given block of bytes.
+        /// This is useful when using the CRC32() class in a Stream.
+        /// </summary>
+        /// <param name="block">block of bytes to slurp</param>
+        /// <param name="offset">starting point in the block</param>
+        /// <param name="count">how many bytes within the block to slurp</param>
+        public void SlurpBlock(byte[] block, int offset, int count)
+        {
+            if (block == null)
+                throw new Exception("The data buffer must not be null.");
+
+            // bzip algorithm
+            for (int i = 0; i < count; i++)
+            {
+                int x = offset + i;
+                byte b = block[x];
+                if (this.reverseBits)
+                {
+                    UInt32 temp = (_register >> 24) ^ b;
+                    _register = (_register << 8) ^ crc32Table[temp];
+                }
+                else
+                {
+                    UInt32 temp = (_register & 0x000000FF) ^ b;
+                    _register = (_register >> 8) ^ crc32Table[temp];
+                }
+            }
+            _TotalBytesRead += count;
+        }
+
+
+        /// <summary>
+        ///   Process one byte in the CRC.
+        /// </summary>
+        /// <param name = "b">the byte to include into the CRC .  </param>
+        public void UpdateCRC(byte b)
+        {
+            if (this.reverseBits)
+            {
+                UInt32 temp = (_register >> 24) ^ b;
+                _register = (_register << 8) ^ crc32Table[temp];
+            }
+            else
+            {
+                UInt32 temp = (_register & 0x000000FF) ^ b;
+                _register = (_register >> 8) ^ crc32Table[temp];
+            }
+        }
+
+        /// <summary>
+        ///   Process a run of N identical bytes into the CRC.
+        /// </summary>
+        /// <remarks>
+        ///   <para>
+        ///     This method serves as an optimization for updating the CRC when a
+        ///     run of identical bytes is found. Rather than passing in a buffer of
+        ///     length n, containing all identical bytes b, this method accepts the
+        ///     byte value and the length of the (virtual) buffer - the length of
+        ///     the run.
+        ///   </para>
+        /// </remarks>
+        /// <param name = "b">the byte to include into the CRC.  </param>
+        /// <param name = "n">the number of times that byte should be repeated. </param>
+        public void UpdateCRC(byte b, int n)
+        {
+            while (n-- > 0)
+            {
+                if (this.reverseBits)
+                {
+                    uint temp = (_register >> 24) ^ b;
+                    _register = (_register << 8) ^ crc32Table[(temp >= 0)
+                                                              ? temp
+                                                              : (temp + 256)];
+                }
+                else
+                {
+                    UInt32 temp = (_register & 0x000000FF) ^ b;
+                    _register = (_register >> 8) ^ crc32Table[(temp >= 0)
+                                                              ? temp
+                                                              : (temp + 256)];
+
+                }
+            }
+        }
+
+
+
+        private static uint ReverseBits(uint data)
+        {
+            unchecked
+            {
+                uint ret = data;
+                ret = (ret & 0x55555555) << 1 | (ret >> 1) & 0x55555555;
+                ret = (ret & 0x33333333) << 2 | (ret >> 2) & 0x33333333;
+                ret = (ret & 0x0F0F0F0F) << 4 | (ret >> 4) & 0x0F0F0F0F;
+                ret = (ret << 24) | ((ret & 0xFF00) << 8) | ((ret >> 8) & 0xFF00) | (ret >> 24);
+                return ret;
+            }
+        }
+
+        private static byte ReverseBits(byte data)
+        {
+            unchecked
+            {
+                uint u = (uint)data * 0x00020202;
+                uint m = 0x01044010;
+                uint s = u & m;
+                uint t = (u << 2) & (m << 1);
+                return (byte)((0x01001001 * (s + t)) >> 24);
+            }
+        }
+
+
+
+        private void GenerateLookupTable()
+        {
+            crc32Table = new UInt32[256];
+            unchecked
+            {
+                UInt32 dwCrc;
+                byte i = 0;
+                do
+                {
+                    dwCrc = i;
+                    for (byte j = 8; j > 0; j--)
+                    {
+                        if ((dwCrc & 1) == 1)
+                        {
+                            dwCrc = (dwCrc >> 1) ^ dwPolynomial;
+                        }
+                        else
+                        {
+                            dwCrc >>= 1;
+                        }
+                    }
+                    if (reverseBits)
+                    {
+                        crc32Table[ReverseBits(i)] = ReverseBits(dwCrc);
+                    }
+                    else
+                    {
+                        crc32Table[i] = dwCrc;
+                    }
+                    i++;
+                } while (i!=0);
+            }
+
+#if VERBOSE
+            Console.WriteLine();
+            Console.WriteLine("private static readonly UInt32[] crc32Table = {");
+            for (int i = 0; i < crc32Table.Length; i+=4)
+            {
+                Console.Write("   ");
+                for (int j=0; j < 4; j++)
+                {
+                    Console.Write(" 0x{0:X8}U,", crc32Table[i+j]);
+                }
+                Console.WriteLine();
+            }
+            Console.WriteLine("};");
+            Console.WriteLine();
+#endif
+        }
+
+
+        private uint gf2_matrix_times(uint[] matrix, uint vec)
+        {
+            uint sum = 0;
+            int i=0;
+            while (vec != 0)
+            {
+                if ((vec & 0x01)== 0x01)
+                    sum ^= matrix[i];
+                vec >>= 1;
+                i++;
+            }
+            return sum;
+        }
+
+        private void gf2_matrix_square(uint[] square, uint[] mat)
+        {
+            for (int i = 0; i < 32; i++)
+                square[i] = gf2_matrix_times(mat, mat[i]);
+        }
+
+
+
+        /// <summary>
+        ///   Combines the given CRC32 value with the current running total.
+        /// </summary>
+        /// <remarks>
+        ///   This is useful when using a divide-and-conquer approach to
+        ///   calculating a CRC.  Multiple threads can each calculate a
+        ///   CRC32 on a segment of the data, and then combine the
+        ///   individual CRC32 values at the end.
+        /// </remarks>
+        /// <param name="crc">the crc value to be combined with this one</param>
+        /// <param name="length">the length of data the CRC value was calculated on</param>
+        public void Combine(int crc, int length)
+        {
+            uint[] even = new uint[32];     // even-power-of-two zeros operator
+            uint[] odd = new uint[32];      // odd-power-of-two zeros operator
+
+            if (length == 0)
+                return;
+
+            uint crc1= ~_register;
+            uint crc2= (uint) crc;
+
+            // put operator for one zero bit in odd
+            odd[0] = this.dwPolynomial;  // the CRC-32 polynomial
+            uint row = 1;
+            for (int i = 1; i < 32; i++)
+            {
+                odd[i] = row;
+                row <<= 1;
+            }
+
+            // put operator for two zero bits in even
+            gf2_matrix_square(even, odd);
+
+            // put operator for four zero bits in odd
+            gf2_matrix_square(odd, even);
+
+            uint len2 = (uint) length;
+
+            // apply len2 zeros to crc1 (first square will put the operator for one
+            // zero byte, eight zero bits, in even)
+            do {
+                // apply zeros operator for this bit of len2
+                gf2_matrix_square(even, odd);
+
+                if ((len2 & 1)== 1)
+                    crc1 = gf2_matrix_times(even, crc1);
+                len2 >>= 1;
+
+                if (len2 == 0)
+                    break;
+
+                // another iteration of the loop with odd and even swapped
+                gf2_matrix_square(odd, even);
+                if ((len2 & 1)==1)
+                    crc1 = gf2_matrix_times(odd, crc1);
+                len2 >>= 1;
+
+
+            } while (len2 != 0);
+
+            crc1 ^= crc2;
+
+            _register= ~crc1;
+
+            //return (int) crc1;
+            return;
+        }
+
+
+        /// <summary>
+        ///   Create an instance of the CRC32 class using the default settings: no
+        ///   bit reversal, and a polynomial of 0xEDB88320.
+        /// </summary>
+        public CRC32() : this(false)
+        {
+        }
+
+        /// <summary>
+        ///   Create an instance of the CRC32 class, specifying whether to reverse
+        ///   data bits or not.
+        /// </summary>
+        /// <param name='reverseBits'>
+        ///   specify true if the instance should reverse data bits.
+        /// </param>
+        /// <remarks>
+        ///   <para>
+        ///     In the CRC-32 used by BZip2, the bits are reversed. Therefore if you
+        ///     want a CRC32 with compatibility with BZip2, you should pass true
+        ///     here. In the CRC-32 used by GZIP and PKZIP, the bits are not
+        ///     reversed; Therefore if you want a CRC32 with compatibility with
+        ///     those, you should pass false.
+        ///   </para>
+        /// </remarks>
+        public CRC32(bool reverseBits) :
+            this( unchecked((int)0xEDB88320), reverseBits)
+        {
+        }
+
+
+        /// <summary>
+        ///   Create an instance of the CRC32 class, specifying the polynomial and
+        ///   whether to reverse data bits or not.
+        /// </summary>
+        /// <param name='polynomial'>
+        ///   The polynomial to use for the CRC, expressed in the reversed (LSB)
+        ///   format: the highest ordered bit in the polynomial value is the
+        ///   coefficient of the 0th power; the second-highest order bit is the
+        ///   coefficient of the 1 power, and so on. Expressed this way, the
+        ///   polynomial for the CRC-32C used in IEEE 802.3, is 0xEDB88320.
+        /// </param>
+        /// <param name='reverseBits'>
+        ///   specify true if the instance should reverse data bits.
+        /// </param>
+        ///
+        /// <remarks>
+        ///   <para>
+        ///     In the CRC-32 used by BZip2, the bits are reversed. Therefore if you
+        ///     want a CRC32 with compatibility with BZip2, you should pass true
+        ///     here for the <c>reverseBits</c> parameter. In the CRC-32 used by
+        ///     GZIP and PKZIP, the bits are not reversed; Therefore if you want a
+        ///     CRC32 with compatibility with those, you should pass false for the
+        ///     <c>reverseBits</c> parameter.
+        ///   </para>
+        /// </remarks>
+        public CRC32(int polynomial, bool reverseBits)
+        {
+            this.reverseBits = reverseBits;
+            this.dwPolynomial = (uint) polynomial;
+            this.GenerateLookupTable();
+        }
+
+        /// <summary>
+        ///   Reset the CRC-32 class - clear the CRC "remainder register."
+        /// </summary>
+        /// <remarks>
+        ///   <para>
+        ///     Use this when employing a single instance of this class to compute
+        ///     multiple, distinct CRCs on multiple, distinct data blocks.
+        ///   </para>
+        /// </remarks>
+        public void Reset()
+        {
+            _register = 0xFFFFFFFFU;
+        }
+
+        // private member vars
+        private UInt32 dwPolynomial;
+        private Int64 _TotalBytesRead;
+        private bool reverseBits;
+        private UInt32[] crc32Table;
+        private const int BUFFER_SIZE = 8192;
+        private UInt32 _register = 0xFFFFFFFFU;
+    }
+
+
+    /// <summary>
+    /// A Stream that calculates a CRC32 (a checksum) on all bytes read,
+    /// or on all bytes written.
+    /// </summary>
+    ///
+    /// <remarks>
+    /// <para>
+    /// This class can be used to verify the CRC of a ZipEntry when
+    /// reading from a stream, or to calculate a CRC when writing to a
+    /// stream.  The stream should be used to either read, or write, but
+    /// not both.  If you intermix reads and writes, the results are not
+    /// defined.
+    /// </para>
+    ///
+    /// <para>
+    /// This class is intended primarily for use internally by the
+    /// DotNetZip library.
+    /// </para>
+    /// </remarks>
+    public class CrcCalculatorStream : System.IO.Stream, IDisposable
+    {
+        static readonly Int64 UnsetLengthLimit = -99;
+
+        readonly System.IO.Stream _innerStream;
+        readonly CRC32 _crc32;
+        readonly Int64 _lengthLimit = -99;
+        bool _leaveOpen;
+
+        /// <summary>
+        /// The default constructor.
+        /// </summary>
+        /// <remarks>
+        ///   <para>
+        ///     Instances returned from this constructor will leave the underlying
+        ///     stream open upon Close().  The stream uses the default CRC32
+        ///     algorithm, which implies a polynomial of 0xEDB88320.
+        ///   </para>
+        /// </remarks>
+        /// <param name="stream">The underlying stream</param>
+        public CrcCalculatorStream(System.IO.Stream stream)
+            : this(true, UnsetLengthLimit, stream, null)
+        {
+        }
+
+        /// <summary>
+        ///   The constructor allows the caller to specify how to handle the
+        ///   underlying stream at close.
+        /// </summary>
+        /// <remarks>
+        ///   <para>
+        ///     The stream uses the default CRC32 algorithm, which implies a
+        ///     polynomial of 0xEDB88320.
+        ///   </para>
+        /// </remarks>
+        /// <param name="stream">The underlying stream</param>
+        /// <param name="leaveOpen">true to leave the underlying stream
+        /// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
+        public CrcCalculatorStream(System.IO.Stream stream, bool leaveOpen)
+            : this(leaveOpen, UnsetLengthLimit, stream, null)
+        {
+        }
+
+        /// <summary>
+        ///   A constructor allowing the specification of the length of the stream
+        ///   to read.
+        /// </summary>
+        /// <remarks>
+        ///   <para>
+        ///     The stream uses the default CRC32 algorithm, which implies a
+        ///     polynomial of 0xEDB88320.
+        ///   </para>
+        ///   <para>
+        ///     Instances returned from this constructor will leave the underlying
+        ///     stream open upon Close().
+        ///   </para>
+        /// </remarks>
+        /// <param name="stream">The underlying stream</param>
+        /// <param name="length">The length of the stream to slurp</param>
+        public CrcCalculatorStream(System.IO.Stream stream, Int64 length)
+            : this(true, length, stream, null)
+        {
+            if (length < 0)
+                throw new ArgumentException("length");
+        }
+
+        /// <summary>
+        ///   A constructor allowing the specification of the length of the stream
+        ///   to read, as well as whether to keep the underlying stream open upon
+        ///   Close().
+        /// </summary>
+        /// <remarks>
+        ///   <para>
+        ///     The stream uses the default CRC32 algorithm, which implies a
+        ///     polynomial of 0xEDB88320.
+        ///   </para>
+        /// </remarks>
+        /// <param name="stream">The underlying stream</param>
+        /// <param name="length">The length of the stream to slurp</param>
+        /// <param name="leaveOpen">true to leave the underlying stream
+        /// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
+        public CrcCalculatorStream(System.IO.Stream stream, Int64 length, bool leaveOpen)
+            : this(leaveOpen, length, stream, null)
+        {
+            if (length < 0)
+                throw new ArgumentException("length");
+        }
+
+        /// <summary>
+        ///   A constructor allowing the specification of the length of the stream
+        ///   to read, as well as whether to keep the underlying stream open upon
+        ///   Close(), and the CRC32 instance to use.
+        /// </summary>
+        /// <remarks>
+        ///   <para>
+        ///     The stream uses the specified CRC32 instance, which allows the
+        ///     application to specify how the CRC gets calculated.
+        ///   </para>
+        /// </remarks>
+        /// <param name="stream">The underlying stream</param>
+        /// <param name="length">The length of the stream to slurp</param>
+        /// <param name="leaveOpen">true to leave the underlying stream
+        /// open upon close of the <c>CrcCalculatorStream</c>; false otherwise.</param>
+        /// <param name="crc32">the CRC32 instance to use to calculate the CRC32</param>
+        public CrcCalculatorStream(System.IO.Stream stream, Int64 length, bool leaveOpen,
+                                   CRC32 crc32)
+            : this(leaveOpen, length, stream, crc32)
+        {
+            if (length < 0)
+                throw new ArgumentException("length");
+        }
+
+
+        // This ctor is private - no validation except null is done here.
+        // This is to allow the use
+        // of a (specific) negative value for the _lengthLimit, to indicate that there
+        // is no length set.  So we validate the length limit in those ctors that use an
+        // explicit param, otherwise we don't validate, because it could be our special
+        // value.
+        CrcCalculatorStream(bool leaveOpen, Int64 length, System.IO.Stream stream, CRC32 crc32)
+        {
+            if (stream == null) throw new ArgumentNullException("stream");
+            _innerStream = stream;
+            _crc32 = crc32 ?? new CRC32();
+            _lengthLimit = length;
+            _leaveOpen = leaveOpen;
+        }
+
+
+        /// <summary>
+        ///   Gets the total number of bytes run through the CRC32 calculator.
+        /// </summary>
+        ///
+        /// <remarks>
+        ///   This is either the total number of bytes read, or the total number of
+        ///   bytes written, depending on the direction of this stream.
+        /// </remarks>
+        public Int64 TotalBytesSlurped
+        {
+            get { return _crc32.TotalBytesRead; }
+        }
+
+        /// <summary>
+        ///   Provides the current CRC for all blocks slurped in.
+        /// </summary>
+        /// <remarks>
+        ///   <para>
+        ///     The running total of the CRC is kept as data is written or read
+        ///     through the stream.  read this property after all reads or writes to
+        ///     get an accurate CRC for the entire stream.
+        ///   </para>
+        /// </remarks>
+        public Int32 Crc
+        {
+            get { return _crc32.Crc32Result; }
+        }
+
+        /// <summary>
+        ///   Indicates whether the underlying stream will be left open when the
+        ///   <c>CrcCalculatorStream</c> is Closed.
+        /// </summary>
+        /// <remarks>
+        ///   <para>
+        ///     Set this at any point before calling <see cref="Close()"/>.
+        ///   </para>
+        /// </remarks>
+        public bool LeaveOpen
+        {
+            get { return _leaveOpen; }
+            set { _leaveOpen = value; }
+        }
+
+        /// <summary>
+        /// Read from the stream
+        /// </summary>
+        /// <param name="buffer">the buffer to read</param>
+        /// <param name="offset">the offset at which to start</param>
+        /// <param name="count">the number of bytes to read</param>
+        /// <returns>the number of bytes actually read</returns>
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            int bytesToRead = count;
+
+            // Need to limit the # of bytes returned, if the stream is intended to have
+            // a definite length.  This is especially useful when returning a stream for
+            // the uncompressed data directly to the application.  The app won't
+            // necessarily read only the UncompressedSize number of bytes.  For example
+            // wrapping the stream returned from OpenReader() into a StreadReader() and
+            // calling ReadToEnd() on it, We can "over-read" the zip data and get a
+            // corrupt string.  The length limits that, prevents that problem.
+
+            if (_lengthLimit != CrcCalculatorStream.UnsetLengthLimit)
+            {
+                if (_crc32.TotalBytesRead >= _lengthLimit) return 0; // EOF
+                Int64 bytesRemaining = _lengthLimit - _crc32.TotalBytesRead;
+                if (bytesRemaining < count) bytesToRead = (int)bytesRemaining;
+            }
+            int n = _innerStream.Read(buffer, offset, bytesToRead);
+            if (n > 0) _crc32.SlurpBlock(buffer, offset, n);
+            return n;
+        }
+
+        /// <summary>
+        /// Write to the stream.
+        /// </summary>
+        /// <param name="buffer">the buffer from which to write</param>
+        /// <param name="offset">the offset at which to start writing</param>
+        /// <param name="count">the number of bytes to write</param>
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            if (count > 0) _crc32.SlurpBlock(buffer, offset, count);
+            _innerStream.Write(buffer, offset, count);
+        }
+
+        /// <summary>
+        /// Indicates whether the stream supports reading.
+        /// </summary>
+        public override bool CanRead
+        {
+            get { return _innerStream.CanRead; }
+        }
+
+        /// <summary>
+        ///   Indicates whether the stream supports seeking.
+        /// </summary>
+        /// <remarks>
+        ///   <para>
+        ///     Always returns false.
+        ///   </para>
+        /// </remarks>
+        public override bool CanSeek
+        {
+            get { return false; }
+        }
+
+        /// <summary>
+        /// Indicates whether the stream supports writing.
+        /// </summary>
+        public override bool CanWrite
+        {
+            get { return _innerStream.CanWrite; }
+        }
+
+        /// <summary>
+        /// Flush the stream.
+        /// </summary>
+        public override void Flush()
+        {
+            _innerStream.Flush();
+        }
+
+        /// <summary>
+        ///   Returns the length of the underlying stream.
+        /// </summary>
+        public override long Length
+        {
+            get
+            {
+                if (_lengthLimit == CrcCalculatorStream.UnsetLengthLimit)
+                    return _innerStream.Length;
+                else return _lengthLimit;
+            }
+        }
+
+        /// <summary>
+        ///   The getter for this property returns the total bytes read.
+        ///   If you use the setter, it will throw
+        /// <see cref="NotSupportedException"/>.
+        /// </summary>
+        public override long Position
+        {
+            get { return _crc32.TotalBytesRead; }
+            set { throw new NotSupportedException(); }
+        }
+
+        /// <summary>
+        /// Seeking is not supported on this stream. This method always throws
+        /// <see cref="NotSupportedException"/>
+        /// </summary>
+        /// <param name="offset">N/A</param>
+        /// <param name="origin">N/A</param>
+        /// <returns>N/A</returns>
+        public override long Seek(long offset, System.IO.SeekOrigin origin)
+        {
+            throw new NotSupportedException();
+        }
+
+        /// <summary>
+        /// This method always throws
+        /// <see cref="NotSupportedException"/>
+        /// </summary>
+        /// <param name="value">N/A</param>
+        public override void SetLength(long value)
+        {
+            throw new NotSupportedException();
+        }
+
+
+        void IDisposable.Dispose()
+        {
+            InnerClose();
+        }
+
+        private void InnerClose()
+        {
+            if (!_leaveOpen)
+            {
+#if !PCL
+                _innerStream.Close();
+#else   
+                _innerStream.Dispose();
+#endif
+            }
+        }
+
+        /// <summary>
+        /// Closes the stream.
+        /// </summary>
+#if !PCL
+        public override void Close()
+        {
+            base.Close();
+            InnerClose();
+        }
+#endif
+
+    }
+
+}

+ 116 - 0
backend/AutoUpdate/MAutoUpdate/Zip DLL/ComHelper.cs

@@ -0,0 +1,116 @@
+// ComHelper.cs
+// ------------------------------------------------------------------
+//
+// Copyright (c) 2009 Dino Chiesa.
+// All rights reserved.
+//
+// This code module is part of DotNetZip, a zipfile class library.
+//
+// ------------------------------------------------------------------
+//
+// This code is licensed under the Microsoft Public License.
+// See the file License.txt for the license details.
+// More info on: http://dotnetzip.codeplex.com
+//
+// ------------------------------------------------------------------
+//
+// last saved (in emacs):
+// Time-stamp: <2011-June-13 17:04:06>
+//
+// ------------------------------------------------------------------
+//
+// This module defines a COM Helper class.
+//
+// Created: Tue, 08 Sep 2009  22:03
+//
+
+using Interop=System.Runtime.InteropServices;
+
+namespace Ionic.Zip
+{
+    /// <summary>
+    /// This class exposes a set of COM-accessible wrappers for static
+    /// methods available on the ZipFile class.  You don't need this
+    /// class unless you are using DotNetZip from a COM environment.
+    /// </summary>
+    [System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000F")]
+    [System.Runtime.InteropServices.ComVisible(true)]
+#if !NETCF
+    [System.Runtime.InteropServices.ClassInterface(System.Runtime.InteropServices.ClassInterfaceType.AutoDispatch)]
+#endif
+
+    public class ComHelper
+    {
+        /// <summary>
+        ///  A wrapper for <see cref="ZipFile.IsZipFile(string)">ZipFile.IsZipFile(string)</see>
+        /// </summary>
+        /// <param name="filename">The filename to of the zip file to check.</param>
+        /// <returns>true if the file contains a valid zip file.</returns>
+        public bool IsZipFile(string filename)
+        {
+            return ZipFile.IsZipFile(filename);
+        }
+
+        /// <summary>
+        ///  A wrapper for <see cref="ZipFile.IsZipFile(string, bool)">ZipFile.IsZipFile(string, bool)</see>
+        /// </summary>
+        /// <remarks>
+        /// We cannot use "overloaded" Method names in COM interop.
+        /// So, here, we use a unique name.
+        /// </remarks>
+        /// <param name="filename">The filename to of the zip file to check.</param>
+        /// <returns>true if the file contains a valid zip file.</returns>
+        public bool IsZipFileWithExtract(string filename)
+        {
+            return ZipFile.IsZipFile(filename, true);
+        }
+
+#if !NETCF
+        /// <summary>
+        ///  A wrapper for <see cref="ZipFile.CheckZip(string)">ZipFile.CheckZip(string)</see>
+        /// </summary>
+        /// <param name="filename">The filename to of the zip file to check.</param>
+        ///
+        /// <returns>true if the named zip file checks OK. Otherwise, false. </returns>
+        public bool CheckZip(string filename)
+        {
+            return ZipFile.CheckZip(filename);
+        }
+
+        /// <summary>
+        ///  A COM-friendly wrapper for the static method <see cref="ZipFile.CheckZipPassword(string,string)"/>.
+        /// </summary>
+        ///
+        /// <param name="filename">The filename to of the zip file to check.</param>
+        ///
+        /// <param name="password">The password to check.</param>
+        ///
+        /// <returns>true if the named zip file checks OK. Otherwise, false. </returns>
+        public bool CheckZipPassword(string filename, string password)
+        {
+            return ZipFile.CheckZipPassword(filename, password);
+        }
+
+        /// <summary>
+        ///  A wrapper for <see cref="ZipFile.FixZipDirectory(string)">ZipFile.FixZipDirectory(string)</see>
+        /// </summary>
+        /// <param name="filename">The filename to of the zip file to fix.</param>
+        public void FixZipDirectory(string filename)
+        {
+            ZipFile.FixZipDirectory(filename);
+        }
+#endif
+
+        /// <summary>
+        ///  A wrapper for <see cref="ZipFile.LibraryVersion">ZipFile.LibraryVersion</see>
+        /// </summary>
+        /// <returns>
+        ///  the version number on the DotNetZip assembly, formatted as a string.
+        /// </returns>
+        public string GetZipLibraryVersion()
+        {
+            return ZipFile.LibraryVersion.ToString();
+        }
+
+    }
+}

File diff suppressed because it is too large
+ 1879 - 0
backend/AutoUpdate/MAutoUpdate/Zip DLL/Deflate.cs


+ 740 - 0
backend/AutoUpdate/MAutoUpdate/Zip DLL/DeflateStream.cs

@@ -0,0 +1,740 @@
+// DeflateStream.cs
+// ------------------------------------------------------------------
+//
+// Copyright (c) 2009-2010 Dino Chiesa.
+// All rights reserved.
+//
+// This code module is part of DotNetZip, a zipfile class library.
+//
+// ------------------------------------------------------------------
+//
+// This code is licensed under the Microsoft Public License.
+// See the file License.txt for the license details.
+// More info on: http://dotnetzip.codeplex.com
+//
+// ------------------------------------------------------------------
+//
+// last saved (in emacs):
+// Time-stamp: <2011-July-31 14:48:11>
+//
+// ------------------------------------------------------------------
+//
+// This module defines the DeflateStream class, which can be used as a replacement for
+// the System.IO.Compression.DeflateStream class in the .NET BCL.
+//
+// ------------------------------------------------------------------
+
+
+using System;
+
+namespace Ionic.Zlib
+{
+    /// <summary>
+    /// A class for compressing and decompressing streams using the Deflate algorithm.
+    /// </summary>
+    ///
+    /// <remarks>
+    ///
+    /// <para>
+    ///   The DeflateStream is a <see
+    ///   href="http://en.wikipedia.org/wiki/Decorator_pattern">Decorator</see> on a <see
+    ///   cref="System.IO.Stream"/>.  It adds DEFLATE compression or decompression to any
+    ///   stream.
+    /// </para>
+    ///
+    /// <para>
+    ///   Using this stream, applications can compress or decompress data via stream
+    ///   <c>Read</c> and <c>Write</c> operations.  Either compresssion or decompression
+    ///   can occur through either reading or writing. The compression format used is
+    ///   DEFLATE, which is documented in <see
+    ///   href="http://www.ietf.org/rfc/rfc1951.txt">IETF RFC 1951</see>, "DEFLATE
+    ///   Compressed Data Format Specification version 1.3.".
+    /// </para>
+    ///
+    /// <para>
+    ///   This class is similar to <see cref="ZlibStream"/>, except that
+    ///   <c>ZlibStream</c> adds the <see href="http://www.ietf.org/rfc/rfc1950.txt">RFC
+    ///   1950 - ZLIB</see> framing bytes to a compressed stream when compressing, or
+    ///   expects the RFC1950 framing bytes when decompressing. The <c>DeflateStream</c>
+    ///   does not.
+    /// </para>
+    ///
+    /// </remarks>
+    ///
+    /// <seealso cref="ZlibStream" />
+    /// <seealso cref="GZipStream" />
+    public class DeflateStream : System.IO.Stream
+    {
+        internal ZlibBaseStream _baseStream;
+        internal System.IO.Stream _innerStream;
+        bool _disposed;
+
+        /// <summary>
+        ///   Create a DeflateStream using the specified CompressionMode.
+        /// </summary>
+        ///
+        /// <remarks>
+        ///   When mode is <c>CompressionMode.Compress</c>, the DeflateStream will use
+        ///   the default compression level. The "captive" stream will be closed when
+        ///   the DeflateStream is closed.
+        /// </remarks>
+        ///
+        /// <example>
+        /// This example uses a DeflateStream to compress data from a file, and writes
+        /// the compressed data to another file.
+        /// <code>
+        /// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
+        /// {
+        ///     using (var raw = System.IO.File.Create(fileToCompress + ".deflated"))
+        ///     {
+        ///         using (Stream compressor = new DeflateStream(raw, CompressionMode.Compress))
+        ///         {
+        ///             byte[] buffer = new byte[WORKING_BUFFER_SIZE];
+        ///             int n;
+        ///             while ((n= input.Read(buffer, 0, buffer.Length)) != 0)
+        ///             {
+        ///                 compressor.Write(buffer, 0, n);
+        ///             }
+        ///         }
+        ///     }
+        /// }
+        /// </code>
+        ///
+        /// <code lang="VB">
+        /// Using input As Stream = File.OpenRead(fileToCompress)
+        ///     Using raw As FileStream = File.Create(fileToCompress &amp; ".deflated")
+        ///         Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress)
+        ///             Dim buffer As Byte() = New Byte(4096) {}
+        ///             Dim n As Integer = -1
+        ///             Do While (n &lt;&gt; 0)
+        ///                 If (n &gt; 0) Then
+        ///                     compressor.Write(buffer, 0, n)
+        ///                 End If
+        ///                 n = input.Read(buffer, 0, buffer.Length)
+        ///             Loop
+        ///         End Using
+        ///     End Using
+        /// End Using
+        /// </code>
+        /// </example>
+        /// <param name="stream">The stream which will be read or written.</param>
+        /// <param name="mode">Indicates whether the DeflateStream will compress or decompress.</param>
+        public DeflateStream(System.IO.Stream stream, CompressionMode mode)
+            : this(stream, mode, CompressionLevel.Default, false)
+        {
+        }
+
+        /// <summary>
+        /// Create a DeflateStream using the specified CompressionMode and the specified CompressionLevel.
+        /// </summary>
+        ///
+        /// <remarks>
+        ///
+        /// <para>
+        ///   When mode is <c>CompressionMode.Decompress</c>, the level parameter is
+        ///   ignored.  The "captive" stream will be closed when the DeflateStream is
+        ///   closed.
+        /// </para>
+        ///
+        /// </remarks>
+        ///
+        /// <example>
+        ///
+        ///   This example uses a DeflateStream to compress data from a file, and writes
+        ///   the compressed data to another file.
+        ///
+        /// <code>
+        /// using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
+        /// {
+        ///     using (var raw = System.IO.File.Create(fileToCompress + ".deflated"))
+        ///     {
+        ///         using (Stream compressor = new DeflateStream(raw,
+        ///                                                      CompressionMode.Compress,
+        ///                                                      CompressionLevel.BestCompression))
+        ///         {
+        ///             byte[] buffer = new byte[WORKING_BUFFER_SIZE];
+        ///             int n= -1;
+        ///             while (n != 0)
+        ///             {
+        ///                 if (n &gt; 0)
+        ///                     compressor.Write(buffer, 0, n);
+        ///                 n= input.Read(buffer, 0, buffer.Length);
+        ///             }
+        ///         }
+        ///     }
+        /// }
+        /// </code>
+        ///
+        /// <code lang="VB">
+        /// Using input As Stream = File.OpenRead(fileToCompress)
+        ///     Using raw As FileStream = File.Create(fileToCompress &amp; ".deflated")
+        ///         Using compressor As Stream = New DeflateStream(raw, CompressionMode.Compress, CompressionLevel.BestCompression)
+        ///             Dim buffer As Byte() = New Byte(4096) {}
+        ///             Dim n As Integer = -1
+        ///             Do While (n &lt;&gt; 0)
+        ///                 If (n &gt; 0) Then
+        ///                     compressor.Write(buffer, 0, n)
+        ///                 End If
+        ///                 n = input.Read(buffer, 0, buffer.Length)
+        ///             Loop
+        ///         End Using
+        ///     End Using
+        /// End Using
+        /// </code>
+        /// </example>
+        /// <param name="stream">The stream to be read or written while deflating or inflating.</param>
+        /// <param name="mode">Indicates whether the <c>DeflateStream</c> will compress or decompress.</param>
+        /// <param name="level">A tuning knob to trade speed for effectiveness.</param>
+        public DeflateStream(System.IO.Stream stream, CompressionMode mode, CompressionLevel level)
+            : this(stream, mode, level, false)
+        {
+        }
+
+        /// <summary>
+        ///   Create a <c>DeflateStream</c> using the specified
+        ///   <c>CompressionMode</c>, and explicitly specify whether the
+        ///   stream should be left open after Deflation or Inflation.
+        /// </summary>
+        ///
+        /// <remarks>
+        ///
+        /// <para>
+        ///   This constructor allows the application to request that the captive stream
+        ///   remain open after the deflation or inflation occurs.  By default, after
+        ///   <c>Close()</c> is called on the stream, the captive stream is also
+        ///   closed. In some cases this is not desired, for example if the stream is a
+        ///   memory stream that will be re-read after compression.  Specify true for
+        ///   the <paramref name="leaveOpen"/> parameter to leave the stream open.
+        /// </para>
+        ///
+        /// <para>
+        ///   The <c>DeflateStream</c> will use the default compression level.
+        /// </para>
+        ///
+        /// <para>
+        ///   See the other overloads of this constructor for example code.
+        /// </para>
+        /// </remarks>
+        ///
+        /// <param name="stream">
+        ///   The stream which will be read or written. This is called the
+        ///   "captive" stream in other places in this documentation.
+        /// </param>
+        ///
+        /// <param name="mode">
+        ///   Indicates whether the <c>DeflateStream</c> will compress or decompress.
+        /// </param>
+        ///
+        /// <param name="leaveOpen">true if the application would like the stream to
+        /// remain open after inflation/deflation.</param>
+        public DeflateStream(System.IO.Stream stream, CompressionMode mode, bool leaveOpen)
+            : this(stream, mode, CompressionLevel.Default, leaveOpen)
+        {
+        }
+
+        /// <summary>
+        ///   Create a <c>DeflateStream</c> using the specified <c>CompressionMode</c>
+        ///   and the specified <c>CompressionLevel</c>, and explicitly specify whether
+        ///   the stream should be left open after Deflation or Inflation.
+        /// </summary>
+        ///
+        /// <remarks>
+        ///
+        /// <para>
+        ///   When mode is <c>CompressionMode.Decompress</c>, the level parameter is ignored.
+        /// </para>
+        ///
+        /// <para>
+        ///   This constructor allows the application to request that the captive stream
+        ///   remain open after the deflation or inflation occurs.  By default, after
+        ///   <c>Close()</c> is called on the stream, the captive stream is also
+        ///   closed. In some cases this is not desired, for example if the stream is a
+        ///   <see cref="System.IO.MemoryStream"/> that will be re-read after
+        ///   compression.  Specify true for the <paramref name="leaveOpen"/> parameter
+        ///   to leave the stream open.
+        /// </para>
+        ///
+        /// </remarks>
+        ///
+        /// <example>
+        ///
+        ///   This example shows how to use a <c>DeflateStream</c> to compress data from
+        ///   a file, and store the compressed data into another file.
+        ///
+        /// <code>
+        /// using (var output = System.IO.File.Create(fileToCompress + ".deflated"))
+        /// {
+        ///     using (System.IO.Stream input = System.IO.File.OpenRead(fileToCompress))
+        ///     {
+        ///         using (Stream compressor = new DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, true))
+        ///         {
+        ///             byte[] buffer = new byte[WORKING_BUFFER_SIZE];
+        ///             int n= -1;
+        ///             while (n != 0)
+        ///             {
+        ///                 if (n &gt; 0)
+        ///                     compressor.Write(buffer, 0, n);
+        ///                 n= input.Read(buffer, 0, buffer.Length);
+        ///             }
+        ///         }
+        ///     }
+        ///     // can write additional data to the output stream here
+        /// }
+        /// </code>
+        ///
+        /// <code lang="VB">
+        /// Using output As FileStream = File.Create(fileToCompress &amp; ".deflated")
+        ///     Using input As Stream = File.OpenRead(fileToCompress)
+        ///         Using compressor As Stream = New DeflateStream(output, CompressionMode.Compress, CompressionLevel.BestCompression, True)
+        ///             Dim buffer As Byte() = New Byte(4096) {}
+        ///             Dim n As Integer = -1
+        ///             Do While (n &lt;&gt; 0)
+        ///                 If (n &gt; 0) Then
+        ///                     compressor.Write(buffer, 0, n)
+        ///                 End If
+        ///                 n = input.Read(buffer, 0, buffer.Length)
+        ///             Loop
+        ///         End Using
+        ///     End Using
+        ///     ' can write additional data to the output stream here.
+        /// End Using
+        /// </code>
+        /// </example>
+        /// <param name="stream">The stream which will be read or written.</param>
+        /// <param name="mode">Indicates whether the DeflateStream will compress or decompress.</param>
+        /// <param name="leaveOpen">true if the application would like the stream to remain open after inflation/deflation.</param>
+        /// <param name="level">A tuning knob to trade speed for effectiveness.</param>
+        public DeflateStream(System.IO.Stream stream, CompressionMode mode, CompressionLevel level, bool leaveOpen)
+        {
+            _innerStream = stream;
+            _baseStream = new ZlibBaseStream(stream, mode, level, ZlibStreamFlavor.DEFLATE, leaveOpen);
+        }
+
+        #region Zlib properties
+
+        /// <summary>
+        /// This property sets the flush behavior on the stream.
+        /// </summary>
+        /// <remarks> See the ZLIB documentation for the meaning of the flush behavior.
+        /// </remarks>
+        virtual public FlushType FlushMode
+        {
+            get { return (this._baseStream._flushMode); }
+            set
+            {
+                if (_disposed) throw new ObjectDisposedException("DeflateStream");
+                this._baseStream._flushMode = value;
+            }
+        }
+
+        /// <summary>
+        ///   The size of the working buffer for the compression codec.
+        /// </summary>
+        ///
+        /// <remarks>
+        /// <para>
+        ///   The working buffer is used for all stream operations.  The default size is
+        ///   1024 bytes.  The minimum size is 128 bytes. You may get better performance
+        ///   with a larger buffer.  Then again, you might not.  You would have to test
+        ///   it.
+        /// </para>
+        ///
+        /// <para>
+        ///   Set this before the first call to <c>Read()</c> or <c>Write()</c> on the
+        ///   stream. If you try to set it afterwards, it will throw.
+        /// </para>
+        /// </remarks>
+        public int BufferSize
+        {
+            get
+            {
+                return this._baseStream._bufferSize;
+            }
+            set
+            {
+                if (_disposed) throw new ObjectDisposedException("DeflateStream");
+                if (this._baseStream._workingBuffer != null)
+                    throw new ZlibException("The working buffer is already set.");
+                if (value < ZlibConstants.WorkingBufferSizeMin)
+                    throw new ZlibException(String.Format("Don't be silly. {0} bytes?? Use a bigger buffer, at least {1}.", value, ZlibConstants.WorkingBufferSizeMin));
+                this._baseStream._bufferSize = value;
+            }
+        }
+
+        /// <summary>
+        ///   The ZLIB strategy to be used during compression.
+        /// </summary>
+        ///
+        /// <remarks>
+        ///   By tweaking this parameter, you may be able to optimize the compression for
+        ///   data with particular characteristics.
+        /// </remarks>
+        public CompressionStrategy Strategy
+        {
+            get
+            {
+                return this._baseStream.Strategy;
+            }
+            set
+            {
+            if (_disposed) throw new ObjectDisposedException("DeflateStream");
+                this._baseStream.Strategy = value;
+            }
+        }
+
+        /// <summary> Returns the total number of bytes input so far.</summary>
+        virtual public long TotalIn
+        {
+            get
+            {
+                return this._baseStream._z.TotalBytesIn;
+            }
+        }
+
+        /// <summary> Returns the total number of bytes output so far.</summary>
+        virtual public long TotalOut
+        {
+            get
+            {
+                return this._baseStream._z.TotalBytesOut;
+            }
+        }
+
+        #endregion
+
+        #region System.IO.Stream methods
+        /// <summary>
+        ///   Dispose the stream.
+        /// </summary>
+        /// <remarks>
+        ///   <para>
+        ///     This may or may not result in a <c>Close()</c> call on the captive
+        ///     stream.  See the constructors that have a <c>leaveOpen</c> parameter
+        ///     for more information.
+        ///   </para>
+        ///   <para>
+        ///     Application code won't call this code directly.  This method may be
+        ///     invoked in two distinct scenarios.  If disposing == true, the method
+        ///     has been called directly or indirectly by a user's code, for example
+        ///     via the public Dispose() method. In this case, both managed and
+        ///     unmanaged resources can be referenced and disposed.  If disposing ==
+        ///     false, the method has been called by the runtime from inside the
+        ///     object finalizer and this method should not reference other objects;
+        ///     in that case only unmanaged resources must be referenced or
+        ///     disposed.
+        ///   </para>
+        /// </remarks>
+        /// <param name="disposing">
+        ///   true if the Dispose method was invoked by user code.
+        /// </param>
+        protected override void Dispose(bool disposing)
+        {
+            try
+            {
+                if (!_disposed)
+                {
+                    if (disposing && (this._baseStream != null))
+                        this._baseStream.Dispose();
+                    _disposed = true;
+                }
+            }
+            finally
+            {
+                base.Dispose(disposing);
+            }
+        }
+
+
+
+        /// <summary>
+        /// Indicates whether the stream can be read.
+        /// </summary>
+        /// <remarks>
+        /// The return value depends on whether the captive stream supports reading.
+        /// </remarks>
+        public override bool CanRead
+        {
+            get
+            {
+                if (_disposed) throw new ObjectDisposedException("DeflateStream");
+                return _baseStream._stream.CanRead;
+            }
+        }
+
+        /// <summary>
+        /// Indicates whether the stream supports Seek operations.
+        /// </summary>
+        /// <remarks>
+        /// Always returns false.
+        /// </remarks>
+        public override bool CanSeek
+        {
+            get { return false; }
+        }
+
+
+        /// <summary>
+        /// Indicates whether the stream can be written.
+        /// </summary>
+        /// <remarks>
+        /// The return value depends on whether the captive stream supports writing.
+        /// </remarks>
+        public override bool CanWrite
+        {
+            get
+            {
+                if (_disposed) throw new ObjectDisposedException("DeflateStream");
+                return _baseStream._stream.CanWrite;
+            }
+        }
+
+        /// <summary>
+        /// Flush the stream.
+        /// </summary>
+        public override void Flush()
+        {
+            if (_disposed) throw new ObjectDisposedException("DeflateStream");
+            _baseStream.Flush();
+        }
+
+        /// <summary>
+        /// Reading this property always throws a <see cref="NotImplementedException"/>.
+        /// </summary>
+        public override long Length
+        {
+            get { throw new NotImplementedException(); }
+        }
+
+        /// <summary>
+        /// The position of the stream pointer.
+        /// </summary>
+        ///
+        /// <remarks>
+        ///   Setting this property always throws a <see
+        ///   cref="NotImplementedException"/>. Reading will return the total bytes
+        ///   written out, if used in writing, or the total bytes read in, if used in
+        ///   reading.  The count may refer to compressed bytes or uncompressed bytes,
+        ///   depending on how you've used the stream.
+        /// </remarks>
+        public override long Position
+        {
+            get
+            {
+                if (this._baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Writer)
+                    return this._baseStream._z.TotalBytesOut;
+                if (this._baseStream._streamMode == Ionic.Zlib.ZlibBaseStream.StreamMode.Reader)
+                    return this._baseStream._z.TotalBytesIn;
+                return 0;
+            }
+            set { throw new NotImplementedException(); }
+        }
+
+        /// <summary>
+        /// Read data from the stream.
+        /// </summary>
+        /// <remarks>
+        ///
+        /// <para>
+        ///   If you wish to use the <c>DeflateStream</c> to compress data while
+        ///   reading, you can create a <c>DeflateStream</c> with
+        ///   <c>CompressionMode.Compress</c>, providing an uncompressed data stream.
+        ///   Then call Read() on that <c>DeflateStream</c>, and the data read will be
+        ///   compressed as you read.  If you wish to use the <c>DeflateStream</c> to
+        ///   decompress data while reading, you can create a <c>DeflateStream</c> with
+        ///   <c>CompressionMode.Decompress</c>, providing a readable compressed data
+        ///   stream.  Then call Read() on that <c>DeflateStream</c>, and the data read
+        ///   will be decompressed as you read.
+        /// </para>
+        ///
+        /// <para>
+        ///   A <c>DeflateStream</c> can be used for <c>Read()</c> or <c>Write()</c>, but not both.
+        /// </para>
+        ///
+        /// </remarks>
+        /// <param name="buffer">The buffer into which the read data should be placed.</param>
+        /// <param name="offset">the offset within that data array to put the first byte read.</param>
+        /// <param name="count">the number of bytes to read.</param>
+        /// <returns>the number of bytes actually read</returns>
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            if (_disposed) throw new ObjectDisposedException("DeflateStream");
+            return _baseStream.Read(buffer, offset, count);
+        }
+
+
+        /// <summary>
+        /// Calling this method always throws a <see cref="NotImplementedException"/>.
+        /// </summary>
+        /// <param name="offset">this is irrelevant, since it will always throw!</param>
+        /// <param name="origin">this is irrelevant, since it will always throw!</param>
+        /// <returns>irrelevant!</returns>
+        public override long Seek(long offset, System.IO.SeekOrigin origin)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        /// Calling this method always throws a <see cref="NotImplementedException"/>.
+        /// </summary>
+        /// <param name="value">this is irrelevant, since it will always throw!</param>
+        public override void SetLength(long value)
+        {
+            throw new NotImplementedException();
+        }
+
+        /// <summary>
+        ///   Write data to the stream.
+        /// </summary>
+        /// <remarks>
+        ///
+        /// <para>
+        ///   If you wish to use the <c>DeflateStream</c> to compress data while
+        ///   writing, you can create a <c>DeflateStream</c> with
+        ///   <c>CompressionMode.Compress</c>, and a writable output stream.  Then call
+        ///   <c>Write()</c> on that <c>DeflateStream</c>, providing uncompressed data
+        ///   as input.  The data sent to the output stream will be the compressed form
+        ///   of the data written.  If you wish to use the <c>DeflateStream</c> to
+        ///   decompress data while writing, you can create a <c>DeflateStream</c> with
+        ///   <c>CompressionMode.Decompress</c>, and a writable output stream.  Then
+        ///   call <c>Write()</c> on that stream, providing previously compressed
+        ///   data. The data sent to the output stream will be the decompressed form of
+        ///   the data written.
+        /// </para>
+        ///
+        /// <para>
+        ///   A <c>DeflateStream</c> can be used for <c>Read()</c> or <c>Write()</c>,
+        ///   but not both.
+        /// </para>
+        ///
+        /// </remarks>
+        ///
+        /// <param name="buffer">The buffer holding data to write to the stream.</param>
+        /// <param name="offset">the offset within that data array to find the first byte to write.</param>
+        /// <param name="count">the number of bytes to write.</param>
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            if (_disposed) throw new ObjectDisposedException("DeflateStream");
+            _baseStream.Write(buffer, offset, count);
+        }
+        #endregion
+
+
+
+
+        /// <summary>
+        ///   Compress a string into a byte array using DEFLATE (RFC 1951).
+        /// </summary>
+        ///
+        /// <remarks>
+        ///   Uncompress it with <see cref="DeflateStream.UncompressString(byte[])"/>.
+        /// </remarks>
+        ///
+        /// <seealso cref="DeflateStream.UncompressString(byte[])">DeflateStream.UncompressString(byte[])</seealso>
+        /// <seealso cref="DeflateStream.CompressBuffer(byte[])">DeflateStream.CompressBuffer(byte[])</seealso>
+        /// <seealso cref="GZipStream.CompressString(string)">GZipStream.CompressString(string)</seealso>
+        /// <seealso cref="ZlibStream.CompressString(string)">ZlibStream.CompressString(string)</seealso>
+        ///
+        /// <param name="s">
+        ///   A string to compress. The string will first be encoded
+        ///   using UTF8, then compressed.
+        /// </param>
+        ///
+        /// <returns>The string in compressed form</returns>
+        public static byte[] CompressString(String s)
+        {
+            using (var ms = new System.IO.MemoryStream())
+            {
+                System.IO.Stream compressor =
+                    new DeflateStream(ms, CompressionMode.Compress, CompressionLevel.BestCompression);
+                ZlibBaseStream.CompressString(s, compressor);
+                return ms.ToArray();
+            }
+        }
+
+
+        /// <summary>
+        ///   Compress a byte array into a new byte array using DEFLATE.
+        /// </summary>
+        ///
+        /// <remarks>
+        ///   Uncompress it with <see cref="DeflateStream.UncompressBuffer(byte[])"/>.
+        /// </remarks>
+        ///
+        /// <seealso cref="DeflateStream.CompressString(string)">DeflateStream.CompressString(string)</seealso>
+        /// <seealso cref="DeflateStream.UncompressBuffer(byte[])">DeflateStream.UncompressBuffer(byte[])</seealso>
+        /// <seealso cref="GZipStream.CompressBuffer(byte[])">GZipStream.CompressBuffer(byte[])</seealso>
+        /// <seealso cref="ZlibStream.CompressBuffer(byte[])">ZlibStream.CompressBuffer(byte[])</seealso>
+        ///
+        /// <param name="b">
+        ///   A buffer to compress.
+        /// </param>
+        ///
+        /// <returns>The data in compressed form</returns>
+        public static byte[] CompressBuffer(byte[] b)
+        {
+            using (var ms = new System.IO.MemoryStream())
+            {
+                System.IO.Stream compressor =
+                    new DeflateStream( ms, CompressionMode.Compress, CompressionLevel.BestCompression );
+
+                ZlibBaseStream.CompressBuffer(b, compressor);
+                return ms.ToArray();
+            }
+        }
+
+
+        /// <summary>
+        ///   Uncompress a DEFLATE'd byte array into a single string.
+        /// </summary>
+        ///
+        /// <seealso cref="DeflateStream.CompressString(String)">DeflateStream.CompressString(String)</seealso>
+        /// <seealso cref="DeflateStream.UncompressBuffer(byte[])">DeflateStream.UncompressBuffer(byte[])</seealso>
+        /// <seealso cref="GZipStream.UncompressString(byte[])">GZipStream.UncompressString(byte[])</seealso>
+        /// <seealso cref="ZlibStream.UncompressString(byte[])">ZlibStream.UncompressString(byte[])</seealso>
+        ///
+        /// <param name="compressed">
+        ///   A buffer containing DEFLATE-compressed data.
+        /// </param>
+        ///
+        /// <returns>The uncompressed string</returns>
+        public static String UncompressString(byte[] compressed)
+        {
+            using (var input = new System.IO.MemoryStream(compressed))
+            {
+                System.IO.Stream decompressor =
+                    new DeflateStream(input, CompressionMode.Decompress);
+
+                return ZlibBaseStream.UncompressString(compressed, decompressor);
+            }
+        }
+
+
+        /// <summary>
+        ///   Uncompress a DEFLATE'd byte array into a byte array.
+        /// </summary>
+        ///
+        /// <seealso cref="DeflateStream.CompressBuffer(byte[])">DeflateStream.CompressBuffer(byte[])</seealso>
+        /// <seealso cref="DeflateStream.UncompressString(byte[])">DeflateStream.UncompressString(byte[])</seealso>
+        /// <seealso cref="GZipStream.UncompressBuffer(byte[])">GZipStream.UncompressBuffer(byte[])</seealso>
+        /// <seealso cref="ZlibStream.UncompressBuffer(byte[])">ZlibStream.UncompressBuffer(byte[])</seealso>
+        ///
+        /// <param name="compressed">
+        ///   A buffer containing data that has been compressed with DEFLATE.
+        /// </param>
+        ///
+        /// <returns>The data in uncompressed form</returns>
+        public static byte[] UncompressBuffer(byte[] compressed)
+        {
+            using (var input = new System.IO.MemoryStream(compressed))
+            {
+                System.IO.Stream decompressor =
+                    new DeflateStream( input, CompressionMode.Decompress );
+
+                return ZlibBaseStream.UncompressBuffer(compressed, decompressor);
+            }
+        }
+
+    }
+
+}
+

+ 135 - 0
backend/AutoUpdate/MAutoUpdate/Zip DLL/EncryptionAlgorithm.cs

@@ -0,0 +1,135 @@
+// EncryptionAlgorithm.cs
+// ------------------------------------------------------------------
+//
+// Copyright (c)  2009 Dino Chiesa
+// All rights reserved.
+//
+// This code module is part of DotNetZip, a zipfile class library.
+//
+// ------------------------------------------------------------------
+//
+// This code is licensed under the Microsoft Public License. 
+// See the file License.txt for the license details.
+// More info on: http://dotnetzip.codeplex.com
+//
+// ------------------------------------------------------------------
+//
+// last saved (in emacs): 
+// Time-stamp: <2009-October-21 17:24:45>
+//
+// ------------------------------------------------------------------
+//
+// This module defines the EncryptionAgorithm enum
+//
+// 
+// ------------------------------------------------------------------
+
+
+namespace Ionic.Zip
+{
+    /// <summary>
+    /// An enum that provides the various encryption algorithms supported by this
+    /// library.
+    /// </summary>
+    ///
+    /// <remarks>
+    ///
+    /// <para>
+    ///   <c>PkzipWeak</c> implies the use of Zip 2.0 encryption, which is known to be
+    ///   weak and subvertible.
+    /// </para>
+    ///
+    /// <para>
+    ///   A note on interoperability: Values of <c>PkzipWeak</c> and <c>None</c> are
+    ///   specified in <see
+    ///   href="http://www.pkware.com/documents/casestudies/APPNOTE.TXT">PKWARE's zip
+    ///   specification</see>, and are considered to be "standard".  Zip archives
+    ///   produced using these options will be interoperable with many other zip tools
+    ///   and libraries, including Windows Explorer.
+    /// </para>
+    ///
+    /// <para>
+    ///   Values of <c>WinZipAes128</c> and <c>WinZipAes256</c> are not part of the Zip
+    ///   specification, but rather imply the use of a vendor-specific extension from
+    ///   WinZip. If you want to produce interoperable Zip archives, do not use these
+    ///   values.  For example, if you produce a zip archive using WinZipAes256, you
+    ///   will be able to open it in Windows Explorer on Windows XP and Vista, but you
+    ///   will not be able to extract entries; trying this will lead to an "unspecified
+    ///   error". For this reason, some people have said that a zip archive that uses
+    ///   WinZip's AES encryption is not actually a zip archive at all.  A zip archive
+    ///   produced this way will be readable with the WinZip tool (Version 11 and
+    ///   beyond).
+    /// </para>
+    ///
+    /// <para>
+    ///   There are other third-party tools and libraries, both commercial and
+    ///   otherwise, that support WinZip's AES encryption. These will be able to read
+    ///   AES-encrypted zip archives produced by DotNetZip, and conversely applications
+    ///   that use DotNetZip to read zip archives will be able to read AES-encrypted
+    ///   archives produced by those tools or libraries.  Consult the documentation for
+    ///   those other tools and libraries to find out if WinZip's AES encryption is
+    ///   supported.
+    /// </para>
+    ///
+    /// <para>
+    ///   In case you care: According to <see
+    ///   href="http://www.winzip.com/aes_info.htm">the WinZip specification</see>, the
+    ///   actual AES key used is derived from the <see cref="ZipEntry.Password"/> via an
+    ///   algorithm that complies with <see
+    ///   href="http://www.ietf.org/rfc/rfc2898.txt">RFC 2898</see>, using an iteration
+    ///   count of 1000.  The algorithm is sometimes referred to as PBKDF2, which stands
+    ///   for "Password Based Key Derivation Function #2".
+    /// </para>
+    ///
+    /// <para>
+    ///   A word about password strength and length: The AES encryption technology is
+    ///   very good, but any system is only as secure as the weakest link.  If you want
+    ///   to secure your data, be sure to use a password that is hard to guess.  To make
+    ///   it harder to guess (increase its "entropy"), you should make it longer.  If
+    ///   you use normal characters from an ASCII keyboard, a password of length 20 will
+    ///   be strong enough that it will be impossible to guess.  For more information on
+    ///   that, I'd encourage you to read <see
+    ///   href="http://www.redkestrel.co.uk/Articles/RandomPasswordStrength.html">this
+    ///   article.</see>
+    /// </para>
+    ///
+    /// <para>
+    ///   The WinZip AES algorithms are not supported with the version of DotNetZip that
+    ///   runs on the .NET Compact Framework.  This is because .NET CF lacks the
+    ///   HMACSHA1 class that is required for producing the archive.
+    /// </para>
+    /// </remarks>
+    public enum EncryptionAlgorithm
+    {
+        /// <summary>
+        /// No encryption at all.
+        /// </summary>
+        None = 0,
+
+        /// <summary>
+        /// Traditional or Classic pkzip encryption.
+        /// </summary>
+        PkzipWeak,
+
+#if AESCRYPTO
+        /// <summary>
+        /// WinZip AES encryption (128 key bits).
+        /// </summary>
+        WinZipAes128,
+
+        /// <summary>
+        /// WinZip AES encryption (256 key bits).
+        /// </summary>
+        WinZipAes256,
+#endif
+
+        /// <summary>
+        /// An encryption algorithm that is not supported by DotNetZip.
+        /// </summary>
+        Unsupported = 4,
+
+
+        // others... not implemented (yet?)
+    }
+
+}

+ 684 - 0
backend/AutoUpdate/MAutoUpdate/Zip DLL/Events.cs

@@ -0,0 +1,684 @@
+// Events.cs
+// ------------------------------------------------------------------
+//
+// Copyright (c) 2006, 2007, 2008, 2009 Dino Chiesa and Microsoft Corporation.
+// All rights reserved.
+//
+// This code module is part of DotNetZip, a zipfile class library.
+//
+// ------------------------------------------------------------------
+//
+// This code is licensed under the Microsoft Public License.
+// See the file License.txt for the license details.
+// More info on: http://dotnetzip.codeplex.com
+//
+// ------------------------------------------------------------------
+//
+// last saved (in emacs):
+// Time-stamp: <2011-August-06 12:26:24>
+//
+// ------------------------------------------------------------------
+//
+// This module defines events used by the ZipFile class.
+//
+//
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+
+namespace Ionic.Zip
+{
+    /// <summary>
+    ///   Delegate in which the application writes the <c>ZipEntry</c> content for the named entry.
+    /// </summary>
+    ///
+    /// <param name="entryName">The name of the entry that must be written.</param>
+    /// <param name="stream">The stream to which the entry data should be written.</param>
+    ///
+    /// <remarks>
+    ///   When you add an entry and specify a <c>WriteDelegate</c>, via <see
+    ///   cref="Ionic.Zip.ZipFile.AddEntry(string, WriteDelegate)"/>, the application
+    ///   code provides the logic that writes the entry data directly into the zip file.
+    /// </remarks>
+    ///
+    /// <example>
+    ///
+    /// This example shows how to define a WriteDelegate that obtains a DataSet, and then
+    /// writes the XML for the DataSet into the zip archive.  There's no need to
+    /// save the XML to a disk file first.
+    ///
+    /// <code lang="C#">
+    /// private void WriteEntry (String filename, Stream output)
+    /// {
+    ///     DataSet ds1 = ObtainDataSet();
+    ///     ds1.WriteXml(output);
+    /// }
+    ///
+    /// private void Run()
+    /// {
+    ///     using (var zip = new ZipFile())
+    ///     {
+    ///         zip.AddEntry(zipEntryName, WriteEntry);
+    ///         zip.Save(zipFileName);
+    ///     }
+    /// }
+    /// </code>
+    ///
+    /// <code lang="vb">
+    /// Private Sub WriteEntry (ByVal filename As String, ByVal output As Stream)
+    ///     DataSet ds1 = ObtainDataSet()
+    ///     ds1.WriteXml(stream)
+    /// End Sub
+    ///
+    /// Public Sub Run()
+    ///     Using zip = New ZipFile
+    ///         zip.AddEntry(zipEntryName, New WriteDelegate(AddressOf WriteEntry))
+    ///         zip.Save(zipFileName)
+    ///     End Using
+    /// End Sub
+    /// </code>
+    /// </example>
+    /// <seealso cref="Ionic.Zip.ZipFile.AddEntry(string, WriteDelegate)"/>
+    public delegate void WriteDelegate(string entryName, System.IO.Stream stream);
+
+
+    /// <summary>
+    ///   Delegate in which the application opens the stream, just-in-time, for the named entry.
+    /// </summary>
+    ///
+    /// <param name="entryName">
+    /// The name of the ZipEntry that the application should open the stream for.
+    /// </param>
+    ///
+    /// <remarks>
+    ///   When you add an entry via <see cref="Ionic.Zip.ZipFile.AddEntry(string,
+    ///   OpenDelegate, CloseDelegate)"/>, the application code provides the logic that
+    ///   opens and closes the stream for the given ZipEntry.
+    /// </remarks>
+    ///
+    /// <seealso cref="Ionic.Zip.ZipFile.AddEntry(string, OpenDelegate, CloseDelegate)"/>
+    public delegate System.IO.Stream OpenDelegate(string entryName);
+
+    /// <summary>
+    ///   Delegate in which the application closes the stream, just-in-time, for the named entry.
+    /// </summary>
+    ///
+    /// <param name="entryName">
+    /// The name of the ZipEntry that the application should close the stream for.
+    /// </param>
+    ///
+    /// <param name="stream">The stream to be closed.</param>
+    ///
+    /// <remarks>
+    ///   When you add an entry via <see cref="Ionic.Zip.ZipFile.AddEntry(string,
+    ///   OpenDelegate, CloseDelegate)"/>, the application code provides the logic that
+    ///   opens and closes the stream for the given ZipEntry.
+    /// </remarks>
+    ///
+    /// <seealso cref="Ionic.Zip.ZipFile.AddEntry(string, OpenDelegate, CloseDelegate)"/>
+    public delegate void CloseDelegate(string entryName, System.IO.Stream stream);
+
+    /// <summary>
+    ///   Delegate for the callback by which the application tells the
+    ///   library the CompressionLevel to use for a file.
+    /// </summary>
+    ///
+    /// <remarks>
+    /// <para>
+    ///   Using this callback, the application can, for example, specify that
+    ///   previously-compressed files (.mp3, .png, .docx, etc) should use a
+    ///   <c>CompressionLevel</c> of <c>None</c>, or can set the compression level based
+    ///   on any other factor.
+    /// </para>
+    /// </remarks>
+    /// <seealso cref="Ionic.Zip.ZipFile.SetCompression"/>
+    public delegate Ionic.Zlib.CompressionLevel SetCompressionCallback(string localFileName, string fileNameInArchive);
+
+    /// <summary>
+    ///   In an EventArgs type, indicates which sort of progress event is being
+    ///   reported.
+    /// </summary>
+    /// <remarks>
+    ///   There are events for reading, events for saving, and events for
+    ///   extracting. This enumeration allows a single EventArgs type to be sued to
+    ///   describe one of multiple subevents. For example, a SaveProgress event is
+    ///   invoked before, after, and during the saving of a single entry.  The value
+    ///   of an enum with this type, specifies which event is being triggered.  The
+    ///   same applies to Extraction, Reading and Adding events.
+    /// </remarks>
+    public enum ZipProgressEventType
+    {
+        /// <summary>
+        /// Indicates that a Add() operation has started.
+        /// </summary>
+        Adding_Started,
+
+        /// <summary>
+        /// Indicates that an individual entry in the archive has been added.
+        /// </summary>
+        Adding_AfterAddEntry,
+
+        /// <summary>
+        /// Indicates that a Add() operation has completed.
+        /// </summary>
+        Adding_Completed,
+
+        /// <summary>
+        /// Indicates that a Read() operation has started.
+        /// </summary>
+        Reading_Started,
+
+        /// <summary>
+        /// Indicates that an individual entry in the archive is about to be read.
+        /// </summary>
+        Reading_BeforeReadEntry,
+
+        /// <summary>
+        /// Indicates that an individual entry in the archive has just been read.
+        /// </summary>
+        Reading_AfterReadEntry,
+
+        /// <summary>
+        /// Indicates that a Read() operation has completed.
+        /// </summary>
+        Reading_Completed,
+
+        /// <summary>
+        /// The given event reports the number of bytes read so far
+        /// during a Read() operation.
+        /// </summary>
+        Reading_ArchiveBytesRead,
+
+        /// <summary>
+        /// Indicates that a Save() operation has started.
+        /// </summary>
+        Saving_Started,
+
+        /// <summary>
+        /// Indicates that an individual entry in the archive is about to be written.
+        /// </summary>
+        Saving_BeforeWriteEntry,
+
+        /// <summary>
+        /// Indicates that an individual entry in the archive has just been saved.
+        /// </summary>
+        Saving_AfterWriteEntry,
+
+        /// <summary>
+        /// Indicates that a Save() operation has completed.
+        /// </summary>
+        Saving_Completed,
+
+        /// <summary>
+        /// Indicates that the zip archive has been created in a
+        /// temporary location during a Save() operation.
+        /// </summary>
+        Saving_AfterSaveTempArchive,
+
+        /// <summary>
+        /// Indicates that the temporary file is about to be renamed to the final archive
+        /// name during a Save() operation.
+        /// </summary>
+        Saving_BeforeRenameTempArchive,
+
+        /// <summary>
+        /// Indicates that the temporary file is has just been renamed to the final archive
+        /// name during a Save() operation.
+        /// </summary>
+        Saving_AfterRenameTempArchive,
+
+        /// <summary>
+        /// Indicates that the self-extracting archive has been compiled
+        /// during a Save() operation.
+        /// </summary>
+        Saving_AfterCompileSelfExtractor,
+
+        /// <summary>
+        /// The given event is reporting the number of source bytes that have run through the compressor so far
+        /// during a Save() operation.
+        /// </summary>
+        Saving_EntryBytesRead,
+
+        /// <summary>
+        /// Indicates that an entry is about to be extracted.
+        /// </summary>
+        Extracting_BeforeExtractEntry,
+
+        /// <summary>
+        /// Indicates that an entry has just been extracted.
+        /// </summary>
+        Extracting_AfterExtractEntry,
+
+        /// <summary>
+        ///   Indicates that extraction of an entry would overwrite an existing
+        ///   filesystem file. You must use
+        ///   <see cref="ExtractExistingFileAction.InvokeExtractProgressEvent">
+        ///   ExtractExistingFileAction.InvokeExtractProgressEvent</see> in the call
+        ///   to <c>ZipEntry.Extract()</c> in order to receive this event.
+        /// </summary>
+        Extracting_ExtractEntryWouldOverwrite,
+
+        /// <summary>
+        ///   The given event is reporting the number of bytes written so far for
+        ///   the current entry during an Extract() operation.
+        /// </summary>
+        Extracting_EntryBytesWritten,
+
+        /// <summary>
+        /// Indicates that an ExtractAll operation is about to begin.
+        /// </summary>
+        Extracting_BeforeExtractAll,
+
+        /// <summary>
+        /// Indicates that an ExtractAll operation has completed.
+        /// </summary>
+        Extracting_AfterExtractAll,
+
+        /// <summary>
+        /// Indicates that an error has occurred while saving a zip file.
+        /// This generally means the file cannot be opened, because it has been
+        /// removed, or because it is locked by another process.  It can also
+        /// mean that the file cannot be Read, because of a range lock conflict.
+        /// </summary>
+        Error_Saving,
+    }
+
+
+    /// <summary>
+    /// Provides information about the progress of a save, read, or extract operation.
+    /// This is a base class; you will probably use one of the classes derived from this one.
+    /// </summary>
+    public class ZipProgressEventArgs : EventArgs
+    {
+        private int _entriesTotal;
+        private bool _cancel;
+        private ZipEntry _latestEntry;
+        private ZipProgressEventType _flavor;
+        private String _archiveName;
+        private Int64 _bytesTransferred;
+        private Int64 _totalBytesToTransfer;
+
+
+        internal ZipProgressEventArgs() { }
+
+        internal ZipProgressEventArgs(string archiveName, ZipProgressEventType flavor)
+        {
+            this._archiveName = archiveName;
+            this._flavor = flavor;
+        }
+
+        /// <summary>
+        /// The total number of entries to be saved or extracted.
+        /// </summary>
+        public int EntriesTotal
+        {
+            get { return _entriesTotal; }
+            set { _entriesTotal = value; }
+        }
+
+        /// <summary>
+        /// The name of the last entry saved or extracted.
+        /// </summary>
+        public ZipEntry CurrentEntry
+        {
+            get { return _latestEntry; }
+            set { _latestEntry = value; }
+        }
+
+        /// <summary>
+        /// In an event handler, set this to cancel the save or extract
+        /// operation that is in progress.
+        /// </summary>
+        public bool Cancel
+        {
+            get { return _cancel; }
+            set { _cancel = _cancel || value; }
+        }
+
+        /// <summary>
+        /// The type of event being reported.
+        /// </summary>
+        public ZipProgressEventType EventType
+        {
+            get { return _flavor; }
+            set { _flavor = value; }
+        }
+
+        /// <summary>
+        /// Returns the archive name associated to this event.
+        /// </summary>
+        public String ArchiveName
+        {
+            get { return _archiveName; }
+            set { _archiveName = value; }
+        }
+
+
+        /// <summary>
+        /// The number of bytes read or written so far for this entry.
+        /// </summary>
+        public Int64 BytesTransferred
+        {
+            get { return _bytesTransferred; }
+            set { _bytesTransferred = value; }
+        }
+
+
+
+        /// <summary>
+        /// Total number of bytes that will be read or written for this entry.
+        /// This number will be -1 if the value cannot be determined.
+        /// </summary>
+        public Int64 TotalBytesToTransfer
+        {
+            get { return _totalBytesToTransfer; }
+            set { _totalBytesToTransfer = value; }
+        }
+    }
+
+
+
+    /// <summary>
+    /// Provides information about the progress of a Read operation.
+    /// </summary>
+    public class ReadProgressEventArgs : ZipProgressEventArgs
+    {
+
+        internal ReadProgressEventArgs() { }
+
+        private ReadProgressEventArgs(string archiveName, ZipProgressEventType flavor)
+            : base(archiveName, flavor)
+        { }
+
+        internal static ReadProgressEventArgs Before(string archiveName, int entriesTotal)
+        {
+            var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_BeforeReadEntry);
+            x.EntriesTotal = entriesTotal;
+            return x;
+        }
+
+        internal static ReadProgressEventArgs After(string archiveName, ZipEntry entry, int entriesTotal)
+        {
+            var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_AfterReadEntry);
+            x.EntriesTotal = entriesTotal;
+            x.CurrentEntry = entry;
+            return x;
+        }
+
+        internal static ReadProgressEventArgs Started(string archiveName)
+        {
+            var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_Started);
+            return x;
+        }
+
+        internal static ReadProgressEventArgs ByteUpdate(string archiveName, ZipEntry entry, Int64 bytesXferred, Int64 totalBytes)
+        {
+            var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_ArchiveBytesRead);
+            x.CurrentEntry = entry;
+            x.BytesTransferred = bytesXferred;
+            x.TotalBytesToTransfer = totalBytes;
+            return x;
+        }
+
+        internal static ReadProgressEventArgs Completed(string archiveName)
+        {
+            var x = new ReadProgressEventArgs(archiveName, ZipProgressEventType.Reading_Completed);
+            return x;
+        }
+
+    }
+
+
+    /// <summary>
+    /// Provides information about the progress of a Add operation.
+    /// </summary>
+    public class AddProgressEventArgs : ZipProgressEventArgs
+    {
+        internal AddProgressEventArgs() { }
+
+        private AddProgressEventArgs(string archiveName, ZipProgressEventType flavor)
+            : base(archiveName, flavor)
+        { }
+
+        internal static AddProgressEventArgs AfterEntry(string archiveName, ZipEntry entry, int entriesTotal)
+        {
+            var x = new AddProgressEventArgs(archiveName, ZipProgressEventType.Adding_AfterAddEntry);
+            x.EntriesTotal = entriesTotal;
+            x.CurrentEntry = entry;
+            return x;
+        }
+
+        internal static AddProgressEventArgs Started(string archiveName)
+        {
+            var x = new AddProgressEventArgs(archiveName, ZipProgressEventType.Adding_Started);
+            return x;
+        }
+
+        internal static AddProgressEventArgs Completed(string archiveName)
+        {
+            var x = new AddProgressEventArgs(archiveName, ZipProgressEventType.Adding_Completed);
+            return x;
+        }
+
+    }
+
+    /// <summary>
+    /// Provides information about the progress of a save operation.
+    /// </summary>
+    public class SaveProgressEventArgs : ZipProgressEventArgs
+    {
+        private int _entriesSaved;
+
+        /// <summary>
+        /// Constructor for the SaveProgressEventArgs.
+        /// </summary>
+        /// <param name="archiveName">the name of the zip archive.</param>
+        /// <param name="before">whether this is before saving the entry, or after</param>
+        /// <param name="entriesTotal">The total number of entries in the zip archive.</param>
+        /// <param name="entriesSaved">Number of entries that have been saved.</param>
+        /// <param name="entry">The entry involved in the event.</param>
+        internal SaveProgressEventArgs(string archiveName, bool before, int entriesTotal, int entriesSaved, ZipEntry entry)
+            : base(archiveName, (before) ? ZipProgressEventType.Saving_BeforeWriteEntry : ZipProgressEventType.Saving_AfterWriteEntry)
+        {
+            this.EntriesTotal = entriesTotal;
+            this.CurrentEntry = entry;
+            this._entriesSaved = entriesSaved;
+        }
+
+        internal SaveProgressEventArgs() { }
+
+        internal SaveProgressEventArgs(string archiveName, ZipProgressEventType flavor)
+            : base(archiveName, flavor)
+        { }
+
+
+        internal static SaveProgressEventArgs ByteUpdate(string archiveName, ZipEntry entry, Int64 bytesXferred, Int64 totalBytes)
+        {
+            var x = new SaveProgressEventArgs(archiveName, ZipProgressEventType.Saving_EntryBytesRead);
+            x.ArchiveName = archiveName;
+            x.CurrentEntry = entry;
+            x.BytesTransferred = bytesXferred;
+            x.TotalBytesToTransfer = totalBytes;
+            return x;
+        }
+
+        internal static SaveProgressEventArgs Started(string archiveName)
+        {
+            var x = new SaveProgressEventArgs(archiveName, ZipProgressEventType.Saving_Started);
+            return x;
+        }
+
+        internal static SaveProgressEventArgs Completed(string archiveName)
+        {
+            var x = new SaveProgressEventArgs(archiveName, ZipProgressEventType.Saving_Completed);
+            return x;
+        }
+
+        /// <summary>
+        /// Number of entries saved so far.
+        /// </summary>
+        public int EntriesSaved
+        {
+            get { return _entriesSaved; }
+        }
+    }
+
+
+    /// <summary>
+    /// Provides information about the progress of the extract operation.
+    /// </summary>
+    public class ExtractProgressEventArgs : ZipProgressEventArgs
+    {
+        private int _entriesExtracted;
+        private string _target;
+
+        /// <summary>
+        /// Constructor for the ExtractProgressEventArgs.
+        /// </summary>
+        /// <param name="archiveName">the name of the zip archive.</param>
+        /// <param name="before">whether this is before saving the entry, or after</param>
+        /// <param name="entriesTotal">The total number of entries in the zip archive.</param>
+        /// <param name="entriesExtracted">Number of entries that have been extracted.</param>
+        /// <param name="entry">The entry involved in the event.</param>
+        /// <param name="extractLocation">The location to which entries are extracted.</param>
+        internal ExtractProgressEventArgs(string archiveName, bool before, int entriesTotal, int entriesExtracted, ZipEntry entry, string extractLocation)
+            : base(archiveName, (before) ? ZipProgressEventType.Extracting_BeforeExtractEntry : ZipProgressEventType.Extracting_AfterExtractEntry)
+        {
+            this.EntriesTotal = entriesTotal;
+            this.CurrentEntry = entry;
+            this._entriesExtracted = entriesExtracted;
+            this._target = extractLocation;
+        }
+
+        internal ExtractProgressEventArgs(string archiveName, ZipProgressEventType flavor)
+            : base(archiveName, flavor)
+        { }
+
+        internal ExtractProgressEventArgs()
+        { }
+
+
+        internal static ExtractProgressEventArgs BeforeExtractEntry(string archiveName, ZipEntry entry, string extractLocation)
+        {
+            var x = new ExtractProgressEventArgs
+                {
+                    ArchiveName = archiveName,
+                    EventType = ZipProgressEventType.Extracting_BeforeExtractEntry,
+                    CurrentEntry = entry,
+                    _target = extractLocation,
+                };
+            return x;
+        }
+
+        internal static ExtractProgressEventArgs ExtractExisting(string archiveName, ZipEntry entry, string extractLocation)
+        {
+            var x = new ExtractProgressEventArgs
+                {
+                    ArchiveName = archiveName,
+                    EventType = ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite,
+                    CurrentEntry = entry,
+                    _target = extractLocation,
+                };
+            return x;
+        }
+
+        internal static ExtractProgressEventArgs AfterExtractEntry(string archiveName, ZipEntry entry, string extractLocation)
+        {
+            var x = new ExtractProgressEventArgs
+                {
+                    ArchiveName = archiveName,
+                    EventType = ZipProgressEventType.Extracting_AfterExtractEntry,
+                    CurrentEntry = entry,
+                    _target = extractLocation,
+                };
+            return x;
+        }
+
+        internal static ExtractProgressEventArgs ExtractAllStarted(string archiveName, string extractLocation)
+        {
+            var x = new ExtractProgressEventArgs(archiveName, ZipProgressEventType.Extracting_BeforeExtractAll);
+            x._target = extractLocation;
+            return x;
+        }
+
+        internal static ExtractProgressEventArgs ExtractAllCompleted(string archiveName, string extractLocation)
+        {
+            var x = new ExtractProgressEventArgs(archiveName, ZipProgressEventType.Extracting_AfterExtractAll);
+            x._target = extractLocation;
+            return x;
+        }
+
+
+        internal static ExtractProgressEventArgs ByteUpdate(string archiveName, ZipEntry entry, Int64 bytesWritten, Int64 totalBytes)
+        {
+            var x = new ExtractProgressEventArgs(archiveName, ZipProgressEventType.Extracting_EntryBytesWritten);
+            x.ArchiveName = archiveName;
+            x.CurrentEntry = entry;
+            x.BytesTransferred = bytesWritten;
+            x.TotalBytesToTransfer = totalBytes;
+            return x;
+        }
+
+
+
+        /// <summary>
+        /// Number of entries extracted so far.  This is set only if the
+        /// EventType is Extracting_BeforeExtractEntry or Extracting_AfterExtractEntry, and
+        /// the Extract() is occurring witin the scope of a call to ExtractAll().
+        /// </summary>
+        public int EntriesExtracted
+        {
+            get { return _entriesExtracted; }
+        }
+
+        /// <summary>
+        /// Returns the extraction target location, a filesystem path.
+        /// </summary>
+        public String ExtractLocation
+        {
+            get { return _target; }
+        }
+
+    }
+
+
+
+    /// <summary>
+    /// Provides information about the an error that occurred while zipping.
+    /// </summary>
+    public class ZipErrorEventArgs : ZipProgressEventArgs
+    {
+        private Exception _exc;
+        private ZipErrorEventArgs() { }
+        internal static ZipErrorEventArgs Saving(string archiveName, ZipEntry entry, Exception exception)
+        {
+            var x = new ZipErrorEventArgs
+                {
+                    EventType = ZipProgressEventType.Error_Saving,
+                    ArchiveName = archiveName,
+                    CurrentEntry = entry,
+                    _exc = exception
+                };
+            return x;
+        }
+
+        /// <summary>
+        /// Returns the exception that occurred, if any.
+        /// </summary>
+        public Exception @Exception
+        {
+            get { return _exc; }
+        }
+
+        /// <summary>
+        /// Returns the name of the file that caused the exception, if any.
+        /// </summary>
+        public String FileName
+        {
+            get { return CurrentEntry.LocalFileName; }
+        }
+    }
+
+
+}

+ 300 - 0
backend/AutoUpdate/MAutoUpdate/Zip DLL/Exceptions.cs

@@ -0,0 +1,300 @@
+// Exceptions.cs
+// ------------------------------------------------------------------
+//
+// Copyright (c) 2008, 2009 Dino Chiesa and Microsoft Corporation.
+// All rights reserved.
+//
+// This code module is part of DotNetZip, a zipfile class library.
+//
+// ------------------------------------------------------------------
+//
+// This code is licensed under the Microsoft Public License.
+// See the file License.txt for the license details.
+// More info on: http://dotnetzip.codeplex.com
+//
+// ------------------------------------------------------------------
+//
+// last saved (in emacs):
+// Time-stamp: <2011-July-12 12:19:10>
+//
+// ------------------------------------------------------------------
+//
+// This module defines exceptions used in the class library.
+//
+
+
+
+using System;
+using System.Collections.Generic;
+using System.Text;
+#if !NETCF
+using System.Runtime.Serialization;
+#endif
+
+namespace Ionic.Zip
+{
+    ///// <summary>
+    ///// Base exception type for all custom exceptions in the Zip library. It acts as a marker class.
+    ///// </summary>
+    //[AttributeUsage(AttributeTargets.Class)]
+    //public class ZipExceptionAttribute : Attribute { }
+
+
+
+    /// <summary>
+    /// Issued when an <c>ZipEntry.ExtractWithPassword()</c> method is invoked
+    /// with an incorrect password.
+    /// </summary>
+#if !SILVERLIGHT
+    [Serializable]
+#endif
+    [System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000B")]
+    public class BadPasswordException : ZipException
+    {
+        /// <summary>
+        /// Default ctor.
+        /// </summary>
+        public BadPasswordException() { }
+
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="message">The message in the exception.</param>
+        public BadPasswordException(String message)
+            : base(message)
+        { }
+
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="message">The message in the exception.</param>
+        /// <param name="innerException">The innerException for this exception.</param>
+        public BadPasswordException(String message, Exception innerException)
+            : base(message, innerException)
+        {
+        }
+
+
+#if ! (NETCF || SILVERLIGHT)
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="info">The serialization info for the exception.</param>
+        /// <param name="context">The streaming context from which to deserialize.</param>
+        protected BadPasswordException(SerializationInfo info, StreamingContext context)
+            : base(info, context)
+          {  }
+#endif
+
+    }
+
+    /// <summary>
+    /// Indicates that a read was attempted on a stream, and bad or incomplete data was
+    /// received.
+    /// </summary>
+#if !SILVERLIGHT
+    [Serializable]
+#endif
+    [System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d0000A")]
+    public class BadReadException : ZipException
+    {
+        /// <summary>
+        /// Default ctor.
+        /// </summary>
+        public BadReadException() { }
+
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="message">The message in the exception.</param>
+        public BadReadException(String message)
+            : base(message)
+        { }
+
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="message">The message in the exception.</param>
+        /// <param name="innerException">The innerException for this exception.</param>
+        public BadReadException(String message, Exception innerException)
+            : base(message, innerException)
+        {
+        }
+
+#if ! (NETCF || SILVERLIGHT)
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="info">The serialization info for the exception.</param>
+        /// <param name="context">The streaming context from which to deserialize.</param>
+        protected BadReadException(SerializationInfo info, StreamingContext context)
+            : base(info, context)
+          {  }
+#endif
+
+    }
+
+
+
+    /// <summary>
+    /// Issued when an CRC check fails upon extracting an entry from a zip archive.
+    /// </summary>
+#if !SILVERLIGHT
+    [Serializable]
+#endif
+    [System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00009")]
+    public class BadCrcException : ZipException
+    {
+        /// <summary>
+        /// Default ctor.
+        /// </summary>
+        public BadCrcException() { }
+
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="message">The message in the exception.</param>
+        public BadCrcException(String message)
+            : base(message)
+        { }
+
+
+#if ! (NETCF || SILVERLIGHT)
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="info">The serialization info for the exception.</param>
+        /// <param name="context">The streaming context from which to deserialize.</param>
+        protected BadCrcException(SerializationInfo info, StreamingContext context)
+            : base(info, context)
+          {  }
+#endif
+
+    }
+
+
+    /// <summary>
+    /// Issued when errors occur saving a self-extracting archive.
+    /// </summary>
+#if !SILVERLIGHT
+    [Serializable]
+#endif
+    [System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00008")]
+    public class SfxGenerationException : ZipException
+    {
+        /// <summary>
+        /// Default ctor.
+        /// </summary>
+        public SfxGenerationException() { }
+
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="message">The message in the exception.</param>
+        public SfxGenerationException(String message)
+            : base(message)
+        { }
+
+#if ! (NETCF || SILVERLIGHT)
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="info">The serialization info for the exception.</param>
+        /// <param name="context">The streaming context from which to deserialize.</param>
+        protected SfxGenerationException(SerializationInfo info, StreamingContext context)
+            : base(info, context)
+          {  }
+#endif
+
+    }
+
+
+    /// <summary>
+    /// Indicates that an operation was attempted on a ZipFile which was not possible
+    /// given the state of the instance. For example, if you call <c>Save()</c> on a ZipFile
+    /// which has no filename set, you can get this exception.
+    /// </summary>
+#if !SILVERLIGHT
+    [Serializable]
+#endif
+    [System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00007")]
+    public class BadStateException : ZipException
+    {
+        /// <summary>
+        /// Default ctor.
+        /// </summary>
+        public BadStateException() { }
+
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="message">The message in the exception.</param>
+        public BadStateException(String message)
+            : base(message)
+        { }
+
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="message">The message in the exception.</param>
+        /// <param name="innerException">The innerException for this exception.</param>
+        public BadStateException(String message, Exception innerException)
+            : base(message, innerException)
+        {}
+
+#if ! (NETCF || SILVERLIGHT)
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="info">The serialization info for the exception.</param>
+        /// <param name="context">The streaming context from which to deserialize.</param>
+        protected BadStateException(SerializationInfo info, StreamingContext context)
+            : base(info, context)
+          {  }
+#endif
+
+    }
+
+    /// <summary>
+    /// Base class for all exceptions defined by and throw by the Zip library.
+    /// </summary>
+#if !SILVERLIGHT
+    [Serializable]
+#endif
+    [System.Runtime.InteropServices.GuidAttribute("ebc25cf6-9120-4283-b972-0e5520d00006")]
+    public class ZipException : Exception
+    {
+        /// <summary>
+        /// Default ctor.
+        /// </summary>
+        public ZipException() { }
+
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="message">The message in the exception.</param>
+        public ZipException(String message) : base(message) { }
+
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="message">The message in the exception.</param>
+        /// <param name="innerException">The innerException for this exception.</param>
+        public ZipException(String message, Exception innerException)
+            : base(message, innerException)
+        { }
+
+#if ! (NETCF || SILVERLIGHT)
+        /// <summary>
+        /// Come on, you know how exceptions work. Why are you looking at this documentation?
+        /// </summary>
+        /// <param name="info">The serialization info for the exception.</param>
+        /// <param name="context">The streaming context from which to deserialize.</param>
+        protected ZipException(SerializationInfo info, StreamingContext context)
+            : base(info, context)
+        { }
+#endif
+
+    }
+
+}

+ 85 - 0
backend/AutoUpdate/MAutoUpdate/Zip DLL/ExtractExistingFileAction.cs

@@ -0,0 +1,85 @@
+// ExtractExistingFileAction.cs
+// ------------------------------------------------------------------
+//
+// Copyright (c)  2009 Dino Chiesa
+// All rights reserved.
+//
+// This code module is part of DotNetZip, a zipfile class library.
+//
+// ------------------------------------------------------------------
+//
+// This code is licensed under the Microsoft Public License. 
+// See the file License.txt for the license details.
+// More info on: http://dotnetzip.codeplex.com
+//
+// ------------------------------------------------------------------
+//
+// last saved (in emacs): 
+// Time-stamp: <2009-August-25 08:44:37>
+//
+// ------------------------------------------------------------------
+//
+// This module defines the ExtractExistingFileAction enum
+//
+// 
+// ------------------------------------------------------------------
+
+
+namespace Ionic.Zip
+{
+
+    /// <summary>
+    /// An enum for the options when extracting an entry would overwrite an existing file. 
+    /// </summary>
+    /// 
+    /// <remarks>
+    ///   <para>
+    ///     This enum describes the actions that the library can take when an
+    ///     <c>Extract()</c> or <c>ExtractWithPassword()</c> method is called to extract an
+    ///     entry to a filesystem, and the extraction would overwrite an existing filesystem
+    ///     file.
+    ///   </para>
+    /// </remarks>
+    ///
+    public enum ExtractExistingFileAction
+    {
+        /// <summary>
+        /// Throw an exception when extraction would overwrite an existing file. (For
+        /// COM clients, this is a 0 (zero).)
+        /// </summary>
+        Throw,
+
+        /// <summary>
+        /// When extraction would overwrite an existing file, overwrite the file silently.
+        /// The overwrite will happen even if the target file is marked as read-only.
+        /// (For COM clients, this is a 1.)
+        /// </summary>
+        OverwriteSilently,
+
+        /// <summary>
+        /// When extraction would overwrite an existing file, don't overwrite the file, silently. 
+        /// (For COM clients, this is a 2.)
+        /// </summary>
+        DoNotOverwrite,
+
+        /// <summary>
+        /// When extraction would overwrite an existing file, invoke the ExtractProgress
+        /// event, using an event type of <see
+        /// cref="ZipProgressEventType.Extracting_ExtractEntryWouldOverwrite"/>.  In
+        /// this way, the application can decide, just-in-time, whether to overwrite the
+        /// file. For example, a GUI application may wish to pop up a dialog to allow
+        /// the user to choose. You may want to examine the <see
+        /// cref="ExtractProgressEventArgs.ExtractLocation"/> property before making
+        /// the decision. If, after your processing in the Extract progress event, you
+        /// want to NOT extract the file, set <see cref="ZipEntry.ExtractExistingFile"/>
+        /// on the <c>ZipProgressEventArgs.CurrentEntry</c> to <c>DoNotOverwrite</c>.
+        /// If you do want to extract the file, set <c>ZipEntry.ExtractExistingFile</c>
+        /// to <c>OverwriteSilently</c>.  If you want to cancel the Extraction, set
+        /// <c>ZipProgressEventArgs.Cancel</c> to true.  Cancelling differs from using
+        /// DoNotOverwrite in that a cancel will not extract any further entries, if
+        /// there are any.  (For COM clients, the value of this enum is a 3.)
+        /// </summary>
+        InvokeExtractProgressEvent,
+    }
+
+}

+ 0 - 0
backend/AutoUpdate/MAutoUpdate/Zip DLL/FileSelector.cs


Some files were not shown because too many files changed in this diff