1
0
mirror of https://github.com/bitwarden/server.git synced 2024-12-25 17:27:45 +01:00

[PM-1380] Modify Device Table (#2937)

* Update Models

- Add Controller Method

* Add MSSQL Migration

* Update SQL Proj

* Update SQL Migration

* Update Models

* Update SQL Project

* Add EF Migrations

* Switch to using Identifier

* Update Code Comment
This commit is contained in:
Justin Baur 2023-06-09 21:36:12 -04:00 committed by GitHub
parent 5f4a303180
commit 5874ff42c3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 6978 additions and 7 deletions

View File

@ -91,6 +91,22 @@ public class DevicesController : Controller
return response;
}
[HttpPut("{identifier}/keys")]
[HttpPost("{identifier}/keys")]
public async Task<DeviceResponseModel> PutKeys(string identifier, [FromBody] DeviceKeysRequestModel model)
{
var device = await _deviceRepository.GetByIdentifierAsync(identifier, _userService.GetProperUserId(User).Value);
if (device == null)
{
throw new NotFoundException();
}
await _deviceService.SaveAsync(model.ToDevice(device));
var response = new DeviceResponseModel(device);
return response;
}
[HttpPut("identifier/{identifier}/token")]
[HttpPost("identifier/{identifier}/token")]
public async Task PutToken(string identifier, [FromBody] DeviceTokenRequestModel model)

View File

@ -1,6 +1,7 @@
using System.ComponentModel.DataAnnotations;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Utilities;
namespace Bit.Api.Models.Request;
@ -47,3 +48,30 @@ public class DeviceTokenRequestModel
return existingDevice;
}
}
public class DeviceKeysRequestModel
{
/// <inheritdoc cref="Device.EncryptedUserKey" />
[Required]
[EncryptedString]
public string EncryptedUserKey { get; set; }
/// <inheritdoc cref="Device.EncryptedPublicKey" />
[Required]
[EncryptedString]
public string EncryptedPublicKey { get; set; }
/// <inheritdoc cref="Device.EncryptedPrivateKey" />
[Required]
[EncryptedString]
public string EncryptedPrivateKey { get; set; }
public Device ToDevice(Device existingDevice)
{
existingDevice.EncryptedUserKey = EncryptedUserKey;
existingDevice.EncryptedPublicKey = EncryptedPublicKey;
existingDevice.EncryptedPrivateKey = EncryptedPrivateKey;
return existingDevice;
}
}

View File

@ -19,6 +19,9 @@ public class DeviceResponseModel : ResponseModel
Type = device.Type;
Identifier = device.Identifier;
CreationDate = device.CreationDate;
EncryptedUserKey = device.EncryptedUserKey;
EncryptedPublicKey = device.EncryptedPublicKey;
EncryptedPrivateKey = device.EncryptedPrivateKey;
}
public string Id { get; set; }
@ -26,4 +29,7 @@ public class DeviceResponseModel : ResponseModel
public DeviceType Type { get; set; }
public string Identifier { get; set; }
public DateTime CreationDate { get; set; }
public string EncryptedUserKey { get; }
public string EncryptedPublicKey { get; }
public string EncryptedPrivateKey { get; }
}

View File

@ -17,6 +17,26 @@ public class Device : ITableObject<Guid>
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
/// <summary>
/// Intended to be the users symmetric key that is encrypted in some form, the current way to encrypt this is with
/// the devices public key.
/// </summary>
public string EncryptedUserKey { get; set; }
/// <summary>
/// Intended to be the public key that was generated for a device upon trust and encrypted. Currenly encrypted using
/// a users symmetric key so that when trusted and unlocked a user can decrypt the public key for all their devices.
/// This enabled a user to rotate the keys for all of their devices.
/// </summary>
public string EncryptedPublicKey { get; set; }
/// <summary>
/// Intended to be the private key that was generated for a device upon trust and encrypted. Currenly encrypted with
/// the devices key, that upon successful login a user can decrypt this value and therefor decrypt their vault.
/// </summary>
public string EncryptedPrivateKey { get; set; }
public void SetNewId()
{
Id = CoreHelpers.GenerateComb();

View File

@ -6,7 +6,10 @@
@Identifier NVARCHAR(50),
@PushToken NVARCHAR(255),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7)
@RevisionDate DATETIME2(7),
@EncryptedUserKey VARCHAR(MAX) = NULL,
@EncryptedPublicKey VARCHAR(MAX) = NULL,
@EncryptedPrivateKey VARCHAR(MAX) = NULL
AS
BEGIN
SET NOCOUNT ON
@ -20,7 +23,10 @@ BEGIN
[Identifier],
[PushToken],
[CreationDate],
[RevisionDate]
[RevisionDate],
[EncryptedUserKey],
[EncryptedPublicKey],
[EncryptedPrivateKey]
)
VALUES
(
@ -31,6 +37,9 @@ BEGIN
@Identifier,
@PushToken,
@CreationDate,
@RevisionDate
@RevisionDate,
@EncryptedUserKey,
@EncryptedPublicKey,
@EncryptedPrivateKey
)
END

