Skip to content

Commit 03cd1af

Browse files
committed
Merge branch 'release/1.3.1'
2 parents 05c6b42 + 4afc33d commit 03cd1af

13 files changed

+78
-54
lines changed

backend/pom.xml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<modelVersion>4.0.0</modelVersion>
55
<groupId>org.cryptomator</groupId>
66
<artifactId>hub-backend</artifactId>
7-
<version>1.3.0</version>
7+
<version>1.3.1</version>
88

99
<properties>
1010
<compiler-plugin.version>3.11.0 </compiler-plugin.version>

backend/src/main/java/org/cryptomator/hub/api/ConfigResource.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ public ConfigDto getConfig() {
4949
var authUri = replacePrefix(oidcConfData.getAuthorizationUri(), trimTrailingSlash(internalRealmUrl), publicRealmUri);
5050
var tokenUri = replacePrefix(oidcConfData.getTokenUri(), trimTrailingSlash(internalRealmUrl), publicRealmUri);
5151

52-
return new ConfigDto(keycloakPublicUrl, keycloakRealm, keycloakClientIdHub, keycloakClientIdCryptomator, authUri, tokenUri, Instant.now().truncatedTo(ChronoUnit.MILLIS), 1);
52+
return new ConfigDto(keycloakPublicUrl, keycloakRealm, keycloakClientIdHub, keycloakClientIdCryptomator, authUri, tokenUri, Instant.now().truncatedTo(ChronoUnit.MILLIS), 2);
5353
}
5454

5555
//visible for testing

backend/src/main/java/org/cryptomator/hub/api/VaultResource.java

