1
0
mirror of https://github.com/bitwarden/server.git synced 2025-06-30 15:42:48 -05:00

Run formatting (#2230)

This commit is contained in:
Justin Baur
2022-08-29 16:06:55 -04:00
committed by GitHub
parent 9b7aef0763
commit 7f5f010e1e
1205 changed files with 73813 additions and 75022 deletions

View File

@ -4,29 +4,28 @@ using System.Runtime.CompilerServices;
using Bit.Core.Utilities;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit
namespace Bit;
// This file is a manual addition to a project that it helps, a project that chooses to compile it
// should have a projet reference to Core.csproj and a package reference to Microsoft.EntityFrameworkCore.Design
// The reason for this is that if it belonged to it's own library you would have to add manual references to the above
// and manage the version for the EntityFrameworkCore package. This way it also doesn't create another dll
// To include this you can view examples in the MySqlMigrations and PostgresMigrations .csproj files.
// <Compile Include="..\EfShared\MigrationBuilderExtensions.cs" />
public static class MigrationBuilderExtensions
{
// This file is a manual addition to a project that it helps, a project that chooses to compile it
// should have a projet reference to Core.csproj and a package reference to Microsoft.EntityFrameworkCore.Design
// The reason for this is that if it belonged to it's own library you would have to add manual references to the above
// and manage the version for the EntityFrameworkCore package. This way it also doesn't create another dll
// To include this you can view examples in the MySqlMigrations and PostgresMigrations .csproj files.
// <Compile Include="..\EfShared\MigrationBuilderExtensions.cs" />
public static class MigrationBuilderExtensions
/// <summary>
/// Reads an embedded resource for it's SQL contents and formats it with the specified direction for easier custom migration steps
/// </summary>
/// <param name="migrationBuilder">The MigrationBuilder instance the sql should be applied to</param>
/// <param name="resourceName">The file name portion of the resource name, it is assumed to be in a Scripts folder</param>
/// <param name="dir">The direction of the migration taking place</param>
public static void SqlResource(this MigrationBuilder migrationBuilder, string resourceName, [CallerMemberName] string dir = null)
{
/// <summary>
/// Reads an embedded resource for it's SQL contents and formats it with the specified direction for easier custom migration steps
/// </summary>
/// <param name="migrationBuilder">The MigrationBuilder instance the sql should be applied to</param>
/// <param name="resourceName">The file name portion of the resource name, it is assumed to be in a Scripts folder</param>
/// <param name="dir">The direction of the migration taking place</param>
public static void SqlResource(this MigrationBuilder migrationBuilder, string resourceName, [CallerMemberName] string dir = null)
{
var formattedResourceName = string.IsNullOrEmpty(dir) ? resourceName : string.Format(resourceName, dir);
var formattedResourceName = string.IsNullOrEmpty(dir) ? resourceName : string.Format(resourceName, dir);
migrationBuilder.Sql(CoreHelpers.GetEmbeddedResourceContentsAsync(
$"Scripts.{formattedResourceName}"));
}
migrationBuilder.Sql(CoreHelpers.GetEmbeddedResourceContentsAsync(
$"Scripts.{formattedResourceName}"));
}
}

View File

@ -5,104 +5,103 @@ using Bit.Core;
using DbUp;
using Microsoft.Extensions.Logging;
namespace Bit.Migrator
namespace Bit.Migrator;
public class DbMigrator
{
public class DbMigrator
private readonly string _connectionString;
private readonly ILogger<DbMigrator> _logger;
private readonly string _masterConnectionString;
public DbMigrator(string connectionString, ILogger<DbMigrator> logger)
{
private readonly string _connectionString;
private readonly ILogger<DbMigrator> _logger;
private readonly string _masterConnectionString;
public DbMigrator(string connectionString, ILogger<DbMigrator> logger)
_connectionString = connectionString;
_logger = logger;
_masterConnectionString = new SqlConnectionStringBuilder(connectionString)
{
_connectionString = connectionString;
_logger = logger;
_masterConnectionString = new SqlConnectionStringBuilder(connectionString)
{
InitialCatalog = "master"
}.ConnectionString;
InitialCatalog = "master"
}.ConnectionString;
}
public bool MigrateMsSqlDatabase(bool enableLogging = true,
CancellationToken cancellationToken = default(CancellationToken))
{
if (enableLogging && _logger != null)
{
_logger.LogInformation(Constants.BypassFiltersEventId, "Migrating database.");
}
public bool MigrateMsSqlDatabase(bool enableLogging = true,
CancellationToken cancellationToken = default(CancellationToken))
using (var connection = new SqlConnection(_masterConnectionString))
{
if (enableLogging && _logger != null)
var databaseName = new SqlConnectionStringBuilder(_connectionString).InitialCatalog;
if (string.IsNullOrWhiteSpace(databaseName))
{
_logger.LogInformation(Constants.BypassFiltersEventId, "Migrating database.");
databaseName = "vault";
}
using (var connection = new SqlConnection(_masterConnectionString))
{
var databaseName = new SqlConnectionStringBuilder(_connectionString).InitialCatalog;
if (string.IsNullOrWhiteSpace(databaseName))
{
databaseName = "vault";
}
var databaseNameQuoted = new SqlCommandBuilder().QuoteIdentifier(databaseName);
var command = new SqlCommand(
"IF ((SELECT COUNT(1) FROM sys.databases WHERE [name] = @DatabaseName) = 0) " +
"CREATE DATABASE " + databaseNameQuoted + ";", connection);
command.Parameters.Add("@DatabaseName", SqlDbType.VarChar).Value = databaseName;
command.Connection.Open();
command.ExecuteNonQuery();
var databaseNameQuoted = new SqlCommandBuilder().QuoteIdentifier(databaseName);
var command = new SqlCommand(
"IF ((SELECT COUNT(1) FROM sys.databases WHERE [name] = @DatabaseName) = 0) " +
"CREATE DATABASE " + databaseNameQuoted + ";", connection);
command.Parameters.Add("@DatabaseName", SqlDbType.VarChar).Value = databaseName;
command.Connection.Open();
command.ExecuteNonQuery();
command.CommandText = "IF ((SELECT DATABASEPROPERTYEX([name], 'IsAutoClose') " +
"FROM sys.databases WHERE [name] = @DatabaseName) = 1) " +
"ALTER DATABASE " + databaseNameQuoted + " SET AUTO_CLOSE OFF;";
command.ExecuteNonQuery();
}
cancellationToken.ThrowIfCancellationRequested();
using (var connection = new SqlConnection(_connectionString))
{
// Rename old migration scripts to new namespace.
var command = new SqlCommand(
"IF OBJECT_ID('Migration','U') IS NOT NULL " +
"UPDATE [dbo].[Migration] SET " +
"[ScriptName] = REPLACE([ScriptName], 'Bit.Setup.', 'Bit.Migrator.');", connection);
command.Connection.Open();
command.ExecuteNonQuery();
}
cancellationToken.ThrowIfCancellationRequested();
var builder = DeployChanges.To
.SqlDatabase(_connectionString)
.JournalToSqlTable("dbo", "Migration")
.WithScriptsAndCodeEmbeddedInAssembly(Assembly.GetExecutingAssembly(),
s => s.Contains($".DbScripts.") && !s.Contains(".Archive."))
.WithTransaction()
.WithExecutionTimeout(new TimeSpan(0, 5, 0));
if (enableLogging)
{
if (_logger != null)
{
builder.LogTo(new DbUpLogger(_logger));
}
else
{
builder.LogToConsole();
}
}
var upgrader = builder.Build();
var result = upgrader.PerformUpgrade();
if (enableLogging && _logger != null)
{
if (result.Successful)
{
_logger.LogInformation(Constants.BypassFiltersEventId, "Migration successful.");
}
else
{
_logger.LogError(Constants.BypassFiltersEventId, result.Error, "Migration failed.");
}
}
cancellationToken.ThrowIfCancellationRequested();
return result.Successful;
command.CommandText = "IF ((SELECT DATABASEPROPERTYEX([name], 'IsAutoClose') " +
"FROM sys.databases WHERE [name] = @DatabaseName) = 1) " +
"ALTER DATABASE " + databaseNameQuoted + " SET AUTO_CLOSE OFF;";
command.ExecuteNonQuery();
}
cancellationToken.ThrowIfCancellationRequested();
using (var connection = new SqlConnection(_connectionString))
{
// Rename old migration scripts to new namespace.
var command = new SqlCommand(
"IF OBJECT_ID('Migration','U') IS NOT NULL " +
"UPDATE [dbo].[Migration] SET " +
"[ScriptName] = REPLACE([ScriptName], 'Bit.Setup.', 'Bit.Migrator.');", connection);
command.Connection.Open();
command.ExecuteNonQuery();
}
cancellationToken.ThrowIfCancellationRequested();
var builder = DeployChanges.To
.SqlDatabase(_connectionString)
.JournalToSqlTable("dbo", "Migration")
.WithScriptsAndCodeEmbeddedInAssembly(Assembly.GetExecutingAssembly(),
s => s.Contains($".DbScripts.") && !s.Contains(".Archive."))
.WithTransaction()
.WithExecutionTimeout(new TimeSpan(0, 5, 0));
if (enableLogging)
{
if (_logger != null)
{
builder.LogTo(new DbUpLogger(_logger));
}
else
{
builder.LogToConsole();
}
}
var upgrader = builder.Build();
var result = upgrader.PerformUpgrade();
if (enableLogging && _logger != null)
{
if (result.Successful)
{
_logger.LogInformation(Constants.BypassFiltersEventId, "Migration successful.");
}
else
{
_logger.LogError(Constants.BypassFiltersEventId, result.Error, "Migration failed.");
}
}
cancellationToken.ThrowIfCancellationRequested();
return result.Successful;
}
}

View File

@ -2,30 +2,29 @@
using DbUp.Engine.Output;
using Microsoft.Extensions.Logging;
namespace Bit.Migrator
namespace Bit.Migrator;
public class DbUpLogger : IUpgradeLog
{
public class DbUpLogger : IUpgradeLog
private readonly ILogger _logger;
public DbUpLogger(ILogger logger)
{
private readonly ILogger _logger;
_logger = logger;
}
public DbUpLogger(ILogger logger)
{
_logger = logger;
}
public void WriteError(string format, params object[] args)
{
_logger.LogError(Constants.BypassFiltersEventId, format, args);
}
public void WriteError(string format, params object[] args)
{
_logger.LogError(Constants.BypassFiltersEventId, format, args);
}
public void WriteInformation(string format, params object[] args)
{
_logger.LogInformation(Constants.BypassFiltersEventId, format, args);
}
public void WriteInformation(string format, params object[] args)
{
_logger.LogInformation(Constants.BypassFiltersEventId, format, args);
}
public void WriteWarning(string format, params object[] args)
{
_logger.LogWarning(Constants.BypassFiltersEventId, format, args);
}
public void WriteWarning(string format, params object[] args)
{
_logger.LogWarning(Constants.BypassFiltersEventId, format, args);
}
}

View File

@ -4,35 +4,34 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
namespace MySqlMigrations
{
public static class GlobalSettingsFactory
{
public static GlobalSettings GlobalSettings { get; } = new GlobalSettings();
static GlobalSettingsFactory()
{
var configBuilder = new ConfigurationBuilder().AddUserSecrets<Bit.Api.Startup>();
var Configuration = configBuilder.Build();
ConfigurationBinder.Bind(Configuration.GetSection("GlobalSettings"), GlobalSettings);
}
}
namespace MySqlMigrations;
public class DatabaseContextFactory : IDesignTimeDbContextFactory<DatabaseContext>
public static class GlobalSettingsFactory
{
public static GlobalSettings GlobalSettings { get; } = new GlobalSettings();
static GlobalSettingsFactory()
{
public DatabaseContext CreateDbContext(string[] args)
{
var globalSettings = GlobalSettingsFactory.GlobalSettings;
var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
var connectionString = globalSettings.MySql?.ConnectionString;
if (string.IsNullOrWhiteSpace(connectionString))
{
throw new Exception("No MySql connection string found.");
}
optionsBuilder.UseMySql(
connectionString,
ServerVersion.AutoDetect(connectionString),
b => b.MigrationsAssembly("MySqlMigrations"));
return new DatabaseContext(optionsBuilder.Options);
}
var configBuilder = new ConfigurationBuilder().AddUserSecrets<Bit.Api.Startup>();
var Configuration = configBuilder.Build();
ConfigurationBinder.Bind(Configuration.GetSection("GlobalSettings"), GlobalSettings);
}
}
public class DatabaseContextFactory : IDesignTimeDbContextFactory<DatabaseContext>
{
public DatabaseContext CreateDbContext(string[] args)
{
var globalSettings = GlobalSettingsFactory.GlobalSettings;
var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
var connectionString = globalSettings.MySql?.ConnectionString;
if (string.IsNullOrWhiteSpace(connectionString))
{
throw new Exception("No MySql connection string found.");
}
optionsBuilder.UseMySql(
connectionString,
ServerVersion.AutoDetect(connectionString),
b => b.MigrationsAssembly("MySqlMigrations"));
return new DatabaseContext(optionsBuilder.Options);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,90 +1,89 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
namespace Bit.MySqlMigrations.Migrations;
public partial class RemoveProviderOrganizationProviderUser : Migration
{
public partial class RemoveProviderOrganizationProviderUser : Migration
protected override void Up(MigrationBuilder migrationBuilder)
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ProviderOrganizationProviderUser");
migrationBuilder.DropTable(
name: "ProviderOrganizationProviderUser");
migrationBuilder.AddColumn<bool>(
name: "UseEvents",
table: "Provider",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "UseEvents",
table: "Provider",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<Guid>(
name: "ProviderId",
table: "Event",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci");
migrationBuilder.AddColumn<Guid>(
name: "ProviderId",
table: "Event",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci");
migrationBuilder.AddColumn<Guid>(
name: "ProviderUserId",
table: "Event",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci");
}
migrationBuilder.AddColumn<Guid>(
name: "ProviderUserId",
table: "Event",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UseEvents",
table: "Provider");
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UseEvents",
table: "Provider");
migrationBuilder.DropColumn(
name: "ProviderId",
table: "Event");
migrationBuilder.DropColumn(
name: "ProviderId",
table: "Event");
migrationBuilder.DropColumn(
name: "ProviderUserId",
table: "Event");
migrationBuilder.DropColumn(
name: "ProviderUserId",
table: "Event");
migrationBuilder.CreateTable(
name: "ProviderOrganizationProviderUser",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
CreationDate = table.Column<DateTime>(type: "datetime(6)", nullable: false),
Permissions = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
ProviderOrganizationId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
ProviderUserId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
RevisionDate = table.Column<DateTime>(type: "datetime(6)", nullable: false),
Type = table.Column<byte>(type: "tinyint unsigned", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ProviderOrganizationProviderUser", x => x.Id);
table.ForeignKey(
name: "FK_ProviderOrganizationProviderUser_ProviderOrganization_Provid~",
column: x => x.ProviderOrganizationId,
principalTable: "ProviderOrganization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ProviderOrganizationProviderUser_ProviderUser_ProviderUserId",
column: x => x.ProviderUserId,
principalTable: "ProviderUser",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "ProviderOrganizationProviderUser",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
CreationDate = table.Column<DateTime>(type: "datetime(6)", nullable: false),
Permissions = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
ProviderOrganizationId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
ProviderUserId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
RevisionDate = table.Column<DateTime>(type: "datetime(6)", nullable: false),
Type = table.Column<byte>(type: "tinyint unsigned", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ProviderOrganizationProviderUser", x => x.Id);
table.ForeignKey(
name: "FK_ProviderOrganizationProviderUser_ProviderOrganization_Provid~",
column: x => x.ProviderOrganizationId,
principalTable: "ProviderOrganization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ProviderOrganizationProviderUser_ProviderUser_ProviderUserId",
column: x => x.ProviderUserId,
principalTable: "ProviderUser",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_ProviderOrganizationProviderUser_ProviderOrganizationId",
table: "ProviderOrganizationProviderUser",
column: "ProviderOrganizationId");
migrationBuilder.CreateIndex(
name: "IX_ProviderOrganizationProviderUser_ProviderOrganizationId",
table: "ProviderOrganizationProviderUser",
column: "ProviderOrganizationId");
migrationBuilder.CreateIndex(
name: "IX_ProviderOrganizationProviderUser_ProviderUserId",
table: "ProviderOrganizationProviderUser",
column: "ProviderUserId");
}
migrationBuilder.CreateIndex(
name: "IX_ProviderOrganizationProviderUser_ProviderUserId",
table: "ProviderOrganizationProviderUser",
column: "ProviderUserId");
}
}

View File

@ -1,24 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
{
public partial class UserForcePasswordReset : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "ForcePasswordReset",
table: "User",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
}
namespace Bit.MySqlMigrations.Migrations;
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ForcePasswordReset",
table: "User");
}
public partial class UserForcePasswordReset : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "ForcePasswordReset",
table: "User",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ForcePasswordReset",
table: "User");
}
}

View File

@ -1,44 +1,43 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
namespace Bit.MySqlMigrations.Migrations;
public partial class AddMaxAutoscaleSeatsToOrganization : Migration
{
public partial class AddMaxAutoscaleSeatsToOrganization : Migration
protected override void Up(MigrationBuilder migrationBuilder)
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "MaxAutoscaleSeats",
table: "Organization",
type: "int",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "MaxAutoscaleSeats",
table: "Organization",
type: "int",
nullable: true);
migrationBuilder.AddColumn<DateTime>(
name: "OwnersNotifiedOfAutoscaling",
table: "Organization",
type: "datetime(6)",
nullable: true);
migrationBuilder.AddColumn<DateTime>(
name: "OwnersNotifiedOfAutoscaling",
table: "Organization",
type: "datetime(6)",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "ProviderOrganizationId",
table: "Event",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci");
}
migrationBuilder.AddColumn<Guid>(
name: "ProviderOrganizationId",
table: "Event",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MaxAutoscaleSeats",
table: "Organization");
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MaxAutoscaleSeats",
table: "Organization");
migrationBuilder.DropColumn(
name: "OwnersNotifiedOfAutoscaling",
table: "Organization");
migrationBuilder.DropColumn(
name: "OwnersNotifiedOfAutoscaling",
table: "Organization");
migrationBuilder.DropColumn(
name: "ProviderOrganizationId",
table: "Event");
}
migrationBuilder.DropColumn(
name: "ProviderOrganizationId",
table: "Event");
}
}

View File

@ -1,21 +1,20 @@
using Bit.Core.Utilities;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
namespace Bit.MySqlMigrations.Migrations;
public partial class SplitManageCollectionsPermissions2 : Migration
{
public partial class SplitManageCollectionsPermissions2 : Migration
private const string _scriptLocation =
"MySqlMigrations.Scripts.2021-09-21_01_SplitManageCollectionsPermission.sql";
protected override void Up(MigrationBuilder migrationBuilder)
{
private const string _scriptLocation =
"MySqlMigrations.Scripts.2021-09-21_01_SplitManageCollectionsPermission.sql";
migrationBuilder.Sql(CoreHelpers.GetEmbeddedResourceContentsAsync(_scriptLocation));
}
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(CoreHelpers.GetEmbeddedResourceContentsAsync(_scriptLocation));
}
protected override void Down(MigrationBuilder migrationBuilder)
{
throw new Exception("Irreversible migration");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
throw new Exception("Irreversible migration");
}
}

View File

@ -1,21 +1,20 @@
using Bit.Core.Utilities;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
namespace Bit.MySqlMigrations.Migrations;
public partial class SetMaxAutoscaleSeatsToCurrentSeatCount : Migration
{
public partial class SetMaxAutoscaleSeatsToCurrentSeatCount : Migration
private const string _scriptLocation =
"MySqlMigrations.Scripts.2021-10-21_00_SetMaxAutoscaleSeatCount.sql";
protected override void Up(MigrationBuilder migrationBuilder)
{
private const string _scriptLocation =
"MySqlMigrations.Scripts.2021-10-21_00_SetMaxAutoscaleSeatCount.sql";
migrationBuilder.Sql(CoreHelpers.GetEmbeddedResourceContentsAsync(_scriptLocation));
}
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(CoreHelpers.GetEmbeddedResourceContentsAsync(_scriptLocation));
}
protected override void Down(MigrationBuilder migrationBuilder)
{
throw new Exception("Irreversible migration");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
throw new Exception("Irreversible migration");
}
}

