feat: session issues

This commit is contained in:
Eli Bosley
2025-01-30 13:32:36 -05:00
parent 1ecac5ee4e
commit 8026ef53e8
10 changed files with 31 additions and 14 deletions

View File

@@ -19,5 +19,5 @@ dynamicRemoteAccessType="DISABLED"
ssoSubIds=""
allowedOrigins="/var/run/unraid-notifications.sock, /var/run/unraid-php.sock, /var/run/unraid-cli.sock, http://localhost:8080, https://localhost:4443, https://tower.local:4443, https://192.168.1.150:4443, https://tower:4443, https://192-168-1-150.thisisfourtyrandomcharacters012345678900.myunraid.net:4443, https://85-121-123-122.thisisfourtyrandomcharacters012345678900.myunraid.net:8443, https://10-252-0-1.hash.myunraid.net:4443, https://10-252-1-1.hash.myunraid.net:4443, https://10-253-3-1.hash.myunraid.net:4443, https://10-253-4-1.hash.myunraid.net:4443, https://10-253-5-1.hash.myunraid.net:4443, https://10-100-0-1.hash.myunraid.net:4443, https://10-100-0-2.hash.myunraid.net:4443, https://10-123-1-2.hash.myunraid.net:4443, https://221-123-121-112.hash.myunraid.net:4443, https://google.com, https://test.com, https://connect.myunraid.net, https://connect-staging.myunraid.net, https://dev-my.myunraid.net:4000, https://studio.apollographql.com"
[connectionStatus]
minigraph="PRE_INIT"
minigraph="ERROR_RETRYING"
upnpStatus=""

View File