View File

@ -6,7 +6,10 @@
@Identifier NVARCHAR(50),
@PushToken NVARCHAR(255),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7)
@RevisionDate DATETIME2(7),
@EncryptedUserKey VARCHAR(MAX) = NULL,
@EncryptedPublicKey VARCHAR(MAX) = NULL,
@EncryptedPrivateKey VARCHAR(MAX) = NULL
AS
BEGIN
SET NOCOUNT ON
@ -20,7 +23,10 @@ BEGIN
[Identifier] = @Identifier,
[PushToken] = @PushToken,
[CreationDate] = @CreationDate,
[RevisionDate] = @RevisionDate
[RevisionDate] = @RevisionDate,
[EncryptedUserKey] = @EncryptedUserKey,
[EncryptedPublicKey] = @EncryptedPublicKey,
[EncryptedPrivateKey] = @EncryptedPrivateKey
WHERE
[Id] = @Id
END
END

View File

@ -7,6 +7,9 @@
[PushToken] NVARCHAR (255) NULL,
[CreationDate] DATETIME2 (7) NOT NULL,
[RevisionDate] DATETIME2 (7) NOT NULL,
[EncryptedUserKey] VARCHAR (MAX) NULL,
[EncryptedPublicKey] VARCHAR (MAX) NULL,
[EncryptedPrivateKey] VARCHAR (MAX) NULL,
CONSTRAINT [PK_Device] PRIMARY KEY CLUSTERED ([Id] ASC),
CONSTRAINT [FK_Device_User] FOREIGN KEY ([UserId]) REFERENCES [dbo].[User] ([Id])
);
@ -20,4 +23,3 @@ CREATE UNIQUE NONCLUSTERED INDEX [UX_Device_UserId_Identifier]
GO
CREATE NONCLUSTERED INDEX [IX_Device_Identifier]
ON [dbo].[Device]([Identifier] ASC);

View File

@ -0,0 +1,116 @@
-- Add EncryptedUserKey column to Device table
IF COL_LENGTH('[dbo].[Device]', 'EncryptedUserKey') IS NULL
BEGIN
ALTER TABLE
[dbo].[Device]
ADD
[EncryptedUserKey] VARCHAR(MAX) NULL;
END
GO
-- Add EncryptedPublicKey column to Device table
IF COL_LENGTH('[dbo].[Device]', 'EncryptedPublicKey') IS NULL
BEGIN
ALTER TABLE
[dbo].[Device]
ADD
[EncryptedPublicKey] VARCHAR(MAX) NULL;
END
GO
-- Add EncryptedPrivateKey column to Device table
IF COL_LENGTH('[dbo].[Device]', 'EncryptedPrivateKey') IS NULL
BEGIN
ALTER TABLE
[dbo].[Device]
ADD
[EncryptedPrivateKey] VARCHAR(MAX) NULL;
END
GO
CREATE OR ALTER PROCEDURE [dbo].[Device_Create]
@Id UNIQUEIDENTIFIER OUTPUT,
@UserId UNIQUEIDENTIFIER,
@Name NVARCHAR(50),
@Type TINYINT,
@Identifier NVARCHAR(50),
@PushToken NVARCHAR(255),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@EncryptedUserKey VARCHAR(MAX) = NULL,
@EncryptedPublicKey VARCHAR(MAX) = NULL,
@EncryptedPrivateKey VARCHAR(MAX) = NULL
AS
BEGIN
SET NOCOUNT ON
INSERT INTO [dbo].[Device]
(
[Id],
[UserId],
[Name],
[Type],
[Identifier],
[PushToken],
[CreationDate],
[RevisionDate],
[EncryptedUserKey],
[EncryptedPublicKey],
[EncryptedPrivateKey]
)
VALUES
(
@Id,
@UserId,
@Name,
@Type,
@Identifier,
@PushToken,
@CreationDate,
@RevisionDate,
@EncryptedUserKey,
@EncryptedPublicKey,
@EncryptedPrivateKey
)
END
GO
CREATE OR ALTER PROCEDURE [dbo].[Device_Update]
@Id UNIQUEIDENTIFIER,
@UserId UNIQUEIDENTIFIER,
@Name NVARCHAR(50),
@Type TINYINT,
@Identifier NVARCHAR(50),
@PushToken NVARCHAR(255),
@CreationDate DATETIME2(7),
@RevisionDate DATETIME2(7),
@EncryptedUserKey VARCHAR(MAX) = NULL,
@EncryptedPublicKey VARCHAR(MAX) = NULL,
@EncryptedPrivateKey VARCHAR(MAX) = NULL
AS
BEGIN
SET NOCOUNT ON
UPDATE
[dbo].[Device]
SET
[UserId] = @UserId,
[Name] = @Name,
[Type] = @Type,
[Identifier] = @Identifier,
[PushToken] = @PushToken,
[CreationDate] = @CreationDate,
[RevisionDate] = @RevisionDate,
[EncryptedUserKey] = @EncryptedUserKey,
[EncryptedPublicKey] = @EncryptedPublicKey,
[EncryptedPrivateKey] = @EncryptedPrivateKey
WHERE
[Id] = @Id
END
GO
IF OBJECT_ID('[dbo].[DeviceView]') IS NOT NULL
BEGIN
EXECUTE sp_refreshsqlmodule N'[dbo].[DeviceView]';
END
GO

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,47 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.MySqlMigrations.Migrations;
public partial class AddKeysToDevice : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "EncryptedPrivateKey",
table: "Device",
type: "longtext",
nullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AddColumn<string>(
name: "EncryptedPublicKey",
table: "Device",
type: "longtext",
nullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
migrationBuilder.AddColumn<string>(
name: "EncryptedUserKey",
table: "Device",
type: "longtext",
nullable: true)
.Annotation("MySql:CharSet", "utf8mb4");
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "EncryptedPrivateKey",
table: "Device");
migrationBuilder.DropColumn(
name: "EncryptedPublicKey",
table: "Device");
migrationBuilder.DropColumn(
name: "EncryptedUserKey",
table: "Device");
}
}

