diff --git a/src/Nancy.Tests/Nancy.Tests.csproj b/src/Nancy.Tests/Nancy.Tests.csproj
index 192368c89c..2c0858585d 100644
--- a/src/Nancy.Tests/Nancy.Tests.csproj
+++ b/src/Nancy.Tests/Nancy.Tests.csproj
@@ -140,6 +140,7 @@
+
diff --git a/src/Nancy.Tests/Unit/Diagnostics/CustomInteractiveDiagnosticsFixture.cs b/src/Nancy.Tests/Unit/Diagnostics/CustomInteractiveDiagnosticsFixture.cs
new file mode 100644
index 0000000000..224f5ee9d3
--- /dev/null
+++ b/src/Nancy.Tests/Unit/Diagnostics/CustomInteractiveDiagnosticsFixture.cs
@@ -0,0 +1,138 @@
+namespace Nancy.Tests.Unit.Diagnostics
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+
+ using Fakes;
+ using FakeItEasy;
+ using Nancy.Bootstrapper;
+ using Nancy.Cookies;
+ using Nancy.Cryptography;
+ using Nancy.Culture;
+ using Nancy.Diagnostics;
+ using Nancy.ModelBinding;
+ using Nancy.Responses.Negotiation;
+ using Nancy.Testing;
+ using Xunit;
+
+ public class CustomInteractiveDiagnosticsHookFixture
+ {
+ private const string DiagsCookieName = "__ncd";
+
+ private readonly CryptographyConfiguration cryptoConfig;
+
+ private readonly IObjectSerializer objectSerializer;
+
+ public CustomInteractiveDiagnosticsHookFixture()
+ {
+ this.cryptoConfig = CryptographyConfiguration.Default;
+ this.objectSerializer = new DefaultObjectSerializer();
+ }
+
+ private class FakeDiagnostics : IDiagnostics
+ {
+ private readonly DiagnosticsConfiguration diagnosticsConfiguration;
+ private readonly IEnumerable diagnosticProviders;
+ private readonly IRootPathProvider rootPathProvider;
+ private readonly IEnumerable serializers;
+ private readonly IRequestTracing requestTracing;
+ private readonly NancyInternalConfiguration configuration;
+ private readonly IModelBinderLocator modelBinderLocator;
+ private readonly IEnumerable responseProcessors;
+ private readonly ICultureService cultureService;
+
+ public FakeDiagnostics(DiagnosticsConfiguration diagnosticsConfiguration, IEnumerable diagnosticProviders, IRootPathProvider rootPathProvider, IEnumerable serializers, IRequestTracing requestTracing, NancyInternalConfiguration configuration, IModelBinderLocator modelBinderLocator, IEnumerable responseProcessors, ICultureService cultureService)
+ {
+ this.diagnosticsConfiguration = diagnosticsConfiguration;
+ this.diagnosticProviders = (new IDiagnosticsProvider[] { new FakeDiagnosticsProvider() }).ToArray();
+ this.rootPathProvider = rootPathProvider;
+ this.serializers = serializers;
+ this.requestTracing = requestTracing;
+ this.configuration = configuration;
+ this.modelBinderLocator = modelBinderLocator;
+ this.responseProcessors = responseProcessors;
+ this.cultureService = cultureService;
+ }
+
+ public void Initialize(IPipelines pipelines)
+ {
+ DiagnosticsHook.Enable(this.diagnosticsConfiguration, pipelines, this.diagnosticProviders, this.rootPathProvider, this.serializers, this.requestTracing, this.configuration, this.modelBinderLocator, this.responseProcessors, this.cultureService);
+ }
+ }
+
+ private class FakeDiagnosticsProvider : IDiagnosticsProvider
+ {
+ public string Name
+ {
+ get { return "Fake testing provider"; }
+ }
+
+ public string Description
+ {
+ get { return "Fake testing provider"; }
+ }
+
+ public object DiagnosticObject
+ {
+ get { return this; }
+ }
+ }
+
+ [Fact]
+ public void Should_return_main_page_with_valid_auth_cookie()
+ {
+ // Given
+ var diagsConfig = new DiagnosticsConfiguration { Password = "password", CryptographyConfiguration = this.cryptoConfig };
+
+ var bootstrapper = new ConfigurableBootstrapper(with =>
+ {
+ with.EnableAutoRegistration();
+ with.DiagnosticsConfiguration(diagsConfig);
+ with.Diagnostics();
+ });
+
+ var browser = new Browser(bootstrapper);
+
+ // When
+ var result = browser.Get(diagsConfig.Path + "/interactive/providers/", with =>
+ {
+ with.Cookie(DiagsCookieName, this.GetSessionCookieValue("password"));
+ });
+
+ // Then should see our fake provider and not the default testing provider
+ result.Body.AsString().ShouldContain("Fake testing provider");
+ result.Body.AsString().ShouldNotContain("Testing Diagnostic Provider");
+ }
+
+ private string GetSessionCookieValue(string password, DateTime? expiry = null)
+ {
+ var salt = DiagnosticsSession.GenerateRandomSalt();
+ var hash = DiagnosticsSession.GenerateSaltedHash(password, salt);
+ var session = new DiagnosticsSession
+ {
+ Hash = hash,
+ Salt = salt,
+ Expiry = expiry.HasValue ? expiry.Value : DateTime.Now.AddMinutes(15),
+ };
+
+ var serializedSession = this.objectSerializer.Serialize(session);
+
+ var encryptedSession = this.cryptoConfig.EncryptionProvider.Encrypt(serializedSession);
+ var hmacBytes = this.cryptoConfig.HmacProvider.GenerateHmac(encryptedSession);
+ var hmacString = Convert.ToBase64String(hmacBytes);
+
+ return String.Format("{1}{0}", encryptedSession, hmacString);
+ }
+
+ private DiagnosticsSession DecodeCookie(INancyCookie nancyCookie)
+ {
+ var cookieValue = nancyCookie.Value;
+ var hmacStringLength = Base64Helpers.GetBase64Length(this.cryptoConfig.HmacProvider.HmacLength);
+ var encryptedSession = cookieValue.Substring(hmacStringLength);
+ var decrypted = this.cryptoConfig.EncryptionProvider.Decrypt(encryptedSession);
+
+ return this.objectSerializer.Deserialize(decrypted) as DiagnosticsSession;
+ }
+ }
+}
diff --git a/src/Nancy.Tests/Unit/Diagnostics/DiagnosticsHookFixture.cs b/src/Nancy.Tests/Unit/Diagnostics/DiagnosticsHookFixture.cs
index 8d0541cb63..c94540d61e 100644
--- a/src/Nancy.Tests/Unit/Diagnostics/DiagnosticsHookFixture.cs
+++ b/src/Nancy.Tests/Unit/Diagnostics/DiagnosticsHookFixture.cs
@@ -29,7 +29,8 @@ public void Should_return_info_page_if_password_null()
// Given
var diagsConfig = new DiagnosticsConfiguration { Password = null, CryptographyConfiguration = this.cryptoConfig };
- var bootstrapper = new ConfigurableBootstrapper(with =>{
+ var bootstrapper = new ConfigurableBootstrapper(with =>
+ {
with.EnableAutoRegistration();
with.DiagnosticsConfiguration(diagsConfig);
with.Diagnostics();
@@ -244,6 +245,32 @@ public void Should_use_rolling_expiry_for_auth_cookie()
.Expiry.ShouldNotEqual(expiryDate);
}
+ [Fact]
+ public void Should_return_diagnostic_example()
+ {
+ // Given no custom interactive diagnostic providers
+ var diagsConfig = new DiagnosticsConfiguration { Password = "password", CryptographyConfiguration = this.cryptoConfig };
+
+ var bootstrapper = new ConfigurableBootstrapper(with =>
+ {
+ with.EnableAutoRegistration();
+ with.DiagnosticsConfiguration(diagsConfig);
+ with.Diagnostics();
+ });
+
+ var browser = new Browser(bootstrapper);
+
+ // When querying the list of interactive providers
+ var result = browser.Get(diagsConfig.Path + "/interactive/providers/", with =>
+ {
+ with.Cookie(DiagsCookieName, this.GetSessionCookieValue("password"));
+ });
+
+ // Then we should see the fake testing provider and not the Nancy provided testing example
+ result.Body.AsString().ShouldNotContain("Fake testing provider");
+ result.Body.AsString().Contains("Testing Diagnostic Provider");
+ }
+
private string GetSessionCookieValue(string password, DateTime? expiry = null)
{
var salt = DiagnosticsSession.GenerateRandomSalt();
@@ -270,7 +297,7 @@ private DiagnosticsSession DecodeCookie(INancyCookie nancyCookie)
var hmacStringLength = Base64Helpers.GetBase64Length(this.cryptoConfig.HmacProvider.HmacLength);
var encryptedSession = cookieValue.Substring(hmacStringLength);
var decrypted = this.cryptoConfig.EncryptionProvider.Decrypt(encryptedSession);
-
+
return this.objectSerializer.Deserialize(decrypted) as DiagnosticsSession;
}
}
diff --git a/src/Nancy/Diagnostics/InteractiveDiagnostics.cs b/src/Nancy/Diagnostics/InteractiveDiagnostics.cs
index fe5d70ebe6..29c1ad00a1 100644
--- a/src/Nancy/Diagnostics/InteractiveDiagnostics.cs
+++ b/src/Nancy/Diagnostics/InteractiveDiagnostics.cs
@@ -15,7 +15,23 @@ public class InteractiveDiagnostics : IInteractiveDiagnostics
public InteractiveDiagnostics(IEnumerable providers)
{
- this.providers = providers.ToArray();
+ var customProvidersAvailable = providers.Any(provider =>
+ {
+ Type providerType = provider.GetType();
+
+ return providerType != typeof(Nancy.Diagnostics.TestingDiagnosticProvider) &
+ providerType != typeof(Nancy.Routing.DefaultRouteCacheProvider);
+ });
+
+ if (customProvidersAvailable)
+ {
+ // Exclude only the TestingDiagnosticProvider
+ this.providers = providers.Where(provider => provider.GetType() != typeof(Nancy.Diagnostics.TestingDiagnosticProvider)).ToArray();
+ }
+ else
+ {
+ this.providers = providers.ToArray();
+ }
this.BuildAvailableDiagnostics();
}