diff --git a/src/Api/Api.csproj b/src/Api/Api.csproj
index 9e8595eb04..e2f14e8508 100644
--- a/src/Api/Api.csproj
+++ b/src/Api/Api.csproj
@@ -22,23 +22,13 @@
-
-
+
-
-
-
-
-
-
-
-
-
diff --git a/src/Api/Startup.cs b/src/Api/Startup.cs
index 5f12d44151..609ffbcca5 100644
--- a/src/Api/Startup.cs
+++ b/src/Api/Startup.cs
@@ -3,7 +3,6 @@ using System.Security.Claims;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
-using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
@@ -11,26 +10,17 @@ using Microsoft.Extensions.Options;
using Microsoft.IdentityModel.Tokens;
using Bit.Api.Utilities;
using Bit.Core;
-using Bit.Core.Models.Table;
using Bit.Core.Identity;
-using System.Text;
using System.Linq;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.Net.Http.Headers;
using Newtonsoft.Json.Serialization;
using AspNetCoreRateLimit;
using Bit.Api.Middleware;
-using IdentityServer4.Validation;
-using IdentityServer4.Services;
-using IdentityServer4.Stores;
-using Bit.Core.Utilities;
-using Serilog;
using Serilog.Events;
using Bit.Core.IdentityServer;
-using Bit.Core.Enums;
-using Microsoft.AspNetCore.DataProtection;
-using Microsoft.WindowsAzure.Storage;
using Stripe;
+using Bit.Core.Utilities;
namespace Bit.Api
{
@@ -65,21 +55,12 @@ namespace Bit.Api
services.AddOptions();
// Settings
- var globalSettings = new GlobalSettings();
- ConfigurationBinder.Bind(Configuration.GetSection("GlobalSettings"), globalSettings);
- services.AddSingleton(s => globalSettings);
+ var globalSettings = services.AddGlobalSettingsServices(Configuration);
services.Configure(Configuration.GetSection("IpRateLimitOptions"));
services.Configure(Configuration.GetSection("IpRateLimitPolicies"));
// Data Protection
- if(Environment.IsProduction())
- {
- var dataProtectionCert = CoreHelpers.GetCertificate(globalSettings.DataProtection.CertificateThumbprint);
- var storageAccount = CloudStorageAccount.Parse(globalSettings.Storage.ConnectionString);
- services.AddDataProtection()
- .PersistKeysToAzureBlobStorage(storageAccount, "aspnet-dataprotection/keys.xml")
- .ProtectKeysWithCertificate(dataProtectionCert);
- }
+ services.AddCustomDataProtectionServices(Environment, globalSettings);
// Stripe Billing
StripeConfiguration.SetApiKey(globalSettings.StripeApiKey);
@@ -98,69 +79,10 @@ namespace Bit.Api
services.AddSingleton();
// IdentityServer
- var identityServerBuilder = services.AddIdentityServer(options =>
- {
- options.Endpoints.EnableAuthorizeEndpoint = false;
- options.Endpoints.EnableIntrospectionEndpoint = false;
- options.Endpoints.EnableEndSessionEndpoint = false;
- options.Endpoints.EnableUserInfoEndpoint = false;
- options.Endpoints.EnableCheckSessionEndpoint = false;
- options.Endpoints.EnableTokenRevocationEndpoint = false;
- })
- .AddInMemoryApiResources(ApiResources.GetApiResources())
- .AddInMemoryClients(Clients.GetClients());
- services.AddTransient();
-
- if(Environment.IsProduction())
- {
- var identityServerCert = CoreHelpers.GetCertificate(globalSettings.IdentityServer.CertificateThumbprint);
- identityServerBuilder.AddSigningCredential(identityServerCert);
- }
- else
- {
- identityServerBuilder.AddTemporarySigningCredential();
- }
-
- services.AddScoped();
- services.AddScoped();
- services.AddSingleton();
+ services.AddCustomIdentityServerServices(Environment, globalSettings);
// Identity
- services.AddTransient();
- services.AddJwtBearerIdentity(options =>
- {
- options.User = new UserOptions
- {
- RequireUniqueEmail = true,
- AllowedUserNameCharacters = null // all
- };
- options.Password = new PasswordOptions
- {
- RequireDigit = false,
- RequireLowercase = false,
- RequiredLength = 8,
- RequireNonAlphanumeric = false,
- RequireUppercase = false
- };
- options.ClaimsIdentity = new ClaimsIdentityOptions
- {
- SecurityStampClaimType = "securitystamp",
- UserNameClaimType = ClaimTypes.Email
- };
- options.Tokens.ChangeEmailTokenProvider = TokenOptions.DefaultEmailProvider;
- }, jwtBearerOptions =>
- {
- jwtBearerOptions.Audience = "bitwarden";
- jwtBearerOptions.Issuer = "bitwarden";
- jwtBearerOptions.TokenLifetime = TimeSpan.FromDays(10 * 365);
- jwtBearerOptions.TwoFactorTokenLifetime = TimeSpan.FromMinutes(10);
- var keyBytes = Encoding.ASCII.GetBytes(globalSettings.JwtSigningKey);
- jwtBearerOptions.SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(keyBytes), SecurityAlgorithms.HmacSha256);
- })
- .AddUserStore()
- .AddRoleStore()
- .AddTokenProvider(TwoFactorProviderType.Authenticator.ToString())
- .AddTokenProvider>(TokenOptions.DefaultEmailProvider);
+ services.AddCustomIdentityServices(globalSettings);
var jwtIdentityOptions = provider.GetRequiredService>().Value;
services.AddAuthorization(config =>
@@ -215,9 +137,8 @@ namespace Bit.Api
IApplicationLifetime appLifetime,
GlobalSettings globalSettings)
{
- if(env.IsProduction())
- {
- Func serilogFilter = (e) =>
+ loggerFactory
+ .AddSerilog(env, appLifetime, globalSettings, (e) =>
{
var context = e.Properties["SourceContext"].ToString();
if(e.Exception != null && (e.Exception.GetType() == typeof(SecurityTokenValidationException) ||
@@ -237,20 +158,8 @@ namespace Bit.Api
}
return e.Level >= LogEventLevel.Error;
- };
-
- var serilog = new LoggerConfiguration()
- .Enrich.FromLogContext()
- .Filter.ByIncludingOnly(serilogFilter)
- .WriteTo.AzureDocumentDB(new Uri(globalSettings.DocumentDb.Uri), globalSettings.DocumentDb.Key,
- timeToLive: TimeSpan.FromDays(7))
- .CreateLogger();
-
- loggerFactory.AddSerilog(serilog);
- appLifetime.ApplicationStopped.Register(Log.CloseAndFlush);
- }
-
- loggerFactory.AddDebug();
+ })
+ .AddDebug();
// Rate limiting
app.UseMiddleware();
diff --git a/src/Billing/Billing.csproj b/src/Billing/Billing.csproj
index 55a71a9037..4a3d37169f 100644
--- a/src/Billing/Billing.csproj
+++ b/src/Billing/Billing.csproj
@@ -24,8 +24,6 @@
-
-
diff --git a/src/Billing/Startup.cs b/src/Billing/Startup.cs
index 5007536ff6..a5bac1925c 100644
--- a/src/Billing/Startup.cs
+++ b/src/Billing/Startup.cs
@@ -1,7 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
@@ -9,6 +6,8 @@ using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Bit.Core;
using Stripe;
+using Bit.Core.Utilities;
+using Serilog.Events;
namespace Bit.Billing
{
@@ -39,10 +38,7 @@ namespace Bit.Billing
services.AddOptions();
// Settings
- var globalSettings = new GlobalSettings();
- ConfigurationBinder.Bind(Configuration.GetSection("GlobalSettings"), globalSettings);
- services.AddSingleton(s => globalSettings);
- services.Configure(Configuration.GetSection("BillingSettings"));
+ var globalSettings = services.AddGlobalSettingsServices(Configuration);
// Stripe Billing
StripeConfiguration.SetApiKey(globalSettings.StripeApiKey);
@@ -61,10 +57,17 @@ namespace Bit.Billing
services.AddMvc();
}
- public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
+ public void Configure(
+ IApplicationBuilder app,
+ IHostingEnvironment env,
+ IApplicationLifetime appLifetime,
+ GlobalSettings globalSettings,
+ ILoggerFactory loggerFactory)
{
- loggerFactory.AddConsole(Configuration.GetSection("Logging"));
- loggerFactory.AddDebug();
+ loggerFactory
+ .AddSerilog(env, appLifetime, globalSettings, (e) => e.Level >= LogEventLevel.Error)
+ .AddConsole()
+ .AddDebug();
app.UseMvc();
}
diff --git a/src/Billing/settings.json b/src/Billing/settings.json
index 2fa3e9db00..3414ba4825 100644
--- a/src/Billing/settings.json
+++ b/src/Billing/settings.json
@@ -1,10 +1,4 @@
{
- "Logging": {
- "IncludeScopes": false,
- "LogLevel": {
- "Default": "Warning"
- }
- },
"globalSettings": {
"siteName": "bitwarden",
"baseVaultUri": "http://localhost:4001/#",
diff --git a/src/Core/Core.csproj b/src/Core/Core.csproj
index 22ed7c4db7..42f42e08bb 100644
--- a/src/Core/Core.csproj
+++ b/src/Core/Core.csproj
@@ -15,13 +15,16 @@
+
-
-
+
+
+
+
diff --git a/src/Core/ServiceCollectionExtensions.cs b/src/Core/ServiceCollectionExtensions.cs
deleted file mode 100644
index 0af68ce060..0000000000
--- a/src/Core/ServiceCollectionExtensions.cs
+++ /dev/null
@@ -1,47 +0,0 @@
-using Bit.Core.Repositories;
-using Bit.Core.Services;
-using Microsoft.Extensions.DependencyInjection;
-using SqlServerRepos = Bit.Core.Repositories.SqlServer;
-
-namespace Bit.Core
-{
- public static class ServiceCollectionExtensions
- {
- public static void AddSqlServerRepositories(this IServiceCollection services)
- {
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- }
-
- public static void AddBaseServices(this IServiceCollection services)
- {
- services.AddSingleton();
- services.AddScoped();
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- }
-
- public static void AddDefaultServices(this IServiceCollection services)
- {
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- }
-
- public static void AddNoopServices(this IServiceCollection services)
- {
- services.AddSingleton();
- services.AddSingleton();
- services.AddSingleton();
- }
- }
-}
diff --git a/src/Core/Utilities/LoggerFactoryExtensions.cs b/src/Core/Utilities/LoggerFactoryExtensions.cs
new file mode 100644
index 0000000000..596ce6b428
--- /dev/null
+++ b/src/Core/Utilities/LoggerFactoryExtensions.cs
@@ -0,0 +1,39 @@
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.Extensions.Logging;
+using Serilog;
+using Serilog.Events;
+using System;
+
+namespace Bit.Core.Utilities
+{
+ public static class LoggerFactoryExtensions
+ {
+ public static ILoggerFactory AddSerilog(
+ this ILoggerFactory factory,
+ IHostingEnvironment env,
+ IApplicationLifetime appLifetime,
+ GlobalSettings globalSettings,
+ Func filter = null)
+ {
+ if(env.IsProduction())
+ {
+ if(filter == null)
+ {
+ filter = (e) => true;
+ }
+
+ var serilog = new LoggerConfiguration()
+ .Enrich.FromLogContext()
+ .Filter.ByIncludingOnly(filter)
+ .WriteTo.AzureDocumentDB(new Uri(globalSettings.DocumentDb.Uri), globalSettings.DocumentDb.Key,
+ timeToLive: TimeSpan.FromDays(7))
+ .CreateLogger();
+
+ factory.AddSerilog(serilog);
+ appLifetime.ApplicationStopped.Register(Log.CloseAndFlush);
+ }
+
+ return factory;
+ }
+ }
+}
diff --git a/src/Core/Utilities/ServiceCollectionExtensions.cs b/src/Core/Utilities/ServiceCollectionExtensions.cs
new file mode 100644
index 0000000000..ee2958feea
--- /dev/null
+++ b/src/Core/Utilities/ServiceCollectionExtensions.cs
@@ -0,0 +1,165 @@
+using Bit.Core.Enums;
+using Bit.Core.Identity;
+using Bit.Core.IdentityServer;
+using Bit.Core.Models.Table;
+using Bit.Core.Repositories;
+using Bit.Core.Services;
+using IdentityServer4.Services;
+using IdentityServer4.Stores;
+using IdentityServer4.Validation;
+using Microsoft.AspNetCore.DataProtection;
+using Microsoft.AspNetCore.Hosting;
+using Microsoft.AspNetCore.Identity;
+using Microsoft.Extensions.Configuration;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.IdentityModel.Tokens;
+using Microsoft.WindowsAzure.Storage;
+using System;
+using System.Security.Claims;
+using System.Text;
+using SqlServerRepos = Bit.Core.Repositories.SqlServer;
+
+namespace Bit.Core.Utilities
+{
+ public static class ServiceCollectionExtensions
+ {
+ public static void AddSqlServerRepositories(this IServiceCollection services)
+ {
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ }
+
+ public static void AddBaseServices(this IServiceCollection services)
+ {
+ services.AddSingleton();
+ services.AddScoped();
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ }
+
+ public static void AddDefaultServices(this IServiceCollection services)
+ {
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ }
+
+ public static void AddNoopServices(this IServiceCollection services)
+ {
+ services.AddSingleton();
+ services.AddSingleton();
+ services.AddSingleton();
+ }
+
+ public static IdentityBuilder AddCustomIdentityServices(
+ this IServiceCollection services, GlobalSettings globalSettings)
+ {
+ services.AddTransient();
+
+ var identityBuilder = services.AddJwtBearerIdentity(options =>
+ {
+ options.User = new UserOptions
+ {
+ RequireUniqueEmail = true,
+ AllowedUserNameCharacters = null // all
+ };
+ options.Password = new PasswordOptions
+ {
+ RequireDigit = false,
+ RequireLowercase = false,
+ RequiredLength = 8,
+ RequireNonAlphanumeric = false,
+ RequireUppercase = false
+ };
+ options.ClaimsIdentity = new ClaimsIdentityOptions
+ {
+ SecurityStampClaimType = "securitystamp",
+ UserNameClaimType = ClaimTypes.Email
+ };
+ options.Tokens.ChangeEmailTokenProvider = TokenOptions.DefaultEmailProvider;
+ }, jwtBearerOptions =>
+ {
+ jwtBearerOptions.Audience = "bitwarden";
+ jwtBearerOptions.Issuer = "bitwarden";
+ jwtBearerOptions.TokenLifetime = TimeSpan.FromDays(10 * 365);
+ jwtBearerOptions.TwoFactorTokenLifetime = TimeSpan.FromMinutes(10);
+ var keyBytes = Encoding.ASCII.GetBytes(globalSettings.JwtSigningKey);
+ jwtBearerOptions.SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(keyBytes), SecurityAlgorithms.HmacSha256);
+ });
+
+ identityBuilder
+ .AddUserStore()
+ .AddRoleStore()
+ .AddTokenProvider(TwoFactorProviderType.Authenticator.ToString())
+ .AddTokenProvider>(TokenOptions.DefaultEmailProvider);
+
+ return identityBuilder;
+ }
+
+ public static IIdentityServerBuilder AddCustomIdentityServerServices(
+ this IServiceCollection services, IHostingEnvironment env, GlobalSettings globalSettings)
+ {
+ var identityServerBuilder = services
+ .AddIdentityServer(options =>
+ {
+ options.Endpoints.EnableAuthorizeEndpoint = false;
+ options.Endpoints.EnableIntrospectionEndpoint = false;
+ options.Endpoints.EnableEndSessionEndpoint = false;
+ options.Endpoints.EnableUserInfoEndpoint = false;
+ options.Endpoints.EnableCheckSessionEndpoint = false;
+ options.Endpoints.EnableTokenRevocationEndpoint = false;
+ })
+ .AddInMemoryApiResources(ApiResources.GetApiResources())
+ .AddInMemoryClients(Clients.GetClients());
+
+ services.AddTransient();
+
+ if(env.IsProduction())
+ {
+ var identityServerCert = CoreHelpers.GetCertificate(globalSettings.IdentityServer.CertificateThumbprint);
+ identityServerBuilder.AddSigningCredential(identityServerCert);
+ }
+ else
+ {
+ identityServerBuilder.AddTemporarySigningCredential();
+ }
+
+ services.AddScoped();
+ services.AddScoped();
+ services.AddSingleton();
+
+ return identityServerBuilder;
+ }
+
+ public static void AddCustomDataProtectionServices(
+ this IServiceCollection services, IHostingEnvironment env, GlobalSettings globalSettings)
+ {
+ if(env.IsProduction())
+ {
+ var dataProtectionCert = CoreHelpers.GetCertificate(globalSettings.DataProtection.CertificateThumbprint);
+ var storageAccount = CloudStorageAccount.Parse(globalSettings.Storage.ConnectionString);
+ services.AddDataProtection()
+ .PersistKeysToAzureBlobStorage(storageAccount, "aspnet-dataprotection/keys.xml")
+ .ProtectKeysWithCertificate(dataProtectionCert);
+ }
+ }
+
+ public static GlobalSettings AddGlobalSettingsServices(this IServiceCollection services,
+ IConfigurationRoot root)
+ {
+ var globalSettings = new GlobalSettings();
+ ConfigurationBinder.Bind(root.GetSection("GlobalSettings"), globalSettings);
+ services.AddSingleton(s => globalSettings);
+ return globalSettings;
+ }
+ }
+}
diff --git a/src/Identity/Identity.csproj b/src/Identity/Identity.csproj
index 47dd9bbf4f..d659ae41b7 100644
--- a/src/Identity/Identity.csproj
+++ b/src/Identity/Identity.csproj
@@ -4,10 +4,13 @@
net461
Identity
Bit.Identity
+ 527b1fab-a4b5-465b-881a-f44f08c42899
+
+
diff --git a/src/Identity/Startup.cs b/src/Identity/Startup.cs
index 21a55bdab3..e6dcd05a00 100644
--- a/src/Identity/Startup.cs
+++ b/src/Identity/Startup.cs
@@ -4,24 +4,84 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
+using Microsoft.Extensions.Configuration;
+using Bit.Core;
+using Bit.Core.Utilities;
+using Serilog.Events;
namespace Bit.Identity
{
public class Startup
{
- public void ConfigureServices(IServiceCollection services)
+ public Startup(IHostingEnvironment env)
{
+ var builder = new ConfigurationBuilder()
+ .SetBasePath(env.ContentRootPath)
+ .AddJsonFile("settings.json")
+ .AddJsonFile($"settings.{env.EnvironmentName}.json", optional: true);
+
+ if(env.IsDevelopment())
+ {
+ builder.AddUserSecrets();
+ }
+
+ builder.AddEnvironmentVariables();
+
+ Configuration = builder.Build();
+ Environment = env;
}
- public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
+ public IConfigurationRoot Configuration { get; private set; }
+ public IHostingEnvironment Environment { get; set; }
+
+ public void ConfigureServices(IServiceCollection services)
{
- loggerFactory.AddConsole();
+ // Options
+ services.AddOptions();
+
+ // Settings
+ var globalSettings = services.AddGlobalSettingsServices(Configuration);
+
+ // Data Protection
+ services.AddCustomDataProtectionServices(Environment, globalSettings);
+
+ // Repositories
+ services.AddSqlServerRepositories();
+
+ // Context
+ services.AddScoped();
+
+ // IdentityServer
+ services.AddCustomIdentityServerServices(Environment, globalSettings);
+
+ // Identity
+ services.AddCustomIdentityServices(globalSettings);
+
+ // Services
+ services.AddBaseServices();
+ services.AddDefaultServices();
+ }
+
+ public void Configure(
+ IApplicationBuilder app,
+ IHostingEnvironment env,
+ ILoggerFactory loggerFactory,
+ IApplicationLifetime appLifetime,
+ GlobalSettings globalSettings)
+ {
+ loggerFactory
+ .AddSerilog(env, appLifetime, globalSettings, (e) => e.Level >= LogEventLevel.Error)
+ .AddConsole()
+ .AddDebug();
if(env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
+ // Add IdentityServer to the request pipeline.
+ app.UseIdentityServer();
+
app.Run(async (context) =>
{
await context.Response.WriteAsync("Hello World!");
diff --git a/src/Identity/settings.Preview.json b/src/Identity/settings.Preview.json
new file mode 100644
index 0000000000..3e61d2d4ce
--- /dev/null
+++ b/src/Identity/settings.Preview.json
@@ -0,0 +1,5 @@
+{
+ "globalSettings": {
+ "baseVaultUri": "https://preview-vault.bitwarden.com/#"
+ }
+}
diff --git a/src/Identity/settings.Production.json b/src/Identity/settings.Production.json
new file mode 100644
index 0000000000..8cb3e0000a
--- /dev/null
+++ b/src/Identity/settings.Production.json
@@ -0,0 +1,5 @@
+{
+ "globalSettings": {
+ "baseVaultUri": "https://vault.bitwarden.com/#"
+ }
+}
diff --git a/src/Identity/settings.Staging.json b/src/Identity/settings.Staging.json
new file mode 100644
index 0000000000..8cb3e0000a
--- /dev/null
+++ b/src/Identity/settings.Staging.json
@@ -0,0 +1,5 @@
+{
+ "globalSettings": {
+ "baseVaultUri": "https://vault.bitwarden.com/#"
+ }
+}
diff --git a/src/Identity/settings.json b/src/Identity/settings.json
new file mode 100644
index 0000000000..4470a98cd0
--- /dev/null
+++ b/src/Identity/settings.json
@@ -0,0 +1,35 @@
+{
+ "globalSettings": {
+ "siteName": "bitwarden",
+ "baseVaultUri": "http://localhost:4001/#",
+ "jwtSigningKey": "THIS IS A SECRET. IT KEEPS YOUR TOKEN SAFE. :)",
+ "stripeApiKey": "SECRET",
+ "sqlServer": {
+ "connectionString": "SECRET"
+ },
+ "mail": {
+ "apiKey": "SECRET",
+ "replyToEmail": "hello@bitwarden.com"
+ },
+ "push": {
+ "apnsCertificateThumbprint": "SECRET",
+ "apnsCertificatePassword": "SECRET",
+ "gcmSenderId": "SECRET",
+ "gcmApiKey": "SECRET",
+ "gcmAppPackageName": "com.x8bit.bitwarden"
+ },
+ "identityServer": {
+ "certificateThumbprint": "SECRET"
+ },
+ "dataProtection": {
+ "certificateThumbprint": "SECRET"
+ },
+ "storage": {
+ "connectionString": "SECRET"
+ },
+ "documentDb": {
+ "uri": "SECRET",
+ "key": "SECRET"
+ }
+ }
+}
diff --git a/src/Mail/Mail.csproj b/src/Mail/Mail.csproj
index 381e1a0f19..9ea040ab2f 100644
--- a/src/Mail/Mail.csproj
+++ b/src/Mail/Mail.csproj
@@ -21,7 +21,6 @@
-
diff --git a/src/Mail/Startup.cs b/src/Mail/Startup.cs
index 0435a6e9f1..9fba56ccbf 100644
--- a/src/Mail/Startup.cs
+++ b/src/Mail/Startup.cs
@@ -10,7 +10,6 @@ namespace Bit.Mail
public void Configure(IApplicationBuilder app)
{
app.UseFileServer();
- app.UseBrowserLink();
}
}
}