@@ -323,7 +323,9 @@ export function ContainerPortSchema(): z.ZodObject<Properties<ContainerPort>> {
export function CreateApiKeyInputSchema(): z.ZodObject<Properties<CreateApiKeyInput>> {
return z.object({
description: z.string().nullish(),
memory: z.boolean().nullish(),
name: z.string(),
overwrite: z.boolean().nullish(),
permissions: z.array(z.lazy(() => AddPermissionInputSchema())).nullish(),
roles: z.array(RoleSchema).nullish()
})

View File

@@ -347,7 +347,11 @@ export enum ContainerState {
export type CreateApiKeyInput = {
description?: InputMaybe<Scalars['String']['input']>;
/** Whether to create the key in memory only (true), or on disk (false) - memory only keys will not persist through reboots of the API */
memory?: InputMaybe<Scalars['Boolean']['input']>;
name: Scalars['String']['input'];
/** This will replace the existing key if one already exists with the same name, otherwise returns the existing key */
overwrite?: InputMaybe<Scalars['Boolean']['input']>;
permissions?: InputMaybe<Array<AddPermissionInput>>;
roles?: InputMaybe<Array<Role>>;
};

View File

@@ -27,6 +27,10 @@ input CreateApiKeyInput {
description: String
roles: [Role!]
permissions: [AddPermissionInput!]
""" This will replace the existing key if one already exists with the same name, otherwise returns the existing key """
overwrite: Boolean
""" Whether to create the key in memory only (true), or on disk (false) - memory only keys will not persist through reboots of the API """
memory: Boolean
}
input AddPermissionInput {

View File

@@ -103,12 +103,14 @@ export class ApiKeyService implements OnModuleInit {
roles,
permissions,
overwrite = false,
memory = false,
}: {
name: string;
description: string | undefined;
roles?: Role[];
permissions?: Permission[] | AddPermissionInput[];
overwrite?: boolean;
memory?: boolean;
}): Promise<ApiKeyWithSecret> {
const trimmedName = name?.trim();
const sanitizedName = this.sanitizeName(trimmedName);
@@ -127,7 +129,7 @@ export class ApiKeyService implements OnModuleInit {
const existingKey = this.findByField('name', sanitizedName);
if (!overwrite && existingKey) {
throw new GraphQLError('API key name already exists, use overwrite flag to update');
return existingKey;
}
const apiKey: Partial<ApiKeyWithSecret> = {
id: uuidv4(),
@@ -142,7 +144,11 @@ export class ApiKeyService implements OnModuleInit {
// Update createdAt date
apiKey.createdAt = new Date().toISOString();
await this.saveApiKey(apiKey as ApiKeyWithSecret);
if (memory) {
this.memoryApiKeys.push(apiKey as ApiKeyWithSecret)
} else {
await this.saveApiKey(apiKey as ApiKeyWithSecret);
}
return apiKey as ApiKeyWithSecret;
}

View File

@@ -8,10 +8,10 @@ import { ApiKeyService } from '@app/unraid-api/auth/api-key.service';
import { AuthService } from '@app/unraid-api/auth/auth.service';
import { CookieService } from '@app/unraid-api/auth/cookie.service';
import { AuthResolver } from './auth.resolver';
import { ApiKeyResolver } from './api-key.resolver';
describe('AuthResolver', () => {
let resolver: AuthResolver;
describe('ApiKeyResolver', () => {
let resolver: ApiKeyResolver;
let authService: AuthService;
let apiKeyService: ApiKeyService;
let authzService: AuthZService;
@@ -45,7 +45,7 @@ describe('AuthResolver', () => {
authzService = new AuthZService(enforcer);
cookieService = new CookieService();
authService = new AuthService(cookieService, apiKeyService, authzService);
resolver = new AuthResolver(authService, apiKeyService);
resolver = new ApiKeyResolver(authService, apiKeyService);
});
describe('apiKeys', () => {

View File

@@ -6,7 +6,6 @@ import { AuthActionVerb, AuthPossession, UsePermissions } from 'nest-authz';
import type {
AddRoleForApiKeyInput,
AddRoleForUserInput,
ApiKey,
ApiKeyWithSecret,
CreateApiKeyInput,
@@ -17,10 +16,10 @@ import { ApiKeyService } from '@app/unraid-api/auth/api-key.service';
import { GraphqlAuthGuard } from '@app/unraid-api/auth/auth.guard';
import { AuthService } from '@app/unraid-api/auth/auth.service';
@Resolver('Auth')
@Resolver('ApiKey')
@UseGuards(GraphqlAuthGuard)
@Throttle({ default: { limit: 100, ttl: 60000 } }) // 100 requests per minute
export class AuthResolver {
export class ApiKeyResolver {
constructor(
private authService: AuthService,
private apiKeyService: ApiKeyService
@@ -61,6 +60,8 @@ export class AuthResolver {
description: input.description ?? undefined,
roles: input.roles ?? [],
permissions: input.permissions ?? [],
memory: input.memory ?? false,
overwrite: input.overwrite ?? false
});
await this.authService.syncApiKeyRoles(apiKey.id, apiKey.roles);

View File

@@ -4,13 +4,14 @@ import { AuthModule } from '@app/unraid-api/auth/auth.module';
import { ArrayResolver } from '@app/unraid-api/graph/resolvers/array/array.resolver';
import { DockerResolver } from '@app/unraid-api/graph/resolvers/docker/docker.resolver';
import { AuthResolver } from './auth/auth.resolver';
import { ApiKeyResolver } from './api-key/api-key.resolver';
import { CloudResolver } from './cloud/cloud.resolver';
import { ConfigResolver } from './config/config.resolver';
import { DisksResolver } from './disks/disks.resolver';
import { DisplayResolver } from './display/display.resolver';
import { FlashResolver } from './flash/flash.resolver';
import { InfoResolver } from './info/info.resolver';
import { MeResolver } from './me/me.resolver';
import { NotificationsResolver } from './notifications/notifications.resolver';
import { NotificationsService } from './notifications/notifications.service';
import { OnlineResolver } from './online/online.resolver';
@@ -19,13 +20,12 @@ import { RegistrationResolver } from './registration/registration.resolver';
import { ServerResolver } from './servers/server.resolver';
import { VarsResolver } from './vars/vars.resolver';
import { VmsResolver } from './vms/vms.resolver';
import { MeResolver } from './me/me.resolver';
@Module({
imports: [AuthModule],
providers: [
ArrayResolver,
AuthResolver,
ApiKeyResolver,
CloudResolver,
ConfigResolver,
DisksResolver,
@@ -43,6 +43,6 @@ import { MeResolver } from './me/me.resolver';
NotificationsService,
MeResolver,
],
exports: [AuthModule, AuthResolver],
exports: [AuthModule, ApiKeyResolver],
})
export class ResolversModule {}