View File

@ -1,24 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
{
public partial class KeyConnector : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UsesKeyConnector",
table: "User",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
}
namespace Bit.MySqlMigrations.Migrations;
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UsesKeyConnector",
table: "User");
}
public partial class KeyConnector : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UsesKeyConnector",
table: "User",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UsesKeyConnector",
table: "User");
}
}

View File

@ -1,85 +1,84 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
namespace Bit.MySqlMigrations.Migrations;
public partial class OrganizationSponsorship : Migration
{
public partial class OrganizationSponsorship : Migration
protected override void Up(MigrationBuilder migrationBuilder)
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UsesCryptoAgent",
table: "User",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "UsesCryptoAgent",
table: "User",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
migrationBuilder.CreateTable(
name: "OrganizationSponsorship",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
InstallationId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
SponsoringOrganizationId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
SponsoringOrganizationUserId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
SponsoredOrganizationId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
FriendlyName = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
OfferedToEmail = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
PlanSponsorshipType = table.Column<byte>(type: "tinyint unsigned", nullable: true),
CloudSponsor = table.Column<bool>(type: "tinyint(1)", nullable: false),
LastSyncDate = table.Column<DateTime>(type: "datetime(6)", nullable: true),
TimesRenewedWithoutValidation = table.Column<byte>(type: "tinyint unsigned", nullable: false),
SponsorshipLapsedDate = table.Column<DateTime>(type: "datetime(6)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationSponsorship", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationSponsorship_Installation_InstallationId",
column: x => x.InstallationId,
principalTable: "Installation",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoredOrganizationId",
column: x => x.SponsoredOrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
column: x => x.SponsoringOrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "OrganizationSponsorship",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
InstallationId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
SponsoringOrganizationId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
SponsoringOrganizationUserId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
SponsoredOrganizationId = table.Column<Guid>(type: "char(36)", nullable: true, collation: "ascii_general_ci"),
FriendlyName = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
OfferedToEmail = table.Column<string>(type: "varchar(256)", maxLength: 256, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
PlanSponsorshipType = table.Column<byte>(type: "tinyint unsigned", nullable: true),
CloudSponsor = table.Column<bool>(type: "tinyint(1)", nullable: false),
LastSyncDate = table.Column<DateTime>(type: "datetime(6)", nullable: true),
TimesRenewedWithoutValidation = table.Column<byte>(type: "tinyint unsigned", nullable: false),
SponsorshipLapsedDate = table.Column<DateTime>(type: "datetime(6)", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationSponsorship", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationSponsorship_Installation_InstallationId",
column: x => x.InstallationId,
principalTable: "Installation",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoredOrganizationId",
column: x => x.SponsoredOrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
column: x => x.SponsoringOrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_InstallationId",
table: "OrganizationSponsorship",
column: "InstallationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_InstallationId",
table: "OrganizationSponsorship",
column: "InstallationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_SponsoredOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoredOrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_SponsoredOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoredOrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_SponsoringOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId");
}
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_SponsoringOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "OrganizationSponsorship");
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "OrganizationSponsorship");
migrationBuilder.DropColumn(
name: "UsesCryptoAgent",
table: "User");
}
migrationBuilder.DropColumn(
name: "UsesCryptoAgent",
table: "User");
}
}

View File

@ -1,24 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
{
public partial class KeyConnectorFlag : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UseKeyConnector",
table: "Organization",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
}
namespace Bit.MySqlMigrations.Migrations;
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UseKeyConnector",
table: "Organization");
}
public partial class KeyConnectorFlag : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UseKeyConnector",
table: "Organization",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UseKeyConnector",
table: "Organization");
}
}

View File

@ -1,51 +1,50 @@
using Microsoft.EntityFrameworkCore.Metadata;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
namespace Bit.MySqlMigrations.Migrations;
public partial class RemoveU2F : Migration
{
public partial class RemoveU2F : Migration
protected override void Up(MigrationBuilder migrationBuilder)
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "U2f");
}
migrationBuilder.DropTable(
name: "U2f");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "U2f",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
AppId = table.Column<string>(type: "varchar(50)", maxLength: 50, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
Challenge = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
CreationDate = table.Column<DateTime>(type: "datetime(6)", nullable: false),
KeyHandle = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
UserId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Version = table.Column<string>(type: "varchar(20)", maxLength: 20, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_U2f", x => x.Id);
table.ForeignKey(
name: "FK_U2f_User_UserId",
column: x => x.UserId,
principalTable: "User",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "U2f",
columns: table => new
{
Id = table.Column<int>(type: "int", nullable: false)
.Annotation("MySql:ValueGenerationStrategy", MySqlValueGenerationStrategy.IdentityColumn),
AppId = table.Column<string>(type: "varchar(50)", maxLength: 50, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
Challenge = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
CreationDate = table.Column<DateTime>(type: "datetime(6)", nullable: false),
KeyHandle = table.Column<string>(type: "varchar(200)", maxLength: 200, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
UserId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Version = table.Column<string>(type: "varchar(20)", maxLength: 20, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_U2f", x => x.Id);
table.ForeignKey(
name: "FK_U2f_User_UserId",
column: x => x.UserId,
principalTable: "User",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_U2f_UserId",
table: "U2f",
column: "UserId");
}
migrationBuilder.CreateIndex(
name: "IX_U2f_UserId",
table: "U2f",
column: "UserId");
}
}

View File

@ -1,34 +1,33 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
namespace Bit.MySqlMigrations.Migrations;
public partial class FailedLoginCaptcha : Migration
{
public partial class FailedLoginCaptcha : Migration
protected override void Up(MigrationBuilder migrationBuilder)
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "FailedLoginCount",
table: "User",
type: "int",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<int>(
name: "FailedLoginCount",
table: "User",
type: "int",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<DateTime>(
name: "LastFailedLoginDate",
table: "User",
type: "datetime(6)",
nullable: true);
}
migrationBuilder.AddColumn<DateTime>(
name: "LastFailedLoginDate",
table: "User",
type: "datetime(6)",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "FailedLoginCount",
table: "User");
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "FailedLoginCount",
table: "User");
migrationBuilder.DropColumn(
name: "LastFailedLoginDate",
table: "User");
}
migrationBuilder.DropColumn(
name: "LastFailedLoginDate",
table: "User");
}
}

View File

@ -1,158 +1,157 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
namespace Bit.MySqlMigrations.Migrations;
public partial class SelfHostF4E : Migration
{
public partial class SelfHostF4E : Migration
private const string _scriptLocationTemplate = "2022-03-01_00_{0}_MigrateOrganizationApiKeys.sql";
protected override void Up(MigrationBuilder migrationBuilder)
{
private const string _scriptLocationTemplate = "2022-03-01_00_{0}_MigrateOrganizationApiKeys.sql";
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Installation_InstallationId",
table: "OrganizationSponsorship");
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Installation_InstallationId",
table: "OrganizationSponsorship");
migrationBuilder.DropIndex(
name: "IX_OrganizationSponsorship_InstallationId",
table: "OrganizationSponsorship");
migrationBuilder.DropIndex(
name: "IX_OrganizationSponsorship_InstallationId",
table: "OrganizationSponsorship");
migrationBuilder.DropColumn(
name: "InstallationId",
table: "OrganizationSponsorship");
migrationBuilder.DropColumn(
name: "InstallationId",
table: "OrganizationSponsorship");
migrationBuilder.DropColumn(
name: "TimesRenewedWithoutValidation",
table: "OrganizationSponsorship");
migrationBuilder.DropColumn(
name: "TimesRenewedWithoutValidation",
table: "OrganizationSponsorship");
migrationBuilder.CreateTable(
name: "OrganizationApiKey",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
OrganizationId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Type = table.Column<byte>(type: "tinyint unsigned", nullable: false),
ApiKey = table.Column<string>(type: "varchar(30)", maxLength: 30, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
RevisionDate = table.Column<DateTime>(type: "datetime(6)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationApiKey", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationApiKey_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "OrganizationApiKey",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
OrganizationId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Type = table.Column<byte>(type: "tinyint unsigned", nullable: false),
ApiKey = table.Column<string>(type: "varchar(30)", maxLength: 30, nullable: true)
.Annotation("MySql:CharSet", "utf8mb4"),
RevisionDate = table.Column<DateTime>(type: "datetime(6)", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationApiKey", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationApiKey_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.SqlResource(_scriptLocationTemplate);
migrationBuilder.SqlResource(_scriptLocationTemplate);
migrationBuilder.DropColumn(
name: "ApiKey",
table: "Organization");
migrationBuilder.DropColumn(
name: "ApiKey",
table: "Organization");
migrationBuilder.RenameColumn(
name: "SponsorshipLapsedDate",
table: "OrganizationSponsorship",
newName: "ValidUntil");
migrationBuilder.RenameColumn(
name: "SponsorshipLapsedDate",
table: "OrganizationSponsorship",
newName: "ValidUntil");
migrationBuilder.RenameColumn(
name: "CloudSponsor",
table: "OrganizationSponsorship",
newName: "ToDelete");
migrationBuilder.RenameColumn(
name: "CloudSponsor",
table: "OrganizationSponsorship",
newName: "ToDelete");
migrationBuilder.CreateTable(
name: "OrganizationConnection",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Type = table.Column<byte>(type: "tinyint unsigned", nullable: false),
OrganizationId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Enabled = table.Column<bool>(type: "tinyint(1)", nullable: false),
Config = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationConnection", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationConnection_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateTable(
name: "OrganizationConnection",
columns: table => new
{
Id = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Type = table.Column<byte>(type: "tinyint unsigned", nullable: false),
OrganizationId = table.Column<Guid>(type: "char(36)", nullable: false, collation: "ascii_general_ci"),
Enabled = table.Column<bool>(type: "tinyint(1)", nullable: false),
Config = table.Column<string>(type: "longtext", nullable: true)
.Annotation("MySql:CharSet", "utf8mb4")
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationConnection", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationConnection_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
})
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.CreateIndex(
name: "IX_OrganizationApiKey_OrganizationId",
table: "OrganizationApiKey",
column: "OrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationApiKey_OrganizationId",
table: "OrganizationApiKey",
column: "OrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationConnection_OrganizationId",
table: "OrganizationConnection",
column: "OrganizationId");
}
migrationBuilder.CreateIndex(
name: "IX_OrganizationConnection_OrganizationId",
table: "OrganizationConnection",
column: "OrganizationId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "ApiKey",
table: "Organization",
type: "varchar(30)",
maxLength: 30,
nullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "ApiKey",
table: "Organization",
type: "varchar(30)",
maxLength: 30,
nullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.SqlResource(_scriptLocationTemplate);
migrationBuilder.SqlResource(_scriptLocationTemplate);
migrationBuilder.DropTable(
name: "OrganizationApiKey");
migrationBuilder.DropTable(
name: "OrganizationApiKey");
migrationBuilder.DropTable(
name: "OrganizationConnection");
migrationBuilder.DropTable(
name: "OrganizationConnection");
migrationBuilder.RenameColumn(
name: "ValidUntil",
table: "OrganizationSponsorship",
newName: "SponsorshipLapsedDate");
migrationBuilder.RenameColumn(
name: "ValidUntil",
table: "OrganizationSponsorship",
newName: "SponsorshipLapsedDate");
migrationBuilder.RenameColumn(
name: "ToDelete",
table: "OrganizationSponsorship",
newName: "CloudSponsor");
migrationBuilder.RenameColumn(
name: "ToDelete",
table: "OrganizationSponsorship",
newName: "CloudSponsor");
migrationBuilder.AddColumn<Guid>(
name: "InstallationId",
table: "OrganizationSponsorship",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci");
migrationBuilder.AddColumn<Guid>(
name: "InstallationId",
table: "OrganizationSponsorship",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci");
migrationBuilder.AddColumn<byte>(
name: "TimesRenewedWithoutValidation",
table: "OrganizationSponsorship",
type: "tinyint unsigned",
nullable: false,
defaultValue: (byte)0);
migrationBuilder.AddColumn<byte>(
name: "TimesRenewedWithoutValidation",
table: "OrganizationSponsorship",
type: "tinyint unsigned",
nullable: false,
defaultValue: (byte)0);
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_InstallationId",
table: "OrganizationSponsorship",
column: "InstallationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_InstallationId",
table: "OrganizationSponsorship",
column: "InstallationId");
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Installation_InstallationId",
table: "OrganizationSponsorship",
column: "InstallationId",
principalTable: "Installation",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Installation_InstallationId",
table: "OrganizationSponsorship",
column: "InstallationId",
principalTable: "Installation",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
}

View File

@ -1,81 +1,80 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
namespace Bit.MySqlMigrations.Migrations;
public partial class SponsorshipBulkActions : Migration
{
public partial class SponsorshipBulkActions : Migration
protected override void Up(MigrationBuilder migrationBuilder)
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship");
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationUserId",
table: "OrganizationSponsorship",
type: "char(36)",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)",
oldNullable: true)
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationUserId",
table: "OrganizationSponsorship",
type: "char(36)",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)",
oldNullable: true)
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "char(36)",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)",
oldNullable: true)
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "char(36)",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)",
oldNullable: true)
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship");
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationUserId",
table: "OrganizationSponsorship",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)")
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationUserId",
table: "OrganizationSponsorship",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)")
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)")
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)")
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
}

View File

@ -1,70 +1,69 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
namespace Bit.MySqlMigrations.Migrations;
public partial class AddInstallationIdToEvents : Migration
{
public partial class AddInstallationIdToEvents : Migration
protected override void Up(MigrationBuilder migrationBuilder)
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship");
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)")
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)")
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AddColumn<Guid>(
name: "InstallationId",
table: "Event",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci");
migrationBuilder.AddColumn<Guid>(
name: "InstallationId",
table: "Event",
type: "char(36)",
nullable: true,
collation: "ascii_general_ci");
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship");
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship");
migrationBuilder.DropColumn(
name: "InstallationId",
table: "Event");
migrationBuilder.DropColumn(
name: "InstallationId",
table: "Event");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "char(36)",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)",
oldNullable: true)
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "char(36)",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
collation: "ascii_general_ci",
oldClrType: typeof(Guid),
oldType: "char(36)",
oldNullable: true)
.OldAnnotation("Relational:Collation", "ascii_general_ci");
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}

View File

@ -1,24 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
{
public partial class DeviceUnknownVerification : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UnknownDeviceVerificationEnabled",
table: "User",
type: "tinyint(1)",
nullable: false,
defaultValue: true);
}
namespace Bit.MySqlMigrations.Migrations;
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UnknownDeviceVerificationEnabled",
table: "User");
}
public partial class DeviceUnknownVerification : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UnknownDeviceVerificationEnabled",
table: "User",
type: "tinyint(1)",
nullable: false,
defaultValue: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UnknownDeviceVerificationEnabled",
table: "User");
}
}

View File

@ -1,29 +1,28 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.MySqlMigrations.Migrations
{
public partial class DeactivatedUserStatus : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<short>(
name: "Status",
table: "OrganizationUser",
type: "smallint",
nullable: false,
oldClrType: typeof(byte),
oldType: "tinyint unsigned");
}
namespace Bit.MySqlMigrations.Migrations;
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<byte>(
name: "Status",
table: "OrganizationUser",
type: "tinyint unsigned",
nullable: false,
oldClrType: typeof(short),
oldType: "smallint");
}
public partial class DeactivatedUserStatus : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<short>(
name: "Status",
table: "OrganizationUser",
type: "smallint",
nullable: false,
oldClrType: typeof(byte),
oldType: "tinyint unsigned");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AlterColumn<byte>(
name: "Status",
table: "OrganizationUser",
type: "tinyint unsigned",
nullable: false,
oldClrType: typeof(short),
oldType: "smallint");
}
}

View File

@ -2,25 +2,24 @@
#nullable disable
namespace Bit.MySqlMigrations.Migrations
{
public partial class UseScimFlag : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UseScim",
table: "Organization",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
}
namespace Bit.MySqlMigrations.Migrations;
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UseScim",
table: "Organization");
}
public partial class UseScimFlag : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UseScim",
table: "Organization",
type: "tinyint(1)",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UseScim",
table: "Organization");
}
}

View File

@ -4,34 +4,33 @@ using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Design;
using Microsoft.Extensions.Configuration;
namespace MySqlMigrations
{
public static class GlobalSettingsFactory
{
public static GlobalSettings GlobalSettings { get; } = new GlobalSettings();
static GlobalSettingsFactory()
{
var configBuilder = new ConfigurationBuilder().AddUserSecrets<Bit.Api.Startup>();
var Configuration = configBuilder.Build();
ConfigurationBinder.Bind(Configuration.GetSection("GlobalSettings"), GlobalSettings);
}
}
namespace MySqlMigrations;
public class DatabaseContextFactory : IDesignTimeDbContextFactory<DatabaseContext>
public static class GlobalSettingsFactory
{
public static GlobalSettings GlobalSettings { get; } = new GlobalSettings();
static GlobalSettingsFactory()
{
public DatabaseContext CreateDbContext(string[] args)
{
var globalSettings = GlobalSettingsFactory.GlobalSettings;
var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
var connectionString = globalSettings.PostgreSql?.ConnectionString;
if (string.IsNullOrWhiteSpace(connectionString))
{
throw new Exception("No Postgres connection string found.");
}
optionsBuilder.UseNpgsql(
connectionString,
b => b.MigrationsAssembly("PostgresMigrations"));
return new DatabaseContext(optionsBuilder.Options);
}
var configBuilder = new ConfigurationBuilder().AddUserSecrets<Bit.Api.Startup>();
var Configuration = configBuilder.Build();
ConfigurationBinder.Bind(Configuration.GetSection("GlobalSettings"), GlobalSettings);
}
}
public class DatabaseContextFactory : IDesignTimeDbContextFactory<DatabaseContext>
{
public DatabaseContext CreateDbContext(string[] args)
{
var globalSettings = GlobalSettingsFactory.GlobalSettings;
var optionsBuilder = new DbContextOptionsBuilder<DatabaseContext>();
var connectionString = globalSettings.PostgreSql?.ConnectionString;
if (string.IsNullOrWhiteSpace(connectionString))
{
throw new Exception("No Postgres connection string found.");
}
optionsBuilder.UseNpgsql(
connectionString,
b => b.MigrationsAssembly("PostgresMigrations"));
return new DatabaseContext(optionsBuilder.Options);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -1,75 +1,74 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.PostgresMigrations.Migrations
namespace Bit.PostgresMigrations.Migrations;
public partial class RemoveProviderOrganizationProviderUser : Migration
{
public partial class RemoveProviderOrganizationProviderUser : Migration
protected override void Up(MigrationBuilder migrationBuilder)
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "ProviderOrganizationProviderUser");
migrationBuilder.DropTable(
name: "ProviderOrganizationProviderUser");
migrationBuilder.AddColumn<Guid>(
name: "ProviderId",
table: "Event",
type: "uuid",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "ProviderId",
table: "Event",
type: "uuid",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "ProviderUserId",
table: "Event",
type: "uuid",
nullable: true);
}
migrationBuilder.AddColumn<Guid>(
name: "ProviderUserId",
table: "Event",
type: "uuid",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ProviderId",
table: "Event");
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ProviderId",
table: "Event");
migrationBuilder.DropColumn(
name: "ProviderUserId",
table: "Event");
migrationBuilder.DropColumn(
name: "ProviderUserId",
table: "Event");
migrationBuilder.CreateTable(
name: "ProviderOrganizationProviderUser",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
CreationDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
Permissions = table.Column<string>(type: "text", nullable: true),
ProviderOrganizationId = table.Column<Guid>(type: "uuid", nullable: false),
ProviderUserId = table.Column<Guid>(type: "uuid", nullable: false),
RevisionDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
Type = table.Column<byte>(type: "smallint", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ProviderOrganizationProviderUser", x => x.Id);
table.ForeignKey(
name: "FK_ProviderOrganizationProviderUser_ProviderOrganization_Provi~",
column: x => x.ProviderOrganizationId,
principalTable: "ProviderOrganization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ProviderOrganizationProviderUser_ProviderUser_ProviderUserId",
column: x => x.ProviderUserId,
principalTable: "ProviderUser",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "ProviderOrganizationProviderUser",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
CreationDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
Permissions = table.Column<string>(type: "text", nullable: true),
ProviderOrganizationId = table.Column<Guid>(type: "uuid", nullable: false),
ProviderUserId = table.Column<Guid>(type: "uuid", nullable: false),
RevisionDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
Type = table.Column<byte>(type: "smallint", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_ProviderOrganizationProviderUser", x => x.Id);
table.ForeignKey(
name: "FK_ProviderOrganizationProviderUser_ProviderOrganization_Provi~",
column: x => x.ProviderOrganizationId,
principalTable: "ProviderOrganization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
table.ForeignKey(
name: "FK_ProviderOrganizationProviderUser_ProviderUser_ProviderUserId",
column: x => x.ProviderUserId,
principalTable: "ProviderUser",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_ProviderOrganizationProviderUser_ProviderOrganizationId",
table: "ProviderOrganizationProviderUser",
column: "ProviderOrganizationId");
migrationBuilder.CreateIndex(
name: "IX_ProviderOrganizationProviderUser_ProviderOrganizationId",
table: "ProviderOrganizationProviderUser",
column: "ProviderOrganizationId");
migrationBuilder.CreateIndex(
name: "IX_ProviderOrganizationProviderUser_ProviderUserId",
table: "ProviderOrganizationProviderUser",
column: "ProviderUserId");
}
migrationBuilder.CreateIndex(
name: "IX_ProviderOrganizationProviderUser_ProviderUserId",
table: "ProviderOrganizationProviderUser",
column: "ProviderUserId");
}
}

View File

@ -1,24 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.PostgresMigrations.Migrations
{
public partial class UserForcePasswordReset : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "ForcePasswordReset",
table: "User",
type: "boolean",
nullable: false,
defaultValue: false);
}
namespace Bit.PostgresMigrations.Migrations;
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ForcePasswordReset",
table: "User");
}
public partial class UserForcePasswordReset : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "ForcePasswordReset",
table: "User",
type: "boolean",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "ForcePasswordReset",
table: "User");
}
}

