Skip to content

Commit

Permalink
uvf metadata (WiP).
Browse files Browse the repository at this point in the history
  • Loading branch information
chenkins committed Apr 4, 2024
1 parent 2d080ea commit f62a43a
Show file tree
Hide file tree
Showing 14 changed files with 272 additions and 54 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -421,6 +421,8 @@ public Response createOrUpdate(@PathParam("vaultId") UUID vaultId, @Valid @NotNu
vault.description = vaultDto.description;
vault.archived = existingVault.isEmpty() ? false : vaultDto.archived;

vault.metadata = vaultDto.metadata;

vault.persistAndFlush(); // trigger PersistenceException before we continue with
if (existingVault.isEmpty()) {
var access = new VaultAccess();
Expand Down Expand Up @@ -504,10 +506,11 @@ public record VaultDto(@JsonProperty("id") UUID id,
@JsonProperty("masterkey") @OnlyBase64Chars String masterkey, @JsonProperty("iterations") Integer iterations,
@JsonProperty("salt") @OnlyBase64Chars String salt,
@JsonProperty("authPublicKey") @OnlyBase64Chars String authPublicKey, @JsonProperty("authPrivateKey") @OnlyBase64Chars String authPrivateKey
,@JsonProperty("metadata") @NotNull String metadata
) {

public static VaultDto fromEntity(Vault entity) {
return new VaultDto(entity.id, entity.name, entity.description, entity.archived, entity.creationTime.truncatedTo(ChronoUnit.MILLIS), entity.masterkey, entity.iterations, entity.salt, entity.authenticationPublicKey, entity.authenticationPrivateKey);
return new VaultDto(entity.id, entity.name, entity.description, entity.archived, entity.creationTime.truncatedTo(ChronoUnit.MILLIS), entity.masterkey, entity.iterations, entity.salt, entity.authenticationPublicKey, entity.authenticationPrivateKey, entity.metadata);
}

}
Expand Down
3 changes: 3 additions & 0 deletions backend/src/main/java/org/cryptomator/hub/entities/Vault.java
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ public class Vault extends PanacheEntityBase {
@Column(name = "archived", nullable = false)
public boolean archived;

@Column(name = "metadata", nullable = false)
public String metadata;

public Optional<ECPublicKey> getAuthenticationPublicKey() {
if (authenticationPublicKey == null) {
return Optional.empty();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE vault ADD metadata VARCHAR UNIQUE; -- encrypted using uvf vault masterkey A256KW
Original file line number Diff line number Diff line change
Expand Up @@ -48,9 +48,8 @@
import static org.hamcrest.CoreMatchers.hasItems;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.not;
import static org.hamcrest.Matchers.comparesEqualTo;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.*;
import static org.hamcrest.text.IsEqualIgnoringCase.equalToIgnoringCase;

@QuarkusTest
Expand Down Expand Up @@ -82,10 +81,13 @@ public class TestVaultDtoValidation {
private static final String VALID_SALT = "base64";
private static final String VALID_AUTH_PUB = "base64";
private static final String VALID_AUTH_PRI = "base64";
private static final String VALID_METADATA = "base64";

@Test
public void testValidDto() {
var dto = new VaultResource.VaultDto(VALID_ID, VALID_NAME, "foobarbaz", false, Instant.parse("2020-02-20T20:20:20Z"), VALID_MASTERKEY, 8, VALID_SALT, VALID_AUTH_PUB, VALID_AUTH_PRI);
var dto = new VaultResource.VaultDto(VALID_ID, VALID_NAME, "foobarbaz", false, Instant.parse("2020-02-20T20:20:20Z"), VALID_MASTERKEY, 8, VALID_SALT, VALID_AUTH_PUB
, VALID_AUTH_PRI, VALID_METADATA
);
var violations = validator.validate(dto);
MatcherAssert.assertThat(violations, Matchers.empty());
}
Expand Down Expand Up @@ -193,7 +195,8 @@ public void testUnlock2() {
}

@Test
@DisplayName("GET /vaults/7E57C0DE-0000-4000-8000-000100001111/keys/noSuchDevice returns 403") // legacy unlock must not encourage to register a legacy device by responding with 404 here
@DisplayName("GET /vaults/7E57C0DE-0000-4000-8000-000100001111/keys/noSuchDevice returns 403")
// legacy unlock must not encourage to register a legacy device by responding with 404 here
public void testUnlock3() {
when().get("/vaults/{vaultId}/keys/{deviceId}", "7E57C0DE-0000-4000-8000-000100001111", "noSuchDevice")
.then().statusCode(403);
Expand Down Expand Up @@ -247,7 +250,7 @@ public class CreateVaults {
@DisplayName("PUT /vaults/7E57C0DE-0000-4000-8000-000100003333 returns 201")
public void testCreateVault1() {
var uuid = UUID.fromString("7E57C0DE-0000-4000-8000-000100003333");
var vaultDto = new VaultResource.VaultDto(uuid, "My Vault", "Test vault 3", false, Instant.parse("2112-12-21T21:12:21Z"), "masterkey3", 42, "NaCl", "authPubKey3", "authPrvKey3");
var vaultDto = new VaultResource.VaultDto(uuid, "My Vault", "Test vault 3", false, Instant.parse("2112-12-21T21:12:21Z"), "masterkey3", 42, "NaCl", "authPubKey3", "authPrvKey3", "metadata1");

given().contentType(ContentType.JSON).body(vaultDto)
.when().put("/vaults/{vaultId}", "7E57C0DE-0000-4000-8000-000100003333")
Expand All @@ -272,7 +275,7 @@ public void testCreateVault2() {
@DisplayName("PUT /vaults/7E57C0DE-0000-4000-8000-000100004444 returns 201 ignoring archived flag")
public void testCreateVault3() {
var uuid = UUID.fromString("7E57C0DE-0000-4000-8000-000100004444");
var vaultDto = new VaultResource.VaultDto(uuid, "My Vault", "Test vault 4", true, Instant.parse("2112-12-21T21:12:21Z"), "masterkey4", 42, "NaCl", "authPubKey4", "authPrvKey4");
var vaultDto = new VaultResource.VaultDto(uuid, "My Vault", "Test vault 4", true, Instant.parse("2112-12-21T21:12:21Z"), "masterkey4", 42, "NaCl", "authPubKey4", "authPrvKey4", "metadata3");

given().contentType(ContentType.JSON).body(vaultDto)
.when().put("/vaults/{vaultId}", "7E57C0DE-0000-4000-8000-000100004444")
Expand All @@ -288,7 +291,7 @@ public void testCreateVault3() {
@DisplayName("PUT /vaults/7E57C0DE-0000-4000-8000-000100003333 returns 200, updating only name, description and archive flag")
public void testUpdateVault() {
var uuid = UUID.fromString("7E57C0DE-0000-4000-8000-000100003333");
var vaultDto = new VaultResource.VaultDto(uuid, "VaultUpdated", "Vault updated.", true, Instant.parse("2222-11-11T11:11:11Z"), "doNotUpdate", 27, "doNotUpdate", "doNotUpdate", "doNotUpdate");
var vaultDto = new VaultResource.VaultDto(uuid, "VaultUpdated", "Vault updated.", true, Instant.parse("2222-11-11T11:11:11Z"), "doNotUpdate", 27, "doNotUpdate", "doNotUpdate", "doNotUpdate", "metadata4");
given().contentType(ContentType.JSON)
.body(vaultDto)
.when().put("/vaults/{vaultId}", "7E57C0DE-0000-4000-8000-000100003333")
Expand Down Expand Up @@ -750,7 +753,7 @@ public void testCreateVaultExceedingSeats() {
assert EffectiveVaultAccess.countSeatOccupyingUsers() == 5;

var uuid = UUID.fromString("7E57C0DE-0000-4000-8000-0001FFFF3333");
var vaultDto = new VaultResource.VaultDto(uuid, "My Vault", "Test vault 4", false, Instant.parse("2112-12-21T21:12:21Z"), "masterkey3", 42, "NaCl", "authPubKey3", "authPrvKey3");
var vaultDto = new VaultResource.VaultDto(uuid, "My Vault", "Test vault 4", false, Instant.parse("2112-12-21T21:12:21Z"), "masterkey3", 42, "NaCl", "authPubKey3", "authPrvKey3", "metadata5");
given().contentType(ContentType.JSON).body(vaultDto)
.when().put("/vaults/{vaultId}", "7E57C0DE-0000-4000-8000-0001FFFF3333")
.then().statusCode(402);
Expand All @@ -763,7 +766,7 @@ public void testCreateVaultNotExceedingSeats() {
assert EffectiveVaultAccess.countSeatOccupyingUsers() == 5;

var uuid = UUID.fromString("7E57C0DE-0000-4000-8000-0001FFFF3333");
var vaultDto = new VaultResource.VaultDto(uuid, "My Vault", "Test vault 3", false, Instant.parse("2112-12-21T21:12:21Z"), "masterkey3", 42, "NaCl", "authPubKey3", "authPrvKey3");
var vaultDto = new VaultResource.VaultDto(uuid, "My Vault", "Test vault 3", false, Instant.parse("2112-12-21T21:12:21Z"), "masterkey3", 42, "NaCl", "authPubKey3", "authPrvKey3", "metadata6");
given().contentType(ContentType.JSON).body(vaultDto)
.when().put("/vaults/{vaultId}", "7E57C0DE-0000-4000-8000-0001FFFF3333")
.then().statusCode(201)
Expand All @@ -780,7 +783,7 @@ public void testUpdateVaultDespiteLicenseExceeded() {
assert EffectiveVaultAccess.countSeatOccupyingUsers() == 5;

var uuid = UUID.fromString("7E57C0DE-0000-4000-8000-0001FFFF3333");
var vaultDto = new VaultResource.VaultDto(uuid, "VaultUpdated", "Vault updated.", true, Instant.parse("2222-11-11T11:11:11Z"), "someVaule", -1, "doNotUpdate", "doNotUpdate", "doNotUpdate");
var vaultDto = new VaultResource.VaultDto(uuid, "VaultUpdated", "Vault updated.", true, Instant.parse("2222-11-11T11:11:11Z"), "someVaule", -1, "doNotUpdate", "doNotUpdate", "doNotUpdate", "metadata7");
given().contentType(ContentType.JSON)
.body(vaultDto)
.when().put("/vaults/{vaultId}", "7E57C0DE-0000-4000-8000-0001FFFF3333")
Expand Down Expand Up @@ -871,6 +874,7 @@ public static void setup() throws GeneralSecurityException {
v.name = "ownership-test-vault";
v.creationTime = Instant.now();
v.authenticationPublicKey = Base64.getEncoder().encodeToString(keyPair.getPublic().getEncoded());
v.metadata = UUID.randomUUID().toString();
v.persist();
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,20 +29,23 @@ VALUES
('group1', 'user1'),
('group2', 'user2');

INSERT INTO "vault" ("id", "name", "description", "creation_time", "salt", "iterations", "masterkey", "auth_pubkey", "auth_prvkey", "archived")
INSERT INTO "vault" ("id", "name", "description", "creation_time", "salt", "iterations", "masterkey", "auth_pubkey", "auth_prvkey", "archived" , "metadata" )
VALUES
('7E57C0DE-0000-4000-8000-000100001111', 'Vault 1', 'This is a testvault.', '2020-02-20 20:20:20', 'salt1', 42, 'masterkey1',
'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAElS+JW3VaBvVr9GKZGn1399WDTd61Q9fwQMmZuBGAYPdl/rWk705QY6WhlmbokmEVva/mEHSoNQ98wFm9FBCqzh45IGd/DGwZ04Xhi5ah+1bKbkVhtds8nZtHRdSJokYp',
'MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDAa57e0Q/KAqmIVOVcWX7b+Sm5YVNRUx8W7nc4wk1IBj2QJmsj+MeShQRHG4ozTE9KhZANiAASVL4lbdVoG9Wv0YpkafXf31YNN3rVD1/BAyZm4EYBg92X+taTvTlBjpaGWZuiSYRW9r+YQdKg1D3zAWb0UEKrOHjkgZ38MbBnTheGLlqH7VspuRWG12zydm0dF1ImiRik=',
FALSE),
FALSE, 'm1'
),
('7E57C0DE-0000-4000-8000-000100002222', 'Vault 2', 'This is a testvault.', '2020-02-20 20:20:20', 'salt2', 42, 'masterkey2',
'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEC1uWSXj2czCDwMTLWV5BFmwxdM6PX9p+Pk9Yf9rIf374m5XP1U8q79dBhLSIuaojsvOT39UUcPJROSD1FqYLued0rXiooIii1D3jaW6pmGVJFhodzC31cy5sfOYotrzF',
'MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCAHpFQ62QnGCEvYh/pE9QmR1C9aLcDItRbslbmhen/h1tt8AyMhskeenT+rAyyPhGhZANiAAQLW5ZJePZzMIPAxMtZXkEWbDF0zo9f2n4+T1h/2sh/fviblc/VTyrv10GEtIi5qiOy85Pf1RRw8lE5IPUWpgu553SteKigiKLUPeNpbqmYZUkWGh3MLfVzLmx85ii2vMU=',
FALSE),
FALSE, 'm2'
),
('7E57C0DE-0000-4000-8000-00010000AAAA', 'Vault Archived', 'This is a archived vault.', '2020-02-20 20:20:20', 'salt3', 42, 'masterkey3',
'MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAEC1uWSXj2czCDwMTLWV5BFmwxdM6PX9p+Pk9Yf9rIf374m5XP1U8q79dBhLSIuaojsvOT39UUcPJROSD1FqYLued0rXiooIii1D3jaW6pmGVJFhodzC31cy5sfOYotrzF',
'MIG2AgEAMBAGByqGSM49AgEGBSuBBAAiBIGeMIGbAgEBBDCAHpFQ62QnGCEvYh/pE9QmR1C9aLcDItRbslbmhen/h1tt8AyMhskeenT+rAyyPhGhZANiAAQLW5ZJePZzMIPAxMtZXkEWbDF0zo9f2n4+T1h/2sh/fviblc/VTyrv10GEtIi5qiOy85Pf1RRw8lE5IPUWpgu553SteKigiKLUPeNpbqmYZUkWGh3MLfVzLmx85ii2vMU=',
TRUE);
TRUE, 'm3'
);

INSERT INTO "vault_access" ("vault_id", "authority_id", "role")
VALUES
Expand Down
36 changes: 34 additions & 2 deletions frontend/src/common/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ export type VaultDto = {
salt?: string;
authPublicKey?: string;
authPrivateKey?: string;
metadata: string;
};

export type DeviceDto = {
Expand Down Expand Up @@ -195,6 +196,18 @@ export type VersionDto = {
keycloakVersion: string;
}

export type ConfigDto = {
keycloakUrl: string;
keycloakRealm: string;
keycloakClientIdHub: string;
keycloakClientIdCryptomator: string;
keycloakAuthEndpoint: string;
keycloakTokenEndpoint: string;
serverTime: string;
apiLevel: number;
uuid: string;
}

/* Services */

export interface VaultIdHeader extends JWTHeader {
Expand Down Expand Up @@ -250,8 +263,12 @@ class VaultService {
.catch(err => rethrowAndConvertIfExpected(err, 403));
}

public async createOrUpdateVault(vaultId: string, name: string, archived: boolean, description?: string): Promise<VaultDto> {
const body: VaultDto = { id: vaultId, name: name, description: description, archived: archived, creationTime: new Date() };
public async createOrUpdateVault(vaultId: string, name: string, archived: boolean
, metadata: string
, description?: string): Promise<VaultDto> {
const body: VaultDto = { id: vaultId, name: name, description: description, archived: archived, creationTime: new Date()
, metadata: metadata
};
return axiosAuth.put(`/vaults/${vaultId}`, body)
.then(response => response.data)
.catch((error) => rethrowAndConvertIfExpected(error, 402, 404));
Expand Down Expand Up @@ -439,3 +456,18 @@ export class ConflictError extends BackendError {
super('Resource already exists');
}
}

export type VaultMetadataJWEAutomaticAccessGrantDto = {
enabled: boolean,
maxWotDepth: number
}

export type VaultMetadataJWEDto = {
fileFormat: string;
nameFormat: string;
keys: Record<string,string>;
latestFileKey: string;
nameKey: string;
kdf: string;
automaticAccessGrant: VaultMetadataJWEAutomaticAccessGrantDto;
}
Loading

0 comments on commit f62a43a

Please sign in to comment.