mirror of
https://github.com/bitwarden/server.git
synced 2025-05-27 14:24:56 -05:00

* Add Cipher attachment upload endpoints * Add validation bool to attachment storage data This bool is used to determine whether or not to renew upload links * Add model to request a new attachment to be made for later upload * Add model to respond with created attachment. The two cipher properties represent the two different cipher model types that can be returned. Cipher Response from personal items and mini response from organizations * Create Azure SAS-authorized upload links for both one-shot and block uploads * Add service methods to handle delayed upload and file size validation * Add emergency access method for downloading attachments direct from Azure * Add new attachment storage methods to other services * Update service interfaces * Log event grid exceptions * Limit Send and Attachment Size to 500MB * capitalize Key property * Add key validation to Azure Event Grid endpoint * Delete blob for unexpected blob creation events * Set Event Grid key at API startup * Change renew attachment upload url request path to match Send * Shore up attachment cleanup method. As long as we have the required information, we should always delete attachments from each the Repository, the cipher in memory, and the file storage service to ensure they're all synched.
235 lines
8.6 KiB
C#
235 lines
8.6 KiB
C#
using Microsoft.AspNetCore.Builder;
|
|
using Microsoft.AspNetCore.Hosting;
|
|
using Microsoft.Extensions.Configuration;
|
|
using Microsoft.Extensions.DependencyInjection;
|
|
using Microsoft.Extensions.Logging;
|
|
using Bit.Api.Utilities;
|
|
using Bit.Core;
|
|
using Bit.Core.Context;
|
|
using Bit.Core.Identity;
|
|
using Bit.Core.Settings;
|
|
using Newtonsoft.Json.Serialization;
|
|
using AspNetCoreRateLimit;
|
|
using Stripe;
|
|
using Bit.Core.Utilities;
|
|
using IdentityModel;
|
|
using System.Globalization;
|
|
using Microsoft.IdentityModel.Logging;
|
|
using Microsoft.Extensions.Hosting;
|
|
using Microsoft.OpenApi.Models;
|
|
using System.Collections.Generic;
|
|
using System;
|
|
|
|
namespace Bit.Api
|
|
{
|
|
public class Startup
|
|
{
|
|
public Startup(IWebHostEnvironment env, IConfiguration configuration)
|
|
{
|
|
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
|
|
Configuration = configuration;
|
|
Environment = env;
|
|
}
|
|
|
|
public IConfiguration Configuration { get; private set; }
|
|
public IWebHostEnvironment Environment { get; set; }
|
|
|
|
public void ConfigureServices(IServiceCollection services)
|
|
{
|
|
// Options
|
|
services.AddOptions();
|
|
|
|
// Settings
|
|
var globalSettings = services.AddGlobalSettingsServices(Configuration);
|
|
if (!globalSettings.SelfHosted)
|
|
{
|
|
services.Configure<IpRateLimitOptions>(Configuration.GetSection("IpRateLimitOptions"));
|
|
services.Configure<IpRateLimitPolicies>(Configuration.GetSection("IpRateLimitPolicies"));
|
|
}
|
|
|
|
// Data Protection
|
|
services.AddCustomDataProtectionServices(Environment, globalSettings);
|
|
|
|
// Event Grid
|
|
if (!string.IsNullOrWhiteSpace(globalSettings.EventGridKey))
|
|
{
|
|
ApiHelpers.EventGridKey = globalSettings.EventGridKey;
|
|
}
|
|
|
|
// Stripe Billing
|
|
StripeConfiguration.ApiKey = globalSettings.StripeApiKey;
|
|
|
|
// Repositories
|
|
services.AddSqlServerRepositories(globalSettings);
|
|
|
|
// Context
|
|
services.AddScoped<ICurrentContext, CurrentContext>();
|
|
|
|
// Caching
|
|
services.AddMemoryCache();
|
|
|
|
// BitPay
|
|
services.AddSingleton<BitPayClient>();
|
|
|
|
if (!globalSettings.SelfHosted)
|
|
{
|
|
// Rate limiting
|
|
services.AddSingleton<IIpPolicyStore, MemoryCacheIpPolicyStore>();
|
|
services.AddSingleton<IRateLimitCounterStore, MemoryCacheRateLimitCounterStore>();
|
|
}
|
|
|
|
// Identity
|
|
services.AddCustomIdentityServices(globalSettings);
|
|
services.AddIdentityAuthenticationServices(globalSettings, Environment, config =>
|
|
{
|
|
config.AddPolicy("Application", policy =>
|
|
{
|
|
policy.RequireAuthenticatedUser();
|
|
policy.RequireClaim(JwtClaimTypes.AuthenticationMethod, "Application", "external");
|
|
policy.RequireClaim(JwtClaimTypes.Scope, "api");
|
|
});
|
|
config.AddPolicy("Web", policy =>
|
|
{
|
|
policy.RequireAuthenticatedUser();
|
|
policy.RequireClaim(JwtClaimTypes.AuthenticationMethod, "Application", "external");
|
|
policy.RequireClaim(JwtClaimTypes.Scope, "api");
|
|
policy.RequireClaim(JwtClaimTypes.ClientId, "web");
|
|
});
|
|
config.AddPolicy("Push", policy =>
|
|
{
|
|
policy.RequireAuthenticatedUser();
|
|
policy.RequireClaim(JwtClaimTypes.Scope, "api.push");
|
|
});
|
|
config.AddPolicy("Licensing", policy =>
|
|
{
|
|
policy.RequireAuthenticatedUser();
|
|
policy.RequireClaim(JwtClaimTypes.Scope, "api.licensing");
|
|
});
|
|
config.AddPolicy("Organization", policy =>
|
|
{
|
|
policy.RequireAuthenticatedUser();
|
|
policy.RequireClaim(JwtClaimTypes.Scope, "api.organization");
|
|
});
|
|
});
|
|
|
|
services.AddScoped<AuthenticatorTokenProvider>();
|
|
|
|
// Services
|
|
services.AddBaseServices();
|
|
services.AddDefaultServices(globalSettings);
|
|
services.AddCoreLocalizationServices();
|
|
|
|
// Fido2
|
|
services.AddFido2(options =>
|
|
{
|
|
options.ServerDomain = new Uri(globalSettings.BaseServiceUri.Vault).Host;
|
|
options.ServerName = "Bitwarden";
|
|
options.Origin = globalSettings.BaseServiceUri.Vault;
|
|
options.TimestampDriftTolerance = 300000;
|
|
});
|
|
|
|
// MVC
|
|
services.AddMvc(config =>
|
|
{
|
|
config.Conventions.Add(new ApiExplorerGroupConvention());
|
|
config.Conventions.Add(new PublicApiControllersModelConvention());
|
|
}).AddNewtonsoftJson(options =>
|
|
{
|
|
if (Environment.IsProduction() && Configuration["swaggerGen"] != "true")
|
|
{
|
|
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
|
|
}
|
|
});
|
|
|
|
services.AddSwagger(globalSettings);
|
|
Jobs.JobsHostedService.AddJobsServices(services);
|
|
services.AddHostedService<Jobs.JobsHostedService>();
|
|
|
|
if (globalSettings.SelfHosted)
|
|
{
|
|
// Jobs service
|
|
Jobs.JobsHostedService.AddJobsServices(services);
|
|
services.AddHostedService<Jobs.JobsHostedService>();
|
|
}
|
|
if (CoreHelpers.SettingHasValue(globalSettings.ServiceBus.ConnectionString) &&
|
|
CoreHelpers.SettingHasValue(globalSettings.ServiceBus.ApplicationCacheTopicName))
|
|
{
|
|
services.AddHostedService<Core.HostedServices.ApplicationCacheHostedService>();
|
|
}
|
|
}
|
|
|
|
public void Configure(
|
|
IApplicationBuilder app,
|
|
IWebHostEnvironment env,
|
|
IHostApplicationLifetime appLifetime,
|
|
GlobalSettings globalSettings,
|
|
ILogger<Startup> logger)
|
|
{
|
|
IdentityModelEventSource.ShowPII = true;
|
|
app.UseSerilog(env, appLifetime, globalSettings);
|
|
|
|
// Default Middleware
|
|
app.UseDefaultMiddleware(env, globalSettings);
|
|
|
|
if (!globalSettings.SelfHosted)
|
|
{
|
|
// Rate limiting
|
|
app.UseMiddleware<CustomIpRateLimitMiddleware>();
|
|
}
|
|
else
|
|
{
|
|
app.UseForwardedHeaders(globalSettings);
|
|
}
|
|
|
|
// Add localization
|
|
app.UseCoreLocalization();
|
|
|
|
// Add static files to the request pipeline.
|
|
app.UseStaticFiles();
|
|
|
|
// Add routing
|
|
app.UseRouting();
|
|
|
|
// Add Cors
|
|
app.UseCors(policy => policy.SetIsOriginAllowed(o => CoreHelpers.IsCorsOriginAllowed(o, globalSettings))
|
|
.AllowAnyMethod().AllowAnyHeader().AllowCredentials());
|
|
|
|
// Add authentication and authorization to the request pipeline.
|
|
app.UseAuthentication();
|
|
app.UseAuthorization();
|
|
|
|
// Add current context
|
|
app.UseMiddleware<CurrentContextMiddleware>();
|
|
|
|
// Add endpoints to the request pipeline.
|
|
app.UseEndpoints(endpoints => endpoints.MapDefaultControllerRoute());
|
|
|
|
// Add Swagger
|
|
if (Environment.IsDevelopment() || globalSettings.SelfHosted)
|
|
{
|
|
app.UseSwagger(config =>
|
|
{
|
|
config.RouteTemplate = "specs/{documentName}/swagger.json";
|
|
config.PreSerializeFilters.Add((swaggerDoc, httpReq) =>
|
|
swaggerDoc.Servers = new List<OpenApiServer>
|
|
{
|
|
new OpenApiServer { Url = globalSettings.BaseServiceUri.Api }
|
|
});
|
|
});
|
|
app.UseSwaggerUI(config =>
|
|
{
|
|
config.DocumentTitle = "Bitwarden API Documentation";
|
|
config.RoutePrefix = "docs";
|
|
config.SwaggerEndpoint($"{globalSettings.BaseServiceUri.Api}/specs/public/swagger.json",
|
|
"Bitwarden Public API");
|
|
config.OAuthClientId("accountType.id");
|
|
config.OAuthClientSecret("secretKey");
|
|
});
|
|
}
|
|
|
|
// Log startup
|
|
logger.LogInformation(Constants.BypassFiltersEventId, globalSettings.ProjectName + " started.");
|
|
}
|
|
}
|
|
}
|