View File

@ -1,43 +1,42 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.PostgresMigrations.Migrations
namespace Bit.PostgresMigrations.Migrations;
public partial class AddMaxAutoscaleSeatsToOrganization : Migration
{
public partial class AddMaxAutoscaleSeatsToOrganization : Migration
protected override void Up(MigrationBuilder migrationBuilder)
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "MaxAutoscaleSeats",
table: "Organization",
type: "integer",
nullable: true);
migrationBuilder.AddColumn<int>(
name: "MaxAutoscaleSeats",
table: "Organization",
type: "integer",
nullable: true);
migrationBuilder.AddColumn<DateTime>(
name: "OwnersNotifiedOfAutoscaling",
table: "Organization",
type: "timestamp without time zone",
nullable: true);
migrationBuilder.AddColumn<DateTime>(
name: "OwnersNotifiedOfAutoscaling",
table: "Organization",
type: "timestamp without time zone",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "ProviderOrganizationId",
table: "Event",
type: "uuid",
nullable: true);
}
migrationBuilder.AddColumn<Guid>(
name: "ProviderOrganizationId",
table: "Event",
type: "uuid",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MaxAutoscaleSeats",
table: "Organization");
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "MaxAutoscaleSeats",
table: "Organization");
migrationBuilder.DropColumn(
name: "OwnersNotifiedOfAutoscaling",
table: "Organization");
migrationBuilder.DropColumn(
name: "OwnersNotifiedOfAutoscaling",
table: "Organization");
migrationBuilder.DropColumn(
name: "ProviderOrganizationId",
table: "Event");
}
migrationBuilder.DropColumn(
name: "ProviderOrganizationId",
table: "Event");
}
}

View File

@ -1,21 +1,20 @@
using Bit.Core.Utilities;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.PostgresMigrations.Migrations
namespace Bit.PostgresMigrations.Migrations;
public partial class SplitManageCollectionsPermissions2 : Migration
{
public partial class SplitManageCollectionsPermissions2 : Migration
private const string _scriptLocation =
"PostgresMigrations.Scripts.2021-09-21_01_SplitManageCollectionsPermission.psql";
protected override void Up(MigrationBuilder migrationBuilder)
{
private const string _scriptLocation =
"PostgresMigrations.Scripts.2021-09-21_01_SplitManageCollectionsPermission.psql";
migrationBuilder.Sql(CoreHelpers.GetEmbeddedResourceContentsAsync(_scriptLocation));
}
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(CoreHelpers.GetEmbeddedResourceContentsAsync(_scriptLocation));
}
protected override void Down(MigrationBuilder migrationBuilder)
{
throw new Exception("Irreversible migration");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
throw new Exception("Irreversible migration");
}
}

View File

@ -1,21 +1,20 @@
using Bit.Core.Utilities;
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.PostgresMigrations.Migrations
namespace Bit.PostgresMigrations.Migrations;
public partial class SetMaxAutoscaleSeatsToCurrentSeatCount : Migration
{
public partial class SetMaxAutoscaleSeatsToCurrentSeatCount : Migration
private const string _scriptLocation =
"PostgresMigrations.Scripts.2021-10-21_00_SetMaxAutoscaleSeatCount.psql";
protected override void Up(MigrationBuilder migrationBuilder)
{
private const string _scriptLocation =
"PostgresMigrations.Scripts.2021-10-21_00_SetMaxAutoscaleSeatCount.psql";
migrationBuilder.Sql(CoreHelpers.GetEmbeddedResourceContentsAsync(_scriptLocation));
}
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.Sql(CoreHelpers.GetEmbeddedResourceContentsAsync(_scriptLocation));
}
protected override void Down(MigrationBuilder migrationBuilder)
{
throw new Exception("Irreversible migration");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
throw new Exception("Irreversible migration");
}
}

View File

@ -1,24 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.PostgresMigrations.Migrations
{
public partial class KeyConnector : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UsesKeyConnector",
table: "User",
type: "boolean",
nullable: false,
defaultValue: false);
}
namespace Bit.PostgresMigrations.Migrations;
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UsesKeyConnector",
table: "User");
}
public partial class KeyConnector : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UsesKeyConnector",
table: "User",
type: "boolean",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UsesKeyConnector",
table: "User");
}
}

View File

@ -1,82 +1,81 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.PostgresMigrations.Migrations
namespace Bit.PostgresMigrations.Migrations;
public partial class OrganizationSponsorship : Migration
{
public partial class OrganizationSponsorship : Migration
protected override void Up(MigrationBuilder migrationBuilder)
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UsesCryptoAgent",
table: "User",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.AddColumn<bool>(
name: "UsesCryptoAgent",
table: "User",
type: "boolean",
nullable: false,
defaultValue: false);
migrationBuilder.CreateTable(
name: "OrganizationSponsorship",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
InstallationId = table.Column<Guid>(type: "uuid", nullable: true),
SponsoringOrganizationId = table.Column<Guid>(type: "uuid", nullable: true),
SponsoringOrganizationUserId = table.Column<Guid>(type: "uuid", nullable: true),
SponsoredOrganizationId = table.Column<Guid>(type: "uuid", nullable: true),
FriendlyName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
OfferedToEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
PlanSponsorshipType = table.Column<byte>(type: "smallint", nullable: true),
CloudSponsor = table.Column<bool>(type: "boolean", nullable: false),
LastSyncDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
TimesRenewedWithoutValidation = table.Column<byte>(type: "smallint", nullable: false),
SponsorshipLapsedDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationSponsorship", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationSponsorship_Installation_InstallationId",
column: x => x.InstallationId,
principalTable: "Installation",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoredOrganizationId",
column: x => x.SponsoredOrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
column: x => x.SponsoringOrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateTable(
name: "OrganizationSponsorship",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
InstallationId = table.Column<Guid>(type: "uuid", nullable: true),
SponsoringOrganizationId = table.Column<Guid>(type: "uuid", nullable: true),
SponsoringOrganizationUserId = table.Column<Guid>(type: "uuid", nullable: true),
SponsoredOrganizationId = table.Column<Guid>(type: "uuid", nullable: true),
FriendlyName = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
OfferedToEmail = table.Column<string>(type: "character varying(256)", maxLength: 256, nullable: true),
PlanSponsorshipType = table.Column<byte>(type: "smallint", nullable: true),
CloudSponsor = table.Column<bool>(type: "boolean", nullable: false),
LastSyncDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: true),
TimesRenewedWithoutValidation = table.Column<byte>(type: "smallint", nullable: false),
SponsorshipLapsedDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationSponsorship", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationSponsorship_Installation_InstallationId",
column: x => x.InstallationId,
principalTable: "Installation",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoredOrganizationId",
column: x => x.SponsoredOrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
table.ForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
column: x => x.SponsoringOrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
});
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_InstallationId",
table: "OrganizationSponsorship",
column: "InstallationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_InstallationId",
table: "OrganizationSponsorship",
column: "InstallationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_SponsoredOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoredOrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_SponsoredOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoredOrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_SponsoringOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId");
}
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_SponsoringOrganizationId",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "OrganizationSponsorship");
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "OrganizationSponsorship");
migrationBuilder.DropColumn(
name: "UsesCryptoAgent",
table: "User");
}
migrationBuilder.DropColumn(
name: "UsesCryptoAgent",
table: "User");
}
}

View File

@ -1,24 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.PostgresMigrations.Migrations
{
public partial class KeyConnectorFlag : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UseKeyConnector",
table: "Organization",
type: "boolean",
nullable: false,
defaultValue: false);
}
namespace Bit.PostgresMigrations.Migrations;
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UseKeyConnector",
table: "Organization");
}
public partial class KeyConnectorFlag : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UseKeyConnector",
table: "Organization",
type: "boolean",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UseKeyConnector",
table: "Organization");
}
}

View File

@ -1,46 +1,45 @@
using Microsoft.EntityFrameworkCore.Migrations;
using Npgsql.EntityFrameworkCore.PostgreSQL.Metadata;
namespace Bit.PostgresMigrations.Migrations
namespace Bit.PostgresMigrations.Migrations;
public partial class RemoveU2F : Migration
{
public partial class RemoveU2F : Migration
protected override void Up(MigrationBuilder migrationBuilder)
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropTable(
name: "U2f");
}
migrationBuilder.DropTable(
name: "U2f");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "U2f",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
AppId = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
Challenge = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
CreationDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
KeyHandle = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
Version = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_U2f", x => x.Id);
table.ForeignKey(
name: "FK_U2f_User_UserId",
column: x => x.UserId,
principalTable: "User",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.CreateTable(
name: "U2f",
columns: table => new
{
Id = table.Column<int>(type: "integer", nullable: false)
.Annotation("Npgsql:ValueGenerationStrategy", NpgsqlValueGenerationStrategy.IdentityByDefaultColumn),
AppId = table.Column<string>(type: "character varying(50)", maxLength: 50, nullable: true),
Challenge = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
CreationDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: false),
KeyHandle = table.Column<string>(type: "character varying(200)", maxLength: 200, nullable: true),
UserId = table.Column<Guid>(type: "uuid", nullable: false),
Version = table.Column<string>(type: "character varying(20)", maxLength: 20, nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_U2f", x => x.Id);
table.ForeignKey(
name: "FK_U2f_User_UserId",
column: x => x.UserId,
principalTable: "User",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_U2f_UserId",
table: "U2f",
column: "UserId");
}
migrationBuilder.CreateIndex(
name: "IX_U2f_UserId",
table: "U2f",
column: "UserId");
}
}

View File

@ -1,34 +1,33 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.PostgresMigrations.Migrations
namespace Bit.PostgresMigrations.Migrations;
public partial class FailedLoginCaptcha : Migration
{
public partial class FailedLoginCaptcha : Migration
protected override void Up(MigrationBuilder migrationBuilder)
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<int>(
name: "FailedLoginCount",
table: "User",
type: "integer",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<int>(
name: "FailedLoginCount",
table: "User",
type: "integer",
nullable: false,
defaultValue: 0);
migrationBuilder.AddColumn<DateTime>(
name: "LastFailedLoginDate",
table: "User",
type: "timestamp without time zone",
nullable: true);
}
migrationBuilder.AddColumn<DateTime>(
name: "LastFailedLoginDate",
table: "User",
type: "timestamp without time zone",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "FailedLoginCount",
table: "User");
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "FailedLoginCount",
table: "User");
migrationBuilder.DropColumn(
name: "LastFailedLoginDate",
table: "User");
}
migrationBuilder.DropColumn(
name: "LastFailedLoginDate",
table: "User");
}
}

View File

@ -1,154 +1,153 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.PostgresMigrations.Migrations
namespace Bit.PostgresMigrations.Migrations;
public partial class SelfHostF4E : Migration
{
public partial class SelfHostF4E : Migration
private const string _scriptLocationTemplate = "2022-03-01_00_{0}_MigrateOrganizationApiKeys.psql";
protected override void Up(MigrationBuilder migrationBuilder)
{
private const string _scriptLocationTemplate = "2022-03-01_00_{0}_MigrateOrganizationApiKeys.psql";
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Installation_InstallationId",
table: "OrganizationSponsorship");
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Installation_InstallationId",
table: "OrganizationSponsorship");
migrationBuilder.DropIndex(
name: "IX_OrganizationSponsorship_InstallationId",
table: "OrganizationSponsorship");
migrationBuilder.DropIndex(
name: "IX_OrganizationSponsorship_InstallationId",
table: "OrganizationSponsorship");
migrationBuilder.DropColumn(
name: "InstallationId",
table: "OrganizationSponsorship");
migrationBuilder.DropColumn(
name: "InstallationId",
table: "OrganizationSponsorship");
migrationBuilder.DropColumn(
name: "TimesRenewedWithoutValidation",
table: "OrganizationSponsorship");
migrationBuilder.DropColumn(
name: "TimesRenewedWithoutValidation",
table: "OrganizationSponsorship");
migrationBuilder.CreateTable(
name: "OrganizationApiKey",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
OrganizationId = table.Column<Guid>(type: "uuid", nullable: false),
Type = table.Column<byte>(type: "smallint", nullable: false),
ApiKey = table.Column<string>(type: "character varying(30)", maxLength: 30, nullable: true),
RevisionDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationApiKey", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationApiKey_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "OrganizationApiKey",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
OrganizationId = table.Column<Guid>(type: "uuid", nullable: false),
Type = table.Column<byte>(type: "smallint", nullable: false),
ApiKey = table.Column<string>(type: "character varying(30)", maxLength: 30, nullable: true),
RevisionDate = table.Column<DateTime>(type: "timestamp without time zone", nullable: false)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationApiKey", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationApiKey_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.SqlResource(_scriptLocationTemplate);
migrationBuilder.SqlResource(_scriptLocationTemplate);
migrationBuilder.DropColumn(
name: "ApiKey",
table: "Organization");
migrationBuilder.DropColumn(
name: "ApiKey",
table: "Organization");
migrationBuilder.RenameColumn(
name: "SponsorshipLapsedDate",
table: "OrganizationSponsorship",
newName: "ValidUntil");
migrationBuilder.RenameColumn(
name: "SponsorshipLapsedDate",
table: "OrganizationSponsorship",
newName: "ValidUntil");
migrationBuilder.RenameColumn(
name: "CloudSponsor",
table: "OrganizationSponsorship",
newName: "ToDelete");
migrationBuilder.RenameColumn(
name: "CloudSponsor",
table: "OrganizationSponsorship",
newName: "ToDelete");
migrationBuilder.CreateTable(
name: "OrganizationConnection",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Type = table.Column<byte>(type: "smallint", nullable: false),
OrganizationId = table.Column<Guid>(type: "uuid", nullable: false),
Enabled = table.Column<bool>(type: "boolean", nullable: false),
Config = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationConnection", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationConnection_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateTable(
name: "OrganizationConnection",
columns: table => new
{
Id = table.Column<Guid>(type: "uuid", nullable: false),
Type = table.Column<byte>(type: "smallint", nullable: false),
OrganizationId = table.Column<Guid>(type: "uuid", nullable: false),
Enabled = table.Column<bool>(type: "boolean", nullable: false),
Config = table.Column<string>(type: "text", nullable: true)
},
constraints: table =>
{
table.PrimaryKey("PK_OrganizationConnection", x => x.Id);
table.ForeignKey(
name: "FK_OrganizationConnection_Organization_OrganizationId",
column: x => x.OrganizationId,
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
});
migrationBuilder.CreateIndex(
name: "IX_OrganizationApiKey_OrganizationId",
table: "OrganizationApiKey",
column: "OrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationApiKey_OrganizationId",
table: "OrganizationApiKey",
column: "OrganizationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationConnection_OrganizationId",
table: "OrganizationConnection",
column: "OrganizationId");
}
migrationBuilder.CreateIndex(
name: "IX_OrganizationConnection_OrganizationId",
table: "OrganizationConnection",
column: "OrganizationId");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "ApiKey",
table: "Organization",
type: "character varying(30)",
maxLength: 30,
nullable: true);
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "ApiKey",
table: "Organization",
type: "character varying(30)",
maxLength: 30,
nullable: true);
migrationBuilder.SqlResource(_scriptLocationTemplate);
migrationBuilder.SqlResource(_scriptLocationTemplate);
migrationBuilder.DropTable(
name: "OrganizationApiKey");
migrationBuilder.DropTable(
name: "OrganizationApiKey");
migrationBuilder.DropTable(
name: "OrganizationConnection");
migrationBuilder.DropTable(
name: "OrganizationConnection");
migrationBuilder.RenameColumn(
name: "ValidUntil",
table: "OrganizationSponsorship",
newName: "SponsorshipLapsedDate");
migrationBuilder.RenameColumn(
name: "ValidUntil",
table: "OrganizationSponsorship",
newName: "SponsorshipLapsedDate");
migrationBuilder.RenameColumn(
name: "ToDelete",
table: "OrganizationSponsorship",
newName: "CloudSponsor");
migrationBuilder.RenameColumn(
name: "ToDelete",
table: "OrganizationSponsorship",
newName: "CloudSponsor");
migrationBuilder.AddColumn<Guid>(
name: "InstallationId",
table: "OrganizationSponsorship",
type: "uuid",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "InstallationId",
table: "OrganizationSponsorship",
type: "uuid",
nullable: true);
migrationBuilder.AddColumn<byte>(
name: "TimesRenewedWithoutValidation",
table: "OrganizationSponsorship",
type: "smallint",
nullable: false,
defaultValue: (byte)0);
migrationBuilder.AddColumn<byte>(
name: "TimesRenewedWithoutValidation",
table: "OrganizationSponsorship",
type: "smallint",
nullable: false,
defaultValue: (byte)0);
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_InstallationId",
table: "OrganizationSponsorship",
column: "InstallationId");
migrationBuilder.CreateIndex(
name: "IX_OrganizationSponsorship_InstallationId",
table: "OrganizationSponsorship",
column: "InstallationId");
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Installation_InstallationId",
table: "OrganizationSponsorship",
column: "InstallationId",
principalTable: "Installation",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Installation_InstallationId",
table: "OrganizationSponsorship",
column: "InstallationId",
principalTable: "Installation",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
}

View File

@ -1,73 +1,72 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.PostgresMigrations.Migrations
namespace Bit.PostgresMigrations.Migrations;
public partial class SponsorshipBulkActions : Migration
{
public partial class SponsorshipBulkActions : Migration
protected override void Up(MigrationBuilder migrationBuilder)
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship");
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationUserId",
table: "OrganizationSponsorship",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationUserId",
table: "OrganizationSponsorship",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship");
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationUserId",
table: "OrganizationSponsorship",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationUserId",
table: "OrganizationSponsorship",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
}

View File

@ -1,65 +1,64 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.PostgresMigrations.Migrations
namespace Bit.PostgresMigrations.Migrations;
public partial class AddInstallationIdToEvents : Migration
{
public partial class AddInstallationIdToEvents : Migration
protected override void Up(MigrationBuilder migrationBuilder)
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship");
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "uuid",
nullable: true,
oldClrType: typeof(Guid),
oldType: "uuid");
migrationBuilder.AddColumn<Guid>(
name: "InstallationId",
table: "Event",
type: "uuid",
nullable: true);
migrationBuilder.AddColumn<Guid>(
name: "InstallationId",
table: "Event",
type: "uuid",
nullable: true);
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Restrict);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship");
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship");
migrationBuilder.DropColumn(
name: "InstallationId",
table: "Event");
migrationBuilder.DropColumn(
name: "InstallationId",
table: "Event");
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AlterColumn<Guid>(
name: "SponsoringOrganizationId",
table: "OrganizationSponsorship",
type: "uuid",
nullable: false,
defaultValue: new Guid("00000000-0000-0000-0000-000000000000"),
oldClrType: typeof(Guid),
oldType: "uuid",
oldNullable: true);
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
migrationBuilder.AddForeignKey(
name: "FK_OrganizationSponsorship_Organization_SponsoringOrganization~",
table: "OrganizationSponsorship",
column: "SponsoringOrganizationId",
principalTable: "Organization",
principalColumn: "Id",
onDelete: ReferentialAction.Cascade);
}
}

