From 3ddeaa5b3949dae4d20c2ffd667ebfdb6c65e0d8 Mon Sep 17 00:00:00 2001 From: Lex Li Date: Sat, 25 Jun 2016 19:39:14 +0800 Subject: [PATCH] Initial commit. --- .editorconfig | 30 + .gitattributes | 22 + .gitignore | 35 + .gitmodules | 6 + .nuget/NuGet.exe | Bin 0 -> 3744336 bytes CertificateInstaller/App.config | 6 + .../CertificateInstaller.csproj | 78 + CertificateInstaller/Program.cs | 146 ++ .../Properties/AssemblyInfo.cs | 40 + CertificateInstaller/app.manifest | 76 + CertificateInstaller/packages.config | 4 + JexusManager.Features.Access/AccessFeature.cs | 103 + JexusManager.Features.Access/AccessModule.cs | 24 + .../AccessModuleProvider.cs | 28 + .../AccessPage.Designer.cs | 283 +++ JexusManager.Features.Access/AccessPage.cs | 198 ++ JexusManager.Features.Access/AccessPage.resx | 126 ++ .../AccessSettingsSavedEventHandler.cs | 8 + .../JexusManager.Features.Access.csproj | 103 + JexusManager.Features.Access/JexusManager.snk | Bin 0 -> 596 bytes .../Properties/AssemblyInfo.cs | 40 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/access_36.png | Bin 0 -> 2072 bytes .../AnonymousAuthenticationFeature.cs | 145 ++ .../AnonymousEditDialog.Designer.cs | 144 ++ .../AnonymousEditDialog.cs | 98 + .../AnonymousEditDialog.resx | 120 + .../AnonymousItem.cs | 29 + .../AuthenticationModule.cs | 22 + .../AuthenticationModuleProvider.cs | 28 + .../AuthenticationPage.Designer.cs | 286 +++ .../AuthenticationPage.cs | 177 ++ .../AuthenticationPage.resx | 129 ++ .../BasicAuthenticationFeature.cs | 145 ++ .../BasicEditDialog.Designer.cs | 123 + .../BasicEditDialog.cs | 43 + .../BasicEditDialog.resx | 120 + .../BasicItem.cs | 29 + .../ClientCertificateAuthenticationFeature.cs | 123 + .../CredentialsDialog.Designer.cs | 147 ++ .../CredentialsDialog.cs | 60 + .../CredentialsDialog.resx | 120 + .../DigestAuthenticationFeature.cs | 145 ++ .../DigestEditDialog.Designer.cs | 101 + .../DigestEditDialog.cs | 42 + .../DigestEditDialog.resx | 120 + .../DigestItem.cs | 26 + .../FormsAuthenticationFeature.cs | 146 ++ .../FormsEditDialog.Designer.cs | 245 ++ .../FormsEditDialog.cs | 98 + .../FormsEditDialog.resx | 120 + .../FormsItem.cs | 53 + .../ImpersonationEditDialog.Designer.cs | 144 ++ .../ImpersonationEditDialog.cs | 99 + .../ImpersonationEditDialog.resx | 120 + .../ImpersonationFeature.cs | 145 ++ .../ImpersonationItem.cs | 29 + ...exusManager.Features.Authentication.csproj | 204 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../Properties/AssemblyInfo.cs | 40 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../ProviderItem.cs | 31 + .../ProvidersDialog.Designer.cs | 186 ++ .../ProvidersDialog.cs | 123 + .../ProvidersDialog.resx | 120 + .../Resources/authentication_36.png | Bin 0 -> 2261 bytes .../WindowsAdvancedDialog.Designer.cs | 137 ++ .../WindowsAdvancedDialog.cs | 58 + .../WindowsAdvancedDialog.resx | 123 + .../WindowsAuthenticationFeature.cs | 167 ++ .../WindowsItem.cs | 56 + .../packages.config | 8 + .../AuthorizationFeature.cs | 183 ++ .../AuthorizationModule.cs | 24 + .../AuthorizationModuleProvider.cs | 28 + .../AuthorizationPage.Designer.cs | 266 +++ .../AuthorizationPage.cs | 140 ++ .../AuthorizationPage.resx | 126 ++ .../AuthorizationRule.cs | 67 + .../AuthorizationSettingsSavedEventHandler.cs | 8 + ...JexusManager.Features.Authorization.csproj | 130 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../NewRuleDialog.Designer.cs | 229 ++ .../NewRuleDialog.cs | 134 ++ .../NewRuleDialog.resx | 120 + .../Properties/AssemblyInfo.cs | 46 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/authorization_36.png | Bin 0 -> 2051 bytes .../packages.config | 8 + .../CachingAdvancedDialog.Designer.cs | 177 ++ .../CachingAdvancedDialog.cs | 68 + .../CachingAdvancedDialog.resx | 120 + .../CachingFeature.cs | 187 ++ JexusManager.Features.Caching/CachingItem.cs | 69 + .../CachingModule.cs | 28 + .../CachingModuleProvider.cs | 28 + .../CachingPage.Designer.cs | 298 +++ JexusManager.Features.Caching/CachingPage.cs | 148 ++ .../CachingPage.resx | 129 ++ .../CachingSettingsDialog.Designer.cs | 152 ++ .../CachingSettingsDialog.cs | 61 + .../CachingSettingsDialog.resx | 120 + .../CachingSettingsSavedEventHandler.cs | 8 + .../JexusManager.Features.Caching.csproj | 148 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../NewCachingDialog.Designer.cs | 286 +++ .../NewCachingDialog.cs | 125 ++ .../NewCachingDialog.resx | 120 + .../Properties/AssemblyInfo.cs | 46 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/caching_36.png | Bin 0 -> 1850 bytes JexusManager.Features.Caching/packages.config | 8 + .../CertificatesFeature.cs | 397 ++++ .../CertificatesItem.cs | 28 + .../CertificatesModule.cs | 25 + .../CertificatesModuleProvider.cs | 28 + .../CertificatesPage.Designer.cs | 369 +++ .../CertificatesPage.cs | 142 ++ .../CertificatesPage.resx | 135 ++ .../CertificatesSettingsSavedEventHandler.cs | 8 + .../CompleteRequestDialog.Designer.cs | 219 ++ .../CompleteRequestDialog.cs | 155 ++ .../CompleteRequestDialog.resx | 120 + .../ExportCertificateDialog.Designer.cs | 160 ++ .../ExportCertificateDialog.cs | 75 + .../ExportCertificateDialog.resx | 120 + .../ImportCertificateDialog.Designer.cs | 184 ++ .../ImportCertificateDialog.cs | 168 ++ .../ImportCertificateDialog.resx | 120 + .../JexusManager.Features.Certificates.csproj | 237 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../Properties/AssemblyInfo.cs | 40 + .../Properties/Resources.Designer.cs | 83 + .../Properties/Resources.resx | 127 ++ .../Resources/certificates_36.png | Bin 0 -> 2147 bytes .../Resources/certificates_48.png | Bin 0 -> 3196 bytes .../SelfCertificateDialog.Designer.cs | 266 +++ .../SelfCertificateDialog.cs | 204 ++ .../SelfCertificateDialog.resx | 120 + .../CertificateRenewWizard.Designer.cs | 48 + .../CertificateRenewWizard.cs | 167 ++ .../CertificateRenewWizard.resx | 120 + .../CertificateRenewWizardData.cs | 18 + .../FinishPage.Designer.cs | 144 ++ .../CertificateRenewWizard/FinishPage.cs | 61 + .../CertificateRenewWizard/FinishPage.resx | 120 + .../OptionsPage.Designer.cs | 133 ++ .../CertificateRenewWizard/OptionsPage.cs | 29 + .../CertificateRenewWizard/OptionsPage.resx | 120 + .../CertificateRequestWizard.Designer.cs | 48 + .../CertificateRequestWizard.cs | 182 ++ .../CertificateRequestWizard.resx | 120 + .../CertificateRequestWizardData.cs | 26 + .../FinishPage.Designer.cs | 144 ++ .../CertificateRequestWizard/FinishPage.cs | 61 + .../CertificateRequestWizard/FinishPage.resx | 120 + .../KeysPage.Designer.cs | 116 + .../CertificateRequestWizard/KeysPage.cs | 53 + .../CertificateRequestWizard/KeysPage.resx | 125 ++ .../PropertiesPage.Designer.cs | 206 ++ .../PropertiesPage.cs | 118 + .../PropertiesPage.resx | 120 + .../packages.config | 9 + JexusManager.Features.Cgi/CgiFeature.cs | 131 ++ JexusManager.Features.Cgi/CgiItem.cs | 52 + JexusManager.Features.Cgi/CgiModule.cs | 29 + .../CgiModuleProvider.cs | 28 + JexusManager.Features.Cgi/CgiPage.Designer.cs | 243 ++ JexusManager.Features.Cgi/CgiPage.cs | 160 ++ JexusManager.Features.Cgi/CgiPage.resx | 129 ++ .../CgiSettingsSavedEventHandler.cs | 8 + .../JexusManager.Features.Cgi.csproj | 104 + JexusManager.Features.Cgi/JexusManager.snk | Bin 0 -> 596 bytes .../Properties/AssemblyInfo.cs | 40 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/cgi_36.png | Bin 0 -> 1866 bytes .../CompressionFeature.cs | 132 ++ .../CompressionModule.cs | 25 + .../CompressionModuleProvider.cs | 28 + .../CompressionPage.Designer.cs | 338 +++ .../CompressionPage.cs | 190 ++ .../CompressionPage.resx | 126 ++ .../CompressionSettingsSavedEventHandler.cs | 8 + .../JexusManager.Features.Compression.csproj | 103 + .../JexusManager.snk | Bin 0 -> 596 bytes .../Properties/AssemblyInfo.cs | 40 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/compression_36.png | Bin 0 -> 1411 bytes .../DefaultDocumentFeature.cs | 289 +++ .../DefaultDocumentModule.cs | 23 + .../DefaultDocumentModuleProvider.cs | 28 + .../DefaultDocumentPage.Designer.cs | 385 ++++ .../DefaultDocumentPage.cs | 137 ++ .../DefaultDocumentPage.resx | 132 ++ ...efaultDocumentSettingsSavedEventHandler.cs | 8 + .../DocumentItem.cs | 42 + ...xusManager.Features.DefaultDocument.csproj | 130 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../NewDefaultDocumentDialog.Designer.cs | 108 + .../NewDefaultDocumentDialog.cs | 62 + .../NewDefaultDocumentDialog.resx | 120 + .../Properties/AssemblyInfo.cs | 46 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/default_document_36.png | Bin 0 -> 2090 bytes .../packages.config | 8 + .../DirectoryBrowseFeature.cs | 209 ++ .../DirectoryBrowseModule.cs | 29 + .../DirectoryBrowseModuleProvider.cs | 28 + .../DirectoryBrowsePage.Designer.cs | 283 +++ .../DirectoryBrowsePage.cs | 160 ++ .../DirectoryBrowsePage.resx | 126 ++ ...irectoryBrowseSettingsSavedEventHandler.cs | 8 + ...xusManager.Features.DirectoryBrowse.csproj | 103 + .../JexusManager.snk | Bin 0 -> 596 bytes .../Properties/AssemblyInfo.cs | 46 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/directory_browsing_36.png | Bin 0 -> 1867 bytes .../EnvironmentVariables.cs | 20 + .../EnvironmentVariablesCollection.cs | 29 + .../EnvironmentVariablesCollectionEditor.cs | 23 + JexusManager.Features.FastCgi/ErrorMode.cs | 23 + .../FastCgiFeature.cs | 166 ++ JexusManager.Features.FastCgi/FastCgiItem.cs | 212 ++ .../FastCgiModule.cs | 25 + .../FastCgiModuleProvider.cs | 28 + .../FastCgiPage.Designer.cs | 259 +++ JexusManager.Features.FastCgi/FastCgiPage.cs | 134 ++ .../FastCgiPage.resx | 126 ++ .../FastCgiSettingsSavedEventHandler.cs | 8 + .../JexusManager.Features.FastCgi.csproj | 136 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../NewApplicationDialog.Designer.cs | 160 ++ .../NewApplicationDialog.cs | 78 + .../NewApplicationDialog.resx | 120 + .../Properties/AssemblyInfo.cs | 46 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + JexusManager.Features.FastCgi/Protocol.cs | 17 + .../Resources/response_header_36.png | Bin 0 -> 1481 bytes JexusManager.Features.FastCgi/packages.config | 8 + .../HandlersFeature.cs | 414 ++++ .../HandlersItem.cs | 170 ++ .../HandlersModule.cs | 25 + .../HandlersModuleProvider.cs | 28 + .../HandlersPage.Designer.cs | 314 +++ .../HandlersPage.cs | 134 ++ .../HandlersPage.resx | 132 ++ .../HandlersSettingsSavedEventHandler.cs | 8 + .../JexusManager.Features.Handlers.csproj | 183 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../NewHandlerDialog.Designer.cs | 182 ++ .../NewHandlerDialog.cs | 90 + .../NewHandlerDialog.resx | 120 + .../NewMappingDialog.Designer.cs | 204 ++ .../NewMappingDialog.cs | 142 ++ .../NewMappingDialog.resx | 120 + .../NewScriptMapDialog.Designer.cs | 182 ++ .../NewScriptMapDialog.cs | 101 + .../NewScriptMapDialog.resx | 120 + .../NewWildcardDialog.Designer.cs | 160 ++ .../NewWildcardDialog.cs | 90 + .../NewWildcardDialog.resx | 120 + .../PermissionsDialog.Designer.cs | 130 ++ .../PermissionsDialog.cs | 69 + .../PermissionsDialog.resx | 120 + .../Properties/AssemblyInfo.cs | 46 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/handlers_36.png | Bin 0 -> 1579 bytes .../RestrictionsDialog.Designer.cs | 342 +++ .../RestrictionsDialog.cs | 119 + .../RestrictionsDialog.resx | 120 + .../packages.config | 8 + .../HttpApiFeature.cs | 45 + .../HttpApiModule.cs | 25 + .../HttpApiModuleProvider.cs | 29 + .../HttpApiPage.Designer.cs | 437 ++++ JexusManager.Features.HttpApi/HttpApiPage.cs | 277 +++ .../HttpApiPage.resx | 129 ++ .../HttpApiSettingsSavedEventHandler.cs | 8 + .../IHttpApiFeature.cs | 17 + .../IpMappingFeature.cs | 304 +++ .../IpMappingItem.cs | 45 + .../JexusManager.Features.HttpApi.csproj | 123 + .../JexusManager.snk | Bin 0 -> 596 bytes .../Properties/AssemblyInfo.cs | 40 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../ReservedUrlsFeature.cs | 303 +++ .../ReservedUrlsItem.cs | 39 + .../Resources/http_36.png | Bin 0 -> 2023 bytes .../SniMappingFeature.cs | 319 +++ .../SniMappingItem.cs | 45 + JexusManager.Features.HttpApi/packages.config | 4 + .../EditDialog.Designer.cs | 224 ++ .../EditDialog.cs | 68 + .../EditDialog.resx | 120 + .../HttpErrorsFeature.cs | 193 ++ .../HttpErrorsItem.cs | 68 + .../HttpErrorsModule.cs | 26 + .../HttpErrorsModuleProvider.cs | 28 + .../HttpErrorsPage.Designer.cs | 298 +++ .../HttpErrorsPage.cs | 137 ++ .../HttpErrorsPage.resx | 132 ++ .../HttpErrorsSettingsSavedEventHandler.cs | 8 + .../JexusManager.Features.HttpErrors.csproj | 151 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../LocalErrorDialog.Designer.cs | 171 ++ .../LocalErrorDialog.cs | 50 + .../LocalErrorDialog.resx | 120 + .../NewErrorDialog.Designer.cs | 285 +++ .../NewErrorDialog.cs | 215 ++ .../NewErrorDialog.resx | 120 + .../Properties/AssemblyInfo.cs | 46 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/custom_error_36.png | Bin 0 -> 1479 bytes .../packages.config | 8 + .../HttpRedirectFeature.cs | 132 ++ .../HttpRedirectModule.cs | 30 + .../HttpRedirectModuleProvider.cs | 28 + .../HttpRedirectPage.Designer.cs | 317 +++ .../HttpRedirectPage.cs | 213 ++ .../HttpRedirectPage.resx | 126 ++ .../HttpRedirectSettingsSavedEventHandler.cs | 8 + .../JexusManager.Features.HttpRedirect.csproj | 103 + .../JexusManager.snk | Bin 0 -> 596 bytes .../Properties/AssemblyInfo.cs | 40 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/http_redirect_36.png | Bin 0 -> 1772 bytes .../DynamicDialog.Designer.cs | 187 ++ .../DynamicDialog.cs | 107 + .../DynamicDialog.resx | 120 + .../IpSecurityFeature.cs | 259 +++ .../IpSecurityItem.cs | 49 + .../IpSecurityModule.cs | 26 + .../IpSecurityModuleProvider.cs | 28 + .../IpSecurityPage.Designer.cs | 290 +++ .../IpSecurityPage.cs | 129 ++ .../IpSecurityPage.resx | 132 ++ .../IpSecuritySettingsSavedEventHandler.cs | 8 + .../JexusManager.Features.IpSecurity.csproj | 148 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../NewRestrictionDialog.Designer.cs | 170 ++ .../NewRestrictionDialog.cs | 135 ++ .../NewRestrictionDialog.resx | 120 + .../Properties/AssemblyInfo.cs | 46 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/ip_restriction_36.png | Bin 0 -> 2210 bytes .../SetRestrictionsDialog.Designer.cs | 161 ++ .../SetRestrictionsDialog.cs | 96 + .../SetRestrictionsDialog.resx | 120 + .../packages.config | 8 + .../IsapiCgiRestrictionFeature.cs | 227 ++ .../IsapiCgiRestrictionItem.cs | 54 + .../IsapiCgiRestrictionModule.cs | 26 + .../IsapiCgiRestrictionModuleProvider.cs | 28 + .../IsapiCgiRestrictionPage.Designer.cs | 290 +++ .../IsapiCgiRestrictionPage.cs | 130 ++ .../IsapiCgiRestrictionPage.resx | 129 ++ ...CgiRestrictionSettingsSavedEventHandler.cs | 8 + ...anager.Features.IsapiCgiRestriction.csproj | 139 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../NewRestrictionDialog.Designer.cs | 149 ++ .../NewRestrictionDialog.cs | 78 + .../NewRestrictionDialog.resx | 120 + .../Properties/AssemblyInfo.cs | 46 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/isapi_cgi_restriction_36.png | Bin 0 -> 2029 bytes .../SettingsDialog.Designer.cs | 104 + .../SettingsDialog.cs | 44 + .../SettingsDialog.resx | 120 + .../packages.config | 8 + .../IsapiFiltersFeature.cs | 304 +++ .../IsapiFiltersItem.cs | 81 + .../IsapiFiltersModule.cs | 26 + .../IsapiFiltersModuleProvider.cs | 28 + .../IsapiFiltersPage.Designer.cs | 290 +++ .../IsapiFiltersPage.cs | 131 ++ .../IsapiFiltersPage.resx | 129 ++ .../IsapiFiltersSettingsSavedEventHandler.cs | 8 + .../JexusManager.Features.IsapiFilters.csproj | 130 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../NewFilterDialog.Designer.cs | 136 ++ .../NewFilterDialog.cs | 79 + .../NewFilterDialog.resx | 120 + .../Properties/AssemblyInfo.cs | 46 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/isapi_filters_36.png | Bin 0 -> 1838 bytes .../packages.config | 8 + JexusManager.Features.Jexus/JexusFeature.cs | 164 ++ .../JexusManager.Features.Jexus.csproj | 103 + JexusManager.Features.Jexus/JexusManager.snk | Bin 0 -> 596 bytes JexusManager.Features.Jexus/JexusModule.cs | 26 + .../JexusModuleProvider.cs | 28 + .../JexusPage.Designer.cs | 222 ++ JexusManager.Features.Jexus/JexusPage.cs | 146 ++ JexusManager.Features.Jexus/JexusPage.resx | 126 ++ .../JexusSettingsSavedEventHandler.cs | 8 + .../Properties/AssemblyInfo.cs | 40 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/jexus_36.png | Bin 0 -> 2512 bytes .../AddFieldDialog.Designer.cs | 153 ++ .../AddFieldDialog.cs | 184 ++ .../AddFieldDialog.resx | 120 + .../FieldsDialog.Designer.cs | 204 ++ JexusManager.Features.Logging/FieldsDialog.cs | 179 ++ .../FieldsDialog.resx | 120 + .../JexusManager.Features.Logging.csproj | 141 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../LoggingFeature.cs | 293 +++ .../LoggingModule.cs | 26 + .../LoggingModuleProvider.cs | 28 + .../LoggingPage.Designer.cs | 546 +++++ JexusManager.Features.Logging/LoggingPage.cs | 274 +++ .../LoggingPage.resx | 129 ++ .../LoggingSettingsSavedEventHandler.cs | 8 + .../Properties/AssemblyInfo.cs | 40 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/logging_36.png | Bin 0 -> 1893 bytes JexusManager.Features.Logging/packages.config | 8 + .../JexusManager.Features.MimeMap.csproj | 130 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../MimeMapFeature.cs | 170 ++ JexusManager.Features.MimeMap/MimeMapItem.cs | 50 + .../MimeMapModule.cs | 26 + .../MimeMapModuleProvider.cs | 28 + .../MimeMapPage.Designer.cs | 290 +++ JexusManager.Features.MimeMap/MimeMapPage.cs | 130 ++ .../MimeMapPage.resx | 132 ++ .../MimeMapSettingsSavedEventHandler.cs | 8 + .../NewMapItemDialog.cs | 71 + .../NewMapItemDialog.designer.cs | 125 ++ .../NewMapItemDialog.resx | 120 + .../Properties/AssemblyInfo.cs | 46 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/mime_map_36.png | Bin 0 -> 1475 bytes JexusManager.Features.MimeMap/packages.config | 8 + JexusManager.Features.Modules/GlobalModule.cs | 48 + .../JexusManager.Features.Modules.csproj | 151 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../ModulesFeature.cs | 383 ++++ JexusManager.Features.Modules/ModulesItem.cs | 153 ++ .../ModulesModule.cs | 25 + .../ModulesModuleProvider.cs | 28 + .../ModulesPage.Designer.cs | 298 +++ JexusManager.Features.Modules/ModulesPage.cs | 132 ++ .../ModulesPage.resx | 132 ++ .../ModulesSettingsSavedEventHandler.cs | 8 + .../NativeModulesDialog.Designer.cs | 155 ++ .../NativeModulesDialog.cs | 127 ++ .../NativeModulesDialog.resx | 120 + .../NewModuleDialog.Designer.cs | 137 ++ .../NewModuleDialog.cs | 74 + .../NewModuleDialog.resx | 120 + .../NewNativeDialog.Designer.cs | 133 ++ .../NewNativeDialog.cs | 64 + .../NewNativeDialog.resx | 120 + .../Properties/AssemblyInfo.cs | 51 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/modules_36.png | Bin 0 -> 1479 bytes JexusManager.Features.Modules/packages.config | 8 + .../AppliesToItem.cs | 42 + .../DenyStringsItem.cs | 42 + .../FileExtensionsFeature.cs | 139 ++ .../FileExtensionsItem.cs | 48 + .../FilteringRulesFeature.cs | 141 ++ .../FilteringRulesItem.cs | 148 ++ .../HeadersFeature.cs | 126 ++ .../HeadersItem.cs | 47 + .../HiddenSegmentsFeature.cs | 122 + .../HiddenSegmentsItem.cs | 42 + .../IRequestFilteringFeature.cs | 17 + ...usManager.Features.RequestFiltering.csproj | 231 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../NewExtensionDialog.Designer.cs | 102 + .../NewExtensionDialog.cs | 51 + .../NewExtensionDialog.resx | 120 + .../NewHeaderDialog.Designer.cs | 124 + .../NewHeaderDialog.cs | 52 + .../NewHeaderDialog.resx | 120 + .../NewHiddenSegmentDialog.Designer.cs | 102 + .../NewHiddenSegmentDialog.cs | 51 + .../NewHiddenSegmentDialog.resx | 120 + .../NewQueryDialog.Designer.cs | 102 + .../NewQueryDialog.cs | 51 + .../NewQueryDialog.resx | 120 + .../NewRuleDialog.Designer.cs | 239 ++ .../NewRuleDialog.cs | 105 + .../NewRuleDialog.resx | 135 ++ .../NewUrlDialog.Designer.cs | 102 + .../NewUrlDialog.cs | 52 + .../NewUrlDialog.resx | 120 + .../NewVerbDialog.Designer.cs | 102 + .../NewVerbDialog.cs | 51 + .../NewVerbDialog.resx | 120 + .../Properties/AssemblyInfo.cs | 46 + .../Properties/Resources.Designer.cs | 143 ++ .../Properties/Resources.resx | 145 ++ .../QueryStringsFeature.cs | 146 ++ .../QueryStringsItem.cs | 60 + .../RequestFilteringFeature.cs | 57 + .../RequestFilteringModule.cs | 26 + .../RequestFilteringModuleProvider.cs | 28 + .../RequestFilteringPage.Designer.cs | 581 +++++ .../RequestFilteringPage.cs | 541 +++++ .../RequestFilteringPage.resx | 129 ++ ...questFilteringSettingsSavedEventHandler.cs | 8 + .../Resources/extensions_16.png | Bin 0 -> 441 bytes .../Resources/headers_16.png | Bin 0 -> 436 bytes .../Resources/hidden_16.png | Bin 0 -> 452 bytes .../Resources/map_16.png | Bin 0 -> 612 bytes .../Resources/query_16.png | Bin 0 -> 590 bytes .../Resources/request_filtering_36.png | Bin 0 -> 1934 bytes .../Resources/url_16.png | Bin 0 -> 474 bytes .../Resources/verbs_16.png | Bin 0 -> 1031 bytes .../ScanHeadersItem.cs | 43 + .../SegmentSettingsDialog.Designer.cs | 227 ++ .../SegmentSettingsDialog.cs | 113 + .../SegmentSettingsDialog.resx | 120 + .../UrlsFeature.cs | 147 ++ .../UrlsItem.cs | 60 + .../VerbsFeature.cs | 139 ++ .../VerbsItem.cs | 47 + .../packages.config | 8 + ...xusManager.Features.ResponseHeaders.csproj | 139 ++ .../JexusManager.snk | Bin 0 -> 596 bytes .../NewHeaderDialog.Designer.cs | 122 + .../NewHeaderDialog.cs | 67 + .../NewHeaderDialog.resx | 120 + .../Properties/AssemblyInfo.cs | 46 + .../Properties/Resources.Designer.cs | 73 + .../Properties/Resources.resx | 124 + .../Resources/response_header_36.png | Bin 0 -> 1481 bytes .../ResponseHeadersFeature.cs | 184 ++ .../ResponseHeadersItem.cs | 46 + .../ResponseHeadersModule.cs | 26 + .../ResponseHeadersModuleProvider.cs | 28 + .../ResponseHeadersPage.Designer.cs | 292 +++ .../ResponseHeadersPage.cs | 141 ++ .../ResponseHeadersPage.resx | 132 ++ ...esponseHeadersSettingsSavedEventHandler.cs | 8 + .../SetCommonHeadersDialog.Designer.cs | 205 ++ .../SetCommonHeadersDialog.cs | 203 ++ .../SetCommonHeadersDialog.resx | 120 + .../packages.config | 8 + .../ConditionItem.cs | 57 + .../ConditionListViewItem.cs | 55 + .../AddAllowedVariableDialog.Designer.cs | 102 + .../Inbound/AddAllowedVariableDialog.cs | 67 + .../Inbound/AddAllowedVariableDialog.resx | 120 + .../Inbound/AddConditionDialog.Designer.cs | 180 ++ .../Inbound/AddConditionDialog.cs | 89 + .../Inbound/AddConditionDialog.resx | 120 + .../Inbound/AddMapDialog.Designer.cs | 124 + .../Inbound/AddMapDialog.cs | 63 + .../Inbound/AddMapDialog.resx | 120 + .../Inbound/AddMapsDialog.Designer.cs | 102 + .../Inbound/AddMapsDialog.cs | 67 + .../Inbound/AddMapsDialog.resx | 120 + .../AddServerVariableDialog.Designer.cs | 138 ++ .../Inbound/AddServerVariableDialog.cs | 72 + .../Inbound/AddServerVariableDialog.resx | 120 + .../Inbound/AllowedVariableItem.cs | 47 + .../Inbound/AllowedVariablesFeature.cs | 251 +++ .../Inbound/InboundFeature.cs | 184 ++ .../Inbound/InboundRule.cs | 227 ++ .../Inbound/InboundRulePage.Designer.cs | 1053 +++++++++ .../Inbound/InboundRulePage.cs | 543 +++++ .../Inbound/InboundRulePage.resx | 126 ++ .../Inbound/MapItem.cs | 70 + .../Inbound/MapPage.Designer.cs | 334 +++ .../Inbound/MapPage.cs | 250 +++ .../Inbound/MapPage.resx | 129 ++ .../Inbound/MapRule.cs | 50 + .../Inbound/MapSettingsDialog.Designer.cs | 136 ++ .../Inbound/MapSettingsDialog.cs | 55 + .../Inbound/MapSettingsDialog.resx | 120 + .../Inbound/MapSettingsUpdatedEventHandler.cs | 8 + .../Inbound/MapsFeature.cs | 303 +++ .../Inbound/MapsPage.Designer.cs | 275 +++ .../Inbound/MapsPage.cs | 180 ++ .../Inbound/MapsPage.resx | 129 ++ .../Inbound/ServerVariableItem.cs | 47 + .../Inbound/ServerVariablesPage.Designer.cs | 281 +++ .../Inbound/ServerVariablesPage.cs | 174 ++ .../Inbound/ServerVariablesPage.resx | 129 ++ .../JexusManager.Features.Rewrite.csproj | 366 +++ .../JexusManager.snk | Bin 0 -> 596 bytes .../NewRewriteRuleDialog.Designer.cs | 201 ++ .../NewRewriteRuleDialog.cs | 150 ++ .../NewRewriteRuleDialog.resx | 129 ++ .../NewRuleBlockingDialog.Designer.cs | 228 ++ .../NewRuleBlockingDialog.cs | 178 ++ .../NewRuleBlockingDialog.resx | 120 + .../NewRuleWithRewriteMapsDialog.Designer.cs | 144 ++ .../NewRuleWithRewriteMapsDialog.cs | 117 + .../NewRuleWithRewriteMapsDialog.resx | 132 ++ .../Outbound/AddCustomTagDialog.Designer.cs | 128 ++ .../Outbound/AddCustomTagDialog.cs | 58 + .../Outbound/AddCustomTagDialog.resx | 120 + .../Outbound/AddCustomTagsDialog.Designer.cs | 160 ++ .../Outbound/AddCustomTagsDialog.cs | 84 + .../Outbound/AddCustomTagsDialog.resx | 126 ++ .../AddPreconditionDialog.Designer.cs | 256 +++ .../Outbound/AddPreconditionDialog.cs | 168 ++ .../Outbound/AddPreconditionDialog.resx | 120 + .../Outbound/CustomTagItem.cs | 47 + .../Outbound/CustomTagsFeature.cs | 229 ++ .../Outbound/CustomTagsItem.cs | 64 + .../Outbound/CustomTagsPage.Designer.cs | 290 +++ .../Outbound/CustomTagsPage.cs | 188 ++ .../Outbound/CustomTagsPage.resx | 129 ++ .../Outbound/OutboundFeature.cs | 156 ++ .../Outbound/OutboundRule.cs | 166 ++ .../Outbound/OutboundRulePage.Designer.cs | 856 +++++++ .../Outbound/OutboundRulePage.cs | 511 +++++ .../Outbound/OutboundRulePage.resx | 126 ++ .../Outbound/PreConditionItem.cs | 67 + .../Outbound/PreConditionsFeature.cs | 289 +++ .../Outbound/PreConditionsPage.Designer.cs | 290 +++ .../Outbound/PreConditionsPage.cs | 188 ++ .../Outbound/PreConditionsPage.resx | 129 ++ .../Properties/AssemblyInfo.cs | 46 + .../Properties/Resources.Designer.cs | 203 ++ .../Properties/Resources.resx | 163 ++ .../RegexTestDialog.Designer.cs | 240 ++ .../RegexTestDialog.cs | 132 ++ .../RegexTestDialog.resx | 120 + .../Resources/blank_16.png | Bin 0 -> 637 bytes .../Resources/blank_32.png | Bin 0 -> 1803 bytes .../Resources/blankout_16.png | Bin 0 -> 637 bytes .../Resources/blankout_32.png | Bin 0 -> 1827 bytes .../Resources/blocking_16.png | Bin 0 -> 718 bytes .../Resources/blocking_32.png | Bin 0 -> 2067 bytes .../Resources/error_16.png | Bin 0 -> 850 bytes .../Resources/info_16.png | Bin 0 -> 757 bytes .../Resources/lowercase_16.png | Bin 0 -> 553 bytes .../Resources/lowercase_32.png | Bin 0 -> 1316 bytes .../Resources/map_16.png | Bin 0 -> 612 bytes .../Resources/map_32.png | Bin 0 -> 1312 bytes .../Resources/tick_16.png | Bin 0 -> 801 bytes .../Resources/url_rewrite_36.png | Bin 0 -> 1887 bytes .../RewriteFeature.cs | 410 ++++ .../RewriteModule.cs | 26 + .../RewriteModuleProvider.cs | 28 + .../RewritePage.Designer.cs | 426 ++++ JexusManager.Features.Rewrite/RewritePage.cs | 271 +++ .../RewritePage.resx | 126 ++ .../RewriteSettingsSavedEventHandler.cs | 8 + .../RuleSettingsUpdatedEventHandler.cs | 8 + JexusManager.Features.Rewrite/packages.config | 8 + JexusManager.Shared/ApplicationExtensions.cs | 22 + .../ConfigurationElementExtensions.cs | 21 + .../ConfigurationSectionExtensions.cs | 16 + JexusManager.Shared/DefaultWizardForm.cs | 21 + JexusManager.Shared/DefaultWizardPage.cs | 26 + JexusManager.Shared/DescriptionConverter.cs | 70 + JexusManager.Shared/DialogHelper.cs | 181 ++ .../Features/DefaultTaskList.cs | 104 + JexusManager.Shared/Features/FeatureBase.cs | 225 ++ JexusManager.Shared/Features/IDuoItem.cs | 11 + JexusManager.Shared/Features/IItem.cs | 31 + .../Features/ScopeExtensions.cs | 31 + .../Features/ShowHelpTaskList.cs | 26 + .../Features/TaskItemExtensions.cs | 171 ++ .../Features/TimeSpanExtensions.cs | 16 + .../JexusManager.Shared.csproj | 148 ++ JexusManager.Shared/JexusManager.snk | Bin 0 -> 596 bytes JexusManager.Shared/NativeMethods.cs | 151 ++ JexusManager.Shared/PhysicalDirectory.cs | 28 + .../Properties/AssemblyInfo.cs | 46 + .../Properties/Resources.Designer.cs | 193 ++ JexusManager.Shared/Properties/Resources.resx | 160 ++ .../Resources/application_32.png | Bin 0 -> 1567 bytes JexusManager.Shared/Resources/back_16.png | Bin 0 -> 655 bytes .../Resources/basic_settings_16.png | Bin 0 -> 440 bytes JexusManager.Shared/Resources/go_16.png | Bin 0 -> 827 bytes JexusManager.Shared/Resources/help_16.png | Bin 0 -> 932 bytes .../Resources/move_down_16.png | Bin 0 -> 683 bytes JexusManager.Shared/Resources/move_up_16.png | Bin 0 -> 652 bytes JexusManager.Shared/Resources/remove_16.png | Bin 0 -> 680 bytes JexusManager.Shared/Resources/show_all_16.png | Bin 0 -> 830 bytes JexusManager.Shared/Resources/site_32.png | Bin 0 -> 2251 bytes JexusManager.Shared/Resources/title_32.png | Bin 0 -> 1293 bytes .../Resources/transparent_16.png | Bin 0 -> 160 bytes JexusManager.Shared/Resources/view_16.png | Bin 0 -> 462 bytes .../ServerManagerExtensions.cs | 17 + .../Services/ConfigurationService.cs | 79 + JexusManager.Shared/Services/ControlPanel.cs | 76 + .../Services/IConfigurationService.cs | 26 + .../Services/ManagementUIService.cs | 80 + JexusManager.Shared/app.config | 11 + JexusManager.Shared/packages.config | 5 + JexusManager.sln | 271 +++ JexusManager/App.config | 18 + .../CertificateErrorsDialog.Designer.cs | 154 ++ .../Dialogs/CertificateErrorsDialog.cs | 41 + .../Dialogs/CertificateErrorsDialog.resx | 120 + .../Dialogs/EditSiteDialog.Designer.cs | 236 ++ JexusManager/Dialogs/EditSiteDialog.cs | 73 + JexusManager/Dialogs/EditSiteDialog.resx | 120 + .../Dialogs/NewApplicationDialog.Designer.cs | 309 +++ JexusManager/Dialogs/NewApplicationDialog.cs | 137 ++ .../Dialogs/NewApplicationDialog.resx | 120 + .../Dialogs/NewFarmServerDialog.Designer.cs | 95 + JexusManager/Dialogs/NewFarmServerDialog.cs | 31 + JexusManager/Dialogs/NewFarmServerDialog.resx | 120 + .../Dialogs/NewSiteDialog.Designer.cs | 438 ++++ JexusManager/Dialogs/NewSiteDialog.cs | 243 ++ JexusManager/Dialogs/NewSiteDialog.resx | 120 + .../NewVirtualDirectoryDialog.Designer.cs | 257 +++ .../Dialogs/NewVirtualDirectoryDialog.cs | 104 + .../Dialogs/NewVirtualDirectoryDialog.resx | 120 + .../Dialogs/SelectPoolDialog.Designer.cs | 160 ++ JexusManager/Dialogs/SelectPoolDialog.cs | 52 + JexusManager/Dialogs/SelectPoolDialog.resx | 120 + JexusManager/Dialogs/UpdateDialog.Designer.cs | 81 + JexusManager/Dialogs/UpdateDialog.cs | 62 + JexusManager/Dialogs/UpdateDialog.resx | 120 + JexusManager/FarmPanel.Designer.cs | 530 +++++ JexusManager/FarmPanel.cs | 104 + JexusManager/FarmPanel.resx | 147 ++ JexusManager/FarmServerAdvancedSettings.cs | 32 + JexusManager/FarmWizard.Designer.cs | 165 ++ JexusManager/FarmWizard.cs | 96 + JexusManager/FarmWizard.resx | 120 + .../Features/Main/ApplicationFeature.cs | 254 +++ .../Features/Main/ApplicationPage.Designer.cs | 363 +++ JexusManager/Features/Main/ApplicationPage.cs | 130 ++ .../Features/Main/ApplicationPage.resx | 138 ++ .../Main/ApplicationPoolAdvancedSettings.cs | 283 +++ ...tionPoolAdvancedSettingsDialog.Designer.cs | 125 ++ .../ApplicationPoolAdvancedSettingsDialog.cs | 38 + ...ApplicationPoolAdvancedSettingsDialog.resx | 120 + ...icationPoolBasicSettingsDialog.Designer.cs | 172 ++ .../ApplicationPoolBasicSettingsDialog.cs | 101 + .../ApplicationPoolBasicSettingsDialog.resx | 120 + .../Main/ApplicationPoolDefaultsSettings.cs | 174 ++ ...tionPoolDefaultsSettingsDialog.Designer.cs | 131 ++ .../ApplicationPoolDefaultsSettingsDialog.cs | 38 + ...ApplicationPoolDefaultsSettingsDialog.resx | 120 + .../Features/Main/ApplicationPoolsFeature.cs | 337 +++ .../Main/ApplicationPoolsPage.Designer.cs | 371 +++ .../Features/Main/ApplicationPoolsPage.cs | 165 ++ .../Features/Main/ApplicationPoolsPage.resx | 135 ++ ...plicationPoolsSettingsSavedEventHandler.cs | 16 + .../Features/Main/BindingDialog.Designer.cs | 257 +++ JexusManager/Features/Main/BindingDialog.cs | 225 ++ JexusManager/Features/Main/BindingDialog.resx | 120 + .../Features/Main/BindingsDialog.Designer.cs | 224 ++ JexusManager/Features/Main/BindingsDialog.cs | 175 ++ .../Features/Main/BindingsDialog.resx | 120 + JexusManager/Features/Main/CLRVersion.cs | 18 + .../Main/CredentialsDialog.Designer.cs | 151 ++ .../Features/Main/CredentialsDialog.cs | 48 + .../Features/Main/CredentialsDialog.resx | 120 + .../Features/Main/HomePage.Designer.cs | 186 ++ JexusManager/Features/Main/HomePage.cs | 39 + JexusManager/Features/Main/HomePage.resx | 120 + .../Features/Main/IdentityDialog.Designer.cs | 150 ++ JexusManager/Features/Main/IdentityDialog.cs | 105 + .../Features/Main/IdentityDialog.resx | 120 + JexusManager/Features/Main/IdentityEditor.cs | 34 + JexusManager/Features/Main/MainModule.cs | 12 + .../Main/ModulePageInfoListViewItem.cs | 33 + .../Features/Main/PhysicalDirectoryFeature.cs | 206 ++ .../Main/PhysicalDirectoryPage.Designer.cs | 363 +++ .../Features/Main/PhysicalDirectoryPage.cs | 129 ++ .../Features/Main/PhysicalDirectoryPage.resx | 138 ++ JexusManager/Features/Main/ServerFeature.cs | 258 +++ .../Features/Main/ServerPage.Designer.cs | 357 +++ JexusManager/Features/Main/ServerPage.cs | 126 ++ JexusManager/Features/Main/ServerPage.resx | 132 ++ .../Main/ServerSettingsSavedEventHandler.cs | 16 + JexusManager/Features/Main/SiteFeature.cs | 405 ++++ .../Features/Main/SitePage.Designer.cs | 363 +++ JexusManager/Features/Main/SitePage.cs | 131 ++ JexusManager/Features/Main/SitePage.resx | 132 ++ JexusManager/Features/Main/SitesFeature.cs | 499 ++++ .../Features/Main/SitesPage.Designer.cs | 406 ++++ JexusManager/Features/Main/SitesPage.cs | 244 ++ JexusManager/Features/Main/SitesPage.resx | 135 ++ .../Features/Main/SslDiagDialog.Designer.cs | 144 ++ JexusManager/Features/Main/SslDiagDialog.cs | 264 +++ JexusManager/Features/Main/SslDiagDialog.resx | 123 + .../Features/Main/VirtualDirectoryFeature.cs | 242 ++ .../Main/VirtualDirectoryPage.Designer.cs | 363 +++ .../Features/Main/VirtualDirectoryPage.cs | 130 ++ .../Features/Main/VirtualDirectoryPage.resx | 138 ++ JexusManager/JexusManager.csproj | 713 ++++++ JexusManager/JexusManager.snk | Bin 0 -> 596 bytes JexusManager/MainForm.Designer.cs | 1997 +++++++++++++++++ JexusManager/MainForm.cs | 858 +++++++ JexusManager/MainForm.resx | 207 ++ JexusManager/Program.cs | 29 + JexusManager/Properties/AssemblyInfo.cs | 33 + JexusManager/Properties/Resources.Designer.cs | 433 ++++ JexusManager/Properties/Resources.resx | 232 ++ JexusManager/Properties/Settings.Designer.cs | 26 + JexusManager/Properties/Settings.settings | 7 + JexusManager/Resources/application_16.png | Bin 0 -> 774 bytes JexusManager/Resources/application_new_16.png | Bin 0 -> 804 bytes .../Resources/application_pool_new_16.png | Bin 0 -> 852 bytes .../Resources/application_pools_16.png | Bin 0 -> 813 bytes .../application_pools_stopped_16.png | Bin 0 -> 802 bytes JexusManager/Resources/back_16.png | Bin 0 -> 655 bytes JexusManager/Resources/basic_settings_16.png | Bin 0 -> 440 bytes JexusManager/Resources/browse_16.png | Bin 0 -> 864 bytes JexusManager/Resources/certificates_16.png | Bin 0 -> 766 bytes JexusManager/Resources/connect_16.png | Bin 0 -> 699 bytes JexusManager/Resources/disconnected_16.png | Bin 0 -> 818 bytes JexusManager/Resources/explore_16.png | Bin 0 -> 617 bytes JexusManager/Resources/farm_16.png | Bin 0 -> 734 bytes JexusManager/Resources/farm_server_16.png | Bin 0 -> 642 bytes JexusManager/Resources/help_16.png | Bin 0 -> 932 bytes JexusManager/Resources/iis_16.png | Bin 0 -> 606 bytes JexusManager/Resources/info_16.png | Bin 0 -> 757 bytes .../Resources/physical_directory_16.png | Bin 0 -> 581 bytes JexusManager/Resources/refresh_16.png | Bin 0 -> 540 bytes JexusManager/Resources/restart_16.png | Bin 0 -> 912 bytes JexusManager/Resources/save_16.png | Bin 0 -> 561 bytes JexusManager/Resources/server_16.png | Bin 0 -> 642 bytes JexusManager/Resources/servers_16.png | Bin 0 -> 517 bytes JexusManager/Resources/site_16.png | Bin 0 -> 928 bytes JexusManager/Resources/site_new_16.png | Bin 0 -> 1036 bytes JexusManager/Resources/site_stopped_16.png | Bin 0 -> 995 bytes JexusManager/Resources/sites_16.png | Bin 0 -> 711 bytes JexusManager/Resources/start_16.png | Bin 0 -> 660 bytes JexusManager/Resources/stop_16.png | Bin 0 -> 429 bytes JexusManager/Resources/switch_16.png | Bin 0 -> 672 bytes JexusManager/Resources/title_48.png | Bin 0 -> 3259 bytes JexusManager/Resources/up_16.png | Bin 0 -> 679 bytes JexusManager/Resources/update_16.png | Bin 0 -> 964 bytes .../Resources/virtual_directory_16.png | Bin 0 -> 697 bytes .../Resources/virtual_directory_new_16.png | Bin 0 -> 949 bytes JexusManager/Resources/warning_32.png | Bin 0 -> 1391 bytes JexusManager/Services/NavigationService.cs | 132 ++ JexusManager/StringFormatter.cs | 19 + JexusManager/Tree/ApplicationPoolsTreeNode.cs | 79 + JexusManager/Tree/ApplicationTreeNode.cs | 145 ++ JexusManager/Tree/HomePageTreeNode.cs | 64 + JexusManager/Tree/ManagerTreeNode.cs | 170 ++ .../Tree/PhysicalDirectoryTreeNode.cs | 138 ++ JexusManager/Tree/ServerTreeNode.cs | 334 +++ JexusManager/Tree/SiteTreeNode.cs | 142 ++ JexusManager/Tree/SitesTreeNode.cs | 78 + JexusManager/Tree/VirtualDirectoryTreeNode.cs | 142 ++ .../ConnectionWizard/AddressPage.Designer.cs | 172 ++ .../Wizards/ConnectionWizard/AddressPage.cs | 145 ++ .../Wizards/ConnectionWizard/AddressPage.resx | 120 + .../ConnectionWizard/BrowsePage.Designer.cs | 85 + .../Wizards/ConnectionWizard/BrowsePage.cs | 86 + .../Wizards/ConnectionWizard/BrowsePage.resx | 120 + .../ConnectionWizard.Designer.cs | 54 + .../ConnectionWizard/ConnectionWizard.cs | 65 + .../ConnectionWizard/ConnectionWizard.resx | 120 + .../ConnectionWizard/ConnectionWizardData.cs | 34 + .../CredentialsPage.Designer.cs | 110 + .../ConnectionWizard/CredentialsPage.cs | 164 ++ .../ConnectionWizard/CredentialsPage.resx | 120 + .../ConnectionWizard/FarmNamePage.Designer.cs | 85 + .../Wizards/ConnectionWizard/FarmNamePage.cs | 50 + .../ConnectionWizard/FarmNamePage.resx | 120 + .../ConnectionWizard/FinishPage.Designer.cs | 86 + .../Wizards/ConnectionWizard/FinishPage.cs | 54 + .../Wizards/ConnectionWizard/FinishPage.resx | 120 + .../ConnectionWizard/ServerPage.Designer.cs | 87 + .../Wizards/ConnectionWizard/ServerPage.cs | 37 + .../Wizards/ConnectionWizard/ServerPage.resx | 120 + .../ConnectionWizard/TypePage.Designer.cs | 142 ++ .../Wizards/ConnectionWizard/TypePage.cs | 48 + .../Wizards/ConnectionWizard/TypePage.resx | 120 + JexusManager/app.manifest | 76 + JexusManager/iis.ico | Bin 0 -> 17542 bytes JexusManager/jexus.xml | 20 + JexusManager/packages.config | 8 + .../AppHostFileProvider.cs | 93 + .../IAppHostProvider.cs | 73 + .../IAppHostProviderChangeHandler.cs | 14 + .../IAppHostSite.cs | 62 + .../IApplication.cs | 50 + .../IApplicationPool.cs | 95 + .../ICpu.cs | 58 + .../ICustomField.cs | 28 + .../ICustomFields.cs | 20 + .../IEnumApplicationPool.cs | 15 + .../IEnumApplications.cs | 15 + .../IEnumBindings.cs | 15 + .../IEnumCustomFields.cs | 15 + .../IEnumEnvironmentVariables.cs | 15 + .../IEnumListenerAdapter.cs | 15 + .../IEnumLocation.cs | 15 + .../IEnumSchedule.cs | 15 + .../IEnumSite.cs | 15 + .../IEnumVirtualDirectory.cs | 15 + .../IEnvironmentVariable.cs | 23 + .../IFailure.cs | 58 + .../IListenerAdapter.cs | 33 + .../ILocation.cs | 18 + .../ILogSettings.cs | 78 + .../IPeriodicRestart.cs | 35 + .../IProcessModel.cs | 93 + .../IRecycling.cs | 33 + .../ISchedule.cs | 18 + .../ISiteBinding.cs | 28 + .../ISiteLimits.cs | 33 + .../ISiteLogFile.cs | 78 + .../ISiteTraceRequestsLogging.cs | 38 + .../IVirtualDirectory.cs | 43 + .../IWebLimits.cs | 48 + .../JexusManager.snk | Bin 0 -> 596 bytes .../LoadOptions.cs | 16 + ...b.Configuration.AppHostFileProvider.csproj | 96 + .../Properties/AssemblyInfo.cs | 39 + .../Client/AssemblyDownloadInfo.cs | 32 + Microsoft.Web.Management/Client/Connection.cs | 104 + .../Client/ConnectionActiveState.cs | 13 + .../Client/ConnectionCredential.cs | 40 + .../Client/ConnectionEventArgs.cs | 14 + .../Client/ConnectionEventHandler.cs | 13 + .../Client/ConnectionInfo.cs | 34 + .../Client/ConnectionInfoCollection.cs | 22 + .../Client/ControlPanelCategorization.cs | 38 + .../Client/ControlPanelCategoryInfo.cs | 42 + .../Client/CredentialInfo.cs | 17 + .../Client/CredentialInfoEventArgs.cs | 20 + .../Extensions/AuthenticationFeature.cs | 72 + ...AuthenticationSettingsSavedEventHandler.cs | 8 + .../Client/Extensions/AuthenticationType.cs | 14 + .../Client/Extensions/HomepageExtension.cs | 23 + .../Extensions/IHomepageTaskListProvider.cs | 16 + .../Client/Extensions/ProtocolProvider.cs | 44 + .../Client/Extensions/ProviderFeature.cs | 20 + .../Client/Extensions/SiteAction.cs | 12 + .../Client/Extensions/SiteUpdatedEventArgs.cs | 14 + .../Client/GroupTaskItem.cs | 27 + .../Client/HierarchyCollectionEventArgs.cs | 24 + .../Client/HierarchyCollectionEventHandler.cs | 13 + .../Client/HierarchyInfo.cs | 122 + .../Client/HierarchyInfoEventArgs.cs | 18 + .../Client/HierarchyInfoEventHandler.cs | 8 + .../HierarchyInfoSyncSelectionEventArgs.cs | 24 + .../Client/HierarchyPriority.cs | 15 + .../Client/HierarchyProvider.cs | 38 + .../Client/HierarchyRenameEventArgs.cs | 19 + .../Client/HierarchyService.cs | 42 + .../Client/HierarchyVisibility.cs | 13 + .../Client/ICertificateVerificationBuilder.cs | 20 + .../Client/IConnectionBuilder.cs | 28 + .../Client/IConnectionManager.cs | 46 + .../Client/IControlPanel.cs | 34 + .../Client/ICredentialBuilder.cs | 76 + .../Client/IExtensibilityManager.cs | 21 + .../Client/IModuleChildPage.cs | 11 + .../Client/IModulePage.cs | 27 + .../Client/INavigationService.cs | 30 + .../Client/IPreferencesService.cs | 26 + .../Client/IPropertyEditingService.cs | 28 + .../Client/IPropertyEditingUser.cs | 19 + .../Client/IProviderConfigurationService.cs | 15 + .../Client/ManagementChannel.cs | 40 + .../Client/ManagementScopePath.cs | 65 + .../Client/MessageTaskItem.cs | 44 + .../Client/MessageTaskItemType.cs | 13 + .../Client/MethodTaskItemUsages.cs | 15 + Microsoft.Web.Management/Client/Module.cs | 70 + .../Client/ModuleHomepageAttribute.cs | 18 + .../Client/ModuleListPageFilter.cs | 22 + .../Client/ModuleListPageGrouping.cs | 47 + .../Client/ModuleListPageSearchField.cs | 26 + .../Client/ModuleListPageSearchOptions.cs | 31 + .../Client/ModuleListPageViewModes.cs | 17 + .../Client/ModulePageIdentifierAttribute.cs | 20 + .../Client/ModulePageInfo.cs | 62 + .../Client/ModuleServiceProxy.cs | 32 + .../Client/NavigationEventArgs.cs | 26 + .../Client/NavigationEventHandler.cs | 13 + .../Client/NavigationItem.cs | 48 + .../Client/PreferencesStore.cs | 69 + .../Client/PropertyGridObject.cs | 106 + .../Client/ProviderConfigurationSettings.cs | 29 + Microsoft.Web.Management/Client/TaskItem.cs | 28 + Microsoft.Web.Management/Client/TaskList.cs | 32 + .../Client/TaskListCollection.cs | 77 + .../Client/Win32/BaseForm.cs | 94 + .../Client/Win32/BaseTaskForm.cs | 88 + .../Client/Win32/DialogForm.cs | 41 + .../Client/Win32/IManagementUIService.cs | 37 + .../Client/Win32/ListPageListView.cs | 38 + .../Client/Win32/ManagementGroupBox.cs | 20 + .../Client/Win32/ManagementPanel.cs | 20 + .../Client/Win32/ManagementTabPage.cs | 20 + .../Client/Win32/ManagementUIColorTable.cs | 41 + .../Client/Win32/MethodTaskItem.cs | 38 + .../Client/Win32/ModuleDialogPage.cs | 141 ++ .../Client/Win32/ModuleDialogPage.resx | 120 + .../Client/Win32/ModuleListPage.cs | 201 ++ .../Client/Win32/ModulePage.cs | 344 +++ .../Client/Win32/ModulePropertiesPage.cs | 87 + .../Client/Win32/ModulePropertiesPage.resx | 120 + .../Client/Win32/SortableListView.cs | 60 + .../Client/Win32/TaskForm.cs | 66 + .../Client/Win32/TextTaskItem.cs | 29 + .../Client/Win32/WaitCursor.cs | 14 + .../Client/Win32/WizardForm.cs | 381 ++++ .../Client/Win32/WizardForm.resx | 120 + .../Client/Win32/WizardPage.cs | 140 ++ .../Client/Win32/WizardPage.resx | 120 + .../AdministratorsModuleProvider.cs | 30 + .../Delegation/DelegationModuleProvider.cs | 27 + .../Services/ServiceModuleProvider.cs | 26 + .../Host/ConnectionManager.cs | 152 ++ .../Host/IManagementHost.cs | 29 + .../Host/Shell/ShellApplication.cs | 32 + .../Host/Shell/ShellComponents.cs | 13 + Microsoft.Web.Management/JexusManager.snk | Bin 0 -> 596 bytes .../Microsoft.Web.Management.csproj | 276 +++ .../Properties/AssemblyInfo.cs | 56 + .../Properties/Resources.Designer.cs | 89 + .../Properties/Resources.resx | 127 ++ .../Resources/apply_16.png | Bin 0 -> 701 bytes .../Resources/cancel_16.png | Bin 0 -> 744 bytes .../Server/AdministrationModule.cs | 16 + .../Server/AdministrationModuleCollection.cs | 40 + .../Server/AdministrationModuleProvider.cs | 12 + .../Server/ApplicationManagementUnit.cs | 27 + .../Server/BindingInfo.cs | 30 + ...onfigurationAuthenticationModuleService.cs | 35 + .../Server/ConfigurationModuleProvider.cs | 24 + .../Server/ConfigurationPathType.cs | 15 + .../Server/DelegationState.cs | 20 + .../Server/IAuthenticationModuleService.cs | 11 + .../Server/IGlobalConfigurationProvider.cs | 18 + .../Server/IManagementContext.cs | 19 + .../Server/ISiteStatusProvider.cs | 19 + .../Server/InvalidPasswordReason.cs | 16 + .../ManagementAdministrationConfiguration.cs | 24 + .../Server/ManagementAuthentication.cs | 74 + .../ManagementAuthenticationProvider.cs | 64 + .../Server/ManagementAuthorization.cs | 74 + .../Server/ManagementAuthorizationInfo.cs | 24 + .../ManagementAuthorizationInfoCollection.cs | 12 + .../Server/ManagementAuthorizationProvider.cs | 58 + .../Server/ManagementConfiguration.cs | 46 + .../Server/ManagementConfigurationPath.cs | 82 + .../Server/ManagementContentNavigator.cs | 79 + .../Server/ManagementFrameworkVersion.cs | 22 + .../Server/ManagementScope.cs | 13 + .../Server/ManagementUnit.cs | 71 + .../Server/ManagementUserInfo.cs | 26 + .../Server/ManagementUserInfoCollection.cs | 12 + .../Server/ModuleDefinition.cs | 21 + Microsoft.Web.Management/Server/ModuleInfo.cs | 15 + .../Server/ModuleProvider.cs | 39 + .../Server/ModuleService.cs | 36 + .../Server/ModuleServiceMethodAttribute.cs | 13 + .../Server/PropertyBag.cs | 256 +++ .../Server/ServerManagementUnit.cs | 45 + .../Server/SimpleDelegatedModuleProvider.cs | 37 + Microsoft.Web.Management/Server/SiteInfo.cs | 28 + .../Server/SiteManagementUnit.cs | 18 + .../Server/TypeInformationGenerator.cs | 15 + .../Server/WebManagementEventLog.cs | 46 + .../Server/WebManagementServiceException.cs | 47 + .../Server/WebManagementServiceHandler.cs | 25 + .../Utility/ServiceUtility.cs | 17 + Microsoft.Web.Management/app.config | 11 + Readme.txt | 7 + Tests.IIS/Helper.cs | 22 + Tests.IIS/JexusManager.snk | Bin 0 -> 596 bytes Tests.IIS/Properties/AssemblyInfo.cs | 40 + Tests.IIS/ServerManagerTestFixture.cs | 196 ++ Tests.IIS/Tests.IIS.csproj | 217 ++ Tests.IIS/default.runsettings | 19 + Tests.IIS/packages.config | 11 + .../AuthorizationFeatureServerTestFixture.cs | 150 ++ .../AuthorizationFeatureSiteTestFixture.cs | 197 ++ .../Authorization/expected_add.config | 1122 +++++++++ .../Authorization/expected_add.site.config | 15 + .../Authorization/expected_edit.config | 1121 +++++++++ .../Authorization/expected_edit.site.config | 18 + .../Authorization/expected_edit1.site.config | 16 + .../Authorization/expected_remove.config | 1117 +++++++++ .../Authorization/expected_remove.site.config | 15 + .../expected_remove1.site.config | 10 + .../CachingFeatureServerTestFixture.cs | 151 ++ .../Caching/CachingFeatureSiteTestFixture.cs | 200 ++ .../Caching/expected_add.config | 1123 +++++++++ .../Caching/expected_add.site.config | 15 + .../Caching/expected_edit.config | 1123 +++++++++ .../Caching/expected_edit.site.config | 16 + .../Caching/expected_edit1.site.config | 15 + .../Caching/expected_remove.config | 1118 +++++++++ .../Caching/expected_remove.site.config | 15 + .../Caching/expected_remove1.site.config | 10 + ...DefaultDocumentFeatureServerTestFixture.cs | 210 ++ .../DefaultDocumentFeatureSiteTestFixture.cs | 220 ++ .../DefaultDocument/expected_add.config | 1122 +++++++++ .../DefaultDocument/expected_add.site.config | 11 + .../DefaultDocument/expected_disabled.config | 1121 +++++++++ .../expected_disabled.site.config | 10 + .../DefaultDocument/expected_remove.config | 1120 +++++++++ .../expected_remove.site.config | 11 + .../expected_remove1.site.config | 4 + .../expected_revert.site.config | 7 + .../DefaultDocument/expected_up.config | 1121 +++++++++ .../DefaultDocument/expected_up.site.config | 17 + .../DefaultDocument/expected_up1.site.config | 12 + ...DirectoryBrowseFeatureServerTestFixture.cs | 113 + .../DirectoryBrowseFeatureSiteTestFixture.cs | 118 + .../DirectoryBrowse/expected_edit.config | 1122 +++++++++ .../expected_edit1.site.config | 11 + .../HandlersFeatureServerTestFixture.cs | 211 ++ .../HandlersFeatureSiteTestFixture.cs | 284 +++ .../Handlers/expected_add.config | 1127 ++++++++++ .../Handlers/expected_add.site.config | 1134 ++++++++++ .../Handlers/expected_edit.config | 1122 +++++++++ .../Handlers/expected_edit.site.config | 1138 ++++++++++ .../Handlers/expected_edit1.site.config | 1134 ++++++++++ .../Handlers/expected_remove.config | 1123 +++++++++ .../Handlers/expected_remove.site.config | 1130 ++++++++++ .../Handlers/expected_remove1.site.config | 1126 ++++++++++ .../Handlers/expected_revert.site.config | 1127 ++++++++++ .../Handlers/expected_up.config | 1123 +++++++++ .../Handlers/expected_up.site.config | 1634 ++++++++++++++ .../Handlers/expected_up1.site.config | 1142 ++++++++++ .../HttpErrorsFeatureServerTestFixture.cs | 155 ++ .../HttpErrorsFeatureSiteTestFixture.cs | 205 ++ .../HttpErrors/expected_add.config | 1125 ++++++++++ .../HttpErrors/expected_add.site.config | 14 + .../HttpErrors/expected_edit.config | 1123 +++++++++ .../HttpErrors/expected_edit.site.config | 16 + .../HttpErrors/expected_edit1.site.config | 14 + .../HttpErrors/expected_remove.config | 1124 ++++++++++ .../HttpErrors/expected_remove.site.config | 13 + .../HttpErrors/expected_remove1.site.config | 10 + .../IpSecurityFeatureServerTestFixture.cs | 140 ++ .../IpSecurityFeatureSiteTestFixture.cs | 176 ++ .../IpSecurity/expected_add.config | 1124 ++++++++++ .../IpSecurity/expected_add.site.config | 1131 ++++++++++ .../IpSecurity/expected_edit.config | 1120 +++++++++ .../IpSecurity/expected_edit.site.config | 16 + .../IpSecurity/expected_edit1.site.config | 14 + .../IpSecurity/expected_remove.config | 1119 +++++++++ .../IpSecurity/expected_remove.site.config | 1131 ++++++++++ .../IpSecurity/expected_remove1.site.config | 1124 ++++++++++ .../IpSecurity/expected_revert.site.config | 1128 ++++++++++ ...iCgiRestrictionFeatureServerTestFixture.cs | 154 ++ ...apiCgiRestrictionFeatureSiteTestFixture.cs | 202 ++ .../IsapiCgiRestriction/expected_add.config | 1125 ++++++++++ .../expected_add.site.config | 1133 ++++++++++ .../IsapiCgiRestriction/expected_edit.config | 1123 +++++++++ .../expected_edit.site.config | 1135 ++++++++++ .../expected_edit1.site.config | 1134 ++++++++++ .../expected_remove.config | 1122 +++++++++ .../expected_remove.site.config | 1131 ++++++++++ .../expected_remove1.site.config | 1124 ++++++++++ .../expected_revert.site.config | 1128 ++++++++++ .../IsapiFiltersFeatureServerTestFixture.cs | 210 ++ .../IsapiFiltersFeatureSiteTestFixture.cs | 284 +++ .../IsapiFilters/expected_add.config | 1124 ++++++++++ .../IsapiFilters/expected_add.site.config | 1130 ++++++++++ .../IsapiFilters/expected_edit.config | 1124 ++++++++++ .../IsapiFilters/expected_edit.site.config | 1134 ++++++++++ .../IsapiFilters/expected_edit1.site.config | 1131 ++++++++++ .../IsapiFilters/expected_remove.config | 1122 +++++++++ .../IsapiFilters/expected_remove.site.config | 1129 ++++++++++ .../IsapiFilters/expected_remove1.site.config | 1124 ++++++++++ .../IsapiFilters/expected_revert.site.config | 1127 ++++++++++ .../IsapiFilters/expected_up.config | 1123 +++++++++ .../IsapiFilters/expected_up.site.config | 1151 ++++++++++ .../IsapiFilters/expected_up1.site.config | 1135 ++++++++++ Tests.JexusManager/JexusManager.snk | Bin 0 -> 596 bytes Tests.JexusManager/Main/SiteTestFixture.cs | 135 ++ .../Main/expected_site_add.config | 1132 ++++++++++ .../MimeMapFeatureServerTestFixture.cs | 153 ++ .../MimeMap/MimeMapFeatureSiteTestFixture.cs | 202 ++ .../MimeMap/expected_add.config | 1123 +++++++++ .../MimeMap/expected_add.site.config | 14 + .../MimeMap/expected_edit.config | 1123 +++++++++ .../MimeMap/expected_edit.site.config | 14 + .../MimeMap/expected_edit1.site.config | 14 + .../MimeMap/expected_remove.config | 1123 +++++++++ .../MimeMap/expected_remove.site.config | 13 + .../MimeMap/expected_remove1.site.config | 10 + .../ModulesFeatureServerTestFixture.cs | 247 ++ .../Modules/ModulesFeatureSiteTestFixture.cs | 287 +++ .../Modules/expected_add.config | 1124 ++++++++++ .../Modules/expected_add.site.config | 1131 ++++++++++ .../Modules/expected_addglobal.config | 1123 +++++++++ .../Modules/expected_edit.config | 1123 +++++++++ .../Modules/expected_edit.site.config | 1133 ++++++++++ .../Modules/expected_edit1.site.config | 1131 ++++++++++ .../Modules/expected_remove.config | 1123 +++++++++ .../Modules/expected_remove.site.config | 1130 ++++++++++ .../Modules/expected_remove1.site.config | 1126 ++++++++++ .../Modules/expected_revert.site.config | 1127 ++++++++++ Tests.JexusManager/Modules/expected_up.config | 1124 ++++++++++ .../Modules/expected_up.site.config | 1233 ++++++++++ .../Modules/expected_up1.site.config | 1135 ++++++++++ Tests.JexusManager/Properties/AssemblyInfo.cs | 40 + .../FileExtensionsFeatureServerTestFixture.cs | 130 ++ .../FileExtensionsFeatureSiteTestFixture.cs | 155 ++ .../FileExtensions/expected_add.config | 1123 +++++++++ .../FileExtensions/expected_add.site.config | 18 + .../FileExtensions/expected_remove.config | 1123 +++++++++ .../expected_remove.site.config | 17 + .../expected_remove1.site.config | 10 + .../FilteringRulesFeatureServerTestFixture.cs | 151 ++ .../FilteringRulesFeatureSiteTestFixture.cs | 199 ++ .../FilteringRules/expected_add.config | 1122 +++++++++ .../FilteringRules/expected_add.site.config | 17 + .../FilteringRules/expected_edit.config | 1121 +++++++++ .../FilteringRules/expected_edit.site.config | 20 + .../FilteringRules/expected_edit1.site.config | 19 + .../FilteringRules/expected_remove.config | 1118 +++++++++ .../expected_remove.site.config | 17 + .../expected_remove1.site.config | 10 + .../HeadersFeatureServerTestFixture.cs | 131 ++ .../Headers/HeadersFeatureSiteTestFixture.cs | 156 ++ .../Headers/expected_add.config | 1122 +++++++++ .../Headers/expected_add.site.config | 20 + .../Headers/expected_remove.config | 1117 +++++++++ .../Headers/expected_remove.site.config | 19 + .../Headers/expected_remove1.site.config | 10 + .../HiddenSegmentsFeatureServerTestFixture.cs | 130 ++ .../HiddenSegmentsFeatureSiteTestFixture.cs | 155 ++ .../HiddenSegments/expected_add.config | 1123 +++++++++ .../HiddenSegments/expected_add.site.config | 17 + .../HiddenSegments/expected_remove.config | 1123 +++++++++ .../expected_remove.site.config | 17 + .../expected_remove1.site.config | 10 + .../QueryStringsFeatureServerTestFixture.cs | 171 ++ .../QueryStringsFeatureSiteTestFixture.cs | 194 ++ .../QueryStrings/expected_add.config | 1122 +++++++++ .../QueryStrings/expected_add.site.config | 17 + .../QueryStrings/expected_add_deny.config | 1122 +++++++++ .../expected_add_deny.site.config | 17 + .../QueryStrings/expected_remove.config | 1119 +++++++++ .../QueryStrings/expected_remove.site.config | 17 + .../QueryStrings/expected_remove1.site.config | 10 + .../expected_remove1_deny.site.config | 10 + .../QueryStrings/expected_remove_deny.config | 1119 +++++++++ .../Urls/UrlsFeatureServerTestFixture.cs | 150 ++ .../Urls/UrlsFeatureSiteTestFixture.cs | 194 ++ .../RequestFiltering/Urls/expected_add.config | 1123 +++++++++ .../Urls/expected_add.site.config | 17 + .../Urls/expected_add_deny.config | 1123 +++++++++ .../Urls/expected_add_deny.site.config | 17 + .../Urls/expected_remove.config | 1119 +++++++++ .../Urls/expected_remove.site.config | 17 + .../Urls/expected_remove1.site.config | 10 + .../Urls/expected_remove1_deny.site.config | 10 + .../Urls/expected_remove_deny.config | 1119 +++++++++ .../Verbs/VerbsFeatureServerTestFixture.cs | 130 ++ .../Verbs/VerbsFeatureSiteTestFixture.cs | 155 ++ .../Verbs/expected_add.config | 1122 +++++++++ .../Verbs/expected_add.site.config | 17 + .../Verbs/expected_remove.config | 1119 +++++++++ .../Verbs/expected_remove.site.config | 17 + .../Verbs/expected_remove1.site.config | 10 + ...ResponseHeadersFeatureServerTestFixture.cs | 153 ++ .../ResponseHeadersFeatureSiteTestFixture.cs | 202 ++ .../ResponseHeaders/expected_add.config | 1123 +++++++++ .../ResponseHeaders/expected_add.site.config | 16 + .../ResponseHeaders/expected_edit.config | 1123 +++++++++ .../ResponseHeaders/expected_edit.site.config | 17 + .../expected_edit1.site.config | 16 + .../ResponseHeaders/expected_remove.config | 1123 +++++++++ .../expected_remove.site.config | 15 + .../expected_remove1.site.config | 10 + Tests.JexusManager/TestFixture.cs | 48 + Tests.JexusManager/Tests.JexusManager.csproj | 773 +++++++ Tests.JexusManager/app.config | 15 + Tests.JexusManager/packages.config | 12 + dist.deploy.bat | 6 + jexus.png | Bin 0 -> 2606 bytes lib/7z.dll | Bin 0 -> 1422336 bytes lib/7z.exe | Bin 0 -> 284160 bytes lib/AssemblyInfoTask.dll | Bin 0 -> 43776 bytes .../CheckBoxComboBox.Designer.cs | 36 + lib/CheckBoxComboBox/CheckBoxComboBox.cs | 912 ++++++++ lib/CheckBoxComboBox/CheckBoxComboBox.csproj | 102 + lib/CheckBoxComboBox/GripBounds.cs | 116 + lib/CheckBoxComboBox/NativeMethods.cs | 60 + lib/CheckBoxComboBox/Popup.Designer.cs | 45 + lib/CheckBoxComboBox/Popup.cs | 520 +++++ .../PopupComboBox.Designer.cs | 48 + lib/CheckBoxComboBox/PopupComboBox.cs | 153 ++ lib/CheckBoxComboBox/PopupComboBox.resx | 123 + .../Properties/AssemblyInfo.cs | 36 + .../ListSelectionWrapper.cs | 238 ++ .../ObjectSelectionWrapper.cs | 141 ++ lib/CheckBoxComboBox/test.snk | Bin 0 -> 596 bytes lib/ExpandCollapsePanel | 1 + lib/Mono.Posix.dll | Bin 0 -> 183808 bytes lib/Mono.Security.dll | Bin 0 -> 289280 bytes lib/SharedAssemblyInfo.cs | 17 + lib/Vista.Controls.BreadcrumbBar/Areo.cs | 282 +++ .../BreadcrumbBar.cs | 820 +++++++ .../BreadcrumbBarButton.cs | 172 ++ .../BreadcrumbBarNode.cs | 358 +++ .../BreadcrumbBarNodeClickedEventArgs.cs | 14 + .../BreadcrumbBarRootNode.cs | 122 + .../BreadcrumbDropDownItem.cs | 60 + .../BreadcrumbDropDownItems.cs | 122 + .../Design/GraphicsTools.cs | 101 + .../Design/WindowsVistaColorTable.cs | 316 +++ .../Design/WindowsVistaRenderer.cs | 673 ++++++ .../ExplorerAddressNavigation.cs | 136 ++ .../ExplorerNavigation.cs | 519 +++++ .../ExplorerNavigationHistory.cs | 139 ++ .../ExplorerNavigationHistoryItem.cs | 81 + .../GlassTextBox.cs | 122 + .../Images/background.pdn | Bin 0 -> 28129 bytes .../Images/leftbuttons.pdn | Bin 0 -> 26335 bytes .../Images/rightbuttons.pdn | Bin 0 -> 26388 bytes .../Properties/AssemblyInfo.cs | 36 + .../Properties/Resources.Designer.cs | 173 ++ .../Properties/Resources.resx | 154 ++ .../Resources/GoToNextHS.png | Bin 0 -> 427 bytes .../Resources/GoToPrevious.png | Bin 0 -> 3087 bytes .../Resources/StopHS.png | Bin 0 -> 410 bytes .../Resources/background.png | Bin 0 -> 6386 bytes .../Resources/background2.png | Bin 0 -> 6203 bytes .../Resources/folder.png | Bin 0 -> 1427 bytes .../Resources/leftbuttons.png | Bin 0 -> 8610 bytes .../Resources/leftbuttons2.png | Bin 0 -> 8868 bytes .../Resources/refresh.png | Bin 0 -> 1308 bytes .../Resources/rightbuttons.png | Bin 0 -> 8564 bytes .../Resources/rightbuttons2.png | Bin 0 -> 8871 bytes .../Vista.Controls.BreadcrumbBar.csproj | 197 ++ ...Vista.Controls.BreadcrumbBar.csproj.vspscc | 10 + .../breadcrumb.snk | Bin 0 -> 596 bytes .../explorernavigation.bmp | Bin 0 -> 1334 bytes lib/XmlDiffPatch.View.dll | Bin 0 -> 35840 bytes lib/xmldiffpatch.dll | Bin 0 -> 100912 bytes list.txt | 8 + merge.bat | 15 + mwa | 1 + obfuscate.bat | 5 + package.bat | 6 + release.bat | 5 + 1360 files changed, 229174 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitattributes create mode 100644 .gitignore create mode 100644 .gitmodules create mode 100644 .nuget/NuGet.exe create mode 100644 CertificateInstaller/App.config create mode 100644 CertificateInstaller/CertificateInstaller.csproj create mode 100644 CertificateInstaller/Program.cs create mode 100644 CertificateInstaller/Properties/AssemblyInfo.cs create mode 100644 CertificateInstaller/app.manifest create mode 100644 CertificateInstaller/packages.config create mode 100644 JexusManager.Features.Access/AccessFeature.cs create mode 100644 JexusManager.Features.Access/AccessModule.cs create mode 100644 JexusManager.Features.Access/AccessModuleProvider.cs create mode 100644 JexusManager.Features.Access/AccessPage.Designer.cs create mode 100644 JexusManager.Features.Access/AccessPage.cs create mode 100644 JexusManager.Features.Access/AccessPage.resx create mode 100644 JexusManager.Features.Access/AccessSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.Access/JexusManager.Features.Access.csproj create mode 100644 JexusManager.Features.Access/JexusManager.snk create mode 100644 JexusManager.Features.Access/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.Access/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.Access/Properties/Resources.resx create mode 100644 JexusManager.Features.Access/Resources/access_36.png create mode 100644 JexusManager.Features.Authentication/AnonymousAuthenticationFeature.cs create mode 100644 JexusManager.Features.Authentication/AnonymousEditDialog.Designer.cs create mode 100644 JexusManager.Features.Authentication/AnonymousEditDialog.cs create mode 100644 JexusManager.Features.Authentication/AnonymousEditDialog.resx create mode 100644 JexusManager.Features.Authentication/AnonymousItem.cs create mode 100644 JexusManager.Features.Authentication/AuthenticationModule.cs create mode 100644 JexusManager.Features.Authentication/AuthenticationModuleProvider.cs create mode 100644 JexusManager.Features.Authentication/AuthenticationPage.Designer.cs create mode 100644 JexusManager.Features.Authentication/AuthenticationPage.cs create mode 100644 JexusManager.Features.Authentication/AuthenticationPage.resx create mode 100644 JexusManager.Features.Authentication/BasicAuthenticationFeature.cs create mode 100644 JexusManager.Features.Authentication/BasicEditDialog.Designer.cs create mode 100644 JexusManager.Features.Authentication/BasicEditDialog.cs create mode 100644 JexusManager.Features.Authentication/BasicEditDialog.resx create mode 100644 JexusManager.Features.Authentication/BasicItem.cs create mode 100644 JexusManager.Features.Authentication/ClientCertificateAuthenticationFeature.cs create mode 100644 JexusManager.Features.Authentication/CredentialsDialog.Designer.cs create mode 100644 JexusManager.Features.Authentication/CredentialsDialog.cs create mode 100644 JexusManager.Features.Authentication/CredentialsDialog.resx create mode 100644 JexusManager.Features.Authentication/DigestAuthenticationFeature.cs create mode 100644 JexusManager.Features.Authentication/DigestEditDialog.Designer.cs create mode 100644 JexusManager.Features.Authentication/DigestEditDialog.cs create mode 100644 JexusManager.Features.Authentication/DigestEditDialog.resx create mode 100644 JexusManager.Features.Authentication/DigestItem.cs create mode 100644 JexusManager.Features.Authentication/FormsAuthenticationFeature.cs create mode 100644 JexusManager.Features.Authentication/FormsEditDialog.Designer.cs create mode 100644 JexusManager.Features.Authentication/FormsEditDialog.cs create mode 100644 JexusManager.Features.Authentication/FormsEditDialog.resx create mode 100644 JexusManager.Features.Authentication/FormsItem.cs create mode 100644 JexusManager.Features.Authentication/ImpersonationEditDialog.Designer.cs create mode 100644 JexusManager.Features.Authentication/ImpersonationEditDialog.cs create mode 100644 JexusManager.Features.Authentication/ImpersonationEditDialog.resx create mode 100644 JexusManager.Features.Authentication/ImpersonationFeature.cs create mode 100644 JexusManager.Features.Authentication/ImpersonationItem.cs create mode 100644 JexusManager.Features.Authentication/JexusManager.Features.Authentication.csproj create mode 100644 JexusManager.Features.Authentication/JexusManager.snk create mode 100644 JexusManager.Features.Authentication/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.Authentication/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.Authentication/Properties/Resources.resx create mode 100644 JexusManager.Features.Authentication/ProviderItem.cs create mode 100644 JexusManager.Features.Authentication/ProvidersDialog.Designer.cs create mode 100644 JexusManager.Features.Authentication/ProvidersDialog.cs create mode 100644 JexusManager.Features.Authentication/ProvidersDialog.resx create mode 100644 JexusManager.Features.Authentication/Resources/authentication_36.png create mode 100644 JexusManager.Features.Authentication/WindowsAdvancedDialog.Designer.cs create mode 100644 JexusManager.Features.Authentication/WindowsAdvancedDialog.cs create mode 100644 JexusManager.Features.Authentication/WindowsAdvancedDialog.resx create mode 100644 JexusManager.Features.Authentication/WindowsAuthenticationFeature.cs create mode 100644 JexusManager.Features.Authentication/WindowsItem.cs create mode 100644 JexusManager.Features.Authentication/packages.config create mode 100644 JexusManager.Features.Authorization/AuthorizationFeature.cs create mode 100644 JexusManager.Features.Authorization/AuthorizationModule.cs create mode 100644 JexusManager.Features.Authorization/AuthorizationModuleProvider.cs create mode 100644 JexusManager.Features.Authorization/AuthorizationPage.Designer.cs create mode 100644 JexusManager.Features.Authorization/AuthorizationPage.cs create mode 100644 JexusManager.Features.Authorization/AuthorizationPage.resx create mode 100644 JexusManager.Features.Authorization/AuthorizationRule.cs create mode 100644 JexusManager.Features.Authorization/AuthorizationSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.Authorization/JexusManager.Features.Authorization.csproj create mode 100644 JexusManager.Features.Authorization/JexusManager.snk create mode 100644 JexusManager.Features.Authorization/NewRuleDialog.Designer.cs create mode 100644 JexusManager.Features.Authorization/NewRuleDialog.cs create mode 100644 JexusManager.Features.Authorization/NewRuleDialog.resx create mode 100644 JexusManager.Features.Authorization/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.Authorization/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.Authorization/Properties/Resources.resx create mode 100644 JexusManager.Features.Authorization/Resources/authorization_36.png create mode 100644 JexusManager.Features.Authorization/packages.config create mode 100644 JexusManager.Features.Caching/CachingAdvancedDialog.Designer.cs create mode 100644 JexusManager.Features.Caching/CachingAdvancedDialog.cs create mode 100644 JexusManager.Features.Caching/CachingAdvancedDialog.resx create mode 100644 JexusManager.Features.Caching/CachingFeature.cs create mode 100644 JexusManager.Features.Caching/CachingItem.cs create mode 100644 JexusManager.Features.Caching/CachingModule.cs create mode 100644 JexusManager.Features.Caching/CachingModuleProvider.cs create mode 100644 JexusManager.Features.Caching/CachingPage.Designer.cs create mode 100644 JexusManager.Features.Caching/CachingPage.cs create mode 100644 JexusManager.Features.Caching/CachingPage.resx create mode 100644 JexusManager.Features.Caching/CachingSettingsDialog.Designer.cs create mode 100644 JexusManager.Features.Caching/CachingSettingsDialog.cs create mode 100644 JexusManager.Features.Caching/CachingSettingsDialog.resx create mode 100644 JexusManager.Features.Caching/CachingSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.Caching/JexusManager.Features.Caching.csproj create mode 100644 JexusManager.Features.Caching/JexusManager.snk create mode 100644 JexusManager.Features.Caching/NewCachingDialog.Designer.cs create mode 100644 JexusManager.Features.Caching/NewCachingDialog.cs create mode 100644 JexusManager.Features.Caching/NewCachingDialog.resx create mode 100644 JexusManager.Features.Caching/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.Caching/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.Caching/Properties/Resources.resx create mode 100644 JexusManager.Features.Caching/Resources/caching_36.png create mode 100644 JexusManager.Features.Caching/packages.config create mode 100644 JexusManager.Features.Certificates/CertificatesFeature.cs create mode 100644 JexusManager.Features.Certificates/CertificatesItem.cs create mode 100644 JexusManager.Features.Certificates/CertificatesModule.cs create mode 100644 JexusManager.Features.Certificates/CertificatesModuleProvider.cs create mode 100644 JexusManager.Features.Certificates/CertificatesPage.Designer.cs create mode 100644 JexusManager.Features.Certificates/CertificatesPage.cs create mode 100644 JexusManager.Features.Certificates/CertificatesPage.resx create mode 100644 JexusManager.Features.Certificates/CertificatesSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.Certificates/CompleteRequestDialog.Designer.cs create mode 100644 JexusManager.Features.Certificates/CompleteRequestDialog.cs create mode 100644 JexusManager.Features.Certificates/CompleteRequestDialog.resx create mode 100644 JexusManager.Features.Certificates/ExportCertificateDialog.Designer.cs create mode 100644 JexusManager.Features.Certificates/ExportCertificateDialog.cs create mode 100644 JexusManager.Features.Certificates/ExportCertificateDialog.resx create mode 100644 JexusManager.Features.Certificates/ImportCertificateDialog.Designer.cs create mode 100644 JexusManager.Features.Certificates/ImportCertificateDialog.cs create mode 100644 JexusManager.Features.Certificates/ImportCertificateDialog.resx create mode 100644 JexusManager.Features.Certificates/JexusManager.Features.Certificates.csproj create mode 100644 JexusManager.Features.Certificates/JexusManager.snk create mode 100644 JexusManager.Features.Certificates/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.Certificates/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.Certificates/Properties/Resources.resx create mode 100644 JexusManager.Features.Certificates/Resources/certificates_36.png create mode 100644 JexusManager.Features.Certificates/Resources/certificates_48.png create mode 100644 JexusManager.Features.Certificates/SelfCertificateDialog.Designer.cs create mode 100644 JexusManager.Features.Certificates/SelfCertificateDialog.cs create mode 100644 JexusManager.Features.Certificates/SelfCertificateDialog.resx create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizard.Designer.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizard.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizard.resx create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizardData.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/FinishPage.Designer.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/FinishPage.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/FinishPage.resx create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/OptionsPage.Designer.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/OptionsPage.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/OptionsPage.resx create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizard.Designer.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizard.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizard.resx create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizardData.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/FinishPage.Designer.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/FinishPage.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/FinishPage.resx create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/KeysPage.Designer.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/KeysPage.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/KeysPage.resx create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/PropertiesPage.Designer.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/PropertiesPage.cs create mode 100644 JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/PropertiesPage.resx create mode 100644 JexusManager.Features.Certificates/packages.config create mode 100644 JexusManager.Features.Cgi/CgiFeature.cs create mode 100644 JexusManager.Features.Cgi/CgiItem.cs create mode 100644 JexusManager.Features.Cgi/CgiModule.cs create mode 100644 JexusManager.Features.Cgi/CgiModuleProvider.cs create mode 100644 JexusManager.Features.Cgi/CgiPage.Designer.cs create mode 100644 JexusManager.Features.Cgi/CgiPage.cs create mode 100644 JexusManager.Features.Cgi/CgiPage.resx create mode 100644 JexusManager.Features.Cgi/CgiSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.Cgi/JexusManager.Features.Cgi.csproj create mode 100644 JexusManager.Features.Cgi/JexusManager.snk create mode 100644 JexusManager.Features.Cgi/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.Cgi/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.Cgi/Properties/Resources.resx create mode 100644 JexusManager.Features.Cgi/Resources/cgi_36.png create mode 100644 JexusManager.Features.Compression/CompressionFeature.cs create mode 100644 JexusManager.Features.Compression/CompressionModule.cs create mode 100644 JexusManager.Features.Compression/CompressionModuleProvider.cs create mode 100644 JexusManager.Features.Compression/CompressionPage.Designer.cs create mode 100644 JexusManager.Features.Compression/CompressionPage.cs create mode 100644 JexusManager.Features.Compression/CompressionPage.resx create mode 100644 JexusManager.Features.Compression/CompressionSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.Compression/JexusManager.Features.Compression.csproj create mode 100644 JexusManager.Features.Compression/JexusManager.snk create mode 100644 JexusManager.Features.Compression/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.Compression/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.Compression/Properties/Resources.resx create mode 100644 JexusManager.Features.Compression/Resources/compression_36.png create mode 100644 JexusManager.Features.DefaultDocument/DefaultDocumentFeature.cs create mode 100644 JexusManager.Features.DefaultDocument/DefaultDocumentModule.cs create mode 100644 JexusManager.Features.DefaultDocument/DefaultDocumentModuleProvider.cs create mode 100644 JexusManager.Features.DefaultDocument/DefaultDocumentPage.Designer.cs create mode 100644 JexusManager.Features.DefaultDocument/DefaultDocumentPage.cs create mode 100644 JexusManager.Features.DefaultDocument/DefaultDocumentPage.resx create mode 100644 JexusManager.Features.DefaultDocument/DefaultDocumentSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.DefaultDocument/DocumentItem.cs create mode 100644 JexusManager.Features.DefaultDocument/JexusManager.Features.DefaultDocument.csproj create mode 100644 JexusManager.Features.DefaultDocument/JexusManager.snk create mode 100644 JexusManager.Features.DefaultDocument/NewDefaultDocumentDialog.Designer.cs create mode 100644 JexusManager.Features.DefaultDocument/NewDefaultDocumentDialog.cs create mode 100644 JexusManager.Features.DefaultDocument/NewDefaultDocumentDialog.resx create mode 100644 JexusManager.Features.DefaultDocument/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.DefaultDocument/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.DefaultDocument/Properties/Resources.resx create mode 100644 JexusManager.Features.DefaultDocument/Resources/default_document_36.png create mode 100644 JexusManager.Features.DefaultDocument/packages.config create mode 100644 JexusManager.Features.DirectoryBrowse/DirectoryBrowseFeature.cs create mode 100644 JexusManager.Features.DirectoryBrowse/DirectoryBrowseModule.cs create mode 100644 JexusManager.Features.DirectoryBrowse/DirectoryBrowseModuleProvider.cs create mode 100644 JexusManager.Features.DirectoryBrowse/DirectoryBrowsePage.Designer.cs create mode 100644 JexusManager.Features.DirectoryBrowse/DirectoryBrowsePage.cs create mode 100644 JexusManager.Features.DirectoryBrowse/DirectoryBrowsePage.resx create mode 100644 JexusManager.Features.DirectoryBrowse/DirectoryBrowseSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.DirectoryBrowse/JexusManager.Features.DirectoryBrowse.csproj create mode 100644 JexusManager.Features.DirectoryBrowse/JexusManager.snk create mode 100644 JexusManager.Features.DirectoryBrowse/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.DirectoryBrowse/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.DirectoryBrowse/Properties/Resources.resx create mode 100644 JexusManager.Features.DirectoryBrowse/Resources/directory_browsing_36.png create mode 100644 JexusManager.Features.FastCgi/EnvironmentVariables.cs create mode 100644 JexusManager.Features.FastCgi/EnvironmentVariablesCollection.cs create mode 100644 JexusManager.Features.FastCgi/EnvironmentVariablesCollectionEditor.cs create mode 100644 JexusManager.Features.FastCgi/ErrorMode.cs create mode 100644 JexusManager.Features.FastCgi/FastCgiFeature.cs create mode 100644 JexusManager.Features.FastCgi/FastCgiItem.cs create mode 100644 JexusManager.Features.FastCgi/FastCgiModule.cs create mode 100644 JexusManager.Features.FastCgi/FastCgiModuleProvider.cs create mode 100644 JexusManager.Features.FastCgi/FastCgiPage.Designer.cs create mode 100644 JexusManager.Features.FastCgi/FastCgiPage.cs create mode 100644 JexusManager.Features.FastCgi/FastCgiPage.resx create mode 100644 JexusManager.Features.FastCgi/FastCgiSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.FastCgi/JexusManager.Features.FastCgi.csproj create mode 100644 JexusManager.Features.FastCgi/JexusManager.snk create mode 100644 JexusManager.Features.FastCgi/NewApplicationDialog.Designer.cs create mode 100644 JexusManager.Features.FastCgi/NewApplicationDialog.cs create mode 100644 JexusManager.Features.FastCgi/NewApplicationDialog.resx create mode 100644 JexusManager.Features.FastCgi/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.FastCgi/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.FastCgi/Properties/Resources.resx create mode 100644 JexusManager.Features.FastCgi/Protocol.cs create mode 100644 JexusManager.Features.FastCgi/Resources/response_header_36.png create mode 100644 JexusManager.Features.FastCgi/packages.config create mode 100644 JexusManager.Features.Handlers/HandlersFeature.cs create mode 100644 JexusManager.Features.Handlers/HandlersItem.cs create mode 100644 JexusManager.Features.Handlers/HandlersModule.cs create mode 100644 JexusManager.Features.Handlers/HandlersModuleProvider.cs create mode 100644 JexusManager.Features.Handlers/HandlersPage.Designer.cs create mode 100644 JexusManager.Features.Handlers/HandlersPage.cs create mode 100644 JexusManager.Features.Handlers/HandlersPage.resx create mode 100644 JexusManager.Features.Handlers/HandlersSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.Handlers/JexusManager.Features.Handlers.csproj create mode 100644 JexusManager.Features.Handlers/JexusManager.snk create mode 100644 JexusManager.Features.Handlers/NewHandlerDialog.Designer.cs create mode 100644 JexusManager.Features.Handlers/NewHandlerDialog.cs create mode 100644 JexusManager.Features.Handlers/NewHandlerDialog.resx create mode 100644 JexusManager.Features.Handlers/NewMappingDialog.Designer.cs create mode 100644 JexusManager.Features.Handlers/NewMappingDialog.cs create mode 100644 JexusManager.Features.Handlers/NewMappingDialog.resx create mode 100644 JexusManager.Features.Handlers/NewScriptMapDialog.Designer.cs create mode 100644 JexusManager.Features.Handlers/NewScriptMapDialog.cs create mode 100644 JexusManager.Features.Handlers/NewScriptMapDialog.resx create mode 100644 JexusManager.Features.Handlers/NewWildcardDialog.Designer.cs create mode 100644 JexusManager.Features.Handlers/NewWildcardDialog.cs create mode 100644 JexusManager.Features.Handlers/NewWildcardDialog.resx create mode 100644 JexusManager.Features.Handlers/PermissionsDialog.Designer.cs create mode 100644 JexusManager.Features.Handlers/PermissionsDialog.cs create mode 100644 JexusManager.Features.Handlers/PermissionsDialog.resx create mode 100644 JexusManager.Features.Handlers/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.Handlers/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.Handlers/Properties/Resources.resx create mode 100644 JexusManager.Features.Handlers/Resources/handlers_36.png create mode 100644 JexusManager.Features.Handlers/RestrictionsDialog.Designer.cs create mode 100644 JexusManager.Features.Handlers/RestrictionsDialog.cs create mode 100644 JexusManager.Features.Handlers/RestrictionsDialog.resx create mode 100644 JexusManager.Features.Handlers/packages.config create mode 100644 JexusManager.Features.HttpApi/HttpApiFeature.cs create mode 100644 JexusManager.Features.HttpApi/HttpApiModule.cs create mode 100644 JexusManager.Features.HttpApi/HttpApiModuleProvider.cs create mode 100644 JexusManager.Features.HttpApi/HttpApiPage.Designer.cs create mode 100644 JexusManager.Features.HttpApi/HttpApiPage.cs create mode 100644 JexusManager.Features.HttpApi/HttpApiPage.resx create mode 100644 JexusManager.Features.HttpApi/HttpApiSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.HttpApi/IHttpApiFeature.cs create mode 100644 JexusManager.Features.HttpApi/IpMappingFeature.cs create mode 100644 JexusManager.Features.HttpApi/IpMappingItem.cs create mode 100644 JexusManager.Features.HttpApi/JexusManager.Features.HttpApi.csproj create mode 100644 JexusManager.Features.HttpApi/JexusManager.snk create mode 100644 JexusManager.Features.HttpApi/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.HttpApi/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.HttpApi/Properties/Resources.resx create mode 100644 JexusManager.Features.HttpApi/ReservedUrlsFeature.cs create mode 100644 JexusManager.Features.HttpApi/ReservedUrlsItem.cs create mode 100644 JexusManager.Features.HttpApi/Resources/http_36.png create mode 100644 JexusManager.Features.HttpApi/SniMappingFeature.cs create mode 100644 JexusManager.Features.HttpApi/SniMappingItem.cs create mode 100644 JexusManager.Features.HttpApi/packages.config create mode 100644 JexusManager.Features.HttpErrors/EditDialog.Designer.cs create mode 100644 JexusManager.Features.HttpErrors/EditDialog.cs create mode 100644 JexusManager.Features.HttpErrors/EditDialog.resx create mode 100644 JexusManager.Features.HttpErrors/HttpErrorsFeature.cs create mode 100644 JexusManager.Features.HttpErrors/HttpErrorsItem.cs create mode 100644 JexusManager.Features.HttpErrors/HttpErrorsModule.cs create mode 100644 JexusManager.Features.HttpErrors/HttpErrorsModuleProvider.cs create mode 100644 JexusManager.Features.HttpErrors/HttpErrorsPage.Designer.cs create mode 100644 JexusManager.Features.HttpErrors/HttpErrorsPage.cs create mode 100644 JexusManager.Features.HttpErrors/HttpErrorsPage.resx create mode 100644 JexusManager.Features.HttpErrors/HttpErrorsSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.HttpErrors/JexusManager.Features.HttpErrors.csproj create mode 100644 JexusManager.Features.HttpErrors/JexusManager.snk create mode 100644 JexusManager.Features.HttpErrors/LocalErrorDialog.Designer.cs create mode 100644 JexusManager.Features.HttpErrors/LocalErrorDialog.cs create mode 100644 JexusManager.Features.HttpErrors/LocalErrorDialog.resx create mode 100644 JexusManager.Features.HttpErrors/NewErrorDialog.Designer.cs create mode 100644 JexusManager.Features.HttpErrors/NewErrorDialog.cs create mode 100644 JexusManager.Features.HttpErrors/NewErrorDialog.resx create mode 100644 JexusManager.Features.HttpErrors/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.HttpErrors/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.HttpErrors/Properties/Resources.resx create mode 100644 JexusManager.Features.HttpErrors/Resources/custom_error_36.png create mode 100644 JexusManager.Features.HttpErrors/packages.config create mode 100644 JexusManager.Features.HttpRedirect/HttpRedirectFeature.cs create mode 100644 JexusManager.Features.HttpRedirect/HttpRedirectModule.cs create mode 100644 JexusManager.Features.HttpRedirect/HttpRedirectModuleProvider.cs create mode 100644 JexusManager.Features.HttpRedirect/HttpRedirectPage.Designer.cs create mode 100644 JexusManager.Features.HttpRedirect/HttpRedirectPage.cs create mode 100644 JexusManager.Features.HttpRedirect/HttpRedirectPage.resx create mode 100644 JexusManager.Features.HttpRedirect/HttpRedirectSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.HttpRedirect/JexusManager.Features.HttpRedirect.csproj create mode 100644 JexusManager.Features.HttpRedirect/JexusManager.snk create mode 100644 JexusManager.Features.HttpRedirect/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.HttpRedirect/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.HttpRedirect/Properties/Resources.resx create mode 100644 JexusManager.Features.HttpRedirect/Resources/http_redirect_36.png create mode 100644 JexusManager.Features.IpSecurity/DynamicDialog.Designer.cs create mode 100644 JexusManager.Features.IpSecurity/DynamicDialog.cs create mode 100644 JexusManager.Features.IpSecurity/DynamicDialog.resx create mode 100644 JexusManager.Features.IpSecurity/IpSecurityFeature.cs create mode 100644 JexusManager.Features.IpSecurity/IpSecurityItem.cs create mode 100644 JexusManager.Features.IpSecurity/IpSecurityModule.cs create mode 100644 JexusManager.Features.IpSecurity/IpSecurityModuleProvider.cs create mode 100644 JexusManager.Features.IpSecurity/IpSecurityPage.Designer.cs create mode 100644 JexusManager.Features.IpSecurity/IpSecurityPage.cs create mode 100644 JexusManager.Features.IpSecurity/IpSecurityPage.resx create mode 100644 JexusManager.Features.IpSecurity/IpSecuritySettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.IpSecurity/JexusManager.Features.IpSecurity.csproj create mode 100644 JexusManager.Features.IpSecurity/JexusManager.snk create mode 100644 JexusManager.Features.IpSecurity/NewRestrictionDialog.Designer.cs create mode 100644 JexusManager.Features.IpSecurity/NewRestrictionDialog.cs create mode 100644 JexusManager.Features.IpSecurity/NewRestrictionDialog.resx create mode 100644 JexusManager.Features.IpSecurity/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.IpSecurity/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.IpSecurity/Properties/Resources.resx create mode 100644 JexusManager.Features.IpSecurity/Resources/ip_restriction_36.png create mode 100644 JexusManager.Features.IpSecurity/SetRestrictionsDialog.Designer.cs create mode 100644 JexusManager.Features.IpSecurity/SetRestrictionsDialog.cs create mode 100644 JexusManager.Features.IpSecurity/SetRestrictionsDialog.resx create mode 100644 JexusManager.Features.IpSecurity/packages.config create mode 100644 JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionFeature.cs create mode 100644 JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionItem.cs create mode 100644 JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionModule.cs create mode 100644 JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionModuleProvider.cs create mode 100644 JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionPage.Designer.cs create mode 100644 JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionPage.cs create mode 100644 JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionPage.resx create mode 100644 JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.IsapiCgiRestriction/JexusManager.Features.IsapiCgiRestriction.csproj create mode 100644 JexusManager.Features.IsapiCgiRestriction/JexusManager.snk create mode 100644 JexusManager.Features.IsapiCgiRestriction/NewRestrictionDialog.Designer.cs create mode 100644 JexusManager.Features.IsapiCgiRestriction/NewRestrictionDialog.cs create mode 100644 JexusManager.Features.IsapiCgiRestriction/NewRestrictionDialog.resx create mode 100644 JexusManager.Features.IsapiCgiRestriction/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.IsapiCgiRestriction/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.IsapiCgiRestriction/Properties/Resources.resx create mode 100644 JexusManager.Features.IsapiCgiRestriction/Resources/isapi_cgi_restriction_36.png create mode 100644 JexusManager.Features.IsapiCgiRestriction/SettingsDialog.Designer.cs create mode 100644 JexusManager.Features.IsapiCgiRestriction/SettingsDialog.cs create mode 100644 JexusManager.Features.IsapiCgiRestriction/SettingsDialog.resx create mode 100644 JexusManager.Features.IsapiCgiRestriction/packages.config create mode 100644 JexusManager.Features.IsapiFilters/IsapiFiltersFeature.cs create mode 100644 JexusManager.Features.IsapiFilters/IsapiFiltersItem.cs create mode 100644 JexusManager.Features.IsapiFilters/IsapiFiltersModule.cs create mode 100644 JexusManager.Features.IsapiFilters/IsapiFiltersModuleProvider.cs create mode 100644 JexusManager.Features.IsapiFilters/IsapiFiltersPage.Designer.cs create mode 100644 JexusManager.Features.IsapiFilters/IsapiFiltersPage.cs create mode 100644 JexusManager.Features.IsapiFilters/IsapiFiltersPage.resx create mode 100644 JexusManager.Features.IsapiFilters/IsapiFiltersSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.IsapiFilters/JexusManager.Features.IsapiFilters.csproj create mode 100644 JexusManager.Features.IsapiFilters/JexusManager.snk create mode 100644 JexusManager.Features.IsapiFilters/NewFilterDialog.Designer.cs create mode 100644 JexusManager.Features.IsapiFilters/NewFilterDialog.cs create mode 100644 JexusManager.Features.IsapiFilters/NewFilterDialog.resx create mode 100644 JexusManager.Features.IsapiFilters/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.IsapiFilters/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.IsapiFilters/Properties/Resources.resx create mode 100644 JexusManager.Features.IsapiFilters/Resources/isapi_filters_36.png create mode 100644 JexusManager.Features.IsapiFilters/packages.config create mode 100644 JexusManager.Features.Jexus/JexusFeature.cs create mode 100644 JexusManager.Features.Jexus/JexusManager.Features.Jexus.csproj create mode 100644 JexusManager.Features.Jexus/JexusManager.snk create mode 100644 JexusManager.Features.Jexus/JexusModule.cs create mode 100644 JexusManager.Features.Jexus/JexusModuleProvider.cs create mode 100644 JexusManager.Features.Jexus/JexusPage.Designer.cs create mode 100644 JexusManager.Features.Jexus/JexusPage.cs create mode 100644 JexusManager.Features.Jexus/JexusPage.resx create mode 100644 JexusManager.Features.Jexus/JexusSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.Jexus/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.Jexus/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.Jexus/Properties/Resources.resx create mode 100644 JexusManager.Features.Jexus/Resources/jexus_36.png create mode 100644 JexusManager.Features.Logging/AddFieldDialog.Designer.cs create mode 100644 JexusManager.Features.Logging/AddFieldDialog.cs create mode 100644 JexusManager.Features.Logging/AddFieldDialog.resx create mode 100644 JexusManager.Features.Logging/FieldsDialog.Designer.cs create mode 100644 JexusManager.Features.Logging/FieldsDialog.cs create mode 100644 JexusManager.Features.Logging/FieldsDialog.resx create mode 100644 JexusManager.Features.Logging/JexusManager.Features.Logging.csproj create mode 100644 JexusManager.Features.Logging/JexusManager.snk create mode 100644 JexusManager.Features.Logging/LoggingFeature.cs create mode 100644 JexusManager.Features.Logging/LoggingModule.cs create mode 100644 JexusManager.Features.Logging/LoggingModuleProvider.cs create mode 100644 JexusManager.Features.Logging/LoggingPage.Designer.cs create mode 100644 JexusManager.Features.Logging/LoggingPage.cs create mode 100644 JexusManager.Features.Logging/LoggingPage.resx create mode 100644 JexusManager.Features.Logging/LoggingSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.Logging/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.Logging/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.Logging/Properties/Resources.resx create mode 100644 JexusManager.Features.Logging/Resources/logging_36.png create mode 100644 JexusManager.Features.Logging/packages.config create mode 100644 JexusManager.Features.MimeMap/JexusManager.Features.MimeMap.csproj create mode 100644 JexusManager.Features.MimeMap/JexusManager.snk create mode 100644 JexusManager.Features.MimeMap/MimeMapFeature.cs create mode 100644 JexusManager.Features.MimeMap/MimeMapItem.cs create mode 100644 JexusManager.Features.MimeMap/MimeMapModule.cs create mode 100644 JexusManager.Features.MimeMap/MimeMapModuleProvider.cs create mode 100644 JexusManager.Features.MimeMap/MimeMapPage.Designer.cs create mode 100644 JexusManager.Features.MimeMap/MimeMapPage.cs create mode 100644 JexusManager.Features.MimeMap/MimeMapPage.resx create mode 100644 JexusManager.Features.MimeMap/MimeMapSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.MimeMap/NewMapItemDialog.cs create mode 100644 JexusManager.Features.MimeMap/NewMapItemDialog.designer.cs create mode 100644 JexusManager.Features.MimeMap/NewMapItemDialog.resx create mode 100644 JexusManager.Features.MimeMap/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.MimeMap/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.MimeMap/Properties/Resources.resx create mode 100644 JexusManager.Features.MimeMap/Resources/mime_map_36.png create mode 100644 JexusManager.Features.MimeMap/packages.config create mode 100644 JexusManager.Features.Modules/GlobalModule.cs create mode 100644 JexusManager.Features.Modules/JexusManager.Features.Modules.csproj create mode 100644 JexusManager.Features.Modules/JexusManager.snk create mode 100644 JexusManager.Features.Modules/ModulesFeature.cs create mode 100644 JexusManager.Features.Modules/ModulesItem.cs create mode 100644 JexusManager.Features.Modules/ModulesModule.cs create mode 100644 JexusManager.Features.Modules/ModulesModuleProvider.cs create mode 100644 JexusManager.Features.Modules/ModulesPage.Designer.cs create mode 100644 JexusManager.Features.Modules/ModulesPage.cs create mode 100644 JexusManager.Features.Modules/ModulesPage.resx create mode 100644 JexusManager.Features.Modules/ModulesSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.Modules/NativeModulesDialog.Designer.cs create mode 100644 JexusManager.Features.Modules/NativeModulesDialog.cs create mode 100644 JexusManager.Features.Modules/NativeModulesDialog.resx create mode 100644 JexusManager.Features.Modules/NewModuleDialog.Designer.cs create mode 100644 JexusManager.Features.Modules/NewModuleDialog.cs create mode 100644 JexusManager.Features.Modules/NewModuleDialog.resx create mode 100644 JexusManager.Features.Modules/NewNativeDialog.Designer.cs create mode 100644 JexusManager.Features.Modules/NewNativeDialog.cs create mode 100644 JexusManager.Features.Modules/NewNativeDialog.resx create mode 100644 JexusManager.Features.Modules/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.Modules/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.Modules/Properties/Resources.resx create mode 100644 JexusManager.Features.Modules/Resources/modules_36.png create mode 100644 JexusManager.Features.Modules/packages.config create mode 100644 JexusManager.Features.RequestFiltering/AppliesToItem.cs create mode 100644 JexusManager.Features.RequestFiltering/DenyStringsItem.cs create mode 100644 JexusManager.Features.RequestFiltering/FileExtensionsFeature.cs create mode 100644 JexusManager.Features.RequestFiltering/FileExtensionsItem.cs create mode 100644 JexusManager.Features.RequestFiltering/FilteringRulesFeature.cs create mode 100644 JexusManager.Features.RequestFiltering/FilteringRulesItem.cs create mode 100644 JexusManager.Features.RequestFiltering/HeadersFeature.cs create mode 100644 JexusManager.Features.RequestFiltering/HeadersItem.cs create mode 100644 JexusManager.Features.RequestFiltering/HiddenSegmentsFeature.cs create mode 100644 JexusManager.Features.RequestFiltering/HiddenSegmentsItem.cs create mode 100644 JexusManager.Features.RequestFiltering/IRequestFilteringFeature.cs create mode 100644 JexusManager.Features.RequestFiltering/JexusManager.Features.RequestFiltering.csproj create mode 100644 JexusManager.Features.RequestFiltering/JexusManager.snk create mode 100644 JexusManager.Features.RequestFiltering/NewExtensionDialog.Designer.cs create mode 100644 JexusManager.Features.RequestFiltering/NewExtensionDialog.cs create mode 100644 JexusManager.Features.RequestFiltering/NewExtensionDialog.resx create mode 100644 JexusManager.Features.RequestFiltering/NewHeaderDialog.Designer.cs create mode 100644 JexusManager.Features.RequestFiltering/NewHeaderDialog.cs create mode 100644 JexusManager.Features.RequestFiltering/NewHeaderDialog.resx create mode 100644 JexusManager.Features.RequestFiltering/NewHiddenSegmentDialog.Designer.cs create mode 100644 JexusManager.Features.RequestFiltering/NewHiddenSegmentDialog.cs create mode 100644 JexusManager.Features.RequestFiltering/NewHiddenSegmentDialog.resx create mode 100644 JexusManager.Features.RequestFiltering/NewQueryDialog.Designer.cs create mode 100644 JexusManager.Features.RequestFiltering/NewQueryDialog.cs create mode 100644 JexusManager.Features.RequestFiltering/NewQueryDialog.resx create mode 100644 JexusManager.Features.RequestFiltering/NewRuleDialog.Designer.cs create mode 100644 JexusManager.Features.RequestFiltering/NewRuleDialog.cs create mode 100644 JexusManager.Features.RequestFiltering/NewRuleDialog.resx create mode 100644 JexusManager.Features.RequestFiltering/NewUrlDialog.Designer.cs create mode 100644 JexusManager.Features.RequestFiltering/NewUrlDialog.cs create mode 100644 JexusManager.Features.RequestFiltering/NewUrlDialog.resx create mode 100644 JexusManager.Features.RequestFiltering/NewVerbDialog.Designer.cs create mode 100644 JexusManager.Features.RequestFiltering/NewVerbDialog.cs create mode 100644 JexusManager.Features.RequestFiltering/NewVerbDialog.resx create mode 100644 JexusManager.Features.RequestFiltering/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.RequestFiltering/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.RequestFiltering/Properties/Resources.resx create mode 100644 JexusManager.Features.RequestFiltering/QueryStringsFeature.cs create mode 100644 JexusManager.Features.RequestFiltering/QueryStringsItem.cs create mode 100644 JexusManager.Features.RequestFiltering/RequestFilteringFeature.cs create mode 100644 JexusManager.Features.RequestFiltering/RequestFilteringModule.cs create mode 100644 JexusManager.Features.RequestFiltering/RequestFilteringModuleProvider.cs create mode 100644 JexusManager.Features.RequestFiltering/RequestFilteringPage.Designer.cs create mode 100644 JexusManager.Features.RequestFiltering/RequestFilteringPage.cs create mode 100644 JexusManager.Features.RequestFiltering/RequestFilteringPage.resx create mode 100644 JexusManager.Features.RequestFiltering/RequestFilteringSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.RequestFiltering/Resources/extensions_16.png create mode 100644 JexusManager.Features.RequestFiltering/Resources/headers_16.png create mode 100644 JexusManager.Features.RequestFiltering/Resources/hidden_16.png create mode 100644 JexusManager.Features.RequestFiltering/Resources/map_16.png create mode 100644 JexusManager.Features.RequestFiltering/Resources/query_16.png create mode 100644 JexusManager.Features.RequestFiltering/Resources/request_filtering_36.png create mode 100644 JexusManager.Features.RequestFiltering/Resources/url_16.png create mode 100644 JexusManager.Features.RequestFiltering/Resources/verbs_16.png create mode 100644 JexusManager.Features.RequestFiltering/ScanHeadersItem.cs create mode 100644 JexusManager.Features.RequestFiltering/SegmentSettingsDialog.Designer.cs create mode 100644 JexusManager.Features.RequestFiltering/SegmentSettingsDialog.cs create mode 100644 JexusManager.Features.RequestFiltering/SegmentSettingsDialog.resx create mode 100644 JexusManager.Features.RequestFiltering/UrlsFeature.cs create mode 100644 JexusManager.Features.RequestFiltering/UrlsItem.cs create mode 100644 JexusManager.Features.RequestFiltering/VerbsFeature.cs create mode 100644 JexusManager.Features.RequestFiltering/VerbsItem.cs create mode 100644 JexusManager.Features.RequestFiltering/packages.config create mode 100644 JexusManager.Features.ResponseHeaders/JexusManager.Features.ResponseHeaders.csproj create mode 100644 JexusManager.Features.ResponseHeaders/JexusManager.snk create mode 100644 JexusManager.Features.ResponseHeaders/NewHeaderDialog.Designer.cs create mode 100644 JexusManager.Features.ResponseHeaders/NewHeaderDialog.cs create mode 100644 JexusManager.Features.ResponseHeaders/NewHeaderDialog.resx create mode 100644 JexusManager.Features.ResponseHeaders/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.ResponseHeaders/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.ResponseHeaders/Properties/Resources.resx create mode 100644 JexusManager.Features.ResponseHeaders/Resources/response_header_36.png create mode 100644 JexusManager.Features.ResponseHeaders/ResponseHeadersFeature.cs create mode 100644 JexusManager.Features.ResponseHeaders/ResponseHeadersItem.cs create mode 100644 JexusManager.Features.ResponseHeaders/ResponseHeadersModule.cs create mode 100644 JexusManager.Features.ResponseHeaders/ResponseHeadersModuleProvider.cs create mode 100644 JexusManager.Features.ResponseHeaders/ResponseHeadersPage.Designer.cs create mode 100644 JexusManager.Features.ResponseHeaders/ResponseHeadersPage.cs create mode 100644 JexusManager.Features.ResponseHeaders/ResponseHeadersPage.resx create mode 100644 JexusManager.Features.ResponseHeaders/ResponseHeadersSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.ResponseHeaders/SetCommonHeadersDialog.Designer.cs create mode 100644 JexusManager.Features.ResponseHeaders/SetCommonHeadersDialog.cs create mode 100644 JexusManager.Features.ResponseHeaders/SetCommonHeadersDialog.resx create mode 100644 JexusManager.Features.ResponseHeaders/packages.config create mode 100644 JexusManager.Features.Rewrite/ConditionItem.cs create mode 100644 JexusManager.Features.Rewrite/ConditionListViewItem.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/AddAllowedVariableDialog.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/AddAllowedVariableDialog.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/AddAllowedVariableDialog.resx create mode 100644 JexusManager.Features.Rewrite/Inbound/AddConditionDialog.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/AddConditionDialog.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/AddConditionDialog.resx create mode 100644 JexusManager.Features.Rewrite/Inbound/AddMapDialog.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/AddMapDialog.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/AddMapDialog.resx create mode 100644 JexusManager.Features.Rewrite/Inbound/AddMapsDialog.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/AddMapsDialog.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/AddMapsDialog.resx create mode 100644 JexusManager.Features.Rewrite/Inbound/AddServerVariableDialog.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/AddServerVariableDialog.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/AddServerVariableDialog.resx create mode 100644 JexusManager.Features.Rewrite/Inbound/AllowedVariableItem.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/AllowedVariablesFeature.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/InboundFeature.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/InboundRule.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/InboundRulePage.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/InboundRulePage.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/InboundRulePage.resx create mode 100644 JexusManager.Features.Rewrite/Inbound/MapItem.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/MapPage.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/MapPage.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/MapPage.resx create mode 100644 JexusManager.Features.Rewrite/Inbound/MapRule.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/MapSettingsDialog.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/MapSettingsDialog.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/MapSettingsDialog.resx create mode 100644 JexusManager.Features.Rewrite/Inbound/MapSettingsUpdatedEventHandler.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/MapsFeature.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/MapsPage.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/MapsPage.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/MapsPage.resx create mode 100644 JexusManager.Features.Rewrite/Inbound/ServerVariableItem.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/ServerVariablesPage.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/ServerVariablesPage.cs create mode 100644 JexusManager.Features.Rewrite/Inbound/ServerVariablesPage.resx create mode 100644 JexusManager.Features.Rewrite/JexusManager.Features.Rewrite.csproj create mode 100644 JexusManager.Features.Rewrite/JexusManager.snk create mode 100644 JexusManager.Features.Rewrite/NewRewriteRuleDialog.Designer.cs create mode 100644 JexusManager.Features.Rewrite/NewRewriteRuleDialog.cs create mode 100644 JexusManager.Features.Rewrite/NewRewriteRuleDialog.resx create mode 100644 JexusManager.Features.Rewrite/NewRuleBlockingDialog.Designer.cs create mode 100644 JexusManager.Features.Rewrite/NewRuleBlockingDialog.cs create mode 100644 JexusManager.Features.Rewrite/NewRuleBlockingDialog.resx create mode 100644 JexusManager.Features.Rewrite/NewRuleWithRewriteMapsDialog.Designer.cs create mode 100644 JexusManager.Features.Rewrite/NewRuleWithRewriteMapsDialog.cs create mode 100644 JexusManager.Features.Rewrite/NewRuleWithRewriteMapsDialog.resx create mode 100644 JexusManager.Features.Rewrite/Outbound/AddCustomTagDialog.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/AddCustomTagDialog.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/AddCustomTagDialog.resx create mode 100644 JexusManager.Features.Rewrite/Outbound/AddCustomTagsDialog.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/AddCustomTagsDialog.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/AddCustomTagsDialog.resx create mode 100644 JexusManager.Features.Rewrite/Outbound/AddPreconditionDialog.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/AddPreconditionDialog.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/AddPreconditionDialog.resx create mode 100644 JexusManager.Features.Rewrite/Outbound/CustomTagItem.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/CustomTagsFeature.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/CustomTagsItem.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/CustomTagsPage.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/CustomTagsPage.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/CustomTagsPage.resx create mode 100644 JexusManager.Features.Rewrite/Outbound/OutboundFeature.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/OutboundRule.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/OutboundRulePage.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/OutboundRulePage.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/OutboundRulePage.resx create mode 100644 JexusManager.Features.Rewrite/Outbound/PreConditionItem.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/PreConditionsFeature.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/PreConditionsPage.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/PreConditionsPage.cs create mode 100644 JexusManager.Features.Rewrite/Outbound/PreConditionsPage.resx create mode 100644 JexusManager.Features.Rewrite/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Features.Rewrite/Properties/Resources.Designer.cs create mode 100644 JexusManager.Features.Rewrite/Properties/Resources.resx create mode 100644 JexusManager.Features.Rewrite/RegexTestDialog.Designer.cs create mode 100644 JexusManager.Features.Rewrite/RegexTestDialog.cs create mode 100644 JexusManager.Features.Rewrite/RegexTestDialog.resx create mode 100644 JexusManager.Features.Rewrite/Resources/blank_16.png create mode 100644 JexusManager.Features.Rewrite/Resources/blank_32.png create mode 100644 JexusManager.Features.Rewrite/Resources/blankout_16.png create mode 100644 JexusManager.Features.Rewrite/Resources/blankout_32.png create mode 100644 JexusManager.Features.Rewrite/Resources/blocking_16.png create mode 100644 JexusManager.Features.Rewrite/Resources/blocking_32.png create mode 100644 JexusManager.Features.Rewrite/Resources/error_16.png create mode 100644 JexusManager.Features.Rewrite/Resources/info_16.png create mode 100644 JexusManager.Features.Rewrite/Resources/lowercase_16.png create mode 100644 JexusManager.Features.Rewrite/Resources/lowercase_32.png create mode 100644 JexusManager.Features.Rewrite/Resources/map_16.png create mode 100644 JexusManager.Features.Rewrite/Resources/map_32.png create mode 100644 JexusManager.Features.Rewrite/Resources/tick_16.png create mode 100644 JexusManager.Features.Rewrite/Resources/url_rewrite_36.png create mode 100644 JexusManager.Features.Rewrite/RewriteFeature.cs create mode 100644 JexusManager.Features.Rewrite/RewriteModule.cs create mode 100644 JexusManager.Features.Rewrite/RewriteModuleProvider.cs create mode 100644 JexusManager.Features.Rewrite/RewritePage.Designer.cs create mode 100644 JexusManager.Features.Rewrite/RewritePage.cs create mode 100644 JexusManager.Features.Rewrite/RewritePage.resx create mode 100644 JexusManager.Features.Rewrite/RewriteSettingsSavedEventHandler.cs create mode 100644 JexusManager.Features.Rewrite/RuleSettingsUpdatedEventHandler.cs create mode 100644 JexusManager.Features.Rewrite/packages.config create mode 100644 JexusManager.Shared/ApplicationExtensions.cs create mode 100644 JexusManager.Shared/ConfigurationElementExtensions.cs create mode 100644 JexusManager.Shared/ConfigurationSectionExtensions.cs create mode 100644 JexusManager.Shared/DefaultWizardForm.cs create mode 100644 JexusManager.Shared/DefaultWizardPage.cs create mode 100644 JexusManager.Shared/DescriptionConverter.cs create mode 100644 JexusManager.Shared/DialogHelper.cs create mode 100644 JexusManager.Shared/Features/DefaultTaskList.cs create mode 100644 JexusManager.Shared/Features/FeatureBase.cs create mode 100644 JexusManager.Shared/Features/IDuoItem.cs create mode 100644 JexusManager.Shared/Features/IItem.cs create mode 100644 JexusManager.Shared/Features/ScopeExtensions.cs create mode 100644 JexusManager.Shared/Features/ShowHelpTaskList.cs create mode 100644 JexusManager.Shared/Features/TaskItemExtensions.cs create mode 100644 JexusManager.Shared/Features/TimeSpanExtensions.cs create mode 100644 JexusManager.Shared/JexusManager.Shared.csproj create mode 100644 JexusManager.Shared/JexusManager.snk create mode 100644 JexusManager.Shared/NativeMethods.cs create mode 100644 JexusManager.Shared/PhysicalDirectory.cs create mode 100644 JexusManager.Shared/Properties/AssemblyInfo.cs create mode 100644 JexusManager.Shared/Properties/Resources.Designer.cs create mode 100644 JexusManager.Shared/Properties/Resources.resx create mode 100644 JexusManager.Shared/Resources/application_32.png create mode 100644 JexusManager.Shared/Resources/back_16.png create mode 100644 JexusManager.Shared/Resources/basic_settings_16.png create mode 100644 JexusManager.Shared/Resources/go_16.png create mode 100644 JexusManager.Shared/Resources/help_16.png create mode 100644 JexusManager.Shared/Resources/move_down_16.png create mode 100644 JexusManager.Shared/Resources/move_up_16.png create mode 100644 JexusManager.Shared/Resources/remove_16.png create mode 100644 JexusManager.Shared/Resources/show_all_16.png create mode 100644 JexusManager.Shared/Resources/site_32.png create mode 100644 JexusManager.Shared/Resources/title_32.png create mode 100644 JexusManager.Shared/Resources/transparent_16.png create mode 100644 JexusManager.Shared/Resources/view_16.png create mode 100644 JexusManager.Shared/ServerManagerExtensions.cs create mode 100644 JexusManager.Shared/Services/ConfigurationService.cs create mode 100644 JexusManager.Shared/Services/ControlPanel.cs create mode 100644 JexusManager.Shared/Services/IConfigurationService.cs create mode 100644 JexusManager.Shared/Services/ManagementUIService.cs create mode 100644 JexusManager.Shared/app.config create mode 100644 JexusManager.Shared/packages.config create mode 100644 JexusManager.sln create mode 100644 JexusManager/App.config create mode 100644 JexusManager/Dialogs/CertificateErrorsDialog.Designer.cs create mode 100644 JexusManager/Dialogs/CertificateErrorsDialog.cs create mode 100644 JexusManager/Dialogs/CertificateErrorsDialog.resx create mode 100644 JexusManager/Dialogs/EditSiteDialog.Designer.cs create mode 100644 JexusManager/Dialogs/EditSiteDialog.cs create mode 100644 JexusManager/Dialogs/EditSiteDialog.resx create mode 100644 JexusManager/Dialogs/NewApplicationDialog.Designer.cs create mode 100644 JexusManager/Dialogs/NewApplicationDialog.cs create mode 100644 JexusManager/Dialogs/NewApplicationDialog.resx create mode 100644 JexusManager/Dialogs/NewFarmServerDialog.Designer.cs create mode 100644 JexusManager/Dialogs/NewFarmServerDialog.cs create mode 100644 JexusManager/Dialogs/NewFarmServerDialog.resx create mode 100644 JexusManager/Dialogs/NewSiteDialog.Designer.cs create mode 100644 JexusManager/Dialogs/NewSiteDialog.cs create mode 100644 JexusManager/Dialogs/NewSiteDialog.resx create mode 100644 JexusManager/Dialogs/NewVirtualDirectoryDialog.Designer.cs create mode 100644 JexusManager/Dialogs/NewVirtualDirectoryDialog.cs create mode 100644 JexusManager/Dialogs/NewVirtualDirectoryDialog.resx create mode 100644 JexusManager/Dialogs/SelectPoolDialog.Designer.cs create mode 100644 JexusManager/Dialogs/SelectPoolDialog.cs create mode 100644 JexusManager/Dialogs/SelectPoolDialog.resx create mode 100644 JexusManager/Dialogs/UpdateDialog.Designer.cs create mode 100644 JexusManager/Dialogs/UpdateDialog.cs create mode 100644 JexusManager/Dialogs/UpdateDialog.resx create mode 100644 JexusManager/FarmPanel.Designer.cs create mode 100644 JexusManager/FarmPanel.cs create mode 100644 JexusManager/FarmPanel.resx create mode 100644 JexusManager/FarmServerAdvancedSettings.cs create mode 100644 JexusManager/FarmWizard.Designer.cs create mode 100644 JexusManager/FarmWizard.cs create mode 100644 JexusManager/FarmWizard.resx create mode 100644 JexusManager/Features/Main/ApplicationFeature.cs create mode 100644 JexusManager/Features/Main/ApplicationPage.Designer.cs create mode 100644 JexusManager/Features/Main/ApplicationPage.cs create mode 100644 JexusManager/Features/Main/ApplicationPage.resx create mode 100644 JexusManager/Features/Main/ApplicationPoolAdvancedSettings.cs create mode 100644 JexusManager/Features/Main/ApplicationPoolAdvancedSettingsDialog.Designer.cs create mode 100644 JexusManager/Features/Main/ApplicationPoolAdvancedSettingsDialog.cs create mode 100644 JexusManager/Features/Main/ApplicationPoolAdvancedSettingsDialog.resx create mode 100644 JexusManager/Features/Main/ApplicationPoolBasicSettingsDialog.Designer.cs create mode 100644 JexusManager/Features/Main/ApplicationPoolBasicSettingsDialog.cs create mode 100644 JexusManager/Features/Main/ApplicationPoolBasicSettingsDialog.resx create mode 100644 JexusManager/Features/Main/ApplicationPoolDefaultsSettings.cs create mode 100644 JexusManager/Features/Main/ApplicationPoolDefaultsSettingsDialog.Designer.cs create mode 100644 JexusManager/Features/Main/ApplicationPoolDefaultsSettingsDialog.cs create mode 100644 JexusManager/Features/Main/ApplicationPoolDefaultsSettingsDialog.resx create mode 100644 JexusManager/Features/Main/ApplicationPoolsFeature.cs create mode 100644 JexusManager/Features/Main/ApplicationPoolsPage.Designer.cs create mode 100644 JexusManager/Features/Main/ApplicationPoolsPage.cs create mode 100644 JexusManager/Features/Main/ApplicationPoolsPage.resx create mode 100644 JexusManager/Features/Main/ApplicationPoolsSettingsSavedEventHandler.cs create mode 100644 JexusManager/Features/Main/BindingDialog.Designer.cs create mode 100644 JexusManager/Features/Main/BindingDialog.cs create mode 100644 JexusManager/Features/Main/BindingDialog.resx create mode 100644 JexusManager/Features/Main/BindingsDialog.Designer.cs create mode 100644 JexusManager/Features/Main/BindingsDialog.cs create mode 100644 JexusManager/Features/Main/BindingsDialog.resx create mode 100644 JexusManager/Features/Main/CLRVersion.cs create mode 100644 JexusManager/Features/Main/CredentialsDialog.Designer.cs create mode 100644 JexusManager/Features/Main/CredentialsDialog.cs create mode 100644 JexusManager/Features/Main/CredentialsDialog.resx create mode 100644 JexusManager/Features/Main/HomePage.Designer.cs create mode 100644 JexusManager/Features/Main/HomePage.cs create mode 100644 JexusManager/Features/Main/HomePage.resx create mode 100644 JexusManager/Features/Main/IdentityDialog.Designer.cs create mode 100644 JexusManager/Features/Main/IdentityDialog.cs create mode 100644 JexusManager/Features/Main/IdentityDialog.resx create mode 100644 JexusManager/Features/Main/IdentityEditor.cs create mode 100644 JexusManager/Features/Main/MainModule.cs create mode 100644 JexusManager/Features/Main/ModulePageInfoListViewItem.cs create mode 100644 JexusManager/Features/Main/PhysicalDirectoryFeature.cs create mode 100644 JexusManager/Features/Main/PhysicalDirectoryPage.Designer.cs create mode 100644 JexusManager/Features/Main/PhysicalDirectoryPage.cs create mode 100644 JexusManager/Features/Main/PhysicalDirectoryPage.resx create mode 100644 JexusManager/Features/Main/ServerFeature.cs create mode 100644 JexusManager/Features/Main/ServerPage.Designer.cs create mode 100644 JexusManager/Features/Main/ServerPage.cs create mode 100644 JexusManager/Features/Main/ServerPage.resx create mode 100644 JexusManager/Features/Main/ServerSettingsSavedEventHandler.cs create mode 100644 JexusManager/Features/Main/SiteFeature.cs create mode 100644 JexusManager/Features/Main/SitePage.Designer.cs create mode 100644 JexusManager/Features/Main/SitePage.cs create mode 100644 JexusManager/Features/Main/SitePage.resx create mode 100644 JexusManager/Features/Main/SitesFeature.cs create mode 100644 JexusManager/Features/Main/SitesPage.Designer.cs create mode 100644 JexusManager/Features/Main/SitesPage.cs create mode 100644 JexusManager/Features/Main/SitesPage.resx create mode 100644 JexusManager/Features/Main/SslDiagDialog.Designer.cs create mode 100644 JexusManager/Features/Main/SslDiagDialog.cs create mode 100644 JexusManager/Features/Main/SslDiagDialog.resx create mode 100644 JexusManager/Features/Main/VirtualDirectoryFeature.cs create mode 100644 JexusManager/Features/Main/VirtualDirectoryPage.Designer.cs create mode 100644 JexusManager/Features/Main/VirtualDirectoryPage.cs create mode 100644 JexusManager/Features/Main/VirtualDirectoryPage.resx create mode 100644 JexusManager/JexusManager.csproj create mode 100644 JexusManager/JexusManager.snk create mode 100644 JexusManager/MainForm.Designer.cs create mode 100644 JexusManager/MainForm.cs create mode 100644 JexusManager/MainForm.resx create mode 100644 JexusManager/Program.cs create mode 100644 JexusManager/Properties/AssemblyInfo.cs create mode 100644 JexusManager/Properties/Resources.Designer.cs create mode 100644 JexusManager/Properties/Resources.resx create mode 100644 JexusManager/Properties/Settings.Designer.cs create mode 100644 JexusManager/Properties/Settings.settings create mode 100644 JexusManager/Resources/application_16.png create mode 100644 JexusManager/Resources/application_new_16.png create mode 100644 JexusManager/Resources/application_pool_new_16.png create mode 100644 JexusManager/Resources/application_pools_16.png create mode 100644 JexusManager/Resources/application_pools_stopped_16.png create mode 100644 JexusManager/Resources/back_16.png create mode 100644 JexusManager/Resources/basic_settings_16.png create mode 100644 JexusManager/Resources/browse_16.png create mode 100644 JexusManager/Resources/certificates_16.png create mode 100644 JexusManager/Resources/connect_16.png create mode 100644 JexusManager/Resources/disconnected_16.png create mode 100644 JexusManager/Resources/explore_16.png create mode 100644 JexusManager/Resources/farm_16.png create mode 100644 JexusManager/Resources/farm_server_16.png create mode 100644 JexusManager/Resources/help_16.png create mode 100644 JexusManager/Resources/iis_16.png create mode 100644 JexusManager/Resources/info_16.png create mode 100644 JexusManager/Resources/physical_directory_16.png create mode 100644 JexusManager/Resources/refresh_16.png create mode 100644 JexusManager/Resources/restart_16.png create mode 100644 JexusManager/Resources/save_16.png create mode 100644 JexusManager/Resources/server_16.png create mode 100644 JexusManager/Resources/servers_16.png create mode 100644 JexusManager/Resources/site_16.png create mode 100644 JexusManager/Resources/site_new_16.png create mode 100644 JexusManager/Resources/site_stopped_16.png create mode 100644 JexusManager/Resources/sites_16.png create mode 100644 JexusManager/Resources/start_16.png create mode 100644 JexusManager/Resources/stop_16.png create mode 100644 JexusManager/Resources/switch_16.png create mode 100644 JexusManager/Resources/title_48.png create mode 100644 JexusManager/Resources/up_16.png create mode 100644 JexusManager/Resources/update_16.png create mode 100644 JexusManager/Resources/virtual_directory_16.png create mode 100644 JexusManager/Resources/virtual_directory_new_16.png create mode 100644 JexusManager/Resources/warning_32.png create mode 100644 JexusManager/Services/NavigationService.cs create mode 100644 JexusManager/StringFormatter.cs create mode 100644 JexusManager/Tree/ApplicationPoolsTreeNode.cs create mode 100644 JexusManager/Tree/ApplicationTreeNode.cs create mode 100644 JexusManager/Tree/HomePageTreeNode.cs create mode 100644 JexusManager/Tree/ManagerTreeNode.cs create mode 100644 JexusManager/Tree/PhysicalDirectoryTreeNode.cs create mode 100644 JexusManager/Tree/ServerTreeNode.cs create mode 100644 JexusManager/Tree/SiteTreeNode.cs create mode 100644 JexusManager/Tree/SitesTreeNode.cs create mode 100644 JexusManager/Tree/VirtualDirectoryTreeNode.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/AddressPage.Designer.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/AddressPage.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/AddressPage.resx create mode 100644 JexusManager/Wizards/ConnectionWizard/BrowsePage.Designer.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/BrowsePage.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/BrowsePage.resx create mode 100644 JexusManager/Wizards/ConnectionWizard/ConnectionWizard.Designer.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/ConnectionWizard.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/ConnectionWizard.resx create mode 100644 JexusManager/Wizards/ConnectionWizard/ConnectionWizardData.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/CredentialsPage.Designer.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/CredentialsPage.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/CredentialsPage.resx create mode 100644 JexusManager/Wizards/ConnectionWizard/FarmNamePage.Designer.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/FarmNamePage.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/FarmNamePage.resx create mode 100644 JexusManager/Wizards/ConnectionWizard/FinishPage.Designer.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/FinishPage.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/FinishPage.resx create mode 100644 JexusManager/Wizards/ConnectionWizard/ServerPage.Designer.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/ServerPage.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/ServerPage.resx create mode 100644 JexusManager/Wizards/ConnectionWizard/TypePage.Designer.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/TypePage.cs create mode 100644 JexusManager/Wizards/ConnectionWizard/TypePage.resx create mode 100644 JexusManager/app.manifest create mode 100644 JexusManager/iis.ico create mode 100644 JexusManager/jexus.xml create mode 100644 JexusManager/packages.config create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/AppHostFileProvider.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IAppHostProvider.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IAppHostProviderChangeHandler.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IAppHostSite.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IApplication.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IApplicationPool.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/ICpu.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/ICustomField.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/ICustomFields.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IEnumApplicationPool.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IEnumApplications.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IEnumBindings.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IEnumCustomFields.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IEnumEnvironmentVariables.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IEnumListenerAdapter.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IEnumLocation.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IEnumSchedule.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IEnumSite.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IEnumVirtualDirectory.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IEnvironmentVariable.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IFailure.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IListenerAdapter.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/ILocation.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/ILogSettings.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IPeriodicRestart.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IProcessModel.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IRecycling.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/ISchedule.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/ISiteBinding.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/ISiteLimits.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/ISiteLogFile.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/ISiteTraceRequestsLogging.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IVirtualDirectory.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/IWebLimits.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/JexusManager.snk create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/LoadOptions.cs create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/Microsoft.Web.Configuration.AppHostFileProvider.csproj create mode 100644 Microsoft.Web.Configuration.AppHostFileProvider/Properties/AssemblyInfo.cs create mode 100644 Microsoft.Web.Management/Client/AssemblyDownloadInfo.cs create mode 100644 Microsoft.Web.Management/Client/Connection.cs create mode 100644 Microsoft.Web.Management/Client/ConnectionActiveState.cs create mode 100644 Microsoft.Web.Management/Client/ConnectionCredential.cs create mode 100644 Microsoft.Web.Management/Client/ConnectionEventArgs.cs create mode 100644 Microsoft.Web.Management/Client/ConnectionEventHandler.cs create mode 100644 Microsoft.Web.Management/Client/ConnectionInfo.cs create mode 100644 Microsoft.Web.Management/Client/ConnectionInfoCollection.cs create mode 100644 Microsoft.Web.Management/Client/ControlPanelCategorization.cs create mode 100644 Microsoft.Web.Management/Client/ControlPanelCategoryInfo.cs create mode 100644 Microsoft.Web.Management/Client/CredentialInfo.cs create mode 100644 Microsoft.Web.Management/Client/CredentialInfoEventArgs.cs create mode 100644 Microsoft.Web.Management/Client/Extensions/AuthenticationFeature.cs create mode 100644 Microsoft.Web.Management/Client/Extensions/AuthenticationSettingsSavedEventHandler.cs create mode 100644 Microsoft.Web.Management/Client/Extensions/AuthenticationType.cs create mode 100644 Microsoft.Web.Management/Client/Extensions/HomepageExtension.cs create mode 100644 Microsoft.Web.Management/Client/Extensions/IHomepageTaskListProvider.cs create mode 100644 Microsoft.Web.Management/Client/Extensions/ProtocolProvider.cs create mode 100644 Microsoft.Web.Management/Client/Extensions/ProviderFeature.cs create mode 100644 Microsoft.Web.Management/Client/Extensions/SiteAction.cs create mode 100644 Microsoft.Web.Management/Client/Extensions/SiteUpdatedEventArgs.cs create mode 100644 Microsoft.Web.Management/Client/GroupTaskItem.cs create mode 100644 Microsoft.Web.Management/Client/HierarchyCollectionEventArgs.cs create mode 100644 Microsoft.Web.Management/Client/HierarchyCollectionEventHandler.cs create mode 100644 Microsoft.Web.Management/Client/HierarchyInfo.cs create mode 100644 Microsoft.Web.Management/Client/HierarchyInfoEventArgs.cs create mode 100644 Microsoft.Web.Management/Client/HierarchyInfoEventHandler.cs create mode 100644 Microsoft.Web.Management/Client/HierarchyInfoSyncSelectionEventArgs.cs create mode 100644 Microsoft.Web.Management/Client/HierarchyPriority.cs create mode 100644 Microsoft.Web.Management/Client/HierarchyProvider.cs create mode 100644 Microsoft.Web.Management/Client/HierarchyRenameEventArgs.cs create mode 100644 Microsoft.Web.Management/Client/HierarchyService.cs create mode 100644 Microsoft.Web.Management/Client/HierarchyVisibility.cs create mode 100644 Microsoft.Web.Management/Client/ICertificateVerificationBuilder.cs create mode 100644 Microsoft.Web.Management/Client/IConnectionBuilder.cs create mode 100644 Microsoft.Web.Management/Client/IConnectionManager.cs create mode 100644 Microsoft.Web.Management/Client/IControlPanel.cs create mode 100644 Microsoft.Web.Management/Client/ICredentialBuilder.cs create mode 100644 Microsoft.Web.Management/Client/IExtensibilityManager.cs create mode 100644 Microsoft.Web.Management/Client/IModuleChildPage.cs create mode 100644 Microsoft.Web.Management/Client/IModulePage.cs create mode 100644 Microsoft.Web.Management/Client/INavigationService.cs create mode 100644 Microsoft.Web.Management/Client/IPreferencesService.cs create mode 100644 Microsoft.Web.Management/Client/IPropertyEditingService.cs create mode 100644 Microsoft.Web.Management/Client/IPropertyEditingUser.cs create mode 100644 Microsoft.Web.Management/Client/IProviderConfigurationService.cs create mode 100644 Microsoft.Web.Management/Client/ManagementChannel.cs create mode 100644 Microsoft.Web.Management/Client/ManagementScopePath.cs create mode 100644 Microsoft.Web.Management/Client/MessageTaskItem.cs create mode 100644 Microsoft.Web.Management/Client/MessageTaskItemType.cs create mode 100644 Microsoft.Web.Management/Client/MethodTaskItemUsages.cs create mode 100644 Microsoft.Web.Management/Client/Module.cs create mode 100644 Microsoft.Web.Management/Client/ModuleHomepageAttribute.cs create mode 100644 Microsoft.Web.Management/Client/ModuleListPageFilter.cs create mode 100644 Microsoft.Web.Management/Client/ModuleListPageGrouping.cs create mode 100644 Microsoft.Web.Management/Client/ModuleListPageSearchField.cs create mode 100644 Microsoft.Web.Management/Client/ModuleListPageSearchOptions.cs create mode 100644 Microsoft.Web.Management/Client/ModuleListPageViewModes.cs create mode 100644 Microsoft.Web.Management/Client/ModulePageIdentifierAttribute.cs create mode 100644 Microsoft.Web.Management/Client/ModulePageInfo.cs create mode 100644 Microsoft.Web.Management/Client/ModuleServiceProxy.cs create mode 100644 Microsoft.Web.Management/Client/NavigationEventArgs.cs create mode 100644 Microsoft.Web.Management/Client/NavigationEventHandler.cs create mode 100644 Microsoft.Web.Management/Client/NavigationItem.cs create mode 100644 Microsoft.Web.Management/Client/PreferencesStore.cs create mode 100644 Microsoft.Web.Management/Client/PropertyGridObject.cs create mode 100644 Microsoft.Web.Management/Client/ProviderConfigurationSettings.cs create mode 100644 Microsoft.Web.Management/Client/TaskItem.cs create mode 100644 Microsoft.Web.Management/Client/TaskList.cs create mode 100644 Microsoft.Web.Management/Client/TaskListCollection.cs create mode 100644 Microsoft.Web.Management/Client/Win32/BaseForm.cs create mode 100644 Microsoft.Web.Management/Client/Win32/BaseTaskForm.cs create mode 100644 Microsoft.Web.Management/Client/Win32/DialogForm.cs create mode 100644 Microsoft.Web.Management/Client/Win32/IManagementUIService.cs create mode 100644 Microsoft.Web.Management/Client/Win32/ListPageListView.cs create mode 100644 Microsoft.Web.Management/Client/Win32/ManagementGroupBox.cs create mode 100644 Microsoft.Web.Management/Client/Win32/ManagementPanel.cs create mode 100644 Microsoft.Web.Management/Client/Win32/ManagementTabPage.cs create mode 100644 Microsoft.Web.Management/Client/Win32/ManagementUIColorTable.cs create mode 100644 Microsoft.Web.Management/Client/Win32/MethodTaskItem.cs create mode 100644 Microsoft.Web.Management/Client/Win32/ModuleDialogPage.cs create mode 100644 Microsoft.Web.Management/Client/Win32/ModuleDialogPage.resx create mode 100644 Microsoft.Web.Management/Client/Win32/ModuleListPage.cs create mode 100644 Microsoft.Web.Management/Client/Win32/ModulePage.cs create mode 100644 Microsoft.Web.Management/Client/Win32/ModulePropertiesPage.cs create mode 100644 Microsoft.Web.Management/Client/Win32/ModulePropertiesPage.resx create mode 100644 Microsoft.Web.Management/Client/Win32/SortableListView.cs create mode 100644 Microsoft.Web.Management/Client/Win32/TaskForm.cs create mode 100644 Microsoft.Web.Management/Client/Win32/TextTaskItem.cs create mode 100644 Microsoft.Web.Management/Client/Win32/WaitCursor.cs create mode 100644 Microsoft.Web.Management/Client/Win32/WizardForm.cs create mode 100644 Microsoft.Web.Management/Client/Win32/WizardForm.resx create mode 100644 Microsoft.Web.Management/Client/Win32/WizardPage.cs create mode 100644 Microsoft.Web.Management/Client/Win32/WizardPage.resx create mode 100644 Microsoft.Web.Management/Features/Administrators/AdministratorsModuleProvider.cs create mode 100644 Microsoft.Web.Management/Features/Delegation/DelegationModuleProvider.cs create mode 100644 Microsoft.Web.Management/Features/Services/ServiceModuleProvider.cs create mode 100644 Microsoft.Web.Management/Host/ConnectionManager.cs create mode 100644 Microsoft.Web.Management/Host/IManagementHost.cs create mode 100644 Microsoft.Web.Management/Host/Shell/ShellApplication.cs create mode 100644 Microsoft.Web.Management/Host/Shell/ShellComponents.cs create mode 100644 Microsoft.Web.Management/JexusManager.snk create mode 100644 Microsoft.Web.Management/Microsoft.Web.Management.csproj create mode 100644 Microsoft.Web.Management/Properties/AssemblyInfo.cs create mode 100644 Microsoft.Web.Management/Properties/Resources.Designer.cs create mode 100644 Microsoft.Web.Management/Properties/Resources.resx create mode 100644 Microsoft.Web.Management/Resources/apply_16.png create mode 100644 Microsoft.Web.Management/Resources/cancel_16.png create mode 100644 Microsoft.Web.Management/Server/AdministrationModule.cs create mode 100644 Microsoft.Web.Management/Server/AdministrationModuleCollection.cs create mode 100644 Microsoft.Web.Management/Server/AdministrationModuleProvider.cs create mode 100644 Microsoft.Web.Management/Server/ApplicationManagementUnit.cs create mode 100644 Microsoft.Web.Management/Server/BindingInfo.cs create mode 100644 Microsoft.Web.Management/Server/ConfigurationAuthenticationModuleService.cs create mode 100644 Microsoft.Web.Management/Server/ConfigurationModuleProvider.cs create mode 100644 Microsoft.Web.Management/Server/ConfigurationPathType.cs create mode 100644 Microsoft.Web.Management/Server/DelegationState.cs create mode 100644 Microsoft.Web.Management/Server/IAuthenticationModuleService.cs create mode 100644 Microsoft.Web.Management/Server/IGlobalConfigurationProvider.cs create mode 100644 Microsoft.Web.Management/Server/IManagementContext.cs create mode 100644 Microsoft.Web.Management/Server/ISiteStatusProvider.cs create mode 100644 Microsoft.Web.Management/Server/InvalidPasswordReason.cs create mode 100644 Microsoft.Web.Management/Server/ManagementAdministrationConfiguration.cs create mode 100644 Microsoft.Web.Management/Server/ManagementAuthentication.cs create mode 100644 Microsoft.Web.Management/Server/ManagementAuthenticationProvider.cs create mode 100644 Microsoft.Web.Management/Server/ManagementAuthorization.cs create mode 100644 Microsoft.Web.Management/Server/ManagementAuthorizationInfo.cs create mode 100644 Microsoft.Web.Management/Server/ManagementAuthorizationInfoCollection.cs create mode 100644 Microsoft.Web.Management/Server/ManagementAuthorizationProvider.cs create mode 100644 Microsoft.Web.Management/Server/ManagementConfiguration.cs create mode 100644 Microsoft.Web.Management/Server/ManagementConfigurationPath.cs create mode 100644 Microsoft.Web.Management/Server/ManagementContentNavigator.cs create mode 100644 Microsoft.Web.Management/Server/ManagementFrameworkVersion.cs create mode 100644 Microsoft.Web.Management/Server/ManagementScope.cs create mode 100644 Microsoft.Web.Management/Server/ManagementUnit.cs create mode 100644 Microsoft.Web.Management/Server/ManagementUserInfo.cs create mode 100644 Microsoft.Web.Management/Server/ManagementUserInfoCollection.cs create mode 100644 Microsoft.Web.Management/Server/ModuleDefinition.cs create mode 100644 Microsoft.Web.Management/Server/ModuleInfo.cs create mode 100644 Microsoft.Web.Management/Server/ModuleProvider.cs create mode 100644 Microsoft.Web.Management/Server/ModuleService.cs create mode 100644 Microsoft.Web.Management/Server/ModuleServiceMethodAttribute.cs create mode 100644 Microsoft.Web.Management/Server/PropertyBag.cs create mode 100644 Microsoft.Web.Management/Server/ServerManagementUnit.cs create mode 100644 Microsoft.Web.Management/Server/SimpleDelegatedModuleProvider.cs create mode 100644 Microsoft.Web.Management/Server/SiteInfo.cs create mode 100644 Microsoft.Web.Management/Server/SiteManagementUnit.cs create mode 100644 Microsoft.Web.Management/Server/TypeInformationGenerator.cs create mode 100644 Microsoft.Web.Management/Server/WebManagementEventLog.cs create mode 100644 Microsoft.Web.Management/Server/WebManagementServiceException.cs create mode 100644 Microsoft.Web.Management/Server/WebManagementServiceHandler.cs create mode 100644 Microsoft.Web.Management/Utility/ServiceUtility.cs create mode 100644 Microsoft.Web.Management/app.config create mode 100644 Readme.txt create mode 100644 Tests.IIS/Helper.cs create mode 100644 Tests.IIS/JexusManager.snk create mode 100644 Tests.IIS/Properties/AssemblyInfo.cs create mode 100644 Tests.IIS/ServerManagerTestFixture.cs create mode 100644 Tests.IIS/Tests.IIS.csproj create mode 100644 Tests.IIS/default.runsettings create mode 100644 Tests.IIS/packages.config create mode 100644 Tests.JexusManager/Authorization/AuthorizationFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/Authorization/AuthorizationFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/Authorization/expected_add.config create mode 100644 Tests.JexusManager/Authorization/expected_add.site.config create mode 100644 Tests.JexusManager/Authorization/expected_edit.config create mode 100644 Tests.JexusManager/Authorization/expected_edit.site.config create mode 100644 Tests.JexusManager/Authorization/expected_edit1.site.config create mode 100644 Tests.JexusManager/Authorization/expected_remove.config create mode 100644 Tests.JexusManager/Authorization/expected_remove.site.config create mode 100644 Tests.JexusManager/Authorization/expected_remove1.site.config create mode 100644 Tests.JexusManager/Caching/CachingFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/Caching/CachingFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/Caching/expected_add.config create mode 100644 Tests.JexusManager/Caching/expected_add.site.config create mode 100644 Tests.JexusManager/Caching/expected_edit.config create mode 100644 Tests.JexusManager/Caching/expected_edit.site.config create mode 100644 Tests.JexusManager/Caching/expected_edit1.site.config create mode 100644 Tests.JexusManager/Caching/expected_remove.config create mode 100644 Tests.JexusManager/Caching/expected_remove.site.config create mode 100644 Tests.JexusManager/Caching/expected_remove1.site.config create mode 100644 Tests.JexusManager/DefaultDocument/DefaultDocumentFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/DefaultDocument/DefaultDocumentFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/DefaultDocument/expected_add.config create mode 100644 Tests.JexusManager/DefaultDocument/expected_add.site.config create mode 100644 Tests.JexusManager/DefaultDocument/expected_disabled.config create mode 100644 Tests.JexusManager/DefaultDocument/expected_disabled.site.config create mode 100644 Tests.JexusManager/DefaultDocument/expected_remove.config create mode 100644 Tests.JexusManager/DefaultDocument/expected_remove.site.config create mode 100644 Tests.JexusManager/DefaultDocument/expected_remove1.site.config create mode 100644 Tests.JexusManager/DefaultDocument/expected_revert.site.config create mode 100644 Tests.JexusManager/DefaultDocument/expected_up.config create mode 100644 Tests.JexusManager/DefaultDocument/expected_up.site.config create mode 100644 Tests.JexusManager/DefaultDocument/expected_up1.site.config create mode 100644 Tests.JexusManager/DirectoryBrowse/DirectoryBrowseFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/DirectoryBrowse/DirectoryBrowseFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/DirectoryBrowse/expected_edit.config create mode 100644 Tests.JexusManager/DirectoryBrowse/expected_edit1.site.config create mode 100644 Tests.JexusManager/Handlers/HandlersFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/Handlers/HandlersFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/Handlers/expected_add.config create mode 100644 Tests.JexusManager/Handlers/expected_add.site.config create mode 100644 Tests.JexusManager/Handlers/expected_edit.config create mode 100644 Tests.JexusManager/Handlers/expected_edit.site.config create mode 100644 Tests.JexusManager/Handlers/expected_edit1.site.config create mode 100644 Tests.JexusManager/Handlers/expected_remove.config create mode 100644 Tests.JexusManager/Handlers/expected_remove.site.config create mode 100644 Tests.JexusManager/Handlers/expected_remove1.site.config create mode 100644 Tests.JexusManager/Handlers/expected_revert.site.config create mode 100644 Tests.JexusManager/Handlers/expected_up.config create mode 100644 Tests.JexusManager/Handlers/expected_up.site.config create mode 100644 Tests.JexusManager/Handlers/expected_up1.site.config create mode 100644 Tests.JexusManager/HttpErrors/HttpErrorsFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/HttpErrors/HttpErrorsFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/HttpErrors/expected_add.config create mode 100644 Tests.JexusManager/HttpErrors/expected_add.site.config create mode 100644 Tests.JexusManager/HttpErrors/expected_edit.config create mode 100644 Tests.JexusManager/HttpErrors/expected_edit.site.config create mode 100644 Tests.JexusManager/HttpErrors/expected_edit1.site.config create mode 100644 Tests.JexusManager/HttpErrors/expected_remove.config create mode 100644 Tests.JexusManager/HttpErrors/expected_remove.site.config create mode 100644 Tests.JexusManager/HttpErrors/expected_remove1.site.config create mode 100644 Tests.JexusManager/IpSecurity/IpSecurityFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/IpSecurity/IpSecurityFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/IpSecurity/expected_add.config create mode 100644 Tests.JexusManager/IpSecurity/expected_add.site.config create mode 100644 Tests.JexusManager/IpSecurity/expected_edit.config create mode 100644 Tests.JexusManager/IpSecurity/expected_edit.site.config create mode 100644 Tests.JexusManager/IpSecurity/expected_edit1.site.config create mode 100644 Tests.JexusManager/IpSecurity/expected_remove.config create mode 100644 Tests.JexusManager/IpSecurity/expected_remove.site.config create mode 100644 Tests.JexusManager/IpSecurity/expected_remove1.site.config create mode 100644 Tests.JexusManager/IpSecurity/expected_revert.site.config create mode 100644 Tests.JexusManager/IsapiCgiRestriction/IsapiCgiRestrictionFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/IsapiCgiRestriction/IsapiCgiRestrictionFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/IsapiCgiRestriction/expected_add.config create mode 100644 Tests.JexusManager/IsapiCgiRestriction/expected_add.site.config create mode 100644 Tests.JexusManager/IsapiCgiRestriction/expected_edit.config create mode 100644 Tests.JexusManager/IsapiCgiRestriction/expected_edit.site.config create mode 100644 Tests.JexusManager/IsapiCgiRestriction/expected_edit1.site.config create mode 100644 Tests.JexusManager/IsapiCgiRestriction/expected_remove.config create mode 100644 Tests.JexusManager/IsapiCgiRestriction/expected_remove.site.config create mode 100644 Tests.JexusManager/IsapiCgiRestriction/expected_remove1.site.config create mode 100644 Tests.JexusManager/IsapiCgiRestriction/expected_revert.site.config create mode 100644 Tests.JexusManager/IsapiFilters/IsapiFiltersFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/IsapiFilters/IsapiFiltersFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/IsapiFilters/expected_add.config create mode 100644 Tests.JexusManager/IsapiFilters/expected_add.site.config create mode 100644 Tests.JexusManager/IsapiFilters/expected_edit.config create mode 100644 Tests.JexusManager/IsapiFilters/expected_edit.site.config create mode 100644 Tests.JexusManager/IsapiFilters/expected_edit1.site.config create mode 100644 Tests.JexusManager/IsapiFilters/expected_remove.config create mode 100644 Tests.JexusManager/IsapiFilters/expected_remove.site.config create mode 100644 Tests.JexusManager/IsapiFilters/expected_remove1.site.config create mode 100644 Tests.JexusManager/IsapiFilters/expected_revert.site.config create mode 100644 Tests.JexusManager/IsapiFilters/expected_up.config create mode 100644 Tests.JexusManager/IsapiFilters/expected_up.site.config create mode 100644 Tests.JexusManager/IsapiFilters/expected_up1.site.config create mode 100644 Tests.JexusManager/JexusManager.snk create mode 100644 Tests.JexusManager/Main/SiteTestFixture.cs create mode 100644 Tests.JexusManager/Main/expected_site_add.config create mode 100644 Tests.JexusManager/MimeMap/MimeMapFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/MimeMap/MimeMapFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/MimeMap/expected_add.config create mode 100644 Tests.JexusManager/MimeMap/expected_add.site.config create mode 100644 Tests.JexusManager/MimeMap/expected_edit.config create mode 100644 Tests.JexusManager/MimeMap/expected_edit.site.config create mode 100644 Tests.JexusManager/MimeMap/expected_edit1.site.config create mode 100644 Tests.JexusManager/MimeMap/expected_remove.config create mode 100644 Tests.JexusManager/MimeMap/expected_remove.site.config create mode 100644 Tests.JexusManager/MimeMap/expected_remove1.site.config create mode 100644 Tests.JexusManager/Modules/ModulesFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/Modules/ModulesFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/Modules/expected_add.config create mode 100644 Tests.JexusManager/Modules/expected_add.site.config create mode 100644 Tests.JexusManager/Modules/expected_addglobal.config create mode 100644 Tests.JexusManager/Modules/expected_edit.config create mode 100644 Tests.JexusManager/Modules/expected_edit.site.config create mode 100644 Tests.JexusManager/Modules/expected_edit1.site.config create mode 100644 Tests.JexusManager/Modules/expected_remove.config create mode 100644 Tests.JexusManager/Modules/expected_remove.site.config create mode 100644 Tests.JexusManager/Modules/expected_remove1.site.config create mode 100644 Tests.JexusManager/Modules/expected_revert.site.config create mode 100644 Tests.JexusManager/Modules/expected_up.config create mode 100644 Tests.JexusManager/Modules/expected_up.site.config create mode 100644 Tests.JexusManager/Modules/expected_up1.site.config create mode 100644 Tests.JexusManager/Properties/AssemblyInfo.cs create mode 100644 Tests.JexusManager/RequestFiltering/FileExtensions/FileExtensionsFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/RequestFiltering/FileExtensions/FileExtensionsFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/RequestFiltering/FileExtensions/expected_add.config create mode 100644 Tests.JexusManager/RequestFiltering/FileExtensions/expected_add.site.config create mode 100644 Tests.JexusManager/RequestFiltering/FileExtensions/expected_remove.config create mode 100644 Tests.JexusManager/RequestFiltering/FileExtensions/expected_remove.site.config create mode 100644 Tests.JexusManager/RequestFiltering/FileExtensions/expected_remove1.site.config create mode 100644 Tests.JexusManager/RequestFiltering/FilteringRules/FilteringRulesFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/RequestFiltering/FilteringRules/FilteringRulesFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/RequestFiltering/FilteringRules/expected_add.config create mode 100644 Tests.JexusManager/RequestFiltering/FilteringRules/expected_add.site.config create mode 100644 Tests.JexusManager/RequestFiltering/FilteringRules/expected_edit.config create mode 100644 Tests.JexusManager/RequestFiltering/FilteringRules/expected_edit.site.config create mode 100644 Tests.JexusManager/RequestFiltering/FilteringRules/expected_edit1.site.config create mode 100644 Tests.JexusManager/RequestFiltering/FilteringRules/expected_remove.config create mode 100644 Tests.JexusManager/RequestFiltering/FilteringRules/expected_remove.site.config create mode 100644 Tests.JexusManager/RequestFiltering/FilteringRules/expected_remove1.site.config create mode 100644 Tests.JexusManager/RequestFiltering/Headers/HeadersFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/RequestFiltering/Headers/HeadersFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/RequestFiltering/Headers/expected_add.config create mode 100644 Tests.JexusManager/RequestFiltering/Headers/expected_add.site.config create mode 100644 Tests.JexusManager/RequestFiltering/Headers/expected_remove.config create mode 100644 Tests.JexusManager/RequestFiltering/Headers/expected_remove.site.config create mode 100644 Tests.JexusManager/RequestFiltering/Headers/expected_remove1.site.config create mode 100644 Tests.JexusManager/RequestFiltering/HiddenSegments/HiddenSegmentsFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/RequestFiltering/HiddenSegments/HiddenSegmentsFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/RequestFiltering/HiddenSegments/expected_add.config create mode 100644 Tests.JexusManager/RequestFiltering/HiddenSegments/expected_add.site.config create mode 100644 Tests.JexusManager/RequestFiltering/HiddenSegments/expected_remove.config create mode 100644 Tests.JexusManager/RequestFiltering/HiddenSegments/expected_remove.site.config create mode 100644 Tests.JexusManager/RequestFiltering/HiddenSegments/expected_remove1.site.config create mode 100644 Tests.JexusManager/RequestFiltering/QueryStrings/QueryStringsFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/RequestFiltering/QueryStrings/QueryStringsFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/RequestFiltering/QueryStrings/expected_add.config create mode 100644 Tests.JexusManager/RequestFiltering/QueryStrings/expected_add.site.config create mode 100644 Tests.JexusManager/RequestFiltering/QueryStrings/expected_add_deny.config create mode 100644 Tests.JexusManager/RequestFiltering/QueryStrings/expected_add_deny.site.config create mode 100644 Tests.JexusManager/RequestFiltering/QueryStrings/expected_remove.config create mode 100644 Tests.JexusManager/RequestFiltering/QueryStrings/expected_remove.site.config create mode 100644 Tests.JexusManager/RequestFiltering/QueryStrings/expected_remove1.site.config create mode 100644 Tests.JexusManager/RequestFiltering/QueryStrings/expected_remove1_deny.site.config create mode 100644 Tests.JexusManager/RequestFiltering/QueryStrings/expected_remove_deny.config create mode 100644 Tests.JexusManager/RequestFiltering/Urls/UrlsFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/RequestFiltering/Urls/UrlsFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/RequestFiltering/Urls/expected_add.config create mode 100644 Tests.JexusManager/RequestFiltering/Urls/expected_add.site.config create mode 100644 Tests.JexusManager/RequestFiltering/Urls/expected_add_deny.config create mode 100644 Tests.JexusManager/RequestFiltering/Urls/expected_add_deny.site.config create mode 100644 Tests.JexusManager/RequestFiltering/Urls/expected_remove.config create mode 100644 Tests.JexusManager/RequestFiltering/Urls/expected_remove.site.config create mode 100644 Tests.JexusManager/RequestFiltering/Urls/expected_remove1.site.config create mode 100644 Tests.JexusManager/RequestFiltering/Urls/expected_remove1_deny.site.config create mode 100644 Tests.JexusManager/RequestFiltering/Urls/expected_remove_deny.config create mode 100644 Tests.JexusManager/RequestFiltering/Verbs/VerbsFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/RequestFiltering/Verbs/VerbsFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/RequestFiltering/Verbs/expected_add.config create mode 100644 Tests.JexusManager/RequestFiltering/Verbs/expected_add.site.config create mode 100644 Tests.JexusManager/RequestFiltering/Verbs/expected_remove.config create mode 100644 Tests.JexusManager/RequestFiltering/Verbs/expected_remove.site.config create mode 100644 Tests.JexusManager/RequestFiltering/Verbs/expected_remove1.site.config create mode 100644 Tests.JexusManager/ResponseHeaders/ResponseHeadersFeatureServerTestFixture.cs create mode 100644 Tests.JexusManager/ResponseHeaders/ResponseHeadersFeatureSiteTestFixture.cs create mode 100644 Tests.JexusManager/ResponseHeaders/expected_add.config create mode 100644 Tests.JexusManager/ResponseHeaders/expected_add.site.config create mode 100644 Tests.JexusManager/ResponseHeaders/expected_edit.config create mode 100644 Tests.JexusManager/ResponseHeaders/expected_edit.site.config create mode 100644 Tests.JexusManager/ResponseHeaders/expected_edit1.site.config create mode 100644 Tests.JexusManager/ResponseHeaders/expected_remove.config create mode 100644 Tests.JexusManager/ResponseHeaders/expected_remove.site.config create mode 100644 Tests.JexusManager/ResponseHeaders/expected_remove1.site.config create mode 100644 Tests.JexusManager/TestFixture.cs create mode 100644 Tests.JexusManager/Tests.JexusManager.csproj create mode 100644 Tests.JexusManager/app.config create mode 100644 Tests.JexusManager/packages.config create mode 100644 dist.deploy.bat create mode 100644 jexus.png create mode 100644 lib/7z.dll create mode 100644 lib/7z.exe create mode 100644 lib/AssemblyInfoTask.dll create mode 100644 lib/CheckBoxComboBox/CheckBoxComboBox.Designer.cs create mode 100644 lib/CheckBoxComboBox/CheckBoxComboBox.cs create mode 100644 lib/CheckBoxComboBox/CheckBoxComboBox.csproj create mode 100644 lib/CheckBoxComboBox/GripBounds.cs create mode 100644 lib/CheckBoxComboBox/NativeMethods.cs create mode 100644 lib/CheckBoxComboBox/Popup.Designer.cs create mode 100644 lib/CheckBoxComboBox/Popup.cs create mode 100644 lib/CheckBoxComboBox/PopupComboBox.Designer.cs create mode 100644 lib/CheckBoxComboBox/PopupComboBox.cs create mode 100644 lib/CheckBoxComboBox/PopupComboBox.resx create mode 100644 lib/CheckBoxComboBox/Properties/AssemblyInfo.cs create mode 100644 lib/CheckBoxComboBox/Selection Wrappers/ListSelectionWrapper.cs create mode 100644 lib/CheckBoxComboBox/Selection Wrappers/ObjectSelectionWrapper.cs create mode 100644 lib/CheckBoxComboBox/test.snk create mode 160000 lib/ExpandCollapsePanel create mode 100644 lib/Mono.Posix.dll create mode 100644 lib/Mono.Security.dll create mode 100644 lib/SharedAssemblyInfo.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/Areo.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/BreadcrumbBar.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/BreadcrumbBarButton.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/BreadcrumbBarNode.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/BreadcrumbBarNodeClickedEventArgs.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/BreadcrumbBarRootNode.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/BreadcrumbDropDownItem.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/BreadcrumbDropDownItems.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/Design/GraphicsTools.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/Design/WindowsVistaColorTable.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/Design/WindowsVistaRenderer.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/ExplorerAddressNavigation.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/ExplorerNavigation.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/ExplorerNavigationHistory.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/ExplorerNavigationHistoryItem.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/GlassTextBox.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/Images/background.pdn create mode 100644 lib/Vista.Controls.BreadcrumbBar/Images/leftbuttons.pdn create mode 100644 lib/Vista.Controls.BreadcrumbBar/Images/rightbuttons.pdn create mode 100644 lib/Vista.Controls.BreadcrumbBar/Properties/AssemblyInfo.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/Properties/Resources.Designer.cs create mode 100644 lib/Vista.Controls.BreadcrumbBar/Properties/Resources.resx create mode 100644 lib/Vista.Controls.BreadcrumbBar/Resources/GoToNextHS.png create mode 100644 lib/Vista.Controls.BreadcrumbBar/Resources/GoToPrevious.png create mode 100644 lib/Vista.Controls.BreadcrumbBar/Resources/StopHS.png create mode 100644 lib/Vista.Controls.BreadcrumbBar/Resources/background.png create mode 100644 lib/Vista.Controls.BreadcrumbBar/Resources/background2.png create mode 100644 lib/Vista.Controls.BreadcrumbBar/Resources/folder.png create mode 100644 lib/Vista.Controls.BreadcrumbBar/Resources/leftbuttons.png create mode 100644 lib/Vista.Controls.BreadcrumbBar/Resources/leftbuttons2.png create mode 100644 lib/Vista.Controls.BreadcrumbBar/Resources/refresh.png create mode 100644 lib/Vista.Controls.BreadcrumbBar/Resources/rightbuttons.png create mode 100644 lib/Vista.Controls.BreadcrumbBar/Resources/rightbuttons2.png create mode 100644 lib/Vista.Controls.BreadcrumbBar/Vista.Controls.BreadcrumbBar.csproj create mode 100644 lib/Vista.Controls.BreadcrumbBar/Vista.Controls.BreadcrumbBar.csproj.vspscc create mode 100644 lib/Vista.Controls.BreadcrumbBar/breadcrumb.snk create mode 100644 lib/Vista.Controls.BreadcrumbBar/explorernavigation.bmp create mode 100644 lib/XmlDiffPatch.View.dll create mode 100644 lib/xmldiffpatch.dll create mode 100644 list.txt create mode 100644 merge.bat create mode 160000 mwa create mode 100644 obfuscate.bat create mode 100644 package.bat create mode 100644 release.bat diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..ab3ba544 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,30 @@ +# editorconfig.org + +# top-most EditorConfig file +root = true + +# Default settings: +# A newline ending every file +# Use 4 spaces as indentation +[*] +insert_final_newline = true +indent_style = space +indent_size = 4 + +# Xml project files +[*.{csproj,vcxproj,vcxproj.filters,proj,nativeproj,locproj}] +indent_size = 2 + +# Xml files +[*.{xml,stylecop,resx,ruleset}] +indent_size = 2 + +# Xml config files +[*.{props,targets,config,nuspec}] +indent_size = 2 + +# Shell scripts +[*.sh] +end_of_line = lf +[*.{cmd, bat}] +end_of_line = crlf \ No newline at end of file diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..8079ae23 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,22 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# 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 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..bee4418f --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +build/ +*.suo +*.user +_ReSharper* +*.csproj.user +*.resharper.user +*.userprefs +*.suo +*.cache +*.trx +*.pidb +Thumbs.db +[Bb]in +[Dd]ebug +[Oo]bj +[Rr]elease +[Tt]est[Rr]esult* +_UpgradeReport_Files +*[Pp]ublish.xml +*.project +*.metadata +logs +*.generated.cs +T4MVC.cs +/SharpSnmpLib/sharpsnmplib.snk +/packages +/lib/sharpsnmplib.snk +/gendarme +/lib/Activelock3.6.NET/ActiveLock3_6NET.xml +/lib/Activelock3.6.NET/SharpSnmpLib.Optional.dll +/lib/NBug.dll + +/SharpSnmpLib.Mib/Help + +/NDependOut diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 00000000..2997131b --- /dev/null +++ b/.gitmodules @@ -0,0 +1,6 @@ +[submodule "lib/ExpandCollapsePanel"] + path = lib/ExpandCollapsePanel + url = git@github.com:lextm/ExpandCollapsePanel.git +[submodule "mwa"] + path = mwa + url = git@github.com:jexuswebserver/Microsoft.Web.Administration.git diff --git a/.nuget/NuGet.exe b/.nuget/NuGet.exe new file mode 100644 index 0000000000000000000000000000000000000000..a9c681c8edabc82e736dd5077d5040317ac42c15 GIT binary patch literal 3744336 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 %r=}=8(cL&=Joz&@ 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�>gt=z>67(#^H| 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

nJI_&)Ql_DMeLu~Ydm zdb=M>ez4tFrs2iWdilXTqkWP+LP3K*skGh~q4n~S5MJxMB#T`L@FwZEh z>_G||rS%69TCW%nt)us=v1k=p7axIE<{71xJ+304QCjbh(0bK)XdS&Tj72N^LM1T* zt;{n@D|?B8)@Z#NL(&f;w0>$lw2t0)#-f#dr_wwEt<1BL*7qu`k)?6#G|>7Z(i)u? z)a&J=>upA!iOSOfWa<~ajf=M%v0`+6 zaIA5P`e39|sr3cpl-B7_B7C}dJbWsAX0-8oEIysh!Y4=I6Z4Gn>BCjffKN&*E+!3) zEt|(f>oNZmt>=({^a!*v&nT_uRzU+=UF%e|zlV2Tr=#o5;W}-v^;OaFsW+b*sZ^@R zX8x{uZ`*m^qqp_3@@88gy^r3bAFguCnZNrZiIFT<1`~RCuvGIsrjlCag_J^h6^+ai$MG$2>~z$a)BPOD`#9DZ5|!+sjp!hRaB zs{U}EVcNpsz{v?~H4XB9k|ZOX%5F6rekznzKj0oQaGXR|!vV*MTG&qoE9|EdQ}qMS z`)C>k)f~ycAYADs!> zErOnu^?P*b=Rl9V0p9mGe0bW^+lI!Pc6*NoB3C14}km?q{i}!Dwv4KN4=)m6M58J_3%di<@O&ZgAq^Z*KqNn8l@F z9>(S7pEK~o!k2|*ez_q0T6{0VZxBCj<-Z%hFXQ(Je)r+`GJf0fYr-apzvA14?*#mK zN?<8|@5Ya>TkMJ79Q=6xs&sx2Phvw_KwSU=VvQqW7m;hF9A=h;9mAgda#Z)id7b zBE92GgcOtPAM8Jtwb;tO#hNt>-ec`;nV^q29^tmqU+hMI=PvH&(MMvnj%rst^yyR# z+YJAKZZ}pRZMP=$1nasJXMTBg_i*mI9Faf}bc$hi}=R*F2^`vciyds+3}A|E-8FJh28DAoZY zQM4sckCpryP_-EE#i;kCh}SOPUzG`RR8}ud;{L_pLNAWRl#_>n&=<(3%0)3uX!$gH z%Jn{k?9;9=Ngh>q1xt57+2EF!elB2Ge2jJW7Hf~iS|8Xe^Z}Nb`wYls;|NcBm<@yQVgE;Ho~LJ*e<|=pH8#AwGqzEQr_65DoJ&u zT|4Gq38xHeE%H8F!k>*Ht~IU)nC}8NE347C*Co^D{Go2}OvpibbNUcNkr|8f)^7VN zUnTDkYu+p;yV|d7c?UU*KG)~il?yNyKqp+Oxfb*r*3gOr)_a3cW-gK3awk*?m}{lyOH}26bu*qPuUU&SR7z+fW-+G zCs=$V%~ewcTT23934kR4mH=3SU_i|yiB!kYoe=Z(xEo?nUX7MBiFJ;G!9OP4i!K>N!UduV@<*2@+9@;{l0YE2N_ z;q6$(uFA)xkFZbW0Q(YY8zKj=^(uh?++*N>TtGxVbpwv&eOchhZNN=I03OO?h6LXP z@a;^Ccj_3%%hpu4?66v=Ta1A`Ry@BIJmg#>o(so;XNm1!1pdhGL7XH-f1Y5i0{&Nk z*RcmUxx}7ufdPXF3R%yshH?38?m)$s#A$#u`wHW_Gf_508p#>j?6>e~p0lT{UZ{Az zQ*Z>7JPG_c?p3S#D;FvIs_}UfAMCfo;TrDA`;Xa6mk95r`>wP05acG8%sFCB>f=^n zNA?xV4ML8XH9B@U+|rFvfO|sY)z-z60uFO^N7qW*W_?e!Y2erhHr?+^^0OziM)0wO$w_y)%E znCmCuGdl)xvkar+^3fA-*fmE0gDK{J67^z>1ktT;d8cwQg8WMfG{iP3n`G@=%&A<$ zh|3TG2D9$73#MBC23db#xpRwZrMGOo#Bv?FfA2P{7yCbyXxzLA@0WYNH)hF8Ea;CxI zkxgka{|9Ui8lAGX+Q6jIMR;G==q?4HQ3GtSbrlh6iCvA%$K24eJ25$^To!7IMkcpg zm;hOSBLB6-+Icvhq~y5?SH_bxjuj@ zTu~)W<$b#~-;76;Ni#v?YpiG42&q!Y?l%gtHXGZG`PYLc)#FTKnq&^O@Z8Z2!0~6| z5Q{;1`Sp-3n98Tt#Y`tW0wLx1GPnn&Ux(9eSAwXe6d`(HZ21~S>W#VHW5`P(VuMgD zAhITH4PtS{VU3OH(j>&1VcAK<+?D=Sz#AHue>ujue1)8#M{=&L4+iQDi zqi|)5EFK!+@E9Cs0&OR7nILEElu5Z$2LP56vh_&Hu7T+YF3-5Z4E2uBq2BDjmO~R# zWR4HoXOnVY4sqG0oE#SMlJLy||2c=@kidTtn0yTemwyLIFs8T2THjw;wwQMf@W{;w zu{DPv)0Bge_i517A{tJ@e+KSWJDzM7Y`9l0m=gSII}JC9wcr!3=C8X&CFb1%ym->o z$uu|npA}jmTxqwOy`RN%Y?wpI=xEMo@Bj|ZXBfjLY;{X$Im3CRtw;-P<%>kY^HTKl z3{Yh?r!comFyB^=1#apVtAYP-Y=8cDc~y_2lWVfxDIXc|Ub(KesoF#ot@$n>)s%SJ zcZsIDa_m&7Fs-lI7L}F1GwXxPFTgb8_g?&F!+$@%u;f@<@eTj}0DlVMJWtVs-^KU^@g*2$tjbF$UTack z^zo!{HkmFFR~-$d_Yr(L_{{n>32@|sb&-jsO9zjTWN(ByH6uZ#g{d)z2~sy}>gIHb z?=jYA_;(Pisih_G<&_|zD+x*=iUJW_{uH5flzBMD2U^BxtR=lvJzs`6>XtF|=5V@N}2PK0%QQ`z0oxg^hw|OZ#V@-Qu z`>zE?(LsJFI&%qEE(_@|gtnB;Zj13_m;q{!DOxMSVUG7n5Y0a6y+Q}lpA?Q48xA_G z5kRyhQUUo7+Ml!bCt#Yfq2OuAE0`Yblw&z`keBJ@+5UBae_doG@8FX;xve?{+ofH8 z3gtBhdkLPc2K(;$ud1W7f4acU{6f$@M>K-V(2N6rqArNV9TUGhK?Dm$ngaXy4$=~_ zkN*Ks|9AHBU`_E)WB@4V8LxhP-(bGFyqHo|xU;_p;pGQ{f@x^zVo*KawT66FzEWT9 zMH;O4K|foGgK~KPh83c9?)slaFN8YR&2qz_hDkoF-oF;X3xDSLgGfP|$d7-873{SY z1gaR^^CrV*$9odTibDs@Y-cOM%qX>El=RQ+EWMfka2yzEyd%G;ur;BK;1_jlxhhTD zo4HNc1%RVUcX00#rp3P|%UL$I=beqW!J4$qd`4N5{$Iyk*h9ZYTF@5{WM5>N=96UB z+uDbu-{^HwuHOtPF4IK}NpyQI{$Q4@B+{=LEUUkTIx z4NepDuq5TU>ZRdDL%^8pQOm@th7|RZa9U%(-OLLM1~9ncM%Ey2@@^hzh=s}{Z{jJP zrXaY@%nS)N=@68sk|YJ3Phk>gVV5*)nNmi76_0;L>LXneC0`B33Ddldt@!0eoz3x& zVl!90t=pQuNcFbS+WQB-`2W`47kp_a=}miIVaoRF{~W{zXpPBw zAGZI)e$F6ylVihmaB)@bdID*Lzm;y3OUD9@!ac8&h&Bj0o~+jaXsF{&hOt%b$Qo>6 zoD%r9Ci!^Z;J&8S&e~3_FRL-r*-E!}1M|YTbCSVNgE(I7l2ksK4MO(wx`_TpfNmtc zqz!%QVC|cZY@@)b0+j0z1cmNx|0*yym^4&>V=mZZ^7_jhx%z#c%3k&H4GgVAbC#c1b zpc8O}#*TQ%Hcs$r&!!27UHR)jU~sWboEeiUjEN%Et&?|%rDjj89UL>;e2 zq`~jh4&;cDAQcn26cY~yd0vPRm%pBfC#a^Fktv-L+-Cbf1WYfBR8HM&`jjRd)z;LF zcf@~-1lVL*Is{g8x z?b|=N?S14mxk=Xj&jz-?7KC!d|hU2Zm_V@{AhPNP7wcjbX2n- z!8QZCl_ES82+;wdW6q$9^CP?;z~=0|->g$nR&ntM4~oE!N{N8I=>md%T2jBWU1<@( zL)<^WHYDKMa2Sw?vVps11`$yC0wo4RCCZx`2q~mv9@OiwJ2BEmWeE#ifVP41-9ZCt zRHj^Sp%jGq6BqA9$c%;Sgj-Bw906C%+mpxwTr+^HU2rvhr7Fgyy_vq*fen^yOs4$Q zD;FXSc4JfLV#73wJ*?GiM%>RqzN3>?zJ#x+3kYN7R&lh-Sk^%tq08S#8P>W<*ciiF z-VAFe6ArB(rfQCl^~0K&*v1^o0=<6{>5Az6+`sdGulMh(ED^nb8F-pgo}P|Q2cFV0 zu6ll6wf~M=P5DOC{wYzxVri#={+|a<$A3py|7ZKh(hu5eRR3qV|3w5-|9@vl|A!vf z<@G7C-I%8hBacqv4f;#99mIuZX)dv@{TMmhJ!ZDGz*=;w%9Ir_gvW%?Bbwi0ZvX0ww8J7~gLZEJTUs6? z5Bwih>mnu-<;hwX+P=-gx9d+v)dX*VHp_O(t_WN+N*wDrB3A^1$%P{zakM_VDtBPF z(K>6jjVFvK)A6DFuJsYx(7fA_0raPY#VwoN#BIRCT@vq<3U-46OWm3W>*ni7H%013 zR&d6#CUnusV=f3?bn=L+LBd5-t-B-7aJ4#E5&Fb)xWP&5SL?KLH7?vco1vj~q8~NZ zEz2Tn7^hgvzNGa^dlz1L@V|^kWU3-yi+?l1W`oPYJc|1WXt(lagZMai%6dNDxd|j1K z^M(mnFl)cA4R;Al@MRqLe%atazVbDRgN;_Y=Cs^}SORP+c1@7BYUP^QWMNMdzJnBI1d4j%tI2czv-^nedL~thSa-v+aGmoZB%oGHIW3#5=n{@X8w!k*8 z_99!Rzt|?dFT!21$;B4$LVUWDXG0(lW3~H9)vSs!E9U=|T`Atn!7|>M_@OZp#}%RO zGk4@co^tUvBYZW^mKDX?j_V-bU>+0jVFmdB8^f?TKnmL@4Z}SsC-%9tn+BR^19gTc z^Aj8HmgXAZdOt-Ic>3l5mpDSWrYo)~2G>l*HCu7PDE{3I z{$+}Pf5pGNhChVsZ2>NEgmBGNT)hU@n-$j)itDY7xDG7uZ(FC^^4EI@h9>k4@MmR! zUmU=HleS%_y!*YuO^wd*I{;-@?na06K8lL7y^pi{Q15Nl^GGubwAe%M1Q2A!CkQaa z6#lK$TO{1faU@tnP%zc%$U-}(HCIcJ&ZP0+h?F25DnU!81;J8+mTaqo zr3Nj5W|&_YribHBxN1yGD$F0?Xqr#em2<>W=hAo|{xpC$_b$fYOsufDpSC|Z7WL0m z$Mk;Ab`Y{e=9O@)?@wyT>;VoI;MlJC#Cuu1@||dGnOJ=jt0P8gAY2&Qe3QMGV3Ajg z8j9P|l${VT946`!n@8?K=uS;OcA})X($m2EwlMFp$dhSP-cJni9xFBo7T#yF?GD~D zA@5~pWkR;rXC{b&x>+}aCvL}5j;tVNCYZTdi}fMUH;3{f!fmH;R6iM2m@Drb7LG~T zX zIy0TMqGcy1#ZuiK%S_h#q-m&D$tIBU3YDzBWPW99UExBbXN?=jAQ2w0ngagz^@zJL zZ>%x~PoJn59FYxm+187}r5peA#v39URI-@9+-waXd;TlU!5`&^_AQkaJ!TtXw8rYO zFZ_X#Q*H9*@7xAC6|Un3dE@nSf-BYAKtO$M*A>&d7!AIDJld%QbpDGBD?J$Wu_?`; zhOgO=kzFv~x)91p5#{W_@t)GVsmp{kxG)C?G_$U+2AWbRa_rKH;)rb*njkNlnT`p)M1|AmX;_To^mAk&5lD83lwhRE1an0}^jQ1|1l%drhU%Qr-?OlR^ z)`sxP6skUD~NmSM-zaj1v=E}$r*UfrFr{nmzC?(p$cb%(xV^^|F)4#h8SrFpz#)KTA}Z1SiLyX-XHymbk1e;E@bw zl8{WWjZ9w_jAN%)DDy^stsgi+^8H#h-yu*m|h)>(GxA4AhmXtF}iMePq~FTqFmYDX0WK}suO{a~{6wH;{G zyWJ6pxPXTVIhsCC+O#Ma4kuOv%vC3!t>O9eB2F!|2(AoeNxdN*+goI_RW2Lb&TV6I zfGI95W8q!4D|6y}F(YT!RNqZoHvx|Sj35rrm2l7tLsv*1mrn)Z+LqWFaK@@!4nq1k zeX`3R4E*vKNGBjRL_%YfFhb-sII3<_M zYo|{KGP^ccsBeAFz^+K?>h;TUA2!TX<$TBs9zQ-8-$YTSo2|*X%y*I_%p-Oi;Ic)u z)-_{S^-GLCc+f$Sm;MVKprOU^LFJHg!?MG6TQ4j*QNkv6p0b5KR1F?jBe;rE5cb=o zoP*vSyvkq5{h2tb<6KXNi%o#{Lh$HgoUq`22Obn0Z}=f;8Uf!$0Nyqg_21r+n}H1m z{wXNjvvISZq|=(Y$YL~YM}yFeX~SE^FV-CBA6f;|6X#g8_wS4E0=9EGv*OGWZq1g> z)vyay!R77~JLl$fTQFR@1y*!B?B_WIHm+epV{MN6^~_4>u;jbKk%N-@BBt$$EjWvF zn8%Sw{A-Mko*&{93cVQs>f;KsMcej^UYEzMF+0t!_ zTsvX?^Gwm+0p@eL-@J39_2goe6Z;wf7t_7vQU#(*YZb`;>QopB9)$xI znWHhU`P;ZUEWJ(gp1%zZTHm9=dZS~pO7C1FEHqeY_1exSvW zwnOEj#59igZNNyoC?9th1|->zis0|CARCTiV~+XvBdP3li0STcoH@S-@p?uTjr%@$ zgx)i4?}vcZJbPJGb^1Tj%x^Xa-tNB9F$dlZD3xzRssCfb=1?}*nu%b@B-q_qh+qZL zP^W=zdz1eFQ?MPC4WJC&LVe{y#0@hw+uB0iFeHoD^dHNf!J@{bK3qesPkb)4gz7 zk^ZBIo{jkIf{Ak23FnG=PE9JT5pP8QdzaSf!~fx z)siib2~jM^w?<<~xDHwTV&!rCU5Bw5ey_~R88`*7(@6h`i zu!4CkymoB(80`crpjrG56yZHq3jc@T#5qDoW@uB?3w_IxONyq3{OHY1(?Wh;hZKe% zfusN7xrUoT2le9x|1Hr-5@KAutx(|p-tn?v>ga#H*vmz&YkjtC2Xa z9W*!BdzJJNp0b&8ViVF}A4aAPmw@pqJMUT41cpjBP#1@?c-fP@GwN)mGo7mx0DxCD z;&E>~TwV|VJjXxJ;}24hlOmFxwPd2~CvrsblD9QmcL8Sk$2X9Z$B~YX zJs39m0hUKvZ6HAPy)5J4pTTbm z{D%Nw_27C!)k`OMTNBp-#^Alyj=GC=;n0 z8a{jzYY4bnG^SjkFJK-yW>AS!QB_$Q6Yk0|2C4Q7(q&M721rmV1|@yo3tAt%C`&}} zIExd-djycQ8mx3@V@WJS{z6bI`7a=^Y_kCokBfB)*ZZYre*qeE?*PlbmCkHDww8TI zCVR21bjoVWT;fia$aaJ37sQ*y8(~TBSAt4`QzpGYYLKoywx>f0y*rV*J(Wp&zh>H) z+|Qwk!V^_RL2vEIwrDI)V6{k(nN-ZQ8X=5@%vSHGIAa0~?8S;9`?WyTaOC>Y?1Y$p z+uA2&+PvRrjvk7p@Q2sn<-*JC#F&0F-iv_6xvUgAWF{jY|0PXMA)v|6t0kAqMzifP z{bt+SGg7{8m z?mfUK`_Ln>SH0beYv(lSQ`U8mA^VA}!7!nO#@5o=+m95sYFdS*1M}c()(cS766;7Q zW1>=PNK8V!0%Rigt!e+0lAA8~eW1`OVyur{8oP!7CekVulTX@iNff#kPeEiN*Z($t z3N8KX<=fT&9(+r$L6#&6%NEa&z+(SW`7YIkeD0dU5hm*pLjF)7m&*!rqHu6OZA_)x z5!ei#{1(iXtLH!h{jb#de^=-KeaJsvL9rbfj!<5y8_J5HJJJnPx$I%+T1@eR%cS~` zk}ryXo;tevPl2QK8Y&W77?v%bslmnm{ncSuK;HcrFmERCeG0r>Z23rausl~-x*5UE z?EZgXsW=>v3k={O5DEBWeZZ@s038^1F6JHuEu%5wS{5GaUbV$$<2JWWpcx1!&<=zX zK|^3n|A{QzOOX2T8BQb$#r^>VBP7I$djWGGf$ve^<^51u33IUA`63%aAmcLem1009 z8|WL1_*O-HM+H7dPqJ~-h_jZrIQE?@PTH9Jxb*I<#a@!8zSG3XYa#pIEl%Dv*|$=h z-EgdAIvwzu7LjJ0$4{*kB~N$_-(bYI zD&jk;>XQwIlzFgOJj~&8hTUBeB@I|-*wd=+*&T&c;DI|GxT$|FMkC-qrw>v9DqGRn zfURArfxxG7kLsN5{Z__gGCeZ32Qfoz6q;Cc2Td#r96_c6UIt?!y9K`2h^p$7i@C)&0ddr4H7*Gs$3FG7 z!N-wJeG}p1K&8G+v7EWvj6HhwN$6-MDA2LTl?yHR7oF4l6U2gywbP1t2>CVmpuzPc zbFQBy_$jo?3ZaQDPD4l3`W%uO0c@L`AYjg$wAkSf;Fu;sW`rRZG(fgarlMmJ7VWSA z7T1S!sb|}^;H~@_q^OcDGY>Nl3HF%ng8kH%wH$fHWE)8AqLXt=mQ{1=-3Lx={UT+O ztLMOk39XvT`k1)E?j-YV7gj35$R(!!qclfp_UX7$V>#Xp;&%mp9cYI8;&&+AN8+~v zZd8T!5qz%-{YrPiV=y-|fvSdo6|))}q%0t6BXj)Il{ONqjgGuB2t*r}LD9c5gjYo~ z#f5)nD7Cc5_E2gD_!~nIY{#+>I>65W|3e`NnOB5yFu?y{L*^VLG~w7~tu&;h9_z0Q zWhs3noFxPN4>u&F*6N=f3YH7*{mVlkqtuBIQNHJRu7_DUTSj1m#+{p8;4z{R>g^ zo>k*n(~jJ{knt>p2|H%6QPgUW2`Wwk6q)R6$hU5vsgZ*08ATQgBg++aJr1{KE5AHz z{yWqjXIm9(!F7RcZs^p27vca~@aO$Om^cvDy&z}33FFRT!izjgg)7Op+=-hc^h(th z#F}f364H6Fn}AeHN zc^Drbl;|7zHx%7>xrzR=L_`0nM*j<`b4$)N@fS+``|9JDLc0<4@0a*D)yFU5NYCsK zmv|1xLH2@wan8igGv8VGD&x(`)t9jYq46|Qj&{;z(vB^QGtlYa-ah!X!p(nZt89;K ztEUBZAr8dxtVbulhodfV*5mEw{K2t${@`75@W9B0;9Q0u;1EX$#|p)9oWb!v#j&~p z#|+q`noVC{QXLFros9CpVZZvY?cI;nD<|}VwKIGMa)x$QApyu2_EOJ7!C>({ok2+Z zIMVR@g!w*czCShJr_A>;ereM@40zrw?eJy<$<;Xa5Hpa2$&mhB{IZA22ysQp#OlS~ zWG0k9f_V$Wo_*obvv+;COZU+v$o>C#dk^rqimPw@>fXC|i=?$zEAPq@wv3IO&=Meo8j?^FLhm4I62QqzC<$pKq>+O8 z|9j`mIYGG8{rA7nSMw>20t52Q;RyH*dca^h*oc4M1(u;Ny=8muOPT zh8#z}zFCJ9$sLLdBv0NghP~^|>q%!}Qd>&~_&HF0(4#GHfwUGdMRT8jTO z@qZcqZ^8eA`2RWne~vN*UD)>={G!?iYg_iR4znsQ0t+x^RfR zqu!BdLUVGaLowA~wRlS+IT0ossj%SNw?)>HJqUxx;el;mPOQhjI#a0#Ea<@8h?(z_T?I15 zz(T(yCw2Fe=vXiA+I0_ddX5Rq{1;08yu;GwzX0=H?%N6EP8f@oGH=HM!e6d%6c2=@ zy$9D3>;a0ILKyEX^`L%$lb?UKR2$U6Krai>!fOe+PLD02-((;)Y}=dtajsRy$lm>w z_!`zDm=b@InWI=D7;odpG&%91Ub3Zv4&9F_TLaft$L)y-$4COg@~+`Lh^OR^&zoRg zdK`WSASgY8t;TkmRM%tJrGk?~smzS*1eE{KN_ zq?2dbs}y-Up_RkEiLMpcFHC>Arqh#5hxn5ePgQ6=ed4K%Ksl+HsF(i&;3?Jze!Lw% z@jKWno!Ej(OTeD_L9{A52#DG)8>763VOT^%^l)@CCANQ` zWxRtWUJZOoZul4%_j65g!)S;;^TT;&AvS8L77%(ni#A3~9FvZ++A&!!A9p`ilCYKK@lr`;pB;b8- zCOP9dX8{lfxLX`f0L9(vZ~`dqHir{Hako310E+v*!wI0cI~+~`#r?qH1W?=$9Zmqn z{m9`2P~4pkCxGJaayS7Lceld{ptyS+P5{OI*x>|F+)o@%0L9(wZ~`dqrw%88;_h=e z0Tg$?!wI0c2OLfS#Xab70x0ewhZ8_?4?COyihIQ21W??g4kv)(9&a381)}h{M=?*7*sbe$P3a0KjprqP(~t z=TW>0oG{qq>dD(;G5-LLVJ4;`6*$w&G57GfP^X~G$&LKlT+aF1Esi=Ru4ntpysW=Z z6;wZP^D?O2iLfvxG(R3EojWY92kFrA{s2j5))tPrNM2bJNUk6DZdTcAUrWW<&9FvG zL4T+ju$;4y{vxE0o4gOT>4%AOhPACxGZu7Pd_fdQ<7t~q8h9Y$jiW;wPq@xA!Y;&VUOB~33smae;Bx4K48{N~O8g;K1a@huV!Bk! zR4zsuI5D5O8q8x$k+<%~%n%oJ+uMrd#5lHLb9!lRRH5$1dUnmBBxoIz2e+Uj*U=ge z;b#B-b?Is?&84h?6YXHY(dt`JWJYSqdw8P?S_FsSaW+hB&GClPLOHLW#$`5(VDSb# z4O(%*urxpG4`+2I8cPPIwt?=7$>D$u9(FM|vvs*ehi75R<`%dD^KIg`1g=zUlk*CS zDzrg8KtEjB8)2MC@0v8ALL1701I6ksV`-x&@D5NTopzfJQH6G-qrm8N+K~>98>@Fc zo%5KE?tcV^4$b*|K!N!>J-Pd)U_1@&XEG>MF<+tN-I0&8bWKqIjtOxNP9NV^d^M#u zKnT~4&w9_OzB0e6w0T|m8JJ5Nxe!d`GEsAxsJURg(!Zl%b196@Wnxn<6Pt7SDsyoa zr9+GNH9&ZR$LdPA@aG)o=TS58BUkxzRw`Va-6>~a4&j_}_Y9ISLFZ>9;9NEN~+qe$hHmlD{hJ4<|a5Y6pon|Wx~V+e(e!l%-opI zSA+SIeGi$>?OBydDY!|XtjL({GK($j50PkPVJDhL7s!S#PA2(M0&16W$2GDqq~g2q z0eQKPpZIS4%HBrL?5}$lLF00$(2Gx^0=dc&a7S{ZAh)4tg*vmXe-9v66_-DaLwW;{ z9K7BswZm~tZ)WxN&|6Z97YqE<_kty53vUd#%ffR3Pqy&V0Z@Rh@!tl*wjTaJga0G(eZj|&?EzwVAgPYIpP2HP`0O2X zG5quisev#5+wLbdi_dN^i5k*k608+#4&WBXHBkEYuZbLh)n+bB(eRJQ9|ow3R3kWyVJ4I|#+KRpk50-mJM= zv>vRdXCUU`vZhFh<|LQXTS3k&TQ%Nts@*To3z#dBgH|Lb+otv{E)8P71>dxefo&jQ z*~hqE8BYtLW!%}@;CL+~-|g54W#pf>T5ooc?1Ls9$mlT?()#Rh)J8F6C|GBaUp`J6 zBH=ZsLGH_@!Sf}zBHP96Lkcmr56ew0Hsi-1+G4J&=OLlw#fo@_<{Mbi%>;4=!qHys z5>lT8M{C341rHt^(P2Un$PSb1#_n~p3byYDy@RfDeZPkHDDX$1K3ZuRndTf+S=(9m zxIhtQrQ%Gfa8pOa3TtbJpUP-5(n{tljgBab!&RAp{;Ary&UY#zR=aNnogB2&SsS_Jov*4k%j@kaFg+4Xo_MA_5)iW@d29Lb>IS}ck#q_A(HFt;WZH* zS4b_YF@N_m*s0QkqaF(m8fi-4KG!CXe0Xtezpvw+af_Qz`X=d-Xp`mdQIf@V$ORNb zEE}tH?zK(qCx={p9)+?ec@*csA)?dthpW(9N?wx2I7sAnP;j006S(vvo^bT6bt?-y?VP1#YJIy-2 z{MBGd?@8)d!79r52OWTH|1UbJ&lCXV0q)-pCxGJq<8T59E?x{7f^lO?mP`}6*)aaR zIs`saVd|Hr!JmIFh@Xm|#enehI72AkRQwF*3h5Kd;I-Lu34nM9`9uFj8N>i8-krJ_ zMKE8MpPqyf_XC1FU&{>_{z3FyjGh>#hd;Cmzkw;CmHnaj0b4~1L&(&1x|3FKKg2cY zAC05Gri_SCnsl+t#`Bmg2{V&;Iy*hBr^M5ZBFN2Ney0>iX%Xr?V0BZa_%$|zzKLaF z=NDS{(}4&tqU=s6t6;*w`uIUgh($@>2JI@vZ!$sZ?WyZpg8JY>5|j+vnOxl?^B=xP zF1v`bY>K-N*Q(mJBIR*aK4xsZ_eaH}8|Ng}(podEv{?hKkw`1!Ed;tcHm!e+N{ep$ zb}jBHkAH?L$b0pU{*q`_C=dr`4`^>7q)ySCIDUF&FY#uA->4y<+L1CZgW+YEm(dV^ z8;$2Hq7=Wu^sTEbuC}x`$(6`M$4OdLOkgg~1uE>Cvok(fb1Y)^4#vO3XP`pNOhNIi zS%T2v#yBB#sU)H69aKUm(nhL(Q%UbgBvgz#plxWy+NV@9-XH8bc0i;<%l)i-w%p+1 zc|Qfm8wk!(Bsf#i5;5w(t}dPTfi4KwqLoe1F&x=MZi+U$VNUVhAoDnYnZ=AyXgHr# zr`QkU_MjJ`+T?R}DzGDKjV@w)?eoY!eidnEq>z663SmQuDW%guFp08j5SvK+YXmfu zp_Q>B7~LW(EM+A&!rMgiyqBUydo^pmEnExo3pl3?yK^$5yU` zYzh;F`3LgzK)#9r{2&H!{1(raQU37D+B>#^i<(}c*y#4kuNh3T@y8AdEp|s|$E5hr zNVCvsyX1QkiSwz@sdK4RD9L!7Ja~R1!NR1H5@g}WE5|i_#%5*9pgE2^{-$vJz0L8* zX4CLZ(}D!Py3c)<0N`4_#*=)0ypj#cWsmEo${9BYTmLyA(eVaA;W&K)P^msBBBuu7 z0U=@ULo-)vuUJo8y2HJ!`=_WI%}wuJsTlZrU8cm?_ysu@dfPJX+4N(r@c>6X z=Y_^Esni9xw&fb$3x8G~b2AN4b^(gBJG^@k4(E7q4qBH9%t~IUga>nBj3yj%9+(ba z7mkdqb@1V2OdlYFwLQQh6DZ3ZYC{Hz`AHqBDEVPK-aYskB<9Py(%`<+c2P=e;*liP zrHRWKS!ULyDQ6NX+f>~>4X}U0csLeyDdjL|)DcjKuxl=ifH)7EqH?SZh*^Sm#RUi;>cB&0KuPhiMt z=0H-&T#8s#lGE_Oko8oGYFIu*dk3FDSON;MLPE&j_nxG;6t@WJIKW61ee)LyeFA>t z$1wBFyPC*f1$`pXj}rYiMgLvU%ZYxR=zl2spMqXdN57}&e+l}OI{M#={trI3UZ(-% z0yDZ^ezIQw)oAZGqMZ(q3(n|hK{DDZjrIXPfjJYuT0xJU>6;dO0`n!JrGmbqC*U)H zU1+rVx$v_sJ5fCg`1GsiWzMr?WRUo#*zmld;VDDMHrUYyt>{0)E$kI1u z7fc^AG+l5jR)filws8zLY!<38S)yNs^coUOgmg;U(W;?YWV$8T7Z9vJmRy2HF0|@0 zq2xkrU>Gc3hZ)pm$_OpydB<~1*0w;P;V#S}pGT{D>FTDdwk~PpWbqgxCY}jD8l zw~lu_)}0fOM$q4n)B>{({6q5zM02~_f-0Z$R~S#@%DeCy0#V$DvcwexZk5+{)xRxc z{WI$253x*XvmTS<>hBQi1A%Km*k@sFQ=}qIgDayp2aFqP87*rzKq$N+$&KNxSr zH2eU=z3Z%5&tXE{F=un&+Qtfb93Lm#6^+YfWz&5+Lc>sDA&nN)NB7BJ3}tIvimilFZM9k2Bp`S@P~gXM>%Fm( zOd%Kw&Uzq)x5h~x$Lnm)ek{MxFwH| z?8vW)%&Zpt)v>HrBcFC}{W*@VWj!w6Co-Q9I=hXK+^hhGC@Cqr*%^p}a-IBB!FW+mft0Um2J8?vdj z7#jg(`31jm1HXyI_srhJ`zFTma+J*<;%E<08T5yaVV>&Xu#VTj5A;nEATp4~p`Ycj zG6MixE417|W8$^|tP&;-4;i3QZ3|#b25!ZIE^Y}7AKcptUzt*7E+9l6#Am&`>gT`~ zBupVVTqURW3ioG0CYe(aSNCN{WtEexh=l?~vkFIN6=+s>YF5FjQZg%P@vWJ9s=|$q zj#Ru2U8q2+k=KS0{7fWy5laIYQU|js@QAT3tMZVhpITMgBT*IhO+OjU$aa)QYy&zl z?4Y_Q9qO3}M7jf7=R+Gd?@R97+BM$%zdLwh%l3P;kaP8pO%k;P8Piiq!q@enqebs3 z0OEkxTf^Z5P}~%U6F_lO9Zmqn^*WpYiks$e0w``xhZ6uezSpulz9(_~Ndf&jy$qCI z*0w`y#(ii5zqUQWPc*>w1>Awy*#!MqMk|SH9OK98x_iBIk;jTg9y+S)IWI5v=w}WVC`<@rplz@-Cl|2sFSzZ@}tp1+n5KH;u(_`&f7;;qvPE zN!~lvAy=gy{qy7+M%PV~fiUE?|nJHd2f*dZ; zuzNw@$O8@AN=>!DdS;*QJ;?H*zDZ+m$E}ls=je-KRbTpbaKFU>}ePat=;Y~)NB~4(CMwGFBG`Ycr2jlwv0g_~3 zs!e{%hm&(BA1+tG`l8a-Qa9N2t>7K+fcgZ6tmObDUt2TUEHyPd1IYaYm9?cK$uaZ` zGonq=h!7|@v5lllt~8l0?Vp;`Wq@S5=Z#9Y5y4vdFYmFPCJ5R*D{MFcfS`BLUmgKHMvHCf> z>=>lonPeImdW}goFim1e|1?Ie&P7o*sP#`_xlfFA;cvf*pb5Lw(pFr3Y_>E|v)MAN zFw$kc3}2&^l;`F^6pLPsXWK-gP%bYz)^o$pm~txYiY+<);fmUrz4wUXgne%btS4%zm_&2iloIQMKF`|J12iJG@*Y7EU~-})(XOBg zdZMzbBx%yzCVBxpoz(a1-n6@1eLLixmoK8eBkyB~%RWZxYyo#c$E%&}u7Gk;%6tZ2 zh>;tjKB;(pG6EZ7<#61>PH6Pnd<0oRta!y6AW#frdaS}`0lc&gu~f2C6;%c&4goD) zGP@x_{5Y%0C9yA*QJ6Nn1KlPvTgL1GxE(eY^-y*?zBzU}hB6afov-j_KA?5pGu2PN z)eWqaUaP}>btur~VDb>ojYDM= z#k`G{?}@_tW-t8Gy+0VL4bc*{y@9ChgP#=)(AT{jG8q!?jz0-4G2c8Lg87#6K>{Ey zaC03_0L4LDt>FYv+|~{!0C1>Rd;q$JWw^?(T?lY^3j}hyy3TknprEANkDp+8OD2G@ zut6XwJ8R2fH^U>aj7Ps7@H^kZ_jJya&UglRG*Row%3M1H&J+B25z>RCrH`fu@mJuC zhIU2@Z5io-3~tXgpG6Z4?2n`{LB4$D|8qiuKI3NXkW$D|&1DB7)qGovG~y zkf#OGS+hStK*LO4X_20MgGDvUnR}J@aLCwS;B9w_XK78@dmU5y4AjAo_hn&&D4t7A zebBo_{2sJ(%eO&tZg`)L5VZr4&kAD2E8d91dt>~x)fU00J>4~j*GRx#2gwve9B14U zu{5o16KS1MPm9>){Ar|B#B)0bO4TagK*L~n{2;p0IKPW%@<3oAJ@WLZUB@K|iU)eq z=3oRCT}T#=&%sfF%>W;%+63in_Mi$DcWiOJga4*u{K*ofyW|}Z_-}|Epl-P?%%zN? z9fAx7_O4$?9IYxXZit`N2-63zx^2b1qvMfS)?XDJ?CRdAaeHN7c-mTLAx@#zS*rN`S`rbJ$ zJ3Oy2ZFWe(&*XSsmP3BIs55>BGr6C{E;3kga`7gt1|aJ;5SVgekWpPkGSLeeNK|p9 zK0Xjld8atLS1uAei|N)DVzUkEmiQ>NfR4CU%!mWg`Dqzx_?J>DkphA#o_sBxc&aDQ{2Uzr;Bl z#7p3{d^@y(o3m#EQTse%uOL>u;tCos7cJjD5$r4mlc`Otc*S_&7K>IrpKkBlEx5-R z`P7c5%!v(A37`vF5dQ__qAfFmeKWNMfYRvqK+Vb;++&w3U5zED1;&BmDyu6Mjqp(t zS#qIe{0o|O_zRF@6RE^+BaQy`QNs~5ou=G%j-&-@S1N?p5H3XJLdrtsNetSyO!Zd~ z=50urxzt0Z>mkzyC&+WfOcZ|#JscS9f3G`yJk5qIVhbWps3S6FOCpBq2$;ugMa+rB ztcp&cSlxzxEoMiy%h+n!5?~V7OOUIVASY$z#5PONMe$su1{)B`9tW^?K-GtbHSr-P zK9PyHr_B;rjL2xfAvLo*kZE&t1J!Q!1ghR|S+R3HoAa-C6Vr({UcN)3=fA|BKZXN@ zSn-MnQI2?P{J>PX3a|23)P7eV#2nW*XDnJsA>M4MAxvK|0{c1bAYBf3L!6*n`l>Zu z8mT#7>8EsgG@@%XV)AH&d5Vlhr`0i~JOY!+T*fWsWA9!DiT=rBjqW9UYXE?S}l0`^nij_E~%4D$ts zh=#t4Al$Qi0hB>=7nG>xfqoI_+DrHuWFgOh@uffF-EDq0zY$-Mxgl#*sWCjY9j)18X+ZSDYaiR!pR!p6h@%k-uD|3h|>sB zd;Uo|2Srx9@dH6y&n2w&6)r!xW{iv3|D0&yB46aR=2?qq~B z7{Si>sZh3qn)PjDX&6Zsys!?Jy+7i69>>0{tj;KuVr>u&9mzHHF^m~G6=H*siGxKe zJ2P#*fYBwL8CZiphQ{`Xq-H)3hk1gS

no1b8p0d5TzFnHMoL^Dq$Q_;rxC0kEVN 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 z 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 =Y%no;iUb_iNIkkU5P{g7jqFk_ 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 z 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%0DGUA^~Q9 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 z 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

Vc9xbzBwVkH|32cD0IN&d8uE?LkzV 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%0DnPk^EX@uYqIL5l6Kwr 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

Z3a5WWD`@Ptw3Wz7<{moIRzviT6p^+r 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%0AqJ;agJ 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 + + + + + diff --git a/CertificateInstaller/CertificateInstaller.csproj b/CertificateInstaller/CertificateInstaller.csproj new file mode 100644 index 00000000..234fe5b5 --- /dev/null +++ b/CertificateInstaller/CertificateInstaller.csproj @@ -0,0 +1,78 @@ + + + + + Debug + AnyCPU + {54BEC09A-B32F-4A66-A871-749E0621D822} + Exe + Properties + CertificateInstaller + CertificateInstaller + v4.5 + 512 + + false + ..\JexusManager\JexusManager.snk + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + false + + + AnyCPU + pdbonly + true + ..\bin\ + TRACE + prompt + 4 + false + + + app.manifest + + + + ..\packages\Mono.Options.4.4.0.0\lib\net4-client\Mono.Options.dll + True + + + + + + + + + + + + + NativeMethods.cs + + + + + + + + Designer + + + + + + \ No newline at end of file diff --git a/CertificateInstaller/Program.cs b/CertificateInstaller/Program.cs new file mode 100644 index 00000000..1ad3c859 --- /dev/null +++ b/CertificateInstaller/Program.cs @@ -0,0 +1,146 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System; + +namespace CertificateInstaller +{ + using System.Collections.Generic; + using System.Linq; + using System.Net; + using System.Security.Cryptography.X509Certificates; + + using Microsoft.Web.Administration; + + using Mono.Options; + + internal class Program + { + private static int Main(string[] args) + { + string p12File = null; + string p12Pwd = null; + string friendlyName = null; + string store = null; + string hash = null; + string address = null; + string port = null; + string id = null; + string host = null; + + OptionSet p = + new OptionSet().Add("f:", "File name", delegate (string v) { if (v != null) p12File = v; }) + .Add("p:", "Password", delegate (string v) { if (v != null) p12Pwd = v; }) + .Add("n:", "Friendly name", delegate (string v) { if (v != null) friendlyName = v; }) + .Add("s:", "Store name", delegate (string v) { if (v != null) store = v; }) + .Add("h:", "Certificate hash (not required when adding certificates)", delegate (string v) { if (v != null) hash = v; }) + .Add("a:", "IP address", delegate (string v) { if (v != null) address = v; }) + .Add("o:", "Port number", delegate (string v) { if (v != null) port = v; }) + .Add("i:", "Application ID", delegate (string v) { if (v != null) id = v; }) + .Add("x:", "SNI host name (not required when managing IP based bindings)", delegate (string v) { if (v != null) host = v; }); + + if (args.Length == 0) + { + ShowHelp(p); + return -1; + } + + List extra; + try + { + extra = p.Parse(args); + } + catch (OptionException ex) + { + Console.WriteLine(ex.Message); + return -1; + } + + if (extra.Count > 0) + { + ShowHelp(p); + return -1; + } + + try + { + X509Store personal = new X509Store(store, StoreLocation.LocalMachine); + personal.Open(OpenFlags.ReadWrite); + if (hash == null) + { + // add certificate + // http://paulstovell.com/blog/x509certificate2 + var x509 = new X509Certificate2( + p12File, + p12Pwd, + X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet + | X509KeyStorageFlags.MachineKeySet); + x509.FriendlyName = friendlyName; + personal.Add(x509); + personal.Close(); + return 0; + } + + var selectedItem = personal.Certificates.Find(X509FindType.FindByThumbprint, hash, false); + if (address == null) + { + if (host == null) + { + // remove certificate and mapping + var mappings = NativeMethods.QuerySslCertificateInfo(); + foreach (var mapping in mappings) + { + if (mapping.Hash.SequenceEqual(selectedItem[0].GetCertHash())) + { + NativeMethods.DeleteCertificateBinding(mapping.IpPort); + } + } + + personal.Remove(selectedItem[0]); + } + else + { + var mappings = NativeMethods.QuerySslSniInfo(); + foreach (var mapping in mappings) + { + if (mapping.Hash.SequenceEqual(selectedItem[0].GetCertHash())) + { + NativeMethods.DeleteSniBinding(new Tuple(mapping.Host, mapping.Port)); + } + } + } + + personal.Close(); + return 0; + } + + if (host == null) + { + // register mapping + var endpoint = new IPEndPoint(IPAddress.Parse(address), int.Parse(port)); + NativeMethods.BindCertificate(endpoint, selectedItem[0].GetCertHash(), store, Guid.Parse(id)); + } + else + { + NativeMethods.BindSni(new Tuple(host, int.Parse(port)), selectedItem[0].GetCertHash(), store, Guid.Parse(id)); + } + + return 0; + } + catch (Exception ex) + { + Console.WriteLine(ex); + return -1; + } + } + + private static void ShowHelp(OptionSet optionSet) + { + Console.WriteLine("Jexus Manager is available at https://jexus.codeplex.com"); + Console.WriteLine("CertificateInstaller.exe [Options]"); + Console.WriteLine("Options:"); + optionSet.WriteOptionDescriptions(Console.Out); + } + } +} diff --git a/CertificateInstaller/Properties/AssemblyInfo.cs b/CertificateInstaller/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..a4e98522 --- /dev/null +++ b/CertificateInstaller/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("CertificateInstaller")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("CertificateInstaller")] +[assembly: AssemblyCopyright("Copyright \u00A9 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("54bec09a-b32f-4a66-a871-749e0621d822")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/CertificateInstaller/app.manifest b/CertificateInstaller/app.manifest new file mode 100644 index 00000000..46701591 --- /dev/null +++ b/CertificateInstaller/app.manifest @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/CertificateInstaller/packages.config b/CertificateInstaller/packages.config new file mode 100644 index 00000000..8a52a680 --- /dev/null +++ b/CertificateInstaller/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/JexusManager.Features.Access/AccessFeature.cs b/JexusManager.Features.Access/AccessFeature.cs new file mode 100644 index 00000000..5d741ccd --- /dev/null +++ b/JexusManager.Features.Access/AccessFeature.cs @@ -0,0 +1,103 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Access +{ + using System; + using System.Diagnostics; + using System.Resources; + + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal class AccessFeature + { + public AccessFeature(Module module, ServerManager server, Application application) + { + this.Module = module; + this.Server = server; + this.Application = application; + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + + protected void DisplayErrorMessage(Exception ex, ResourceManager resourceManager) + { + var service = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + service.ShowError(ex, resourceManager.GetString("General"), "", false); + } + + protected object GetService(Type type) + { + return (this.Module as IServiceProvider).GetService(type); + } + + public void Load() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/security/access"); + this.SslFlags = (long)section["sslFlags"]; + + this.OnAccessSettingsSaved(); + } + + public string Directory { get; set; } + + protected void OnAccessSettingsSaved() + { + this.AccessSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210534"); + return false; + } + + public AccessSettingsSavedEventHandler AccessSettingsUpdated { get; set; } + public string Description { get; } + + public virtual bool IsFeatureEnabled + { + get { return true; } + } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public Module Module { get; } + public ServerManager Server { get; set; } + public Application Application { get; set; } + + public string Name + { + get { return "SSL Settings"; } + } + + + public long SslFlags { get; set; } + + public void CancelChanges() + { + this.Load(); + } + + public bool ApplyChanges() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/security/access"); + section["sslFlags"] = this.SslFlags; + service.ServerManager.CommitChanges(); + return true; + } + } +} diff --git a/JexusManager.Features.Access/AccessModule.cs b/JexusManager.Features.Access/AccessModule.cs new file mode 100644 index 00000000..58a959ea --- /dev/null +++ b/JexusManager.Features.Access/AccessModule.cs @@ -0,0 +1,24 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Access +{ + using System; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + using Properties; + + internal class AccessModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)this.GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(AccessPage), "SSL Settings", + "Specify requirements for SSL and client certificates.", + Resources.access_36, Resources.access_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.Access/AccessModuleProvider.cs b/JexusManager.Features.Access/AccessModuleProvider.cs new file mode 100644 index 00000000..7a422c22 --- /dev/null +++ b/JexusManager.Features.Access/AccessModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Access +{ + using System; + + using Microsoft.Web.Management.Server; + + public class AccessModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(this.Name, typeof(AccessModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return scope == ManagementScope.Site || scope == ManagementScope.Application; + } + } +} diff --git a/JexusManager.Features.Access/AccessPage.Designer.cs b/JexusManager.Features.Access/AccessPage.Designer.cs new file mode 100644 index 00000000..8fb9afb0 --- /dev/null +++ b/JexusManager.Features.Access/AccessPage.Designer.cs @@ -0,0 +1,283 @@ +namespace JexusManager.Features.Access +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class AccessPage + { + ///

+ /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.rbRequire = new System.Windows.Forms.RadioButton(); + this.rbAccept = new System.Windows.Forms.RadioButton(); + this.rbIgnore = new System.Windows.Forms.RadioButton(); + this.label4 = new System.Windows.Forms.Label(); + this.cbSSL = new System.Windows.Forms.CheckBox(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 5; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.SplitContainer1SplitterMoved); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.rbRequire); + this.panel2.Controls.Add(this.rbAccept); + this.panel2.Controls.Add(this.rbIgnore); + this.panel2.Controls.Add(this.label4); + this.panel2.Controls.Add(this.cbSSL); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 11; + // + // rbRequire + // + this.rbRequire.AutoSize = true; + this.rbRequire.Enabled = false; + this.rbRequire.Location = new System.Drawing.Point(29, 130); + this.rbRequire.Name = "rbRequire"; + this.rbRequire.Size = new System.Drawing.Size(62, 17); + this.rbRequire.TabIndex = 8; + this.rbRequire.TabStop = true; + this.rbRequire.Text = "Require"; + this.rbRequire.UseVisualStyleBackColor = true; + this.rbRequire.CheckedChanged += new System.EventHandler(this.CbSslCheckedChanged); + // + // rbAccept + // + this.rbAccept.AutoSize = true; + this.rbAccept.Enabled = false; + this.rbAccept.Location = new System.Drawing.Point(29, 107); + this.rbAccept.Name = "rbAccept"; + this.rbAccept.Size = new System.Drawing.Size(59, 17); + this.rbAccept.TabIndex = 7; + this.rbAccept.TabStop = true; + this.rbAccept.Text = "Accept"; + this.rbAccept.UseVisualStyleBackColor = true; + this.rbAccept.CheckedChanged += new System.EventHandler(this.CbSslCheckedChanged); + // + // rbIgnore + // + this.rbIgnore.AutoSize = true; + this.rbIgnore.Enabled = false; + this.rbIgnore.Location = new System.Drawing.Point(29, 84); + this.rbIgnore.Name = "rbIgnore"; + this.rbIgnore.Size = new System.Drawing.Size(55, 17); + this.rbIgnore.TabIndex = 6; + this.rbIgnore.TabStop = true; + this.rbIgnore.Text = "Ignore"; + this.rbIgnore.UseVisualStyleBackColor = true; + this.rbIgnore.CheckedChanged += new System.EventHandler(this.CbSslCheckedChanged); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(13, 56); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(90, 13); + this.label4.TabIndex = 5; + this.label4.Text = "Client certificates:"; + // + // cbSSL + // + this.cbSSL.AutoSize = true; + this.cbSSL.Enabled = false; + this.cbSSL.Location = new System.Drawing.Point(16, 21); + this.cbSSL.Name = "cbSSL"; + this.cbSSL.Size = new System.Drawing.Size(86, 17); + this.cbSSL.TabIndex = 4; + this.cbSSL.Text = "Require SSL"; + this.cbSSL.UseVisualStyleBackColor = true; + this.cbSSL.CheckedChanged += new System.EventHandler(this.CbSslCheckedChanged); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(407, 13); + this.label2.TabIndex = 1; + this.label2.Text = "This page lets you modify the SSL settings for the content of a website or applic" + + "ation."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 10; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(136, 25); + this.label3.TabIndex = 2; + this.label3.Text = "SSL Settings"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // AccessPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "AccessPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Panel panel2; + private PictureBox pictureBox1; + private CheckBox cbSSL; + private ContextMenuStrip cmsActionPanel; + private RadioButton rbRequire; + private RadioButton rbAccept; + private RadioButton rbIgnore; + private Label label4; + } +} diff --git a/JexusManager.Features.Access/AccessPage.cs b/JexusManager.Features.Access/AccessPage.cs new file mode 100644 index 00000000..4e182400 --- /dev/null +++ b/JexusManager.Features.Access/AccessPage.cs @@ -0,0 +1,198 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Access +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + using Microsoft.Web.Management.Server; + + using Binding = Microsoft.Web.Administration.Binding; + + internal partial class AccessPage : ModuleDialogPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly AccessPage _owner; + + public PageTaskList(AccessPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private AccessFeature _feature; + private bool _hasChanges; + private bool _initialized; + private TaskList _taskList; + + public AccessPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new AccessFeature(this.Module, null, null); + _feature.AccessSettingsUpdated = this.Refresh; + _feature.Load(); + base.Initialize(navigationData); + } + + protected override bool ShowHelp() + { + return _feature.ShowHelp(); + } + + private void SplitContainer1SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + protected override bool ApplyChanges() + { + long result = 0; + if (cbSSL.Checked) + { + result |= 8; + } + + if (rbAccept.Checked) + { + result |= 32; + } + + if (rbRequire.Checked) + { + result |= 64; + } + + _feature.SslFlags = result; + if (!_feature.ApplyChanges()) + { + return false; + } + + this.ClearChanges(); + return true; + } + + protected override void CancelChanges() + { + _feature.CancelChanges(); + this.ClearChanges(); + } + + protected override bool HasChanges + { + get { return _hasChanges; } + } + + protected override bool CanApplyChanges + { + get { return true; } + } + + private void InformChanges() + { + if (!_initialized) + { + return; + } + + _hasChanges = true; + this.Refresh(); + } + + private void ClearChanges() + { + _hasChanges = false; + this.Refresh(); + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + + protected override void OnRefresh() + { + if (!_hasChanges) + { + cbSSL.Checked = (_feature.SslFlags & 8) == 8; + rbAccept.Checked = (_feature.SslFlags & 32) == 32; + rbRequire.Checked = (_feature.SslFlags & 64) == 64; + rbIgnore.Checked = !rbAccept.Checked && !rbRequire.Checked; + + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + if (service.Scope == ManagementScope.Site) + { + var result = false; + foreach (Binding binding in service.Site.Bindings) + { + if (binding.Protocol == "https") + { + result = true; + break; + } + } + + cbSSL.Enabled = rbAccept.Enabled = rbIgnore.Enabled = rbRequire.Enabled = result; + } + else if (service.Scope == ManagementScope.Application) + { + var result = false; + foreach (Binding binding in service.Application.GetSite().Bindings) + { + if (binding.Protocol == "https") + { + result = true; + break; + } + } + + cbSSL.Enabled = rbAccept.Enabled = rbIgnore.Enabled = rbRequire.Enabled = result; + } + + _initialized = true; + } + + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + } + + private void CbSslCheckedChanged(object sender, EventArgs e) + { + InformChanges(); + } + } +} diff --git a/JexusManager.Features.Access/AccessPage.resx b/JexusManager.Features.Access/AccessPage.resx new file mode 100644 index 00000000..950be5d2 --- /dev/null +++ b/JexusManager.Features.Access/AccessPage.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 143, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.Access/AccessSettingsSavedEventHandler.cs b/JexusManager.Features.Access/AccessSettingsSavedEventHandler.cs new file mode 100644 index 00000000..2ddba5e9 --- /dev/null +++ b/JexusManager.Features.Access/AccessSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Access +{ + public delegate void AccessSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.Access/JexusManager.Features.Access.csproj b/JexusManager.Features.Access/JexusManager.Features.Access.csproj new file mode 100644 index 00000000..9e20662e --- /dev/null +++ b/JexusManager.Features.Access/JexusManager.Features.Access.csproj @@ -0,0 +1,103 @@ + + + + + Debug + AnyCPU + {B756B3A0-CFC8-4E71-A95A-0E9DC2A8D0C9} + Library + Properties + JexusManager.Features.Access + JexusManager.Features.Access + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + + + + + + + + + + + + + UserControl + + + AccessPage.cs + + + + + True + True + Resources.resx + + + + + AccessPage.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Access/JexusManager.snk b/JexusManager.Features.Access/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Access/Properties/AssemblyInfo.cs b/JexusManager.Features.Access/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..a17ac568 --- /dev/null +++ b/JexusManager.Features.Access/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.Access")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.Access")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("b756b3a0-cfc8-4e71-a95a-0e9dc2a8d0c9")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JexusManager.Features.Access/Properties/Resources.Designer.cs b/JexusManager.Features.Access/Properties/Resources.Designer.cs new file mode 100644 index 00000000..e8f2e853 --- /dev/null +++ b/JexusManager.Features.Access/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.Access.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.Access.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap access_36 { + get { + object obj = ResourceManager.GetObject("access_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.Access/Properties/Resources.resx b/JexusManager.Features.Access/Properties/Resources.resx new file mode 100644 index 00000000..19e92a4a --- /dev/null +++ b/JexusManager.Features.Access/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\access_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.Access/Resources/access_36.png b/JexusManager.Features.Access/Resources/access_36.png new file mode 100644 index 0000000000000000000000000000000000000000..4d27421d2d947efca36ac83294eeab44fcee9bdd GIT binary patch literal 2072 zcmV+z2;81(GG2gmKKx`(^O0dniyY{XpF{3B|hL2CTgM& zzKj@&m@$nn#9~BVKm`&L0VBo)j3Jh4l^BOYp-d~G(`kn?U%hwEIeV|=!#?u?Ogp#L z7tg&Xd!2pu+53Oif35#s_X<~eJo@N^o1=AqCCmJ07Z=On7^Qm?vXv$XCVY;=4SBT zyzrT@)0&)s$7fe-!c z`0?XzWAq$Cr`e%psMGx%$-K0LgP@3 z3~$@9ZPRTZxn)atPZv=moBB7o12^rzZhZX2w}BsAGaxgQ$A0zbJtKSeHrwqMi^U>S z=cdB%o_YGr?99y9Hf-pB?!NoJ|GqcA_gnYgIC=K1ClB3zXk_d5!G@|bvUgAKtFOFv z4{$$V*F@Ry@Q#Cc9;b$9%q2VF>&gR z*$~=Kbt)AW?Agi5safwcGVkf??s9n}-+j$7R2AjsJj=lh=N${}OLlQX>q4i1Hg4Q_ zpBB^T5U33Z^>uoY zmHsotMxNz_`ets^JAeF5Zl7P^pQ8`aS{KlBM;Pep-EgdD`v(VhoSN@eQ`8jIK;EeO zhi~5h3`EQfvxuo-C}xRVGp+9>d76Bw^xm&{Xy=aepTA*f>t|kld3I{_8^vv-hq-t~ zKu);3e`MeGc6*|`kxw%*@j8uWgSoj`Vki(d<((LaAP6F?X{WCsVoaQVojlK3n4e>C zAj{Oi=S6h+34fmsfHIHS?Hm3BES!uSU|ilHpuGSj#Hi%pmHk`unvkKD+)e_YLizRC1a$i{m$|6#hk)qgzcAEAg z4M8vgL(I%#{nl1*i-w7TGpOSUNw-YWxMVN+lK1tQIo3k7riYyOmYJDzW+ICBX3iT< z4Hd&ou$m?3KKpMyHgS0b(YGiK!)R(Pif^w_+f=yuFw$(UmA& zrp#7s!)o9iDzz#&FP5pQ^U=gPyaVSG9kw*NrirDds?IA+4RNVhe-~xZ@ZRt)Q78T? z0I3FI3}PlCUJ!hW6V;lsfLTlwuA(pXCCZlRRIB@JnKo6sI?7bjb^&Ub!D{V6S6WH5 zC3>_DZe>-Tz3ZdYNm0|*v4^}9%S6>VHRsfvH@r&|I#W~(sRL6{B(_kUgSddk7HA8L zEmW&Istqwiw1FqbiAS7t2*{u+-d0>GnHSX39$^To0gVe-m_@@yVwfd{dCbb1x`1j- zbdQ=6x?Jpem?2OkE0G5mW@LTUF}5 z6>#Y}h#u5Ia7jEnE6@})mQ(>}ViJjhQI_>Yj0zed#$;bE z%iaq}%7~BATnuC)c$_#@oL?y_k|!k + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.rbSpecific = new System.Windows.Forms.RadioButton(); + this.rbPool = new System.Windows.Forms.RadioButton(); + this.txtName = new System.Windows.Forms.TextBox(); + this.btnSet = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(7, 15); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(124, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Anonymous user identity:"; + // + // rbSpecific + // + this.rbSpecific.AutoSize = true; + this.rbSpecific.Location = new System.Drawing.Point(10, 42); + this.rbSpecific.Name = "rbSpecific"; + this.rbSpecific.Size = new System.Drawing.Size(89, 17); + this.rbSpecific.TabIndex = 1; + this.rbSpecific.TabStop = true; + this.rbSpecific.Text = "Specific user:"; + this.rbSpecific.UseVisualStyleBackColor = true; + // + // rbPool + // + this.rbPool.AutoSize = true; + this.rbPool.Location = new System.Drawing.Point(10, 111); + this.rbPool.Name = "rbPool"; + this.rbPool.Size = new System.Drawing.Size(136, 17); + this.rbPool.TabIndex = 2; + this.rbPool.TabStop = true; + this.rbPool.Text = "Application pool identity"; + this.rbPool.UseVisualStyleBackColor = true; + // + // txtName + // + this.txtName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtName.Location = new System.Drawing.Point(29, 74); + this.txtName.Name = "txtName"; + this.txtName.ReadOnly = true; + this.txtName.Size = new System.Drawing.Size(275, 20); + this.txtName.TabIndex = 3; + // + // btnSet + // + this.btnSet.Location = new System.Drawing.Point(310, 72); + this.btnSet.Name = "btnSet"; + this.btnSet.Size = new System.Drawing.Size(95, 23); + this.btnSet.TabIndex = 4; + this.btnSet.Text = "Set..."; + this.btnSet.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(313, 146); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(92, 23); + this.btnCancel.TabIndex = 5; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(217, 146); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 6; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // AnonymousEditDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(414, 181); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnSet); + this.Controls.Add(this.txtName); + this.Controls.Add(this.rbPool); + this.Controls.Add(this.rbSpecific); + this.Controls.Add(this.label1); + this.Name = "AnonymousEditDialog"; + this.Text = "Edit Anonymous Authentication Credentials"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.AnonymousEditDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label1; + private RadioButton rbSpecific; + private RadioButton rbPool; + private TextBox txtName; + private Button btnSet; + private Button btnCancel; + private Button btnOK; + } +} diff --git a/JexusManager.Features.Authentication/AnonymousEditDialog.cs b/JexusManager.Features.Authentication/AnonymousEditDialog.cs new file mode 100644 index 00000000..6220a769 --- /dev/null +++ b/JexusManager.Features.Authentication/AnonymousEditDialog.cs @@ -0,0 +1,98 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + using System.Reactive.Linq; + using System.Reactive.Disposables; + public partial class AnonymousEditDialog : DialogForm + { + public AnonymousEditDialog(IServiceProvider serviceProvider, AnonymousItem existing) + : base(serviceProvider) + { + InitializeComponent(); + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + rbPool.Checked = txtName.Text.Length == 0; + })); + + container.Add( + Observable.FromEventPattern(btnSet, "Click") + .Subscribe(evt => + { + var dialog = new CredentialsDialog(ServiceProvider, existing.Name); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + txtName.Text = dialog.UserName; + existing.Name = dialog.UserName; + existing.Password = dialog.Password; + SetButton(); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + DialogResult = DialogResult.OK; + if (rbPool.Checked) + { + existing.Name = string.Empty; + // TODO: reset password. + existing.Password = null; + } + + existing.Apply(); + })); + + container.Add( + Observable.FromEventPattern(rbPool, "CheckedChanged") + .Merge(Observable.FromEventPattern(rbSpecific, "CheckedChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnSet.Enabled = !rbPool.Checked; + SetButton(); + var toElevate = !rbPool.Checked; + if (toElevate) + { + NativeMethods.TryAddShieldToButton(btnOK); + } + else + { + NativeMethods.RemoveShieldFromButton(btnOK); + } + })); + + txtName.Text = "test"; // IMPORTANT: trigger a change event. + txtName.Text = existing.Name; + } + + private void SetButton() + { + // TODO: disable if not elevated. Need to find an in-place elevation approach. + btnOK.Enabled = rbPool.Checked || (txtName.Text.Length != 0 && NativeMethods.IsProcessElevated); + } + + private void AnonymousEditDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210461#Anonymous"); + } + } +} diff --git a/JexusManager.Features.Authentication/AnonymousEditDialog.resx b/JexusManager.Features.Authentication/AnonymousEditDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Authentication/AnonymousEditDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Authentication/AnonymousItem.cs b/JexusManager.Features.Authentication/AnonymousItem.cs new file mode 100644 index 00000000..61a66ae2 --- /dev/null +++ b/JexusManager.Features.Authentication/AnonymousItem.cs @@ -0,0 +1,29 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using Microsoft.Web.Administration; + + public class AnonymousItem + { + public ConfigurationElement Element { get; set; } + + public AnonymousItem(ConfigurationElement element) + { + this.Element = element; + Name = (string)element["userName"]; + Password = (string)element["password"]; + } + + public string Name { get; set; } + public string Password { get; set; } + + public void Apply() + { + Element["userName"] = this.Name; + Element["password"] = this.Password; + } + } +} \ No newline at end of file diff --git a/JexusManager.Features.Authentication/AuthenticationModule.cs b/JexusManager.Features.Authentication/AuthenticationModule.cs new file mode 100644 index 00000000..d61d8be7 --- /dev/null +++ b/JexusManager.Features.Authentication/AuthenticationModule.cs @@ -0,0 +1,22 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + using Properties; + + internal class AuthenticationModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(AuthenticationPage), "Authentication", "Configure authentication settings for sites and applications", Resources.authentication_36, Resources.authentication_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.Authentication/AuthenticationModuleProvider.cs b/JexusManager.Features.Authentication/AuthenticationModuleProvider.cs new file mode 100644 index 00000000..24a324b2 --- /dev/null +++ b/JexusManager.Features.Authentication/AuthenticationModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + + using Microsoft.Web.Management.Server; + + public class AuthenticationModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(Name, typeof(AuthenticationModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.Authentication/AuthenticationPage.Designer.cs b/JexusManager.Features.Authentication/AuthenticationPage.Designer.cs new file mode 100644 index 00000000..94144cbd --- /dev/null +++ b/JexusManager.Features.Authentication/AuthenticationPage.Designer.cs @@ -0,0 +1,286 @@ +namespace JexusManager.Features.Authentication +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class AuthenticationPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chStatus = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chResponse = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.toolStrip2 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel3 = new System.Windows.Forms.ToolStripLabel(); + this.cbGroup = new System.Windows.Forms.ToolStripComboBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + this.btnHelp = new System.Windows.Forms.ToolStripButton(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.panel2.SuspendLayout(); + this.toolStrip2.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.tsActionPanel.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 3; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.splitContainer1_SplitterMoved); + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 9; + this.pictureBox1.TabStop = false; + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.toolStrip2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 8; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chName, + this.chStatus, + this.chResponse}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 25); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 515); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListView1SelectedIndexChanged); + // + // chName + // + this.chName.Text = "Name"; + this.chName.Width = 200; + // + // chStatus + // + this.chStatus.Text = "Status"; + this.chStatus.Width = 100; + // + // chResponse + // + this.chResponse.Text = "Response Type"; + this.chResponse.Width = 150; + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // toolStrip2 + // + this.toolStrip2.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel3, + this.cbGroup}); + this.toolStrip2.Location = new System.Drawing.Point(0, 0); + this.toolStrip2.Name = "toolStrip2"; + this.toolStrip2.Size = new System.Drawing.Size(560, 25); + this.toolStrip2.TabIndex = 3; + this.toolStrip2.Text = "toolStrip2"; + // + // toolStripLabel3 + // + this.toolStripLabel3.Name = "toolStripLabel3"; + this.toolStripLabel3.Size = new System.Drawing.Size(59, 22); + this.toolStripLabel3.Text = "Group by:"; + // + // cbGroup + // + this.cbGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbGroup.Items.AddRange(new object[] { + "No Grouping", + "Category", + "Area"}); + this.cbGroup.Name = "cbGroup"; + this.cbGroup.Size = new System.Drawing.Size(121, 25); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(149, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Authentication"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.btnHelp}); + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // btnHelp + // + this.btnHelp.Name = "btnHelp"; + this.btnHelp.Size = new System.Drawing.Size(214, 4); + // + // AuthenticationPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "AuthenticationPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.toolStrip2.ResumeLayout(false); + this.toolStrip2.PerformLayout(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.tsActionPanel.ResumeLayout(false); + this.tsActionPanel.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private ListView listView1; + private ColumnHeader chName; + private ColumnHeader chStatus; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private ToolStripButton btnHelp; + private Label label3; + private PictureBox pictureBox1; + private Panel panel2; + private ToolStrip toolStrip2; + private ToolStripLabel toolStripLabel3; + private ToolStripComboBox cbGroup; + private ColumnHeader chResponse; + private ContextMenuStrip cmsActionPanel; + } +} diff --git a/JexusManager.Features.Authentication/AuthenticationPage.cs b/JexusManager.Features.Authentication/AuthenticationPage.cs new file mode 100644 index 00000000..ada0ae90 --- /dev/null +++ b/JexusManager.Features.Authentication/AuthenticationPage.cs @@ -0,0 +1,177 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Extensions; + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class AuthenticationPage : ModuleListPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly AuthenticationPage _owner; + + public PageTaskList(AuthenticationPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class AuthenticationListViewItem : ListViewItem + { + private readonly AuthenticationPage _page; + private readonly ListViewSubItem _status; + + public AuthenticationListViewItem(AuthenticationFeature feature, AuthenticationPage page) + : base(feature.Name) + { + _page = page; + Feature = feature; + _status = new ListViewSubItem(this, feature.IsEnabled ? "Enabled" : "Disabled"); + SubItems.Add(_status); + SubItems.Add(new ListViewSubItem(this, GetString(feature.AuthenticationType))); + feature.AuthenticationSettingsUpdated = AuthenticationSettingsUpdated; + } + + private void AuthenticationSettingsUpdated() + { + var service = _page.GetService(typeof(IConfigurationService)) as IConfigurationService; + service?.ServerManager.CommitChanges(); + + _status.Text = Feature.IsEnabled ? "Enabled" : "Disabled"; + _page.ListView1SelectedIndexChanged(ListView, EventArgs.Empty); + } + + private string GetString(AuthenticationType authenticationType) + { + switch (authenticationType) + { + case AuthenticationType.ChallengeBase: + case AuthenticationType.ClientCertificateBased: + return "HTTP 401 Challenge"; + case AuthenticationType.LoginRedirectBased: + return "HTTP 302 Login/Redirect"; + case AuthenticationType.Other: + return string.Empty; + default: + throw new ArgumentOutOfRangeException(nameof(authenticationType)); + } + } + + public AuthenticationFeature Feature { get; } + } + + private TaskList _taskList; + + public AuthenticationPage() + { + InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + var certificateFeature = new ClientCertificateAuthenticationFeature(Module); + listView1.Items.Add(new AuthenticationListViewItem(certificateFeature, this)); + + var anonymousFeature = new AnonymousAuthenticationFeature(Module); + listView1.Items.Add(new AuthenticationListViewItem(anonymousFeature, this)); + + var impersonationFeature = new ImpersonationFeature(Module); + listView1.Items.Add(new AuthenticationListViewItem(impersonationFeature, this)); + + var basicFeature = new BasicAuthenticationFeature(Module); + listView1.Items.Add(new AuthenticationListViewItem(basicFeature, this)); + + var digestFeature = new DigestAuthenticationFeature(Module); + listView1.Items.Add(new AuthenticationListViewItem(digestFeature, this)); + + var formsFeature = new FormsAuthenticationFeature(Module); + listView1.Items.Add(new AuthenticationListViewItem(formsFeature, this)); + + var windowsFeature = new WindowsAuthenticationFeature(Module); + listView1.Items.Add(new AuthenticationListViewItem(windowsFeature, this)); + + certificateFeature.Load(); + anonymousFeature.Load(); + impersonationFeature.Load(); + basicFeature.Load(); + digestFeature.Load(); + formsFeature.Load(); + windowsFeature.Load(); + + InitializeListPage(); + } + + protected override void InitializeListPage() + { + TaskList extra = null; + if (listView1.SelectedItems.Count != 0) + { + var item = (AuthenticationListViewItem)listView1.SelectedItems[0]; + extra = item.Feature.GetTaskList(); + } + + Tasks.Fill(tsActionPanel, cmsActionPanel, extra); + } + + private void ListView1SelectedIndexChanged(object sender, EventArgs e) + { + InitializeListPage(); + } + + protected override bool ShowHelp() + { + if (listView1.SelectedItems.Count == 0) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210461"); + return true; + } + + return ((AuthenticationListViewItem)listView1.SelectedItems[0]).Feature.ShowHelp(); + } + + private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + } +} diff --git a/JexusManager.Features.Authentication/AuthenticationPage.resx b/JexusManager.Features.Authentication/AuthenticationPage.resx new file mode 100644 index 00000000..3046fb13 --- /dev/null +++ b/JexusManager.Features.Authentication/AuthenticationPage.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 807, 17 + + + 702, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.Authentication/BasicAuthenticationFeature.cs b/JexusManager.Features.Authentication/BasicAuthenticationFeature.cs new file mode 100644 index 00000000..7cf619d7 --- /dev/null +++ b/JexusManager.Features.Authentication/BasicAuthenticationFeature.cs @@ -0,0 +1,145 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Extensions; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + internal class BasicAuthenticationFeature : AuthenticationFeature + { + private FeatureTaskList _taskList; + + private sealed class FeatureTaskList : TaskList + { + private readonly BasicAuthenticationFeature _owner; + + public FeatureTaskList(BasicAuthenticationFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + if (!_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Enable", "Enable", string.Empty).SetUsage()); + } + + if (_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Disable", "Disable", string.Empty).SetUsage()); + } + + result.Add(new MethodTaskItem("Edit", "Edit...", string.Empty).SetUsage()); + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Enable() + { + _owner.Enable(); + } + + [Obfuscation(Exclude = true)] + public void Disable() + { + _owner.Disable(); + } + + [Obfuscation(Exclude = true)] + public void Edit() + { + _owner.Edit(); + } + } + + public BasicAuthenticationFeature(Module module) : base(module) + { + } + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public override void Load() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/security/authentication/basicAuthentication"); + var basicEnabled = (bool)section["enabled"]; + SetEnabled(basicEnabled); + } + + private void Enable() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var basicSection = service.GetSection("system.webServer/security/authentication/basicAuthentication"); + basicSection["enabled"] = true; + service.ServerManager.CommitChanges(); + SetEnabled(true); + } + + private void Disable() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var basicSection = service.GetSection("system.webServer/security/authentication/basicAuthentication"); + basicSection["enabled"] = false; + service.ServerManager.CommitChanges(); + SetEnabled(false); + } + + private void Edit() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var basicSection = service.GetSection("system.webServer/security/authentication/basicAuthentication"); + var dialog = new BasicEditDialog(this.Module, new BasicItem(basicSection)); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + service.ServerManager.CommitChanges(); + OnAuthenticationSettingsSaved(); + } + + public override Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210461#Basic"); + return true; + } + + public override bool IsFeatureEnabled + { + get { return true; } + } + + public override AuthenticationType AuthenticationType + { + get { return AuthenticationType.ChallengeBase; } + } + + public override string Name + { + get { return "Basic Authentication"; } + } + } +} diff --git a/JexusManager.Features.Authentication/BasicEditDialog.Designer.cs b/JexusManager.Features.Authentication/BasicEditDialog.Designer.cs new file mode 100644 index 00000000..2ce880bd --- /dev/null +++ b/JexusManager.Features.Authentication/BasicEditDialog.Designer.cs @@ -0,0 +1,123 @@ +namespace JexusManager.Features.Authentication +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class BasicEditDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.txtDomain = new System.Windows.Forms.TextBox(); + this.txtRealm = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(257, 131); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(161, 131); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(13, 13); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(81, 13); + this.label1.TabIndex = 2; + this.label1.Text = "Default domain:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(13, 64); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(40, 13); + this.label2.TabIndex = 3; + this.label2.Text = "Realm:"; + // + // txtDomain + // + this.txtDomain.Location = new System.Drawing.Point(16, 29); + this.txtDomain.Name = "txtDomain"; + this.txtDomain.Size = new System.Drawing.Size(336, 20); + this.txtDomain.TabIndex = 4; + // + // txtRealm + // + this.txtRealm.Location = new System.Drawing.Point(16, 80); + this.txtRealm.Name = "txtRealm"; + this.txtRealm.Size = new System.Drawing.Size(336, 20); + this.txtRealm.TabIndex = 5; + // + // BasicEditDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(364, 166); + this.Controls.Add(this.txtRealm); + this.Controls.Add(this.txtDomain); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "BasicEditDialog"; + this.Text = "Edit Basic Authentication Settings"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.BasicEditDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label label1; + private Label label2; + private TextBox txtDomain; + private TextBox txtRealm; + } +} diff --git a/JexusManager.Features.Authentication/BasicEditDialog.cs b/JexusManager.Features.Authentication/BasicEditDialog.cs new file mode 100644 index 00000000..a8de342c --- /dev/null +++ b/JexusManager.Features.Authentication/BasicEditDialog.cs @@ -0,0 +1,43 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + using System.Reactive.Linq; + using System.Reactive.Disposables; + public partial class BasicEditDialog : DialogForm + { + public BasicEditDialog(IServiceProvider serviceProvider, BasicItem existing) + : base(serviceProvider) + { + InitializeComponent(); + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + txtDomain.Text = existing.Domain; + txtRealm.Text = existing.Realm; + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + existing.Domain = txtDomain.Text; + existing.Realm = txtRealm.Text; + existing.Apply(); + DialogResult = DialogResult.OK; + })); + } + + private void BasicEditDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210461#Basic"); + } + } +} diff --git a/JexusManager.Features.Authentication/BasicEditDialog.resx b/JexusManager.Features.Authentication/BasicEditDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Authentication/BasicEditDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Authentication/BasicItem.cs b/JexusManager.Features.Authentication/BasicItem.cs new file mode 100644 index 00000000..0da02a0f --- /dev/null +++ b/JexusManager.Features.Authentication/BasicItem.cs @@ -0,0 +1,29 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using Microsoft.Web.Administration; + + public class BasicItem + { + public ConfigurationElement Element { get; set; } + + public BasicItem(ConfigurationElement element) + { + this.Element = element; + Domain = (string)element["defaultLogonDomain"]; + Realm = (string)element["realm"]; + } + + public string Domain { get; set; } + public string Realm { get; set; } + + public void Apply() + { + Element["defaultLogonDomain"] = Domain; + Element["realm"] = Realm; + } + } +} \ No newline at end of file diff --git a/JexusManager.Features.Authentication/ClientCertificateAuthenticationFeature.cs b/JexusManager.Features.Authentication/ClientCertificateAuthenticationFeature.cs new file mode 100644 index 00000000..c7baf548 --- /dev/null +++ b/JexusManager.Features.Authentication/ClientCertificateAuthenticationFeature.cs @@ -0,0 +1,123 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Extensions; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + internal class ClientCertificateAuthenticationFeature : AuthenticationFeature + { + private sealed class FeatureTaskList : TaskList + { + private readonly ClientCertificateAuthenticationFeature _owner; + + public FeatureTaskList(ClientCertificateAuthenticationFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + if (!_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Enable", "Enable", string.Empty).SetUsage()); + } + + if (_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Disable", "Disable", string.Empty).SetUsage()); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Enable() + { + _owner.Enable(); + } + + [Obfuscation(Exclude = true)] + public void Disable() + { + _owner.Disable(); + } + } + + private FeatureTaskList _taskList; + + public ClientCertificateAuthenticationFeature(Module module) : base(module) + { + } + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public override void Load() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var anonymousSection = service.GetSection("system.webServer/security/authentication/clientCertificateMappingAuthentication"); + var anonymousEnabled = (bool)anonymousSection["enabled"]; + SetEnabled(anonymousEnabled); + } + + private void Enable() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var anonymousSection = service.GetSection("system.webServer/security/authentication/clientCertificateMappingAuthentication"); + anonymousSection["enabled"] = true; + service.ServerManager.CommitChanges(); + SetEnabled(true); + } + + private void Disable() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var anonymousSection = service.GetSection("system.webServer/security/authentication/clientCertificateMappingAuthentication"); + anonymousSection["enabled"] = false; + service.ServerManager.CommitChanges(); + SetEnabled(false); + } + + public override Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210461#Active_Directory"); + return true; + } + + public override bool IsFeatureEnabled + { + get { return true; } + } + + public override AuthenticationType AuthenticationType + { + get { return AuthenticationType.ClientCertificateBased; } + } + + public override string Name + { + get { return "Active Directory Client Certificate Authentication"; } + } + } +} \ No newline at end of file diff --git a/JexusManager.Features.Authentication/CredentialsDialog.Designer.cs b/JexusManager.Features.Authentication/CredentialsDialog.Designer.cs new file mode 100644 index 00000000..85db7cbd --- /dev/null +++ b/JexusManager.Features.Authentication/CredentialsDialog.Designer.cs @@ -0,0 +1,147 @@ +namespace JexusManager.Features.Authentication +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class CredentialsDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.txtPassword = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.txtConfirm = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(207, 176); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(111, 176); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(13, 13); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(61, 13); + this.label1.TabIndex = 2; + this.label1.Text = "User name:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(16, 29); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(286, 20); + this.txtName.TabIndex = 3; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(13, 67); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(56, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Password:"; + // + // txtPassword + // + this.txtPassword.Location = new System.Drawing.Point(16, 83); + this.txtPassword.Name = "txtPassword"; + this.txtPassword.PasswordChar = '*'; + this.txtPassword.Size = new System.Drawing.Size(286, 20); + this.txtPassword.TabIndex = 5; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(13, 122); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(93, 13); + this.label3.TabIndex = 6; + this.label3.Text = "Confirm password:"; + // + // txtConfirm + // + this.txtConfirm.Location = new System.Drawing.Point(16, 138); + this.txtConfirm.Name = "txtConfirm"; + this.txtConfirm.PasswordChar = '*'; + this.txtConfirm.Size = new System.Drawing.Size(286, 20); + this.txtConfirm.TabIndex = 7; + // + // CredentialsDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(314, 211); + this.Controls.Add(this.txtConfirm); + this.Controls.Add(this.label3); + this.Controls.Add(this.txtPassword); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtName); + this.Controls.Add(this.label1); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "CredentialsDialog"; + this.Text = "Set Credentials"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.CredentialsDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label label1; + private TextBox txtName; + private Label label2; + private TextBox txtPassword; + private Label label3; + private TextBox txtConfirm; + } +} diff --git a/JexusManager.Features.Authentication/CredentialsDialog.cs b/JexusManager.Features.Authentication/CredentialsDialog.cs new file mode 100644 index 00000000..be215090 --- /dev/null +++ b/JexusManager.Features.Authentication/CredentialsDialog.cs @@ -0,0 +1,60 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + using System.Reactive.Linq; + using System.Reactive.Disposables; + public partial class CredentialsDialog : DialogForm + { + public CredentialsDialog(IServiceProvider serviceProvider, string name) + : base(serviceProvider) + { + InitializeComponent(); + btnOK.Enabled = false; + txtName.Text = name; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Merge(Observable.FromEventPattern(txtPassword, "TextChanged")) + .Merge(Observable.FromEventPattern(txtConfirm, "TextChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text) + && !string.IsNullOrWhiteSpace(txtPassword.Text) + && txtConfirm.Text == txtPassword.Text; + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + UserName = txtName.Text; + Password = txtPassword.Text; + // TODO: verify user + // DialogResult = DialogResult.Cancel; + DialogResult = DialogResult.OK; + })); + } + + private void CredentialsDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210461#Anonymous"); + } + + public string Password { get; set; } + + public string UserName { get; set; } + } +} diff --git a/JexusManager.Features.Authentication/CredentialsDialog.resx b/JexusManager.Features.Authentication/CredentialsDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Authentication/CredentialsDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Authentication/DigestAuthenticationFeature.cs b/JexusManager.Features.Authentication/DigestAuthenticationFeature.cs new file mode 100644 index 00000000..0a2d4425 --- /dev/null +++ b/JexusManager.Features.Authentication/DigestAuthenticationFeature.cs @@ -0,0 +1,145 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Extensions; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + internal class DigestAuthenticationFeature : AuthenticationFeature + { + private FeatureTaskList _taskList; + + private sealed class FeatureTaskList : TaskList + { + private readonly DigestAuthenticationFeature _owner; + + public FeatureTaskList(DigestAuthenticationFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + if (!_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Enable", "Enable", string.Empty).SetUsage()); + } + + if (_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Disable", "Disable", string.Empty).SetUsage()); + } + + result.Add(new MethodTaskItem("Edit", "Edit...", string.Empty).SetUsage()); + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Enable() + { + _owner.Enable(); + } + + [Obfuscation(Exclude = true)] + public void Disable() + { + _owner.Disable(); + } + + [Obfuscation(Exclude = true)] + public void Edit() + { + _owner.Edit(); + } + } + + public DigestAuthenticationFeature(Module module) : base(module) + { + } + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public override void Load() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var digestSection = service.GetSection("system.webServer/security/authentication/digestAuthentication"); + var digestEnabled = (bool)digestSection["enabled"]; + SetEnabled(digestEnabled); + } + + private void Enable() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var digestSection = service.GetSection("system.webServer/security/authentication/digestAuthentication"); + digestSection["enabled"] = true; + service.ServerManager.CommitChanges(); + SetEnabled(true); + } + + private void Disable() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var digestSection = service.GetSection("system.webServer/security/authentication/digestAuthentication"); + digestSection["enabled"] = false; + service.ServerManager.CommitChanges(); + SetEnabled(false); + } + + private void Edit() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var digestSection = service.GetSection("system.webServer/security/authentication/digestAuthentication"); + var dialog = new DigestEditDialog(this.Module, new DigestItem(digestSection)); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + service.ServerManager.CommitChanges(); + OnAuthenticationSettingsSaved(); + } + + public override Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210461#Digest"); + return true; + } + + public override bool IsFeatureEnabled + { + get { return true; } + } + + public override AuthenticationType AuthenticationType + { + get { return AuthenticationType.ChallengeBase; } + } + + public override string Name + { + get { return "Digest Authentication"; } + } + } +} diff --git a/JexusManager.Features.Authentication/DigestEditDialog.Designer.cs b/JexusManager.Features.Authentication/DigestEditDialog.Designer.cs new file mode 100644 index 00000000..82333c42 --- /dev/null +++ b/JexusManager.Features.Authentication/DigestEditDialog.Designer.cs @@ -0,0 +1,101 @@ +namespace JexusManager.Features.Authentication +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class DigestEditDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.label2 = new System.Windows.Forms.Label(); + this.txtRealm = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(257, 79); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(161, 79); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(13, 12); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(40, 13); + this.label2.TabIndex = 3; + this.label2.Text = "Realm:"; + // + // txtRealm + // + this.txtRealm.Location = new System.Drawing.Point(16, 28); + this.txtRealm.Name = "txtRealm"; + this.txtRealm.Size = new System.Drawing.Size(336, 20); + this.txtRealm.TabIndex = 5; + // + // DigestEditDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(364, 116); + this.Controls.Add(this.txtRealm); + this.Controls.Add(this.label2); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "DigestEditDialog"; + this.Text = "Edit Digest Authentication Settings"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.BasicEditDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label label2; + private TextBox txtRealm; + } +} diff --git a/JexusManager.Features.Authentication/DigestEditDialog.cs b/JexusManager.Features.Authentication/DigestEditDialog.cs new file mode 100644 index 00000000..e4324f0f --- /dev/null +++ b/JexusManager.Features.Authentication/DigestEditDialog.cs @@ -0,0 +1,42 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + using System.Reactive.Disposables; + public partial class DigestEditDialog : DialogForm + { + public DigestEditDialog(IServiceProvider serviceProvider, DigestItem item) + : base(serviceProvider) + { + InitializeComponent(); + txtRealm.Text = item.Realm; + txtRealm.SelectAll(); + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + item.Realm = txtRealm.Text; + item.Apply(); + DialogResult = DialogResult.OK; + })); + } + + private void BasicEditDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210461#Digest"); + } + } +} diff --git a/JexusManager.Features.Authentication/DigestEditDialog.resx b/JexusManager.Features.Authentication/DigestEditDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Authentication/DigestEditDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Authentication/DigestItem.cs b/JexusManager.Features.Authentication/DigestItem.cs new file mode 100644 index 00000000..75738d58 --- /dev/null +++ b/JexusManager.Features.Authentication/DigestItem.cs @@ -0,0 +1,26 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using Microsoft.Web.Administration; + + public class DigestItem + { + public ConfigurationElement Element { get; set; } + + public DigestItem(ConfigurationElement element) + { + this.Element = element; + Realm = (string)element["realm"]; + } + + public string Realm { get; set; } + + public void Apply() + { + Element["realm"] = Realm; + } + } +} \ No newline at end of file diff --git a/JexusManager.Features.Authentication/FormsAuthenticationFeature.cs b/JexusManager.Features.Authentication/FormsAuthenticationFeature.cs new file mode 100644 index 00000000..94349ee0 --- /dev/null +++ b/JexusManager.Features.Authentication/FormsAuthenticationFeature.cs @@ -0,0 +1,146 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Extensions; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + internal class FormsAuthenticationFeature : AuthenticationFeature + { + private sealed class FeatureTaskList : TaskList + { + private readonly FormsAuthenticationFeature _owner; + + public FeatureTaskList(FormsAuthenticationFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + if (!_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Enable", "Enable", string.Empty).SetUsage()); + } + + if (_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Disable", "Disable", string.Empty).SetUsage()); + } + + result.Add(new MethodTaskItem("Edit", "Edit...", string.Empty).SetUsage()); + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Enable() + { + _owner.Enable(); + } + + [Obfuscation(Exclude = true)] + public void Disable() + { + _owner.Disable(); + } + + [Obfuscation(Exclude = true)] + public void Edit() + { + _owner.Edit(); + } + } + + private FeatureTaskList _taskList; + + public FormsAuthenticationFeature(Module module) + : base(module) + { + } + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public override void Load() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.web/authentication"); + var enabled = 3L == (long)section["mode"]; + this.SetEnabled(enabled); + } + + private void Enable() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.web/authentication"); + section["mode"] = "Forms"; + service.ServerManager.CommitChanges(); + this.SetEnabled(true); + } + + private void Disable() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.web/authentication"); + section["mode"] = "Windows"; + service.ServerManager.CommitChanges(); + this.SetEnabled(false); + } + + private void Edit() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.web/authentication"); + var dialog = new FormsEditDialog(this.Module, new FormsItem(section.GetChildElement("forms"))); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + service.ServerManager.CommitChanges(); + this.OnAuthenticationSettingsSaved(); + } + + public override Version MinimumFrameworkVersion + { + get { return FxVersion20; } + } + + public override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210461#Forms"); + return true; + } + + public override bool IsFeatureEnabled + { + get { return true; } + } + + public override AuthenticationType AuthenticationType + { + get { return AuthenticationType.LoginRedirectBased; } + } + + public override string Name + { + get { return "Forms Authentication"; } + } + } +} diff --git a/JexusManager.Features.Authentication/FormsEditDialog.Designer.cs b/JexusManager.Features.Authentication/FormsEditDialog.Designer.cs new file mode 100644 index 00000000..69629ff8 --- /dev/null +++ b/JexusManager.Features.Authentication/FormsEditDialog.Designer.cs @@ -0,0 +1,245 @@ +namespace JexusManager.Features.Authentication +{ + using System.Windows.Forms; + + partial class FormsEditDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.txtURL = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.txtTimeout = new System.Windows.Forms.TextBox(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.cbExpire = new System.Windows.Forms.CheckBox(); + this.cbSSL = new System.Windows.Forms.CheckBox(); + this.cbProtectedMode = new System.Windows.Forms.ComboBox(); + this.label5 = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.cbMode = new System.Windows.Forms.ComboBox(); + this.label3 = new System.Windows.Forms.Label(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(287, 396); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(191, 396); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 18); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(61, 13); + this.label1.TabIndex = 2; + this.label1.Text = "Login URL:"; + // + // txtURL + // + this.txtURL.Location = new System.Drawing.Point(12, 34); + this.txtURL.Name = "txtURL"; + this.txtURL.Size = new System.Drawing.Size(209, 20); + this.txtURL.TabIndex = 3; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 70); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(209, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Authentication cookie time-out (in minutes):"; + // + // txtTimeout + // + this.txtTimeout.Location = new System.Drawing.Point(12, 86); + this.txtTimeout.Name = "txtTimeout"; + this.txtTimeout.Size = new System.Drawing.Size(92, 20); + this.txtTimeout.TabIndex = 5; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.cbExpire); + this.groupBox1.Controls.Add(this.cbSSL); + this.groupBox1.Controls.Add(this.cbProtectedMode); + this.groupBox1.Controls.Add(this.label5); + this.groupBox1.Controls.Add(this.txtName); + this.groupBox1.Controls.Add(this.label4); + this.groupBox1.Controls.Add(this.cbMode); + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Location = new System.Drawing.Point(12, 112); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(370, 264); + this.groupBox1.TabIndex = 6; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Cookie settings"; + // + // cbExpire + // + this.cbExpire.AutoSize = true; + this.cbExpire.Location = new System.Drawing.Point(19, 224); + this.cbExpire.Name = "cbExpire"; + this.cbExpire.Size = new System.Drawing.Size(224, 17); + this.cbExpire.TabIndex = 7; + this.cbExpire.Text = "Extend cookie expiration on every request"; + this.cbExpire.UseVisualStyleBackColor = true; + // + // cbSSL + // + this.cbSSL.AutoSize = true; + this.cbSSL.Location = new System.Drawing.Point(19, 190); + this.cbSSL.Name = "cbSSL"; + this.cbSSL.Size = new System.Drawing.Size(86, 17); + this.cbSSL.TabIndex = 6; + this.cbSSL.Text = "Require SSL"; + this.cbSSL.UseVisualStyleBackColor = true; + // + // cbProtectedMode + // + this.cbProtectedMode.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbProtectedMode.FormattingEnabled = true; + this.cbProtectedMode.Items.AddRange(new object[] { + "Encryption and validation", + "None", + "Encryption", + "Validation"}); + this.cbProtectedMode.Location = new System.Drawing.Point(19, 153); + this.cbProtectedMode.Name = "cbProtectedMode"; + this.cbProtectedMode.Size = new System.Drawing.Size(176, 21); + this.cbProtectedMode.TabIndex = 5; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(16, 137); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(85, 13); + this.label5.TabIndex = 4; + this.label5.Text = "Protected mode:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(19, 97); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(176, 20); + this.txtName.TabIndex = 3; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(16, 81); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(38, 13); + this.label4.TabIndex = 2; + this.label4.Text = "Name:"; + // + // cbMode + // + this.cbMode.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbMode.FormattingEnabled = true; + this.cbMode.Items.AddRange(new object[] { + "Do not use cookies", + "Use cookies", + "Auto Detect", + "Use device profile"}); + this.cbMode.Location = new System.Drawing.Point(19, 43); + this.cbMode.Name = "cbMode"; + this.cbMode.Size = new System.Drawing.Size(176, 21); + this.cbMode.TabIndex = 1; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(16, 27); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(37, 13); + this.label3.TabIndex = 0; + this.label3.Text = "Mode:"; + // + // FormsEditDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(394, 431); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.txtTimeout); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtURL); + this.Controls.Add(this.label1); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "FormsEditDialog"; + this.Text = "Edit Forms Authentication Settings"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.FormsEditDialogHelpButtonClicked); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.Button btnOK; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox txtURL; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox txtTimeout; + private System.Windows.Forms.GroupBox groupBox1; + private System.Windows.Forms.CheckBox cbExpire; + private System.Windows.Forms.CheckBox cbSSL; + private System.Windows.Forms.ComboBox cbProtectedMode; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.TextBox txtName; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.ComboBox cbMode; + private System.Windows.Forms.Label label3; + } +} diff --git a/JexusManager.Features.Authentication/FormsEditDialog.cs b/JexusManager.Features.Authentication/FormsEditDialog.cs new file mode 100644 index 00000000..dbf90d3b --- /dev/null +++ b/JexusManager.Features.Authentication/FormsEditDialog.cs @@ -0,0 +1,98 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.ComponentModel; + +namespace JexusManager.Features.Authentication +{ + using System; + using System.Diagnostics; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + using System.Reactive.Disposables; + public partial class FormsEditDialog : DialogForm + { + public FormsEditDialog(IServiceProvider serviceProvider, FormsItem existing) + : base(serviceProvider) + { + InitializeComponent(); + + txtURL.Text = existing.LoginUrl; + txtTimeout.Text = TimeSpanExtensions.GetTotalMinutes(existing.Timeout).ToString(); + + cbMode.SelectedIndex = (int)existing.Mode; + txtName.Text = existing.Name; + cbProtectedMode.SelectedIndex = (int)existing.ProtectedMode; + cbSSL.Checked = existing.RequireSsl; + cbExpire.Checked = existing.SlidinngExpiration; + btnOK.Enabled = false; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + if (string.IsNullOrWhiteSpace(txtURL.Text)) + { + ShowMessage( + "You must specify a login page URL.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + int minutes; + if (!int.TryParse(txtTimeout.Text, out minutes)) + { + ShowMessage( + "You must specify a valid, positive integer for the authentication time-out.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + if (string.IsNullOrWhiteSpace(txtName.Text)) + { + ShowMessage( + "You must specify a cookie name.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + existing.LoginUrl = txtURL.Text; + existing.Timeout = new TimeSpan(0, 0, minutes, 0); + existing.Mode = cbMode.SelectedIndex; + existing.Name = txtName.Text; + existing.ProtectedMode = cbProtectedMode.SelectedIndex; + existing.RequireSsl = cbSSL.Checked; + existing.SlidinngExpiration = cbExpire.Checked; + existing.Apply(); + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(cbSSL, "CheckedChanged") + .Merge(Observable.FromEventPattern(txtURL, "TextChanged")) + .Merge(Observable.FromEventPattern(cbMode, "SelectedIndexChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = true; + })); + } + + private void FormsEditDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210461#Forms"); + } + } +} diff --git a/JexusManager.Features.Authentication/FormsEditDialog.resx b/JexusManager.Features.Authentication/FormsEditDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Authentication/FormsEditDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Authentication/FormsItem.cs b/JexusManager.Features.Authentication/FormsItem.cs new file mode 100644 index 00000000..70f01e0a --- /dev/null +++ b/JexusManager.Features.Authentication/FormsItem.cs @@ -0,0 +1,53 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + + using Microsoft.Web.Administration; + + + public class FormsItem + { + public ConfigurationElement Element { get; set; } + + public FormsItem(ConfigurationElement element) + { + this.Element = element; + LoginUrl = (string)element["loginUrl"]; + Timeout = (TimeSpan)element["timeout"]; + Mode = (long)element["cookieless"]; + Name = (string)element["name"]; + ProtectedMode = (long)element["protection"]; + RequireSsl = (bool)element["requireSSL"]; + SlidinngExpiration = (bool)element["slidingExpiration"]; + } + + public long Mode { get; set; } + + public long ProtectedMode { get; set; } + + public bool RequireSsl { get; set; } + + public bool SlidinngExpiration { get; set; } + + public string Name { get; set; } + + public TimeSpan Timeout { get; set; } + + public string LoginUrl { get; set; } + + public void Apply() + { + Element["loginUrl"] = LoginUrl; + Element["timeout"] = Timeout; + Element["cookieless"] = Mode; + Element["name"] = Name; + Element["protection"] = ProtectedMode; + Element["requireSSL"] = RequireSsl; + Element["slidingExpiration"] = SlidinngExpiration; + } + } +} diff --git a/JexusManager.Features.Authentication/ImpersonationEditDialog.Designer.cs b/JexusManager.Features.Authentication/ImpersonationEditDialog.Designer.cs new file mode 100644 index 00000000..36c3314f --- /dev/null +++ b/JexusManager.Features.Authentication/ImpersonationEditDialog.Designer.cs @@ -0,0 +1,144 @@ +namespace JexusManager.Features.Authentication +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class ImpersonationEditDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.rbSpecific = new System.Windows.Forms.RadioButton(); + this.rbPool = new System.Windows.Forms.RadioButton(); + this.txtName = new System.Windows.Forms.TextBox(); + this.btnSet = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(7, 15); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(116, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Identity to impersonate:"; + // + // rbSpecific + // + this.rbSpecific.AutoSize = true; + this.rbSpecific.Location = new System.Drawing.Point(10, 42); + this.rbSpecific.Name = "rbSpecific"; + this.rbSpecific.Size = new System.Drawing.Size(89, 17); + this.rbSpecific.TabIndex = 1; + this.rbSpecific.TabStop = true; + this.rbSpecific.Text = "Specific user:"; + this.rbSpecific.UseVisualStyleBackColor = true; + // + // rbPool + // + this.rbPool.AutoSize = true; + this.rbPool.Location = new System.Drawing.Point(10, 111); + this.rbPool.Name = "rbPool"; + this.rbPool.Size = new System.Drawing.Size(114, 17); + this.rbPool.TabIndex = 2; + this.rbPool.TabStop = true; + this.rbPool.Text = "Authenticated user"; + this.rbPool.UseVisualStyleBackColor = true; + // + // txtName + // + this.txtName.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtName.Location = new System.Drawing.Point(29, 74); + this.txtName.Name = "txtName"; + this.txtName.ReadOnly = true; + this.txtName.Size = new System.Drawing.Size(275, 20); + this.txtName.TabIndex = 3; + // + // btnSet + // + this.btnSet.Location = new System.Drawing.Point(310, 72); + this.btnSet.Name = "btnSet"; + this.btnSet.Size = new System.Drawing.Size(95, 23); + this.btnSet.TabIndex = 4; + this.btnSet.Text = "Set..."; + this.btnSet.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(313, 146); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(92, 23); + this.btnCancel.TabIndex = 5; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(217, 146); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 6; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // ImpersonationEditDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(414, 181); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnSet); + this.Controls.Add(this.txtName); + this.Controls.Add(this.rbPool); + this.Controls.Add(this.rbSpecific); + this.Controls.Add(this.label1); + this.Name = "ImpersonationEditDialog"; + this.Text = "Edit ASP.NET Impersonation Settings"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.AnonymousEditDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label1; + private RadioButton rbSpecific; + private RadioButton rbPool; + private TextBox txtName; + private Button btnSet; + private Button btnCancel; + private Button btnOK; + } +} diff --git a/JexusManager.Features.Authentication/ImpersonationEditDialog.cs b/JexusManager.Features.Authentication/ImpersonationEditDialog.cs new file mode 100644 index 00000000..2db3ee20 --- /dev/null +++ b/JexusManager.Features.Authentication/ImpersonationEditDialog.cs @@ -0,0 +1,99 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + using System.Reactive.Disposables; + + public partial class ImpersonationEditDialog : DialogForm + { + public ImpersonationEditDialog(IServiceProvider serviceProvider, ImpersonationItem existing) + : base(serviceProvider) + { + InitializeComponent(); + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + rbPool.Checked = txtName.Text.Length == 0; + })); + + container.Add( + Observable.FromEventPattern(btnSet, "Click") + .Subscribe(evt => + { + var dialog = new CredentialsDialog(ServiceProvider, existing.Name); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + txtName.Text = dialog.UserName; + existing.Name = dialog.UserName; + existing.Password = dialog.Password; + SetButton(); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + DialogResult = DialogResult.OK; + if (rbPool.Checked) + { + existing.Name = string.Empty; + // TODO: reset password. + existing.Password = null; + } + + existing.Apply(); + })); + + container.Add( + Observable.FromEventPattern(rbPool, "CheckedChanged") + .Merge(Observable.FromEventPattern(rbSpecific, "CheckedChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnSet.Enabled = !rbPool.Checked; + SetButton(); + var toElevate = !rbPool.Checked; + if (toElevate) + { + NativeMethods.TryAddShieldToButton(btnOK); + } + else + { + NativeMethods.RemoveShieldFromButton(btnOK); + } + })); + + txtName.Text = "test"; // IMPORTANT: trigger a change event. + txtName.Text = existing.Name; + } + + private void SetButton() + { + // TODO: disable if not elevated. Need to find an in-place elevation approach. + btnOK.Enabled = rbPool.Checked || (txtName.Text.Length != 0 && NativeMethods.IsProcessElevated); + } + + private void AnonymousEditDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210461#Impersonation"); + } + } +} diff --git a/JexusManager.Features.Authentication/ImpersonationEditDialog.resx b/JexusManager.Features.Authentication/ImpersonationEditDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Authentication/ImpersonationEditDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Authentication/ImpersonationFeature.cs b/JexusManager.Features.Authentication/ImpersonationFeature.cs new file mode 100644 index 00000000..a1a3775d --- /dev/null +++ b/JexusManager.Features.Authentication/ImpersonationFeature.cs @@ -0,0 +1,145 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Extensions; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + internal class ImpersonationFeature : AuthenticationFeature + { + private sealed class FeatureTaskList : TaskList + { + private readonly ImpersonationFeature _owner; + + public FeatureTaskList(ImpersonationFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + if (!_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Enable", "Enable", string.Empty).SetUsage()); + } + + if (_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Disable", "Disable", string.Empty).SetUsage()); + } + + result.Add(new MethodTaskItem("Edit", "Edit...", string.Empty).SetUsage()); + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Enable() + { + _owner.Enable(); + } + + [Obfuscation(Exclude = true)] + public void Disable() + { + _owner.Disable(); + } + + [Obfuscation(Exclude = true)] + public void Edit() + { + _owner.Edit(); + } + } + + private FeatureTaskList _taskList; + + public ImpersonationFeature(Module module) : base(module) + { + } + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public override void Load() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.web/identity"); + var enabled = (bool)section["impersonate"]; + SetEnabled(enabled); + } + + private void Enable() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.web/identity"); + section["impersonate"] = true; + service.ServerManager.CommitChanges(); + SetEnabled(true); + } + + private void Disable() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.web/identity"); + section["impersonate"] = false; + service.ServerManager.CommitChanges(); + SetEnabled(false); + } + + private void Edit() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.web/identity"); + var dialog = new ImpersonationEditDialog(this.Module, new ImpersonationItem(section)); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + service.ServerManager.CommitChanges(); + OnAuthenticationSettingsSaved(); + } + + public override Version MinimumFrameworkVersion + { + get { return FxVersion20; } + } + + public override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210461#Impersonation"); + return true; + } + + public override bool IsFeatureEnabled + { + get { return true; } + } + + public override AuthenticationType AuthenticationType + { + get { return AuthenticationType.Other; } + } + + public override string Name + { + get { return "ASP.NET Impersonation"; } + } + } +} diff --git a/JexusManager.Features.Authentication/ImpersonationItem.cs b/JexusManager.Features.Authentication/ImpersonationItem.cs new file mode 100644 index 00000000..4a3dad2e --- /dev/null +++ b/JexusManager.Features.Authentication/ImpersonationItem.cs @@ -0,0 +1,29 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using Microsoft.Web.Administration; + + public class ImpersonationItem + { + public ConfigurationElement Element { get; set; } + + public ImpersonationItem(ConfigurationElement element) + { + this.Element = element; + Name = (string)element["userName"]; + Password = (string)element["password"]; + } + + public string Name { get; set; } + public string Password { get; set; } + + public void Apply() + { + Element["userName"] = this.Name; + Element["password"] = this.Password; + } + } +} diff --git a/JexusManager.Features.Authentication/JexusManager.Features.Authentication.csproj b/JexusManager.Features.Authentication/JexusManager.Features.Authentication.csproj new file mode 100644 index 00000000..6bde76f9 --- /dev/null +++ b/JexusManager.Features.Authentication/JexusManager.Features.Authentication.csproj @@ -0,0 +1,204 @@ + + + + + Debug + AnyCPU + {AA7CCFC5-B695-4773-BA79-77CF6C36908F} + Library + Properties + JexusManager.Features.Authentication + JexusManager.Features.Authentication + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + + form + + + AnonymousEditDialog.cs + + + + + + UserControl + + + AuthenticationPage.cs + + + + Form + + + BasicEditDialog.cs + + + + + form + + + CredentialsDialog.cs + + + + Form + + + DigestEditDialog.cs + + + + + Form + + + FormsEditDialog.cs + + + + form + + + ImpersonationEditDialog.cs + + + + + + True + True + Resources.resx + + + + Form + + + ProvidersDialog.cs + + + Form + + + WindowsAdvancedDialog.cs + + + + + + + AnonymousEditDialog.cs + + + AuthenticationPage.cs + + + BasicEditDialog.cs + + + CredentialsDialog.cs + + + DigestEditDialog.cs + + + FormsEditDialog.cs + + + ImpersonationEditDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + ProvidersDialog.cs + + + WindowsAdvancedDialog.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Authentication/JexusManager.snk b/JexusManager.Features.Authentication/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Authentication/Properties/AssemblyInfo.cs b/JexusManager.Features.Authentication/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..89c86fd1 --- /dev/null +++ b/JexusManager.Features.Authentication/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.Authentication")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.Authentication")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("aa7ccfc5-b695-4773-ba79-77cf6c36908f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JexusManager.Features.Authentication/Properties/Resources.Designer.cs b/JexusManager.Features.Authentication/Properties/Resources.Designer.cs new file mode 100644 index 00000000..74533dfa --- /dev/null +++ b/JexusManager.Features.Authentication/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.Authentication.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.Authentication.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap authentication_36 { + get { + object obj = ResourceManager.GetObject("authentication_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.Authentication/Properties/Resources.resx b/JexusManager.Features.Authentication/Properties/Resources.resx new file mode 100644 index 00000000..d37ef7c2 --- /dev/null +++ b/JexusManager.Features.Authentication/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\authentication_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.Authentication/ProviderItem.cs b/JexusManager.Features.Authentication/ProviderItem.cs new file mode 100644 index 00000000..3c9211b0 --- /dev/null +++ b/JexusManager.Features.Authentication/ProviderItem.cs @@ -0,0 +1,31 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using Microsoft.Web.Administration; + + public class ProviderItem + { + public ConfigurationElement Element { get; set; } + + public ProviderItem(ConfigurationElement element) + { + this.Element = element; + if (element == null) + { + return; + } + + this.Value = (string)element["value"]; + } + + public string Value { get; set; } + + public void Apply() + { + Element["value"] = Value; + } + } +} diff --git a/JexusManager.Features.Authentication/ProvidersDialog.Designer.cs b/JexusManager.Features.Authentication/ProvidersDialog.Designer.cs new file mode 100644 index 00000000..8d78cffc --- /dev/null +++ b/JexusManager.Features.Authentication/ProvidersDialog.Designer.cs @@ -0,0 +1,186 @@ +namespace JexusManager.Features.Authentication +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class ProvidersDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.lbProviders = new System.Windows.Forms.ListBox(); + this.btnUp = new System.Windows.Forms.Button(); + this.btnDown = new System.Windows.Forms.Button(); + this.btnRemove = new System.Windows.Forms.Button(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.cbAvailable = new System.Windows.Forms.ComboBox(); + this.btnAdd = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(14, 18); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(96, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Enabled Providers:"; + // + // lbProviders + // + this.lbProviders.FormattingEnabled = true; + this.lbProviders.Location = new System.Drawing.Point(17, 34); + this.lbProviders.Name = "lbProviders"; + this.lbProviders.Size = new System.Drawing.Size(290, 108); + this.lbProviders.TabIndex = 1; + // + // btnUp + // + this.btnUp.Location = new System.Drawing.Point(316, 34); + this.btnUp.Name = "btnUp"; + this.btnUp.Size = new System.Drawing.Size(85, 23); + this.btnUp.TabIndex = 2; + this.btnUp.Text = "Move Up"; + this.btnUp.UseVisualStyleBackColor = true; + // + // btnDown + // + this.btnDown.Location = new System.Drawing.Point(316, 64); + this.btnDown.Name = "btnDown"; + this.btnDown.Size = new System.Drawing.Size(85, 23); + this.btnDown.TabIndex = 3; + this.btnDown.Text = "Move Down"; + this.btnDown.UseVisualStyleBackColor = true; + // + // btnRemove + // + this.btnRemove.Location = new System.Drawing.Point(316, 94); + this.btnRemove.Name = "btnRemove"; + this.btnRemove.Size = new System.Drawing.Size(85, 23); + this.btnRemove.TabIndex = 4; + this.btnRemove.Text = "Remove"; + this.btnRemove.UseVisualStyleBackColor = true; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(14, 154); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(314, 26); + this.label2.TabIndex = 5; + this.label2.Text = "Select a provider from the list of available providers and click Add\r\nto add it t" + + "o the enabled providers."; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(14, 198); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(100, 13); + this.label3.TabIndex = 6; + this.label3.Text = "Available Providers:"; + // + // cbAvailable + // + this.cbAvailable.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbAvailable.FormattingEnabled = true; + this.cbAvailable.Location = new System.Drawing.Point(17, 214); + this.cbAvailable.Name = "cbAvailable"; + this.cbAvailable.Size = new System.Drawing.Size(290, 21); + this.cbAvailable.TabIndex = 7; + // + // btnAdd + // + this.btnAdd.Location = new System.Drawing.Point(316, 212); + this.btnAdd.Name = "btnAdd"; + this.btnAdd.Size = new System.Drawing.Size(85, 23); + this.btnAdd.TabIndex = 8; + this.btnAdd.Text = "Add"; + this.btnAdd.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(312, 281); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 9; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(216, 281); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 10; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // ProvidersDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(419, 316); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnAdd); + this.Controls.Add(this.cbAvailable); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.btnRemove); + this.Controls.Add(this.btnDown); + this.Controls.Add(this.btnUp); + this.Controls.Add(this.lbProviders); + this.Controls.Add(this.label1); + this.Name = "ProvidersDialog"; + this.Text = "Providers"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label1; + private ListBox lbProviders; + private Button btnUp; + private Button btnDown; + private Button btnRemove; + private Label label2; + private Label label3; + private ComboBox cbAvailable; + private Button btnAdd; + private Button btnCancel; + private Button btnOK; + } +} diff --git a/JexusManager.Features.Authentication/ProvidersDialog.cs b/JexusManager.Features.Authentication/ProvidersDialog.cs new file mode 100644 index 00000000..881172fa --- /dev/null +++ b/JexusManager.Features.Authentication/ProvidersDialog.cs @@ -0,0 +1,123 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + using System.Reactive.Disposables; + public partial class ProvidersDialog : DialogForm + { + private readonly string[] _allProviders = { "Negotiate", "NTLM", "Negotiate:Kerberos" }; + + public ProvidersDialog(IServiceProvider serviceProvider, WindowsItem item) + : base(serviceProvider) + { + InitializeComponent(); + foreach (var provider in item.Providers) + { + lbProviders.Items.Add(provider.Value); + } + + foreach (var each in _allProviders) + { + if (!lbProviders.Items.Contains(each)) + { + cbAvailable.Items.Add(each); + } + } + + btnOK.Enabled = false; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnRemove, "Click") + .Subscribe(evt => + { + cbAvailable.Items.Add(lbProviders.SelectedItem); + lbProviders.Items.Remove(lbProviders.SelectedItem); + cbAvailable.Enabled = true; + btnOK.Enabled = true; + })); + + var add = Observable.FromEventPattern(btnAdd, "Click"); + var load = Observable.FromEventPattern(this, "Load"); + container.Add( + add.Subscribe(evt => + { + var selected = cbAvailable.Text; + lbProviders.Items.Add(selected); + cbAvailable.Items.RemoveAt(cbAvailable.SelectedIndex); + cbAvailable.SelectedIndex = -1; + btnOK.Enabled = true; + })); + + container.Add( + Observable.FromEventPattern(cbAvailable, "SelectedIndexChanged") + .Merge(load) + .Merge(add) + .Subscribe(evt => + { + btnAdd.Enabled = cbAvailable.SelectedIndex > -1; + if (cbAvailable.Items.Count == 0) + { + cbAvailable.Enabled = false; + } + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + item.Providers.Clear(); + foreach (string provider in lbProviders.Items) + { + item.Providers.Add(new ProviderItem(null) { Value = provider }); + } + + item.Apply(); + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(lbProviders, "SelectedIndexChanged") + .Merge(load) + .Subscribe(evt => + { + btnRemove.Enabled = lbProviders.SelectedIndex > -1; + btnUp.Enabled = lbProviders.SelectedIndex > 0; + btnDown.Enabled = lbProviders.SelectedIndex > -1 && lbProviders.SelectedIndex < lbProviders.Items.Count - 1; + })); + + container.Add( + Observable.FromEventPattern(btnUp, "Click") + .Subscribe(evt => + { + var current = lbProviders.SelectedItem; + var up = lbProviders.SelectedIndex - 1; + lbProviders.Items.RemoveAt(lbProviders.SelectedIndex); + lbProviders.Items.Insert(up, current); + lbProviders.SelectedIndex = up; + btnOK.Enabled = true; + })); + + container.Add( + Observable.FromEventPattern(btnDown, "Click") + .Subscribe(evt => + { + var current = lbProviders.SelectedItem; + var down = lbProviders.SelectedIndex + 1; + lbProviders.Items.RemoveAt(lbProviders.SelectedIndex); + lbProviders.Items.Insert(down, current); + lbProviders.SelectedIndex = down; + btnOK.Enabled = true; + })); + } + } +} diff --git a/JexusManager.Features.Authentication/ProvidersDialog.resx b/JexusManager.Features.Authentication/ProvidersDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Authentication/ProvidersDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Authentication/Resources/authentication_36.png b/JexusManager.Features.Authentication/Resources/authentication_36.png new file mode 100644 index 0000000000000000000000000000000000000000..93d30564a48615995e449f87ead4388b5691b8c7 GIT binary patch literal 2261 zcmV;`2rBo9P) z&ScJS{?Gq;=6Mc$ygqn|t$y%3H~HsTxZg%_z@P(RM9&EGM=jO;KYTnr{67P_^;Yb; zxb#4^QoU*C+~jz*R77h{n&&iIA;(r4t8o-PRJk(x=D~yLj|$|R4S23sdSut)j_c>A z#{y&wCPNy9)+rTVu{c{F-)Kc&I{tiP0>aOKR3Q6DG?&%9I2j*C(X+qSW73rh%u z5U4z+QY{7FzfE4XZz0%YyX?21Dvfy8sQi)Zoc2><3m!WokP&7f2!g82GqmfWlq5+q za$Ay1iBbx!HQE@AF({dF-h?$YH!}M8@Z@5lSRM6+02#Llo5$~Xw&}0^{kzE*_uboh z;ao$8)`~38Nz#lcPUwUo?M|0oFD6MdvMeXhB>*$qGA`OZZ!cW_x!SggMc;FM9HH@C zo8i%^>h{IGi>_Du{nPi3+YIo8^3Bq1P zr`uPj-RaWlhJ?KyyV`d}Qj|Qy(AXSCrU=`|a!c637HT{~paTb(J>tvTkG8wcW|-p^YvfXqW*JiUePdY;wMv0f zWeA-|U^Ezokts%{U}XP23}%pEMn)8Znq|q_%$Bok|Be2l?TaTay?oDXv$??=Z>>-d zD@@miDf$i=gAjr^mGq(p0*#RoI`5&97DlUnQe<6p-owZQBeOn`(FohJv}2XF1a#m4 zHQV7&mtArGY@95kX%p2AN3)1N0xN(tTH-jg3;(K1OXu8x^*FQG1w;LNr zv1~8~EE~!dK^nCw6cw&#^;22ItoI}f_-M1Wj5eV4$*q(j%W^yq3I*_eK^o_zS&^R|`7Ey;Swa-*fIuaisARJr zI->!B9gNXS1urdS)}621`L`_r8O#lpa!Djfh*F>w=)tKJND1zF^{nRgx_KRb6mgUWuL&tI+)^`S=*2KMf;w~>9OH% z*dWWmvB4ODVUW@0)LjD}? z=O4}&SnE2>PmfkMHaj<$cU}8X`;8}CXYx=0L`Dnptlvv21wt4^Uv7*zqVU#<$4t?>ttw@0wqBzgH(o2Jce7m0402SaYkQ4SnFD(&Itcp z^Vzw$n}t1lsg6vsnv`i}1y&jz0HRb9Ws=E>ksWg-|Ep*6kbL)8{@~kh9dB)`OkmsY zppczn?t!O{hSyV{oM*iiVT{2Tg)xdaPU%KD$GaAh38>fWyuB%~-2#n`4qCk*cf)2o zqCQd$T+6=uOdiTRP4eL}kTSk($J|ce^?Zb7VOb82T zvJZ>nKEHitiKW#LqZLMLjM4ocpbd^KFk0oo)O8Oxk36w?x}G{cepLS}DCNto*2cwY zf^zHtn*d=7Mwo&Yrl8l7D@0Hk65S|6WigiR^kZi9Krv08=Ulz3!mplOB1*E8Fj}Fq z7=#6Aik{^(yV29F!%w_+x=O8p)k81pUqklj^p3{)<;vy-!Z552p3ykQU^{!nmj$L` zRF2j;mXa7D`juGpjeq#PHp}ZR)|=4@<@(BKgyoQj8yIH<%M-4!tn%4f*f!8U_6`lu zhkznb09?SCpO>Gsg}z9pA+{T!l{^7r24||^`8PJvN&Z_sYL^-W6>4RuBxYk$6(iydaVR<9# ztUUMN_wuL_ZUyK++H9cQJ@(?dUBB{E9agOtx07ih3+Wfw~#rlOeI(~Uk2&-(2a==&^ zW4%8vAcRI(N(f6TnJj0$^%vT&KlWH2wby_(Ao9fP{00000NkvXXu0mjf_9|8q literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Authentication/WindowsAdvancedDialog.Designer.cs b/JexusManager.Features.Authentication/WindowsAdvancedDialog.Designer.cs new file mode 100644 index 00000000..b616a482 --- /dev/null +++ b/JexusManager.Features.Authentication/WindowsAdvancedDialog.Designer.cs @@ -0,0 +1,137 @@ +namespace JexusManager.Features.Authentication +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class WindowsAdvancedDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(WindowsAdvancedDialog)); + this.label1 = new System.Windows.Forms.Label(); + this.cbExtended = new System.Windows.Forms.ComboBox(); + this.cbKernelMode = new System.Windows.Forms.CheckBox(); + this.textBox1 = new System.Windows.Forms.TextBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(13, 13); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(106, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Extended Protection:"; + // + // cbExtended + // + this.cbExtended.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbExtended.FormattingEnabled = true; + this.cbExtended.Items.AddRange(new object[] { + "Off", + "Accept", + "Required"}); + this.cbExtended.Location = new System.Drawing.Point(16, 39); + this.cbExtended.Name = "cbExtended"; + this.cbExtended.Size = new System.Drawing.Size(121, 21); + this.cbExtended.TabIndex = 1; + // + // cbKernelMode + // + this.cbKernelMode.AutoSize = true; + this.cbKernelMode.Checked = true; + this.cbKernelMode.CheckState = System.Windows.Forms.CheckState.Checked; + this.cbKernelMode.Location = new System.Drawing.Point(16, 89); + this.cbKernelMode.Name = "cbKernelMode"; + this.cbKernelMode.Size = new System.Drawing.Size(191, 17); + this.cbKernelMode.TabIndex = 2; + this.cbKernelMode.Text = "Enable Kernel-mode authentication"; + this.cbKernelMode.UseVisualStyleBackColor = true; + // + // textBox1 + // + this.textBox1.Location = new System.Drawing.Point(16, 112); + this.textBox1.Multiline = true; + this.textBox1.Name = "textBox1"; + this.textBox1.ReadOnly = true; + this.textBox1.ScrollBars = System.Windows.Forms.ScrollBars.Vertical; + this.textBox1.Size = new System.Drawing.Size(461, 158); + this.textBox1.TabIndex = 3; + this.textBox1.Text = resources.GetString("textBox1.Text"); + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(286, 301); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 4; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(382, 301); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 5; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // WindowsAdvancedDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(489, 336); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.textBox1); + this.Controls.Add(this.cbKernelMode); + this.Controls.Add(this.cbExtended); + this.Controls.Add(this.label1); + this.Name = "WindowsAdvancedDialog"; + this.Text = "Advanced Settings"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.WindowsAdvancedDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label1; + private ComboBox cbExtended; + private CheckBox cbKernelMode; + private TextBox textBox1; + private Button btnOK; + private Button btnCancel; + } +} diff --git a/JexusManager.Features.Authentication/WindowsAdvancedDialog.cs b/JexusManager.Features.Authentication/WindowsAdvancedDialog.cs new file mode 100644 index 00000000..32385002 --- /dev/null +++ b/JexusManager.Features.Authentication/WindowsAdvancedDialog.cs @@ -0,0 +1,58 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using Microsoft.Web.Management.Client.Win32; + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + public partial class WindowsAdvancedDialog : DialogForm + { + public WindowsAdvancedDialog(IServiceProvider serviceProvider, WindowsItem item) + : base(serviceProvider) + { + InitializeComponent(); + btnOK.Enabled = false; + cbExtended.SelectedIndex = item.TokenChecking; + cbKernelMode.Checked = item.UseKernelMode; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(cbExtended, "SelectedIndexChanged") + .Subscribe(evt => + { + btnOK.Enabled = true; + })); + + container.Add( + Observable.FromEventPattern(cbKernelMode, "CheckedChanged") + .Subscribe(evt => + { + btnOK.Enabled = true; + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + item.TokenChecking = cbExtended.SelectedIndex; + item.UseKernelMode = cbKernelMode.Checked; + item.Apply(); + DialogResult = DialogResult.OK; + })); + } + + private void WindowsAdvancedDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210461#Advanced_Windows"); + } + } +} diff --git a/JexusManager.Features.Authentication/WindowsAdvancedDialog.resx b/JexusManager.Features.Authentication/WindowsAdvancedDialog.resx new file mode 100644 index 00000000..cab860cb --- /dev/null +++ b/JexusManager.Features.Authentication/WindowsAdvancedDialog.resx @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + By default, IIS enables kernel-mode authentication, which may improve authentication performance and prevent authentication problems with application pools configured to use a custom identity. As a best practice, do not disable this setting if Kerberos authentication is used in your environment and the application pool is configured to use a custom identity. + + \ No newline at end of file diff --git a/JexusManager.Features.Authentication/WindowsAuthenticationFeature.cs b/JexusManager.Features.Authentication/WindowsAuthenticationFeature.cs new file mode 100644 index 00000000..4757ff34 --- /dev/null +++ b/JexusManager.Features.Authentication/WindowsAuthenticationFeature.cs @@ -0,0 +1,167 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Extensions; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + internal class WindowsAuthenticationFeature : AuthenticationFeature + { + private FeatureTaskList _taskList; + + private sealed class FeatureTaskList : TaskList + { + private readonly WindowsAuthenticationFeature _owner; + + public FeatureTaskList(WindowsAuthenticationFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + if (!_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Enable", "Enable", string.Empty).SetUsage()); + } + + if (_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Disable", "Disable", string.Empty).SetUsage()); + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Edit", "Advanced Settings...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Providers", "Providers...", string.Empty).SetUsage()); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Enable() + { + _owner.Enable(); + } + + [Obfuscation(Exclude = true)] + public void Disable() + { + _owner.Disable(); + } + + [Obfuscation(Exclude = true)] + public void Edit() + { + _owner.Edit(); + } + + [Obfuscation(Exclude = true)] + public void Providers() + { + _owner.Providers(); + } + } + + public WindowsAuthenticationFeature(Module module) : base(module) + { + } + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public override void Load() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var windowsSection = service.GetSection("system.webServer/security/authentication/windowsAuthentication"); + var windowsEnabled = (bool)windowsSection["enabled"]; + SetEnabled(windowsEnabled); + } + + private void Enable() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var windowsSection = service.GetSection("system.webServer/security/authentication/windowsAuthentication"); + windowsSection["enabled"] = true; + service.ServerManager.CommitChanges(); + SetEnabled(true); + } + + private void Disable() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var windowsSection = service.GetSection("system.webServer/security/authentication/windowsAuthentication"); + windowsSection["enabled"] = false; + service.ServerManager.CommitChanges(); + SetEnabled(false); + } + + private void Edit() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var windowsSection = service.GetSection("system.webServer/security/authentication/windowsAuthentication"); + var dialog = new WindowsAdvancedDialog(Module, new WindowsItem(windowsSection)); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + service.ServerManager.CommitChanges(); + OnAuthenticationSettingsSaved(); + } + + private void Providers() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var windowsSection = service.GetSection("system.webServer/security/authentication/windowsAuthentication"); + var dialog = new ProvidersDialog(Module, new WindowsItem(windowsSection)); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + service.ServerManager.CommitChanges(); + OnAuthenticationSettingsSaved(); + } + + public override Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210461#Windows"); + return true; + } + + public override bool IsFeatureEnabled + { + get { return true; } + } + + public override AuthenticationType AuthenticationType + { + get { return AuthenticationType.ChallengeBase; } + } + + public override string Name + { + get { return "Windows Authentication"; } + } + } +} diff --git a/JexusManager.Features.Authentication/WindowsItem.cs b/JexusManager.Features.Authentication/WindowsItem.cs new file mode 100644 index 00000000..6fb2a624 --- /dev/null +++ b/JexusManager.Features.Authentication/WindowsItem.cs @@ -0,0 +1,56 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authentication +{ + using System; + using System.Collections.Generic; + + using Microsoft.Web.Administration; + + public class WindowsItem + { + public ConfigurationElement Element { get; set; } + + public WindowsItem(ConfigurationElement element) + { + this.Element = element; + var extended = element.ChildElements["extendedProtection"]; + this.TokenChecking = Convert.ToInt32((long)extended["tokenChecking"]); + this.UseKernelMode = (bool)element["useKernelMode"]; + + var providers = element.GetCollection("providers"); + Providers = new List(providers.Count); + foreach (ConfigurationElement provider in providers) + { + Providers.Add(new ProviderItem(provider)); + } + } + + public List Providers { get; set; } + + public int TokenChecking { get; set; } + public bool UseKernelMode { get; set; } + + public void Apply() + { + this.Element["useKernelMode"] = this.UseKernelMode; + var extended = this.Element.ChildElements["extendedProtection"]; + extended["tokenChecking"] = (long)this.TokenChecking; + + var providers = Element.GetCollection("providers"); + providers.Clear(); + foreach (var item in Providers) + { + if (item.Element == null) + { + item.Element = providers.CreateElement(); + item.Apply(); + } + + providers.Add(item.Element); + } + } + } +} diff --git a/JexusManager.Features.Authentication/packages.config b/JexusManager.Features.Authentication/packages.config new file mode 100644 index 00000000..bdc4e5c2 --- /dev/null +++ b/JexusManager.Features.Authentication/packages.config @@ -0,0 +1,8 @@ + + + + + + + + diff --git a/JexusManager.Features.Authorization/AuthorizationFeature.cs b/JexusManager.Features.Authorization/AuthorizationFeature.cs new file mode 100644 index 00000000..1b42df3c --- /dev/null +++ b/JexusManager.Features.Authorization/AuthorizationFeature.cs @@ -0,0 +1,183 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/* + * Created by SharpDevelop. + * User: lextm + * Time: 11:06 AM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace JexusManager.Features.Authorization +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + /// + /// Authorization feature. + /// + internal class AuthorizationFeature : FeatureBase + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly AuthorizationFeature _owner; + + public FeatureTaskList(AuthorizationFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("AddAllow", "Add Allow Rule...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("AddDeny", "Add Deny Rule...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Set", "Edit...", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void AddAllow() + { + _owner.AddAllow(); + } + + [Obfuscation(Exclude = true)] + public void AddDeny() + { + _owner.AddDeny(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void Set() + { + _owner.Edit(); + } + } + + public AuthorizationFeature(Module module) + : base(module) + { + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + var section = service.GetSection("system.webServer/security/authorization"); + return section.GetCollection(); + } + + public void Load() + { + LoadItems(); + } + + public void AddAllow() + { + var dialog = new NewRuleDialog(this.Module, null, true, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void AddDeny() + { + var dialog = new NewRuleDialog(this.Module, null, false, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected authorization rule?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + this.RemoveItem(); + } + + public void Edit() + { + var dialog = new NewRuleDialog(this.Module, this.SelectedItem, false, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.EditItem(dialog.Item); + } + + protected override void OnSettingsSaved() + { + this.AuthorizationSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210462"); + return false; + } + + public AuthorizationSettingsSavedEventHandler AuthorizationSettingsUpdated { get; set; } + + public string Description { get; } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public string Name + { + get { return "Authorization Rules"; } + } + } +} diff --git a/JexusManager.Features.Authorization/AuthorizationModule.cs b/JexusManager.Features.Authorization/AuthorizationModule.cs new file mode 100644 index 00000000..5ccd65dc --- /dev/null +++ b/JexusManager.Features.Authorization/AuthorizationModule.cs @@ -0,0 +1,24 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authorization +{ + using System; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + using Properties; + + internal class AuthorizationModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)this.GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(AuthorizationPage), "Authorization Rules", + "Configure rules for authorizing users to access websites and applications", Resources.authorization_36, + Resources.authorization_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.Authorization/AuthorizationModuleProvider.cs b/JexusManager.Features.Authorization/AuthorizationModuleProvider.cs new file mode 100644 index 00000000..558e8650 --- /dev/null +++ b/JexusManager.Features.Authorization/AuthorizationModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authorization +{ + using System; + + using Microsoft.Web.Management.Server; + + public class AuthorizationModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(this.Name, typeof(AuthorizationModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.Authorization/AuthorizationPage.Designer.cs b/JexusManager.Features.Authorization/AuthorizationPage.Designer.cs new file mode 100644 index 00000000..80e50877 --- /dev/null +++ b/JexusManager.Features.Authorization/AuthorizationPage.Designer.cs @@ -0,0 +1,266 @@ +namespace JexusManager.Features.Authorization +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class AuthorizationPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chMode = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chUsers = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chRoles = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chVerbs = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 6; + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 6; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chMode, + this.chUsers, + this.chRoles, + this.chVerbs, + this.chType}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 13); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 527); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.listView1_SelectedIndexChanged); + // + // chMode + // + this.chMode.Text = "Mode"; + this.chMode.Width = 80; + // + // chUsers + // + this.chUsers.Text = "Users"; + this.chUsers.Width = 120; + // + // chRoles + // + this.chRoles.Text = "Roles"; + this.chRoles.Width = 120; + // + // chVerbs + // + this.chVerbs.Text = "Verbs"; + this.chVerbs.Width = 120; + // + // chType + // + this.chType.Text = "Entry Type"; + this.chType.Width = 120; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(427, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to specify rules for authorizing users to access websites and ap" + + "plications."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 5; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(199, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Authorization Rules"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // AuthorizationPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "AuthorizationPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private ListView listView1; + private ColumnHeader chMode; + private ColumnHeader chUsers; + private ColumnHeader chType; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Panel panel2; + private PictureBox pictureBox1; + private ContextMenuStrip cmsActionPanel; + private ColumnHeader chRoles; + private ColumnHeader chVerbs; + } +} diff --git a/JexusManager.Features.Authorization/AuthorizationPage.cs b/JexusManager.Features.Authorization/AuthorizationPage.cs new file mode 100644 index 00000000..3c31ba49 --- /dev/null +++ b/JexusManager.Features.Authorization/AuthorizationPage.cs @@ -0,0 +1,140 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authorization +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class AuthorizationPage : ModuleListPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly AuthorizationPage _owner; + + public PageTaskList(AuthorizationPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class AuthorizationListViewItem : ListViewItem + { + public AuthorizationRule Item { get; } + + private readonly AuthorizationPage _page; + + public AuthorizationListViewItem(AuthorizationRule item, AuthorizationPage page) + : base(item.AccessType == 0L ? "Allow" : "Deny") + { + this.Item = item; + _page = page; + this.SubItems.Add(new ListViewSubItem(this, item.UsersString)); + this.SubItems.Add(new ListViewSubItem(this, item.Roles)); + this.SubItems.Add(new ListViewSubItem(this, item.Verbs)); + this.SubItems.Add(new ListViewSubItem(this, item.Flag)); + } + } + + private AuthorizationFeature _feature; + private PageTaskList _taskList; + + public AuthorizationPage() + { + this.InitializeComponent(); + } + + public override ModuleListPageViewModes ViewModes + { + get + { + return ModuleListPageViewModes.Details; + } + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new AuthorizationFeature(Module); + _feature.AuthorizationSettingsUpdated = this.InitializeListPage; + _feature.Load(); + } + + protected override void InitializeListPage() + { + listView1.Items.Clear(); + foreach (var file in _feature.Items) + { + listView1.Items.Add(new AuthorizationListViewItem(file, this)); + } + + if (_feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (AuthorizationListViewItem item in listView1.Items) + { + if (item.Item == _feature.SelectedItem) + { + item.Selected = true; + } + } + } + + protected override void Refresh() + { + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + private void listView1_SelectedIndexChanged(object sender, EventArgs e) + { + _feature.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((AuthorizationListViewItem)listView1.SelectedItems[0]).Item + : null; + // TODO: optimize refresh when null to not null (vice versa) + this.Refresh(); + } + + protected override bool ShowHelp() + { + _feature.ShowHelp(); + return true; + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + } +} diff --git a/JexusManager.Features.Authorization/AuthorizationPage.resx b/JexusManager.Features.Authorization/AuthorizationPage.resx new file mode 100644 index 00000000..80c56e6e --- /dev/null +++ b/JexusManager.Features.Authorization/AuthorizationPage.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 602, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.Authorization/AuthorizationRule.cs b/JexusManager.Features.Authorization/AuthorizationRule.cs new file mode 100644 index 00000000..5931960b --- /dev/null +++ b/JexusManager.Features.Authorization/AuthorizationRule.cs @@ -0,0 +1,67 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authorization +{ + using Microsoft.Web.Administration; + + internal class AuthorizationRule : IItem + { + public AuthorizationRule(ConfigurationElement element) + { + this.Element = element; + this.Flag = element == null || element.IsLocallyStored ? "Local" : "Inhertied"; + if (element == null) + { + Users = Roles = Verbs = string.Empty; + return; + } + + this.AccessType = (long)element["accessType"]; + this.Users = (string)element["users"]; + this.Roles = (string)element["roles"]; + this.Verbs = (string)element["verbs"]; + } + + public string Verbs { get; set; } + + public string Roles { get; set; } + + public string Users { get; set; } + + public long AccessType { get; set; } + + public ConfigurationElement Element { get; set; } + + public string Flag { get; set; } + + public string UsersString + { + get + { + return Users == "*" ? "All Users" : Users == "?" ? "Anonymous Users" : Users; + } + } + + public bool Equals(AuthorizationRule other) + { + // all properties + return Match(other) && other.AccessType == AccessType; + } + + public void Apply() + { + Element["accessType"] = AccessType; + Element["users"] = Users; + Element["roles"] = Roles; + Element["verbs"] = Verbs; + } + + public bool Match(AuthorizationRule other) + { + // match combined keys. + return other != null && other.Verbs == this.Verbs && other.Roles == this.Roles && other.Users == this.Users; + } + } +} diff --git a/JexusManager.Features.Authorization/AuthorizationSettingsSavedEventHandler.cs b/JexusManager.Features.Authorization/AuthorizationSettingsSavedEventHandler.cs new file mode 100644 index 00000000..e042e1d0 --- /dev/null +++ b/JexusManager.Features.Authorization/AuthorizationSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authorization +{ + public delegate void AuthorizationSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.Authorization/JexusManager.Features.Authorization.csproj b/JexusManager.Features.Authorization/JexusManager.Features.Authorization.csproj new file mode 100644 index 00000000..b115621f --- /dev/null +++ b/JexusManager.Features.Authorization/JexusManager.Features.Authorization.csproj @@ -0,0 +1,130 @@ + + + + + Debug + AnyCPU + {FEFD62BE-AA83-42B9-A79D-2DF0150F4F81} + Library + Properties + JexusManager.Features.Authorization + JexusManager.Features.Authorization + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + + + + UserControl + + + AuthorizationPage.cs + + + + + Form + + + NewRuleDialog.cs + + + + True + True + Resources.resx + + + + + AuthorizationPage.cs + + + NewRuleDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Authorization/JexusManager.snk b/JexusManager.Features.Authorization/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Authorization/NewRuleDialog.Designer.cs b/JexusManager.Features.Authorization/NewRuleDialog.Designer.cs new file mode 100644 index 00000000..8e0efb85 --- /dev/null +++ b/JexusManager.Features.Authorization/NewRuleDialog.Designer.cs @@ -0,0 +1,229 @@ +namespace JexusManager.Features.Authorization +{ + using System.ComponentModel; + using System.Windows.Forms; + + sealed partial class NewRuleDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.txtDescription = new System.Windows.Forms.Label(); + this.rbAll = new System.Windows.Forms.RadioButton(); + this.rbRoles = new System.Windows.Forms.RadioButton(); + this.txtRoles = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.txtUsers = new System.Windows.Forms.TextBox(); + this.rbAnonymous = new System.Windows.Forms.RadioButton(); + this.rbUsers = new System.Windows.Forms.RadioButton(); + this.label1 = new System.Windows.Forms.Label(); + this.cbVerbs = new System.Windows.Forms.CheckBox(); + this.label3 = new System.Windows.Forms.Label(); + this.txtVerbs = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(342, 386); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(241, 386); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // txtDescription + // + this.txtDescription.AutoSize = true; + this.txtDescription.Location = new System.Drawing.Point(12, 9); + this.txtDescription.Name = "txtDescription"; + this.txtDescription.Size = new System.Drawing.Size(180, 13); + this.txtDescription.TabIndex = 2; + this.txtDescription.Text = "Allow access to this Web content to:"; + // + // rbAll + // + this.rbAll.AutoSize = true; + this.rbAll.Checked = true; + this.rbAll.Location = new System.Drawing.Point(15, 34); + this.rbAll.Name = "rbAll"; + this.rbAll.Size = new System.Drawing.Size(64, 17); + this.rbAll.TabIndex = 3; + this.rbAll.TabStop = true; + this.rbAll.Text = "All users"; + this.rbAll.UseVisualStyleBackColor = true; + // + // rbRoles + // + this.rbRoles.AutoSize = true; + this.rbRoles.Location = new System.Drawing.Point(15, 102); + this.rbRoles.Name = "rbRoles"; + this.rbRoles.Size = new System.Drawing.Size(167, 17); + this.rbRoles.TabIndex = 4; + this.rbRoles.Text = "Specified roles or user groups:"; + this.rbRoles.UseVisualStyleBackColor = true; + // + // txtRoles + // + this.txtRoles.Enabled = false; + this.txtRoles.Location = new System.Drawing.Point(33, 125); + this.txtRoles.Name = "txtRoles"; + this.txtRoles.Size = new System.Drawing.Size(404, 20); + this.txtRoles.TabIndex = 6; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(30, 148); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(118, 13); + this.label2.TabIndex = 7; + this.label2.Text = "Example: Administrators"; + // + // txtUsers + // + this.txtUsers.Enabled = false; + this.txtUsers.Location = new System.Drawing.Point(33, 196); + this.txtUsers.Name = "txtUsers"; + this.txtUsers.Size = new System.Drawing.Size(404, 20); + this.txtUsers.TabIndex = 8; + // + // rbAnonymous + // + this.rbAnonymous.AutoSize = true; + this.rbAnonymous.Location = new System.Drawing.Point(15, 69); + this.rbAnonymous.Name = "rbAnonymous"; + this.rbAnonymous.Size = new System.Drawing.Size(121, 17); + this.rbAnonymous.TabIndex = 9; + this.rbAnonymous.TabStop = true; + this.rbAnonymous.Text = "All anonymous users"; + this.rbAnonymous.UseVisualStyleBackColor = true; + // + // rbUsers + // + this.rbUsers.AutoSize = true; + this.rbUsers.Location = new System.Drawing.Point(15, 173); + this.rbUsers.Name = "rbUsers"; + this.rbUsers.Size = new System.Drawing.Size(100, 17); + this.rbUsers.TabIndex = 10; + this.rbUsers.TabStop = true; + this.rbUsers.Text = "Specified users:"; + this.rbUsers.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(30, 219); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(115, 13); + this.label1.TabIndex = 11; + this.label1.Text = "Example: User1, User2"; + // + // cbVerbs + // + this.cbVerbs.AutoSize = true; + this.cbVerbs.Location = new System.Drawing.Point(15, 253); + this.cbVerbs.Name = "cbVerbs"; + this.cbVerbs.Size = new System.Drawing.Size(174, 17); + this.cbVerbs.TabIndex = 12; + this.cbVerbs.Text = "Apply this rule to specific verbs:"; + this.cbVerbs.UseVisualStyleBackColor = true; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(30, 299); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(110, 13); + this.label3.TabIndex = 13; + this.label3.Text = "Example: GET, POST"; + // + // txtVerbs + // + this.txtVerbs.Enabled = false; + this.txtVerbs.Location = new System.Drawing.Point(33, 276); + this.txtVerbs.Name = "txtVerbs"; + this.txtVerbs.Size = new System.Drawing.Size(404, 20); + this.txtVerbs.TabIndex = 14; + // + // NewRuleDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(449, 421); + this.Controls.Add(this.txtVerbs); + this.Controls.Add(this.label3); + this.Controls.Add(this.cbVerbs); + this.Controls.Add(this.label1); + this.Controls.Add(this.rbUsers); + this.Controls.Add(this.rbAnonymous); + this.Controls.Add(this.txtUsers); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtRoles); + this.Controls.Add(this.rbRoles); + this.Controls.Add(this.rbAll); + this.Controls.Add(this.txtDescription); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewRuleDialog"; + this.Text = "Add Allow Restriction Rule"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewRestrictionDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label txtDescription; + private RadioButton rbAll; + private RadioButton rbRoles; + private TextBox txtRoles; + private Label label2; + private TextBox txtUsers; + private RadioButton rbAnonymous; + private RadioButton rbUsers; + private Label label1; + private CheckBox cbVerbs; + private Label label3; + private TextBox txtVerbs; + } +} diff --git a/JexusManager.Features.Authorization/NewRuleDialog.cs b/JexusManager.Features.Authorization/NewRuleDialog.cs new file mode 100644 index 00000000..f400ad2a --- /dev/null +++ b/JexusManager.Features.Authorization/NewRuleDialog.cs @@ -0,0 +1,134 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Authorization +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Linq; + using System.Reactive.Disposables; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewRuleDialog : DialogForm + { + private readonly bool _allowed; + private readonly AuthorizationFeature _feature; + + public NewRuleDialog(IServiceProvider serviceProvider, AuthorizationRule existing, bool allowed, AuthorizationFeature feature) + : base(serviceProvider) + { + this.InitializeComponent(); + _allowed = existing == null ? allowed : existing.AccessType == 0L; + Text = string.Format("{0} {1} Authorization Rule", existing == null ? "Add" : "Edit", _allowed ? "Allow" : "Deny"); + txtDescription.Text = _allowed + ? "Allow access to this Web content to:" + : "Deny access to this Web content to:"; + _feature = feature; + Item = existing ?? new AuthorizationRule(null); + if (existing != null) + { + txtRoles.Text = Item.Roles; + txtVerbs.Text = Item.Verbs; + if (Item.Users == "*") + { + rbAll.Checked = true; + } + else if (Item.Users == "?") + { + rbAnonymous.Checked = true; + } + else + { + rbUsers.Checked = true; + txtUsers.Text = Item.Users; + } + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item.AccessType = _allowed ? 0L : 1L; + Item.Roles = string.Empty; + if (rbAll.Checked) + { + Item.Users = "*"; + } + else if (rbAnonymous.Checked) + { + Item.Users = "?"; + } + else if (rbUsers.Checked) + { + Item.Users = txtUsers.Text; + } + + if (rbRoles.Checked) + { + Item.Roles = txtRoles.Text; + Item.Users = string.Empty; + } + + if (cbVerbs.Checked) + { + Item.Verbs = txtVerbs.Text; + } + + if (_feature.Items.Any(item => item.Match(this.Item))) + { + ShowMessage( + "This authorization rule already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(rbAll, "CheckedChanged") + .Merge(Observable.FromEventPattern(rbRoles, "CheckedChanged")) + .Merge(Observable.FromEventPattern(rbAnonymous, "CheckedChanged")) + .Merge(Observable.FromEventPattern(rbUsers, "CheckedChanged")) + .Merge(Observable.FromEventPattern(cbVerbs, "CheckedChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + txtVerbs.Enabled = cbVerbs.Checked; + txtRoles.Enabled = rbRoles.Checked; + txtUsers.Enabled = rbUsers.Checked; + btnOK.Enabled = (rbRoles.Checked && !string.IsNullOrWhiteSpace(txtRoles.Text)) + || (rbUsers.Checked && !string.IsNullOrWhiteSpace(txtUsers.Text)) + || rbAll.Checked + || rbAnonymous.Checked; + })); + + container.Add( + Observable.FromEventPattern(txtRoles, "TextChanged") + .Merge(Observable.FromEventPattern(txtUsers, "TextChanged")) + .Merge(Observable.FromEventPattern(txtVerbs, "TextChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = true; + })); + } + + public AuthorizationRule Item { get; set; } + + private void NewRestrictionDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210462"); + } + } +} diff --git a/JexusManager.Features.Authorization/NewRuleDialog.resx b/JexusManager.Features.Authorization/NewRuleDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Authorization/NewRuleDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Authorization/Properties/AssemblyInfo.cs b/JexusManager.Features.Authorization/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..535aefbc --- /dev/null +++ b/JexusManager.Features.Authorization/Properties/AssemblyInfo.cs @@ -0,0 +1,46 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.Authorization")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.Authorization")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fefd62be-aa83-42b9-a79d-2df0150f4f81")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("Tests.JexusManager, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] diff --git a/JexusManager.Features.Authorization/Properties/Resources.Designer.cs b/JexusManager.Features.Authorization/Properties/Resources.Designer.cs new file mode 100644 index 00000000..bbde6b1c --- /dev/null +++ b/JexusManager.Features.Authorization/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.Authorization.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.Authorization.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap authorization_36 { + get { + object obj = ResourceManager.GetObject("authorization_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.Authorization/Properties/Resources.resx b/JexusManager.Features.Authorization/Properties/Resources.resx new file mode 100644 index 00000000..f80f7e7a --- /dev/null +++ b/JexusManager.Features.Authorization/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\authorization_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.Authorization/Resources/authorization_36.png b/JexusManager.Features.Authorization/Resources/authorization_36.png new file mode 100644 index 0000000000000000000000000000000000000000..b1025f0977cb9662d0cc0dd831513f1be6fa07bf GIT binary patch literal 2051 zcmV+e2>kbnP)r2arib zK~z}7&6rzkT*VoHzqy<_yK6hXB=HT~A&yCCQ)p>(serb$C<2reT1ti5q6%KPJe8L| zgjV9EQ1zukDh)~`Kt)wsWJJ=m6|_JqML{Syq1=)}0h>6n$=Z(BjyK-jbD8ObceiV2 z*WS=RbfnRlGv}X~Z~n_%4*Z`bv9w~}zI_`#&%4Rv7mN<^F))GZgxg3UJ z`FlwwilRm3l59yn2!izV^z?zj!NJ_p@pa|P-o1O9J3Bj%Tz~!bYlRR9v6$C6S9Mm_ z+C|@2dS)^iyJydyXMyi83ls!FUteFJA4L(_Y!>Gn#u(x_UQlNduoARZxmI${(bLl- zt+iKI`>t!+QV6WIiy&44suyaxq-()cLR5pP2DcKBbB=1RP!lK&!?K;1LI@$4oSY<| z&o4W0t@_T+PK+^^uAyqPD3yKRuS+Y{pp;T|nNu&jCM?lXDwQIUNUUhKssm}gNUm1I zE{(E_Ojem^XJ^Ufa#aCVg6it(TBPB+fR;0v5Mq%JTxxWEDw734fVH-&mH-+W8c3y5 zH6!v;OjcS<>(UUw*w`3dU0sU?o}Ha#et!N_EsWjW-DQ*2t)Vas%N=)gbYP5Gq$Oia z*`&*9CypH_Pfe4ao@X{&z<7#v>6mLab+fiLRlieL3L0aGqG-{q8X6i%CX+Q+?sKy_ zp8C_<9DnaDTRzvvhRa$R=;$H{LQYN0@$Aco2&0I5Z{POcuR}rzW@cu}CR?hNSB{VI z(i>^+xpgad?b^m`@1ACOEW^7aQy8siX-aVSZCmJRZ{{}#k1;gWbNTvPAL$r5_>**9 zVPDOuOHsBIcHhBwxe!Qx@!(GW@Yi?P^ZXD>N~9{bN8o_NZ;sN|l;F-CS8?;Tn;LdM z{=yr5w>-LI^o55`mim*+0WFQD#>PfkT3TpsZl+uf^D{>wePes%z}C%u-|fHo=Uc0Wed!Fe+%Z82!T8i1 z`M{DdM7(!u3g38mM&lcer!}6ZI6X0k5CSC?h0x*q8Wl?-As?r_fsAc?wS}JgqUl#%N6;wB&*qDJ)V+ zeBVPymY@h@onv@>hOX6(v^6Jpjo?JhC|kE~9ZIQ1kd>R`nW-GtZENS1p%Ju_Xr<8J z0+`Vr##d}!znZJouSQDATf^tb<|0BFm0@DHa1r?M%rqN%S9eU^^l0ZrK&A7uQtG1p zCY4H&OePURkj-0GH>a4%=J7m@QW7l{S}U|CG1@C1g8@9P@Qnts0OQ4$SXv^bn8_As zZ)?P9*{y3GHLIn{D9ab0QVOJ$C@E1&pp+_Ws}jf<56^g595%MZ+M=QespKMGUD2s4 zL%;HH*5200x!HNznp0$R5lDfM0x84-oRmoMpIyD=V{s%2r9@Q7w>0@oW-g$VJyUns zmrPb#5H}BW@y-XIu(`jz;>KB;1PB4nQNARq(&U6FUrz-KvRC%5;pA}o?8w1~CN2pm zlgThXKF;{~I9FcgbNKiO+c)>%O6{D(Ifr!)XN%?HjWsHQIlCZ-TWHhY-NNaKS>`Sj z4uEjF-mRl_bEq`s(=QI=dy-APt2vdP#ac&fEpcp#ti=|Agb;*bOb|vy))K|G47cmL z0eOQ5^HNYx(+3~wF5kP;B_9jV+&6n{0Bi4BSnM& z2LJvql$PZ~y^SqF6cGk7U)t2c=F8i-|B?M4S|RSQy4y!lH%`7W z_~EkuhXAp2=gyYW%f!Tlf9~A5rb4065Qbqgj^m_r&RA=GKso1>bIv&DQZm)v-Z*g6 zH`jJ=_`=t>Z}d0xw6UhGk)RMVK6#$k-ahT#esB1r`Kgho)5o6qJ&*xrRsyOg$zoQ; zJ_KNZCLrZ`%}uL5bK`dHuj-ZBZ*$HDF3hKM>3<$Sf9BZ7Ko&S(% + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Caching/CachingAdvancedDialog.Designer.cs b/JexusManager.Features.Caching/CachingAdvancedDialog.Designer.cs new file mode 100644 index 00000000..4878f1c1 --- /dev/null +++ b/JexusManager.Features.Caching/CachingAdvancedDialog.Designer.cs @@ -0,0 +1,177 @@ +namespace JexusManager.Features.Caching +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal partial class CachingAdvancedDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label3 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.txtHeaders = new System.Windows.Forms.TextBox(); + this.txtString = new System.Windows.Forms.TextBox(); + this.cbHeaders = new System.Windows.Forms.CheckBox(); + this.cbString = new System.Windows.Forms.CheckBox(); + this.label1 = new System.Windows.Forms.Label(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(347, 256); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(251, 256); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.label2); + this.groupBox1.Controls.Add(this.txtHeaders); + this.groupBox1.Controls.Add(this.txtString); + this.groupBox1.Controls.Add(this.cbHeaders); + this.groupBox1.Controls.Add(this.cbString); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Location = new System.Drawing.Point(12, 12); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(430, 238); + this.groupBox1.TabIndex = 2; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Multiple File Versions"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(37, 183); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(217, 13); + this.label3.TabIndex = 6; + this.label3.Text = "Example: Accept-Language, Accept-Charset"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(37, 102); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(124, 13); + this.label2.TabIndex = 5; + this.label2.Text = "Example: Locale, Culture"; + // + // txtHeaders + // + this.txtHeaders.Enabled = false; + this.txtHeaders.Location = new System.Drawing.Point(40, 160); + this.txtHeaders.Name = "txtHeaders"; + this.txtHeaders.Size = new System.Drawing.Size(321, 20); + this.txtHeaders.TabIndex = 4; + // + // txtString + // + this.txtString.Enabled = false; + this.txtString.Location = new System.Drawing.Point(40, 79); + this.txtString.Name = "txtString"; + this.txtString.Size = new System.Drawing.Size(321, 20); + this.txtString.TabIndex = 3; + // + // cbHeaders + // + this.cbHeaders.AutoSize = true; + this.cbHeaders.Location = new System.Drawing.Point(21, 137); + this.cbHeaders.Name = "cbHeaders"; + this.cbHeaders.Size = new System.Drawing.Size(69, 17); + this.cbHeaders.TabIndex = 2; + this.cbHeaders.Text = "Headers:"; + this.cbHeaders.UseVisualStyleBackColor = true; + // + // cbString + // + this.cbString.AutoSize = true; + this.cbString.Location = new System.Drawing.Point(21, 56); + this.cbString.Name = "cbString"; + this.cbString.Size = new System.Drawing.Size(136, 17); + this.cbString.TabIndex = 1; + this.cbString.Text = "Query string variable(s):"; + this.cbString.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(18, 31); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(208, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Cache different versions of a file based on:"; + // + // CachingAdvancedDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(454, 291); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "CachingAdvancedDialog"; + this.Text = "Advanced Output Cache Rule Settings"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.CachingAdvancedDialogHelpButtonClicked); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private GroupBox groupBox1; + private Label label3; + private Label label2; + private TextBox txtHeaders; + private TextBox txtString; + private CheckBox cbHeaders; + private CheckBox cbString; + private Label label1; + } +} diff --git a/JexusManager.Features.Caching/CachingAdvancedDialog.cs b/JexusManager.Features.Caching/CachingAdvancedDialog.cs new file mode 100644 index 00000000..07736998 --- /dev/null +++ b/JexusManager.Features.Caching/CachingAdvancedDialog.cs @@ -0,0 +1,68 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Caching +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal partial class CachingAdvancedDialog : DialogForm + { + public CachingAdvancedDialog(IServiceProvider serviceProvider, CachingItem item) + : base(serviceProvider) + { + InitializeComponent(); + cbString.Checked = !string.IsNullOrWhiteSpace(item.VaryByQueryString); + txtString.Text = item.VaryByQueryString; + + cbHeaders.Checked = !string.IsNullOrWhiteSpace(item.VaryByHeaders); + txtHeaders.Text = item.VaryByHeaders; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + item.VaryByHeaders = txtHeaders.Text; + item.VaryByQueryString = txtString.Text; + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(cbString, "CheckedChanged") + .Subscribe(evt => + { + txtString.Enabled = cbString.Checked; + if (!cbString.Checked) + { + txtString.Text = string.Empty; + } + })); + + container.Add( + Observable.FromEventPattern(cbHeaders, "CheckedChanged") + .Subscribe(evt => + { + txtHeaders.Enabled = cbHeaders.Checked; + if (!cbHeaders.Checked) + { + txtHeaders.Text = string.Empty; + } + })); + } + + private void CachingAdvancedDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210522"); + } + } +} diff --git a/JexusManager.Features.Caching/CachingAdvancedDialog.resx b/JexusManager.Features.Caching/CachingAdvancedDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Caching/CachingAdvancedDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Caching/CachingFeature.cs b/JexusManager.Features.Caching/CachingFeature.cs new file mode 100644 index 00000000..0c766b43 --- /dev/null +++ b/JexusManager.Features.Caching/CachingFeature.cs @@ -0,0 +1,187 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/* + * Created by SharpDevelop. + * User: lextm + * Time: 11:06 AM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace JexusManager.Features.Caching +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + /// + /// Description of DefaultDocumentFeature. + /// + internal class CachingFeature : FeatureBase + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly CachingFeature _owner; + + public FeatureTaskList(CachingFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("Add", "Add...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem("Edit", "Edit...", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Set", "Edit Feature Settings...", string.Empty).SetUsage()); + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Add() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void Edit() + { + _owner.Edit(); + } + + [Obfuscation(Exclude = true)] + public void Set() + { + _owner.Set(); + } + } + + public CachingFeature(Module module) + : base(module) + { + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + LoadItems(); + } + + public void Add() + { + var dialog = new NewCachingDialog(this.Module, null, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Set() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/caching"); + var dialog = new CachingSettingsDialog(this.Module, section); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + service.ServerManager.CommitChanges(); + this.OnSettingsSaved(); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected restriction?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + public void Edit() + { + var dialog = new NewCachingDialog(this.Module, this.SelectedItem, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.EditItem(dialog.Item); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + var section = service.GetSection("system.webServer/caching"); + return section.GetCollection("profiles"); + } + + protected override void OnSettingsSaved() + { + this.CachingSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210522"); + return false; + } + + public CachingSettingsSavedEventHandler CachingSettingsUpdated { get; set; } + + public string Description { get; } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public string Name + { + get { return "Output Caching"; } + } + } +} diff --git a/JexusManager.Features.Caching/CachingItem.cs b/JexusManager.Features.Caching/CachingItem.cs new file mode 100644 index 00000000..344d13f1 --- /dev/null +++ b/JexusManager.Features.Caching/CachingItem.cs @@ -0,0 +1,69 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Caching +{ + using System; + + using Microsoft.Web.Administration; + + internal class CachingItem : IItem + { + public CachingItem(ConfigurationElement element) + { + this.Element = element; + this.Flag = element == null || element.IsLocallyStored ? "Local" : "Inhertied"; + if (element == null) + { + Extension = VaryByQueryString = VaryByHeaders = string.Empty; + return; + } + + this.Extension = (string)element["extension"]; + this.Policy = (long)element["policy"]; + this.KernelCachePolicy = (long)element["kernelCachePolicy"]; + this.Duration = (TimeSpan)element["duration"]; + this.VaryByQueryString = (string)element["varyByQueryString"]; + this.VaryByHeaders = (string)element["varyByHeaders"]; + } + + public string VaryByHeaders { get; set; } + + public string VaryByQueryString { get; set; } + + public TimeSpan Duration { get; set; } + + public long KernelCachePolicy { get; set; } + + public long Policy { get; set; } + + public string Extension { get; set; } + + public ConfigurationElement Element { get; set; } + + public string Flag { get; set; } + + public bool Equals(CachingItem other) + { + // all properties + return this.Match(other); + } + + public void Apply() + { + Element["extension"] = Extension; + Element["policy"] = Policy; + Element["kernelCachePolicy"] = KernelCachePolicy; + Element["duration"] = Duration; + Element["varyByQueryString"] = VaryByQueryString; + Element["varyByHeaders"] = VaryByHeaders; + } + + public bool Match(CachingItem other) + { + // match combined keys. + return other != null && other.Extension == this.Extension; + } + } +} diff --git a/JexusManager.Features.Caching/CachingModule.cs b/JexusManager.Features.Caching/CachingModule.cs new file mode 100644 index 00000000..2a81c33e --- /dev/null +++ b/JexusManager.Features.Caching/CachingModule.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Caching +{ + using System; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + using Properties; + + internal class CachingModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)this.GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo( + this, + typeof(CachingPage), + "Output Caching", + "Specify rules for caching served content in the output cache", + Resources.caching_36, + Resources.caching_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.Caching/CachingModuleProvider.cs b/JexusManager.Features.Caching/CachingModuleProvider.cs new file mode 100644 index 00000000..3099c263 --- /dev/null +++ b/JexusManager.Features.Caching/CachingModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Caching +{ + using System; + + using Microsoft.Web.Management.Server; + + public class CachingModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(this.Name, typeof(CachingModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.Caching/CachingPage.Designer.cs b/JexusManager.Features.Caching/CachingPage.Designer.cs new file mode 100644 index 00000000..b65dc050 --- /dev/null +++ b/JexusManager.Features.Caching/CachingPage.Designer.cs @@ -0,0 +1,298 @@ +namespace JexusManager.Features.Caching +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class CachingPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chExtension = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chUser = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chKernel = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.toolStrip2 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel2 = new System.Windows.Forms.ToolStripLabel(); + this.cbGroup = new System.Windows.Forms.ToolStripComboBox(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + this.chType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.toolStrip2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 6; + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.toolStrip2); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 6; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chExtension, + this.chUser, + this.chKernel, + this.chType}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 38); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 502); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListView1SelectedIndexChanged); + // + // chExtension + // + this.chExtension.Text = "Extension"; + this.chExtension.Width = 120; + // + // chUser + // + this.chUser.Text = "User-Mode Policy"; + this.chUser.Width = 120; + // + // chKernel + // + this.chKernel.Text = "Kernel-Mode Policy"; + this.chKernel.Width = 120; + // + // toolStrip2 + // + this.toolStrip2.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel2, + this.cbGroup}); + this.toolStrip2.Location = new System.Drawing.Point(0, 13); + this.toolStrip2.Name = "toolStrip2"; + this.toolStrip2.Size = new System.Drawing.Size(560, 25); + this.toolStrip2.TabIndex = 3; + this.toolStrip2.Text = "toolStrip2"; + // + // toolStripLabel2 + // + this.toolStripLabel2.Name = "toolStripLabel2"; + this.toolStripLabel2.Size = new System.Drawing.Size(59, 22); + this.toolStripLabel2.Text = "Group by:"; + // + // cbGroup + // + this.cbGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbGroup.Items.AddRange(new object[] { + "No Grouping", + "Status", + "IP Address", + "Protocol", + "Port"}); + this.cbGroup.Name = "cbGroup"; + this.cbGroup.Size = new System.Drawing.Size(121, 25); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(567, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to configure output cache settings and to specify rules for cach" + + "ing served content in the output cache."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 5; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(161, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Output Caching"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // chType + // + this.chType.Text = "Entry Type"; + this.chType.Width = 120; + // + // CachingPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "CachingPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.toolStrip2.ResumeLayout(false); + this.toolStrip2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private ListView listView1; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Panel panel2; + private ToolStrip toolStrip2; + private ToolStripLabel toolStripLabel2; + private ToolStripComboBox cbGroup; + private PictureBox pictureBox1; + private ContextMenuStrip cmsActionPanel; + private ColumnHeader chExtension; + private ColumnHeader chUser; + private ColumnHeader chKernel; + private ColumnHeader chType; + } +} diff --git a/JexusManager.Features.Caching/CachingPage.cs b/JexusManager.Features.Caching/CachingPage.cs new file mode 100644 index 00000000..b3dbe30f --- /dev/null +++ b/JexusManager.Features.Caching/CachingPage.cs @@ -0,0 +1,148 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Caching +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class CachingPage : ModuleListPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly CachingPage _owner; + + public PageTaskList(CachingPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class CachingListViewItem : ListViewItem + { + public CachingItem Item { get; } + + private readonly CachingPage _page; + + public CachingListViewItem(CachingItem item, CachingPage page) + : base(item.Extension) + { + this.Item = item; + _page = page; + this.SubItems.Add(new ListViewSubItem(this, ToString(item.Policy))); + this.SubItems.Add(new ListViewSubItem(this, ToString(item.KernelCachePolicy))); + this.SubItems.Add(new ListViewSubItem(this, item.Flag)); + } + + private static string ToString(long policy) + { + switch (policy) + { + case 0L: + return "Do not cache"; + case 1L: + return "Cache until change"; + case 2: + return "Cache for time period"; + case 3: + return "Prevent all caching"; + } + + return string.Empty; + } + } + + private CachingFeature _feature; + private PageTaskList _taskList; + + public CachingPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new CachingFeature(this.Module); + _feature.CachingSettingsUpdated = this.InitializeListPage; + _feature.Load(); + } + + protected override void InitializeListPage() + { + listView1.Items.Clear(); + foreach (var file in _feature.Items) + { + listView1.Items.Add(new CachingListViewItem(file, this)); + } + + if (_feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (CachingListViewItem item in listView1.Items) + { + if (item.Item == _feature.SelectedItem) + { + item.Selected = true; + } + } + } + + protected override void Refresh() + { + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + private void ListView1SelectedIndexChanged(object sender, EventArgs e) + { + _feature.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((CachingListViewItem)listView1.SelectedItems[0]).Item + : null; + // TODO: optimize refresh when null to not null (vice versa) + this.Refresh(); + } + + protected override bool ShowHelp() + { + _feature.ShowHelp(); + return true; + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + } +} diff --git a/JexusManager.Features.Caching/CachingPage.resx b/JexusManager.Features.Caching/CachingPage.resx new file mode 100644 index 00000000..7a2db0ac --- /dev/null +++ b/JexusManager.Features.Caching/CachingPage.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 602, 17 + + + 497, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.Caching/CachingSettingsDialog.Designer.cs b/JexusManager.Features.Caching/CachingSettingsDialog.Designer.cs new file mode 100644 index 00000000..76729b98 --- /dev/null +++ b/JexusManager.Features.Caching/CachingSettingsDialog.Designer.cs @@ -0,0 +1,152 @@ +namespace JexusManager.Features.Caching +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal partial class CachingSettingsDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.cbUser = new System.Windows.Forms.CheckBox(); + this.cbKernel = new System.Windows.Forms.CheckBox(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.txtSize = new System.Windows.Forms.TextBox(); + this.cbLimit = new System.Windows.Forms.CheckBox(); + this.txtLimit = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // cbUser + // + this.cbUser.AutoSize = true; + this.cbUser.Location = new System.Drawing.Point(12, 12); + this.cbUser.Name = "cbUser"; + this.cbUser.Size = new System.Drawing.Size(92, 17); + this.cbUser.TabIndex = 1; + this.cbUser.Text = "Enable cache"; + this.cbUser.UseVisualStyleBackColor = true; + // + // cbKernel + // + this.cbKernel.AutoSize = true; + this.cbKernel.Location = new System.Drawing.Point(12, 49); + this.cbKernel.Name = "cbKernel"; + this.cbKernel.Size = new System.Drawing.Size(124, 17); + this.cbKernel.TabIndex = 2; + this.cbKernel.Text = "Enable kernel cache"; + this.cbKernel.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(227, 191); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 4; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(131, 191); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 5; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 83); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(205, 13); + this.label1.TabIndex = 6; + this.label1.Text = "Maximum cached response size (in bytes):"; + // + // txtSize + // + this.txtSize.Enabled = false; + this.txtSize.Location = new System.Drawing.Point(12, 99); + this.txtSize.Name = "txtSize"; + this.txtSize.Size = new System.Drawing.Size(249, 20); + this.txtSize.TabIndex = 7; + // + // cbLimit + // + this.cbLimit.AutoSize = true; + this.cbLimit.Enabled = false; + this.cbLimit.Location = new System.Drawing.Point(12, 125); + this.cbLimit.Name = "cbLimit"; + this.cbLimit.Size = new System.Drawing.Size(137, 17); + this.cbLimit.TabIndex = 8; + this.cbLimit.Text = "Cache size limit (in MB):"; + this.cbLimit.UseVisualStyleBackColor = true; + // + // txtLimit + // + this.txtLimit.Enabled = false; + this.txtLimit.Location = new System.Drawing.Point(30, 148); + this.txtLimit.Name = "txtLimit"; + this.txtLimit.Size = new System.Drawing.Size(245, 20); + this.txtLimit.TabIndex = 9; + // + // CachingSettingsDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(334, 226); + this.Controls.Add(this.txtLimit); + this.Controls.Add(this.cbLimit); + this.Controls.Add(this.txtSize); + this.Controls.Add(this.label1); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.cbKernel); + this.Controls.Add(this.cbUser); + this.Name = "CachingSettingsDialog"; + this.Text = "Edit Output Cache Settings"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.PermissionsDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private CheckBox cbUser; + private CheckBox cbKernel; + private Button btnCancel; + private Button btnOK; + private Label label1; + private TextBox txtSize; + private CheckBox cbLimit; + private TextBox txtLimit; + } +} diff --git a/JexusManager.Features.Caching/CachingSettingsDialog.cs b/JexusManager.Features.Caching/CachingSettingsDialog.cs new file mode 100644 index 00000000..95c786b8 --- /dev/null +++ b/JexusManager.Features.Caching/CachingSettingsDialog.cs @@ -0,0 +1,61 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Caching +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client.Win32; + + internal partial class CachingSettingsDialog : DialogForm + { + public CachingSettingsDialog(IServiceProvider serviceProvider, ConfigurationElement element) + : base(serviceProvider) + { + InitializeComponent(); + cbUser.Checked = (bool)element["enabled"]; + cbKernel.Checked = (bool)element["enableKernelCache"]; + txtSize.Text = element["maxResponseSize"].ToString(); + var limit = (uint)element["maxCacheSize"]; + cbLimit.Checked = limit != 0; + if (cbLimit.Checked) + { + txtLimit.Text = limit.ToString(); + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + element["enableKernelCache"] = cbKernel.Checked; + element["enabled"] = cbUser.Checked; + element["maxResponseSize"] = uint.Parse(txtSize.Text); + if (!cbLimit.Checked) + { + element["maxCacheSize"] = 0U; + } + else + { + element["maxCacheSize"] = uint.Parse(txtLimit.Text); + } + + DialogResult = DialogResult.OK; + })); + } + + private void PermissionsDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210522"); + } + } +} diff --git a/JexusManager.Features.Caching/CachingSettingsDialog.resx b/JexusManager.Features.Caching/CachingSettingsDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Caching/CachingSettingsDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Caching/CachingSettingsSavedEventHandler.cs b/JexusManager.Features.Caching/CachingSettingsSavedEventHandler.cs new file mode 100644 index 00000000..05cf21cd --- /dev/null +++ b/JexusManager.Features.Caching/CachingSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Caching +{ + public delegate void CachingSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.Caching/JexusManager.Features.Caching.csproj b/JexusManager.Features.Caching/JexusManager.Features.Caching.csproj new file mode 100644 index 00000000..51a23afc --- /dev/null +++ b/JexusManager.Features.Caching/JexusManager.Features.Caching.csproj @@ -0,0 +1,148 @@ + + + + + Debug + AnyCPU + {30A30352-CA83-446E-8AF8-598EA7397988} + Library + Properties + JexusManager.Features.Caching + JexusManager.Features.Caching + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + Form + + + CachingAdvancedDialog.cs + + + + + + + UserControl + + + CachingPage.cs + + + Form + + + CachingSettingsDialog.cs + + + + Form + + + NewCachingDialog.cs + + + + True + True + Resources.resx + + + + + CachingAdvancedDialog.cs + + + CachingPage.cs + + + CachingSettingsDialog.cs + + + NewCachingDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Caching/JexusManager.snk b/JexusManager.Features.Caching/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Caching/NewCachingDialog.Designer.cs b/JexusManager.Features.Caching/NewCachingDialog.Designer.cs new file mode 100644 index 00000000..c82327c7 --- /dev/null +++ b/JexusManager.Features.Caching/NewCachingDialog.Designer.cs @@ -0,0 +1,286 @@ +namespace JexusManager.Features.Caching +{ + using System.ComponentModel; + using System.Windows.Forms; + + sealed partial class NewCachingDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.txtDescription = new System.Windows.Forms.Label(); + this.txtExtension = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.cbUser = new System.Windows.Forms.CheckBox(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.btnAdvanced = new System.Windows.Forms.Button(); + this.txtUserTime = new System.Windows.Forms.TextBox(); + this.rbUserNo = new System.Windows.Forms.RadioButton(); + this.rbUserTime = new System.Windows.Forms.RadioButton(); + this.rbUserFile = new System.Windows.Forms.RadioButton(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.txtKernelTime = new System.Windows.Forms.TextBox(); + this.rbKernelNo = new System.Windows.Forms.RadioButton(); + this.rbKernelTime = new System.Windows.Forms.RadioButton(); + this.rbKernelFile = new System.Windows.Forms.RadioButton(); + this.cbKernel = new System.Windows.Forms.CheckBox(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(377, 506); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(276, 506); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // txtDescription + // + this.txtDescription.AutoSize = true; + this.txtDescription.Location = new System.Drawing.Point(9, 48); + this.txtDescription.Name = "txtDescription"; + this.txtDescription.Size = new System.Drawing.Size(113, 13); + this.txtDescription.TabIndex = 2; + this.txtDescription.Text = "Example: .aspx or .axd"; + // + // txtExtension + // + this.txtExtension.Location = new System.Drawing.Point(12, 25); + this.txtExtension.Name = "txtExtension"; + this.txtExtension.Size = new System.Drawing.Size(338, 20); + this.txtExtension.TabIndex = 8; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 9); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(103, 13); + this.label3.TabIndex = 11; + this.label3.Text = "File name extension:"; + // + // cbUser + // + this.cbUser.AutoSize = true; + this.cbUser.Location = new System.Drawing.Point(12, 89); + this.cbUser.Name = "cbUser"; + this.cbUser.Size = new System.Drawing.Size(118, 17); + this.cbUser.TabIndex = 16; + this.cbUser.Text = "User-mode caching"; + this.cbUser.UseVisualStyleBackColor = true; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.btnAdvanced); + this.groupBox1.Controls.Add(this.txtUserTime); + this.groupBox1.Controls.Add(this.rbUserNo); + this.groupBox1.Controls.Add(this.rbUserTime); + this.groupBox1.Controls.Add(this.rbUserFile); + this.groupBox1.Location = new System.Drawing.Point(15, 112); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(438, 192); + this.groupBox1.TabIndex = 17; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "File Cache Monitoring"; + // + // btnAdvanced + // + this.btnAdvanced.Location = new System.Drawing.Point(280, 163); + this.btnAdvanced.Name = "btnAdvanced"; + this.btnAdvanced.Size = new System.Drawing.Size(152, 23); + this.btnAdvanced.TabIndex = 8; + this.btnAdvanced.Text = "Advanced..."; + this.btnAdvanced.UseVisualStyleBackColor = true; + // + // txtUserTime + // + this.txtUserTime.Location = new System.Drawing.Point(35, 76); + this.txtUserTime.Name = "txtUserTime"; + this.txtUserTime.Size = new System.Drawing.Size(190, 20); + this.txtUserTime.TabIndex = 7; + // + // rbUserNo + // + this.rbUserNo.AutoSize = true; + this.rbUserNo.Location = new System.Drawing.Point(15, 125); + this.rbUserNo.Name = "rbUserNo"; + this.rbUserNo.Size = new System.Drawing.Size(116, 17); + this.rbUserNo.TabIndex = 6; + this.rbUserNo.TabStop = true; + this.rbUserNo.Text = "Prevent all caching"; + this.rbUserNo.UseVisualStyleBackColor = true; + // + // rbUserTime + // + this.rbUserTime.AutoSize = true; + this.rbUserTime.Location = new System.Drawing.Point(15, 53); + this.rbUserTime.Name = "rbUserTime"; + this.rbUserTime.Size = new System.Drawing.Size(155, 17); + this.rbUserTime.TabIndex = 5; + this.rbUserTime.TabStop = true; + this.rbUserTime.Text = "At time intervals (hh:mm:ss):"; + this.rbUserTime.UseVisualStyleBackColor = true; + // + // rbUserFile + // + this.rbUserFile.AutoSize = true; + this.rbUserFile.Location = new System.Drawing.Point(15, 19); + this.rbUserFile.Name = "rbUserFile"; + this.rbUserFile.Size = new System.Drawing.Size(166, 17); + this.rbUserFile.TabIndex = 4; + this.rbUserFile.TabStop = true; + this.rbUserFile.Text = "Using file change notifications"; + this.rbUserFile.UseVisualStyleBackColor = true; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.txtKernelTime); + this.groupBox2.Controls.Add(this.rbKernelNo); + this.groupBox2.Controls.Add(this.rbKernelTime); + this.groupBox2.Controls.Add(this.rbKernelFile); + this.groupBox2.Location = new System.Drawing.Point(15, 333); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(438, 164); + this.groupBox2.TabIndex = 19; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "File Cache Monitoring"; + // + // txtKernelTime + // + this.txtKernelTime.Location = new System.Drawing.Point(35, 76); + this.txtKernelTime.Name = "txtKernelTime"; + this.txtKernelTime.Size = new System.Drawing.Size(190, 20); + this.txtKernelTime.TabIndex = 3; + // + // rbKernelNo + // + this.rbKernelNo.AutoSize = true; + this.rbKernelNo.Location = new System.Drawing.Point(15, 125); + this.rbKernelNo.Name = "rbKernelNo"; + this.rbKernelNo.Size = new System.Drawing.Size(116, 17); + this.rbKernelNo.TabIndex = 2; + this.rbKernelNo.TabStop = true; + this.rbKernelNo.Text = "Prevent all caching"; + this.rbKernelNo.UseVisualStyleBackColor = true; + // + // rbKernelTime + // + this.rbKernelTime.AutoSize = true; + this.rbKernelTime.Location = new System.Drawing.Point(15, 53); + this.rbKernelTime.Name = "rbKernelTime"; + this.rbKernelTime.Size = new System.Drawing.Size(152, 17); + this.rbKernelTime.TabIndex = 1; + this.rbKernelTime.TabStop = true; + this.rbKernelTime.Text = "At time intervals (hh:mm:ss)"; + this.rbKernelTime.UseVisualStyleBackColor = true; + // + // rbKernelFile + // + this.rbKernelFile.AutoSize = true; + this.rbKernelFile.Location = new System.Drawing.Point(15, 19); + this.rbKernelFile.Name = "rbKernelFile"; + this.rbKernelFile.Size = new System.Drawing.Size(166, 17); + this.rbKernelFile.TabIndex = 0; + this.rbKernelFile.TabStop = true; + this.rbKernelFile.Text = "Using file change notifications"; + this.rbKernelFile.UseVisualStyleBackColor = true; + // + // cbKernel + // + this.cbKernel.AutoSize = true; + this.cbKernel.Location = new System.Drawing.Point(12, 310); + this.cbKernel.Name = "cbKernel"; + this.cbKernel.Size = new System.Drawing.Size(126, 17); + this.cbKernel.TabIndex = 18; + this.cbKernel.Text = "Kernel-mode caching"; + this.cbKernel.UseVisualStyleBackColor = true; + // + // NewCachingDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(484, 541); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.cbKernel); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.cbUser); + this.Controls.Add(this.label3); + this.Controls.Add(this.txtExtension); + this.Controls.Add(this.txtDescription); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewCachingDialog"; + this.Text = "Add Cache Rule"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewRestrictionDialogHelpButtonClicked); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label txtDescription; + private TextBox txtExtension; + private Label label3; + private CheckBox cbUser; + private GroupBox groupBox1; + private Button btnAdvanced; + private TextBox txtUserTime; + private RadioButton rbUserNo; + private RadioButton rbUserTime; + private RadioButton rbUserFile; + private GroupBox groupBox2; + private TextBox txtKernelTime; + private RadioButton rbKernelNo; + private RadioButton rbKernelTime; + private RadioButton rbKernelFile; + private CheckBox cbKernel; + } +} diff --git a/JexusManager.Features.Caching/NewCachingDialog.cs b/JexusManager.Features.Caching/NewCachingDialog.cs new file mode 100644 index 00000000..24e5c586 --- /dev/null +++ b/JexusManager.Features.Caching/NewCachingDialog.cs @@ -0,0 +1,125 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Caching +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewCachingDialog : DialogForm + { + private readonly CachingFeature _feature; + + public NewCachingDialog(IServiceProvider serviceProvider, CachingItem existing, CachingFeature feature) + : base(serviceProvider) + { + InitializeComponent(); + Text = existing == null ? "Add Cache Rule" : "Edit Cache Rule"; + _feature = feature; + Item = existing ?? new CachingItem(null); + if (existing == null) + { + return; + } + + txtExtension.Text = Item.Extension; + cbUser.Checked = Item.Policy != 0L; + rbUserFile.Checked = Item.Policy == 1L; + rbUserTime.Checked = Item.Policy == 2L; + rbUserNo.Checked = Item.Policy == 3L; + + cbKernel.Checked = Item.KernelCachePolicy != 0L; + rbKernelFile.Checked = Item.KernelCachePolicy == 1L; + rbKernelTime.Checked = Item.KernelCachePolicy == 2L; + rbKernelNo.Checked = Item.KernelCachePolicy == 3L; + + txtKernelTime.Text = txtUserTime.Text = Item.Duration.ToString(); + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item.Extension = txtExtension.Text; + Item.Duration = TimeSpan.Parse(txtKernelTime.Text); + if (!cbUser.Checked) + { + Item.Policy = 0L; + } + else if (rbUserFile.Checked) + { + Item.Policy = 1L; + } + else if (rbUserTime.Checked) + { + Item.Policy = 2L; + } + else if (rbUserNo.Checked) + { + Item.Policy = 3L; + } + + if (!cbKernel.Checked) + { + Item.KernelCachePolicy = 0L; + } + else if (rbKernelFile.Checked) + { + Item.KernelCachePolicy = 1L; + } + else if (rbKernelTime.Checked) + { + Item.KernelCachePolicy = 2L; + } + else if (rbKernelNo.Checked) + { + Item.KernelCachePolicy = 3L; + } + + if (_feature.Items.Any(item => item.Match(Item))) + { + ShowMessage( + "This rule already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(btnAdvanced, "Click") + .Subscribe(evt => + { + var dialog = new CachingAdvancedDialog(ServiceProvider, Item); + dialog.ShowDialog(); + })); + + container.Add( + Observable.FromEventPattern(txtExtension, "TextChanged") + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtExtension.Text); + })); + } + + public CachingItem Item { get; set; } + + private void NewRestrictionDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210522"); + } + } +} diff --git a/JexusManager.Features.Caching/NewCachingDialog.resx b/JexusManager.Features.Caching/NewCachingDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Caching/NewCachingDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Caching/Properties/AssemblyInfo.cs b/JexusManager.Features.Caching/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..17fd3077 --- /dev/null +++ b/JexusManager.Features.Caching/Properties/AssemblyInfo.cs @@ -0,0 +1,46 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.Caching")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.Caching")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("30a30352-ca83-446e-8af8-598ea7397988")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("Tests.JexusManager, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] diff --git a/JexusManager.Features.Caching/Properties/Resources.Designer.cs b/JexusManager.Features.Caching/Properties/Resources.Designer.cs new file mode 100644 index 00000000..0bd691f4 --- /dev/null +++ b/JexusManager.Features.Caching/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.Caching.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.Caching.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap caching_36 { + get { + object obj = ResourceManager.GetObject("caching_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.Caching/Properties/Resources.resx b/JexusManager.Features.Caching/Properties/Resources.resx new file mode 100644 index 00000000..036724fb --- /dev/null +++ b/JexusManager.Features.Caching/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\caching_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.Caching/Resources/caching_36.png b/JexusManager.Features.Caching/Resources/caching_36.png new file mode 100644 index 0000000000000000000000000000000000000000..7eb3cd374cdde7a84ebc08f6ba79de4449d73970 GIT binary patch literal 1850 zcmV-A2gUe_P)$$SP*sIU@2O;%?W-G(SM9t-?3;eX4x%+LUbEi93eiynh+uD7gsoA4 z7Kssf$@1n#L6P_0;rR_*w~Fgl+1U=b{{9^%$8KS&S8<$bd#zq?FgbP$L%GWJ_wP_H zx$U)s*om=QMAfS_8daR;p4O@jE{@+K8oA1ipWLBTa%nnMT(8mohC?*HSjn>bY=Ymc z-NyGlJWt07$C-L-4uA)DFR?T;jqmBq{Noc=*Wc#Sw;vES-9uQ{(`g3dOkSQt2>9yW zC06r$*r$&^VP*Yo&cFEpJ<{>2+~sLM%P&9rE$Mg<2#BZ}xokf_eD7my;|eMB1{dGB zLd=X|nKrVlaAshHpI`s4$j122W;nbS;YGI7pI&A9^%{FLAti z^79RtQUBc>R;k|Yq*W5v$a|Lz1&S$l&Q(@cFo9=#MzN? zB1$htWQ<(47g_GWw1~#U`D=(U%EcqFVq9_Eyr|Nz|)0t->-=JCV#x5+)V#FTObT?Rh7R8Eouzu*X zQ~mqdl*)D9dRs4*2dY-1Y%#*nQ%gj-( zl*nXqJYATk7T!jZ>dZd9&)SN?(9kfh+hl8JlNVc`p_}v6o6F?$0Wm8_sZt`F$uT!S z%~ts~nx^5qdmcJehcdY`nfLAz@iUmIHAc)D)#g&0=gV(RV?{E!;d6u=@~wC7wJUKV zRi^*le}bDLku77Do)Cza?e+5$)8vvFvhFH!C^$E7K>& znjp(WwHShzsES3c_7E!=U@uN(Bq3qP6L@}}AoNiU8N@*Qyt3^$ey~OyiKp{_=sH&R zgZfB=BuU1O<=8E}z%-J0L6g7_FpL;Gr47=F9@aOXlS%he-dV?vC2`y)f$yU>H44RD za+w~Ar6OS{_RcT?rE(e14`|jM{2*+{&cPUxk1{A3@26be#t(c1ff_^i8M>g%hW10>eV{6mX?YYYLz;^AGAZ@V3j`7 zAR$20Eh^Pr^oU8NvWu$d)EhN?KSV;J(QKd_7KP$2QQf3a+(lJ28uc2!A0SH-jYfm8 zwc$a1l_n8(d#FuWCUuS=3@BG#cHD@B5FiNA(1`@W_M&Fxc3RF!83%<3|p|XKiX#6~jt0Fc4vLL*wuFm&(Q6!s@|3NgSO+0twfx zv#j3xGpoQ4fSwP3%DrsPWb~ZG%;N~>--xmDyu`#*n)%rVrk%vLHLCR(XD{e{{ZQq? zWQ^sd5*IJ0S$OKA8A;OV2w(jT!T|sCKk+l5_L?@&2Ry(9Tp5T01HhmVsJ3m;({Erz z4f+QxWF=(qbR0zs>FbYU#X^!vi=I9MO*c3-XaONZXX40;PyZtkQ{0`UwipM-2wkY!fcfS{i068Gma-n=&jrtEHXvIYZs2=x2(lRV)8RSdH oJg6M=Kk;8X>>CU^k$+qM1$7II!l%u~Y5)KL07*qoM6N<$f(<-!kpKVy literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Caching/packages.config b/JexusManager.Features.Caching/packages.config new file mode 100644 index 00000000..571e4fe0 --- /dev/null +++ b/JexusManager.Features.Caching/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Certificates/CertificatesFeature.cs b/JexusManager.Features.Certificates/CertificatesFeature.cs new file mode 100644 index 00000000..6430ee5e --- /dev/null +++ b/JexusManager.Features.Certificates/CertificatesFeature.cs @@ -0,0 +1,397 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/* + * Created by SharpDevelop. + * User: lextm + * Time: 11:06 AM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace JexusManager.Features.Certificates +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using System.IO; + using System.Reflection; + using System.Resources; + using System.Security.Cryptography; + using System.Security.Cryptography.X509Certificates; + using System.Windows.Forms; + + using JexusManager.Services; + using JexusManager.Features.Certificates.Wizards.CertificateRenewWizard; + using JexusManager.Features.Certificates.Wizards.CertificateRequestWizard; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + /// + /// Description of DefaultDocumentFeature. + /// + internal class CertificatesFeature + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly CertificatesFeature _owner; + + public FeatureTaskList(CertificatesFeature owner) + { + _owner = owner; + } + + private const string LocalhostIssuer = "CN=localhost"; + private readonly string _localMachineIssuer = string.Format("CN={0}", Environment.MachineName); + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("Import", "Import...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("CreateRequest", "Create Certificate Request...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Complete", "Complete Certificate Request...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("CreateDomain", "Create Domain Certificate...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("CreateSelf", "Create Self-Signed Certificate...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("View", "View...", string.Empty).SetUsage()); + if (_owner.SelectedItem.Certificate.HasPrivateKey) + { + try + { + var keyInfo = (RSACryptoServiceProvider)_owner.SelectedItem.Certificate.PrivateKey; + if (keyInfo.CspKeyContainerInfo.Exportable) + { + result.Add(new MethodTaskItem("Export", "Export...", string.Empty).SetUsage()); + if (_owner.SelectedItem.Certificate.Issuer != LocalhostIssuer && _owner.SelectedItem.Certificate.Issuer != _localMachineIssuer) + { + result.Add(new MethodTaskItem("Renew", "Renew...", string.Empty).SetUsage()); + } + } + } + catch (CryptographicException ex) + { + if (ex.HResult != -2146893802) + { + throw; + } + } + } + + result.Add(RemoveTaskItem); + } + + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + if (!_owner.AutomicRebindEnabled) + { + result.Add(new MethodTaskItem("Enable", "Enable Automatic Rebind of Renewed Certificate", string.Empty).SetUsage()); + } + + if (_owner.AutomicRebindEnabled) + { + result.Add(new MethodTaskItem("Disable", "Disable Automatic Rebind of Renewed Certificate", string.Empty).SetUsage()); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Import() + { + _owner.Import(); + } + + [Obfuscation(Exclude = true)] + public void View() + { + _owner.View(); + } + + [Obfuscation(Exclude = true)] + public void Export() + { + _owner.Export(); + } + + [Obfuscation(Exclude = true)] + public void Renew() + { + _owner.Renew(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void CreateRequest() + { + _owner.CreateRequest(); + } + + [Obfuscation(Exclude = true)] + public void Complete() + { + _owner.Complete(); + } + + [Obfuscation(Exclude = true)] + public void CreateDomain() + { + _owner.CreateDomain(); + } + + [Obfuscation(Exclude = true)] + public void CreateSelf() + { + _owner.CreateSelf(); + } + + [Obfuscation(Exclude = true)] + public void Enable() + { + _owner.Enable(); + } + + [Obfuscation(Exclude = true)] + public void Disable() + { + _owner.Disable(); + } + } + + public CertificatesFeature(Module module) + { + Module = module; + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + protected void DisplayErrorMessage(Exception ex, ResourceManager resourceManager) + { + var service = (IManagementUIService)GetService(typeof(IManagementUIService)); + service.ShowError(ex, resourceManager.GetString("General"), "", false); + } + + protected object GetService(Type type) + { + return (Module as IServiceProvider).GetService(type); + } + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + Items = new List(); + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + if (service.ServerManager.Mode == WorkingMode.Jexus) + { + var certificate = AsyncHelper.RunSync(() => service.ServerManager.GetCertificateAsync()); + if (certificate != null) + { + Items.Add(new CertificatesItem(certificate, "Jexus", this)); + } + } + else + { + X509Store personal = new X509Store("MY", StoreLocation.LocalMachine); + personal.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); + foreach (var certificate in personal.Certificates) + { + Items.Add(new CertificatesItem(certificate, "Personal", this)); + } + + personal.Close(); + + if (Environment.OSVersion.Version.Major >= 8) + { + // IMPORTANT: WebHosting store is available since Windows 8. + X509Store hosting = new X509Store("WebHosting", StoreLocation.LocalMachine); + hosting.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); + foreach (var certificate in hosting.Certificates) + { + Items.Add(new CertificatesItem(certificate, "WebHosting", this)); + } + + hosting.Close(); + } + } + + OnCertificatesSettingsSaved(); + } + + public List Items { get; set; } + + public void Import() + { + var dialog = new ImportCertificateDialog(Module); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + Items.Add(new CertificatesItem(dialog.Item, dialog.Store, this)); + OnCertificatesSettingsSaved(); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove this certificate, and permanently remove it from the certificate store?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) != + DialogResult.Yes) + { + return; + } + + try + { + // remove certificate and mapping + using (var process = new Process()) + { + var start = process.StartInfo; + start.Verb = "runas"; + start.FileName = "cmd"; + start.Arguments = string.Format( + "/c \"\"{2}\" /h:\"{0}\" /s:{1}\"", + SelectedItem.Certificate.Thumbprint, + SelectedItem.Store == "Personal" ? "MY" : "WebHosting", + Path.Combine(Environment.CurrentDirectory, "certificateinstaller.exe")); + start.CreateNoWindow = true; + start.WindowStyle = ProcessWindowStyle.Hidden; + process.Start(); + process.WaitForExit(); + + if (process.ExitCode == 0) + { + Items.Remove(SelectedItem); + SelectedItem = null; + OnCertificatesSettingsSaved(); + } + } + } + catch (Exception) + { + // elevation is cancelled. + } + } + + protected void OnCertificatesSettingsSaved() + { + CertificatesSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210528"); + return false; + } + + private void Disable() + { + } + + private void Enable() + { + } + + private void CreateSelf() + { + var dialog = new SelfCertificateDialog(Module); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + Items.Add(new CertificatesItem(dialog.Item, dialog.Store, this)); + OnCertificatesSettingsSaved(); + } + + private void CreateDomain() + { + } + + private void Complete() + { + var dialog = new CompleteRequestDialog(Module); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + Items.Add(new CertificatesItem(dialog.Item, dialog.Store, this)); + OnCertificatesSettingsSaved(); + } + + private void CreateRequest() + { + var wizard = new CertificateRequestWizard(Module); + wizard.ShowDialog(); + } + + private void Export() + { + var dialog = new ExportCertificateDialog(SelectedItem.Certificate, Module); + dialog.ShowDialog(); + } + + private void Renew() + { + var wizard = new CertificateRenewWizard(SelectedItem.Certificate, Module); + wizard.ShowDialog(); + } + + private void View() + { + var cert = SelectedItem.Certificate; + DialogHelper.DisplayCertificate(cert, IntPtr.Zero); + } + + public bool AutomicRebindEnabled { get; set; } + + public CertificatesItem SelectedItem { get; internal set; } + + public CertificatesSettingsSavedEventHandler CertificatesSettingsUpdated { get; set; } + public string Description { get; } + + public virtual bool IsFeatureEnabled + { + get { return true; } + } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public Module Module { get; } + + public string Name + { + get + { + return "Server Certificates"; + } + } + } +} diff --git a/JexusManager.Features.Certificates/CertificatesItem.cs b/JexusManager.Features.Certificates/CertificatesItem.cs new file mode 100644 index 00000000..9688bc10 --- /dev/null +++ b/JexusManager.Features.Certificates/CertificatesItem.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates +{ + using System; + using System.Security.Cryptography.X509Certificates; + + internal class CertificatesItem : IEquatable + { + public CertificatesItem(X509Certificate2 certificate, string store, CertificatesFeature feature) + { + Certificate = certificate; + Store = store; + Feature = feature; + } + + public X509Certificate2 Certificate { get; set; } + public string Store { get; set; } + public CertificatesFeature Feature { get; private set; } + + public bool Equals(CertificatesItem other) + { + return other != null && other.Certificate.GetCertHashString() == Certificate.GetCertHashString(); + } + } +} \ No newline at end of file diff --git a/JexusManager.Features.Certificates/CertificatesModule.cs b/JexusManager.Features.Certificates/CertificatesModule.cs new file mode 100644 index 00000000..e9b35e8a --- /dev/null +++ b/JexusManager.Features.Certificates/CertificatesModule.cs @@ -0,0 +1,25 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates +{ + using System; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + using Properties; + + internal class CertificatesModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(CertificatesPage), "Server Certificates", + "Request and manage certificates for websites that use SSL", Resources.certificates_36, + Resources.certificates_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.Certificates/CertificatesModuleProvider.cs b/JexusManager.Features.Certificates/CertificatesModuleProvider.cs new file mode 100644 index 00000000..1c687d49 --- /dev/null +++ b/JexusManager.Features.Certificates/CertificatesModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates +{ + using System; + + using Microsoft.Web.Management.Server; + + public class CertificatesModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(Name, typeof(CertificatesModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return scope == ManagementScope.Server; + } + } +} diff --git a/JexusManager.Features.Certificates/CertificatesPage.Designer.cs b/JexusManager.Features.Certificates/CertificatesPage.Designer.cs new file mode 100644 index 00000000..d1f44730 --- /dev/null +++ b/JexusManager.Features.Certificates/CertificatesPage.Designer.cs @@ -0,0 +1,369 @@ +namespace JexusManager.Features.Certificates +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class CertificatesPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chIssuedTo = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chIssuedBy = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chExpiration = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chHash = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chStore = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.toolStrip2 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel2 = new System.Windows.Forms.ToolStripLabel(); + this.cbFilter = new System.Windows.Forms.ToolStripComboBox(); + this.btnGo = new System.Windows.Forms.ToolStripSplitButton(); + this.protocolToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.btnShowAll = new System.Windows.Forms.ToolStripButton(); + this.toolStripSeparator7 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripLabel3 = new System.Windows.Forms.ToolStripLabel(); + this.cbGroup = new System.Windows.Forms.ToolStripComboBox(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.toolStrip2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 6; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.splitContainer1_SplitterMoved); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "contextMenuStrip1"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.toolStrip2); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 9; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chName, + this.chIssuedTo, + this.chIssuedBy, + this.chExpiration, + this.chHash, + this.chStore}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 38); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 502); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.listView1_SelectedIndexChanged); + // + // chName + // + this.chName.Text = "Name"; + this.chName.Width = 180; + // + // chIssuedTo + // + this.chIssuedTo.Text = "Issued To"; + this.chIssuedTo.Width = 180; + // + // chIssuedBy + // + this.chIssuedBy.Text = "Issued By"; + this.chIssuedBy.Width = 180; + // + // chExpiration + // + this.chExpiration.Text = "Expiration Date"; + this.chExpiration.Width = 120; + // + // chHash + // + this.chHash.Text = "Certificate Hash"; + this.chHash.Width = 180; + // + // chStore + // + this.chStore.Text = "Certificate Store"; + this.chStore.Width = 120; + // + // toolStrip2 + // + this.toolStrip2.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel2, + this.cbFilter, + this.btnGo, + this.btnShowAll, + this.toolStripSeparator7, + this.toolStripLabel3, + this.cbGroup}); + this.toolStrip2.Location = new System.Drawing.Point(0, 13); + this.toolStrip2.Name = "toolStrip2"; + this.toolStrip2.Size = new System.Drawing.Size(560, 25); + this.toolStrip2.TabIndex = 3; + this.toolStrip2.Text = "toolStrip2"; + // + // toolStripLabel2 + // + this.toolStripLabel2.Name = "toolStripLabel2"; + this.toolStripLabel2.Size = new System.Drawing.Size(36, 22); + this.toolStripLabel2.Text = "Filter:"; + // + // cbFilter + // + this.cbFilter.Name = "cbFilter"; + this.cbFilter.Size = new System.Drawing.Size(121, 25); + // + // btnGo + // + this.btnGo.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.protocolToolStripMenuItem}); + this.btnGo.ImageTransparentColor = System.Drawing.Color.Magenta; + this.btnGo.Name = "btnGo"; + this.btnGo.Size = new System.Drawing.Size(54, 22); + this.btnGo.Text = "Go"; + this.btnGo.ToolTipText = "Go"; + // + // protocolToolStripMenuItem + // + this.protocolToolStripMenuItem.Name = "protocolToolStripMenuItem"; + this.protocolToolStripMenuItem.Size = new System.Drawing.Size(88, 22); + this.protocolToolStripMenuItem.Text = "All"; + // + // btnShowAll + // + this.btnShowAll.ImageTransparentColor = System.Drawing.Color.Magenta; + this.btnShowAll.Name = "btnShowAll"; + this.btnShowAll.Size = new System.Drawing.Size(73, 22); + this.btnShowAll.Text = "Show All"; + // + // toolStripSeparator7 + // + this.toolStripSeparator7.Name = "toolStripSeparator7"; + this.toolStripSeparator7.Size = new System.Drawing.Size(6, 25); + // + // toolStripLabel3 + // + this.toolStripLabel3.Name = "toolStripLabel3"; + this.toolStripLabel3.Size = new System.Drawing.Size(59, 22); + this.toolStripLabel3.Text = "Group by:"; + // + // cbGroup + // + this.cbGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbGroup.Items.AddRange(new object[] { + "No Grouping", + "Category", + "Area"}); + this.cbGroup.Name = "cbGroup"; + this.cbGroup.Size = new System.Drawing.Size(121, 25); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(545, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to request and manage certificates that the Web server can use w" + + "ith websites configured for SSL."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 8; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(189, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Server Certificates"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // CertificatesPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "CertificatesPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.toolStrip2.ResumeLayout(false); + this.toolStrip2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private ListView listView1; + private ColumnHeader chName; + private ColumnHeader chIssuedTo; + private ColumnHeader chIssuedBy; + private ColumnHeader chExpiration; + private ColumnHeader chHash; + private ColumnHeader chStore; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private ContextMenuStrip cmsActionPanel; + private PictureBox pictureBox1; + private Panel panel2; + private ToolStrip toolStrip2; + private ToolStripLabel toolStripLabel2; + private ToolStripComboBox cbFilter; + private ToolStripSplitButton btnGo; + private ToolStripMenuItem protocolToolStripMenuItem; + private ToolStripButton btnShowAll; + private ToolStripSeparator toolStripSeparator7; + private ToolStripLabel toolStripLabel3; + private ToolStripComboBox cbGroup; + } +} diff --git a/JexusManager.Features.Certificates/CertificatesPage.cs b/JexusManager.Features.Certificates/CertificatesPage.cs new file mode 100644 index 00000000..14e450c3 --- /dev/null +++ b/JexusManager.Features.Certificates/CertificatesPage.cs @@ -0,0 +1,142 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates +{ + using System; + using System.Collections; + using System.Reflection; + using System.Security.Cryptography.X509Certificates; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class CertificatesPage : ModuleListPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly CertificatesPage _owner; + + public PageTaskList(CertificatesPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class CertificatesListViewItem : ListViewItem + { + public CertificatesItem Item { get; } + private readonly CertificatesPage _page; + + public CertificatesListViewItem(CertificatesItem item, CertificatesPage page) + : base(item.Certificate.FriendlyName) + { + Item = item; + _page = page; + SubItems.Add(new ListViewSubItem(this, item.Certificate.GetNameInfo(X509NameType.DnsName, false))); + SubItems.Add(new ListViewSubItem(this, item.Certificate.GetNameInfo(X509NameType.DnsName, true))); + SubItems.Add(new ListViewSubItem(this, item.Certificate.GetExpirationDateString())); + SubItems.Add(new ListViewSubItem(this, item.Certificate.GetCertHashString())); + SubItems.Add(new ListViewSubItem(this, item.Store)); + } + } + + private CertificatesFeature _feature; + private PageTaskList _taskList; + + public CertificatesPage() + { + InitializeComponent(); + btnGo.Image = DefaultTaskList.GoImage; + btnShowAll.Image = DefaultTaskList.ShowAllImage; + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new CertificatesFeature(Module); + _feature.CertificatesSettingsUpdated = InitializeListPage; + _feature.Load(); + } + + protected override void InitializeListPage() + { + listView1.Items.Clear(); + foreach (var file in _feature.Items) + { + listView1.Items.Add(new CertificatesListViewItem(file, this)); + } + + if (_feature.SelectedItem == null) + { + Refresh(); + return; + } + + foreach (CertificatesListViewItem item in listView1.Items) + { + if (item.Item == _feature.SelectedItem) + { + item.Selected = true; + } + } + } + + protected override void Refresh() + { + Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + private void listView1_SelectedIndexChanged(object sender, EventArgs e) + { + _feature.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((CertificatesListViewItem)listView1.SelectedItems[0]).Item + : null; + Refresh(); + } + + protected override bool ShowHelp() + { + _feature.ShowHelp(); + return true; + } + + private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + } +} diff --git a/JexusManager.Features.Certificates/CertificatesPage.resx b/JexusManager.Features.Certificates/CertificatesPage.resx new file mode 100644 index 00000000..330bdf72 --- /dev/null +++ b/JexusManager.Features.Certificates/CertificatesPage.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 122, 17 + + + 451, 56 + + + 17, 17 + + + 17, 17 + + + 179 + + \ No newline at end of file diff --git a/JexusManager.Features.Certificates/CertificatesSettingsSavedEventHandler.cs b/JexusManager.Features.Certificates/CertificatesSettingsSavedEventHandler.cs new file mode 100644 index 00000000..3fe2e50a --- /dev/null +++ b/JexusManager.Features.Certificates/CertificatesSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates +{ + public delegate void CertificatesSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.Certificates/CompleteRequestDialog.Designer.cs b/JexusManager.Features.Certificates/CompleteRequestDialog.Designer.cs new file mode 100644 index 00000000..f49c5924 --- /dev/null +++ b/JexusManager.Features.Certificates/CompleteRequestDialog.Designer.cs @@ -0,0 +1,219 @@ +namespace JexusManager.Features.Certificates +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class CompleteRequestDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.panel1 = new System.Windows.Forms.Panel(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.txtTitle = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.cbStore = new System.Windows.Forms.ComboBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.label4 = new System.Windows.Forms.Label(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.panel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // panel1 + // + this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel1.BackColor = System.Drawing.Color.White; + this.panel1.Controls.Add(this.pictureBox1); + this.panel1.Controls.Add(this.txtTitle); + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(670, 65); + this.panel1.TabIndex = 11; + // + // pictureBox1 + // + this.pictureBox1.Image = Properties.Resources.certificates_48; + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(48, 48); + this.pictureBox1.TabIndex = 1; + this.pictureBox1.TabStop = false; + // + // txtTitle + // + this.txtTitle.AutoSize = true; + this.txtTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtTitle.Location = new System.Drawing.Point(87, 22); + this.txtTitle.Name = "txtTitle"; + this.txtTitle.Size = new System.Drawing.Size(326, 24); + this.txtTitle.TabIndex = 2; + this.txtTitle.Text = "Specify Certificate Authority Response"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(23, 82); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(502, 26); + this.label1.TabIndex = 12; + this.label1.Text = "Specify a previously created certificate request by retrieving the file that cont" + + "ains the certificate authority\'s\r\nresponse."; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(23, 180); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(75, 13); + this.label2.TabIndex = 13; + this.label2.Text = "Friendly name:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(26, 196); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(238, 20); + this.txtName.TabIndex = 2; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(23, 246); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(229, 13); + this.label3.TabIndex = 15; + this.label3.Text = "Select a certificate store for the new certificate:"; + // + // cbStore + // + this.cbStore.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbStore.FormattingEnabled = true; + this.cbStore.Items.AddRange(new object[] { + "Personal", + "Web Hosting"}); + this.cbStore.Location = new System.Drawing.Point(26, 262); + this.cbStore.Name = "cbStore"; + this.cbStore.Size = new System.Drawing.Size(238, 21); + this.cbStore.TabIndex = 3; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(466, 441); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(85, 23); + this.btnOK.TabIndex = 4; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(557, 441); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(85, 23); + this.btnCancel.TabIndex = 5; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(23, 119); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(278, 13); + this.label4.TabIndex = 19; + this.label4.Text = "File name containing the certification authority\'s response:"; + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(26, 135); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(360, 20); + this.txtPath.TabIndex = 0; + // + // btnBrowse + // + this.btnBrowse.Location = new System.Drawing.Point(392, 133); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(30, 23); + this.btnBrowse.TabIndex = 1; + this.btnBrowse.Text = "..."; + this.btnBrowse.UseVisualStyleBackColor = true; + // + // CompleteRequestDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(654, 476); + this.Controls.Add(this.btnBrowse); + this.Controls.Add(this.txtPath); + this.Controls.Add(this.label4); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.cbStore); + this.Controls.Add(this.label3); + this.Controls.Add(this.txtName); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Controls.Add(this.panel1); + this.Name = "CompleteRequestDialog"; + this.Text = "Complete Certificate Request"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.SelfCertificateDialogHelpButtonClicked); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Panel panel1; + private PictureBox pictureBox1; + private Label txtTitle; + private Label label1; + private Label label2; + private TextBox txtName; + private Label label3; + private ComboBox cbStore; + private Button btnOK; + private Button btnCancel; + private Label label4; + private TextBox txtPath; + private Button btnBrowse; + } +} diff --git a/JexusManager.Features.Certificates/CompleteRequestDialog.cs b/JexusManager.Features.Certificates/CompleteRequestDialog.cs new file mode 100644 index 00000000..c737e11d --- /dev/null +++ b/JexusManager.Features.Certificates/CompleteRequestDialog.cs @@ -0,0 +1,155 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Web.Administration; + +namespace JexusManager.Features.Certificates +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.IO; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Security.Cryptography.X509Certificates; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + using Mono.Security.Authenticode; + + public partial class CompleteRequestDialog : DialogForm + { + public CompleteRequestDialog(IServiceProvider serviceProvider) + : base(serviceProvider) + { + InitializeComponent(); + cbStore.SelectedIndex = 0; + if (Environment.OSVersion.Version.Major < 8) + { + // IMPORTANT: WebHosting store is available since Windows 8. + cbStore.Enabled = false; + } + + if (!Helper.IsRunningOnMono()) + { + NativeMethods.TryAddShieldToButton(btnOK); + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text) + && !string.IsNullOrWhiteSpace(txtPath.Text); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + if (!File.Exists(txtPath.Text)) + { + ShowMessage( + string.Format( + "There was an error while performing this operation.{0}{0}Details:{0}{0}Could not find file '{1}'.", + Environment.NewLine, + txtPath.Text), + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + // TODO: check administrator permission. + var x509 = new X509Certificate2(txtPath.Text); + + var filename = DialogHelper.GetPrivateKeyFile(x509.Subject); + if (!File.Exists(filename)) + { + ShowMessage( + string.Format( + "There was an error while performing this operation.{0}{0}Details:{0}{0}Could not find private key for '{1}'.", + Environment.NewLine, + txtPath.Text), + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + x509.PrivateKey = PrivateKey.CreateFromFile(filename).RSA; + x509.FriendlyName = txtName.Text; + var p12File = DialogHelper.GetTempFileName(); + var p12pwd = "test"; + var raw = x509.Export(X509ContentType.Pfx, p12pwd); + File.WriteAllBytes(p12File, raw); + + Item = x509; + Store = cbStore.SelectedIndex == 0 ? "Personal" : "WebHosting"; + + try + { + // add certificate + using (var process = new Process()) + { + var start = process.StartInfo; + start.Verb = "runas"; + start.FileName = "cmd"; + start.Arguments = string.Format("/c \"\"{4}\" /f:\"{0}\" /p:{1} /n:\"{2}\" /s:{3}\"", + p12File, + p12pwd, + txtName.Text, + cbStore.SelectedIndex == 0 ? "MY" : "WebHosting", + Path.Combine(Environment.CurrentDirectory, "certificateinstaller.exe")); + start.CreateNoWindow = true; + start.WindowStyle = ProcessWindowStyle.Hidden; + process.Start(); + process.WaitForExit(); + File.Delete(p12File); + if (process.ExitCode == 0) + { + this.DialogResult = DialogResult.OK; + } + else + { + MessageBox.Show(process.ExitCode.ToString()); + } + } + } + catch (Exception) + { + // elevation is cancelled. + } + })); + + container.Add( + Observable.FromEventPattern(btnBrowse, "Click") + .Subscribe(evt => + { + var dialog = new OpenFileDialog + { + FileName = txtPath.Text + }; + if (dialog.ShowDialog() == DialogResult.Cancel) + { + return; + } + + txtPath.Text = dialog.FileName; + })); + } + + public string Store { get; set; } + + public X509Certificate2 Item { get; set; } + + private void SelfCertificateDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210528"); + } + } +} diff --git a/JexusManager.Features.Certificates/CompleteRequestDialog.resx b/JexusManager.Features.Certificates/CompleteRequestDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Certificates/CompleteRequestDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Certificates/ExportCertificateDialog.Designer.cs b/JexusManager.Features.Certificates/ExportCertificateDialog.Designer.cs new file mode 100644 index 00000000..7f2d8b59 --- /dev/null +++ b/JexusManager.Features.Certificates/ExportCertificateDialog.Designer.cs @@ -0,0 +1,160 @@ +namespace JexusManager.Features.Certificates +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class ExportCertificateDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.txtPassword = new System.Windows.Forms.TextBox(); + this.txtConfirm = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 18); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(52, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Export to:"; + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(15, 34); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(277, 20); + this.txtPath.TabIndex = 1; + // + // txtPassword + // + this.txtPassword.Location = new System.Drawing.Point(15, 95); + this.txtPassword.Name = "txtPassword"; + this.txtPassword.PasswordChar = '*'; + this.txtPassword.Size = new System.Drawing.Size(317, 20); + this.txtPassword.TabIndex = 2; + // + // txtConfirm + // + this.txtConfirm.Location = new System.Drawing.Point(15, 159); + this.txtConfirm.Name = "txtConfirm"; + this.txtConfirm.PasswordChar = '*'; + this.txtConfirm.Size = new System.Drawing.Size(317, 20); + this.txtConfirm.TabIndex = 3; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 79); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(56, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Password:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 143); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(93, 13); + this.label3.TabIndex = 5; + this.label3.Text = "Confirm password:"; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(242, 216); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(90, 23); + this.btnCancel.TabIndex = 6; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(151, 216); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(85, 23); + this.btnOK.TabIndex = 7; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnBrowse + // + this.btnBrowse.Location = new System.Drawing.Point(299, 32); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(33, 23); + this.btnBrowse.TabIndex = 8; + this.btnBrowse.Text = "..."; + this.btnBrowse.UseVisualStyleBackColor = true; + // + // ExportCertificateDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(344, 251); + this.Controls.Add(this.btnBrowse); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtConfirm); + this.Controls.Add(this.txtPassword); + this.Controls.Add(this.txtPath); + this.Controls.Add(this.label1); + this.Name = "ExportCertificateDialog"; + this.Text = "Export Certificate"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.ExportCertificateDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label1; + private TextBox txtPath; + private TextBox txtPassword; + private TextBox txtConfirm; + private Label label2; + private Label label3; + private Button btnCancel; + private Button btnOK; + private Button btnBrowse; + } +} diff --git a/JexusManager.Features.Certificates/ExportCertificateDialog.cs b/JexusManager.Features.Certificates/ExportCertificateDialog.cs new file mode 100644 index 00000000..1d895f36 --- /dev/null +++ b/JexusManager.Features.Certificates/ExportCertificateDialog.cs @@ -0,0 +1,75 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.IO; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Security.Cryptography.X509Certificates; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + public partial class ExportCertificateDialog : DialogForm + { + private readonly X509Certificate2 _certificate2; + + public ExportCertificateDialog(X509Certificate2 certificate2, IServiceProvider serviceProvider) + : base(serviceProvider) + { + _certificate2 = certificate2; + InitializeComponent(); + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtPath, "TextChanged") + .Merge(Observable.FromEventPattern(txtPassword, "TextChanged")) + .Merge(Observable.FromEventPattern(txtConfirm, "TextChange")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtPath.Text) + && !string.IsNullOrWhiteSpace(txtPassword.Text) + && !string.IsNullOrWhiteSpace(txtConfirm.Text) + && txtPassword.Text == txtConfirm.Text; + })); + + container.Add( + Observable.FromEventPattern(btnBrowse, "Click") + .Subscribe(evt => + { + var dialog = new SaveFileDialog + { + FileName = txtPath.Text + }; + if (dialog.ShowDialog() == DialogResult.Cancel) + { + return; + } + + txtPath.Text = dialog.FileName; + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + var raw = _certificate2.Export(X509ContentType.Pfx, txtPassword.Text); + File.WriteAllBytes(txtPath.Text, raw); + DialogResult = DialogResult.OK; + })); + } + + private void ExportCertificateDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210528"); + } + } +} diff --git a/JexusManager.Features.Certificates/ExportCertificateDialog.resx b/JexusManager.Features.Certificates/ExportCertificateDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Certificates/ExportCertificateDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Certificates/ImportCertificateDialog.Designer.cs b/JexusManager.Features.Certificates/ImportCertificateDialog.Designer.cs new file mode 100644 index 00000000..25f53edc --- /dev/null +++ b/JexusManager.Features.Certificates/ImportCertificateDialog.Designer.cs @@ -0,0 +1,184 @@ +namespace JexusManager.Features.Certificates +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class ImportCertificateDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.txtFile = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.txtPassword = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.cbStore = new System.Windows.Forms.ComboBox(); + this.cbExport = new System.Windows.Forms.CheckBox(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(252, 251); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(156, 251); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnBrowse + // + this.btnBrowse.Location = new System.Drawing.Point(317, 36); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(30, 23); + this.btnBrowse.TabIndex = 2; + this.btnBrowse.Text = "..."; + this.btnBrowse.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(9, 22); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(99, 13); + this.label1.TabIndex = 3; + this.label1.Text = "Certificate file (.pfx):"; + // + // txtFile + // + this.txtFile.Location = new System.Drawing.Point(12, 38); + this.txtFile.Name = "txtFile"; + this.txtFile.Size = new System.Drawing.Size(299, 20); + this.txtFile.TabIndex = 4; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(9, 78); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(56, 13); + this.label2.TabIndex = 5; + this.label2.Text = "Password:"; + // + // txtPassword + // + this.txtPassword.Location = new System.Drawing.Point(12, 94); + this.txtPassword.Name = "txtPassword"; + this.txtPassword.Size = new System.Drawing.Size(335, 20); + this.txtPassword.TabIndex = 6; + this.txtPassword.UseSystemPasswordChar = true; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(9, 135); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(118, 13); + this.label3.TabIndex = 7; + this.label3.Text = "Select Certificate Store:"; + // + // cbStore + // + this.cbStore.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbStore.Enabled = false; + this.cbStore.FormattingEnabled = true; + this.cbStore.Items.AddRange(new object[] { + "Jexus"}); + this.cbStore.Location = new System.Drawing.Point(12, 151); + this.cbStore.Name = "cbStore"; + this.cbStore.Size = new System.Drawing.Size(335, 21); + this.cbStore.TabIndex = 8; + // + // cbExport + // + this.cbExport.AutoSize = true; + this.cbExport.Enabled = false; + this.cbExport.Location = new System.Drawing.Point(12, 200); + this.cbExport.Name = "cbExport"; + this.cbExport.Size = new System.Drawing.Size(190, 17); + this.cbExport.TabIndex = 9; + this.cbExport.Text = "Allow this certificate to be exported"; + this.cbExport.UseVisualStyleBackColor = true; + // + // ImportCertificateDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(359, 286); + this.Controls.Add(this.cbExport); + this.Controls.Add(this.cbStore); + this.Controls.Add(this.label3); + this.Controls.Add(this.txtPassword); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtFile); + this.Controls.Add(this.label1); + this.Controls.Add(this.btnBrowse); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.HelpButton = true; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "ImportCertificateDialog"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Import Certificate"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.ImportCertificateDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Button btnBrowse; + private Label label1; + private TextBox txtFile; + private Label label2; + private TextBox txtPassword; + private Label label3; + private ComboBox cbStore; + private CheckBox cbExport; + } +} diff --git a/JexusManager.Features.Certificates/ImportCertificateDialog.cs b/JexusManager.Features.Certificates/ImportCertificateDialog.cs new file mode 100644 index 00000000..4267eb42 --- /dev/null +++ b/JexusManager.Features.Certificates/ImportCertificateDialog.cs @@ -0,0 +1,168 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.IO; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Security.Cryptography; + using System.Security.Cryptography.X509Certificates; + using System.Text; + using System.Windows.Forms; + + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client.Win32; + + using Org.BouncyCastle.Crypto; + using Org.BouncyCastle.OpenSsl; + using Org.BouncyCastle.Security; + + public partial class ImportCertificateDialog : DialogForm + { + public ImportCertificateDialog(IServiceProvider serviceProvider) + : base(serviceProvider) + { + InitializeComponent(); + cbStore.SelectedIndex = 0; + if (Environment.OSVersion.Version.Major < 8) + { + // IMPORTANT: WebHosting store is available since Windows 8. + cbStore.Enabled = false; + } + + if (!Helper.IsRunningOnMono()) + { + NativeMethods.TryAddShieldToButton(btnOK); + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnBrowse, "Click") + .Subscribe(evt => + { + var dialog = new OpenFileDialog { Filter = ".pfx|*.pfx|*.*|*.*", FilterIndex = 0, Multiselect = false }; + if (dialog.ShowDialog() == DialogResult.Cancel) + { + return; + } + + txtFile.Text = dialog.FileName; + })); + + container.Add( + Observable.FromEventPattern(txtFile, "TextChanged") + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtFile.Text); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(async evt => + { + try + { + // Load your certificate from file + Item = new X509Certificate2(txtFile.Text, txtPassword.Text, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.PersistKeySet); + Store = cbStore.SelectedIndex == 0 ? "Personal" : "WebHosting"; + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + if (service.ServerManager.Mode == WorkingMode.Jexus) + { + // Public Key; + StringBuilder publicBuilder = new StringBuilder(); + publicBuilder.AppendLine("-----BEGIN CERTIFICATE-----"); + publicBuilder.AppendLine(Convert.ToBase64String(Item.Export(X509ContentType.Cert), Base64FormattingOptions.InsertLineBreaks)); + publicBuilder.AppendLine("-----END CERTIFICATE-----"); + var file = await service.ServerManager.SaveCertificateAsync(publicBuilder.ToString()); + service.ServerManager.SetCertificate(file); + // Private Key + RSACryptoServiceProvider rsa = (RSACryptoServiceProvider)Item.PrivateKey; + MemoryStream memoryStream = new MemoryStream(); + TextWriter streamWriter = new StreamWriter(memoryStream); + PemWriter pemWriter = new PemWriter(streamWriter); + AsymmetricCipherKeyPair keyPair = DotNetUtilities.GetRsaKeyPair(rsa); + pemWriter.WriteObject(keyPair.Private); + streamWriter.Flush(); + string output = Encoding.ASCII.GetString(memoryStream.GetBuffer()).Trim(); + int indexOfFooter = output.IndexOf("-----END RSA PRIVATE KEY-----", StringComparison.Ordinal); + memoryStream.Close(); + streamWriter.Close(); + string key = output.Substring(0, indexOfFooter + 29); + var keyFile = await service.ServerManager.SaveKeyAsync(key); + service.ServerManager.SetKeyFile(keyFile); + await service.ServerManager.CommitChangesAsync(); + } + else + { + try + { + using (var process = new Process()) + { + // add certificate + var start = process.StartInfo; + start.Verb = "runas"; + start.FileName = "cmd"; + start.Arguments = string.Format( + "/c \"\"{4}\" /f:\"{0}\" /p:{1} /n:\"{2}\" /s:{3}\"", + txtFile.Text, + txtPassword.Text, + Item.FriendlyName, + cbStore.SelectedIndex == 0 ? "MY" : "WebHosting", + Path.Combine(Environment.CurrentDirectory, "certificateinstaller.exe")); + start.CreateNoWindow = true; + start.WindowStyle = ProcessWindowStyle.Hidden; + process.Start(); + process.WaitForExit(); + if (process.ExitCode == 0) + { + this.DialogResult = DialogResult.OK; + } + else + { + MessageBox.Show(process.ExitCode.ToString()); + } + } + } + catch (Exception) + { + // elevation is cancelled. + } + } + } + catch (Exception ex) + { + var message = new StringBuilder() + .AppendLine("There was an error while performing this operation.") + .AppendLine() + .AppendLine("Details:") + .AppendLine() + .AppendLine(ex.Message); + ShowMessage( + message.ToString(), + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + } + })); + } + + private void ImportCertificateDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210528"); + } + + public string Store { get; set; } + + public X509Certificate2 Item { get; set; } + } +} diff --git a/JexusManager.Features.Certificates/ImportCertificateDialog.resx b/JexusManager.Features.Certificates/ImportCertificateDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Certificates/ImportCertificateDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Certificates/JexusManager.Features.Certificates.csproj b/JexusManager.Features.Certificates/JexusManager.Features.Certificates.csproj new file mode 100644 index 00000000..c8fbb50d --- /dev/null +++ b/JexusManager.Features.Certificates/JexusManager.Features.Certificates.csproj @@ -0,0 +1,237 @@ + + + + + Debug + AnyCPU + {D37CF28B-10F1-4F28-B933-C5E18D7F09AA} + Library + Properties + JexusManager.Features.Certificates + JexusManager.Features.Certificates + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + ..\packages\BouncyCastle.1.8.1\lib\BouncyCastle.Crypto.dll + True + + + ..\lib\Mono.Security.dll + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + Helper.cs + + + + + + + UserControl + + + CertificatesPage.cs + + + + Form + + + CompleteRequestDialog.cs + + + Form + + + ExportCertificateDialog.cs + + + Form + + + ImportCertificateDialog.cs + + + + True + True + Resources.resx + + + Form + + + SelfCertificateDialog.cs + + + Form + + + CertificateRenewWizard.cs + + + + UserControl + + + FinishPage.cs + + + usercontrol + + + OptionsPage.cs + + + Form + + + CertificateRequestWizard.cs + + + + UserControl + + + FinishPage.cs + + + UserControl + + + KeysPage.cs + + + usercontrol + + + PropertiesPage.cs + + + + + CertificatesPage.cs + + + CompleteRequestDialog.cs + + + ExportCertificateDialog.cs + + + ImportCertificateDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SelfCertificateDialog.cs + + + CertificateRenewWizard.cs + + + FinishPage.cs + + + OptionsPage.cs + + + CertificateRequestWizard.cs + + + FinishPage.cs + + + KeysPage.cs + + + PropertiesPage.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Certificates/JexusManager.snk b/JexusManager.Features.Certificates/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Certificates/Properties/AssemblyInfo.cs b/JexusManager.Features.Certificates/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..d103ce55 --- /dev/null +++ b/JexusManager.Features.Certificates/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.Certificates")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.Certificates")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("d37cf28b-10f1-4f28-b933-c5e18d7f09aa")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JexusManager.Features.Certificates/Properties/Resources.Designer.cs b/JexusManager.Features.Certificates/Properties/Resources.Designer.cs new file mode 100644 index 00000000..d5176bb8 --- /dev/null +++ b/JexusManager.Features.Certificates/Properties/Resources.Designer.cs @@ -0,0 +1,83 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.Certificates.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.Certificates.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap certificates_36 { + get { + object obj = ResourceManager.GetObject("certificates_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap certificates_48 { + get { + object obj = ResourceManager.GetObject("certificates_48", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.Certificates/Properties/Resources.resx b/JexusManager.Features.Certificates/Properties/Resources.resx new file mode 100644 index 00000000..96b46ac7 --- /dev/null +++ b/JexusManager.Features.Certificates/Properties/Resources.resx @@ -0,0 +1,127 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\certificates_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\certificates_48.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.Certificates/Resources/certificates_36.png b/JexusManager.Features.Certificates/Resources/certificates_36.png new file mode 100644 index 0000000000000000000000000000000000000000..790b2a64ba7e1756e39d894a91ea7f1a69d46a77 GIT binary patch literal 2147 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 Z;=fyR_=cz&1o;2}002ovPDHLkV1f*A8lwOJ literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Certificates/Resources/certificates_48.png b/JexusManager.Features.Certificates/Resources/certificates_48.png new file mode 100644 index 0000000000000000000000000000000000000000..572f2bd55ca61f52c0522f9283b9af478bab901f GIT binary patch literal 3196 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 + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.panel1 = new System.Windows.Forms.Panel(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.txtTitle = new System.Windows.Forms.Label(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.cbStore = new System.Windows.Forms.ComboBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.label4 = new System.Windows.Forms.Label(); + this.txtCommonName = new System.Windows.Forms.TextBox(); + this.cbLength = new System.Windows.Forms.ComboBox(); + this.label5 = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + this.cbHashing = new System.Windows.Forms.ComboBox(); + this.panel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // panel1 + // + this.panel1.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel1.BackColor = System.Drawing.Color.White; + this.panel1.Controls.Add(this.pictureBox1); + this.panel1.Controls.Add(this.txtTitle); + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(670, 65); + this.panel1.TabIndex = 11; + // + // pictureBox1 + // + this.pictureBox1.Image = Properties.Resources.certificates_48; + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(48, 48); + this.pictureBox1.TabIndex = 1; + this.pictureBox1.TabStop = false; + // + // txtTitle + // + this.txtTitle.AutoSize = true; + this.txtTitle.Font = new System.Drawing.Font("Microsoft Sans Serif", 14.25F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.txtTitle.Location = new System.Drawing.Point(87, 22); + this.txtTitle.Name = "txtTitle"; + this.txtTitle.Size = new System.Drawing.Size(200, 24); + this.txtTitle.TabIndex = 2; + this.txtTitle.Text = "Specify Friendly Name"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(23, 82); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(483, 26); + this.label1.TabIndex = 12; + this.label1.Text = "Specify a file name for the certificate request. This information can be sent to " + + "a certificate authority for\r\nsigning:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(23, 126); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(201, 13); + this.label2.TabIndex = 13; + this.label2.Text = "Specify a friendly name for the certificate:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(26, 142); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(360, 20); + this.txtName.TabIndex = 14; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(23, 192); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(229, 13); + this.label3.TabIndex = 15; + this.label3.Text = "Select a certificate store for the new certificate:"; + // + // cbStore + // + this.cbStore.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbStore.FormattingEnabled = true; + this.cbStore.Items.AddRange(new object[] { + "Personal", + "Web Hosting"}); + this.cbStore.Location = new System.Drawing.Point(26, 208); + this.cbStore.Name = "cbStore"; + this.cbStore.Size = new System.Drawing.Size(238, 21); + this.cbStore.TabIndex = 16; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(466, 441); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(85, 23); + this.btnOK.TabIndex = 17; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(557, 441); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(85, 23); + this.btnCancel.TabIndex = 18; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(23, 260); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(163, 13); + this.label4.TabIndex = 19; + this.label4.Text = "Specify a custom common name:"; + // + // txtCommonName + // + this.txtCommonName.Location = new System.Drawing.Point(26, 276); + this.txtCommonName.Name = "txtCommonName"; + this.txtCommonName.Size = new System.Drawing.Size(360, 20); + this.txtCommonName.TabIndex = 20; + // + // cbLength + // + this.cbLength.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbLength.FormattingEnabled = true; + this.cbLength.Items.AddRange(new object[] { + "384", + "512", + "1024", + "2048", + "4096", + "8192", + "16384"}); + this.cbLength.Location = new System.Drawing.Point(26, 331); + this.cbLength.Name = "cbLength"; + this.cbLength.Size = new System.Drawing.Size(238, 21); + this.cbLength.TabIndex = 22; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(23, 315); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(54, 13); + this.label5.TabIndex = 21; + this.label5.Text = "Bit length:"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(23, 372); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(87, 13); + this.label6.TabIndex = 23; + this.label6.Text = "Hashing method:"; + // + // cbHashing + // + this.cbHashing.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbHashing.FormattingEnabled = true; + this.cbHashing.Items.AddRange(new object[] { + "SHA1", + "SHA2 (SHA256)"}); + this.cbHashing.Location = new System.Drawing.Point(26, 388); + this.cbHashing.Name = "cbHashing"; + this.cbHashing.Size = new System.Drawing.Size(238, 21); + this.cbHashing.TabIndex = 24; + // + // SelfCertificateDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(654, 476); + this.Controls.Add(this.cbHashing); + this.Controls.Add(this.label6); + this.Controls.Add(this.cbLength); + this.Controls.Add(this.label5); + this.Controls.Add(this.txtCommonName); + this.Controls.Add(this.label4); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.cbStore); + this.Controls.Add(this.label3); + this.Controls.Add(this.txtName); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Controls.Add(this.panel1); + this.Name = "SelfCertificateDialog"; + this.Text = "Create Self-Signed Certificate"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.SelfCertificateDialogHelpButtonClicked); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Panel panel1; + private PictureBox pictureBox1; + private Label txtTitle; + private Label label1; + private Label label2; + private TextBox txtName; + private Label label3; + private ComboBox cbStore; + private Button btnOK; + private Button btnCancel; + private Label label4; + private TextBox txtCommonName; + private ComboBox cbLength; + private Label label5; + private Label label6; + private ComboBox cbHashing; + } +} diff --git a/JexusManager.Features.Certificates/SelfCertificateDialog.cs b/JexusManager.Features.Certificates/SelfCertificateDialog.cs new file mode 100644 index 00000000..1d47a7c2 --- /dev/null +++ b/JexusManager.Features.Certificates/SelfCertificateDialog.cs @@ -0,0 +1,204 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Web.Administration; + +namespace JexusManager.Features.Certificates +{ + using System; + using System.Collections; + using System.ComponentModel; + using System.Diagnostics; + using System.IO; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Security.Cryptography; + using System.Security.Cryptography.X509Certificates; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + using Mono.Security.X509; + using Mono.Security.X509.Extensions; + + using Org.BouncyCastle.Crypto; + using Org.BouncyCastle.Crypto.Digests; + using Org.BouncyCastle.Security; + using Org.BouncyCastle.X509; + + using X509Certificate = Mono.Security.X509.X509Certificate; + + public partial class SelfCertificateDialog : DialogForm + { + public SelfCertificateDialog(IServiceProvider serviceProvider) + : base(serviceProvider) + { + InitializeComponent(); + cbStore.SelectedIndex = 0; + cbLength.SelectedIndex = 3; + cbHashing.SelectedIndex = 1; + txtCommonName.Text = Environment.MachineName; + + if (Environment.OSVersion.Version.Major < 8) + { + // IMPORTANT: WebHosting store is available since Windows 8. + cbStore.Enabled = false; + } + + if (!Helper.IsRunningOnMono()) + { + NativeMethods.TryAddShieldToButton(btnOK); + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + // Generate certificate + string defaultIssuer = string.Format("CN={0}", txtCommonName.Text); + string defaultSubject = defaultIssuer; + byte[] sn = Guid.NewGuid().ToByteArray(); + string subject = defaultSubject; + string issuer = defaultIssuer; + DateTime notBefore = DateTime.Now; + DateTime notAfter = new DateTime(643445675990000000); // 12/31/2039 23:59:59Z + + RSA issuerKey = new RSACryptoServiceProvider(int.Parse(cbLength.Text)); + RSA subjectKey = null; + + CspParameters subjectParams = new CspParameters(); + CspParameters issuerParams = new CspParameters(); + BasicConstraintsExtension bce = new BasicConstraintsExtension + { + PathLenConstraint = BasicConstraintsExtension.NoPathLengthConstraint, + CertificateAuthority = true + }; + ExtendedKeyUsageExtension eku = new ExtendedKeyUsageExtension(); + eku.KeyPurpose.Add("1.3.6.1.5.5.7.3.1"); + SubjectAltNameExtension alt = null; + string p12File = Path.GetTempFileName(); + string p12pwd = "test"; + + // serial number MUST be positive + if ((sn[0] & 0x80) == 0x80) + { + sn[0] -= 0x80; + } + + if (subject != defaultSubject) + { + issuer = subject; + issuerKey = null; + } + else + { + subject = issuer; + subjectKey = issuerKey; + } + + if (subject == null) + throw new Exception("Missing Subject Name"); + + X509CertificateBuilder cb = new X509CertificateBuilder(3); + cb.SerialNumber = sn; + cb.IssuerName = issuer; + cb.NotBefore = notBefore; + cb.NotAfter = notAfter; + cb.SubjectName = subject; + cb.SubjectPublicKey = subjectKey; + // extensions + if (bce != null) + cb.Extensions.Add(bce); + if (eku != null) + cb.Extensions.Add(eku); + if (alt != null) + cb.Extensions.Add(alt); + + IDigest digest = new Sha1Digest(); + byte[] resBuf = new byte[digest.GetDigestSize()]; + var spki = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(DotNetUtilities.GetRsaPublicKey(issuerKey)); + byte[] bytes = spki.PublicKeyData.GetBytes(); + digest.BlockUpdate(bytes, 0, bytes.Length); + digest.DoFinal(resBuf, 0); + + cb.Extensions.Add(new SubjectKeyIdentifierExtension { Identifier = resBuf }); + cb.Extensions.Add(new AuthorityKeyIdentifierExtension { Identifier = resBuf }); + // signature + string hashName = cbHashing.SelectedIndex == 0 ? "SHA1" : "SHA256"; + cb.Hash = hashName; + byte[] rawcert = cb.Sign(issuerKey); + + PKCS12 p12 = new PKCS12(); + p12.Password = p12pwd; + + ArrayList list = new ArrayList(); + // we use a fixed array to avoid endianess issues + // (in case some tools requires the ID to be 1). + list.Add(new byte[] { 1, 0, 0, 0 }); + Hashtable attributes = new Hashtable(1); + attributes.Add(PKCS9.localKeyId, list); + + p12.AddCertificate(new X509Certificate(rawcert), attributes); + p12.AddPkcs8ShroudedKeyBag(subjectKey, attributes); + p12.SaveToFile(p12File); + + Item = new X509Certificate2(p12File, p12pwd) { FriendlyName = txtName.Text }; + Store = cbStore.SelectedIndex == 0 ? "Personal" : "WebHosting"; + + try + { + using (var process = new Process()) + { + // add certificate + var start = process.StartInfo; + start.Verb = "runas"; + start.FileName = "cmd"; + start.Arguments = string.Format("/c \"\"{4}\" /f:\"{0}\" /p:{1} /n:\"{2}\" /s:{3}\"", + p12File, + p12pwd, + txtName.Text, + cbStore.SelectedIndex == 0 ? "MY" : "WebHosting", + Path.Combine(Environment.CurrentDirectory, "certificateinstaller.exe")); + start.CreateNoWindow = true; + start.WindowStyle = ProcessWindowStyle.Hidden; + process.Start(); + process.WaitForExit(); + File.Delete(p12File); + if (process.ExitCode == 0) + { + this.DialogResult = DialogResult.OK; + } + else + { + MessageBox.Show(process.ExitCode.ToString()); + } + } + } + catch (Exception) + { + // elevation is cancelled. + } + })); + } + + public string Store { get; set; } + + public X509Certificate2 Item { get; set; } + + private void SelfCertificateDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210528"); + } + } +} diff --git a/JexusManager.Features.Certificates/SelfCertificateDialog.resx b/JexusManager.Features.Certificates/SelfCertificateDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Certificates/SelfCertificateDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizard.Designer.cs b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizard.Designer.cs new file mode 100644 index 00000000..78cd100a --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizard.Designer.cs @@ -0,0 +1,48 @@ +namespace JexusManager.Features.Certificates.Wizards.CertificateRenewWizard +{ + using System.ComponentModel; + + partial class CertificateRenewWizard + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // CertificateRequestWizard + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(669, 481); + this.Name = "CertificateRequestWizard"; + this.Text = "Connect to Server"; + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizard.cs b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizard.cs new file mode 100644 index 00000000..09a92062 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizard.cs @@ -0,0 +1,167 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates.Wizards.CertificateRenewWizard +{ + using System; + using System.Diagnostics; + using System.IO; + using System.Security.Cryptography; + using System.Security.Cryptography.X509Certificates; + + using Microsoft.Web.Management.Client.Win32; + + using Mono.Security.Authenticode; + + using Org.BouncyCastle.Asn1; + using Org.BouncyCastle.Asn1.X509; + using Org.BouncyCastle.Crypto.Parameters; + using Org.BouncyCastle.Pkcs; + using Org.BouncyCastle.Security; + using Properties; + using Org.BouncyCastle.Crypto.Operators; + + public partial class CertificateRenewWizard : WizardForm + { + private readonly X509Certificate2 _existing; + private CertificateRenewWizardData _wizardData; + + public CertificateRenewWizard(X509Certificate2 existing, IServiceProvider serviceProvider) + : base(serviceProvider) + { + _existing = existing; + InitializeComponent(); + TaskGlyph = Resources.certificates_48; + } + + protected override object WizardData + { + get { return _wizardData ?? (_wizardData = new CertificateRenewWizardData()); } + } + + protected override void CompleteWizard() + { + X509Name subjectName = new X509Name(_existing.Subject); + + // Generate the private/public keypair + var keyPair = DotNetUtilities.GetKeyPair(_existing.PrivateKey); + + // Generate the CSR + Asn1Set attributes = new DerSet( + new DerSequence( + new DerObjectIdentifier("1.3.6.1.4.1.311.13.2.3"), + new DerSet(new DerIA5String(Environment.OSVersion.Version.ToString()))), + new DerSequence( + new DerObjectIdentifier("1.3.6.1.4.1.311.21.20"), + new DerSet( + new DerSequence( + new DerInteger(5), + new DerUtf8String(Environment.MachineName), + new DerUtf8String(Environment.UserName), + new DerUtf8String("JexusManager.exe")))), + new DerSequence( + new DerObjectIdentifier("1.3.6.1.4.1.311.13.2.2"), + new DerSet( + new DerSequence( + new DerInteger(1), + new DerBmpString("Microsoft RSA SChannel Cryptographic Provider"), + new DerBitString(new byte[0])))), + new DerSequence( + new DerObjectIdentifier("1.2.840.113549.1.9.14"), + new DerSet( + new DerSequence( + new DerSequence( + new DerObjectIdentifier("2.5.29.15"), + new DerBoolean(new byte[] { 0x01 }), + new DerOctetString(new byte[] { 0x03, 0x02, 0x04, 0xF0 })), + new DerSequence( + new DerObjectIdentifier("2.5.29.37"), + new DerOctetString(new byte[] + { + 0x30, 0x0a, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x01 })), + new DerSequence( + new DerObjectIdentifier("1.2.840.113549.1.9.15"), + new DerOctetString(new byte[] + { + 0x30, 0x69, 0x30, 0x0e, + 0x06, 0x08, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, + 0x03, 0x02, 0x02, 0x02, + 0x00, 0x80, 0x30, 0x0e, + 0x06, 0x08, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, + 0x03, 0x04, 0x02, 0x02, + 0x00, 0x80, 0x30, 0x0b, + 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, + 0x04, 0x01, 0x2a, 0x30, + 0x0b, 0x06, 0x09, 0x60, + 0x86, 0x48, 0x01, 0x65, + 0x03, 0x04, 0x01, 0x2d, + 0x30, 0x0b, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x01, + 0x02, 0x30, 0x0b, 0x06, + 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, + 0x01, 0x05, 0x30, 0x07, + 0x06, 0x05, 0x2b, 0x0e, + 0x03, 0x02, 0x07, 0x30, + 0x0a, 0x06, 0x08, 0x2a, + 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x03, 0x07 + })), + new DerSequence( + new DerObjectIdentifier("2.5.29.14"), + new DerOctetString(new byte[] + { + 0x04, 0x14, 0xaa, 0x25, + 0xd9, 0xa2, 0x39, 0x7e, + 0x49, 0xd2, 0x94, 0x85, + 0x7e, 0x82, 0xa8, 0x8f, + 0x3b, 0x20, 0xf1, 0x4e, 0x65, 0xe5 + })))))); + + var signing = new Asn1SignatureFactory("SHA256withRSA", keyPair.Private); + Pkcs10CertificationRequest kpGen = new Pkcs10CertificationRequest(signing, subjectName, keyPair.Public, attributes, keyPair.Private); + using (var stream = new StreamWriter(_wizardData.FileName)) + { + stream.WriteLine(_wizardData.UseIisStyle ? "-----BEGIN NEW CERTIFICATE REQUEST-----" : "-----BEGIN CERTIFICATE REQUEST-----"); + stream.WriteLine(Convert.ToBase64String(kpGen.GetDerEncoded(), Base64FormattingOptions.InsertLineBreaks)); + stream.WriteLine(_wizardData.UseIisStyle ? "-----END NEW CERTIFICATE REQUEST-----" : "-----END CERTIFICATE REQUEST-----"); + } + + var key = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)keyPair.Private); + PrivateKey pvk = new PrivateKey(); + pvk.RSA = new RSACryptoServiceProvider(); + pvk.RSA.ImportParameters(key); + pvk.Save(DialogHelper.GetPrivateKeyFile(_existing.Subject)); + } + + protected override bool CanComplete + { + get + { + var data = (CertificateRenewWizardData)WizardData; + return data?.IsComplete ?? false; + } + } + + protected override WizardPage[] GetWizardPages() + { + var optionsPage = new OptionsPage(); + optionsPage.SetWizard(this); + var finish = new FinishPage(); + finish.SetWizard(this); + return new WizardPage[] { optionsPage, finish }; + } + + protected override void ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210528"); + } + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizard.resx b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizard.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizard.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizardData.cs b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizardData.cs new file mode 100644 index 00000000..301177cb --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/CertificateRenewWizardData.cs @@ -0,0 +1,18 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates.Wizards.CertificateRenewWizard +{ + internal class CertificateRenewWizardData + { + public string FileName { get; set; } + + public bool IsComplete + { + get { return !string.IsNullOrWhiteSpace(FileName); } + } + + public bool UseIisStyle { get; set; } + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/FinishPage.Designer.cs b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/FinishPage.Designer.cs new file mode 100644 index 00000000..7a9635f6 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/FinishPage.Designer.cs @@ -0,0 +1,144 @@ +namespace JexusManager.Features.Certificates.Wizards.CertificateRenewWizard +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class FinishPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label2 = new System.Windows.Forms.Label(); + this.txtConnect = new System.Windows.Forms.Label(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.rbOpen = new System.Windows.Forms.RadioButton(); + this.rbIis = new System.Windows.Forms.RadioButton(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(20, 74); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(259, 13); + this.label2.TabIndex = 7; + this.label2.Text = "Specify a file name for the certificate renewal request:"; + // + // txtConnect + // + this.txtConnect.AutoSize = true; + this.txtConnect.Location = new System.Drawing.Point(20, 25); + this.txtConnect.Name = "txtConnect"; + this.txtConnect.Size = new System.Drawing.Size(503, 26); + this.txtConnect.TabIndex = 6; + this.txtConnect.Text = "Specify the file name for the certificate request. This information can be sent t" + + "o a certification authority for \r\nsigning."; + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(23, 90); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(358, 20); + this.txtPath.TabIndex = 8; + this.txtPath.TextChanged += new System.EventHandler(this.txtPath_TextChanged); + this.txtPath.VisibleChanged += new System.EventHandler(this.txtPath_TextChanged); + // + // btnBrowse + // + this.btnBrowse.Location = new System.Drawing.Point(387, 88); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(30, 25); + this.btnBrowse.TabIndex = 9; + this.btnBrowse.Text = "..."; + this.btnBrowse.UseVisualStyleBackColor = true; + this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.rbOpen); + this.groupBox1.Controls.Add(this.rbIis); + this.groupBox1.Location = new System.Drawing.Point(23, 132); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(200, 100); + this.groupBox1.TabIndex = 10; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Request file style"; + // + // rbOpen + // + this.rbOpen.AutoSize = true; + this.rbOpen.Location = new System.Drawing.Point(15, 55); + this.rbOpen.Name = "rbOpen"; + this.rbOpen.Size = new System.Drawing.Size(71, 17); + this.rbOpen.TabIndex = 12; + this.rbOpen.Text = "OpenSSL"; + this.rbOpen.UseVisualStyleBackColor = true; + this.rbOpen.CheckedChanged += new System.EventHandler(this.FileStyle_Changed); + // + // rbIis + // + this.rbIis.AutoSize = true; + this.rbIis.Checked = true; + this.rbIis.Location = new System.Drawing.Point(15, 32); + this.rbIis.Name = "rbIis"; + this.rbIis.Size = new System.Drawing.Size(38, 17); + this.rbIis.TabIndex = 11; + this.rbIis.TabStop = true; + this.rbIis.Text = "IIS"; + this.rbIis.UseVisualStyleBackColor = true; + this.rbIis.CheckedChanged += new System.EventHandler(this.FileStyle_Changed); + // + // FinishPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.btnBrowse); + this.Controls.Add(this.txtPath); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtConnect); + this.Name = "FinishPage"; + this.Size = new System.Drawing.Size(670, 380); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private Label label2; + private Label txtConnect; + private TextBox txtPath; + private Button btnBrowse; + private GroupBox groupBox1; + private RadioButton rbOpen; + private RadioButton rbIis; + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/FinishPage.cs b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/FinishPage.cs new file mode 100644 index 00000000..4611fdd5 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/FinishPage.cs @@ -0,0 +1,61 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates.Wizards.CertificateRenewWizard +{ + using System; + using System.Windows.Forms; + + public partial class FinishPage : DefaultWizardPage + { + private bool _initialized; + + public FinishPage() + { + InitializeComponent(); + Caption = "Specify save as file name"; + } + + + private void txtPath_TextChanged(object sender, EventArgs e) + { + if (!_initialized) + { + return; + } + + ((CertificateRenewWizardData)WizardData).FileName = txtPath.Text; + ((DefaultWizardForm)Wizard).UpdateWizard(); + } + + protected override void Activate() + { + base.Activate(); + _initialized = false; + txtPath.Text = ((CertificateRenewWizardData)WizardData).FileName; + _initialized = true; + txtPath.Focus(); + txtPath.SelectAll(); + } + + private void btnBrowse_Click(object sender, EventArgs e) + { + var dialog = new SaveFileDialog + { + FileName = txtPath.Text + }; + if (dialog.ShowDialog() == DialogResult.Cancel) + { + return; + } + + txtPath.Text = dialog.FileName; + } + + private void FileStyle_Changed(object sender, EventArgs e) + { + ((CertificateRenewWizardData)WizardData).UseIisStyle = rbIis.Checked; + } + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/FinishPage.resx b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/FinishPage.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/FinishPage.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/OptionsPage.Designer.cs b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/OptionsPage.Designer.cs new file mode 100644 index 00000000..99378cdf --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/OptionsPage.Designer.cs @@ -0,0 +1,133 @@ +namespace JexusManager.Features.Certificates.Wizards.CertificateRenewWizard +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class OptionsPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.RenewDomain = new System.Windows.Forms.RadioButton(); + this.label1 = new System.Windows.Forms.Label(); + this.rbRequestRenewal = new System.Windows.Forms.RadioButton(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.rbCompleteRenewal = new System.Windows.Forms.RadioButton(); + this.SuspendLayout(); + // + // RenewDomain + // + this.RenewDomain.AutoSize = true; + this.RenewDomain.Checked = true; + this.RenewDomain.Location = new System.Drawing.Point(27, 42); + this.RenewDomain.Name = "RenewDomain"; + this.RenewDomain.Size = new System.Drawing.Size(161, 17); + this.RenewDomain.TabIndex = 0; + this.RenewDomain.TabStop = true; + this.RenewDomain.Text = "Renew an existing certificate"; + this.RenewDomain.UseVisualStyleBackColor = true; + this.RenewDomain.Click += new System.EventHandler(this.Option_Click); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(50, 62); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(387, 13); + this.label1.TabIndex = 1; + this.label1.Text = "Lets you renew an existing certificate by using a certificate server in your doma" + + "in."; + // + // rbRequestRenewal + // + this.rbRequestRenewal.AutoSize = true; + this.rbRequestRenewal.Location = new System.Drawing.Point(27, 99); + this.rbRequestRenewal.Name = "rbRequestRenewal"; + this.rbRequestRenewal.Size = new System.Drawing.Size(192, 17); + this.rbRequestRenewal.TabIndex = 2; + this.rbRequestRenewal.Text = "Create a renewal certificate request"; + this.rbRequestRenewal.UseVisualStyleBackColor = true; + this.rbRequestRenewal.Click += new System.EventHandler(this.Option_Click); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(50, 119); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(421, 13); + this.label2.TabIndex = 3; + this.label2.Text = "Lets you package renewal information to submit to a certification authority at a " + + "later time."; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(50, 176); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(466, 26); + this.label3.TabIndex = 4; + this.label3.Text = "Lets you complete the certificate renewal request by using the certificate that w" + + "as received from a\r\ncertification authority."; + // + // rbCompleteRenewal + // + this.rbCompleteRenewal.AutoSize = true; + this.rbCompleteRenewal.Location = new System.Drawing.Point(27, 156); + this.rbCompleteRenewal.Name = "rbCompleteRenewal"; + this.rbCompleteRenewal.Size = new System.Drawing.Size(196, 17); + this.rbCompleteRenewal.TabIndex = 5; + this.rbCompleteRenewal.Text = "Complete certificate renewal request"; + this.rbCompleteRenewal.UseVisualStyleBackColor = true; + this.rbCompleteRenewal.Click += new System.EventHandler(this.Option_Click); + // + // OptionsPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.rbCompleteRenewal); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.rbRequestRenewal); + this.Controls.Add(this.label1); + this.Controls.Add(this.RenewDomain); + this.Name = "OptionsPage"; + this.Size = new System.Drawing.Size(670, 380); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private RadioButton RenewDomain; + private Label label1; + private RadioButton rbRequestRenewal; + private Label label2; + private Label label3; + private RadioButton rbCompleteRenewal; + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/OptionsPage.cs b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/OptionsPage.cs new file mode 100644 index 00000000..8ad4e182 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/OptionsPage.cs @@ -0,0 +1,29 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates.Wizards.CertificateRenewWizard +{ + using System; + + public partial class OptionsPage : DefaultWizardPage + { + public OptionsPage() + { + InitializeComponent(); + Caption = "Renew an existing certificate"; + } + + private void Option_Click(object sender, EventArgs e) + { + if (rbRequestRenewal.Checked) + { + var finish = (DefaultWizardPage)Pages[1]; + SetNextPage(finish); + finish.SetPreviousPage(this); + } + + UpdateWizard(); + } + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/OptionsPage.resx b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/OptionsPage.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRenewWizard/OptionsPage.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizard.Designer.cs b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizard.Designer.cs new file mode 100644 index 00000000..d003aad7 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizard.Designer.cs @@ -0,0 +1,48 @@ +namespace JexusManager.Features.Certificates.Wizards.CertificateRequestWizard +{ + using System.ComponentModel; + + partial class CertificateRequestWizard + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.SuspendLayout(); + // + // CertificateRequestWizard + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(669, 481); + this.Name = "CertificateRequestWizard"; + this.Text = "Connect to Server"; + this.ResumeLayout(false); + + } + + #endregion + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizard.cs b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizard.cs new file mode 100644 index 00000000..0ae099c1 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizard.cs @@ -0,0 +1,182 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates.Wizards.CertificateRequestWizard +{ + using System; + using System.Diagnostics; + using System.IO; + using System.Security.Cryptography; + + using Microsoft.Web.Management.Client.Win32; + + using Org.BouncyCastle.Asn1; + using Org.BouncyCastle.Asn1.X509; + using Org.BouncyCastle.Crypto; + using Org.BouncyCastle.Crypto.Generators; + using Org.BouncyCastle.Crypto.Parameters; + using Org.BouncyCastle.Crypto.Prng; + using Org.BouncyCastle.Pkcs; + using Org.BouncyCastle.Security; + using Properties; + using Mono.Security.Authenticode; + using Org.BouncyCastle.Crypto.Operators; + public partial class CertificateRequestWizard : DefaultWizardForm + { + private CertificateRequestWizardData _wizardData; + + public CertificateRequestWizard(IServiceProvider serviceProvider) + : base(serviceProvider) + { + InitializeComponent(); + TaskGlyph = Resources.certificates_48; + } + + protected override object WizardData + { + get { return _wizardData ?? (_wizardData = new CertificateRequestWizardData()); } + } + + protected override void CompleteWizard() + { + // Generate the CSR + X509Name subjectName = + new X509Name(string.Format("C={0},ST={1},L={2},O={3},OU={4},CN={5}", + _wizardData.Country, + _wizardData.State, + _wizardData.City, + _wizardData.Organization, + _wizardData.Unit, + _wizardData.CommonName)); + + // Generate the private/public keypair + RsaKeyPairGenerator kpgen = new RsaKeyPairGenerator(); + CryptoApiRandomGenerator randomGenerator = new CryptoApiRandomGenerator(); + kpgen.Init(new KeyGenerationParameters(new SecureRandom(randomGenerator), _wizardData.Length)); + AsymmetricCipherKeyPair keyPair = kpgen.GenerateKeyPair(); + // Generate the CSR + + Asn1Set attributes = new DerSet( + new DerSequence( + new DerObjectIdentifier("1.3.6.1.4.1.311.13.2.3"), + new DerSet(new DerIA5String(Environment.OSVersion.Version.ToString()))), + new DerSequence( + new DerObjectIdentifier("1.3.6.1.4.1.311.21.20"), + new DerSet( + new DerSequence( + new DerInteger(5), + new DerUtf8String(Environment.MachineName), + new DerUtf8String(Environment.UserName), + new DerUtf8String("JexusManager.exe")))), + new DerSequence( + new DerObjectIdentifier("1.3.6.1.4.1.311.13.2.2"), + new DerSet( + new DerSequence( + new DerInteger(1), + new DerBmpString("Microsoft RSA SChannel Cryptographic Provider"), + new DerBitString(new byte[0])))), + new DerSequence( + new DerObjectIdentifier("1.2.840.113549.1.9.14"), + new DerSet( + new DerSequence( + new DerSequence( + new DerObjectIdentifier("2.5.29.15"), + new DerBoolean(new byte[] { 0x01 }), + new DerOctetString(new byte[] { 0x03, 0x02, 0x04, 0xF0 })), + new DerSequence( + new DerObjectIdentifier("2.5.29.37"), + new DerOctetString(new byte[] + { + 0x30, 0x0a, 0x06, 0x08, + 0x2b, 0x06, 0x01, 0x05, + 0x05, 0x07, 0x03, 0x01 })), + new DerSequence( + new DerObjectIdentifier("1.2.840.113549.1.9.15"), + new DerOctetString(new byte[] + { + 0x30, 0x69, 0x30, 0x0e, + 0x06, 0x08, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, + 0x03, 0x02, 0x02, 0x02, + 0x00, 0x80, 0x30, 0x0e, + 0x06, 0x08, 0x2a, 0x86, + 0x48, 0x86, 0xf7, 0x0d, + 0x03, 0x04, 0x02, 0x02, + 0x00, 0x80, 0x30, 0x0b, + 0x06, 0x09, 0x60, 0x86, + 0x48, 0x01, 0x65, 0x03, + 0x04, 0x01, 0x2a, 0x30, + 0x0b, 0x06, 0x09, 0x60, + 0x86, 0x48, 0x01, 0x65, + 0x03, 0x04, 0x01, 0x2d, + 0x30, 0x0b, 0x06, 0x09, + 0x60, 0x86, 0x48, 0x01, + 0x65, 0x03, 0x04, 0x01, + 0x02, 0x30, 0x0b, 0x06, + 0x09, 0x60, 0x86, 0x48, + 0x01, 0x65, 0x03, 0x04, + 0x01, 0x05, 0x30, 0x07, + 0x06, 0x05, 0x2b, 0x0e, + 0x03, 0x02, 0x07, 0x30, + 0x0a, 0x06, 0x08, 0x2a, + 0x86, 0x48, 0x86, 0xf7, + 0x0d, 0x03, 0x07 + })), + new DerSequence( + new DerObjectIdentifier("2.5.29.14"), + new DerOctetString(new byte[] + { + 0x04, 0x14, 0xaa, 0x25, + 0xd9, 0xa2, 0x39, 0x7e, + 0x49, 0xd2, 0x94, 0x85, + 0x7e, 0x82, 0xa8, 0x8f, + 0x3b, 0x20, 0xf1, 0x4e, 0x65, 0xe5 + })))))); + + var signing = new Asn1SignatureFactory("SHA256withRSA", keyPair.Private); + Pkcs10CertificationRequest kpGen = new Pkcs10CertificationRequest(signing, subjectName, keyPair.Public, attributes, keyPair.Private); + using (var stream = new StreamWriter(_wizardData.FileName)) + { + stream.WriteLine(_wizardData.UseIisStyle ? "-----BEGIN NEW CERTIFICATE REQUEST-----" : "-----BEGIN CERTIFICATE REQUEST-----"); + stream.WriteLine(Convert.ToBase64String(kpGen.GetDerEncoded(), Base64FormattingOptions.InsertLineBreaks)); + stream.WriteLine(_wizardData.UseIisStyle ? "-----END NEW CERTIFICATE REQUEST-----" : "-----END CERTIFICATE REQUEST-----"); + } + + var key = DotNetUtilities.ToRSAParameters((RsaPrivateCrtKeyParameters)keyPair.Private); + PrivateKey pvk = new PrivateKey(); + pvk.RSA = new RSACryptoServiceProvider(); + pvk.RSA.ImportParameters(key); + pvk.Save(DialogHelper.GetPrivateKeyFile(subjectName.ToString())); + } + + protected override bool CanComplete + { + get + { + var data = (CertificateRequestWizardData)WizardData; + return data?.IsComplete ?? false; + } + } + + protected override WizardPage[] GetWizardPages() + { + var properties = new PropertiesPage(); + var keys = new KeysPage(); + var finish = new FinishPage(); + properties.SetNextPage(keys); + properties.SetWizard(this); + keys.SetPreviousPage(properties); + keys.SetNextPage(finish); + keys.SetWizard(this); + finish.SetPreviousPage(keys); + finish.SetWizard(this); + return new WizardPage[] { properties, keys, finish }; + } + + protected override void ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210528"); + } + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizard.resx b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizard.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizard.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizardData.cs b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizardData.cs new file mode 100644 index 00000000..16ad64f8 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/CertificateRequestWizardData.cs @@ -0,0 +1,26 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates.Wizards.CertificateRequestWizard +{ + internal class CertificateRequestWizardData + { + public string CommonName; + public string Organization { get; set; } + public string Unit { get; set; } + public string City { get; set; } + public string State { get; set; } + public string Country { get; set; } + public int Provider = 1; + public int Length { get; set; } + public string FileName { get; set; } + + public bool IsComplete + { + get { return !string.IsNullOrWhiteSpace(FileName); } + } + + public bool UseIisStyle { get; set; } + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/FinishPage.Designer.cs b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/FinishPage.Designer.cs new file mode 100644 index 00000000..7cd7e68e --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/FinishPage.Designer.cs @@ -0,0 +1,144 @@ +namespace JexusManager.Features.Certificates.Wizards.CertificateRequestWizard +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class FinishPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label2 = new System.Windows.Forms.Label(); + this.txtConnect = new System.Windows.Forms.Label(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.rbIis = new System.Windows.Forms.RadioButton(); + this.rbOpen = new System.Windows.Forms.RadioButton(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(20, 74); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(219, 13); + this.label2.TabIndex = 7; + this.label2.Text = "Specify a file name for the certificate request:"; + // + // txtConnect + // + this.txtConnect.AutoSize = true; + this.txtConnect.Location = new System.Drawing.Point(20, 25); + this.txtConnect.Name = "txtConnect"; + this.txtConnect.Size = new System.Drawing.Size(495, 26); + this.txtConnect.TabIndex = 6; + this.txtConnect.Text = "Specify the file name for the certificate request. This information can be sent t" + + "o a certificate authority for \r\nsigning."; + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(23, 90); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(358, 20); + this.txtPath.TabIndex = 8; + this.txtPath.TextChanged += new System.EventHandler(this.txtPath_TextChanged); + this.txtPath.VisibleChanged += new System.EventHandler(this.txtPath_TextChanged); + // + // btnBrowse + // + this.btnBrowse.Location = new System.Drawing.Point(387, 88); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(30, 25); + this.btnBrowse.TabIndex = 9; + this.btnBrowse.Text = "..."; + this.btnBrowse.UseVisualStyleBackColor = true; + this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.rbOpen); + this.groupBox1.Controls.Add(this.rbIis); + this.groupBox1.Location = new System.Drawing.Point(23, 132); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(200, 100); + this.groupBox1.TabIndex = 10; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Request file style"; + // + // rbIis + // + this.rbIis.AutoSize = true; + this.rbIis.Checked = true; + this.rbIis.Location = new System.Drawing.Point(15, 32); + this.rbIis.Name = "rbIis"; + this.rbIis.Size = new System.Drawing.Size(38, 17); + this.rbIis.TabIndex = 11; + this.rbIis.TabStop = true; + this.rbIis.Text = "IIS"; + this.rbIis.UseVisualStyleBackColor = true; + this.rbIis.CheckedChanged += new System.EventHandler(this.FileStyle_Changed); + // + // rbOpen + // + this.rbOpen.AutoSize = true; + this.rbOpen.Location = new System.Drawing.Point(15, 55); + this.rbOpen.Name = "rbOpen"; + this.rbOpen.Size = new System.Drawing.Size(71, 17); + this.rbOpen.TabIndex = 12; + this.rbOpen.Text = "OpenSSL"; + this.rbOpen.UseVisualStyleBackColor = true; + this.rbOpen.CheckedChanged += new System.EventHandler(this.FileStyle_Changed); + // + // FinishPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.btnBrowse); + this.Controls.Add(this.txtPath); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtConnect); + this.Name = "FinishPage"; + this.Size = new System.Drawing.Size(670, 380); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private Label label2; + private Label txtConnect; + private TextBox txtPath; + private Button btnBrowse; + private GroupBox groupBox1; + private RadioButton rbOpen; + private RadioButton rbIis; + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/FinishPage.cs b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/FinishPage.cs new file mode 100644 index 00000000..0a601b8b --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/FinishPage.cs @@ -0,0 +1,61 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates.Wizards.CertificateRequestWizard +{ + using System; + using System.Windows.Forms; + + public partial class FinishPage : DefaultWizardPage + { + private bool _initialized; + + public FinishPage() + { + InitializeComponent(); + Caption = "File Name"; + } + + + private void txtPath_TextChanged(object sender, EventArgs e) + { + if (!_initialized) + { + return; + } + + ((CertificateRequestWizardData)WizardData).FileName = txtPath.Text; + ((DefaultWizardForm)Wizard).UpdateWizard(); + } + + protected override void Activate() + { + base.Activate(); + _initialized = false; + txtPath.Text = ((CertificateRequestWizardData)WizardData).FileName; + _initialized = true; + txtPath.Focus(); + txtPath.SelectAll(); + } + + private void btnBrowse_Click(object sender, EventArgs e) + { + var dialog = new SaveFileDialog + { + FileName = txtPath.Text + }; + if (dialog.ShowDialog() == DialogResult.Cancel) + { + return; + } + + txtPath.Text = dialog.FileName; + } + + private void FileStyle_Changed(object sender, EventArgs e) + { + ((CertificateRequestWizardData)WizardData).UseIisStyle = rbIis.Checked; + } + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/FinishPage.resx b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/FinishPage.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/FinishPage.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/KeysPage.Designer.cs b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/KeysPage.Designer.cs new file mode 100644 index 00000000..827756b6 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/KeysPage.Designer.cs @@ -0,0 +1,116 @@ +namespace JexusManager.Features.Certificates.Wizards.CertificateRequestWizard +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class KeysPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(KeysPage)); + this.txtConnect = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.cbProvider = new System.Windows.Forms.ComboBox(); + this.label3 = new System.Windows.Forms.Label(); + this.cbLength = new System.Windows.Forms.ComboBox(); + this.SuspendLayout(); + // + // txtConnect + // + this.txtConnect.AutoSize = true; + this.txtConnect.Location = new System.Drawing.Point(20, 25); + this.txtConnect.Name = "txtConnect"; + this.txtConnect.Size = new System.Drawing.Size(515, 39); + this.txtConnect.TabIndex = 0; + this.txtConnect.Text = resources.GetString("txtConnect.Text"); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(20, 73); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(153, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Cryptographic service provider:"; + // + // cbProvider + // + this.cbProvider.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbProvider.FormattingEnabled = true; + this.cbProvider.Items.AddRange(new object[] { + "Microsoft DH SChannel Cryptographic Provider", + "Microsoft RSA SChannel Cryptographic Provider"}); + this.cbProvider.Location = new System.Drawing.Point(23, 89); + this.cbProvider.Name = "cbProvider"; + this.cbProvider.Size = new System.Drawing.Size(392, 21); + this.cbProvider.TabIndex = 0; + this.cbProvider.SelectedIndexChanged += new System.EventHandler(this.CbProviderSelectedIndexChanged); + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(20, 124); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(54, 13); + this.label3.TabIndex = 3; + this.label3.Text = "Bit length:"; + // + // cbLength + // + this.cbLength.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbLength.FormattingEnabled = true; + this.cbLength.Location = new System.Drawing.Point(23, 140); + this.cbLength.Name = "cbLength"; + this.cbLength.Size = new System.Drawing.Size(121, 21); + this.cbLength.TabIndex = 4; + this.cbLength.SelectedIndexChanged += new System.EventHandler(this.CbLengthSelectedIndexChanged); + // + // KeysPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.cbLength); + this.Controls.Add(this.label3); + this.Controls.Add(this.cbProvider); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtConnect); + this.Name = "KeysPage"; + this.Size = new System.Drawing.Size(670, 380); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label txtConnect; + private Label label2; + private ComboBox cbProvider; + private Label label3; + private ComboBox cbLength; + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/KeysPage.cs b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/KeysPage.cs new file mode 100644 index 00000000..feeadd23 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/KeysPage.cs @@ -0,0 +1,53 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates.Wizards.CertificateRequestWizard +{ + using System; + + public partial class KeysPage : DefaultWizardPage + { + public KeysPage() + { + InitializeComponent(); + Caption = "Cryptographic Service Provider Properties"; + } + + protected override void Activate() + { + base.Activate(); + var wizardData = (CertificateRequestWizardData)WizardData; + cbProvider.SelectedIndex = wizardData.Provider; + } + + private void CbProviderSelectedIndexChanged(object sender, EventArgs e) + { + cbLength.Items.Clear(); + if (cbProvider.SelectedIndex == 0) + { + cbLength.Items.Add("512"); + cbLength.Items.Add("1024"); + cbLength.SelectedIndex = 0; + } + else + { + cbLength.Items.Add("384"); + cbLength.Items.Add("512"); + cbLength.Items.Add("1024"); + cbLength.Items.Add("2048"); + cbLength.Items.Add("4096"); + cbLength.Items.Add("8192"); + cbLength.Items.Add("16384"); + cbLength.SelectedIndex = 2; + } + } + + private void CbLengthSelectedIndexChanged(object sender, EventArgs e) + { + var wizardData = (CertificateRequestWizardData)WizardData; + wizardData.Provider = cbProvider.SelectedIndex; + wizardData.Length = int.Parse(cbLength.Text); + } + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/KeysPage.resx b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/KeysPage.resx new file mode 100644 index 00000000..163164ed --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/KeysPage.resx @@ -0,0 +1,125 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Select a cryptographic service provider and a bit length. The bit length of the encryption key determines the +certificate's encryption strength. The greater the bit length, the stronger the security. However, a greater bit +length may decrease performance. + + \ No newline at end of file diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/PropertiesPage.Designer.cs b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/PropertiesPage.Designer.cs new file mode 100644 index 00000000..e6b4485e --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/PropertiesPage.Designer.cs @@ -0,0 +1,206 @@ +namespace JexusManager.Features.Certificates.Wizards.CertificateRequestWizard +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class PropertiesPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.txtCommonName = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.label6 = new System.Windows.Forms.Label(); + this.label7 = new System.Windows.Forms.Label(); + this.txtOrganization = new System.Windows.Forms.TextBox(); + this.txtUnit = new System.Windows.Forms.TextBox(); + this.txtCity = new System.Windows.Forms.TextBox(); + this.txtState = new System.Windows.Forms.TextBox(); + this.cbCountry = new System.Windows.Forms.ComboBox(); + this.SuspendLayout(); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F); + this.label2.Location = new System.Drawing.Point(20, 69); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(80, 13); + this.label2.TabIndex = 5; + this.label2.Text = "Common name:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(20, 25); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(494, 26); + this.label3.TabIndex = 6; + this.label3.Text = "Specify the required information for the certificate. State/province and City/loc" + + "ality must be specified as \r\nofficial names and they cannot contain abbreviation" + + "s.\r\n"; + // + // txtCommonName + // + this.txtCommonName.Location = new System.Drawing.Point(180, 66); + this.txtCommonName.Name = "txtCommonName"; + this.txtCommonName.Size = new System.Drawing.Size(299, 20); + this.txtCommonName.TabIndex = 7; + this.txtCommonName.TextChanged += new System.EventHandler(this.txtCommonName_TextChanged); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(20, 95); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(69, 13); + this.label1.TabIndex = 8; + this.label1.Text = "Organization:"; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(20, 121); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(97, 13); + this.label4.TabIndex = 9; + this.label4.Text = "Organizational unit:"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(20, 147); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(64, 13); + this.label5.TabIndex = 10; + this.label5.Text = "City/locality:"; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(20, 173); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(81, 13); + this.label6.TabIndex = 11; + this.label6.Text = "State/province:"; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(20, 199); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(80, 13); + this.label7.TabIndex = 12; + this.label7.Text = "Country/region:"; + // + // txtOrganization + // + this.txtOrganization.Location = new System.Drawing.Point(180, 92); + this.txtOrganization.Name = "txtOrganization"; + this.txtOrganization.Size = new System.Drawing.Size(299, 20); + this.txtOrganization.TabIndex = 13; + this.txtOrganization.TextChanged += new System.EventHandler(this.txtOrganization_TextChanged); + // + // txtUnit + // + this.txtUnit.Location = new System.Drawing.Point(180, 118); + this.txtUnit.Name = "txtUnit"; + this.txtUnit.Size = new System.Drawing.Size(94, 20); + this.txtUnit.TabIndex = 14; + this.txtUnit.TextChanged += new System.EventHandler(this.txtUnit_TextChanged); + // + // txtCity + // + this.txtCity.Location = new System.Drawing.Point(180, 144); + this.txtCity.Name = "txtCity"; + this.txtCity.Size = new System.Drawing.Size(154, 20); + this.txtCity.TabIndex = 15; + this.txtCity.TextChanged += new System.EventHandler(this.txtCity_TextChanged); + // + // txtState + // + this.txtState.Location = new System.Drawing.Point(180, 170); + this.txtState.Name = "txtState"; + this.txtState.Size = new System.Drawing.Size(154, 20); + this.txtState.TabIndex = 16; + this.txtState.TextChanged += new System.EventHandler(this.txtState_TextChanged); + // + // cbCountry + // + this.cbCountry.FormattingEnabled = true; + this.cbCountry.Location = new System.Drawing.Point(180, 196); + this.cbCountry.Name = "cbCountry"; + this.cbCountry.Size = new System.Drawing.Size(299, 21); + this.cbCountry.TabIndex = 17; + this.cbCountry.Text = "US"; + this.cbCountry.TextChanged += new System.EventHandler(this.cbCountry_TextChanged); + // + // PropertiesPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.cbCountry); + this.Controls.Add(this.txtState); + this.Controls.Add(this.txtCity); + this.Controls.Add(this.txtUnit); + this.Controls.Add(this.txtOrganization); + this.Controls.Add(this.label7); + this.Controls.Add(this.label6); + this.Controls.Add(this.label5); + this.Controls.Add(this.label4); + this.Controls.Add(this.label1); + this.Controls.Add(this.txtCommonName); + this.Controls.Add(this.label2); + this.Controls.Add(this.label3); + this.Name = "PropertiesPage"; + this.Size = new System.Drawing.Size(670, 380); + this.Load += new System.EventHandler(this.PropertiesPage_Load); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label2; + private Label label3; + private TextBox txtCommonName; + private Label label1; + private Label label4; + private Label label5; + private Label label6; + private Label label7; + private TextBox txtOrganization; + private TextBox txtUnit; + private TextBox txtCity; + private TextBox txtState; + private ComboBox cbCountry; + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/PropertiesPage.cs b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/PropertiesPage.cs new file mode 100644 index 00000000..e04ab9e3 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/PropertiesPage.cs @@ -0,0 +1,118 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Certificates.Wizards.CertificateRequestWizard +{ + using System; + using System.Collections.Generic; + using System.Globalization; + using System.Linq; + using System.Threading.Tasks; + + using Microsoft.Web.Management.Client.Win32; + + public partial class PropertiesPage : DefaultWizardPage + { + public PropertiesPage() + { + InitializeComponent(); + Caption = "Distinguished Name Properties"; + } + + protected override bool CanNavigateNext + { + get + { + return base.CanNavigateNext + && !string.IsNullOrWhiteSpace(txtCommonName.Text) + && !string.IsNullOrWhiteSpace(txtOrganization.Text) + && !string.IsNullOrWhiteSpace(txtUnit.Text) + && !string.IsNullOrWhiteSpace(txtCity.Text) + && !string.IsNullOrWhiteSpace(txtState.Text) + && !string.IsNullOrWhiteSpace(cbCountry.Text); + } + } + + private void txtCommonName_TextChanged(object sender, EventArgs e) + { + var wizardData = ((CertificateRequestWizardData)WizardData); + wizardData.CommonName = txtCommonName.Text; + UpdateWizard(); + } + + protected override void Activate() + { + base.Activate(); + txtCommonName.SelectAll(); + txtCommonName.Focus(); + } + + private void txtOrganization_TextChanged(object sender, EventArgs e) + { + var wizardData = ((CertificateRequestWizardData)WizardData); + wizardData.Organization = txtOrganization.Text; + UpdateWizard(); + } + + private void txtUnit_TextChanged(object sender, EventArgs e) + { + var wizardData = ((CertificateRequestWizardData)WizardData); + wizardData.Unit = txtUnit.Text; + UpdateWizard(); + } + + private void txtCity_TextChanged(object sender, EventArgs e) + { + var wizardData = ((CertificateRequestWizardData)WizardData); + wizardData.City = txtCity.Text; + UpdateWizard(); + } + + private void txtState_TextChanged(object sender, EventArgs e) + { + var wizardData = ((CertificateRequestWizardData)WizardData); + wizardData.State = txtState.Text; + UpdateWizard(); + } + + private void cbCountry_TextChanged(object sender, EventArgs e) + { + var wizardData = ((CertificateRequestWizardData)WizardData); + wizardData.Country = cbCountry.Text; + UpdateWizard(); + } + + private async void PropertiesPage_Load(object sender, EventArgs e) + { + var codes = await Task.Factory.StartNew(() => + { + var result = new HashSet(); + CultureInfo[] cinfo = CultureInfo.GetCultures(CultureTypes.AllCultures & ~CultureTypes.NeutralCultures); + foreach (CultureInfo cul in cinfo) + { + RegionInfo ri; + try + { + ri = new RegionInfo(cul.Name); + result.Add(ri.TwoLetterISORegionName); + } + catch + { + } + } + + var list = result.ToList(); + list.Sort(); + return list; + }); + + foreach (var code in codes) + { + cbCountry.Items.Add(code); + } + + cbCountry.Text = "US"; + } + } +} diff --git a/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/PropertiesPage.resx b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/PropertiesPage.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Certificates/Wizards/CertificateRequestWizard/PropertiesPage.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Certificates/packages.config b/JexusManager.Features.Certificates/packages.config new file mode 100644 index 00000000..789e25ea --- /dev/null +++ b/JexusManager.Features.Certificates/packages.config @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Cgi/CgiFeature.cs b/JexusManager.Features.Cgi/CgiFeature.cs new file mode 100644 index 00000000..4f2c5a0a --- /dev/null +++ b/JexusManager.Features.Cgi/CgiFeature.cs @@ -0,0 +1,131 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Cgi +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Resources; + + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal class CgiFeature + { + private sealed class FeatureTaskList : TaskList + { + private readonly CgiFeature _owner; + + public FeatureTaskList(CgiFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + return new TaskItem[0]; + } + } + + public CgiFeature(Module module) + { + this.Module = module; + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + + private TaskList _taskList; + + protected void DisplayErrorMessage(Exception ex, ResourceManager resourceManager) + { + var service = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + service.ShowError(ex, resourceManager.GetString("General"), "", false); + } + + protected object GetService(Type type) + { + return (this.Module as IServiceProvider).GetService(type); + } + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/cgi"); + PropertyGridObject = new CgiItem(section); + this.OnCgiSettingsSaved(); + } + + public CgiItem PropertyGridObject { get; set; } + + protected void OnCgiSettingsSaved() + { + this.CgiSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210534"); + return false; + } + + public CgiSettingsSavedEventHandler CgiSettingsUpdated { get; set; } + public string Description { get; } + + public virtual bool IsFeatureEnabled + { + get { return true; } + } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public Module Module { get; } + public ServerManager Server { get; set; } + public Application Application { get; set; } + + public string Name + { + get { return "Cgi"; } + } + + public bool IsEnabled { get; set; } + + public void CancelChanges() + { + this.Load(); + } + + public bool ApplyChanges() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + PropertyGridObject.Apply(); + service.ServerManager.CommitChanges(); + return true; + } + + public bool LongDateEnabled { get; set; } + + public bool ExtensionEnabled { get; set; } + + public bool SizeEnabled { get; set; } + + public bool TimeEnabled { get; set; } + + public bool DateEnabled { get; set; } + } +} diff --git a/JexusManager.Features.Cgi/CgiItem.cs b/JexusManager.Features.Cgi/CgiItem.cs new file mode 100644 index 00000000..f717b7ae --- /dev/null +++ b/JexusManager.Features.Cgi/CgiItem.cs @@ -0,0 +1,52 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Cgi +{ + using System; + using System.ComponentModel; + + using Microsoft.Web.Administration; + + internal class CgiItem + { + public ConfigurationElement Element { get; set; } + + public CgiItem(ConfigurationElement element) + { + this.Element = element; + CreateCgiWithNewConsole = (bool)element["createCGIWithNewConsole"]; + CreateProcessAsUser = (bool)element["createProcessAsUser"]; + Timeout = (TimeSpan)element["timeout"]; + } + + public void Apply() + { + Element["createCGIWithNewConsole"] = CreateCgiWithNewConsole; + Element["createProcessAsUser"] = CreateProcessAsUser; + Element["timeout"] = Timeout; + } + + [Browsable(true)] + [Category("Behavior")] + [Description("Indicates whether a CGI application runs in its own console. If the value is set to true, each CGI application creates a new console when started. A value of false indicaes that CGI applications should run without a console.")] + [DisplayName("Use New Console For Each Invocation")] + [DefaultValue(false)] + public bool CreateCgiWithNewConsole { get; set; } + + [Browsable(true)] + [Category("Security")] + [Description("Specifies whether a CGI process is created in the system context or in the context of the requesting user.")] + [DisplayName("Impersonate User")] + [DefaultValue(true)] + public bool CreateProcessAsUser { get; set; } + + [Browsable(true)] + [Category("Behavior")] + [Description("Specifies the time-out value for CGI applications.")] + [DisplayName("Timeout (hh:mm:ss)")] + [DefaultValue(typeof(TimeSpan), "0:15:00")] + public TimeSpan Timeout { get; set; } + } +} \ No newline at end of file diff --git a/JexusManager.Features.Cgi/CgiModule.cs b/JexusManager.Features.Cgi/CgiModule.cs new file mode 100644 index 00000000..1ffc7ea9 --- /dev/null +++ b/JexusManager.Features.Cgi/CgiModule.cs @@ -0,0 +1,29 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Cgi +{ + using System; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + using Properties; + + internal class CgiModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)this.GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo( + this, + typeof(CgiPage), + "CGI", + "Configure properties for CGI programs", + Resources.cgi_36, + Resources.cgi_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.Cgi/CgiModuleProvider.cs b/JexusManager.Features.Cgi/CgiModuleProvider.cs new file mode 100644 index 00000000..a9713ba5 --- /dev/null +++ b/JexusManager.Features.Cgi/CgiModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Cgi +{ + using System; + + using Microsoft.Web.Management.Server; + + public class CgiModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(this.Name, typeof(CgiModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.Cgi/CgiPage.Designer.cs b/JexusManager.Features.Cgi/CgiPage.Designer.cs new file mode 100644 index 00000000..0fbfa0fc --- /dev/null +++ b/JexusManager.Features.Cgi/CgiPage.Designer.cs @@ -0,0 +1,243 @@ +namespace JexusManager.Features.Cgi +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class CgiPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.pgCGI = new System.Windows.Forms.PropertyGrid(); + this.toolStrip1 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel1 = new System.Windows.Forms.ToolStripLabel(); + this.toolStripComboBox1 = new System.Windows.Forms.ToolStripComboBox(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.toolStrip1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 5; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.SplitContainer1SplitterMoved); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.pgCGI); + this.panel2.Controls.Add(this.toolStrip1); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 11; + // + // pgCGI + // + this.pgCGI.CategoryForeColor = System.Drawing.SystemColors.InactiveCaptionText; + this.pgCGI.Dock = System.Windows.Forms.DockStyle.Fill; + this.pgCGI.Location = new System.Drawing.Point(0, 25); + this.pgCGI.Name = "pgCGI"; + this.pgCGI.Size = new System.Drawing.Size(560, 515); + this.pgCGI.TabIndex = 1; + this.pgCGI.ToolbarVisible = false; + this.pgCGI.PropertyValueChanged += new System.Windows.Forms.PropertyValueChangedEventHandler(this.PgCgiPropertyValueChanged); + // + // toolStrip1 + // + this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel1, + this.toolStripComboBox1}); + this.toolStrip1.Location = new System.Drawing.Point(0, 0); + this.toolStrip1.Name = "toolStrip1"; + this.toolStrip1.Size = new System.Drawing.Size(560, 25); + this.toolStrip1.TabIndex = 0; + this.toolStrip1.Text = "toolStrip1"; + // + // toolStripLabel1 + // + this.toolStripLabel1.Name = "toolStripLabel1"; + this.toolStripLabel1.Size = new System.Drawing.Size(48, 22); + this.toolStripLabel1.Text = "Display:"; + // + // toolStripComboBox1 + // + this.toolStripComboBox1.Items.AddRange(new object[] { + "Friendly Names", + "Configuration Names", + "Both Names"}); + this.toolStripComboBox1.Name = "toolStripComboBox1"; + this.toolStripComboBox1.Size = new System.Drawing.Size(121, 25); + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 10; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(48, 25); + this.label3.TabIndex = 2; + this.label3.Text = "CGI"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // CgiPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "CgiPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.toolStrip1.ResumeLayout(false); + this.toolStrip1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Panel panel2; + private PictureBox pictureBox1; + private ContextMenuStrip cmsActionPanel; + private PropertyGrid pgCGI; + private ToolStrip toolStrip1; + private ToolStripLabel toolStripLabel1; + private ToolStripComboBox toolStripComboBox1; + } +} diff --git a/JexusManager.Features.Cgi/CgiPage.cs b/JexusManager.Features.Cgi/CgiPage.cs new file mode 100644 index 00000000..77698e06 --- /dev/null +++ b/JexusManager.Features.Cgi/CgiPage.cs @@ -0,0 +1,160 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Cgi +{ + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + using Microsoft.Web.Management.Server; + + internal partial class CgiPage : ModulePropertiesPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly CgiPage _owner; + + public PageTaskList(CgiPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private CgiFeature _feature; + private bool _hasChanges; + private bool _initialized; + private TaskList _taskList; + + public CgiPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new CgiFeature(this.Module); + _feature.CgiSettingsUpdated = this.Refresh; + _feature.Load(); + base.Initialize(navigationData); + } + + protected override bool ShowHelp() + { + return _feature.ShowHelp(); + } + + private void SplitContainer1SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + protected override bool ApplyChanges() + { + if (!_feature.ApplyChanges()) + { + return false; + } + + this.ClearChanges(); + return true; + } + + protected override void CancelChanges() + { + _feature.CancelChanges(); + this.ClearChanges(); + } + + protected override bool HasChanges + { + get { return _hasChanges; } + } + + protected override bool CanApplyChanges + { + get { return true; } + } + + private void InformChanges() + { + if (!_initialized) + { + return; + } + + _hasChanges = true; + this.Refresh(); + } + + private void ClearChanges() + { + _hasChanges = false; + this.Refresh(); + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + + protected override void OnRefresh() + { + if (!_hasChanges) + { + pgCGI.SelectedObject = _feature.PropertyGridObject; + _initialized = true; + } + + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + } + + private void PgCgiPropertyValueChanged(object s, PropertyValueChangedEventArgs e) + { + InformChanges(); + } + + protected override PropertyBag GetProperties() + { + return null; + } + + protected override PropertyBag UpdateProperties(out bool updateSuccessful) + { + updateSuccessful = false; + return null; + } + + protected override void ProcessProperties(PropertyBag properties) + { + } + } +} diff --git a/JexusManager.Features.Cgi/CgiPage.resx b/JexusManager.Features.Cgi/CgiPage.resx new file mode 100644 index 00000000..85df29e1 --- /dev/null +++ b/JexusManager.Features.Cgi/CgiPage.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 143, 17 + + + 281, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.Cgi/CgiSettingsSavedEventHandler.cs b/JexusManager.Features.Cgi/CgiSettingsSavedEventHandler.cs new file mode 100644 index 00000000..31789ef9 --- /dev/null +++ b/JexusManager.Features.Cgi/CgiSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Cgi +{ + public delegate void CgiSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.Cgi/JexusManager.Features.Cgi.csproj b/JexusManager.Features.Cgi/JexusManager.Features.Cgi.csproj new file mode 100644 index 00000000..cc2c439c --- /dev/null +++ b/JexusManager.Features.Cgi/JexusManager.Features.Cgi.csproj @@ -0,0 +1,104 @@ + + + + + Debug + AnyCPU + {0ADF28C5-377F-4AA3-B732-AA8C8AEEBB16} + Library + Properties + JexusManager.Features.Cgi + JexusManager.Features.Cgi + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + + + + + + + + + + + + + + UserControl + + + CgiPage.cs + + + + + True + True + Resources.resx + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + CgiPage.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Cgi/JexusManager.snk b/JexusManager.Features.Cgi/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Cgi/Properties/AssemblyInfo.cs b/JexusManager.Features.Cgi/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..6c249dae --- /dev/null +++ b/JexusManager.Features.Cgi/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.Cgi")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.Cgi")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0adf28c5-377f-4aa3-b732-aa8c8aeebb16")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JexusManager.Features.Cgi/Properties/Resources.Designer.cs b/JexusManager.Features.Cgi/Properties/Resources.Designer.cs new file mode 100644 index 00000000..55248572 --- /dev/null +++ b/JexusManager.Features.Cgi/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.Cgi.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.Cgi.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap cgi_36 { + get { + object obj = ResourceManager.GetObject("cgi_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.Cgi/Properties/Resources.resx b/JexusManager.Features.Cgi/Properties/Resources.resx new file mode 100644 index 00000000..5e320a7a --- /dev/null +++ b/JexusManager.Features.Cgi/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\cgi_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.Cgi/Resources/cgi_36.png b/JexusManager.Features.Cgi/Resources/cgi_36.png new file mode 100644 index 0000000000000000000000000000000000000000..7812d7e62d9eda1f4e5dc1709f292621ce7070e0 GIT binary patch literal 1866 zcmV-Q2etT#P)0AH+2G>bM zK~z}7?U+f79Y-0*f7P$wdxMQVM%amG#<3G;jMq2`$b=;rY$OgKflwqO!~t-(qtJM%ds8F%Zz7xOTX@_`aTZT%Nx&( zi2z3&=tFl`S9R6D{{L^OD)|3(>&p}`&ph+%PndYczj{^ zJpIStKL_lN4<3AKX#JhT!`)7oUfN^qI|X^+DCO!(DK$- zotJfC8C~>u`Oz4|zWra}&O3%_G#U)9SPOPVF5X%FvRV94iyoO6iif;izt=(Lj@P`?aP4J?&pD%xj9 z1?W)r-qG&N(@9$N(jHzM05;2T&f&c$%Tk=}15~(&F($Vmk6^>>8V0pK2T~ZNpoUP7 zphhuNWidj#J5Q(EqL(J2e*;kr5w!p{m)tp*v)0d0KOhmj7uvaG!^8KmZrup)ji01D z+eUpMpH!0NK%BSCwPt8{TBvH3mzD_p1*@fGE-)86=g`1^n56`U+O06N$i#em?{}Hs z^9{x(jx#p)8don~#;30IB0*@i=9q8Kqbkc`Sdc(PDu!&9A>JuKjB|(z&O5BLx#bHY z7FFfO%oJ~(e}ipz?PUM`U+1CiU*?U8V~mX*<O-9xDb{uw}*D zs?(p+7mWJhY^W-!gmJw0D1y&DJ$BY1BB*3o=gNlp5|fFsw|VE-nPq!7+_cg#3)Ur7 zy(w;a&Xg*@X%)*t_>(e)8j=6G!oq175gxfggPDQPSCDN&O0=F6b??MV?%P zF+1zZhJFDtx`>2J7ccUgKmBUiXq@yCy!Uv2Q{*<4WFLI! zLnnFj(8>R3_o2da4287eY{u}=5T{N-x0T-J9iic_4I8RptfdWs%^B*YJ$CHa$^E+@ zSaKIpJpY}`c~6>#NjB>Z;(AQ4*JHjlOS9Q5<%^YcuA6im3f5Y{lBUUjjfh=eUB|@f z%gkQ(#PvG$dL7#sAhYQLE4S8qMU!Y^{KCZ9bLX;68#mn+Wmb;185l~a*PApO4Qf%u z$5*agz;v_OWM+EKO^ly^KR$8dL~Z@Z+CN;{vh{~w{KA*&?_a!7E|#=d$QN6mysZ7( zp?n=p-*%~rbISPB02>$_6dLsg&E^2LT8&21EWuo#n(WQYOg%e3KJH^cUwZN7C)3n6 z?;YLzox3;QGZ4pho}QirTEJ|- z%M1W3fCf+l;@f=AAb service.ServerManager.CommitChangesAsync()); + return true; + } + } +} diff --git a/JexusManager.Features.Compression/CompressionModule.cs b/JexusManager.Features.Compression/CompressionModule.cs new file mode 100644 index 00000000..e4673674 --- /dev/null +++ b/JexusManager.Features.Compression/CompressionModule.cs @@ -0,0 +1,25 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Compression +{ + using System; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + using Properties; + + internal class CompressionModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(CompressionPage), "Compression", + "Configure settings to compress responses", + Resources.compression_36, Resources.compression_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.Compression/CompressionModuleProvider.cs b/JexusManager.Features.Compression/CompressionModuleProvider.cs new file mode 100644 index 00000000..8c5daef3 --- /dev/null +++ b/JexusManager.Features.Compression/CompressionModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Compression +{ + using System; + + using Microsoft.Web.Management.Server; + + public class CompressionModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(Name, typeof(CompressionModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.Compression/CompressionPage.Designer.cs b/JexusManager.Features.Compression/CompressionPage.Designer.cs new file mode 100644 index 00000000..030af0c4 --- /dev/null +++ b/JexusManager.Features.Compression/CompressionPage.Designer.cs @@ -0,0 +1,338 @@ +namespace JexusManager.Features.Compression +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class CompressionPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.gbStatic = new System.Windows.Forms.GroupBox(); + this.txtDiskspaceLimit = new System.Windows.Forms.TextBox(); + this.cbDiskspaceLimit = new System.Windows.Forms.CheckBox(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.txtFileSize = new System.Windows.Forms.TextBox(); + this.cbFileSize = new System.Windows.Forms.CheckBox(); + this.cbDynamic = new System.Windows.Forms.CheckBox(); + this.cbStatic = new System.Windows.Forms.CheckBox(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.gbStatic.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 5; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.splitContainer1_SplitterMoved); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.gbStatic); + this.panel2.Controls.Add(this.cbDynamic); + this.panel2.Controls.Add(this.cbStatic); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 11; + // + // gbStatic + // + this.gbStatic.Controls.Add(this.txtDiskspaceLimit); + this.gbStatic.Controls.Add(this.cbDiskspaceLimit); + this.gbStatic.Controls.Add(this.btnBrowse); + this.gbStatic.Controls.Add(this.txtPath); + this.gbStatic.Controls.Add(this.label4); + this.gbStatic.Controls.Add(this.txtFileSize); + this.gbStatic.Controls.Add(this.cbFileSize); + this.gbStatic.Location = new System.Drawing.Point(16, 80); + this.gbStatic.Name = "gbStatic"; + this.gbStatic.Size = new System.Drawing.Size(450, 210); + this.gbStatic.TabIndex = 5; + this.gbStatic.TabStop = false; + this.gbStatic.Text = "Static Compression"; + // + // txtDiskspaceLimit + // + this.txtDiskspaceLimit.Location = new System.Drawing.Point(27, 172); + this.txtDiskspaceLimit.Name = "txtDiskspaceLimit"; + this.txtDiskspaceLimit.Size = new System.Drawing.Size(110, 20); + this.txtDiskspaceLimit.TabIndex = 6; + this.txtDiskspaceLimit.TextChanged += new System.EventHandler(this.cbStatic_CheckedChanged); + // + // cbDiskspaceLimit + // + this.cbDiskspaceLimit.AutoSize = true; + this.cbDiskspaceLimit.Location = new System.Drawing.Point(6, 142); + this.cbDiskspaceLimit.Name = "cbDiskspaceLimit"; + this.cbDiskspaceLimit.Size = new System.Drawing.Size(232, 17); + this.cbDiskspaceLimit.TabIndex = 5; + this.cbDiskspaceLimit.Text = "Per application pool disk space limit (in MB):"; + this.cbDiskspaceLimit.UseVisualStyleBackColor = true; + this.cbDiskspaceLimit.CheckedChanged += new System.EventHandler(this.cbDiskspaceLimit_CheckedChanged); + // + // btnBrowse + // + this.btnBrowse.Location = new System.Drawing.Point(387, 107); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(30, 23); + this.btnBrowse.TabIndex = 4; + this.btnBrowse.Text = "..."; + this.btnBrowse.UseVisualStyleBackColor = true; + this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click); + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(6, 109); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(375, 20); + this.txtPath.TabIndex = 3; + this.txtPath.TextChanged += new System.EventHandler(this.cbStatic_CheckedChanged); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(6, 82); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(84, 13); + this.label4.TabIndex = 2; + this.label4.Text = "Cache directory:"; + // + // txtFileSize + // + this.txtFileSize.Location = new System.Drawing.Point(27, 46); + this.txtFileSize.Name = "txtFileSize"; + this.txtFileSize.Size = new System.Drawing.Size(110, 20); + this.txtFileSize.TabIndex = 1; + this.txtFileSize.TextChanged += new System.EventHandler(this.txtFileSize_TextChanged); + // + // cbFileSize + // + this.cbFileSize.AutoSize = true; + this.cbFileSize.Location = new System.Drawing.Point(6, 19); + this.cbFileSize.Name = "cbFileSize"; + this.cbFileSize.Size = new System.Drawing.Size(217, 17); + this.cbFileSize.TabIndex = 0; + this.cbFileSize.Text = "Only compress files larger than (in bytes):"; + this.cbFileSize.UseVisualStyleBackColor = true; + this.cbFileSize.CheckedChanged += new System.EventHandler(this.cbFileSize_CheckedChanged); + // + // cbDynamic + // + this.cbDynamic.AutoSize = true; + this.cbDynamic.Location = new System.Drawing.Point(16, 21); + this.cbDynamic.Name = "cbDynamic"; + this.cbDynamic.Size = new System.Drawing.Size(202, 17); + this.cbDynamic.TabIndex = 4; + this.cbDynamic.Text = "Enable dynamic content compression"; + this.cbDynamic.UseVisualStyleBackColor = true; + this.cbDynamic.CheckedChanged += new System.EventHandler(this.cbDynamic_CheckedChanged); + // + // cbStatic + // + this.cbStatic.AutoSize = true; + this.cbStatic.Location = new System.Drawing.Point(16, 44); + this.cbStatic.Name = "cbStatic"; + this.cbStatic.Size = new System.Drawing.Size(188, 17); + this.cbStatic.TabIndex = 3; + this.cbStatic.Text = "Enable static content compression"; + this.cbStatic.UseVisualStyleBackColor = true; + this.cbStatic.CheckedChanged += new System.EventHandler(this.cbStatic_CheckedChanged); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(818, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to configure settings for compression of responses. This can imp" + + "rove the perceived performance of a website greatly and reduce bandwidth-related" + + " charges."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 10; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(138, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Compression"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // CompressionPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "CompressionPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.gbStatic.ResumeLayout(false); + this.gbStatic.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private CheckBox cbStatic; + private Panel panel2; + private PictureBox pictureBox1; + private CheckBox cbDynamic; + private GroupBox gbStatic; + private TextBox txtDiskspaceLimit; + private CheckBox cbDiskspaceLimit; + private Button btnBrowse; + private TextBox txtPath; + private Label label4; + private TextBox txtFileSize; + private CheckBox cbFileSize; + private ContextMenuStrip cmsActionPanel; + } +} diff --git a/JexusManager.Features.Compression/CompressionPage.cs b/JexusManager.Features.Compression/CompressionPage.cs new file mode 100644 index 00000000..57b435f3 --- /dev/null +++ b/JexusManager.Features.Compression/CompressionPage.cs @@ -0,0 +1,190 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Compression +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + using Microsoft.Web.Management.Server; + + internal partial class CompressionPage : ModuleDialogPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly CompressionPage _owner; + + public PageTaskList(CompressionPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private CompressionFeature _feature; + private bool _hasChanges; + private bool _initialized; + private TaskList _taskList; + + public CompressionPage() + { + InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new CompressionFeature(Module); + _feature.CompressionSettingsUpdated = Refresh; + _feature.Load(); + base.Initialize(navigationData); + } + + protected override bool ShowHelp() + { + return _feature.ShowHelp(); + } + + private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + private void cbStatic_CheckedChanged(object sender, EventArgs e) + { + _feature.StaticEnabled = cbStatic.Checked; + InformChanges(); + } + + private void cbDynamic_CheckedChanged(object sender, EventArgs e) + { + _feature.DynamicEnabled = cbDynamic.Checked; + InformChanges(); + } + + private void btnBrowse_Click(object sender, EventArgs e) + { + DialogHelper.ShowBrowseDialog(txtPath); + _feature.Directory = txtPath.Text; + InformChanges(); + } + + private void cbFileSize_CheckedChanged(object sender, EventArgs e) + { + _feature.DoFileSize = cbFileSize.Checked; + InformChanges(); + } + + private void cbDiskspaceLimit_CheckedChanged(object sender, EventArgs e) + { + _feature.DoDiskSpaceLimiting = cbDiskspaceLimit.Checked; + InformChanges(); + } + + private void txtFileSize_TextChanged(object sender, EventArgs e) + { + _feature.MinFileSizeForComp = txtFileSize.Text; + InformChanges(); + } + + protected override bool ApplyChanges() + { + if (!_feature.ApplyChanges()) + { + return false; + } + + ClearChanges(); + return true; + } + + protected override void CancelChanges() + { + _feature.CancelChanges(); + ClearChanges(); + } + + protected override bool HasChanges + { + get { return _hasChanges; } + } + + protected override bool CanApplyChanges + { + get { return true; } + } + + private void InformChanges() + { + if (!_initialized) + { + return; + } + + _hasChanges = true; + Refresh(); + } + + private void ClearChanges() + { + _hasChanges = false; + Refresh(); + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + + protected override void OnRefresh() + { + if (!_hasChanges) + { + cbDynamic.Checked = _feature.DynamicEnabled; + cbStatic.Checked = _feature.StaticEnabled; + + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + gbStatic.Visible = service.Scope == ManagementScope.Server; + if (service.Scope == ManagementScope.Server) + { + txtDiskspaceLimit.Enabled = cbDiskspaceLimit.Checked = _feature.DoDiskSpaceLimiting; + txtDiskspaceLimit.Text = _feature.MaxDiskSpaceUsage.ToString(); + txtPath.Text = _feature.Directory; + txtFileSize.Text = _feature.FileSize; + txtFileSize.Enabled = cbFileSize.Checked = _feature.DoFileSize; + } + + _initialized = true; + } + + Tasks.Fill(tsActionPanel, cmsActionPanel); + } + } +} diff --git a/JexusManager.Features.Compression/CompressionPage.resx b/JexusManager.Features.Compression/CompressionPage.resx new file mode 100644 index 00000000..950be5d2 --- /dev/null +++ b/JexusManager.Features.Compression/CompressionPage.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 143, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.Compression/CompressionSettingsSavedEventHandler.cs b/JexusManager.Features.Compression/CompressionSettingsSavedEventHandler.cs new file mode 100644 index 00000000..9e5e1ba3 --- /dev/null +++ b/JexusManager.Features.Compression/CompressionSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Compression +{ + public delegate void CompressionSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.Compression/JexusManager.Features.Compression.csproj b/JexusManager.Features.Compression/JexusManager.Features.Compression.csproj new file mode 100644 index 00000000..716153c3 --- /dev/null +++ b/JexusManager.Features.Compression/JexusManager.Features.Compression.csproj @@ -0,0 +1,103 @@ + + + + + Debug + AnyCPU + {CD9A8535-A6B1-46BB-8ACB-73D5E393147E} + Library + Properties + JexusManager.Features.Compression + JexusManager.Features.Compression + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + + + + + + + + + + + + + UserControl + + + CompressionPage.cs + + + + + True + True + Resources.resx + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + CompressionPage.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Compression/JexusManager.snk b/JexusManager.Features.Compression/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Compression/Properties/AssemblyInfo.cs b/JexusManager.Features.Compression/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..f8c5d9d3 --- /dev/null +++ b/JexusManager.Features.Compression/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.Compression")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.Compression")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("cd9a8535-a6b1-46bb-8acb-73d5e393147e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JexusManager.Features.Compression/Properties/Resources.Designer.cs b/JexusManager.Features.Compression/Properties/Resources.Designer.cs new file mode 100644 index 00000000..d30cbb62 --- /dev/null +++ b/JexusManager.Features.Compression/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.Compression.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.Compression.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap compression_36 { + get { + object obj = ResourceManager.GetObject("compression_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.Compression/Properties/Resources.resx b/JexusManager.Features.Compression/Properties/Resources.resx new file mode 100644 index 00000000..7603ddfe --- /dev/null +++ b/JexusManager.Features.Compression/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\compression_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.Compression/Resources/compression_36.png b/JexusManager.Features.Compression/Resources/compression_36.png new file mode 100644 index 0000000000000000000000000000000000000000..49a0e3de44fd0bf333b0fd8f29006e7333f44a3b GIT binary patch literal 1411 zcmV-}1$_F6P)ymAwZkgLaSl5EBsSuZghF3 zcnKxO;2LENgehQ@Ne~7?3v)^tKw04lf^0VLhz3t5q8CrUE|QMU_MLs{aRW(!?0d2C zO-Zn#zGZ2Z*X_`{e>p;keS%Q}g;6lZz!(K%6r52|M!_g6&KaeULO`GMxVZSu1~b?f zj$49!naq=pRonXGV+QJa`MS=AmZfdiFIuku_3LNm`JcaL;b2dJhXA_MgX-z?L74(0 z8~}_kbayqJ*USYVA!7m1d<>ita0cX^4Z=HnsX$;m|2vwodi&Bp<|NjR){N%XN1N|_Mo)$>AeZW=gD?Q#YPc7RmTiF7SA$e4g+x4tKLaPwa@!I(T^=M7 z3B>v%=smg>zP|kc06lwwnnp^Bsurs{f09W_=J#HfhxR_1Xl?64uJnF3#4;~6uC19q zZ`~~quJeKrM7j?l*mH(()dh#U8V2>FX>kXPffS-wE+ZBR;llZIm^QNs=|l{%Xc+Nm z7z61zxUU|O%YVS*(m`||kPT7qyyZ0Adjy#&D9CksuO9$s-1pQDQ;SMnWTzvIm zM|UO_*$qin3MuL+!}IN1lH1u63ta~^r{_~E(cfkwd#Z84Bb%qqx=9zQARtUYn2`2> zFac=-A`eJgCrkCi_7>0Ni+iP+0fC9SIjz1+=f3}4RU-GBmX?x2u7BuO?F&+xdp>!! z`PAJjw>C>7TKJ*j8<*^og{K^x7u`8H|94OERO!0C#;fWP_;yFK`^15^Wm}>Luln0} zKIghe&m?F6(DhnOSeBP@l}ao3-wM)@ml&4#7>8x$1tm0*%ciJB#QOjmM@@{oI;zes zShA`qbmsF3FP{GT+i~{CgTb~^cM zH~_e_rcCB?IdFHKT@=eSxud7*5wo@=3Niy}0l){q1dy@&GHW=HU5Fs|AMbzH>Dsh$ z>a}w?84YBxH5pPh + /// Description of DefaultDocumentFeature. + /// + public class DefaultDocumentFeature : FeatureBase + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly DefaultDocumentFeature _owner; + + public FeatureTaskList(DefaultDocumentFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("Add", "Add...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + result.Add(GetMoveUpTaskItem(_owner.CanMoveUp)); + result.Add(GetMoveDownTaskItem(_owner.CanMoveDown)); + } + + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + if (!_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Enable", "Enable", string.Empty).SetUsage()); + } + + if (_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Disable", "Disable", string.Empty).SetUsage()); + } + + if (_owner.CanRevert) + { + result.Add(new MethodTaskItem("Revert", "Revert To Parent", string.Empty).SetUsage()); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Add() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public override void MoveUp() + { + _owner.MoveUp(); + } + + [Obfuscation(Exclude = true)] + public override void MoveDown() + { + _owner.MoveDown(); + } + + [Obfuscation(Exclude = true)] + public void Enable() + { + _owner.Enable(); + } + + [Obfuscation(Exclude = true)] + public void Disable() + { + _owner.Disable(); + } + + [Obfuscation(Exclude = true)] + public void Revert() + { + _owner.Revert(); + } + } + + public DefaultDocumentFeature(Module module) + : base(module) + { + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/defaultDocument"); + var enabled = (bool)section["enabled"]; + CanRevert = section.CanRevert(); + SetEnabled(enabled); + + LoadItems(); + } + + public void Add() + { + var dialog = new NewDefaultDocumentDialog(Module); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + var index = this.Items.FindIndex(item => item.Flag == "Local"); + this.InsertItem(index == -1 ? 0 : index, dialog.Item); + } + + public void Remove() + { + var service = (IManagementUIService)GetService(typeof(IManagementUIService)); + var result = + service.ShowMessage( + "Are you sure that you want to remove the selected default document?", + "Confirm Remove", MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + public void MoveUp() + { + if (Items.Any(item => item.Flag != "Local")) + { + var service = (IManagementUIService)GetService(typeof(IManagementUIService)); + var result = + service.ShowMessage( + "The list order will be changed for this feature. If you continue, changes made to this feature at a parent level will no longer be inherited at this level. Do you want to continue?", + Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + } + + this.MoveUpItem(); + } + + public void MoveDown() + { + if (Items.Any(item => item.Flag != "Local")) + { + var service = (IManagementUIService)GetService(typeof(IManagementUIService)); + var result = + service.ShowMessage( + "The list order will be changed for this feature. If you continue, changes made to this feature at a parent level will no longer be inherited at this level. Do you want to continue?", + Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + } + + this.MoveDownItem(); + } + + public void Enable() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/defaultDocument"); + section["enabled"] = true; + SetEnabled(true); + service.ServerManager.CommitChanges(); + } + + public void Disable() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/defaultDocument"); + section["enabled"] = false; + SetEnabled(false); + service.ServerManager.CommitChanges(); + } + + public void Revert() + { + if (!CanRevert) + { + throw new InvalidOperationException("Revert operation cannot be done at server level"); + } + + var service = (IManagementUIService)GetService(typeof(IManagementUIService)); + var result = + service.ShowMessage( + "Reverting to the parent configuration will result in the loss of all settings in the local configuration file for this feature. Are you sure you want to continue?", + Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + + this.RevertItems(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + var section = service.GetSection("system.webServer/defaultDocument"); + return section.GetCollection("files"); + } + + protected override void OnSettingsSaved() + { + DefaultDocumentSettingsUpdated?.Invoke(); + } + + public void SetEnabled(bool enabled) + { + IsEnabled = enabled; + this.OnSettingsSaved(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210478"); + return false; + } + + public DefaultDocumentSettingsSavedEventHandler DefaultDocumentSettingsUpdated { get; set; } + public string Description { get; } + public bool IsEnabled { get; private set; } + public bool CanRevert { get; private set; } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public string Name + { + get { return "Default Document"; } + } + } +} diff --git a/JexusManager.Features.DefaultDocument/DefaultDocumentModule.cs b/JexusManager.Features.DefaultDocument/DefaultDocumentModule.cs new file mode 100644 index 00000000..c6e2300b --- /dev/null +++ b/JexusManager.Features.DefaultDocument/DefaultDocumentModule.cs @@ -0,0 +1,23 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.DefaultDocument +{ + using System; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + using Properties; + + public class DefaultDocumentModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(DefaultDocumentPage), "Default Document", "Configure default files to return when clients do not specify a file in a request", Resources.default_document_36, Resources.default_document_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.DefaultDocument/DefaultDocumentModuleProvider.cs b/JexusManager.Features.DefaultDocument/DefaultDocumentModuleProvider.cs new file mode 100644 index 00000000..fbda0945 --- /dev/null +++ b/JexusManager.Features.DefaultDocument/DefaultDocumentModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.DefaultDocument +{ + using System; + + using Microsoft.Web.Management.Server; + + public class DefaultDocumentModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(Name, typeof(DefaultDocumentModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.DefaultDocument/DefaultDocumentPage.Designer.cs b/JexusManager.Features.DefaultDocument/DefaultDocumentPage.Designer.cs new file mode 100644 index 00000000..ad4fbd70 --- /dev/null +++ b/JexusManager.Features.DefaultDocument/DefaultDocumentPage.Designer.cs @@ -0,0 +1,385 @@ +namespace JexusManager.Features.DefaultDocument +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class DefaultDocumentPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.toolStrip2 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel2 = new System.Windows.Forms.ToolStripLabel(); + this.cbFilter = new System.Windows.Forms.ToolStripComboBox(); + this.btnGo = new System.Windows.Forms.ToolStripSplitButton(); + this.protocolToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.btnShowAll = new System.Windows.Forms.ToolStripButton(); + this.toolStripSeparator4 = new System.Windows.Forms.ToolStripSeparator(); + this.toolStripLabel3 = new System.Windows.Forms.ToolStripLabel(); + this.cbGroup = new System.Windows.Forms.ToolStripComboBox(); + this.btnView = new System.Windows.Forms.ToolStripSplitButton(); + this.detailsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.iconsToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.tilesToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.listToolStripMenuItem = new System.Windows.Forms.ToolStripMenuItem(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.panel2.SuspendLayout(); + this.toolStrip2.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 3; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.splitContainer1_SplitterMoved); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 9; + this.pictureBox1.TabStop = false; + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.toolStrip2); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 8; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chName, + this.chType}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 38); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 502); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.listView1_SelectedIndexChanged); + // + // chName + // + this.chName.Text = "Name"; + this.chName.Width = 200; + // + // chType + // + this.chType.Text = "Entry Type"; + this.chType.Width = 80; + // + // toolStrip2 + // + this.toolStrip2.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel2, + this.cbFilter, + this.btnGo, + this.btnShowAll, + this.toolStripSeparator4, + this.toolStripLabel3, + this.cbGroup, + this.btnView}); + this.toolStrip2.Location = new System.Drawing.Point(0, 13); + this.toolStrip2.Name = "toolStrip2"; + this.toolStrip2.Size = new System.Drawing.Size(560, 25); + this.toolStrip2.TabIndex = 3; + this.toolStrip2.Text = "toolStrip2"; + // + // toolStripLabel2 + // + this.toolStripLabel2.Name = "toolStripLabel2"; + this.toolStripLabel2.Size = new System.Drawing.Size(36, 22); + this.toolStripLabel2.Text = "Filter:"; + // + // cbFilter + // + this.cbFilter.Name = "cbFilter"; + this.cbFilter.Size = new System.Drawing.Size(121, 25); + // + // btnGo + // + this.btnGo.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.protocolToolStripMenuItem}); + this.btnGo.ImageTransparentColor = System.Drawing.Color.Magenta; + this.btnGo.Name = "btnGo"; + this.btnGo.Size = new System.Drawing.Size(54, 22); + this.btnGo.Text = "Go"; + this.btnGo.ToolTipText = "Go"; + // + // protocolToolStripMenuItem + // + this.protocolToolStripMenuItem.Name = "protocolToolStripMenuItem"; + this.protocolToolStripMenuItem.Size = new System.Drawing.Size(88, 22); + this.protocolToolStripMenuItem.Text = "All"; + // + // btnShowAll + // + this.btnShowAll.ImageTransparentColor = System.Drawing.Color.Magenta; + this.btnShowAll.Name = "btnShowAll"; + this.btnShowAll.Size = new System.Drawing.Size(73, 22); + this.btnShowAll.Text = "Show All"; + // + // toolStripSeparator4 + // + this.toolStripSeparator4.Name = "toolStripSeparator4"; + this.toolStripSeparator4.Size = new System.Drawing.Size(6, 25); + // + // toolStripLabel3 + // + this.toolStripLabel3.Name = "toolStripLabel3"; + this.toolStripLabel3.Size = new System.Drawing.Size(59, 22); + this.toolStripLabel3.Text = "Group by:"; + // + // cbGroup + // + this.cbGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbGroup.Items.AddRange(new object[] { + "No Grouping", + "Category", + "Area"}); + this.cbGroup.Name = "cbGroup"; + this.cbGroup.Size = new System.Drawing.Size(121, 25); + // + // btnView + // + this.btnView.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.btnView.DropDownItems.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.detailsToolStripMenuItem, + this.iconsToolStripMenuItem, + this.tilesToolStripMenuItem, + this.listToolStripMenuItem}); + this.btnView.ImageTransparentColor = System.Drawing.Color.Magenta; + this.btnView.Name = "btnView"; + this.btnView.Size = new System.Drawing.Size(32, 22); + this.btnView.Text = "toolStripButton1"; + // + // detailsToolStripMenuItem + // + this.detailsToolStripMenuItem.Name = "detailsToolStripMenuItem"; + this.detailsToolStripMenuItem.Size = new System.Drawing.Size(109, 22); + this.detailsToolStripMenuItem.Text = "Details"; + // + // iconsToolStripMenuItem + // + this.iconsToolStripMenuItem.Name = "iconsToolStripMenuItem"; + this.iconsToolStripMenuItem.Size = new System.Drawing.Size(109, 22); + this.iconsToolStripMenuItem.Text = "Icons"; + // + // tilesToolStripMenuItem + // + this.tilesToolStripMenuItem.Name = "tilesToolStripMenuItem"; + this.tilesToolStripMenuItem.Size = new System.Drawing.Size(109, 22); + this.tilesToolStripMenuItem.Text = "Tiles"; + // + // listToolStripMenuItem + // + this.listToolStripMenuItem.Name = "listToolStripMenuItem"; + this.listToolStripMenuItem.Size = new System.Drawing.Size(109, 22); + this.listToolStripMenuItem.Text = "List"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(666, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to specify the default files(s) to return when a client does not" + + " request a specific file. Set default documents in order of priority."; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(183, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Default Document"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // DefaultDocumentPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "DefaultDocumentPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.toolStrip2.ResumeLayout(false); + this.toolStrip2.PerformLayout(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private ListView listView1; + private ColumnHeader chName; + private ColumnHeader chType; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Label label2; + private Label label3; + private PictureBox pictureBox1; + private Panel panel2; + private ToolStrip toolStrip2; + private ToolStripLabel toolStripLabel2; + private ToolStripComboBox cbFilter; + private ToolStripSplitButton btnGo; + private ToolStripMenuItem protocolToolStripMenuItem; + private ToolStripButton btnShowAll; + private ToolStripSeparator toolStripSeparator4; + private ToolStripLabel toolStripLabel3; + private ToolStripComboBox cbGroup; + private ToolStripSplitButton btnView; + private ToolStripMenuItem detailsToolStripMenuItem; + private ToolStripMenuItem iconsToolStripMenuItem; + private ToolStripMenuItem tilesToolStripMenuItem; + private ToolStripMenuItem listToolStripMenuItem; + private ContextMenuStrip cmsActionPanel; + } +} diff --git a/JexusManager.Features.DefaultDocument/DefaultDocumentPage.cs b/JexusManager.Features.DefaultDocument/DefaultDocumentPage.cs new file mode 100644 index 00000000..e3e2bfe7 --- /dev/null +++ b/JexusManager.Features.DefaultDocument/DefaultDocumentPage.cs @@ -0,0 +1,137 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.DefaultDocument +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class DefaultDocumentPage : ModuleListPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly DefaultDocumentPage _owner; + + public PageTaskList(DefaultDocumentPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class DefaultDocumentListViewItem : ListViewItem + { + public DocumentItem Item { get; } + private readonly DefaultDocumentPage _page; + + public DefaultDocumentListViewItem(DocumentItem item, DefaultDocumentPage page) + : base(item.Name) + { + Item = item; + _page = page; + SubItems.Add(new ListViewSubItem(this, item.Flag)); + } + } + + private DefaultDocumentFeature _feature; + private PageTaskList _taskList; + + public DefaultDocumentPage() + { + InitializeComponent(); + btnView.Image = DefaultTaskList.ViewImage; + btnGo.Image = DefaultTaskList.GoImage; + btnShowAll.Image = DefaultTaskList.ShowAllImage; + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new DefaultDocumentFeature(Module); + _feature.DefaultDocumentSettingsUpdated = InitializeListPage; + _feature.Load(); + } + + protected override void InitializeListPage() + { + listView1.Items.Clear(); + foreach (var file in _feature.Items) + { + listView1.Items.Add(new DefaultDocumentListViewItem(file, this)); + } + + if (_feature.SelectedItem != null) + { + foreach (DefaultDocumentListViewItem item in listView1.Items) + { + if (item.Item == _feature.SelectedItem) + { + item.Selected = true; + } + } + } + + Refresh(); + } + + protected override void Refresh() + { + Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + private void listView1_SelectedIndexChanged(object sender, EventArgs e) + { + // TODO: use WatchDog to suppress extra refresh (one selection triggers this event twice) + _feature.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((DefaultDocumentListViewItem)listView1.SelectedItems[0]).Item + : null; + Refresh(); + } + + protected override bool ShowHelp() + { + return _feature.ShowHelp(); + } + + private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + } +} diff --git a/JexusManager.Features.DefaultDocument/DefaultDocumentPage.resx b/JexusManager.Features.DefaultDocument/DefaultDocumentPage.resx new file mode 100644 index 00000000..5408911a --- /dev/null +++ b/JexusManager.Features.DefaultDocument/DefaultDocumentPage.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 807, 17 + + + 702, 17 + + + 17, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.DefaultDocument/DefaultDocumentSettingsSavedEventHandler.cs b/JexusManager.Features.DefaultDocument/DefaultDocumentSettingsSavedEventHandler.cs new file mode 100644 index 00000000..fef86a2f --- /dev/null +++ b/JexusManager.Features.DefaultDocument/DefaultDocumentSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.DefaultDocument +{ + public delegate void DefaultDocumentSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.DefaultDocument/DocumentItem.cs b/JexusManager.Features.DefaultDocument/DocumentItem.cs new file mode 100644 index 00000000..f939c36a --- /dev/null +++ b/JexusManager.Features.DefaultDocument/DocumentItem.cs @@ -0,0 +1,42 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.DefaultDocument +{ + using Microsoft.Web.Administration; + + public class DocumentItem : IItem + { + public ConfigurationElement Element { get; set; } + public string Name { get; set; } + public string Flag { get; set; } + + public DocumentItem(ConfigurationElement element) + { + Flag = element == null || element.IsLocallyStored ? "Local" : "Inherited"; + Element = element; + if (element == null) + { + return; + } + + Name = (string)element["value"]; + } + + public bool Equals(DocumentItem other) + { + return Match(other); + } + + public void Apply() + { + Element["value"] = Name; + } + + public bool Match(DocumentItem other) + { + return other != null && other.Name == Name; + } + } +} diff --git a/JexusManager.Features.DefaultDocument/JexusManager.Features.DefaultDocument.csproj b/JexusManager.Features.DefaultDocument/JexusManager.Features.DefaultDocument.csproj new file mode 100644 index 00000000..e53a9361 --- /dev/null +++ b/JexusManager.Features.DefaultDocument/JexusManager.Features.DefaultDocument.csproj @@ -0,0 +1,130 @@ + + + + + Debug + AnyCPU + {1E54F67A-3538-4F8D-B2EE-5DA6A821A528} + Library + Properties + JexusManager.Features.DefaultDocument + JexusManager.Features.DefaultDocument + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + + + + UserControl + + + DefaultDocumentPage.cs + + + + + Form + + + NewDefaultDocumentDialog.cs + + + + True + True + Resources.resx + + + + + DefaultDocumentPage.cs + + + NewDefaultDocumentDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.DefaultDocument/JexusManager.snk b/JexusManager.Features.DefaultDocument/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.DefaultDocument/NewDefaultDocumentDialog.Designer.cs b/JexusManager.Features.DefaultDocument/NewDefaultDocumentDialog.Designer.cs new file mode 100644 index 00000000..d8ce5f6e --- /dev/null +++ b/JexusManager.Features.DefaultDocument/NewDefaultDocumentDialog.Designer.cs @@ -0,0 +1,108 @@ +namespace JexusManager.Features.DefaultDocument +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class NewDefaultDocumentDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.txtName = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(242, 91); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(141, 91); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(17, 29); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(320, 20); + this.txtName.TabIndex = 2; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(14, 13); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(38, 13); + this.label1.TabIndex = 3; + this.label1.Text = "Name:"; + // + // NewDefaultDocumentDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(349, 126); + this.Controls.Add(this.label1); + this.Controls.Add(this.txtName); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.HelpButton = true; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "NewDefaultDocumentDialog"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Add Default Document"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewDefaultDocumentDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private TextBox txtName; + private Label label1; + } +} diff --git a/JexusManager.Features.DefaultDocument/NewDefaultDocumentDialog.cs b/JexusManager.Features.DefaultDocument/NewDefaultDocumentDialog.cs new file mode 100644 index 00000000..fc2621de --- /dev/null +++ b/JexusManager.Features.DefaultDocument/NewDefaultDocumentDialog.cs @@ -0,0 +1,62 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.DefaultDocument +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + public partial class NewDefaultDocumentDialog : DialogForm + { + public NewDefaultDocumentDialog(IServiceProvider serviceProvider) + : base(serviceProvider) + { + InitializeComponent(); + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + var invalid = "*".ToCharArray(); + foreach (var ch in invalid) + { + if (txtName.Text.Contains(ch)) + { + MessageBox.Show(string.Format("The specific default document contains the following invalid character: {0}.", ch), Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + } + + Item = new DocumentItem(null); + Item.Name = txtName.Text; + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text); + })); + } + + public DocumentItem Item { get; set; } + + private void NewDefaultDocumentDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210478"); + } + } +} diff --git a/JexusManager.Features.DefaultDocument/NewDefaultDocumentDialog.resx b/JexusManager.Features.DefaultDocument/NewDefaultDocumentDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.DefaultDocument/NewDefaultDocumentDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.DefaultDocument/Properties/AssemblyInfo.cs b/JexusManager.Features.DefaultDocument/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..aa9e597e --- /dev/null +++ b/JexusManager.Features.DefaultDocument/Properties/AssemblyInfo.cs @@ -0,0 +1,46 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.DefaultDocument")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.DefaultDocument")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1e54f67a-3538-4f8d-b2ee-5da6a821a528")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("Tests.JexusManager, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] diff --git a/JexusManager.Features.DefaultDocument/Properties/Resources.Designer.cs b/JexusManager.Features.DefaultDocument/Properties/Resources.Designer.cs new file mode 100644 index 00000000..c1b98093 --- /dev/null +++ b/JexusManager.Features.DefaultDocument/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.DefaultDocument.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.DefaultDocument.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap default_document_36 { + get { + object obj = ResourceManager.GetObject("default_document_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.DefaultDocument/Properties/Resources.resx b/JexusManager.Features.DefaultDocument/Properties/Resources.resx new file mode 100644 index 00000000..db6c7fcc --- /dev/null +++ b/JexusManager.Features.DefaultDocument/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\default_document_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.DefaultDocument/Resources/default_document_36.png b/JexusManager.Features.DefaultDocument/Resources/default_document_36.png new file mode 100644 index 0000000000000000000000000000000000000000..afb3741a1a35b5dec75d63d532695eb01831888d GIT binary patch literal 2090 zcmV+_2-WwAP)1c9i*0Py-nC5)c5N33DghE>1tglP;vrB4npB`vt<;C~tx*-J z>O(^wQ6-Sts;Y!kwGZu6O)FH9mb3(-hD#x_02^O0*kEIG@p{+0vzNJ?x%2_sUF_X8 zuKL(dI+`=*`k(**JKs5T;QvK1Jf3b@mQfT10Nb{490%LB%jPZ1 zDqB~YO3Q^1_h)Bk-|Oq^%a+dXSq{i?oFn`8?fZT_9#^V;iR-$orGEMQ%*@Q*6DLlL z06(h=NS5Vwp-@OkCX-l}h2uB`gF%E4NYXPx7oXMgRb`PRYHMpHkH^!nyw0;)$K@a@ zJ=Y4Tl9iLJESSZ-rfC%ctu|RG6k4@iRY2t!Fbt#WfYktn!{JrgTLH+n?Ii~+$C9e5 zD<*$Ysn)MwkL$YsTgjT5n#vCNBEGcz0~Y66vt*@!bX{N7xhq*D5?N|nDQr{(R1VCd zWNTq#xn!l|l>=4QhnCA!`d%toxi$boSmbg#nM@wP-%CwRh?<(vbN$xDkn6hWx=uQs zUIMT?8%a=!(OBHFTj}ncBFbtD)I!Cdn)6>(~Vy&eXJCz#Jm_*|ROp$UHa!SC6- zXA5t?y?1Rsq$tYLhFI!L%Ne_Rb(Hg;+~)Z4cPVH^9%u6S`~g}LF-Atmm`N81$J&_7 z8#Ha+#E*A(a`F5Z96R<0Oq0-xt*eq`<(ztPmFc>UrfFQcGR&=8lbk&H14bS^B4;=_ zwu9nP_{+x^5TR!3>uT})6zaS>o12433LN<6Zr(ifGE)x&hkJW}6s!tJ2vK!kQ&p90 zHp|4s3}?^Y;MlS6^7v_z^$oSWx~&66vT00gV0+Kk@CW?VHnt!aQ#fXk$8%Y_+BeV~ zkMYW`mw4-2JqbxNf4wS0mDpJfjEO{o3m5M2;fL=K2>AI*XFEGKZ{q6pFR=080 zOZDeJ{R|}%1{t_!XU5)w$z(HP)w7yrfSk3Qw*;K<@J2g5Kpbodoy+5X83GgL0P zjgCI$$dNtB^0V$&uJ@DZ-c4ho6=wmA>w;xFShmaL%q-itcH#?$xiusB)#)qPj)M?_ z&dxTerZ#YJ=gxOSWmnmv54o<3X_|OEp6BE%7K;oF+~?5Yz5Mn3XXH!?Uo?i_mI%2Z zN#FuP*yzH>$jVfHna^NZHtn10{Mn50GH|(~Wchp^*L9c9 z)QhHR8gr>EpzIt5KUOS(YQ1@T(X3Z`XQV({)mnqupiev-tt z1IV(wp=un8L?Xztj1U5k=ReIdnGCuv7#M!Q-mW^X4L?K+M-ak9H~pwZ36CTp;UI*~ zmW_4Kjc*tRrfE_a_Hun-j7uX~>O5W?N2)99L#2D!@}MY55{X2DXe3A`qjP3Z$95IA zHt6i$AfwOTWnR^Inkg_nS70ic=kHgCupNiF)I7FrqiGtNrqR8rm8QBdlI%y*Ok|m4 zMTW}lF{P5#*M~{ZWf4vtnczCwS`!2Ve%^e2J*Pju%DkMwvK>reF>6No;J5!IZ+SSn ztA;Nn8YmWvXqv{Ei#LgcTS(_MB#Ftg3|W>{^-Pn=Wa#LKF*G<%z}8Sqm0-ZXRR7lg zUcS-gA)8K;&FiQIouV7U5O8yBntVP_p-^CI`Vr%5l!l;}+1X6Gx%ughs>{BT#p7{a ze|;yz!&5Z*EXGqdljmf)@NTrg$ymaXok1GKR z=W@Boi(L!YeCM5B&V6)+&AtLfO^`~ZxOi=lq|-nqr;*KT}B3~V;j@5!uI^U8+FFk;95hn`6#TLuTQhhxJxBlJS$6GeVe8f=?%n%G z2FL@sO4l*#+S=MS_4fAu#&zB11rQbgZyd)#*LB%6P1!IE$ut#@ZAX2Q)Zh&SBC_A_ z$F?0bO>>1v*|Mw(Mah|dzt{G9z3Kk`{`Zo} zAh^)i8w%A&gwQP^iW(pQeSwiIkSfXB6)&tx%DoFo;lDGbWPE2KE#}2SS`qaA4I$z; U4ac#pPXGV_07*qoM6N<$f;OWIl>h($ literal 0 HcmV?d00001 diff --git a/JexusManager.Features.DefaultDocument/packages.config b/JexusManager.Features.DefaultDocument/packages.config new file mode 100644 index 00000000..571e4fe0 --- /dev/null +++ b/JexusManager.Features.DefaultDocument/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.DirectoryBrowse/DirectoryBrowseFeature.cs b/JexusManager.Features.DirectoryBrowse/DirectoryBrowseFeature.cs new file mode 100644 index 00000000..b1bbdfc7 --- /dev/null +++ b/JexusManager.Features.DirectoryBrowse/DirectoryBrowseFeature.cs @@ -0,0 +1,209 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.DirectoryBrowse +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Resources; + + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + internal class DirectoryBrowseFeature + { + private sealed class FeatureTaskList : TaskList + { + private readonly DirectoryBrowseFeature _owner; + + public FeatureTaskList(DirectoryBrowseFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + if (!_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Enable", "Enable", string.Empty).SetUsage()); + } + + if (_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Disable", "Disable", string.Empty).SetUsage()); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Enable() + { + _owner.Enable(); + } + + [Obfuscation(Exclude = true)] + public void Disable() + { + _owner.Disable(); + } + } + + public DirectoryBrowseFeature(Module module) + { + this.Module = module; + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + + private TaskList _taskList; + + protected void DisplayErrorMessage(Exception ex, ResourceManager resourceManager) + { + var service = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + service.ShowError(ex, resourceManager.GetString("General"), "", false); + } + + protected object GetService(Type type) + { + return (this.Module as IServiceProvider).GetService(type); + } + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/directoryBrowse"); + var enabled = (bool)section["enabled"]; + var flags = (long)section["showFlags"]; + TimeEnabled = (flags & 4) == 4; + SizeEnabled = (flags & 8) == 8; + ExtensionEnabled = (flags & 16) == 16; + DateEnabled = (flags & 2) == 2; + LongDateEnabled = (flags & 32) == 32; + this.SetEnabled(enabled); + } + + private void Enable() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + ConfigurationSection section = service.GetSection("system.webServer/directoryBrowse"); + section["enabled"] = true; + this.SetEnabled(true); + } + + private void Disable() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + ConfigurationSection section = service.GetSection("system.webServer/directoryBrowse"); + section["enabled"] = false; + this.SetEnabled(false); + } + + public void SetEnabled(bool enabled) + { + this.IsEnabled = enabled; + this.OnDirectoryBrowseSettingsSaved(); + } + + protected void OnDirectoryBrowseSettingsSaved() + { + this.DirectoryBrowseSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210534"); + return false; + } + + public DirectoryBrowseSettingsSavedEventHandler DirectoryBrowseSettingsUpdated { get; set; } + public string Description { get; } + + public virtual bool IsFeatureEnabled + { + get { return true; } + } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public Module Module { get; } + + public string Name + { + get { return "Directory Browsing"; } + } + + public bool IsEnabled { get; set; } + + public void CancelChanges() + { + this.Load(); + } + + public bool ApplyChanges() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/directoryBrowse"); + section["enabled"] = this.IsEnabled; + long flags = 0; + if (DateEnabled) + { + flags |= 2; + } + + if (TimeEnabled) + { + flags |= 4; + } + + if (SizeEnabled) + { + flags |= 8; + } + + if (ExtensionEnabled) + { + flags |= 16; + } + + if (LongDateEnabled) + { + flags |= 32; + } + + section["showFlags"] = flags; + service.ServerManager.CommitChanges(); + return true; + } + + public bool LongDateEnabled { get; set; } + + public bool ExtensionEnabled { get; set; } + + public bool SizeEnabled { get; set; } + + public bool TimeEnabled { get; set; } + + public bool DateEnabled { get; set; } + } +} diff --git a/JexusManager.Features.DirectoryBrowse/DirectoryBrowseModule.cs b/JexusManager.Features.DirectoryBrowse/DirectoryBrowseModule.cs new file mode 100644 index 00000000..15384bc6 --- /dev/null +++ b/JexusManager.Features.DirectoryBrowse/DirectoryBrowseModule.cs @@ -0,0 +1,29 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.DirectoryBrowse +{ + using System; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + using Properties; + + internal class DirectoryBrowseModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)this.GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo( + this, + typeof(DirectoryBrowsePage), + "Directory Browsing", + "Configure information to display in a directory listing", + Resources.directory_browsing_36, + Resources.directory_browsing_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.DirectoryBrowse/DirectoryBrowseModuleProvider.cs b/JexusManager.Features.DirectoryBrowse/DirectoryBrowseModuleProvider.cs new file mode 100644 index 00000000..4a07c61d --- /dev/null +++ b/JexusManager.Features.DirectoryBrowse/DirectoryBrowseModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.DirectoryBrowse +{ + using System; + + using Microsoft.Web.Management.Server; + + public class DirectoryBrowseModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(this.Name, typeof(DirectoryBrowseModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.DirectoryBrowse/DirectoryBrowsePage.Designer.cs b/JexusManager.Features.DirectoryBrowse/DirectoryBrowsePage.Designer.cs new file mode 100644 index 00000000..03435590 --- /dev/null +++ b/JexusManager.Features.DirectoryBrowse/DirectoryBrowsePage.Designer.cs @@ -0,0 +1,283 @@ +namespace JexusManager.Features.DirectoryBrowse +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class DirectoryBrowsePage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.cbLongDate = new System.Windows.Forms.CheckBox(); + this.cbDate = new System.Windows.Forms.CheckBox(); + this.cbExtension = new System.Windows.Forms.CheckBox(); + this.cbSize = new System.Windows.Forms.CheckBox(); + this.cbTime = new System.Windows.Forms.CheckBox(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 5; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.SplitContainer1SplitterMoved); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.cbLongDate); + this.panel2.Controls.Add(this.cbDate); + this.panel2.Controls.Add(this.cbExtension); + this.panel2.Controls.Add(this.cbSize); + this.panel2.Controls.Add(this.cbTime); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 11; + // + // cbLongDate + // + this.cbLongDate.AutoSize = true; + this.cbLongDate.Enabled = false; + this.cbLongDate.Location = new System.Drawing.Point(33, 158); + this.cbLongDate.Name = "cbLongDate"; + this.cbLongDate.Size = new System.Drawing.Size(74, 17); + this.cbLongDate.TabIndex = 8; + this.cbLongDate.Text = "Long date"; + this.cbLongDate.UseVisualStyleBackColor = true; + this.cbLongDate.CheckedChanged += new System.EventHandler(this.CbSslCheckedChanged); + // + // cbDate + // + this.cbDate.AutoSize = true; + this.cbDate.Enabled = false; + this.cbDate.Location = new System.Drawing.Point(16, 125); + this.cbDate.Name = "cbDate"; + this.cbDate.Size = new System.Drawing.Size(49, 17); + this.cbDate.TabIndex = 7; + this.cbDate.Text = "Date"; + this.cbDate.UseVisualStyleBackColor = true; + this.cbDate.CheckedChanged += new System.EventHandler(this.CbDateCheckedChanged); + // + // cbExtension + // + this.cbExtension.AutoSize = true; + this.cbExtension.Enabled = false; + this.cbExtension.Location = new System.Drawing.Point(16, 90); + this.cbExtension.Name = "cbExtension"; + this.cbExtension.Size = new System.Drawing.Size(72, 17); + this.cbExtension.TabIndex = 6; + this.cbExtension.Text = "Extension"; + this.cbExtension.UseVisualStyleBackColor = true; + this.cbExtension.CheckedChanged += new System.EventHandler(this.CbSslCheckedChanged); + // + // cbSize + // + this.cbSize.AutoSize = true; + this.cbSize.Enabled = false; + this.cbSize.Location = new System.Drawing.Point(16, 54); + this.cbSize.Name = "cbSize"; + this.cbSize.Size = new System.Drawing.Size(46, 17); + this.cbSize.TabIndex = 5; + this.cbSize.Text = "Size"; + this.cbSize.UseVisualStyleBackColor = true; + this.cbSize.CheckedChanged += new System.EventHandler(this.CbSslCheckedChanged); + // + // cbTime + // + this.cbTime.AutoSize = true; + this.cbTime.Enabled = false; + this.cbTime.Location = new System.Drawing.Point(16, 21); + this.cbTime.Name = "cbTime"; + this.cbTime.Size = new System.Drawing.Size(49, 17); + this.cbTime.TabIndex = 4; + this.cbTime.Text = "Time"; + this.cbTime.UseVisualStyleBackColor = true; + this.cbTime.CheckedChanged += new System.EventHandler(this.CbSslCheckedChanged); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(357, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to specify the information that displays in a directory listing." + + ""; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 10; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(192, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Directory Browsing"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // DirectoryBrowsePage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "DirectoryBrowsePage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Panel panel2; + private PictureBox pictureBox1; + private CheckBox cbTime; + private ContextMenuStrip cmsActionPanel; + private CheckBox cbLongDate; + private CheckBox cbDate; + private CheckBox cbExtension; + private CheckBox cbSize; + } +} diff --git a/JexusManager.Features.DirectoryBrowse/DirectoryBrowsePage.cs b/JexusManager.Features.DirectoryBrowse/DirectoryBrowsePage.cs new file mode 100644 index 00000000..e1d4a6ba --- /dev/null +++ b/JexusManager.Features.DirectoryBrowse/DirectoryBrowsePage.cs @@ -0,0 +1,160 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.DirectoryBrowse +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class DirectoryBrowsePage : ModuleDialogPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly DirectoryBrowsePage _owner; + + public PageTaskList(DirectoryBrowsePage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private DirectoryBrowseFeature _feature; + private bool _hasChanges; + private bool _initialized; + private TaskList _taskList; + + public DirectoryBrowsePage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new DirectoryBrowseFeature(this.Module); + _feature.DirectoryBrowseSettingsUpdated = this.Refresh; + _feature.Load(); + base.Initialize(navigationData); + } + + protected override bool ShowHelp() + { + return _feature.ShowHelp(); + } + + private void SplitContainer1SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + protected override bool ApplyChanges() + { + _feature.TimeEnabled = cbTime.Checked; + _feature.SizeEnabled = cbSize.Checked; + _feature.ExtensionEnabled = cbExtension.Checked; + _feature.DateEnabled = cbDate.Checked; + _feature.LongDateEnabled = cbLongDate.Checked; + if (!_feature.ApplyChanges()) + { + return false; + } + + this.ClearChanges(); + return true; + } + + protected override void CancelChanges() + { + _feature.CancelChanges(); + this.ClearChanges(); + } + + protected override bool HasChanges + { + get { return _hasChanges; } + } + + protected override bool CanApplyChanges + { + get { return true; } + } + + private void InformChanges() + { + if (!_initialized) + { + return; + } + + _hasChanges = true; + this.Refresh(); + } + + private void ClearChanges() + { + _hasChanges = false; + this.Refresh(); + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + + protected override void OnRefresh() + { + cbTime.Enabled = cbSize.Enabled = cbExtension.Enabled = cbDate.Enabled = _feature.IsEnabled; + if (!_hasChanges) + { + cbTime.Checked = _feature.TimeEnabled; + cbSize.Checked = _feature.SizeEnabled; + cbExtension.Checked = _feature.ExtensionEnabled; + cbDate.Checked = _feature.DateEnabled; + cbLongDate.Checked = _feature.LongDateEnabled; + _initialized = true; + } + + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + } + + private void CbDateCheckedChanged(object sender, EventArgs e) + { + this.InformChanges(); + cbLongDate.Enabled = cbDate.Checked && cbDate.Enabled; + } + + private void CbSslCheckedChanged(object sender, EventArgs e) + { + InformChanges(); + } + } +} diff --git a/JexusManager.Features.DirectoryBrowse/DirectoryBrowsePage.resx b/JexusManager.Features.DirectoryBrowse/DirectoryBrowsePage.resx new file mode 100644 index 00000000..950be5d2 --- /dev/null +++ b/JexusManager.Features.DirectoryBrowse/DirectoryBrowsePage.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 143, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.DirectoryBrowse/DirectoryBrowseSettingsSavedEventHandler.cs b/JexusManager.Features.DirectoryBrowse/DirectoryBrowseSettingsSavedEventHandler.cs new file mode 100644 index 00000000..ba7ae2ba --- /dev/null +++ b/JexusManager.Features.DirectoryBrowse/DirectoryBrowseSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.DirectoryBrowse +{ + public delegate void DirectoryBrowseSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.DirectoryBrowse/JexusManager.Features.DirectoryBrowse.csproj b/JexusManager.Features.DirectoryBrowse/JexusManager.Features.DirectoryBrowse.csproj new file mode 100644 index 00000000..04cd8a25 --- /dev/null +++ b/JexusManager.Features.DirectoryBrowse/JexusManager.Features.DirectoryBrowse.csproj @@ -0,0 +1,103 @@ + + + + + Debug + AnyCPU + {5FB94CD1-AF29-4396-A27F-891243F12E8C} + Library + Properties + JexusManager.Features.DirectoryBrowse + JexusManager.Features.DirectoryBrowse + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + + + + + + + + + + + + + UserControl + + + DirectoryBrowsePage.cs + + + + + True + True + Resources.resx + + + + + DirectoryBrowsePage.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.DirectoryBrowse/JexusManager.snk b/JexusManager.Features.DirectoryBrowse/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.DirectoryBrowse/Properties/AssemblyInfo.cs b/JexusManager.Features.DirectoryBrowse/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..24b92c07 --- /dev/null +++ b/JexusManager.Features.DirectoryBrowse/Properties/AssemblyInfo.cs @@ -0,0 +1,46 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.DirectoryBrowse")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.DirectoryBrowse")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5fb94cd1-af29-4396-a27f-891243f12e8c")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("Tests.JexusManager, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] diff --git a/JexusManager.Features.DirectoryBrowse/Properties/Resources.Designer.cs b/JexusManager.Features.DirectoryBrowse/Properties/Resources.Designer.cs new file mode 100644 index 00000000..f2f230b7 --- /dev/null +++ b/JexusManager.Features.DirectoryBrowse/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.DirectoryBrowse.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.DirectoryBrowse.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap directory_browsing_36 { + get { + object obj = ResourceManager.GetObject("directory_browsing_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.DirectoryBrowse/Properties/Resources.resx b/JexusManager.Features.DirectoryBrowse/Properties/Resources.resx new file mode 100644 index 00000000..4c08315c --- /dev/null +++ b/JexusManager.Features.DirectoryBrowse/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\directory_browsing_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.DirectoryBrowse/Resources/directory_browsing_36.png b/JexusManager.Features.DirectoryBrowse/Resources/directory_browsing_36.png new file mode 100644 index 0000000000000000000000000000000000000000..f550bdfecfa0ff6a23bd7f69ea9698f1d86a463a GIT binary patch literal 1867 zcmV-R2ekN!P)*u7Fz6UYhL(T?qt&LpLH-NtCvmEukc|NgR*u@p!(6LtiruxZscp{57h(mJn!vOr%wGiolZ-wRuTjOd%0hKzOu4%^3tVC zPl3xV0ZEdSQWQm6TU*0*U3}js7K`CH4uY^rXyw?d-_k9DKq8S4BuVP6zZcr+!FmwQ zj(Y{v%(emYeZL`?O21q#HwCoQWQwBfIIbn2MhsY%)$)a{0JXKX?Z{puQC9`nh^0cI zux;|)x+;}Q5d^{i)@8lDy$xTu8!go@pfcBNJ=ZC6*HOeX2<>?9J20MOmt-H_Q`0g@!Cx*^tT zsh+WXKF{LfB4cA?RgF|8H4KB<*;zDAdC2Z0#D5<2Wt%wTjDhT}M?_`UhU; z-OC>_@LCr?`u0&$$r!HZvz{;W=f5rU-p~KY`)?m&a&nS;_wF%1K8`4gpFJ_w(_C@c z!-o$!cKihIUjB%$9~SkY!mcEiG~I;6biGm?xb|a(ZkZK>&^y5CEbeAPOLf0-fuM`8>&FlHbk#i#NYGgdm7`0XUwI=lQUuK}i&_U5}nlg^~p? z*Yl*)X*5l1nuo+@8VZ5{+qSof+b|6B`TQnZu1_=~VmmIj<6zqkj_cxjF23hdG)!E_ zMZzc5*~Y?BmiG2`^7;JUG!z5@x~>xng{n1m#meRKR$c5v0JiO7J1ztwAyGgSHy2~t zE^FB$B0fUk6P82_%b{J`TbhBoLNB z#HUoY$mVq{SHN}yTu(sDmw2r+jj@p>nM`iFr$Mxdt@g6|q$mgieSLlO_4Q$zCWjBS z^J3j#MYGs2T#8nJ;XqrPLQg71s;h&Jj&@|F4c)N$-2P6UKYvbNUtd#(8j8A+`fFX* z)6>I~Cr|j{H#5x4FQe;aN`^_XRHjt6(253zX;C&UY}?@vGk@p1CkLuBkY%~)*0Bwc z>$)v#8coyieV>(;6_hZ%_pK3b|LGI{xtb?mERoCWWVI4mtw>fY@!?-SC7lQ{b@B_` zy?d8vH2T>p#%7jIrx8VwuC6Zb+_}Tl)D-D1m5aamD}p34(AQ2RB(j<-v%Fg1+&6}J z>*VLj<#G%U53{ti#MP@;Id|^d-fQYcR@uu0L11ibj9a&Eas2pke)*HLEUy(<_{RpW z>(hU%pUhAXS}w=Un>QIA9%g-g9e|#m9+bIUFOl!tw~t4U9x*dB z!@$4*1E~~}Bw-k9{Q6f9a2yB6aadVdAr^}v%QD$)mP{tYix)4xH#s?Z@%HW8%heCn z`Ux|c%va8wIWry(hpP!P6bd!000comk|g^3`xzY_MHEF$)5NxIB9RD3j~?a3i4z<; zbcpHcX~N+!i9`ZLQOMrg8q9`beLM#>|91d6WROPRS<2ab6iD4M%x=yiJ zq);eOC=}3jol>d9#KZ*gc%1q9d1P5eRaHhuM>&7~d_+-{i}e}`fM9NJ?!ko%7bbz; zM&TI*L8S>5z18-8-xq4f)t54&Cvsv@{ z_3Pi+0vl?PP{l2mOErD5rU`Y61@Hj}aGySXy8q?Nm%liB_H6IM!h)5{3T4%d$qp;qa%^)6+SCe*?LDntc}jPgVc`002ovPDHLk FV1nEFf|LLN literal 0 HcmV?d00001 diff --git a/JexusManager.Features.FastCgi/EnvironmentVariables.cs b/JexusManager.Features.FastCgi/EnvironmentVariables.cs new file mode 100644 index 00000000..2461198b --- /dev/null +++ b/JexusManager.Features.FastCgi/EnvironmentVariables.cs @@ -0,0 +1,20 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.FastCgi +{ + using System.ComponentModel; + + internal class EnvironmentVariables + { + [Category("Misc")] + [DisplayName("Name")] + [DefaultValue("Name")] + public string Name { get; set; } + + [Category("Misc")] + [DisplayName("Value")] + public string Value { get; set; } + } +} diff --git a/JexusManager.Features.FastCgi/EnvironmentVariablesCollection.cs b/JexusManager.Features.FastCgi/EnvironmentVariablesCollection.cs new file mode 100644 index 00000000..c4cbcafe --- /dev/null +++ b/JexusManager.Features.FastCgi/EnvironmentVariablesCollection.cs @@ -0,0 +1,29 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.FastCgi +{ + using System.Collections; + + internal class EnvironmentVariablesCollection : CollectionBase + { + public EnvironmentVariables this[int index] + { + get + { + return (EnvironmentVariables)this.List[index]; + } + } + + public void Add(EnvironmentVariables variable) + { + this.List.Add(variable); + } + + public void Remove(EnvironmentVariables variable) + { + this.List.Remove(variable); + } + } +} diff --git a/JexusManager.Features.FastCgi/EnvironmentVariablesCollectionEditor.cs b/JexusManager.Features.FastCgi/EnvironmentVariablesCollectionEditor.cs new file mode 100644 index 00000000..c80bd91c --- /dev/null +++ b/JexusManager.Features.FastCgi/EnvironmentVariablesCollectionEditor.cs @@ -0,0 +1,23 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.FastCgi +{ + using System; + using System.ComponentModel.Design; + + internal class EnvironmentVariablesCollectionEditor : CollectionEditor + { + public EnvironmentVariablesCollectionEditor(Type type) + : base(type) + { + } + + protected override string GetDisplayText(object value) + { + EnvironmentVariables item = (EnvironmentVariables)value; + return item.Name; + } + } +} \ No newline at end of file diff --git a/JexusManager.Features.FastCgi/ErrorMode.cs b/JexusManager.Features.FastCgi/ErrorMode.cs new file mode 100644 index 00000000..b495fa2b --- /dev/null +++ b/JexusManager.Features.FastCgi/ErrorMode.cs @@ -0,0 +1,23 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.FastCgi +{ + using System.ComponentModel; + + internal enum ErrorMode : long + { + [Description("ReturnStdErrIn500")] + ReturnStdErrIn500 = 0, + + [Description("ReturnGeneric500")] + ReturnGeneric500 = 1, + + [Description("IgnoreAndReturn200")] + IgnoreAndReturn200 = 2, + + [Description("TerminateProcess")] + TerminateProcess = 3 + } +} diff --git a/JexusManager.Features.FastCgi/FastCgiFeature.cs b/JexusManager.Features.FastCgi/FastCgiFeature.cs new file mode 100644 index 00000000..f2ff50b3 --- /dev/null +++ b/JexusManager.Features.FastCgi/FastCgiFeature.cs @@ -0,0 +1,166 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/* + * Created by SharpDevelop. + * User: lextm + * Time: 11:06 AM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace JexusManager.Features.FastCgi +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + /// + /// Authorization feature. + /// + internal class FastCgiFeature : FeatureBase + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly FastCgiFeature _owner; + + public FeatureTaskList(FastCgiFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("AddAllow", "Add Application...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Set", "Edit...", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void AddAllow() + { + _owner.AddAllow(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void Set() + { + _owner.Edit(); + } + } + + public FastCgiFeature(Module module) + : base(module) + { + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + // IMPORTANT: force to be server only. + var section = service.ServerManager.GetApplicationHostConfiguration().GetSection("system.webServer/fastCgi"); + return section.GetCollection(); + } + + public void Load() + { + this.LoadItems(); + } + + public void AddAllow() + { + var dialog = new NewApplicationDialog(this.Module, null, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected FastCGI Application?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + this.RemoveItem(); + } + + public void Edit() + { + var dialog = new NewApplicationDialog(this.Module, this.SelectedItem, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.EditItem(dialog.Item); + } + + protected override void OnSettingsSaved() + { + this.FastCgiSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210483"); + return false; + } + + public FastCgiSettingsSavedEventHandler FastCgiSettingsUpdated { get; set; } + + public string Description { get; } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public string Name + { + get { return "FastCGI Settings"; } + } + } +} diff --git a/JexusManager.Features.FastCgi/FastCgiItem.cs b/JexusManager.Features.FastCgi/FastCgiItem.cs new file mode 100644 index 00000000..ef3ed91e --- /dev/null +++ b/JexusManager.Features.FastCgi/FastCgiItem.cs @@ -0,0 +1,212 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.FastCgi +{ + using System.ComponentModel; + + using Microsoft.Web.Administration; + + internal class FastCgiItem : IItem + { + public FastCgiItem(ConfigurationElement element) + { + this.Element = element; + this.Flag = element == null || element.IsLocallyStored ? "Local" : "Inhertied"; + EnvironmentVariables = new EnvironmentVariablesCollection(); + AdvancedSettings = new AdvancedSettings(); + if (element == null) + { + this.Path = this.Arguments = MonitorChangesTo = string.Empty; + MaxInstances = 4U; + InstanceMaxRequests = 200U; + ActivityTimeout = 30U; + IdleTimeout = 300U; + QueueLength = 1000U; + RapidFailsPerMinute = 10U; + RequestTimeout = 90U; + return; + } + + this.Path = (string)element["fullPath"]; + this.Arguments = (string)element["arguments"]; + + this.MonitorChangesTo = (string)element["monitorChangesTo"]; + ErrorMode = (ErrorMode)element["stderrMode"]; + MaxInstances = (uint)element["maxInstances"]; + IdleTimeout = (uint)element["idleTimeout"]; + ActivityTimeout = (uint)element["activityTimeout"]; + RequestTimeout = (uint)element["requestTimeout"]; + this.InstanceMaxRequests = (uint)element["instanceMaxRequests"]; + this.SignalBeforeTerminateSeconds = (uint)element["signalBeforeTerminateSeconds"]; + AdvancedSettings.Protocol = (Protocol)element["protocol"]; + QueueLength = (uint)element["queueLength"]; + AdvancedSettings.FlushNamedPipe = (bool)element["flushNamedPipe"]; + this.RapidFailsPerMinute = (uint)element["rapidFailsPerMinute"]; + + foreach (ConfigurationElement child in element.GetCollection("environmentVariables")) + { + EnvironmentVariables.Add( + new EnvironmentVariables { Name = (string)child["name"], Value = (string)child["value"] }); + } + } + + [Browsable(false)] + public string Arguments { get; set; } + + [Browsable(false)] + public string Path { get; set; } + + [Browsable(false)] + public ConfigurationElement Element { get; set; } + + [Browsable(false)] + public string Flag { get; set; } + + public bool Equals(FastCgiItem other) + { + // all properties + return this.Match(other); + } + + public void Apply() + { + this.Element["fullPath"] = this.Path; + this.Element["arguments"] = this.Arguments; + + this.Element["monitorChangesTo"] = this.MonitorChangesTo; + this.Element["stderrMode"] = this.ErrorMode; + this.Element["maxInstances"] = this.MaxInstances; + this.Element["idleTimeout"] = this.IdleTimeout; + this.Element["activityTimeout"] = this.ActivityTimeout; + this.Element["requestTimeout"] = this.RequestTimeout; + this.Element["instanceMaxRequests"] = this.InstanceMaxRequests; + this.Element["signalBeforeTerminateSeconds"] = this.SignalBeforeTerminateSeconds; + this.Element["protocol"] = this.AdvancedSettings.Protocol; + this.Element["queueLength"] = this.QueueLength; + this.Element["flushNamedPipe"] = this.AdvancedSettings.FlushNamedPipe; + this.Element["rapidFailsPerMinute"] = this.RapidFailsPerMinute; + + var collection = Element.GetCollection("environmentVariables"); + collection.Clear(); + foreach (EnvironmentVariables item in EnvironmentVariables) + { + var newElement = collection.CreateElement(); + newElement["name"] = item.Name; + newElement["value"] = item.Value; + collection.Add(newElement); + } + } + + public bool Match(FastCgiItem other) + { + // match combined keys. + return other != null && other.Arguments == this.Arguments && other.Path == this.Path; + } + + [Browsable(true)] + [Category("General")] + [Description("Specifies optional environment variables that will be set in the FastCGI executable.")] + [DisplayName("Environment Variables")] + [Editor(typeof(EnvironmentVariablesCollectionEditor), + typeof(System.Drawing.Design.UITypeEditor))] + public EnvironmentVariablesCollection EnvironmentVariables { get; set; } + + [Browsable(true)] + [Category("General")] + [Description("Specifies the number of requests a FastCGI process for this application is allowed to handle.")] + [DisplayName("Instance MaxRequests")] + [DefaultValue(200U)] + public uint InstanceMaxRequests { get; set; } + + [Browsable(true)] + [Category("General")] + [Description("Specifies the maximum number of FastCGI process that are allowed in the application's process pool.")] + [DisplayName("Max Instances")] + [DefaultValue(4U)] + public uint MaxInstances { get; set; } + + [Browsable(true)] + [Category("General")] + [Description("Specifies path to a file changes to which will trigger recycle of FastCGI processes.")] + [DisplayName("Monitor changes to file")] + [DefaultValue("")] + [Editor(typeof(System.Windows.Forms.Design.FileNameEditor), typeof(System.Drawing.Design.UITypeEditor))] + public string MonitorChangesTo { get; set; } + + [Browsable(true)] + [Category("General")] + [Description("Specifies how FastCGI module should behave when FastCGI process sends text on standard error stream.")] + [DisplayName("Standard error mode")] + [TypeConverter(typeof(DescriptionConverter))] + public ErrorMode ErrorMode { get; set; } + + [Browsable(true)] + [Category("Process Model")] + [Description("Specifies the time, in seconds, that a FastCGI process for this application is allowed to run without communicating with IIS.")] + [DisplayName("Activity Timeout")] + [DefaultValue(30U)] + public uint ActivityTimeout { get; set; } + + [Browsable(true)] + [Category("Process Model")] + [DisplayName("Advanced Settings")] + public AdvancedSettings AdvancedSettings { get; set; } + + [Browsable(true)] + [Category("Process Model")] + [Description("Specifies the time, in seconds, that a FastCGI process for this application is allowed to remain idle.")] + [DisplayName("Idle Timeout")] + [DefaultValue(300U)] + public uint IdleTimeout { get; set; } + + [Browsable(true)] + [Category("Process Model")] + [Description("Maximum number of requests that are permitted into FastCGI handler queue.")] + [DisplayName("Queue Length")] + [DefaultValue(1000U)] + public uint QueueLength { get; set; } + + [Browsable(true)] + [Category("Process Model")] + [Description("Specifies the number of FastCGI process failures allowed in a single minute before the FastCGI handler takes it off line.")] + [DisplayName("Rapid Fails PerMinute")] + [DefaultValue(10U)] + public uint RapidFailsPerMinute { get; set; } + + [Browsable(true)] + [Category("Process Model")] + [Description("Specifies the maximum allowed time, in seconds, for request processing.")] + [DisplayName("Request Timeout")] + [DefaultValue(90U)] + public uint RequestTimeout { get; set; } + + [Browsable(true)] + [Category("Process Model")] + [Description("Specifies the amount of time, in seconds, that IIS will wait after IIS signals a FastCGI application that it needs to shut down.")] + [DisplayName("Signal Before Terminate")] + [DefaultValue(300U)] + public uint SignalBeforeTerminateSeconds { get; set; } + } + + [TypeConverter(typeof(ExpandableObjectConverter))] + internal class AdvancedSettings + { + [Browsable(true)] + [Description("Specifies whether or not the named pipe between FastCGI processes for this application is flushed before shutting down the application.")] + [DisplayName("FlushNamedpipe")] + public bool FlushNamedPipe { get; set; } + + [Browsable(true)] + [Description("Specifies protocol to be used to communicate with FastCGI process.")] + [DisplayName("Protocol")] + [TypeConverter(typeof(DescriptionConverter))] + public Protocol Protocol { get; set; } + + public override string ToString() + { + return string.Empty; + } + } +} diff --git a/JexusManager.Features.FastCgi/FastCgiModule.cs b/JexusManager.Features.FastCgi/FastCgiModule.cs new file mode 100644 index 00000000..8b708c58 --- /dev/null +++ b/JexusManager.Features.FastCgi/FastCgiModule.cs @@ -0,0 +1,25 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.FastCgi +{ + using System; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + using Properties; + + internal class FastCgiModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)this.GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(FastCgiPage), "FastCGI Settings", + "Configure FastCGI process application pools", Resources.response_header_36, + Resources.response_header_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.FastCgi/FastCgiModuleProvider.cs b/JexusManager.Features.FastCgi/FastCgiModuleProvider.cs new file mode 100644 index 00000000..680ed72c --- /dev/null +++ b/JexusManager.Features.FastCgi/FastCgiModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.FastCgi +{ + using System; + + using Microsoft.Web.Management.Server; + + public class FastCgiModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(this.Name, typeof(FastCgiModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return scope == ManagementScope.Server; + } + } +} diff --git a/JexusManager.Features.FastCgi/FastCgiPage.Designer.cs b/JexusManager.Features.FastCgi/FastCgiPage.Designer.cs new file mode 100644 index 00000000..0f93ab49 --- /dev/null +++ b/JexusManager.Features.FastCgi/FastCgiPage.Designer.cs @@ -0,0 +1,259 @@ +namespace JexusManager.Features.FastCgi +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class FastCgiPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chPath = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chArguments = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chInstances = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chRequests = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 6; + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 6; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chPath, + this.chArguments, + this.chInstances, + this.chRequests}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 13); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 527); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListView1SelectedIndexChanged); + this.listView1.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.ListView1MouseDoubleClick); + // + // chPath + // + this.chPath.Text = "Full Path"; + this.chPath.Width = 300; + // + // chArguments + // + this.chArguments.Text = "Arguments"; + this.chArguments.Width = 200; + // + // chInstances + // + this.chInstances.Text = "Max. Instances"; + this.chInstances.Width = 120; + // + // chRequests + // + this.chRequests.Text = "Instance Max. Requests"; + this.chRequests.Width = 180; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(393, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to configure FastCGI applications used by websites on this serve" + + "r."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 5; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(174, 25); + this.label3.TabIndex = 2; + this.label3.Text = "FastCGI Settings"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // FastCgiPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "FastCgiPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private ListView listView1; + private ColumnHeader chPath; + private ColumnHeader chArguments; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Panel panel2; + private PictureBox pictureBox1; + private ContextMenuStrip cmsActionPanel; + private ColumnHeader chInstances; + private ColumnHeader chRequests; + } +} diff --git a/JexusManager.Features.FastCgi/FastCgiPage.cs b/JexusManager.Features.FastCgi/FastCgiPage.cs new file mode 100644 index 00000000..442187a5 --- /dev/null +++ b/JexusManager.Features.FastCgi/FastCgiPage.cs @@ -0,0 +1,134 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.FastCgi +{ + using System; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class FastCgiPage : ModuleListPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly FastCgiPage _owner; + + public PageTaskList(FastCgiPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class FastCgiListViewItem : ListViewItem + { + public FastCgiItem Item { get; } + + private readonly FastCgiPage _page; + + public FastCgiListViewItem(FastCgiItem item, FastCgiPage page) + : base(item.Path) + { + this.Item = item; + _page = page; + this.SubItems.Add(new ListViewSubItem(this, item.Arguments)); + this.SubItems.Add(new ListViewSubItem(this, item.MaxInstances.ToString())); + this.SubItems.Add(new ListViewSubItem(this, item.InstanceMaxRequests.ToString())); + } + } + + private FastCgiFeature _feature; + private PageTaskList _taskList; + + public FastCgiPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new FastCgiFeature(this.Module); + _feature.FastCgiSettingsUpdated = this.InitializeListPage; + _feature.Load(); + } + + protected override void InitializeListPage() + { + listView1.Items.Clear(); + foreach (var file in _feature.Items) + { + listView1.Items.Add(new FastCgiListViewItem(file, this)); + } + + if (_feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (FastCgiListViewItem item in listView1.Items) + { + if (item.Item == _feature.SelectedItem) + { + item.Selected = true; + } + } + } + + protected override void Refresh() + { + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + private void ListView1SelectedIndexChanged(object sender, EventArgs e) + { + _feature.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((FastCgiListViewItem)listView1.SelectedItems[0]).Item + : null; + // TODO: optimize refresh when null to not null (vice versa) + this.Refresh(); + } + + protected override bool ShowHelp() + { + _feature.ShowHelp(); + return true; + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + + private void ListView1MouseDoubleClick(object sender, MouseEventArgs e) + { + _feature.Edit(); + } + } +} diff --git a/JexusManager.Features.FastCgi/FastCgiPage.resx b/JexusManager.Features.FastCgi/FastCgiPage.resx new file mode 100644 index 00000000..80c56e6e --- /dev/null +++ b/JexusManager.Features.FastCgi/FastCgiPage.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 602, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.FastCgi/FastCgiSettingsSavedEventHandler.cs b/JexusManager.Features.FastCgi/FastCgiSettingsSavedEventHandler.cs new file mode 100644 index 00000000..ac31185a --- /dev/null +++ b/JexusManager.Features.FastCgi/FastCgiSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.FastCgi +{ + public delegate void FastCgiSettingsSavedEventHandler(); +} diff --git a/JexusManager.Features.FastCgi/JexusManager.Features.FastCgi.csproj b/JexusManager.Features.FastCgi/JexusManager.Features.FastCgi.csproj new file mode 100644 index 00000000..d58d6942 --- /dev/null +++ b/JexusManager.Features.FastCgi/JexusManager.Features.FastCgi.csproj @@ -0,0 +1,136 @@ + + + + + Debug + AnyCPU + {AA816B3F-8B23-4440-A276-898958204A6D} + Library + Properties + JexusManager.Features.FastCgi + JexusManager.Features.FastCgi + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + + + + + + + + + UserControl + + + FastCgiPage.cs + + + + Form + + + NewApplicationDialog.cs + + + + True + True + Resources.resx + + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + FastCgiPage.cs + + + NewApplicationDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.FastCgi/JexusManager.snk b/JexusManager.Features.FastCgi/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.FastCgi/NewApplicationDialog.Designer.cs b/JexusManager.Features.FastCgi/NewApplicationDialog.Designer.cs new file mode 100644 index 00000000..e1f83c1b --- /dev/null +++ b/JexusManager.Features.FastCgi/NewApplicationDialog.Designer.cs @@ -0,0 +1,160 @@ +namespace JexusManager.Features.FastCgi +{ + using System.ComponentModel; + using System.Windows.Forms; + + sealed partial class NewApplicationDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.txtArguments = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.pgProperties = new System.Windows.Forms.PropertyGrid(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(382, 471); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(281, 471); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(15, 25); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(420, 20); + this.txtPath.TabIndex = 6; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 9); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(51, 13); + this.label2.TabIndex = 7; + this.label2.Text = "Full Path:"; + // + // txtArguments + // + this.txtArguments.Location = new System.Drawing.Point(15, 80); + this.txtArguments.Name = "txtArguments"; + this.txtArguments.Size = new System.Drawing.Size(462, 20); + this.txtArguments.TabIndex = 8; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 64); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(60, 13); + this.label1.TabIndex = 11; + this.label1.Text = "Arguments:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 114); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(98, 13); + this.label3.TabIndex = 13; + this.label3.Text = "FastCGI Properties:"; + // + // btnBrowse + // + this.btnBrowse.Location = new System.Drawing.Point(441, 23); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(35, 23); + this.btnBrowse.TabIndex = 14; + this.btnBrowse.Text = "..."; + this.btnBrowse.UseVisualStyleBackColor = true; + // + // pgProperties + // + this.pgProperties.CategoryForeColor = System.Drawing.SystemColors.InactiveCaptionText; + this.pgProperties.Location = new System.Drawing.Point(15, 130); + this.pgProperties.Name = "pgProperties"; + this.pgProperties.Size = new System.Drawing.Size(461, 335); + this.pgProperties.TabIndex = 15; + this.pgProperties.ToolbarVisible = false; + // + // NewApplicationDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(489, 506); + this.Controls.Add(this.pgProperties); + this.Controls.Add(this.btnBrowse); + this.Controls.Add(this.label3); + this.Controls.Add(this.label1); + this.Controls.Add(this.txtArguments); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtPath); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewApplicationDialog"; + this.Text = "Add FastCGI Application"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewRestrictionDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private TextBox txtPath; + private Label label2; + private TextBox txtArguments; + private Label label1; + private Label label3; + private Button btnBrowse; + private PropertyGrid pgProperties; + } +} diff --git a/JexusManager.Features.FastCgi/NewApplicationDialog.cs b/JexusManager.Features.FastCgi/NewApplicationDialog.cs new file mode 100644 index 00000000..258669d7 --- /dev/null +++ b/JexusManager.Features.FastCgi/NewApplicationDialog.cs @@ -0,0 +1,78 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.FastCgi +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewApplicationDialog : DialogForm + { + private readonly FastCgiFeature _feature; + + public NewApplicationDialog(IServiceProvider serviceProvider, FastCgiItem existing, FastCgiFeature feature) + : base(serviceProvider) + { + this.InitializeComponent(); + this.Text = string.Format("{0} FastCGI Application", existing == null ? "Add" : "Edit"); + _feature = feature; + txtPath.ReadOnly = txtArguments.ReadOnly = existing != null; + this.Item = existing ?? new FastCgiItem(null); + txtPath.Text = this.Item.Path; + txtArguments.Text = this.Item.Arguments; + pgProperties.SelectedObject = this.Item; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + this.Item.Path = txtPath.Text; + Item.Arguments = txtArguments.Text; + + if (!txtPath.ReadOnly && _feature.Items.Any(item => item.Match(this.Item))) + { + ShowMessage( + "This FastCGI application already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + this.DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(txtPath, "TextChanged") + .Subscribe(evt => + { + btnOK.Enabled = true; + })); + + container.Add( + Observable.FromEventPattern(btnBrowse, "Click") + .Subscribe(evt => + { + DialogHelper.ShowFileDialog(txtPath, "CGI Executables|*.exe|CGI Files|*.dll|All Files|*.*"); + })); + } + + public FastCgiItem Item { get; set; } + + private void NewRestrictionDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210483"); + } + } +} diff --git a/JexusManager.Features.FastCgi/NewApplicationDialog.resx b/JexusManager.Features.FastCgi/NewApplicationDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.FastCgi/NewApplicationDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.FastCgi/Properties/AssemblyInfo.cs b/JexusManager.Features.FastCgi/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..32ee4e73 --- /dev/null +++ b/JexusManager.Features.FastCgi/Properties/AssemblyInfo.cs @@ -0,0 +1,46 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.FastCgi")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.FastCgi")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("aa816b3f-8b23-4440-a276-898958204a6d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("JexusManager.Features.Handlers, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] diff --git a/JexusManager.Features.FastCgi/Properties/Resources.Designer.cs b/JexusManager.Features.FastCgi/Properties/Resources.Designer.cs new file mode 100644 index 00000000..3be8801d --- /dev/null +++ b/JexusManager.Features.FastCgi/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.FastCgi.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.FastCgi.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap response_header_36 { + get { + object obj = ResourceManager.GetObject("response_header_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.FastCgi/Properties/Resources.resx b/JexusManager.Features.FastCgi/Properties/Resources.resx new file mode 100644 index 00000000..d6b63b74 --- /dev/null +++ b/JexusManager.Features.FastCgi/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\response_header_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.FastCgi/Protocol.cs b/JexusManager.Features.FastCgi/Protocol.cs new file mode 100644 index 00000000..d137a94c --- /dev/null +++ b/JexusManager.Features.FastCgi/Protocol.cs @@ -0,0 +1,17 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.FastCgi +{ + using System.ComponentModel; + + internal enum Protocol : long + { + [Description("NamedPipe")] + NamedPipe = 0, + + [Description("Tcp")] + Tcp = 1 + } +} diff --git a/JexusManager.Features.FastCgi/Resources/response_header_36.png b/JexusManager.Features.FastCgi/Resources/response_header_36.png new file mode 100644 index 0000000000000000000000000000000000000000..7b24c374f8e6847721a61daaa193945dd9655c24 GIT binary patch literal 1481 zcmV;)1vdJLP)VGd000McNliru-UJv76dNfV>5>2d1y)H! zK~z}7&6rzg990;{e{*KCySbF4t+{UkQqnYmwnQ-&Efq?AuuxjGLJ=$_SQM$W)&~&^ zf)64}1m7ywCxwbHYQ13*1T9q&ig>A3t=L4Hn5?Vtl_MK9od_F(4fB*iy*=!cA^%AvZRee%pOyqaQn8@1T zKA0OB85uZw^yp#WsYD>HwWzPJXLNM5s6<^|9iHc5SyseoFpit62A@i$0;NaV_jfUMYMLEMz8q_w7}r>ANxRRT-Oys9x2 zHWZw;ZIjF8$`rCJtISv&Oj}zU#+X=;sxDiC5Y#vhHFgT$^06$7si~=d6hm5TIyyQ~ zN<|c35m4Z=iP=%!x$qKe8=ARq`{Ve^W#h(;u>qgtwm=cBbye_kAY}lHk1xK-gRQ`%HEbOwl_7VXKKt{$Tw?4||%jtLT-_gFCY-cxP3qMlhq&fG) z8+`Qi>E&K*xOdxe?%DPT#^_a5?9zT0tI+vjN$Ua9t?M{)Q}6Z@TY3kZr1+EX$3LUi zX&}3$B1PmbX@{(`AxyaPi6vpVp*eNw0c3Guta|Vyo*i^s%wOxbzcBUKb)X4mo zAPgxd&8)w`)hm}+aOY53(pcNfK=WM`77P55%V999%CgSR&Im-TLKa}OqTuI|p3j^f zV^K}xxeG`mQBosagLD-$`7yfcw$R+%!lq4|(913hVAAPyB3zL2iG}g==b7z3II}M| zbNa~EzO5&Edi$CdGFO;%FO#ww=&aq0O$NW9K-S>c4$}(@OiWBffNa|?wuW$ehqJE~ zHr&WdgW6sDAj9AN{MFgX+{CMcw+wE%dBX-K+{@I>w(0Sm1a2k$sRM`veQ zP=~iFm0~KXj}?O&puWN3{ILA`frod!lK<6z?$XR}3~arfG52?N^d8`eyHDatAJ=n{ z+M`fdjI@<-n~75+*nT9rD^iC7FmK)#$M!tSxl3>J$)~R~=Z|yannChz9#0h*A0IEa zj<`yll=2-N9aXD!S*7-+i@~s?e=ofq1HARci>z(90mG6za=9F~ZO7K0r2ZzQq^qkd zv9TuhGJw{mZXUYx88Vp+1#b}{1buydW&5N`ZYy=!N?sbufTWbg;M7{Es!(HNBTY?B#oANNRh6^M_eEUs3jS#}n~hZ^ z4l)c9zJ_*;cG){y$$h3!DAXrCO{tOaZZMpsr4JK#l~UFL^_74epuzLJOxReEuHkVK zO!#kF>&V*hn&p_x0BeABoXZ4YYpsP4f|iz+>-rgHZf-8HDZ;{pfqcMKO1*dJ(4pN* zsm8d^HP_%U0Jd$ + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Handlers/HandlersFeature.cs b/JexusManager.Features.Handlers/HandlersFeature.cs new file mode 100644 index 00000000..c438f097 --- /dev/null +++ b/JexusManager.Features.Handlers/HandlersFeature.cs @@ -0,0 +1,414 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/* + * Created by SharpDevelop. + * User: lextm + * Time: 11:06 AM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace JexusManager.Features.Handlers +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + using Microsoft.Web.Management.Server; + + using Module = Microsoft.Web.Management.Client.Module; + + /// + /// Description of DefaultDocumentFeature. + /// + internal class HandlersFeature : FeatureBase + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly HandlersFeature _owner; + + public FeatureTaskList(HandlersFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + if (_owner.IsInOrder) + { + result.Add(GetMoveUpTaskItem(_owner.CanMoveUp)); + result.Add(GetMoveDownTaskItem(_owner.CanMoveDown)); + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Unorder", "View Unordered List...", string.Empty).SetUsage()); + } + else + { + result.Add(new MethodTaskItem("AddManaged", "Add Managed Handler...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("AddScript", "Add Script Map...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("AddWildcard", "Add Wildcard Script Map...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Add", "Add Module Mapping...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Edit", "Edit...", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Set", "Edit Feature Permissions...", string.Empty).SetUsage()); + if (_owner.CanRevert) + { + result.Add(new MethodTaskItem("Revert", "Revert to Parent", string.Empty).SetUsage()); + } + + result.Add(new MethodTaskItem("InOrder", "View Ordered List...", string.Empty).SetUsage()); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void AddManaged() + { + _owner.AddManaged(); + } + + [Obfuscation(Exclude = true)] + public void AddScript() + { + _owner.AddScript(); + } + + [Obfuscation(Exclude = true)] + public void AddWildcard() + { + _owner.AddWildcard(); + } + + [Obfuscation(Exclude = true)] + public void Add() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void Edit() + { + _owner.Edit(); + } + + [Obfuscation(Exclude = true)] + public void Set() + { + _owner.Set(); + } + + [Obfuscation(Exclude = true)] + public void Rename() + { + _owner.Rename(); + } + + [Obfuscation(Exclude = true)] + public override void MoveUp() + { + _owner.MoveUp(); + } + + [Obfuscation(Exclude = true)] + public override void MoveDown() + { + _owner.MoveDown(); + } + + [Obfuscation(Exclude = true)] + public void InOrder() + { + _owner.InOrder(); + } + + [Obfuscation(Exclude = true)] + public void Unorder() + { + _owner.Unorder(); + } + + [Obfuscation(Exclude = true)] + public void Revert() + { + _owner.Revert(); + } + } + + public HandlersFeature(Module module) + : base(module) + { + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + this.Items = new List(); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + + // server level modules are in "" location. + ConfigurationSection section = service.Scope == ManagementScope.Server ? service.GetSection("system.webServer/handlers", string.Empty) : service.GetSection("system.webServer/handlers", null, false); + this.AccessPolicy = (long)section["accessPolicy"]; + this.CanRevert = service.Scope != ManagementScope.Server; + this.IsInOrder = false; + LoadItems(); + } + + public long AccessPolicy { get; set; } + + public void Add() + { + var dialog = new NewMappingDialog(this.Module, null, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + AddItem(dialog.Item); + } + + public void AddManaged() + { + var dialog = new NewHandlerDialog(this.Module, null, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void AddScript() + { + var dialog = new NewScriptMapDialog(this.Module, null, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void AddWildcard() + { + var dialog = new NewWildcardDialog(this.Module, null, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Set() + { + var dialog = new PermissionsDialog(this.Module, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + service.ServerManager.CommitChanges(); + this.OnSettingsSaved(); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected authorization rule?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + public void Edit() + { + HandlersItem newItem; + + if (!string.IsNullOrWhiteSpace(SelectedItem.Type)) + { + var dialog = new NewHandlerDialog(this.Module, this.SelectedItem, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + newItem = dialog.Item; + } + else if (SelectedItem.Modules == "IsapiModule" && !string.IsNullOrWhiteSpace(SelectedItem.ScriptProcessor)) + { + var dialog = new NewScriptMapDialog(this.Module, this.SelectedItem, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + newItem = dialog.Item; + } + else + { + var dialog = new NewMappingDialog(this.Module, this.SelectedItem, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + newItem = dialog.Item; + } + + this.EditItem(newItem); + } + + public void Rename() + { + } + + public void MoveUp() + { + if (this.Items.Any(item => item.Flag != "Local")) + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + var result = + dialog.ShowMessage( + "The list order will be changed for this feature. If you continue, changes made to this feature at a parent level will no longer be inherited at this level. Do you want to continue?", + this.Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + } + + MoveUpItem(); + } + + public void MoveDown() + { + if (this.Items.Any(item => item.Flag != "Local")) + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + var result = + dialog.ShowMessage( + "The list order will be changed for this feature. If you continue, changes made to this feature at a parent level will no longer be inherited at this level. Do you want to continue?", + this.Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + } + + MoveDownItem(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + // server level modules are in "" location. + ConfigurationSection section = service.Scope == ManagementScope.Server ? service.GetSection("system.webServer/handlers", string.Empty) : service.GetSection("system.webServer/handlers", null, false); + return section.GetCollection(); + } + + public void InOrder() + { + this.IsInOrder = true; + this.OnSettingsSaved(); + } + + public void Unorder() + { + this.IsInOrder = false; + this.OnSettingsSaved(); + } + + public void Revert() + { + if (!CanRevert) + { + throw new InvalidOperationException("Revert operation cannot be done at server level"); + } + + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + var result = + dialog.ShowMessage( + "Reverting to the parent configuration will result in the loss of all settings in the local configuration file for this feature. Are you sure you want to continue?", + this.Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + + RevertItems(); + } + + protected override void OnSettingsSaved() + { + this.HandlersSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210505"); + return false; + } + + public bool IsInOrder { get; private set; } + + public bool CanRevert { get; private set; } + + public HandlersSettingsSavedEventHandler HandlersSettingsUpdated { get; set; } + + public string Description { get; } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + + public string Name + { + get { return "Handler Mappings"; } + } + } +} diff --git a/JexusManager.Features.Handlers/HandlersItem.cs b/JexusManager.Features.Handlers/HandlersItem.cs new file mode 100644 index 00000000..1ef2f75c --- /dev/null +++ b/JexusManager.Features.Handlers/HandlersItem.cs @@ -0,0 +1,170 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Handlers +{ + using System.Collections.Generic; + using System.Linq; + using System.Text; + + using Microsoft.Web.Administration; + + internal class HandlersItem : IItem + { + public HandlersItem(ConfigurationElement element) + { + this.Element = element; + this.Flag = element == null || element.IsLocallyStored ? "Local" : "Inhertied"; + if (element == null) + { + this.PreConditions = new List(0); + Verb = "*"; + Path = Modules = ScriptProcessor = Type = string.Empty; + ResponseBufferLimit = 4194304; + RequireAccess = 3; + return; + } + + this.Name = (string)element["name"]; + this.Path = (string)element["path"]; + this.ResourceType = (long)element["resourceType"]; + this.Verb = (string)element["verb"]; + this.RequireAccess = (long)element["requireAccess"]; + this.Modules = (string)element["modules"]; + this.ScriptProcessor = (string)element["scriptProcessor"]; + this.Type = (string)element["type"]; + var content = (string)element["preCondition"]; + this.PreConditions = content.Split(',').ToList(); + ResponseBufferLimit = (uint)element["responseBufferLimit"]; + AllowPathInfo = (bool)element["allowPathInfo"]; + } + + public bool AllowPathInfo { get; set; } + + public uint ResponseBufferLimit { get; set; } + + public string ScriptProcessor { get; set; } + + public long RequireAccess { get; set; } + + public string Verb { get; set; } + + public long ResourceType { get; set; } + + public string Path { get; set; } + + public List PreConditions { get; set; } + + public string Type { get; set; } + + public string Modules { get; set; } + + public string Name { get; set; } + + public ConfigurationElement Element { get; set; } + + public string Flag { get; set; } + + public string GetState(long accessPolicy) + { + if (this.RequireAccess == 0L) + { + return "Enabled"; + } + + if (this.RequireAccess == 1L && (accessPolicy & 1L) == 1L) + { + return "Enabled"; + } + + if (this.RequireAccess == 2L && (accessPolicy & 2L) == 2L) + { + return "Enabled"; + } + + if (this.RequireAccess == 3L && (accessPolicy & 512L) == 512L) + { + return "Enabled"; + } + + if (this.RequireAccess == 4L && (accessPolicy & 4L) == 4L) + { + return "Enabled"; + } + + return "Disabled"; + } + + public string PathType + { + get + { + switch (this.ResourceType) + { + case 0: + return "File"; + case 1: + return "Folder"; + case 2: + return "File or Folder"; + case 3: + return "Unspecified"; + } + + return "Unspecified"; + } + } + + public string TypeString + { + get + { + return !string.IsNullOrWhiteSpace(this.Type) ? this.Type : this.Modules; + } + } + + public bool Equals(HandlersItem other) + { + // all properties + return this.Match(other) && other.Type == this.Type; + } + + public void Apply() + { + Element["name"] = Name; + Element["path"] = Path; + Element["resourceType"] = ResourceType; + Element["verb"] = Verb; + Element["requireAccess"] = RequireAccess; + Element["modules"] = Modules; + Element["scriptProcessor"] = ScriptProcessor; + Element["type"] = Type; + Element["preCondition"] = Combine(PreConditions); + Element["responseBufferLimit"] = ResponseBufferLimit; + Element["allowPathInfo"] = AllowPathInfo; + } + + private static string Combine(List preConditions) + { + if (preConditions.Count == 0) + { + return string.Empty; + } + + var result = new StringBuilder(preConditions[0]); + for (int index = 1; index < preConditions.Count; index++) + { + result.AppendFormat(",{0}", preConditions[index]); + } + + return result.ToString(); + } + + public bool Match(HandlersItem other) + { + // match combined keys. + return other != null && other.Name == this.Name; + } + } +} \ No newline at end of file diff --git a/JexusManager.Features.Handlers/HandlersModule.cs b/JexusManager.Features.Handlers/HandlersModule.cs new file mode 100644 index 00000000..aec3ffe3 --- /dev/null +++ b/JexusManager.Features.Handlers/HandlersModule.cs @@ -0,0 +1,25 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Handlers +{ + using System; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + using Properties; + + internal class HandlersModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)this.GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(HandlersPage), "Handler Mappings", + "Specify resources that handle responses for specific request types", Resources.handlers_36, + Resources.handlers_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.Handlers/HandlersModuleProvider.cs b/JexusManager.Features.Handlers/HandlersModuleProvider.cs new file mode 100644 index 00000000..ac0abf01 --- /dev/null +++ b/JexusManager.Features.Handlers/HandlersModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Handlers +{ + using System; + + using Microsoft.Web.Management.Server; + + public class HandlersModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(this.Name, typeof(HandlersModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.Handlers/HandlersPage.Designer.cs b/JexusManager.Features.Handlers/HandlersPage.Designer.cs new file mode 100644 index 00000000..a415547c --- /dev/null +++ b/JexusManager.Features.Handlers/HandlersPage.Designer.cs @@ -0,0 +1,314 @@ +namespace JexusManager.Features.Handlers +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class HandlersPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chPath = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chState = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.cbPathType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chHandler = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.toolStrip2 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel2 = new System.Windows.Forms.ToolStripLabel(); + this.cbGroup = new System.Windows.Forms.ToolStripComboBox(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.toolStrip2.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 6; + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.toolStrip2); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 6; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chName, + this.chPath, + this.chState, + this.cbPathType, + this.chHandler, + this.chType}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 38); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 502); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListView1SelectedIndexChanged); + // + // chName + // + this.chName.Text = "Name"; + this.chName.Width = 180; + // + // chPath + // + this.chPath.Text = "Path"; + this.chPath.Width = 120; + // + // chState + // + this.chState.Text = "State"; + this.chState.Width = 100; + // + // cbPathType + // + this.cbPathType.Text = "Path Type"; + this.cbPathType.Width = 100; + // + // chHandler + // + this.chHandler.Text = "Handler"; + this.chHandler.Width = 180; + // + // chType + // + this.chType.Text = "Entry Type"; + this.chType.Width = 80; + // + // toolStrip2 + // + this.toolStrip2.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel2, + this.cbGroup}); + this.toolStrip2.Location = new System.Drawing.Point(0, 13); + this.toolStrip2.Name = "toolStrip2"; + this.toolStrip2.Size = new System.Drawing.Size(560, 25); + this.toolStrip2.TabIndex = 3; + this.toolStrip2.Text = "toolStrip2"; + // + // toolStripLabel2 + // + this.toolStripLabel2.Name = "toolStripLabel2"; + this.toolStripLabel2.Size = new System.Drawing.Size(59, 22); + this.toolStripLabel2.Text = "Group by:"; + // + // cbGroup + // + this.cbGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbGroup.Items.AddRange(new object[] { + "No Grouping", + "Status", + "IP Address", + "Protocol", + "Port"}); + this.cbGroup.Name = "cbGroup"; + this.cbGroup.Size = new System.Drawing.Size(121, 25); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(595, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to specify the resources, such as DLLs and managed code, that ha" + + "ndle responses for specific request types."; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(187, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Handler Mappings"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 5; + this.pictureBox1.TabStop = false; + // + // HandlersPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "HandlersPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.toolStrip2.ResumeLayout(false); + this.toolStrip2.PerformLayout(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private ListView listView1; + private ColumnHeader chType; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Panel panel2; + private ToolStrip toolStrip2; + private ToolStripLabel toolStripLabel2; + private ToolStripComboBox cbGroup; + private PictureBox pictureBox1; + private ContextMenuStrip cmsActionPanel; + private ColumnHeader chName; + private ColumnHeader chPath; + private ColumnHeader chHandler; + private ColumnHeader chState; + private ColumnHeader cbPathType; + } +} diff --git a/JexusManager.Features.Handlers/HandlersPage.cs b/JexusManager.Features.Handlers/HandlersPage.cs new file mode 100644 index 00000000..b3d7579c --- /dev/null +++ b/JexusManager.Features.Handlers/HandlersPage.cs @@ -0,0 +1,134 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Handlers +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class HandlersPage : ModuleListPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly HandlersPage _owner; + + public PageTaskList(HandlersPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class HandlersListViewItem : ListViewItem + { + public HandlersItem Item { get; } + + private readonly HandlersPage _page; + + public HandlersListViewItem(HandlersItem item, HandlersPage page) + : base(item.Name) + { + this.Item = item; + _page = page; + this.SubItems.Add(new ListViewSubItem(this, item.Path)); + this.SubItems.Add(new ListViewSubItem(this, item.GetState(page._feature.AccessPolicy))); + this.SubItems.Add(new ListViewSubItem(this, item.PathType)); + this.SubItems.Add(new ListViewSubItem(this, item.TypeString)); + this.SubItems.Add(new ListViewSubItem(this, item.Flag)); + } + } + + private HandlersFeature _feature; + private PageTaskList _taskList; + + public HandlersPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new HandlersFeature(this.Module); + _feature.HandlersSettingsUpdated = this.InitializeListPage; + _feature.Load(); + } + + protected override void InitializeListPage() + { + toolStrip2.Visible = !_feature.IsInOrder; + listView1.Items.Clear(); + foreach (var file in _feature.Items) + { + listView1.Items.Add(new HandlersListViewItem(file, this)); + } + + if (_feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (HandlersListViewItem item in listView1.Items) + { + if (item.Item == _feature.SelectedItem) + { + item.Selected = true; + } + } + } + + protected override void Refresh() + { + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + private void ListView1SelectedIndexChanged(object sender, EventArgs e) + { + _feature.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((HandlersListViewItem)listView1.SelectedItems[0]).Item + : null; + // TODO: optimize refresh when null to not null (vice versa) + this.Refresh(); + } + + protected override bool ShowHelp() + { + _feature.ShowHelp(); + return true; + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + } +} diff --git a/JexusManager.Features.Handlers/HandlersPage.resx b/JexusManager.Features.Handlers/HandlersPage.resx new file mode 100644 index 00000000..464d127c --- /dev/null +++ b/JexusManager.Features.Handlers/HandlersPage.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 602, 17 + + + 497, 17 + + + 17, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.Handlers/HandlersSettingsSavedEventHandler.cs b/JexusManager.Features.Handlers/HandlersSettingsSavedEventHandler.cs new file mode 100644 index 00000000..eba701d4 --- /dev/null +++ b/JexusManager.Features.Handlers/HandlersSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Handlers +{ + public delegate void HandlersSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.Handlers/JexusManager.Features.Handlers.csproj b/JexusManager.Features.Handlers/JexusManager.Features.Handlers.csproj new file mode 100644 index 00000000..30bac6b2 --- /dev/null +++ b/JexusManager.Features.Handlers/JexusManager.Features.Handlers.csproj @@ -0,0 +1,183 @@ + + + + + Debug + AnyCPU + {BD450763-248D-4117-9AF0-51A625667B61} + Library + Properties + JexusManager.Features.Handlers + JexusManager.Features.Handlers + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + + + + + UserControl + + + HandlersPage.cs + + + + Form + + + NewHandlerDialog.cs + + + Form + + + NewMappingDialog.cs + + + Form + + + NewScriptMapDialog.cs + + + Form + + + NewWildcardDialog.cs + + + Form + + + PermissionsDialog.cs + + + + True + True + Resources.resx + + + Form + + + RestrictionsDialog.cs + + + + + HandlersPage.cs + + + NewHandlerDialog.cs + + + NewMappingDialog.cs + + + NewScriptMapDialog.cs + + + NewWildcardDialog.cs + + + PermissionsDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + RestrictionsDialog.cs + + + + + {aa816b3f-8b23-4440-a276-898958204a6d} + JexusManager.Features.FastCgi + + + {8bfab6bc-57c1-44fc-88e2-b3ce5b75be9f} + JexusManager.Features.Modules + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Handlers/JexusManager.snk b/JexusManager.Features.Handlers/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Handlers/NewHandlerDialog.Designer.cs b/JexusManager.Features.Handlers/NewHandlerDialog.Designer.cs new file mode 100644 index 00000000..7dbaa8b4 --- /dev/null +++ b/JexusManager.Features.Handlers/NewHandlerDialog.Designer.cs @@ -0,0 +1,182 @@ +namespace JexusManager.Features.Handlers +{ + using System.ComponentModel; + using System.Windows.Forms; + + sealed partial class NewHandlerDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.txtDescription = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.txtType = new System.Windows.Forms.ComboBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.btnRestrictions = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(332, 301); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(231, 301); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // txtDescription + // + this.txtDescription.AutoSize = true; + this.txtDescription.Location = new System.Drawing.Point(12, 156); + this.txtDescription.Name = "txtDescription"; + this.txtDescription.Size = new System.Drawing.Size(38, 13); + this.txtDescription.TabIndex = 2; + this.txtDescription.Text = "Name:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(15, 172); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(269, 20); + this.txtName.TabIndex = 6; + // + // txtType + // + this.txtType.Location = new System.Drawing.Point(15, 96); + this.txtType.Name = "txtType"; + this.txtType.Size = new System.Drawing.Size(393, 21); + this.txtType.TabIndex = 8; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 80); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(34, 13); + this.label1.TabIndex = 9; + this.label1.Text = "Type:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 120); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(227, 13); + this.label2.TabIndex = 10; + this.label2.Text = "Example: System.Web.UI.PageHandlerFactory"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 9); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(74, 13); + this.label3.TabIndex = 11; + this.label3.Text = "Request path:"; + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(15, 25); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(297, 20); + this.txtPath.TabIndex = 12; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(12, 48); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(128, 13); + this.label4.TabIndex = 13; + this.label4.Text = "Example: *.bas, wsvc.axd"; + // + // btnRestrictions + // + this.btnRestrictions.Location = new System.Drawing.Point(15, 216); + this.btnRestrictions.Name = "btnRestrictions"; + this.btnRestrictions.Size = new System.Drawing.Size(140, 23); + this.btnRestrictions.TabIndex = 14; + this.btnRestrictions.Text = "Request Restrictions..."; + this.btnRestrictions.UseVisualStyleBackColor = true; + // + // NewHandlerDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(439, 336); + this.Controls.Add(this.btnRestrictions); + this.Controls.Add(this.label4); + this.Controls.Add(this.txtPath); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Controls.Add(this.txtType); + this.Controls.Add(this.txtName); + this.Controls.Add(this.txtDescription); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewHandlerDialog"; + this.Text = "Add Managed Handler"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewRestrictionDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label txtDescription; + private TextBox txtName; + private ComboBox txtType; + private Label label1; + private Label label2; + private Label label3; + private TextBox txtPath; + private Label label4; + private Button btnRestrictions; + } +} diff --git a/JexusManager.Features.Handlers/NewHandlerDialog.cs b/JexusManager.Features.Handlers/NewHandlerDialog.cs new file mode 100644 index 00000000..0e987971 --- /dev/null +++ b/JexusManager.Features.Handlers/NewHandlerDialog.cs @@ -0,0 +1,90 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Handlers +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewHandlerDialog : DialogForm + { + private readonly HandlersFeature _feature; + + public NewHandlerDialog(IServiceProvider serviceProvider, HandlersItem existing, HandlersFeature feature) + : base(serviceProvider) + { + InitializeComponent(); + Text = existing == null ? "Add Managed Handler" : "Edit Managed Handler"; + txtName.ReadOnly = existing != null; + _feature = feature; + Item = existing ?? new HandlersItem(null); + if (existing != null) + { + txtType.Text = Item.Type; + txtName.Text = Item.Name; + txtPath.Text = Item.Path; + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item.Type = txtType.Text; + Item.Name = txtName.Text; + Item.Path = txtPath.Text; + if (!txtName.ReadOnly && _feature.Items.Any(item => item.Match(Item))) + { + ShowMessage( + "A handler with this name already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Merge(Observable.FromEventPattern(txtType, "TextChanged")) + .Merge(Observable.FromEventPattern(txtPath, "TextChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text) + && !string.IsNullOrWhiteSpace(txtType.Text) + && !string.IsNullOrWhiteSpace(txtPath.Text); + })); + + container.Add( + Observable.FromEventPattern(btnRestrictions, "Click") + .Subscribe(evt => + { + var dialog = new RestrictionsDialog(ServiceProvider, Item); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + })); + } + + public HandlersItem Item { get; set; } + + private void NewRestrictionDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210505#Add_Handler"); + } + } +} diff --git a/JexusManager.Features.Handlers/NewHandlerDialog.resx b/JexusManager.Features.Handlers/NewHandlerDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Handlers/NewHandlerDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Handlers/NewMappingDialog.Designer.cs b/JexusManager.Features.Handlers/NewMappingDialog.Designer.cs new file mode 100644 index 00000000..31a599f7 --- /dev/null +++ b/JexusManager.Features.Handlers/NewMappingDialog.Designer.cs @@ -0,0 +1,204 @@ +namespace JexusManager.Features.Handlers +{ + using System.ComponentModel; + using System.Windows.Forms; + + sealed partial class NewMappingDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.txtDescription = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.txtExecutable = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.btnRestrictions = new System.Windows.Forms.Button(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.label2 = new System.Windows.Forms.Label(); + this.txtModule = new System.Windows.Forms.ComboBox(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(332, 301); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(231, 301); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // txtDescription + // + this.txtDescription.AutoSize = true; + this.txtDescription.Location = new System.Drawing.Point(12, 175); + this.txtDescription.Name = "txtDescription"; + this.txtDescription.Size = new System.Drawing.Size(38, 13); + this.txtDescription.TabIndex = 2; + this.txtDescription.Text = "Name:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(15, 191); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(269, 20); + this.txtName.TabIndex = 6; + // + // txtExecutable + // + this.txtExecutable.Location = new System.Drawing.Point(15, 140); + this.txtExecutable.Name = "txtExecutable"; + this.txtExecutable.Size = new System.Drawing.Size(367, 20); + this.txtExecutable.TabIndex = 8; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 124); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(109, 13); + this.label1.TabIndex = 9; + this.label1.Text = "Executable (optional):"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 9); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(74, 13); + this.label3.TabIndex = 11; + this.label3.Text = "Request path:"; + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(15, 25); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(297, 20); + this.txtPath.TabIndex = 12; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(12, 48); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(128, 13); + this.label4.TabIndex = 13; + this.label4.Text = "Example: *.bas, wsvc.axd"; + // + // btnRestrictions + // + this.btnRestrictions.Location = new System.Drawing.Point(15, 220); + this.btnRestrictions.Name = "btnRestrictions"; + this.btnRestrictions.Size = new System.Drawing.Size(140, 23); + this.btnRestrictions.TabIndex = 14; + this.btnRestrictions.Text = "Request Restrictions..."; + this.btnRestrictions.UseVisualStyleBackColor = true; + // + // btnBrowse + // + this.btnBrowse.Location = new System.Drawing.Point(388, 138); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(28, 23); + this.btnBrowse.TabIndex = 15; + this.btnBrowse.Text = "..."; + this.btnBrowse.UseVisualStyleBackColor = true; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 76); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(45, 13); + this.label2.TabIndex = 17; + this.label2.Text = "Module:"; + // + // txtModule + // + this.txtModule.Location = new System.Drawing.Point(15, 92); + this.txtModule.Name = "txtModule"; + this.txtModule.Size = new System.Drawing.Size(393, 21); + this.txtModule.TabIndex = 16; + // + // NewMappingDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(439, 336); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtModule); + this.Controls.Add(this.btnBrowse); + this.Controls.Add(this.btnRestrictions); + this.Controls.Add(this.label4); + this.Controls.Add(this.txtPath); + this.Controls.Add(this.label3); + this.Controls.Add(this.label1); + this.Controls.Add(this.txtExecutable); + this.Controls.Add(this.txtName); + this.Controls.Add(this.txtDescription); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewMappingDialog"; + this.Text = "Add Module Mapping"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewRestrictionDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label txtDescription; + private TextBox txtName; + private TextBox txtExecutable; + private Label label1; + private Label label3; + private TextBox txtPath; + private Label label4; + private Button btnRestrictions; + private Button btnBrowse; + private Label label2; + private ComboBox txtModule; + } +} diff --git a/JexusManager.Features.Handlers/NewMappingDialog.cs b/JexusManager.Features.Handlers/NewMappingDialog.cs new file mode 100644 index 00000000..c6f88673 --- /dev/null +++ b/JexusManager.Features.Handlers/NewMappingDialog.cs @@ -0,0 +1,142 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Handlers +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.IO; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using JexusManager.Features.FastCgi; + using JexusManager.Features.Modules; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewMappingDialog : DialogForm + { + private readonly HandlersFeature _feature; + + public NewMappingDialog(IServiceProvider serviceProvider, HandlersItem existing, HandlersFeature feature) + : base(serviceProvider) + { + InitializeComponent(); + Text = existing == null ? "Add Module Mapping" : "Edit Module Mapping"; + txtName.ReadOnly = existing != null; + _feature = feature; + Item = existing ?? new HandlersItem(null); + + var modules = new ModulesFeature((Module)serviceProvider); + modules.Load(); + foreach (var module in modules.Items.Where(module => !module.IsManaged).OrderBy(module => module.Name)) + { + txtModule.Items.Add(module.Name); + } + + if (existing != null) + { + txtExecutable.Text = Item.ScriptProcessor; + txtModule.Text = Item.Modules; + txtName.Text = Item.Name; + txtPath.Text = Item.Path; + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item.ScriptProcessor = txtExecutable.Text; + Item.Modules = txtModule.Text; + Item.Name = txtName.Text; + Item.Path = txtPath.Text; + if (!txtName.ReadOnly) + { + if (_feature.Items.Any(item => item.Match(Item))) + { + ShowMessage( + "A handler with this name already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + if (txtModule.Text == "FastCgiModule") + { + var result = ShowMessage( + "Do you want to create a FastCGI application for this executable? Click \"Yes\" to add the entry to the FastCGI collection and to enable this executable to run as a FastCGI application.", + MessageBoxButtons.YesNoCancel, + MessageBoxIcon.Information, + MessageBoxDefaultButton.Button1); + if (result == DialogResult.Yes) + { + var fastCgi = new FastCgiFeature((Module)ServiceProvider); + if (fastCgi.Items.All(item => item.Path != txtExecutable.Text)) + { + fastCgi.AddItem(new FastCgiItem(null) { Path = txtExecutable.Text }); + } + } + } + + if (!string.IsNullOrWhiteSpace(txtExecutable.Text) && !File.Exists(txtExecutable.Text)) + { + ShowMessage( + "The specific executable does not exist on the server.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + } + + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Merge(Observable.FromEventPattern(txtExecutable, "TextChanged")) + .Merge(Observable.FromEventPattern(txtPath, "TextChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text) + && !string.IsNullOrWhiteSpace(txtModule.Text) + && !string.IsNullOrWhiteSpace(txtPath.Text); + })); + + container.Add( + Observable.FromEventPattern(btnRestrictions, "Click") + .Subscribe(evt => + { + var dialog = new RestrictionsDialog(ServiceProvider, Item); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + })); + + container.Add( + Observable.FromEventPattern(btnBrowse, "Click") + .Subscribe(evt => + { + DialogHelper.ShowFileDialog(txtExecutable, "|*.dll||*.exe"); + })); + } + + public HandlersItem Item { get; set; } + + private void NewRestrictionDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210505#Add_Module"); + } + } +} diff --git a/JexusManager.Features.Handlers/NewMappingDialog.resx b/JexusManager.Features.Handlers/NewMappingDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Handlers/NewMappingDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Handlers/NewScriptMapDialog.Designer.cs b/JexusManager.Features.Handlers/NewScriptMapDialog.Designer.cs new file mode 100644 index 00000000..03ac8068 --- /dev/null +++ b/JexusManager.Features.Handlers/NewScriptMapDialog.Designer.cs @@ -0,0 +1,182 @@ +namespace JexusManager.Features.Handlers +{ + using System.ComponentModel; + using System.Windows.Forms; + + sealed partial class NewScriptMapDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.txtDescription = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.txtExecutable = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.btnRestrictions = new System.Windows.Forms.Button(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(332, 301); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(231, 301); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // txtDescription + // + this.txtDescription.AutoSize = true; + this.txtDescription.Location = new System.Drawing.Point(12, 156); + this.txtDescription.Name = "txtDescription"; + this.txtDescription.Size = new System.Drawing.Size(38, 13); + this.txtDescription.TabIndex = 2; + this.txtDescription.Text = "Name:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(15, 172); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(269, 20); + this.txtName.TabIndex = 6; + // + // txtExecutable + // + this.txtExecutable.Location = new System.Drawing.Point(15, 96); + this.txtExecutable.Name = "txtExecutable"; + this.txtExecutable.Size = new System.Drawing.Size(367, 20); + this.txtExecutable.TabIndex = 8; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 80); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(63, 13); + this.label1.TabIndex = 9; + this.label1.Text = "Executable:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 9); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(74, 13); + this.label3.TabIndex = 11; + this.label3.Text = "Request path:"; + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(15, 25); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(297, 20); + this.txtPath.TabIndex = 12; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(12, 48); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(128, 13); + this.label4.TabIndex = 13; + this.label4.Text = "Example: *.bas, wsvc.axd"; + // + // btnRestrictions + // + this.btnRestrictions.Location = new System.Drawing.Point(15, 216); + this.btnRestrictions.Name = "btnRestrictions"; + this.btnRestrictions.Size = new System.Drawing.Size(140, 23); + this.btnRestrictions.TabIndex = 14; + this.btnRestrictions.Text = "Request Restrictions..."; + this.btnRestrictions.UseVisualStyleBackColor = true; + // + // btnBrowse + // + this.btnBrowse.Location = new System.Drawing.Point(388, 94); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(28, 23); + this.btnBrowse.TabIndex = 15; + this.btnBrowse.Text = "..."; + this.btnBrowse.UseVisualStyleBackColor = true; + // + // NewScriptMapDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(439, 336); + this.Controls.Add(this.btnBrowse); + this.Controls.Add(this.btnRestrictions); + this.Controls.Add(this.label4); + this.Controls.Add(this.txtPath); + this.Controls.Add(this.label3); + this.Controls.Add(this.label1); + this.Controls.Add(this.txtExecutable); + this.Controls.Add(this.txtName); + this.Controls.Add(this.txtDescription); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewScriptMapDialog"; + this.Text = "Add Script Map"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewRestrictionDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label txtDescription; + private TextBox txtName; + private TextBox txtExecutable; + private Label label1; + private Label label3; + private TextBox txtPath; + private Label label4; + private Button btnRestrictions; + private Button btnBrowse; + } +} diff --git a/JexusManager.Features.Handlers/NewScriptMapDialog.cs b/JexusManager.Features.Handlers/NewScriptMapDialog.cs new file mode 100644 index 00000000..06a6ecc3 --- /dev/null +++ b/JexusManager.Features.Handlers/NewScriptMapDialog.cs @@ -0,0 +1,101 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Handlers +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewScriptMapDialog : DialogForm + { + private readonly HandlersFeature _feature; + + public NewScriptMapDialog(IServiceProvider serviceProvider, HandlersItem existing, HandlersFeature feature) + : base(serviceProvider) + { + InitializeComponent(); + Text = existing == null ? "Add Script Map" : "Edit Script Map"; + txtName.ReadOnly = existing != null; + _feature = feature; + Item = existing ?? new HandlersItem(null); + if (existing == null) + { + Item.Modules = "IsapiModule"; + } + else + { + txtExecutable.Text = Item.ScriptProcessor; + txtName.Text = Item.Name; + txtPath.Text = Item.Path; + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item.ScriptProcessor = txtExecutable.Text; + Item.Name = txtName.Text; + Item.Path = txtPath.Text; + if (!txtName.ReadOnly && _feature.Items.Any(item => item.Match(Item))) + { + ShowMessage( + "A handler with this name already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Merge(Observable.FromEventPattern(txtExecutable, "TextChanged")) + .Merge(Observable.FromEventPattern(txtPath, "TextChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text) + && !string.IsNullOrWhiteSpace(txtExecutable.Text) + && !string.IsNullOrWhiteSpace(txtPath.Text); + })); + + container.Add( + Observable.FromEventPattern(btnRestrictions, "Click") + .Subscribe(evt => + { + var dialog = new RestrictionsDialog(ServiceProvider, Item); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + })); + + container.Add( + Observable.FromEventPattern(btnBrowse, "Click") + .Subscribe(evt => + { + DialogHelper.ShowBrowseDialog(txtExecutable); + })); + } + + public HandlersItem Item { get; set; } + + private void NewRestrictionDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210505#Add_ScriptMap"); + } + } +} diff --git a/JexusManager.Features.Handlers/NewScriptMapDialog.resx b/JexusManager.Features.Handlers/NewScriptMapDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Handlers/NewScriptMapDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Handlers/NewWildcardDialog.Designer.cs b/JexusManager.Features.Handlers/NewWildcardDialog.Designer.cs new file mode 100644 index 00000000..26c8a218 --- /dev/null +++ b/JexusManager.Features.Handlers/NewWildcardDialog.Designer.cs @@ -0,0 +1,160 @@ +namespace JexusManager.Features.Handlers +{ + using System.ComponentModel; + using System.Windows.Forms; + + sealed partial class NewWildcardDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.txtDescription = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.txtExecutable = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(332, 301); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(231, 301); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // txtDescription + // + this.txtDescription.AutoSize = true; + this.txtDescription.Location = new System.Drawing.Point(12, 156); + this.txtDescription.Name = "txtDescription"; + this.txtDescription.Size = new System.Drawing.Size(38, 13); + this.txtDescription.TabIndex = 2; + this.txtDescription.Text = "Name:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(15, 172); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(269, 20); + this.txtName.TabIndex = 6; + // + // txtExecutable + // + this.txtExecutable.Location = new System.Drawing.Point(15, 96); + this.txtExecutable.Name = "txtExecutable"; + this.txtExecutable.Size = new System.Drawing.Size(367, 20); + this.txtExecutable.TabIndex = 8; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 80); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(63, 13); + this.label1.TabIndex = 9; + this.label1.Text = "Executable:"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 9); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(74, 13); + this.label3.TabIndex = 11; + this.label3.Text = "Request path:"; + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(15, 25); + this.txtPath.Name = "txtPath"; + this.txtPath.ReadOnly = true; + this.txtPath.Size = new System.Drawing.Size(297, 20); + this.txtPath.TabIndex = 12; + this.txtPath.Text = "*"; + // + // btnBrowse + // + this.btnBrowse.Location = new System.Drawing.Point(388, 94); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(28, 23); + this.btnBrowse.TabIndex = 15; + this.btnBrowse.Text = "..."; + this.btnBrowse.UseVisualStyleBackColor = true; + // + // NewWildcardDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(439, 336); + this.Controls.Add(this.btnBrowse); + this.Controls.Add(this.txtPath); + this.Controls.Add(this.label3); + this.Controls.Add(this.label1); + this.Controls.Add(this.txtExecutable); + this.Controls.Add(this.txtName); + this.Controls.Add(this.txtDescription); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewWildcardDialog"; + this.Text = "Add Wildcard Script Map"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewRestrictionDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label txtDescription; + private TextBox txtName; + private TextBox txtExecutable; + private Label label1; + private Label label3; + private TextBox txtPath; + private Button btnBrowse; + } +} diff --git a/JexusManager.Features.Handlers/NewWildcardDialog.cs b/JexusManager.Features.Handlers/NewWildcardDialog.cs new file mode 100644 index 00000000..be7e48f3 --- /dev/null +++ b/JexusManager.Features.Handlers/NewWildcardDialog.cs @@ -0,0 +1,90 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Handlers +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewWildcardDialog : DialogForm + { + private readonly HandlersFeature _feature; + + public NewWildcardDialog(IServiceProvider serviceProvider, HandlersItem existing, HandlersFeature feature) + : base(serviceProvider) + { + InitializeComponent(); + Text = existing == null ? "Add Wildcard Script Map" : "Edit Wildcard Script Map"; + txtName.ReadOnly = existing != null; + _feature = feature; + Item = existing ?? new HandlersItem(null); + if (existing == null) + { + Item.Modules = "IsapiModule"; + } + else + { + txtExecutable.Text = Item.ScriptProcessor; + txtName.Text = Item.Name; + txtPath.Text = Item.Path; + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item.ScriptProcessor = txtExecutable.Text; + Item.Name = txtName.Text; + Item.Path = txtPath.Text; + if (!txtName.ReadOnly && _feature.Items.Any(item => item.Match(Item))) + { + ShowMessage( + "A handler with this name already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Merge(Observable.FromEventPattern(txtExecutable, "TextChanged")) + .Merge(Observable.FromEventPattern(txtPath, "TextChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text) + && !string.IsNullOrWhiteSpace(txtExecutable.Text) + && !string.IsNullOrWhiteSpace(txtPath.Text); + })); + + container.Add( + Observable.FromEventPattern(btnBrowse, "Click") + .Subscribe(evt => + { + DialogHelper.ShowBrowseDialog(txtExecutable); + })); + } + + public HandlersItem Item { get; set; } + + private void NewRestrictionDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210505#Add_Wildcard"); + } + } +} diff --git a/JexusManager.Features.Handlers/NewWildcardDialog.resx b/JexusManager.Features.Handlers/NewWildcardDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Handlers/NewWildcardDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Handlers/PermissionsDialog.Designer.cs b/JexusManager.Features.Handlers/PermissionsDialog.Designer.cs new file mode 100644 index 00000000..3e393d2d --- /dev/null +++ b/JexusManager.Features.Handlers/PermissionsDialog.Designer.cs @@ -0,0 +1,130 @@ +namespace JexusManager.Features.Handlers +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal partial class PermissionsDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.cbRead = new System.Windows.Forms.CheckBox(); + this.cbScript = new System.Windows.Forms.CheckBox(); + this.cbExecute = new System.Windows.Forms.CheckBox(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(65, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Permissions:"; + // + // cbRead + // + this.cbRead.AutoSize = true; + this.cbRead.Location = new System.Drawing.Point(15, 38); + this.cbRead.Name = "cbRead"; + this.cbRead.Size = new System.Drawing.Size(52, 17); + this.cbRead.TabIndex = 1; + this.cbRead.Text = "Read"; + this.cbRead.UseVisualStyleBackColor = true; + // + // cbScript + // + this.cbScript.AutoSize = true; + this.cbScript.Location = new System.Drawing.Point(15, 61); + this.cbScript.Name = "cbScript"; + this.cbScript.Size = new System.Drawing.Size(53, 17); + this.cbScript.TabIndex = 2; + this.cbScript.Text = "Script"; + this.cbScript.UseVisualStyleBackColor = true; + // + // cbExecute + // + this.cbExecute.AutoSize = true; + this.cbExecute.Location = new System.Drawing.Point(37, 84); + this.cbExecute.Name = "cbExecute"; + this.cbExecute.Size = new System.Drawing.Size(65, 17); + this.cbExecute.TabIndex = 3; + this.cbExecute.Text = "Execute"; + this.cbExecute.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(192, 131); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 4; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(96, 131); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 5; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // PermissionsDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(299, 166); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.cbExecute); + this.Controls.Add(this.cbScript); + this.Controls.Add(this.cbRead); + this.Controls.Add(this.label1); + this.Name = "PermissionsDialog"; + this.Text = "Edit Feature Permissions"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.PermissionsDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label1; + private CheckBox cbRead; + private CheckBox cbScript; + private CheckBox cbExecute; + private Button btnCancel; + private Button btnOK; + } +} diff --git a/JexusManager.Features.Handlers/PermissionsDialog.cs b/JexusManager.Features.Handlers/PermissionsDialog.cs new file mode 100644 index 00000000..ffc8028b --- /dev/null +++ b/JexusManager.Features.Handlers/PermissionsDialog.cs @@ -0,0 +1,69 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Handlers +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal partial class PermissionsDialog : DialogForm + { + public PermissionsDialog(IServiceProvider serviceProvider, HandlersFeature feature) + : base(serviceProvider) + { + InitializeComponent(); + cbRead.Checked = (feature.AccessPolicy & 1L) == 1L; + cbScript.Checked = (feature.AccessPolicy & 512L) == 512L; + cbExecute.Checked = (feature.AccessPolicy & 4L) == 4L; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + if (cbRead.Checked) + { + feature.AccessPolicy |= 1L; + } + else + { + feature.AccessPolicy &= ~1L; + } + + if (cbScript.Checked) + { + feature.AccessPolicy |= 512L; + } + else + { + feature.AccessPolicy &= ~512L; + } + + if (cbExecute.Checked) + { + feature.AccessPolicy |= 4L; + } + else + { + feature.AccessPolicy &= ~4L; + } + + DialogResult = DialogResult.OK; + })); + } + + private void PermissionsDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210505"); + } + } +} diff --git a/JexusManager.Features.Handlers/PermissionsDialog.resx b/JexusManager.Features.Handlers/PermissionsDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Handlers/PermissionsDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Handlers/Properties/AssemblyInfo.cs b/JexusManager.Features.Handlers/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..5dc76fe3 --- /dev/null +++ b/JexusManager.Features.Handlers/Properties/AssemblyInfo.cs @@ -0,0 +1,46 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.Handlers")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.Handlers")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("bd450763-248d-4117-9af0-51a625667b61")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("Tests.JexusManager, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] diff --git a/JexusManager.Features.Handlers/Properties/Resources.Designer.cs b/JexusManager.Features.Handlers/Properties/Resources.Designer.cs new file mode 100644 index 00000000..8d60a11c --- /dev/null +++ b/JexusManager.Features.Handlers/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.Handlers.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.Handlers.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap handlers_36 { + get { + object obj = ResourceManager.GetObject("handlers_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.Handlers/Properties/Resources.resx b/JexusManager.Features.Handlers/Properties/Resources.resx new file mode 100644 index 00000000..e851bc89 --- /dev/null +++ b/JexusManager.Features.Handlers/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\handlers_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.Handlers/Resources/handlers_36.png b/JexusManager.Features.Handlers/Resources/handlers_36.png new file mode 100644 index 0000000000000000000000000000000000000000..b333c93f62351c8fdbcd4bafe2330855d51b8007 GIT binary patch literal 1579 zcmV+`2Gse9P)Ha5Vq`1-MB> zK~z}7?U+qyT-O!HfA_t6-+MFqnz1Zdu`C=bc4|bua26#F2%0Jmv<5Hoy>Lkg4s?~I zNx&M{o|_jB&~zyCS++;a!Mlka3}qFPN(OiT+IOr*rNbStzj3DhPAb})=$r+$E~%TIdkTpzz^>Wkn6f`Hk%EuOij`I z$Rl_`K$0Xia7w9$?Pk*1*@^G_ZmTs;tI6uu-8grS=@Tc2ip84Z`zh^+-q6XEqHA!F z?VX)`dg25f&p(epFwizD0DXOZrV*kcEsxjCbZ!7&D9435^g zu8VRUD3w@QUM5^vAlKc^-H$%v=JYiEM~p;Th{si#`{(njWN2uNqM`2GC^N|6DwK%f*pV3Z;O zO7rtzEj9>{C!Zu78e-)5@rI|ZUb)t~wx$|NngUYR&i(iL_0LRSA9pK(NmXje=l5@a z;DIgy9-NvY@qHE#9U|PnpZ=pqDHe+jS*Qo(`+oZ-dn*jT;L4RBG@3kh>eN4e^3qGA zpSf6|4ttOKs0ibtmjG-e(P?-#I9Ix}6Mhq#XYUTv^ zaOz7g{Pi+#zwzU(T^-enbohlA0GOSfWo2ch=^a(yw^o?=!$o%Fck}Szga03srIqd3 zvj=N!(~C1*hf&NMzxa@De~_;(mDu%==2!3jjk*5>-`{s={9^zsf*^<>VuhvU!e81l zSyj>1t5?@C)F=f3Sh`c@)VWLaW_ELF_AXjG%*`sYnH}ux8psWF$P;mx5Ji@97!#Ib zyo`$<%;Z`Es`^V+Mn*e)|9P5n+)c5l@O&T7 z_b{G88-sORBC80?V3UM6hBy`+y@_LAl~xQ@%dTEHdU$~I_8S)G`nhvQ;|BrRjsQR7 zqm5q6AVf&wn5Y~PmCN{^uoOG(pR#5Q)wAU|4x^)rCw{cRYvbqHR@lX@TZV_f7qXh% zU}5ogsT7-Qh#(5Yw>U-!#j<$o?k8Jj$Vufw)pGFQLG}!7XL902j=woczITAtIAr|i zhxy}szy0*&$&;h^9T?M&-OPs?`ILyzk@0x%*T;DM?LYDDtzuj0M_aFs`smuIpB}6B zMFj0S{N|U>ad>neJGOUk?dq`BuBEb-JVtB1?$m9RcBIFC_S4a=KZ6Q|!u0s~c&~^k zK#7P_N~vnU!bS~6#h;`CL;y+GA|lJn%NOtWZLa_iFqJypPS*ygzD5%us+6!noo>r! z8LFnz>AtO$xU#XEN;1=HlFFJm1u)tO%!dDd)UDI0;?{vl14@HR1B+V$*({)Dzf}$P dkW|^U{10uwzuE%|wx9q2002ovPDHLkV1i=@4>bS) literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Handlers/RestrictionsDialog.Designer.cs b/JexusManager.Features.Handlers/RestrictionsDialog.Designer.cs new file mode 100644 index 00000000..e4ca165c --- /dev/null +++ b/JexusManager.Features.Handlers/RestrictionsDialog.Designer.cs @@ -0,0 +1,342 @@ +namespace JexusManager.Features.Handlers +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal partial class RestrictionsDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tabPage1 = new System.Windows.Forms.TabPage(); + this.rbEither = new System.Windows.Forms.RadioButton(); + this.rbFolder = new System.Windows.Forms.RadioButton(); + this.rbFile = new System.Windows.Forms.RadioButton(); + this.cbInvoke = new System.Windows.Forms.CheckBox(); + this.tabPage2 = new System.Windows.Forms.TabPage(); + this.label2 = new System.Windows.Forms.Label(); + this.txtVerbs = new System.Windows.Forms.TextBox(); + this.rbSelectedVerbs = new System.Windows.Forms.RadioButton(); + this.rbAllVerbs = new System.Windows.Forms.RadioButton(); + this.label1 = new System.Windows.Forms.Label(); + this.tabPage3 = new System.Windows.Forms.TabPage(); + this.rbExecute = new System.Windows.Forms.RadioButton(); + this.rbScript = new System.Windows.Forms.RadioButton(); + this.rbWrite = new System.Windows.Forms.RadioButton(); + this.rbRead = new System.Windows.Forms.RadioButton(); + this.label3 = new System.Windows.Forms.Label(); + this.rbNone = new System.Windows.Forms.RadioButton(); + this.tabControl1.SuspendLayout(); + this.tabPage1.SuspendLayout(); + this.tabPage2.SuspendLayout(); + this.tabPage3.SuspendLayout(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(332, 301); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(236, 301); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // tabControl1 + // + this.tabControl1.Controls.Add(this.tabPage1); + this.tabControl1.Controls.Add(this.tabPage2); + this.tabControl1.Controls.Add(this.tabPage3); + this.tabControl1.Location = new System.Drawing.Point(12, 12); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(415, 283); + this.tabControl1.TabIndex = 2; + // + // tabPage1 + // + this.tabPage1.Controls.Add(this.rbEither); + this.tabPage1.Controls.Add(this.rbFolder); + this.tabPage1.Controls.Add(this.rbFile); + this.tabPage1.Controls.Add(this.cbInvoke); + this.tabPage1.Location = new System.Drawing.Point(4, 22); + this.tabPage1.Name = "tabPage1"; + this.tabPage1.Padding = new System.Windows.Forms.Padding(3); + this.tabPage1.Size = new System.Drawing.Size(407, 257); + this.tabPage1.TabIndex = 0; + this.tabPage1.Text = "Mapping"; + this.tabPage1.UseVisualStyleBackColor = true; + // + // rbEither + // + this.rbEither.AutoSize = true; + this.rbEither.Enabled = false; + this.rbEither.Location = new System.Drawing.Point(44, 110); + this.rbEither.Name = "rbEither"; + this.rbEither.Size = new System.Drawing.Size(82, 17); + this.rbEither.TabIndex = 3; + this.rbEither.TabStop = true; + this.rbEither.Text = "File or folder"; + this.rbEither.UseVisualStyleBackColor = true; + // + // rbFolder + // + this.rbFolder.AutoSize = true; + this.rbFolder.Enabled = false; + this.rbFolder.Location = new System.Drawing.Point(44, 73); + this.rbFolder.Name = "rbFolder"; + this.rbFolder.Size = new System.Drawing.Size(54, 17); + this.rbFolder.TabIndex = 2; + this.rbFolder.TabStop = true; + this.rbFolder.Text = "Folder"; + this.rbFolder.UseVisualStyleBackColor = true; + // + // rbFile + // + this.rbFile.AutoSize = true; + this.rbFile.Enabled = false; + this.rbFile.Location = new System.Drawing.Point(44, 40); + this.rbFile.Name = "rbFile"; + this.rbFile.Size = new System.Drawing.Size(41, 17); + this.rbFile.TabIndex = 1; + this.rbFile.TabStop = true; + this.rbFile.Text = "File"; + this.rbFile.UseVisualStyleBackColor = true; + // + // cbInvoke + // + this.cbInvoke.AutoSize = true; + this.cbInvoke.Location = new System.Drawing.Point(23, 17); + this.cbInvoke.Name = "cbInvoke"; + this.cbInvoke.Size = new System.Drawing.Size(231, 17); + this.cbInvoke.TabIndex = 0; + this.cbInvoke.Text = "Invoke handler only if request is mapped to:"; + this.cbInvoke.UseVisualStyleBackColor = true; + // + // tabPage2 + // + this.tabPage2.Controls.Add(this.label2); + this.tabPage2.Controls.Add(this.txtVerbs); + this.tabPage2.Controls.Add(this.rbSelectedVerbs); + this.tabPage2.Controls.Add(this.rbAllVerbs); + this.tabPage2.Controls.Add(this.label1); + this.tabPage2.Location = new System.Drawing.Point(4, 22); + this.tabPage2.Name = "tabPage2"; + this.tabPage2.Padding = new System.Windows.Forms.Padding(3); + this.tabPage2.Size = new System.Drawing.Size(407, 257); + this.tabPage2.TabIndex = 1; + this.tabPage2.Text = "Verbs"; + this.tabPage2.UseVisualStyleBackColor = true; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(49, 137); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(110, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Example: GET, POST"; + // + // txtVerbs + // + this.txtVerbs.Enabled = false; + this.txtVerbs.Location = new System.Drawing.Point(52, 114); + this.txtVerbs.Name = "txtVerbs"; + this.txtVerbs.Size = new System.Drawing.Size(241, 20); + this.txtVerbs.TabIndex = 3; + // + // rbSelectedVerbs + // + this.rbSelectedVerbs.AutoSize = true; + this.rbSelectedVerbs.Location = new System.Drawing.Point(34, 82); + this.rbSelectedVerbs.Name = "rbSelectedVerbs"; + this.rbSelectedVerbs.Size = new System.Drawing.Size(151, 17); + this.rbSelectedVerbs.TabIndex = 2; + this.rbSelectedVerbs.TabStop = true; + this.rbSelectedVerbs.Text = "One of the following verbs:"; + this.rbSelectedVerbs.UseVisualStyleBackColor = true; + // + // rbAllVerbs + // + this.rbAllVerbs.AutoSize = true; + this.rbAllVerbs.Location = new System.Drawing.Point(34, 47); + this.rbAllVerbs.Name = "rbAllVerbs"; + this.rbAllVerbs.Size = new System.Drawing.Size(65, 17); + this.rbAllVerbs.TabIndex = 1; + this.rbAllVerbs.TabStop = true; + this.rbAllVerbs.Text = "All verbs"; + this.rbAllVerbs.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(31, 21); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(160, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Specify the verbs to be handled:"; + // + // tabPage3 + // + this.tabPage3.Controls.Add(this.rbExecute); + this.tabPage3.Controls.Add(this.rbScript); + this.tabPage3.Controls.Add(this.rbWrite); + this.tabPage3.Controls.Add(this.rbRead); + this.tabPage3.Controls.Add(this.label3); + this.tabPage3.Controls.Add(this.rbNone); + this.tabPage3.Location = new System.Drawing.Point(4, 22); + this.tabPage3.Name = "tabPage3"; + this.tabPage3.Padding = new System.Windows.Forms.Padding(3); + this.tabPage3.Size = new System.Drawing.Size(407, 257); + this.tabPage3.TabIndex = 2; + this.tabPage3.Text = "Access"; + this.tabPage3.UseVisualStyleBackColor = true; + // + // rbExecute + // + this.rbExecute.AutoSize = true; + this.rbExecute.Location = new System.Drawing.Point(47, 138); + this.rbExecute.Name = "rbExecute"; + this.rbExecute.Size = new System.Drawing.Size(64, 17); + this.rbExecute.TabIndex = 5; + this.rbExecute.TabStop = true; + this.rbExecute.Text = "Execute"; + this.rbExecute.UseVisualStyleBackColor = true; + // + // rbScript + // + this.rbScript.AutoSize = true; + this.rbScript.Location = new System.Drawing.Point(47, 115); + this.rbScript.Name = "rbScript"; + this.rbScript.Size = new System.Drawing.Size(52, 17); + this.rbScript.TabIndex = 4; + this.rbScript.TabStop = true; + this.rbScript.Text = "Script"; + this.rbScript.UseVisualStyleBackColor = true; + // + // rbWrite + // + this.rbWrite.AutoSize = true; + this.rbWrite.Location = new System.Drawing.Point(47, 92); + this.rbWrite.Name = "rbWrite"; + this.rbWrite.Size = new System.Drawing.Size(50, 17); + this.rbWrite.TabIndex = 3; + this.rbWrite.TabStop = true; + this.rbWrite.Text = "Write"; + this.rbWrite.UseVisualStyleBackColor = true; + // + // rbRead + // + this.rbRead.AutoSize = true; + this.rbRead.Location = new System.Drawing.Point(47, 69); + this.rbRead.Name = "rbRead"; + this.rbRead.Size = new System.Drawing.Size(51, 17); + this.rbRead.TabIndex = 2; + this.rbRead.TabStop = true; + this.rbRead.Text = "Read"; + this.rbRead.UseVisualStyleBackColor = true; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(34, 16); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(211, 13); + this.label3.TabIndex = 1; + this.label3.Text = "Specify the access required by the handler:"; + // + // rbNone + // + this.rbNone.AutoSize = true; + this.rbNone.Location = new System.Drawing.Point(47, 46); + this.rbNone.Name = "rbNone"; + this.rbNone.Size = new System.Drawing.Size(51, 17); + this.rbNone.TabIndex = 0; + this.rbNone.TabStop = true; + this.rbNone.Text = "None"; + this.rbNone.UseVisualStyleBackColor = true; + // + // RestrictionsDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(439, 336); + this.Controls.Add(this.tabControl1); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "RestrictionsDialog"; + this.Text = "Request Restrictions"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.RestrictionsDialogHelpButtonClicked); + this.tabControl1.ResumeLayout(false); + this.tabPage1.ResumeLayout(false); + this.tabPage1.PerformLayout(); + this.tabPage2.ResumeLayout(false); + this.tabPage2.PerformLayout(); + this.tabPage3.ResumeLayout(false); + this.tabPage3.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private TabControl tabControl1; + private TabPage tabPage1; + private RadioButton rbEither; + private RadioButton rbFolder; + private RadioButton rbFile; + private CheckBox cbInvoke; + private TabPage tabPage2; + private Label label2; + private TextBox txtVerbs; + private RadioButton rbSelectedVerbs; + private RadioButton rbAllVerbs; + private Label label1; + private TabPage tabPage3; + private RadioButton rbExecute; + private RadioButton rbScript; + private RadioButton rbWrite; + private RadioButton rbRead; + private Label label3; + private RadioButton rbNone; + } +} diff --git a/JexusManager.Features.Handlers/RestrictionsDialog.cs b/JexusManager.Features.Handlers/RestrictionsDialog.cs new file mode 100644 index 00000000..88ab3b98 --- /dev/null +++ b/JexusManager.Features.Handlers/RestrictionsDialog.cs @@ -0,0 +1,119 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Handlers +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal partial class RestrictionsDialog : DialogForm + { + public RestrictionsDialog(IServiceProvider serviceProvider, HandlersItem item) + : base(serviceProvider) + { + InitializeComponent(); + cbInvoke.Checked = item.ResourceType != 3L; + rbFile.Checked = item.ResourceType == 0L; + rbFolder.Checked = item.ResourceType == 1L; + rbEither.Checked = item.ResourceType == 2L; + + rbNone.Checked = item.RequireAccess == 0L; + rbRead.Checked = item.RequireAccess == 1L; + rbWrite.Checked = item.RequireAccess == 2L; + rbScript.Checked = item.RequireAccess == 3L; + rbExecute.Checked = item.RequireAccess == 4L; + + rbAllVerbs.Checked = item.Verb == "*"; + rbSelectedVerbs.Checked = !rbAllVerbs.Checked; + if (rbSelectedVerbs.Checked) + { + txtVerbs.Text = item.Verb; + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + if (!cbInvoke.Checked) + { + item.ResourceType = 3L; + } + else if (rbFile.Checked) + { + item.ResourceType = 0L; + } + else if (rbFolder.Checked) + { + item.ResourceType = 1L; + } + else if (rbEither.Checked) + { + item.ResourceType = 2L; + } + + if (rbNone.Checked) + { + item.RequireAccess = 0L; + } + else if (rbRead.Checked) + { + item.RequireAccess = 1L; + } + else if (rbWrite.Checked) + { + item.RequireAccess = 2L; + } + else if (rbScript.Checked) + { + item.RequireAccess = 3L; + } + else if (rbExecute.Checked) + { + item.RequireAccess = 4L; + } + + if (rbAllVerbs.Checked) + { + item.Verb = "*"; + } + else if (rbSelectedVerbs.Checked) + { + item.Verb = txtVerbs.Text; + } + + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(cbInvoke, "CheckedChanged") + .Subscribe(evt => + { + rbFile.Enabled = rbFolder.Enabled = rbEither.Enabled = cbInvoke.Checked; + })); + + container.Add( + Observable.FromEventPattern(rbSelectedVerbs, "CheckedChanged") + .Merge(Observable.FromEventPattern(rbAllVerbs, "CheckedChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + txtVerbs.Enabled = rbSelectedVerbs.Checked; + })); + } + + private void RestrictionsDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210505#Request_Restrictions"); + } + } +} diff --git a/JexusManager.Features.Handlers/RestrictionsDialog.resx b/JexusManager.Features.Handlers/RestrictionsDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Handlers/RestrictionsDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Handlers/packages.config b/JexusManager.Features.Handlers/packages.config new file mode 100644 index 00000000..571e4fe0 --- /dev/null +++ b/JexusManager.Features.Handlers/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.HttpApi/HttpApiFeature.cs b/JexusManager.Features.HttpApi/HttpApiFeature.cs new file mode 100644 index 00000000..73812ee4 --- /dev/null +++ b/JexusManager.Features.HttpApi/HttpApiFeature.cs @@ -0,0 +1,45 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Web.Management.Client; +using System; + +namespace JexusManager.Features.HttpApi +{ + internal abstract class HttpApiFeature : FeatureBase, IHttpApiFeature + where T : class, IItem + { + protected HttpApiFeature(Module module) + : base(module) + { + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + + public abstract TaskList GetTaskList(); + + public abstract void Load(); + + protected override void OnSettingsSaved() + { + this.HttpApiSettingsUpdate?.Invoke(); + } + + public abstract bool ShowHelp(); + + public HttpApiSettingsSavedEventHandler HttpApiSettingsUpdate { get; set; } + + public string Description { get; } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public abstract string Name { get; } + } +} diff --git a/JexusManager.Features.HttpApi/HttpApiModule.cs b/JexusManager.Features.HttpApi/HttpApiModule.cs new file mode 100644 index 00000000..ef3a9be1 --- /dev/null +++ b/JexusManager.Features.HttpApi/HttpApiModule.cs @@ -0,0 +1,25 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpApi +{ + using System; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + using Properties; + + internal class HttpApiModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)this.GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(HttpApiPage), "HTTP API", + "Manage certificate bindings for websites that use SSL", Resources.http_36, + Resources.http_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.HttpApi/HttpApiModuleProvider.cs b/JexusManager.Features.HttpApi/HttpApiModuleProvider.cs new file mode 100644 index 00000000..44bd51ca --- /dev/null +++ b/JexusManager.Features.HttpApi/HttpApiModuleProvider.cs @@ -0,0 +1,29 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpApi +{ + using System; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Server; + + public class HttpApiModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(this.Name, typeof(HttpApiModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return scope == ManagementScope.Server && !Helper.IsRunningOnMono(); + } + } +} diff --git a/JexusManager.Features.HttpApi/HttpApiPage.Designer.cs b/JexusManager.Features.HttpApi/HttpApiPage.Designer.cs new file mode 100644 index 00000000..0f23fe7c --- /dev/null +++ b/JexusManager.Features.HttpApi/HttpApiPage.Designer.cs @@ -0,0 +1,437 @@ +namespace JexusManager.Features.HttpApi +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class HttpApiPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tpIP = new System.Windows.Forms.TabPage(); + this.lvIP = new System.Windows.Forms.ListView(); + this.chAddress = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chPort = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chApp = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chAppId = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chHash = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chStore = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.tpSNI = new System.Windows.Forms.TabPage(); + this.lvSni = new System.Windows.Forms.ListView(); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader5 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader6 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.tpURL = new System.Windows.Forms.TabPage(); + this.lvURL = new System.Windows.Forms.ListView(); + this.columnHeader7 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader10 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.tabControl1.SuspendLayout(); + this.tpIP.SuspendLayout(); + this.tpSNI.SuspendLayout(); + this.tpURL.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 6; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.splitContainer1_SplitterMoved); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "contextMenuStrip1"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.tabControl1); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 9; + // + // tabControl1 + // + this.tabControl1.Controls.Add(this.tpIP); + this.tabControl1.Controls.Add(this.tpSNI); + this.tabControl1.Controls.Add(this.tpURL); + this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl1.Location = new System.Drawing.Point(0, 13); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(560, 527); + this.tabControl1.TabIndex = 2; + this.tabControl1.SelectedIndexChanged += new System.EventHandler(this.TabControl1SelectedIndexChanged); + // + // tpIP + // + this.tpIP.Controls.Add(this.lvIP); + this.tpIP.Location = new System.Drawing.Point(4, 22); + this.tpIP.Name = "tpIP"; + this.tpIP.Padding = new System.Windows.Forms.Padding(3); + this.tpIP.Size = new System.Drawing.Size(552, 501); + this.tpIP.TabIndex = 0; + this.tpIP.Text = "IP Based"; + this.tpIP.UseVisualStyleBackColor = true; + // + // lvIP + // + this.lvIP.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chAddress, + this.chPort, + this.chApp, + this.chAppId, + this.chHash, + this.chStore}); + this.lvIP.Dock = System.Windows.Forms.DockStyle.Fill; + this.lvIP.FullRowSelect = true; + this.lvIP.HideSelection = false; + this.lvIP.Location = new System.Drawing.Point(3, 3); + this.lvIP.Margin = new System.Windows.Forms.Padding(5); + this.lvIP.MultiSelect = false; + this.lvIP.Name = "lvIP"; + this.lvIP.Size = new System.Drawing.Size(546, 495); + this.lvIP.TabIndex = 1; + this.lvIP.UseCompatibleStateImageBehavior = false; + this.lvIP.View = System.Windows.Forms.View.Details; + this.lvIP.SelectedIndexChanged += new System.EventHandler(this.LvIPSelectedIndexChanged); + // + // chAddress + // + this.chAddress.Text = "Address"; + this.chAddress.Width = 180; + // + // chPort + // + this.chPort.Text = "Port"; + this.chPort.Width = 80; + // + // chApp + // + this.chApp.Text = "Application Name"; + this.chApp.Width = 100; + // + // chAppId + // + this.chAppId.Text = "Application ID"; + this.chAppId.Width = 180; + // + // chHash + // + this.chHash.Text = "Certificate Hash"; + this.chHash.Width = 180; + // + // chStore + // + this.chStore.Text = "Certificate Store"; + this.chStore.Width = 120; + // + // tpSNI + // + this.tpSNI.Controls.Add(this.lvSni); + this.tpSNI.Location = new System.Drawing.Point(4, 22); + this.tpSNI.Name = "tpSNI"; + this.tpSNI.Padding = new System.Windows.Forms.Padding(3); + this.tpSNI.Size = new System.Drawing.Size(552, 501); + this.tpSNI.TabIndex = 1; + this.tpSNI.Text = "SNI"; + this.tpSNI.UseVisualStyleBackColor = true; + // + // lvSni + // + this.lvSni.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader1, + this.columnHeader2, + this.columnHeader3, + this.columnHeader4, + this.columnHeader5, + this.columnHeader6}); + this.lvSni.Dock = System.Windows.Forms.DockStyle.Fill; + this.lvSni.FullRowSelect = true; + this.lvSni.HideSelection = false; + this.lvSni.Location = new System.Drawing.Point(3, 3); + this.lvSni.Margin = new System.Windows.Forms.Padding(5); + this.lvSni.MultiSelect = false; + this.lvSni.Name = "lvSni"; + this.lvSni.Size = new System.Drawing.Size(546, 495); + this.lvSni.TabIndex = 2; + this.lvSni.UseCompatibleStateImageBehavior = false; + this.lvSni.View = System.Windows.Forms.View.Details; + this.lvSni.SelectedIndexChanged += new System.EventHandler(this.LvSniSelectedIndexChanged); + // + // columnHeader1 + // + this.columnHeader1.Text = "Host Name"; + this.columnHeader1.Width = 180; + // + // columnHeader2 + // + this.columnHeader2.Text = "Port"; + this.columnHeader2.Width = 80; + // + // columnHeader3 + // + this.columnHeader3.Text = "Application Name"; + this.columnHeader3.Width = 100; + // + // columnHeader4 + // + this.columnHeader4.Text = "Application ID"; + this.columnHeader4.Width = 180; + // + // columnHeader5 + // + this.columnHeader5.Text = "Certificate Hash"; + this.columnHeader5.Width = 180; + // + // columnHeader6 + // + this.columnHeader6.Text = "Certificate Store"; + this.columnHeader6.Width = 120; + // + // tpURL + // + this.tpURL.Controls.Add(this.lvURL); + this.tpURL.Location = new System.Drawing.Point(4, 22); + this.tpURL.Name = "tpURL"; + this.tpURL.Padding = new System.Windows.Forms.Padding(3); + this.tpURL.Size = new System.Drawing.Size(552, 501); + this.tpURL.TabIndex = 2; + this.tpURL.Text = "Reserved URL"; + this.tpURL.UseVisualStyleBackColor = true; + // + // lvURL + // + this.lvURL.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader7, + this.columnHeader10}); + this.lvURL.Dock = System.Windows.Forms.DockStyle.Fill; + this.lvURL.FullRowSelect = true; + this.lvURL.HideSelection = false; + this.lvURL.Location = new System.Drawing.Point(3, 3); + this.lvURL.Margin = new System.Windows.Forms.Padding(5); + this.lvURL.MultiSelect = false; + this.lvURL.Name = "lvURL"; + this.lvURL.Size = new System.Drawing.Size(546, 495); + this.lvURL.TabIndex = 2; + this.lvURL.UseCompatibleStateImageBehavior = false; + this.lvURL.View = System.Windows.Forms.View.Details; + this.lvURL.SelectedIndexChanged += new System.EventHandler(this.LvURLSelectedIndexChanged); + // + // columnHeader7 + // + this.columnHeader7.Text = "URL Prefix"; + this.columnHeader7.Width = 180; + // + // columnHeader10 + // + this.columnHeader10.Text = "Security Descriptor"; + this.columnHeader10.Width = 180; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(523, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to manage certificate bindings that the Web server can use with " + + "websites configured for SSL."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 8; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(106, 25); + this.label3.TabIndex = 2; + this.label3.Text = "HTTP API"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // HttpApiPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "HttpApiPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.tabControl1.ResumeLayout(false); + this.tpIP.ResumeLayout(false); + this.tpSNI.ResumeLayout(false); + this.tpURL.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private ContextMenuStrip cmsActionPanel; + private PictureBox pictureBox1; + private Panel panel2; + private TabControl tabControl1; + private TabPage tpIP; + private ListView lvIP; + private ColumnHeader chAddress; + private ColumnHeader chPort; + private ColumnHeader chApp; + private ColumnHeader chAppId; + private ColumnHeader chHash; + private ColumnHeader chStore; + private TabPage tpSNI; + private TabPage tpURL; + private ListView lvSni; + private ColumnHeader columnHeader1; + private ColumnHeader columnHeader2; + private ColumnHeader columnHeader3; + private ColumnHeader columnHeader4; + private ColumnHeader columnHeader5; + private ColumnHeader columnHeader6; + private ListView lvURL; + private ColumnHeader columnHeader7; + private ColumnHeader columnHeader10; + } +} diff --git a/JexusManager.Features.HttpApi/HttpApiPage.cs b/JexusManager.Features.HttpApi/HttpApiPage.cs new file mode 100644 index 00000000..fcdc6267 --- /dev/null +++ b/JexusManager.Features.HttpApi/HttpApiPage.cs @@ -0,0 +1,277 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpApi +{ + using System; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class HttpApiPage : ModuleListPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly HttpApiPage _owner; + + public PageTaskList(HttpApiPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class SniMappingListViewItem : ListViewItem + { + public SniMappingItem Item { get; } + private readonly HttpApiPage _page; + + public SniMappingListViewItem(SniMappingItem item, HttpApiPage page) + : base(item.Host) + { + this.Item = item; + _page = page; + this.SubItems.Add(new ListViewSubItem(this, item.Port)); + this.SubItems.Add(new ListViewSubItem(this, BindingExtensions.GetAppName(item.AppId))); + this.SubItems.Add(new ListViewSubItem(this, item.AppId)); + this.SubItems.Add(new ListViewSubItem(this, item.Hash)); + this.SubItems.Add(new ListViewSubItem(this, item.Store)); + } + } + + private sealed class IpMappingListViewItem : ListViewItem + { + public IpMappingItem Item { get; } + private readonly HttpApiPage _page; + + public IpMappingListViewItem(IpMappingItem item, HttpApiPage page) + : base(item.Address) + { + this.Item = item; + _page = page; + this.SubItems.Add(new ListViewSubItem(this, item.Port)); + this.SubItems.Add(new ListViewSubItem(this, BindingExtensions.GetAppName(item.AppId))); + this.SubItems.Add(new ListViewSubItem(this, item.AppId)); + this.SubItems.Add(new ListViewSubItem(this, item.Hash)); + this.SubItems.Add(new ListViewSubItem(this, item.Store)); + } + } + + private sealed class ReservedUrlListViewItem : ListViewItem + { + public ReservedUrlsItem Item { get; } + private readonly HttpApiPage _page; + + public ReservedUrlListViewItem(ReservedUrlsItem item, HttpApiPage page) + : base(item.UrlPrefix) + { + Item = item; + _page = page; + SubItems.Add(new ListViewSubItem(this, item.SecurityDescriptor)); + } + } + + private PageTaskList _taskList; + + public HttpApiPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + var ip = new IpMappingFeature(Module); + ip.HttpApiSettingsUpdate = RefreshIp; + ip.Load(); + tpIP.Tag = ip; + RefreshIp(); + + var sni = new SniMappingFeature(Module); + sni.HttpApiSettingsUpdate = RefreshSni; + sni.Load(); + tpSNI.Tag = sni; + + var url = new ReservedUrlsFeature(Module); + url.HttpApiSettingsUpdate = RefreshUrl; + url.Load(); + tpURL.Tag = url; + } + + private void RefreshSni() + { + var feature = (SniMappingFeature)tpSNI.Tag; + if (feature == null) + { + return; + } + + lvSni.Items.Clear(); + foreach (var file in feature.Items) + { + lvSni.Items.Add(new SniMappingListViewItem(file, this)); + } + + if (feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (SniMappingListViewItem item in lvSni.Items) + { + if (item.Item == feature.SelectedItem) + { + item.Selected = true; + } + } + } + + private void RefreshIp() + { + var feature = (IpMappingFeature)tpIP.Tag; + if (feature == null) + { + return; + } + + lvIP.Items.Clear(); + foreach (var file in feature.Items) + { + lvIP.Items.Add(new IpMappingListViewItem(file, this)); + } + + if (feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (IpMappingListViewItem item in lvIP.Items) + { + if (item.Item == feature.SelectedItem) + { + item.Selected = true; + } + } + } + + private void RefreshUrl() + { + var feature = (ReservedUrlsFeature)tpURL.Tag; + if (feature == null) + { + return; + } + + lvURL.Items.Clear(); + foreach (var file in feature.Items) + { + lvURL.Items.Add(new ReservedUrlListViewItem(file, this)); + } + + if (feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (ReservedUrlListViewItem item in lvURL.Items) + { + if (item.Item == feature.SelectedItem) + { + item.Selected = true; + } + } + } + + protected override void InitializeListPage() + { + } + + protected override void Refresh() + { + var feature = (IHttpApiFeature)tabControl1.SelectedTab.Tag; + var extra = feature?.GetTaskList(); + this.Tasks.Fill(tsActionPanel, cmsActionPanel, extra); + base.Refresh(); + } + + private void LvSniSelectedIndexChanged(object sender, EventArgs e) + { + var feature = (SniMappingFeature)tpSNI.Tag; + feature.SelectedItem = lvSni.SelectedItems.Count > 0 + ? ((SniMappingListViewItem)lvSni.SelectedItems[0]).Item + : null; + this.Refresh(); + } + + private void LvIPSelectedIndexChanged(object sender, EventArgs e) + { + var feature = (IpMappingFeature)tpIP.Tag; + feature.SelectedItem = lvIP.SelectedItems.Count > 0 + ? ((IpMappingListViewItem)lvIP.SelectedItems[0]).Item + : null; + this.Refresh(); + } + + private void LvURLSelectedIndexChanged(object sender, EventArgs e) + { + var feature = (ReservedUrlsFeature)tpURL.Tag; + feature.SelectedItem = lvURL.SelectedItems.Count > 0 + ? ((ReservedUrlListViewItem)lvURL.SelectedItems[0]).Item + : null; + this.Refresh(); + } + + protected override bool ShowHelp() + { + var feature = (IHttpApiFeature)tabControl1.SelectedTab.Tag; + feature.ShowHelp(); + return true; + } + + private void TabControl1SelectedIndexChanged(object sender, EventArgs e) + { + var feature = (IHttpApiFeature)tabControl1.SelectedTab.Tag; + feature.HttpApiSettingsUpdate.Invoke(); + Refresh(); + } + + private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + } +} diff --git a/JexusManager.Features.HttpApi/HttpApiPage.resx b/JexusManager.Features.HttpApi/HttpApiPage.resx new file mode 100644 index 00000000..8d1dcaa6 --- /dev/null +++ b/JexusManager.Features.HttpApi/HttpApiPage.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 122, 17 + + + 17, 17 + + + 179 + + \ No newline at end of file diff --git a/JexusManager.Features.HttpApi/HttpApiSettingsSavedEventHandler.cs b/JexusManager.Features.HttpApi/HttpApiSettingsSavedEventHandler.cs new file mode 100644 index 00000000..5505a450 --- /dev/null +++ b/JexusManager.Features.HttpApi/HttpApiSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpApi +{ + public delegate void HttpApiSettingsSavedEventHandler(); +} diff --git a/JexusManager.Features.HttpApi/IHttpApiFeature.cs b/JexusManager.Features.HttpApi/IHttpApiFeature.cs new file mode 100644 index 00000000..663535b3 --- /dev/null +++ b/JexusManager.Features.HttpApi/IHttpApiFeature.cs @@ -0,0 +1,17 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Web.Management.Client; + +namespace JexusManager.Features.HttpApi +{ + internal interface IHttpApiFeature + { + TaskList GetTaskList(); + + bool ShowHelp(); + + HttpApiSettingsSavedEventHandler HttpApiSettingsUpdate { get; } + } +} diff --git a/JexusManager.Features.HttpApi/IpMappingFeature.cs b/JexusManager.Features.HttpApi/IpMappingFeature.cs new file mode 100644 index 00000000..e20910b0 --- /dev/null +++ b/JexusManager.Features.HttpApi/IpMappingFeature.cs @@ -0,0 +1,304 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using JexusManager.Services; +using Microsoft.Web.Administration; +using Microsoft.Web.Management.Client; +using Microsoft.Web.Management.Client.Win32; +using Org.BouncyCastle.Utilities.Encoders; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Windows.Forms; + +namespace JexusManager.Features.HttpApi +{ + internal class IpMappingFeature : HttpApiFeature + { + private sealed class FeatureTaskList : TaskList + { + private readonly IpMappingFeature _owner; + + public FeatureTaskList(IpMappingFeature owner) + { + _owner = owner; + } + + private const string LocalhostIssuer = "CN=localhost"; + private readonly string _localMachineIssuer = string.Format("CN={0}", Environment.MachineName); + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + //result.Add(new MethodTaskItem("Import", "Import...", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem("CreateRequest", "Create Certificate Request...", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem("Complete", "Complete Certificate Request...", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem("CreateDomain", "Create Domain Certificate...", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem("CreateSelf", "Create Self-Signed Certificate...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem("View", "View...", string.Empty).SetUsage()); + //if (_owner.SelectedItem.Certificate.HasPrivateKey) + //{ + // try + // { + // var keyInfo = (RSACryptoServiceProvider)_owner.SelectedItem.Certificate.PrivateKey; + // if (keyInfo.CspKeyContainerInfo.Exportable) + // { + // result.Add(new MethodTaskItem("Export", "Export...", string.Empty).SetUsage()); + // if (_owner.SelectedItem.Certificate.Issuer != LocalhostIssuer && _owner.SelectedItem.Certificate.Issuer != _localMachineIssuer) + // { + // result.Add(new MethodTaskItem("Renew", "Renew...", string.Empty).SetUsage()); + // } + // } + // } + // catch (CryptographicException ex) + // { + // if (ex.HResult != -2146893802) + // { + // throw; + // } + // } + //} + + //result.Add(new MethodTaskItem("Remove", "Remove", string.Empty, string.Empty, Resources.remove_16).SetUsage()); + } + + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + //if (!this._owner.AutomicRebindEnabled) + //{ + // result.Add(new MethodTaskItem("Enable", "Enable Automatic Rebind of Renewed Certificate", string.Empty).SetUsage()); + //} + + //if (this._owner.AutomicRebindEnabled) + //{ + // result.Add(new MethodTaskItem("Disable", "Disable Automatic Rebind of Renewed Certificate", string.Empty).SetUsage()); + //} + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Import() + { + _owner.Import(); + } + + [Obfuscation(Exclude = true)] + public void View() + { + _owner.View(); + } + + [Obfuscation(Exclude = true)] + public void Export() + { + _owner.Export(); + } + + [Obfuscation(Exclude = true)] + public void Renew() + { + _owner.Renew(); + } + + [Obfuscation(Exclude = true)] + public void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void CreateRequest() + { + _owner.CreateRequest(); + } + + [Obfuscation(Exclude = true)] + public void Complete() + { + _owner.Complete(); + } + + [Obfuscation(Exclude = true)] + public void CreateDomain() + { + _owner.CreateDomain(); + } + + [Obfuscation(Exclude = true)] + public void CreateSelf() + { + _owner.CreateSelf(); + } + + [Obfuscation(Exclude = true)] + public void Enable() + { + _owner.Enable(); + } + + [Obfuscation(Exclude = true)] + public void Disable() + { + _owner.Disable(); + } + } + + public IpMappingFeature(Microsoft.Web.Management.Client.Module module) + : base(module) + { + } + + private FeatureTaskList _taskList; + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public override void Load() + { + this.Items = new List(); + var ipMappings = Microsoft.Web.Administration.NativeMethods.QuerySslCertificateInfo(); + foreach (var mapping in ipMappings) + { + this.Items.Add(new IpMappingItem(mapping.IpPort.Address.ToString(), mapping.IpPort.Port.ToString(), mapping.AppId.ToString(), Hex.ToHexString(mapping.Hash), mapping.StoreName, this)); + } + + this.OnHttpApiSettingsSaved(); + } + + public void Import() + { + //var dialog = new ImportCertificateDialog(Module); + //dialog.ShowDialog(); + + //Items.Add(new CertificatesItem(dialog.Item, dialog.Store, this)); + this.OnHttpApiSettingsSaved(); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove this certificate, and permanently remove it from the certificate store?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) != + DialogResult.Yes) + { + return; + } + + // remove certificate and mapping + //using (var process = new Process()) + //{ + // var start = process.StartInfo; + // start.Verb = "runas"; + // start.FileName = "cmd"; + // start.Arguments = string.Format( + // "/c \"\"{2}\" /h:\"{0}\" /s:{1}\"", + // SelectedItem.Certificate.Thumbprint, + // SelectedItem.Store == "Personal" ? "MY" : "WebHosting", + // Path.Combine(Environment.CurrentDirectory, "certificateinstaller.exe")); + // start.CreateNoWindow = true; + // start.WindowStyle = ProcessWindowStyle.Hidden; + // process.Start(); + // process.WaitForExit(); + + // if (process.ExitCode == 0) + // { + // Items.Remove(SelectedItem); + // SelectedItem = null; + // this.OnHttpApiSettingsSaved(); + // } + //} + } + + protected void OnHttpApiSettingsSaved() + { + this.HttpApiSettingsUpdated?.Invoke(); + } + + public override bool ShowHelp() + { + Process.Start("https://msdn.microsoft.com/en-us/library/windows/desktop/cc307243(v=vs.85).aspx"); + return false; + } + + private void Disable() + { + } + + private void Enable() + { + } + + private void CreateSelf() + { + //var dialog = new SelfCertificateDialog(Module); + //dialog.ShowDialog(); + + //Items.Add(new CertificatesItem(dialog.Item, dialog.Store, this)); + this.OnHttpApiSettingsSaved(); + } + + private void CreateDomain() + { + } + + private void Complete() + { + //var dialog = new CompleteRequestDialog(Module); + //dialog.ShowDialog(); + + //Items.Add(new CertificatesItem(dialog.Item, dialog.Store, this)); + this.OnHttpApiSettingsSaved(); + } + + private void CreateRequest() + { + //var wizard = new CertificateRequestWizard(this.Module); + //wizard.ShowDialog(); + } + + private void Export() + { + //var dialog = new ExportCertificateDialog(SelectedItem.Certificate, Module); + //dialog.ShowDialog(); + } + + private void Renew() + { + //var wizard = new CertificateRenewWizard(SelectedItem.Certificate, Module); + //wizard.ShowDialog(); + } + + private void View() + { + } + + public bool AutomicRebindEnabled { get; set; } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + return null; + } + + public HttpApiSettingsSavedEventHandler HttpApiSettingsUpdated { get; set; } + + public override string Name + { + get + { + return "IP Mappings"; + } + } + } +} diff --git a/JexusManager.Features.HttpApi/IpMappingItem.cs b/JexusManager.Features.HttpApi/IpMappingItem.cs new file mode 100644 index 00000000..2ccddea4 --- /dev/null +++ b/JexusManager.Features.HttpApi/IpMappingItem.cs @@ -0,0 +1,45 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Web.Administration; + +namespace JexusManager.Features.HttpApi +{ + internal class IpMappingItem : IItem + { + public IpMappingItem(string address, string port, string appId, string hash, string store, IpMappingFeature feature) + { + this.Address = address; + this.Port = port; + this.AppId = appId; + this.Hash = hash; + this.Store = store; + this.Feature = feature; + } + + public string Hash { get; set; } + public string Address { get; set; } + public string Port { get; set; } + public string AppId { get; set; } + public string Store { get; set; } + public IpMappingFeature Feature { get; private set; } + + public string Flag { get; set; } + public ConfigurationElement Element { get; set; } + + public void Apply() + { } + + public bool Equals(IpMappingItem other) + { + return Match(other); + } + + public bool Match(IpMappingItem other) + { + return other != null && other.Hash == this.Hash && other.Store == this.Store && other.Address == this.Address + && other.Port == this.Port && other.AppId == this.AppId; + } + } +} diff --git a/JexusManager.Features.HttpApi/JexusManager.Features.HttpApi.csproj b/JexusManager.Features.HttpApi/JexusManager.Features.HttpApi.csproj new file mode 100644 index 00000000..8ce2c1c8 --- /dev/null +++ b/JexusManager.Features.HttpApi/JexusManager.Features.HttpApi.csproj @@ -0,0 +1,123 @@ + + + + + Debug + AnyCPU + {2B03E7FE-3DBD-4914-AD8C-4CB7007A9EED} + Library + Properties + JexusManager.Features.HttpApi + JexusManager.Features.HttpApi + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + ..\packages\BouncyCastle.1.8.1\lib\BouncyCastle.Crypto.dll + True + + + + + + + + + + + + + + + Helper.cs + + + NativeMethods.cs + + + + + + + + + + + + + UserControl + + + HttpApiPage.cs + + + + + True + True + Resources.resx + + + + + HttpApiPage.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.HttpApi/JexusManager.snk b/JexusManager.Features.HttpApi/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.HttpApi/Properties/AssemblyInfo.cs b/JexusManager.Features.HttpApi/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..2df47ee7 --- /dev/null +++ b/JexusManager.Features.HttpApi/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.HttpApi")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.HttpApi")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("2b03e7fe-3dbd-4914-ad8c-4cb7007a9eed")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JexusManager.Features.HttpApi/Properties/Resources.Designer.cs b/JexusManager.Features.HttpApi/Properties/Resources.Designer.cs new file mode 100644 index 00000000..fd6c5b9c --- /dev/null +++ b/JexusManager.Features.HttpApi/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.HttpApi.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.HttpApi.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap http_36 { + get { + object obj = ResourceManager.GetObject("http_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.HttpApi/Properties/Resources.resx b/JexusManager.Features.HttpApi/Properties/Resources.resx new file mode 100644 index 00000000..bbdff26a --- /dev/null +++ b/JexusManager.Features.HttpApi/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\http_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.HttpApi/ReservedUrlsFeature.cs b/JexusManager.Features.HttpApi/ReservedUrlsFeature.cs new file mode 100644 index 00000000..c8186f0b --- /dev/null +++ b/JexusManager.Features.HttpApi/ReservedUrlsFeature.cs @@ -0,0 +1,303 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using JexusManager.Services; +using Microsoft.Web.Administration; +using Microsoft.Web.Management.Client; +using Microsoft.Web.Management.Client.Win32; +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Reflection; +using System.Windows.Forms; + +namespace JexusManager.Features.HttpApi +{ + internal class ReservedUrlsFeature : HttpApiFeature + { + private sealed class FeatureTaskList : TaskList + { + private readonly ReservedUrlsFeature _owner; + + public FeatureTaskList(ReservedUrlsFeature owner) + { + _owner = owner; + } + + private const string LocalhostIssuer = "CN=localhost"; + private readonly string _localMachineIssuer = string.Format("CN={0}", Environment.MachineName); + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + //result.Add(new MethodTaskItem("Import", "Import...", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem("CreateRequest", "Create Certificate Request...", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem("Complete", "Complete Certificate Request...", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem("CreateDomain", "Create Domain Certificate...", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem("CreateSelf", "Create Self-Signed Certificate...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem("View", "View...", string.Empty).SetUsage()); + //if (_owner.SelectedItem.Certificate.HasPrivateKey) + //{ + // try + // { + // var keyInfo = (RSACryptoServiceProvider)_owner.SelectedItem.Certificate.PrivateKey; + // if (keyInfo.CspKeyContainerInfo.Exportable) + // { + // result.Add(new MethodTaskItem("Export", "Export...", string.Empty).SetUsage()); + // if (_owner.SelectedItem.Certificate.Issuer != LocalhostIssuer && _owner.SelectedItem.Certificate.Issuer != _localMachineIssuer) + // { + // result.Add(new MethodTaskItem("Renew", "Renew...", string.Empty).SetUsage()); + // } + // } + // } + // catch (CryptographicException ex) + // { + // if (ex.HResult != -2146893802) + // { + // throw; + // } + // } + //} + + //result.Add(new MethodTaskItem("Remove", "Remove", string.Empty, string.Empty, Resources.remove_16).SetUsage()); + } + + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + //if (!this._owner.AutomicRebindEnabled) + //{ + // result.Add(new MethodTaskItem("Enable", "Enable Automatic Rebind of Renewed Certificate", string.Empty).SetUsage()); + //} + + //if (this._owner.AutomicRebindEnabled) + //{ + // result.Add(new MethodTaskItem("Disable", "Disable Automatic Rebind of Renewed Certificate", string.Empty).SetUsage()); + //} + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Import() + { + _owner.Import(); + } + + [Obfuscation(Exclude = true)] + public void View() + { + _owner.View(); + } + + [Obfuscation(Exclude = true)] + public void Export() + { + _owner.Export(); + } + + [Obfuscation(Exclude = true)] + public void Renew() + { + _owner.Renew(); + } + + [Obfuscation(Exclude = true)] + public void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void CreateRequest() + { + _owner.CreateRequest(); + } + + [Obfuscation(Exclude = true)] + public void Complete() + { + _owner.Complete(); + } + + [Obfuscation(Exclude = true)] + public void CreateDomain() + { + _owner.CreateDomain(); + } + + [Obfuscation(Exclude = true)] + public void CreateSelf() + { + _owner.CreateSelf(); + } + + [Obfuscation(Exclude = true)] + public void Enable() + { + _owner.Enable(); + } + + [Obfuscation(Exclude = true)] + public void Disable() + { + _owner.Disable(); + } + } + + public ReservedUrlsFeature(Microsoft.Web.Management.Client.Module module) + : base(module) + { + } + + private FeatureTaskList _taskList; + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public override void Load() + { + this.Items = new List(); + var httpNamespaceAcls = Microsoft.Web.Administration.NativeMethods.QueryHttpNamespaceAcls(); + foreach (var mapping in httpNamespaceAcls) + { + this.Items.Add(new ReservedUrlsItem(mapping.UrlPrefix, mapping.SecurityDescriptor, this)); + } + + this.OnHttpApiSettingsSaved(); + } + + public void Import() + { + //var dialog = new ImportCertificateDialog(Module); + //dialog.ShowDialog(); + + //Items.Add(new CertificatesItem(dialog.Item, dialog.Store, this)); + this.OnHttpApiSettingsSaved(); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove this certificate, and permanently remove it from the certificate store?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) != + DialogResult.Yes) + { + return; + } + + // remove certificate and mapping + //using (var process = new Process()) + //{ + // var start = process.StartInfo; + // start.Verb = "runas"; + // start.FileName = "cmd"; + // start.Arguments = string.Format( + // "/c \"\"{2}\" /h:\"{0}\" /s:{1}\"", + // SelectedItem.Certificate.Thumbprint, + // SelectedItem.Store == "Personal" ? "MY" : "WebHosting", + // Path.Combine(Environment.CurrentDirectory, "certificateinstaller.exe")); + // start.CreateNoWindow = true; + // start.WindowStyle = ProcessWindowStyle.Hidden; + // process.Start(); + // process.WaitForExit(); + + // if (process.ExitCode == 0) + // { + // Items.Remove(SelectedItem); + // SelectedItem = null; + // this.OnHttpApiSettingsSaved(); + // } + //} + } + + protected void OnHttpApiSettingsSaved() + { + this.HttpApiSettingsUpdated?.Invoke(); + } + + public override bool ShowHelp() + { + Process.Start("https://msdn.microsoft.com/en-us/library/windows/desktop/cc307243(v=vs.85).aspx"); + return false; + } + + private void Disable() + { + } + + private void Enable() + { + } + + private void CreateSelf() + { + //var dialog = new SelfCertificateDialog(Module); + //dialog.ShowDialog(); + + //Items.Add(new CertificatesItem(dialog.Item, dialog.Store, this)); + this.OnHttpApiSettingsSaved(); + } + + private void CreateDomain() + { + } + + private void Complete() + { + //var dialog = new CompleteRequestDialog(Module); + //dialog.ShowDialog(); + + //Items.Add(new CertificatesItem(dialog.Item, dialog.Store, this)); + this.OnHttpApiSettingsSaved(); + } + + private void CreateRequest() + { + //var wizard = new CertificateRequestWizard(this.Module); + //wizard.ShowDialog(); + } + + private void Export() + { + //var dialog = new ExportCertificateDialog(SelectedItem.Certificate, Module); + //dialog.ShowDialog(); + } + + private void Renew() + { + //var wizard = new CertificateRenewWizard(SelectedItem.Certificate, Module); + //wizard.ShowDialog(); + } + + private void View() + { + } + + public bool AutomicRebindEnabled { get; set; } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + return null; + } + + public HttpApiSettingsSavedEventHandler HttpApiSettingsUpdated { get; set; } + + public override string Name + { + get + { + return "Reserved URLs"; + } + } + } +} diff --git a/JexusManager.Features.HttpApi/ReservedUrlsItem.cs b/JexusManager.Features.HttpApi/ReservedUrlsItem.cs new file mode 100644 index 00000000..18161c53 --- /dev/null +++ b/JexusManager.Features.HttpApi/ReservedUrlsItem.cs @@ -0,0 +1,39 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using Microsoft.Web.Administration; + +namespace JexusManager.Features.HttpApi +{ + internal class ReservedUrlsItem : IItem + { + public string UrlPrefix { get; set; } + public string SecurityDescriptor { get; set; } + + public ReservedUrlsItem(string urlPrefix, string securityDescriptor, ReservedUrlsFeature feature) + { + SecurityDescriptor = securityDescriptor; + UrlPrefix = urlPrefix; + Feature = feature; + } + + public ReservedUrlsFeature Feature { get; private set; } + + public string Flag { get; set; } + public ConfigurationElement Element { get; set; } + + public void Apply() + { } + + public bool Equals(ReservedUrlsItem other) + { + return Match(other) && other.SecurityDescriptor == this.SecurityDescriptor; + } + + public bool Match(ReservedUrlsItem other) + { + return other != null && other.UrlPrefix == this.UrlPrefix; + } + } +} diff --git a/JexusManager.Features.HttpApi/Resources/http_36.png b/JexusManager.Features.HttpApi/Resources/http_36.png new file mode 100644 index 0000000000000000000000000000000000000000..4ac1e182bda1f0655ee3ed2499cb182e0e381001 GIT binary patch literal 2023 zcmVi44_VBK~ zj=g!Mk!ELRXa4j2|IahejN%Ty0|yQ~VcYi0wr$$w`ZF2N^*sOJv17+hRywzJCxDbv zcWvLk&2DRJF5BPR`$6E%H{V`=M{_TB;NHD^>uYMNj~j-uK`FvbP4!DfGG)h#Sd5Lu zZiq0gwf@iKI7J}pifEi`aHSNM6`;SiDY&8`8Z5LsF-&KiNKoO4>;mQjT3Ov;225R; zY_j7J4?nh#{H`WneHE=Wp64NwZxssFLcO#t6pGN&y@Q?m_ZKL6$`u2xvt@8_l#Y&7bLQ7lew{fMl02YUgS)%C z2?PQpk_pboPH=DCC$Uv%L9dBKBDA-+7gr6{|D(10}6h++(1A{}ju1l}?Cjjnm-(4|~a&;*a2CZ`X(M7;7^w`gl?Tacc)ptAjo z_A))oLbbKE?0VpH*;u4Ke)QI-_{3e$fNwHzZD3w{it8d!Q&U4tO|)e53tA}8nJz-) zI1ZQlu7FnjBlT-K>o>7}#Wq~my{#om>p2nU0g_u|adAjW(EqFNJioj4ZT4+^mdh8; z@!X?XPqS^C*4EaFKov*u{2EfJmqo1xOl9%Xg)g$V`2`GRAtJc0%gD&+0syk#vSmvN zg~BEJ(({}M#zJ1!+S1Ge(ZlSh|0xrjF`Ni2MalBMv$FZpidU}sD?WATcBBfMG zwrK5FrXeXpRaI5Rj{9~2Fy-9f`#pPjYU_(E3D;278s*>p=lJFSo}qooX4bA=SCoQC z8U29P8tv;`q+aA%re!9E#wTOEd*v*3ffoKS@jM^yJV;aZIvmI0Z|}UpD}&!8YBjR6 z{b>dVhvrF1vY?uqn^8&?Sx9bw+RLn1Ap%zh{>$s*N0_XBk7*~xL#sav2vNZx9JZ%Fr`Y&n9aYhGC#Z7y1`1>O9hDU^&aeZJd7Zd+claDTpF5J;m`$Uni-? z`OLbX@S*N)C6<^S98J?KDOyX3<5X~T2yLycd@S=N+@;g3S-AlaPG0x{{myyr4)3PD zdJ6*sgLCMqtE(d#jg|m03Ta)Ee((-_$pdqa_S_>PhcQTMT!=EQ! z0HD#^%wzW)E}^HKMMg%3@jXplO)Zg76^TRw+ejf=qjOiOa-UKDaLob|5!&kSrZbdH zS0idETk8*DSvDeqX`0x!jb&K{&E!ik5Tq&`A(2QDkHwjom|$dlgyErKGOn{o4arRU zp?x0_p|hi%uGr(KbTw-t57NDQOTiN5G-4PAB7*08B$Fw;jK{?F39jE9=jQbr)YjBt z7?}zl8}jK#&J&g|U%}pwA4KZ|1$v5U%7e&*bDT7;>ySuH5xW^D7Qab+GEU-Ff`%0h zG&VMHeQXeSF@U5f4oxK{dH0>Oh-lD)s9dKi9zApI^nD-C_whZCWGczf=s2F|k-Rm9 zX+XpBTB^bpekOI>Cyug_S_G`VV_f;*bnbSLrIMlxUOw!X{LZBn#STAc zG0gz_NWU9;EA{V0cVzKpg-8002ovPDHLk FV1hdg(?9?K literal 0 HcmV?d00001 diff --git a/JexusManager.Features.HttpApi/SniMappingFeature.cs b/JexusManager.Features.HttpApi/SniMappingFeature.cs new file mode 100644 index 00000000..b5395c76 --- /dev/null +++ b/JexusManager.Features.HttpApi/SniMappingFeature.cs @@ -0,0 +1,319 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/* + * Created by SharpDevelop. + * User: lextm + * Time: 11:06 AM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace JexusManager.Features.HttpApi +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + using Services; + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Org.BouncyCastle.Utilities.Encoders; + + using Module = Microsoft.Web.Management.Client.Module; + + /// + /// Description of DefaultDocumentFeature. + /// + internal class SniMappingFeature : HttpApiFeature + { + private sealed class FeatureTaskList : TaskList + { + private readonly SniMappingFeature _owner; + + public FeatureTaskList(SniMappingFeature owner) + { + _owner = owner; + } + + private const string LocalhostIssuer = "CN=localhost"; + private readonly string _localMachineIssuer = string.Format("CN={0}", Environment.MachineName); + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + //result.Add(new MethodTaskItem("Import", "Import...", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem("CreateRequest", "Create Certificate Request...", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem("Complete", "Complete Certificate Request...", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem("CreateDomain", "Create Domain Certificate...", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem("CreateSelf", "Create Self-Signed Certificate...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + //result.Add(new MethodTaskItem("View", "View...", string.Empty).SetUsage()); + //if (_owner.SelectedItem.Certificate.HasPrivateKey) + //{ + // try + // { + // var keyInfo = (RSACryptoServiceProvider)_owner.SelectedItem.Certificate.PrivateKey; + // if (keyInfo.CspKeyContainerInfo.Exportable) + // { + // result.Add(new MethodTaskItem("Export", "Export...", string.Empty).SetUsage()); + // if (_owner.SelectedItem.Certificate.Issuer != LocalhostIssuer && _owner.SelectedItem.Certificate.Issuer != _localMachineIssuer) + // { + // result.Add(new MethodTaskItem("Renew", "Renew...", string.Empty).SetUsage()); + // } + // } + // } + // catch (CryptographicException ex) + // { + // if (ex.HResult != -2146893802) + // { + // throw; + // } + // } + //} + + //result.Add(new MethodTaskItem("Remove", "Remove", string.Empty, string.Empty, Resources.remove_16).SetUsage()); + } + + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + //if (!this._owner.AutomicRebindEnabled) + //{ + // result.Add(new MethodTaskItem("Enable", "Enable Automatic Rebind of Renewed Certificate", string.Empty).SetUsage()); + //} + + //if (this._owner.AutomicRebindEnabled) + //{ + // result.Add(new MethodTaskItem("Disable", "Disable Automatic Rebind of Renewed Certificate", string.Empty).SetUsage()); + //} + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Import() + { + _owner.Import(); + } + + [Obfuscation(Exclude = true)] + public void View() + { + _owner.View(); + } + + [Obfuscation(Exclude = true)] + public void Export() + { + _owner.Export(); + } + + [Obfuscation(Exclude = true)] + public void Renew() + { + _owner.Renew(); + } + + [Obfuscation(Exclude = true)] + public void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void CreateRequest() + { + _owner.CreateRequest(); + } + + [Obfuscation(Exclude = true)] + public void Complete() + { + _owner.Complete(); + } + + [Obfuscation(Exclude = true)] + public void CreateDomain() + { + _owner.CreateDomain(); + } + + [Obfuscation(Exclude = true)] + public void CreateSelf() + { + _owner.CreateSelf(); + } + + [Obfuscation(Exclude = true)] + public void Enable() + { + _owner.Enable(); + } + + [Obfuscation(Exclude = true)] + public void Disable() + { + _owner.Disable(); + } + } + + public SniMappingFeature(Module module) + : base(module) + { + } + + private FeatureTaskList _taskList; + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public override void Load() + { + this.Items = new List(); + var sniMappings = NativeMethods.QuerySslSniInfo(); + foreach (var mapping in sniMappings) + { + this.Items.Add(new SniMappingItem(mapping.Host, mapping.Port.ToString(), mapping.AppId.ToString(), Hex.ToHexString(mapping.Hash), mapping.StoreName, this)); + } + + this.OnHttpApiSettingsSaved(); + } + + public void Import() + { + //var dialog = new ImportCertificateDialog(Module); + //dialog.ShowDialog(); + + //Items.Add(new CertificatesItem(dialog.Item, dialog.Store, this)); + this.OnHttpApiSettingsSaved(); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove this certificate, and permanently remove it from the certificate store?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button2) != + DialogResult.Yes) + { + return; + } + + // remove certificate and mapping + //using (var process = new Process()) + //{ + // var start = process.StartInfo; + // start.Verb = "runas"; + // start.FileName = "cmd"; + // start.Arguments = string.Format( + // "/c \"\"{2}\" /h:\"{0}\" /s:{1}\"", + // SelectedItem.Certificate.Thumbprint, + // SelectedItem.Store == "Personal" ? "MY" : "WebHosting", + // Path.Combine(Environment.CurrentDirectory, "certificateinstaller.exe")); + // start.CreateNoWindow = true; + // start.WindowStyle = ProcessWindowStyle.Hidden; + // process.Start(); + // process.WaitForExit(); + + // if (process.ExitCode == 0) + // { + // Items.Remove(SelectedItem); + // SelectedItem = null; + // this.OnHttpApiSettingsSaved(); + // } + //} + } + + protected void OnHttpApiSettingsSaved() + { + this.HttpApiSettingsUpdated?.Invoke(); + } + + public override bool ShowHelp() + { + Process.Start("https://msdn.microsoft.com/en-us/library/windows/desktop/cc307243(v=vs.85).aspx"); + return false; + } + + private void Disable() + { + } + + private void Enable() + { + } + + private void CreateSelf() + { + //var dialog = new SelfCertificateDialog(Module); + //dialog.ShowDialog(); + + //Items.Add(new CertificatesItem(dialog.Item, dialog.Store, this)); + this.OnHttpApiSettingsSaved(); + } + + private void CreateDomain() + { + } + + private void Complete() + { + //var dialog = new CompleteRequestDialog(Module); + //dialog.ShowDialog(); + + //Items.Add(new CertificatesItem(dialog.Item, dialog.Store, this)); + this.OnHttpApiSettingsSaved(); + } + + private void CreateRequest() + { + //var wizard = new CertificateRequestWizard(this.Module); + //wizard.ShowDialog(); + } + + private void Export() + { + //var dialog = new ExportCertificateDialog(SelectedItem.Certificate, Module); + //dialog.ShowDialog(); + } + + private void Renew() + { + //var wizard = new CertificateRenewWizard(SelectedItem.Certificate, Module); + //wizard.ShowDialog(); + } + + private void View() + { + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + return null; + } + + public bool AutomicRebindEnabled { get; set; } + + + public HttpApiSettingsSavedEventHandler HttpApiSettingsUpdated { get; set; } + + public override string Name + { + get + { + return "SNI Mappings"; + } + } + } +} diff --git a/JexusManager.Features.HttpApi/SniMappingItem.cs b/JexusManager.Features.HttpApi/SniMappingItem.cs new file mode 100644 index 00000000..b3555195 --- /dev/null +++ b/JexusManager.Features.HttpApi/SniMappingItem.cs @@ -0,0 +1,45 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpApi +{ + using Microsoft.Web.Administration; + + internal class SniMappingItem : IItem + { + public SniMappingItem(string host, string port, string appId, string hash, string store, SniMappingFeature feature) + { + this.Host = host; + this.Port = port; + this.AppId = appId; + this.Hash = hash; + this.Store = store; + this.Feature = feature; + } + + public string Hash { get; set; } + public string Host { get; set; } + public string Port { get; set; } + public string AppId { get; set; } + public string Store { get; set; } + public SniMappingFeature Feature { get; private set; } + + public string Flag { get; set; } + public ConfigurationElement Element { get; set; } + + public void Apply() + { } + + public bool Equals(SniMappingItem other) + { + return Match(other); + } + + public bool Match(SniMappingItem other) + { + return other != null && other.Hash == this.Hash && other.Store == this.Store && other.Host == this.Host + && other.Port == this.Port && other.AppId == this.AppId; + } + } +} diff --git a/JexusManager.Features.HttpApi/packages.config b/JexusManager.Features.HttpApi/packages.config new file mode 100644 index 00000000..730a601e --- /dev/null +++ b/JexusManager.Features.HttpApi/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/JexusManager.Features.HttpErrors/EditDialog.Designer.cs b/JexusManager.Features.HttpErrors/EditDialog.Designer.cs new file mode 100644 index 00000000..ba0facdf --- /dev/null +++ b/JexusManager.Features.HttpErrors/EditDialog.Designer.cs @@ -0,0 +1,224 @@ +namespace JexusManager.Features.HttpErrors +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class EditDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.label1 = new System.Windows.Forms.Label(); + this.rbCustom = new System.Windows.Forms.RadioButton(); + this.rbDetailed = new System.Windows.Forms.RadioButton(); + this.rbRemote = new System.Windows.Forms.RadioButton(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.label2 = new System.Windows.Forms.Label(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.cbType = new System.Windows.Forms.ComboBox(); + this.btnSelect = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.rbRemote); + this.groupBox1.Controls.Add(this.rbDetailed); + this.groupBox1.Controls.Add(this.rbCustom); + this.groupBox1.Controls.Add(this.label1); + this.groupBox1.Location = new System.Drawing.Point(12, 12); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(399, 152); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Error Responses"; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(7, 20); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(217, 13); + this.label1.TabIndex = 0; + this.label1.Text = "When the server encounters an error, return:"; + // + // rbCustom + // + this.rbCustom.AutoSize = true; + this.rbCustom.Location = new System.Drawing.Point(10, 48); + this.rbCustom.Name = "rbCustom"; + this.rbCustom.Size = new System.Drawing.Size(116, 17); + this.rbCustom.TabIndex = 1; + this.rbCustom.TabStop = true; + this.rbCustom.Text = "Custom error pages"; + this.rbCustom.UseVisualStyleBackColor = true; + // + // rbDetailed + // + this.rbDetailed.AutoSize = true; + this.rbDetailed.Location = new System.Drawing.Point(10, 71); + this.rbDetailed.Name = "rbDetailed"; + this.rbDetailed.Size = new System.Drawing.Size(93, 17); + this.rbDetailed.TabIndex = 2; + this.rbDetailed.TabStop = true; + this.rbDetailed.Text = "Detailed errors"; + this.rbDetailed.UseVisualStyleBackColor = true; + // + // rbRemote + // + this.rbRemote.AutoSize = true; + this.rbRemote.Location = new System.Drawing.Point(10, 94); + this.rbRemote.Name = "rbRemote"; + this.rbRemote.Size = new System.Drawing.Size(290, 30); + this.rbRemote.TabIndex = 3; + this.rbRemote.TabStop = true; + this.rbRemote.Text = "Detailed errors for local requests and custom error pages\r\nfor remote requests"; + this.rbRemote.UseVisualStyleBackColor = true; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.btnSelect); + this.groupBox2.Controls.Add(this.cbType); + this.groupBox2.Controls.Add(this.label3); + this.groupBox2.Controls.Add(this.txtPath); + this.groupBox2.Controls.Add(this.label2); + this.groupBox2.Location = new System.Drawing.Point(12, 182); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(399, 155); + this.groupBox2.TabIndex = 1; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Default Page"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(7, 27); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(32, 13); + this.label2.TabIndex = 0; + this.label2.Text = "Path:"; + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(10, 52); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(268, 20); + this.txtPath.TabIndex = 1; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(7, 88); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(59, 13); + this.label3.TabIndex = 2; + this.label3.Text = "Path Type:"; + // + // cbType + // + this.cbType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbType.FormattingEnabled = true; + this.cbType.Items.AddRange(new object[] { + "File", + "Execute URL", + "Redirect"}); + this.cbType.Location = new System.Drawing.Point(10, 115); + this.cbType.Name = "cbType"; + this.cbType.Size = new System.Drawing.Size(238, 21); + this.cbType.TabIndex = 3; + // + // btnSelect + // + this.btnSelect.Location = new System.Drawing.Point(284, 50); + this.btnSelect.Name = "btnSelect"; + this.btnSelect.Size = new System.Drawing.Size(34, 23); + this.btnSelect.TabIndex = 4; + this.btnSelect.Text = "..."; + this.btnSelect.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(236, 351); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 2; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(332, 351); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 3; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // EditDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(439, 386); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.Name = "EditDialog"; + this.Text = "Edit Error Pages Settings"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.EditDialog_HelpButtonClicked); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private GroupBox groupBox1; + private RadioButton rbRemote; + private RadioButton rbDetailed; + private RadioButton rbCustom; + private Label label1; + private GroupBox groupBox2; + private Button btnSelect; + private ComboBox cbType; + private Label label3; + private TextBox txtPath; + private Label label2; + private Button btnOK; + private Button btnCancel; + } +} diff --git a/JexusManager.Features.HttpErrors/EditDialog.cs b/JexusManager.Features.HttpErrors/EditDialog.cs new file mode 100644 index 00000000..5b297214 --- /dev/null +++ b/JexusManager.Features.HttpErrors/EditDialog.cs @@ -0,0 +1,68 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpErrors +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client.Win32; + + public partial class EditDialog : DialogForm + { + public EditDialog(IServiceProvider serviceProvider, ConfigurationElement element) + : base(serviceProvider) + { + InitializeComponent(); + var mode = (long)element["errorMode"]; + rbCustom.Checked = mode == 1; + rbDetailed.Checked = mode == 2; + rbRemote.Checked = mode == 0; + + var defaultMode = (long)element["defaultResponseMode"]; + cbType.SelectedIndex = (int)defaultMode; + + txtPath.Text = (string)element["defaultPath"]; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnSelect, "Click") + .Subscribe(evt => + { + DialogHelper.ShowBrowseDialog(txtPath); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + if (rbCustom.Checked) + { + element["errorMode"] = 1L; + } + else if (rbDetailed.Checked) + { + element["errorMode"] = 2L; + } + else + { + element["errorMode"] = 0L; + } + + element["defaultResponseMode"] = (long)cbType.SelectedIndex; + element["defaultPath"] = txtPath.Text; + })); + } + + private void EditDialog_HelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210481"); + } + } +} diff --git a/JexusManager.Features.HttpErrors/EditDialog.resx b/JexusManager.Features.HttpErrors/EditDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.HttpErrors/EditDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.HttpErrors/HttpErrorsFeature.cs b/JexusManager.Features.HttpErrors/HttpErrorsFeature.cs new file mode 100644 index 00000000..c0dca7e7 --- /dev/null +++ b/JexusManager.Features.HttpErrors/HttpErrorsFeature.cs @@ -0,0 +1,193 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/* + * Created by SharpDevelop. + * User: lextm + * Time: 11:06 AM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace JexusManager.Features.HttpErrors +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + /// + /// Description of DefaultDocumentFeature. + /// + internal class HttpErrorsFeature : FeatureBase + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly HttpErrorsFeature _owner; + + public FeatureTaskList(HttpErrorsFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("Add", "Add...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Edit", "Edit...", string.Empty).SetUsage()); + if (_owner.SelectedItem.Flag == "Local") + { + result.Add(new MethodTaskItem("Change", "Change Status Code", string.Empty).SetUsage()); + } + + result.Add(RemoveTaskItem); + } + + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Set", "Edit Feature Settings...", string.Empty).SetUsage()); + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Add() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void Edit() + { + _owner.Edit(); + } + + [Obfuscation(Exclude = true)] + public void Set() + { + _owner.Set(); + } + } + + public HttpErrorsFeature(Module module) + : base(module) + { + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + LoadItems(); + } + + public void Add() + { + var dialog = new NewErrorDialog(this.Module, null, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected custom error page?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + public void Edit() + { + var dialog = new NewErrorDialog(this.Module, this.SelectedItem, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.EditItem(this.SelectedItem); + } + + public void Set() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/httpErrors"); + var dialog = new EditDialog(this.Module, section); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + service.ServerManager.CommitChanges(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + ConfigurationSection section = service.GetSection("system.webServer/httpErrors"); + return section.GetCollection(); + } + + protected override void OnSettingsSaved() + { + this.HttpErrorsSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210481"); + return false; + } + + public HttpErrorsSettingsSavedEventHandler HttpErrorsSettingsUpdated { get; set; } + public string Description { get; } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public string Name + { + get + { + return "Error Pages"; + } + } + } +} diff --git a/JexusManager.Features.HttpErrors/HttpErrorsItem.cs b/JexusManager.Features.HttpErrors/HttpErrorsItem.cs new file mode 100644 index 00000000..a6af3de4 --- /dev/null +++ b/JexusManager.Features.HttpErrors/HttpErrorsItem.cs @@ -0,0 +1,68 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpErrors +{ + using Microsoft.Web.Administration; + + internal class HttpErrorsItem : IItem + { + public HttpErrorsItem(ConfigurationElement element) + { + this.Flag = element == null || element.IsLocallyStored ? "Local" : "Inherited"; + this.Element = element; + if (element == null) + { + Prefix = Path = string.Empty; + Response = "File"; + Substatus = -1; + return; + } + + this.Status = (uint)element["statusCode"]; + this.Substatus = (int)element["subStatusCode"]; + this.Path = (string)element["path"]; + this.Prefix = (string)element["prefixLanguageFilePath"]; + this.Response = element.Schema.AttributeSchemas["responseMode"].Format(element["responseMode"]); + } + + public string Prefix { get; set; } + + public uint Status { get; set; } + public int Substatus { get; set; } + public string Path { get; set; } + public string Response { get; set; } + public string Flag { get; set; } + public ConfigurationElement Element { get; set; } + + public string FullPath + { + get { return string.IsNullOrEmpty(this.Prefix) ? this.Path : string.Format("{0}\\\\{1}", this.Prefix, this.Path); } + } + + public string Code + { + get { return this.Substatus == -1 || this.Substatus == 0 ? this.Status.ToString() : string.Format("{0}.{1}", this.Status, this.Substatus); } + } + + public bool Equals(HttpErrorsItem other) + { + return Match(other); + } + + public bool Match(HttpErrorsItem other) + { + return other != null && other.Status == this.Status && other.Substatus == this.Substatus; + } + + public void Apply() + { + this.Element["statusCode"] = this.Status; + this.Element["subStatusCode"] = this.Substatus; + this.Element["prefixLanguageFilePath"] = this.Prefix; + this.Element["path"] = this.Path; + this.Element["responseMode"] = this.Response; + } + } +} diff --git a/JexusManager.Features.HttpErrors/HttpErrorsModule.cs b/JexusManager.Features.HttpErrors/HttpErrorsModule.cs new file mode 100644 index 00000000..2dd838e7 --- /dev/null +++ b/JexusManager.Features.HttpErrors/HttpErrorsModule.cs @@ -0,0 +1,26 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpErrors +{ + using System; + + using Properties; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + + internal class HttpErrorsModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)this.GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(HttpErrorsPage), "Error Pages", + "Configure pages to return when errors occur", Resources.custom_error_36, + Resources.custom_error_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.HttpErrors/HttpErrorsModuleProvider.cs b/JexusManager.Features.HttpErrors/HttpErrorsModuleProvider.cs new file mode 100644 index 00000000..5178f35d --- /dev/null +++ b/JexusManager.Features.HttpErrors/HttpErrorsModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpErrors +{ + using System; + + using Microsoft.Web.Management.Server; + + public class HttpErrorsModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(this.Name, typeof(HttpErrorsModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.HttpErrors/HttpErrorsPage.Designer.cs b/JexusManager.Features.HttpErrors/HttpErrorsPage.Designer.cs new file mode 100644 index 00000000..c610e7c8 --- /dev/null +++ b/JexusManager.Features.HttpErrors/HttpErrorsPage.Designer.cs @@ -0,0 +1,298 @@ +namespace JexusManager.Features.HttpErrors +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class HttpErrorsPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chStatus = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chPath = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chPage = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.toolStrip2 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel3 = new System.Windows.Forms.ToolStripLabel(); + this.cbGroup = new System.Windows.Forms.ToolStripComboBox(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.toolStrip2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 5; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.splitContainer1_SplitterMoved); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.toolStrip2); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 11; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chStatus, + this.chPath, + this.chPage, + this.chType}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 38); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 502); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.listView1_SelectedIndexChanged); + // + // chStatus + // + this.chStatus.Text = "Status Code"; + this.chStatus.Width = 120; + // + // chPath + // + this.chPath.Text = "Path"; + this.chPath.Width = 150; + // + // chPage + // + this.chPage.Text = "Type"; + this.chPage.Width = 120; + // + // chType + // + this.chType.Text = "Entry Type"; + this.chType.Width = 120; + // + // toolStrip2 + // + this.toolStrip2.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel3, + this.cbGroup}); + this.toolStrip2.Location = new System.Drawing.Point(0, 13); + this.toolStrip2.Name = "toolStrip2"; + this.toolStrip2.Size = new System.Drawing.Size(560, 25); + this.toolStrip2.TabIndex = 3; + this.toolStrip2.Text = "toolStrip2"; + // + // toolStripLabel3 + // + this.toolStripLabel3.Name = "toolStripLabel3"; + this.toolStripLabel3.Size = new System.Drawing.Size(59, 22); + this.toolStripLabel3.Text = "Group by:"; + // + // cbGroup + // + this.cbGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbGroup.Items.AddRange(new object[] { + "No Grouping", + "Category", + "Area"}); + this.cbGroup.Name = "cbGroup"; + this.cbGroup.Size = new System.Drawing.Size(121, 25); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(796, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to configure HTTP error responses. The error responses can be cu" + + "stom error pages, or detailed error messages that contain troubleshooting inform" + + "ation."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 10; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(126, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Error Pages"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // CustomErrorsPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "HttpErrorsPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.toolStrip2.ResumeLayout(false); + this.toolStrip2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private ListView listView1; + private ColumnHeader chStatus; + private ColumnHeader chPath; + private ColumnHeader chType; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private ColumnHeader chPage; + private Panel panel2; + private ToolStrip toolStrip2; + private ToolStripLabel toolStripLabel3; + private ToolStripComboBox cbGroup; + private PictureBox pictureBox1; + private ContextMenuStrip cmsActionPanel; + } +} diff --git a/JexusManager.Features.HttpErrors/HttpErrorsPage.cs b/JexusManager.Features.HttpErrors/HttpErrorsPage.cs new file mode 100644 index 00000000..184fe559 --- /dev/null +++ b/JexusManager.Features.HttpErrors/HttpErrorsPage.cs @@ -0,0 +1,137 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpErrors +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class HttpErrorsPage : ModuleListPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly HttpErrorsPage _owner; + + public PageTaskList(HttpErrorsPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class CustomErrorsListViewItem : ListViewItem + { + public HttpErrorsItem Item { get; } + private readonly HttpErrorsPage _page; + + public CustomErrorsListViewItem(HttpErrorsItem item, HttpErrorsPage page) + : base(item.Code) + { + this.Item = item; + _page = page; + this.SubItems.Add(new ListViewSubItem(this, item.FullPath)); + this.SubItems.Add(new ListViewSubItem(this, item.Response)); + this.SubItems.Add(new ListViewSubItem(this, item.Flag)); + } + } + + private HttpErrorsFeature _feature; + private PageTaskList _taskList; + + public HttpErrorsPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new HttpErrorsFeature(this.Module); + _feature.HttpErrorsSettingsUpdated = this.InitializeListPage; + _feature.Load(); + } + + protected override void InitializeListPage() + { + listView1.Items.Clear(); + foreach (var file in _feature.Items) + { + listView1.Items.Add(new CustomErrorsListViewItem(file, this)); + } + + if (_feature.SelectedItem != null) + { + foreach (CustomErrorsListViewItem item in listView1.Items) + { + if (item.Item == _feature.SelectedItem) + { + item.Selected = true; + } + } + } + + this.Refresh(); + } + + protected override void Refresh() + { + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + private void listView1_SelectedIndexChanged(object sender, EventArgs e) + { + _feature.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((CustomErrorsListViewItem)listView1.SelectedItems[0]).Item + : null; + // TODO: optimize refresh when null to not null (vice versa) + this.Refresh(); + } + + protected override bool ShowHelp() + { + _feature.ShowHelp(); + return true; + } + + private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + } +} diff --git a/JexusManager.Features.HttpErrors/HttpErrorsPage.resx b/JexusManager.Features.HttpErrors/HttpErrorsPage.resx new file mode 100644 index 00000000..876b3bf2 --- /dev/null +++ b/JexusManager.Features.HttpErrors/HttpErrorsPage.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 143, 17 + + + 281, 17 + + + 17, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.HttpErrors/HttpErrorsSettingsSavedEventHandler.cs b/JexusManager.Features.HttpErrors/HttpErrorsSettingsSavedEventHandler.cs new file mode 100644 index 00000000..350a05d8 --- /dev/null +++ b/JexusManager.Features.HttpErrors/HttpErrorsSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpErrors +{ + public delegate void HttpErrorsSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.HttpErrors/JexusManager.Features.HttpErrors.csproj b/JexusManager.Features.HttpErrors/JexusManager.Features.HttpErrors.csproj new file mode 100644 index 00000000..53011d60 --- /dev/null +++ b/JexusManager.Features.HttpErrors/JexusManager.Features.HttpErrors.csproj @@ -0,0 +1,151 @@ + + + + + Debug + AnyCPU + {76F1FA9F-3E56-4D5C-9324-D69DB260EFA9} + Library + Properties + JexusManager.Features.HttpErrors + JexusManager.Features.HttpErrors + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + ConfigurationAttributeSchemaExtensions.cs + + + Form + + + EditDialog.cs + + + + + + + UserControl + + + HttpErrorsPage.cs + + + + Form + + + LocalErrorDialog.cs + + + Form + + + NewErrorDialog.cs + + + + True + True + Resources.resx + + + + + EditDialog.cs + + + HttpErrorsPage.cs + + + LocalErrorDialog.cs + + + NewErrorDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.HttpErrors/JexusManager.snk b/JexusManager.Features.HttpErrors/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.HttpErrors/LocalErrorDialog.Designer.cs b/JexusManager.Features.HttpErrors/LocalErrorDialog.Designer.cs new file mode 100644 index 00000000..aa0b4b39 --- /dev/null +++ b/JexusManager.Features.HttpErrors/LocalErrorDialog.Designer.cs @@ -0,0 +1,171 @@ +namespace JexusManager.Features.HttpErrors +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class LocalErrorDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.txtDirectory = new System.Windows.Forms.TextBox(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.label4 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(76, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Directory path:"; + // + // txtDirectory + // + this.txtDirectory.Location = new System.Drawing.Point(15, 25); + this.txtDirectory.Name = "txtDirectory"; + this.txtDirectory.Size = new System.Drawing.Size(300, 20); + this.txtDirectory.TabIndex = 1; + // + // btnBrowse + // + this.btnBrowse.Location = new System.Drawing.Point(321, 23); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(85, 23); + this.btnBrowse.TabIndex = 2; + this.btnBrowse.Text = "Browse..."; + this.btnBrowse.UseVisualStyleBackColor = true; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 48); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(164, 13); + this.label2.TabIndex = 3; + this.label2.Text = "Example: d:\\errors, relative\\errors"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 79); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(89, 13); + this.label3.TabIndex = 4; + this.label3.Text = "Relative file path:"; + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(15, 95); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(255, 20); + this.txtPath.TabIndex = 5; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(226, 211); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 6; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(322, 211); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 7; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(12, 118); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(148, 13); + this.label4.TabIndex = 8; + this.label4.Text = "Example: \\NotFound\\404.htm"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(12, 161); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(226, 13); + this.label5.TabIndex = 9; + this.label5.Text = "Example: d:\\errors\\EN-US\\NotFound\\404.htm"; + // + // LocalErrorDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(429, 246); + this.Controls.Add(this.label5); + this.Controls.Add(this.label4); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.txtPath); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.btnBrowse); + this.Controls.Add(this.txtDirectory); + this.Controls.Add(this.label1); + this.Name = "LocalErrorDialog"; + this.Text = "Set Localized Custom Error Path"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.LocalErrorDialog_HelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label1; + private TextBox txtDirectory; + private Button btnBrowse; + private Label label2; + private Label label3; + private TextBox txtPath; + private Button btnOK; + private Button btnCancel; + private Label label4; + private Label label5; + } +} diff --git a/JexusManager.Features.HttpErrors/LocalErrorDialog.cs b/JexusManager.Features.HttpErrors/LocalErrorDialog.cs new file mode 100644 index 00000000..e5ddb44a --- /dev/null +++ b/JexusManager.Features.HttpErrors/LocalErrorDialog.cs @@ -0,0 +1,50 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpErrors +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal partial class LocalErrorDialog : DialogForm + { + public LocalErrorDialog(IServiceProvider serviceProvider, HttpErrorsItem item) + : base(serviceProvider) + { + InitializeComponent(); + txtDirectory.Text = item.Prefix; + txtPath.Text = item.Path; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnBrowse, "Click") + .Subscribe(evt => + { + DialogHelper.ShowBrowseDialog(txtDirectory); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + item.Prefix = txtDirectory.Text; + item.Path = txtPath.Text; + DialogResult = DialogResult.OK; + })); + } + + private void LocalErrorDialog_HelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210481"); + } + } +} diff --git a/JexusManager.Features.HttpErrors/LocalErrorDialog.resx b/JexusManager.Features.HttpErrors/LocalErrorDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.HttpErrors/LocalErrorDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.HttpErrors/NewErrorDialog.Designer.cs b/JexusManager.Features.HttpErrors/NewErrorDialog.Designer.cs new file mode 100644 index 00000000..00dc648a --- /dev/null +++ b/JexusManager.Features.HttpErrors/NewErrorDialog.Designer.cs @@ -0,0 +1,285 @@ +namespace JexusManager.Features.HttpErrors +{ + using System.ComponentModel; + using System.Windows.Forms; + + sealed partial class NewErrorDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.txtStatusCode = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.btnSet = new System.Windows.Forms.Button(); + this.label6 = new System.Windows.Forms.Label(); + this.txtRedirect = new System.Windows.Forms.TextBox(); + this.label7 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.txtExecute = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.cbLocalize = new System.Windows.Forms.CheckBox(); + this.txtStatic = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.rbRedirect = new System.Windows.Forms.RadioButton(); + this.rbExecute = new System.Windows.Forms.RadioButton(); + this.rbStatic = new System.Windows.Forms.RadioButton(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(67, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Status code:"; + // + // txtStatusCode + // + this.txtStatusCode.Location = new System.Drawing.Point(12, 25); + this.txtStatusCode.Name = "txtStatusCode"; + this.txtStatusCode.Size = new System.Drawing.Size(120, 20); + this.txtStatusCode.TabIndex = 1; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 48); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(113, 13); + this.label2.TabIndex = 2; + this.label2.Text = "Example: 404 or 404.2"; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.btnSet); + this.groupBox1.Controls.Add(this.label6); + this.groupBox1.Controls.Add(this.txtRedirect); + this.groupBox1.Controls.Add(this.label7); + this.groupBox1.Controls.Add(this.label5); + this.groupBox1.Controls.Add(this.txtExecute); + this.groupBox1.Controls.Add(this.label4); + this.groupBox1.Controls.Add(this.cbLocalize); + this.groupBox1.Controls.Add(this.txtStatic); + this.groupBox1.Controls.Add(this.label3); + this.groupBox1.Controls.Add(this.rbRedirect); + this.groupBox1.Controls.Add(this.rbExecute); + this.groupBox1.Controls.Add(this.rbStatic); + this.groupBox1.Location = new System.Drawing.Point(12, 77); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(470, 343); + this.groupBox1.TabIndex = 3; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Response Action"; + // + // btnSet + // + this.btnSet.Location = new System.Drawing.Point(376, 75); + this.btnSet.Name = "btnSet"; + this.btnSet.Size = new System.Drawing.Size(88, 23); + this.btnSet.TabIndex = 12; + this.btnSet.Text = "Set..."; + this.btnSet.UseVisualStyleBackColor = true; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(33, 306); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(220, 13); + this.label6.TabIndex = 11; + this.label6.Text = "Example: http://www.contoso.com/404.aspx"; + // + // txtRedirect + // + this.txtRedirect.Location = new System.Drawing.Point(36, 283); + this.txtRedirect.Name = "txtRedirect"; + this.txtRedirect.Size = new System.Drawing.Size(334, 20); + this.txtRedirect.TabIndex = 10; + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(33, 267); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(76, 13); + this.label7.TabIndex = 9; + this.label7.Text = "Absolute URL:"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(33, 207); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(158, 13); + this.label5.TabIndex = 8; + this.label5.Text = "Example: /ErrorPages/404.aspx"; + // + // txtExecute + // + this.txtExecute.Location = new System.Drawing.Point(36, 184); + this.txtExecute.Name = "txtExecute"; + this.txtExecute.Size = new System.Drawing.Size(334, 20); + this.txtExecute.TabIndex = 7; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(33, 168); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(127, 13); + this.label4.TabIndex = 6; + this.label4.Text = "URL (relative to site root):"; + // + // cbLocalize + // + this.cbLocalize.AutoSize = true; + this.cbLocalize.Location = new System.Drawing.Point(36, 104); + this.cbLocalize.Name = "cbLocalize"; + this.cbLocalize.Size = new System.Drawing.Size(245, 17); + this.cbLocalize.TabIndex = 5; + this.cbLocalize.Text = "Try to return the error file in the client language"; + this.cbLocalize.UseVisualStyleBackColor = true; + // + // txtStatic + // + this.txtStatic.Location = new System.Drawing.Point(36, 77); + this.txtStatic.Name = "txtStatic"; + this.txtStatic.Size = new System.Drawing.Size(334, 20); + this.txtStatic.TabIndex = 4; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(33, 61); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(50, 13); + this.label3.TabIndex = 3; + this.label3.Text = "File path:"; + // + // rbRedirect + // + this.rbRedirect.AutoSize = true; + this.rbRedirect.Location = new System.Drawing.Point(15, 235); + this.rbRedirect.Name = "rbRedirect"; + this.rbRedirect.Size = new System.Drawing.Size(158, 17); + this.rbRedirect.TabIndex = 2; + this.rbRedirect.Text = "Respond with a 302 redirect"; + this.rbRedirect.UseVisualStyleBackColor = true; + // + // rbExecute + // + this.rbExecute.AutoSize = true; + this.rbExecute.Checked = true; + this.rbExecute.Location = new System.Drawing.Point(15, 137); + this.rbExecute.Name = "rbExecute"; + this.rbExecute.Size = new System.Drawing.Size(150, 17); + this.rbExecute.TabIndex = 1; + this.rbExecute.TabStop = true; + this.rbExecute.Text = "Execute a URL on the site"; + this.rbExecute.UseVisualStyleBackColor = true; + // + // rbStatic + // + this.rbStatic.AutoSize = true; + this.rbStatic.Location = new System.Drawing.Point(15, 28); + this.rbStatic.Name = "rbStatic"; + this.rbStatic.Size = new System.Drawing.Size(265, 17); + this.rbStatic.TabIndex = 0; + this.rbStatic.Text = "Insert content from static file into the error response"; + this.rbStatic.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(387, 451); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 4; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(287, 451); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 5; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // NewCustomErrorDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(494, 486); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtStatusCode); + this.Controls.Add(this.label1); + this.Name = "NewErrorDialog"; + this.Text = "Add Custom Error Page"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewCustomErrorDialogHelpButtonClicked); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label1; + private TextBox txtStatusCode; + private Label label2; + private GroupBox groupBox1; + private Label label6; + private TextBox txtRedirect; + private Label label7; + private Label label5; + private TextBox txtExecute; + private Label label4; + private CheckBox cbLocalize; + private TextBox txtStatic; + private Label label3; + private RadioButton rbRedirect; + private RadioButton rbExecute; + private RadioButton rbStatic; + private Button btnCancel; + private Button btnOK; + private Button btnSet; + } +} diff --git a/JexusManager.Features.HttpErrors/NewErrorDialog.cs b/JexusManager.Features.HttpErrors/NewErrorDialog.cs new file mode 100644 index 00000000..4b16e28a --- /dev/null +++ b/JexusManager.Features.HttpErrors/NewErrorDialog.cs @@ -0,0 +1,215 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpErrors +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewErrorDialog : DialogForm + { + public NewErrorDialog(IServiceProvider serviceProvider, HttpErrorsItem item, HttpErrorsFeature feature) + : base(serviceProvider) + { + InitializeComponent(); + txtStatusCode.ReadOnly = item != null; + if (item != null) + { + txtStatusCode.Text = item.Code; + } + + Text = item == null ? "Add Custom Error Page" : "Edit Custom Error Page"; + Item = item ?? new HttpErrorsItem(null); + var mode = Item.Response; + rbStatic.Checked = mode == "File"; + rbExecute.Checked = mode == "ExecuteURL"; + rbRedirect.Checked = mode == "Redirect"; + UpdateUI(Item); + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtStatusCode, "TextChanged") + .Merge(Observable.FromEventPattern(txtRedirect, "TextChanged")) + .Merge(Observable.FromEventPattern(txtExecute, "TextChanged")) + .Merge(Observable.FromEventPattern(txtStatic, "TextChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtStatusCode.Text) && + !(string.IsNullOrWhiteSpace(txtExecute.Text) && string.IsNullOrWhiteSpace(txtStatic.Text) && string.IsNullOrWhiteSpace(txtRedirect.Text)); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + var index = txtStatusCode.Text.IndexOf('.'); + if (index == -1) + { + int statusCode; + var statusParsed = int.TryParse(txtStatusCode.Text, out statusCode); + if (!statusParsed || statusCode < 100 || statusCode > 999) + { + ShowMessage( + string.Format( + "'{0}' is an invalid status code. Status codes must be numbers in the form of 400 or 400.1. Status codes must be between 100 and 999. Sub-status codes must be between 1 and 999.", + txtStatusCode.Text), + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + Item.Status = uint.Parse(txtStatusCode.Text); + Item.Substatus = -1; + } + else + { + var status = index == 0 ? string.Empty : txtStatusCode.Text.Substring(0, index); + var substatus = index == txtStatusCode.Text.Length - 1 ? string.Empty : txtStatusCode.Text.Substring(index + 1); + uint statusCode; + var statusParsed = uint.TryParse(status, out statusCode); + int substatusCode; + var substatusParsed = int.TryParse(substatus, out substatusCode); + if (!statusParsed || statusCode < 100 || statusCode > 999 || !substatusParsed || substatusCode < 1 || + substatusCode > 999) + { + ShowMessage( + string.Format( + "'{0}' is an invalid status code. Status codes must be numbers in the form of 400 or 400.1. Status codes must be between 100 and 999. Sub-status codes must be between 1 and 999.", + txtStatusCode.Text), + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + Item.Status = statusCode; + Item.Substatus = substatusCode; + } + + if (Item.Response == "Redirect") + { + Item.Path = txtRedirect.Text; + } + else if (Item.Response == "ExecuteURL") + { + if (!Item.Path.StartsWith("/", StringComparison.OrdinalIgnoreCase)) + { + ShowMessage( + "The specific URL is invalid. It must be a relative URL path that begins with \"/\"", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + Item.Path = txtExecute.Text; + } + else + { + Item.Path = txtStatic.Text; + } + + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(rbRedirect, "CheckedChanged") + .Merge(Observable.FromEventPattern(rbExecute, "CheckedChanged")) + .Merge(Observable.FromEventPattern(rbStatic, "CheckedChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + if (rbStatic.Checked) + { + Item.Response = "File"; + } + else if (rbExecute.Checked) + { + Item.Response = "ExecuteURL"; + } + else + { + Item.Response = "Redirect"; + } + + UpdateUI(Item); + })); + + container.Add( + Observable.FromEventPattern(btnSet, "Click") + .Subscribe(evt => + { + if (cbLocalize.Checked) + { + var dialog = new LocalErrorDialog(ServiceProvider, Item); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + txtStatic.Text = Item.FullPath; + } + else + { + DialogHelper.ShowBrowseDialog(txtStatic); + } + })); + + container.Add( + Observable.FromEventPattern(cbLocalize, "CheckedChanged") + .Subscribe(evt => + { + btnSet.Text = cbLocalize.Checked ? "Set..." : "Browse..."; + txtStatic.Text = string.Empty; + txtStatic.ReadOnly = cbLocalize.Checked; + })); + } + + private void UpdateUI(HttpErrorsItem item) + { + cbLocalize.Checked = !string.IsNullOrEmpty(item.Prefix); + var mode = item.Response; + if (mode == "File") + { + txtStatic.Text = string.IsNullOrEmpty(item.Prefix) ? item.Path : item.FullPath; + txtStatic.ReadOnly = cbLocalize.Checked; + txtExecute.Text = string.Empty; + txtRedirect.Text = string.Empty; + } + else if (mode == "ExecuteURL") + { + txtStatic.Text = string.Empty; + txtExecute.Text = Item.Path; + txtRedirect.Text = string.Empty; + } + else + { + txtStatic.Text = string.Empty; + txtExecute.Text = string.Empty; + txtRedirect.Text = Item.Path; + } + + txtExecute.Enabled = mode == "ExecuteURL"; + txtRedirect.Enabled = mode == "Redirect"; + cbLocalize.Enabled = btnSet.Enabled = txtStatic.Enabled = mode == "File"; + } + + public HttpErrorsItem Item { get; set; } + + private void NewCustomErrorDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210481"); + } + } +} diff --git a/JexusManager.Features.HttpErrors/NewErrorDialog.resx b/JexusManager.Features.HttpErrors/NewErrorDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.HttpErrors/NewErrorDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.HttpErrors/Properties/AssemblyInfo.cs b/JexusManager.Features.HttpErrors/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..c2b8b8ec --- /dev/null +++ b/JexusManager.Features.HttpErrors/Properties/AssemblyInfo.cs @@ -0,0 +1,46 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.HttpErrors")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.HttpErrors")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("76f1fa9f-3e56-4d5c-9324-d69db260efa9")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("Tests.JexusManager, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] diff --git a/JexusManager.Features.HttpErrors/Properties/Resources.Designer.cs b/JexusManager.Features.HttpErrors/Properties/Resources.Designer.cs new file mode 100644 index 00000000..485c00ad --- /dev/null +++ b/JexusManager.Features.HttpErrors/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.HttpErrors.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.HttpErrors.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap custom_error_36 { + get { + object obj = ResourceManager.GetObject("custom_error_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.HttpErrors/Properties/Resources.resx b/JexusManager.Features.HttpErrors/Properties/Resources.resx new file mode 100644 index 00000000..c60a8d60 --- /dev/null +++ b/JexusManager.Features.HttpErrors/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\custom_error_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.HttpErrors/Resources/custom_error_36.png b/JexusManager.Features.HttpErrors/Resources/custom_error_36.png new file mode 100644 index 0000000000000000000000000000000000000000..0fe5c3e553c03982b9deec8abc896f00d55dfaf9 GIT binary patch literal 1479 zcmV;&1vvVNP)hFB9c-SC`#)}x7%*JdwtlU6bnTAp)q=s zlbyLcIro?UIp@x~1OJcz;^=^Q2gK*YmpWGm?Xa^VmAc@sufNa%JLc+7nWHj`%j)XB z4L$OR2{3r%$k?wJF4R2<1OJRdLhOlb-D>vl+eiPteLS#bi>V5+XHG8X5UPirrlz)u zbeeQ;FNN`OjPi0!$62*`VBqk9S*kQEg?59gS=L*@_3OFz#TQfaS3mz8r>P0evR;?7 zOov$kErD%SEiLuezWkEH!~~|MVF*ECVuHcLhpB3APJIa5{uZDQz++ZczTt^RxpC?g z07=Io84Ln&Z_1gpbg05X>^gR0`GsoB*I;ROSds`_$x z<3{UBXD0v=pO2tzBZWW;LD05|_Fgxb(&AB7_2mUA`wm#+OC;Ww`Mi?u>qAu( zHq_Qql1xHtE2L5|IZ0r2l<$82naOMx({T`{nSA{E^+TV))p=D&HH@~(#zuAU*f9W> z27`Dk3t3VE@i@d{NKM0ISu72O02n-al)&1xs-o*{^BS@ac%mYe+AwtLRB;2;G!oU- zplL8V3Zid1StJG9OVP$w9|w%;hLt!3!+X#iG6qv)nt z%$-aIEDJ0PnaLo9KsO9lE?x}4P)`qKwYBJFWpD0>k~sqn!81-{V{Gu)F_045<6&te z0zwpRbQBDuXqik=HBDn_B!cbnfRtQ6aRO)Ey4W~8Gbf<;Az%iBFKL!lEM=g6$r8}C zsmhXt0_5|M&m&=K9!)Dg>uwRkvM6<&-S0zS)<7D(=rlF?ZzXb7Ai$zv@U}Yc!ep~k z`7_-Xg+f#XitArLew@n2M!$d;W>xm>Q0I-s-V=tQ{&xO6ilVT7^=b^$1XV4X5TL3Q zdU_~ycf;i5?f+aW_xt&NV1Rr!ix~=ml&Qzk>5mV>jlZOjD#YIMh6e4I?rs2L)z#QO z-)&Vi4TM0csX^Pb2ko7AP@>U0mD4nApO08HT71ua{Wawc4Vn;Q?_Ua8J3MMHTejuq z#f#*#S#(_|v3&U*Al%B8NCXT6#qXcmi{$hi6N1Ew73jK7er$}9OPBCH_+V=XZ2VI| z`$1@>rLTG8anilL04%So!|-_SSVX!|h2CBYU0viq`;5YwGc)oCAuue9Wp#A`r2G2t z#^b1^rEUA~k}_giZ><387I-Rrr%lhB{J+ z8KIGPQRh~ORb3~MOipzJy3dDU+pj(i4xqaXisoJzfVBpmFJHCF8FCvhfUc7#7vwBA zeD*B<6)T)%SJ!jED?k>QP+dAN5D3`zc3CKp8y;Tp!)0!02&AOEtZX~r2TB2POCb~R zWyZ(Tj%ij_H8&%ryhl?c?=da!(@5Rh*H|u>2FhH8vWj~X0ID8>#5UNe7l{{o$O-uM z0KEGZoC5}dwBkzTbD_%Jdwo7mw)cZ^EeG7BxN8psBN{LXi~t4qSD#jW3#t&12gZR> hH)Q$$Ki&N6#_s|avDM|CXT$&i002ovPDHLkV1in@vx5Kt literal 0 HcmV?d00001 diff --git a/JexusManager.Features.HttpErrors/packages.config b/JexusManager.Features.HttpErrors/packages.config new file mode 100644 index 00000000..571e4fe0 --- /dev/null +++ b/JexusManager.Features.HttpErrors/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.HttpRedirect/HttpRedirectFeature.cs b/JexusManager.Features.HttpRedirect/HttpRedirectFeature.cs new file mode 100644 index 00000000..8523459a --- /dev/null +++ b/JexusManager.Features.HttpRedirect/HttpRedirectFeature.cs @@ -0,0 +1,132 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpRedirect +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.Resources; + + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal class HttpRedirectFeature + { + public HttpRedirectFeature(Module module, ServerManager server, Application application) + { + this.Module = module; + this.Server = server; + this.Application = application; + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + + protected void DisplayErrorMessage(Exception ex, ResourceManager resourceManager) + { + var service = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + service.ShowError(ex, resourceManager.GetString("General"), "", false); + } + + protected object GetService(Type type) + { + return (this.Module as IServiceProvider).GetService(type); + } + + public void Load() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/httpRedirect"); + this.Enabled = (bool)section["enabled"]; + this.Link = (string)section["destination"]; + this.Exact = (bool)section["exactDestination"]; + this.OnlyRoot = !(bool)section["childOnly"]; + this.Mode = (long)section["httpResponseStatus"]; + + SupportedModes = new List(); + foreach (ConfigurationEnumValue item in section.Schema.AttributeSchemas["httpResponseStatus"].GetEnumValues()) + { + SupportedModes.Add(item.Value); + } + + this.OnHttpRedirectSettingsSaved(); + } + + public List SupportedModes { get; set; } + + public string Directory { get; set; } + + protected void OnHttpRedirectSettingsSaved() + { + this.HttpRedirectSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210508"); + return false; + } + + public HttpRedirectSettingsSavedEventHandler HttpRedirectSettingsUpdated { get; set; } + public string Description { get; } + + public virtual bool IsFeatureEnabled + { + get { return true; } + } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public Module Module { get; } + public ServerManager Server { get; set; } + public Application Application { get; set; } + + public string Name + { + get { return "HTTP Redirect"; } + } + + + public bool Enabled { get; set; } + public string Link { get; set; } + public bool Exact { get; set; } + public bool OnlyRoot { get; set; } + public long Mode { get; set; } + + public void CancelChanges() + { + this.Load(); + } + + public bool ApplyChanges() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/httpRedirect"); + section["enabled"] = this.Enabled; + section["destination"] = this.Link; + section["exactDestination"] = this.Exact; + section["childOnly"] = !this.OnlyRoot; + if (section.Schema.AttributeSchemas["httpResponseStatus"].GetEnumValues().GetName(this.Mode) == null) + { + section["httpResponseStatus"] = 301; + } + else + { + section["httpResponseStatus"] = this.Mode; + } + + service.ServerManager.CommitChanges(); + return true; + } + } +} diff --git a/JexusManager.Features.HttpRedirect/HttpRedirectModule.cs b/JexusManager.Features.HttpRedirect/HttpRedirectModule.cs new file mode 100644 index 00000000..9066c6cc --- /dev/null +++ b/JexusManager.Features.HttpRedirect/HttpRedirectModule.cs @@ -0,0 +1,30 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpRedirect +{ + using System; + + using Properties; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + + internal class HttpRedirectModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)this.GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo( + this, + typeof(HttpRedirectPage), + "HTTP Redirect", + "Specify rules for redirecting incoming requests to another file or URL", + Resources.http_redirect_36, + Resources.http_redirect_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.HttpRedirect/HttpRedirectModuleProvider.cs b/JexusManager.Features.HttpRedirect/HttpRedirectModuleProvider.cs new file mode 100644 index 00000000..8e264b54 --- /dev/null +++ b/JexusManager.Features.HttpRedirect/HttpRedirectModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpRedirect +{ + using System; + + using Microsoft.Web.Management.Server; + + public class HttpRedirectModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(this.Name, typeof(HttpRedirectModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.HttpRedirect/HttpRedirectPage.Designer.cs b/JexusManager.Features.HttpRedirect/HttpRedirectPage.Designer.cs new file mode 100644 index 00000000..46f0831c --- /dev/null +++ b/JexusManager.Features.HttpRedirect/HttpRedirectPage.Designer.cs @@ -0,0 +1,317 @@ +namespace JexusManager.Features.HttpRedirect +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class HttpRedirectPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.cbCode = new System.Windows.Forms.ComboBox(); + this.label5 = new System.Windows.Forms.Label(); + this.cbThis = new System.Windows.Forms.CheckBox(); + this.cbExact = new System.Windows.Forms.CheckBox(); + this.label4 = new System.Windows.Forms.Label(); + this.txtLink = new System.Windows.Forms.TextBox(); + this.cbRedirect = new System.Windows.Forms.CheckBox(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.groupBox1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 5; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.SplitContainer1SplitterMoved); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.groupBox1); + this.panel2.Controls.Add(this.label4); + this.panel2.Controls.Add(this.txtLink); + this.panel2.Controls.Add(this.cbRedirect); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 11; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.cbCode); + this.groupBox1.Controls.Add(this.label5); + this.groupBox1.Controls.Add(this.cbThis); + this.groupBox1.Controls.Add(this.cbExact); + this.groupBox1.Location = new System.Drawing.Point(16, 97); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(529, 171); + this.groupBox1.TabIndex = 7; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Redirect Behavior"; + // + // cbCode + // + this.cbCode.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbCode.Enabled = false; + this.cbCode.FormattingEnabled = true; + this.cbCode.Location = new System.Drawing.Point(17, 121); + this.cbCode.Name = "cbCode"; + this.cbCode.Size = new System.Drawing.Size(303, 21); + this.cbCode.TabIndex = 3; + this.cbCode.SelectedIndexChanged += new System.EventHandler(this.CbCodeSelectedIndexChanged); + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(14, 105); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(67, 13); + this.label5.TabIndex = 2; + this.label5.Text = "Status code:"; + // + // cbThis + // + this.cbThis.AutoSize = true; + this.cbThis.Enabled = false; + this.cbThis.Location = new System.Drawing.Point(17, 72); + this.cbThis.Name = "cbThis"; + this.cbThis.Size = new System.Drawing.Size(344, 17); + this.cbThis.TabIndex = 1; + this.cbThis.Text = "Only redirect requests to content in this directory (not subdirectories)"; + this.cbThis.UseVisualStyleBackColor = true; + this.cbThis.CheckedChanged += new System.EventHandler(this.CbExactCheckedChanged); + // + // cbExact + // + this.cbExact.AutoSize = true; + this.cbExact.Enabled = false; + this.cbExact.Location = new System.Drawing.Point(17, 35); + this.cbExact.Name = "cbExact"; + this.cbExact.Size = new System.Drawing.Size(375, 17); + this.cbExact.TabIndex = 0; + this.cbExact.Text = "Redirect all requests to exact destination (instead of relative to destination)"; + this.cbExact.UseVisualStyleBackColor = true; + this.cbExact.CheckedChanged += new System.EventHandler(this.CbExactCheckedChanged); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(30, 67); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(201, 13); + this.label4.TabIndex = 6; + this.label4.Text = "Example: http://www.contoso.com/sales"; + // + // txtLink + // + this.txtLink.Enabled = false; + this.txtLink.Location = new System.Drawing.Point(33, 44); + this.txtLink.Name = "txtLink"; + this.txtLink.Size = new System.Drawing.Size(383, 20); + this.txtLink.TabIndex = 5; + this.txtLink.TextChanged += new System.EventHandler(this.TxtLinkTextChanged); + // + // cbRedirect + // + this.cbRedirect.AutoSize = true; + this.cbRedirect.Location = new System.Drawing.Point(16, 21); + this.cbRedirect.Name = "cbRedirect"; + this.cbRedirect.Size = new System.Drawing.Size(197, 17); + this.cbRedirect.TabIndex = 4; + this.cbRedirect.Text = "Redirect requests to this destination:"; + this.cbRedirect.UseVisualStyleBackColor = true; + this.cbRedirect.CheckedChanged += new System.EventHandler(this.CbSslCheckedChanged); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(416, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to specify rules for redirecting incoming requests to another fi" + + "le or URL."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 10; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(153, 25); + this.label3.TabIndex = 2; + this.label3.Text = "HTTP Redirect"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // HttpRedirectPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "HttpRedirectPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Panel panel2; + private PictureBox pictureBox1; + private CheckBox cbRedirect; + private ContextMenuStrip cmsActionPanel; + private GroupBox groupBox1; + private ComboBox cbCode; + private Label label5; + private CheckBox cbThis; + private CheckBox cbExact; + private Label label4; + private TextBox txtLink; + } +} diff --git a/JexusManager.Features.HttpRedirect/HttpRedirectPage.cs b/JexusManager.Features.HttpRedirect/HttpRedirectPage.cs new file mode 100644 index 00000000..f42740cd --- /dev/null +++ b/JexusManager.Features.HttpRedirect/HttpRedirectPage.cs @@ -0,0 +1,213 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpRedirect +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class HttpRedirectPage : ModuleDialogPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly HttpRedirectPage _owner; + + public PageTaskList(HttpRedirectPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private class CodeItem + { + public long Code { get; set; } + public string Description { get; set; } + + public CodeItem(long code, string description) + { + this.Code = code; + this.Description = description; + } + + public override string ToString() + { + return this.Description; + } + } + + private HttpRedirectFeature _feature; + private bool _hasChanges; + private bool _initialized; + private TaskList _taskList; + + public HttpRedirectPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new HttpRedirectFeature(this.Module, null, null); + _feature.HttpRedirectSettingsUpdated = this.Refresh; + _feature.Load(); + + base.Initialize(navigationData); + } + + protected override bool ShowHelp() + { + return _feature.ShowHelp(); + } + + private void SplitContainer1SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + protected override bool ApplyChanges() + { + _feature.Enabled = cbRedirect.Checked; + _feature.Link = txtLink.Text; + _feature.Exact = cbExact.Checked; + _feature.OnlyRoot = cbThis.Checked; + _feature.Mode = ((CodeItem)(cbCode.SelectedItem)).Code; + if (!_feature.ApplyChanges()) + { + return false; + } + + this.ClearChanges(); + return true; + } + + protected override void CancelChanges() + { + _feature.CancelChanges(); + this.ClearChanges(); + } + + protected override bool HasChanges + { + get { return _hasChanges; } + } + + protected override bool CanApplyChanges + { + get { return true; } + } + + private void InformChanges() + { + if (!_initialized) + { + return; + } + + _hasChanges = true; + this.Refresh(); + } + + private void ClearChanges() + { + _hasChanges = false; + this.Refresh(); + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + + protected override void OnRefresh() + { + if (!_hasChanges) + { + if (!_initialized) + { + var lines = new List + { + new CodeItem(302, "Found(302)"), + new CodeItem(301, "Permanent(301)"), + new CodeItem(307, "Temporary(307)"), + new CodeItem(308, "Permanent Redirect (308)") + }; + foreach (var line in lines) + { + if (_feature.SupportedModes.Contains(line.Code)) + { + cbCode.Items.Add(line); + } + } + } + + cbRedirect.Checked = _feature.Enabled; + txtLink.Text = _feature.Link; + cbExact.Checked = _feature.Exact; + cbThis.Checked = _feature.OnlyRoot; + foreach (CodeItem item in cbCode.Items) + { + if (item.Code == _feature.Mode) + { + cbCode.SelectedItem = item; + } + } + + _initialized = true; + } + + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + } + + private void CbSslCheckedChanged(object sender, EventArgs e) + { + this.InformChanges(); + txtLink.Enabled = cbCode.Enabled = cbExact.Enabled = cbThis.Enabled = cbRedirect.Checked; + } + + private void CbExactCheckedChanged(object sender, EventArgs e) + { + this.InformChanges(); + } + + private void CbCodeSelectedIndexChanged(object sender, EventArgs e) + { + this.InformChanges(); + } + + private void TxtLinkTextChanged(object sender, EventArgs e) + { + this.InformChanges(); + } + } +} diff --git a/JexusManager.Features.HttpRedirect/HttpRedirectPage.resx b/JexusManager.Features.HttpRedirect/HttpRedirectPage.resx new file mode 100644 index 00000000..950be5d2 --- /dev/null +++ b/JexusManager.Features.HttpRedirect/HttpRedirectPage.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 143, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.HttpRedirect/HttpRedirectSettingsSavedEventHandler.cs b/JexusManager.Features.HttpRedirect/HttpRedirectSettingsSavedEventHandler.cs new file mode 100644 index 00000000..fd47d877 --- /dev/null +++ b/JexusManager.Features.HttpRedirect/HttpRedirectSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.HttpRedirect +{ + public delegate void HttpRedirectSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.HttpRedirect/JexusManager.Features.HttpRedirect.csproj b/JexusManager.Features.HttpRedirect/JexusManager.Features.HttpRedirect.csproj new file mode 100644 index 00000000..7896f56f --- /dev/null +++ b/JexusManager.Features.HttpRedirect/JexusManager.Features.HttpRedirect.csproj @@ -0,0 +1,103 @@ + + + + + Debug + AnyCPU + {C0C1DDE1-6447-4D3E-BC1A-F62CABBDBB53} + Library + Properties + JexusManager.Features.HttpRedirect + JexusManager.Features.HttpRedirect + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + + + + + + + + + + + + + UserControl + + + HttpRedirectPage.cs + + + + + True + True + Resources.resx + + + + + HttpRedirectPage.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.HttpRedirect/JexusManager.snk b/JexusManager.Features.HttpRedirect/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.HttpRedirect/Properties/AssemblyInfo.cs b/JexusManager.Features.HttpRedirect/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..ebd24a57 --- /dev/null +++ b/JexusManager.Features.HttpRedirect/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.HttpRedirect")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.HttpRedirect")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("c0c1dde1-6447-4d3e-bc1a-f62cabbdbb53")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JexusManager.Features.HttpRedirect/Properties/Resources.Designer.cs b/JexusManager.Features.HttpRedirect/Properties/Resources.Designer.cs new file mode 100644 index 00000000..e8319f81 --- /dev/null +++ b/JexusManager.Features.HttpRedirect/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.HttpRedirect.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.HttpRedirect.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap http_redirect_36 { + get { + object obj = ResourceManager.GetObject("http_redirect_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.HttpRedirect/Properties/Resources.resx b/JexusManager.Features.HttpRedirect/Properties/Resources.resx new file mode 100644 index 00000000..97b03f61 --- /dev/null +++ b/JexusManager.Features.HttpRedirect/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\http_redirect_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.HttpRedirect/Resources/http_redirect_36.png b/JexusManager.Features.HttpRedirect/Resources/http_redirect_36.png new file mode 100644 index 0000000000000000000000000000000000000000..94f848845e29080d11a59843117a2a16483fd2f2 GIT binary patch literal 1772 zcmV_f9KxW_ipXAQ=9m)4mb%CPznJlriz0Vfhyrtg-TT;5RH=3ssdH~ zMN!pOaO=8D+__5x#cgCKX%OAU} zAG=@BicU+;!`J7flk})l_dR#H1Q5oR-@bg9TWVY9 z0TL08y?dEpZEJDORu-@Q?VTG!<9QzcJl^jHAyAef5dLuJ-@HF`^=3$j6}3?ud)h0Z zZ7!e{Eo(@thMNPZF2Re-coh?MSc&1$6p zNGpu(u;aV;@S6iim)!U(n?BBCyAEON>RhL_PzKLJh6JS)zQEA6310pC=_NP5eeFu5 zz-~1|lmdi`8qx)Ze4z8wZS?JVWLcX(zrPP%EkjF&3=kzn-MFs1?9B~kd3swA4Jw9A zKr1PJX*GZ_#h>|M5m_{pN(<%glyw=VIzWO?QadHrwGG_+ofnDJB+D?QmT;K}N~FM$!SlRj19BX#c>=C z9Nf>@b7vVJAH!f+qdWqajuDQ8vF#k==?TONGnH&ZB&;giUh=k&C*s5t@zNf~_s9-k zp^3mycPqSyw3$!++5D_xj47uy)lM_i(KLi)b7FS&e zS>+69c)C^)=df zSD!fw8_F`2ulQ0yF9HTWzp;xyzjBaxJjRy$zM3z{zK=16Y&JVbJDNx&LaH^zQ&0W` zFq}AXg5UT2j=H*f+ES~?IriEuTfV$%@7|XO^1@jlzNMxy24f7}U)oGdONt*q^#tj3 znp`f&=;$bp;}oZD+l-Bk5sgOiJdd6idU*3MZ}Q38K1Ew<72$B0_7At$DJy(m8QV)y zLyOuM!FD_buVnxTCmQJN>gMM=pW%*<4mNgfWOQ^C*L4YnLd4^7Mn*^3{j2907&u2~ z$9iJXcrj!EjSUUj3Ix6YJXyx}k}n;L`WNb&n|QouVS~S#{{8RJ_pcK?^6*252on<% z?AZM*?_Ko>wXTQQBwA~<*7N=ui^UM+Lkk%aFj6e86-Gm20}YMk`tFZ%F*D4g-}@1% zrbfi`qI>gOU zQ&UsYB?f~*W@ct4fe_$W1yF&h$($p;OWUp0ogQXva7NQSxNZ9)slw-ppYDPghx+<@ zCMPH7-FH0~W6V%qp?NUVfSta0{0F;sKKp%3TQM-prb&Q1KcSPcSWIOynUed7M1rxA zD}G(FmOvn&LZQ%XnXoL*p8bzIo}PH4fCCFi17_sRTfHM^-uegmqphxnr8`ph|9Wt6 z@UwwHprnuTeV-M{nA5r8a~7b&;qW~D^c{P9WbFFbi-21&GCq(4CV?p+Q@GA7cP49+ z{ewdn?rQ(Y>d5%`IGIeQIMeAg#u&@@ecjrc!m=zZ%OV<$a(>{PcjU;CR}LIFxDW7H zz=RLX08Rnma_98Gz`)g(*5=@uGwiFe3y+H*MO~wX(VKQ6xr-z4!M*zDJo#_t>&}? + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.cbConcurrent = new System.Windows.Forms.CheckBox(); + this.cbInterval = new System.Windows.Forms.CheckBox(); + this.cbLogging = new System.Windows.Forms.CheckBox(); + this.label1 = new System.Windows.Forms.Label(); + this.txtConcurrent = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.txtNumer = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.txtPeriod = new System.Windows.Forms.TextBox(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // cbConcurrent + // + this.cbConcurrent.AutoSize = true; + this.cbConcurrent.Location = new System.Drawing.Point(31, 22); + this.cbConcurrent.Name = "cbConcurrent"; + this.cbConcurrent.Size = new System.Drawing.Size(317, 17); + this.cbConcurrent.TabIndex = 0; + this.cbConcurrent.Text = "Deny IP Address based on the number of concurrent requests"; + this.cbConcurrent.UseVisualStyleBackColor = true; + // + // cbInterval + // + this.cbInterval.AutoSize = true; + this.cbInterval.Location = new System.Drawing.Point(31, 141); + this.cbInterval.Name = "cbInterval"; + this.cbInterval.Size = new System.Drawing.Size(362, 17); + this.cbInterval.TabIndex = 1; + this.cbInterval.Text = "Deny IP Address based on the number of requests over a period of time"; + this.cbInterval.UseVisualStyleBackColor = true; + // + // cbLogging + // + this.cbLogging.AutoSize = true; + this.cbLogging.Location = new System.Drawing.Point(31, 298); + this.cbLogging.Name = "cbLogging"; + this.cbLogging.Size = new System.Drawing.Size(154, 17); + this.cbLogging.TabIndex = 2; + this.cbLogging.Text = "Enable Logging Only Mode"; + this.cbLogging.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(56, 56); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(201, 13); + this.label1.TabIndex = 3; + this.label1.Text = "Maximum number of concurrent requests:"; + // + // txtConcurrent + // + this.txtConcurrent.Enabled = false; + this.txtConcurrent.Location = new System.Drawing.Point(59, 81); + this.txtConcurrent.Name = "txtConcurrent"; + this.txtConcurrent.Size = new System.Drawing.Size(140, 20); + this.txtConcurrent.TabIndex = 4; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(56, 173); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(147, 13); + this.label2.TabIndex = 5; + this.label2.Text = "Maximum number of requests:"; + // + // txtNumer + // + this.txtNumer.Enabled = false; + this.txtNumer.Location = new System.Drawing.Point(59, 199); + this.txtNumer.Name = "txtNumer"; + this.txtNumer.Size = new System.Drawing.Size(140, 20); + this.txtNumer.TabIndex = 6; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(56, 235); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(142, 13); + this.label3.TabIndex = 7; + this.label3.Text = "Time Period (in milliseconds):"; + // + // txtPeriod + // + this.txtPeriod.Enabled = false; + this.txtPeriod.Location = new System.Drawing.Point(59, 262); + this.txtPeriod.Name = "txtPeriod"; + this.txtPeriod.Size = new System.Drawing.Size(140, 20); + this.txtPeriod.TabIndex = 8; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(442, 356); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 9; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(346, 356); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 10; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // DynamicDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(549, 391); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.txtPeriod); + this.Controls.Add(this.label3); + this.Controls.Add(this.txtNumer); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtConcurrent); + this.Controls.Add(this.label1); + this.Controls.Add(this.cbLogging); + this.Controls.Add(this.cbInterval); + this.Controls.Add(this.cbConcurrent); + this.Name = "DynamicDialog"; + this.Text = "Dynamic IP Restriction Settings"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.DynamicDialog_HelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private CheckBox cbConcurrent; + private CheckBox cbInterval; + private CheckBox cbLogging; + private Label label1; + private TextBox txtConcurrent; + private Label label2; + private TextBox txtNumer; + private Label label3; + private TextBox txtPeriod; + private Button btnCancel; + private Button btnOK; + } +} diff --git a/JexusManager.Features.IpSecurity/DynamicDialog.cs b/JexusManager.Features.IpSecurity/DynamicDialog.cs new file mode 100644 index 00000000..1be6efb5 --- /dev/null +++ b/JexusManager.Features.IpSecurity/DynamicDialog.cs @@ -0,0 +1,107 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IpSecurity +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client.Win32; + + public partial class DynamicDialog : DialogForm + { + public DynamicDialog(IServiceProvider serviceProvider, ConfigurationSection section) + : base(serviceProvider) + { + InitializeComponent(); + var concurrent = section.ChildElements["denyByConcurrentRequests"]; + cbConcurrent.Checked = (bool)concurrent["enabled"]; + txtConcurrent.Text = concurrent["maxConcurrentRequests"].ToString(); + var rate = section.ChildElements["denyByRequestRate"]; + cbInterval.Checked = (bool)rate["enabled"]; + txtNumer.Text = rate["maxRequests"].ToString(); + txtPeriod.Text = rate["requestIntervalInMilliseconds"].ToString(); + cbLogging.Checked = (bool)section["enableLoggingOnlyMode"]; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + var load = Observable.FromEventPattern(this, "Load"); + + container.Add( + Observable.FromEventPattern(cbInterval, "CheckedChanged") + .Merge(load) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + txtPeriod.Enabled = txtNumer.Enabled = cbInterval.Checked; + })); + + container.Add( + Observable.FromEventPattern(cbConcurrent, "CheckedChanged") + .Merge(load) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + txtConcurrent.Enabled = cbConcurrent.Checked; + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + uint result; + if (!uint.TryParse(txtConcurrent.Text, out result)) + { + ShowMessage( + "Input string was not in a correct format", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + concurrent["enabled"] = cbConcurrent.Checked; + concurrent["maxConcurrentRequests"] = result; + rate["enabled"] = cbInterval.Checked; + if (!uint.TryParse(txtNumer.Text, out result)) + { + // TODO: show validator error. + ShowMessage( + "Input string was not in a correct format", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + rate["maxRequests"] = result; + if (!uint.TryParse(txtNumer.Text, out result)) + { + // TODO: show validator error. + ShowMessage( + "Input string was not in a correct format", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + rate["requestIntervalInMilliseconds"] = result; + section["enableLoggingOnlyMode"] = cbLogging.Checked; + DialogResult = DialogResult.OK; + })); + } + + private void DynamicDialog_HelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210513"); + } + } +} diff --git a/JexusManager.Features.IpSecurity/DynamicDialog.resx b/JexusManager.Features.IpSecurity/DynamicDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.IpSecurity/DynamicDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.IpSecurity/IpSecurityFeature.cs b/JexusManager.Features.IpSecurity/IpSecurityFeature.cs new file mode 100644 index 00000000..99519c92 --- /dev/null +++ b/JexusManager.Features.IpSecurity/IpSecurityFeature.cs @@ -0,0 +1,259 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/* + * Created by SharpDevelop. + * User: lextm + * Time: 11:06 AM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace JexusManager.Features.IpSecurity +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + using Microsoft.Web.Management.Server; + + using Module = Microsoft.Web.Management.Client.Module; + + /// + /// Description of DefaultDocumentFeature. + /// + internal class IpSecurityFeature : FeatureBase + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly IpSecurityFeature _owner; + + public FeatureTaskList(IpSecurityFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("AddAllow", "Add Allow Entry...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("AddDeny", "Add Deny Entry...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); // IMPORTANT: this is where IIS Manager was wrong + result.Add(new MethodTaskItem("Set", "Edit Feature Settings...", string.Empty).SetUsage()); + if (_owner.CanRevert) + { + result.Add(new MethodTaskItem("Revert", "Revert To Parent", string.Empty).SetUsage()); + } + + result.Add(new MethodTaskItem("View", "View Ordered List...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Dynamic", "Edit Dynamic Restriction Settings...", string.Empty).SetUsage()); + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void AddAllow() + { + _owner.AddAllow(); + } + + [Obfuscation(Exclude = true)] + public void AddDeny() + { + _owner.AddDeny(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void Set() + { + _owner.Set(); + } + + [Obfuscation(Exclude = true)] + public void Revert() + { + _owner.Revert(); + } + + [Obfuscation(Exclude = true)] + public void View() + { + _owner.View(); + } + [Obfuscation(Exclude = true)] + public void Dynamic() + { + _owner.Dynamic(); + } + } + + public IpSecurityFeature(Module module) + : base(module) + { + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + CanRevert = service.Scope != ManagementScope.Server; + LoadItems(); + } + + public void AddAllow() + { + var dialog = new NewRestrictionDialog(Module, true, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void AddDeny() + { + var dialog = new NewRestrictionDialog(Module, false, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Remove() + { + var dialog = (IManagementUIService)GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected restriction?", Name, + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + public void Revert() + { + if (!CanRevert) + { + throw new InvalidOperationException("Revert operation cannot be done at server level"); + } + + var dialog = (IManagementUIService)GetService(typeof(IManagementUIService)); + var result = + dialog.ShowMessage( + "Reverting to the parent configuration will result in the loss of all settings in the local configuration file for this feature. Are you sure you want to continue?", + Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + + RevertItems(); + } + + public void Set() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/security/ipSecurity"); + var dialog = new SetRestrictionsDialog(Module, section); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + service.ServerManager.CommitChanges(); + } + + public void View() + { + } + + public void Dynamic() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/security/dynamicIpSecurity"); + if (section == null) + { + // TODO: display a friendly error message. + return; + } + + var dialog = new DynamicDialog(Module, section); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + service.ServerManager.CommitChanges(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + ConfigurationSection section = service.GetSection("system.webServer/security/ipSecurity", null, false); + return section.GetCollection(); + } + + protected override void OnSettingsSaved() + { + IpSecuritySettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210513"); + return false; + } + + public bool CanRevert { get; private set; } + + public IpSecuritySettingsSavedEventHandler IpSecuritySettingsUpdated { get; set; } + public string Description { get; } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public string Name + { + get { return "IP Address and Domain Restrictions"; } + } + } +} diff --git a/JexusManager.Features.IpSecurity/IpSecurityItem.cs b/JexusManager.Features.IpSecurity/IpSecurityItem.cs new file mode 100644 index 00000000..3a640ef9 --- /dev/null +++ b/JexusManager.Features.IpSecurity/IpSecurityItem.cs @@ -0,0 +1,49 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IpSecurity +{ + using Microsoft.Web.Administration; + + internal class IpSecurityItem : IItem + { + public IpSecurityItem(ConfigurationElement element) + { + Element = element; + Flag = element == null || element.IsLocallyStored ? "Local" : "Inherited"; + if (element == null) + { + Mask = "255.255.255.255"; + return; + } + + Address = (string)element["ipAddress"]; + Mask = (string)element["subnetMask"]; + this.Allowed = (bool)element["allowed"]; + } + + public ConfigurationElement Element { get; set; } + public string Address { get; set; } + public string Mask { get; set; } + public bool Allowed { get; set; } + public string Flag { get; set; } + + public void Apply() + { + Element["ipAddress"] = Address; + Element["subnetMask"] = Mask; + Element["allowed"] = this.Allowed; + } + + public bool Equals(IpSecurityItem other) + { + return other != null && other.Address == Address && other.Mask == Mask && other.Allowed == this.Allowed; + } + + public bool Match(IpSecurityItem other) + { + return other != null && other.Address == Address && other.Mask == Mask; + } + } +} diff --git a/JexusManager.Features.IpSecurity/IpSecurityModule.cs b/JexusManager.Features.IpSecurity/IpSecurityModule.cs new file mode 100644 index 00000000..07f278e1 --- /dev/null +++ b/JexusManager.Features.IpSecurity/IpSecurityModule.cs @@ -0,0 +1,26 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IpSecurity +{ + using System; + + using Properties; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + + internal class IpSecurityModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(IpSecurityPage), "IP Address and Domain Restrictions", + "Restrict or grant access to Web content based on IP addresses or domain names", Resources.ip_restriction_36, + Resources.ip_restriction_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.IpSecurity/IpSecurityModuleProvider.cs b/JexusManager.Features.IpSecurity/IpSecurityModuleProvider.cs new file mode 100644 index 00000000..9558dac2 --- /dev/null +++ b/JexusManager.Features.IpSecurity/IpSecurityModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IpSecurity +{ + using System; + + using Microsoft.Web.Management.Server; + + public class IpSecurityModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(Name, typeof(IpSecurityModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.IpSecurity/IpSecurityPage.Designer.cs b/JexusManager.Features.IpSecurity/IpSecurityPage.Designer.cs new file mode 100644 index 00000000..f77beb13 --- /dev/null +++ b/JexusManager.Features.IpSecurity/IpSecurityPage.Designer.cs @@ -0,0 +1,290 @@ +namespace JexusManager.Features.IpSecurity +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class IpSecurityPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chMode = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chRequestor = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.toolStrip2 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel2 = new System.Windows.Forms.ToolStripLabel(); + this.cbGroup = new System.Windows.Forms.ToolStripComboBox(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.toolStrip2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 6; + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.toolStrip2); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 6; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chMode, + this.chRequestor, + this.chType}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 38); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 502); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.listView1_SelectedIndexChanged); + // + // chMode + // + this.chMode.Text = "Mode"; + this.chMode.Width = 80; + // + // chRequestor + // + this.chRequestor.Text = "Requestor"; + this.chRequestor.Width = 150; + // + // chType + // + this.chType.Text = "Entry Type"; + this.chType.Width = 120; + // + // toolStrip2 + // + this.toolStrip2.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel2, + this.cbGroup}); + this.toolStrip2.Location = new System.Drawing.Point(0, 13); + this.toolStrip2.Name = "toolStrip2"; + this.toolStrip2.Size = new System.Drawing.Size(560, 25); + this.toolStrip2.TabIndex = 3; + this.toolStrip2.Text = "toolStrip2"; + // + // toolStripLabel2 + // + this.toolStripLabel2.Name = "toolStripLabel2"; + this.toolStripLabel2.Size = new System.Drawing.Size(59, 22); + this.toolStripLabel2.Text = "Group by:"; + // + // cbGroup + // + this.cbGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbGroup.Items.AddRange(new object[] { + "No Grouping", + "Status", + "IP Address", + "Protocol", + "Port"}); + this.cbGroup.Name = "cbGroup"; + this.cbGroup.Size = new System.Drawing.Size(121, 25); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(653, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to restrict or grant access to Web content based on IP addresses" + + " or domain names. Set the restrictions in order of priority."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 5; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(356, 25); + this.label3.TabIndex = 2; + this.label3.Text = "IP Address and Domain Restrictions"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // IpSecurityPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "IpSecurityPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.toolStrip2.ResumeLayout(false); + this.toolStrip2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private ListView listView1; + private ColumnHeader chMode; + private ColumnHeader chRequestor; + private ColumnHeader chType; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Panel panel2; + private ToolStrip toolStrip2; + private ToolStripLabel toolStripLabel2; + private ToolStripComboBox cbGroup; + private PictureBox pictureBox1; + private ContextMenuStrip cmsActionPanel; + } +} diff --git a/JexusManager.Features.IpSecurity/IpSecurityPage.cs b/JexusManager.Features.IpSecurity/IpSecurityPage.cs new file mode 100644 index 00000000..01516bd4 --- /dev/null +++ b/JexusManager.Features.IpSecurity/IpSecurityPage.cs @@ -0,0 +1,129 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IpSecurity +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class IpSecurityPage : ModuleListPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly IpSecurityPage _owner; + + public PageTaskList(IpSecurityPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class IpSecurityListViewItem : ListViewItem + { + public IpSecurityItem Item { get; } + private readonly IpSecurityPage _page; + + public IpSecurityListViewItem(IpSecurityItem item, IpSecurityPage page) + : base(item.Allowed ? "Allow" : "Deny") + { + Item = item; + _page = page; + SubItems.Add(new ListViewSubItem(this, item.Mask == string.Empty ? item.Address : string.Format("{0}({1})", item.Address, item.Mask))); + SubItems.Add(new ListViewSubItem(this, item.Flag)); + } + } + + private IpSecurityFeature _feature; + private PageTaskList _taskList; + + public IpSecurityPage() + { + InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new IpSecurityFeature(Module); + _feature.IpSecuritySettingsUpdated = InitializeListPage; + _feature.Load(); + } + + protected override void InitializeListPage() + { + listView1.Items.Clear(); + foreach (var file in _feature.Items) + { + listView1.Items.Add(new IpSecurityListViewItem(file, this)); + } + + if (_feature.SelectedItem == null) + { + Refresh(); + return; + } + + foreach (IpSecurityListViewItem item in listView1.Items) + { + if (item.Item == _feature.SelectedItem) + { + item.Selected = true; + } + } + } + + protected override void Refresh() + { + Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + private void listView1_SelectedIndexChanged(object sender, EventArgs e) + { + _feature.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((IpSecurityListViewItem)listView1.SelectedItems[0]).Item + : null; + // TODO: optimize refresh when null to not null (vice versa) + Refresh(); + } + + protected override bool ShowHelp() + { + _feature.ShowHelp(); + return true; + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + } +} diff --git a/JexusManager.Features.IpSecurity/IpSecurityPage.resx b/JexusManager.Features.IpSecurity/IpSecurityPage.resx new file mode 100644 index 00000000..464d127c --- /dev/null +++ b/JexusManager.Features.IpSecurity/IpSecurityPage.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 602, 17 + + + 497, 17 + + + 17, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.IpSecurity/IpSecuritySettingsSavedEventHandler.cs b/JexusManager.Features.IpSecurity/IpSecuritySettingsSavedEventHandler.cs new file mode 100644 index 00000000..003f3509 --- /dev/null +++ b/JexusManager.Features.IpSecurity/IpSecuritySettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IpSecurity +{ + public delegate void IpSecuritySettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.IpSecurity/JexusManager.Features.IpSecurity.csproj b/JexusManager.Features.IpSecurity/JexusManager.Features.IpSecurity.csproj new file mode 100644 index 00000000..90946f04 --- /dev/null +++ b/JexusManager.Features.IpSecurity/JexusManager.Features.IpSecurity.csproj @@ -0,0 +1,148 @@ + + + + + Debug + AnyCPU + {361E2F47-289F-480F-B976-A6E3F7D96EDC} + Library + Properties + JexusManager.Features.IpSecurity + JexusManager.Features.IpSecurity + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + Form + + + DynamicDialog.cs + + + + + + + UserControl + + + IpSecurityPage.cs + + + + Form + + + NewRestrictionDialog.cs + + + + True + True + Resources.resx + + + Form + + + SetRestrictionsDialog.cs + + + + + DynamicDialog.cs + + + IpSecurityPage.cs + + + NewRestrictionDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SetRestrictionsDialog.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.IpSecurity/JexusManager.snk b/JexusManager.Features.IpSecurity/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.IpSecurity/NewRestrictionDialog.Designer.cs b/JexusManager.Features.IpSecurity/NewRestrictionDialog.Designer.cs new file mode 100644 index 00000000..869d5a10 --- /dev/null +++ b/JexusManager.Features.IpSecurity/NewRestrictionDialog.Designer.cs @@ -0,0 +1,170 @@ +namespace JexusManager.Features.IpSecurity +{ + using System.ComponentModel; + using System.Windows.Forms; + + sealed partial class NewRestrictionDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.txtDescription = new System.Windows.Forms.Label(); + this.rbAddress = new System.Windows.Forms.RadioButton(); + this.rbRange = new System.Windows.Forms.RadioButton(); + this.txtAddress = new System.Windows.Forms.TextBox(); + this.txtRange = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.txtMask = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(327, 336); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(226, 336); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // txtDescription + // + this.txtDescription.AutoSize = true; + this.txtDescription.Location = new System.Drawing.Point(12, 9); + this.txtDescription.Name = "txtDescription"; + this.txtDescription.Size = new System.Drawing.Size(280, 13); + this.txtDescription.TabIndex = 2; + this.txtDescription.Text = "Allow access for the following IP address or domain name:"; + // + // rbAddress + // + this.rbAddress.AutoSize = true; + this.rbAddress.Checked = true; + this.rbAddress.Location = new System.Drawing.Point(15, 34); + this.rbAddress.Name = "rbAddress"; + this.rbAddress.Size = new System.Drawing.Size(116, 17); + this.rbAddress.TabIndex = 3; + this.rbAddress.TabStop = true; + this.rbAddress.Text = "Specify IP address:"; + this.rbAddress.UseVisualStyleBackColor = true; + // + // rbRange + // + this.rbRange.AutoSize = true; + this.rbRange.Location = new System.Drawing.Point(15, 92); + this.rbRange.Name = "rbRange"; + this.rbRange.Size = new System.Drawing.Size(108, 17); + this.rbRange.TabIndex = 4; + this.rbRange.Text = "IP address range:"; + this.rbRange.UseVisualStyleBackColor = true; + // + // txtAddress + // + this.txtAddress.Location = new System.Drawing.Point(33, 57); + this.txtAddress.Name = "txtAddress"; + this.txtAddress.Size = new System.Drawing.Size(314, 20); + this.txtAddress.TabIndex = 5; + // + // txtRange + // + this.txtRange.Enabled = false; + this.txtRange.Location = new System.Drawing.Point(33, 125); + this.txtRange.Name = "txtRange"; + this.txtRange.Size = new System.Drawing.Size(314, 20); + this.txtRange.TabIndex = 6; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(33, 164); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(77, 13); + this.label2.TabIndex = 7; + this.label2.Text = "Mask or Prefix:"; + // + // txtMask + // + this.txtMask.Enabled = false; + this.txtMask.Location = new System.Drawing.Point(33, 192); + this.txtMask.Name = "txtMask"; + this.txtMask.Size = new System.Drawing.Size(314, 20); + this.txtMask.TabIndex = 8; + // + // NewRestrictionDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(434, 371); + this.Controls.Add(this.txtMask); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtRange); + this.Controls.Add(this.txtAddress); + this.Controls.Add(this.rbRange); + this.Controls.Add(this.rbAddress); + this.Controls.Add(this.txtDescription); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; + this.HelpButton = true; + this.MaximizeBox = false; + this.MinimizeBox = false; + this.Name = "NewRestrictionDialog"; + this.ShowIcon = false; + this.ShowInTaskbar = false; + this.StartPosition = System.Windows.Forms.FormStartPosition.CenterParent; + this.Text = "Add Allow Restriction Rule"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewRestrictionDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label txtDescription; + private RadioButton rbAddress; + private RadioButton rbRange; + private TextBox txtAddress; + private TextBox txtRange; + private Label label2; + private TextBox txtMask; + } +} diff --git a/JexusManager.Features.IpSecurity/NewRestrictionDialog.cs b/JexusManager.Features.IpSecurity/NewRestrictionDialog.cs new file mode 100644 index 00000000..890c06b6 --- /dev/null +++ b/JexusManager.Features.IpSecurity/NewRestrictionDialog.cs @@ -0,0 +1,135 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IpSecurity +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Net; + using System.Net.Sockets; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewRestrictionDialog : DialogForm + { + public NewRestrictionDialog(IServiceProvider serviceProvider, bool allowed, IpSecurityFeature feature) + : base(serviceProvider) + { + InitializeComponent(); + Text = allowed ? "Add Allow Restriction Rule" : "Add Deny Restriction Rule"; + txtDescription.Text = allowed + ? "Allow access for the following IP address or domain name:" + : "Deny access for the following IP address or domain name:"; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(rbAddress, "CheckedChanged") + .Merge(Observable.FromEventPattern(rbRange, "CheckedChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + txtAddress.Enabled = rbAddress.Checked; + txtRange.Enabled = rbRange.Checked; + txtMask.Enabled = rbRange.Checked; + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + if (rbAddress.Checked) + { + IPAddress result; + var passed = IPAddress.TryParse(txtAddress.Text, out result); + if (!passed) + { + MessageBox.Show(string.Format("'{0}' is an invalid IP address.", txtAddress.Text), Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation); + return; + } + + Item = new IpSecurityItem(null); + Item.Address = txtAddress.Text; + Item.Mask = string.Empty; + Item.Allowed = allowed; + if (feature.Items.Any(item => item.Match(Item))) + { + ShowMessage( + "A restriction for this domain name or IP address already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + DialogResult = DialogResult.OK; + return; + } + + IPAddress result1; + var passed1 = IPAddress.TryParse(txtRange.Text, out result1); + if (!passed1) + { + ShowMessage( + string.Format("'{0}' is an invalid IP address.", txtRange.Text), + MessageBoxButtons.OK, + MessageBoxIcon.Exclamation, + MessageBoxDefaultButton.Button1); + return; + } + + var passed2 = IPAddress.TryParse(txtMask.Text, out result1); + if (!passed2) + { + int value; + var passed3 = int.TryParse(txtMask.Text, out value); + if (!passed3 || + (result1.AddressFamily == AddressFamily.InterNetwork + && (value < 0 || value > 32)) || + (result1.AddressFamily == AddressFamily.InterNetworkV6 + && (value < 0 || value > 128))) + { + ShowMessage( + string.Format( + "'{0}' is an invalid subnet mask. It must be a valid IP address or an integer value between 0-32 for IPv4 ad 0-128 for IPv6.", + txtMask.Text), + MessageBoxButtons.OK, + MessageBoxIcon.Exclamation, + MessageBoxDefaultButton.Button1); + return; + } + } + + Item = new IpSecurityItem(null); + Item.Address = txtRange.Text; + Item.Mask = txtMask.Text; + Item.Allowed = allowed; + if (feature.Items.Any(item => item.Match(Item))) + { + ShowMessage( + "A restriction for this domain name or IP address already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + DialogResult = DialogResult.OK; + })); + } + + public IpSecurityItem Item { get; set; } + + private void NewRestrictionDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210513"); + } + } +} diff --git a/JexusManager.Features.IpSecurity/NewRestrictionDialog.resx b/JexusManager.Features.IpSecurity/NewRestrictionDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.IpSecurity/NewRestrictionDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.IpSecurity/Properties/AssemblyInfo.cs b/JexusManager.Features.IpSecurity/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..44e4bfa6 --- /dev/null +++ b/JexusManager.Features.IpSecurity/Properties/AssemblyInfo.cs @@ -0,0 +1,46 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.IpSecurity")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.IpSecurity")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("361e2f47-289f-480f-b976-a6e3f7d96edc")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("Tests.JexusManager, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] diff --git a/JexusManager.Features.IpSecurity/Properties/Resources.Designer.cs b/JexusManager.Features.IpSecurity/Properties/Resources.Designer.cs new file mode 100644 index 00000000..f6dfe2ed --- /dev/null +++ b/JexusManager.Features.IpSecurity/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.IpSecurity.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.IpSecurity.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap ip_restriction_36 { + get { + object obj = ResourceManager.GetObject("ip_restriction_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.IpSecurity/Properties/Resources.resx b/JexusManager.Features.IpSecurity/Properties/Resources.resx new file mode 100644 index 00000000..7b5dda3b --- /dev/null +++ b/JexusManager.Features.IpSecurity/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\ip_restriction_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.IpSecurity/Resources/ip_restriction_36.png b/JexusManager.Features.IpSecurity/Resources/ip_restriction_36.png new file mode 100644 index 0000000000000000000000000000000000000000..641bbbd63125eb61bec5165101b5f0b9fbd266f8 GIT binary patch literal 2210 zcmV;T2wnGyP)VGd000McNliru-UJv76EMo*h7|w+2ro%Q zK~z}7?U-9^9mN@dznPu0>vNoA;#^6bCUzPyt{tdS3Y4@Ek@ks3rcI-u))Xs&h$2)} zAxkYU<*7)9(v((hlt5&O+(bozv|Oqr2qz>_QK6-QP=gbj_!h^8)xNbV-d0HOTU< z`X$o?wY9aecJ11)S5;O0>XAntshmpiz<~pI@7c2_wSD{c2PdS}%8$M^jy zw=$E-(Ae0>u3fv<0uz9w5PW!Q7$ptXf)EkQ68(7QEI1Yt=Y!s}&z->ceb%j8_Yoig z;d$OkDdhu?J@(i?6+kQ&S@B9JkL?(XhscWAPs zCkO)WxTBHpt#z=B1;5Rkf6d6qS>`NR&hvl%QFYrzCzK+KW+>Gk(``0n}mfrcQ* z$7e?Q#WROdQWU*0hy*KVtD+_pfa5rHbaYG$luoCqsi~RJS5{Vb?@ucXuI#)^sx zthG3fGd>UG1C8goF#aJzO7eb4OgWgy5QGtD(*evrf8I^7p;@zLO=?3I9*~6+hGFF` zx7^aWYSpS@pXYfTJ9Z4Pq%%I1b7mIb^?Z^io%Kqrbm@ zN*mHzUlczE2M4c6CX)yu&{|Va|M(~HaVpDb#wX{8NGTZlWR!uSQDVyB{8R#K%|sw$ z47IhjXsrpukfEWW;sT|fb^%aXXJ=<+M@L6iYn{+qqm)8QiImbxDMVNQS-#rzo8o{d zG8e!A7Ho+IWI#kHP)t#uQSo4MIYOOr)osp4|SB){up1+7SwMQ_Kp7t;`#_*+UzlPS~d7vnY zxccg=85kH~(V|6UG8wG3xUP%ijJa_#Iq?d!6ZkF6i^DgD_U-%fXkTCDH;*5$KMLYO zrC3_Cgr7Xrf)IjBU2Tmq{Q0GqP)eZ+p?t=S87yAB7;7y`DPpl$G0ZEa2*a>=6#;k( z?pv5lK6=d!Hzb^yGhJg0D;gT=|MJ#b8|Urc|7QEjmDjJRtCOW(TBxPZ0H;r%=Dl~{ zZFgPwoGKjIGPlchJHaQdm zW6Yap&YU@|j4_G#-+zCCj-`~m{r1}kA&PA&CC|P5GD#hQQdk>J?KOar;2F(}d-f~> z$}W*VSReu-)!p6Q+1A!}yYKs6!GoqMgPxb!QRY2s^7#tN%lT-<3TzZ%jlp6uW=#8{ ztPC53U^!Pv;XZAyr&6iZU@Db*18_f0ZfMHN_U8Pc$tp$I-8~jSvDopn$6AYZB!P|) z*1mAL$!EdKMn3HTlh3!F9vxX%wP2y=cb*vYumXrN7_Cu@syLJP{d^ESak)V9a)fsP z--lyeCr>_fc65~Z^ + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.cbAccess = new System.Windows.Forms.ComboBox(); + this.cbDomain = new System.Windows.Forms.CheckBox(); + this.cbProxy = new System.Windows.Forms.CheckBox(); + this.label2 = new System.Windows.Forms.Label(); + this.cbAction = new System.Windows.Forms.ComboBox(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(242, 201); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(146, 201); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(150, 13); + this.label1.TabIndex = 2; + this.label1.Text = "Access for unspecified clients:"; + // + // cbAccess + // + this.cbAccess.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbAccess.FormattingEnabled = true; + this.cbAccess.Items.AddRange(new object[] { + "Allow", + "Deny"}); + this.cbAccess.Location = new System.Drawing.Point(12, 25); + this.cbAccess.Name = "cbAccess"; + this.cbAccess.Size = new System.Drawing.Size(224, 21); + this.cbAccess.TabIndex = 3; + // + // cbDomain + // + this.cbDomain.AutoSize = true; + this.cbDomain.Location = new System.Drawing.Point(12, 64); + this.cbDomain.Name = "cbDomain"; + this.cbDomain.Size = new System.Drawing.Size(149, 17); + this.cbDomain.TabIndex = 4; + this.cbDomain.Text = "Enable domain restrictions"; + this.cbDomain.UseVisualStyleBackColor = true; + // + // cbProxy + // + this.cbProxy.AutoSize = true; + this.cbProxy.Location = new System.Drawing.Point(12, 96); + this.cbProxy.Name = "cbProxy"; + this.cbProxy.Size = new System.Drawing.Size(118, 17); + this.cbProxy.TabIndex = 5; + this.cbProxy.Text = "Enable Proxy Mode"; + this.cbProxy.UseVisualStyleBackColor = true; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 131); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(95, 13); + this.label2.TabIndex = 6; + this.label2.Text = "Deny Action Type:"; + // + // cbAction + // + this.cbAction.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbAction.FormattingEnabled = true; + this.cbAction.Items.AddRange(new object[] { + "Unauthorized", + "Forbidden", + "Not Found", + "Abort"}); + this.cbAction.Location = new System.Drawing.Point(12, 147); + this.cbAction.Name = "cbAction"; + this.cbAction.Size = new System.Drawing.Size(178, 21); + this.cbAction.TabIndex = 7; + // + // SetRestrictionsDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(349, 236); + this.Controls.Add(this.cbAction); + this.Controls.Add(this.label2); + this.Controls.Add(this.cbProxy); + this.Controls.Add(this.cbDomain); + this.Controls.Add(this.cbAccess); + this.Controls.Add(this.label1); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "SetRestrictionsDialog"; + this.Text = "Edit IP and Domain Restrictions Settings"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.SetRestrictionsDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label label1; + private ComboBox cbAccess; + private CheckBox cbDomain; + private CheckBox cbProxy; + private Label label2; + private ComboBox cbAction; + } +} diff --git a/JexusManager.Features.IpSecurity/SetRestrictionsDialog.cs b/JexusManager.Features.IpSecurity/SetRestrictionsDialog.cs new file mode 100644 index 00000000..2a99c81f --- /dev/null +++ b/JexusManager.Features.IpSecurity/SetRestrictionsDialog.cs @@ -0,0 +1,96 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IpSecurity +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client.Win32; + + public partial class SetRestrictionsDialog : DialogForm + { + public SetRestrictionsDialog(IServiceProvider serviceProvider, ConfigurationSection section) + : base(serviceProvider) + { + InitializeComponent(); + cbDomain.Checked = (bool)section["enableReverseDns"]; + cbAccess.SelectedIndex = (bool)section["allowUnlisted"] ? 0 : 1; + cbProxy.Enabled = section.Schema.AttributeSchemas["enabled"] != null; + if (cbProxy.Enabled) + { + cbProxy.Checked = (bool)section["enableProxyMode"]; + } + + cbAction.Enabled = section.Schema.AttributeSchemas["denyAction"] != null; + if (cbAction.Enabled) + { + var action = (long)section["denyAction"]; + if (action == 0L) + { + cbAction.SelectedIndex = 0; + } + else if (action == 401L) + { + cbAction.SelectedIndex = 1; + } + else if (action == 403L) + { + cbAction.SelectedIndex = 2; + } + else + { + cbAction.SelectedIndex = 3; + } + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + section["enableReverseDns"] = cbDomain.Checked; + section["allowUnlisted"] = cbAccess.SelectedIndex == 0; + if (cbProxy.Enabled) + { + section["enableProxyMode"] = cbProxy.Checked; + } + + if (cbAction.Enabled) + { + if (cbAction.SelectedIndex == 0) + { + section["denyAction"] = 0L; + } + else if (cbAction.SelectedIndex == 1) + { + section["denyAction"] = 401L; + } + else if (cbAction.SelectedIndex == 2) + { + section["denyAction"] = 403L; + } + else + { + section["denyAction"] = 404L; + } + } + + DialogResult = DialogResult.OK; + })); + } + + private void SetRestrictionsDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210513"); + } + } +} diff --git a/JexusManager.Features.IpSecurity/SetRestrictionsDialog.resx b/JexusManager.Features.IpSecurity/SetRestrictionsDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.IpSecurity/SetRestrictionsDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.IpSecurity/packages.config b/JexusManager.Features.IpSecurity/packages.config new file mode 100644 index 00000000..571e4fe0 --- /dev/null +++ b/JexusManager.Features.IpSecurity/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionFeature.cs b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionFeature.cs new file mode 100644 index 00000000..4c391a94 --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionFeature.cs @@ -0,0 +1,227 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/* + * Created by SharpDevelop. + * User: lextm + * Time: 11:06 AM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace JexusManager.Features.IsapiCgiRestriction +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + /// + /// Description of DefaultDocumentFeature. + /// + internal class IsapiCgiRestrictionFeature : FeatureBase + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly IsapiCgiRestrictionFeature _owner; + + public FeatureTaskList(IsapiCgiRestrictionFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("Add", "Add...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + if (_owner.SelectedItem.Allowed) + { + result.Add(new MethodTaskItem("Deny", "Deny...", string.Empty).SetUsage()); + } + else + { + result.Add(new MethodTaskItem("Allow", "Allow...", string.Empty).SetUsage()); + } + + result.Add(new MethodTaskItem("Edit", "Edit...", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Set", "Edit Feature Settings...", string.Empty).SetUsage()); + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Add() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void Edit() + { + _owner.Edit(); + } + + [Obfuscation(Exclude = true)] + public void Set() + { + _owner.Set(); + } + + [Obfuscation(Exclude = true)] + public void Deny() + { + _owner.Deny(); + } + + [Obfuscation(Exclude = true)] + public void Allow() + { + _owner.Allow(); + } + } + + public IsapiCgiRestrictionFeature(Module module) + : base(module) + { + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + LoadItems(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + ConfigurationSection section = service.GetSection("system.webServer/security/isapiCgiRestriction", null, false); + return section.GetCollection(); + } + + public void Add() + { + var dialog = new NewRestrictionDialog(this.Module, null, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Deny() + { + SetAllowed(false); + } + + public void Allow() + { + this.SetAllowed(true); + } + + private void SetAllowed(bool allowed) + { + this.SelectedItem.Allowed = allowed; + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + service.ServerManager.CommitChanges(); + this.OnSettingsSaved(); + } + + public void Set() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/security/isapiCgiRestriction"); + var dialog = new SettingsDialog(this.Module, section); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + service.ServerManager.CommitChanges(); + this.OnSettingsSaved(); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected restriction?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + public void Edit() + { + var dialog = new NewRestrictionDialog(this.Module, this.SelectedItem, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.EditItem(dialog.Item); + } + + protected override void OnSettingsSaved() + { + this.IsapiCgiRestrictionSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210515"); + return false; + } + + public IsapiCgiRestrictionSettingsSavedEventHandler IsapiCgiRestrictionSettingsUpdated { get; set; } + + public string Description { get; } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public string Name + { + get { return "ISAPI and CGI Restrictions"; } + } + } +} diff --git a/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionItem.cs b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionItem.cs new file mode 100644 index 00000000..51d4e7a5 --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionItem.cs @@ -0,0 +1,54 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IsapiCgiRestriction +{ + using Microsoft.Web.Administration; + + internal class IsapiCgiRestrictionItem : IItem + { + public IsapiCgiRestrictionItem(ConfigurationElement element) + { + this.Element = element; + this.Flag = element == null || element.IsLocallyStored ? "Local" : "Inhertied"; + if (element == null) + { + return; + } + + this.Description = (string)element["description"]; + this.Path = (string)element["path"]; + this.Allowed = (bool)element["allowed"]; + } + + public bool Allowed { get; set; } + + public string Path { get; set; } + + public string Description { get; set; } + + public ConfigurationElement Element { get; set; } + + public string Flag { get; set; } + + public bool Equals(IsapiCgiRestrictionItem other) + { + // all properties + return this.Match(other) && other.Description == this.Description; + } + + public void Apply() + { + Element["description"] = Description; + Element["path"] = Path; + Element["allowed"] = Allowed; + } + + public bool Match(IsapiCgiRestrictionItem other) + { + // match combined keys. + return other != null && other.Path == this.Path; + } + } +} diff --git a/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionModule.cs b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionModule.cs new file mode 100644 index 00000000..09263d40 --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionModule.cs @@ -0,0 +1,26 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IsapiCgiRestriction +{ + using System; + + using Properties; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + + internal class IsapiCgiRestrictionModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)this.GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(IsapiCgiRestrictionPage), "ISAPI and CGI Restrictions", + "Restrict or enable ISAPI and CGI extensions on the Web server", Resources.isapi_cgi_restriction_36, + Resources.isapi_cgi_restriction_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionModuleProvider.cs b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionModuleProvider.cs new file mode 100644 index 00000000..bef8806f --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IsapiCgiRestriction +{ + using System; + + using Microsoft.Web.Management.Server; + + public class IsapiCgiRestrictionModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(this.Name, typeof(IsapiCgiRestrictionModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return scope == ManagementScope.Server; + } + } +} diff --git a/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionPage.Designer.cs b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionPage.Designer.cs new file mode 100644 index 00000000..4212c02d --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionPage.Designer.cs @@ -0,0 +1,290 @@ +namespace JexusManager.Features.IsapiCgiRestriction +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class IsapiCgiRestrictionPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chDescription = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chRestriction = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chPath = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.toolStrip2 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel2 = new System.Windows.Forms.ToolStripLabel(); + this.cbGroup = new System.Windows.Forms.ToolStripComboBox(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.toolStrip2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 6; + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.toolStrip2); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 6; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chDescription, + this.chRestriction, + this.chPath}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 38); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 502); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListView1SelectedIndexChanged); + // + // chDescription + // + this.chDescription.Text = "Description"; + this.chDescription.Width = 125; + // + // chRestriction + // + this.chRestriction.Text = "Restriction"; + this.chRestriction.Width = 120; + // + // chPath + // + this.chPath.Text = "Path"; + this.chPath.Width = 400; + // + // toolStrip2 + // + this.toolStrip2.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel2, + this.cbGroup}); + this.toolStrip2.Location = new System.Drawing.Point(0, 13); + this.toolStrip2.Name = "toolStrip2"; + this.toolStrip2.Size = new System.Drawing.Size(560, 25); + this.toolStrip2.TabIndex = 3; + this.toolStrip2.Text = "toolStrip2"; + // + // toolStripLabel2 + // + this.toolStripLabel2.Name = "toolStripLabel2"; + this.toolStripLabel2.Size = new System.Drawing.Size(59, 22); + this.toolStripLabel2.Text = "Group by:"; + // + // cbGroup + // + this.cbGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbGroup.Items.AddRange(new object[] { + "No Grouping", + "Status", + "IP Address", + "Protocol", + "Port"}); + this.cbGroup.Name = "cbGroup"; + this.cbGroup.Size = new System.Drawing.Size(121, 25); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(426, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to specify the ISAPI and CGI extensions that can run on the Web " + + "server."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 5; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(267, 25); + this.label3.TabIndex = 2; + this.label3.Text = "ISAPI and CGI Restrictions"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // IsapiCgiRestrictionPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "IsapiCgiRestrictionPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.toolStrip2.ResumeLayout(false); + this.toolStrip2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private ListView listView1; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Panel panel2; + private ToolStrip toolStrip2; + private ToolStripLabel toolStripLabel2; + private ToolStripComboBox cbGroup; + private PictureBox pictureBox1; + private ContextMenuStrip cmsActionPanel; + private ColumnHeader chDescription; + private ColumnHeader chRestriction; + private ColumnHeader chPath; + } +} diff --git a/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionPage.cs b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionPage.cs new file mode 100644 index 00000000..6720f156 --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionPage.cs @@ -0,0 +1,130 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IsapiCgiRestriction +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class IsapiCgiRestrictionPage : ModuleListPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly IsapiCgiRestrictionPage _owner; + + public PageTaskList(IsapiCgiRestrictionPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class IsapiCgiRestrictionListViewItem : ListViewItem + { + public IsapiCgiRestrictionItem Item { get; } + + private readonly IsapiCgiRestrictionPage _page; + + public IsapiCgiRestrictionListViewItem(IsapiCgiRestrictionItem item, IsapiCgiRestrictionPage page) + : base(item.Description) + { + this.Item = item; + _page = page; + this.SubItems.Add(new ListViewSubItem(this, item.Allowed ? "Allowed" : "Not Allowed")); + this.SubItems.Add(new ListViewSubItem(this, item.Path)); + } + } + + private IsapiCgiRestrictionFeature _feature; + private PageTaskList _taskList; + + public IsapiCgiRestrictionPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new IsapiCgiRestrictionFeature(this.Module); + _feature.IsapiCgiRestrictionSettingsUpdated = this.InitializeListPage; + _feature.Load(); + } + + protected override void InitializeListPage() + { + listView1.Items.Clear(); + foreach (var file in _feature.Items) + { + listView1.Items.Add(new IsapiCgiRestrictionListViewItem(file, this)); + } + + if (_feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (IsapiCgiRestrictionListViewItem item in listView1.Items) + { + if (item.Item == _feature.SelectedItem) + { + item.Selected = true; + } + } + } + + protected override void Refresh() + { + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + private void ListView1SelectedIndexChanged(object sender, EventArgs e) + { + _feature.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((IsapiCgiRestrictionListViewItem)listView1.SelectedItems[0]).Item + : null; + // TODO: optimize refresh when null to not null (vice versa) + this.Refresh(); + } + + protected override bool ShowHelp() + { + _feature.ShowHelp(); + return true; + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + } +} diff --git a/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionPage.resx b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionPage.resx new file mode 100644 index 00000000..7a2db0ac --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionPage.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 602, 17 + + + 497, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionSettingsSavedEventHandler.cs b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionSettingsSavedEventHandler.cs new file mode 100644 index 00000000..c0245317 --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/IsapiCgiRestrictionSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IsapiCgiRestriction +{ + public delegate void IsapiCgiRestrictionSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.IsapiCgiRestriction/JexusManager.Features.IsapiCgiRestriction.csproj b/JexusManager.Features.IsapiCgiRestriction/JexusManager.Features.IsapiCgiRestriction.csproj new file mode 100644 index 00000000..2a4acccb --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/JexusManager.Features.IsapiCgiRestriction.csproj @@ -0,0 +1,139 @@ + + + + + Debug + AnyCPU + {1571B862-8CD9-4314-9CCF-B1339D50298B} + Library + Properties + JexusManager.Features.IsapiCgiRestriction + JexusManager.Features.IsapiCgiRestriction + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + + + + + UserControl + + + IsapiCgiRestrictionPage.cs + + + + Form + + + NewRestrictionDialog.cs + + + + True + True + Resources.resx + + + Form + + + SettingsDialog.cs + + + + + IsapiCgiRestrictionPage.cs + + + NewRestrictionDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + SettingsDialog.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.IsapiCgiRestriction/JexusManager.snk b/JexusManager.Features.IsapiCgiRestriction/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.IsapiCgiRestriction/NewRestrictionDialog.Designer.cs b/JexusManager.Features.IsapiCgiRestriction/NewRestrictionDialog.Designer.cs new file mode 100644 index 00000000..6f68a523 --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/NewRestrictionDialog.Designer.cs @@ -0,0 +1,149 @@ +namespace JexusManager.Features.IsapiCgiRestriction +{ + using System.ComponentModel; + using System.Windows.Forms; + + sealed partial class NewRestrictionDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.txtDescription = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.cbAllowed = new System.Windows.Forms.CheckBox(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(292, 166); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(186, 166); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // txtDescription + // + this.txtDescription.AutoSize = true; + this.txtDescription.Location = new System.Drawing.Point(12, 58); + this.txtDescription.Name = "txtDescription"; + this.txtDescription.Size = new System.Drawing.Size(63, 13); + this.txtDescription.TabIndex = 2; + this.txtDescription.Text = "Description:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(12, 74); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(375, 20); + this.txtName.TabIndex = 6; + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(12, 25); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(338, 20); + this.txtPath.TabIndex = 8; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(12, 9); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(94, 13); + this.label3.TabIndex = 11; + this.label3.Text = "ISAPI or CGI path:"; + // + // btnBrowse + // + this.btnBrowse.Location = new System.Drawing.Point(359, 23); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(28, 23); + this.btnBrowse.TabIndex = 15; + this.btnBrowse.Text = "..."; + this.btnBrowse.UseVisualStyleBackColor = true; + // + // cbAllowed + // + this.cbAllowed.AutoSize = true; + this.cbAllowed.Location = new System.Drawing.Point(12, 100); + this.cbAllowed.Name = "cbAllowed"; + this.cbAllowed.Size = new System.Drawing.Size(176, 17); + this.cbAllowed.TabIndex = 16; + this.cbAllowed.Text = "Allow extension path to execute"; + this.cbAllowed.UseVisualStyleBackColor = true; + // + // NewRestrictionDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(399, 201); + this.Controls.Add(this.cbAllowed); + this.Controls.Add(this.btnBrowse); + this.Controls.Add(this.label3); + this.Controls.Add(this.txtPath); + this.Controls.Add(this.txtName); + this.Controls.Add(this.txtDescription); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewRestrictionDialog"; + this.Text = "Add ISAPI or CGI Restriction"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewRestrictionDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label txtDescription; + private TextBox txtName; + private TextBox txtPath; + private Label label3; + private Button btnBrowse; + private CheckBox cbAllowed; + } +} diff --git a/JexusManager.Features.IsapiCgiRestriction/NewRestrictionDialog.cs b/JexusManager.Features.IsapiCgiRestriction/NewRestrictionDialog.cs new file mode 100644 index 00000000..db07eff0 --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/NewRestrictionDialog.cs @@ -0,0 +1,78 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IsapiCgiRestriction +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewRestrictionDialog : DialogForm + { + public NewRestrictionDialog(IServiceProvider serviceProvider, IsapiCgiRestrictionItem existing, IsapiCgiRestrictionFeature feature) + : base(serviceProvider) + { + InitializeComponent(); + Text = existing == null ? "Add ISAPI or CGI Restriction" : "Edit ISAPI or CGI Restriction"; + Item = existing ?? new IsapiCgiRestrictionItem(null); + if (existing != null) + { + txtPath.Text = Item.Path; + txtName.Text = Item.Description; + cbAllowed.Checked = Item.Allowed; + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item.Path = txtPath.Text; + Item.Description = txtName.Text; + Item.Allowed = cbAllowed.Checked; + if (feature.Items.Any(item => item.Match(Item))) + { + ShowMessage( + "This restriction already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(txtPath, "TextChanged") + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtPath.Text); + })); + + container.Add( + Observable.FromEventPattern(btnBrowse, "Click") + .Subscribe(evt => + { + DialogHelper.ShowBrowseDialog(txtPath); + })); + } + + public IsapiCgiRestrictionItem Item { get; set; } + + private void NewRestrictionDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210515"); + } + } +} diff --git a/JexusManager.Features.IsapiCgiRestriction/NewRestrictionDialog.resx b/JexusManager.Features.IsapiCgiRestriction/NewRestrictionDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/NewRestrictionDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.IsapiCgiRestriction/Properties/AssemblyInfo.cs b/JexusManager.Features.IsapiCgiRestriction/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..3bbe4b97 --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/Properties/AssemblyInfo.cs @@ -0,0 +1,46 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.IsapiCgiRestriction")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.IsapiCgiRestriction")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("1571b862-8cd9-4314-9ccf-b1339d50298b")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("Tests.JexusManager, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] diff --git a/JexusManager.Features.IsapiCgiRestriction/Properties/Resources.Designer.cs b/JexusManager.Features.IsapiCgiRestriction/Properties/Resources.Designer.cs new file mode 100644 index 00000000..d460028c --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.IsapiCgiRestriction.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.IsapiCgiRestriction.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap isapi_cgi_restriction_36 { + get { + object obj = ResourceManager.GetObject("isapi_cgi_restriction_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.IsapiCgiRestriction/Properties/Resources.resx b/JexusManager.Features.IsapiCgiRestriction/Properties/Resources.resx new file mode 100644 index 00000000..3da76608 --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\isapi_cgi_restriction_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.IsapiCgiRestriction/Resources/isapi_cgi_restriction_36.png b/JexusManager.Features.IsapiCgiRestriction/Resources/isapi_cgi_restriction_36.png new file mode 100644 index 0000000000000000000000000000000000000000..e20252ac87fdf94b73705f7f95d9200373dda142 GIT binary patch literal 2029 zcmVp37 zC5S~fvp|Zn0co;ANJtC_83ssp5l93G9up@+KEveaPq*Fw*RQJXWznzOuiI@W!wzXm zs;>8{Ufnu%@40nvHSlryKPzIe_yp?{3G-*}I)daXHm@$I+2 z4dDAj0Wq_9=hyG(IF9hvTbFVB_QUjg7<}nIDg{VE+kIjP=wz%=DBwHadl}4(LVf}e zayE^j577DZ=W`1S^MaXCE>&^j*vNpox6J|wOwD94J{F={t6+0;6V?&pNF#2C118*_ zd*|*3wzeuT+F*Qa5=?%4S3q$b=S?OM!~|%Lp3Yj2~%nauo;@GBk*Reej zBcBiO=}*0c)zvjDF8%@adS|hb9OL4kGKg9MO6viZt}Wy6 z+yUso!~4$nt(L{w+7@ozx`%q*qSyX6*L+x00Ke)CK!iS8rnDz5yBuadz#D`qdO*}1Q1e0 z28e)G)JD7A0#iqm+h75P!1VrUluA|Hzh4F*ptb1%0(*Ft$b=!h_fSgfy)_gVP2}PG z0ByT(#x(HxW52=bUoYX!7lG(mg0mKJ?9h%aJULwX^Q4u$JIl*Q*4GI$Ah=?9X`h%RfLaw+43qfwK)bSBH0X zcw2|HH8@*Gvwa-R)<5y+%0gHB008G0jfThk`~i6KkV@%YNey7XRvJ-k;k^eD!?}(S zqE1N2Wm*WblYsp@IKB#w{|0LR1HQck*ItHeufVl$!rKSPm5v{rpEbwD2sPk6~kijTK@S!de0EvS9XDTiw9D z^`{aJZJSI8z&hWJ3<$$eGjm}mAgNTALD<@CBa<;bHK*0R)jEia@4kuAunfjnVp5Ti zUGxa-Xatsu&>A}cIopi@gdhk^I-d0dlF|?n+L1#PWryaL9oZRF>Un_s7uxwThK?)k z!C-h#FoDrh%CVtX@U^d>!kMog?WCcdpKc)R>titDc8p483*LE5&&>2^h}@r~ zbz5TuzyQI+7=s`P_7CR}Af5B5)hjy|?#n?_eL{HTMl^&l@V+sSw(?L=-UF=`Ln{p_ zB#be`O;*|{-QC#Om@ba*QvidBdqRn62gqJuYOI&YQxbGB7@(6jNp*j>_-?h)X#8>L zt>f(3vlF>o?z_sUDe@$&v)VbQoO9Y+uZT!_@0Is{QYvw1vRGUo=DuuznPIK9>+2iK z-uVYo$`&(wX7)k|FQsr&3NNK{%-~wB_WQ-f#b51u4N8>}0NGTVJu-jf=@*}W;oR)u z*?mWkJ(F)Wnj&SzZ7v1@s@00Sas5W4T;BTa4SJ~EfNar6Dt0Dk%; z;bu2Ll%VhK!mh5au5YZDR+ipddf~|2TyXsO2~18*f&qBfxt&NUA*4jqYU1Ag`?&G% z>sVS^uHL zCUQiwV@jFaC8p|viiTr literal 0 HcmV?d00001 diff --git a/JexusManager.Features.IsapiCgiRestriction/SettingsDialog.Designer.cs b/JexusManager.Features.IsapiCgiRestriction/SettingsDialog.Designer.cs new file mode 100644 index 00000000..abdef53d --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/SettingsDialog.Designer.cs @@ -0,0 +1,104 @@ +namespace JexusManager.Features.IsapiCgiRestriction +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal partial class SettingsDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.cbCgi = new System.Windows.Forms.CheckBox(); + this.cbIsapi = new System.Windows.Forms.CheckBox(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // cbCgi + // + this.cbCgi.AutoSize = true; + this.cbCgi.Location = new System.Drawing.Point(12, 12); + this.cbCgi.Name = "cbCgi"; + this.cbCgi.Size = new System.Drawing.Size(171, 17); + this.cbCgi.TabIndex = 1; + this.cbCgi.Text = "Allow unspecified CGI modules"; + this.cbCgi.UseVisualStyleBackColor = true; + // + // cbIsapi + // + this.cbIsapi.AutoSize = true; + this.cbIsapi.Location = new System.Drawing.Point(12, 49); + this.cbIsapi.Name = "cbIsapi"; + this.cbIsapi.Size = new System.Drawing.Size(180, 17); + this.cbIsapi.TabIndex = 2; + this.cbIsapi.Text = "Allow unspecified ISAPI modules"; + this.cbIsapi.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(227, 96); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 4; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(131, 96); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 5; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // SettingsDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(334, 131); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.cbIsapi); + this.Controls.Add(this.cbCgi); + this.Name = "SettingsDialog"; + this.Text = "Edit ISAPI and CGI Restrictions Settings"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.PermissionsDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + private CheckBox cbCgi; + private CheckBox cbIsapi; + private Button btnCancel; + private Button btnOK; + } +} diff --git a/JexusManager.Features.IsapiCgiRestriction/SettingsDialog.cs b/JexusManager.Features.IsapiCgiRestriction/SettingsDialog.cs new file mode 100644 index 00000000..2e3934d9 --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/SettingsDialog.cs @@ -0,0 +1,44 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IsapiCgiRestriction +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client.Win32; + + internal partial class SettingsDialog : DialogForm + { + public SettingsDialog(IServiceProvider serviceProvider, ConfigurationElement element) + : base(serviceProvider) + { + InitializeComponent(); + cbCgi.Checked = (bool)element["notListedCgisAllowed"]; + cbIsapi.Checked = (bool)element["notListedIsapisAllowed"]; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + element["notListedIsapisAllowed"] = cbIsapi.Checked; + element["notListedCgisAllowed"] = cbCgi.Checked; + DialogResult = DialogResult.OK; + })); + } + + private void PermissionsDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210515"); + } + } +} diff --git a/JexusManager.Features.IsapiCgiRestriction/SettingsDialog.resx b/JexusManager.Features.IsapiCgiRestriction/SettingsDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/SettingsDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.IsapiCgiRestriction/packages.config b/JexusManager.Features.IsapiCgiRestriction/packages.config new file mode 100644 index 00000000..571e4fe0 --- /dev/null +++ b/JexusManager.Features.IsapiCgiRestriction/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.IsapiFilters/IsapiFiltersFeature.cs b/JexusManager.Features.IsapiFilters/IsapiFiltersFeature.cs new file mode 100644 index 00000000..818af8c6 --- /dev/null +++ b/JexusManager.Features.IsapiFilters/IsapiFiltersFeature.cs @@ -0,0 +1,304 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/* + * Created by SharpDevelop. + * User: lextm + * Time: 11:06 AM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace JexusManager.Features.IsapiFilters +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Linq; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + using Microsoft.Web.Management.Server; + + using Module = Microsoft.Web.Management.Client.Module; + + /// + /// Description of DefaultDocumentFeature. + /// + internal class IsapiFiltersFeature : FeatureBase + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly IsapiFiltersFeature _owner; + + public FeatureTaskList(IsapiFiltersFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + if (_owner.IsInOrder) + { + result.Add(GetMoveUpTaskItem(_owner.CanMoveUp)); + result.Add(GetMoveDownTaskItem(_owner.CanMoveDown)); + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Unorder", "View Unordered List...", string.Empty).SetUsage()); + } + else + { + result.Add(new MethodTaskItem("Add", "Add...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Edit", "Edit...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Rename", "Rename", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + if (_owner.CanRevert) + { + result.Add(new MethodTaskItem("Revert", "Revert to Parent", string.Empty).SetUsage()); + } + + result.Add(new MethodTaskItem("InOrder", "View Ordered List...", string.Empty).SetUsage()); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Add() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void Edit() + { + _owner.Edit(); + } + + [Obfuscation(Exclude = true)] + public void Rename() + { + _owner.Rename(); + } + + [Obfuscation(Exclude = true)] + public override void MoveUp() + { + _owner.MoveUp(); + } + + [Obfuscation(Exclude = true)] + public override void MoveDown() + { + _owner.MoveDown(); + } + + [Obfuscation(Exclude = true)] + public void InOrder() + { + _owner.InOrder(); + } + + [Obfuscation(Exclude = true)] + public void Unorder() + { + _owner.Unorder(); + } + + [Obfuscation(Exclude = true)] + public void Revert() + { + _owner.Revert(); + } + } + + public IsapiFiltersFeature(Module module) + : base(module) + { + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + this.CanRevert = service.Scope != ManagementScope.Server; + this.IsInOrder = false; + LoadItems(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + ConfigurationSection section = service.GetSection("system.webServer/isapiFilters", null, false); + return section.GetCollection(); + } + + public void Add() + { + var dialog = new NewFilterDialog(this.Module, null, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected authorization rule?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + public void Edit() + { + var dialog = new NewFilterDialog(this.Module, this.SelectedItem, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.EditItem(dialog.Item); + } + + public void Rename() + { + } + + public void MoveUp() + { + if (this.Items.Any(item => item.Flag != "Local")) + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + var result = + dialog.ShowMessage( + "The list order will be changed for this feature. If you continue, changes made to this feature at a parent level will no longer be inherited at this level. Do you want to continue?", + this.Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + } + + MoveUpItem(); + } + + public void MoveDown() + { + if (this.Items.Any(item => item.Flag != "Local")) + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + var result = + dialog.ShowMessage( + "The list order will be changed for this feature. If you continue, changes made to this feature at a parent level will no longer be inherited at this level. Do you want to continue?", + this.Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + } + + MoveDownItem(); + } + + public void InOrder() + { + this.IsInOrder = true; + this.OnSettingsSaved(); + } + + public void Unorder() + { + this.IsInOrder = false; + this.OnSettingsSaved(); + } + + public void Revert() + { + if (!CanRevert) + { + throw new InvalidOperationException("Revert operation cannot be done at server level"); + } + + var dialog = (IManagementUIService)GetService(typeof(IManagementUIService)); + var result = + dialog.ShowMessage( + "Reverting to the parent configuration will result in the loss of all settings in the local configuration file for this feature. Are you sure you want to continue?", + Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + + RevertItems(); + } + + protected override void OnSettingsSaved() + { + this.IsapiFiltersSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210462"); + return false; + } + + public bool IsInOrder { get; private set; } + + public bool CanRevert { get; private set; } + + public IsapiFiltersSettingsSavedEventHandler IsapiFiltersSettingsUpdated { get; set; } + + public string Description { get; } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public string Name + { + get { return "ISAPI Filters"; } + } + } +} diff --git a/JexusManager.Features.IsapiFilters/IsapiFiltersItem.cs b/JexusManager.Features.IsapiFilters/IsapiFiltersItem.cs new file mode 100644 index 00000000..c7aa3ac6 --- /dev/null +++ b/JexusManager.Features.IsapiFilters/IsapiFiltersItem.cs @@ -0,0 +1,81 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IsapiFilters +{ + using System.Collections.Generic; + using System.Linq; + using System.Text; + + using Microsoft.Web.Administration; + + internal class IsapiFiltersItem : IItem + { + public IsapiFiltersItem(ConfigurationElement element) + { + this.Element = element; + this.Flag = element == null || element.IsLocallyStored ? "Local" : "Inherited"; + if (element == null) + { + Path = string.Empty; + PreConditions = new List(0); + return; + } + + this.Name = (string)element["name"]; + this.Path = (string)element["path"]; + var content = (string)element["preCondition"]; + this.PreConditions = content.Split(',').ToList(); + EnableCache = (bool)element["enableCache"]; + } + + public List PreConditions { get; set; } + + public bool EnableCache { get; set; } + + public string Path { get; set; } + + public string Name { get; set; } + + public ConfigurationElement Element { get; set; } + + public string Flag { get; set; } + + public bool Equals(IsapiFiltersItem other) + { + // all properties + return this.Match(other) && other.Path == this.Path; + } + + public void Apply() + { + Element["name"] = Name; + Element["path"] = Path; + Element["preCondition"] = Combine(PreConditions); + Element["enableCache"] = EnableCache; + } + + private static string Combine(List preConditions) + { + if (preConditions.Count == 0) + { + return string.Empty; + } + + var result = new StringBuilder(preConditions[0]); + for (int index = 1; index < preConditions.Count; index++) + { + result.AppendFormat(",{0}", preConditions[index]); + } + + return result.ToString(); + } + + public bool Match(IsapiFiltersItem other) + { + // match combined keys. + return other != null && other.Name == this.Name; + } + } +} diff --git a/JexusManager.Features.IsapiFilters/IsapiFiltersModule.cs b/JexusManager.Features.IsapiFilters/IsapiFiltersModule.cs new file mode 100644 index 00000000..accba651 --- /dev/null +++ b/JexusManager.Features.IsapiFilters/IsapiFiltersModule.cs @@ -0,0 +1,26 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IsapiFilters +{ + using System; + + using Properties; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + + internal class IsapiFiltersModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)this.GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(IsapiFiltersPage), "ISAPI Filters", + "Specify ISAPI filters that modify IIS functionality", Resources.isapi_filters_36, + Resources.isapi_filters_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.IsapiFilters/IsapiFiltersModuleProvider.cs b/JexusManager.Features.IsapiFilters/IsapiFiltersModuleProvider.cs new file mode 100644 index 00000000..9b0146d3 --- /dev/null +++ b/JexusManager.Features.IsapiFilters/IsapiFiltersModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IsapiFilters +{ + using System; + + using Microsoft.Web.Management.Server; + + public class IsapiFiltersModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(this.Name, typeof(IsapiFiltersModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.IsapiFilters/IsapiFiltersPage.Designer.cs b/JexusManager.Features.IsapiFilters/IsapiFiltersPage.Designer.cs new file mode 100644 index 00000000..4b790544 --- /dev/null +++ b/JexusManager.Features.IsapiFilters/IsapiFiltersPage.Designer.cs @@ -0,0 +1,290 @@ +namespace JexusManager.Features.IsapiFilters +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class IsapiFiltersPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chExecutable = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.toolStrip2 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel2 = new System.Windows.Forms.ToolStripLabel(); + this.cbGroup = new System.Windows.Forms.ToolStripComboBox(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.toolStrip2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 6; + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.toolStrip2); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 6; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chName, + this.chExecutable, + this.chType}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 38); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 502); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListView1SelectedIndexChanged); + // + // chName + // + this.chName.Text = "Name"; + this.chName.Width = 120; + // + // chExecutable + // + this.chExecutable.Text = "Executable"; + this.chExecutable.Width = 180; + // + // chType + // + this.chType.Text = "Entry Type"; + this.chType.Width = 120; + // + // toolStrip2 + // + this.toolStrip2.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel2, + this.cbGroup}); + this.toolStrip2.Location = new System.Drawing.Point(0, 13); + this.toolStrip2.Name = "toolStrip2"; + this.toolStrip2.Size = new System.Drawing.Size(560, 25); + this.toolStrip2.TabIndex = 3; + this.toolStrip2.Text = "toolStrip2"; + // + // toolStripLabel2 + // + this.toolStripLabel2.Name = "toolStripLabel2"; + this.toolStripLabel2.Size = new System.Drawing.Size(59, 22); + this.toolStripLabel2.Text = "Group by:"; + // + // cbGroup + // + this.cbGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbGroup.Items.AddRange(new object[] { + "No Grouping", + "Status", + "IP Address", + "Protocol", + "Port"}); + this.cbGroup.Name = "cbGroup"; + this.cbGroup.Size = new System.Drawing.Size(121, 25); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(421, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to configure ISAPI filters that process requests made to the Web" + + " server."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 5; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(129, 25); + this.label3.TabIndex = 2; + this.label3.Text = "ISAPI Filters"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // IsapiFiltersPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "IsapiFiltersPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.toolStrip2.ResumeLayout(false); + this.toolStrip2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private ListView listView1; + private ColumnHeader chType; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Panel panel2; + private ToolStrip toolStrip2; + private ToolStripLabel toolStripLabel2; + private ToolStripComboBox cbGroup; + private PictureBox pictureBox1; + private ContextMenuStrip cmsActionPanel; + private ColumnHeader chName; + private ColumnHeader chExecutable; + } +} diff --git a/JexusManager.Features.IsapiFilters/IsapiFiltersPage.cs b/JexusManager.Features.IsapiFilters/IsapiFiltersPage.cs new file mode 100644 index 00000000..02004e27 --- /dev/null +++ b/JexusManager.Features.IsapiFilters/IsapiFiltersPage.cs @@ -0,0 +1,131 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IsapiFilters +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class IsapiFiltersPage : ModuleListPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly IsapiFiltersPage _owner; + + public PageTaskList(IsapiFiltersPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class IsapiFiltersListViewItem : ListViewItem + { + public IsapiFiltersItem Item { get; } + + private readonly IsapiFiltersPage _page; + + public IsapiFiltersListViewItem(IsapiFiltersItem item, IsapiFiltersPage page) + : base(item.Name) + { + this.Item = item; + _page = page; + this.SubItems.Add(new ListViewSubItem(this, item.Path)); + this.SubItems.Add(new ListViewSubItem(this, item.Flag)); + } + } + + private IsapiFiltersFeature _feature; + private PageTaskList _taskList; + + public IsapiFiltersPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new IsapiFiltersFeature(this.Module); + _feature.IsapiFiltersSettingsUpdated = this.InitializeListPage; + _feature.Load(); + } + + protected override void InitializeListPage() + { + toolStrip2.Visible = !_feature.IsInOrder; + listView1.Items.Clear(); + foreach (var file in _feature.Items) + { + listView1.Items.Add(new IsapiFiltersListViewItem(file, this)); + } + + if (_feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (IsapiFiltersListViewItem item in listView1.Items) + { + if (item.Item == _feature.SelectedItem) + { + item.Selected = true; + } + } + } + + protected override void Refresh() + { + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + private void ListView1SelectedIndexChanged(object sender, EventArgs e) + { + _feature.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((IsapiFiltersListViewItem)listView1.SelectedItems[0]).Item + : null; + // TODO: optimize refresh when null to not null (vice versa) + this.Refresh(); + } + + protected override bool ShowHelp() + { + _feature.ShowHelp(); + return true; + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + } +} diff --git a/JexusManager.Features.IsapiFilters/IsapiFiltersPage.resx b/JexusManager.Features.IsapiFilters/IsapiFiltersPage.resx new file mode 100644 index 00000000..7a2db0ac --- /dev/null +++ b/JexusManager.Features.IsapiFilters/IsapiFiltersPage.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 602, 17 + + + 497, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.IsapiFilters/IsapiFiltersSettingsSavedEventHandler.cs b/JexusManager.Features.IsapiFilters/IsapiFiltersSettingsSavedEventHandler.cs new file mode 100644 index 00000000..026e00d0 --- /dev/null +++ b/JexusManager.Features.IsapiFilters/IsapiFiltersSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IsapiFilters +{ + public delegate void IsapiFiltersSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.IsapiFilters/JexusManager.Features.IsapiFilters.csproj b/JexusManager.Features.IsapiFilters/JexusManager.Features.IsapiFilters.csproj new file mode 100644 index 00000000..55399720 --- /dev/null +++ b/JexusManager.Features.IsapiFilters/JexusManager.Features.IsapiFilters.csproj @@ -0,0 +1,130 @@ + + + + + Debug + AnyCPU + {DBA682A8-0579-4F41-A852-18235A9A4A93} + Library + Properties + JexusManager.Features.IsapiFilters + JexusManager.Features.IsapiFilters + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + + + + + UserControl + + + IsapiFiltersPage.cs + + + + Form + + + NewFilterDialog.cs + + + + True + True + Resources.resx + + + + + IsapiFiltersPage.cs + + + NewFilterDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.IsapiFilters/JexusManager.snk b/JexusManager.Features.IsapiFilters/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.IsapiFilters/NewFilterDialog.Designer.cs b/JexusManager.Features.IsapiFilters/NewFilterDialog.Designer.cs new file mode 100644 index 00000000..fcd7e36e --- /dev/null +++ b/JexusManager.Features.IsapiFilters/NewFilterDialog.Designer.cs @@ -0,0 +1,136 @@ +namespace JexusManager.Features.IsapiFilters +{ + using System.ComponentModel; + using System.Windows.Forms; + + sealed partial class NewFilterDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.txtDescription = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(317, 186); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(216, 186); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // txtDescription + // + this.txtDescription.AutoSize = true; + this.txtDescription.Location = new System.Drawing.Point(12, 9); + this.txtDescription.Name = "txtDescription"; + this.txtDescription.Size = new System.Drawing.Size(61, 13); + this.txtDescription.TabIndex = 2; + this.txtDescription.Text = "Filter name:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(15, 25); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(269, 20); + this.txtName.TabIndex = 6; + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(15, 82); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(360, 20); + this.txtPath.TabIndex = 8; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 66); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(63, 13); + this.label1.TabIndex = 9; + this.label1.Text = "Executable:"; + // + // btnBrowse + // + this.btnBrowse.Location = new System.Drawing.Point(381, 80); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(28, 23); + this.btnBrowse.TabIndex = 10; + this.btnBrowse.Text = "..."; + this.btnBrowse.UseVisualStyleBackColor = true; + // + // NewFilterDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(424, 221); + this.Controls.Add(this.btnBrowse); + this.Controls.Add(this.label1); + this.Controls.Add(this.txtPath); + this.Controls.Add(this.txtName); + this.Controls.Add(this.txtDescription); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewFilterDialog"; + this.Text = "Add ISAPI Filter"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewRestrictionDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label txtDescription; + private TextBox txtName; + private TextBox txtPath; + private Label label1; + private Button btnBrowse; + } +} diff --git a/JexusManager.Features.IsapiFilters/NewFilterDialog.cs b/JexusManager.Features.IsapiFilters/NewFilterDialog.cs new file mode 100644 index 00000000..3c1a0dee --- /dev/null +++ b/JexusManager.Features.IsapiFilters/NewFilterDialog.cs @@ -0,0 +1,79 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.IsapiFilters +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewFilterDialog : DialogForm + { + public NewFilterDialog(IServiceProvider serviceProvider, IsapiFiltersItem existing, IsapiFiltersFeature feature) + : base(serviceProvider) + { + InitializeComponent(); + Text = existing == null ? "Add ISAPI Filter" : "Edit ISAPI Filter"; + txtName.ReadOnly = existing != null; + Item = existing ?? new IsapiFiltersItem(null); + if (existing != null) + { + txtPath.Text = Item.Path; + txtName.Text = Item.Name; + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item.Path = txtPath.Text; + Item.Name = txtName.Text; + if (!txtName.ReadOnly && feature.Items.Any(item => item.Match(Item))) + { + ShowMessage( + "A filter with this name already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Merge(Observable.FromEventPattern(txtPath, "TextChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text) + && !string.IsNullOrWhiteSpace(txtPath.Text); + })); + + container.Add( + Observable.FromEventPattern(btnBrowse, "Click") + .Subscribe(evt => + { + DialogHelper.ShowBrowseDialog(txtPath); + })); + } + + public IsapiFiltersItem Item { get; set; } + + private void NewRestrictionDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210516"); + } + } +} diff --git a/JexusManager.Features.IsapiFilters/NewFilterDialog.resx b/JexusManager.Features.IsapiFilters/NewFilterDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.IsapiFilters/NewFilterDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.IsapiFilters/Properties/AssemblyInfo.cs b/JexusManager.Features.IsapiFilters/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..5ab51de3 --- /dev/null +++ b/JexusManager.Features.IsapiFilters/Properties/AssemblyInfo.cs @@ -0,0 +1,46 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.IsapiFilters")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.IsapiFilters")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("dba682a8-0579-4f41-a852-18235a9a4a93")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("Tests.JexusManager, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] diff --git a/JexusManager.Features.IsapiFilters/Properties/Resources.Designer.cs b/JexusManager.Features.IsapiFilters/Properties/Resources.Designer.cs new file mode 100644 index 00000000..9403a4fd --- /dev/null +++ b/JexusManager.Features.IsapiFilters/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.IsapiFilters.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.IsapiFilters.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap isapi_filters_36 { + get { + object obj = ResourceManager.GetObject("isapi_filters_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.IsapiFilters/Properties/Resources.resx b/JexusManager.Features.IsapiFilters/Properties/Resources.resx new file mode 100644 index 00000000..3e4bffd0 --- /dev/null +++ b/JexusManager.Features.IsapiFilters/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\isapi_filters_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.IsapiFilters/Resources/isapi_filters_36.png b/JexusManager.Features.IsapiFilters/Resources/isapi_filters_36.png new file mode 100644 index 0000000000000000000000000000000000000000..809750b2f78955ecc674ab722188f48dcdde540e GIT binary patch literal 1838 zcmV+}2hsS6P) zfEL}v?Fy+vChU+9$^r@-M4A#7>7o({L`YFcozzZ3;>33B`1ak8o&Wsi{Lh^41OC7M#}=(Nv0i`asic%X&xDPLG7Mr%jB7E(sXXib;?SYPZ$31j z`b7OpOmck7<}ExjGBQ=ElqtrzwcYOE+UzwzV*|4)z+&4GKxMmKEC4* zKrGJ8%%pklm_YBbX4hA(-q`i{6Zx65XFd(!;Q$36et!A#%oq0T-utIgsk8u~M?}rO z{=S7~V`=#0Z%%$rLa47sn^%)`=+NO)A%?fJtbIL*y8@0gX{B&JciHvX>$6KfcfUJ$ z@Wm6W(blVNYVUk5f;mK()Ct4GuJ6Dwmes>RcEbj4G)jZEH)Ni zcp$s|(W6J#>xADN-m>r1e3wc$7Tbe9suCHSu_?BD0UaM`NfA`ZN=T_0H}qL`?c!Tc z_ay(!;jbUQdSB;IWIom|jL-jhUhnB-e%N_q1VoyQ<0w4#JAVAQn!a@L_uZlWRgjtqS+m)5NF!7MN?SGsAHlr{>VzmQ5Q$|W!%?KS zWR%i_x?mnD&Yo^;dSvs*4jecT)@0fA<%?hA>X^;BP!N&ro>QVkdK!Mo7?ZOi4?!o7 zG}m)<0~+mwsT_#5_QY;NkbdoSQmu^T?_Ij^RRFKu?S1NQ4_|%t+v~uEA1(FmE(1it zJAw!R(gIb2wv`A~3&aCKkmfPy5CCH+N(?nXN-_8XK}=p8O^V%1yFdHPzMq^p@!QVo zdWZ_IptjQqm_!5;<3E{wYZd|!At4xIHX>1b9~805NoxlnKt!Am6#I7usPvUpRp{u^ zmv$&yKDb!kRlRi}%ZUIYCT4;*#wcTqRz#YalwsBd!)&cGwUS8_%_RWE;CwM68i|pE z9k9jh%GlFSed1Sdym4ybo+_k_{cc$IVPYaygv2PMT2pG2q>7O!<^(Ysk*GujQGyNL zm&NC$Jnt0~4wZ`K;aVl>D<>*VttudREkjSRvBmG)OH(rdC9FPDs*Mg+8D^=`MGi&~ zkq`k9xn&jskjNs$AR z0ErJ`C2!f;mLo+FYb|i=$O;gFl!6ElMKJ^t0S{3cF&3=?C5j9&RDdQD&pt$&om;}D zp0xOM6qUBK^Q}mVNwJ1DS`uqX>j+i~iWLFS zkVxLU;PQ;R(W?Z`l48z-P&aepyu(PX%*YmcS-Uj_U>HCXKxZY8x&zQCfPtxZFPz!7 zad6K-C9xYfthePfC8Eea&$;J3vOK3wr%Rnqhq~Pkbvtcpce~tbv|`?C6QVOkt&;v~ zB^l~Z^@duJRp)Bw>cv0)?T0@&_Pu7a8J9tBE?alUNzDMZ0ayp1q?9Ur@%hhx^05!@ ze5PFOA4`f=T`Ui%q*P{Yi>yo$V1__NhzP-l=<;54-H4D$o;A^0TGUy$Ev-i5%3t1j z=j7|J|MIO6LU*|`3jqEK!2c^C0x$-k1|S7smqP(i+aKFLG`@B7#{T}nq5fKJC{2qs z5L?BhV~i4lQ_K@mitKV2Bhx*!7D<&FZXUhSn+Ge_ucyy c@!z}t4rnbqda{A%SpWb407*qoM6N<$f&gAw-v9sr literal 0 HcmV?d00001 diff --git a/JexusManager.Features.IsapiFilters/packages.config b/JexusManager.Features.IsapiFilters/packages.config new file mode 100644 index 00000000..571e4fe0 --- /dev/null +++ b/JexusManager.Features.IsapiFilters/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Jexus/JexusFeature.cs b/JexusManager.Features.Jexus/JexusFeature.cs new file mode 100644 index 00000000..90a54b43 --- /dev/null +++ b/JexusManager.Features.Jexus/JexusFeature.cs @@ -0,0 +1,164 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Jexus +{ + using System; + using System.Collections.Generic; + using System.Diagnostics; + using System.IO; + using System.Resources; + using System.Text; + + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal class JexusFeature + { + public JexusFeature(Module module) + { + this.Module = module; + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + + protected void DisplayErrorMessage(Exception ex, ResourceManager resourceManager) + { + var service = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + service.ShowError(ex, resourceManager.GetString("General"), "", false); + } + + protected object GetService(Type type) + { + return (this.Module as IServiceProvider).GetService(type); + } + + public void Load() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + if (service.ServerManager.Mode != WorkingMode.Jexus) + { + this.IsFeatureEnabled = false; + return; + } + + this.IsFeatureEnabled = true; + var settings = service.Server == null ? service.Application.GetExtra() : service.Server.GetExtra(); + var text = new StringBuilder(); + foreach (var key in settings.Keys) + { + foreach (var item in settings[key]) + { + text.AppendFormat("{0}={1}", key, item).AppendLine(); + } + } + + Contents = text.ToString(); + this.OnJexusSettingsSaved(); + } + + public string Contents { get; set; } + + protected void OnJexusSettingsSaved() + { + this.JexusSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("https://jexus.codeplex.com/wikipage?title=Configuration%20Files"); + return false; + } + + public JexusSettingsSavedEventHandler JexusSettingsUpdated { get; set; } + public string Description { get; } + + public bool IsFeatureEnabled { get; private set; } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public Module Module { get; } + + public string Name + { + get + { + return "Jexus Specific"; + } + } + + public void CancelChanges() + { + this.Load(); + } + + public bool ApplyChanges() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + if (service.Server == null) + { + service.Application.GetExtra().Clear(); + } + else + { + service.Server.GetExtra().Clear(); + } + + var reader = new StringReader(Contents); + string line; + while ((line = reader.ReadLine()) != null) + { + var index = line.IndexOf('='); + if (index == -1) + { + continue; + } + + var key = line.Substring(0, index).Trim(); + if (key.Length == 0) + { + continue; + } + + var value = line.Substring(index + 1).Trim(); + if (service.Server == null) + { + var extra = service.Application.GetExtra(); + if (extra.ContainsKey(key)) + { + extra[key].Add(value); + } + else + { + extra.Add(key, new List { value }); + } + } + else + { + var extra = service.Server.GetExtra(); + if (extra.ContainsKey(key)) + { + extra[key].Add(value); + } + else + { + extra.Add(key, new List { value }); + } + } + } + + AsyncHelper.RunSync(() => service.ServerManager.CommitChangesAsync()); + return true; + } + } +} diff --git a/JexusManager.Features.Jexus/JexusManager.Features.Jexus.csproj b/JexusManager.Features.Jexus/JexusManager.Features.Jexus.csproj new file mode 100644 index 00000000..85c8c013 --- /dev/null +++ b/JexusManager.Features.Jexus/JexusManager.Features.Jexus.csproj @@ -0,0 +1,103 @@ + + + + + Debug + AnyCPU + {EA333EE8-6551-4B5B-A733-119C5560608D} + Library + Properties + JexusManager.Features.Jexus + JexusManager.Features.Jexus + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + + + + + + + + + + + + + UserControl + + + JexusPage.cs + + + + + True + True + Resources.resx + + + + + JexusPage.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Jexus/JexusManager.snk b/JexusManager.Features.Jexus/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Jexus/JexusModule.cs b/JexusManager.Features.Jexus/JexusModule.cs new file mode 100644 index 00000000..b010a1a9 --- /dev/null +++ b/JexusManager.Features.Jexus/JexusModule.cs @@ -0,0 +1,26 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Jexus +{ + using System; + + using Properties; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + + internal class JexusModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)this.GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(JexusPage), "Jexus Specific", + "Configure Jexus specific settings", + Resources.jexus_36, Resources.jexus_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.Jexus/JexusModuleProvider.cs b/JexusManager.Features.Jexus/JexusModuleProvider.cs new file mode 100644 index 00000000..8b2a184e --- /dev/null +++ b/JexusManager.Features.Jexus/JexusModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Jexus +{ + using System; + + using Microsoft.Web.Management.Server; + + public class JexusModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(this.Name, typeof(JexusModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.Jexus/JexusPage.Designer.cs b/JexusManager.Features.Jexus/JexusPage.Designer.cs new file mode 100644 index 00000000..f8ef96c4 --- /dev/null +++ b/JexusManager.Features.Jexus/JexusPage.Designer.cs @@ -0,0 +1,222 @@ +namespace JexusManager.Features.Jexus +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class JexusPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.txtSettings = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 5; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.SplitContainer1SplitterMoved); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.txtSettings); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 11; + // + // txtSettings + // + this.txtSettings.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.txtSettings.Location = new System.Drawing.Point(16, 18); + this.txtSettings.Multiline = true; + this.txtSettings.Name = "txtSettings"; + this.txtSettings.Size = new System.Drawing.Size(529, 505); + this.txtSettings.TabIndex = 3; + this.txtSettings.TextChanged += new System.EventHandler(this.txtSettings_TextChanged); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(251, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to configure Jexus specific settings."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 10; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(151, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Jexus Specific"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // JexusPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "JexusPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Panel panel2; + private PictureBox pictureBox1; + private ContextMenuStrip cmsActionPanel; + private TextBox txtSettings; + } +} diff --git a/JexusManager.Features.Jexus/JexusPage.cs b/JexusManager.Features.Jexus/JexusPage.cs new file mode 100644 index 00000000..194a1be7 --- /dev/null +++ b/JexusManager.Features.Jexus/JexusPage.cs @@ -0,0 +1,146 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Jexus +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class JexusPage : ModuleDialogPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly JexusPage _owner; + + public PageTaskList(JexusPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private JexusFeature _feature; + private bool _hasChanges; + private bool _initialized; + private TaskList _taskList; + + public JexusPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new JexusFeature(this.Module); + _feature.JexusSettingsUpdated = this.Refresh; + _feature.Load(); + txtSettings.Enabled = _feature.IsFeatureEnabled; + base.Initialize(navigationData); + } + + protected override bool ShowHelp() + { + return _feature.ShowHelp(); + } + + private void SplitContainer1SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + private void txtSettings_TextChanged(object sender, EventArgs e) + { + _feature.Contents = txtSettings.Text; + this.InformChanges(); + } + + protected override bool ApplyChanges() + { + if (!_feature.ApplyChanges()) + { + return false; + } + + this.ClearChanges(); + return true; + } + + protected override void CancelChanges() + { + _feature.CancelChanges(); + this.ClearChanges(); + } + + protected override bool HasChanges + { + get { return _hasChanges; } + } + + protected override bool CanApplyChanges + { + get { return true; } + } + + private void InformChanges() + { + if (!_initialized) + { + return; + } + + _hasChanges = true; + this.Refresh(); + } + + private void ClearChanges() + { + _hasChanges = false; + this.Refresh(); + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + + protected override void OnRefresh() + { + if (!_hasChanges) + { + txtSettings.Text = _feature.Contents; + _initialized = true; + } + + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + } + } +} diff --git a/JexusManager.Features.Jexus/JexusPage.resx b/JexusManager.Features.Jexus/JexusPage.resx new file mode 100644 index 00000000..950be5d2 --- /dev/null +++ b/JexusManager.Features.Jexus/JexusPage.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 143, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.Jexus/JexusSettingsSavedEventHandler.cs b/JexusManager.Features.Jexus/JexusSettingsSavedEventHandler.cs new file mode 100644 index 00000000..b6a2a6f9 --- /dev/null +++ b/JexusManager.Features.Jexus/JexusSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Jexus +{ + public delegate void JexusSettingsSavedEventHandler(); +} diff --git a/JexusManager.Features.Jexus/Properties/AssemblyInfo.cs b/JexusManager.Features.Jexus/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..bebda1e7 --- /dev/null +++ b/JexusManager.Features.Jexus/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.Jexus")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.Jexus")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ea333ee8-6551-4b5b-a733-119c5560608d")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JexusManager.Features.Jexus/Properties/Resources.Designer.cs b/JexusManager.Features.Jexus/Properties/Resources.Designer.cs new file mode 100644 index 00000000..3205b0c7 --- /dev/null +++ b/JexusManager.Features.Jexus/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.Jexus.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.Jexus.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap jexus_36 { + get { + object obj = ResourceManager.GetObject("jexus_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.Jexus/Properties/Resources.resx b/JexusManager.Features.Jexus/Properties/Resources.resx new file mode 100644 index 00000000..30e7d5f4 --- /dev/null +++ b/JexusManager.Features.Jexus/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\jexus_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.Jexus/Resources/jexus_36.png b/JexusManager.Features.Jexus/Resources/jexus_36.png new file mode 100644 index 0000000000000000000000000000000000000000..a008100e6d01c6ba66f9802b05a9d8fbe0199652 GIT binary patch literal 2512 zcmV;>2`~1EP)(VY{}gEZP^KrR)i*5L z*xl3J+ndk2GMjNsfNIT;7OI|_E*1)55I?DtEc;0*KfYO zeOb;FQKdi})KEbK0BNT%oGfO`GNvk#e*LZEbF;Tb%59ZptGxpxw zuD@oW%c)v(XWvE#b)*0(E_R{;rJE+~H0`T4Gwo-?mtKGK#9Sk~VedQT`OgfreJIn@ z-;&#R*B7r^?VbI*sMacAy2!{UB|{uTA(ML*5GskMOk%@9!~vO13+WZt>gQfLbb4xf zaron=(D*putNJsq-o5kM4Rfash%nX0=IeH`W$R6Jtz5^{Vu0uSr0_w&qHINW4zP8{ zoou@5268>C7@satD~^dRo3GBFnVh`kc%kvjPYra-M)$tqtyes#=0=^i-Zk9w)%)qr zIk-kdd&XhYrpSWn=dE znVIOle>JAL^yH=u?yxZUve2@kRs3|yb$+zFA=GnbRy#xQG zq1%VtM{+IpgX@-A?XeQ-$hbe-+0kuXxh%|Ixn(;WS9YUBUnU0P&+odjsue}c0n1?t-M$zAxW8_yZ|9hgkdA30YWyXMaU0mKx>828nn6y6bHBlC?t+)%3a$A zxq15*79x{J_xy%+-EmuKPCf!`l{XKP&A3KSsVaG3*Dx7NAe|Og^e-pY3MmA!0%@h2 zW~T{-!$XfB;GxG45DFV@VJ&mwkgyrHZ6O^Xvh4d}!K}P{P4p?{D3PNp@OFS7;YYEH9N0`7pJJ|gK#nkCqsQna;OC$EEj3H znCW&Vrlv70hf1|huB8PXM`#sO^Xh1=31XBm3{U=b%$r!KMGafTymojj(TRmH9em$M zrrJ0-vJazWSu#MHdvDvurZv3`uI=OAUBeeVbnmWVHm&JnaBUy=+`1KMr4g2kkzdZi zH(x`h+6cp-slQ|ayu5cmwh=ME82GP`)(Zk)=SKG@*R1dS_S{0%-a52_fr0h>>5UO8 zRgcT^KAW%I!M3Zmp@KTXu)wgI;L-qLG~-TF(M=Jn7_Fk_s*FQqD#ys-5e~lbXHG5H zw5BAtY+23N^dfJMo+O{k1tX)AKYRJ8_X7i9ZLVd1spdU!*@}+ViNcgPa^e)HCg=5* zRT;5y@M^YRy`5rlic~s_VY^5(g)|+6!!##l2rpkyfv~HrOoib3!6B4AvHXWAtw$i`C zL0HMu8Fo`bae#_^bl5;gK00bNL4<6k7!{Il>%wFd4FexGwEVC}4Zc#~`Cb#`!?sUC zTs%vX>4iIl_|RvBG^sagL<$7>pBPBRyjk`lrV8hfRyxV<3RE-GYaK%zHS<;Eqk=jr zs5iY5hs|r}cLgeLrV*`>PKL?xlT_*Wfm$5P+ z4grAzgjNU@UG$<>Nx%z}NF1V7gjNwkn#?U!SS-&nUaFO%NIvn2J@o3)`k}dMedlf>c{FSdeHV(Mjkf-l-*4M~B`L4f*IeXvU{ZC(l3g80ETVzUH5JZM1gy-`O#W zj;yhF(Tl#G&yYEH`aL#mz7a!cbmS*fkYsWdfeMo#7$oLHlBnD*^TBrxj|ayAD;Zxe1rwLRq!M$^*H?DggKN9Y zM_2b|JNsI&(`lEr>$k9W-4%3p_v5;09LEJ92pV{vN2&Ner;Z(FZ1fOy&ttNpf-{AB z>EulGy>q4DD9shtSaNIt;U@wDoRmrKidCs^wx+E+`#Rm0?yRs)5tB}(Kp6^XV z-3y426e~KIn5!?AtI-Qb#v6MY5sR0Ad?e6PDCZKh0Xt>VvaZ*@z121Da2&JGbxfIZ zq+uXzfEXQkzETZ8ihVySl)dzsP + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.cbType = new System.Windows.Forms.ComboBox(); + this.label3 = new System.Windows.Forms.Label(); + this.cbSource = new System.Windows.Forms.ComboBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(22, 20); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(63, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Field Name:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(25, 36); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(351, 20); + this.txtName.TabIndex = 1; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(22, 76); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(71, 13); + this.label2.TabIndex = 2; + this.label2.Text = "Source Type:"; + // + // cbType + // + this.cbType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbType.FormattingEnabled = true; + this.cbType.Items.AddRange(new object[] { + "Request Header", + "Response Header", + "Server Variable"}); + this.cbType.Location = new System.Drawing.Point(25, 92); + this.cbType.Name = "cbType"; + this.cbType.Size = new System.Drawing.Size(351, 21); + this.cbType.TabIndex = 3; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(22, 137); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(44, 13); + this.label3.TabIndex = 4; + this.label3.Text = "Source:"; + // + // cbSource + // + this.cbSource.FormattingEnabled = true; + this.cbSource.Location = new System.Drawing.Point(25, 153); + this.cbSource.Name = "cbSource"; + this.cbSource.Size = new System.Drawing.Size(351, 21); + this.cbSource.TabIndex = 5; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(226, 251); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 6; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(322, 251); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 7; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // AddFieldDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(429, 286); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.cbSource); + this.Controls.Add(this.label3); + this.Controls.Add(this.cbType); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtName); + this.Controls.Add(this.label1); + this.Name = "AddFieldDialog"; + this.Text = "Add Custom Field"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.AddFieldDialog_HelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label1; + private TextBox txtName; + private Label label2; + private ComboBox cbType; + private Label label3; + private ComboBox cbSource; + private Button btnOK; + private Button btnCancel; + } +} diff --git a/JexusManager.Features.Logging/AddFieldDialog.cs b/JexusManager.Features.Logging/AddFieldDialog.cs new file mode 100644 index 00000000..122b8a97 --- /dev/null +++ b/JexusManager.Features.Logging/AddFieldDialog.cs @@ -0,0 +1,184 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Logging +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client.Win32; + + public partial class AddFieldDialog : DialogForm + { + public CustomLogField Custom { get; private set; } + + public AddFieldDialog(IServiceProvider serviceProvider, CustomLogField custom, SiteLogFile logFile) + : base(serviceProvider) + { + Custom = custom; + InitializeComponent(); + if (custom != null) + { + txtName.Text = custom.LogFieldName; + cbType.SelectedIndex = (int)custom.SourceType; + cbSource.Text = custom.SourceName; + } + else + { + cbType.SelectedIndex = 0; + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Merge(Observable.FromEventPattern(cbSource, "TextChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text) && !string.IsNullOrWhiteSpace(cbSource.Text); + })); + + container.Add( + Observable.FromEventPattern(cbType, "SelectedIndexChanged") + .Subscribe(evt => + { + cbSource.Items.Clear(); + if (cbType.SelectedIndex == 0) + { + cbSource.Items.AddRange(new object[] + { + "Accept", + "Accept_Charset", + "Accept_Encoding", + "Authorization", + "Cache-Control", + "Connection", + "Content-Length", + "Content-MD5", + "Content-Type", + "Date", + "Expect", + "From", + "Host", + "If-Match", + "If-Modified-Since", + "If-None-Match", + "If-Range", + "If-Unmodified-Since", + "Max-Forwards", + "Pragma", + "Proxy-Authorization", + "Range", + "Referer", + "TE", + "Upgrade", + "User-Agent", + "Via", + "Warning" + }); + } + else if (cbType.SelectedIndex == 1) + { + cbSource.Items.AddRange(new object[] + { + "Accept-Range", + "Content-Type", + "ETag", + "Last-Modified", + "Server" + }); + } + else if (cbType.SelectedIndex == 2) + { + cbSource.Items.AddRange(new object[] + { + "ALL_HTTP", + "ALL_RAW", + "APPL_MD_PATH", + "APPL_PHYSICAL_PATH", + "AUTH_PASSWORD", + "AUTH_TYPE", + "AUTH_USER", + "CERT_COOKIE", + "CERT_FLAGS", + "CERT_ISSUER", + "CERT_KEYSIZE", + "CERT_SECRETKEYSIZE", + "CERT_SERIALNUMBER", + "CERT_SERVER_ISSUER", + "CERT_SERVER_SUBJECT", + "CERT_SUBJECT", + "CONTENT_LENGTH", + "CONTENT_TYPE", + "GATEWAY_INTERFACE", + "HTTP_ACCEPT", + "HTTP_ACCEPT_ENCODING", + "HTTP_ACCEPT_LANGUAGE", + "HTTP_CONNECTION", + "HTTP_COOKIE", + "HTTP_HOST", + "HTTP_METHOD", + "HTTP_REFERER", + "HTTP_URL", + "HTTP_USER_AGENT", + "HTTP_VERSION", + "HTTPS", + "HTTPS_KEYSIZE", + "HTTPS_SECRETKEYSIZE", + "HTTPS_SERVER_ISSUER", + "HTTPS_SERVER_SUBJECT", + "INSTANCE_ID", + "INSTANCE_META_PATH", + "LOCAL_ADDR", + "LOGON_USER", + "PATH_INFO", + "PATH_TRANSLATED", + "QUERY_STRING", + "REMOTE_ADDR", + "REMOTE_HOST", + "REMOTE_PORT", + "REMOTE_USER", + "REQUEST_METHOD", + "SCRIPT_NAME", + "SERVER_NAME", + "SERVER_PORT", + "SERVER_PORT_SECURE", + "SERVER_PROTOCOL", + "SERVER_SOFTWARE", + "UNMAPPED_REMOTE_USER", + "URL" + }); + } + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + if (Custom == null) + { + Custom = logFile.CustomLogFields.CreateElement(); + logFile.CustomLogFields.Add(Custom); + } + + Custom.LogFieldName = txtName.Text; + Custom.SourceType = (CustomLogFieldSourceType)Enum.ToObject(typeof(CustomLogFieldSourceType), cbType.SelectedIndex); + Custom.SourceName = cbSource.Text; + DialogResult = DialogResult.OK; + })); + } + + private void AddFieldDialog_HelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210517#W3CLoggingFields"); + } + } +} diff --git a/JexusManager.Features.Logging/AddFieldDialog.resx b/JexusManager.Features.Logging/AddFieldDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Logging/AddFieldDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Logging/FieldsDialog.Designer.cs b/JexusManager.Features.Logging/FieldsDialog.Designer.cs new file mode 100644 index 00000000..bbf2d116 --- /dev/null +++ b/JexusManager.Features.Logging/FieldsDialog.Designer.cs @@ -0,0 +1,204 @@ +namespace JexusManager.Features.Logging +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class FieldsDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.lvStandard = new System.Windows.Forms.ListView(); + this.chName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.label1 = new System.Windows.Forms.Label(); + this.lvCustom = new System.Windows.Forms.ListView(); + this.chField = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chSource = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.label2 = new System.Windows.Forms.Label(); + this.btnAdd = new System.Windows.Forms.Button(); + this.btnRemove = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnEdit = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // lvStandard + // + this.lvStandard.CheckBoxes = true; + this.lvStandard.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chName}); + this.lvStandard.FullRowSelect = true; + this.lvStandard.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; + this.lvStandard.Location = new System.Drawing.Point(12, 36); + this.lvStandard.Name = "lvStandard"; + this.lvStandard.Size = new System.Drawing.Size(545, 235); + this.lvStandard.TabIndex = 0; + this.lvStandard.UseCompatibleStateImageBehavior = false; + this.lvStandard.View = System.Windows.Forms.View.Details; + // + // chName + // + this.chName.Text = "Name"; + this.chName.Width = 350; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(9, 20); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(83, 13); + this.label1.TabIndex = 1; + this.label1.Text = "Standard Fields:"; + // + // lvCustom + // + this.lvCustom.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chField, + this.chType, + this.chSource}); + this.lvCustom.FullRowSelect = true; + this.lvCustom.Location = new System.Drawing.Point(12, 315); + this.lvCustom.Name = "lvCustom"; + this.lvCustom.Size = new System.Drawing.Size(545, 200); + this.lvCustom.TabIndex = 2; + this.lvCustom.UseCompatibleStateImageBehavior = false; + this.lvCustom.View = System.Windows.Forms.View.Details; + // + // chField + // + this.chField.Text = "Log Field"; + this.chField.Width = 175; + // + // chType + // + this.chType.Text = "Source Type"; + this.chType.Width = 175; + // + // chSource + // + this.chSource.Text = "Source"; + this.chSource.Width = 175; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(9, 299); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(75, 13); + this.label2.TabIndex = 3; + this.label2.Text = "Custom Fields:"; + // + // btnAdd + // + this.btnAdd.Location = new System.Drawing.Point(12, 521); + this.btnAdd.Name = "btnAdd"; + this.btnAdd.Size = new System.Drawing.Size(100, 23); + this.btnAdd.TabIndex = 4; + this.btnAdd.Text = "Add Field..."; + this.btnAdd.UseVisualStyleBackColor = true; + // + // btnRemove + // + this.btnRemove.Enabled = false; + this.btnRemove.Location = new System.Drawing.Point(118, 521); + this.btnRemove.Name = "btnRemove"; + this.btnRemove.Size = new System.Drawing.Size(105, 23); + this.btnRemove.TabIndex = 5; + this.btnRemove.Text = "Remove Field"; + this.btnRemove.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(366, 567); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 6; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(462, 567); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 7; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnEdit + // + this.btnEdit.Enabled = false; + this.btnEdit.Location = new System.Drawing.Point(467, 521); + this.btnEdit.Name = "btnEdit"; + this.btnEdit.Size = new System.Drawing.Size(90, 23); + this.btnEdit.TabIndex = 8; + this.btnEdit.Text = "Edit Field..."; + this.btnEdit.UseVisualStyleBackColor = true; + // + // FieldsDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(569, 602); + this.Controls.Add(this.btnEdit); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnRemove); + this.Controls.Add(this.btnAdd); + this.Controls.Add(this.label2); + this.Controls.Add(this.lvCustom); + this.Controls.Add(this.label1); + this.Controls.Add(this.lvStandard); + this.Name = "FieldsDialog"; + this.Text = "W3C Logging Fields"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.FieldsDialog_HelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private ListView lvStandard; + private Label label1; + private ListView lvCustom; + private ColumnHeader chField; + private ColumnHeader chType; + private ColumnHeader chSource; + private Label label2; + private Button btnAdd; + private Button btnRemove; + private Button btnOK; + private Button btnCancel; + private Button btnEdit; + private ColumnHeader chName; + } +} diff --git a/JexusManager.Features.Logging/FieldsDialog.cs b/JexusManager.Features.Logging/FieldsDialog.cs new file mode 100644 index 00000000..5ae256ce --- /dev/null +++ b/JexusManager.Features.Logging/FieldsDialog.cs @@ -0,0 +1,179 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Logging +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reflection; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client.Win32; + + public partial class FieldsDialog : DialogForm + { + private class StandardListViewItem : ListViewItem + { + public StandardListViewItem(LogExtFileFlags flag) + { + Text = ToString(flag); + Flag = flag; + } + + public LogExtFileFlags Flag { get; } + + private static string ToString(LogExtFileFlags flag) + { + FieldInfo fi = typeof(LogExtFileFlags).GetField(flag.ToString()); + DescriptionAttribute dna = + (DescriptionAttribute)Attribute.GetCustomAttribute( + fi, typeof(DescriptionAttribute)); + return dna.Description; + } + } + + private class CustomListViewItem : ListViewItem + { + public CustomLogField Custom { get; } + + public CustomListViewItem(CustomLogField custom) + { + Custom = custom; + Text = custom.LogFieldName; + SubItems.Add(ToString(custom.SourceType)); + SubItems.Add(custom.SourceName); + } + + private static string ToString(CustomLogFieldSourceType type) + { + switch (type) + { + case CustomLogFieldSourceType.RequestHeader: + return "Request Header"; + case CustomLogFieldSourceType.ResponseHeader: + return "Response Header"; + case CustomLogFieldSourceType.ServerVariable: + return "Server Variable"; + default: + throw new ArgumentOutOfRangeException(nameof(type), type, null); + } + } + + public void Update() + { + Text = Custom.LogFieldName; + SubItems[0].Text = ToString(Custom.SourceType); + SubItems[1].Text = Custom.SourceName; + } + } + + public FieldsDialog(IServiceProvider serviceProvider, SiteLogFile logFile) + : base(serviceProvider) + { + InitializeComponent(); + if (logFile.CustomLogFields != null) + { + foreach (CustomLogField custom in logFile.CustomLogFields) + { + lvCustom.Items.Add(new CustomListViewItem(custom)); + } + } + + foreach (LogExtFileFlags flag in Enum.GetValues(typeof(LogExtFileFlags))) + { + lvStandard.Items.Add(new StandardListViewItem(flag) + { + Checked = (logFile.LogExtFileFlags & flag) == flag + }); + } + + btnAdd.Enabled = logFile.CustomLogFields != null; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(lvCustom, "SelectedIndexChanged") + .Subscribe(evt => + { + btnRemove.Enabled = lvCustom.SelectedItems.Count > 0; + btnEdit.Enabled = lvCustom.SelectedItems.Count == 1; + })); + + container.Add( + Observable.FromEventPattern(lvStandard, "ItemChecked") + .Subscribe(evt => + { + btnOK.Enabled = true; + })); + + container.Add( + Observable.FromEventPattern(btnAdd, "Click") + .Subscribe(evt => + { + var dialog = new AddFieldDialog(ServiceProvider, null, logFile); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + lvCustom.Items.Add(new CustomListViewItem(dialog.Custom)); + btnOK.Enabled = true; + })); + + container.Add( + Observable.FromEventPattern(btnEdit, "Click") + .Subscribe(evt => + { + var selected = (CustomListViewItem)lvCustom.SelectedItems[0]; + var dialog = new AddFieldDialog(ServiceProvider, selected.Custom, logFile); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + selected.Update(); + btnOK.Enabled = true; + })); + + container.Add( + Observable.FromEventPattern(btnRemove, "Click") + .Subscribe(evt => + { + foreach (CustomListViewItem item in lvCustom.SelectedItems) + { + item.Remove(); + item.Custom.Delete(); + } + + btnOK.Enabled = true; + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + logFile.LogExtFileFlags = 0; + foreach (StandardListViewItem item in lvStandard.Items) + { + if (item.Checked) + { + logFile.LogExtFileFlags |= item.Flag; + } + } + + DialogResult = DialogResult.OK; + })); + } + + private void FieldsDialog_HelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210517#W3CLoggingFields"); + } + } +} diff --git a/JexusManager.Features.Logging/FieldsDialog.resx b/JexusManager.Features.Logging/FieldsDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Logging/FieldsDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Logging/JexusManager.Features.Logging.csproj b/JexusManager.Features.Logging/JexusManager.Features.Logging.csproj new file mode 100644 index 00000000..9ed1a2cb --- /dev/null +++ b/JexusManager.Features.Logging/JexusManager.Features.Logging.csproj @@ -0,0 +1,141 @@ + + + + + Debug + AnyCPU + {5C2AE18D-D829-481B-8FCA-8AD0F69E68C8} + Library + Properties + JexusManager.Features.Logging + JexusManager.Features.Logging + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + Helper.cs + + + Form + + + AddFieldDialog.cs + + + Form + + + FieldsDialog.cs + + + + + + UserControl + + + LoggingPage.cs + + + + + True + True + Resources.resx + + + + + AddFieldDialog.cs + + + FieldsDialog.cs + + + LoggingPage.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Logging/JexusManager.snk b/JexusManager.Features.Logging/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Logging/LoggingFeature.cs b/JexusManager.Features.Logging/LoggingFeature.cs new file mode 100644 index 00000000..a84fff71 --- /dev/null +++ b/JexusManager.Features.Logging/LoggingFeature.cs @@ -0,0 +1,293 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Logging +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Resources; + using System.Windows.Forms; + + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + internal class LoggingFeature + { + private sealed class FeatureTaskList : TaskList + { + private readonly LoggingFeature _owner; + + public FeatureTaskList(LoggingFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + if (!_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Enable", "Enable", string.Empty).SetUsage()); + } + + if (_owner.IsEnabled) + { + result.Add(new MethodTaskItem("Disable", "Disable", string.Empty).SetUsage()); + } + + result.Add(new MethodTaskItem("View", "View Log Files...", string.Empty).SetUsage()); + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Enable() + { + _owner.Enable(); + } + + [Obfuscation(Exclude = true)] + public void Disable() + { + _owner.Disable(); + } + + [Obfuscation(Exclude = true)] + public void View() + { + _owner.View(); + } + } + + public LoggingFeature(Module module) + { + Module = module; + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + protected void DisplayErrorMessage(Exception ex, ResourceManager resourceManager) + { + var service = (IManagementUIService)GetService(typeof(IManagementUIService)); + service.ShowError(ex, resourceManager.GetString("General"), "", false); + } + + protected object GetService(Type type) + { + return (Module as IServiceProvider).GetService(type); + } + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.applicationHost/log"); + Mode = (long)section.Attributes["centralLogFileMode"].Value; + Encoding = (bool)section.Attributes["logInUTF8"].Value ? 0 : 1; + + if (service.Server != null) + { + var section2 = service.GetSection("system.applicationHost/sites"); + var element = section2.ChildElements["siteDefaults"].ChildElements["logFile"]; + LogFormat = (long)element.Attributes["logFormat"].Value; + Directory = element.Attributes["directory"].Value.ToString(); + if (element.Schema.AttributeSchemas["logTargetW3C"] != null) + { + LogTargetW3C = (long)element.Attributes["logTargetW3C"].Value; + } + else + { + this.LogTargetW3C = -1; + } + + LocalTimeRollover = (bool)element.Attributes["localTimeRollover"].Value; + TruncateSize = (long)element.Attributes["truncateSize"].Value; + Period = (long)element.Attributes["period"].Value; + } + else + { + var logFile = service.Application.GetSite().LogFile; + LogFormat = (long)logFile.LogFormat; + Directory = logFile.Directory; + if (logFile.Schema.AttributeSchemas["logTargetW3C"] != null) + { + LogTargetW3C = (long)logFile.LogTargetW3C; + } + else + { + this.LogTargetW3C = -1; + } + + LocalTimeRollover = logFile.LocalTimeRollover; + TruncateSize = logFile.TruncateSize; + Period = (long)logFile.Period; + } + + CanBrowse = service.Application == null || service.Application.IsRoot(); + CanEncoding = service.Server != null; + + ConfigurationSection httpLoggingSection1 = service.GetSection("system.webServer/httpLogging", null, false); + var dontLog = (bool)httpLoggingSection1["dontLog"]; + SetEnabled(!dontLog); + } + + public long Period { get; set; } + + public long TruncateSize { get; set; } + + public bool LocalTimeRollover { get; set; } + + public long LogTargetW3C { get; set; } + + public bool CanBrowse { get; set; } + + public long LogFormat { get; set; } + + public string Directory { get; set; } + + public int Encoding { get; set; } + + public long Mode { get; set; } + + private void Enable() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + ConfigurationSection httpLoggingSection1 = service.GetSection("system.webServer/httpLogging", null, false); + httpLoggingSection1["dontLog"] = false; + SetEnabled(true); + } + + private void Disable() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + ConfigurationSection httpLoggingSection1 = service.GetSection("system.webServer/httpLogging", null, false); + httpLoggingSection1["dontLog"] = true; + SetEnabled(false); + } + + private void View() + { + var path = Directory.ExpandIisExpressEnvironmentVariables(); + if (System.IO.Directory.Exists(path)) + { + Process.Start(path); + return; + } + + var service = (IManagementUIService)GetService(typeof(IManagementUIService)); + service.ShowMessage("The specific log directory is invalid.", Name, MessageBoxButtons.OK, MessageBoxIcon.Warning); + } + + internal void SelectFields() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var dialog = new FieldsDialog(Module, service.Application.GetSite().LogFile); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + service.ServerManager.CommitChanges(); + } + + protected void OnLoggingSettingsSaved() + { + LoggingSettingsUpdated?.Invoke(); + } + + public void SetEnabled(bool enabled) + { + IsEnabled = enabled; + OnLoggingSettingsSaved(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210517"); + return false; + } + + public LoggingSettingsSavedEventHandler LoggingSettingsUpdated { get; set; } + public string Description { get; } + public bool IsEnabled { get; private set; } + + public virtual bool IsFeatureEnabled + { + get { return true; } + } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public Module Module { get; } + + public string Name + { + get { return "Logging"; } + } + + public bool CanEncoding { get; set; } + + public void CancelChanges() + { + Load(); + } + + public bool ApplyChanges() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + if (service.Server != null) + { + var section = service.GetSection("system.applicationHost/log"); + section.Attributes["centralLogFileMode"].Value = Mode; + section.Attributes["logInUTF8"].Value = Encoding == 0; + + var section2 = service.GetSection("system.applicationHost/sites"); + var element = section2.ChildElements["siteDefaults"].ChildElements["logFile"]; + element.Attributes["logFormat"].Value = LogFormat; + element.Attributes["directory"].Value = Directory; + if (element.Schema.AttributeSchemas["logTargetW3C"] != null) + { + element.Attributes["logTargetW3C"].Value = LogTargetW3C; + } + + element.Attributes["localTimeRollover"].Value = LocalTimeRollover; + element.Attributes["truncateSize"].Value = TruncateSize; + element.Attributes["period"].Value = Period; + } + else + { + var logFile = service.Application.GetSite().LogFile; + logFile.LogFormat = (LogFormat)LogFormat; + logFile.Directory = Directory; + if (logFile.Schema.AttributeSchemas["logTargetW3C"] != null) + { + logFile.LogTargetW3C = (LogTargetW3C)LogTargetW3C; + } + + logFile.LocalTimeRollover = LocalTimeRollover; + logFile.TruncateSize = TruncateSize; + logFile.Period = (LoggingRolloverPeriod)Period; + } + + return true; + } + } +} diff --git a/JexusManager.Features.Logging/LoggingModule.cs b/JexusManager.Features.Logging/LoggingModule.cs new file mode 100644 index 00000000..b527e71f --- /dev/null +++ b/JexusManager.Features.Logging/LoggingModule.cs @@ -0,0 +1,26 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Logging +{ + using System; + + using Properties; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + + internal class LoggingModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(LoggingPage), "Logging", + "Configure how IIS logs requests on the Web server", + Resources.logging_36, Resources.logging_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.Logging/LoggingModuleProvider.cs b/JexusManager.Features.Logging/LoggingModuleProvider.cs new file mode 100644 index 00000000..c205c192 --- /dev/null +++ b/JexusManager.Features.Logging/LoggingModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Logging +{ + using System; + + using Microsoft.Web.Management.Server; + + public class LoggingModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(Name, typeof(LoggingModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.Logging/LoggingPage.Designer.cs b/JexusManager.Features.Logging/LoggingPage.Designer.cs new file mode 100644 index 00000000..f29bcdc8 --- /dev/null +++ b/JexusManager.Features.Logging/LoggingPage.Designer.cs @@ -0,0 +1,546 @@ +namespace JexusManager.Features.Logging +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class LoggingPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.cbLocalTime = new System.Windows.Forms.CheckBox(); + this.rbNoFile = new System.Windows.Forms.RadioButton(); + this.txtSize = new System.Windows.Forms.TextBox(); + this.rbSize = new System.Windows.Forms.RadioButton(); + this.cbSchedule = new System.Windows.Forms.ComboBox(); + this.rbSchedule = new System.Windows.Forms.RadioButton(); + this.label9 = new System.Windows.Forms.Label(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.rbBoth = new System.Windows.Forms.RadioButton(); + this.rbEvent = new System.Windows.Forms.RadioButton(); + this.rbFile = new System.Windows.Forms.RadioButton(); + this.label8 = new System.Windows.Forms.Label(); + this.label4 = new System.Windows.Forms.Label(); + this.cbLogType = new System.Windows.Forms.ComboBox(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.cbEncoding = new System.Windows.Forms.ComboBox(); + this.label7 = new System.Windows.Forms.Label(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.label6 = new System.Windows.Forms.Label(); + this.btnSelect = new System.Windows.Forms.Button(); + this.cbFormat = new System.Windows.Forms.ComboBox(); + this.label5 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.groupBox3.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.groupBox1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.label2); + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 4; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.splitContainer1_SplitterMoved); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.AutoScroll = true; + this.panel2.Controls.Add(this.groupBox3); + this.panel2.Controls.Add(this.groupBox2); + this.panel2.Controls.Add(this.label4); + this.panel2.Controls.Add(this.cbLogType); + this.panel2.Controls.Add(this.groupBox1); + this.panel2.Location = new System.Drawing.Point(10, 69); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 7; + // + // groupBox3 + // + this.groupBox3.Controls.Add(this.cbLocalTime); + this.groupBox3.Controls.Add(this.rbNoFile); + this.groupBox3.Controls.Add(this.txtSize); + this.groupBox3.Controls.Add(this.rbSize); + this.groupBox3.Controls.Add(this.cbSchedule); + this.groupBox3.Controls.Add(this.rbSchedule); + this.groupBox3.Controls.Add(this.label9); + this.groupBox3.Location = new System.Drawing.Point(6, 429); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Size = new System.Drawing.Size(517, 219); + this.groupBox3.TabIndex = 7; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "Log File Rollover"; + // + // cbLocalTime + // + this.cbLocalTime.AutoSize = true; + this.cbLocalTime.Location = new System.Drawing.Point(9, 189); + this.cbLocalTime.Name = "cbLocalTime"; + this.cbLocalTime.Size = new System.Drawing.Size(218, 17); + this.cbLocalTime.TabIndex = 6; + this.cbLocalTime.Text = "Use local time for file naming and rollover"; + this.cbLocalTime.UseVisualStyleBackColor = true; + this.cbLocalTime.CheckedChanged += new System.EventHandler(this.cbLocalTime_CheckedChanged); + // + // rbNoFile + // + this.rbNoFile.AutoSize = true; + this.rbNoFile.Location = new System.Drawing.Point(9, 154); + this.rbNoFile.Name = "rbNoFile"; + this.rbNoFile.Size = new System.Drawing.Size(151, 17); + this.rbNoFile.TabIndex = 5; + this.rbNoFile.TabStop = true; + this.rbNoFile.Text = "Do not create new log files"; + this.rbNoFile.UseVisualStyleBackColor = true; + this.rbNoFile.CheckedChanged += new System.EventHandler(this.rbSchedule_CheckedChanged); + // + // txtSize + // + this.txtSize.Location = new System.Drawing.Point(24, 128); + this.txtSize.Name = "txtSize"; + this.txtSize.Size = new System.Drawing.Size(110, 20); + this.txtSize.TabIndex = 4; + // + // rbSize + // + this.rbSize.AutoSize = true; + this.rbSize.Location = new System.Drawing.Point(9, 105); + this.rbSize.Name = "rbSize"; + this.rbSize.Size = new System.Drawing.Size(154, 17); + this.rbSize.TabIndex = 3; + this.rbSize.TabStop = true; + this.rbSize.Text = "Maximum file size (in bytes):"; + this.rbSize.UseVisualStyleBackColor = true; + this.rbSize.CheckedChanged += new System.EventHandler(this.rbSchedule_CheckedChanged); + // + // cbSchedule + // + this.cbSchedule.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbSchedule.FormattingEnabled = true; + this.cbSchedule.Items.AddRange(new object[] { + "Hourly", + "Daily", + "Weekly", + "Monthly"}); + this.cbSchedule.Location = new System.Drawing.Point(24, 78); + this.cbSchedule.Name = "cbSchedule"; + this.cbSchedule.Size = new System.Drawing.Size(175, 21); + this.cbSchedule.TabIndex = 2; + // + // rbSchedule + // + this.rbSchedule.AutoSize = true; + this.rbSchedule.Location = new System.Drawing.Point(9, 55); + this.rbSchedule.Name = "rbSchedule"; + this.rbSchedule.Size = new System.Drawing.Size(73, 17); + this.rbSchedule.TabIndex = 1; + this.rbSchedule.TabStop = true; + this.rbSchedule.Text = "Schedule:"; + this.rbSchedule.UseVisualStyleBackColor = true; + this.rbSchedule.CheckedChanged += new System.EventHandler(this.rbSchedule_CheckedChanged); + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(21, 29); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(268, 13); + this.label9.TabIndex = 0; + this.label9.Text = "Select the method that IIS uses to create a new log file."; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.rbBoth); + this.groupBox2.Controls.Add(this.rbEvent); + this.groupBox2.Controls.Add(this.rbFile); + this.groupBox2.Controls.Add(this.label8); + this.groupBox2.Location = new System.Drawing.Point(6, 265); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(517, 147); + this.groupBox2.TabIndex = 6; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Log Event Destination"; + // + // rbBoth + // + this.rbBoth.AutoSize = true; + this.rbBoth.Location = new System.Drawing.Point(9, 110); + this.rbBoth.Name = "rbBoth"; + this.rbBoth.Size = new System.Drawing.Size(159, 17); + this.rbBoth.TabIndex = 3; + this.rbBoth.TabStop = true; + this.rbBoth.Text = "Both log file and ETW event"; + this.rbBoth.UseVisualStyleBackColor = true; + this.rbBoth.CheckedChanged += new System.EventHandler(this.rbFile_CheckedChanged); + // + // rbEvent + // + this.rbEvent.AutoSize = true; + this.rbEvent.Location = new System.Drawing.Point(9, 83); + this.rbEvent.Name = "rbEvent"; + this.rbEvent.Size = new System.Drawing.Size(102, 17); + this.rbEvent.TabIndex = 2; + this.rbEvent.TabStop = true; + this.rbEvent.Text = "ETW event only"; + this.rbEvent.UseVisualStyleBackColor = true; + this.rbEvent.CheckedChanged += new System.EventHandler(this.rbFile_CheckedChanged); + // + // rbFile + // + this.rbFile.AutoSize = true; + this.rbFile.Location = new System.Drawing.Point(9, 56); + this.rbFile.Name = "rbFile"; + this.rbFile.Size = new System.Drawing.Size(81, 17); + this.rbFile.TabIndex = 1; + this.rbFile.TabStop = true; + this.rbFile.Text = "Log file only"; + this.rbFile.UseVisualStyleBackColor = true; + this.rbFile.CheckedChanged += new System.EventHandler(this.rbFile_CheckedChanged); + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(13, 28); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(254, 13); + this.label8.TabIndex = 0; + this.label8.Text = "Select the destination where IIS will write log events."; + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(3, 6); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(81, 13); + this.label4.TabIndex = 3; + this.label4.Text = "One log file per:"; + // + // cbLogType + // + this.cbLogType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbLogType.Enabled = false; + this.cbLogType.FormattingEnabled = true; + this.cbLogType.Items.AddRange(new object[] { + "Server", + "Site"}); + this.cbLogType.Location = new System.Drawing.Point(6, 22); + this.cbLogType.Name = "cbLogType"; + this.cbLogType.Size = new System.Drawing.Size(121, 21); + this.cbLogType.TabIndex = 4; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.cbEncoding); + this.groupBox1.Controls.Add(this.label7); + this.groupBox1.Controls.Add(this.btnBrowse); + this.groupBox1.Controls.Add(this.txtPath); + this.groupBox1.Controls.Add(this.label6); + this.groupBox1.Controls.Add(this.btnSelect); + this.groupBox1.Controls.Add(this.cbFormat); + this.groupBox1.Controls.Add(this.label5); + this.groupBox1.Location = new System.Drawing.Point(6, 50); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(517, 188); + this.groupBox1.TabIndex = 5; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Log File"; + // + // cbEncoding + // + this.cbEncoding.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbEncoding.Enabled = false; + this.cbEncoding.FormattingEnabled = true; + this.cbEncoding.Items.AddRange(new object[] { + "UTF-8", + "ANSI"}); + this.cbEncoding.Location = new System.Drawing.Point(9, 152); + this.cbEncoding.Name = "cbEncoding"; + this.cbEncoding.Size = new System.Drawing.Size(158, 21); + this.cbEncoding.TabIndex = 7; + this.cbEncoding.SelectedIndexChanged += new System.EventHandler(this.cbEncoding_SelectedIndexChanged); + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(6, 136); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(55, 13); + this.label7.TabIndex = 6; + this.label7.Text = "Encoding:"; + // + // btnBrowse + // + this.btnBrowse.Enabled = false; + this.btnBrowse.Location = new System.Drawing.Point(379, 95); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(95, 23); + this.btnBrowse.TabIndex = 5; + this.btnBrowse.Text = "Browse..."; + this.btnBrowse.UseVisualStyleBackColor = true; + this.btnBrowse.Click += new System.EventHandler(this.btnBrowse_Click); + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(9, 97); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(364, 20); + this.txtPath.TabIndex = 4; + this.txtPath.TextChanged += new System.EventHandler(this.txtPath_TextChanged); + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(6, 81); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(52, 13); + this.label6.TabIndex = 3; + this.label6.Text = "Directory:"; + // + // btnSelect + // + this.btnSelect.Enabled = false; + this.btnSelect.Location = new System.Drawing.Point(173, 42); + this.btnSelect.Name = "btnSelect"; + this.btnSelect.Size = new System.Drawing.Size(95, 23); + this.btnSelect.TabIndex = 2; + this.btnSelect.Text = "Select Fields..."; + this.btnSelect.UseVisualStyleBackColor = true; + this.btnSelect.Click += new System.EventHandler(this.btnSelect_Click); + // + // cbFormat + // + this.cbFormat.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbFormat.Enabled = false; + this.cbFormat.FormattingEnabled = true; + this.cbFormat.Items.AddRange(new object[] { + "IIS", + "NCSA", + "W3C", + "Custom"}); + this.cbFormat.Location = new System.Drawing.Point(9, 44); + this.cbFormat.Name = "cbFormat"; + this.cbFormat.Size = new System.Drawing.Size(158, 21); + this.cbFormat.TabIndex = 1; + this.cbFormat.SelectedIndexChanged += new System.EventHandler(this.cbFormat_SelectedIndexChanged); + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(6, 28); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(42, 13); + this.label5.TabIndex = 0; + this.label5.Text = "Format:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(7, 48); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(338, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to configure how IIS logs requests on the Web server."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 6; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(89, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Logging"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, -17); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // LoggingPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "LoggingPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.groupBox3.ResumeLayout(false); + this.groupBox3.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private GroupBox groupBox1; + private ComboBox cbEncoding; + private Label label7; + private Button btnBrowse; + private TextBox txtPath; + private Label label6; + private Button btnSelect; + private ComboBox cbFormat; + private Label label5; + private ComboBox cbLogType; + private Label label4; + private Panel panel2; + private PictureBox pictureBox1; + private ContextMenuStrip cmsActionPanel; + private GroupBox groupBox3; + private CheckBox cbLocalTime; + private RadioButton rbNoFile; + private TextBox txtSize; + private RadioButton rbSize; + private ComboBox cbSchedule; + private RadioButton rbSchedule; + private Label label9; + private GroupBox groupBox2; + private RadioButton rbBoth; + private RadioButton rbEvent; + private RadioButton rbFile; + private Label label8; + } +} diff --git a/JexusManager.Features.Logging/LoggingPage.cs b/JexusManager.Features.Logging/LoggingPage.cs new file mode 100644 index 00000000..77fa4851 --- /dev/null +++ b/JexusManager.Features.Logging/LoggingPage.cs @@ -0,0 +1,274 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Logging +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class LoggingPage : ModuleDialogPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly LoggingPage _owner; + + public PageTaskList(LoggingPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private PageTaskList _taskList; + private LoggingFeature _feature; + private bool _hasChanges; + private bool _initialized; + + public LoggingPage() + { + InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new LoggingFeature(Module); + _feature.LoggingSettingsUpdated = Refresh; + _feature.Load(); + } + + protected override bool ShowHelp() + { + return _feature.ShowHelp(); + } + + private void splitContainer1_SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + private void btnBrowse_Click(object sender, EventArgs e) + { + DialogHelper.ShowBrowseDialog(txtPath); + _feature.Directory = txtPath.Text; + InformChanges(); + } + + private void cbFormat_SelectedIndexChanged(object sender, EventArgs e) + { + btnSelect.Enabled = cbFormat.SelectedIndex == cbFormat.Items.Count - 1; + _feature.LogFormat = cbFormat.SelectedIndex; + InformChanges(); + } + + private void InformChanges() + { + if (!_initialized) + { + return; + } + + _hasChanges = true; + Refresh(); + } + + private void ClearChanges() + { + _hasChanges = false; + Refresh(); + } + + protected override void OnRefresh() + { + if (!_hasChanges) + { + cbLogType.SelectedIndex = (int)_feature.Mode; + cbEncoding.SelectedIndex = _feature.Encoding; + cbFormat.SelectedIndex = (int)_feature.LogFormat; + txtPath.Text = _feature.Directory; + txtPath.Enabled = _feature.CanBrowse && _feature.IsEnabled; + btnSelect.Enabled = _feature.IsEnabled; + btnBrowse.Enabled = _feature.CanBrowse && _feature.IsEnabled; + cbFormat.Enabled = _feature.CanBrowse && _feature.IsEnabled; + cbEncoding.Enabled = _feature.CanEncoding; + + rbFile.Enabled = rbEvent.Enabled = rbBoth.Enabled = _feature.LogTargetW3C == -1; + if (_feature.LogTargetW3C != -1) + { + switch (_feature.LogTargetW3C) + { + case 1: + rbFile.Checked = true; + break; + case 2: + rbEvent.Checked = true; + break; + default: + rbBoth.Checked = true; + break; + } + } + + if (_feature.Period == 0) + { + rbSize.Checked = true; + cbSchedule.Enabled = false; + txtSize.Text = _feature.TruncateSize.ToString(); + } + else + { + rbSchedule.Checked = true; + txtSize.Enabled = false; + switch (_feature.Period) + { + case 2: + cbSchedule.SelectedIndex = 2; + break; + case 1: + cbSchedule.SelectedIndex = 1; + break; + case 4: + cbSchedule.SelectedIndex = 0; + break; + case 3: + cbSchedule.SelectedIndex = 3; + break; + } + } + + cbLocalTime.Checked = _feature.LocalTimeRollover; + + _initialized = true; + } + + Tasks.Fill(tsActionPanel, cmsActionPanel); + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + + private void txtPath_TextChanged(object sender, EventArgs e) + { + _feature.Directory = txtPath.Text; + InformChanges(); + } + + protected override bool HasChanges + { + get { return _hasChanges; } + } + + protected override bool CanApplyChanges + { + get { return true; } + } + + private void cbEncoding_SelectedIndexChanged(object sender, EventArgs e) + { + _feature.Encoding = cbEncoding.SelectedIndex; + InformChanges(); + } + + protected override bool ApplyChanges() + { + if (!_feature.ApplyChanges()) + { + return false; + } + + ClearChanges(); + return true; + } + + protected override void CancelChanges() + { + _feature.CancelChanges(); + ClearChanges(); + } + + private void btnSelect_Click(object sender, EventArgs e) + { + _feature.SelectFields(); + } + + private void rbFile_CheckedChanged(object sender, EventArgs e) + { + if (rbFile.Checked) + { + _feature.LogTargetW3C = 1; + } + else if (rbEvent.Checked) + { + _feature.LogTargetW3C = 2; + } + else + { + _feature.LogTargetW3C = 3; + } + } + + private void rbSchedule_CheckedChanged(object sender, EventArgs e) + { + if (rbSchedule.Checked) + { + switch (cbSchedule.SelectedIndex) + { + case 0: + _feature.Period = 4; + break; + case 1: + _feature.Period = 1; + break; + case 2: + _feature.Period = 2; + break; + case 3: + _feature.Period = 3; + break; + } + } + else if (rbSize.Checked) + { + _feature.Period = 0; + _feature.TruncateSize = long.Parse(txtSize.Text); + } + } + + private void cbLocalTime_CheckedChanged(object sender, EventArgs e) + { + _feature.LocalTimeRollover = cbLocalTime.Checked; + } + } +} diff --git a/JexusManager.Features.Logging/LoggingPage.resx b/JexusManager.Features.Logging/LoggingPage.resx new file mode 100644 index 00000000..5849981e --- /dev/null +++ b/JexusManager.Features.Logging/LoggingPage.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 143, 17 + + + 17, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.Logging/LoggingSettingsSavedEventHandler.cs b/JexusManager.Features.Logging/LoggingSettingsSavedEventHandler.cs new file mode 100644 index 00000000..d34e4924 --- /dev/null +++ b/JexusManager.Features.Logging/LoggingSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Logging +{ + public delegate void LoggingSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.Logging/Properties/AssemblyInfo.cs b/JexusManager.Features.Logging/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..1e24a619 --- /dev/null +++ b/JexusManager.Features.Logging/Properties/AssemblyInfo.cs @@ -0,0 +1,40 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.Logging")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.Logging")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("5c2ae18d-d829-481b-8fca-8ad0f69e68c8")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/JexusManager.Features.Logging/Properties/Resources.Designer.cs b/JexusManager.Features.Logging/Properties/Resources.Designer.cs new file mode 100644 index 00000000..bf8a19c1 --- /dev/null +++ b/JexusManager.Features.Logging/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.Logging.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.Logging.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap logging_36 { + get { + object obj = ResourceManager.GetObject("logging_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.Logging/Properties/Resources.resx b/JexusManager.Features.Logging/Properties/Resources.resx new file mode 100644 index 00000000..4ee996c0 --- /dev/null +++ b/JexusManager.Features.Logging/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\logging_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.Logging/Resources/logging_36.png b/JexusManager.Features.Logging/Resources/logging_36.png new file mode 100644 index 0000000000000000000000000000000000000000..903e25a092825ee1d196537e0b9d6c014c9acc63 GIT binary patch literal 1893 zcmV-r2b%baP)%~i~$<4qckj)h)oqNCW(2;~X)@Vos(6Qq$b721iD5dz(k>|hi z@+t4Bj;^F0pDCdD{~;-*=t+0<uKRfHwco5xCfB~2PGvR?4qx$R=B`mzsX+Ke>yjzlm@7(^AnR7QyiD9H4AOkG=~wExNb-Z-dUT~k(I00NClCI)C_2~Ek6IrJ)C`K^l4yuK!rkqd_KqQ-29!c z>$NPF-lH^ef#Dg$`VD=wx5tAhtbEsas(K+X6NGFq9w1xxh_|)jx^A-3Qgrx7E|)v6 z(4Z0zKl+(l*w{MBcfPcj4E_!;_^45udX7V;`lAV#2`iLT4F{VP5ktzuPe#8u(XSi;Z z0raF&M^oJyPM?uSlb(^4X(*LW-_em+#kuqU#&{kJMa{XJb%`7!z%*vu{X=0=}kG*i2OOqbmnKbcut6vtX zQC8^;YelxcA*hxQk;*nmj2~r9AT>>lhac=^S0>97U%rPs(sPWBO)b$6K^HGXdmp7L zlT-cnw;*9^Z#XgDyYDX2J>C4Zzn`hBrn9phg#;}~Wzx!oS}BxPXiH;hjaC}1ROMPL zwAR73rB%bm?YfEa$A22#zjgaIE>5hnARwZCNYxP(ELvYqjC*;KVO`lQBBVBYa|GmKXacC>Gb# zyDo(m0gIq+)mAFeJ*)(B_PwP5gJ;09HPS@Y5kT2&_IuOQ(@(DM?Ai3QL){dLC0b)? zhTa|J^qh-rSx9xmWry18V3QW5E3y?301Hn9$F@O?4Yc|rOAP^?9ys&E-oBJc#1l^# zQC8lyI5S*ksIY;pTh?J)I$&9rKXs|w^H(uBmc|GmZq7deDFV~LV%>Q_Jl>}A`9cTK zmfHLE#}7Pk|07#ArnOeowVl#z_9kG(KOyjp@YdhnF8=)wzy878+b_Kc%mWiZnI_q( z6{XgIPIkWk!2`4;*H;qCjhvG$=RSiwf9Y)Y!teV* + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.MimeMap/JexusManager.Features.MimeMap.csproj b/JexusManager.Features.MimeMap/JexusManager.Features.MimeMap.csproj new file mode 100644 index 00000000..c9d8f5cf --- /dev/null +++ b/JexusManager.Features.MimeMap/JexusManager.Features.MimeMap.csproj @@ -0,0 +1,130 @@ + + + + + Debug + AnyCPU + {FD1A63C6-458F-496B-9923-80ECA082C7EC} + Library + Properties + JexusManager.Features.MimeMap + JexusManager.Features.MimeMap + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + + + + + UserControl + + + MimeMapPage.cs + + + + Form + + + NewMapItemDialog.cs + + + + True + True + Resources.resx + + + + + MimeMapPage.cs + + + NewMapItemDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.MimeMap/JexusManager.snk b/JexusManager.Features.MimeMap/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.MimeMap/MimeMapFeature.cs b/JexusManager.Features.MimeMap/MimeMapFeature.cs new file mode 100644 index 00000000..3331d07d --- /dev/null +++ b/JexusManager.Features.MimeMap/MimeMapFeature.cs @@ -0,0 +1,170 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/* + * Created by SharpDevelop. + * User: lextm + * Time: 11:06 AM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace JexusManager.Features.MimeMap +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + /// + /// Description of DefaultDocumentFeature. + /// + internal class MimeMapFeature : FeatureBase + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly MimeMapFeature _owner; + + public FeatureTaskList(MimeMapFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("Add", "Add...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Edit", "Edit...", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Add() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void Edit() + { + _owner.Edit(); + } + } + + public MimeMapFeature(Module module) + : base(module) + { + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + ConfigurationSection section = service.GetSection("system.webServer/staticContent"); + this.CanRevert = section.CanRevert(); + LoadItems(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + ConfigurationSection section = service.GetSection("system.webServer/staticContent"); + return section.GetCollection(); + } + + public void Add() + { + var dialog = new NewMapItemDialog(this.Module, null, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected authorization rule?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + public void Edit() + { + var dialog = new NewMapItemDialog(this.Module, this.SelectedItem, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.EditItem(dialog.Item); + } + + protected override void OnSettingsSaved() + { + this.MimeMapSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210520"); + return false; + } + + public bool CanRevert { get; private set; } + + public MimeMapSettingsSavedEventHandler MimeMapSettingsUpdated { get; set; } + + public string Description { get; } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public string Name + { + get { return "MIME Types"; } + } + } +} diff --git a/JexusManager.Features.MimeMap/MimeMapItem.cs b/JexusManager.Features.MimeMap/MimeMapItem.cs new file mode 100644 index 00000000..cd1317cc --- /dev/null +++ b/JexusManager.Features.MimeMap/MimeMapItem.cs @@ -0,0 +1,50 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.MimeMap +{ + using Microsoft.Web.Administration; + + internal class MimeMapItem : IItem + { + public MimeMapItem(ConfigurationElement element) + { + this.Element = element; + this.Flag = element == null || element.IsLocallyStored ? "Local" : "Inhertied"; + if (element == null) + { + return; + } + + this.FileExtension = (string)element["fileExtension"]; + this.MimeType = (string)element["mimeType"]; + } + + public string MimeType { get; set; } + + public string FileExtension { get; set; } + + public ConfigurationElement Element { get; set; } + + public string Flag { get; set; } + + public bool Equals(MimeMapItem other) + { + // all properties + return this.Match(other) && other.MimeType == this.MimeType; + } + + public void Apply() + { + this.Element["fileExtension"] = this.FileExtension; + this.Element["mimeType"] = this.MimeType; + } + + public bool Match(MimeMapItem other) + { + // match combined keys. + return other != null && other.FileExtension == this.FileExtension; + } + } +} diff --git a/JexusManager.Features.MimeMap/MimeMapModule.cs b/JexusManager.Features.MimeMap/MimeMapModule.cs new file mode 100644 index 00000000..e4bd60af --- /dev/null +++ b/JexusManager.Features.MimeMap/MimeMapModule.cs @@ -0,0 +1,26 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.MimeMap +{ + using System; + + using Properties; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + + internal class MimeMapModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)this.GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(MimeMapPage), "MIME Types", + "Configure extensions and associated content types that are served as static files", Resources.mime_map_36, + Resources.mime_map_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.MimeMap/MimeMapModuleProvider.cs b/JexusManager.Features.MimeMap/MimeMapModuleProvider.cs new file mode 100644 index 00000000..091f198c --- /dev/null +++ b/JexusManager.Features.MimeMap/MimeMapModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.MimeMap +{ + using System; + + using Microsoft.Web.Management.Server; + + public class MimeMapModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(this.Name, typeof(MimeMapModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.MimeMap/MimeMapPage.Designer.cs b/JexusManager.Features.MimeMap/MimeMapPage.Designer.cs new file mode 100644 index 00000000..e3d54338 --- /dev/null +++ b/JexusManager.Features.MimeMap/MimeMapPage.Designer.cs @@ -0,0 +1,290 @@ +namespace JexusManager.Features.MimeMap +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class MimeMapPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chExtension = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chMime = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.toolStrip2 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel2 = new System.Windows.Forms.ToolStripLabel(); + this.cbGroup = new System.Windows.Forms.ToolStripComboBox(); + this.label2 = new System.Windows.Forms.Label(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.toolStrip2.SuspendLayout(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 6; + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.toolStrip2); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 6; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chExtension, + this.chMime, + this.chType}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 38); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 502); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.listView1_SelectedIndexChanged); + // + // chExtension + // + this.chExtension.Text = "Extension"; + this.chExtension.Width = 120; + // + // chMime + // + this.chMime.Text = "MIME Type"; + this.chMime.Width = 120; + // + // chType + // + this.chType.Text = "Entry Type"; + this.chType.Width = 120; + // + // toolStrip2 + // + this.toolStrip2.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel2, + this.cbGroup}); + this.toolStrip2.Location = new System.Drawing.Point(0, 13); + this.toolStrip2.Name = "toolStrip2"; + this.toolStrip2.Size = new System.Drawing.Size(560, 25); + this.toolStrip2.TabIndex = 3; + this.toolStrip2.Text = "toolStrip2"; + // + // toolStripLabel2 + // + this.toolStripLabel2.Name = "toolStripLabel2"; + this.toolStripLabel2.Size = new System.Drawing.Size(59, 22); + this.toolStripLabel2.Text = "Group by:"; + // + // cbGroup + // + this.cbGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbGroup.Items.AddRange(new object[] { + "No Grouping", + "Status", + "IP Address", + "Protocol", + "Port"}); + this.cbGroup.Name = "cbGroup"; + this.cbGroup.Size = new System.Drawing.Size(121, 25); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(649, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to manage the list of file name extensions and associated conten" + + "t types that are served as static files by the Web server."; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(132, 25); + this.label3.TabIndex = 2; + this.label3.Text = "MIME Types"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 5; + this.pictureBox1.TabStop = false; + // + // MimeMapPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "MimeMapPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.toolStrip2.ResumeLayout(false); + this.toolStrip2.PerformLayout(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private ListView listView1; + private ColumnHeader chType; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Panel panel2; + private ToolStrip toolStrip2; + private ToolStripLabel toolStripLabel2; + private ToolStripComboBox cbGroup; + private PictureBox pictureBox1; + private ContextMenuStrip cmsActionPanel; + private ColumnHeader chExtension; + private ColumnHeader chMime; + } +} diff --git a/JexusManager.Features.MimeMap/MimeMapPage.cs b/JexusManager.Features.MimeMap/MimeMapPage.cs new file mode 100644 index 00000000..a705c7e4 --- /dev/null +++ b/JexusManager.Features.MimeMap/MimeMapPage.cs @@ -0,0 +1,130 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.MimeMap +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class MimeMapPage : ModuleListPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly MimeMapPage _owner; + + public PageTaskList(MimeMapPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class MimeMapListViewItem : ListViewItem + { + public MimeMapItem Item { get; } + + private readonly MimeMapPage _page; + + public MimeMapListViewItem(MimeMapItem item, MimeMapPage page) + : base(item.FileExtension) + { + this.Item = item; + _page = page; + this.SubItems.Add(new ListViewSubItem(this, item.MimeType)); + this.SubItems.Add(new ListViewSubItem(this, item.Flag)); + } + } + + private MimeMapFeature _feature; + private PageTaskList _taskList; + + public MimeMapPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new MimeMapFeature(this.Module); + _feature.MimeMapSettingsUpdated = this.InitializeListPage; + _feature.Load(); + } + + protected override void InitializeListPage() + { + listView1.Items.Clear(); + foreach (var file in _feature.Items) + { + listView1.Items.Add(new MimeMapListViewItem(file, this)); + } + + if (_feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (MimeMapListViewItem item in listView1.Items) + { + if (item.Item == _feature.SelectedItem) + { + item.Selected = true; + } + } + } + + protected override void Refresh() + { + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + private void listView1_SelectedIndexChanged(object sender, EventArgs e) + { + _feature.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((MimeMapListViewItem)listView1.SelectedItems[0]).Item + : null; + // TODO: optimize refresh when null to not null (vice versa) + this.Refresh(); + } + + protected override bool ShowHelp() + { + _feature.ShowHelp(); + return true; + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + } +} diff --git a/JexusManager.Features.MimeMap/MimeMapPage.resx b/JexusManager.Features.MimeMap/MimeMapPage.resx new file mode 100644 index 00000000..464d127c --- /dev/null +++ b/JexusManager.Features.MimeMap/MimeMapPage.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 602, 17 + + + 497, 17 + + + 17, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.MimeMap/MimeMapSettingsSavedEventHandler.cs b/JexusManager.Features.MimeMap/MimeMapSettingsSavedEventHandler.cs new file mode 100644 index 00000000..2ed136af --- /dev/null +++ b/JexusManager.Features.MimeMap/MimeMapSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.MimeMap +{ + public delegate void MimeMapSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.MimeMap/NewMapItemDialog.cs b/JexusManager.Features.MimeMap/NewMapItemDialog.cs new file mode 100644 index 00000000..cb9efef5 --- /dev/null +++ b/JexusManager.Features.MimeMap/NewMapItemDialog.cs @@ -0,0 +1,71 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.MimeMap +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewMapItemDialog : DialogForm + { + public NewMapItemDialog(IServiceProvider serviceProvider, MimeMapItem existing, MimeMapFeature feature) + : base(serviceProvider) + { + InitializeComponent(); + Text = string.Format("{0} MIME Type", existing == null ? "Add" : "Edit"); + Item = existing ?? new MimeMapItem(null); + if (existing != null) + { + txtExtension.Text = Item.FileExtension; + txtType.Text = Item.MimeType; + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item.FileExtension = txtExtension.Text; + Item.MimeType = txtType.Text; + if (feature.Items.Any(item => item.Match(Item))) + { + ShowMessage( + "This MIME map already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(txtExtension, "TextChanged") + .Merge(Observable.FromEventPattern(txtType, "TextChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtExtension.Text) + && !string.IsNullOrWhiteSpace(txtType.Text); + })); + } + + public MimeMapItem Item { get; set; } + + private void NewRestrictionDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210520"); + } + } +} diff --git a/JexusManager.Features.MimeMap/NewMapItemDialog.designer.cs b/JexusManager.Features.MimeMap/NewMapItemDialog.designer.cs new file mode 100644 index 00000000..1b233746 --- /dev/null +++ b/JexusManager.Features.MimeMap/NewMapItemDialog.designer.cs @@ -0,0 +1,125 @@ +namespace JexusManager.Features.MimeMap +{ + using System.ComponentModel; + using System.Windows.Forms; + + sealed partial class NewMapItemDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.txtDescription = new System.Windows.Forms.Label(); + this.txtExtension = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.txtType = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(227, 131); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(126, 131); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // txtDescription + // + this.txtDescription.AutoSize = true; + this.txtDescription.Location = new System.Drawing.Point(12, 9); + this.txtDescription.Name = "txtDescription"; + this.txtDescription.Size = new System.Drawing.Size(103, 13); + this.txtDescription.TabIndex = 2; + this.txtDescription.Text = "File name extension:"; + // + // txtExtension + // + this.txtExtension.Enabled = false; + this.txtExtension.Location = new System.Drawing.Point(15, 25); + this.txtExtension.Name = "txtExtension"; + this.txtExtension.Size = new System.Drawing.Size(133, 20); + this.txtExtension.TabIndex = 6; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 64); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(61, 13); + this.label2.TabIndex = 7; + this.label2.Text = "MIME type:"; + // + // txtType + // + this.txtType.Location = new System.Drawing.Point(15, 80); + this.txtType.Name = "txtType"; + this.txtType.Size = new System.Drawing.Size(307, 20); + this.txtType.TabIndex = 8; + // + // NewMapItemDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(334, 166); + this.Controls.Add(this.txtType); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtExtension); + this.Controls.Add(this.txtDescription); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewMapItemDialog"; + this.Text = "Add MIME Type"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewRestrictionDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label txtDescription; + private TextBox txtExtension; + private Label label2; + private TextBox txtType; + } +} diff --git a/JexusManager.Features.MimeMap/NewMapItemDialog.resx b/JexusManager.Features.MimeMap/NewMapItemDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.MimeMap/NewMapItemDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.MimeMap/Properties/AssemblyInfo.cs b/JexusManager.Features.MimeMap/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..704151e2 --- /dev/null +++ b/JexusManager.Features.MimeMap/Properties/AssemblyInfo.cs @@ -0,0 +1,46 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.MimeMap")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.MimeMap")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("fd1a63c6-458f-496b-9923-80eca082c7ec")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("Tests.JexusManager, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] diff --git a/JexusManager.Features.MimeMap/Properties/Resources.Designer.cs b/JexusManager.Features.MimeMap/Properties/Resources.Designer.cs new file mode 100644 index 00000000..7d0b5793 --- /dev/null +++ b/JexusManager.Features.MimeMap/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.MimeMap.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.MimeMap.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap mime_map_36 { + get { + object obj = ResourceManager.GetObject("mime_map_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.MimeMap/Properties/Resources.resx b/JexusManager.Features.MimeMap/Properties/Resources.resx new file mode 100644 index 00000000..bf830da3 --- /dev/null +++ b/JexusManager.Features.MimeMap/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\mime_map_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.MimeMap/Resources/mime_map_36.png b/JexusManager.Features.MimeMap/Resources/mime_map_36.png new file mode 100644 index 0000000000000000000000000000000000000000..621d950979d3f63d4f04afe205023c170c6c068b GIT binary patch literal 1475 zcmV;!1w8tRP)1bQGrL~zdL5f6hJ-jc0i1A4BuEvBq*hfS5uvIoNJL5sh)4mU zR(+yj8MM))!mqm;MoMx1qzdth;T~+-Sgh z!?xR;#>QkrCSw(HITzngFDcLgSnIm(hYhW*$y7FLHDQgUx6x2=f2x@eK;IM|g#HsibT==wyL?mdfxoGGVFJQ;@j4u;`-Uwhs?7Kjh$o`sP)EBI!B?8X>d4?n`t-6j zwurxZ6)TeuASX_zp5OA)et^HuwjQnD?f&@9k$GFn&E`-nX>sS1o5(LeC8dY&$M<`# zoU_DEJoC$^_RQ`_hcEHrp(8$Ua>;;hJS-TvwnOgI>Ev$iSiayr=J#!^ol~K=c4uA| zrC%7)QS)7MH~s56uz|6tk6YIG<#TWDa(-f3a(qvBu=CpU*FAXOPTE`A?&<#Np1o~J zzvNgFVl3N$a#x|;Rd|Iw)u|D~y>laxZkt|#&tU$ahS$1@ENjTJ1~YOwo9m-v>PIA+ z8%Q)aFgh|u+ATXzY+v70sZQOodFALQhkME0P$9?7bU*sUi!C~sz+K(RWbO+li=#Ea zA0O4M816d>%={chQ<5y>pY?!fKvODdS_-WUjeUS$l7)n_y0#7d~P~21m zDwG9*e7}mDbkMQ%k^)7<@%`$J6%qrvTo@+EG)>mzm2ve@jOp?8+r=<{r=FgO3=F9$ zqv_*HK&3Q}%9P_{+n+Jvr6*ys|Z974;y3NhjE#k^&|&<6uH5T9wNv&*P?j?64ovjQLl dgj-ez`!A_Dmwdt~6R-dP002ovPDHLkV1h4>y`=yE literal 0 HcmV?d00001 diff --git a/JexusManager.Features.MimeMap/packages.config b/JexusManager.Features.MimeMap/packages.config new file mode 100644 index 00000000..571e4fe0 --- /dev/null +++ b/JexusManager.Features.MimeMap/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Modules/GlobalModule.cs b/JexusManager.Features.Modules/GlobalModule.cs new file mode 100644 index 00000000..9798ad47 --- /dev/null +++ b/JexusManager.Features.Modules/GlobalModule.cs @@ -0,0 +1,48 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Modules +{ + using Microsoft.Web.Administration; + + internal class GlobalModule : IItem + { + public GlobalModule(ConfigurationElement element) + { + if (element == null) + { + return; + } + + this.Name = (string)element["name"]; + this.Image = (string)element["image"]; + this.Element = element; + } + + public string Name { get; set; } + + public string Image { get; set; } + public bool Loaded { get; set; } + + public bool Equals(GlobalModule other) + { + return Match(other) && other.Image == this.Image; + } + + public string Flag { get; set; } + + public void Apply() + { + this.Element["name"] = this.Name; + this.Element["image"] = this.Image; + } + + public ConfigurationElement Element { get; set; } + + public bool Match(GlobalModule other) + { + return other != null && other.Name == this.Name; + } + } +} diff --git a/JexusManager.Features.Modules/JexusManager.Features.Modules.csproj b/JexusManager.Features.Modules/JexusManager.Features.Modules.csproj new file mode 100644 index 00000000..95e5692c --- /dev/null +++ b/JexusManager.Features.Modules/JexusManager.Features.Modules.csproj @@ -0,0 +1,151 @@ + + + + + Debug + AnyCPU + {8BFAB6BC-57C1-44FC-88E2-B3CE5B75BE9F} + Library + Properties + JexusManager.Features.Modules + JexusManager.Features.Modules + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + + + + + + UserControl + + + ModulesPage.cs + + + + Form + + + NativeModulesDialog.cs + + + Form + + + NewModuleDialog.cs + + + Form + + + NewNativeDialog.cs + + + + True + True + Resources.resx + + + + + ModulesPage.cs + + + NativeModulesDialog.cs + + + NewModuleDialog.cs + + + NewNativeDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Modules/JexusManager.snk b/JexusManager.Features.Modules/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Modules/ModulesFeature.cs b/JexusManager.Features.Modules/ModulesFeature.cs new file mode 100644 index 00000000..bbbc6ba6 --- /dev/null +++ b/JexusManager.Features.Modules/ModulesFeature.cs @@ -0,0 +1,383 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/* + * Created by SharpDevelop. + * User: lextm + * Time: 11:06 AM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace JexusManager.Features.Modules +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using System.Linq; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + using Microsoft.Web.Management.Server; + + using Module = Microsoft.Web.Management.Client.Module; + + /// + /// Description of DefaultDocumentFeature. + /// + internal class ModulesFeature : FeatureBase + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly ModulesFeature _owner; + + public FeatureTaskList(ModulesFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + if (_owner.IsInOrder) + { + result.Add(GetMoveUpTaskItem(_owner.CanMoveUp)); + result.Add(GetMoveDownTaskItem(_owner.CanMoveDown)); + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Unorder", "View Unordered List...", string.Empty).SetUsage()); + } + else + { + result.Add(new MethodTaskItem("AddManaged", "Add Managed Module...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Add", "Configure Native Modules...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Edit", "Edit...", string.Empty).SetUsage(_owner.SelectedItem.IsManaged)); + result.Add(RemoveTaskItem); + } + + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + if (_owner.CanRevert) + { + result.Add(new MethodTaskItem("Revert", "Revert to Parent", string.Empty).SetUsage()); + } + + result.Add(new MethodTaskItem("InOrder", "View Ordered List...", string.Empty).SetUsage()); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void AddManaged() + { + _owner.AddManaged(); + } + + [Obfuscation(Exclude = true)] + public void Add() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void Edit() + { + _owner.Edit(); + } + + [Obfuscation(Exclude = true)] + public void Rename() + { + _owner.Rename(); + } + + [Obfuscation(Exclude = true)] + public override void MoveUp() + { + _owner.MoveUp(); + } + + [Obfuscation(Exclude = true)] + public override void MoveDown() + { + _owner.MoveDown(); + } + + [Obfuscation(Exclude = true)] + public void InOrder() + { + _owner.InOrder(); + } + + [Obfuscation(Exclude = true)] + public void Unorder() + { + _owner.Unorder(); + } + + [Obfuscation(Exclude = true)] + public void Revert() + { + _owner.Revert(); + } + } + + public ModulesFeature(Module module) + : base(module) + { + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + this.GlobalModules = new List(); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + + ConfigurationSection globalSection = service.GetSection("system.webServer/globalModules", null, false); + ConfigurationElementCollection globalCollection = globalSection.GetCollection(); + foreach (ConfigurationElement addElement in globalCollection) + { + this.GlobalModules.Add(new GlobalModule(addElement)); + } + + this.CanRevert = service.Scope != ManagementScope.Server; + this.IsInOrder = false; + LoadItems(); + } + + public override void LoadItems() + { + this.Items.Clear(); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + ConfigurationElementCollection collection = this.GetCollection(service); + foreach (ConfigurationElement addElement in collection) + { + var item = new ModulesItem(addElement); + item.Load(this); + this.Items.Add(item); + } + + this.OnSettingsSaved(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + // server level modules are in "" location. + ConfigurationSection section = service.Scope == ManagementScope.Server ? service.GetSection("system.webServer/modules", string.Empty) : service.GetSection("system.webServer/modules", null, false); + return section.GetCollection(); + } + + public List GlobalModules { get; set; } + + public void Add() + { + var dialog = new NativeModulesDialog(this.Module, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + foreach (var item in dialog.Items) + { + this.Items.Add(item); + this.SelectedItem = item; + // server level modules are in "" location. + ConfigurationSection section = service.Scope == ManagementScope.Server ? service.GetSection("system.webServer/modules", string.Empty) : service.GetSection("system.webServer/modules"); + ConfigurationElementCollection collection = section.GetCollection(); + item.AppendTo(collection); + } + + // TODO: how to add item? + service.ServerManager.CommitChanges(); + this.OnSettingsSaved(); + } + + public void AddManaged() + { + var dialog = new NewModuleDialog(this.Module, null, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void AddGlobal(GlobalModule item) + { + this.GlobalModules.Add(item); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + ConfigurationSection globalSection = service.GetSection("system.webServer/globalModules", null, false); + ConfigurationElementCollection globalCollection = globalSection.GetCollection(); + item.AppendTo(globalCollection); + service.ServerManager.CommitChanges(); + } + + public void RemoveGlobal(GlobalModule item) + { + this.GlobalModules.Remove(item); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + ConfigurationSection globalSection = service.GetSection("system.webServer/globalModules", null, false); + ConfigurationElementCollection globalCollection = globalSection.GetCollection(); + globalCollection.Remove(item.Element); + service.ServerManager.CommitChanges(); + } + + public void Remove() + { + // TODO: add multiple support + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected module or modules?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + public void Edit() + { + var dialog = new NewModuleDialog(this.Module, this.SelectedItem, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.EditItem(dialog.Item); + } + + public void Rename() + { + } + + public void MoveUp() + { + if (this.Items.Any(item => item.Flag != "Local")) + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + var result = + dialog.ShowMessage( + "The list order will be changed for this feature. If you continue, changes made to this feature at a parent level will no longer be inherited at this level. Do you want to continue?", + this.Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + } + + MoveUpItem(); + } + + public void MoveDown() + { + if (this.Items.Any(item => item.Flag != "Local")) + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + var result = + dialog.ShowMessage( + "The list order will be changed for this feature. If you continue, changes made to this feature at a parent level will no longer be inherited at this level. Do you want to continue?", + this.Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + } + + MoveDownItem(); + } + + public void InOrder() + { + this.IsInOrder = true; + this.OnSettingsSaved(); + } + + public void Unorder() + { + this.IsInOrder = false; + this.OnSettingsSaved(); + } + + public void Revert() + { + if (!CanRevert) + { + throw new InvalidOperationException("Revert operation cannot be done at server level"); + } + + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + var result = + dialog.ShowMessage( + "Reverting to the parent configuration will result in the loss of all settings in the local configuration file for this feature. Are you sure you want to continue?", + this.Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + + RevertItems(); + } + + protected override void OnSettingsSaved() + { + this.ModulesSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210521"); + return false; + } + + public bool IsInOrder { get; private set; } + + public bool CanRevert { get; private set; } + + public ModulesSettingsSavedEventHandler ModulesSettingsUpdated { get; set; } + + public string Description { get; } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public string Name + { + get { return "Modules"; } + } + } +} diff --git a/JexusManager.Features.Modules/ModulesItem.cs b/JexusManager.Features.Modules/ModulesItem.cs new file mode 100644 index 00000000..f0258f8b --- /dev/null +++ b/JexusManager.Features.Modules/ModulesItem.cs @@ -0,0 +1,153 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Modules +{ + using System.Collections.Generic; + using System.Linq; + using System.Text; + + using Microsoft.Web.Administration; + + internal class ModulesItem : IItem + { + public ModulesItem(ConfigurationElement element) + { + this.Element = element; + this.Flag = element == null || element.IsLocallyStored ? "Local" : "Inhertied"; + if (element == null) + { + PreConditions = new List(); + Type = string.Empty; + return; + } + + this.Name = (string)element["name"]; + this.Type = (string)element["type"]; + var content = (string)element["preCondition"]; + this.PreConditions = content.Split(',').ToList(); + + IsLocked = element.GetIsLocked(); + if (!string.IsNullOrWhiteSpace(this.Type)) + { + this.IsManaged = true; + } + } + + public ModulesItem Load(ModulesFeature feature) + { + if (IsManaged) + { + return this; + } + + foreach (var item in feature.GlobalModules) + { + if (item.Name == this.Name) + { + this.Type = item.Image; + item.Loaded = true; + this.GlobalModule = item; + this.IsManaged = false; + break; + } + } + + return this; + } + + public string IsLocked { get; set; } + + public GlobalModule GlobalModule { get; set; } + + public List PreConditions { get; set; } + + public string Type { get; set; } + + public string Name { get; set; } + + public ConfigurationElement Element { get; set; } + + public string Flag { get; set; } + + public bool IsManaged { get; set; } + + public bool ForManagedOnly + { + get + { + return this.PreConditions.Contains("managedHandler"); + } + + set + { + var current = this.PreConditions.Contains("managedHandler"); + if (value == current) + { + return; + } + + if (value) + { + this.PreConditions.Add("managedHandler"); + } + else + { + this.PreConditions.Remove("managedHandler"); + } + } + } + + public bool Equals(ModulesItem other) + { + // all properties + return this.Match(other) && other.Type == this.Type; + } + + public void Apply() + { + Element["name"] = Name; + if (IsManaged) + { + Element["type"] = Type; + } + + Element["preCondition"] = Combine(PreConditions); + Element.SetIsLocked(IsLocked); + } + + private static string Combine(List preConditions) + { + if (preConditions.Count == 0) + { + return string.Empty; + } + + var result = new StringBuilder(preConditions[0]); + for (int index = 1; index < preConditions.Count; index++) + { + result.AppendFormat(",{0}", preConditions[index]); + } + + return result.ToString(); + } + + public bool Match(ModulesItem other) + { + // match combined keys. + return other != null && other.Name == this.Name; + } + + public void Unload() + { + if (GlobalModule == null) + { + return; + } + + this.GlobalModule.Loaded = false; + this.GlobalModule = null; + } + } +} diff --git a/JexusManager.Features.Modules/ModulesModule.cs b/JexusManager.Features.Modules/ModulesModule.cs new file mode 100644 index 00000000..c4f38f30 --- /dev/null +++ b/JexusManager.Features.Modules/ModulesModule.cs @@ -0,0 +1,25 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Modules +{ + using System; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + using Properties; + + internal class ModulesModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)this.GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(ModulesPage), "Modules", + "Configure native and managed code modules that process requests on the Web server", Resources.modules_36, + Resources.modules_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.Modules/ModulesModuleProvider.cs b/JexusManager.Features.Modules/ModulesModuleProvider.cs new file mode 100644 index 00000000..445c1a4f --- /dev/null +++ b/JexusManager.Features.Modules/ModulesModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Modules +{ + using System; + + using Microsoft.Web.Management.Server; + + public class ModulesModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(this.Name, typeof(ModulesModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.Modules/ModulesPage.Designer.cs b/JexusManager.Features.Modules/ModulesPage.Designer.cs new file mode 100644 index 00000000..627d381b --- /dev/null +++ b/JexusManager.Features.Modules/ModulesPage.Designer.cs @@ -0,0 +1,298 @@ +namespace JexusManager.Features.Modules +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class ModulesPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chCode = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chModule = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.toolStrip2 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel2 = new System.Windows.Forms.ToolStripLabel(); + this.cbGroup = new System.Windows.Forms.ToolStripComboBox(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.toolStrip2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 6; + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.toolStrip2); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 6; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chName, + this.chCode, + this.chModule, + this.chType}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 38); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 502); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListView1SelectedIndexChanged); + // + // chName + // + this.chName.Text = "Name"; + this.chName.Width = 180; + // + // chCode + // + this.chCode.Text = "Code"; + this.chCode.Width = 180; + // + // chModule + // + this.chModule.Text = "Module Type"; + this.chModule.Width = 120; + // + // chType + // + this.chType.Text = "Entry Type"; + this.chType.Width = 120; + // + // toolStrip2 + // + this.toolStrip2.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel2, + this.cbGroup}); + this.toolStrip2.Location = new System.Drawing.Point(0, 13); + this.toolStrip2.Name = "toolStrip2"; + this.toolStrip2.Size = new System.Drawing.Size(560, 25); + this.toolStrip2.TabIndex = 3; + this.toolStrip2.Text = "toolStrip2"; + // + // toolStripLabel2 + // + this.toolStripLabel2.Name = "toolStripLabel2"; + this.toolStripLabel2.Size = new System.Drawing.Size(59, 22); + this.toolStripLabel2.Text = "Group by:"; + // + // cbGroup + // + this.cbGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbGroup.Items.AddRange(new object[] { + "No Grouping", + "Status", + "IP Address", + "Protocol", + "Port"}); + this.cbGroup.Name = "cbGroup"; + this.cbGroup.Size = new System.Drawing.Size(121, 25); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(551, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to configure the native and managed code modules that process re" + + "quests made to the Web server."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 5; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(94, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Modules"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // ModulesPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "ModulesPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.toolStrip2.ResumeLayout(false); + this.toolStrip2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private ListView listView1; + private ColumnHeader chType; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Panel panel2; + private ToolStrip toolStrip2; + private ToolStripLabel toolStripLabel2; + private ToolStripComboBox cbGroup; + private PictureBox pictureBox1; + private ContextMenuStrip cmsActionPanel; + private ColumnHeader chName; + private ColumnHeader chCode; + private ColumnHeader chModule; + } +} diff --git a/JexusManager.Features.Modules/ModulesPage.cs b/JexusManager.Features.Modules/ModulesPage.cs new file mode 100644 index 00000000..b72201c9 --- /dev/null +++ b/JexusManager.Features.Modules/ModulesPage.cs @@ -0,0 +1,132 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Modules +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class ModulesPage : ModuleListPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly ModulesPage _owner; + + public PageTaskList(ModulesPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class ModulesListViewItem : ListViewItem + { + public ModulesItem Item { get; } + + private readonly ModulesPage _page; + + public ModulesListViewItem(ModulesItem item, ModulesPage page) + : base(item.Name) + { + this.Item = item; + _page = page; + this.SubItems.Add(new ListViewSubItem(this, item.IsManaged ? item.Type : item.GlobalModule.Image)); + this.SubItems.Add(new ListViewSubItem(this, item.IsManaged ? "Managed" : "Native")); + this.SubItems.Add(new ListViewSubItem(this, item.Flag)); + } + } + + private ModulesFeature _feature; + private PageTaskList _taskList; + + public ModulesPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new ModulesFeature(this.Module); + _feature.ModulesSettingsUpdated = this.InitializeListPage; + _feature.Load(); + } + + protected override void InitializeListPage() + { + toolStrip2.Visible = !_feature.IsInOrder; + listView1.Items.Clear(); + foreach (var file in _feature.Items) + { + listView1.Items.Add(new ModulesListViewItem(file, this)); + } + + if (_feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (ModulesListViewItem item in listView1.Items) + { + if (item.Item == _feature.SelectedItem) + { + item.Selected = true; + } + } + } + + protected override void Refresh() + { + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + private void ListView1SelectedIndexChanged(object sender, EventArgs e) + { + _feature.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((ModulesListViewItem)listView1.SelectedItems[0]).Item + : null; + // TODO: optimize refresh when null to not null (vice versa) + this.Refresh(); + } + + protected override bool ShowHelp() + { + _feature.ShowHelp(); + return true; + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + } +} diff --git a/JexusManager.Features.Modules/ModulesPage.resx b/JexusManager.Features.Modules/ModulesPage.resx new file mode 100644 index 00000000..464d127c --- /dev/null +++ b/JexusManager.Features.Modules/ModulesPage.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 602, 17 + + + 497, 17 + + + 17, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.Modules/ModulesSettingsSavedEventHandler.cs b/JexusManager.Features.Modules/ModulesSettingsSavedEventHandler.cs new file mode 100644 index 00000000..74b1cdcc --- /dev/null +++ b/JexusManager.Features.Modules/ModulesSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Modules +{ + public delegate void ModulesSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.Modules/NativeModulesDialog.Designer.cs b/JexusManager.Features.Modules/NativeModulesDialog.Designer.cs new file mode 100644 index 00000000..6d793c5a --- /dev/null +++ b/JexusManager.Features.Modules/NativeModulesDialog.Designer.cs @@ -0,0 +1,155 @@ +namespace JexusManager.Features.Modules +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal partial class NativeModulesDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.lvModules = new System.Windows.Forms.ListView(); + this.chName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.label1 = new System.Windows.Forms.Label(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnRegister = new System.Windows.Forms.Button(); + this.btnEdit = new System.Windows.Forms.Button(); + this.btnRemove = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // lvModules + // + this.lvModules.CheckBoxes = true; + this.lvModules.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chName}); + this.lvModules.FullRowSelect = true; + this.lvModules.HeaderStyle = System.Windows.Forms.ColumnHeaderStyle.None; + this.lvModules.HideSelection = false; + this.lvModules.Location = new System.Drawing.Point(12, 25); + this.lvModules.MultiSelect = false; + this.lvModules.Name = "lvModules"; + this.lvModules.Size = new System.Drawing.Size(300, 270); + this.lvModules.TabIndex = 1; + this.lvModules.UseCompatibleStateImageBehavior = false; + this.lvModules.View = System.Windows.Forms.View.Details; + // + // chName + // + this.chName.Text = "Name"; + this.chName.Width = 350; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(237, 13); + this.label1.TabIndex = 2; + this.label1.Text = "Select one or more registered modules to enable:"; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(347, 301); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 3; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(251, 301); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 4; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnRegister + // + this.btnRegister.Location = new System.Drawing.Point(318, 25); + this.btnRegister.Name = "btnRegister"; + this.btnRegister.Size = new System.Drawing.Size(124, 23); + this.btnRegister.TabIndex = 5; + this.btnRegister.Text = "Register..."; + this.btnRegister.UseVisualStyleBackColor = true; + // + // btnEdit + // + this.btnEdit.Enabled = false; + this.btnEdit.Location = new System.Drawing.Point(318, 54); + this.btnEdit.Name = "btnEdit"; + this.btnEdit.Size = new System.Drawing.Size(124, 23); + this.btnEdit.TabIndex = 6; + this.btnEdit.Text = "Edit..."; + this.btnEdit.UseVisualStyleBackColor = true; + // + // btnRemove + // + this.btnRemove.Enabled = false; + this.btnRemove.Location = new System.Drawing.Point(318, 83); + this.btnRemove.Name = "btnRemove"; + this.btnRemove.Size = new System.Drawing.Size(124, 23); + this.btnRemove.TabIndex = 7; + this.btnRemove.Text = "Remove"; + this.btnRemove.UseVisualStyleBackColor = true; + // + // NativeModulesDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(454, 336); + this.Controls.Add(this.btnRemove); + this.Controls.Add(this.btnEdit); + this.Controls.Add(this.btnRegister); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.label1); + this.Controls.Add(this.lvModules); + this.Name = "NativeModulesDialog"; + this.Text = "Configure Native Modules"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NativeModulesDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private ListView lvModules; + private ColumnHeader chName; + private Label label1; + private Button btnCancel; + private Button btnOK; + private Button btnRegister; + private Button btnEdit; + private Button btnRemove; + } +} diff --git a/JexusManager.Features.Modules/NativeModulesDialog.cs b/JexusManager.Features.Modules/NativeModulesDialog.cs new file mode 100644 index 00000000..a758417c --- /dev/null +++ b/JexusManager.Features.Modules/NativeModulesDialog.cs @@ -0,0 +1,127 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Modules +{ + using System; + using System.Collections.Generic; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal partial class NativeModulesDialog : DialogForm + { + public NativeModulesDialog(IServiceProvider serviceProvider, ModulesFeature feature) + : base(serviceProvider) + { + InitializeComponent(); + if (feature.CanRevert) + { + btnRegister.Visible = btnEdit.Visible = btnRemove.Visible = false; + lvModules.Width += 130; + } + + foreach (var global in feature.GlobalModules) + { + if (feature.Items.Any(module => module.Name == global.Name)) + { + continue; + } + + var item = lvModules.Items.Add(global.Name); + item.Tag = global; + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Items = new List(); + foreach (ListViewItem item in lvModules.Items) + { + if (!item.Checked) + { + continue; + } + + var module = (GlobalModule)item.Tag; + module.Loaded = true; + Items.Add(new ModulesItem(null) { Name = module.Name }.Load(feature)); + } + + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(lvModules, "SelectedIndexChanged") + .Subscribe(evt => + { + btnEdit.Enabled = btnRemove.Enabled = lvModules.SelectedItems.Count > 0; + })); + + container.Add( + Observable.FromEventPattern(btnRegister, "Click") + .Subscribe(evt => + { + var dialog = new NewNativeDialog(ServiceProvider, null); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + var item = lvModules.Items.Add(dialog.Item.Name); + item.Tag = dialog.Item; + feature.AddGlobal(dialog.Item); + })); + + container.Add( + Observable.FromEventPattern(btnEdit, "Click") + .Subscribe(evt => + { + GlobalModule item = (GlobalModule)lvModules.SelectedItems[0].Tag; + var dialog = new NewNativeDialog(ServiceProvider, item); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + dialog.Item.Apply(); + lvModules.SelectedItems[0].Text = dialog.Item.Name; + })); + + container.Add( + Observable.FromEventPattern(btnRemove, "Click") + .Subscribe(evt => + { + var dialog = (IManagementUIService)GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected native module registration?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + GlobalModule item = (GlobalModule)lvModules.SelectedItems[0].Tag; + feature.RemoveGlobal(item); + lvModules.SelectedItems[0].Remove(); + })); + } + + public List Items { get; set; } + + private void NativeModulesDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210521"); + } + } +} diff --git a/JexusManager.Features.Modules/NativeModulesDialog.resx b/JexusManager.Features.Modules/NativeModulesDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Modules/NativeModulesDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Modules/NewModuleDialog.Designer.cs b/JexusManager.Features.Modules/NewModuleDialog.Designer.cs new file mode 100644 index 00000000..d8c3594b --- /dev/null +++ b/JexusManager.Features.Modules/NewModuleDialog.Designer.cs @@ -0,0 +1,137 @@ +namespace JexusManager.Features.Modules +{ + using System.ComponentModel; + using System.Windows.Forms; + + sealed partial class NewModuleDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.txtDescription = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.txtPath = new System.Windows.Forms.ComboBox(); + this.label1 = new System.Windows.Forms.Label(); + this.cbManagedHandler = new System.Windows.Forms.CheckBox(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(317, 186); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(216, 186); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // txtDescription + // + this.txtDescription.AutoSize = true; + this.txtDescription.Location = new System.Drawing.Point(12, 9); + this.txtDescription.Name = "txtDescription"; + this.txtDescription.Size = new System.Drawing.Size(38, 13); + this.txtDescription.TabIndex = 2; + this.txtDescription.Text = "Name:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(15, 25); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(269, 20); + this.txtName.TabIndex = 6; + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(15, 82); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(360, 21); + this.txtPath.TabIndex = 8; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 66); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(34, 13); + this.label1.TabIndex = 9; + this.label1.Text = "Type:"; + // + // cbManagedHandler + // + this.cbManagedHandler.AutoSize = true; + this.cbManagedHandler.Location = new System.Drawing.Point(15, 130); + this.cbManagedHandler.Name = "cbManagedHandler"; + this.cbManagedHandler.Size = new System.Drawing.Size(361, 17); + this.cbManagedHandler.TabIndex = 10; + this.cbManagedHandler.Text = "Invoke only for requests to ASP.NET applications or managed handlers"; + this.cbManagedHandler.UseVisualStyleBackColor = true; + // + // NewModuleDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(424, 221); + this.Controls.Add(this.cbManagedHandler); + this.Controls.Add(this.label1); + this.Controls.Add(this.txtPath); + this.Controls.Add(this.txtName); + this.Controls.Add(this.txtDescription); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewModuleDialog"; + this.Text = "Add Managed Module"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewRestrictionDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label txtDescription; + private TextBox txtName; + private ComboBox txtPath; + private Label label1; + private CheckBox cbManagedHandler; + } +} diff --git a/JexusManager.Features.Modules/NewModuleDialog.cs b/JexusManager.Features.Modules/NewModuleDialog.cs new file mode 100644 index 00000000..ec550dda --- /dev/null +++ b/JexusManager.Features.Modules/NewModuleDialog.cs @@ -0,0 +1,74 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Modules +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewModuleDialog : DialogForm + { + public NewModuleDialog(IServiceProvider serviceProvider, ModulesItem existing, ModulesFeature feature) + : base(serviceProvider) + { + InitializeComponent(); + Text = existing == null ? "Add Managed Module" : "Edit Managed Module"; + txtName.ReadOnly = existing != null; + Item = existing ?? new ModulesItem(null); + if (existing != null) + { + txtPath.Text = Item.Type; + txtName.Text = Item.Name; + cbManagedHandler.Checked = Item.ForManagedOnly; + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item.Type = txtPath.Text; + Item.Name = txtName.Text; + Item.ForManagedOnly = cbManagedHandler.Checked; + if (!txtName.ReadOnly && feature.Items.Any(item => item.Match(Item))) + { + ShowMessage( + "A module with this name already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Merge(Observable.FromEventPattern(txtPath, "TextChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text) + && !string.IsNullOrWhiteSpace(txtPath.Text); + })); + } + + public ModulesItem Item { get; set; } + + private void NewRestrictionDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210521"); + } + } +} diff --git a/JexusManager.Features.Modules/NewModuleDialog.resx b/JexusManager.Features.Modules/NewModuleDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Modules/NewModuleDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Modules/NewNativeDialog.Designer.cs b/JexusManager.Features.Modules/NewNativeDialog.Designer.cs new file mode 100644 index 00000000..e7323573 --- /dev/null +++ b/JexusManager.Features.Modules/NewNativeDialog.Designer.cs @@ -0,0 +1,133 @@ +namespace JexusManager.Features.Modules +{ + internal sealed partial class NewNativeDialog + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.txtPath = new System.Windows.Forms.TextBox(); + this.btnBrowse = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(327, 136); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.DialogResult = System.Windows.Forms.DialogResult.OK; + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(231, 136); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(38, 13); + this.label1.TabIndex = 2; + this.label1.Text = "Name:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(12, 25); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(260, 20); + this.txtName.TabIndex = 3; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 57); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(32, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Path:"; + // + // txtPath + // + this.txtPath.Location = new System.Drawing.Point(12, 73); + this.txtPath.Name = "txtPath"; + this.txtPath.Size = new System.Drawing.Size(372, 20); + this.txtPath.TabIndex = 5; + // + // btnBrowse + // + this.btnBrowse.Location = new System.Drawing.Point(390, 71); + this.btnBrowse.Name = "btnBrowse"; + this.btnBrowse.Size = new System.Drawing.Size(30, 23); + this.btnBrowse.TabIndex = 6; + this.btnBrowse.Text = "..."; + this.btnBrowse.UseVisualStyleBackColor = true; + // + // NewNativeDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(434, 171); + this.Controls.Add(this.btnBrowse); + this.Controls.Add(this.txtPath); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtName); + this.Controls.Add(this.label1); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewNativeDialog"; + this.Text = "Register Native Module"; + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Button btnCancel; + private System.Windows.Forms.Button btnOK; + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox txtName; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.TextBox txtPath; + private System.Windows.Forms.Button btnBrowse; + } +} diff --git a/JexusManager.Features.Modules/NewNativeDialog.cs b/JexusManager.Features.Modules/NewNativeDialog.cs new file mode 100644 index 00000000..5dd210ee --- /dev/null +++ b/JexusManager.Features.Modules/NewNativeDialog.cs @@ -0,0 +1,64 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Modules +{ + using System; + using System.Reactive.Disposables; + using System.Reactive.Linq; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewNativeDialog : DialogForm + { + public NewNativeDialog(IServiceProvider serviceProvider, GlobalModule existing) + : base(serviceProvider) + { + InitializeComponent(); + if (existing != null) + { + txtName.Text = existing.Name; + txtPath.Text = existing.Image; + this.Text = "Edit Native Module Registration"; + txtName.SelectAll(); + this.Item = existing; + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnBrowse, "Click") + .Subscribe(evt => + { + DialogHelper.ShowFileDialog(txtPath, "(*.dll)|*.dll|All Files (*.*)|*.*"); + })); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Merge(Observable.FromEventPattern(txtPath, "TextChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text) + && !string.IsNullOrWhiteSpace(txtPath.Text); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + if (Item == null) + { + Item = new GlobalModule(null); + } + + this.Item.Name = txtName.Text; + this.Item.Image = txtPath.Text; + })); + } + + public GlobalModule Item { get; set; } + } +} diff --git a/JexusManager.Features.Modules/NewNativeDialog.resx b/JexusManager.Features.Modules/NewNativeDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Modules/NewNativeDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Modules/Properties/AssemblyInfo.cs b/JexusManager.Features.Modules/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..e1c33f8b --- /dev/null +++ b/JexusManager.Features.Modules/Properties/AssemblyInfo.cs @@ -0,0 +1,51 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.Modules")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.Modules")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("8bfab6bc-57c1-44fc-88e2-b3ce5b75be9f")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("JexusManager.Features.Handlers, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] +[assembly: InternalsVisibleTo("Tests.JexusManager, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] diff --git a/JexusManager.Features.Modules/Properties/Resources.Designer.cs b/JexusManager.Features.Modules/Properties/Resources.Designer.cs new file mode 100644 index 00000000..8207b510 --- /dev/null +++ b/JexusManager.Features.Modules/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.Modules.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.Modules.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap modules_36 { + get { + object obj = ResourceManager.GetObject("modules_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.Modules/Properties/Resources.resx b/JexusManager.Features.Modules/Properties/Resources.resx new file mode 100644 index 00000000..a8f57377 --- /dev/null +++ b/JexusManager.Features.Modules/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\modules_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.Modules/Resources/modules_36.png b/JexusManager.Features.Modules/Resources/modules_36.png new file mode 100644 index 0000000000000000000000000000000000000000..512d5b7ccab065774f25a97508a751aaa5756f25 GIT binary patch literal 1479 zcmV;&1vvVNP)L=8hkewoX+tj-C3EXw;^S#nf7Chd~8F9Z?t` z1Yr~zMFe9z^HQ}B>Yyknic*NSB#byitB6udrL9(LM86>R@*lF{+1`kJEdh?d4PB&AXI6s%$ z^xO68U)t>ZPfm4>zh?8_Zo2AsFXtA{-}H+UGQgbrdfGN_d|+#Reg6xP{mIE4FJ$Yx zxAt#b-FE-XhS_Iw%+zNJ5DgA8v1^yKZ`jZoH8p+S1G&>CuIkA(EwW#1Sl!;a>+pmO zo`^t%|A|5wRZKq5$c`PdvZEuHYiT+71gt1ey6%Y;E$8G8c3l4Z<{bw{BwsYBmpLPa zvJ{;m{#Y5vz!TSiovB zW|1h0*#mwsYgSpEKouWiUs5V*msBz(vVIo1>~`v}?_&Ho)QRQZwgsGfV2qbTWxN~$ zuA+{O5a-9rI1jM~oR{=%La4D3CXw(FXor=W}`&lLx65fg=o4Us5;4dbzBBJR5g zpBgD%R-zQpN&J-J%S@bvosSTmI7arCd(h)E5HH~5;w;+^IiA;mq7UL6LNQUvqQ-zT zh!_w9k_5jmxQmq9Dn%BJ$$Wr3DkKA*OUl;!Ub*&zn0p(`v1ly?gNh^*r2~ zHGD8I5Iwtp|HE%A-^9gh?|M9U@nwGh*9MD#vs|*k;T_$l!^1y>mFn!0YHbtmKve~Y z05eh{lJ-@2EtmUuXH!!Xd-mWpG~l|rbm#8f!`p_2{`5W!0`RLV7caW@-e=o8*Us(x z%E;)1<HW?Uqg1b48{A0$)0YKuY#YDiBbg8B+5zVMD#y} z0{wk`Ten0}&#BWBv!e3oz*yn!M{e1EYV^VD*LK|}>J%8Sap5#6EvJ3zxuOJSGQK)` z^vy#90|y_2*VEOZCLvHbMf9&n|N55N{eE5c!Wx81IPD`i)&H5Kyi6iBnNT_&OW~lk h2u$0wP22yy{Rmkm;eo|lykr0X002ovPDHLkV1m>Z$7TQk literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Modules/packages.config b/JexusManager.Features.Modules/packages.config new file mode 100644 index 00000000..571e4fe0 --- /dev/null +++ b/JexusManager.Features.Modules/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/AppliesToItem.cs b/JexusManager.Features.RequestFiltering/AppliesToItem.cs new file mode 100644 index 00000000..78d58169 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/AppliesToItem.cs @@ -0,0 +1,42 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using Microsoft.Web.Administration; + + internal class AppliesToItem + { + public ConfigurationElement Child { get; set; } + + public AppliesToItem(ConfigurationElement child) + { + this.Child = child; + if (child == null) + { + return; + } + + this.FileExtension = (string)child["fileExtension"]; + } + + public string FileExtension { get; set; } + + public void Apply() + { + Child["fileExtension"] = FileExtension; + } + + public void AppendTo(ConfigurationElementCollection appliesToCollection) + { + if (Child == null) + { + Child = appliesToCollection.CreateElement(); + appliesToCollection.Add(Child); + } + + Apply(); + } + } +} \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/DenyStringsItem.cs b/JexusManager.Features.RequestFiltering/DenyStringsItem.cs new file mode 100644 index 00000000..4d3aa2d3 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/DenyStringsItem.cs @@ -0,0 +1,42 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using Microsoft.Web.Administration; + + internal class DenyStringsItem + { + public ConfigurationElement Child { get; set; } + + public DenyStringsItem(ConfigurationElement child) + { + this.Child = child; + if (child == null) + { + return; + } + + this.DenyString = (string)child["string"]; + } + + public string DenyString { get; set; } + + public void Apply() + { + Child["string"] = DenyString; + } + + public void AppendTo(ConfigurationElementCollection denyStringsCollection) + { + if (Child == null) + { + Child = denyStringsCollection.CreateElement(); + denyStringsCollection.Add(Child); + } + + Apply(); + } + } +} \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/FileExtensionsFeature.cs b/JexusManager.Features.RequestFiltering/FileExtensionsFeature.cs new file mode 100644 index 00000000..f2a3f55f --- /dev/null +++ b/JexusManager.Features.RequestFiltering/FileExtensionsFeature.cs @@ -0,0 +1,139 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + internal class FileExtensionsFeature : RequestFilteringFeature + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly FileExtensionsFeature _owner; + + public FeatureTaskList(FileExtensionsFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + + result.Add(new MethodTaskItem("AddExtension", "Allow File Name Extension...", string.Empty).SetUsage()); + result.Add( + new MethodTaskItem("AddDenyExtension", "Deny File Name Extension...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void AddExtension() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public void AddDenyExtension() + { + _owner.AddDeny(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + } + + public FileExtensionsFeature(Module module) + : base(module) + { + } + + private TaskList _taskList; + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Add() + { + this.CreateExtension(true); + } + + public void AddDeny() + { + this.CreateExtension(false); + } + + private void CreateExtension(bool allowed) + { + var dialog = new NewExtensionDialog(this.Module, allowed); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected file extension?", this.Name, + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + public override void Load() + { + LoadItems(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + ConfigurationSection requestFilteringSection = service.GetSection("system.webServer/security/requestFiltering"); + return requestFilteringSection.GetCollection("fileExtensions"); + } + + public override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210526"); + return true; + } + + public override string Name + { + get + { + return "File Name Extensions"; + } + } + } +} diff --git a/JexusManager.Features.RequestFiltering/FileExtensionsItem.cs b/JexusManager.Features.RequestFiltering/FileExtensionsItem.cs new file mode 100644 index 00000000..1db92f91 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/FileExtensionsItem.cs @@ -0,0 +1,48 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using Microsoft.Web.Administration; + + internal class FileExtensionsItem : IItem + { + public ConfigurationElement Element { get; set; } + + public bool Match(FileExtensionsItem other) + { + return other != null && other.Extension == Extension; + } + + public FileExtensionsItem(ConfigurationElement element) + { + this.Element = element; + Flag = element == null || element.IsLocallyStored ? "Local" : "Inherited"; + if (element == null) + { + return; + } + + Extension = (string)element["fileExtension"]; + Allowed = (bool)element["allowed"]; + } + + public string Flag { get; set; } + + public bool Allowed { get; set; } + + public string Extension { get; set; } + + public void Apply() + { + Element["fileExtension"] = Extension; + Element["allowed"] = Allowed; + } + + public bool Equals(FileExtensionsItem other) + { + return Match(other) && other.Allowed == Allowed; + } + } +} diff --git a/JexusManager.Features.RequestFiltering/FilteringRulesFeature.cs b/JexusManager.Features.RequestFiltering/FilteringRulesFeature.cs new file mode 100644 index 00000000..b8a442c1 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/FilteringRulesFeature.cs @@ -0,0 +1,141 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + internal class FilteringRulesFeature : RequestFilteringFeature + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly FilteringRulesFeature _owner; + + public FeatureTaskList(FilteringRulesFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + + result.Add(new MethodTaskItem("AddRule", "Add Filtering Rule...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem("EditRule", "Edit Filtering Rule...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void AddRule() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public void EditRule() + { + _owner.Edit(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + } + + public FilteringRulesFeature(Module module) + : base(module) + { + } + + private TaskList _taskList; + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Add() + { + var dialog = new NewRuleDialog(this.Module, null); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Edit() + { + var dialog = new NewRuleDialog(this.Module, this.SelectedItem); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + var newItem = dialog.Item; + this.EditItem(newItem); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected rule?", this.Name, + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + public override void Load() + { + LoadItems(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + ConfigurationSection requestFilteringSection = + service.GetSection("system.webServer/security/requestFiltering"); + return requestFilteringSection.GetCollection("filteringRules"); + } + + public override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210526#Rules"); + return true; + } + + public override string Name + { + get + { + return "Rules"; + } + } + } +} diff --git a/JexusManager.Features.RequestFiltering/FilteringRulesItem.cs b/JexusManager.Features.RequestFiltering/FilteringRulesItem.cs new file mode 100644 index 00000000..3254e52e --- /dev/null +++ b/JexusManager.Features.RequestFiltering/FilteringRulesItem.cs @@ -0,0 +1,148 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System.Collections.Generic; + using System.Linq; + using System.Text; + + using Microsoft.Web.Administration; + + internal class FilteringRulesItem : IItem + { + public ConfigurationElement Element { get; set; } + + public bool Match(FilteringRulesItem other) + { + return other != null && other.Name == Name; + } + + public string Name { get; set; } + + public string ScanString + { + get + { + var result = new StringBuilder("Header"); + if (ScanUrl) + { + result.Insert(0, "Url, "); + } + + if (ScanQueryString) + { + result.Insert(0, "Query string, "); + } + + return result.ToString(); + } + } + + public string AppliesToString + { + get + { + return Combine(Extensions.Select(item => item.FileExtension).ToList()); + } + } + + private static string Combine(List preConditions) + { + if (preConditions.Count == 0) + { + return string.Empty; + } + + var result = new StringBuilder(preConditions[0]); + for (int index = 1; index < preConditions.Count; index++) + { + result.AppendFormat(", {0}", preConditions[index]); + } + + return result.ToString(); + } + + public string DenyStringsString + { + get + { + return Combine(DenyStrings.Select(item => item.DenyString).ToList()); + } + } + + public bool ScanUrl { get; set; } + public bool ScanQueryString { get; set; } + public List Headers { get; set; } + public List Extensions { get; set; } + public List DenyStrings { get; set; } + public string Flag { get; set; } + + public FilteringRulesItem(ConfigurationElement element) + { + this.Element = element; + Headers = new List(); + Extensions = new List(); + DenyStrings = new List(); + Flag = element == null || element.IsLocallyStored ? "Local" : "Inherited"; + if (element == null) + { + return; + } + + Name = (string)element["name"]; + ScanQueryString = (bool)element["scanQueryString"]; + ScanUrl = (bool)element["scanUrl"]; + foreach (ConfigurationElement child in element.GetCollection("scanHeaders")) + { + Headers.Add(new ScanHeadersItem(child)); + } + + foreach (ConfigurationElement child in element.GetCollection("appliesTo")) + { + Extensions.Add(new AppliesToItem(child)); + } + + foreach (ConfigurationElement child in element.GetCollection("denyStrings")) + { + DenyStrings.Add(new DenyStringsItem(child)); + } + } + + public void Apply() + { + Element["name"] = Name; + Element["scanQueryString"] = ScanQueryString; + Element["scanUrl"] = ScanUrl; + var collection = Element.GetCollection("scanHeaders"); + collection.Clear(); + collection.Delete(); + foreach (var header in Headers) + { + header.AppendTo(collection); + } + + var appliesToCollection = Element.GetCollection("appliesTo"); + appliesToCollection.Clear(); + appliesToCollection.Delete(); + foreach (var header in Extensions) + { + header.AppendTo(appliesToCollection); + } + + var denyStringsCollection = Element.GetCollection("denyStrings"); + denyStringsCollection.Clear(); + denyStringsCollection.Delete(); + foreach (var header in DenyStrings) + { + header.AppendTo(denyStringsCollection); + } + } + + public bool Equals(FilteringRulesItem other) + { + return Match(other); + } + } +} diff --git a/JexusManager.Features.RequestFiltering/HeadersFeature.cs b/JexusManager.Features.RequestFiltering/HeadersFeature.cs new file mode 100644 index 00000000..075a25aa --- /dev/null +++ b/JexusManager.Features.RequestFiltering/HeadersFeature.cs @@ -0,0 +1,126 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + internal class HeadersFeature : RequestFilteringFeature + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly HeadersFeature _owner; + + public FeatureTaskList(HeadersFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + + { + result.Add(new MethodTaskItem("AddHeader", "Add Header...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void AddHeader() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + } + + public HeadersFeature(Module module) + : base(module) + { + } + + private TaskList _taskList; + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + public void Add() + { + var dialog = new NewHeaderDialog(this.Module); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected header?", this.Name, + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + public override void Load() + { + LoadItems(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + ConfigurationSection requestFilteringSection = + service.GetSection("system.webServer/security/requestFiltering"); + + + ConfigurationElement childElement = requestFilteringSection.ChildElements["requestLimits"]; + return childElement.GetCollection("headerLimits"); + } + + public override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210526#Headers"); + return true; + } + + public override string Name + { + get + { + return "Headers"; + } + } + } +} diff --git a/JexusManager.Features.RequestFiltering/HeadersItem.cs b/JexusManager.Features.RequestFiltering/HeadersItem.cs new file mode 100644 index 00000000..c27fa7f6 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/HeadersItem.cs @@ -0,0 +1,47 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using Microsoft.Web.Administration; + + internal class HeadersItem : IItem + { + public ConfigurationElement Element { get; set; } + + public bool Match(HeadersItem other) + { + return other != null && other.Header == Header; + } + + public HeadersItem(ConfigurationElement element) + { + this.Element = element; + if (element == null) + { + return; + } + + Header = (string)element["header"]; + SizeLimit = (uint)element["sizeLimit"]; + } + + public uint SizeLimit { get; set; } + + public string Header { get; set; } + + public void Apply() + { + Element["header"] = Header; + Element["sizeLimit"] = SizeLimit; + } + + public string Flag { get; set; } + + public bool Equals(HeadersItem other) + { + return Match(other) && other.SizeLimit == SizeLimit; + } + } +} diff --git a/JexusManager.Features.RequestFiltering/HiddenSegmentsFeature.cs b/JexusManager.Features.RequestFiltering/HiddenSegmentsFeature.cs new file mode 100644 index 00000000..9426dc76 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/HiddenSegmentsFeature.cs @@ -0,0 +1,122 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + internal class HiddenSegmentsFeature : RequestFilteringFeature + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly HiddenSegmentsFeature _owner; + + public FeatureTaskList(HiddenSegmentsFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + + result.Add(new MethodTaskItem("AddSegement", "Add Hidden Segment...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void AddSegment() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + } + + public HiddenSegmentsFeature(Module module) + : base(module) + { + } + + private TaskList _taskList; + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Add() + { + var dialog = new NewHiddenSegmentDialog(this.Module); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected hidden segment?", this.Name, + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + public override void Load() + { + LoadItems(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + ConfigurationSection requestFilteringSection = + service.GetSection("system.webServer/security/requestFiltering"); + return requestFilteringSection.GetCollection("hiddenSegments"); + } + + public override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210526#Hidden_Segments"); + return true; + } + + public override string Name + { + get + { + return " Hidden Segments"; + } + } + } +} diff --git a/JexusManager.Features.RequestFiltering/HiddenSegmentsItem.cs b/JexusManager.Features.RequestFiltering/HiddenSegmentsItem.cs new file mode 100644 index 00000000..eb611c0c --- /dev/null +++ b/JexusManager.Features.RequestFiltering/HiddenSegmentsItem.cs @@ -0,0 +1,42 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using Microsoft.Web.Administration; + + internal class HiddenSegmentsItem : IItem + { + public HiddenSegmentsItem(ConfigurationElement element) + { + Flag = element == null || element.IsLocallyStored ? "Local" : "Inherited"; + Element = element; + if (element == null) + { + return; + } + + Segment = (string)element["segment"]; + } + + public string Segment { get; set; } + public string Flag { get; set; } + public ConfigurationElement Element { get; set; } + + public bool Equals(HiddenSegmentsItem other) + { + return Match(other); + } + + public bool Match(HiddenSegmentsItem other) + { + return other != null && other.Segment == Segment; + } + + public void Apply() + { + Element["segment"] = Segment; + } + } +} diff --git a/JexusManager.Features.RequestFiltering/IRequestFilteringFeature.cs b/JexusManager.Features.RequestFiltering/IRequestFilteringFeature.cs new file mode 100644 index 00000000..9354a7fc --- /dev/null +++ b/JexusManager.Features.RequestFiltering/IRequestFilteringFeature.cs @@ -0,0 +1,17 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using Microsoft.Web.Management.Client; + + internal interface IRequestFilteringFeature + { + TaskList GetTaskList(); + + bool ShowHelp(); + + RequestFilteringSettingsSavedEventHandler RequestFilteringSettingsUpdate { get; } + } +} \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/JexusManager.Features.RequestFiltering.csproj b/JexusManager.Features.RequestFiltering/JexusManager.Features.RequestFiltering.csproj new file mode 100644 index 00000000..a5abb2f0 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/JexusManager.Features.RequestFiltering.csproj @@ -0,0 +1,231 @@ + + + + + Debug + AnyCPU + {56D44318-5979-4FC5-9F01-4D7F78709A0E} + Library + Properties + JexusManager.Features.RequestFiltering + JexusManager.Features.RequestFiltering + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + + + + + + + + + + + + Form + + + NewExtensionDialog.cs + + + Form + + + NewHeaderDialog.cs + + + Form + + + NewHiddenSegmentDialog.cs + + + Form + + + NewQueryDialog.cs + + + Form + + + NewRuleDialog.cs + + + Form + + + NewUrlDialog.cs + + + Form + + + NewVerbDialog.cs + + + + True + True + Resources.resx + + + + + + + + UserControl + + + RequestFilteringPage.cs + + + + + Form + + + SegmentSettingsDialog.cs + + + + + + + + + NewExtensionDialog.cs + + + NewHeaderDialog.cs + + + NewHiddenSegmentDialog.cs + + + NewQueryDialog.cs + + + NewRuleDialog.cs + + + NewUrlDialog.cs + + + NewVerbDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + RequestFilteringPage.cs + + + SegmentSettingsDialog.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/JexusManager.snk b/JexusManager.Features.RequestFiltering/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.RequestFiltering/NewExtensionDialog.Designer.cs b/JexusManager.Features.RequestFiltering/NewExtensionDialog.Designer.cs new file mode 100644 index 00000000..93c537a4 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewExtensionDialog.Designer.cs @@ -0,0 +1,102 @@ +namespace JexusManager.Features.RequestFiltering +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal sealed partial class NewExtensionDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(103, 13); + this.label1.TabIndex = 7; + this.label1.Text = "File name extension:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(15, 25); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(320, 20); + this.txtName.TabIndex = 6; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(139, 87); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 5; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(240, 87); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 4; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // NewExtensionDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(349, 126); + this.Controls.Add(this.label1); + this.Controls.Add(this.txtName); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewExtensionDialog"; + this.Text = "Allow File Name Extension"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewHiddenSegmentDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label1; + private TextBox txtName; + private Button btnOK; + private Button btnCancel; + } +} diff --git a/JexusManager.Features.RequestFiltering/NewExtensionDialog.cs b/JexusManager.Features.RequestFiltering/NewExtensionDialog.cs new file mode 100644 index 00000000..d1d54ec4 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewExtensionDialog.cs @@ -0,0 +1,51 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewExtensionDialog : DialogForm + { + public NewExtensionDialog(IServiceProvider serviceProvider, bool allowed) + : base(serviceProvider) + { + InitializeComponent(); + Text = string.Format("{0} File Name Extension", allowed ? "Allow" : "Deny"); + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item = new FileExtensionsItem(null) { Extension = txtName.Text }; + DialogResult = DialogResult.OK; + })); + } + + public FileExtensionsItem Item { get; set; } + + private void NewHiddenSegmentDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210526#Allow_Extension"); + } + } +} diff --git a/JexusManager.Features.RequestFiltering/NewExtensionDialog.resx b/JexusManager.Features.RequestFiltering/NewExtensionDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewExtensionDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/NewHeaderDialog.Designer.cs b/JexusManager.Features.RequestFiltering/NewHeaderDialog.Designer.cs new file mode 100644 index 00000000..e989d092 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewHeaderDialog.Designer.cs @@ -0,0 +1,124 @@ +namespace JexusManager.Features.RequestFiltering +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal sealed partial class NewHeaderDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.lblName = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.txtLimit = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // lblName + // + this.lblName.AutoSize = true; + this.lblName.Location = new System.Drawing.Point(12, 9); + this.lblName.Name = "lblName"; + this.lblName.Size = new System.Drawing.Size(45, 13); + this.lblName.TabIndex = 7; + this.lblName.Text = "Header:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(15, 25); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(320, 20); + this.txtName.TabIndex = 6; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(141, 131); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 5; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(242, 131); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 4; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(13, 65); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(50, 13); + this.label1.TabIndex = 9; + this.label1.Text = "Size limit:"; + // + // txtLimit + // + this.txtLimit.Location = new System.Drawing.Point(16, 81); + this.txtLimit.Name = "txtLimit"; + this.txtLimit.Size = new System.Drawing.Size(320, 20); + this.txtLimit.TabIndex = 8; + // + // NewHeaderDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(349, 166); + this.Controls.Add(this.label1); + this.Controls.Add(this.txtLimit); + this.Controls.Add(this.lblName); + this.Controls.Add(this.txtName); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewHeaderDialog"; + this.Text = "Allow Query String"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewHiddenSegmentDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label lblName; + private TextBox txtName; + private Button btnOK; + private Button btnCancel; + private Label label1; + private TextBox txtLimit; + } +} diff --git a/JexusManager.Features.RequestFiltering/NewHeaderDialog.cs b/JexusManager.Features.RequestFiltering/NewHeaderDialog.cs new file mode 100644 index 00000000..6d49acb2 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewHeaderDialog.cs @@ -0,0 +1,52 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewHeaderDialog : DialogForm + { + public NewHeaderDialog(IServiceProvider serviceProvider) + : base(serviceProvider) + { + InitializeComponent(); + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Merge(Observable.FromEventPattern(txtLimit, "TextChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text) + && !string.IsNullOrWhiteSpace(txtLimit.Text); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item = new HeadersItem(null) { Header = txtName.Text, SizeLimit = uint.Parse(txtLimit.Text) }; + DialogResult = DialogResult.OK; + })); + } + + public HeadersItem Item { get; set; } + + private void NewHiddenSegmentDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210526#Allow_Header"); + } + } +} diff --git a/JexusManager.Features.RequestFiltering/NewHeaderDialog.resx b/JexusManager.Features.RequestFiltering/NewHeaderDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewHeaderDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/NewHiddenSegmentDialog.Designer.cs b/JexusManager.Features.RequestFiltering/NewHiddenSegmentDialog.Designer.cs new file mode 100644 index 00000000..b8d66ba0 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewHiddenSegmentDialog.Designer.cs @@ -0,0 +1,102 @@ +namespace JexusManager.Features.RequestFiltering +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal partial class NewHiddenSegmentDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(87, 13); + this.label1.TabIndex = 7; + this.label1.Text = "Hidden segment:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(15, 25); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(320, 20); + this.txtName.TabIndex = 6; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(139, 87); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 5; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(240, 87); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 4; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // NewHiddenSegmentDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(349, 126); + this.Controls.Add(this.label1); + this.Controls.Add(this.txtName); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewHiddenSegmentDialog"; + this.Text = "Add Hidden Segment"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewHiddenSegmentDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label1; + private TextBox txtName; + private Button btnOK; + private Button btnCancel; + } +} diff --git a/JexusManager.Features.RequestFiltering/NewHiddenSegmentDialog.cs b/JexusManager.Features.RequestFiltering/NewHiddenSegmentDialog.cs new file mode 100644 index 00000000..f5bd8c34 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewHiddenSegmentDialog.cs @@ -0,0 +1,51 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal partial class NewHiddenSegmentDialog : DialogForm + { + public NewHiddenSegmentDialog(IServiceProvider serviceProvider) + : base(serviceProvider) + { + InitializeComponent(); + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item = new HiddenSegmentsItem(null); + Item.Segment = txtName.Text; + DialogResult = DialogResult.OK; + })); + } + + public HiddenSegmentsItem Item { get; set; } + + private void NewHiddenSegmentDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210526#Add_Hidden"); + } + } +} diff --git a/JexusManager.Features.RequestFiltering/NewHiddenSegmentDialog.resx b/JexusManager.Features.RequestFiltering/NewHiddenSegmentDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewHiddenSegmentDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/NewQueryDialog.Designer.cs b/JexusManager.Features.RequestFiltering/NewQueryDialog.Designer.cs new file mode 100644 index 00000000..8d888185 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewQueryDialog.Designer.cs @@ -0,0 +1,102 @@ +namespace JexusManager.Features.RequestFiltering +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal sealed partial class NewQueryDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.lblName = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // lblName + // + this.lblName.AutoSize = true; + this.lblName.Location = new System.Drawing.Point(12, 9); + this.lblName.Name = "lblName"; + this.lblName.Size = new System.Drawing.Size(66, 13); + this.lblName.TabIndex = 7; + this.lblName.Text = "Query string:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(15, 25); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(320, 20); + this.txtName.TabIndex = 6; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(139, 87); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 5; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(240, 87); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 4; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // NewQueryDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(349, 126); + this.Controls.Add(this.lblName); + this.Controls.Add(this.txtName); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewQueryDialog"; + this.Text = "Allow Query String"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewHiddenSegmentDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label lblName; + private TextBox txtName; + private Button btnOK; + private Button btnCancel; + } +} diff --git a/JexusManager.Features.RequestFiltering/NewQueryDialog.cs b/JexusManager.Features.RequestFiltering/NewQueryDialog.cs new file mode 100644 index 00000000..4946798c --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewQueryDialog.cs @@ -0,0 +1,51 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewQueryDialog : DialogForm + { + public NewQueryDialog(IServiceProvider serviceProvider, bool allowed) + : base(serviceProvider) + { + InitializeComponent(); + Text = allowed ? "Allow Query String" : "Deny Query String"; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item = new QueryStringsItem(null, allowed) { QueryString = txtName.Text }; + DialogResult = DialogResult.OK; + })); + } + + public QueryStringsItem Item { get; set; } + + private void NewHiddenSegmentDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210526#Allow_Query"); + } + } +} diff --git a/JexusManager.Features.RequestFiltering/NewQueryDialog.resx b/JexusManager.Features.RequestFiltering/NewQueryDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewQueryDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/NewRuleDialog.Designer.cs b/JexusManager.Features.RequestFiltering/NewRuleDialog.Designer.cs new file mode 100644 index 00000000..0c81a162 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewRuleDialog.Designer.cs @@ -0,0 +1,239 @@ +namespace JexusManager.Features.RequestFiltering +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal sealed partial class NewRuleDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.lblName = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.cbUrl = new System.Windows.Forms.CheckBox(); + this.cbQuery = new System.Windows.Forms.CheckBox(); + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.dgvHeaders = new System.Windows.Forms.DataGridView(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.dgvExtensions = new System.Windows.Forms.DataGridView(); + this.groupBox3 = new System.Windows.Forms.GroupBox(); + this.dgvStrings = new System.Windows.Forms.DataGridView(); + this.chString = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.chExtension = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.chHeader = new System.Windows.Forms.DataGridViewTextBoxColumn(); + this.groupBox1.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.dgvHeaders)).BeginInit(); + this.groupBox2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.dgvExtensions)).BeginInit(); + this.groupBox3.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.dgvStrings)).BeginInit(); + this.SuspendLayout(); + // + // lblName + // + this.lblName.AutoSize = true; + this.lblName.Location = new System.Drawing.Point(12, 9); + this.lblName.Name = "lblName"; + this.lblName.Size = new System.Drawing.Size(38, 13); + this.lblName.TabIndex = 7; + this.lblName.Text = "Name:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(15, 25); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(320, 20); + this.txtName.TabIndex = 6; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(251, 591); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 5; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(352, 591); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 4; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // cbUrl + // + this.cbUrl.AutoSize = true; + this.cbUrl.Location = new System.Drawing.Point(15, 62); + this.cbUrl.Name = "cbUrl"; + this.cbUrl.Size = new System.Drawing.Size(65, 17); + this.cbUrl.TabIndex = 8; + this.cbUrl.Text = "Scan url"; + this.cbUrl.UseVisualStyleBackColor = true; + // + // cbQuery + // + this.cbQuery.AutoSize = true; + this.cbQuery.Location = new System.Drawing.Point(15, 97); + this.cbQuery.Name = "cbQuery"; + this.cbQuery.Size = new System.Drawing.Size(108, 17); + this.cbQuery.TabIndex = 9; + this.cbQuery.Text = "Scan query string"; + this.cbQuery.UseVisualStyleBackColor = true; + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.dgvHeaders); + this.groupBox1.Location = new System.Drawing.Point(15, 120); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(432, 130); + this.groupBox1.TabIndex = 10; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "Scan Headers"; + // + // dgvHeaders + // + this.dgvHeaders.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.dgvHeaders.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.chHeader}); + this.dgvHeaders.Location = new System.Drawing.Point(6, 19); + this.dgvHeaders.Name = "dgvHeaders"; + this.dgvHeaders.Size = new System.Drawing.Size(420, 105); + this.dgvHeaders.TabIndex = 0; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.dgvExtensions); + this.groupBox2.Location = new System.Drawing.Point(15, 266); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(432, 130); + this.groupBox2.TabIndex = 11; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Applied To"; + // + // dgvExtensions + // + this.dgvExtensions.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.dgvExtensions.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.chExtension}); + this.dgvExtensions.Location = new System.Drawing.Point(6, 19); + this.dgvExtensions.Name = "dgvExtensions"; + this.dgvExtensions.Size = new System.Drawing.Size(420, 105); + this.dgvExtensions.TabIndex = 0; + // + // groupBox3 + // + this.groupBox3.Controls.Add(this.dgvStrings); + this.groupBox3.Location = new System.Drawing.Point(15, 418); + this.groupBox3.Name = "groupBox3"; + this.groupBox3.Size = new System.Drawing.Size(432, 130); + this.groupBox3.TabIndex = 11; + this.groupBox3.TabStop = false; + this.groupBox3.Text = "Deny Strings"; + // + // dgvStrings + // + this.dgvStrings.ColumnHeadersHeightSizeMode = System.Windows.Forms.DataGridViewColumnHeadersHeightSizeMode.AutoSize; + this.dgvStrings.Columns.AddRange(new System.Windows.Forms.DataGridViewColumn[] { + this.chString}); + this.dgvStrings.Location = new System.Drawing.Point(6, 19); + this.dgvStrings.Name = "dgvStrings"; + this.dgvStrings.Size = new System.Drawing.Size(420, 105); + this.dgvStrings.TabIndex = 0; + // + // chString + // + this.chString.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.chString.HeaderText = "String"; + this.chString.Name = "chString"; + // + // chExtension + // + this.chExtension.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.chExtension.HeaderText = "File Extension"; + this.chExtension.Name = "chExtension"; + // + // chHeader + // + this.chHeader.AutoSizeMode = System.Windows.Forms.DataGridViewAutoSizeColumnMode.Fill; + this.chHeader.HeaderText = "Header"; + this.chHeader.Name = "chHeader"; + // + // NewRuleDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(459, 626); + this.Controls.Add(this.groupBox3); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.Controls.Add(this.cbQuery); + this.Controls.Add(this.cbUrl); + this.Controls.Add(this.lblName); + this.Controls.Add(this.txtName); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewRuleDialog"; + this.Text = "Add Filtering Rule"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewHiddenSegmentDialogHelpButtonClicked); + this.groupBox1.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.dgvHeaders)).EndInit(); + this.groupBox2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.dgvExtensions)).EndInit(); + this.groupBox3.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.dgvStrings)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label lblName; + private TextBox txtName; + private Button btnOK; + private Button btnCancel; + private CheckBox cbUrl; + private CheckBox cbQuery; + private GroupBox groupBox1; + private DataGridView dgvHeaders; + private DataGridViewTextBoxColumn chHeader; + private GroupBox groupBox2; + private DataGridView dgvExtensions; + private DataGridViewTextBoxColumn chExtension; + private GroupBox groupBox3; + private DataGridView dgvStrings; + private DataGridViewTextBoxColumn chString; + } +} diff --git a/JexusManager.Features.RequestFiltering/NewRuleDialog.cs b/JexusManager.Features.RequestFiltering/NewRuleDialog.cs new file mode 100644 index 00000000..e6ef6db1 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewRuleDialog.cs @@ -0,0 +1,105 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewRuleDialog : DialogForm + { + public NewRuleDialog(IServiceProvider serviceProvider, FilteringRulesItem existing) + : base(serviceProvider) + { + InitializeComponent(); + Text = existing == null ? "Add Filtering Rule" : "Edit Filtering Rule"; + txtName.ReadOnly = existing != null; + if (existing != null) + { + txtName.Text = existing.Name; + dgvHeaders.DataSource = existing.Headers; + dgvExtensions.DataSource = existing.Extensions; + dgvStrings.DataSource = existing.DenyStrings; + cbUrl.Checked = existing.ScanUrl; + cbQuery.Checked = existing.ScanQueryString; + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item = new FilteringRulesItem(null) { Name = txtName.Text }; + Item.ScanQueryString = cbQuery.Checked; + Item.ScanUrl = cbUrl.Checked; + Item.Headers.Clear(); + foreach (DataGridViewRow row in dgvHeaders.Rows) + { + if (row.IsNewRow) + { + continue; + } + + var header = row.Cells[0].Value.ToString(); + Item.Headers.Add(new ScanHeadersItem(null) { RequestHeader = header }); + } + + Item.Extensions.Clear(); + foreach (DataGridViewRow row in dgvExtensions.Rows) + { + if (row.IsNewRow) + { + continue; + } + + var header = row.Cells[0].Value.ToString(); + Item.Extensions.Add(new AppliesToItem(null) { FileExtension = header }); + } + + Item.DenyStrings.Clear(); + foreach (DataGridViewRow row in dgvStrings.Rows) + { + if (row.IsNewRow) + { + continue; + } + + var header = row.Cells[0].Value.ToString(); + Item.DenyStrings.Add(new DenyStringsItem(null) { DenyString = header }); + } + + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Merge(Observable.FromEventPattern(dgvHeaders, "RowsAdded")) + .Merge(Observable.FromEventPattern(dgvExtensions, "RowsAdded")) + .Merge(Observable.FromEventPattern(dgvStrings, "RowsAdded")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text) + && dgvHeaders.RowCount > 1 + && dgvExtensions.RowCount > 1 + && dgvStrings.RowCount > 1; + })); + } + + public FilteringRulesItem Item { get; set; } + + private void NewHiddenSegmentDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210526#Add_Filtering"); + } + } +} diff --git a/JexusManager.Features.RequestFiltering/NewRuleDialog.resx b/JexusManager.Features.RequestFiltering/NewRuleDialog.resx new file mode 100644 index 00000000..e956b17d --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewRuleDialog.resx @@ -0,0 +1,135 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + True + + + True + + + True + + + True + + + True + + \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/NewUrlDialog.Designer.cs b/JexusManager.Features.RequestFiltering/NewUrlDialog.Designer.cs new file mode 100644 index 00000000..1c158ab0 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewUrlDialog.Designer.cs @@ -0,0 +1,102 @@ +namespace JexusManager.Features.RequestFiltering +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal sealed partial class NewUrlDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.lblName = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // lblName + // + this.lblName.AutoSize = true; + this.lblName.Location = new System.Drawing.Point(12, 9); + this.lblName.Name = "lblName"; + this.lblName.Size = new System.Drawing.Size(32, 13); + this.lblName.TabIndex = 7; + this.lblName.Text = "URL:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(15, 25); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(320, 20); + this.txtName.TabIndex = 6; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(139, 87); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 5; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(240, 87); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 4; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // NewUrlDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(349, 126); + this.Controls.Add(this.lblName); + this.Controls.Add(this.txtName); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewUrlDialog"; + this.Text = "Allow URL"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewHiddenSegmentDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label lblName; + private TextBox txtName; + private Button btnOK; + private Button btnCancel; + } +} diff --git a/JexusManager.Features.RequestFiltering/NewUrlDialog.cs b/JexusManager.Features.RequestFiltering/NewUrlDialog.cs new file mode 100644 index 00000000..e5e98931 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewUrlDialog.cs @@ -0,0 +1,52 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewUrlDialog : DialogForm + { + public NewUrlDialog(IServiceProvider serviceProvider, bool allowed) + : base(serviceProvider) + { + InitializeComponent(); + Text = allowed ? "Allow URL" : "Deny Sequence"; + lblName.Text = allowed ? "URL:" : "URL sequence"; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item = new UrlsItem(null, allowed) { Url = txtName.Text }; + DialogResult = DialogResult.OK; + })); + } + + public UrlsItem Item { get; set; } + + private void NewHiddenSegmentDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210526#Add_Sequence"); + } + } +} diff --git a/JexusManager.Features.RequestFiltering/NewUrlDialog.resx b/JexusManager.Features.RequestFiltering/NewUrlDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewUrlDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/NewVerbDialog.Designer.cs b/JexusManager.Features.RequestFiltering/NewVerbDialog.Designer.cs new file mode 100644 index 00000000..480324fa --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewVerbDialog.Designer.cs @@ -0,0 +1,102 @@ +namespace JexusManager.Features.RequestFiltering +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal sealed partial class NewVerbDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.lblName = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // lblName + // + this.lblName.AutoSize = true; + this.lblName.Location = new System.Drawing.Point(12, 9); + this.lblName.Name = "lblName"; + this.lblName.Size = new System.Drawing.Size(66, 13); + this.lblName.TabIndex = 7; + this.lblName.Text = "Query string:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(15, 25); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(320, 20); + this.txtName.TabIndex = 6; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(139, 87); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(95, 23); + this.btnOK.TabIndex = 5; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(240, 87); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 4; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // NewVerbDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(349, 126); + this.Controls.Add(this.lblName); + this.Controls.Add(this.txtName); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewVerbDialog"; + this.Text = "Allow Query String"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewHiddenSegmentDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label lblName; + private TextBox txtName; + private Button btnOK; + private Button btnCancel; + } +} diff --git a/JexusManager.Features.RequestFiltering/NewVerbDialog.cs b/JexusManager.Features.RequestFiltering/NewVerbDialog.cs new file mode 100644 index 00000000..c140ed39 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewVerbDialog.cs @@ -0,0 +1,51 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewVerbDialog : DialogForm + { + public NewVerbDialog(IServiceProvider serviceProvider, bool allowed) + : base(serviceProvider) + { + InitializeComponent(); + Text = allowed ? "Allow Verb" : "Deny Verb"; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item = new VerbsItem(null) { Verb = txtName.Text, Allowed = allowed }; + DialogResult = DialogResult.OK; + })); + } + + public VerbsItem Item { get; set; } + + private void NewHiddenSegmentDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210526#Allow_Verb"); + } + } +} diff --git a/JexusManager.Features.RequestFiltering/NewVerbDialog.resx b/JexusManager.Features.RequestFiltering/NewVerbDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/NewVerbDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/Properties/AssemblyInfo.cs b/JexusManager.Features.RequestFiltering/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..d9e223b7 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/Properties/AssemblyInfo.cs @@ -0,0 +1,46 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.RequestFiltering")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.RequestFiltering")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("56d44318-5979-4fc5-9f01-4d7f78709a0e")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("Tests.JexusManager, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] diff --git a/JexusManager.Features.RequestFiltering/Properties/Resources.Designer.cs b/JexusManager.Features.RequestFiltering/Properties/Resources.Designer.cs new file mode 100644 index 00000000..437c750a --- /dev/null +++ b/JexusManager.Features.RequestFiltering/Properties/Resources.Designer.cs @@ -0,0 +1,143 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.RequestFiltering.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.RequestFiltering.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap extensions_16 { + get { + object obj = ResourceManager.GetObject("extensions_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap headers_16 { + get { + object obj = ResourceManager.GetObject("headers_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap hidden_16 { + get { + object obj = ResourceManager.GetObject("hidden_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap map_16 { + get { + object obj = ResourceManager.GetObject("map_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap query_16 { + get { + object obj = ResourceManager.GetObject("query_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap request_filtering_36 { + get { + object obj = ResourceManager.GetObject("request_filtering_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap url_16 { + get { + object obj = ResourceManager.GetObject("url_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap verbs_16 { + get { + object obj = ResourceManager.GetObject("verbs_16", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.RequestFiltering/Properties/Resources.resx b/JexusManager.Features.RequestFiltering/Properties/Resources.resx new file mode 100644 index 00000000..be887598 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/Properties/Resources.resx @@ -0,0 +1,145 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\extensions_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\headers_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\hidden_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\map_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\query_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\request_filtering_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\url_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + + ..\Resources\verbs_16.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/QueryStringsFeature.cs b/JexusManager.Features.RequestFiltering/QueryStringsFeature.cs new file mode 100644 index 00000000..c907469d --- /dev/null +++ b/JexusManager.Features.RequestFiltering/QueryStringsFeature.cs @@ -0,0 +1,146 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + internal class QueryStringsFeature : RequestFilteringFeature + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly QueryStringsFeature _owner; + + public FeatureTaskList(QueryStringsFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("AddQuery", "Allow Query String...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("AddDenyQuery", "Deny Query String...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void AddQuery() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public void AddDenyQuery() + { + _owner.AddDeny(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + } + + public QueryStringsFeature(Module module) + : base(module) + { + } + + private TaskList _taskList; + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Add() + { + var dialog = new NewQueryDialog(this.Module, true); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void AddDeny() + { + var dialog = new NewQueryDialog(this.Module, false); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + AddItem(dialog.Item); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected query string?", this.Name, + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + var section = service.GetSection("system.webServer/security/requestFiltering"); + ConfigurationElement hiddenSegmentsElement = section.ChildElements["alwaysAllowedQueryStrings"]; + return hiddenSegmentsElement.GetCollection(); + } + + protected override ConfigurationElementCollection GetSecondaryCollection(IConfigurationService service) + { + var section = service.GetSection("system.webServer/security/requestFiltering"); + ConfigurationElement hiddenSegmentsElement = section.ChildElements["denyQueryStringSequences"]; + return hiddenSegmentsElement.GetCollection(); + } + + public override void Load() + { + LoadItems(); + } + + public override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210526#Query_Strings"); + return true; + } + + public override string Name + { + get + { + return "Query Strings"; + } + } + } +} diff --git a/JexusManager.Features.RequestFiltering/QueryStringsItem.cs b/JexusManager.Features.RequestFiltering/QueryStringsItem.cs new file mode 100644 index 00000000..c4e417a1 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/QueryStringsItem.cs @@ -0,0 +1,60 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using Microsoft.Web.Administration; + + internal class QueryStringsItem : IDuoItem + { + public bool Allowed { get; } + + public ConfigurationElement Element { get; set; } + + public bool Match(QueryStringsItem other) + { + return other != null && other.QueryString == QueryString; + } + + public QueryStringsItem(ConfigurationElement element, bool allowed) + { + this.Allowed = allowed; + this.Element = element; + if (element == null) + { + return; + } + + if (allowed) + { + QueryString = (string)element["queryString"]; + } + else + { + QueryString = (string)element["sequence"]; + } + } + + public string QueryString { get; set; } + + public void Apply() + { + if (Allowed) + { + Element["queryString"] = QueryString; + } + else + { + Element["sequence"] = QueryString; + } + } + + public string Flag { get; set; } + + public bool Equals(QueryStringsItem other) + { + return Match(other) && other.Allowed == Allowed; + } + } +} diff --git a/JexusManager.Features.RequestFiltering/RequestFilteringFeature.cs b/JexusManager.Features.RequestFiltering/RequestFilteringFeature.cs new file mode 100644 index 00000000..f894dbc8 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/RequestFilteringFeature.cs @@ -0,0 +1,57 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +/* + * Created by SharpDevelop. + * User: lextm + * Time: 11:06 AM + * + * To change this template use Tools | Options | Coding | Edit Standard Headers. + */ + +namespace JexusManager.Features.RequestFiltering +{ + using System; + + using Microsoft.Web.Management.Client; + + /// + /// Description of DefaultDocumentFeature. + /// + internal abstract class RequestFilteringFeature : FeatureBase, IRequestFilteringFeature + where T : class, IItem + { + protected RequestFilteringFeature(Module module) + : base(module) + { + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + + public abstract TaskList GetTaskList(); + + public abstract void Load(); + + protected override void OnSettingsSaved() + { + this.RequestFilteringSettingsUpdate?.Invoke(); + } + + public abstract bool ShowHelp(); + + public RequestFilteringSettingsSavedEventHandler RequestFilteringSettingsUpdate { get; set; } + + public string Description { get; } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public abstract string Name { get; } + } +} diff --git a/JexusManager.Features.RequestFiltering/RequestFilteringModule.cs b/JexusManager.Features.RequestFiltering/RequestFilteringModule.cs new file mode 100644 index 00000000..2723b07a --- /dev/null +++ b/JexusManager.Features.RequestFiltering/RequestFilteringModule.cs @@ -0,0 +1,26 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System; + + using Properties; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + + internal class RequestFilteringModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(RequestFilteringPage), "Request Filtering", + "Use this feature to configure filtering rules", Resources.request_filtering_36, + Resources.request_filtering_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.RequestFiltering/RequestFilteringModuleProvider.cs b/JexusManager.Features.RequestFiltering/RequestFilteringModuleProvider.cs new file mode 100644 index 00000000..8d832ac6 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/RequestFilteringModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System; + + using Microsoft.Web.Management.Server; + + public class RequestFilteringModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(Name, typeof(RequestFilteringModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.RequestFiltering/RequestFilteringPage.Designer.cs b/JexusManager.Features.RequestFiltering/RequestFilteringPage.Designer.cs new file mode 100644 index 00000000..4b97cd08 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/RequestFilteringPage.Designer.cs @@ -0,0 +1,581 @@ +namespace JexusManager.Features.RequestFiltering +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class RequestFilteringPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.tabControl1 = new System.Windows.Forms.TabControl(); + this.tpExtensions = new System.Windows.Forms.TabPage(); + this.lvExtensions = new System.Windows.Forms.ListView(); + this.chExtension = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chAllowedExtension = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.tpRules = new System.Windows.Forms.TabPage(); + this.lvRules = new System.Windows.Forms.ListView(); + this.columnHeader2 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader10 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader11 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader12 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.tpSegments = new System.Windows.Forms.TabPage(); + this.lvSegments = new System.Windows.Forms.ListView(); + this.chName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.tpUrl = new System.Windows.Forms.TabPage(); + this.lvUrls = new System.Windows.Forms.ListView(); + this.columnHeader3 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader9 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.tpVerbs = new System.Windows.Forms.TabPage(); + this.lvVerbs = new System.Windows.Forms.ListView(); + this.columnHeader4 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader8 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.tpHeaders = new System.Windows.Forms.TabPage(); + this.lvHeaders = new System.Windows.Forms.ListView(); + this.columnHeader5 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader7 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.tpQuery = new System.Windows.Forms.TabPage(); + this.lvQueries = new System.Windows.Forms.ListView(); + this.columnHeader6 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.columnHeader1 = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.imageList1 = new System.Windows.Forms.ImageList(this.components); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.tabControl1.SuspendLayout(); + this.tpExtensions.SuspendLayout(); + this.tpRules.SuspendLayout(); + this.tpSegments.SuspendLayout(); + this.tpUrl.SuspendLayout(); + this.tpVerbs.SuspendLayout(); + this.tpHeaders.SuspendLayout(); + this.tpQuery.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 4; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.SplitContainer1SplitterMoved); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.tabControl1); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 6; + // + // tabControl1 + // + this.tabControl1.Controls.Add(this.tpExtensions); + this.tabControl1.Controls.Add(this.tpRules); + this.tabControl1.Controls.Add(this.tpSegments); + this.tabControl1.Controls.Add(this.tpUrl); + this.tabControl1.Controls.Add(this.tpVerbs); + this.tabControl1.Controls.Add(this.tpHeaders); + this.tabControl1.Controls.Add(this.tpQuery); + this.tabControl1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tabControl1.ImageList = this.imageList1; + this.tabControl1.Location = new System.Drawing.Point(0, 13); + this.tabControl1.Name = "tabControl1"; + this.tabControl1.SelectedIndex = 0; + this.tabControl1.Size = new System.Drawing.Size(560, 527); + this.tabControl1.TabIndex = 2; + this.tabControl1.SelectedIndexChanged += new System.EventHandler(this.TabControl1SelectedIndexChanged); + // + // tpExtensions + // + this.tpExtensions.Controls.Add(this.lvExtensions); + this.tpExtensions.Location = new System.Drawing.Point(4, 23); + this.tpExtensions.Name = "tpExtensions"; + this.tpExtensions.Size = new System.Drawing.Size(552, 500); + this.tpExtensions.TabIndex = 2; + this.tpExtensions.Text = "File Name Extensions"; + this.tpExtensions.UseVisualStyleBackColor = true; + // + // lvExtensions + // + this.lvExtensions.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chExtension, + this.chAllowedExtension}); + this.lvExtensions.Dock = System.Windows.Forms.DockStyle.Fill; + this.lvExtensions.FullRowSelect = true; + this.lvExtensions.HideSelection = false; + this.lvExtensions.Location = new System.Drawing.Point(0, 0); + this.lvExtensions.Margin = new System.Windows.Forms.Padding(5); + this.lvExtensions.MultiSelect = false; + this.lvExtensions.Name = "lvExtensions"; + this.lvExtensions.Size = new System.Drawing.Size(552, 500); + this.lvExtensions.TabIndex = 1; + this.lvExtensions.UseCompatibleStateImageBehavior = false; + this.lvExtensions.View = System.Windows.Forms.View.Details; + this.lvExtensions.SelectedIndexChanged += new System.EventHandler(this.LvExtensionsSelectedIndexChanged); + // + // chExtension + // + this.chExtension.Text = "Extension"; + this.chExtension.Width = 105; + // + // chAllowedExtension + // + this.chAllowedExtension.Text = "Allowed"; + // + // tpRules + // + this.tpRules.Controls.Add(this.lvRules); + this.tpRules.Location = new System.Drawing.Point(4, 23); + this.tpRules.Name = "tpRules"; + this.tpRules.Size = new System.Drawing.Size(552, 500); + this.tpRules.TabIndex = 3; + this.tpRules.Text = "Rules"; + this.tpRules.UseVisualStyleBackColor = true; + // + // lvRules + // + this.lvRules.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader2, + this.columnHeader10, + this.columnHeader11, + this.columnHeader12}); + this.lvRules.Dock = System.Windows.Forms.DockStyle.Fill; + this.lvRules.FullRowSelect = true; + this.lvRules.HideSelection = false; + this.lvRules.Location = new System.Drawing.Point(0, 0); + this.lvRules.Margin = new System.Windows.Forms.Padding(5); + this.lvRules.MultiSelect = false; + this.lvRules.Name = "lvRules"; + this.lvRules.Size = new System.Drawing.Size(552, 500); + this.lvRules.TabIndex = 1; + this.lvRules.UseCompatibleStateImageBehavior = false; + this.lvRules.View = System.Windows.Forms.View.Details; + this.lvRules.SelectedIndexChanged += new System.EventHandler(this.LvRuleSelectedIndexChanged); + // + // columnHeader2 + // + this.columnHeader2.Text = "Name"; + this.columnHeader2.Width = 105; + // + // columnHeader10 + // + this.columnHeader10.Text = "Scan"; + this.columnHeader10.Width = 105; + // + // columnHeader11 + // + this.columnHeader11.Text = "Applied To"; + this.columnHeader11.Width = 105; + // + // columnHeader12 + // + this.columnHeader12.Text = "Deny Strings"; + this.columnHeader12.Width = 105; + // + // tpSegments + // + this.tpSegments.Controls.Add(this.lvSegments); + this.tpSegments.Location = new System.Drawing.Point(4, 23); + this.tpSegments.Name = "tpSegments"; + this.tpSegments.Padding = new System.Windows.Forms.Padding(3); + this.tpSegments.Size = new System.Drawing.Size(552, 500); + this.tpSegments.TabIndex = 0; + this.tpSegments.Text = "Hidden Segments"; + this.tpSegments.UseVisualStyleBackColor = true; + // + // lvSegments + // + this.lvSegments.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chName}); + this.lvSegments.Dock = System.Windows.Forms.DockStyle.Fill; + this.lvSegments.FullRowSelect = true; + this.lvSegments.HideSelection = false; + this.lvSegments.Location = new System.Drawing.Point(3, 3); + this.lvSegments.Margin = new System.Windows.Forms.Padding(5); + this.lvSegments.MultiSelect = false; + this.lvSegments.Name = "lvSegments"; + this.lvSegments.Size = new System.Drawing.Size(546, 494); + this.lvSegments.TabIndex = 0; + this.lvSegments.UseCompatibleStateImageBehavior = false; + this.lvSegments.View = System.Windows.Forms.View.Details; + this.lvSegments.SelectedIndexChanged += new System.EventHandler(this.LvSegmentsSelectedIndexChanged); + // + // chName + // + this.chName.Text = "Segment"; + this.chName.Width = 200; + // + // tpUrl + // + this.tpUrl.Controls.Add(this.lvUrls); + this.tpUrl.Location = new System.Drawing.Point(4, 23); + this.tpUrl.Name = "tpUrl"; + this.tpUrl.Padding = new System.Windows.Forms.Padding(3); + this.tpUrl.Size = new System.Drawing.Size(552, 500); + this.tpUrl.TabIndex = 1; + this.tpUrl.Text = "URL"; + this.tpUrl.UseVisualStyleBackColor = true; + // + // lvUrls + // + this.lvUrls.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader3, + this.columnHeader9}); + this.lvUrls.Dock = System.Windows.Forms.DockStyle.Fill; + this.lvUrls.FullRowSelect = true; + this.lvUrls.HideSelection = false; + this.lvUrls.Location = new System.Drawing.Point(3, 3); + this.lvUrls.Margin = new System.Windows.Forms.Padding(5); + this.lvUrls.MultiSelect = false; + this.lvUrls.Name = "lvUrls"; + this.lvUrls.Size = new System.Drawing.Size(546, 494); + this.lvUrls.TabIndex = 1; + this.lvUrls.UseCompatibleStateImageBehavior = false; + this.lvUrls.View = System.Windows.Forms.View.Details; + this.lvUrls.SelectedIndexChanged += new System.EventHandler(this.LvUrlsSelectedIndexChanged); + // + // columnHeader3 + // + this.columnHeader3.Text = "Url"; + this.columnHeader3.Width = 145; + // + // columnHeader9 + // + this.columnHeader9.Text = "Action"; + this.columnHeader9.Width = 145; + // + // tpVerbs + // + this.tpVerbs.Controls.Add(this.lvVerbs); + this.tpVerbs.Location = new System.Drawing.Point(4, 23); + this.tpVerbs.Name = "tpVerbs"; + this.tpVerbs.Size = new System.Drawing.Size(552, 500); + this.tpVerbs.TabIndex = 4; + this.tpVerbs.Text = "HTTP Verbs"; + this.tpVerbs.UseVisualStyleBackColor = true; + // + // lvVerbs + // + this.lvVerbs.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader4, + this.columnHeader8}); + this.lvVerbs.Dock = System.Windows.Forms.DockStyle.Fill; + this.lvVerbs.FullRowSelect = true; + this.lvVerbs.HideSelection = false; + this.lvVerbs.Location = new System.Drawing.Point(0, 0); + this.lvVerbs.Margin = new System.Windows.Forms.Padding(5); + this.lvVerbs.MultiSelect = false; + this.lvVerbs.Name = "lvVerbs"; + this.lvVerbs.Size = new System.Drawing.Size(552, 500); + this.lvVerbs.TabIndex = 1; + this.lvVerbs.UseCompatibleStateImageBehavior = false; + this.lvVerbs.View = System.Windows.Forms.View.Details; + this.lvVerbs.SelectedIndexChanged += new System.EventHandler(this.LvVerbsSelectedIndexChanged); + // + // columnHeader4 + // + this.columnHeader4.Text = "Verb"; + this.columnHeader4.Width = 175; + // + // columnHeader8 + // + this.columnHeader8.Text = "Allowed"; + // + // tpHeaders + // + this.tpHeaders.Controls.Add(this.lvHeaders); + this.tpHeaders.Location = new System.Drawing.Point(4, 23); + this.tpHeaders.Name = "tpHeaders"; + this.tpHeaders.Size = new System.Drawing.Size(552, 500); + this.tpHeaders.TabIndex = 5; + this.tpHeaders.Text = "Headers"; + this.tpHeaders.UseVisualStyleBackColor = true; + // + // lvHeaders + // + this.lvHeaders.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader5, + this.columnHeader7}); + this.lvHeaders.Dock = System.Windows.Forms.DockStyle.Fill; + this.lvHeaders.FullRowSelect = true; + this.lvHeaders.HideSelection = false; + this.lvHeaders.Location = new System.Drawing.Point(0, 0); + this.lvHeaders.Margin = new System.Windows.Forms.Padding(5); + this.lvHeaders.MultiSelect = false; + this.lvHeaders.Name = "lvHeaders"; + this.lvHeaders.Size = new System.Drawing.Size(552, 500); + this.lvHeaders.TabIndex = 1; + this.lvHeaders.UseCompatibleStateImageBehavior = false; + this.lvHeaders.View = System.Windows.Forms.View.Details; + this.lvHeaders.SelectedIndexChanged += new System.EventHandler(this.LvHeadersSelectedIndexChanged); + // + // columnHeader5 + // + this.columnHeader5.Text = "Header"; + this.columnHeader5.Width = 175; + // + // columnHeader7 + // + this.columnHeader7.Text = "Size Limit"; + // + // tpQuery + // + this.tpQuery.Controls.Add(this.lvQueries); + this.tpQuery.Location = new System.Drawing.Point(4, 23); + this.tpQuery.Name = "tpQuery"; + this.tpQuery.Size = new System.Drawing.Size(552, 500); + this.tpQuery.TabIndex = 6; + this.tpQuery.Text = "Query Strings"; + this.tpQuery.UseVisualStyleBackColor = true; + // + // lvQueries + // + this.lvQueries.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.columnHeader6, + this.columnHeader1}); + this.lvQueries.Dock = System.Windows.Forms.DockStyle.Fill; + this.lvQueries.FullRowSelect = true; + this.lvQueries.HideSelection = false; + this.lvQueries.Location = new System.Drawing.Point(0, 0); + this.lvQueries.Margin = new System.Windows.Forms.Padding(5); + this.lvQueries.MultiSelect = false; + this.lvQueries.Name = "lvQueries"; + this.lvQueries.Size = new System.Drawing.Size(552, 500); + this.lvQueries.TabIndex = 1; + this.lvQueries.UseCompatibleStateImageBehavior = false; + this.lvQueries.View = System.Windows.Forms.View.Details; + this.lvQueries.SelectedIndexChanged += new System.EventHandler(this.LvQueriesSelectedIndexChanged); + // + // columnHeader6 + // + this.columnHeader6.Text = "Query String"; + this.columnHeader6.Width = 145; + // + // columnHeader1 + // + this.columnHeader1.Text = "Action"; + this.columnHeader1.Width = 145; + // + // imageList1 + // + this.imageList1.ColorDepth = System.Windows.Forms.ColorDepth.Depth8Bit; + this.imageList1.ImageSize = new System.Drawing.Size(16, 16); + this.imageList1.TransparentColor = System.Drawing.Color.Transparent; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(204, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to configure filtering rules."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 5; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(175, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Request Filtering"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // RequestFilteringPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "RequestFilteringPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.tabControl1.ResumeLayout(false); + this.tpExtensions.ResumeLayout(false); + this.tpRules.ResumeLayout(false); + this.tpSegments.ResumeLayout(false); + this.tpUrl.ResumeLayout(false); + this.tpVerbs.ResumeLayout(false); + this.tpHeaders.ResumeLayout(false); + this.tpQuery.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private ListView lvSegments; + private ColumnHeader chName; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private Panel panel2; + private PictureBox pictureBox1; + private ContextMenuStrip cmsActionPanel; + private TabControl tabControl1; + private TabPage tpExtensions; + private TabPage tpRules; + private TabPage tpSegments; + private TabPage tpUrl; + private TabPage tpVerbs; + private TabPage tpHeaders; + private TabPage tpQuery; + private ImageList imageList1; + private ListView lvExtensions; + private ColumnHeader chExtension; + private ListView lvRules; + private ColumnHeader columnHeader2; + private ListView lvUrls; + private ColumnHeader columnHeader3; + private ListView lvVerbs; + private ColumnHeader columnHeader4; + private ListView lvHeaders; + private ColumnHeader columnHeader5; + private ListView lvQueries; + private ColumnHeader columnHeader6; + private ColumnHeader chAllowedExtension; + private ColumnHeader columnHeader10; + private ColumnHeader columnHeader11; + private ColumnHeader columnHeader12; + private ColumnHeader columnHeader9; + private ColumnHeader columnHeader8; + private ColumnHeader columnHeader7; + private ColumnHeader columnHeader1; + } +} diff --git a/JexusManager.Features.RequestFiltering/RequestFilteringPage.cs b/JexusManager.Features.RequestFiltering/RequestFilteringPage.cs new file mode 100644 index 00000000..471de78d --- /dev/null +++ b/JexusManager.Features.RequestFiltering/RequestFilteringPage.cs @@ -0,0 +1,541 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class RequestFilteringPage : ModuleListPage + { + private sealed class PageTaskList : DefaultTaskList + { + private readonly RequestFilteringPage _owner; + + public PageTaskList(RequestFilteringPage owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("Set", "Edit Feature Settings...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(HelpTaskItem); + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Set() + { + _owner.Set(); + } + + [Obfuscation(Exclude = true)] + public void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class ExtensionListViewItem : ListViewItem + { + public FileExtensionsItem Item { get; } + private readonly RequestFilteringPage _page; + + public ExtensionListViewItem(FileExtensionsItem item, RequestFilteringPage page) + : base(item.Extension) + { + Item = item; + _page = page; + SubItems.Add(new ListViewSubItem(this, item.Allowed ? "True" : "False")); + } + } + + private sealed class RuleListViewItem : ListViewItem + { + public FilteringRulesItem Item { get; } + private readonly RequestFilteringPage _page; + + public RuleListViewItem(FilteringRulesItem item, RequestFilteringPage page) + : base(item.Name) + { + Item = item; + _page = page; + SubItems.Add(new ListViewSubItem(this, item.ScanString)); + SubItems.Add(new ListViewSubItem(this, item.AppliesToString)); + SubItems.Add(new ListViewSubItem(this, item.DenyStringsString)); + } + } + + private sealed class SegmentListViewItem : ListViewItem + { + public HiddenSegmentsItem Item { get; } + private readonly RequestFilteringPage _page; + + public SegmentListViewItem(HiddenSegmentsItem item, RequestFilteringPage page) + : base(item.Segment) + { + Item = item; + _page = page; + } + } + + private sealed class UrlListViewItem : ListViewItem + { + public UrlsItem Item { get; } + private readonly RequestFilteringPage _page; + + public UrlListViewItem(UrlsItem item, RequestFilteringPage page) + : base(item.Url) + { + Item = item; + _page = page; + SubItems.Add(new ListViewSubItem(this, item.Allowed ? "always allow" : "Deny")); + } + } + + private sealed class VerbListViewItem : ListViewItem + { + public VerbsItem Item { get; } + private readonly RequestFilteringPage _page; + + public VerbListViewItem(VerbsItem item, RequestFilteringPage page) + : base(item.Verb) + { + Item = item; + _page = page; + SubItems.Add(new ListViewSubItem(this, item.Allowed ? "True" : "False")); + } + } + + private sealed class HeaderListViewItem : ListViewItem + { + public HeadersItem Item { get; } + private readonly RequestFilteringPage _page; + + public HeaderListViewItem(HeadersItem item, RequestFilteringPage page) + : base(item.Header) + { + Item = item; + _page = page; + SubItems.Add(new ListViewSubItem(this, item.SizeLimit.ToString())); + } + } + + private sealed class QueryListViewItem : ListViewItem + { + public QueryStringsItem Item { get; } + private readonly RequestFilteringPage _page; + + public QueryListViewItem(QueryStringsItem item, RequestFilteringPage page) + : base(item.QueryString) + { + Item = item; + _page = page; + SubItems.Add(new ListViewSubItem(this, item.Allowed ? "Always allow" : "Deny")); + } + } + + private PageTaskList _taskList; + + public RequestFilteringPage() + { + InitializeComponent(); + imageList1.Images.Add(Resources.extensions_16); + imageList1.Images.Add(Resources.map_16); + imageList1.Images.Add(Resources.hidden_16); + imageList1.Images.Add(Resources.url_16); + imageList1.Images.Add(Resources.verbs_16); + imageList1.Images.Add(Resources.headers_16); + imageList1.Images.Add(Resources.query_16); + tpExtensions.ImageIndex = 0; + tpRules.ImageIndex = 1; + tpSegments.ImageIndex = 2; + tpUrl.ImageIndex = 3; + tpVerbs.ImageIndex = 4; + tpHeaders.ImageIndex = 5; + tpQuery.ImageIndex = 6; + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + var extensions = new FileExtensionsFeature(Module); + extensions.RequestFilteringSettingsUpdate = RefreshExtensions; + extensions.Load(); + tpExtensions.Tag = extensions; + RefreshExtensions(); + + var rules = new FilteringRulesFeature(Module); + rules.RequestFilteringSettingsUpdate = RefreshRules; + rules.Load(); + tpRules.Tag = rules; + + var segments = new HiddenSegmentsFeature(Module); + segments.RequestFilteringSettingsUpdate = RefreshSegments; + segments.Load(); + tpSegments.Tag = segments; + + var urls = new UrlsFeature(Module); + urls.RequestFilteringSettingsUpdate = RefreshUrls; + urls.Load(); + tpUrl.Tag = urls; + + var verbs = new VerbsFeature(Module); + verbs.RequestFilteringSettingsUpdate = RefreshVerbs; + verbs.Load(); + tpVerbs.Tag = verbs; + + var headers = new HeadersFeature(Module); + headers.RequestFilteringSettingsUpdate = RefreshHeaders; + headers.Load(); + tpHeaders.Tag = headers; + + var queries = new QueryStringsFeature(Module); + queries.RequestFilteringSettingsUpdate = RefreshQueries; + queries.Load(); + tpQuery.Tag = queries; + } + + protected override void InitializeListPage() + { + } + + private void RefreshExtensions() + { + var feature = (FileExtensionsFeature)tpExtensions.Tag; + if (feature == null) + { + return; + } + + lvExtensions.Items.Clear(); + foreach (var file in feature.Items) + { + lvExtensions.Items.Add(new ExtensionListViewItem(file, this)); + } + + if (feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (ExtensionListViewItem item in lvExtensions.Items) + { + if (item.Item == feature.SelectedItem) + { + item.Selected = true; + } + } + } + + private void RefreshRules() + { + var feature = (FilteringRulesFeature)tpRules.Tag; + if (feature == null) + { + return; + } + + lvRules.Items.Clear(); + foreach (var file in feature.Items) + { + lvRules.Items.Add(new RuleListViewItem(file, this)); + } + + if (feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (RuleListViewItem item in lvRules.Items) + { + if (item.Item == feature.SelectedItem) + { + item.Selected = true; + } + } + } + + private void RefreshSegments() + { + var feature = (HiddenSegmentsFeature)tpSegments.Tag; + if (feature == null) + { + return; + } + + lvSegments.Items.Clear(); + foreach (var file in feature.Items) + { + lvSegments.Items.Add(new SegmentListViewItem(file, this)); + } + + if (feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (SegmentListViewItem item in lvSegments.Items) + { + if (item.Item == feature.SelectedItem) + { + item.Selected = true; + } + } + } + + private void RefreshUrls() + { + var feature = (UrlsFeature)tpUrl.Tag; + if (feature == null) + { + return; + } + + lvUrls.Items.Clear(); + foreach (var url in feature.Items) + { + lvUrls.Items.Add(new UrlListViewItem(url, this)); + } + + if (feature.SelectedItem == null) + { + Refresh(); + return; + } + + foreach (UrlListViewItem item in lvUrls.Items) + { + if (item.Item == feature.SelectedItem) + { + item.Selected = true; + } + } + } + + private void RefreshVerbs() + { + var feature = (VerbsFeature)tpVerbs.Tag; + if (feature == null) + { + return; + } + + lvVerbs.Items.Clear(); + foreach (var url in feature.Items) + { + lvVerbs.Items.Add(new VerbListViewItem(url, this)); + } + + if (feature.SelectedItem == null) + { + Refresh(); + return; + } + + foreach (VerbListViewItem item in lvVerbs.Items) + { + if (item.Item == feature.SelectedItem) + { + item.Selected = true; + } + } + } + + private void RefreshHeaders() + { + var feature = (HeadersFeature)tpHeaders.Tag; + if (feature == null) + { + return; + } + + lvHeaders.Items.Clear(); + foreach (var url in feature.Items) + { + lvHeaders.Items.Add(new HeaderListViewItem(url, this)); + } + + if (feature.SelectedItem == null) + { + Refresh(); + return; + } + + foreach (HeaderListViewItem item in lvHeaders.Items) + { + if (item.Item == feature.SelectedItem) + { + item.Selected = true; + } + } + } + + private void RefreshQueries() + { + var feature = (QueryStringsFeature)tpQuery.Tag; + if (feature == null) + { + return; + } + + lvQueries.Items.Clear(); + foreach (var url in feature.Items) + { + lvQueries.Items.Add(new QueryListViewItem(url, this)); + } + + if (feature.SelectedItem == null) + { + Refresh(); + return; + } + + foreach (QueryListViewItem item in lvQueries.Items) + { + if (item.Item == feature.SelectedItem) + { + item.Selected = true; + } + } + } + + protected override void Refresh() + { + var feature = (IRequestFilteringFeature)tabControl1.SelectedTab.Tag; + TaskList extra = feature.GetTaskList(); + Tasks.Fill(tsActionPanel, cmsActionPanel, extra); + base.Refresh(); + } + + private void LvExtensionsSelectedIndexChanged(object sender, EventArgs e) + { + var feature = (FileExtensionsFeature)tpExtensions.Tag; + feature.SelectedItem = lvExtensions.SelectedItems.Count > 0 + ? ((ExtensionListViewItem)lvExtensions.SelectedItems[0]).Item + : null; + Refresh(); + } + + private void LvRuleSelectedIndexChanged(object sender, EventArgs e) + { + var feature = (FilteringRulesFeature)tpRules.Tag; + feature.SelectedItem = lvRules.SelectedItems.Count > 0 + ? ((RuleListViewItem)lvRules.SelectedItems[0]).Item + : null; + Refresh(); + } + + private void LvSegmentsSelectedIndexChanged(object sender, EventArgs e) + { + var feature = (HiddenSegmentsFeature)tpSegments.Tag; + feature.SelectedItem = lvSegments.SelectedItems.Count > 0 + ? ((SegmentListViewItem)lvSegments.SelectedItems[0]).Item + : null; + Refresh(); + } + + private void LvUrlsSelectedIndexChanged(object sender, EventArgs e) + { + var feature = (UrlsFeature)tpUrl.Tag; + feature.SelectedItem = lvUrls.SelectedItems.Count > 0 + ? ((UrlListViewItem)lvUrls.SelectedItems[0]).Item + : null; + Refresh(); + } + + private void LvVerbsSelectedIndexChanged(object sender, EventArgs e) + { + var feature = (VerbsFeature)tpVerbs.Tag; + feature.SelectedItem = lvVerbs.SelectedItems.Count > 0 + ? ((VerbListViewItem)lvVerbs.SelectedItems[0]).Item + : null; + Refresh(); + } + + private void LvHeadersSelectedIndexChanged(object sender, EventArgs e) + { + var feature = (HeadersFeature)tpHeaders.Tag; + feature.SelectedItem = lvHeaders.SelectedItems.Count > 0 + ? ((HeaderListViewItem)lvHeaders.SelectedItems[0]).Item + : null; + Refresh(); + } + + private void LvQueriesSelectedIndexChanged(object sender, EventArgs e) + { + var feature = (QueryStringsFeature)tpQuery.Tag; + feature.SelectedItem = lvQueries.SelectedItems.Count > 0 + ? ((QueryListViewItem)lvQueries.SelectedItems[0]).Item + : null; + Refresh(); + } + + protected override bool ShowHelp() + { + var feature = (IRequestFilteringFeature)tabControl1.SelectedTab.Tag; + feature.ShowHelp(); + return true; + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + + private void SplitContainer1SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + private void TabControl1SelectedIndexChanged(object sender, EventArgs e) + { + var feature = (IRequestFilteringFeature)tabControl1.SelectedTab.Tag; + feature.RequestFilteringSettingsUpdate.Invoke(); + Refresh(); + } + + public void Set() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/security/requestFiltering"); + var dialog = new SegmentSettingsDialog(Module, section); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + service.ServerManager.CommitChanges(); + } + } +} diff --git a/JexusManager.Features.RequestFiltering/RequestFilteringPage.resx b/JexusManager.Features.RequestFiltering/RequestFilteringPage.resx new file mode 100644 index 00000000..89b194c5 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/RequestFilteringPage.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 143, 17 + + + 281, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/RequestFilteringSettingsSavedEventHandler.cs b/JexusManager.Features.RequestFiltering/RequestFilteringSettingsSavedEventHandler.cs new file mode 100644 index 00000000..88ead1bc --- /dev/null +++ b/JexusManager.Features.RequestFiltering/RequestFilteringSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + public delegate void RequestFilteringSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/Resources/extensions_16.png b/JexusManager.Features.RequestFiltering/Resources/extensions_16.png new file mode 100644 index 0000000000000000000000000000000000000000..f4b0b19e0911c64b51a27f62439117b771c89a2d GIT binary patch literal 441 zcmV;q0Y?6bP)5 zlRZwuKoEuBShkdo6Ce-`g&oB%5D1AAAQ1N;1q8tjkfK1KNiIPN7oddNiR2Ov5h<~E z_fdp3{)rVb&8)pM-@G@{3Q0UZ4Mtk4OKcFX>yB@(@46s~{@~tdt!a#*F@{=eYOSf1 zqEd=kmNCmRrfJGFO}SVs_%Q4nl5l^40st@X2}ET1qmqkpcDR%GSO7!>B7!7IO2xkK zV>+FdzDri@f#k|*B7z_Yns?E7Q-Rnx+21PNIsZ`*$1&nK&TTd-5E1ykpBLKVPN(xX z(Q%pq7E)}k=0*TX0KjB2soAg*MG+jw$!k|yXt&!X1sBJAc>Vao`Oz-kKEKy1r~+;C zY&KiDbCm>MlzSK^K=cW00000NkvXXu0mjf50ACM literal 0 HcmV?d00001 diff --git a/JexusManager.Features.RequestFiltering/Resources/headers_16.png b/JexusManager.Features.RequestFiltering/Resources/headers_16.png new file mode 100644 index 0000000000000000000000000000000000000000..1787a7ff480ef4c79c433a779bddfb8c1b7fe6f5 GIT binary patch literal 436 zcmV;l0ZaagP) z1PDMPpWjX5xmCdD*GGz^a$N<*WJb%e6hXCe6K7WZax@wtM0|~vEZWYx21!B^;UJ{d zX(nIbfV%HZoe@Y#QKD>Z2}$PR0DlGsnyn^w$;Lh`QL=50Pfj-|kQl6h zNxHvq-c-WRFr3RyQ~Xa*cFP2Quy*riJAg8pC<)g+qTvN=8Kks3)kFZ-b@06g!BYc( z+WkYajYt&t53Aq&EEYEwwOZ}MvaF-D7X$(CcDwf(zJmeA>N5-scG8&F8xoZ(_pb!+%W*G-|u^^R_kCFz+fKj>2H%kT0)3t08juRilWb-s{Bp9?}xM5>>-);Ua$8krHr=~=iCKwm|PIp uwtYPu4$tE_&TWD*CMT206Mzr=3w;B{53tq1HH0Ss0000;aHD<3@Oy-9MR5C$NnoDxDz3n4&6V2q`?KZqzXwfO52 zoO5u_;rl+KD4Hm_QmJJ69Dp%~LZOgTU{3SQM1X-LNrE_z{|O+X6u?bkOfw3kl(}?W z7oE>55NprMi6oi>84ReacW zFn{&>&ZFl$D>)C$2*%K%{~c?~cTt=1(b;&1Z^;Qs!X{pD5W68?>0#ijE1|| zXgomeP=MCQPY4gzarVM3*aewcV`cx7*zdf&fG$2Huu9f9)RQmTd(Q y5cPVRbFNH!o;S?>jT4lW0J!5m1TY$(nfL`#q2NF~LU1ks0000OgT literal 0 HcmV?d00001 diff --git a/JexusManager.Features.RequestFiltering/Resources/query_16.png b/JexusManager.Features.RequestFiltering/Resources/query_16.png new file mode 100644 index 0000000000000000000000000000000000000000..ee4a4441d3c6c922ccfd47074c1f34070f508b20 GIT binary patch literal 590 zcmV-U0n4gV(PAovV%1XAg9ioiAPDsoLC+#y6lwA3LA>P9-lV63 zhk6jiQ+x6xQN)8vQIuA(H8oA5+iY!`Zqq;6+1br(ytEKDY12L!2EO^d$IN4ZT@+6w z^>`ww@5YeEQH}IJcrkMFME5g7(D2zOmD%dhe$V z%QuYWNtZ=BN?g%=JeD#B}aEJWmH)#Z?$0C%OIIdU$tUxN~#qYb^unb+)(X$-u znSK65;K-F^^!nBF2BB2r_BuX%nd$qJ8p`eY24Uu0u7xAotZ8c{hbrxd4-W3@3C>0? zyH;MM(TE0kZf!9$^%+1L05!<6X2sftpI&KY^Skc~ZGQUWv!&_rcL4mY<+kjg?u>5j c+vW!S2ad?bdZ{EuTL1t607*qoM6N<$g7T*qH~;_u literal 0 HcmV?d00001 diff --git a/JexusManager.Features.RequestFiltering/Resources/request_filtering_36.png b/JexusManager.Features.RequestFiltering/Resources/request_filtering_36.png new file mode 100644 index 0000000000000000000000000000000000000000..4860de2f0641a069843573badfb70f1115812b84 GIT binary patch literal 1934 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 B(ux28 literal 0 HcmV?d00001 diff --git a/JexusManager.Features.RequestFiltering/ScanHeadersItem.cs b/JexusManager.Features.RequestFiltering/ScanHeadersItem.cs new file mode 100644 index 00000000..691f3886 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/ScanHeadersItem.cs @@ -0,0 +1,43 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using Microsoft.Web.Administration; + + internal class ScanHeadersItem : IItem + { + public ConfigurationElement Element { get; set; } + + public bool Match(ScanHeadersItem other) + { + return other != null && other.RequestHeader == RequestHeader; + } + + public ScanHeadersItem(ConfigurationElement element) + { + this.Element = element; + if (element == null) + { + return; + } + + this.RequestHeader = (string)element["requestHeader"]; + } + + public string RequestHeader { get; set; } + + public string Flag { get; set; } + + public void Apply() + { + this.Element["requestHeader"] = RequestHeader; + } + + public bool Equals(ScanHeadersItem other) + { + return Match(other); + } + } +} diff --git a/JexusManager.Features.RequestFiltering/SegmentSettingsDialog.Designer.cs b/JexusManager.Features.RequestFiltering/SegmentSettingsDialog.Designer.cs new file mode 100644 index 00000000..e74b0ead --- /dev/null +++ b/JexusManager.Features.RequestFiltering/SegmentSettingsDialog.Designer.cs @@ -0,0 +1,227 @@ +namespace JexusManager.Features.RequestFiltering +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class SegmentSettingsDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.groupBox1 = new System.Windows.Forms.GroupBox(); + this.cbDouble = new System.Windows.Forms.CheckBox(); + this.cbHigh = new System.Windows.Forms.CheckBox(); + this.cbVerb = new System.Windows.Forms.CheckBox(); + this.cbExtension = new System.Windows.Forms.CheckBox(); + this.groupBox2 = new System.Windows.Forms.GroupBox(); + this.txtQuery = new System.Windows.Forms.TextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.txtURL = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.txtContent = new System.Windows.Forms.TextBox(); + this.label1 = new System.Windows.Forms.Label(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.groupBox1.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.SuspendLayout(); + // + // groupBox1 + // + this.groupBox1.Controls.Add(this.cbDouble); + this.groupBox1.Controls.Add(this.cbHigh); + this.groupBox1.Controls.Add(this.cbVerb); + this.groupBox1.Controls.Add(this.cbExtension); + this.groupBox1.Location = new System.Drawing.Point(12, 12); + this.groupBox1.Name = "groupBox1"; + this.groupBox1.Size = new System.Drawing.Size(355, 164); + this.groupBox1.TabIndex = 0; + this.groupBox1.TabStop = false; + this.groupBox1.Text = "General"; + // + // cbDouble + // + this.cbDouble.AutoSize = true; + this.cbDouble.Location = new System.Drawing.Point(6, 125); + this.cbDouble.Name = "cbDouble"; + this.cbDouble.Size = new System.Drawing.Size(132, 17); + this.cbDouble.TabIndex = 3; + this.cbDouble.Text = "Allow double escaping"; + this.cbDouble.UseVisualStyleBackColor = true; + // + // cbHigh + // + this.cbHigh.AutoSize = true; + this.cbHigh.Location = new System.Drawing.Point(6, 90); + this.cbHigh.Name = "cbHigh"; + this.cbHigh.Size = new System.Drawing.Size(141, 17); + this.cbHigh.TabIndex = 2; + this.cbHigh.Text = "Allow high-bit characters"; + this.cbHigh.UseVisualStyleBackColor = true; + // + // cbVerb + // + this.cbVerb.AutoSize = true; + this.cbVerb.Location = new System.Drawing.Point(6, 53); + this.cbVerb.Name = "cbVerb"; + this.cbVerb.Size = new System.Drawing.Size(119, 17); + this.cbVerb.TabIndex = 1; + this.cbVerb.Text = "Allow unlisted verbs"; + this.cbVerb.UseVisualStyleBackColor = true; + // + // cbExtension + // + this.cbExtension.AutoSize = true; + this.cbExtension.Location = new System.Drawing.Point(6, 19); + this.cbExtension.Name = "cbExtension"; + this.cbExtension.Size = new System.Drawing.Size(188, 17); + this.cbExtension.TabIndex = 0; + this.cbExtension.Text = "Allow unlisted file name extensions"; + this.cbExtension.UseVisualStyleBackColor = true; + // + // groupBox2 + // + this.groupBox2.Controls.Add(this.txtQuery); + this.groupBox2.Controls.Add(this.label3); + this.groupBox2.Controls.Add(this.txtURL); + this.groupBox2.Controls.Add(this.label2); + this.groupBox2.Controls.Add(this.txtContent); + this.groupBox2.Controls.Add(this.label1); + this.groupBox2.Location = new System.Drawing.Point(12, 182); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(355, 184); + this.groupBox2.TabIndex = 1; + this.groupBox2.TabStop = false; + this.groupBox2.Text = "Request Limits"; + // + // txtQuery + // + this.txtQuery.Location = new System.Drawing.Point(6, 146); + this.txtQuery.Name = "txtQuery"; + this.txtQuery.Size = new System.Drawing.Size(228, 20); + this.txtQuery.TabIndex = 5; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(3, 130); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(146, 13); + this.label3.TabIndex = 4; + this.label3.Text = "Maximum query string (Bytes):"; + // + // txtURL + // + this.txtURL.Location = new System.Drawing.Point(6, 91); + this.txtURL.Name = "txtURL"; + this.txtURL.Size = new System.Drawing.Size(228, 20); + this.txtURL.TabIndex = 3; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(3, 75); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(146, 13); + this.label2.TabIndex = 2; + this.label2.Text = "Maximum URL length (Bytes):"; + // + // txtContent + // + this.txtContent.Location = new System.Drawing.Point(6, 43); + this.txtContent.Name = "txtContent"; + this.txtContent.Size = new System.Drawing.Size(228, 20); + this.txtContent.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(3, 27); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(199, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Maximum allowed content length (Bytes):"; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(272, 401); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 2; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(176, 401); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 3; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // SegmentSettingsDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(379, 436); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.groupBox2); + this.Controls.Add(this.groupBox1); + this.Name = "SegmentSettingsDialog"; + this.Text = "Edit Request Filtering Settings"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.SegmentSettingsDialog_HelpButtonClicked); + this.groupBox1.ResumeLayout(false); + this.groupBox1.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private GroupBox groupBox1; + private CheckBox cbDouble; + private CheckBox cbHigh; + private CheckBox cbVerb; + private CheckBox cbExtension; + private GroupBox groupBox2; + private TextBox txtQuery; + private Label label3; + private TextBox txtURL; + private Label label2; + private TextBox txtContent; + private Label label1; + private Button btnCancel; + private Button btnOK; + } +} diff --git a/JexusManager.Features.RequestFiltering/SegmentSettingsDialog.cs b/JexusManager.Features.RequestFiltering/SegmentSettingsDialog.cs new file mode 100644 index 00000000..41c29b5b --- /dev/null +++ b/JexusManager.Features.RequestFiltering/SegmentSettingsDialog.cs @@ -0,0 +1,113 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client.Win32; + + public partial class SegmentSettingsDialog : DialogForm + { + public SegmentSettingsDialog(IServiceProvider serviceProvider, ConfigurationSection section) + : base(serviceProvider) + { + InitializeComponent(); + cbExtension.Checked = (bool)section.ChildElements["fileExtensions"]["allowUnlisted"]; + cbVerb.Checked = (bool)section.ChildElements["verbs"]["allowUnlisted"]; + cbHigh.Checked = (bool)section["allowHighBitCharacters"]; + cbDouble.Checked = (bool)section["allowDoubleEscaping"]; + var limits = section.ChildElements["requestLimits"]; + txtContent.Text = limits["maxAllowedContentLength"].ToString(); + txtURL.Text = limits["maxUrl"].ToString(); + txtQuery.Text = limits["maxQueryString"].ToString(); + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + section.ChildElements["fileExtensions"]["allowUnlisted"] = cbExtension.Checked; + section.ChildElements["verbs"]["allowUnlisted"] = cbVerb.Checked; + section["allowHighBitCharacters"] = cbHigh.Checked; + section["allowDoubleEscaping"] = cbDouble.Checked; + + uint result; + if (!uint.TryParse(txtContent.Text, out result)) + { + ShowMessage( + string.Format( + "'{0}' is an invalid maximum {1}. Enter an integer between 0 and 4294967295", + txtContent.Text, + "content length"), + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + txtContent.SelectAll(); + return; + } + + limits["maxAllowedContentLength"] = result; + + if (!uint.TryParse(txtURL.Text, out result)) + { + ShowMessage( + string.Format( + "'{0}' is an invalid maximum {1}. Enter an integer between 0 and 4294967295", + txtURL.Text, + "URL length"), + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + txtURL.SelectAll(); + return; + } + + limits["maxUrl"] = result; + + if (!uint.TryParse(txtQuery.Text, out result)) + { + ShowMessage( + string.Format( + "'{0}' is an invalid maximum {1}. Enter an integer between 0 and 4294967295", + txtQuery.Text, + "query string length"), + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + txtQuery.SelectAll(); + return; + } + + limits["maxQueryString"] = result; + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(txtContent, "TextChanged") + .Merge(Observable.FromEventPattern(txtQuery, "TextChanged")) + .Merge(Observable.FromEventPattern(txtURL, "TextChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtContent.Text) && + !string.IsNullOrWhiteSpace(txtURL.Text) && + !string.IsNullOrWhiteSpace(txtQuery.Text); + })); + } + + private void SegmentSettingsDialog_HelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210526#Edit_Filtering"); + } + } +} diff --git a/JexusManager.Features.RequestFiltering/SegmentSettingsDialog.resx b/JexusManager.Features.RequestFiltering/SegmentSettingsDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/SegmentSettingsDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.RequestFiltering/UrlsFeature.cs b/JexusManager.Features.RequestFiltering/UrlsFeature.cs new file mode 100644 index 00000000..6ab445ff --- /dev/null +++ b/JexusManager.Features.RequestFiltering/UrlsFeature.cs @@ -0,0 +1,147 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + internal class UrlsFeature : RequestFilteringFeature + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly UrlsFeature _owner; + + public FeatureTaskList(UrlsFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + + result.Add(new MethodTaskItem("AddUrl", "Allow URL...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("AddDenyUrl", "Deny Sequence...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void AddUrl() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public void AddDenyUrl() + { + _owner.AddDeny(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + } + + public UrlsFeature(Module module) + : base(module) + { + } + + private TaskList _taskList; + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Add() + { + var dialog = new NewUrlDialog(this.Module, true); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void AddDeny() + { + var dialog = new NewUrlDialog(this.Module, false); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected URL?", this.Name, + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + ConfigurationSection requestFilteringSection = + service.GetSection("system.webServer/security/requestFiltering"); + return requestFilteringSection.GetCollection("alwaysAllowedUrls"); + } + + protected override ConfigurationElementCollection GetSecondaryCollection(IConfigurationService service) + { + ConfigurationSection requestFilteringSection = + service.GetSection("system.webServer/security/requestFiltering"); + return requestFilteringSection.GetCollection("denyUrlSequences"); + } + + public override void Load() + { + LoadItems(); + } + + public override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210526#URL_Page"); + return true; + } + + public override string Name + { + get + { + return "URL"; + } + } + } +} diff --git a/JexusManager.Features.RequestFiltering/UrlsItem.cs b/JexusManager.Features.RequestFiltering/UrlsItem.cs new file mode 100644 index 00000000..556e3e74 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/UrlsItem.cs @@ -0,0 +1,60 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using Microsoft.Web.Administration; + + internal class UrlsItem : IDuoItem + { + public bool Allowed { get; } + + public ConfigurationElement Element { get; set; } + + public bool Match(UrlsItem other) + { + return other != null && other.Url == Url; + } + + public UrlsItem(ConfigurationElement element, bool allowed) + { + this.Allowed = allowed; + this.Element = element; + if (element == null) + { + return; + } + + if (allowed) + { + Url = (string)element["url"]; + } + else + { + Url = (string)element["sequence"]; + } + } + + public string Url { get; set; } + + public void Apply() + { + if (Allowed) + { + Element["url"] = Url; + } + else + { + Element["sequence"] = Url; + } + } + + public string Flag { get; set; } + + public bool Equals(UrlsItem other) + { + return Match(other) && other.Allowed == Allowed; + } + } +} diff --git a/JexusManager.Features.RequestFiltering/VerbsFeature.cs b/JexusManager.Features.RequestFiltering/VerbsFeature.cs new file mode 100644 index 00000000..a9931bdc --- /dev/null +++ b/JexusManager.Features.RequestFiltering/VerbsFeature.cs @@ -0,0 +1,139 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + internal class VerbsFeature : RequestFilteringFeature + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly VerbsFeature _owner; + + public FeatureTaskList(VerbsFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("AddVerb", "Allow Verb...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("AddDenyVerb", "Deny Verb...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void AddVerb() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public void AddDenyVerb() + { + _owner.AddDeny(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + } + + public VerbsFeature(Module module) + : base(module) + { + } + + private TaskList _taskList; + + public override TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Add() + { + var dialog = new NewVerbDialog(this.Module, true); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void AddDeny() + { + var dialog = new NewVerbDialog(this.Module, false); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected verb?", this.Name, + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + ConfigurationSection requestFilteringSection = + service.GetSection("system.webServer/security/requestFiltering"); + return requestFilteringSection.GetCollection("verbs"); + } + + public override void Load() + { + LoadItems(); + } + + public override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210526#Http_Verbs"); + return true; + } + + public override string Name + { + get + { + return "HTTP Verbs"; + } + } + } +} diff --git a/JexusManager.Features.RequestFiltering/VerbsItem.cs b/JexusManager.Features.RequestFiltering/VerbsItem.cs new file mode 100644 index 00000000..88f3a1e9 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/VerbsItem.cs @@ -0,0 +1,47 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.RequestFiltering +{ + using Microsoft.Web.Administration; + + internal class VerbsItem : IItem + { + public ConfigurationElement Element { get; set; } + + public bool Match(VerbsItem other) + { + return other != null && other.Verb == Verb; + } + + public VerbsItem(ConfigurationElement element) + { + this.Element = element; + if (element == null) + { + return; + } + + Verb = (string)element["verb"]; + Allowed = (bool)element["allowed"]; + } + + public bool Allowed { get; set; } + + public string Verb { get; set; } + + public void Apply() + { + Element["verb"] = Verb; + Element["allowed"] = Allowed; + } + + public string Flag { get; set; } + + public bool Equals(VerbsItem other) + { + return Match(other) && other.Allowed == Allowed; + } + } +} diff --git a/JexusManager.Features.RequestFiltering/packages.config b/JexusManager.Features.RequestFiltering/packages.config new file mode 100644 index 00000000..571e4fe0 --- /dev/null +++ b/JexusManager.Features.RequestFiltering/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.ResponseHeaders/JexusManager.Features.ResponseHeaders.csproj b/JexusManager.Features.ResponseHeaders/JexusManager.Features.ResponseHeaders.csproj new file mode 100644 index 00000000..eb5833b9 --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/JexusManager.Features.ResponseHeaders.csproj @@ -0,0 +1,139 @@ + + + + + Debug + AnyCPU + {7184AE3D-12D2-444D-B75A-2589F66E6B54} + Library + Properties + JexusManager.Features.ResponseHeaders + JexusManager.Features.ResponseHeaders + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + Form + + + NewHeaderDialog.cs + + + + True + True + Resources.resx + + + + + + + UserControl + + + ResponseHeadersPage.cs + + + + Form + + + SetCommonHeadersDialog.cs + + + + + NewHeaderDialog.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + ResponseHeadersPage.cs + + + SetCommonHeadersDialog.cs + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.ResponseHeaders/JexusManager.snk b/JexusManager.Features.ResponseHeaders/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.ResponseHeaders/NewHeaderDialog.Designer.cs b/JexusManager.Features.ResponseHeaders/NewHeaderDialog.Designer.cs new file mode 100644 index 00000000..c685d071 --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/NewHeaderDialog.Designer.cs @@ -0,0 +1,122 @@ +namespace JexusManager.Features.ResponseHeaders +{ + using System.ComponentModel; + using System.Windows.Forms; + + sealed partial class NewHeaderDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.txtValue = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.Location = new System.Drawing.Point(252, 146); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(156, 146); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(38, 13); + this.label1.TabIndex = 2; + this.label1.Text = "Name:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(15, 25); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(332, 20); + this.txtName.TabIndex = 3; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 60); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(37, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Value:"; + // + // txtValue + // + this.txtValue.Location = new System.Drawing.Point(15, 76); + this.txtValue.Name = "txtValue"; + this.txtValue.Size = new System.Drawing.Size(332, 20); + this.txtValue.TabIndex = 5; + // + // NewHeaderDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(359, 181); + this.Controls.Add(this.txtValue); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtName); + this.Controls.Add(this.label1); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewHeaderDialog"; + this.Text = "Add Custom HTTP Response Header"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewHeaderDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label label1; + private TextBox txtName; + private Label label2; + private TextBox txtValue; + } +} diff --git a/JexusManager.Features.ResponseHeaders/NewHeaderDialog.cs b/JexusManager.Features.ResponseHeaders/NewHeaderDialog.cs new file mode 100644 index 00000000..0c6ac847 --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/NewHeaderDialog.cs @@ -0,0 +1,67 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.ResponseHeaders +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal sealed partial class NewHeaderDialog : DialogForm + { + public NewHeaderDialog(IServiceProvider serviceProvider, ResponseHeadersItem selectedItem, ResponseHeadersFeature feature) + : base(serviceProvider) + { + Item = selectedItem; + InitializeComponent(); + Text = selectedItem == null ? "Add Custom HTTP Response Header" : "Edit Custom HTTP Response Header"; + if (selectedItem != null) + { + txtName.Text = Item.Name; + txtValue.Text = Item.Value; + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + if (feature.Items.Any(item => item != Item && txtName.Text == item.Name)) + { + ShowMessage( + "A header with this name already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + if (Item == null) + { + Item = new ResponseHeadersItem(null); + } + + Item.Name = txtName.Text; + Item.Value = txtValue.Text; + + DialogResult = DialogResult.OK; + })); + } + + private void NewHeaderDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210509"); + } + + public ResponseHeadersItem Item { get; set; } + } +} diff --git a/JexusManager.Features.ResponseHeaders/NewHeaderDialog.resx b/JexusManager.Features.ResponseHeaders/NewHeaderDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/NewHeaderDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.ResponseHeaders/Properties/AssemblyInfo.cs b/JexusManager.Features.ResponseHeaders/Properties/AssemblyInfo.cs new file mode 100644 index 00000000..e328621e --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/Properties/AssemblyInfo.cs @@ -0,0 +1,46 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("JexusManager.Features.ResponseHeaders")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("JexusManager.Features.ResponseHeaders")] +[assembly: AssemblyCopyright("Copyright \u00A9 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("7184ae3d-12d2-444d-b75a-2589f66e6b54")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] + +[assembly: InternalsVisibleTo("Tests.JexusManager, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f7030532c52524" ++ "993841a0d09420340f3814e1b65473851bdcd18815510b035a2ae9ecee69c4cd2d9e4d6e6d5fbf" ++ "a564e86c4a4cddc9597619a31c060846ebb2e99511a0323ff82b1ebd95d6a4912502945f0e769f" ++ "190a69a439dbfb969ebad72a6f7e2e047907da4a7b9c08c6e98d5f1be8b8cafaf3eb978914059a" ++ "245d4bc1")] diff --git a/JexusManager.Features.ResponseHeaders/Properties/Resources.Designer.cs b/JexusManager.Features.ResponseHeaders/Properties/Resources.Designer.cs new file mode 100644 index 00000000..37dc2aa2 --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/Properties/Resources.Designer.cs @@ -0,0 +1,73 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace JexusManager.Features.ResponseHeaders.Properties { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [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() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [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("JexusManager.Features.ResponseHeaders.Properties.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized resource of type System.Drawing.Bitmap. + /// + internal static System.Drawing.Bitmap response_header_36 { + get { + object obj = ResourceManager.GetObject("response_header_36", resourceCulture); + return ((System.Drawing.Bitmap)(obj)); + } + } + } +} diff --git a/JexusManager.Features.ResponseHeaders/Properties/Resources.resx b/JexusManager.Features.ResponseHeaders/Properties/Resources.resx new file mode 100644 index 00000000..d6b63b74 --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/Properties/Resources.resx @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + + ..\Resources\response_header_36.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a + + \ No newline at end of file diff --git a/JexusManager.Features.ResponseHeaders/Resources/response_header_36.png b/JexusManager.Features.ResponseHeaders/Resources/response_header_36.png new file mode 100644 index 0000000000000000000000000000000000000000..7b24c374f8e6847721a61daaa193945dd9655c24 GIT binary patch literal 1481 zcmV;)1vdJLP)VGd000McNliru-UJv76dNfV>5>2d1y)H! zK~z}7&6rzg990;{e{*KCySbF4t+{UkQqnYmwnQ-&Efq?AuuxjGLJ=$_SQM$W)&~&^ zf)64}1m7ywCxwbHYQ13*1T9q&ig>A3t=L4Hn5?Vtl_MK9od_F(4fB*iy*=!cA^%AvZRee%pOyqaQn8@1T zKA0OB85uZw^yp#WsYD>HwWzPJXLNM5s6<^|9iHc5SyseoFpit62A@i$0;NaV_jfUMYMLEMz8q_w7}r>ANxRRT-Oys9x2 zHWZw;ZIjF8$`rCJtISv&Oj}zU#+X=;sxDiC5Y#vhHFgT$^06$7si~=d6hm5TIyyQ~ zN<|c35m4Z=iP=%!x$qKe8=ARq`{Ve^W#h(;u>qgtwm=cBbye_kAY}lHk1xK-gRQ`%HEbOwl_7VXKKt{$Tw?4||%jtLT-_gFCY-cxP3qMlhq&fG) z8+`Qi>E&K*xOdxe?%DPT#^_a5?9zT0tI+vjN$Ua9t?M{)Q}6Z@TY3kZr1+EX$3LUi zX&}3$B1PmbX@{(`AxyaPi6vpVp*eNw0c3Guta|Vyo*i^s%wOxbzcBUKb)X4mo zAPgxd&8)w`)hm}+aOY53(pcNfK=WM`77P55%V999%CgSR&Im-TLKa}OqTuI|p3j^f zV^K}xxeG`mQBosagLD-$`7yfcw$R+%!lq4|(913hVAAPyB3zL2iG}g==b7z3II}M| zbNa~EzO5&Edi$CdGFO;%FO#ww=&aq0O$NW9K-S>c4$}(@OiWBffNa|?wuW$ehqJE~ zHr&WdgW6sDAj9AN{MFgX+{CMcw+wE%dBX-K+{@I>w(0Sm1a2k$sRM`veQ zP=~iFm0~KXj}?O&puWN3{ILA`frod!lK<6z?$XR}3~arfG52?N^d8`eyHDatAJ=n{ z+M`fdjI@<-n~75+*nT9rD^iC7FmK)#$M!tSxl3>J$)~R~=Z|yannChz9#0h*A0IEa zj<`yll=2-N9aXD!S*7-+i@~s?e=ofq1HARci>z(90mG6za=9F~ZO7K0r2ZzQq^qkd zv9TuhGJw{mZXUYx88Vp+1#b}{1buydW&5N`ZYy=!N?sbufTWbg;M7{Es!(HNBTY?B#oANNRh6^M_eEUs3jS#}n~hZ^ z4l)c9zJ_*;cG){y$$h3!DAXrCO{tOaZZMpsr4JK#l~UFL^_74epuzLJOxReEuHkVK zO!#kF>&V*hn&p_x0BeABoXZ4YYpsP4f|iz+>-rgHZf-8HDZ;{pfqcMKO1*dJ(4pN* zsm8d^HP_%U0Jd$ + /// Description of DefaultDocumentFeature. + /// + internal class ResponseHeadersFeature : FeatureBase + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly ResponseHeadersFeature _owner; + + public FeatureTaskList(ResponseHeadersFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("Add", "Add...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Set", "Set Common Headers...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Edit", "Edit...", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Add() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void Edit() + { + _owner.Edit(); + } + + [Obfuscation(Exclude = true)] + public void Set() + { + _owner.Set(); + } + } + + public ResponseHeadersFeature(Module module) + : base(module) + { + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + LoadItems(); + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + var section = service.GetSection("system.webServer/httpProtocol"); + return section.GetCollection("customHeaders"); + } + + public void Add() + { + var dialog = new NewHeaderDialog(Module, null, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.AddItem(dialog.Item); + } + + public void Remove() + { + var dialog = (IManagementUIService)GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected header?", Name, + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + RemoveItem(); + } + + public void Edit() + { + var dialog = new NewHeaderDialog(Module, SelectedItem, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.EditItem(dialog.Item); + } + + public void Set() + { + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + var staticContent = service.GetSection("system.webServer/staticContent"); + var dialog = new SetCommonHeadersDialog(Module, service.GetSection("system.webServer/httpProtocol"), staticContent.ChildElements["clientCache"]); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + service.ServerManager.CommitChanges(); + } + + protected override void OnSettingsSaved() + { + ResponseHeadersSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210509"); + return false; + } + + public ResponseHeadersSettingsSavedEventHandler ResponseHeadersSettingsUpdated { get; set; } + public string Description { get; } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public string Name + { + get { return "HTTP Response Headers"; } + } + } +} diff --git a/JexusManager.Features.ResponseHeaders/ResponseHeadersItem.cs b/JexusManager.Features.ResponseHeaders/ResponseHeadersItem.cs new file mode 100644 index 00000000..23e7cca8 --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/ResponseHeadersItem.cs @@ -0,0 +1,46 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.ResponseHeaders +{ + using Microsoft.Web.Administration; + + internal class ResponseHeadersItem : IItem + { + public string Name { get; internal set; } + public string Value { get; internal set; } + public string Flag { get; set; } + public ConfigurationElement Element { get; set; } + + public ResponseHeadersItem(ConfigurationElement element) + { + Flag = element == null || element.IsLocallyStored ? "Local" : "Inherited"; + Element = element; + if (element == null) + { + Value = string.Empty; + return; + } + + Name = (string)element["name"]; + Value = (string)element["value"]; + } + + public bool Equals(ResponseHeadersItem other) + { + return Match(other); + } + + public bool Match(ResponseHeadersItem other) + { + return other != null && other.Name == Name; + } + + public void Apply() + { + Element["name"] = Name; + Element["value"] = Value; + } + } +} diff --git a/JexusManager.Features.ResponseHeaders/ResponseHeadersModule.cs b/JexusManager.Features.ResponseHeaders/ResponseHeadersModule.cs new file mode 100644 index 00000000..d2f8097e --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/ResponseHeadersModule.cs @@ -0,0 +1,26 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.ResponseHeaders +{ + using System; + + using Properties; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Server; + + internal class ResponseHeadersModule : Module + { + protected override void Initialize(IServiceProvider serviceProvider, ModuleInfo moduleInfo) + { + base.Initialize(serviceProvider, moduleInfo); + var controlPanel = (IControlPanel)GetService(typeof(IControlPanel)); + var modulePage = new ModulePageInfo(this, typeof(ResponseHeadersPage), "HTTP Response Headers", + "Configure HTTP headers that are added to responses from the Web server", Resources.response_header_36, + Resources.response_header_36); + controlPanel.RegisterPage(modulePage); + } + } +} diff --git a/JexusManager.Features.ResponseHeaders/ResponseHeadersModuleProvider.cs b/JexusManager.Features.ResponseHeaders/ResponseHeadersModuleProvider.cs new file mode 100644 index 00000000..39447348 --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/ResponseHeadersModuleProvider.cs @@ -0,0 +1,28 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.ResponseHeaders +{ + using System; + + using Microsoft.Web.Management.Server; + + public class ResponseHeadersModuleProvider : ModuleProvider + { + public override Type ServiceType + { + get { return null; } + } + + public override ModuleDefinition GetModuleDefinition(IManagementContext context) + { + return new ModuleDefinition(Name, typeof(ResponseHeadersModule).AssemblyQualifiedName); + } + + public override bool SupportsScope(ManagementScope scope) + { + return true; + } + } +} diff --git a/JexusManager.Features.ResponseHeaders/ResponseHeadersPage.Designer.cs b/JexusManager.Features.ResponseHeaders/ResponseHeadersPage.Designer.cs new file mode 100644 index 00000000..36ce4a9c --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/ResponseHeadersPage.Designer.cs @@ -0,0 +1,292 @@ +namespace JexusManager.Features.ResponseHeaders +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class ResponseHeadersPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chValue = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.toolStrip2 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel2 = new System.Windows.Forms.ToolStripLabel(); + this.cbGroup = new System.Windows.Forms.ToolStripComboBox(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.toolStrip2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 4; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.SplitContainer1SplitterMoved); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.toolStrip2); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 6; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chName, + this.chValue, + this.chType}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 38); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 502); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListView1SelectedIndexChanged); + this.listView1.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.ListView1MouseDoubleClick); + // + // chName + // + this.chName.Text = "Name"; + this.chName.Width = 120; + // + // chValue + // + this.chValue.Text = "Value"; + this.chValue.Width = 120; + // + // chType + // + this.chType.Text = "Entry Type"; + this.chType.Width = 120; + // + // toolStrip2 + // + this.toolStrip2.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel2, + this.cbGroup}); + this.toolStrip2.Location = new System.Drawing.Point(0, 13); + this.toolStrip2.Name = "toolStrip2"; + this.toolStrip2.Size = new System.Drawing.Size(560, 25); + this.toolStrip2.TabIndex = 3; + this.toolStrip2.Text = "toolStrip2"; + // + // toolStripLabel2 + // + this.toolStripLabel2.Name = "toolStripLabel2"; + this.toolStripLabel2.Size = new System.Drawing.Size(59, 22); + this.toolStripLabel2.Text = "Group by:"; + // + // cbGroup + // + this.cbGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbGroup.Items.AddRange(new object[] { + "No Grouping", + "Status", + "IP Address", + "Protocol", + "Port"}); + this.cbGroup.Name = "cbGroup"; + this.cbGroup.Size = new System.Drawing.Size(121, 25); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(450, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to configure HTTP headers that are added to responses from the W" + + "eb server."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 5; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(257, 25); + this.label3.TabIndex = 2; + this.label3.Text = "HTTP Response Headers"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // ResponseHeadersPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "ResponseHeadersPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.toolStrip2.ResumeLayout(false); + this.toolStrip2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private ListView listView1; + private ColumnHeader chName; + private ColumnHeader chValue; + private ColumnHeader chType; + private Label label2; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private Panel panel2; + private ToolStrip toolStrip2; + private ToolStripLabel toolStripLabel2; + private ToolStripComboBox cbGroup; + private PictureBox pictureBox1; + private ToolStrip tsActionPanel; + private ContextMenuStrip cmsActionPanel; + } +} diff --git a/JexusManager.Features.ResponseHeaders/ResponseHeadersPage.cs b/JexusManager.Features.ResponseHeaders/ResponseHeadersPage.cs new file mode 100644 index 00000000..b08ead6d --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/ResponseHeadersPage.cs @@ -0,0 +1,141 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.ResponseHeaders +{ + using System; + using System.Collections; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class ResponseHeadersPage : ModuleListPage + { + private sealed class PageTaskList : ShowHelpTaskList + { + private readonly ResponseHeadersPage _owner; + + public PageTaskList(ResponseHeadersPage owner) + { + _owner = owner; + } + + [Obfuscation(Exclude = true)] + public override void ShowHelp() + { + _owner.ShowHelp(); + } + } + + private sealed class ResponseHeadersListViewItem : ListViewItem + { + public ResponseHeadersItem Item { get; } + private readonly ResponseHeadersPage _page; + + public ResponseHeadersListViewItem(ResponseHeadersItem item, ResponseHeadersPage page) + : base(item.Name) + { + Item = item; + _page = page; + SubItems.Add(new ListViewSubItem(this, item.Value)); + SubItems.Add(new ListViewSubItem(this, item.Flag)); + } + } + + private ResponseHeadersFeature _feature; + private PageTaskList _taskList; + + public ResponseHeadersPage() + { + InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new ResponseHeadersFeature(Module); + _feature.ResponseHeadersSettingsUpdated = InitializeListPage; + _feature.Load(); + } + + protected override void InitializeListPage() + { + listView1.Items.Clear(); + foreach (var file in _feature.Items) + { + listView1.Items.Add(new ResponseHeadersListViewItem(file, this)); + } + + if (_feature.SelectedItem == null) + { + Refresh(); + return; + } + + foreach (ResponseHeadersListViewItem item in listView1.Items) + { + if (item.Item == _feature.SelectedItem) + { + item.Selected = true; + } + } + } + + protected override void Refresh() + { + Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + private void ListView1SelectedIndexChanged(object sender, EventArgs e) + { + _feature.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((ResponseHeadersListViewItem)listView1.SelectedItems[0]).Item + : null; + Refresh(); + } + + private void ListView1MouseDoubleClick(object sender, MouseEventArgs e) + { + _feature.Edit(); + } + + protected override bool ShowHelp() + { + _feature.ShowHelp(); + return true; + } + + private void SplitContainer1SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + } +} diff --git a/JexusManager.Features.ResponseHeaders/ResponseHeadersPage.resx b/JexusManager.Features.ResponseHeaders/ResponseHeadersPage.resx new file mode 100644 index 00000000..876b3bf2 --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/ResponseHeadersPage.resx @@ -0,0 +1,132 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 143, 17 + + + 281, 17 + + + 17, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.ResponseHeaders/ResponseHeadersSettingsSavedEventHandler.cs b/JexusManager.Features.ResponseHeaders/ResponseHeadersSettingsSavedEventHandler.cs new file mode 100644 index 00000000..bfd7b533 --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/ResponseHeadersSettingsSavedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.ResponseHeaders +{ + public delegate void ResponseHeadersSettingsSavedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.ResponseHeaders/SetCommonHeadersDialog.Designer.cs b/JexusManager.Features.ResponseHeaders/SetCommonHeadersDialog.Designer.cs new file mode 100644 index 00000000..4f2151e9 --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/SetCommonHeadersDialog.Designer.cs @@ -0,0 +1,205 @@ +namespace JexusManager.Features.ResponseHeaders +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class SetCommonHeadersDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.cbKeepAlive = new System.Windows.Forms.CheckBox(); + this.cbExpired = new System.Windows.Forms.CheckBox(); + this.rbImmediate = new System.Windows.Forms.RadioButton(); + this.rbAfter = new System.Windows.Forms.RadioButton(); + this.txtAfter = new System.Windows.Forms.TextBox(); + this.cbUnit = new System.Windows.Forms.ComboBox(); + this.rbTime = new System.Windows.Forms.RadioButton(); + this.dtpDate = new System.Windows.Forms.DateTimePicker(); + this.dtpTime = new System.Windows.Forms.DateTimePicker(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // cbKeepAlive + // + this.cbKeepAlive.AutoSize = true; + this.cbKeepAlive.Location = new System.Drawing.Point(12, 12); + this.cbKeepAlive.Name = "cbKeepAlive"; + this.cbKeepAlive.Size = new System.Drawing.Size(143, 17); + this.cbKeepAlive.TabIndex = 0; + this.cbKeepAlive.Text = "Enable HTTP keep-alive"; + this.cbKeepAlive.UseVisualStyleBackColor = true; + // + // cbExpired + // + this.cbExpired.AutoSize = true; + this.cbExpired.Location = new System.Drawing.Point(12, 35); + this.cbExpired.Name = "cbExpired"; + this.cbExpired.Size = new System.Drawing.Size(123, 17); + this.cbExpired.TabIndex = 1; + this.cbExpired.Text = "Expire Web content:"; + this.cbExpired.UseVisualStyleBackColor = true; + this.cbExpired.CheckedChanged += new System.EventHandler(this.cbExpired_CheckedChanged); + // + // rbImmediate + // + this.rbImmediate.AutoSize = true; + this.rbImmediate.Enabled = false; + this.rbImmediate.Location = new System.Drawing.Point(33, 58); + this.rbImmediate.Name = "rbImmediate"; + this.rbImmediate.Size = new System.Drawing.Size(80, 17); + this.rbImmediate.TabIndex = 2; + this.rbImmediate.TabStop = true; + this.rbImmediate.Text = "Immediately"; + this.rbImmediate.UseVisualStyleBackColor = true; + // + // rbAfter + // + this.rbAfter.AutoSize = true; + this.rbAfter.Enabled = false; + this.rbAfter.Location = new System.Drawing.Point(33, 81); + this.rbAfter.Name = "rbAfter"; + this.rbAfter.Size = new System.Drawing.Size(47, 17); + this.rbAfter.TabIndex = 3; + this.rbAfter.TabStop = true; + this.rbAfter.Text = "After"; + this.rbAfter.UseVisualStyleBackColor = true; + this.rbAfter.CheckedChanged += new System.EventHandler(this.rbAfter_CheckedChanged); + // + // txtAfter + // + this.txtAfter.Enabled = false; + this.txtAfter.Location = new System.Drawing.Point(53, 104); + this.txtAfter.Name = "txtAfter"; + this.txtAfter.Size = new System.Drawing.Size(60, 20); + this.txtAfter.TabIndex = 4; + // + // cbUnit + // + this.cbUnit.Enabled = false; + this.cbUnit.FormattingEnabled = true; + this.cbUnit.Items.AddRange(new object[] { + "Second(s)", + "Minute(s)", + "Hour(s)", + "Day(s)"}); + this.cbUnit.Location = new System.Drawing.Point(119, 104); + this.cbUnit.Name = "cbUnit"; + this.cbUnit.Size = new System.Drawing.Size(121, 21); + this.cbUnit.TabIndex = 5; + // + // rbTime + // + this.rbTime.AutoSize = true; + this.rbTime.Enabled = false; + this.rbTime.Location = new System.Drawing.Point(33, 130); + this.rbTime.Name = "rbTime"; + this.rbTime.Size = new System.Drawing.Size(209, 17); + this.rbTime.TabIndex = 6; + this.rbTime.TabStop = true; + this.rbTime.Text = "On (Coordinated Universal Time (UTC))"; + this.rbTime.UseVisualStyleBackColor = true; + this.rbTime.CheckedChanged += new System.EventHandler(this.rbTime_CheckedChanged); + // + // dtpDate + // + this.dtpDate.Enabled = false; + this.dtpDate.Location = new System.Drawing.Point(53, 166); + this.dtpDate.Name = "dtpDate"; + this.dtpDate.Size = new System.Drawing.Size(200, 20); + this.dtpDate.TabIndex = 7; + // + // dtpTime + // + this.dtpTime.Enabled = false; + this.dtpTime.Format = System.Windows.Forms.DateTimePickerFormat.Time; + this.dtpTime.Location = new System.Drawing.Point(259, 166); + this.dtpTime.Name = "dtpTime"; + this.dtpTime.Size = new System.Drawing.Size(101, 20); + this.dtpTime.TabIndex = 8; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(352, 221); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 9; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(256, 221); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 10; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + this.btnOK.Click += new System.EventHandler(this.btnOK_Click); + // + // SetCommonHeadersDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(459, 256); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.dtpTime); + this.Controls.Add(this.dtpDate); + this.Controls.Add(this.rbTime); + this.Controls.Add(this.cbUnit); + this.Controls.Add(this.txtAfter); + this.Controls.Add(this.rbAfter); + this.Controls.Add(this.rbImmediate); + this.Controls.Add(this.cbExpired); + this.Controls.Add(this.cbKeepAlive); + this.Name = "SetCommonHeadersDialog"; + this.Text = "Set Common HTTP Response Headers"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.SetCommonHeadersDialog_HelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private CheckBox cbKeepAlive; + private CheckBox cbExpired; + private RadioButton rbImmediate; + private RadioButton rbAfter; + private TextBox txtAfter; + private ComboBox cbUnit; + private RadioButton rbTime; + private DateTimePicker dtpDate; + private DateTimePicker dtpTime; + private Button btnCancel; + private Button btnOK; + } +} \ No newline at end of file diff --git a/JexusManager.Features.ResponseHeaders/SetCommonHeadersDialog.cs b/JexusManager.Features.ResponseHeaders/SetCommonHeadersDialog.cs new file mode 100644 index 00000000..55afa4d9 --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/SetCommonHeadersDialog.cs @@ -0,0 +1,203 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.ResponseHeaders +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Windows.Forms; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client.Win32; + + public partial class SetCommonHeadersDialog : DialogForm + { + private readonly ConfigurationSection _httpProtocolSection; + private readonly ConfigurationElement _staticContent; + + public SetCommonHeadersDialog(IServiceProvider serviceProvider, ConfigurationSection httpProtocolSection, ConfigurationElement staticContent) + : base(serviceProvider) + { + InitializeComponent(); + _httpProtocolSection = httpProtocolSection; + _staticContent = staticContent; + cbKeepAlive.Checked = (bool)httpProtocolSection["allowKeepAlive"]; + var mode = (long)_staticContent["cacheControlMode"]; + cbExpired.Checked = mode != 0L; + rbImmediate.Checked = mode == 1L; + rbAfter.Checked = mode == 2L; + rbTime.Checked = mode == 3L; + string time = (string)_staticContent["httpExpires"]; + DateTime output; + if (DateTime.TryParse(time, out output)) + { + dtpDate.Value = output; + dtpTime.Value = output; + } + + var span = (TimeSpan)_staticContent["cacheControlMaxAge"]; + if (span.Seconds == 0) + { + if (span.Minutes == 0) + { + if (span.Hours == 0) + { + cbUnit.SelectedIndex = 3; + txtAfter.Text = span.Days.ToString(); + } + else + { + cbUnit.SelectedIndex = 2; + txtAfter.Text = (span.Hours + span.Days * 24).ToString(); + } + } + else + { + cbUnit.SelectedIndex = 1; + txtAfter.Text = (span.Minutes + (span.Hours + span.Days * 24) * 60).ToString(); + } + } + else + { + cbUnit.SelectedIndex = 0; + txtAfter.Text = (span.Seconds + (span.Minutes + (span.Hours + span.Days * 24) * 60) * 60).ToString(); + } + } + + private void btnOK_Click(object sender, EventArgs e) + { + _httpProtocolSection["allowKeepAlive"] = cbKeepAlive.Checked; + if (cbExpired.Checked) + { + if (rbImmediate.Checked) + { + _staticContent["cacheControlMode"] = 1L; + } + else if (rbAfter.Checked) + { + _staticContent["cacheControlMode"] = 2L; + long value; + if (!long.TryParse(txtAfter.Text, out value) || value < 0) + { + ShowMessage( + GetMessage(cbUnit.SelectedIndex), + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + if (cbUnit.SelectedIndex == 0) + { + if (value > GetMax(cbUnit.SelectedIndex)) + { + ShowMessage( + GetMessage(cbUnit.SelectedIndex), + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + _staticContent["cacheControlMaxAge"] = TimeSpan.FromSeconds(value); + } + else if (cbUnit.SelectedIndex == 1) + { + if (value > GetMax(cbUnit.SelectedIndex)) + { + ShowMessage( + GetMessage(cbUnit.SelectedIndex), + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + _staticContent["cacheControlMaxAge"] = TimeSpan.FromMinutes(value); + } + else if (cbUnit.SelectedIndex == 2) + { + if (value > GetMax(cbUnit.SelectedIndex)) + { + ShowMessage( + GetMessage(cbUnit.SelectedIndex), + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + _staticContent["cacheControlMaxAge"] = TimeSpan.FromHours(value); + } + else + { + if (value > GetMax(cbUnit.SelectedIndex)) + { + ShowMessage( + GetMessage(cbUnit.SelectedIndex), + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + _staticContent["cacheControlMaxAge"] = TimeSpan.FromDays(value); + } + } + else + { + _staticContent["cacheControlMode"] = 3L; + // Wed, 27 May 2015 00:00:00 GMT + _staticContent["httpExpires"] = (dtpDate.Value.Date + dtpTime.Value.TimeOfDay).ToString("R"); + } + } + else + { + _staticContent["cacheControlMode"] = 0L; + } + + DialogResult = DialogResult.OK; + } + + private string GetMessage(int selectedIndex) + { + return string.Format( + "The specified expiration value is invalid. The valid range is between 0 and {0} {1}.", GetMax(selectedIndex), cbUnit.Text); + } + + private readonly long[] _max = { 922337203686, 15372286728, 256204778, 10675199 }; + + private long GetMax(int index) + { + return _max[index]; + } + + private void SetCommonHeadersDialog_HelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=210509"); + } + + private void cbExpired_CheckedChanged(object sender, EventArgs e) + { + rbImmediate.Enabled = cbExpired.Checked; + rbAfter.Enabled = cbExpired.Checked; + rbTime.Enabled = cbExpired.Checked; + rbAfter_CheckedChanged(sender, e); + rbTime_CheckedChanged(sender, e); + } + + private void rbAfter_CheckedChanged(object sender, EventArgs e) + { + txtAfter.Enabled = rbAfter.Checked && rbAfter.Enabled; + cbUnit.Enabled = rbAfter.Checked && rbAfter.Enabled; + } + + private void rbTime_CheckedChanged(object sender, EventArgs e) + { + dtpDate.Enabled = rbTime.Checked && rbTime.Enabled; + dtpTime.Enabled = rbTime.Checked && rbTime.Enabled; + } + } +} diff --git a/JexusManager.Features.ResponseHeaders/SetCommonHeadersDialog.resx b/JexusManager.Features.ResponseHeaders/SetCommonHeadersDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/SetCommonHeadersDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.ResponseHeaders/packages.config b/JexusManager.Features.ResponseHeaders/packages.config new file mode 100644 index 00000000..571e4fe0 --- /dev/null +++ b/JexusManager.Features.ResponseHeaders/packages.config @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/ConditionItem.cs b/JexusManager.Features.Rewrite/ConditionItem.cs new file mode 100644 index 00000000..fe30a6a3 --- /dev/null +++ b/JexusManager.Features.Rewrite/ConditionItem.cs @@ -0,0 +1,57 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Rewrite +{ + using Microsoft.Web.Administration; + + public class ConditionItem + { + public ConfigurationElement Element { get; set; } + + public ConditionItem(ConfigurationElement element) + { + this.Element = element; + if (element == null) + { + this.Input = "{QUERY_STRING}"; + this.MatchType = 4; + this.IgnoreCase = true; + return; + } + + this.Input = (string)element["input"]; + this.Pattern = (string)element["pattern"]; + this.IgnoreCase = (bool)element["ignoreCase"]; + + var root = (long)element["matchType"]; + var negate = (bool)element["negate"]; + this.MatchType = (int)root * 2 + (negate ? 1 : 0); + } + + public bool IgnoreCase { get; set; } + + public string Pattern { get; set; } + + public string Input { get; set; } + + public int MatchType { get; set; } + + public void Apply() + { + Element["input"] = Input; + Element["pattern"] = Pattern; + Element["ignoreCase"] = IgnoreCase; + Element["negate"] = MatchType % 2 == 1; + Element["matchType"] = MatchType / 2; + } + + public void AppendTo(ConfigurationElementCollection conditionsCollection) + { + Element = conditionsCollection.CreateElement(); + Apply(); + conditionsCollection.Add(Element); + } + } +} \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/ConditionListViewItem.cs b/JexusManager.Features.Rewrite/ConditionListViewItem.cs new file mode 100644 index 00000000..95f6b2cb --- /dev/null +++ b/JexusManager.Features.Rewrite/ConditionListViewItem.cs @@ -0,0 +1,55 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Rewrite +{ + using System.Windows.Forms; + + internal class ConditionListViewItem : ListViewItem + { + private readonly ListViewSubItem _matchType; + + private readonly ListViewSubItem _pattern; + + public ConditionListViewItem(ConditionItem condition) + : base(condition.Input) + { + _matchType = new ListViewSubItem(this, GetText(condition.MatchType)); + this.SubItems.Add(_matchType); + _pattern = new ListViewSubItem(this, condition.Pattern); + this.SubItems.Add(_pattern); + this.Item = condition; + } + + public ConditionItem Item { get; } + + public void Update() + { + this.Text = this.Item.Input; + _matchType.Text = GetText(this.Item.MatchType); + _pattern.Text = this.Item.MatchType > 3 ? this.Item.Pattern : "N/A"; + } + + private static string GetText(int matchType) + { + switch (matchType) + { + case 0: + return "Is File"; + case 1: + return "Is Not File"; + case 2: + return "Is Directory"; + case 3: + return "Is Not Directory"; + case 4: + return "Matches the Pattern"; + case 5: + return "Does Not Match the Pattern"; + } + + return string.Empty; + } + } +} \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/Inbound/AddAllowedVariableDialog.Designer.cs b/JexusManager.Features.Rewrite/Inbound/AddAllowedVariableDialog.Designer.cs new file mode 100644 index 00000000..9a21d9bb --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AddAllowedVariableDialog.Designer.cs @@ -0,0 +1,102 @@ +namespace JexusManager.Features.Rewrite.Inbound +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class AddAllowedVariableDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(13, 13); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(110, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Server variable name:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(16, 39); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(351, 20); + this.txtName.TabIndex = 1; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(176, 81); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 2; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(272, 81); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 3; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // AddVariableDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(379, 116); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.txtName); + this.Controls.Add(this.label1); + this.Name = "AddVariableDialog"; + this.Text = "Add Server Variable"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.AddVariableDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label1; + private TextBox txtName; + private Button btnOK; + private Button btnCancel; + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/AddAllowedVariableDialog.cs b/JexusManager.Features.Rewrite/Inbound/AddAllowedVariableDialog.cs new file mode 100644 index 00000000..de06ea74 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AddAllowedVariableDialog.cs @@ -0,0 +1,67 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// -------------------------------------------------------------------------------------------------------------------- +// +// +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace JexusManager.Features.Rewrite.Inbound +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal partial class AddAllowedVariableDialog : DialogForm + { + public AddAllowedVariableDialog(IServiceProvider serviceProvider, AllowedVariablesFeature feature) + : base(serviceProvider) + { + InitializeComponent(); + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + if (feature.Items.Any(item => txtName.Text == item.Name)) + { + ShowMessage( + "The specified server variable already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + Item = new AllowedVariableItem(null, feature) { Name = txtName.Text }; + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text); + })); + } + + private void AddVariableDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=163108"); + } + + public AllowedVariableItem Item { get; set; } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/AddAllowedVariableDialog.resx b/JexusManager.Features.Rewrite/Inbound/AddAllowedVariableDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AddAllowedVariableDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/Inbound/AddConditionDialog.Designer.cs b/JexusManager.Features.Rewrite/Inbound/AddConditionDialog.Designer.cs new file mode 100644 index 00000000..12edc038 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AddConditionDialog.Designer.cs @@ -0,0 +1,180 @@ +namespace JexusManager.Features.Rewrite.Inbound +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal partial class AddConditionDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.txtInput = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.cbCheck = new System.Windows.Forms.ComboBox(); + this.label3 = new System.Windows.Forms.Label(); + this.txtPattern = new System.Windows.Forms.TextBox(); + this.btnTest = new System.Windows.Forms.Button(); + this.cbIgnore = new System.Windows.Forms.CheckBox(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(352, 241); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(256, 241); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(9, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(80, 13); + this.label1.TabIndex = 2; + this.label1.Text = "Condition input:"; + // + // txtInput + // + this.txtInput.Location = new System.Drawing.Point(12, 25); + this.txtInput.Name = "txtInput"; + this.txtInput.Size = new System.Drawing.Size(435, 20); + this.txtInput.TabIndex = 3; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(9, 67); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(103, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Check if input string:"; + // + // cbCheck + // + this.cbCheck.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbCheck.FormattingEnabled = true; + this.cbCheck.Items.AddRange(new object[] { + "Is a File", + "Is Not a File", + "Is a Directory", + "Is Not a Directory", + "Matches the Pattern", + "Does Not Match the Pattern"}); + this.cbCheck.Location = new System.Drawing.Point(12, 83); + this.cbCheck.Name = "cbCheck"; + this.cbCheck.Size = new System.Drawing.Size(243, 21); + this.cbCheck.TabIndex = 5; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(9, 130); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(44, 13); + this.label3.TabIndex = 6; + this.label3.Text = "Pattern:"; + // + // txtPattern + // + this.txtPattern.Location = new System.Drawing.Point(12, 146); + this.txtPattern.Name = "txtPattern"; + this.txtPattern.Size = new System.Drawing.Size(305, 20); + this.txtPattern.TabIndex = 7; + // + // btnTest + // + this.btnTest.Location = new System.Drawing.Point(323, 144); + this.btnTest.Name = "btnTest"; + this.btnTest.Size = new System.Drawing.Size(125, 23); + this.btnTest.TabIndex = 8; + this.btnTest.Text = "Test pattern..."; + this.btnTest.UseVisualStyleBackColor = true; + // + // cbIgnore + // + this.cbIgnore.AutoSize = true; + this.cbIgnore.Location = new System.Drawing.Point(12, 184); + this.cbIgnore.Name = "cbIgnore"; + this.cbIgnore.Size = new System.Drawing.Size(82, 17); + this.cbIgnore.TabIndex = 9; + this.cbIgnore.Text = "Ignore case"; + this.cbIgnore.UseVisualStyleBackColor = true; + // + // AddConditionDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(459, 276); + this.Controls.Add(this.cbIgnore); + this.Controls.Add(this.btnTest); + this.Controls.Add(this.txtPattern); + this.Controls.Add(this.label3); + this.Controls.Add(this.cbCheck); + this.Controls.Add(this.label2); + this.Controls.Add(this.txtInput); + this.Controls.Add(this.label1); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "AddConditionDialog"; + this.Text = "Add Condition"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.AddConditionDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label label1; + private TextBox txtInput; + private Label label2; + private ComboBox cbCheck; + private Label label3; + private TextBox txtPattern; + private Button btnTest; + private CheckBox cbIgnore; + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/AddConditionDialog.cs b/JexusManager.Features.Rewrite/Inbound/AddConditionDialog.cs new file mode 100644 index 00000000..ad343774 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AddConditionDialog.cs @@ -0,0 +1,89 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// -------------------------------------------------------------------------------------------------------------------- +// +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace JexusManager.Features.Rewrite.Inbound +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal partial class AddConditionDialog : DialogForm + { + public AddConditionDialog(IServiceProvider serviceProvider, ConditionItem existing) + : base(serviceProvider) + { + InitializeComponent(); + Item = existing ?? new ConditionItem(null); + txtInput.Text = Item.Input; + txtPattern.Text = Item.Pattern; + cbIgnore.Checked = Item.IgnoreCase; + cbCheck.SelectedIndex = Item.MatchType; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + var check = Observable.FromEventPattern(cbCheck, "SelectedIndexChanged"); + container.Add( + check.Subscribe(evt => + { + txtPattern.Enabled = btnTest.Enabled = cbCheck.SelectedIndex > 3; + if (!txtPattern.Enabled) + { + txtPattern.Text = string.Empty; + } + })); + + container.Add( + Observable.FromEventPattern(txtPattern, "TextChanged") + .Merge(check) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtInput.Text) && (cbCheck.SelectedIndex < 4 || !string.IsNullOrWhiteSpace(txtPattern.Text)); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item.Input = txtInput.Text; + Item.Pattern = txtPattern.Text; + Item.IgnoreCase = cbIgnore.Checked; + Item.MatchType = cbCheck.SelectedIndex; + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(btnTest, "Click") + .Subscribe(evt => + { + var dialog = new RegexTestDialog(ServiceProvider, txtPattern.Text, cbIgnore.Checked, true); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + txtPattern.Text = dialog.Pattern; + cbIgnore.Checked = dialog.IgnoreCase; + })); + } + + public ConditionItem Item { get; private set; } + + private void AddConditionDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkID=130403&clcid=0x409"); + } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/AddConditionDialog.resx b/JexusManager.Features.Rewrite/Inbound/AddConditionDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AddConditionDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/Inbound/AddMapDialog.Designer.cs b/JexusManager.Features.Rewrite/Inbound/AddMapDialog.Designer.cs new file mode 100644 index 00000000..cfa6fc8a --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AddMapDialog.Designer.cs @@ -0,0 +1,124 @@ +namespace JexusManager.Features.Rewrite.Inbound +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class AddMapDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.txtOriginal = new System.Windows.Forms.TextBox(); + this.txtNew = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(216, 156); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 0; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(312, 156); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 1; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 13); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(74, 13); + this.label1.TabIndex = 2; + this.label1.Text = "Original value:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 73); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(61, 13); + this.label2.TabIndex = 3; + this.label2.Text = "New value:"; + // + // txtOriginal + // + this.txtOriginal.Location = new System.Drawing.Point(12, 29); + this.txtOriginal.Name = "txtOriginal"; + this.txtOriginal.Size = new System.Drawing.Size(395, 20); + this.txtOriginal.TabIndex = 4; + // + // txtNew + // + this.txtNew.Location = new System.Drawing.Point(12, 89); + this.txtNew.Name = "txtNew"; + this.txtNew.Size = new System.Drawing.Size(395, 20); + this.txtNew.TabIndex = 5; + // + // AddMapDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(419, 191); + this.Controls.Add(this.txtNew); + this.Controls.Add(this.txtOriginal); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Name = "AddMapDialog"; + this.Text = "Add Mapping Entry"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.AddMapDialog_HelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnOK; + private Button btnCancel; + private Label label1; + private Label label2; + private TextBox txtOriginal; + private TextBox txtNew; + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/AddMapDialog.cs b/JexusManager.Features.Rewrite/Inbound/AddMapDialog.cs new file mode 100644 index 00000000..6581a0e2 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AddMapDialog.cs @@ -0,0 +1,63 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// -------------------------------------------------------------------------------------------------------------------- +// +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace JexusManager.Features.Rewrite.Inbound +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal partial class AddMapDialog : DialogForm + { + public MapRule Item { get; set; } + + public AddMapDialog(IServiceProvider serviceProvider, MapRule existing, MapsFeature feature) + : base(serviceProvider) + { + Item = existing; + InitializeComponent(); + Text = existing == null ? "Add Mapping Entry" : "Edit Mapping Entry"; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtOriginal, "TextChanged") + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtOriginal.Text); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + if (Item == null) + { + Item = new MapRule(null, feature); + } + + Item.Original = txtOriginal.Text; + Item.New = txtNew.Text; + DialogResult = DialogResult.OK; + })); + } + + private void AddMapDialog_HelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkID=130406&clcid=0x409"); + } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/AddMapDialog.resx b/JexusManager.Features.Rewrite/Inbound/AddMapDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AddMapDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/Inbound/AddMapsDialog.Designer.cs b/JexusManager.Features.Rewrite/Inbound/AddMapsDialog.Designer.cs new file mode 100644 index 00000000..49d13dbb --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AddMapsDialog.Designer.cs @@ -0,0 +1,102 @@ +namespace JexusManager.Features.Rewrite.Inbound +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class AddMapsDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(13, 13); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(110, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Server variable name:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(16, 39); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(351, 20); + this.txtName.TabIndex = 1; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(176, 81); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 2; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(272, 81); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 3; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // AddVariableDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(379, 116); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.txtName); + this.Controls.Add(this.label1); + this.Name = "AddVariableDialog"; + this.Text = "Add Server Variable"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.AddVariableDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Label label1; + private TextBox txtName; + private Button btnOK; + private Button btnCancel; + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/AddMapsDialog.cs b/JexusManager.Features.Rewrite/Inbound/AddMapsDialog.cs new file mode 100644 index 00000000..5d0de39a --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AddMapsDialog.cs @@ -0,0 +1,67 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// -------------------------------------------------------------------------------------------------------------------- +// +// +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace JexusManager.Features.Rewrite.Inbound +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal partial class AddMapsDialog : DialogForm + { + public AddMapsDialog(IServiceProvider serviceProvider, MapsFeature feature) + : base(serviceProvider) + { + InitializeComponent(); + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + if (feature.Items.Any(item => txtName.Text == item.Name)) + { + ShowMessage( + "The specified server variable already exists.", + MessageBoxButtons.OK, + MessageBoxIcon.Error, + MessageBoxDefaultButton.Button1); + return; + } + + Item = new MapItem(null, feature) { Name = txtName.Text, DefaultValue = string.Empty }; + DialogResult = DialogResult.OK; + })); + + container.Add( + Observable.FromEventPattern(txtName, "TextChanged") + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtName.Text); + })); + } + + private void AddVariableDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=163108"); + } + + public MapItem Item { get; set; } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/AddMapsDialog.resx b/JexusManager.Features.Rewrite/Inbound/AddMapsDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AddMapsDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/Inbound/AddServerVariableDialog.Designer.cs b/JexusManager.Features.Rewrite/Inbound/AddServerVariableDialog.Designer.cs new file mode 100644 index 00000000..763be652 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AddServerVariableDialog.Designer.cs @@ -0,0 +1,138 @@ +namespace JexusManager.Features.Rewrite.Inbound +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal partial class AddServerVariableDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.cbName = new System.Windows.Forms.ComboBox(); + this.label2 = new System.Windows.Forms.Label(); + this.txtValue = new System.Windows.Forms.TextBox(); + this.cbReplace = new System.Windows.Forms.CheckBox(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(242, 211); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(146, 211); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(110, 13); + this.label1.TabIndex = 2; + this.label1.Text = "Server variable name:"; + // + // cbName + // + this.cbName.FormattingEnabled = true; + this.cbName.Location = new System.Drawing.Point(15, 25); + this.cbName.Name = "cbName"; + this.cbName.Size = new System.Drawing.Size(294, 21); + this.cbName.TabIndex = 3; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 84); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(37, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Value:"; + // + // txtValue + // + this.txtValue.Location = new System.Drawing.Point(15, 100); + this.txtValue.Name = "txtValue"; + this.txtValue.Size = new System.Drawing.Size(294, 20); + this.txtValue.TabIndex = 5; + // + // cbReplace + // + this.cbReplace.AutoSize = true; + this.cbReplace.Location = new System.Drawing.Point(15, 149); + this.cbReplace.Name = "cbReplace"; + this.cbReplace.Size = new System.Drawing.Size(151, 17); + this.cbReplace.TabIndex = 6; + this.cbReplace.Text = "Replace the existing value"; + this.cbReplace.UseVisualStyleBackColor = true; + // + // AddServerVariableDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(349, 246); + this.Controls.Add(this.cbReplace); + this.Controls.Add(this.txtValue); + this.Controls.Add(this.label2); + this.Controls.Add(this.cbName); + this.Controls.Add(this.label1); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "AddServerVariableDialog"; + this.Text = "Set Server Variable"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.AddServerVariableDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label label1; + private ComboBox cbName; + private Label label2; + private TextBox txtValue; + private CheckBox cbReplace; + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/AddServerVariableDialog.cs b/JexusManager.Features.Rewrite/Inbound/AddServerVariableDialog.cs new file mode 100644 index 00000000..7ea8300e --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AddServerVariableDialog.cs @@ -0,0 +1,72 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// -------------------------------------------------------------------------------------------------------------------- +// +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace JexusManager.Features.Rewrite.Inbound +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client.Win32; + + internal partial class AddServerVariableDialog : DialogForm + { + public AddServerVariableDialog(IServiceProvider serviceProvider, ServerVariableItem existing) + : base(serviceProvider) + { + InitializeComponent(); + Item = existing ?? new ServerVariableItem(null); + cbName.Text = Item.Name; + txtValue.Text = Item.Value; + cbReplace.Checked = Item.Replace; + var service = (IConfigurationService)serviceProvider.GetService(typeof(IConfigurationService)); + var rulesSection = service.GetSection("system.webServer/rewrite/allowedServerVariables"); + ConfigurationElementCollection rulesCollection = rulesSection.GetCollection(); + foreach (ConfigurationElement ruleElement in rulesCollection) + { + cbName.Items.Add(ruleElement["name"]); + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(txtValue, "TextChanged") + .Merge(Observable.FromEventPattern(cbName, "TextChanged")) + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(cbName.Text) && !string.IsNullOrWhiteSpace(txtValue.Text); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + Item.Name = cbName.Text; + Item.Value = txtValue.Text; + Item.Replace = cbReplace.Checked; + DialogResult = DialogResult.OK; + })); + } + + public ServerVariableItem Item { get; set; } + + private void AddServerVariableDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkId=163108"); + } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/AddServerVariableDialog.resx b/JexusManager.Features.Rewrite/Inbound/AddServerVariableDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AddServerVariableDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/Inbound/AllowedVariableItem.cs b/JexusManager.Features.Rewrite/Inbound/AllowedVariableItem.cs new file mode 100644 index 00000000..7743a6d0 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AllowedVariableItem.cs @@ -0,0 +1,47 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Rewrite.Inbound +{ + using Microsoft.Web.Administration; + + internal class AllowedVariableItem : IItem + { + public ConfigurationElement Element { get; set; } + + public bool Match(AllowedVariableItem other) + { + return other != null && other.Name == Name; + } + + private readonly AllowedVariablesFeature _feature; + + public string Name { get; internal set; } + + public string Flag { get; set; } + + public AllowedVariableItem(ConfigurationElement element, AllowedVariablesFeature feature) + { + this.Element = element; + _feature = feature; + this.Flag = element == null || element.IsLocallyStored ? "Local" : "Inherited"; + if (element == null) + { + return; + } + + this.Name = (string)element["name"]; + } + + public void Apply() + { + Element["name"] = Name; + } + + public bool Equals(AllowedVariableItem other) + { + return Match(other); + } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/AllowedVariablesFeature.cs b/JexusManager.Features.Rewrite/Inbound/AllowedVariablesFeature.cs new file mode 100644 index 00000000..d7441429 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/AllowedVariablesFeature.cs @@ -0,0 +1,251 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// -------------------------------------------------------------------------------------------------------------------- +// +// +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace JexusManager.Features.Rewrite.Inbound +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using System.Reflection; + using System.Resources; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + /// + /// Description of DefaultDocumentFeature. + /// + internal class AllowedVariablesFeature + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly AllowedVariablesFeature _owner; + + public FeatureTaskList(AllowedVariablesFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("Add", "Add...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Rename", "Rename", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + if (_owner.CanRevert) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Revert", "Revert to Parent", string.Empty).SetUsage()); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Add() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void Rename() + { + _owner.Rename(); + } + + [Obfuscation(Exclude = true)] + public void Revert() + { + _owner.Revert(); + } + } + + public AllowedVariablesFeature(Module module) + { + this.Module = module; + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + protected void DisplayErrorMessage(Exception ex, ResourceManager resourceManager) + { + var service = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + service.ShowError(ex, resourceManager.GetString("General"), string.Empty, false); + } + + protected object GetService(Type type) + { + return (this.Module as IServiceProvider).GetService(type); + } + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + this.Items = new List(); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/rewrite/allowedServerVariables"); + ConfigurationElementCollection rulesCollection = section.GetCollection(); + foreach (ConfigurationElement ruleElement in rulesCollection) + { + var node = new AllowedVariableItem(ruleElement, this); + this.Items.Add(node); + } + + this.CanRevert = section.CanRevert(); + this.OnRewriteSettingsSaved(); + } + + public List Items { get; set; } + + public void Add() + { + var dialog = new AddAllowedVariableDialog(this.Module, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + var newItem = dialog.Item; + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var rulesSection = service.GetSection("system.webServer/rewrite/allowedServerVariables"); + ConfigurationElementCollection rulesCollection = rulesSection.GetCollection(); + + if (this.SelectedItem != newItem) + { + this.Items.Add(newItem); + this.SelectedItem = newItem; + } + else if (newItem.Flag != "Local") + { + rulesCollection.Remove(newItem.Element); + newItem.Flag = "Local"; + } + + newItem.AppendTo(rulesCollection); + service.ServerManager.CommitChanges(); + this.OnRewriteSettingsSaved(); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected entry?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + this.Items.Remove(this.SelectedItem); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/rewrite/allowedServerVariables"); + ConfigurationElementCollection collection = section.GetCollection(); + collection.Remove(this.SelectedItem.Element); + service.ServerManager.CommitChanges(); + + this.SelectedItem = null; + this.OnRewriteSettingsSaved(); + } + + internal protected void OnRewriteSettingsSaved() + { + this.RewriteSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkID=130403&clcid=0x409"); + return false; + } + + public void Revert() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + var result = + dialog.ShowMessage( + "Reverting to the parent configuration will result in the loss of all settings in the local configuration file for this feature. Are you sure you want to continue?", + this.Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/rewrite/allowedServerVariables"); + ConfigurationElementCollection collection = section.GetCollection(); + collection.Clear(); + collection.Delete(); + collection = section.GetCollection(); + + this.SelectedItem = null; + this.Items.Clear(); + foreach (ConfigurationElement ruleElement in collection) + { + var node = new AllowedVariableItem(ruleElement, this); + this.Items.Add(node); + } + + service.ServerManager.CommitChanges(); + this.OnRewriteSettingsSaved(); + } + + private void Rename() + { + } + + public AllowedVariableItem SelectedItem { get; internal set; } + public bool CanRevert { get; private set; } + + public RewriteSettingsSavedEventHandler RewriteSettingsUpdated { get; set; } + public string Description { get; } + + public virtual bool IsFeatureEnabled + { + get { return true; } + } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public Module Module { get; } + public string Name { get; } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/InboundFeature.cs b/JexusManager.Features.Rewrite/Inbound/InboundFeature.cs new file mode 100644 index 00000000..b5316898 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/InboundFeature.cs @@ -0,0 +1,184 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Rewrite.Inbound +{ + using System; + using System.Linq; + using System.Windows.Forms; + + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + public class InboundFeature : FeatureBase + { + public InboundFeature(Module module) + : base(module) + { + } + + protected override ConfigurationElementCollection GetCollection(IConfigurationService service) + { + var outSection = service.GetSection("system.webServer/rewrite/rules"); + return outSection.GetCollection(); + } + + protected override void OnSettingsSaved() + { + this.RewriteSettingsUpdated?.Invoke(); + } + + public void Refresh() + { + OnSettingsSaved(); + } + + public RewriteSettingsSavedEventHandler RewriteSettingsUpdated { get; set; } + + public string Name + { + get { return "URL Rewrite"; } + } + + public void Load() + { + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/rewrite/rules"); + this.CanRevert = section.CanRevert(); + } + + public bool CanRevert { get; set; } + + public void Add() + { + int index = 0; + string name; + do + { + index++; + name = string.Format("LowerCaseRule{0}", index); + } + while (this.Items.All(item => item.Name != name)); + var newRule = new InboundRule(null); + newRule.Name = name; + newRule.Input = "URL Path"; + newRule.PatternSyntax = 0L; + newRule.PatternUrl = "[A-Z]"; + newRule.Type = 2L; + newRule.ActionUrl = "{ToLower:{URL}}"; + newRule.IgnoreCase = false; + newRule.RedirectType = 301; + + this.AddItem(newRule); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected rule?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + this.RemoveItem(); + } + + public void AddConditions() + { + var dialog = new AddConditionDialog(this.Module, null); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + var newItem = dialog.Item; + this.SelectedItem.Conditions.Add(newItem); + } + + public void MoveUp() + { + if (this.Items.Any(item => item.Flag != "Local")) + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + var result = + dialog.ShowMessage( + "The list order will be changed for this feature. If you continue, changes made to this feature at a parent level will no longer be inherited at this level. Do you want to continue?", + this.Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + } + + this.MoveUpItem(); + } + + public void MoveDown() + { + if (this.Items.Any(item => item.Flag != "Local")) + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + var result = + dialog.ShowMessage( + "The list order will be changed for this feature. If you continue, changes made to this feature at a parent level will no longer be inherited at this level. Do you want to continue?", + this.Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + } + + this.MoveDownItem(); + } + + public void Disable() + { + this.SelectedItem.Enabled = false; + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + this.SelectedItem.Element["enabled"] = false; + service.ServerManager.CommitChanges(); + this.OnSettingsSaved(); + } + + public void Enable() + { + this.SelectedItem.Enabled = true; + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + this.SelectedItem.Element["enabled"] = true; + service.ServerManager.CommitChanges(); + this.OnSettingsSaved(); + } + + public void Revert() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + var result = + dialog.ShowMessage( + "Reverting to the parent configuration will result in the loss of all settings in the local configuration file for this feature. Are you sure you want to continue?", + this.Name, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Warning, + MessageBoxDefaultButton.Button1); + if (result != DialogResult.Yes) + { + return; + } + + this.RevertItems(); + } + + public void Edit() + { + var service = (INavigationService)this.GetService(typeof(INavigationService)); + service.Navigate(null, null, typeof(InboundRulePage), new Tuple(this, this.SelectedItem)); + this.OnSettingsSaved(); + } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/InboundRule.cs b/JexusManager.Features.Rewrite/Inbound/InboundRule.cs new file mode 100644 index 00000000..8097573e --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/InboundRule.cs @@ -0,0 +1,227 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// -------------------------------------------------------------------------------------------------------------------- +// +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace JexusManager.Features.Rewrite.Inbound +{ + using System.Collections.Generic; + using System.Diagnostics; + + using Microsoft.Web.Administration; + + public class InboundRule : IItem + { + public InboundRule(ConfigurationElement element) + { + Flag = element == null || element.IsLocallyStored ? "Local" : "Inherited"; + this.Element = element; + this.ServerVariables = new List(); + this.Conditions = new List(); + if (element == null) + { + this.Type = 1; + IgnoreCase = true; + this.AppendQueryString = true; + Enabled = true; + return; + } + + CancelChanges(); + } + + public string Name { get; set; } + + public string Input { get; set; } + + public bool Negate { get; set; } + + public string PatternUrl { get; set; } + + public long Type { get; set; } + + public string ActionUrl { get; set; } + + public bool StopProcessing { get; set; } + + public string Flag { get; set; } + + public ConfigurationElement Element { get; set; } + + public bool Enabled { get; set; } + + public RuleSettingsUpdatedEventHandler RuleSettingsUpdated { get; set; } + + public bool IgnoreCase { get; set; } + + public long PatternSyntax { get; set; } + + public bool AppendQueryString { get; set; } + + public bool LogRewrittenUrl { get; set; } + + public int RedirectType { get; set; } + + public uint StatusCode { get; set; } + + public uint SubStatusCode { get; set; } + + public string StatusReason { get; set; } + + public string StatusDescription { get; set; } + + public List ServerVariables { get; } + + public List Conditions { get; } + + public bool Equals(InboundRule other) + { + return Match(other); + } + + public bool Match(InboundRule other) + { + return other != null && other.Name == this.Name; + } + + public bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkID=130425&clcid=0x409"); + return true; + } + + public void CancelChanges() + { + if (Element == null) + { + return; + } + + this.Name = (string)this.Element["name"]; + this.Enabled = (bool)this.Element["enabled"]; + this.PatternSyntax = (long)this.Element["patternSyntax"]; + this.StopProcessing = (bool)this.Element["stopProcessing"]; + ConfigurationElement matchElement = this.Element.ChildElements["match"]; + this.PatternUrl = (string)matchElement["url"]; + this.Negate = (bool)matchElement["negate"]; + ConfigurationElement actionElement = this.Element.ChildElements["action"]; + this.Type = (long)actionElement["type"]; + this.ActionUrl = (string)actionElement["url"]; + this.AppendQueryString = (bool)actionElement["appendQueryString"]; + this.LogRewrittenUrl = (bool)actionElement["logRewrittenUrl"]; + var redirect = (long)actionElement["redirectType"]; + switch (redirect) + { + case 301: + this.RedirectType = 0; + break; + case 302: + this.RedirectType = 1; + break; + case 303: + this.RedirectType = 2; + break; + case 307: + this.RedirectType = 3; + break; + } + + this.StatusCode = (uint)actionElement["statusCode"]; + this.SubStatusCode = (uint)actionElement["subStatusCode"]; + this.StatusReason = (string)actionElement["statusReason"]; + this.StatusDescription = (string)actionElement["statusDescription"]; + + var conditions = this.Element.ChildElements["conditions"]; + this.TrackAllCaptures = (bool)conditions["trackAllCaptures"]; + this.LogicalGrouping = (long)conditions["logicalGrouping"]; + + foreach (ConfigurationElement condition in conditions.GetCollection()) + { + var item = new ConditionItem(condition); + this.Conditions.Add(item); + } + + var variables = this.Element.ChildElements["serverVariables"]; + foreach (ConfigurationElement variable in variables.GetCollection()) + { + var item = new ServerVariableItem(variable); + this.ServerVariables.Add(item); + } + } + + public long LogicalGrouping { get; set; } + + public bool TrackAllCaptures { get; set; } + + public bool ApplyChanges() + { + this.Apply(); + return true; + } + + public void Apply() + { + Element["name"] = Name; + Element["enabled"] = Enabled; + Element["patternSyntax"] = this.PatternSyntax; + Element["stopProcessing"] = this.StopProcessing; + ConfigurationElement matchElement = Element.ChildElements["match"]; + matchElement["url"] = this.PatternUrl; + matchElement["negate"] = this.Negate; + ConfigurationElement actionElement = Element.ChildElements["action"]; + actionElement["type"] = this.Type; + actionElement["url"] = this.ActionUrl; + actionElement["appendQueryString"] = this.AppendQueryString; + actionElement["logRewrittenUrl"] = this.LogRewrittenUrl; + + switch (RedirectType) + { + case 0: + actionElement["redirectType"] = 301L; + break; + case 1: + actionElement["redirectType"] = 302L; + break; + case 2: + actionElement["redirectType"] = 303L; + break; + case 3: + actionElement["redirectType"] = 307L; + break; + } + + actionElement["statusCode"] = this.StatusCode; + actionElement["subStatusCode"] = this.SubStatusCode; + actionElement["statusReason"] = this.StatusReason; + actionElement["statusDescription"] = this.StatusDescription; + + var conditions = Element.ChildElements["conditions"]; + conditions["trackAllCaptures"] = TrackAllCaptures; + conditions["logicalGrouping"] = LogicalGrouping; + var conditionsCollection = conditions.GetCollection(); + conditionsCollection.Clear(); + foreach (var condition in Conditions) + { + condition.AppendTo(conditionsCollection); + } + + var variableCollection = Element.ChildElements["serverVariables"].GetCollection(); + variableCollection.Clear(); + foreach (var variable in ServerVariables) + { + variable.AppendTo(variableCollection); + } + } + + public void AppendTo(ConfigurationElementCollection rulesCollection) + { + Element = rulesCollection.CreateElement(); + Apply(); + rulesCollection.Add(Element); + } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/InboundRulePage.Designer.cs b/JexusManager.Features.Rewrite/Inbound/InboundRulePage.Designer.cs new file mode 100644 index 00000000..d0b6fd57 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/InboundRulePage.Designer.cs @@ -0,0 +1,1053 @@ +namespace JexusManager.Features.Rewrite.Inbound +{ + using System.ComponentModel; + using System.Windows.Forms; + + using MakarovDev.ExpandCollapsePanel; + + partial class InboundRulePage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.tableLayoutPanel3 = new System.Windows.Forms.TableLayoutPanel(); + this.advancedFlowLayoutPanel1 = new MakarovDev.ExpandCollapsePanel.AdvancedFlowLayoutPanel(); + this.gbMatch = new MakarovDev.ExpandCollapsePanel.ExpandCollapsePanel(); + this.cbIgnoreCase = new System.Windows.Forms.CheckBox(); + this.btnTest = new System.Windows.Forms.Button(); + this.txtPattern = new System.Windows.Forms.TextBox(); + this.label6 = new System.Windows.Forms.Label(); + this.cbType = new System.Windows.Forms.ComboBox(); + this.label5 = new System.Windows.Forms.Label(); + this.cbMatch = new System.Windows.Forms.ComboBox(); + this.label4 = new System.Windows.Forms.Label(); + this.gbConditions = new MakarovDev.ExpandCollapsePanel.ExpandCollapsePanel(); + this.btnDown = new System.Windows.Forms.Button(); + this.btnUp = new System.Windows.Forms.Button(); + this.btnRemove = new System.Windows.Forms.Button(); + this.btnEdit = new System.Windows.Forms.Button(); + this.lvConditions = new System.Windows.Forms.ListView(); + this.chInput = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chType = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chPattern = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.cbTrack = new System.Windows.Forms.CheckBox(); + this.btnAdd = new System.Windows.Forms.Button(); + this.label19 = new System.Windows.Forms.Label(); + this.cbAny = new System.Windows.Forms.ComboBox(); + this.label20 = new System.Windows.Forms.Label(); + this.gbVariables = new MakarovDev.ExpandCollapsePanel.ExpandCollapsePanel(); + this.btnVarRemove = new System.Windows.Forms.Button(); + this.btnVarEdit = new System.Windows.Forms.Button(); + this.btnVarAdd = new System.Windows.Forms.Button(); + this.btnVarUp = new System.Windows.Forms.Button(); + this.btnVarDown = new System.Windows.Forms.Button(); + this.lvVariables = new System.Windows.Forms.ListView(); + this.chName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chValue = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chReplace = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.groupBox2 = new MakarovDev.ExpandCollapsePanel.ExpandCollapsePanel(); + this.gbRedirect = new System.Windows.Forms.GroupBox(); + this.cbRedirect = new System.Windows.Forms.ComboBox(); + this.label14 = new System.Windows.Forms.Label(); + this.cbAppendRedirect = new System.Windows.Forms.CheckBox(); + this.txtRedirect = new System.Windows.Forms.TextBox(); + this.label9 = new System.Windows.Forms.Label(); + this.gbCustom = new System.Windows.Forms.GroupBox(); + this.txtError = new System.Windows.Forms.TextBox(); + this.txtReason = new System.Windows.Forms.TextBox(); + this.label13 = new System.Windows.Forms.Label(); + this.label12 = new System.Windows.Forms.Label(); + this.txtStatus = new System.Windows.Forms.TextBox(); + this.label11 = new System.Windows.Forms.Label(); + this.txtSubstatus = new System.Windows.Forms.TextBox(); + this.label10 = new System.Windows.Forms.Label(); + this.cbStop = new System.Windows.Forms.CheckBox(); + this.gbRewrite = new System.Windows.Forms.GroupBox(); + this.cbLog = new System.Windows.Forms.CheckBox(); + this.cbAppend = new System.Windows.Forms.CheckBox(); + this.txtUrl = new System.Windows.Forms.TextBox(); + this.label8 = new System.Windows.Forms.Label(); + this.cbAction = new System.Windows.Forms.ComboBox(); + this.label7 = new System.Windows.Forms.Label(); + this.panel2 = new System.Windows.Forms.Panel(); + this.label2 = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.panel3 = new System.Windows.Forms.Panel(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + this.tableLayoutPanel3.SuspendLayout(); + this.advancedFlowLayoutPanel1.SuspendLayout(); + this.gbMatch.SuspendLayout(); + this.gbConditions.SuspendLayout(); + this.gbVariables.SuspendLayout(); + this.groupBox2.SuspendLayout(); + this.gbRedirect.SuspendLayout(); + this.gbCustom.SuspendLayout(); + this.gbRewrite.SuspendLayout(); + this.panel2.SuspendLayout(); + this.panel3.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.tableLayoutPanel2); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 6; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.SplitContainer1SplitterMoved); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.ColumnCount = 1; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle()); + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel2.Controls.Add(this.tableLayoutPanel3, 0, 1); + this.tableLayoutPanel2.Controls.Add(this.panel3, 0, 0); + this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 3; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 60F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(580, 600); + this.tableLayoutPanel2.TabIndex = 12; + // + // tableLayoutPanel3 + // + this.tableLayoutPanel3.ColumnCount = 1; + this.tableLayoutPanel3.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel3.Controls.Add(this.advancedFlowLayoutPanel1, 0, 1); + this.tableLayoutPanel3.Controls.Add(this.panel2, 0, 0); + this.tableLayoutPanel3.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel3.Location = new System.Drawing.Point(3, 63); + this.tableLayoutPanel3.Name = "tableLayoutPanel3"; + this.tableLayoutPanel3.RowCount = 2; + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 60F)); + this.tableLayoutPanel3.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel3.Size = new System.Drawing.Size(574, 514); + this.tableLayoutPanel3.TabIndex = 8; + // + // advancedFlowLayoutPanel1 + // + this.advancedFlowLayoutPanel1.AutoScroll = true; + this.advancedFlowLayoutPanel1.Controls.Add(this.gbMatch); + this.advancedFlowLayoutPanel1.Controls.Add(this.gbConditions); + this.advancedFlowLayoutPanel1.Controls.Add(this.gbVariables); + this.advancedFlowLayoutPanel1.Controls.Add(this.groupBox2); + this.advancedFlowLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.advancedFlowLayoutPanel1.Location = new System.Drawing.Point(3, 63); + this.advancedFlowLayoutPanel1.Name = "advancedFlowLayoutPanel1"; + this.advancedFlowLayoutPanel1.Size = new System.Drawing.Size(568, 448); + this.advancedFlowLayoutPanel1.TabIndex = 7; + // + // gbMatch + // + this.gbMatch.ButtonStyle = MakarovDev.ExpandCollapsePanel.ExpandCollapseButton.ExpandButtonStyle.Circle; + this.gbMatch.Controls.Add(this.cbIgnoreCase); + this.gbMatch.Controls.Add(this.btnTest); + this.gbMatch.Controls.Add(this.txtPattern); + this.gbMatch.Controls.Add(this.label6); + this.gbMatch.Controls.Add(this.cbType); + this.gbMatch.Controls.Add(this.label5); + this.gbMatch.Controls.Add(this.cbMatch); + this.gbMatch.Controls.Add(this.label4); + this.gbMatch.ExpandedHeight = 182; + this.gbMatch.Location = new System.Drawing.Point(3, 3); + this.gbMatch.Name = "gbMatch"; + this.gbMatch.Size = new System.Drawing.Size(545, 182); + this.gbMatch.TabIndex = 5; + this.gbMatch.Text = "Match URL"; + // + // cbIgnoreCase + // + this.cbIgnoreCase.AutoSize = true; + this.cbIgnoreCase.Location = new System.Drawing.Point(18, 140); + this.cbIgnoreCase.Name = "cbIgnoreCase"; + this.cbIgnoreCase.Size = new System.Drawing.Size(90, 19); + this.cbIgnoreCase.TabIndex = 7; + this.cbIgnoreCase.Text = "Ignore case"; + this.cbIgnoreCase.UseVisualStyleBackColor = true; + this.cbIgnoreCase.CheckedChanged += new System.EventHandler(this.CbAppendRedirectCheckedChanged); + // + // btnTest + // + this.btnTest.Location = new System.Drawing.Point(549, 111); + this.btnTest.Name = "btnTest"; + this.btnTest.Size = new System.Drawing.Size(95, 23); + this.btnTest.TabIndex = 6; + this.btnTest.Text = "Test patterns..."; + this.btnTest.UseVisualStyleBackColor = true; + this.btnTest.Click += new System.EventHandler(this.BtnTestClick); + // + // txtPattern + // + this.txtPattern.Location = new System.Drawing.Point(18, 113); + this.txtPattern.Name = "txtPattern"; + this.txtPattern.Size = new System.Drawing.Size(525, 21); + this.txtPattern.TabIndex = 5; + this.txtPattern.TextChanged += new System.EventHandler(this.TxtNameTextChanged); + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(15, 85); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(49, 15); + this.label6.TabIndex = 4; + this.label6.Text = "Pattern:"; + // + // cbType + // + this.cbType.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbType.FormattingEnabled = true; + this.cbType.Items.AddRange(new object[] { + "Regular Expressions", + "Wildcards", + "Exact Match"}); + this.cbType.Location = new System.Drawing.Point(379, 43); + this.cbType.Name = "cbType"; + this.cbType.Size = new System.Drawing.Size(265, 21); + this.cbType.TabIndex = 3; + this.cbType.TextChanged += new System.EventHandler(this.TxtNameTextChanged); + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(376, 27); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(42, 15); + this.label5.TabIndex = 2; + this.label5.Text = "Using:"; + // + // cbMatch + // + this.cbMatch.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbMatch.FormattingEnabled = true; + this.cbMatch.Items.AddRange(new object[] { + "Matches the Pattern", + "Does Not Match the Pattern"}); + this.cbMatch.Location = new System.Drawing.Point(18, 43); + this.cbMatch.Name = "cbMatch"; + this.cbMatch.Size = new System.Drawing.Size(265, 21); + this.cbMatch.TabIndex = 1; + this.cbMatch.TextChanged += new System.EventHandler(this.TxtNameTextChanged); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(15, 27); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(98, 15); + this.label4.TabIndex = 0; + this.label4.Text = "Requested URL:"; + // + // gbConditions + // + this.gbConditions.ButtonStyle = MakarovDev.ExpandCollapsePanel.ExpandCollapseButton.ExpandButtonStyle.Circle; + this.gbConditions.Controls.Add(this.btnDown); + this.gbConditions.Controls.Add(this.btnUp); + this.gbConditions.Controls.Add(this.btnRemove); + this.gbConditions.Controls.Add(this.btnEdit); + this.gbConditions.Controls.Add(this.lvConditions); + this.gbConditions.Controls.Add(this.cbTrack); + this.gbConditions.Controls.Add(this.btnAdd); + this.gbConditions.Controls.Add(this.label19); + this.gbConditions.Controls.Add(this.cbAny); + this.gbConditions.Controls.Add(this.label20); + this.gbConditions.ExpandedHeight = 288; + this.gbConditions.IsExpanded = false; + this.gbConditions.Location = new System.Drawing.Point(3, 191); + this.gbConditions.Name = "gbConditions"; + this.gbConditions.Size = new System.Drawing.Size(545, 35); + this.gbConditions.TabIndex = 9; + this.gbConditions.Text = "Conditions"; + // + // btnDown + // + this.btnDown.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.btnDown.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(70)))), ((int)(((byte)(130)))), ((int)(((byte)(180))))); + this.btnDown.Location = new System.Drawing.Point(539, 219); + this.btnDown.Name = "btnDown"; + this.btnDown.Size = new System.Drawing.Size(95, 23); + this.btnDown.TabIndex = 12; + this.btnDown.Text = "Move Down"; + this.btnDown.UseVisualStyleBackColor = false; + this.btnDown.Click += new System.EventHandler(this.BtnDownClick); + // + // btnUp + // + this.btnUp.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.btnUp.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(70)))), ((int)(((byte)(130)))), ((int)(((byte)(180))))); + this.btnUp.Location = new System.Drawing.Point(539, 190); + this.btnUp.Name = "btnUp"; + this.btnUp.Size = new System.Drawing.Size(95, 23); + this.btnUp.TabIndex = 11; + this.btnUp.Text = "Move Up"; + this.btnUp.UseVisualStyleBackColor = false; + this.btnUp.Click += new System.EventHandler(this.BtnUpClick); + // + // btnRemove + // + this.btnRemove.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.btnRemove.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(70)))), ((int)(((byte)(130)))), ((int)(((byte)(180))))); + this.btnRemove.Location = new System.Drawing.Point(539, 141); + this.btnRemove.Name = "btnRemove"; + this.btnRemove.Size = new System.Drawing.Size(95, 23); + this.btnRemove.TabIndex = 10; + this.btnRemove.Text = "Remove"; + this.btnRemove.UseVisualStyleBackColor = false; + this.btnRemove.Click += new System.EventHandler(this.BtnRemoveClick); + // + // btnEdit + // + this.btnEdit.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.btnEdit.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(70)))), ((int)(((byte)(130)))), ((int)(((byte)(180))))); + this.btnEdit.Location = new System.Drawing.Point(539, 112); + this.btnEdit.Name = "btnEdit"; + this.btnEdit.Size = new System.Drawing.Size(95, 23); + this.btnEdit.TabIndex = 9; + this.btnEdit.Text = "Edit..."; + this.btnEdit.UseVisualStyleBackColor = false; + this.btnEdit.Click += new System.EventHandler(this.BtnEditClick); + // + // lvConditions + // + this.lvConditions.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.lvConditions.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chInput, + this.chType, + this.chPattern}); + this.lvConditions.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.lvConditions.FullRowSelect = true; + this.lvConditions.HideSelection = false; + this.lvConditions.Location = new System.Drawing.Point(8, 70); + this.lvConditions.MultiSelect = false; + this.lvConditions.Name = "lvConditions"; + this.lvConditions.Size = new System.Drawing.Size(525, 185); + this.lvConditions.TabIndex = 8; + this.lvConditions.UseCompatibleStateImageBehavior = false; + this.lvConditions.View = System.Windows.Forms.View.Details; + // + // chInput + // + this.chInput.Text = "Input"; + this.chInput.Width = 100; + // + // chType + // + this.chType.Text = "Type"; + this.chType.Width = 160; + // + // chPattern + // + this.chPattern.Text = "Pattern"; + this.chPattern.Width = 180; + // + // cbTrack + // + this.cbTrack.AutoSize = true; + this.cbTrack.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.cbTrack.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(70)))), ((int)(((byte)(130)))), ((int)(((byte)(180))))); + this.cbTrack.Location = new System.Drawing.Point(18, 261); + this.cbTrack.Name = "cbTrack"; + this.cbTrack.Size = new System.Drawing.Size(239, 19); + this.cbTrack.TabIndex = 7; + this.cbTrack.Text = "Track capture groups across conditions"; + this.cbTrack.UseVisualStyleBackColor = false; + // + // btnAdd + // + this.btnAdd.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.btnAdd.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(70)))), ((int)(((byte)(130)))), ((int)(((byte)(180))))); + this.btnAdd.Location = new System.Drawing.Point(539, 83); + this.btnAdd.Name = "btnAdd"; + this.btnAdd.Size = new System.Drawing.Size(95, 23); + this.btnAdd.TabIndex = 6; + this.btnAdd.Text = "Add..."; + this.btnAdd.UseVisualStyleBackColor = false; + this.btnAdd.Click += new System.EventHandler(this.BtnAddClick); + // + // label19 + // + this.label19.AutoSize = true; + this.label19.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.label19.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(70)))), ((int)(((byte)(130)))), ((int)(((byte)(180))))); + this.label19.Location = new System.Drawing.Point(376, 27); + this.label19.Name = "label19"; + this.label19.Size = new System.Drawing.Size(42, 15); + this.label19.TabIndex = 2; + this.label19.Text = "Using:"; + // + // cbAny + // + this.cbAny.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.cbAny.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbAny.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.cbAny.FormattingEnabled = true; + this.cbAny.Items.AddRange(new object[] { + "Match All", + "Match Any"}); + this.cbAny.Location = new System.Drawing.Point(18, 43); + this.cbAny.Name = "cbAny"; + this.cbAny.Size = new System.Drawing.Size(131, 21); + this.cbAny.TabIndex = 1; + // + // label20 + // + this.label20.AutoSize = true; + this.label20.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.label20.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(70)))), ((int)(((byte)(130)))), ((int)(((byte)(180))))); + this.label20.Location = new System.Drawing.Point(15, 27); + this.label20.Name = "label20"; + this.label20.Size = new System.Drawing.Size(102, 15); + this.label20.TabIndex = 0; + this.label20.Text = "Logical grouping:"; + // + // gbVariables + // + this.gbVariables.ButtonStyle = MakarovDev.ExpandCollapsePanel.ExpandCollapseButton.ExpandButtonStyle.Circle; + this.gbVariables.Controls.Add(this.btnVarRemove); + this.gbVariables.Controls.Add(this.btnVarEdit); + this.gbVariables.Controls.Add(this.btnVarAdd); + this.gbVariables.Controls.Add(this.btnVarUp); + this.gbVariables.Controls.Add(this.btnVarDown); + this.gbVariables.Controls.Add(this.lvVariables); + this.gbVariables.ExpandedHeight = 229; + this.gbVariables.IsExpanded = false; + this.gbVariables.Location = new System.Drawing.Point(3, 232); + this.gbVariables.Name = "gbVariables"; + this.gbVariables.Size = new System.Drawing.Size(545, 35); + this.gbVariables.TabIndex = 8; + this.gbVariables.Text = "Server Variables"; + // + // btnVarRemove + // + this.btnVarRemove.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.btnVarRemove.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(70)))), ((int)(((byte)(130)))), ((int)(((byte)(180))))); + this.btnVarRemove.Location = new System.Drawing.Point(539, 99); + this.btnVarRemove.Name = "btnVarRemove"; + this.btnVarRemove.Size = new System.Drawing.Size(95, 23); + this.btnVarRemove.TabIndex = 17; + this.btnVarRemove.Text = "Remove"; + this.btnVarRemove.UseVisualStyleBackColor = false; + this.btnVarRemove.Click += new System.EventHandler(this.BtnVarRemoveClick); + // + // btnVarEdit + // + this.btnVarEdit.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.btnVarEdit.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(70)))), ((int)(((byte)(130)))), ((int)(((byte)(180))))); + this.btnVarEdit.Location = new System.Drawing.Point(539, 70); + this.btnVarEdit.Name = "btnVarEdit"; + this.btnVarEdit.Size = new System.Drawing.Size(95, 23); + this.btnVarEdit.TabIndex = 16; + this.btnVarEdit.Text = "Edit.."; + this.btnVarEdit.UseVisualStyleBackColor = false; + this.btnVarEdit.Click += new System.EventHandler(this.BtnVarEditClick); + // + // btnVarAdd + // + this.btnVarAdd.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.btnVarAdd.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(70)))), ((int)(((byte)(130)))), ((int)(((byte)(180))))); + this.btnVarAdd.Location = new System.Drawing.Point(539, 41); + this.btnVarAdd.Name = "btnVarAdd"; + this.btnVarAdd.Size = new System.Drawing.Size(95, 23); + this.btnVarAdd.TabIndex = 15; + this.btnVarAdd.Text = "Add..."; + this.btnVarAdd.UseVisualStyleBackColor = false; + this.btnVarAdd.Click += new System.EventHandler(this.BtnVarAddClick); + // + // btnVarUp + // + this.btnVarUp.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.btnVarUp.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(70)))), ((int)(((byte)(130)))), ((int)(((byte)(180))))); + this.btnVarUp.Location = new System.Drawing.Point(539, 152); + this.btnVarUp.Name = "btnVarUp"; + this.btnVarUp.Size = new System.Drawing.Size(95, 23); + this.btnVarUp.TabIndex = 14; + this.btnVarUp.Text = "Move Up"; + this.btnVarUp.UseVisualStyleBackColor = false; + this.btnVarUp.Click += new System.EventHandler(this.BtnVarUpClick); + // + // btnVarDown + // + this.btnVarDown.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.btnVarDown.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(70)))), ((int)(((byte)(130)))), ((int)(((byte)(180))))); + this.btnVarDown.Location = new System.Drawing.Point(539, 181); + this.btnVarDown.Name = "btnVarDown"; + this.btnVarDown.Size = new System.Drawing.Size(95, 23); + this.btnVarDown.TabIndex = 13; + this.btnVarDown.Text = "Move Down"; + this.btnVarDown.UseVisualStyleBackColor = false; + this.btnVarDown.Click += new System.EventHandler(this.BtnVarDownClick); + // + // lvVariables + // + this.lvVariables.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(255)))), ((int)(((byte)(255)))), ((int)(((byte)(255))))); + this.lvVariables.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chName, + this.chValue, + this.chReplace}); + this.lvVariables.ForeColor = System.Drawing.Color.FromArgb(((int)(((byte)(0)))), ((int)(((byte)(0)))), ((int)(((byte)(0))))); + this.lvVariables.FullRowSelect = true; + this.lvVariables.HideSelection = false; + this.lvVariables.Location = new System.Drawing.Point(8, 29); + this.lvVariables.MultiSelect = false; + this.lvVariables.Name = "lvVariables"; + this.lvVariables.Size = new System.Drawing.Size(525, 185); + this.lvVariables.TabIndex = 9; + this.lvVariables.UseCompatibleStateImageBehavior = false; + this.lvVariables.View = System.Windows.Forms.View.Details; + // + // chName + // + this.chName.Text = "Name"; + this.chName.Width = 100; + // + // chValue + // + this.chValue.Text = "Value"; + this.chValue.Width = 160; + // + // chReplace + // + this.chReplace.Text = "Replace"; + this.chReplace.Width = 180; + // + // groupBox2 + // + this.groupBox2.ButtonStyle = MakarovDev.ExpandCollapsePanel.ExpandCollapseButton.ExpandButtonStyle.Circle; + this.groupBox2.Controls.Add(this.gbRedirect); + this.groupBox2.Controls.Add(this.gbCustom); + this.groupBox2.Controls.Add(this.cbStop); + this.groupBox2.Controls.Add(this.gbRewrite); + this.groupBox2.Controls.Add(this.cbAction); + this.groupBox2.Controls.Add(this.label7); + this.groupBox2.ExpandedHeight = 261; + this.groupBox2.Location = new System.Drawing.Point(3, 273); + this.groupBox2.Name = "groupBox2"; + this.groupBox2.Size = new System.Drawing.Size(545, 261); + this.groupBox2.TabIndex = 6; + this.groupBox2.Text = "Action"; + // + // gbRedirect + // + this.gbRedirect.Controls.Add(this.cbRedirect); + this.gbRedirect.Controls.Add(this.label14); + this.gbRedirect.Controls.Add(this.cbAppendRedirect); + this.gbRedirect.Controls.Add(this.txtRedirect); + this.gbRedirect.Controls.Add(this.label9); + this.gbRedirect.Location = new System.Drawing.Point(18, 70); + this.gbRedirect.Name = "gbRedirect"; + this.gbRedirect.Size = new System.Drawing.Size(626, 176); + this.gbRedirect.TabIndex = 4; + this.gbRedirect.TabStop = false; + this.gbRedirect.Text = "Action Properties"; + // + // cbRedirect + // + this.cbRedirect.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbRedirect.FormattingEnabled = true; + this.cbRedirect.Items.AddRange(new object[] { + "Permanent (301)", + "Found (302)", + "See Other (303)", + "Temporary (307)"}); + this.cbRedirect.Location = new System.Drawing.Point(21, 122); + this.cbRedirect.Name = "cbRedirect"; + this.cbRedirect.Size = new System.Drawing.Size(584, 21); + this.cbRedirect.TabIndex = 4; + this.cbRedirect.TextChanged += new System.EventHandler(this.TxtNameTextChanged); + // + // label14 + // + this.label14.AutoSize = true; + this.label14.Location = new System.Drawing.Point(18, 101); + this.label14.Name = "label14"; + this.label14.Size = new System.Drawing.Size(81, 15); + this.label14.TabIndex = 3; + this.label14.Text = "Redirect type:"; + // + // cbAppendRedirect + // + this.cbAppendRedirect.AutoSize = true; + this.cbAppendRedirect.Checked = true; + this.cbAppendRedirect.CheckState = System.Windows.Forms.CheckState.Checked; + this.cbAppendRedirect.Location = new System.Drawing.Point(21, 72); + this.cbAppendRedirect.Name = "cbAppendRedirect"; + this.cbAppendRedirect.Size = new System.Drawing.Size(134, 19); + this.cbAppendRedirect.TabIndex = 2; + this.cbAppendRedirect.Text = "Append query string"; + this.cbAppendRedirect.UseVisualStyleBackColor = true; + this.cbAppendRedirect.CheckedChanged += new System.EventHandler(this.CbAppendRedirectCheckedChanged); + // + // txtRedirect + // + this.txtRedirect.Location = new System.Drawing.Point(21, 43); + this.txtRedirect.Name = "txtRedirect"; + this.txtRedirect.Size = new System.Drawing.Size(584, 21); + this.txtRedirect.TabIndex = 1; + this.txtRedirect.TextChanged += new System.EventHandler(this.TxtNameTextChanged); + // + // label9 + // + this.label9.AutoSize = true; + this.label9.Location = new System.Drawing.Point(18, 26); + this.label9.Name = "label9"; + this.label9.Size = new System.Drawing.Size(84, 15); + this.label9.TabIndex = 0; + this.label9.Text = "Redirect URL:"; + // + // gbCustom + // + this.gbCustom.Controls.Add(this.txtError); + this.gbCustom.Controls.Add(this.txtReason); + this.gbCustom.Controls.Add(this.label13); + this.gbCustom.Controls.Add(this.label12); + this.gbCustom.Controls.Add(this.txtStatus); + this.gbCustom.Controls.Add(this.label11); + this.gbCustom.Controls.Add(this.txtSubstatus); + this.gbCustom.Controls.Add(this.label10); + this.gbCustom.Location = new System.Drawing.Point(18, 70); + this.gbCustom.Name = "gbCustom"; + this.gbCustom.Size = new System.Drawing.Size(626, 197); + this.gbCustom.TabIndex = 4; + this.gbCustom.TabStop = false; + this.gbCustom.Text = "Action Properties"; + // + // txtError + // + this.txtError.Location = new System.Drawing.Point(21, 164); + this.txtError.Name = "txtError"; + this.txtError.Size = new System.Drawing.Size(584, 21); + this.txtError.TabIndex = 9; + this.txtError.TextChanged += new System.EventHandler(this.TxtNameTextChanged); + // + // txtReason + // + this.txtReason.Location = new System.Drawing.Point(21, 117); + this.txtReason.Name = "txtReason"; + this.txtReason.Size = new System.Drawing.Size(584, 21); + this.txtReason.TabIndex = 8; + this.txtReason.TextChanged += new System.EventHandler(this.TxtNameTextChanged); + // + // label13 + // + this.label13.AutoSize = true; + this.label13.Location = new System.Drawing.Point(18, 143); + this.label13.Name = "label13"; + this.label13.Size = new System.Drawing.Size(100, 15); + this.label13.TabIndex = 7; + this.label13.Text = "Error description:"; + // + // label12 + // + this.label12.AutoSize = true; + this.label12.Location = new System.Drawing.Point(18, 101); + this.label12.Name = "label12"; + this.label12.Size = new System.Drawing.Size(53, 15); + this.label12.TabIndex = 6; + this.label12.Text = "Reason:"; + // + // txtStatus + // + this.txtStatus.Location = new System.Drawing.Point(133, 23); + this.txtStatus.Name = "txtStatus"; + this.txtStatus.Size = new System.Drawing.Size(472, 21); + this.txtStatus.TabIndex = 5; + this.txtStatus.TextChanged += new System.EventHandler(this.TxtNameTextChanged); + // + // label11 + // + this.label11.AutoSize = true; + this.label11.Location = new System.Drawing.Point(18, 64); + this.label11.Name = "label11"; + this.label11.Size = new System.Drawing.Size(94, 15); + this.label11.TabIndex = 4; + this.label11.Text = "Substatus code:"; + // + // txtSubstatus + // + this.txtSubstatus.Location = new System.Drawing.Point(133, 61); + this.txtSubstatus.Name = "txtSubstatus"; + this.txtSubstatus.Size = new System.Drawing.Size(472, 21); + this.txtSubstatus.TabIndex = 1; + this.txtSubstatus.TextChanged += new System.EventHandler(this.TxtNameTextChanged); + // + // label10 + // + this.label10.AutoSize = true; + this.label10.Location = new System.Drawing.Point(18, 26); + this.label10.Name = "label10"; + this.label10.Size = new System.Drawing.Size(74, 15); + this.label10.TabIndex = 0; + this.label10.Text = "Status code:"; + // + // cbStop + // + this.cbStop.AutoSize = true; + this.cbStop.Location = new System.Drawing.Point(18, 229); + this.cbStop.Name = "cbStop"; + this.cbStop.Size = new System.Drawing.Size(224, 19); + this.cbStop.TabIndex = 3; + this.cbStop.Text = "Stop processing of subsequent rules"; + this.cbStop.UseVisualStyleBackColor = true; + this.cbStop.CheckedChanged += new System.EventHandler(this.CbAppendRedirectCheckedChanged); + // + // gbRewrite + // + this.gbRewrite.Controls.Add(this.cbLog); + this.gbRewrite.Controls.Add(this.cbAppend); + this.gbRewrite.Controls.Add(this.txtUrl); + this.gbRewrite.Controls.Add(this.label8); + this.gbRewrite.Location = new System.Drawing.Point(18, 70); + this.gbRewrite.Name = "gbRewrite"; + this.gbRewrite.Size = new System.Drawing.Size(626, 143); + this.gbRewrite.TabIndex = 2; + this.gbRewrite.TabStop = false; + this.gbRewrite.Text = "Action Properties"; + // + // cbLog + // + this.cbLog.AutoSize = true; + this.cbLog.Location = new System.Drawing.Point(21, 108); + this.cbLog.Name = "cbLog"; + this.cbLog.Size = new System.Drawing.Size(125, 19); + this.cbLog.TabIndex = 3; + this.cbLog.Text = "Log rewritten URL"; + this.cbLog.UseVisualStyleBackColor = true; + this.cbLog.CheckedChanged += new System.EventHandler(this.CbAppendRedirectCheckedChanged); + // + // cbAppend + // + this.cbAppend.AutoSize = true; + this.cbAppend.Checked = true; + this.cbAppend.CheckState = System.Windows.Forms.CheckState.Checked; + this.cbAppend.Location = new System.Drawing.Point(21, 72); + this.cbAppend.Name = "cbAppend"; + this.cbAppend.Size = new System.Drawing.Size(134, 19); + this.cbAppend.TabIndex = 2; + this.cbAppend.Text = "Append query string"; + this.cbAppend.UseVisualStyleBackColor = true; + this.cbAppend.CheckedChanged += new System.EventHandler(this.CbAppendRedirectCheckedChanged); + // + // txtUrl + // + this.txtUrl.Location = new System.Drawing.Point(21, 43); + this.txtUrl.Name = "txtUrl"; + this.txtUrl.Size = new System.Drawing.Size(584, 21); + this.txtUrl.TabIndex = 1; + this.txtUrl.TextChanged += new System.EventHandler(this.TxtNameTextChanged); + // + // label8 + // + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(18, 26); + this.label8.Name = "label8"; + this.label8.Size = new System.Drawing.Size(80, 15); + this.label8.TabIndex = 0; + this.label8.Text = "Rewrite URL:"; + // + // cbAction + // + this.cbAction.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbAction.FormattingEnabled = true; + this.cbAction.Items.AddRange(new object[] { + "None", + "Rewrite", + "Redirect", + "Custom Response", + "Abort Request"}); + this.cbAction.Location = new System.Drawing.Point(18, 42); + this.cbAction.Name = "cbAction"; + this.cbAction.Size = new System.Drawing.Size(140, 21); + this.cbAction.TabIndex = 1; + this.cbAction.SelectedIndexChanged += new System.EventHandler(this.CbActionSelectedIndexChanged); + this.cbAction.TextChanged += new System.EventHandler(this.TxtNameTextChanged); + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(15, 26); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(68, 15); + this.label7.TabIndex = 0; + this.label7.Text = "Action type:"; + // + // panel2 + // + this.panel2.Controls.Add(this.label2); + this.panel2.Controls.Add(this.txtName); + this.panel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel2.Location = new System.Drawing.Point(3, 3); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(568, 54); + this.panel2.TabIndex = 11; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(18, 11); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(38, 13); + this.label2.TabIndex = 3; + this.label2.Text = "Name:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(21, 27); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(665, 20); + this.txtName.TabIndex = 4; + this.txtName.TextChanged += new System.EventHandler(this.TxtNameTextChanged); + // + // panel3 + // + this.panel3.Controls.Add(this.pictureBox1); + this.panel3.Controls.Add(this.label3); + this.panel3.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel3.Location = new System.Drawing.Point(3, 3); + this.panel3.Name = "panel3"; + this.panel3.Size = new System.Drawing.Size(574, 54); + this.panel3.TabIndex = 8; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 10; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(182, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Edit Inbound Rule"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // InboundRulePage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "InboundRulePage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.tableLayoutPanel2.ResumeLayout(false); + this.tableLayoutPanel3.ResumeLayout(false); + this.advancedFlowLayoutPanel1.ResumeLayout(false); + this.gbMatch.ResumeLayout(false); + this.gbMatch.PerformLayout(); + this.gbConditions.ResumeLayout(false); + this.gbConditions.PerformLayout(); + this.gbVariables.ResumeLayout(false); + this.gbVariables.PerformLayout(); + this.groupBox2.ResumeLayout(false); + this.groupBox2.PerformLayout(); + this.gbRedirect.ResumeLayout(false); + this.gbRedirect.PerformLayout(); + this.gbCustom.ResumeLayout(false); + this.gbCustom.PerformLayout(); + this.gbRewrite.ResumeLayout(false); + this.gbRewrite.PerformLayout(); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.panel3.ResumeLayout(false); + this.panel3.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + + private SplitContainer splitContainer1; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private PictureBox pictureBox1; + private ContextMenuStrip cmsActionPanel; + private TableLayoutPanel tableLayoutPanel2; + private TableLayoutPanel tableLayoutPanel3; + private AdvancedFlowLayoutPanel advancedFlowLayoutPanel1; + private ExpandCollapsePanel gbMatch; + private CheckBox cbIgnoreCase; + private Button btnTest; + private TextBox txtPattern; + private Label label6; + private ComboBox cbType; + private Label label5; + private ComboBox cbMatch; + private Label label4; + private ExpandCollapsePanel gbConditions; + private Button btnDown; + private Button btnUp; + private Button btnRemove; + private Button btnEdit; + private ListView lvConditions; + private ColumnHeader chInput; + private ColumnHeader chType; + private ColumnHeader chPattern; + private CheckBox cbTrack; + private Button btnAdd; + private Label label19; + private ComboBox cbAny; + private Label label20; + private ExpandCollapsePanel gbVariables; + private Button btnVarRemove; + private Button btnVarEdit; + private Button btnVarAdd; + private Button btnVarUp; + private Button btnVarDown; + private ListView lvVariables; + private ColumnHeader chName; + private ColumnHeader chValue; + private ColumnHeader chReplace; + private ExpandCollapsePanel groupBox2; + private GroupBox gbRedirect; + private ComboBox cbRedirect; + private Label label14; + private CheckBox cbAppendRedirect; + private TextBox txtRedirect; + private Label label9; + private GroupBox gbCustom; + private TextBox txtError; + private TextBox txtReason; + private Label label13; + private Label label12; + private TextBox txtStatus; + private Label label11; + private TextBox txtSubstatus; + private Label label10; + private CheckBox cbStop; + private GroupBox gbRewrite; + private CheckBox cbLog; + private CheckBox cbAppend; + private TextBox txtUrl; + private Label label8; + private ComboBox cbAction; + private Label label7; + private Panel panel2; + private Label label2; + private TextBox txtName; + private Panel panel3; + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/InboundRulePage.cs b/JexusManager.Features.Rewrite/Inbound/InboundRulePage.cs new file mode 100644 index 00000000..0d62b5d8 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/InboundRulePage.cs @@ -0,0 +1,543 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// -------------------------------------------------------------------------------------------------------------------- +// +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace JexusManager.Features.Rewrite.Inbound +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class InboundRulePage : ModuleDialogPage, IModuleChildPage + { + private sealed class PageTaskList : DefaultTaskList + { + private readonly InboundRulePage _owner; + + public PageTaskList(InboundRulePage owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + return new TaskItem[] + { + GetBackTaskItem("Back", "Back to Rules"), + new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage(), + HelpTaskItem + }; + } + + [Obfuscation(Exclude = true)] + public void ShowHelp() + { + _owner.ShowHelp(); + } + + [Obfuscation(Exclude = true)] + public void Back() + { + _owner.Back(); + } + } + + private class ServerVariableListViewItem : ListViewItem + { + private readonly ListViewSubItem _value; + + private readonly ListViewSubItem _replace; + + public ServerVariableListViewItem(ServerVariableItem variable) + : base(variable.Name) + { + _value = new ListViewSubItem(this, variable.Value); + this.SubItems.Add(_value); + _replace = new ListViewSubItem(this, variable.Replace.ToString()); + this.SubItems.Add(_replace); + this.Item = variable; + } + + public ServerVariableItem Item { get; } + + public void Update() + { + this.Text = this.Item.Name; + _value.Text = this.Item.Value; + _replace.Text = this.Item.Replace.ToString(); + } + } + + private bool _hasChanges; + + private bool _initialized; + + private TaskList _taskList; + + private InboundFeature _feature; + + public InboundRulePage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + // TODO: pictureBox1.Image + var info = (Tuple)navigationData; + _feature = info.Item1; + this.Rule = info.Item2; + txtName.ReadOnly = this.Rule != null; + if (this.Rule != null) + { + // TODO: invoke RuleSettingsUpdate somewhere. + this.Rule.RuleSettingsUpdated = this.Refresh; + } + + if (this.Rule == null) + { + this.Rule = new InboundRule(null); + Rule.Enabled = true; + } + + this.Refresh(); + } + + protected override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkID=130425&clcid=0x409"); + return true; + } + + private void SplitContainer1SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + private void Back() + { + if (_hasChanges) + { + var result = ShowMessage( + "The changes you have made will be lost. Do you want to save changes?", + MessageBoxButtons.YesNoCancel, + MessageBoxIcon.Question, + MessageBoxDefaultButton.Button1); + if (result == DialogResult.Cancel) + { + return; + } + + if (result == DialogResult.Yes) + { + this.ApplyChanges(); + } + } + + var service = (INavigationService)this.GetService(typeof(INavigationService)); + service?.NavigateBack(1); + _feature.SelectedItem = this.Rule; + _feature.Refresh(); + } + + private void TxtNameTextChanged(object sender, EventArgs e) + { + this.InformChanges(); + } + + public InboundRule Rule { get; set; } + + private void BtnTestClick(object sender, EventArgs e) + { + var dialog = new RegexTestDialog(this.Module, txtPattern.Text, cbIgnoreCase.Checked, false); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + txtPattern.Text = dialog.Pattern; + cbIgnoreCase.Checked = dialog.IgnoreCase; + } + + protected override bool ApplyChanges() + { + uint status = 0; + uint substatus = 0; + if (cbAction.SelectedIndex == 3) + { + if (!uint.TryParse(txtStatus.Text, out status) || status < 100 || status > 999 + || (status > 299 && status < 308)) + { + ShowMessage( + string.Format( + "The specific code '{0}' is not valid. The status code must be between 100 and 999 and cannot contain values between 300 and 307.", + txtStatus.Text), + MessageBoxButtons.OK, + MessageBoxIcon.Warning, + MessageBoxDefaultButton.Button1); + return false; + } + + if (!uint.TryParse(txtSubstatus.Text, out substatus) || substatus > 999) + { + ShowMessage( + string.Format( + "The specified code '{0}' is not valid. Sub-status codes must be between 0 and 999.", + txtSubstatus.Text), + MessageBoxButtons.OK, + MessageBoxIcon.Warning, + MessageBoxDefaultButton.Button1); + return false; + } + } + + Rule.Name = txtName.Text; + Rule.PatternSyntax = cbType.SelectedIndex; + Rule.StopProcessing = cbStop.Checked; + Rule.PatternUrl = txtPattern.Text; + Rule.IgnoreCase = cbIgnoreCase.Checked; + Rule.Negate = cbMatch.SelectedIndex == 1; + Rule.Type = cbAction.SelectedIndex; + Rule.ActionUrl = cbAction.SelectedIndex == 1 ? txtUrl.Text : txtRedirect.Text; + Rule.AppendQueryString = cbAction.SelectedIndex == 1 ? cbAppend.Checked : cbAppendRedirect.Checked; + Rule.LogRewrittenUrl = cbLog.Checked; + Rule.RedirectType = cbRedirect.SelectedIndex; + Rule.StatusCode = status; + Rule.SubStatusCode = substatus; + Rule.StatusReason = txtReason.Text; + Rule.StatusDescription = txtError.Text; + + if (!this.Rule.ApplyChanges()) + { + return false; + } + + this.ClearChanges(); + txtName.ReadOnly = true; + _feature.AddItem(this.Rule); + return true; + } + + protected override void CancelChanges() + { + this.Rule.CancelChanges(); + this.ClearChanges(); + } + + protected override bool HasChanges + { + get + { + return _hasChanges; + } + } + + protected override bool CanApplyChanges + { + get + { + return !string.IsNullOrWhiteSpace(txtName.Text) && !string.IsNullOrWhiteSpace(txtPattern.Text) + && !string.IsNullOrWhiteSpace(txtUrl.Text); + } + } + + private void InformChanges() + { + if (!_initialized) + { + return; + } + + _hasChanges = true; + this.Refresh(); + } + + private void ClearChanges() + { + _hasChanges = false; + _initialized = false; + this.Refresh(); + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + + protected override void OnRefresh() + { + if (!_hasChanges) + { + cbAction.SelectedIndex = 1; + cbAppend.Checked = true; + cbAppendRedirect.Checked = true; + cbIgnoreCase.Checked = true; + cbMatch.SelectedIndex = 0; + cbStop.Checked = false; + cbType.SelectedIndex = 0; + cbLog.Checked = false; + cbRedirect.SelectedIndex = 0; + cbAny.SelectedIndex = 0; + if (this.Rule != null) + { + txtName.Text = this.Rule.Name; + cbAction.SelectedIndex = (int)this.Rule.Type; + cbAppend.Checked = cbAppendRedirect.Checked = this.Rule.AppendQueryString; + cbIgnoreCase.Checked = this.Rule.IgnoreCase; + txtRedirect.Text = txtUrl.Text = this.Rule.ActionUrl; + cbMatch.SelectedIndex = this.Rule.Negate ? 1 : 0; + cbStop.Checked = this.Rule.StopProcessing; + cbType.SelectedIndex = (int)this.Rule.PatternSyntax; + txtPattern.Text = this.Rule.PatternUrl; + cbLog.Checked = this.Rule.LogRewrittenUrl; + cbRedirect.SelectedIndex = this.Rule.RedirectType; + txtStatus.Text = this.Rule.StatusCode.ToString(); + txtSubstatus.Text = this.Rule.SubStatusCode.ToString(); + txtReason.Text = this.Rule.StatusReason; + txtError.Text = this.Rule.StatusDescription; + + lvVariables.Items.Clear(); + foreach (var variable in this.Rule.ServerVariables) + { + lvVariables.Items.Add(new ServerVariableListViewItem(variable)); + gbVariables.IsExpanded = true; + } + + lvConditions.Items.Clear(); + foreach (var condition in this.Rule.Conditions) + { + lvConditions.Items.Add(new ConditionListViewItem(condition)); + gbConditions.IsExpanded = true; + } + + cbAny.SelectedIndex = (int)this.Rule.LogicalGrouping; + cbTrack.Checked = this.Rule.TrackAllCaptures; + } + + _initialized = true; + } + + this.CbActionSelectedIndexChanged(null, null); + cbStop.Visible = cbAction.SelectedIndex == 0 || cbAction.SelectedIndex == 1; + this.UpdateVariablesButtons(); + this.UpdateConditionsButtons(); + + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + } + + public IModulePage ParentPage { get; set; } + + private void CbActionSelectedIndexChanged(object sender, EventArgs e) + { + gbRewrite.Visible = cbAction.SelectedIndex == 1; + gbRedirect.Visible = cbAction.SelectedIndex == 2; + gbCustom.Visible = cbAction.SelectedIndex == 3; + } + + private void CbAppendRedirectCheckedChanged(object sender, EventArgs e) + { + this.InformChanges(); + } + + private void BtnAddClick(object sender, EventArgs e) + { + var dialog = new AddConditionDialog(this.ServiceProvider, null); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + var newItem = dialog.Item; + this.Rule.Conditions.Add(newItem); + var listViewItem = new ConditionListViewItem(newItem); + lvConditions.Items.Add(listViewItem); + listViewItem.Selected = true; + this.InformChanges(); + } + + private void BtnRemoveClick(object sender, EventArgs e) + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if (dialog.ShowMessage( + "Are you sure that you want to remove the selected condition?", + "Confirm Remove", + MessageBoxButtons.YesNoCancel, + MessageBoxIcon.Question, + MessageBoxDefaultButton.Button1) != DialogResult.Yes) + { + return; + } + + var listViewItem = ((ConditionListViewItem)lvConditions.SelectedItems[0]); + listViewItem.Remove(); + var item = listViewItem.Item; + this.Rule.Conditions.Remove(item); + this.InformChanges(); + } + + private void BtnEditClick(object sender, EventArgs e) + { + var listViewItem = ((ConditionListViewItem)lvConditions.SelectedItems[0]); + var dialog = new AddConditionDialog(this.ServiceProvider, listViewItem.Item); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + listViewItem.Update(); + this.InformChanges(); + } + + private void BtnDownClick(object sender, EventArgs e) + { + var listViewItem = ((ConditionListViewItem)lvConditions.SelectedItems[0]); + var index = listViewItem.Index; + + var item = listViewItem.Item; + this.Rule.Conditions.RemoveAt(index); + listViewItem.Remove(); + + this.Rule.Conditions.Insert(index + 1, item); + lvConditions.Items.Insert(index + 1, listViewItem); + listViewItem.Selected = true; + this.InformChanges(); + } + + private void BtnUpClick(object sender, EventArgs e) + { + var listViewItem = ((ConditionListViewItem)lvConditions.SelectedItems[0]); + var index = listViewItem.Index; + + var item = listViewItem.Item; + this.Rule.Conditions.RemoveAt(index); + listViewItem.Remove(); + + this.Rule.Conditions.Insert(index - 1, item); + lvConditions.Items.Insert(index - 1, listViewItem); + listViewItem.Selected = true; + this.InformChanges(); + } + + private void UpdateConditionsButtons() + { + var hasSelection = lvConditions.SelectedItems.Count > 0; + btnRemove.Enabled = btnEdit.Enabled = hasSelection; + btnDown.Enabled = hasSelection + && lvConditions.SelectedItems[0].Index < lvConditions.Items.Count - 1; + btnUp.Enabled = hasSelection && lvConditions.SelectedItems[0].Index > 0; + } + + private void BtnVarAddClick(object sender, EventArgs e) + { + var dialog = new AddServerVariableDialog(this.ServiceProvider, null); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + var newItem = dialog.Item; + this.Rule.ServerVariables.Add(newItem); + var listViewItem = new ServerVariableListViewItem(newItem); + lvVariables.Items.Add(listViewItem); + listViewItem.Selected = true; + this.InformChanges(); + } + + private void BtnVarRemoveClick(object sender, EventArgs e) + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if (dialog.ShowMessage( + "Are you sure that you want to remove the selected entry?", + "Confirm Remove", + MessageBoxButtons.YesNoCancel, + MessageBoxIcon.Question, + MessageBoxDefaultButton.Button1) != DialogResult.Yes) + { + return; + } + + var listViewItem = ((ServerVariableListViewItem)lvVariables.SelectedItems[0]); + listViewItem.Remove(); + var item = listViewItem.Item; + this.Rule.ServerVariables.Remove(item); + this.InformChanges(); + } + + private void BtnVarEditClick(object sender, EventArgs e) + { + var listViewItem = ((ServerVariableListViewItem)lvVariables.SelectedItems[0]); + var dialog = new AddServerVariableDialog(this.ServiceProvider, listViewItem.Item); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + listViewItem.Update(); + this.InformChanges(); + } + + private void BtnVarDownClick(object sender, EventArgs e) + { + var listViewItem = ((ServerVariableListViewItem)lvVariables.SelectedItems[0]); + var index = listViewItem.Index; + + var item = listViewItem.Item; + this.Rule.ServerVariables.RemoveAt(index); + listViewItem.Remove(); + + this.Rule.ServerVariables.Insert(index + 1, item); + lvVariables.Items.Insert(index + 1, listViewItem); + listViewItem.Selected = true; + this.InformChanges(); + } + + private void BtnVarUpClick(object sender, EventArgs e) + { + var listViewItem = ((ServerVariableListViewItem)lvVariables.SelectedItems[0]); + var index = listViewItem.Index; + + var item = listViewItem.Item; + this.Rule.ServerVariables.RemoveAt(index); + listViewItem.Remove(); + + this.Rule.ServerVariables.Insert(index - 1, item); + lvVariables.Items.Insert(index - 1, listViewItem); + listViewItem.Selected = true; + this.InformChanges(); + } + + private void UpdateVariablesButtons() + { + var hasSelection = lvVariables.SelectedItems.Count > 0; + btnVarRemove.Enabled = btnVarEdit.Enabled = hasSelection; + btnVarDown.Enabled = hasSelection + && lvVariables.SelectedItems[0].Index < lvVariables.Items.Count - 1; + btnVarUp.Enabled = hasSelection && lvVariables.SelectedItems[0].Index > 0; + } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/InboundRulePage.resx b/JexusManager.Features.Rewrite/Inbound/InboundRulePage.resx new file mode 100644 index 00000000..950be5d2 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/InboundRulePage.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 143, 17 + + + 17, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/Inbound/MapItem.cs b/JexusManager.Features.Rewrite/Inbound/MapItem.cs new file mode 100644 index 00000000..4beb2ca5 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/MapItem.cs @@ -0,0 +1,70 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Rewrite.Inbound +{ + using System.Collections.Generic; + + using Microsoft.Web.Administration; + + internal class MapItem : IItem + { + public ConfigurationElement Element { get; set; } + + public bool Match(MapItem other) + { + return other != null && other.Name == Name; + } + + private readonly MapsFeature _feature; + + public string Name { get; internal set; } + + public string Flag { get; set; } + + public string DefaultValue { get; set; } + + public MapSettingsUpdatedEventHandler MapSettingsUpdated { get; set; } + + public List Items { get; private set; } + + public MapRule SelectedItem { get; set; } + + public MapItem(ConfigurationElement element, MapsFeature feature) + { + this.Element = element; + _feature = feature; + this.Flag = element == null || element.IsLocallyStored ? "Local" : "Inherited"; + this.Name = element == null ? string.Empty : (string)element["name"]; + this.Items = new List(); + if (element != null) + { + var collection = element.GetCollection(); + foreach (ConfigurationElement rule in collection) + { + this.Items.Add(new MapRule(rule, _feature)); + } + } + } + + public void Apply() + { + Element["name"] = Name; + Element["defaultValue"] = DefaultValue; + Element["ignoreCase"] = IgnoreCase; + } + + internal protected void OnRewriteSettingsSaved() + { + this.MapSettingsUpdated?.Invoke(); + } + + public bool IgnoreCase { get; set; } + + public bool Equals(MapItem other) + { + return Match(other) && other.DefaultValue == DefaultValue && other.IgnoreCase == IgnoreCase; + } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/MapPage.Designer.cs b/JexusManager.Features.Rewrite/Inbound/MapPage.Designer.cs new file mode 100644 index 00000000..51b19490 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/MapPage.Designer.cs @@ -0,0 +1,334 @@ +namespace JexusManager.Features.Rewrite.Inbound +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class MapPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.panel2 = new System.Windows.Forms.Panel(); + this.tableLayoutPanel2 = new System.Windows.Forms.TableLayoutPanel(); + this.panel3 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chOriginal = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chNew = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.toolStrip2 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel3 = new System.Windows.Forms.ToolStripLabel(); + this.cbGroup = new System.Windows.Forms.ToolStripComboBox(); + this.panel4 = new System.Windows.Forms.Panel(); + this.txtName = new System.Windows.Forms.TextBox(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.tableLayoutPanel2.SuspendLayout(); + this.panel3.SuspendLayout(); + this.toolStrip2.SuspendLayout(); + this.panel4.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 7; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.SplitContainer1SplitterMoved); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.tableLayoutPanel2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 9; + // + // tableLayoutPanel2 + // + this.tableLayoutPanel2.ColumnCount = 1; + this.tableLayoutPanel2.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.Controls.Add(this.panel3, 0, 1); + this.tableLayoutPanel2.Controls.Add(this.panel4, 0, 0); + this.tableLayoutPanel2.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel2.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel2.Name = "tableLayoutPanel2"; + this.tableLayoutPanel2.RowCount = 3; + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 60F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel2.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 20F)); + this.tableLayoutPanel2.Size = new System.Drawing.Size(560, 540); + this.tableLayoutPanel2.TabIndex = 10; + // + // panel3 + // + this.panel3.Controls.Add(this.listView1); + this.panel3.Controls.Add(this.toolStrip2); + this.panel3.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel3.Location = new System.Drawing.Point(3, 63); + this.panel3.Name = "panel3"; + this.panel3.Size = new System.Drawing.Size(554, 454); + this.panel3.TabIndex = 10; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chOriginal, + this.chNew}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 25); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(554, 429); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListView1SelectedIndexChanged); + this.listView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ListView1KeyDown); + // + // chOriginal + // + this.chOriginal.Text = "Original Value"; + this.chOriginal.Width = 200; + // + // chNew + // + this.chNew.Text = "New Value"; + this.chNew.Width = 200; + // + // toolStrip2 + // + this.toolStrip2.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel3, + this.cbGroup}); + this.toolStrip2.Location = new System.Drawing.Point(0, 0); + this.toolStrip2.Name = "toolStrip2"; + this.toolStrip2.Size = new System.Drawing.Size(554, 25); + this.toolStrip2.TabIndex = 3; + this.toolStrip2.Text = "toolStrip2"; + // + // toolStripLabel3 + // + this.toolStripLabel3.Name = "toolStripLabel3"; + this.toolStripLabel3.Size = new System.Drawing.Size(59, 22); + this.toolStripLabel3.Text = "Group by:"; + // + // cbGroup + // + this.cbGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbGroup.Items.AddRange(new object[] { + "No Grouping", + "Category", + "Area"}); + this.cbGroup.Name = "cbGroup"; + this.cbGroup.Size = new System.Drawing.Size(121, 25); + // + // panel4 + // + this.panel4.Controls.Add(this.txtName); + this.panel4.Controls.Add(this.label2); + this.panel4.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel4.Location = new System.Drawing.Point(3, 3); + this.panel4.Name = "panel4"; + this.panel4.Size = new System.Drawing.Size(554, 54); + this.panel4.TabIndex = 11; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(16, 26); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(177, 20); + this.txtName.TabIndex = 1; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(13, 10); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(98, 13); + this.label2.TabIndex = 0; + this.label2.Text = "Rewrite map name:"; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 8; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(175, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Edit Rewrite Map"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // MapPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "MapPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.tableLayoutPanel2.ResumeLayout(false); + this.panel3.ResumeLayout(false); + this.panel3.PerformLayout(); + this.toolStrip2.ResumeLayout(false); + this.toolStrip2.PerformLayout(); + this.panel4.ResumeLayout(false); + this.panel4.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + private ContextMenuStrip cmsActionPanel; + private SplitContainer splitContainer1; + private Panel panel2; + private ListView listView1; + private ColumnHeader chOriginal; + private ColumnHeader chNew; + private ToolStrip toolStrip2; + private ToolStripLabel toolStripLabel3; + private ToolStripComboBox cbGroup; + private PictureBox pictureBox1; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private TableLayoutPanel tableLayoutPanel2; + private Panel panel3; + private Panel panel4; + private TextBox txtName; + private Label label2; + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/MapPage.cs b/JexusManager.Features.Rewrite/Inbound/MapPage.cs new file mode 100644 index 00000000..72101947 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/MapPage.cs @@ -0,0 +1,250 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// -------------------------------------------------------------------------------------------------------------------- +// +// +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace JexusManager.Features.Rewrite.Inbound +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class MapPage : ModuleListPage, IModuleChildPage + { + private sealed class PageTaskList : DefaultTaskList + { + private readonly MapPage _owner; + + public PageTaskList(MapPage owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("Add", "Add Mapping Entry...", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Set", "Edit Map Settings...", string.Empty).SetUsage()); + if (_owner.Map.SelectedItem != null) + { + //result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Edit", "Edit Mapping Entry...", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(GetBackTaskItem("BackMore", "Back to Rewrite Maps")); + result.Add(GetBackTaskItem("Back", "Back to Rules")); + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(HelpTaskItem); + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void ShowHelp() + { + _owner.ShowHelp(); + } + + [Obfuscation(Exclude = true)] + public void Back() + { + _owner.Back(); + } + + [Obfuscation(Exclude = true)] + public void BackMore() + { + _owner.BackMore(); + } + + [Obfuscation(Exclude = true)] + public void Add() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void Edit() + { + _owner.Edit(); + } + + [Obfuscation(Exclude = true)] + public void Set() + { + _owner.Set(); + } + } + + private sealed class MapListViewItem : ListViewItem + { + public MapRule Item { get; } + private readonly MapPage _page; + + public MapListViewItem(MapRule item, MapPage page) + : base(item.Original) + { + this.Item = item; + _page = page; + this.SubItems.Add(new ListViewSubItem(this, item.New)); + } + } + + private TaskList _taskList; + private MapsFeature _feature; + + public MapPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var info = (Tuple)navigationData; + + // TODO: pictureBox1.Image = service.Scope.GetImage(); + + _feature = info.Item1; + this.Map = info.Item2; + txtName.ReadOnly = this.Map != null; + if (this.Map != null) + { + this.Map.MapSettingsUpdated = this.InitializeListPage; + txtName.Text = this.Map.Name; + } + + this.Map?.OnRewriteSettingsSaved(); + } + + public MapItem Map { get; set; } + + protected override void InitializeListPage() + { + listView1.Items.Clear(); + foreach (var file in this.Map.Items) + { + listView1.Items.Add(new MapListViewItem(file, this)); + } + + if (this.Map.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (MapListViewItem item in listView1.Items) + { + if (item.Item == this.Map.SelectedItem) + { + item.Selected = true; + } + } + } + + private void ListView1SelectedIndexChanged(object sender, EventArgs e) + { + this.Map.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((MapListViewItem)listView1.SelectedItems[0]).Item + : null; + this.Refresh(); + } + + private void ListView1KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Delete) + { + _feature.Remove(); + } + } + + protected override void Refresh() + { + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + protected override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkID=130425&clcid=0x409"); + return true; + } + + private void SplitContainer1SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + private void Back() + { + var service = (INavigationService)GetService(typeof(INavigationService)); + service?.NavigateBack(2); + _feature.SelectedItem = this.Map; + _feature.OnRewriteSettingsSaved(); + } + + private void BackMore() + { + var service = (INavigationService)GetService(typeof(INavigationService)); + service?.NavigateBack(1); + } + + public void Add() + { + _feature.AddRule(); + } + + public void Remove() + { + _feature.RemoveRule(); + } + + private void Edit() + { + _feature.EditRule(); + } + + private void Set() + { + _feature.Set(); + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + + public IModulePage ParentPage { get; set; } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/MapPage.resx b/JexusManager.Features.Rewrite/Inbound/MapPage.resx new file mode 100644 index 00000000..2e9f734f --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/MapPage.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 143, 17 + + + 556, 56 + + + 661, 56 + + \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/Inbound/MapRule.cs b/JexusManager.Features.Rewrite/Inbound/MapRule.cs new file mode 100644 index 00000000..91d380c6 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/MapRule.cs @@ -0,0 +1,50 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Rewrite.Inbound +{ + using Microsoft.Web.Administration; + + internal class MapRule : IItem + { + public ConfigurationElement Element { get; set; } + + public bool Match(MapRule other) + { + return other != null && other.Original == Original; + } + + private MapsFeature _feature; + + public MapRule(ConfigurationElement element, MapsFeature feature) + { + this.Element = element; + _feature = feature; + if (element != null) + { + this.Original = (string)element["key"]; + this.New = (string)element["value"]; + } + + this.Flag = element == null || element.IsLocallyStored ? "Local" : "Inherited"; + } + + public string Original { get; set; } + + public string New { get; set; } + + public string Flag { get; set; } + + public void Apply() + { + Element["key"] = Original; + Element["value"] = New; + } + + public bool Equals(MapRule other) + { + return Match(other) && other.New == New; + } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/MapSettingsDialog.Designer.cs b/JexusManager.Features.Rewrite/Inbound/MapSettingsDialog.Designer.cs new file mode 100644 index 00000000..33b1572e --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/MapSettingsDialog.Designer.cs @@ -0,0 +1,136 @@ +namespace JexusManager.Features.Rewrite.Inbound +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class MapSettingsDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnOK = new System.Windows.Forms.Button(); + this.btnCancel = new System.Windows.Forms.Button(); + this.cbIgnore = new System.Windows.Forms.CheckBox(); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.txtName = new System.Windows.Forms.TextBox(); + this.txtDefaultValue = new System.Windows.Forms.TextBox(); + this.SuspendLayout(); + // + // btnOK + // + this.btnOK.Location = new System.Drawing.Point(216, 176); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 0; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(312, 176); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 1; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // cbIgnore + // + this.cbIgnore.AutoSize = true; + this.cbIgnore.Location = new System.Drawing.Point(15, 129); + this.cbIgnore.Name = "cbIgnore"; + this.cbIgnore.Size = new System.Drawing.Size(218, 17); + this.cbIgnore.TabIndex = 2; + this.cbIgnore.Text = "Ignore case when performing key lookup"; + this.cbIgnore.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 9); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(98, 13); + this.label1.TabIndex = 3; + this.label1.Text = "Rewrite map name:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(12, 69); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(282, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Default value to use when the key is not found in the map:"; + // + // txtName + // + this.txtName.Location = new System.Drawing.Point(15, 25); + this.txtName.Name = "txtName"; + this.txtName.Size = new System.Drawing.Size(392, 20); + this.txtName.TabIndex = 5; + // + // txtDefaultValue + // + this.txtDefaultValue.Location = new System.Drawing.Point(15, 85); + this.txtDefaultValue.Name = "txtDefaultValue"; + this.txtDefaultValue.Size = new System.Drawing.Size(392, 20); + this.txtDefaultValue.TabIndex = 6; + // + // MapSettingsDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(419, 211); + this.Controls.Add(this.txtDefaultValue); + this.Controls.Add(this.txtName); + this.Controls.Add(this.label2); + this.Controls.Add(this.label1); + this.Controls.Add(this.cbIgnore); + this.Controls.Add(this.btnCancel); + this.Controls.Add(this.btnOK); + this.Name = "MapSettingsDialog"; + this.Text = "Edit Rewrite Map"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.MapSettingsDialogHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnOK; + private Button btnCancel; + private CheckBox cbIgnore; + private Label label1; + private Label label2; + private TextBox txtName; + private TextBox txtDefaultValue; + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/MapSettingsDialog.cs b/JexusManager.Features.Rewrite/Inbound/MapSettingsDialog.cs new file mode 100644 index 00000000..c53323b8 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/MapSettingsDialog.cs @@ -0,0 +1,55 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// -------------------------------------------------------------------------------------------------------------------- +// +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace JexusManager.Features.Rewrite.Inbound +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Microsoft.Web.Management.Client.Win32; + + internal partial class MapSettingsDialog : DialogForm + { + public MapSettingsDialog(IServiceProvider serviceProvider, MapItem item) + : base(serviceProvider) + { + InitializeComponent(); + if (item != null) + { + txtName.Text = item.Name; + txtName.ReadOnly = true; + txtDefaultValue.Text = item.DefaultValue; + cbIgnore.Checked = item.IgnoreCase; + } + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + item.Name = txtName.Text; + item.DefaultValue = txtDefaultValue.Text; + item.IgnoreCase = cbIgnore.Checked; + item.Apply(); + DialogResult = DialogResult.OK; + })); + } + + private void MapSettingsDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkID=130406&clcid=0x409"); + } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/MapSettingsDialog.resx b/JexusManager.Features.Rewrite/Inbound/MapSettingsDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/MapSettingsDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/Inbound/MapSettingsUpdatedEventHandler.cs b/JexusManager.Features.Rewrite/Inbound/MapSettingsUpdatedEventHandler.cs new file mode 100644 index 00000000..e8fa61cb --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/MapSettingsUpdatedEventHandler.cs @@ -0,0 +1,8 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Rewrite.Inbound +{ + internal delegate void MapSettingsUpdatedEventHandler(); +} \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/Inbound/MapsFeature.cs b/JexusManager.Features.Rewrite/Inbound/MapsFeature.cs new file mode 100644 index 00000000..01825d95 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/MapsFeature.cs @@ -0,0 +1,303 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// -------------------------------------------------------------------------------------------------------------------- +// +// +// +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace JexusManager.Features.Rewrite.Inbound +{ + using System; + using System.Collections; + using System.Collections.Generic; + using System.Diagnostics; + using System.Reflection; + using System.Resources; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Administration; + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + using Module = Microsoft.Web.Management.Client.Module; + + /// + /// Description of DefaultDocumentFeature. + /// + internal class MapsFeature + { + private sealed class FeatureTaskList : DefaultTaskList + { + private readonly MapsFeature _owner; + + public FeatureTaskList(MapsFeature owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + var result = new ArrayList(); + result.Add(new MethodTaskItem("Add", "Add Rewrite Map...", string.Empty).SetUsage()); + if (_owner.SelectedItem != null) + { + result.Add(new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage()); + result.Add(new MethodTaskItem("Edit", "Edit Rewrite Map", string.Empty).SetUsage()); + result.Add(RemoveTaskItem); + } + + return result.ToArray(typeof(TaskItem)) as TaskItem[]; + } + + [Obfuscation(Exclude = true)] + public void Add() + { + _owner.Add(); + } + + [Obfuscation(Exclude = true)] + public override void Remove() + { + _owner.Remove(); + } + + [Obfuscation(Exclude = true)] + public void Edit() + { + _owner.Edit(); + } + } + + public MapsFeature(Module module) + { + this.Module = module; + } + + protected static readonly Version FxVersion10 = new Version("1.0"); + protected static readonly Version FxVersion11 = new Version("1.1"); + protected static readonly Version FxVersion20 = new Version("2.0"); + protected static readonly Version FxVersionNotRequired = new Version(); + private FeatureTaskList _taskList; + + protected void DisplayErrorMessage(Exception ex, ResourceManager resourceManager) + { + var service = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + service.ShowError(ex, resourceManager.GetString("General"), string.Empty, false); + } + + protected object GetService(Type type) + { + return (this.Module as IServiceProvider).GetService(type); + } + + public TaskList GetTaskList() + { + return _taskList ?? (_taskList = new FeatureTaskList(this)); + } + + public void Load() + { + this.Items = new List(); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var rulesSection = service.GetSection("system.webServer/rewrite/rewriteMaps"); + ConfigurationElementCollection rulesCollection = rulesSection.GetCollection(); + foreach (ConfigurationElement ruleElement in rulesCollection) + { + var node = new MapItem(ruleElement, this); + this.Items.Add(node); + } + + this.OnRewriteSettingsSaved(); + } + + public List Items { get; set; } + + public void Add() + { + var dialog = new AddMapsDialog(this.Module, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + var newItem = dialog.Item; + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var rulesSection = service.GetSection("system.webServer/rewrite/rewriteMaps"); + ConfigurationElementCollection rulesCollection = rulesSection.GetCollection(); + + if (this.SelectedItem != newItem) + { + this.Items.Add(newItem); + this.SelectedItem = newItem; + } + else if (newItem.Flag != "Local") + { + rulesCollection.Remove(newItem.Element); + newItem.Flag = "Local"; + } + + newItem.AppendTo(rulesCollection); + service.ServerManager.CommitChanges(); + this.OnRewriteSettingsSaved(); + + this.Edit(); + } + + public void AddRule() + { + var dialog = new AddMapDialog(this.Module, null, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + var newItem = dialog.Item; + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + ConfigurationElementCollection rulesCollection = this.SelectedItem.Element.GetCollection(); + + if (this.SelectedItem.SelectedItem != newItem) + { + this.SelectedItem.Items.Add(newItem); + this.SelectedItem.SelectedItem = newItem; + } + else if (newItem.Flag != "Local") + { + rulesCollection.Remove(newItem.Element); + newItem.Flag = "Local"; + } + + newItem.AppendTo(rulesCollection); + service.ServerManager.CommitChanges(); + this.OnRewriteSettingsSaved(); + this.SelectedItem.OnRewriteSettingsSaved(); + } + + public void Remove() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected entry?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + this.Items.Remove(this.SelectedItem); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + var section = service.GetSection("system.webServer/rewrite/rewriteMaps"); + ConfigurationElementCollection collection = section.GetCollection(); + collection.Remove(this.SelectedItem.Element); + service.ServerManager.CommitChanges(); + + this.SelectedItem = null; + this.OnRewriteSettingsSaved(); + } + + public void RemoveRule() + { + var dialog = (IManagementUIService)this.GetService(typeof(IManagementUIService)); + if ( + dialog.ShowMessage("Are you sure that you want to remove the selected entry?", "Confirm Remove", + MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1) != + DialogResult.Yes) + { + return; + } + + this.SelectedItem.Items.Remove(this.SelectedItem.SelectedItem); + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + ConfigurationElementCollection collection = this.SelectedItem.Element.GetCollection(); + collection.Remove(this.SelectedItem.SelectedItem.Element); + service.ServerManager.CommitChanges(); + + this.SelectedItem.SelectedItem = null; + this.OnRewriteSettingsSaved(); + this.SelectedItem.OnRewriteSettingsSaved(); + } + + internal protected void OnRewriteSettingsSaved() + { + this.RewriteSettingsUpdated?.Invoke(); + } + + public virtual bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkID=130403&clcid=0x409"); + return false; + } + + internal void Edit() + { + var service = (INavigationService)this.GetService(typeof(INavigationService)); + service.Navigate(null, null, typeof(MapPage), new Tuple(this, this.SelectedItem)); + this.OnRewriteSettingsSaved(); + } + + public void EditRule() + { + var dialog = new AddMapDialog(this.Module, this.SelectedItem.SelectedItem, this); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + var newItem = dialog.Item; + var service = (IConfigurationService)this.GetService(typeof(IConfigurationService)); + ConfigurationElementCollection rulesCollection = this.SelectedItem.Element.GetCollection(); + + if (this.SelectedItem.SelectedItem != newItem) + { + this.SelectedItem.Items.Add(newItem); + this.SelectedItem.SelectedItem = newItem; + } + else if (newItem.Flag != "Local") + { + rulesCollection.Remove(newItem.Element); + newItem.Flag = "Local"; + } + + newItem.AppendTo(rulesCollection); + service.ServerManager.CommitChanges(); + this.OnRewriteSettingsSaved(); + this.SelectedItem.OnRewriteSettingsSaved(); + } + + public MapItem SelectedItem { get; internal set; } + public bool CanRevert { get; private set; } + + public RewriteSettingsSavedEventHandler RewriteSettingsUpdated { get; set; } + public string Description { get; } + + public virtual bool IsFeatureEnabled + { + get { return true; } + } + + public virtual Version MinimumFrameworkVersion + { + get { return FxVersionNotRequired; } + } + + public Module Module { get; } + public string Name { get; } + + public void Set() + { + var dialog = new MapSettingsDialog(this.Module, this.SelectedItem); + if (dialog.ShowDialog() != DialogResult.OK) + { + return; + } + + this.OnRewriteSettingsSaved(); + } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/MapsPage.Designer.cs b/JexusManager.Features.Rewrite/Inbound/MapsPage.Designer.cs new file mode 100644 index 00000000..2ec2dd3b --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/MapsPage.Designer.cs @@ -0,0 +1,275 @@ +namespace JexusManager.Features.Rewrite.Inbound +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class MapsPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chNumber = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chValue = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.toolStrip2 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel3 = new System.Windows.Forms.ToolStripLabel(); + this.cbGroup = new System.Windows.Forms.ToolStripComboBox(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.toolStrip2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 7; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.SplitContainer1SplitterMoved); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.toolStrip2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 9; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chName, + this.chNumber, + this.chValue}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 25); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 515); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListView1SelectedIndexChanged); + this.listView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ListView1KeyDown); + this.listView1.MouseDoubleClick += new System.Windows.Forms.MouseEventHandler(this.ListView1MouseDoubleClick); + // + // chName + // + this.chName.Text = "Name"; + this.chName.Width = 200; + // + // chNumber + // + this.chNumber.Text = "Number of Items"; + this.chNumber.Width = 200; + // + // chValue + // + this.chValue.Text = "Default Value"; + this.chValue.Width = 200; + // + // toolStrip2 + // + this.toolStrip2.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel3, + this.cbGroup}); + this.toolStrip2.Location = new System.Drawing.Point(0, 0); + this.toolStrip2.Name = "toolStrip2"; + this.toolStrip2.Size = new System.Drawing.Size(560, 25); + this.toolStrip2.TabIndex = 3; + this.toolStrip2.Text = "toolStrip2"; + // + // toolStripLabel3 + // + this.toolStripLabel3.Name = "toolStripLabel3"; + this.toolStripLabel3.Size = new System.Drawing.Size(59, 22); + this.toolStripLabel3.Text = "Group by:"; + // + // cbGroup + // + this.cbGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbGroup.Items.AddRange(new object[] { + "No Grouping", + "Category", + "Area"}); + this.cbGroup.Name = "cbGroup"; + this.cbGroup.Size = new System.Drawing.Size(121, 25); + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 8; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(191, 25); + this.label3.TabIndex = 2; + this.label3.Text = "URL Rewrite Maps"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // MapsPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "MapsPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.toolStrip2.ResumeLayout(false); + this.toolStrip2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + private ContextMenuStrip cmsActionPanel; + private SplitContainer splitContainer1; + private Panel panel2; + private ListView listView1; + private ColumnHeader chName; + private ColumnHeader chNumber; + private ToolStrip toolStrip2; + private ToolStripLabel toolStripLabel3; + private ToolStripComboBox cbGroup; + private PictureBox pictureBox1; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + private ColumnHeader chValue; + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/MapsPage.cs b/JexusManager.Features.Rewrite/Inbound/MapsPage.cs new file mode 100644 index 00000000..796a2bcb --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/MapsPage.cs @@ -0,0 +1,180 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// -------------------------------------------------------------------------------------------------------------------- +// +// +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace JexusManager.Features.Rewrite.Inbound +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class MapsPage : ModuleListPage, IModuleChildPage + { + private sealed class PageTaskList : DefaultTaskList + { + private readonly MapsPage _owner; + + public PageTaskList(MapsPage owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + return new TaskItem[] + { + GetBackTaskItem("Back", "Back to Rules"), + new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage(), + HelpTaskItem + }; + } + + [Obfuscation(Exclude = true)] + public void ShowHelp() + { + _owner.ShowHelp(); + } + + [Obfuscation(Exclude = true)] + public void Back() + { + _owner.Back(); + } + } + + private sealed class MapsListViewItem : ListViewItem + { + public MapItem Item { get; } + private readonly MapsPage _page; + + public MapsListViewItem(MapItem item, MapsPage page) + : base(item.Name) + { + this.Item = item; + _page = page; + this.SubItems.Add(new ListViewSubItem(this, item.Items.Count.ToString())); + this.SubItems.Add(new ListViewSubItem(this, item.DefaultValue)); + } + } + + private TaskList _taskList; + private MapsFeature _feature; + + public MapsPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new MapsFeature(Module); + _feature.RewriteSettingsUpdated = this.InitializeListPage; + _feature.Load(); + } + + protected override void InitializeListPage() + { + listView1.Items.Clear(); + foreach (var file in _feature.Items) + { + listView1.Items.Add(new MapsListViewItem(file, this)); + } + + if (_feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (MapsListViewItem item in listView1.Items) + { + if (item.Item == _feature.SelectedItem) + { + item.Selected = true; + } + } + } + + private void ListView1SelectedIndexChanged(object sender, EventArgs e) + { + _feature.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((MapsListViewItem)listView1.SelectedItems[0]).Item + : null; + this.Refresh(); + } + + private void ListView1KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Delete) + { + _feature.Remove(); + } + } + + private void ListView1MouseDoubleClick(object sender, MouseEventArgs e) + { + _feature.Edit(); + } + + protected override void Refresh() + { + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + protected override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkID=130425&clcid=0x409"); + return true; + } + + private void SplitContainer1SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + private void Back() + { + var service = (INavigationService)GetService(typeof(INavigationService)); + service?.NavigateBack(1); + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + + public IModulePage ParentPage { get; set; } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/MapsPage.resx b/JexusManager.Features.Rewrite/Inbound/MapsPage.resx new file mode 100644 index 00000000..2e9f734f --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/MapsPage.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 143, 17 + + + 556, 56 + + + 661, 56 + + \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/Inbound/ServerVariableItem.cs b/JexusManager.Features.Rewrite/Inbound/ServerVariableItem.cs new file mode 100644 index 00000000..384c20c7 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/ServerVariableItem.cs @@ -0,0 +1,47 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Rewrite.Inbound +{ + using Microsoft.Web.Administration; + + public class ServerVariableItem + { + public ConfigurationElement Element { get; set; } + + public ServerVariableItem(ConfigurationElement element) + { + this.Element = element; + if (element == null) + { + this.Replace = true; + return; + } + + this.Name = (string)element["name"]; + this.Value = (string)element["value"]; + this.Replace = (bool)element["replace"]; + } + + public bool Replace { get; set; } + + public string Value { get; set; } + + public string Name { get; set; } + + public void Apply() + { + Element["name"] = Name; + Element["value"] = Value; + Element["replace"] = Replace; + } + + public void AppendTo(ConfigurationElementCollection variableCollection) + { + Element = variableCollection.CreateElement(); + Apply(); + variableCollection.Add(Element); + } + } +} \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/Inbound/ServerVariablesPage.Designer.cs b/JexusManager.Features.Rewrite/Inbound/ServerVariablesPage.Designer.cs new file mode 100644 index 00000000..4f499ba5 --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/ServerVariablesPage.Designer.cs @@ -0,0 +1,281 @@ +namespace JexusManager.Features.Rewrite.Inbound +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class ServerVariablesPage + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (this.components != null)) + { + this.components.Dispose(); + } + base.Dispose(disposing); + } + + #region Component Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.cmsActionPanel = new System.Windows.Forms.ContextMenuStrip(this.components); + this.splitContainer1 = new System.Windows.Forms.SplitContainer(); + this.panel2 = new System.Windows.Forms.Panel(); + this.listView1 = new System.Windows.Forms.ListView(); + this.chName = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.chEntry = ((System.Windows.Forms.ColumnHeader)(new System.Windows.Forms.ColumnHeader())); + this.toolStrip2 = new System.Windows.Forms.ToolStrip(); + this.toolStripLabel3 = new System.Windows.Forms.ToolStripLabel(); + this.cbGroup = new System.Windows.Forms.ToolStripComboBox(); + this.label2 = new System.Windows.Forms.Label(); + this.pictureBox1 = new System.Windows.Forms.PictureBox(); + this.label3 = new System.Windows.Forms.Label(); + this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel(); + this.panel1 = new System.Windows.Forms.Panel(); + this.label1 = new System.Windows.Forms.Label(); + this.tsActionPanel = new System.Windows.Forms.ToolStrip(); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).BeginInit(); + this.splitContainer1.Panel1.SuspendLayout(); + this.splitContainer1.Panel2.SuspendLayout(); + this.splitContainer1.SuspendLayout(); + this.panel2.SuspendLayout(); + this.toolStrip2.SuspendLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).BeginInit(); + this.tableLayoutPanel1.SuspendLayout(); + this.panel1.SuspendLayout(); + this.SuspendLayout(); + // + // cmsActionPanel + // + this.cmsActionPanel.Name = "cmsActionPanel"; + this.cmsActionPanel.Size = new System.Drawing.Size(61, 4); + // + // splitContainer1 + // + this.splitContainer1.Dock = System.Windows.Forms.DockStyle.Fill; + this.splitContainer1.Location = new System.Drawing.Point(0, 0); + this.splitContainer1.Name = "splitContainer1"; + // + // splitContainer1.Panel1 + // + this.splitContainer1.Panel1.BackColor = System.Drawing.Color.White; + this.splitContainer1.Panel1.ContextMenuStrip = this.cmsActionPanel; + this.splitContainer1.Panel1.Controls.Add(this.panel2); + this.splitContainer1.Panel1.Controls.Add(this.pictureBox1); + this.splitContainer1.Panel1.Controls.Add(this.label3); + // + // splitContainer1.Panel2 + // + this.splitContainer1.Panel2.Controls.Add(this.tableLayoutPanel1); + this.splitContainer1.Panel2MinSize = 200; + this.splitContainer1.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.SplitterDistance = 580; + this.splitContainer1.TabIndex = 7; + this.splitContainer1.SplitterMoved += new System.Windows.Forms.SplitterEventHandler(this.SplitContainer1SplitterMoved); + // + // panel2 + // + this.panel2.Anchor = ((System.Windows.Forms.AnchorStyles)((((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom) + | System.Windows.Forms.AnchorStyles.Left) + | System.Windows.Forms.AnchorStyles.Right))); + this.panel2.Controls.Add(this.listView1); + this.panel2.Controls.Add(this.toolStrip2); + this.panel2.Controls.Add(this.label2); + this.panel2.Location = new System.Drawing.Point(10, 50); + this.panel2.Name = "panel2"; + this.panel2.Size = new System.Drawing.Size(560, 540); + this.panel2.TabIndex = 9; + // + // listView1 + // + this.listView1.Columns.AddRange(new System.Windows.Forms.ColumnHeader[] { + this.chName, + this.chEntry}); + this.listView1.Dock = System.Windows.Forms.DockStyle.Fill; + this.listView1.FullRowSelect = true; + this.listView1.HideSelection = false; + this.listView1.Location = new System.Drawing.Point(0, 38); + this.listView1.Margin = new System.Windows.Forms.Padding(5); + this.listView1.MultiSelect = false; + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(560, 502); + this.listView1.TabIndex = 0; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.Details; + this.listView1.SelectedIndexChanged += new System.EventHandler(this.ListView1SelectedIndexChanged); + this.listView1.KeyDown += new System.Windows.Forms.KeyEventHandler(this.ListView1KeyDown); + // + // chName + // + this.chName.Text = "Name"; + this.chName.Width = 300; + // + // chEntry + // + this.chEntry.Text = "Entry Type"; + this.chEntry.Width = 300; + // + // toolStrip2 + // + this.toolStrip2.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip2.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.toolStripLabel3, + this.cbGroup}); + this.toolStrip2.Location = new System.Drawing.Point(0, 13); + this.toolStrip2.Name = "toolStrip2"; + this.toolStrip2.Size = new System.Drawing.Size(560, 25); + this.toolStrip2.TabIndex = 3; + this.toolStrip2.Text = "toolStrip2"; + // + // toolStripLabel3 + // + this.toolStripLabel3.Name = "toolStripLabel3"; + this.toolStripLabel3.Size = new System.Drawing.Size(59, 22); + this.toolStripLabel3.Text = "Group by:"; + // + // cbGroup + // + this.cbGroup.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbGroup.Items.AddRange(new object[] { + "No Grouping", + "Category", + "Area"}); + this.cbGroup.Name = "cbGroup"; + this.cbGroup.Size = new System.Drawing.Size(121, 25); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Dock = System.Windows.Forms.DockStyle.Top; + this.label2.Location = new System.Drawing.Point(0, 0); + this.label2.Margin = new System.Windows.Forms.Padding(5); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(490, 13); + this.label2.TabIndex = 1; + this.label2.Text = "Use this feature to manage the list of server variables that you can set or chang" + + "e by using rewrite rules."; + // + // pictureBox1 + // + this.pictureBox1.Location = new System.Drawing.Point(10, 10); + this.pictureBox1.Name = "pictureBox1"; + this.pictureBox1.Size = new System.Drawing.Size(32, 32); + this.pictureBox1.TabIndex = 8; + this.pictureBox1.TabStop = false; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Font = new System.Drawing.Font("Microsoft Sans Serif", 15.75F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label3.Location = new System.Drawing.Point(48, 10); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(252, 25); + this.label3.TabIndex = 2; + this.label3.Text = "Allowed Server Variables"; + // + // tableLayoutPanel1 + // + this.tableLayoutPanel1.ColumnCount = 1; + this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 50F)); + this.tableLayoutPanel1.Controls.Add(this.panel1, 0, 0); + this.tableLayoutPanel1.Controls.Add(this.tsActionPanel, 0, 1); + this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0); + this.tableLayoutPanel1.Name = "tableLayoutPanel1"; + this.tableLayoutPanel1.RowCount = 2; + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Absolute, 23F)); + this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F)); + this.tableLayoutPanel1.Size = new System.Drawing.Size(216, 600); + this.tableLayoutPanel1.TabIndex = 1; + // + // panel1 + // + this.panel1.BackColor = System.Drawing.SystemColors.ActiveBorder; + this.panel1.Controls.Add(this.label1); + this.panel1.Dock = System.Windows.Forms.DockStyle.Fill; + this.panel1.Location = new System.Drawing.Point(0, 0); + this.panel1.Margin = new System.Windows.Forms.Padding(0); + this.panel1.Name = "panel1"; + this.panel1.Size = new System.Drawing.Size(216, 23); + this.panel1.TabIndex = 1; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F, System.Drawing.FontStyle.Bold, System.Drawing.GraphicsUnit.Point, ((byte)(0))); + this.label1.Location = new System.Drawing.Point(3, 5); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(49, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Actions"; + // + // tsActionPanel + // + this.tsActionPanel.CanOverflow = false; + this.tsActionPanel.Dock = System.Windows.Forms.DockStyle.Fill; + this.tsActionPanel.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.tsActionPanel.LayoutStyle = System.Windows.Forms.ToolStripLayoutStyle.VerticalStackWithOverflow; + this.tsActionPanel.Location = new System.Drawing.Point(0, 23); + this.tsActionPanel.Name = "tsActionPanel"; + this.tsActionPanel.Size = new System.Drawing.Size(216, 577); + this.tsActionPanel.TabIndex = 2; + this.tsActionPanel.Text = "toolStrip1"; + // + // ServerVariablesPage + // + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.Controls.Add(this.splitContainer1); + this.Name = "ServerVariablesPage"; + this.Size = new System.Drawing.Size(800, 600); + this.splitContainer1.Panel1.ResumeLayout(false); + this.splitContainer1.Panel1.PerformLayout(); + this.splitContainer1.Panel2.ResumeLayout(false); + ((System.ComponentModel.ISupportInitialize)(this.splitContainer1)).EndInit(); + this.splitContainer1.ResumeLayout(false); + this.panel2.ResumeLayout(false); + this.panel2.PerformLayout(); + this.toolStrip2.ResumeLayout(false); + this.toolStrip2.PerformLayout(); + ((System.ComponentModel.ISupportInitialize)(this.pictureBox1)).EndInit(); + this.tableLayoutPanel1.ResumeLayout(false); + this.tableLayoutPanel1.PerformLayout(); + this.panel1.ResumeLayout(false); + this.panel1.PerformLayout(); + this.ResumeLayout(false); + + } + + #endregion + private ContextMenuStrip cmsActionPanel; + private SplitContainer splitContainer1; + private Panel panel2; + private ListView listView1; + private ColumnHeader chName; + private ColumnHeader chEntry; + private ToolStrip toolStrip2; + private ToolStripLabel toolStripLabel3; + private ToolStripComboBox cbGroup; + private Label label2; + private PictureBox pictureBox1; + private Label label3; + private TableLayoutPanel tableLayoutPanel1; + private Panel panel1; + private Label label1; + private ToolStrip tsActionPanel; + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/ServerVariablesPage.cs b/JexusManager.Features.Rewrite/Inbound/ServerVariablesPage.cs new file mode 100644 index 00000000..4648fe0d --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/ServerVariablesPage.cs @@ -0,0 +1,174 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// -------------------------------------------------------------------------------------------------------------------- +// +// +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace JexusManager.Features.Rewrite.Inbound +{ + using System; + using System.Collections; + using System.Diagnostics; + using System.Reflection; + using System.Windows.Forms; + + using JexusManager.Properties; + using JexusManager.Services; + + using Microsoft.Web.Management.Client; + using Microsoft.Web.Management.Client.Win32; + + internal partial class ServerVariablesPage : ModuleListPage, IModuleChildPage + { + private sealed class PageTaskList : DefaultTaskList + { + private readonly ServerVariablesPage _owner; + + public PageTaskList(ServerVariablesPage owner) + { + _owner = owner; + } + + public override ICollection GetTaskItems() + { + return new TaskItem[] + { + GetBackTaskItem("Back", "Back to Rules"), + new MethodTaskItem(string.Empty, "-", string.Empty).SetUsage(), + HelpTaskItem + }; + } + + [Obfuscation(Exclude = true)] + public void ShowHelp() + { + _owner.ShowHelp(); + } + + [Obfuscation(Exclude = true)] + public void Back() + { + _owner.Back(); + } + } + + private sealed class VariableListViewItem : ListViewItem + { + public AllowedVariableItem Item { get; } + private readonly ServerVariablesPage _page; + + public VariableListViewItem(AllowedVariableItem item, ServerVariablesPage page) + : base(item.Name) + { + this.Item = item; + _page = page; + this.SubItems.Add(new ListViewSubItem(this, item.Flag)); + } + } + + private TaskList _taskList; + private AllowedVariablesFeature _feature; + + public ServerVariablesPage() + { + this.InitializeComponent(); + } + + protected override void Initialize(object navigationData) + { + base.Initialize(navigationData); + var service = (IConfigurationService)GetService(typeof(IConfigurationService)); + pictureBox1.Image = service.Scope.GetImage(); + + _feature = new AllowedVariablesFeature(Module); + _feature.RewriteSettingsUpdated = this.InitializeListPage; + _feature.Load(); + } + + protected override void InitializeListPage() + { + listView1.Items.Clear(); + foreach (var file in _feature.Items) + { + listView1.Items.Add(new VariableListViewItem(file, this)); + } + + if (_feature.SelectedItem == null) + { + this.Refresh(); + return; + } + + foreach (VariableListViewItem item in listView1.Items) + { + if (item.Item == _feature.SelectedItem) + { + item.Selected = true; + } + } + } + + private void ListView1SelectedIndexChanged(object sender, EventArgs e) + { + _feature.SelectedItem = listView1.SelectedItems.Count > 0 + ? ((VariableListViewItem)listView1.SelectedItems[0]).Item + : null; + this.Refresh(); + } + + private void ListView1KeyDown(object sender, KeyEventArgs e) + { + if (e.KeyCode == Keys.Delete) + { + _feature.Remove(); + } + } + + protected override void Refresh() + { + this.Tasks.Fill(tsActionPanel, cmsActionPanel); + base.Refresh(); + } + + protected override bool ShowHelp() + { + Process.Start("http://go.microsoft.com/fwlink/?LinkID=130425&clcid=0x409"); + return true; + } + + private void SplitContainer1SplitterMoved(object sender, SplitterEventArgs e) + { + if (splitContainer1.Panel2.Width > 500) + { + splitContainer1.SplitterDistance = splitContainer1.Width - 500; + } + } + + private void Back() + { + var service = (INavigationService)GetService(typeof(INavigationService)); + service?.NavigateBack(1); + } + + protected override TaskListCollection Tasks + { + get + { + if (_taskList == null) + { + _taskList = new PageTaskList(this); + } + + base.Tasks.Add(_feature.GetTaskList()); + base.Tasks.Add(_taskList); + return base.Tasks; + } + } + + public IModulePage ParentPage { get; set; } + } +} diff --git a/JexusManager.Features.Rewrite/Inbound/ServerVariablesPage.resx b/JexusManager.Features.Rewrite/Inbound/ServerVariablesPage.resx new file mode 100644 index 00000000..2e9f734f --- /dev/null +++ b/JexusManager.Features.Rewrite/Inbound/ServerVariablesPage.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 143, 17 + + + 556, 56 + + + 661, 56 + + \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/JexusManager.Features.Rewrite.csproj b/JexusManager.Features.Rewrite/JexusManager.Features.Rewrite.csproj new file mode 100644 index 00000000..46ea318f --- /dev/null +++ b/JexusManager.Features.Rewrite/JexusManager.Features.Rewrite.csproj @@ -0,0 +1,366 @@ + + + + + Debug + AnyCPU + {425CEE66-72B3-42C0-989C-685B28B05230} + Library + Properties + JexusManager.Features.Rewrite + JexusManager.Features.Rewrite + v4.5 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + true + + + JexusManager.snk + + + + + + + ..\packages\Rx-Core.2.2.5\lib\net45\System.Reactive.Core.dll + True + + + ..\packages\Rx-Interfaces.2.2.5\lib\net45\System.Reactive.Interfaces.dll + True + + + ..\packages\Rx-Linq.2.2.5\lib\net45\System.Reactive.Linq.dll + True + + + ..\packages\Rx-PlatformServices.2.2.5\lib\net45\System.Reactive.PlatformServices.dll + True + + + + + + + + + + + + + + Form + + + AddAllowedVariableDialog.cs + + + Form + + + AddConditionDialog.cs + + + Form + + + AddMapDialog.cs + + + Form + + + AddMapsDialog.cs + + + Form + + + AddServerVariableDialog.cs + + + + + + + UserControl + + + InboundRulePage.cs + + + + UserControl + + + MapPage.cs + + + + Form + + + MapSettingsDialog.cs + + + + + UserControl + + + MapsPage.cs + + + + UserControl + + + ServerVariablesPage.cs + + + Form + + + NewRewriteRuleDialog.cs + + + Form + + + NewRuleBlockingDialog.cs + + + Form + + + NewRuleWithRewriteMapsDialog.cs + + + Form + + + AddCustomTagDialog.cs + + + Form + + + AddCustomTagsDialog.cs + + + Form + + + AddPreconditionDialog.cs + + + + + + UserControl + + + CustomTagsPage.cs + + + + + UserControl + + + OutboundRulePage.cs + + + + + UserControl + + + PreConditionsPage.cs + + + + True + True + Resources.resx + + + Form + + + RegexTestDialog.cs + + + + + + UserControl + + + RewritePage.cs + + + + + + + AddAllowedVariableDialog.cs + + + AddConditionDialog.cs + + + AddMapDialog.cs + + + AddMapsDialog.cs + + + AddServerVariableDialog.cs + + + InboundRulePage.cs + + + MapPage.cs + + + MapSettingsDialog.cs + + + MapsPage.cs + + + ServerVariablesPage.cs + + + NewRewriteRuleDialog.cs + + + NewRuleBlockingDialog.cs + + + NewRuleWithRewriteMapsDialog.cs + + + AddCustomTagDialog.cs + + + AddCustomTagsDialog.cs + + + AddPreconditionDialog.cs + + + CustomTagsPage.cs + + + OutboundRulePage.cs + + + PreConditionsPage.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + RegexTestDialog.cs + + + RewritePage.cs + + + + + + + + + + {e4040a45-b156-4048-b1a4-bd262ba18047} + JexusManager.Shared + + + {70a25201-8ea4-48f8-a4a6-ed13adf8823c} + CheckBoxComboBox + + + {be76a6fe-225f-4287-9ca0-231f5af4cdc1} + MakarovDev.ExpandCollapsePanel + + + {17e994b0-5a31-4f79-9796-83a45e87853d} + Microsoft.Web.Management + + + {bd24afda-292f-4f41-ba80-c48f21d4d9f2} + Microsoft.Web.Administration + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/JexusManager.snk b/JexusManager.Features.Rewrite/JexusManager.snk new file mode 100644 index 0000000000000000000000000000000000000000..fe6f345af4820b6758f6909a2d489ac524eaf889 GIT binary patch literal 596 zcmV-a0;~N80ssI2Bme+XQ$aES1ONa50098^0|he0B_x?RL7>o-AT$p+6ydg1bA=n+ z(TEjM3jFn-l#LX?9O>S*pzolg8Y)VYs$ys(8qZ|eZM(eWal@XvaKlm#iy_MFa zktG6@Uk-Mk8478nIotb|p1Rj6Z+5X3-=(x)I^Xr$16a|_jT}#2q z4>os95Q>xdhUx6jI|K!RX~hw1f!(|e#!5;$P6^h;CwzlPPCzNSv5=EJ`&INw3Z=7z zpCl>Gkp_CX1_JoM)uqwp7RO;18$@HiTuXhh8G#I(lCQ>caMi|5DbsK=Ij`BFCHTSV z)k^SjW~pvk&&IH|pd-nVVYBt0_=U$ArZ<6G8WE6Fm+B494}Ss(+%Lc_4Ia8yP8XWx z#8OMKTbAeI*{B6YjJi>DVo}}N8VwM^Q}Dt#D!-QYa4P@XO=Y9CSTeQ4?wa literal 0 HcmV?d00001 diff --git a/JexusManager.Features.Rewrite/NewRewriteRuleDialog.Designer.cs b/JexusManager.Features.Rewrite/NewRewriteRuleDialog.Designer.cs new file mode 100644 index 00000000..cfb8f7b7 --- /dev/null +++ b/JexusManager.Features.Rewrite/NewRewriteRuleDialog.Designer.cs @@ -0,0 +1,201 @@ +namespace JexusManager.Features.Rewrite +{ + using System.ComponentModel; + using System.Windows.Forms; + + partial class NewRewriteRuleDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.components = new System.ComponentModel.Container(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.listView1 = new System.Windows.Forms.ListView(); + this.ilLarge = new System.Windows.Forms.ImageList(this.components); + this.ilSmall = new System.Windows.Forms.ImageList(this.components); + this.txtDescription = new System.Windows.Forms.TextBox(); + this.toolStripContainer1 = new System.Windows.Forms.ToolStripContainer(); + this.toolStrip1 = new System.Windows.Forms.ToolStrip(); + this.btnBig = new System.Windows.Forms.ToolStripButton(); + this.btnSmall = new System.Windows.Forms.ToolStripButton(); + this.toolStripContainer1.TopToolStripPanel.SuspendLayout(); + this.toolStripContainer1.SuspendLayout(); + this.toolStrip1.SuspendLayout(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(567, 386); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(471, 386); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(22, 25); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(112, 13); + this.label1.TabIndex = 2; + this.label1.Text = "Select a rule template:"; + // + // listView1 + // + this.listView1.Location = new System.Drawing.Point(25, 41); + this.listView1.Name = "listView1"; + this.listView1.Size = new System.Drawing.Size(622, 258); + this.listView1.TabIndex = 3; + this.listView1.UseCompatibleStateImageBehavior = false; + this.listView1.View = System.Windows.Forms.View.SmallIcon; + // + // ilLarge + // + this.ilLarge.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit; + this.ilLarge.ImageSize = new System.Drawing.Size(32, 32); + this.ilLarge.TransparentColor = System.Drawing.Color.Transparent; + // + // ilSmall + // + this.ilSmall.ColorDepth = System.Windows.Forms.ColorDepth.Depth32Bit; + this.ilSmall.ImageSize = new System.Drawing.Size(16, 16); + this.ilSmall.TransparentColor = System.Drawing.Color.Transparent; + // + // txtDescription + // + this.txtDescription.Location = new System.Drawing.Point(25, 299); + this.txtDescription.Multiline = true; + this.txtDescription.Name = "txtDescription"; + this.txtDescription.ReadOnly = true; + this.txtDescription.Size = new System.Drawing.Size(622, 64); + this.txtDescription.TabIndex = 4; + // + // toolStripContainer1 + // + // + // toolStripContainer1.ContentPanel + // + this.toolStripContainer1.ContentPanel.Size = new System.Drawing.Size(50, 0); + this.toolStripContainer1.Location = new System.Drawing.Point(597, 13); + this.toolStripContainer1.Name = "toolStripContainer1"; + this.toolStripContainer1.Size = new System.Drawing.Size(50, 23); + this.toolStripContainer1.TabIndex = 5; + this.toolStripContainer1.Text = "toolStripContainer1"; + // + // toolStripContainer1.TopToolStripPanel + // + this.toolStripContainer1.TopToolStripPanel.Controls.Add(this.toolStrip1); + // + // toolStrip1 + // + this.toolStrip1.CanOverflow = false; + this.toolStrip1.Dock = System.Windows.Forms.DockStyle.None; + this.toolStrip1.GripStyle = System.Windows.Forms.ToolStripGripStyle.Hidden; + this.toolStrip1.Items.AddRange(new System.Windows.Forms.ToolStripItem[] { + this.btnBig, + this.btnSmall}); + this.toolStrip1.Location = new System.Drawing.Point(3, 0); + this.toolStrip1.Name = "toolStrip1"; + this.toolStrip1.RenderMode = System.Windows.Forms.ToolStripRenderMode.System; + this.toolStrip1.Size = new System.Drawing.Size(49, 25); + this.toolStrip1.TabIndex = 0; + // + // btnBig + // + this.btnBig.CheckOnClick = true; + this.btnBig.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.btnBig.ImageTransparentColor = System.Drawing.Color.Magenta; + this.btnBig.Name = "btnBig"; + this.btnBig.Size = new System.Drawing.Size(23, 22); + this.btnBig.Text = "Large icon view"; + // + // btnSmall + // + this.btnSmall.Checked = true; + this.btnSmall.CheckOnClick = true; + this.btnSmall.CheckState = System.Windows.Forms.CheckState.Checked; + this.btnSmall.DisplayStyle = System.Windows.Forms.ToolStripItemDisplayStyle.Image; + this.btnSmall.ImageTransparentColor = System.Drawing.Color.Magenta; + this.btnSmall.Name = "btnSmall"; + this.btnSmall.Size = new System.Drawing.Size(23, 22); + this.btnSmall.Text = "Small icon view"; + // + // NewRewriteRuleDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(674, 421); + this.Controls.Add(this.toolStripContainer1); + this.Controls.Add(this.txtDescription); + this.Controls.Add(this.listView1); + this.Controls.Add(this.label1); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewRewriteRuleDialog"; + this.Text = "Add Rule(s)"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewRewriteRuleDialogHelpButtonClicked); + this.toolStripContainer1.TopToolStripPanel.ResumeLayout(false); + this.toolStripContainer1.TopToolStripPanel.PerformLayout(); + this.toolStripContainer1.ResumeLayout(false); + this.toolStripContainer1.PerformLayout(); + this.toolStrip1.ResumeLayout(false); + this.toolStrip1.PerformLayout(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label label1; + private ListView listView1; + private TextBox txtDescription; + private ImageList ilSmall; + private ImageList ilLarge; + private ToolStripContainer toolStripContainer1; + private ToolStrip toolStrip1; + private ToolStripButton btnBig; + private ToolStripButton btnSmall; + } +} diff --git a/JexusManager.Features.Rewrite/NewRewriteRuleDialog.cs b/JexusManager.Features.Rewrite/NewRewriteRuleDialog.cs new file mode 100644 index 00000000..19d173b6 --- /dev/null +++ b/JexusManager.Features.Rewrite/NewRewriteRuleDialog.cs @@ -0,0 +1,150 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +namespace JexusManager.Features.Rewrite +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using Properties; + + using Microsoft.Web.Management.Client.Win32; + + public partial class NewRewriteRuleDialog : DialogForm + { + public NewRewriteRuleDialog(IServiceProvider serviceProvider) + : base(serviceProvider) + { + InitializeComponent(); + btnBig.Image = DefaultTaskList.BasicSettingsImage; + btnSmall.Image = DefaultTaskList.ViewImage; + + ilLarge.Images.Add(Resources.blank_32); + ilLarge.Images.Add(Resources.map_32); + ilLarge.Images.Add(Resources.blocking_32); + ilLarge.Images.Add(Resources.blankout_32); + ilLarge.Images.Add(Resources.lowercase_32); + + ilSmall.Images.Add(Resources.blank_16); + ilSmall.Images.Add(Resources.map_16); + ilSmall.Images.Add(Resources.blocking_16); + ilSmall.Images.Add(Resources.blankout_16); + ilSmall.Images.Add(Resources.lowercase_16); + listView1.LargeImageList = ilLarge; + listView1.SmallImageList = ilSmall; + ListViewGroup listViewGroup1 = new ListViewGroup("Inbound rules", HorizontalAlignment.Left); + ListViewGroup listViewGroup2 = new ListViewGroup("Inbound and Outbound Rules", HorizontalAlignment.Left); + ListViewGroup listViewGroup3 = new ListViewGroup("Outbound rules", HorizontalAlignment.Left); + ListViewGroup listViewGroup4 = new ListViewGroup( + "Search Engine Optimization (SEO)", + HorizontalAlignment.Left); + ListViewItem listViewItem1 = new ListViewItem("Blank rule"); + listViewItem1.ImageIndex = 0; + ListViewItem listViewItem2 = new ListViewItem("Rule with rewrite map"); + listViewItem2.ImageIndex = 1; + ListViewItem listViewItem3 = new ListViewItem("Request blocking"); + listViewItem3.ImageIndex = 2; + ListViewItem listViewItem4 = new ListViewItem("User-friendly URL"); + listViewItem4.ImageIndex = 1; + ListViewItem listViewItem5 = new ListViewItem("Blank rule"); + listViewItem5.ImageIndex = 3; + ListViewItem listViewItem6 = new ListViewItem("Enforce lowercase URLs"); + listViewItem6.ImageIndex = 4; + + listViewGroup1.Header = "Inbound rules"; + listViewGroup1.Name = "lvgIn"; + listViewGroup2.Header = "Inbound and Outbound Rules"; + listViewGroup2.Name = "lvgInOut"; + listViewGroup3.Header = "Outbound rules"; + listViewGroup3.Name = "lvgOut"; + listViewGroup4.Header = "Search Engine Optimization (SEO)"; + listViewGroup4.Name = "lvgSeo"; + listView1.Groups.AddRange(new[] { listViewGroup1, listViewGroup2, listViewGroup3, listViewGroup4 }); + listViewItem1.Group = listViewGroup1; + listViewItem1.ToolTipText = + "Select this template to create a new inbound rule without any preset values. This template opens the \"Edit Rule\" page that you can use to define a new rewrite rule for changing the requested URL address."; + listViewItem2.Group = listViewGroup1; + listViewItem2.ToolTipText = + "Select this template to create a rewrite or redirect rule that uses a rewrite map. The rewrite map for this rule can contain a large number of static mappings between original URLs and rewritten URLs or redirection URLs, depending on whether the rule is rewriting or redirecting requests."; + listViewItem3.Group = listViewGroup1; + listViewItem3.ToolTipText = + "Select this template to create a rule that will block client requests based on ce" + + "rtain text patterns in the URL path, query string, HTTP headers, and server vari" + "ables."; + listViewItem4.Group = listViewGroup2; + listViewItem4.ToolTipText = + "Select this template to create rules for enabling user-friendly URLs for your dynamic Web applications. This template creates rules that rewrite user-friendly URLs to internal URLs that your Web application understands."; + listViewItem5.Group = listViewGroup3; + listViewItem5.ToolTipText = + "Select this template to create a new outbound rule without any preset values. This template opens the \"Edit Rule\" page that you can use to define a new rewrite rule for changing the content of an HTTP response."; + listViewItem6.Group = listViewGroup4; + listViewItem6.ToolTipText = + "Use this template to create a rule that will enforce the use of lowercase letters" + " in the URL."; + listView1.Items.AddRange( + new[] { listViewItem1, listViewItem2, listViewItem3, listViewItem4, listViewItem5, listViewItem6 }); + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(listView1, "SelectedIndexChanged") + .Subscribe(evt => + { + txtDescription.Text = listView1.SelectedItems.Count == 0 + ? string.Empty + : listView1.SelectedItems[0].ToolTipText; + btnOK.Enabled = listView1.SelectedItems.Count > 0; + })); + + var doubleClick = Observable.FromEventPattern(listView1, "DoubleClick"); + container.Add( + doubleClick.Subscribe(evt => + { + if (listView1.SelectedItems.Count == 0) + { + return; + } + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Merge(doubleClick) + .Subscribe(evt => + { + SelectedIndex = listView1.SelectedIndices[0]; + DialogResult = DialogResult.OK; + })); + + var big = Observable.FromEventPattern(btnBig, "Click"); + container.Add( + big.Subscribe(evt => + { + btnSmall.Checked = !btnBig.Checked; + })); + + var small = Observable.FromEventPattern(btnSmall, "Click"); + container.Add( + small.Subscribe(evt => + { + btnBig.Checked = !btnSmall.Checked; + })); + + container.Add( + big.Merge(small).Subscribe(evt => + { + listView1.View = btnBig.Checked ? View.LargeIcon : View.SmallIcon; + })); + } + + public int SelectedIndex { get; private set; } + + private void NewRewriteRuleDialogHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkID=130421&clcid=0x409"); + } + } +} diff --git a/JexusManager.Features.Rewrite/NewRewriteRuleDialog.resx b/JexusManager.Features.Rewrite/NewRewriteRuleDialog.resx new file mode 100644 index 00000000..2424ecae --- /dev/null +++ b/JexusManager.Features.Rewrite/NewRewriteRuleDialog.resx @@ -0,0 +1,129 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + 127, 17 + + + 17, 17 + + + 215, 17 + + \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/NewRuleBlockingDialog.Designer.cs b/JexusManager.Features.Rewrite/NewRuleBlockingDialog.Designer.cs new file mode 100644 index 00000000..76c533fe --- /dev/null +++ b/JexusManager.Features.Rewrite/NewRuleBlockingDialog.Designer.cs @@ -0,0 +1,228 @@ +namespace JexusManager.Features.Rewrite +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal partial class NewRuleBlockingDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.label1 = new System.Windows.Forms.Label(); + this.cbInput = new System.Windows.Forms.ComboBox(); + this.label2 = new System.Windows.Forms.Label(); + this.cbMatch = new System.Windows.Forms.ComboBox(); + this.lblPattern = new System.Windows.Forms.Label(); + this.txtPattern = new System.Windows.Forms.TextBox(); + this.lblExample = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.cbMode = new System.Windows.Forms.ComboBox(); + this.label6 = new System.Windows.Forms.Label(); + this.cbResponse = new System.Windows.Forms.ComboBox(); + this.SuspendLayout(); + // + // btnCancel + // + this.btnCancel.DialogResult = System.Windows.Forms.DialogResult.Cancel; + this.btnCancel.Location = new System.Drawing.Point(282, 361); + this.btnCancel.Name = "btnCancel"; + this.btnCancel.Size = new System.Drawing.Size(95, 23); + this.btnCancel.TabIndex = 0; + this.btnCancel.Text = "Cancel"; + this.btnCancel.UseVisualStyleBackColor = true; + // + // btnOK + // + this.btnOK.Enabled = false; + this.btnOK.Location = new System.Drawing.Point(186, 361); + this.btnOK.Name = "btnOK"; + this.btnOK.Size = new System.Drawing.Size(90, 23); + this.btnOK.TabIndex = 1; + this.btnOK.Text = "OK"; + this.btnOK.UseVisualStyleBackColor = true; + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(13, 13); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(121, 13); + this.label1.TabIndex = 2; + this.label1.Text = "Block access based on:"; + // + // cbInput + // + this.cbInput.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbInput.FormattingEnabled = true; + this.cbInput.Items.AddRange(new object[] { + "URL Path", + "User-agent Header", + "IP Address", + "Query String", + "Referer", + "Host Header"}); + this.cbInput.Location = new System.Drawing.Point(12, 29); + this.cbInput.Name = "cbInput"; + this.cbInput.Size = new System.Drawing.Size(365, 21); + this.cbInput.TabIndex = 3; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(13, 72); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(96, 13); + this.label2.TabIndex = 4; + this.label2.Text = "Block request that:"; + // + // cbMatch + // + this.cbMatch.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbMatch.FormattingEnabled = true; + this.cbMatch.Items.AddRange(new object[] { + "Matches the Pattern", + "Does Not Match the Pattern"}); + this.cbMatch.Location = new System.Drawing.Point(12, 88); + this.cbMatch.Name = "cbMatch"; + this.cbMatch.Size = new System.Drawing.Size(365, 21); + this.cbMatch.TabIndex = 5; + // + // lblPattern + // + this.lblPattern.AutoSize = true; + this.lblPattern.Location = new System.Drawing.Point(13, 135); + this.lblPattern.Name = "lblPattern"; + this.lblPattern.Size = new System.Drawing.Size(100, 13); + this.lblPattern.TabIndex = 6; + this.lblPattern.Text = "Pattern (URL Path):"; + // + // txtPattern + // + this.txtPattern.Location = new System.Drawing.Point(12, 151); + this.txtPattern.Name = "txtPattern"; + this.txtPattern.Size = new System.Drawing.Size(365, 20); + this.txtPattern.TabIndex = 7; + // + // lblExample + // + this.lblExample.AutoSize = true; + this.lblExample.Location = new System.Drawing.Point(13, 174); + this.lblExample.Name = "lblExample"; + this.lblExample.Size = new System.Drawing.Size(94, 13); + this.lblExample.TabIndex = 8; + this.lblExample.Text = "Example: IMG*.jpg"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(13, 212); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(37, 13); + this.label5.TabIndex = 9; + this.label5.Text = "Using:"; + // + // cbMode + // + this.cbMode.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbMode.FormattingEnabled = true; + this.cbMode.Items.AddRange(new object[] { + "Regular Expressions", + "Wildcards"}); + this.cbMode.Location = new System.Drawing.Point(12, 228); + this.cbMode.Name = "cbMode"; + this.cbMode.Size = new System.Drawing.Size(365, 21); + this.cbMode.TabIndex = 10; + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(13, 271); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(73, 13); + this.label6.TabIndex = 11; + this.label6.Text = "How to block:"; + // + // cbResponse + // + this.cbResponse.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbResponse.FormattingEnabled = true; + this.cbResponse.Items.AddRange(new object[] { + "Send an HTTP 401 (Unauthorized) Response", + "Send an HTTP 403 (Forbidden) Response", + "Send an HTTP 404 (File Not Found) Response", + "Abort Request"}); + this.cbResponse.Location = new System.Drawing.Point(12, 287); + this.cbResponse.Name = "cbResponse"; + this.cbResponse.Size = new System.Drawing.Size(365, 21); + this.cbResponse.TabIndex = 12; + // + // NewRuleBlockingDialog + // + this.AcceptButton = this.btnOK; + this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.CancelButton = this.btnCancel; + this.ClientSize = new System.Drawing.Size(389, 396); + this.Controls.Add(this.cbResponse); + this.Controls.Add(this.label6); + this.Controls.Add(this.cbMode); + this.Controls.Add(this.label5); + this.Controls.Add(this.lblExample); + this.Controls.Add(this.txtPattern); + this.Controls.Add(this.lblPattern); + this.Controls.Add(this.cbMatch); + this.Controls.Add(this.label2); + this.Controls.Add(this.cbInput); + this.Controls.Add(this.label1); + this.Controls.Add(this.btnOK); + this.Controls.Add(this.btnCancel); + this.Name = "NewRuleBlockingDialog"; + this.Text = "Add Request Blocking Rule"; + this.HelpButtonClicked += new System.ComponentModel.CancelEventHandler(this.NewRuleBlockingHelpButtonClicked); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private Button btnCancel; + private Button btnOK; + private Label label1; + private ComboBox cbInput; + private Label label2; + private ComboBox cbMatch; + private Label lblPattern; + private TextBox txtPattern; + private Label lblExample; + private Label label5; + private ComboBox cbMode; + private Label label6; + private ComboBox cbResponse; + } +} diff --git a/JexusManager.Features.Rewrite/NewRuleBlockingDialog.cs b/JexusManager.Features.Rewrite/NewRuleBlockingDialog.cs new file mode 100644 index 00000000..215725f0 --- /dev/null +++ b/JexusManager.Features.Rewrite/NewRuleBlockingDialog.cs @@ -0,0 +1,178 @@ +// Copyright (c) Lex Li. All rights reserved. +// +// Licensed under the MIT license. See LICENSE file in the project root for full license information. + +// -------------------------------------------------------------------------------------------------------------------- +// +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace JexusManager.Features.Rewrite +{ + using System; + using System.ComponentModel; + using System.Diagnostics; + using System.Linq; + using System.Reactive.Disposables; + using System.Reactive.Linq; + using System.Windows.Forms; + + using JexusManager.Features.Rewrite.Inbound; + + using Microsoft.Web.Management.Client.Win32; + + internal partial class NewRuleBlockingDialog : DialogForm + { + public NewRuleBlockingDialog(IServiceProvider serviceProvider, InboundFeature rewriteFeature) + : base(serviceProvider) + { + InitializeComponent(); + cbMode.SelectedIndex = 1; + cbInput.SelectedIndex = 0; + cbMatch.SelectedIndex = 0; + cbResponse.SelectedIndex = 1; + + var container = new CompositeDisposable(); + FormClosed += (sender, args) => container.Dispose(); + + container.Add( + Observable.FromEventPattern(cbInput, "SelectedIndexChanged") + .Merge(Observable.FromEventPattern(cbMode, "SelectedIndexChanged")) + .Subscribe(evt => + { + switch (cbInput.SelectedIndex) + { + case 0: + lblPattern.Text = "Pattern (URL Path):"; + lblExample.Text = cbMode.SelectedIndex == 1 ? "Example: IMG*.jpg" : "Example: ^IMG.*\\.jpg$"; + break; + case 1: + lblPattern.Text = "Pattern (User-agent Header):"; + lblExample.Text = cbMode.SelectedIndex == 1 ? "Example: Mozilla/4*" : "Example: ^Mozilla/[1234].*"; + break; + case 2: + lblPattern.Text = "Pattern (IP Address):"; + lblExample.Text = cbMode.SelectedIndex == 1 ? "Exmaple: 192.168.1.*" : "Example: 192\\.168\\.1\\.[1-9]"; + break; + case 3: + lblPattern.Text = "Pattern (Query String):"; + lblExample.Text = cbMode.SelectedIndex == 1 ? "Example: *id=*&p=*" : "Example: id=[0-9]+&p=[a-z]+"; + break; + case 4: + lblPattern.Text = "Pattern (Referer):"; + lblExample.Text = cbMode.SelectedIndex == 1 ? "Example: http://*.consoto.com" : "Example: http://(?:www\\.)?contoso\\.com$"; + break; + case 5: + lblPattern.Text = "Pattern (Host Header):"; + lblExample.Text = cbMode.SelectedIndex == 1 ? "Example: *.consoto.com" : "Example: (?:www\\.)?contoso\\.com$"; + break; + } + })); + + container.Add( + Observable.FromEventPattern(txtPattern, "TextChanged") + .Sample(TimeSpan.FromSeconds(1)) + .Subscribe(evt => + { + btnOK.Enabled = !string.IsNullOrWhiteSpace(txtPattern.Text); + })); + + container.Add( + Observable.FromEventPattern(btnOK, "Click") + .Subscribe(evt => + { + var inputType = cbInput.SelectedIndex; + var pattern = txtPattern.Text; + var match = cbMatch.SelectedIndex; + var response = cbResponse.SelectedIndex; + var mode = cbMode.SelectedIndex; + + int index = 0; + string name; + do + { + index++; + name = string.Format("RequestBlockingRule{0}", index); + } + while (rewriteFeature.Items.All(item => item.Name != name)); + var newRule = new InboundRule(null); + newRule.Name = name; + newRule.Input = "URL Path"; + newRule.Enabled = true; + newRule.PatternSyntax = mode == 0 ? 0L : 1L; + newRule.PatternUrl = mode == 0 ? ".*" : "*"; + newRule.Type = response == 3 ? 4L : 3L; + newRule.ActionUrl = "{C:1}"; + newRule.RedirectType = 301; + newRule.StatusCode = GetStatusCode(response); + newRule.SubStatusCode = 0; + newRule.StatusReason = GetReason(response); + newRule.StatusDescription = GetMessage(response); + newRule.Conditions.Add( + new ConditionItem(null) + { + Input = GetInput(inputType), + MatchType = match == 0 ? 4 : 5, + Pattern = pattern, + IgnoreCase = true + }); + rewriteFeature.AddItem(newRule); + DialogResult = DialogResult.OK; + })); + } + + private void NewRuleBlockingHelpButtonClicked(object sender, CancelEventArgs e) + { + Process.Start("http://go.microsoft.com/fwlink/?LinkID=130412&clcid=0x409"); + } + + private string GetInput(int inputType) + { + switch (inputType) + { + case 0: + return "{URL}"; + case 1: + return "{HTTP_USER_AGENT}"; + case 2: + return "{REMOTE_ADDR}"; + case 3: + return "{QUERY_STRING}"; + case 4: + return "{HTTP_REFERER}"; + case 5: + return "{HTTP_HOST}"; + default: + throw new ArgumentOutOfRangeException(nameof(inputType)); + } + } + + private string GetMessage(int response) + { + return response == 0 + ? UnauthorizedText + : response == 1 ? ForbiddenText : response == 2 ? FileNotFoundText : string.Empty; + } + + private string GetReason(int response) + { + return response == 0 + ? "Unauthorized: Access is denied due to invalid credentials" + : response == 1 + ? "Forbidden: Access is denied." + : response == 2 ? "File or directory not found." : string.Empty; + } + + private uint GetStatusCode(int response) + { + return response == 0 ? 401U : response == 1 ? 403U : response == 2 ? 404U : 0U; + } + + private const string UnauthorizedText = "You do not have permission to view this directory or page using the credentials that you supplied."; + + private const string ForbiddenText = + "You do not have permission to view this directory or page using the credentials that you supplied."; + + private const string FileNotFoundText = "The resource you are looking for might have been removed, had its name changed, or is temporarily unavailable."; + } +} diff --git a/JexusManager.Features.Rewrite/NewRuleBlockingDialog.resx b/JexusManager.Features.Rewrite/NewRuleBlockingDialog.resx new file mode 100644 index 00000000..1af7de15 --- /dev/null +++ b/JexusManager.Features.Rewrite/NewRuleBlockingDialog.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/JexusManager.Features.Rewrite/NewRuleWithRewriteMapsDialog.Designer.cs b/JexusManager.Features.Rewrite/NewRuleWithRewriteMapsDialog.Designer.cs new file mode 100644 index 00000000..46a645b8 --- /dev/null +++ b/JexusManager.Features.Rewrite/NewRuleWithRewriteMapsDialog.Designer.cs @@ -0,0 +1,144 @@ +namespace JexusManager.Features.Rewrite +{ + using System.ComponentModel; + using System.Windows.Forms; + + internal partial class NewRuleWithRewriteMapsDialog + { + /// + /// Required designer variable. + /// + private IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(NewRuleWithRewriteMapsDialog)); + this.label1 = new System.Windows.Forms.Label(); + this.label2 = new System.Windows.Forms.Label(); + this.cbAction = new System.Windows.Forms.ComboBox(); + this.cbMap = new System.Windows.Forms.ComboBox(); + this.lblDescription = new System.Windows.Forms.Label(); + this.btnCancel = new System.Windows.Forms.Button(); + this.btnOK = new System.Windows.Forms.Button(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(12, 25); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(124, 13); + this.label1.TabIndex = 0; + this.label1.Text = "Selection the rule action:"; + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(9, 84); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(115, 13); + this.label2.TabIndex = 2; + this.label2.Text = "Select the rewrite map:"; + // + // cbAction + // + this.cbAction.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList; + this.cbAction.FormattingEnabled = true; + this.cbAction.Items.AddRange(new object[] { + "Rewrite", + "Redirect"}); + this.cbAction.Location = new System.Drawing.Point(12, 41); + this.cbAction.Name = "cbAction"; + this.cbAction.Size = new System.Drawing.Size(395, 21); + this.cbAction.TabIndex = 3; + // + // cbMap + // + this.cbMap.FormattingEnabled = true; + this.cbMap.Location = new System.Drawing.Point(12, 100); + this.cbMap.Name = "cbMap"; + this.cbMap.Size = new System.Drawing.Size(395, 21); + this.cbMap.TabIndex = 4; + this.cbMap.Text = "