+4-2
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ public Response legacyUnlock(@PathParam("vaultId") UUID vaultId, @PathParam("dev
297297
@APIResponse(responseCode = "410", description = "Vault is archived. Only returned if evenIfArchived query param is false or not set, otherwise the archived flag is ignored")
298298
@APIResponse(responseCode = "449", description = "User account not yet initialized. Retry after setting up user")
299299
@ActiveLicense // may throw 402
300-
public String unlock(@PathParam("vaultId") UUID vaultId, @QueryParam("evenIfArchived") @DefaultValue("false") boolean ignoreArchived) {
300+
public Response unlock(@PathParam("vaultId") UUID vaultId, @QueryParam("evenIfArchived") @DefaultValue("false") boolean ignoreArchived) {
301301
var vault = Vault.<Vault>findById(vaultId); // should always be found, since @VaultRole filter would have triggered
302302
if (vault.archived && !ignoreArchived) {
303303
throw new GoneException("Vault is archived.");
@@ -316,7 +316,9 @@ public String unlock(@PathParam("vaultId") UUID vaultId, @QueryParam("evenIfArch
316316
var access = AccessToken.unlock(vaultId, jwt.getSubject());
317317
if (access != null) {
318318
AuditEventVaultKeyRetrieve.log(jwt.getSubject(), vaultId, AuditEventVaultKeyRetrieve.Result.SUCCESS);
319-
return access.vaultKey;
319+
var subscriptionStateHeaderName = "Hub-Subscription-State";
320+
var subscriptionStateHeaderValue = license.isSet() ? "ACTIVE" : "INACTIVE"; // license expiration is not checked here, because it is checked in the ActiveLicense filter
321+
return Response.ok(access.vaultKey).header(subscriptionStateHeaderName, subscriptionStateHeaderValue).build();
320322
} else if (Vault.findById(vaultId) == null) {
321323
throw new NotFoundException("No such vault.");
322324
} else {

frontend/.vscode/settings.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
{
22
"[typescript]": {
33
"editor.codeActionsOnSave": {
4-
"source.organizeImports": true,
5-
"source.fixAll.tslint": true
4+
"source.organizeImports": "explicit",
5+
"source.fixAll.tslint": "explicit"
66
},
77
"editor.foldingStrategy": "indentation",
88
"editor.formatOnSave": true,
@@ -27,4 +27,4 @@
2727
"mochaExplorer.files": "test/**/*.spec.ts",
2828
"mochaExplorer.require": "ts-node/register",
2929
"eslint.validate": ["typescript", "javascript", "vue"]
30-
}
30+
}

frontend/README.md

+18-4
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,25 @@
1-
# Vue 3 + Typescript + Vite
1+
# Cryptomator Frontend
22

3-
This template should help get you started developing with Vue 3 and Typescript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
3+
This project uses Vue 3 + Typescript + Vite.
44

55
## Recommended IDE Setup
66

77
- [VSCode](https://code.visualstudio.com/) + [Volar](https://marketplace.visualstudio.com/items?itemName=johnsoncodehk.volar)
88

9-
## Type Support For `.vue` Imports in TS
9+
## Dev Mode
1010

11-
Since TypeScript cannot handle type information for `.vue` imports, they are shimmed to be a generic Vue component type by default. In most cases this is fine if you don't really care about component prop types outside of templates. However, if you wish to get actual prop types in `.vue` imports (for example to get props validation when using manual `h(...)` calls), you can enable Volar's `.vue` type support plugin by running `Volar: Switch TS Plugin on/off` from VSCode command palette.
11+
You can run your application in dev mode that enables live coding using:
12+
13+
```shell script
14+
npm install
15+
npm run dev
16+
```
17+
18+
## Production Build
19+
20+
To build an optimized (production) version of the app, run:
21+
22+
```shell script
23+
npm install
24+
npm run dist
25+
```

frontend/package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

frontend/package.json

+20-20
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "cryptomator-hub",
3-
"version": "1.3.0",
3+
"version": "1.3.1",
44
"description": "Web-Frontend for Cryptomator Hub",
55
"author": "Skymatic GmbH",
66
"license": "AGPL-3.0-or-later",
@@ -12,26 +12,26 @@
1212
"lint": "eslint -c .eslintrc.js",
1313
"test": "nyc --reporter lcov mocha -r ts-node/register test/**/*.spec.ts",
1414
"serve": "vite preview",
15-
"dist": "vite build --sourcemap --outDir=\"../backend/src/main/resources/META-INF/resources\" --emptyOutDir"
15+
"dist": "vue-tsc --noEmit && vite build --sourcemap --outDir=\"../backend/src/main/resources/META-INF/resources\" --emptyOutDir"
1616
},
1717
"directories": {
1818
"src": "./src",
1919
"test": "./test"
2020
},
2121
"devDependencies": {
2222
"@intlify/unplugin-vue-i18n": "^1.4.0",
23-
"@tailwindcss/forms": "^0.5.6",
24-
"@types/blueimp-md5": "^2.18.1",
25-
"@types/chai": "^4.3.9",
26-
"@types/chai-as-promised": "^7.1.7",
27-
"@types/file-saver": "^2.0.6",
28-
"@types/mocha": "^10.0.3",
23+
"@tailwindcss/forms": "^0.5.7",
24+
"@types/blueimp-md5": "^2.18.2",
25+
"@types/chai": "^4.3.11",
26+
"@types/chai-as-promised": "^7.1.8",
27+
"@types/file-saver": "^2.0.7",
28+
"@types/mocha": "^10.0.6",
2929
"@types/node": "^20.8.10",
30-
"@types/semver": "^7.5.4",
30+
"@types/semver": "^7.5.6",
3131
"@typescript-eslint/eslint-plugin": "^6.9.1",
3232
"@typescript-eslint/parser": "^6.9.1",
33-
"@vitejs/plugin-vue": "^4.4.0",
34-
"@vue/compiler-sfc": "^3.3.4",
33+
"@vitejs/plugin-vue": "^4.4.1",
34+
"@vue/compiler-sfc": "^3.3.13",
3535
"autoprefixer": "^10.4.16",
3636
"chai": "^4.3.10",
3737
"chai-as-promised": "^7.1.1",
@@ -40,27 +40,27 @@
4040
"eslint-plugin-vue": "^9.18.1",
4141
"mocha": "^10.2.0",
4242
"nyc": "^15.1.0",
43-
"postcss": "^8.4.31",
44-
"tailwindcss": "^3.3.5",
45-
"ts-node": "^10.9.1",
43+
"postcss": "^8.4.33",
44+
"tailwindcss": "^3.3.7",
45+
"ts-node": "^10.9.2",
4646
"typescript": "^5.2.2",
47-
"vite": "^4.5.0",
48-
"vue-tsc": "^1.8.22"
47+
"vite": "^4.5.1",
48+
"vue-tsc": "^1.8.27"
4949
},
5050
"dependencies": {
5151
"@headlessui/tailwindcss": "^0.2.0",
52-
"@headlessui/vue": "^1.7.16",
52+
"@headlessui/vue": "^1.7.17",
5353
"@heroicons/vue": "^2.0.18",
54-
"axios": "^1.6.0",
54+
"axios": "^1.6.5",
5555
"file-saver": "^2.0.5",
5656
"jdenticon": "^3.2.0",
5757
"jszip": "^3.10.1",
5858
"keycloak-js": "^22.0.5",
5959
"miscreant": "^0.3.2",
6060
"rfc4648": "^1.5.3",
6161
"semver": "^7.5.4",
62-
"vue": "^3.3.4",
63-
"vue-i18n": "^9.6.2",
62+
"vue": "^3.3.13",
63+
"vue-i18n": "^9.6.5",
6464
"vue-router": "^4.2.5"
6565
}
6666
}

frontend/src/components/DeviceList.vue

+2-2
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ async function determineMyDevice() {
124124
throw new Error('User not initialized.');
125125
}
126126
const browserKeys = await BrowserKeys.load(me.value.id);
127-
const browserId = await browserKeys.id();
127+
const browserId = await browserKeys?.id();
128128
myDevice.value = me.value.devices.find(d => d.id == browserId);
129129
}
130130
@@ -138,7 +138,7 @@ async function determineMyDevice() {
138138
// /* decrypt user key on this browser: */
139139
// const userPublicKey = crypto.subtle.importKey('spki', base64.parse(me.value.publicKey), UserKeys.KEY_DESIGNATION, false, []);
140140
// const browserKeys = await BrowserKeys.load(me.value.id);
141-
// const browserId = await browserKeys.id();
141+
// const browserId = await browserKeys?.id();
142142
// const browser = me.value.devices.find(d => d.id === browserId);
143143
// if (!browser || !browser.userPrivateKey) {
144144
// throw new Error('Browser not validated.');

frontend/src/components/ManageSetupCode.vue

+3
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,9 @@ async function fetchData() {
7575
throw new Error('User not initialized.');
7676
}
7777
const browserKeys = await BrowserKeys.load(me.id);
78+
if (browserKeys == null) {
79+
throw new Error('Browser keys not found.');
80+
}
7881
const browserId = await browserKeys.id();
7982
const myDevice = me.devices.find(d => d.id == browserId);
8083
if (myDevice == null) {

frontend/src/components/RegenerateSetupCodeDialog.vue

+3
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,9 @@ async function regenerateSetupCode() {
156156
throw new Error('User not initialized.');
157157
}
158158
const browserKeys = await BrowserKeys.load(me.id);
159+
if (browserKeys == null) {
160+
throw new Error('Browser keys not found.');
161+
}
159162
const browserId = await browserKeys.id();
160163
const myDevice = me.devices.find(d => d.id == browserId);
161164
if (myDevice == null) {

frontend/src/components/VaultDetails.vue

+17-16
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,6 @@
165165
{{ t('vaultDetails.recoverVault') }}
166166
</button>
167167
</div>
168-
169168
</div>
170169

171170
<ClaimVaultOwnershipDialog v-if="claimingVaultOwnership && vault != null" ref="claimVaultOwnershipDialog" :vault="vault" @action="provedOwnership" @close="claimingVaultOwnership = false" />
@@ -260,28 +259,30 @@ async function fetchData() {
260259
}
261260
262261
async function fetchOwnerData() {
263-
try {
264-
const vaultKeyJwe = await backend.vaults.accessToken(props.vaultId, true);
265-
vaultKeys.value = await loadVaultKeys(vaultKeyJwe);
266-
(await backend.vaults.getMembers(props.vaultId)).forEach(member => members.value.set(member.id, member));
267-
usersRequiringAccessGrant.value = await backend.vaults.getUsersRequiringAccessGrant(props.vaultId);
268-
vaultRecoveryRequired.value = false;
269-
} catch(error) {
270-
if (error instanceof ForbiddenError) {
271-
vaultRecoveryRequired.value = true;
272-
} else {
273-
console.error('Retrieving ownership failed.', error);
274-
onFetchError.value = error instanceof Error ? error : new Error('Unknown Error');
275-
}
262+
try {
263+
const vaultKeyJwe = await backend.vaults.accessToken(props.vaultId, true);
264+
vaultKeys.value = await loadVaultKeys(vaultKeyJwe);
265+
(await backend.vaults.getMembers(props.vaultId)).forEach(member => members.value.set(member.id, member));
266+
usersRequiringAccessGrant.value = await backend.vaults.getUsersRequiringAccessGrant(props.vaultId);
267+
vaultRecoveryRequired.value = false;
268+
} catch (error) {
269+
if (error instanceof ForbiddenError) {
270+
vaultRecoveryRequired.value = true;
271+
} else {
272+
console.error('Retrieving ownership failed.', error);
273+
onFetchError.value = error instanceof Error ? error : new Error('Unknown Error');
276274
}
277-
275+
}
278276
}
279277
280278
async function loadVaultKeys(vaultKeyJwe: string): Promise<VaultKeys> {
281279
if (!me.value || !me.value.publicKey) {
282280
throw new Error('User not initialized.');
283281
}
284282
const browserKeys = await BrowserKeys.load(me.value.id);
283+
if (browserKeys == null) {
284+
throw new Error('Browser keys not found.');
285+
}
285286
const browserId = await browserKeys.id();
286287
const myDevice = me.value.devices.find(d => d.id == browserId);
287288
if (myDevice == null) {
@@ -421,7 +422,7 @@ function refreshVault(updatedVault: VaultDto) {
421422
}
422423
423424
async function reloadView() {
424-
await fetchOwnerData()
425+
await fetchOwnerData();
425426
vaultRecoveryRequired.value = false;
426427
}
427428

frontend/tsconfig.json

+1
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"esModuleInterop": true,
1111
"lib": ["esnext", "dom"],
1212
"noUnusedLocals": true,
13+
"useUnknownInCatchVariables": false, // Workaround for `node_modules/miscreant/src/providers/webcrypto.ts:21:11 - error TS18046: 'e' is of type 'unknown'.`
1314
},
1415
"ts-node": {
1516
"compilerOptions": {

hub.code-workspace

+3-3
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
"typescript.referencesCodeLens.enabled": true,
2828
"typescript.implementationsCodeLens.enabled": true,
2929
"editor.codeActionsOnSave": {
30-
"source.organizeImports": true,
31-
"source.fixAll.eslint": true
30+
"source.organizeImports": "explicit",
31+
"source.fixAll.eslint": "explicit"
3232
}
3333
}
34-
}
34+
}

0 commit comments

Comments
 (0)