View File

@ -319,6 +319,15 @@ namespace Bit.MySqlMigrations.Migrations
b.Property<DateTime>("CreationDate")
.HasColumnType("datetime(6)");
b.Property<string>("EncryptedPrivateKey")
.HasColumnType("longtext");
b.Property<string>("EncryptedPublicKey")
.HasColumnType("longtext");
b.Property<string>("EncryptedUserKey")
.HasColumnType("longtext");
b.Property<string>("Identifier")
.HasMaxLength(50)
.HasColumnType("varchar(50)");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.PostgresMigrations.Migrations;
public partial class AddKeysToDevice : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "EncryptedPrivateKey",
table: "Device",
type: "text",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "EncryptedPublicKey",
table: "Device",
type: "text",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "EncryptedUserKey",
table: "Device",
type: "text",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "EncryptedPrivateKey",
table: "Device");
migrationBuilder.DropColumn(
name: "EncryptedPublicKey",
table: "Device");
migrationBuilder.DropColumn(
name: "EncryptedUserKey",
table: "Device");
}
}

View File

@ -328,6 +328,15 @@ namespace Bit.PostgresMigrations.Migrations
b.Property<DateTime>("CreationDate")
.HasColumnType("timestamp with time zone");
b.Property<string>("EncryptedPrivateKey")
.HasColumnType("text");
b.Property<string>("EncryptedPublicKey")
.HasColumnType("text");
b.Property<string>("EncryptedUserKey")
.HasColumnType("text");
b.Property<string>("Identifier")
.HasMaxLength(50)
.HasColumnType("character varying(50)");

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,44 @@
using Microsoft.EntityFrameworkCore.Migrations;
#nullable disable
namespace Bit.SqliteMigrations.Migrations;
public partial class AddKeysToDevice : Migration
{
protected override void Up(MigrationBuilder migrationBuilder)
{
migrationBuilder.AddColumn<string>(
name: "EncryptedPrivateKey",
table: "Device",
type: "TEXT",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "EncryptedPublicKey",
table: "Device",
type: "TEXT",
nullable: true);
migrationBuilder.AddColumn<string>(
name: "EncryptedUserKey",
table: "Device",
type: "TEXT",
nullable: true);
}
protected override void Down(MigrationBuilder migrationBuilder)
{
migrationBuilder.DropColumn(
name: "EncryptedPrivateKey",
table: "Device");
migrationBuilder.DropColumn(
name: "EncryptedPublicKey",
table: "Device");
migrationBuilder.DropColumn(
name: "EncryptedUserKey",
table: "Device");
}
}

View File

@ -317,6 +317,15 @@ namespace Bit.SqliteMigrations.Migrations
b.Property<DateTime>("CreationDate")
.HasColumnType("TEXT");
b.Property<string>("EncryptedPrivateKey")
.HasColumnType("TEXT");
b.Property<string>("EncryptedPublicKey")
.HasColumnType("TEXT");
b.Property<string>("EncryptedUserKey")
.HasColumnType("TEXT");
b.Property<string>("Identifier")
.HasMaxLength(50)
.HasColumnType("TEXT");