View File

@ -1,24 +1,23 @@
using Microsoft.EntityFrameworkCore.Migrations;
namespace Bit.PostgresMigrations.Migrations
{
public partial class DeviceUnknownVerification : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UnknownDeviceVerificationEnabled",
table: "User",
type: "boolean",
nullable: false,
defaultValue: true);
}
namespace Bit.PostgresMigrations.Migrations;
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UnknownDeviceVerificationEnabled",
table: "User");
}
public partial class DeviceUnknownVerification : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UnknownDeviceVerificationEnabled",
table: "User",
type: "boolean",
nullable: false,
defaultValue: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UnknownDeviceVerificationEnabled",
table: "User");
}
}

View File

@ -2,25 +2,24 @@
#nullable disable
namespace Bit.PostgresMigrations.Migrations
{
public partial class UseScimFlag : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UseScim",
table: "Organization",
type: "boolean",
nullable: false,
defaultValue: false);
}
namespace Bit.PostgresMigrations.Migrations;
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UseScim",
table: "Organization");
}
public partial class UseScimFlag : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<bool>(
name: "UseScim",
table: "Organization",
type: "boolean",
nullable: false,
defaultValue: false);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "UseScim",
table: "Organization");
}
}

View File

@ -1,41 +1,40 @@
namespace Bit.Server
namespace Bit.Server;
public class Program
{
public class Program
public static void Main(string[] args)
{
public static void Main(string[] args)
var config = new ConfigurationBuilder()
.AddCommandLine(args)
.Build();
var builder = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>()
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConsole().AddDebug();
})
.ConfigureKestrel((context, options) => { });
var contentRoot = config.GetValue<string>("contentRoot");
if (!string.IsNullOrWhiteSpace(contentRoot))
{
var config = new ConfigurationBuilder()
.AddCommandLine(args)
.Build();
var builder = new WebHostBuilder()
.UseConfiguration(config)
.UseKestrel()
.UseStartup<Startup>()
.ConfigureLogging((hostingContext, logging) =>
{
logging.AddConsole().AddDebug();
})
.ConfigureKestrel((context, options) => { });
var contentRoot = config.GetValue<string>("contentRoot");
if (!string.IsNullOrWhiteSpace(contentRoot))
{
builder.UseContentRoot(contentRoot);
}
else
{
builder.UseContentRoot(Directory.GetCurrentDirectory());
}
var webRoot = config.GetValue<string>("webRoot");
if (string.IsNullOrWhiteSpace(webRoot))
{
builder.UseWebRoot(webRoot);
}
var host = builder.Build();
host.Run();
builder.UseContentRoot(contentRoot);
}
else
{
builder.UseContentRoot(Directory.GetCurrentDirectory());
}
var webRoot = config.GetValue<string>("webRoot");
if (string.IsNullOrWhiteSpace(webRoot))
{
builder.UseWebRoot(webRoot);
}
var host = builder.Build();
host.Run();
}
}

View File

@ -1,90 +1,89 @@
using System.Globalization;
using Microsoft.AspNetCore.StaticFiles;
namespace Bit.Server
namespace Bit.Server;
public class Startup
{
public class Startup
private readonly List<string> _longCachedPaths = new List<string>
{
private readonly List<string> _longCachedPaths = new List<string>
{
"/app/", "/locales/", "/fonts/", "/connectors/", "/scripts/"
};
private readonly List<string> _mediumCachedPaths = new List<string>
{
"/images/"
};
"/app/", "/locales/", "/fonts/", "/connectors/", "/scripts/"
};
private readonly List<string> _mediumCachedPaths = new List<string>
{
"/images/"
};
public Startup()
{
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
}
public Startup()
{
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
}
public void ConfigureServices(IServiceCollection services)
{
services.AddRouting();
}
public void ConfigureServices(IServiceCollection services)
{
services.AddRouting();
}
public void Configure(
IApplicationBuilder app,
IConfiguration configuration)
public void Configure(
IApplicationBuilder app,
IConfiguration configuration)
{
if (configuration.GetValue<bool?>("serveUnknown") ?? false)
{
if (configuration.GetValue<bool?>("serveUnknown") ?? false)
app.UseStaticFiles(new StaticFileOptions
{
app.UseStaticFiles(new StaticFileOptions
{
ServeUnknownFileTypes = true,
DefaultContentType = "application/octet-stream"
});
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/alive",
async context => await context.Response.WriteAsync(System.DateTime.UtcNow.ToString()));
});
}
else if (configuration.GetValue<bool?>("webVault") ?? false)
ServeUnknownFileTypes = true,
DefaultContentType = "application/octet-stream"
});
app.UseRouting();
app.UseEndpoints(endpoints =>
{
// TODO: This should be removed when asp.net natively support avif
var provider = new FileExtensionContentTypeProvider { Mappings = { [".avif"] = "image/avif" } };
endpoints.MapGet("/alive",
async context => await context.Response.WriteAsync(System.DateTime.UtcNow.ToString()));
});
}
else if (configuration.GetValue<bool?>("webVault") ?? false)
{
// TODO: This should be removed when asp.net natively support avif
var provider = new FileExtensionContentTypeProvider { Mappings = { [".avif"] = "image/avif" } };
var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("index.html");
app.UseDefaultFiles(options);
app.UseStaticFiles(new StaticFileOptions
var options = new DefaultFilesOptions();
options.DefaultFileNames.Clear();
options.DefaultFileNames.Add("index.html");
app.UseDefaultFiles(options);
app.UseStaticFiles(new StaticFileOptions
{
ContentTypeProvider = provider,
OnPrepareResponse = ctx =>
{
ContentTypeProvider = provider,
OnPrepareResponse = ctx =>
if (!ctx.Context.Request.Path.HasValue ||
ctx.Context.Response.Headers.ContainsKey("Cache-Control"))
{
if (!ctx.Context.Request.Path.HasValue ||
ctx.Context.Response.Headers.ContainsKey("Cache-Control"))
{
return;
}
var path = ctx.Context.Request.Path.Value;
if (_longCachedPaths.Any(ext => path.StartsWith(ext)))
{
// 14 days
ctx.Context.Response.Headers.Append("Cache-Control", "max-age=1209600");
}
if (_mediumCachedPaths.Any(ext => path.StartsWith(ext)))
{
// 7 days
ctx.Context.Response.Headers.Append("Cache-Control", "max-age=604800");
}
return;
}
});
}
else
var path = ctx.Context.Request.Path.Value;
if (_longCachedPaths.Any(ext => path.StartsWith(ext)))
{
// 14 days
ctx.Context.Response.Headers.Append("Cache-Control", "max-age=1209600");
}
if (_mediumCachedPaths.Any(ext => path.StartsWith(ext)))
{
// 7 days
ctx.Context.Response.Headers.Append("Cache-Control", "max-age=604800");
}
}
});
}
else
{
app.UseFileServer();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
app.UseFileServer();
app.UseRouting();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/alive",
async context => await context.Response.WriteAsync(System.DateTime.UtcNow.ToString()));
});
}
endpoints.MapGet("/alive",
async context => await context.Response.WriteAsync(System.DateTime.UtcNow.ToString()));
});
}
}
}

View File

@ -1,34 +1,33 @@
namespace Bit.Setup
namespace Bit.Setup;
public class AppIdBuilder
{
public class AppIdBuilder
private readonly Context _context;
public AppIdBuilder(Context context)
{
private readonly Context _context;
_context = context;
}
public AppIdBuilder(Context context)
public void Build()
{
var model = new TemplateModel
{
_context = context;
}
Url = _context.Config.Url
};
public void Build()
// Needed for backwards compatability with migrated U2F tokens.
Helpers.WriteLine(_context, "Building FIDO U2F app id.");
Directory.CreateDirectory("/bitwarden/web/");
var template = Helpers.ReadTemplate("AppId");
using (var sw = File.CreateText("/bitwarden/web/app-id.json"))
{
var model = new TemplateModel
{
Url = _context.Config.Url
};
// Needed for backwards compatability with migrated U2F tokens.
Helpers.WriteLine(_context, "Building FIDO U2F app id.");
Directory.CreateDirectory("/bitwarden/web/");
var template = Helpers.ReadTemplate("AppId");
using (var sw = File.CreateText("/bitwarden/web/app-id.json"))
{
sw.Write(template(model));
}
}
public class TemplateModel
{
public string Url { get; set; }
sw.Write(template(model));
}
}
public class TemplateModel
{
public string Url { get; set; }
}
}

View File

