From 22fe91cd561e88aa24e8f8cfa5a6143e7644e4e0 Mon Sep 17 00:00:00 2001 From: Eli Bosley Date: Wed, 25 Jun 2025 16:19:09 -0400 Subject: [PATCH] fix: delete legacy connect keys and ensure description --- .../src/service/connect-api-key.service.ts | 58 ++++++++++++++++--- web/components/ApiKey/ApiKeyCreate.vue | 6 +- 2 files changed, 51 insertions(+), 13 deletions(-) diff --git a/packages/unraid-api-plugin-connect/src/service/connect-api-key.service.ts b/packages/unraid-api-plugin-connect/src/service/connect-api-key.service.ts index e7a180a66..5199e195d 100644 --- a/packages/unraid-api-plugin-connect/src/service/connect-api-key.service.ts +++ b/packages/unraid-api-plugin-connect/src/service/connect-api-key.service.ts @@ -12,6 +12,8 @@ import { ConnectConfigService } from './connect-config.service.js'; export class ConnectApiKeyService implements ApiKeyService { private readonly logger = new Logger(ConnectApiKeyService.name); private static readonly validRoles: Set = new Set(Object.values(Role)); + private static readonly CONNECT_API_KEY_NAME = 'Connect'; + private static readonly CONNECT_API_KEY_DESCRIPTION = 'Internal API Key Used By Unraid Connect to access your server resources for the connect.myunraid.net dashboard'; constructor( @Inject(API_KEY_SERVICE_TOKEN) @@ -72,11 +74,13 @@ export class ConnectApiKeyService implements ApiKeyService { public async createLocalConnectApiKey(): Promise { try { return await this.create({ - name: 'Connect', + name: ConnectApiKeyService.CONNECT_API_KEY_NAME, description: 'API key for Connect user', roles: [Role.CONNECT], overwrite: true, }); + + // Delete all other API keys with the role CONNECT } catch (err) { this.logger.error(`Failed to create local API key for Connect user: ${err}`); return null; @@ -87,21 +91,57 @@ export class ConnectApiKeyService implements ApiKeyService { * Gets or creates a local API key for Connect */ public async getOrCreateLocalApiKey(): Promise { - // 1. Check in-memory config + const targetDescription = ConnectApiKeyService.CONNECT_API_KEY_DESCRIPTION; + + // 1. Get all API keys first + const allKeys = await this.findAll(); + + // 2. Check in-memory config and verify key exists const { localApiKey: localApiKeyFromConfig } = this.connectConfig.getConfig(); if (localApiKeyFromConfig && localApiKeyFromConfig !== '') { - return localApiKeyFromConfig; + const keyExists = allKeys.some(key => { + const keyWithSecret = this.findByIdWithSecret(key.id); + return keyWithSecret?.key === localApiKeyFromConfig; + }); + if (keyExists) { + return localApiKeyFromConfig; + } } - // 2. Check disk - const localApiKeyFromDisk = this.apiKeyService.findByField('name', 'Connect'); - if (localApiKeyFromDisk) { - return localApiKeyFromDisk.key; + + // 3. Filter by name "Connect" + const connectKeys = allKeys.filter(key => key.name === ConnectApiKeyService.CONNECT_API_KEY_NAME); + + // 4. Find keys with correct description vs incorrect description + const correctKeys = connectKeys.filter(key => key.description === targetDescription); + const incorrectKeys = connectKeys.filter(key => key.description !== targetDescription); + + // 5. Delete keys with incorrect description + if (incorrectKeys.length > 0) { + const idsToDelete = incorrectKeys.map(key => key.id); + await this.deleteApiKeys(idsToDelete); + this.logger.log(`Deleted ${incorrectKeys.length} Connect API keys with incorrect descriptions`); } - // 3. If no key found, create one - const localApiKey = await this.createLocalConnectApiKey(); + + // 6. If we have a correct key, return it + if (correctKeys.length > 0) { + const correctKeyWithSecret = this.findByIdWithSecret(correctKeys[0].id); + if (correctKeyWithSecret) { + return correctKeyWithSecret.key; + } + } + + // 7. Create a new key with the correct description + const localApiKey = await this.create({ + name: ConnectApiKeyService.CONNECT_API_KEY_NAME, + description: targetDescription, + roles: [Role.CONNECT], + overwrite: true, + }); + if (!localApiKey?.key) { throw new Error('Failed to create local API key'); } + return localApiKey.key; } } diff --git a/web/components/ApiKey/ApiKeyCreate.vue b/web/components/ApiKey/ApiKeyCreate.vue index 374a4b511..ccb59bf58 100644 --- a/web/components/ApiKey/ApiKeyCreate.vue +++ b/web/components/ApiKey/ApiKeyCreate.vue @@ -180,11 +180,9 @@ async function upsertKey() { const apiKeyResult = res?.data?.apiKey; if (isEdit && apiKeyResult && 'update' in apiKeyResult) { const fragmentData = useFragment(API_KEY_FRAGMENT_WITH_KEY, apiKeyResult.update); - console.log('fragmentData', fragmentData); apiKeyStore.setCreatedKey(fragmentData); } else if (!isEdit && apiKeyResult && 'create' in apiKeyResult) { const fragmentData = useFragment(API_KEY_FRAGMENT_WITH_KEY, apiKeyResult.create); - console.log('fragmentData', fragmentData); apiKeyStore.setCreatedKey(fragmentData); } @@ -262,7 +260,7 @@ async function upsertKey() { areAllPermissionsSelected() ? clearAllPermissions() : selectAllPermissions() " > - {{ areAllPermissionsSelected() ? 'Select None' : 'Select All' }} + {{ areAllPermissionsSelected() ? 'Clear All' : 'Select All' }}
@@ -283,7 +281,7 @@ async function upsertKey() { : selectAllActions(perm.resource) " > - {{ areAllActionsSelected(perm.resource) ? 'Select None' : 'Select All' }} + {{ areAllActionsSelected(perm.resource) ? 'Clear All' : 'Select All' }}