mirror of
https://github.com/unraid/api.git
synced 2025-12-31 13:39:52 -06:00
fix: delete legacy connect keys and ensure description
This commit is contained in:
@@ -12,6 +12,8 @@ import { ConnectConfigService } from './connect-config.service.js';
|
|||||||
export class ConnectApiKeyService implements ApiKeyService {
|
export class ConnectApiKeyService implements ApiKeyService {
|
||||||
private readonly logger = new Logger(ConnectApiKeyService.name);
|
private readonly logger = new Logger(ConnectApiKeyService.name);
|
||||||
private static readonly validRoles: Set<Role> = new Set(Object.values(Role));
|
private static readonly validRoles: Set<Role> = 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(
|
constructor(
|
||||||
@Inject(API_KEY_SERVICE_TOKEN)
|
@Inject(API_KEY_SERVICE_TOKEN)
|
||||||
@@ -72,11 +74,13 @@ export class ConnectApiKeyService implements ApiKeyService {
|
|||||||
public async createLocalConnectApiKey(): Promise<ApiKeyWithSecret | null> {
|
public async createLocalConnectApiKey(): Promise<ApiKeyWithSecret | null> {
|
||||||
try {
|
try {
|
||||||
return await this.create({
|
return await this.create({
|
||||||
name: 'Connect',
|
name: ConnectApiKeyService.CONNECT_API_KEY_NAME,
|
||||||
description: 'API key for Connect user',
|
description: 'API key for Connect user',
|
||||||
roles: [Role.CONNECT],
|
roles: [Role.CONNECT],
|
||||||
overwrite: true,
|
overwrite: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Delete all other API keys with the role CONNECT
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this.logger.error(`Failed to create local API key for Connect user: ${err}`);
|
this.logger.error(`Failed to create local API key for Connect user: ${err}`);
|
||||||
return null;
|
return null;
|
||||||
@@ -87,21 +91,57 @@ export class ConnectApiKeyService implements ApiKeyService {
|
|||||||
* Gets or creates a local API key for Connect
|
* Gets or creates a local API key for Connect
|
||||||
*/
|
*/
|
||||||
public async getOrCreateLocalApiKey(): Promise<string> {
|
public async getOrCreateLocalApiKey(): Promise<string> {
|
||||||
// 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();
|
const { localApiKey: localApiKeyFromConfig } = this.connectConfig.getConfig();
|
||||||
if (localApiKeyFromConfig && localApiKeyFromConfig !== '') {
|
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');
|
// 3. Filter by name "Connect"
|
||||||
if (localApiKeyFromDisk) {
|
const connectKeys = allKeys.filter(key => key.name === ConnectApiKeyService.CONNECT_API_KEY_NAME);
|
||||||
return localApiKeyFromDisk.key;
|
|
||||||
|
// 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) {
|
if (!localApiKey?.key) {
|
||||||
throw new Error('Failed to create local API key');
|
throw new Error('Failed to create local API key');
|
||||||
}
|
}
|
||||||
|
|
||||||
return localApiKey.key;
|
return localApiKey.key;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,11 +180,9 @@ async function upsertKey() {
|
|||||||
const apiKeyResult = res?.data?.apiKey;
|
const apiKeyResult = res?.data?.apiKey;
|
||||||
if (isEdit && apiKeyResult && 'update' in apiKeyResult) {
|
if (isEdit && apiKeyResult && 'update' in apiKeyResult) {
|
||||||
const fragmentData = useFragment(API_KEY_FRAGMENT_WITH_KEY, apiKeyResult.update);
|
const fragmentData = useFragment(API_KEY_FRAGMENT_WITH_KEY, apiKeyResult.update);
|
||||||
console.log('fragmentData', fragmentData);
|
|
||||||
apiKeyStore.setCreatedKey(fragmentData);
|
apiKeyStore.setCreatedKey(fragmentData);
|
||||||
} else if (!isEdit && apiKeyResult && 'create' in apiKeyResult) {
|
} else if (!isEdit && apiKeyResult && 'create' in apiKeyResult) {
|
||||||
const fragmentData = useFragment(API_KEY_FRAGMENT_WITH_KEY, apiKeyResult.create);
|
const fragmentData = useFragment(API_KEY_FRAGMENT_WITH_KEY, apiKeyResult.create);
|
||||||
console.log('fragmentData', fragmentData);
|
|
||||||
apiKeyStore.setCreatedKey(fragmentData);
|
apiKeyStore.setCreatedKey(fragmentData);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,7 +260,7 @@ async function upsertKey() {
|
|||||||
areAllPermissionsSelected() ? clearAllPermissions() : selectAllPermissions()
|
areAllPermissionsSelected() ? clearAllPermissions() : selectAllPermissions()
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ areAllPermissionsSelected() ? 'Select None' : 'Select All' }}
|
{{ areAllPermissionsSelected() ? 'Clear All' : 'Select All' }}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex flex-col gap-2 mt-1">
|
<div class="flex flex-col gap-2 mt-1">
|
||||||
@@ -283,7 +281,7 @@ async function upsertKey() {
|
|||||||
: selectAllActions(perm.resource)
|
: selectAllActions(perm.resource)
|
||||||
"
|
"
|
||||||
>
|
>
|
||||||
{{ areAllActionsSelected(perm.resource) ? 'Select None' : 'Select All' }}
|
{{ areAllActionsSelected(perm.resource) ? 'Clear All' : 'Select All' }}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div class="flex gap-4 flex-wrap">
|
<div class="flex gap-4 flex-wrap">
|
||||||
|
|||||||
Reference in New Issue
Block a user