@ -1,112 +1,111 @@
namespace Bit.Setup
{
public class CertBuilder
{
private readonly Context _context;
namespace Bit.Setup;
public CertBuilder(Context context)
public class CertBuilder
{
private readonly Context _context;
public CertBuilder(Context context)
{
_context = context;
}
public void BuildForInstall()
{
if (_context.Stub)
{
_context = context;
_context.Config.Ssl = true;
_context.Install.Trusted = true;
_context.Install.SelfSignedCert = false;
_context.Install.DiffieHellman = false;
_context.Install.IdentityCertPassword = "IDENTITY_CERT_PASSWORD";
return;
}
public void BuildForInstall()
_context.Config.Ssl = _context.Config.SslManagedLetsEncrypt;
if (!_context.Config.Ssl)
{
if (_context.Stub)
var skipSSL = _context.Parameters.ContainsKey("skip-ssl") && (_context.Parameters["skip-ssl"] == "true" || _context.Parameters["skip-ssl"] == "1");
if (!skipSSL)
{
_context.Config.Ssl = true;
_context.Install.Trusted = true;
_context.Install.SelfSignedCert = false;
_context.Install.DiffieHellman = false;
_context.Install.IdentityCertPassword = "IDENTITY_CERT_PASSWORD";
return;
}
_context.Config.Ssl = _context.Config.SslManagedLetsEncrypt;
if (!_context.Config.Ssl)
{
var skipSSL = _context.Parameters.ContainsKey("skip-ssl") && (_context.Parameters["skip-ssl"] == "true" || _context.Parameters["skip-ssl"] == "1");
if (!skipSSL)
_context.Config.Ssl = Helpers.ReadQuestion("Do you have a SSL certificate to use?");
if (_context.Config.Ssl)
{
_context.Config.Ssl = Helpers.ReadQuestion("Do you have a SSL certificate to use?");
if (_context.Config.Ssl)
{
Directory.CreateDirectory($"/bitwarden/ssl/{_context.Install.Domain}/");
var message = "Make sure 'certificate.crt' and 'private.key' are provided in the \n" +
"appropriate directory before running 'start' (see docs for info).";
Helpers.ShowBanner(_context, "NOTE", message);
}
else if (Helpers.ReadQuestion("Do you want to generate a self-signed SSL certificate?"))
{
Directory.CreateDirectory($"/bitwarden/ssl/self/{_context.Install.Domain}/");
Helpers.WriteLine(_context, "Generating self signed SSL certificate.");
_context.Config.Ssl = true;
_context.Install.Trusted = false;
_context.Install.SelfSignedCert = true;
Helpers.Exec("openssl req -x509 -newkey rsa:4096 -sha256 -nodes -days 36500 " +
$"-keyout /bitwarden/ssl/self/{_context.Install.Domain}/private.key " +
$"-out /bitwarden/ssl/self/{_context.Install.Domain}/certificate.crt " +
$"-reqexts SAN -extensions SAN " +
$"-config <(cat /usr/lib/ssl/openssl.cnf <(printf '[SAN]\nsubjectAltName=DNS:{_context.Install.Domain}\nbasicConstraints=CA:true')) " +
$"-subj \"/C=US/ST=California/L=Santa Barbara/O=Bitwarden Inc./OU=Bitwarden/CN={_context.Install.Domain}\"");
}
Directory.CreateDirectory($"/bitwarden/ssl/{_context.Install.Domain}/");
var message = "Make sure 'certificate.crt' and 'private.key' are provided in the \n" +
"appropriate directory before running 'start' (see docs for info).";
Helpers.ShowBanner(_context, "NOTE", message);
}
else if (Helpers.ReadQuestion("Do you want to generate a self-signed SSL certificate?"))
{
Directory.CreateDirectory($"/bitwarden/ssl/self/{_context.Install.Domain}/");
Helpers.WriteLine(_context, "Generating self signed SSL certificate.");
_context.Config.Ssl = true;
_context.Install.Trusted = false;
_context.Install.SelfSignedCert = true;
Helpers.Exec("openssl req -x509 -newkey rsa:4096 -sha256 -nodes -days 36500 " +
$"-keyout /bitwarden/ssl/self/{_context.Install.Domain}/private.key " +
$"-out /bitwarden/ssl/self/{_context.Install.Domain}/certificate.crt " +
$"-reqexts SAN -extensions SAN " +
$"-config <(cat /usr/lib/ssl/openssl.cnf <(printf '[SAN]\nsubjectAltName=DNS:{_context.Install.Domain}\nbasicConstraints=CA:true')) " +
$"-subj \"/C=US/ST=California/L=Santa Barbara/O=Bitwarden Inc./OU=Bitwarden/CN={_context.Install.Domain}\"");
}
}
if (_context.Config.SslManagedLetsEncrypt)
{
_context.Install.Trusted = true;
_context.Install.DiffieHellman = true;
Directory.CreateDirectory($"/bitwarden/letsencrypt/live/{_context.Install.Domain}/");
Helpers.Exec($"openssl dhparam -out " +
$"/bitwarden/letsencrypt/live/{_context.Install.Domain}/dhparam.pem 2048");
}
else if (_context.Config.Ssl && !_context.Install.SelfSignedCert)
{
_context.Install.Trusted = Helpers.ReadQuestion("Is this a trusted SSL certificate " +
"(requires ca.crt, see docs)?");
}
Helpers.WriteLine(_context, "Generating key for IdentityServer.");
_context.Install.IdentityCertPassword = Helpers.SecureRandomString(32, alpha: true, numeric: true);
Directory.CreateDirectory("/bitwarden/identity/");
Helpers.Exec("openssl req -x509 -newkey rsa:4096 -sha256 -nodes -keyout identity.key " +
"-out identity.crt -subj \"/CN=Bitwarden IdentityServer\" -days 36500");
Helpers.Exec("openssl pkcs12 -export -out /bitwarden/identity/identity.pfx -inkey identity.key " +
$"-in identity.crt -passout pass:{_context.Install.IdentityCertPassword}");
Helpers.WriteLine(_context);
if (!_context.Config.Ssl)
{
var message = "You are not using a SSL certificate. Bitwarden requires HTTPS to operate. \n" +
"You must front your installation with a HTTPS proxy or the web vault (and \n" +
"other Bitwarden apps) will not work properly.";
Helpers.ShowBanner(_context, "WARNING", message, ConsoleColor.Yellow);
}
else if (_context.Config.Ssl && !_context.Install.Trusted)
{
var message = "You are using an untrusted SSL certificate. This certificate will not be \n" +
"trusted by Bitwarden client applications. You must add this certificate to \n" +
"the trusted store on each device or else you will receive errors when trying \n" +
"to connect to your installation.";
Helpers.ShowBanner(_context, "WARNING", message, ConsoleColor.Yellow);
}
}
public void BuildForUpdater()
if (_context.Config.SslManagedLetsEncrypt)
{
if (_context.Config.EnableKeyConnector && !File.Exists("/bitwarden/key-connector/bwkc.pfx"))
{
Directory.CreateDirectory("/bitwarden/key-connector/");
var keyConnectorCertPassword = Helpers.GetValueFromEnvFile("key-connector",
"keyConnectorSettings__certificate__filesystemPassword");
Helpers.Exec("openssl req -x509 -newkey rsa:4096 -sha256 -nodes -keyout bwkc.key " +
"-out bwkc.crt -subj \"/CN=Bitwarden Key Connector\" -days 36500");
Helpers.Exec("openssl pkcs12 -export -out /bitwarden/key-connector/bwkc.pfx -inkey bwkc.key " +
$"-in bwkc.crt -passout pass:{keyConnectorCertPassword}");
}
_context.Install.Trusted = true;
_context.Install.DiffieHellman = true;
Directory.CreateDirectory($"/bitwarden/letsencrypt/live/{_context.Install.Domain}/");
Helpers.Exec($"openssl dhparam -out " +
$"/bitwarden/letsencrypt/live/{_context.Install.Domain}/dhparam.pem 2048");
}
else if (_context.Config.Ssl && !_context.Install.SelfSignedCert)
{
_context.Install.Trusted = Helpers.ReadQuestion("Is this a trusted SSL certificate " +
"(requires ca.crt, see docs)?");
}
Helpers.WriteLine(_context, "Generating key for IdentityServer.");
_context.Install.IdentityCertPassword = Helpers.SecureRandomString(32, alpha: true, numeric: true);
Directory.CreateDirectory("/bitwarden/identity/");
Helpers.Exec("openssl req -x509 -newkey rsa:4096 -sha256 -nodes -keyout identity.key " +
"-out identity.crt -subj \"/CN=Bitwarden IdentityServer\" -days 36500");
Helpers.Exec("openssl pkcs12 -export -out /bitwarden/identity/identity.pfx -inkey identity.key " +
$"-in identity.crt -passout pass:{_context.Install.IdentityCertPassword}");
Helpers.WriteLine(_context);
if (!_context.Config.Ssl)
{
var message = "You are not using a SSL certificate. Bitwarden requires HTTPS to operate. \n" +
"You must front your installation with a HTTPS proxy or the web vault (and \n" +
"other Bitwarden apps) will not work properly.";
Helpers.ShowBanner(_context, "WARNING", message, ConsoleColor.Yellow);
}
else if (_context.Config.Ssl && !_context.Install.Trusted)
{
var message = "You are using an untrusted SSL certificate. This certificate will not be \n" +
"trusted by Bitwarden client applications. You must add this certificate to \n" +
"the trusted store on each device or else you will receive errors when trying \n" +
"to connect to your installation.";
Helpers.ShowBanner(_context, "WARNING", message, ConsoleColor.Yellow);
}
}
public void BuildForUpdater()
{
if (_context.Config.EnableKeyConnector && !File.Exists("/bitwarden/key-connector/bwkc.pfx"))
{
Directory.CreateDirectory("/bitwarden/key-connector/");
var keyConnectorCertPassword = Helpers.GetValueFromEnvFile("key-connector",
"keyConnectorSettings__certificate__filesystemPassword");
Helpers.Exec("openssl req -x509 -newkey rsa:4096 -sha256 -nodes -keyout bwkc.key " +
"-out bwkc.crt -subj \"/CN=Bitwarden Key Connector\" -days 36500");
Helpers.Exec("openssl pkcs12 -export -out /bitwarden/key-connector/bwkc.pfx -inkey bwkc.key " +
$"-in bwkc.crt -passout pass:{keyConnectorCertPassword}");
}
}
}

View File

@ -1,122 +1,121 @@
using System.ComponentModel;
using YamlDotNet.Serialization;
namespace Bit.Setup
namespace Bit.Setup;
public class Configuration
{
public class Configuration
[Description("Note: After making changes to this file you need to run the `rebuild` or `update`\n" +
"command for them to be applied.\n\n" +
"Full URL for accessing the installation from a browser. (Required)")]
public string Url { get; set; } = "https://localhost";
[Description("Auto-generate the `./docker/docker-compose.yml` config file.\n" +
"WARNING: Disabling generated config files can break future updates. You will be\n" +
"responsible for maintaining this config file.\n" +
"Template: https://github.com/bitwarden/server/blob/master/util/Setup/Templates/DockerCompose.hbs")]
public bool GenerateComposeConfig { get; set; } = true;
[Description("Auto-generate the `./nginx/default.conf` file.\n" +
"WARNING: Disabling generated config files can break future updates. You will be\n" +
"responsible for maintaining this config file.\n" +
"Template: https://github.com/bitwarden/server/blob/master/util/Setup/Templates/NginxConfig.hbs")]
public bool GenerateNginxConfig { get; set; } = true;
[Description("Docker compose file port mapping for HTTP. Leave empty to remove the port mapping.\n" +
"Learn more: https://docs.docker.com/compose/compose-file/#ports")]
public string HttpPort { get; set; } = "80";
[Description("Docker compose file port mapping for HTTPS. Leave empty to remove the port mapping.\n" +
"Learn more: https://docs.docker.com/compose/compose-file/#ports")]
public string HttpsPort { get; set; } = "443";
[Description("Docker compose file version. Leave empty for default.\n" +
"Learn more: https://docs.docker.com/compose/compose-file/compose-versioning/")]
public string ComposeVersion { get; set; }
[Description("Configure Nginx for Captcha.")]
public bool Captcha { get; set; } = false;
[Description("Configure Nginx for SSL.")]
public bool Ssl { get; set; } = true;
[Description("SSL versions used by Nginx (ssl_protocols). Leave empty for recommended default.\n" +
"Learn more: https://wiki.mozilla.org/Security/Server_Side_TLS")]
public string SslVersions { get; set; }
[Description("SSL ciphersuites used by Nginx (ssl_ciphers). Leave empty for recommended default.\n" +
"Learn more: https://wiki.mozilla.org/Security/Server_Side_TLS")]
public string SslCiphersuites { get; set; }
[Description("Installation uses a managed Let's Encrypt certificate.")]
public bool SslManagedLetsEncrypt { get; set; }
[Description("The actual certificate. (Required if using SSL without managed Let's Encrypt)\n" +
"Note: Path uses the container's ssl directory. The `./ssl` host directory is mapped to\n" +
"`/etc/ssl` within the container.")]
public string SslCertificatePath { get; set; }
[Description("The certificate's private key. (Required if using SSL without managed Let's Encrypt)\n" +
"Note: Path uses the container's ssl directory. The `./ssl` host directory is mapped to\n" +
"`/etc/ssl` within the container.")]
public string SslKeyPath { get; set; }
[Description("If the certificate is trusted by a CA, you should provide the CA's certificate.\n" +
"Note: Path uses the container's ssl directory. The `./ssl` host directory is mapped to\n" +
"`/etc/ssl` within the container.")]
public string SslCaPath { get; set; }
[Description("Diffie Hellman ephemeral parameters\n" +
"Learn more: https://security.stackexchange.com/q/94390/79072\n" +
"Note: Path uses the container's ssl directory. The `./ssl` host directory is mapped to\n" +
"`/etc/ssl` within the container.")]
public string SslDiffieHellmanPath { get; set; }
[Description("Nginx Header Content-Security-Policy parameter\n" +
"WARNING: Reconfiguring this parameter may break features. By changing this parameter\n" +
"you become responsible for maintaining this value.")]
public string NginxHeaderContentSecurityPolicy { get; set; } = "default-src 'self'; style-src 'self' " +
"'unsafe-inline'; img-src 'self' data: https://haveibeenpwned.com https://www.gravatar.com; " +
"child-src 'self' https://*.duosecurity.com https://*.duofederal.com; " +
"frame-src 'self' https://*.duosecurity.com https://*.duofederal.com; " +
"connect-src 'self' wss://{0} https://api.pwnedpasswords.com " +
"https://2fa.directory; object-src 'self' blob:;";
[Description("Communicate with the Bitwarden push relay service (push.bitwarden.com) for mobile\n" +
"app live sync.")]
public bool PushNotifications { get; set; } = true;
[Description("Use a docker volume (`mssql_data`) instead of a host-mapped volume for the persisted " +
"database.\n" +
"WARNING: Changing this value will cause you to lose access to the existing persisted database.\n" +
"Learn more: https://docs.docker.com/storage/volumes/")]
public bool DatabaseDockerVolume { get; set; }
[Description("Defines \"real\" IPs in nginx.conf. Useful for defining proxy servers that forward the \n" +
"client IP address.\n" +
"Learn more: https://nginx.org/en/docs/http/ngx_http_realip_module.html\n\n" +
"Defined as a dictionary, e.g.:\n" +
"real_ips: ['10.10.0.0/24', '172.16.0.0/16']")]
public List<string> RealIps { get; set; }
[Description("Enable Key Connector (https://bitwarden.com/help/article/deploy-key-connector)")]
public bool EnableKeyConnector { get; set; } = false;
[Description("Enable SCIM")]
public bool EnableScim { get; set; } = false;
[YamlIgnore]
public string Domain
{
[Description("Note: After making changes to this file you need to run the `rebuild` or `update`\n" +
"command for them to be applied.\n\n" +
"Full URL for accessing the installation from a browser. (Required)")]
public string Url { get; set; } = "https://localhost";
[Description("Auto-generate the `./docker/docker-compose.yml` config file.\n" +
"WARNING: Disabling generated config files can break future updates. You will be\n" +
"responsible for maintaining this config file.\n" +
"Template: https://github.com/bitwarden/server/blob/master/util/Setup/Templates/DockerCompose.hbs")]
public bool GenerateComposeConfig { get; set; } = true;
[Description("Auto-generate the `./nginx/default.conf` file.\n" +
"WARNING: Disabling generated config files can break future updates. You will be\n" +
"responsible for maintaining this config file.\n" +
"Template: https://github.com/bitwarden/server/blob/master/util/Setup/Templates/NginxConfig.hbs")]
public bool GenerateNginxConfig { get; set; } = true;
[Description("Docker compose file port mapping for HTTP. Leave empty to remove the port mapping.\n" +
"Learn more: https://docs.docker.com/compose/compose-file/#ports")]
public string HttpPort { get; set; } = "80";
[Description("Docker compose file port mapping for HTTPS. Leave empty to remove the port mapping.\n" +
"Learn more: https://docs.docker.com/compose/compose-file/#ports")]
public string HttpsPort { get; set; } = "443";
[Description("Docker compose file version. Leave empty for default.\n" +
"Learn more: https://docs.docker.com/compose/compose-file/compose-versioning/")]
public string ComposeVersion { get; set; }
[Description("Configure Nginx for Captcha.")]
public bool Captcha { get; set; } = false;
[Description("Configure Nginx for SSL.")]
public bool Ssl { get; set; } = true;
[Description("SSL versions used by Nginx (ssl_protocols). Leave empty for recommended default.\n" +
"Learn more: https://wiki.mozilla.org/Security/Server_Side_TLS")]
public string SslVersions { get; set; }
[Description("SSL ciphersuites used by Nginx (ssl_ciphers). Leave empty for recommended default.\n" +
"Learn more: https://wiki.mozilla.org/Security/Server_Side_TLS")]
public string SslCiphersuites { get; set; }
[Description("Installation uses a managed Let's Encrypt certificate.")]
public bool SslManagedLetsEncrypt { get; set; }
[Description("The actual certificate. (Required if using SSL without managed Let's Encrypt)\n" +
"Note: Path uses the container's ssl directory. The `./ssl` host directory is mapped to\n" +
"`/etc/ssl` within the container.")]
public string SslCertificatePath { get; set; }
[Description("The certificate's private key. (Required if using SSL without managed Let's Encrypt)\n" +
"Note: Path uses the container's ssl directory. The `./ssl` host directory is mapped to\n" +
"`/etc/ssl` within the container.")]
public string SslKeyPath { get; set; }
[Description("If the certificate is trusted by a CA, you should provide the CA's certificate.\n" +
"Note: Path uses the container's ssl directory. The `./ssl` host directory is mapped to\n" +
"`/etc/ssl` within the container.")]
public string SslCaPath { get; set; }
[Description("Diffie Hellman ephemeral parameters\n" +
"Learn more: https://security.stackexchange.com/q/94390/79072\n" +
"Note: Path uses the container's ssl directory. The `./ssl` host directory is mapped to\n" +
"`/etc/ssl` within the container.")]
public string SslDiffieHellmanPath { get; set; }
[Description("Nginx Header Content-Security-Policy parameter\n" +
"WARNING: Reconfiguring this parameter may break features. By changing this parameter\n" +
"you become responsible for maintaining this value.")]
public string NginxHeaderContentSecurityPolicy { get; set; } = "default-src 'self'; style-src 'self' " +
"'unsafe-inline'; img-src 'self' data: https://haveibeenpwned.com https://www.gravatar.com; " +
"child-src 'self' https://*.duosecurity.com https://*.duofederal.com; " +
"frame-src 'self' https://*.duosecurity.com https://*.duofederal.com; " +
"connect-src 'self' wss://{0} https://api.pwnedpasswords.com " +
"https://2fa.directory; object-src 'self' blob:;";
[Description("Communicate with the Bitwarden push relay service (push.bitwarden.com) for mobile\n" +
"app live sync.")]
public bool PushNotifications { get; set; } = true;
[Description("Use a docker volume (`mssql_data`) instead of a host-mapped volume for the persisted " +
"database.\n" +
"WARNING: Changing this value will cause you to lose access to the existing persisted database.\n" +
"Learn more: https://docs.docker.com/storage/volumes/")]
public bool DatabaseDockerVolume { get; set; }
[Description("Defines \"real\" IPs in nginx.conf. Useful for defining proxy servers that forward the \n" +
"client IP address.\n" +
"Learn more: https://nginx.org/en/docs/http/ngx_http_realip_module.html\n\n" +
"Defined as a dictionary, e.g.:\n" +
"real_ips: ['10.10.0.0/24', '172.16.0.0/16']")]
public List<string> RealIps { get; set; }
[Description("Enable Key Connector (https://bitwarden.com/help/article/deploy-key-connector)")]
public bool EnableKeyConnector { get; set; } = false;
[Description("Enable SCIM")]
public bool EnableScim { get; set; } = false;
[YamlIgnore]
public string Domain
get
{
get
if (Uri.TryCreate(Url, UriKind.Absolute, out var uri))
{
if (Uri.TryCreate(Url, UriKind.Absolute, out var uri))
{
return uri.Host;
}
return null;
return uri.Host;
}
return null;
}
}
}

View File

@ -1,153 +1,152 @@
using YamlDotNet.Serialization;
using YamlDotNet.Serialization.NamingConventions;
namespace Bit.Setup
namespace Bit.Setup;
public class Context
{
public class Context
private const string ConfigPath = "/bitwarden/config.yml";
public string[] Args { get; set; }
public bool Quiet { get; set; }
public bool Stub { get; set; }
public IDictionary<string, string> Parameters { get; set; }
public string OutputDir { get; set; } = "/etc/bitwarden";
public string HostOS { get; set; } = "win";
public string CoreVersion { get; set; } = "latest";
public string WebVersion { get; set; } = "latest";
public string KeyConnectorVersion { get; set; } = "latest";
public Installation Install { get; set; } = new Installation();
public Configuration Config { get; set; } = new Configuration();
public bool PrintToScreen()
{
private const string ConfigPath = "/bitwarden/config.yml";
return !Quiet || Parameters.ContainsKey("install");
}
public string[] Args { get; set; }
public bool Quiet { get; set; }
public bool Stub { get; set; }
public IDictionary<string, string> Parameters { get; set; }
public string OutputDir { get; set; } = "/etc/bitwarden";
public string HostOS { get; set; } = "win";
public string CoreVersion { get; set; } = "latest";
public string WebVersion { get; set; } = "latest";
public string KeyConnectorVersion { get; set; } = "latest";
public Installation Install { get; set; } = new Installation();
public Configuration Config { get; set; } = new Configuration();
public bool PrintToScreen()
public void LoadConfiguration()
{
if (!File.Exists(ConfigPath))
{
return !Quiet || Parameters.ContainsKey("install");
}
Helpers.WriteLine(this, "No existing `config.yml` detected. Let's generate one.");
public void LoadConfiguration()
{
if (!File.Exists(ConfigPath))
// Looks like updating from older version. Try to create config file.
var url = Helpers.GetValueFromEnvFile("global", "globalSettings__baseServiceUri__vault");
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
{
Helpers.WriteLine(this, "No existing `config.yml` detected. Let's generate one.");
Helpers.WriteLine(this, "Unable to determine existing installation url.");
return;
}
Config.Url = url;
// Looks like updating from older version. Try to create config file.
var url = Helpers.GetValueFromEnvFile("global", "globalSettings__baseServiceUri__vault");
if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
var push = Helpers.GetValueFromEnvFile("global", "globalSettings__pushRelayBaseUri");
Config.PushNotifications = push != "REPLACE";
var composeFile = "/bitwarden/docker/docker-compose.yml";
if (File.Exists(composeFile))
{
var fileLines = File.ReadAllLines(composeFile);
foreach (var line in fileLines)
{
Helpers.WriteLine(this, "Unable to determine existing installation url.");
return;
}
Config.Url = url;
var push = Helpers.GetValueFromEnvFile("global", "globalSettings__pushRelayBaseUri");
Config.PushNotifications = push != "REPLACE";
var composeFile = "/bitwarden/docker/docker-compose.yml";
if (File.Exists(composeFile))
{
var fileLines = File.ReadAllLines(composeFile);
foreach (var line in fileLines)
if (!line.StartsWith("# Parameter:"))
{
if (!line.StartsWith("# Parameter:"))
{
continue;
}
continue;
}
var paramParts = line.Split("=");
if (paramParts.Length < 2)
{
continue;
}
var paramParts = line.Split("=");
if (paramParts.Length < 2)
{
continue;
}
if (paramParts[0] == "# Parameter:MssqlDataDockerVolume" &&
bool.TryParse(paramParts[1], out var mssqlDataDockerVolume))
{
Config.DatabaseDockerVolume = mssqlDataDockerVolume;
continue;
}
if (paramParts[0] == "# Parameter:MssqlDataDockerVolume" &&
bool.TryParse(paramParts[1], out var mssqlDataDockerVolume))
{
Config.DatabaseDockerVolume = mssqlDataDockerVolume;
continue;
}
if (paramParts[0] == "# Parameter:HttpPort" && int.TryParse(paramParts[1], out var httpPort))
{
Config.HttpPort = httpPort == 0 ? null : httpPort.ToString();
continue;
}
if (paramParts[0] == "# Parameter:HttpPort" && int.TryParse(paramParts[1], out var httpPort))
{
Config.HttpPort = httpPort == 0 ? null : httpPort.ToString();
continue;
}
if (paramParts[0] == "# Parameter:HttpsPort" && int.TryParse(paramParts[1], out var httpsPort))
{
Config.HttpsPort = httpsPort == 0 ? null : httpsPort.ToString();
continue;
}
if (paramParts[0] == "# Parameter:HttpsPort" && int.TryParse(paramParts[1], out var httpsPort))
{
Config.HttpsPort = httpsPort == 0 ? null : httpsPort.ToString();
continue;
}
}
}
var nginxFile = "/bitwarden/nginx/default.conf";
if (File.Exists(nginxFile))
var nginxFile = "/bitwarden/nginx/default.conf";
if (File.Exists(nginxFile))
{
var confContent = File.ReadAllText(nginxFile);
var selfSigned = confContent.Contains("/etc/ssl/self/");
Config.Ssl = confContent.Contains("ssl http2;");
Config.SslManagedLetsEncrypt = !selfSigned && confContent.Contains("/etc/letsencrypt/live/");
var diffieHellman = confContent.Contains("/dhparam.pem;");
var trusted = confContent.Contains("ssl_trusted_certificate ");
if (Config.SslManagedLetsEncrypt)
{
var confContent = File.ReadAllText(nginxFile);
var selfSigned = confContent.Contains("/etc/ssl/self/");
Config.Ssl = confContent.Contains("ssl http2;");
Config.SslManagedLetsEncrypt = !selfSigned && confContent.Contains("/etc/letsencrypt/live/");
var diffieHellman = confContent.Contains("/dhparam.pem;");
var trusted = confContent.Contains("ssl_trusted_certificate ");
if (Config.SslManagedLetsEncrypt)
Config.Ssl = true;
}
else if (Config.Ssl)
{
var sslPath = selfSigned ? $"/etc/ssl/self/{Config.Domain}" : $"/etc/ssl/{Config.Domain}";
Config.SslCertificatePath = string.Concat(sslPath, "/", "certificate.crt");
Config.SslKeyPath = string.Concat(sslPath, "/", "private.key");
if (trusted)
{
Config.Ssl = true;
Config.SslCaPath = string.Concat(sslPath, "/", "ca.crt");
}
else if (Config.Ssl)
if (diffieHellman)
{
var sslPath = selfSigned ? $"/etc/ssl/self/{Config.Domain}" : $"/etc/ssl/{Config.Domain}";
Config.SslCertificatePath = string.Concat(sslPath, "/", "certificate.crt");
Config.SslKeyPath = string.Concat(sslPath, "/", "private.key");
if (trusted)
{
Config.SslCaPath = string.Concat(sslPath, "/", "ca.crt");
}
if (diffieHellman)
{
Config.SslDiffieHellmanPath = string.Concat(sslPath, "/", "dhparam.pem");
}
Config.SslDiffieHellmanPath = string.Concat(sslPath, "/", "dhparam.pem");
}
}
SaveConfiguration();
}
var configText = File.ReadAllText(ConfigPath);
var deserializer = new DeserializerBuilder()
.WithNamingConvention(UnderscoredNamingConvention.Instance)
.Build();
Config = deserializer.Deserialize<Configuration>(configText);
SaveConfiguration();
}
public void SaveConfiguration()
{
if (Config == null)
{
throw new Exception("Config is null.");
}
var serializer = new SerializerBuilder()
.WithNamingConvention(UnderscoredNamingConvention.Instance)
.WithTypeInspector(inner => new CommentGatheringTypeInspector(inner))
.WithEmissionPhaseObjectGraphVisitor(args => new CommentsObjectGraphVisitor(args.InnerVisitor))
.Build();
var yaml = serializer.Serialize(Config);
Directory.CreateDirectory("/bitwarden/");
using (var sw = File.CreateText(ConfigPath))
{
sw.Write(yaml);
}
}
var configText = File.ReadAllText(ConfigPath);
var deserializer = new DeserializerBuilder()
.WithNamingConvention(UnderscoredNamingConvention.Instance)
.Build();
Config = deserializer.Deserialize<Configuration>(configText);
}
public class Installation
public void SaveConfiguration()
{
if (Config == null)
{
public Guid InstallationId { get; set; }
public string InstallationKey { get; set; }
public bool DiffieHellman { get; set; }
public bool Trusted { get; set; }
public bool SelfSignedCert { get; set; }
public string IdentityCertPassword { get; set; }
public string Domain { get; set; }
public string Database { get; set; }
throw new Exception("Config is null.");
}
var serializer = new SerializerBuilder()
.WithNamingConvention(UnderscoredNamingConvention.Instance)
.WithTypeInspector(inner => new CommentGatheringTypeInspector(inner))
.WithEmissionPhaseObjectGraphVisitor(args => new CommentsObjectGraphVisitor(args.InnerVisitor))
.Build();
var yaml = serializer.Serialize(Config);
Directory.CreateDirectory("/bitwarden/");
using (var sw = File.CreateText(ConfigPath))
{
sw.Write(yaml);
}
}
public class Installation
{
public Guid InstallationId { get; set; }
public string InstallationKey { get; set; }
public bool DiffieHellman { get; set; }
public bool Trusted { get; set; }
public bool SelfSignedCert { get; set; }
public string IdentityCertPassword { get; set; }
public string Domain { get; set; }
public string Database { get; set; }
}
}

View File

@ -1,80 +1,79 @@
namespace Bit.Setup
namespace Bit.Setup;
public class DockerComposeBuilder
{
public class DockerComposeBuilder
private readonly Context _context;
public DockerComposeBuilder(Context context)
{
private readonly Context _context;
_context = context;
}
public DockerComposeBuilder(Context context)
public void BuildForInstaller()
{
_context.Config.DatabaseDockerVolume = _context.HostOS == "mac";
Build();
}
public void BuildForUpdater()
{
Build();
}
private void Build()
{
Directory.CreateDirectory("/bitwarden/docker/");
Helpers.WriteLine(_context, "Building docker-compose.yml.");
if (!_context.Config.GenerateComposeConfig)
{
_context = context;
Helpers.WriteLine(_context, "...skipped");
return;
}
public void BuildForInstaller()
var template = Helpers.ReadTemplate("DockerCompose");
var model = new TemplateModel(_context);
using (var sw = File.CreateText("/bitwarden/docker/docker-compose.yml"))
{
_context.Config.DatabaseDockerVolume = _context.HostOS == "mac";
Build();
}
public void BuildForUpdater()
{
Build();
}
private void Build()
{
Directory.CreateDirectory("/bitwarden/docker/");
Helpers.WriteLine(_context, "Building docker-compose.yml.");
if (!_context.Config.GenerateComposeConfig)
{
Helpers.WriteLine(_context, "...skipped");
return;
}
var template = Helpers.ReadTemplate("DockerCompose");
var model = new TemplateModel(_context);
using (var sw = File.CreateText("/bitwarden/docker/docker-compose.yml"))
{
sw.Write(template(model));
}
}
public class TemplateModel
{
public TemplateModel(Context context)
{
if (!string.IsNullOrWhiteSpace(context.Config.ComposeVersion))
{
ComposeVersion = context.Config.ComposeVersion;
}
MssqlDataDockerVolume = context.Config.DatabaseDockerVolume;
EnableKeyConnector = context.Config.EnableKeyConnector;
EnableScim = context.Config.EnableScim;
HttpPort = context.Config.HttpPort;
HttpsPort = context.Config.HttpsPort;
if (!string.IsNullOrWhiteSpace(context.CoreVersion))
{
CoreVersion = context.CoreVersion;
}
if (!string.IsNullOrWhiteSpace(context.WebVersion))
{
WebVersion = context.WebVersion;
}
if (!string.IsNullOrWhiteSpace(context.KeyConnectorVersion))
{
KeyConnectorVersion = context.KeyConnectorVersion;
}
}
public string ComposeVersion { get; set; } = "3";
public bool MssqlDataDockerVolume { get; set; }
public bool EnableKeyConnector { get; set; }
public bool EnableScim { get; set; }
public string HttpPort { get; set; }
public string HttpsPort { get; set; }
public bool HasPort => !string.IsNullOrWhiteSpace(HttpPort) || !string.IsNullOrWhiteSpace(HttpsPort);
public string CoreVersion { get; set; } = "latest";
public string WebVersion { get; set; } = "latest";
public string KeyConnectorVersion { get; set; } = "latest";
sw.Write(template(model));
}
}
public class TemplateModel
{
public TemplateModel(Context context)
{
if (!string.IsNullOrWhiteSpace(context.Config.ComposeVersion))
{
ComposeVersion = context.Config.ComposeVersion;
}
MssqlDataDockerVolume = context.Config.DatabaseDockerVolume;
EnableKeyConnector = context.Config.EnableKeyConnector;
EnableScim = context.Config.EnableScim;
HttpPort = context.Config.HttpPort;
HttpsPort = context.Config.HttpsPort;
if (!string.IsNullOrWhiteSpace(context.CoreVersion))
{
CoreVersion = context.CoreVersion;
}
if (!string.IsNullOrWhiteSpace(context.WebVersion))
{
WebVersion = context.WebVersion;
}
if (!string.IsNullOrWhiteSpace(context.KeyConnectorVersion))
{
KeyConnectorVersion = context.KeyConnectorVersion;
}
}
public string ComposeVersion { get; set; } = "3";
public bool MssqlDataDockerVolume { get; set; }
public bool EnableKeyConnector { get; set; }
public bool EnableScim { get; set; }
public string HttpPort { get; set; }
public string HttpsPort { get; set; }
public bool HasPort => !string.IsNullOrWhiteSpace(HttpPort) || !string.IsNullOrWhiteSpace(HttpsPort);
public string CoreVersion { get; set; } = "latest";
public string WebVersion { get; set; } = "latest";
public string KeyConnectorVersion { get; set; } = "latest";
}
}

View File

@ -1,225 +1,224 @@
using System.Data.SqlClient;
namespace Bit.Setup
namespace Bit.Setup;
public class EnvironmentFileBuilder
{
public class EnvironmentFileBuilder
private readonly Context _context;
private IDictionary<string, string> _globalValues;
private IDictionary<string, string> _mssqlValues;
private IDictionary<string, string> _globalOverrideValues;
private IDictionary<string, string> _mssqlOverrideValues;
private IDictionary<string, string> _keyConnectorOverrideValues;
public EnvironmentFileBuilder(Context context)
{
private readonly Context _context;
private IDictionary<string, string> _globalValues;
private IDictionary<string, string> _mssqlValues;
private IDictionary<string, string> _globalOverrideValues;
private IDictionary<string, string> _mssqlOverrideValues;
private IDictionary<string, string> _keyConnectorOverrideValues;
public EnvironmentFileBuilder(Context context)
_context = context;
_globalValues = new Dictionary<string, string>
{
_context = context;
_globalValues = new Dictionary<string, string>
{
["ASPNETCORE_ENVIRONMENT"] = "Production",
["globalSettings__selfHosted"] = "true",
["globalSettings__baseServiceUri__vault"] = "http://localhost",
["globalSettings__pushRelayBaseUri"] = "https://push.bitwarden.com",
};
_mssqlValues = new Dictionary<string, string>
{
["ACCEPT_EULA"] = "Y",
["MSSQL_PID"] = "Express",
["SA_PASSWORD"] = "SECRET",
};
["ASPNETCORE_ENVIRONMENT"] = "Production",
["globalSettings__selfHosted"] = "true",
["globalSettings__baseServiceUri__vault"] = "http://localhost",
["globalSettings__pushRelayBaseUri"] = "https://push.bitwarden.com",
};
_mssqlValues = new Dictionary<string, string>
{
["ACCEPT_EULA"] = "Y",
["MSSQL_PID"] = "Express",
["SA_PASSWORD"] = "SECRET",
};
}
public void BuildForInstaller()
{
Directory.CreateDirectory("/bitwarden/env/");
Init();
Build();
}
public void BuildForUpdater()
{
Init();
LoadExistingValues(_globalOverrideValues, "/bitwarden/env/global.override.env");
LoadExistingValues(_mssqlOverrideValues, "/bitwarden/env/mssql.override.env");
LoadExistingValues(_keyConnectorOverrideValues, "/bitwarden/env/key-connector.override.env");
if (_context.Config.PushNotifications &&
_globalOverrideValues.ContainsKey("globalSettings__pushRelayBaseUri") &&
_globalOverrideValues["globalSettings__pushRelayBaseUri"] == "REPLACE")
{
_globalOverrideValues.Remove("globalSettings__pushRelayBaseUri");
}
public void BuildForInstaller()
Build();
}
private void Init()
{
var dbPassword = _context.Stub ? "RANDOM_DATABASE_PASSWORD" : Helpers.SecureRandomString(32);
var dbConnectionString = new SqlConnectionStringBuilder
{
Directory.CreateDirectory("/bitwarden/env/");
Init();
Build();
DataSource = "tcp:mssql,1433",
InitialCatalog = _context.Install?.Database ?? "vault",
UserID = "sa",
Password = dbPassword,
MultipleActiveResultSets = false,
Encrypt = true,
ConnectTimeout = 30,
TrustServerCertificate = true,
PersistSecurityInfo = false
}.ConnectionString;
_globalOverrideValues = new Dictionary<string, string>
{
["globalSettings__baseServiceUri__vault"] = _context.Config.Url,
["globalSettings__sqlServer__connectionString"] = $"\"{dbConnectionString.Replace("\"", "\\\"")}\"",
["globalSettings__identityServer__certificatePassword"] = _context.Install?.IdentityCertPassword,
["globalSettings__internalIdentityKey"] = _context.Stub ? "RANDOM_IDENTITY_KEY" :
Helpers.SecureRandomString(64, alpha: true, numeric: true),
["globalSettings__oidcIdentityClientKey"] = _context.Stub ? "RANDOM_IDENTITY_KEY" :
Helpers.SecureRandomString(64, alpha: true, numeric: true),
["globalSettings__duo__aKey"] = _context.Stub ? "RANDOM_DUO_AKEY" :
Helpers.SecureRandomString(64, alpha: true, numeric: true),
["globalSettings__installation__id"] = _context.Install?.InstallationId.ToString(),
["globalSettings__installation__key"] = _context.Install?.InstallationKey,
["globalSettings__yubico__clientId"] = "REPLACE",
["globalSettings__yubico__key"] = "REPLACE",
["globalSettings__mail__replyToEmail"] = $"no-reply@{_context.Config.Domain}",
["globalSettings__mail__smtp__host"] = "REPLACE",
["globalSettings__mail__smtp__port"] = "587",
["globalSettings__mail__smtp__ssl"] = "false",
["globalSettings__mail__smtp__username"] = "REPLACE",
["globalSettings__mail__smtp__password"] = "REPLACE",
["globalSettings__disableUserRegistration"] = "false",
["globalSettings__hibpApiKey"] = "REPLACE",
["adminSettings__admins"] = string.Empty,
};
if (!_context.Config.PushNotifications)
{
_globalOverrideValues.Add("globalSettings__pushRelayBaseUri", "REPLACE");
}
public void BuildForUpdater()
_mssqlOverrideValues = new Dictionary<string, string>
{
Init();
LoadExistingValues(_globalOverrideValues, "/bitwarden/env/global.override.env");
LoadExistingValues(_mssqlOverrideValues, "/bitwarden/env/mssql.override.env");
LoadExistingValues(_keyConnectorOverrideValues, "/bitwarden/env/key-connector.override.env");
["SA_PASSWORD"] = dbPassword,
};
if (_context.Config.PushNotifications &&
_globalOverrideValues.ContainsKey("globalSettings__pushRelayBaseUri") &&
_globalOverrideValues["globalSettings__pushRelayBaseUri"] == "REPLACE")
{
_globalOverrideValues.Remove("globalSettings__pushRelayBaseUri");
}
_keyConnectorOverrideValues = new Dictionary<string, string>
{
["keyConnectorSettings__webVaultUri"] = _context.Config.Url,
["keyConnectorSettings__identityServerUri"] = "http://identity:5000",
["keyConnectorSettings__database__provider"] = "json",
["keyConnectorSettings__database__jsonFilePath"] = "/etc/bitwarden/key-connector/data.json",
["keyConnectorSettings__rsaKey__provider"] = "certificate",
["keyConnectorSettings__certificate__provider"] = "filesystem",
["keyConnectorSettings__certificate__filesystemPath"] = "/etc/bitwarden/key-connector/bwkc.pfx",
["keyConnectorSettings__certificate__filesystemPassword"] = Helpers.SecureRandomString(32, alpha: true, numeric: true),
};
}
Build();
private void LoadExistingValues(IDictionary<string, string> _values, string file)
{
if (!File.Exists(file))
{
return;
}
private void Init()
var fileLines = File.ReadAllLines(file);
foreach (var line in fileLines)
{
var dbPassword = _context.Stub ? "RANDOM_DATABASE_PASSWORD" : Helpers.SecureRandomString(32);
var dbConnectionString = new SqlConnectionStringBuilder
if (!line.Contains("="))
{
DataSource = "tcp:mssql,1433",
InitialCatalog = _context.Install?.Database ?? "vault",
UserID = "sa",
Password = dbPassword,
MultipleActiveResultSets = false,
Encrypt = true,
ConnectTimeout = 30,
TrustServerCertificate = true,
PersistSecurityInfo = false
}.ConnectionString;
_globalOverrideValues = new Dictionary<string, string>
{
["globalSettings__baseServiceUri__vault"] = _context.Config.Url,
["globalSettings__sqlServer__connectionString"] = $"\"{dbConnectionString.Replace("\"", "\\\"")}\"",
["globalSettings__identityServer__certificatePassword"] = _context.Install?.IdentityCertPassword,
["globalSettings__internalIdentityKey"] = _context.Stub ? "RANDOM_IDENTITY_KEY" :
Helpers.SecureRandomString(64, alpha: true, numeric: true),
["globalSettings__oidcIdentityClientKey"] = _context.Stub ? "RANDOM_IDENTITY_KEY" :
Helpers.SecureRandomString(64, alpha: true, numeric: true),
["globalSettings__duo__aKey"] = _context.Stub ? "RANDOM_DUO_AKEY" :
Helpers.SecureRandomString(64, alpha: true, numeric: true),
["globalSettings__installation__id"] = _context.Install?.InstallationId.ToString(),
["globalSettings__installation__key"] = _context.Install?.InstallationKey,
["globalSettings__yubico__clientId"] = "REPLACE",
["globalSettings__yubico__key"] = "REPLACE",
["globalSettings__mail__replyToEmail"] = $"no-reply@{_context.Config.Domain}",
["globalSettings__mail__smtp__host"] = "REPLACE",
["globalSettings__mail__smtp__port"] = "587",
["globalSettings__mail__smtp__ssl"] = "false",
["globalSettings__mail__smtp__username"] = "REPLACE",
["globalSettings__mail__smtp__password"] = "REPLACE",
["globalSettings__disableUserRegistration"] = "false",
["globalSettings__hibpApiKey"] = "REPLACE",
["adminSettings__admins"] = string.Empty,
};
if (!_context.Config.PushNotifications)
{
_globalOverrideValues.Add("globalSettings__pushRelayBaseUri", "REPLACE");
continue;
}
_mssqlOverrideValues = new Dictionary<string, string>
var value = string.Empty;
var lineParts = line.Split("=", 2);
if (lineParts.Length < 1)
{
["SA_PASSWORD"] = dbPassword,
};
_keyConnectorOverrideValues = new Dictionary<string, string>
{
["keyConnectorSettings__webVaultUri"] = _context.Config.Url,
["keyConnectorSettings__identityServerUri"] = "http://identity:5000",
["keyConnectorSettings__database__provider"] = "json",
["keyConnectorSettings__database__jsonFilePath"] = "/etc/bitwarden/key-connector/data.json",
["keyConnectorSettings__rsaKey__provider"] = "certificate",
["keyConnectorSettings__certificate__provider"] = "filesystem",
["keyConnectorSettings__certificate__filesystemPath"] = "/etc/bitwarden/key-connector/bwkc.pfx",
["keyConnectorSettings__certificate__filesystemPassword"] = Helpers.SecureRandomString(32, alpha: true, numeric: true),
};
}
private void LoadExistingValues(IDictionary<string, string> _values, string file)
{
if (!File.Exists(file))
{
return;
continue;
}
var fileLines = File.ReadAllLines(file);
foreach (var line in fileLines)
if (lineParts.Length > 1)
{
if (!line.Contains("="))
{
continue;
}
var value = string.Empty;
var lineParts = line.Split("=", 2);
if (lineParts.Length < 1)
{
continue;
}
if (lineParts.Length > 1)
{
value = lineParts[1];
}
if (_values.ContainsKey(lineParts[0]))
{
_values[lineParts[0]] = value;
}
else
{
_values.Add(lineParts[0], value.Replace("\\\"", "\""));
}
}
}
private void Build()
{
var template = Helpers.ReadTemplate("EnvironmentFile");
Helpers.WriteLine(_context, "Building docker environment files.");
Directory.CreateDirectory("/bitwarden/docker/");
using (var sw = File.CreateText("/bitwarden/docker/global.env"))
{
sw.Write(template(new TemplateModel(_globalValues)));
}
Helpers.Exec("chmod 600 /bitwarden/docker/global.env");
using (var sw = File.CreateText("/bitwarden/docker/mssql.env"))
{
sw.Write(template(new TemplateModel(_mssqlValues)));
}
Helpers.Exec("chmod 600 /bitwarden/docker/mssql.env");
Helpers.WriteLine(_context, "Building docker environment override files.");
Directory.CreateDirectory("/bitwarden/env/");
using (var sw = File.CreateText("/bitwarden/env/global.override.env"))
{
sw.Write(template(new TemplateModel(_globalOverrideValues)));
}
Helpers.Exec("chmod 600 /bitwarden/env/global.override.env");
using (var sw = File.CreateText("/bitwarden/env/mssql.override.env"))
{
sw.Write(template(new TemplateModel(_mssqlOverrideValues)));
}
Helpers.Exec("chmod 600 /bitwarden/env/mssql.override.env");
if (_context.Config.EnableKeyConnector)
{
using (var sw = File.CreateText("/bitwarden/env/key-connector.override.env"))
{
sw.Write(template(new TemplateModel(_keyConnectorOverrideValues)));
}
Helpers.Exec("chmod 600 /bitwarden/env/key-connector.override.env");
value = lineParts[1];
}
// Empty uid env file. Only used on Linux hosts.
if (!File.Exists("/bitwarden/env/uid.env"))
if (_values.ContainsKey(lineParts[0]))
{
using (var sw = File.CreateText("/bitwarden/env/uid.env")) { }
_values[lineParts[0]] = value;
}
}
public class TemplateModel
{
public TemplateModel(IEnumerable<KeyValuePair<string, string>> variables)
else
{
Variables = variables.Select(v => new Kvp { Key = v.Key, Value = v.Value });
}
public IEnumerable<Kvp> Variables { get; set; }
public class Kvp
{
public string Key { get; set; }
public string Value { get; set; }
_values.Add(lineParts[0], value.Replace("\\\"", "\""));
}
}
}
private void Build()
{
var template = Helpers.ReadTemplate("EnvironmentFile");
Helpers.WriteLine(_context, "Building docker environment files.");
Directory.CreateDirectory("/bitwarden/docker/");
using (var sw = File.CreateText("/bitwarden/docker/global.env"))
{
sw.Write(template(new TemplateModel(_globalValues)));
}
Helpers.Exec("chmod 600 /bitwarden/docker/global.env");
using (var sw = File.CreateText("/bitwarden/docker/mssql.env"))
{
sw.Write(template(new TemplateModel(_mssqlValues)));
}
Helpers.Exec("chmod 600 /bitwarden/docker/mssql.env");
Helpers.WriteLine(_context, "Building docker environment override files.");
Directory.CreateDirectory("/bitwarden/env/");
using (var sw = File.CreateText("/bitwarden/env/global.override.env"))
{
sw.Write(template(new TemplateModel(_globalOverrideValues)));
}
Helpers.Exec("chmod 600 /bitwarden/env/global.override.env");
using (var sw = File.CreateText("/bitwarden/env/mssql.override.env"))
{
sw.Write(template(new TemplateModel(_mssqlOverrideValues)));
}
Helpers.Exec("chmod 600 /bitwarden/env/mssql.override.env");
if (_context.Config.EnableKeyConnector)
{
using (var sw = File.CreateText("/bitwarden/env/key-connector.override.env"))
{
sw.Write(template(new TemplateModel(_keyConnectorOverrideValues)));
}
Helpers.Exec("chmod 600 /bitwarden/env/key-connector.override.env");
}
// Empty uid env file. Only used on Linux hosts.
if (!File.Exists("/bitwarden/env/uid.env"))
{
using (var sw = File.CreateText("/bitwarden/env/uid.env")) { }
}
}
public class TemplateModel
{
public TemplateModel(IEnumerable<KeyValuePair<string, string>> variables)
{
Variables = variables.Select(v => new Kvp { Key = v.Key, Value = v.Value });
}
public IEnumerable<Kvp> Variables { get; set; }
public class Kvp
{
public string Key { get; set; }
public string Value { get; set; }
}
}
}

