Skip to content

Commit

Permalink
fix various linter problems
Browse files Browse the repository at this point in the history
  • Loading branch information
overheadhunter committed Aug 22, 2024
1 parent 8246506 commit cd5d146
Show file tree
Hide file tree
Showing 27 changed files with 73 additions and 81 deletions.
6 changes: 3 additions & 3 deletions frontend/src/common/auditlog.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ export class AuditLogEntityCache {
return this.getEntity<DeviceDto>(deviceId, this.devices, this.debouncedResolvePendingDevices);
}

private async getEntity<T>(entityId: string, entities: Map<string, Deferred<T>>, debouncedResolvePendingEntities: Function): Promise<T> {
private async getEntity<T>(entityId: string, entities: Map<string, Deferred<T>>, debouncedResolvePendingEntities: () => void): Promise<T> {
const cachedEntity = entities.get(entityId);
if (!cachedEntity) {
const deferredEntity = new Deferred<T>();
Expand All @@ -133,8 +133,8 @@ export class AuditLogEntityCache {
private debouncedResolvePendingDevices = debounce(async () => await this.resolvePendingEntities<DeviceDto>(this.devices, backend.devices.listSome), 100);

private async resolvePendingEntities<T extends { id: string }>(entities: Map<string, Deferred<T>>, listSome: (ids: string[]) => Promise<T[]>): Promise<void> {
const pendingEntities = Array.from(entities.entries()).filter(([_, v]) => v.status === 'pending');
const entitiesResult = await listSome(pendingEntities.map(([k, _]) => k));
const pendingEntities = Array.from(entities.entries()).filter(([, v]) => v.status === 'pending');
const entitiesResult = await listSome(pendingEntities.map(([k,]) => k));
for (const [entityId, deferredEntity] of pendingEntities) {
const entity = entitiesResult.find(v => v.id === entityId);
if (entity) {
Expand Down
15 changes: 8 additions & 7 deletions frontend/src/common/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ axiosAuth.interceptors.request.use(async request => {
request.headers = AxiosHeaders.from({ 'Authorization': `Bearer ${token}` });
}
return request;
} catch (err: unknown) {
} catch {
// only things from auth module can throw errors here
throw new UnauthorizedError();
}
Expand Down Expand Up @@ -160,7 +160,7 @@ class VaultService {
public async get(vaultId: string): Promise<VaultDto> {
return axiosAuth.get(`/vaults/${vaultId}`)
.then(response => {
let dateString = response.data.creationTime;
const dateString = response.data.creationTime;
response.data.creationTime = new Date(dateString);
return response.data;
})
Expand Down Expand Up @@ -228,12 +228,12 @@ class DeviceService {
return axiosAuth.get<DeviceDto[]>(`/devices?${query}`).then(response => response.data);
}

public async removeDevice(deviceId: string): Promise<AxiosResponse<any>> {
public async removeDevice(deviceId: string): Promise<AxiosResponse<unknown>> {
return axiosAuth.delete(`/devices/${deviceId}`)
.catch((error) => rethrowAndConvertIfExpected(error, 404));
}

public async putDevice(device: DeviceDto): Promise<AxiosResponse<any>> {
public async putDevice(device: DeviceDto): Promise<AxiosResponse<unknown>> {
return axiosAuth.put(`/devices/${device.id}`, device);
}
}
Expand All @@ -260,6 +260,7 @@ class TrustService {
public async trustUser(userId: string, signature: string): Promise<void> {
return axiosAuth.put(`/users/trusted/${userId}`, signature, { headers: { 'Content-Type': 'text/plain' } });
}

public async get(userId: string): Promise<TrustDto | undefined> {
return axiosAuth.get<TrustDto>(`/users/trusted/${userId}`).then(response => response.data)
.catch(e => {
Expand Down Expand Up @@ -288,9 +289,9 @@ class AuthorityService {
return {
...authority,
pictureUrl: authority.pictureUrl
}
};
} else {
let cfg = AuthorityService.getJdenticonConfig(authority.type);
const cfg = AuthorityService.getJdenticonConfig(authority.type);
const svg = toSvg(authority.id, 100, cfg);
const bytes = new TextEncoder().encode(svg);
const url = `data:image/svg+xml;base64,${base64.stringify(bytes)}`;
Expand Down Expand Up @@ -407,7 +408,7 @@ function convertExpectedToBackendError(status: number): BackendError {
* @param error A thrown object
* @param expectedStatusCodes The expected http status codes of the backend call
*/
export function rethrowAndConvertIfExpected(error: unknown, ...expectedStatusCodes: number[]): Promise<any> {
export function rethrowAndConvertIfExpected(error: unknown, ...expectedStatusCodes: number[]): never {
if (AxiosStatic.isAxiosError(error) && error.response != null && expectedStatusCodes.includes(error.response.status)) {
throw convertExpectedToBackendError(error.response.status);
} else {
Expand Down
5 changes: 2 additions & 3 deletions frontend/src/common/crypto.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ import { base16, base32, base64, base64url } from 'rfc4648';
import { JWEBuilder, JWEParser } from './jwe';
import { CRC32, DB, wordEncoder } from './util';
export class UnwrapKeyError extends Error {
readonly actualError: any;
readonly actualError: unknown;

constructor(actualError: any) {
constructor(actualError: unknown) {
super('Unwrapping key failed');
this.actualError = actualError;
}
Expand Down Expand Up @@ -270,7 +270,6 @@ export class UserKeys {

public static readonly ECDSA_KEY_DESIGNATION: EcKeyImportParams | EcKeyGenParams = { name: 'ECDSA', namedCurve: 'P-384' };


protected constructor(readonly ecdhKeyPair: CryptoKeyPair, readonly ecdsaKeyPair: CryptoKeyPair) { }

/**
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/common/jwe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ export class JWEParser {
* @param recipientPrivateKey The recipient's private key
* @returns Decrypted payload
*/
public async decryptEcdhEs(recipientPrivateKey: CryptoKey): Promise<any> {
public async decryptEcdhEs<T>(recipientPrivateKey: CryptoKey): Promise<T> {
if (this.header.alg != 'ECDH-ES' || this.header.enc != 'A256GCM' || !this.header.epk) {
throw new Error('unsupported alg or enc');
}
Expand All @@ -96,7 +96,7 @@ export class JWEParser {
* @returns Decrypted payload
* @throws {UnwrapKeyError} if decryption failed (wrong password?)
*/
public async decryptPbes2(password: string): Promise<any> {
public async decryptPbes2<T>(password: string): Promise<T> {
if (this.header.alg != 'PBES2-HS512+A256KW' || /* this.header.enc != 'A256GCM' || */ !this.header.p2s || !this.header.p2c) {
throw new Error('unsupported alg or enc');
}
Expand All @@ -110,7 +110,7 @@ export class JWEParser {
}
}

private async decrypt(cek: CryptoKey): Promise<any> {
private async decrypt<T>(cek: CryptoKey): Promise<T> {
const utf8enc = new TextEncoder();
const m = new Uint8Array(this.ciphertext.length + this.tag.length);
m.set(this.ciphertext, 0);
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/common/jwt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export class JWT {
* @param payload The payload
* @param signerPrivateKey The signers's private key
*/
public static async build(header: JWTHeader, payload: any, signerPrivateKey: CryptoKey): Promise<string> {
public static async build(header: JWTHeader, payload: object, signerPrivateKey: CryptoKey): Promise<string> {
const encodedHeader = base64url.stringify(new TextEncoder().encode(JSON.stringify(header)), { pad: false });
const encodedPayload = base64url.stringify(new TextEncoder().encode(JSON.stringify(payload)), { pad: false });
const encodedSignature = await this.es384sign(encodedHeader, encodedPayload, signerPrivateKey);
Expand Down Expand Up @@ -46,8 +46,8 @@ export class JWT {
* @returns header and payload
* @throws Error if the JWT is invalid
*/
public static async parse(jwt: string, signerPublicKey: CryptoKey): Promise<[JWTHeader, any]> {
const [encodedHeader, encodedPayload, encodedSignature] = jwt.split('.');
public static async parse(jwt: string, signerPublicKey: CryptoKey): Promise<[JWTHeader, object]> {
const [encodedHeader, encodedPayload] = jwt.split('.');
const header: JWTHeader = JSON.parse(new TextDecoder().decode(base64url.parse(encodedHeader, { loose: true })));
if (header.alg !== 'ES384') {
throw new Error('Unsupported algorithm');
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/common/updatecheck.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ export type LatestVersionDto = {

class UpdatesService {
public async get(localVersion: string): Promise<LatestVersionDto> {
let config = {
const config = {
headers: {
'Content-Type': 'application/json',
'Cryptomator-Hub-Version': localVersion,
Expand Down
2 changes: 0 additions & 2 deletions frontend/src/common/userdata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import { BrowserKeys, UserKeys } from './crypto';
import { JWEParser } from './jwe';

class UserData {

#me?: Promise<UserDto>;
#browserKeys?: Promise<BrowserKeys | undefined>;

Expand Down Expand Up @@ -136,7 +135,6 @@ class UserData {
await backend.users.putMe(me);
}
}

}

const instance = new UserData();
Expand Down
7 changes: 4 additions & 3 deletions frontend/src/common/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { dictionary } from './4096words_en';
export class DB {
private static readonly NAME = 'hub';

public static async transaction<T = any>(objectStore: string, mode: IDBTransactionMode, query: (transaction: IDBTransaction) => IDBRequest<T>): Promise<T> {
public static async transaction<T>(objectStore: string, mode: IDBTransactionMode, query: (transaction: IDBTransaction) => IDBRequest<T>): Promise<T> {
const db = await new Promise<IDBDatabase>((resolve, reject) => {
const req = indexedDB.open(DB.NAME);
req.onsuccess = () => resolve(req.result);
Expand All @@ -23,7 +23,7 @@ export class DB {

export class Deferred<T> {
public promise: Promise<T>;
public reject: (reason?: any) => void;
public reject: (reason?: unknown) => void;
public resolve: (value: T) => void;
public status: 'pending' | 'resolved' | 'rejected' = 'pending';

Expand All @@ -43,9 +43,10 @@ export class Deferred<T> {
* @param wait time to wait before calling function
* @returns debounced function
*/
// eslint-disable-next-line @typescript-eslint/no-unsafe-function-type
export const debounce = (func: Function, wait = 300) => {
let timeoutId: ReturnType<typeof setTimeout>;
function debounceCore(this: any, ...args: any[]) {
function debounceCore(this: unknown, ...args: unknown[]) {
cancel();
timeoutId = setTimeout(() => func.apply(this, args), wait);
}
Expand Down
4 changes: 2 additions & 2 deletions frontend/src/common/wot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ async function sign(user: UserDto): Promise<TrustDto> {
* @param allegedSignedKey The public key that should be signed by the last signature in the chain
*/
async function verify(signatureChain: string[], allegedSignedKey: SignedKeys) {
let signerPublicKey = await userdata.decryptUserKeysWithBrowser().then(keys => keys.ecdsaKeyPair.publicKey);
const signerPublicKey = await userdata.decryptUserKeysWithBrowser().then(keys => keys.ecdsaKeyPair.publicKey);
await verifyRescursive(signatureChain, signerPublicKey, allegedSignedKey);
}

Expand All @@ -62,7 +62,7 @@ async function verify(signatureChain: string[], allegedSignedKey: SignedKeys) {
async function verifyRescursive(signatureChain: string[], signerPublicKey: CryptoKey, allegedSignedKey: SignedKeys) {
// get first element of signature chain:
const [signature, ...remainingChain] = signatureChain;
const [_, signedKeys] = await JWT.parse(signature, signerPublicKey) as [JWTHeader, SignedKeys];
const [, signedKeys] = await JWT.parse(signature, signerPublicKey) as [JWTHeader, SignedKeys];
if (remainingChain.length === 0) {
// last element in chain should match signed public key
if (!deeplyEqual(signedKeys, allegedSignedKey)) {
Expand Down
6 changes: 3 additions & 3 deletions frontend/src/components/AdminSettings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -238,7 +238,7 @@ const numberOfExceededSeats = computed(() => {
});
onMounted(async () => {
let cfg = config.get();
const cfg = config.get();
keycloakAdminRealmURL.value = `${cfg.keycloakUrl}/admin/${cfg.keycloakRealm}/console`;
if (props.token) {
await setToken(props.token);
Expand All @@ -256,8 +256,8 @@ async function setToken(token: string) {
async function fetchData() {
try {
let versionDto = backend.version.get();
let versionAvailable = versionDto.then(versionDto => updateChecker.get(versionDto.hubVersion));
const versionDto = backend.version.get();
const versionAvailable = versionDto.then(versionDto => updateChecker.get(versionDto.hubVersion));
admin.value = await backend.billing.get();
version.value = await versionDto;
latestVersion.value = await versionAvailable;
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/AuditLogDetailsSignedWotId.vue
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ onMounted(async () => {
try {
const signerPublicKey = await asPublicKey(base64.parse(props.event.signerKey), UserKeys.ECDSA_KEY_DESIGNATION, UserKeys.ECDSA_PUB_KEY_USAGES);
const [_, signedKeys] = await JWT.parse(props.event.signature, signerPublicKey) as [JWTHeader, SignedKeys];
signedFingerprint.value = await wot.computeFingerprint({ecdhPublicKey: signedKeys.ecdhPublicKey, ecdsaPublicKey: signedKeys.ecdsaPublicKey});
signedFingerprint.value = await wot.computeFingerprint({ ecdhPublicKey: signedKeys.ecdhPublicKey, ecdsaPublicKey: signedKeys.ecdsaPublicKey });
if (props.event.signerKey === signingUser?.ecdsaPublicKey && signedFingerprint.value === currentFingerprint.value) {
signatureStatus.value = SignatureStatus.STILL_VALID;
} else if (props.event.signerKey !== signingUser?.ecdsaPublicKey) {
Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/DeviceList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ async function removeDevice(device: DeviceDto) {
if (error instanceof NotFoundError) {
// if device is already missing in backend → ignore and proceed to then()
} else {
let e = error instanceof Error ? error : new Error('Unknown Error');
const e = error instanceof Error ? error : new Error('Unknown Error');
onRemoveDeviceError.value[device.id] = e;
throw e;
}
Expand Down
3 changes: 1 addition & 2 deletions frontend/src/components/GrantPermissionDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ import backend, { AccessGrant, ConflictError, NotFoundError, TrustDto, UserDto,
import { VaultKeys } from '../common/crypto';
import TrustDetails from './TrustDetails.vue';
const { t } = useI18n({ useScope: 'global' });
const open = ref(false);
Expand Down Expand Up @@ -122,7 +121,7 @@ async function grantAccess() {
}
async function giveUsersAccess(users: UserDto[]) {
let tokens: AccessGrant[] = [];
const tokens: AccessGrant[] = [];
for (const user of users) {
if (user.ecdhPublicKey) { // some users might not have set up their key pair, so we can't share secrets with them yet
const publicKey = base64.parse(user.ecdhPublicKey);
Expand Down
10 changes: 6 additions & 4 deletions frontend/src/components/NavigationBar.vue
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@

<script setup lang="ts">
import { Disclosure, DisclosureButton, DisclosurePanel, Menu, MenuButton, MenuItem, MenuItems } from '@headlessui/vue';
import { ArrowRightOnRectangleIcon, Bars3Icon, ListBulletIcon, UserIcon, WrenchIcon, XMarkIcon } from '@heroicons/vue/24/outline';
import { onMounted, ref } from 'vue';
import { ArrowRightStartOnRectangleIcon, Bars3Icon, ListBulletIcon, UserIcon, WrenchIcon, XMarkIcon } from '@heroicons/vue/24/outline';
import { FunctionalComponent, onMounted, ref } from 'vue';
import { useI18n } from 'vue-i18n';
import auth from '../common/auth';
import { UserDto } from '../common/backend';
Expand All @@ -80,6 +80,8 @@ const navigation = [
{ name: 'nav.vaults', to: '/app/vaults' },
];
type ProfileDropdownItem = { icon: FunctionalComponent, name: string, to: string };
const profileDropdownSections = {
infoSection :
[
Expand All @@ -94,12 +96,12 @@ const profileDropdownSections = {
hubSection :
[
{ icon: ArrowRightOnRectangleIcon, name: 'nav.profile.signOut', to: '/app/logout' }
{ icon: ArrowRightStartOnRectangleIcon, name: 'nav.profile.signOut', to: '/app/logout' }
],
};
const profileDropdown = ref<any []>([]);
const profileDropdown = ref<ProfileDropdownItem[][]>([]);
const props = defineProps<{
me : UserDto
}>();
Expand Down
8 changes: 4 additions & 4 deletions frontend/src/components/SignUserKeysDialog.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@
<div class="my-2">
<label for="fingerprint" class="block text-sm font-medium leading-6 text-gray-900">Fingerprint</label>
<div class="relative mt-2 rounded-md shadow-sm">
<input type="text" name="fingerprint" v-model="enteredFingerprint" :readonly="minVerificationLen === 0" @keyup="tryAutocomplete()" id="fingerprint" class="block w-full rounded-md border-0 py-1.5 pr-10 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-primary text-sm sm:leading-6" />
<input id="fingerprint" v-model="enteredFingerprint" type="text" name="fingerprint" :readonly="minVerificationLen === 0" class="block w-full rounded-md border-0 py-1.5 pr-10 text-gray-900 ring-1 ring-inset ring-gray-300 focus:ring-2 focus:ring-inset focus:ring-primary text-sm sm:leading-6" @keyup="tryAutocomplete()" />
<div class="pointer-events-none absolute inset-y-0 right-0 flex items-center pr-3">
<CheckIcon class="h-5 w-5 text-primary" aria-hidden="true" v-if="fingerprintMatches"/>
<CheckIcon v-if="fingerprintMatches" class="h-5 w-5 text-primary" aria-hidden="true"/>
</div>
</div>
</div>
Expand Down Expand Up @@ -94,7 +94,7 @@ async function fetchData() {
expectedFingerprint.value = await wot.computeFingerprint(props.user);
minVerificationLen.value = (await backend.settings.get()).wotIdVerifyLen;
if (minVerificationLen.value === 0) {
enteredFingerprint.value = expectedFingerprint.value.replace(/.{8}/g, "$&" + " ").trim();
enteredFingerprint.value = expectedFingerprint.value.replace(/.{8}/g, '$&' + ' ').trim();
}
}
Expand All @@ -105,7 +105,7 @@ function show() {
async function tryAutocomplete() {
if (enteredFingerprint.value.length >= minVerificationLen.value) {
if (expectedFingerprint.value?.startsWith(enteredFingerprint.value)) {
enteredFingerprint.value = expectedFingerprint.value.replace(/.{8}/g, "$&" + " ").trim();
enteredFingerprint.value = expectedFingerprint.value.replace(/.{8}/g, '$&' + ' ').trim();
}
}
}
Expand Down
18 changes: 9 additions & 9 deletions frontend/src/components/TrustDetails.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,15 @@
</PopoverButton>

<transition enter-active-class="transition ease-out duration-100" enter-from-class="transform opacity-0 scale-95" enter-to-class="transform opacity-100 scale-100" leave-active-class="transition ease-in duration-75" leave-from-class="transform opacity-100 scale-100" leave-to-class="transform opacity-0 scale-95">
<PopoverPanel class="absolute right-0 z-10 mt-2 origin-top-right rounded-md bg-white p-4 shadow-2xl ring-1 ring-black ring-opacity-5 focus:outline-none">
<p v-if="trustLevel === -1" class="text-sm mb-2">{{ t('trustDetails.trustLevel.untrusted') }}</p>
<p v-else-if="trustLevel === 0" class="text-sm mb-2">{{ t('trustDetails.trustLevel', [ n(1, 'percent')]) }}</p>
<p v-else-if="trustLevel > 0" class="text-sm mb-2">{{ t('trustDetails.trustLevel', [ n(1 / trustLevel, 'percent')]) }}</p>
<button v-if="trustLevel !== 0 && trustedUser.ecdhPublicKey && trustedUser.ecdsaPublicKey" @click="showSignUserKeysDialog()" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-primary text-base font-medium text-white hover:bg-primary-d1 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary sm:w-auto sm:text-sm">
{{ t('trustDetails.showSignDialogBtn') }}
</button>
<p v-if="!trustedUser.ecdhPublicKey || !trustedUser.ecdsaPublicKey" class="text-sm mb-2">{{ t('trustDetails.userNotSetUp') }}</p>
</PopoverPanel>
<PopoverPanel class="absolute right-0 z-10 mt-2 origin-top-right rounded-md bg-white p-4 shadow-2xl ring-1 ring-black ring-opacity-5 focus:outline-none">
<p v-if="trustLevel === -1" class="text-sm mb-2">{{ t('trustDetails.trustLevel.untrusted') }}</p>
<p v-else-if="trustLevel === 0" class="text-sm mb-2">{{ t('trustDetails.trustLevel', [ n(1, 'percent')]) }}</p>
<p v-else-if="trustLevel > 0" class="text-sm mb-2">{{ t('trustDetails.trustLevel', [ n(1 / trustLevel, 'percent')]) }}</p>
<button v-if="trustLevel !== 0 && trustedUser.ecdhPublicKey && trustedUser.ecdsaPublicKey" class="w-full inline-flex justify-center rounded-md border border-transparent shadow-sm px-4 py-2 bg-primary text-base font-medium text-white hover:bg-primary-d1 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-primary sm:w-auto sm:text-sm" @click="showSignUserKeysDialog()">
{{ t('trustDetails.showSignDialogBtn') }}
</button>
<p v-if="!trustedUser.ecdhPublicKey || !trustedUser.ecdsaPublicKey" class="text-sm mb-2">{{ t('trustDetails.userNotSetUp') }}</p>
</PopoverPanel>
</transition>
</Popover>

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/components/UserProfile.vue
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ const version = ref<VersionDto>();
const onFetchError = ref<Error | null>();
onMounted(async () => {
let cfg = config.get();
const cfg = config.get();
keycloakUserAccountURL.value = `${cfg.keycloakUrl}/realms/${cfg.keycloakRealm}/account`;
await fetchData();
});
Expand Down
Loading

0 comments on commit cd5d146

Please sign in to comment.