View File

@ -4,223 +4,222 @@ using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Text;
namespace Bit.Setup
namespace Bit.Setup;
public static class Helpers
{
public static class Helpers
public static string SecureRandomString(int length, bool alpha = true, bool upper = true, bool lower = true,
bool numeric = true, bool special = false)
{
public static string SecureRandomString(int length, bool alpha = true, bool upper = true, bool lower = true,
bool numeric = true, bool special = false)
return SecureRandomString(length, RandomStringCharacters(alpha, upper, lower, numeric, special));
}
// ref https://stackoverflow.com/a/8996788/1090359 with modifications
public static string SecureRandomString(int length, string characters)
{
if (length < 0)
{
return SecureRandomString(length, RandomStringCharacters(alpha, upper, lower, numeric, special));
throw new ArgumentOutOfRangeException(nameof(length), "length cannot be less than zero.");
}
// ref https://stackoverflow.com/a/8996788/1090359 with modifications
public static string SecureRandomString(int length, string characters)
if ((characters?.Length ?? 0) == 0)
{
if (length < 0)
{
throw new ArgumentOutOfRangeException(nameof(length), "length cannot be less than zero.");
}
throw new ArgumentOutOfRangeException(nameof(characters), "characters invalid.");
}
if ((characters?.Length ?? 0) == 0)
{
throw new ArgumentOutOfRangeException(nameof(characters), "characters invalid.");
}
const int byteSize = 0x100;
if (byteSize < characters.Length)
{
throw new ArgumentException(
string.Format("{0} may contain no more than {1} characters.", nameof(characters), byteSize),
nameof(characters));
}
const int byteSize = 0x100;
if (byteSize < characters.Length)
var outOfRangeStart = byteSize - (byteSize % characters.Length);
using (var rng = RandomNumberGenerator.Create())
{
var sb = new StringBuilder();
var buffer = new byte[128];
while (sb.Length < length)
{
throw new ArgumentException(
string.Format("{0} may contain no more than {1} characters.", nameof(characters), byteSize),
nameof(characters));
}
var outOfRangeStart = byteSize - (byteSize % characters.Length);
using (var rng = RandomNumberGenerator.Create())
{
var sb = new StringBuilder();
var buffer = new byte[128];
while (sb.Length < length)
rng.GetBytes(buffer);
for (var i = 0; i < buffer.Length && sb.Length < length; ++i)
{
rng.GetBytes(buffer);
for (var i = 0; i < buffer.Length && sb.Length < length; ++i)
// Divide the byte into charSet-sized groups. If the random value falls into the last group and the
// last group is too small to choose from the entire allowedCharSet, ignore the value in order to
// avoid biasing the result.
if (outOfRangeStart <= buffer[i])
{
// Divide the byte into charSet-sized groups. If the random value falls into the last group and the
// last group is too small to choose from the entire allowedCharSet, ignore the value in order to
// avoid biasing the result.
if (outOfRangeStart <= buffer[i])
{
continue;
}
sb.Append(characters[buffer[i] % characters.Length]);
continue;
}
}
return sb.ToString();
sb.Append(characters[buffer[i] % characters.Length]);
}
}
return sb.ToString();
}
}
private static string RandomStringCharacters(bool alpha, bool upper, bool lower, bool numeric, bool special)
{
var characters = string.Empty;
if (alpha)
{
if (upper)
{
characters += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
}
if (lower)
{
characters += "abcdefghijklmnopqrstuvwxyz";
}
}
private static string RandomStringCharacters(bool alpha, bool upper, bool lower, bool numeric, bool special)
if (numeric)
{
var characters = string.Empty;
if (alpha)
{
if (upper)
{
characters += "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
}
if (lower)
{
characters += "abcdefghijklmnopqrstuvwxyz";
}
}
if (numeric)
{
characters += "0123456789";
}
if (special)
{
characters += "!@#$%^*&";
}
return characters;
characters += "0123456789";
}
public static string GetValueFromEnvFile(string envFile, string key)
if (special)
{
if (!File.Exists($"/bitwarden/env/{envFile}.override.env"))
{
return null;
}
characters += "!@#$%^*&";
}
var lines = File.ReadAllLines($"/bitwarden/env/{envFile}.override.env");
foreach (var line in lines)
{
if (line.StartsWith($"{key}="))
{
return line.Split(new char[] { '=' }, 2)[1].Trim('"').Replace("\\\"", "\"");
}
}
return characters;
}
public static string GetValueFromEnvFile(string envFile, string key)
{
if (!File.Exists($"/bitwarden/env/{envFile}.override.env"))
{
return null;
}
public static string Exec(string cmd, bool returnStdout = false)
var lines = File.ReadAllLines($"/bitwarden/env/{envFile}.override.env");
foreach (var line in lines)
{
var process = new Process
if (line.StartsWith($"{key}="))
{
StartInfo = new ProcessStartInfo
{
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
}
};
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var escapedArgs = cmd.Replace("\"", "\\\"");
process.StartInfo.FileName = "/bin/bash";
process.StartInfo.Arguments = $"-c \"{escapedArgs}\"";
return line.Split(new char[] { '=' }, 2)[1].Trim('"').Replace("\\\"", "\"");
}
else
{
process.StartInfo.FileName = "powershell";
process.StartInfo.Arguments = cmd;
}
process.Start();
var result = returnStdout ? process.StandardOutput.ReadToEnd() : null;
process.WaitForExit();
return result;
}
public static string ReadInput(string prompt)
return null;
}
public static string Exec(string cmd, bool returnStdout = false)
{
var process = new Process
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("(!) ");
Console.ResetColor();
Console.Write(prompt);
if (prompt.EndsWith("?"))
StartInfo = new ProcessStartInfo
{
Console.Write(" (y/n)");
RedirectStandardOutput = true,
UseShellExecute = false,
CreateNoWindow = true,
WindowStyle = ProcessWindowStyle.Hidden
}
Console.Write(": ");
var input = Console.ReadLine();
};
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var escapedArgs = cmd.Replace("\"", "\\\"");
process.StartInfo.FileName = "/bin/bash";
process.StartInfo.Arguments = $"-c \"{escapedArgs}\"";
}
else
{
process.StartInfo.FileName = "powershell";
process.StartInfo.Arguments = cmd;
}
process.Start();
var result = returnStdout ? process.StandardOutput.ReadToEnd() : null;
process.WaitForExit();
return result;
}
public static string ReadInput(string prompt)
{
Console.ForegroundColor = ConsoleColor.Cyan;
Console.Write("(!) ");
Console.ResetColor();
Console.Write(prompt);
if (prompt.EndsWith("?"))
{
Console.Write(" (y/n)");
}
Console.Write(": ");
var input = Console.ReadLine();
Console.WriteLine();
return input;
}
public static bool ReadQuestion(string prompt)
{
var input = ReadInput(prompt).ToLowerInvariant().Trim();
return input == "y" || input == "yes";
}
public static void ShowBanner(Context context, string title, string message, ConsoleColor? color = null)
{
if (!context.PrintToScreen())
{
return;
}
if (color != null)
{
Console.ForegroundColor = color.Value;
}
Console.WriteLine($"!!!!!!!!!! {title} !!!!!!!!!!");
Console.WriteLine(message);
Console.WriteLine();
Console.ResetColor();
}
public static HandlebarsDotNet.HandlebarsTemplate<object, object> ReadTemplate(string templateName)
{
var assembly = typeof(Helpers).GetTypeInfo().Assembly;
var fullTemplateName = $"Bit.Setup.Templates.{templateName}.hbs";
if (!assembly.GetManifestResourceNames().Any(f => f == fullTemplateName))
{
return null;
}
using (var s = assembly.GetManifestResourceStream(fullTemplateName))
using (var sr = new StreamReader(s))
{
var templateText = sr.ReadToEnd();
return HandlebarsDotNet.Handlebars.Compile(templateText);
}
}
public static void WriteLine(Context context, string format = null, object arg0 = null, object arg1 = null,
object arg2 = null)
{
if (!context.PrintToScreen())
{
return;
}
if (format != null && arg0 != null && arg1 != null && arg2 != null)
{
Console.WriteLine(format, arg0, arg1, arg2);
}
else if (format != null && arg0 != null && arg1 != null)
{
Console.WriteLine(format, arg0, arg1);
}
else if (format != null && arg0 != null)
{
Console.WriteLine(format, arg0);
}
else if (format != null)
{
Console.WriteLine(format);
}
else
{
Console.WriteLine();
return input;
}
public static bool ReadQuestion(string prompt)
{
var input = ReadInput(prompt).ToLowerInvariant().Trim();
return input == "y" || input == "yes";
}
public static void ShowBanner(Context context, string title, string message, ConsoleColor? color = null)
{
if (!context.PrintToScreen())
{
return;
}
if (color != null)
{
Console.ForegroundColor = color.Value;
}
Console.WriteLine($"!!!!!!!!!! {title} !!!!!!!!!!");
Console.WriteLine(message);
Console.WriteLine();
Console.ResetColor();
}
public static HandlebarsDotNet.HandlebarsTemplate<object, object> ReadTemplate(string templateName)
{
var assembly = typeof(Helpers).GetTypeInfo().Assembly;
var fullTemplateName = $"Bit.Setup.Templates.{templateName}.hbs";
if (!assembly.GetManifestResourceNames().Any(f => f == fullTemplateName))
{
return null;
}
using (var s = assembly.GetManifestResourceStream(fullTemplateName))
using (var sr = new StreamReader(s))
{
var templateText = sr.ReadToEnd();
return HandlebarsDotNet.Handlebars.Compile(templateText);
}
}
public static void WriteLine(Context context, string format = null, object arg0 = null, object arg1 = null,
object arg2 = null)
{
if (!context.PrintToScreen())
{
return;
}
if (format != null && arg0 != null && arg1 != null && arg2 != null)
{
Console.WriteLine(format, arg0, arg1, arg2);
}
else if (format != null && arg0 != null && arg1 != null)
{
Console.WriteLine(format, arg0, arg1);
}
else if (format != null && arg0 != null)
{
Console.WriteLine(format, arg0);
}
else if (format != null)
{
Console.WriteLine(format);
}
else
{
Console.WriteLine();
}
}
}
}

View File

@ -1,133 +1,132 @@
namespace Bit.Setup
namespace Bit.Setup;
public class NginxConfigBuilder
{
public class NginxConfigBuilder
private const string ConfFile = "/bitwarden/nginx/default.conf";
private readonly Context _context;
public NginxConfigBuilder(Context context)
{
private const string ConfFile = "/bitwarden/nginx/default.conf";
_context = context;
}
private readonly Context _context;
public NginxConfigBuilder(Context context)
public void BuildForInstaller()
{
var model = new TemplateModel(_context);
if (model.Ssl && !_context.Config.SslManagedLetsEncrypt)
{
_context = context;
}
public void BuildForInstaller()
{
var model = new TemplateModel(_context);
if (model.Ssl && !_context.Config.SslManagedLetsEncrypt)
var sslPath = _context.Install.SelfSignedCert ?
$"/etc/ssl/self/{model.Domain}" : $"/etc/ssl/{model.Domain}";
_context.Config.SslCertificatePath = model.CertificatePath =
string.Concat(sslPath, "/", "certificate.crt");
_context.Config.SslKeyPath = model.KeyPath =
string.Concat(sslPath, "/", "private.key");
if (_context.Install.Trusted)
{
var sslPath = _context.Install.SelfSignedCert ?
$"/etc/ssl/self/{model.Domain}" : $"/etc/ssl/{model.Domain}";
_context.Config.SslCertificatePath = model.CertificatePath =
string.Concat(sslPath, "/", "certificate.crt");
_context.Config.SslKeyPath = model.KeyPath =
string.Concat(sslPath, "/", "private.key");
if (_context.Install.Trusted)
{
_context.Config.SslCaPath = model.CaPath =
string.Concat(sslPath, "/", "ca.crt");
}
if (_context.Install.DiffieHellman)
{
_context.Config.SslDiffieHellmanPath = model.DiffieHellmanPath =
string.Concat(sslPath, "/", "dhparam.pem");
}
_context.Config.SslCaPath = model.CaPath =
string.Concat(sslPath, "/", "ca.crt");
}
Build(model);
}
public void BuildForUpdater()
{
var model = new TemplateModel(_context);
Build(model);
}
private void Build(TemplateModel model)
{
Directory.CreateDirectory("/bitwarden/nginx/");
Helpers.WriteLine(_context, "Building nginx config.");
if (!_context.Config.GenerateNginxConfig)
if (_context.Install.DiffieHellman)
{
Helpers.WriteLine(_context, "...skipped");
return;
}
var template = Helpers.ReadTemplate("NginxConfig");
using (var sw = File.CreateText(ConfFile))
{
sw.WriteLine(template(model));
_context.Config.SslDiffieHellmanPath = model.DiffieHellmanPath =
string.Concat(sslPath, "/", "dhparam.pem");
}
}
Build(model);
}
public class TemplateModel
public void BuildForUpdater()
{
var model = new TemplateModel(_context);
Build(model);
}
private void Build(TemplateModel model)
{
Directory.CreateDirectory("/bitwarden/nginx/");
Helpers.WriteLine(_context, "Building nginx config.");
if (!_context.Config.GenerateNginxConfig)
{
public TemplateModel() { }
Helpers.WriteLine(_context, "...skipped");
return;
}
public TemplateModel(Context context)
{
Captcha = context.Config.Captcha;
Ssl = context.Config.Ssl;
EnableKeyConnector = context.Config.EnableKeyConnector;
EnableScim = context.Config.EnableScim;
Domain = context.Config.Domain;
Url = context.Config.Url;
RealIps = context.Config.RealIps;
ContentSecurityPolicy = string.Format(context.Config.NginxHeaderContentSecurityPolicy, Domain);
if (Ssl)
{
if (context.Config.SslManagedLetsEncrypt)
{
var sslPath = $"/etc/letsencrypt/live/{Domain}";
CertificatePath = CaPath = string.Concat(sslPath, "/", "fullchain.pem");
KeyPath = string.Concat(sslPath, "/", "privkey.pem");
DiffieHellmanPath = string.Concat(sslPath, "/", "dhparam.pem");
}
else
{
CertificatePath = context.Config.SslCertificatePath;
KeyPath = context.Config.SslKeyPath;
CaPath = context.Config.SslCaPath;
DiffieHellmanPath = context.Config.SslDiffieHellmanPath;
}
}
if (!string.IsNullOrWhiteSpace(context.Config.SslCiphersuites))
{
SslCiphers = context.Config.SslCiphersuites;
}
else
{
SslCiphers = "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:" +
"ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:" +
"ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:" +
"ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256";
}
if (!string.IsNullOrWhiteSpace(context.Config.SslVersions))
{
SslProtocols = context.Config.SslVersions;
}
else
{
SslProtocols = "TLSv1.2";
}
}
public bool Captcha { get; set; }
public bool Ssl { get; set; }
public bool EnableKeyConnector { get; set; }
public bool EnableScim { get; set; }
public string Domain { get; set; }
public string Url { get; set; }
public string CertificatePath { get; set; }
public string KeyPath { get; set; }
public string CaPath { get; set; }
public string DiffieHellmanPath { get; set; }
public string SslCiphers { get; set; }
public string SslProtocols { get; set; }
public string ContentSecurityPolicy { get; set; }
public List<string> RealIps { get; set; }
var template = Helpers.ReadTemplate("NginxConfig");
using (var sw = File.CreateText(ConfFile))
{
sw.WriteLine(template(model));
}
}
public class TemplateModel
{
public TemplateModel() { }
public TemplateModel(Context context)
{
Captcha = context.Config.Captcha;
Ssl = context.Config.Ssl;
EnableKeyConnector = context.Config.EnableKeyConnector;
EnableScim = context.Config.EnableScim;
Domain = context.Config.Domain;
Url = context.Config.Url;
RealIps = context.Config.RealIps;
ContentSecurityPolicy = string.Format(context.Config.NginxHeaderContentSecurityPolicy, Domain);
if (Ssl)
{
if (context.Config.SslManagedLetsEncrypt)
{
var sslPath = $"/etc/letsencrypt/live/{Domain}";
CertificatePath = CaPath = string.Concat(sslPath, "/", "fullchain.pem");
KeyPath = string.Concat(sslPath, "/", "privkey.pem");
DiffieHellmanPath = string.Concat(sslPath, "/", "dhparam.pem");
}
else
{
CertificatePath = context.Config.SslCertificatePath;
KeyPath = context.Config.SslKeyPath;
CaPath = context.Config.SslCaPath;
DiffieHellmanPath = context.Config.SslDiffieHellmanPath;
}
}
if (!string.IsNullOrWhiteSpace(context.Config.SslCiphersuites))
{
SslCiphers = context.Config.SslCiphersuites;
}
else
{
SslCiphers = "ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:" +
"ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:" +
"ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:" +
"ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256";
}
if (!string.IsNullOrWhiteSpace(context.Config.SslVersions))
{
SslProtocols = context.Config.SslVersions;
}
else
{
SslProtocols = "TLSv1.2";
}
}
public bool Captcha { get; set; }
public bool Ssl { get; set; }
public bool EnableKeyConnector { get; set; }
public bool EnableScim { get; set; }
public string Domain { get; set; }
public string Url { get; set; }
public string CertificatePath { get; set; }
public string KeyPath { get; set; }
public string CaPath { get; set; }
public string DiffieHellmanPath { get; set; }
public string SslCiphers { get; set; }
public string SslProtocols { get; set; }
public string ContentSecurityPolicy { get; set; }
public List<string> RealIps { get; set; }
}
}

View File

@ -3,328 +3,327 @@ using System.Globalization;
using System.Net.Http.Json;
using Bit.Migrator;
namespace Bit.Setup
namespace Bit.Setup;
public class Program
{
public class Program
private static Context _context;
public static void Main(string[] args)
{
private static Context _context;
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
public static void Main(string[] args)
_context = new Context
{
CultureInfo.DefaultThreadCurrentCulture = new CultureInfo("en-US");
Args = args
};
ParseParameters();
_context = new Context
{
Args = args
};
ParseParameters();
if (_context.Parameters.ContainsKey("q"))
{
_context.Quiet = _context.Parameters["q"] == "true" || _context.Parameters["q"] == "1";
}
if (_context.Parameters.ContainsKey("os"))
{
_context.HostOS = _context.Parameters["os"];
}
if (_context.Parameters.ContainsKey("corev"))
{
_context.CoreVersion = _context.Parameters["corev"];
}
if (_context.Parameters.ContainsKey("webv"))
{
_context.WebVersion = _context.Parameters["webv"];
}
if (_context.Parameters.ContainsKey("keyconnectorv"))
{
_context.KeyConnectorVersion = _context.Parameters["keyconnectorv"];
}
if (_context.Parameters.ContainsKey("stub"))
{
_context.Stub = _context.Parameters["stub"] == "true" ||
_context.Parameters["stub"] == "1";
}
if (_context.Parameters.ContainsKey("q"))
{
_context.Quiet = _context.Parameters["q"] == "true" || _context.Parameters["q"] == "1";
}
if (_context.Parameters.ContainsKey("os"))
{
_context.HostOS = _context.Parameters["os"];
}
if (_context.Parameters.ContainsKey("corev"))
{
_context.CoreVersion = _context.Parameters["corev"];
}
if (_context.Parameters.ContainsKey("webv"))
{
_context.WebVersion = _context.Parameters["webv"];
}
if (_context.Parameters.ContainsKey("keyconnectorv"))
{
_context.KeyConnectorVersion = _context.Parameters["keyconnectorv"];
}
if (_context.Parameters.ContainsKey("stub"))
{
_context.Stub = _context.Parameters["stub"] == "true" ||
_context.Parameters["stub"] == "1";
}
Helpers.WriteLine(_context);
Helpers.WriteLine(_context);
if (_context.Parameters.ContainsKey("install"))
{
Install();
}
else if (_context.Parameters.ContainsKey("update"))
{
Update();
}
else if (_context.Parameters.ContainsKey("printenv"))
{
PrintEnvironment();
}
else
{
Helpers.WriteLine(_context, "No top-level command detected. Exiting...");
}
}
if (_context.Parameters.ContainsKey("install"))
private static void Install()
{
if (_context.Parameters.ContainsKey("letsencrypt"))
{
_context.Config.SslManagedLetsEncrypt =
_context.Parameters["letsencrypt"].ToLowerInvariant() == "y";
}
if (_context.Parameters.ContainsKey("domain"))
{
_context.Install.Domain = _context.Parameters["domain"].ToLowerInvariant();
}
if (_context.Parameters.ContainsKey("dbname"))
{
_context.Install.Database = _context.Parameters["dbname"];
}
if (_context.Stub)
{
_context.Install.InstallationId = Guid.Empty;
_context.Install.InstallationKey = "SECRET_INSTALLATION_KEY";
}
else if (!ValidateInstallation())
{
return;
}
var certBuilder = new CertBuilder(_context);
certBuilder.BuildForInstall();
// Set the URL
_context.Config.Url = string.Format("http{0}://{1}",
_context.Config.Ssl ? "s" : string.Empty, _context.Install.Domain);
var nginxBuilder = new NginxConfigBuilder(_context);
nginxBuilder.BuildForInstaller();
var environmentFileBuilder = new EnvironmentFileBuilder(_context);
environmentFileBuilder.BuildForInstaller();
var appIdBuilder = new AppIdBuilder(_context);
appIdBuilder.Build();
var dockerComposeBuilder = new DockerComposeBuilder(_context);
dockerComposeBuilder.BuildForInstaller();
_context.SaveConfiguration();
Console.WriteLine("\nInstallation complete");
Console.WriteLine("\nIf you need to make additional configuration changes, you can modify\n" +
"the settings in `{0}` and then run:\n{1}",
_context.HostOS == "win" ? ".\\bwdata\\config.yml" : "./bwdata/config.yml",
_context.HostOS == "win" ? "`.\\bitwarden.ps1 -rebuild` or `.\\bitwarden.ps1 -update`" :
"`./bitwarden.sh rebuild` or `./bitwarden.sh update`");
Console.WriteLine("\nNext steps, run:");
if (_context.HostOS == "win")
{
Console.WriteLine("`.\\bitwarden.ps1 -start`");
}
else
{
Console.WriteLine("`./bitwarden.sh start`");
}
Console.WriteLine(string.Empty);
}
private static void Update()
{
// This portion of code checks for multiple certs in the Identity.pfx PKCS12 bag. If found, it generates
// a new cert and bag to replace the old Identity.pfx. This fixes an issue that came up as a result of
// moving the project to .NET 5.
_context.Install.IdentityCertPassword = Helpers.GetValueFromEnvFile("global", "globalSettings__identityServer__certificatePassword");
var certCountString = Helpers.Exec("openssl pkcs12 -nokeys -info -in /bitwarden/identity/identity.pfx " +
$"-passin pass:{_context.Install.IdentityCertPassword} 2> /dev/null | grep -c \"\\-----BEGIN CERTIFICATE----\"", true);
if (int.TryParse(certCountString, out var certCount) && certCount > 1)
{
// Extract key from identity.pfx
Helpers.Exec("openssl pkcs12 -in /bitwarden/identity/identity.pfx -nocerts -nodes -out identity.key " +
$"-passin pass:{_context.Install.IdentityCertPassword} > /dev/null 2>&1");
// Extract certificate from identity.pfx
Helpers.Exec("openssl pkcs12 -in /bitwarden/identity/identity.pfx -clcerts -nokeys -out identity.crt " +
$"-passin pass:{_context.Install.IdentityCertPassword} > /dev/null 2>&1");
// Create new PKCS12 bag with certificate and key
Helpers.Exec("openssl pkcs12 -export -out /bitwarden/identity/identity.pfx -inkey identity.key " +
$"-in identity.crt -passout pass:{_context.Install.IdentityCertPassword} > /dev/null 2>&1");
}
if (_context.Parameters.ContainsKey("db"))
{
MigrateDatabase();
}
else
{
RebuildConfigs();
}
}
private static void PrintEnvironment()
{
_context.LoadConfiguration();
if (!_context.PrintToScreen())
{
return;
}
Console.WriteLine("\nBitwarden is up and running!");
Console.WriteLine("===================================================");
Console.WriteLine("\nvisit {0}", _context.Config.Url);
Console.Write("to update, run ");
if (_context.HostOS == "win")
{
Console.Write("`.\\bitwarden.ps1 -updateself` and then `.\\bitwarden.ps1 -update`");
}
else
{
Console.Write("`./bitwarden.sh updateself` and then `./bitwarden.sh update`");
}
Console.WriteLine("\n");
}
private static void MigrateDatabase(int attempt = 1)
{
try
{
Helpers.WriteLine(_context, "Migrating database.");
var vaultConnectionString = Helpers.GetValueFromEnvFile("global",
"globalSettings__sqlServer__connectionString");
var migrator = new DbMigrator(vaultConnectionString, null);
var success = migrator.MigrateMsSqlDatabase(false);
if (success)
{
Install();
}
else if (_context.Parameters.ContainsKey("update"))
{
Update();
}
else if (_context.Parameters.ContainsKey("printenv"))
{
PrintEnvironment();
Helpers.WriteLine(_context, "Migration successful.");
}
else
{
Helpers.WriteLine(_context, "No top-level command detected. Exiting...");
Helpers.WriteLine(_context, "Migration failed.");
}
}
private static void Install()
catch (SqlException e)
{
if (_context.Parameters.ContainsKey("letsencrypt"))
{
_context.Config.SslManagedLetsEncrypt =
_context.Parameters["letsencrypt"].ToLowerInvariant() == "y";
}
if (_context.Parameters.ContainsKey("domain"))
{
_context.Install.Domain = _context.Parameters["domain"].ToLowerInvariant();
}
if (_context.Parameters.ContainsKey("dbname"))
{
_context.Install.Database = _context.Parameters["dbname"];
}
if (_context.Stub)
{
_context.Install.InstallationId = Guid.Empty;
_context.Install.InstallationKey = "SECRET_INSTALLATION_KEY";
}
else if (!ValidateInstallation())
if (e.Message.Contains("Server is in script upgrade mode") && attempt < 10)
{
var nextAttempt = attempt + 1;
Helpers.WriteLine(_context, "Database is in script upgrade mode. " +
"Trying again (attempt #{0})...", nextAttempt);
System.Threading.Thread.Sleep(20000);
MigrateDatabase(nextAttempt);
return;
}
throw;
}
}
var certBuilder = new CertBuilder(_context);
certBuilder.BuildForInstall();
private static bool ValidateInstallation()
{
var installationId = string.Empty;
var installationKey = string.Empty;
// Set the URL
_context.Config.Url = string.Format("http{0}://{1}",
_context.Config.Ssl ? "s" : string.Empty, _context.Install.Domain);
var nginxBuilder = new NginxConfigBuilder(_context);
nginxBuilder.BuildForInstaller();
var environmentFileBuilder = new EnvironmentFileBuilder(_context);
environmentFileBuilder.BuildForInstaller();
var appIdBuilder = new AppIdBuilder(_context);
appIdBuilder.Build();
var dockerComposeBuilder = new DockerComposeBuilder(_context);
dockerComposeBuilder.BuildForInstaller();
_context.SaveConfiguration();
Console.WriteLine("\nInstallation complete");
Console.WriteLine("\nIf you need to make additional configuration changes, you can modify\n" +
"the settings in `{0}` and then run:\n{1}",
_context.HostOS == "win" ? ".\\bwdata\\config.yml" : "./bwdata/config.yml",
_context.HostOS == "win" ? "`.\\bitwarden.ps1 -rebuild` or `.\\bitwarden.ps1 -update`" :
"`./bitwarden.sh rebuild` or `./bitwarden.sh update`");
Console.WriteLine("\nNext steps, run:");
if (_context.HostOS == "win")
{
Console.WriteLine("`.\\bitwarden.ps1 -start`");
}
else
{
Console.WriteLine("`./bitwarden.sh start`");
}
Console.WriteLine(string.Empty);
if (_context.Parameters.ContainsKey("install-id"))
{
installationId = _context.Parameters["install-id"].ToLowerInvariant();
}
else
{
installationId = Helpers.ReadInput("Enter your installation id (get at https://bitwarden.com/host)");
}
private static void Update()
if (!Guid.TryParse(installationId.Trim(), out var installationidGuid))
{
// This portion of code checks for multiple certs in the Identity.pfx PKCS12 bag. If found, it generates
// a new cert and bag to replace the old Identity.pfx. This fixes an issue that came up as a result of
// moving the project to .NET 5.
_context.Install.IdentityCertPassword = Helpers.GetValueFromEnvFile("global", "globalSettings__identityServer__certificatePassword");
var certCountString = Helpers.Exec("openssl pkcs12 -nokeys -info -in /bitwarden/identity/identity.pfx " +
$"-passin pass:{_context.Install.IdentityCertPassword} 2> /dev/null | grep -c \"\\-----BEGIN CERTIFICATE----\"", true);
if (int.TryParse(certCountString, out var certCount) && certCount > 1)
{
// Extract key from identity.pfx
Helpers.Exec("openssl pkcs12 -in /bitwarden/identity/identity.pfx -nocerts -nodes -out identity.key " +
$"-passin pass:{_context.Install.IdentityCertPassword} > /dev/null 2>&1");
// Extract certificate from identity.pfx
Helpers.Exec("openssl pkcs12 -in /bitwarden/identity/identity.pfx -clcerts -nokeys -out identity.crt " +
$"-passin pass:{_context.Install.IdentityCertPassword} > /dev/null 2>&1");
// Create new PKCS12 bag with certificate and key
Helpers.Exec("openssl pkcs12 -export -out /bitwarden/identity/identity.pfx -inkey identity.key " +
$"-in identity.crt -passout pass:{_context.Install.IdentityCertPassword} > /dev/null 2>&1");
}
if (_context.Parameters.ContainsKey("db"))
{
MigrateDatabase();
}
else
{
RebuildConfigs();
}
Console.WriteLine("Invalid installation id.");
return false;
}
private static void PrintEnvironment()
if (_context.Parameters.ContainsKey("install-key"))
{
_context.LoadConfiguration();
if (!_context.PrintToScreen())
{
return;
}
Console.WriteLine("\nBitwarden is up and running!");
Console.WriteLine("===================================================");
Console.WriteLine("\nvisit {0}", _context.Config.Url);
Console.Write("to update, run ");
if (_context.HostOS == "win")
{
Console.Write("`.\\bitwarden.ps1 -updateself` and then `.\\bitwarden.ps1 -update`");
}
else
{
Console.Write("`./bitwarden.sh updateself` and then `./bitwarden.sh update`");
}
Console.WriteLine("\n");
installationKey = _context.Parameters["install-key"];
}
else
{
installationKey = Helpers.ReadInput("Enter your installation key");
}
private static void MigrateDatabase(int attempt = 1)
_context.Install.InstallationId = installationidGuid;
_context.Install.InstallationKey = installationKey;
try
{
try
var response = new HttpClient().GetAsync("https://api.bitwarden.com/installations/" +
_context.Install.InstallationId).GetAwaiter().GetResult();
if (!response.IsSuccessStatusCode)
{
Helpers.WriteLine(_context, "Migrating database.");
var vaultConnectionString = Helpers.GetValueFromEnvFile("global",
"globalSettings__sqlServer__connectionString");
var migrator = new DbMigrator(vaultConnectionString, null);
var success = migrator.MigrateMsSqlDatabase(false);
if (success)
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
{
Helpers.WriteLine(_context, "Migration successful.");
Console.WriteLine("Invalid installation id.");
}
else
{
Helpers.WriteLine(_context, "Migration failed.");
Console.WriteLine("Unable to validate installation id.");
}
}
catch (SqlException e)
{
if (e.Message.Contains("Server is in script upgrade mode") && attempt < 10)
{
var nextAttempt = attempt + 1;
Helpers.WriteLine(_context, "Database is in script upgrade mode. " +
"Trying again (attempt #{0})...", nextAttempt);
System.Threading.Thread.Sleep(20000);
MigrateDatabase(nextAttempt);
return;
}
throw;
}
}
private static bool ValidateInstallation()
{
var installationId = string.Empty;
var installationKey = string.Empty;
if (_context.Parameters.ContainsKey("install-id"))
{
installationId = _context.Parameters["install-id"].ToLowerInvariant();
}
else
{
installationId = Helpers.ReadInput("Enter your installation id (get at https://bitwarden.com/host)");
}
if (!Guid.TryParse(installationId.Trim(), out var installationidGuid))
{
Console.WriteLine("Invalid installation id.");
return false;
}
if (_context.Parameters.ContainsKey("install-key"))
var result = response.Content.ReadFromJsonAsync<InstallationValidationResponseModel>().GetAwaiter().GetResult();
if (!result.Enabled)
{
installationKey = _context.Parameters["install-key"];
}
else
{
installationKey = Helpers.ReadInput("Enter your installation key");
}
_context.Install.InstallationId = installationidGuid;
_context.Install.InstallationKey = installationKey;
try
{
var response = new HttpClient().GetAsync("https://api.bitwarden.com/installations/" +
_context.Install.InstallationId).GetAwaiter().GetResult();
if (!response.IsSuccessStatusCode)
{
if (response.StatusCode == System.Net.HttpStatusCode.NotFound)
{
Console.WriteLine("Invalid installation id.");
}
else
{
Console.WriteLine("Unable to validate installation id.");
}
return false;
}
var result = response.Content.ReadFromJsonAsync<InstallationValidationResponseModel>().GetAwaiter().GetResult();
if (!result.Enabled)
{
Console.WriteLine("Installation id has been disabled.");
return false;
}
return true;
}
catch
{
Console.WriteLine("Unable to validate installation id. Problem contacting Bitwarden server.");
Console.WriteLine("Installation id has been disabled.");
return false;
}
return true;
}
private static void RebuildConfigs()
catch
{
_context.LoadConfiguration();
var environmentFileBuilder = new EnvironmentFileBuilder(_context);
environmentFileBuilder.BuildForUpdater();
var certBuilder = new CertBuilder(_context);
certBuilder.BuildForUpdater();
var nginxBuilder = new NginxConfigBuilder(_context);
nginxBuilder.BuildForUpdater();
var appIdBuilder = new AppIdBuilder(_context);
appIdBuilder.Build();
var dockerComposeBuilder = new DockerComposeBuilder(_context);
dockerComposeBuilder.BuildForUpdater();
_context.SaveConfiguration();
Console.WriteLine(string.Empty);
}
private static void ParseParameters()
{
_context.Parameters = new Dictionary<string, string>();
for (var i = 0; i < _context.Args.Length; i = i + 2)
{
if (!_context.Args[i].StartsWith("-"))
{
continue;
}
_context.Parameters.Add(_context.Args[i].Substring(1), _context.Args[i + 1]);
}
}
class InstallationValidationResponseModel
{
public bool Enabled { get; init; }
Console.WriteLine("Unable to validate installation id. Problem contacting Bitwarden server.");
return false;
}
}
private static void RebuildConfigs()
{
_context.LoadConfiguration();
var environmentFileBuilder = new EnvironmentFileBuilder(_context);
environmentFileBuilder.BuildForUpdater();
var certBuilder = new CertBuilder(_context);
certBuilder.BuildForUpdater();
var nginxBuilder = new NginxConfigBuilder(_context);
nginxBuilder.BuildForUpdater();
var appIdBuilder = new AppIdBuilder(_context);
appIdBuilder.Build();
var dockerComposeBuilder = new DockerComposeBuilder(_context);
dockerComposeBuilder.BuildForUpdater();
_context.SaveConfiguration();
Console.WriteLine(string.Empty);
}
private static void ParseParameters()
{
_context.Parameters = new Dictionary<string, string>();
for (var i = 0; i < _context.Args.Length; i = i + 2)
{
if (!_context.Args[i].StartsWith("-"))
{
continue;
}
_context.Parameters.Add(_context.Args[i].Substring(1), _context.Args[i + 1]);
}
}
class InstallationValidationResponseModel
{
public bool Enabled { get; init; }
}
}

View File

@ -7,102 +7,101 @@ using YamlDotNet.Serialization.TypeInspectors;
// ref: https://github.com/aaubry/YamlDotNet/issues/152#issuecomment-349034754
namespace Bit.Setup
namespace Bit.Setup;
public class CommentGatheringTypeInspector : TypeInspectorSkeleton
{
public class CommentGatheringTypeInspector : TypeInspectorSkeleton
private readonly ITypeInspector _innerTypeDescriptor;
public CommentGatheringTypeInspector(ITypeInspector innerTypeDescriptor)
{
private readonly ITypeInspector _innerTypeDescriptor;
public CommentGatheringTypeInspector(ITypeInspector innerTypeDescriptor)
{
_innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException(nameof(innerTypeDescriptor));
}
public override IEnumerable<IPropertyDescriptor> GetProperties(Type type, object container)
{
return _innerTypeDescriptor.GetProperties(type, container).Select(d => new CommentsPropertyDescriptor(d));
}
private sealed class CommentsPropertyDescriptor : IPropertyDescriptor
{
private readonly IPropertyDescriptor _baseDescriptor;
public CommentsPropertyDescriptor(IPropertyDescriptor baseDescriptor)
{
_baseDescriptor = baseDescriptor;
Name = baseDescriptor.Name;
}
public string Name { get; set; }
public int Order { get; set; }
public Type Type => _baseDescriptor.Type;
public bool CanWrite => _baseDescriptor.CanWrite;
public Type TypeOverride
{
get { return _baseDescriptor.TypeOverride; }
set { _baseDescriptor.TypeOverride = value; }
}
public ScalarStyle ScalarStyle
{
get { return _baseDescriptor.ScalarStyle; }
set { _baseDescriptor.ScalarStyle = value; }
}
public void Write(object target, object value)
{
_baseDescriptor.Write(target, value);
}
public T GetCustomAttribute<T>() where T : Attribute
{
return _baseDescriptor.GetCustomAttribute<T>();
}
public IObjectDescriptor Read(object target)
{
var description = _baseDescriptor.GetCustomAttribute<DescriptionAttribute>();
return description != null ?
new CommentsObjectDescriptor(_baseDescriptor.Read(target), description.Description) :
_baseDescriptor.Read(target);
}
}
_innerTypeDescriptor = innerTypeDescriptor ?? throw new ArgumentNullException(nameof(innerTypeDescriptor));
}
public sealed class CommentsObjectDescriptor : IObjectDescriptor
public override IEnumerable<IPropertyDescriptor> GetProperties(Type type, object container)
{
private readonly IObjectDescriptor _innerDescriptor;
public CommentsObjectDescriptor(IObjectDescriptor innerDescriptor, string comment)
{
_innerDescriptor = innerDescriptor;
Comment = comment;
}
public string Comment { get; private set; }
public object Value => _innerDescriptor.Value;
public Type Type => _innerDescriptor.Type;
public Type StaticType => _innerDescriptor.StaticType;
public ScalarStyle ScalarStyle => _innerDescriptor.ScalarStyle;
return _innerTypeDescriptor.GetProperties(type, container).Select(d => new CommentsPropertyDescriptor(d));
}
public class CommentsObjectGraphVisitor : ChainedObjectGraphVisitor
private sealed class CommentsPropertyDescriptor : IPropertyDescriptor
{
public CommentsObjectGraphVisitor(IObjectGraphVisitor<IEmitter> nextVisitor)
: base(nextVisitor) { }
private readonly IPropertyDescriptor _baseDescriptor;
public override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context)
public CommentsPropertyDescriptor(IPropertyDescriptor baseDescriptor)
{
if (value is CommentsObjectDescriptor commentsDescriptor && commentsDescriptor.Comment != null)
{
context.Emit(new Comment(string.Empty, false));
foreach (var comment in commentsDescriptor.Comment.Split(Environment.NewLine))
{
context.Emit(new Comment(comment, false));
}
}
return base.EnterMapping(key, value, context);
_baseDescriptor = baseDescriptor;
Name = baseDescriptor.Name;
}
public string Name { get; set; }
public int Order { get; set; }
public Type Type => _baseDescriptor.Type;
public bool CanWrite => _baseDescriptor.CanWrite;
public Type TypeOverride
{
get { return _baseDescriptor.TypeOverride; }
set { _baseDescriptor.TypeOverride = value; }
}
public ScalarStyle ScalarStyle
{
get { return _baseDescriptor.ScalarStyle; }
set { _baseDescriptor.ScalarStyle = value; }
}
public void Write(object target, object value)
{
_baseDescriptor.Write(target, value);
}
public T GetCustomAttribute<T>() where T : Attribute
{
return _baseDescriptor.GetCustomAttribute<T>();
}
public IObjectDescriptor Read(object target)
{
var description = _baseDescriptor.GetCustomAttribute<DescriptionAttribute>();
return description != null ?
new CommentsObjectDescriptor(_baseDescriptor.Read(target), description.Description) :
_baseDescriptor.Read(target);
}
}
}
public sealed class CommentsObjectDescriptor : IObjectDescriptor
{
private readonly IObjectDescriptor _innerDescriptor;
public CommentsObjectDescriptor(IObjectDescriptor innerDescriptor, string comment)
{
_innerDescriptor = innerDescriptor;
Comment = comment;
}
public string Comment { get; private set; }
public object Value => _innerDescriptor.Value;
public Type Type => _innerDescriptor.Type;
public Type StaticType => _innerDescriptor.StaticType;
public ScalarStyle ScalarStyle => _innerDescriptor.ScalarStyle;
}
public class CommentsObjectGraphVisitor : ChainedObjectGraphVisitor
{
public CommentsObjectGraphVisitor(IObjectGraphVisitor<IEmitter> nextVisitor)
: base(nextVisitor) { }
public override bool EnterMapping(IPropertyDescriptor key, IObjectDescriptor value, IEmitter context)
{
if (value is CommentsObjectDescriptor commentsDescriptor && commentsDescriptor.Comment != null)
{
context.Emit(new Comment(string.Empty, false));
foreach (var comment in commentsDescriptor.Comment.Split(Environment.NewLine))
{
context.Emit(new Comment(comment, false));
}
}
return base.EnterMapping(key, value, context);
}
}