Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 0 additions & 9 deletions api/generated-schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1778,17 +1778,8 @@ input ConnectSignInInput {
"""The API key for authentication"""
apiKey: String!

"""The ID token for authentication"""
idToken: String

"""User information for the sign-in"""
userInfo: ConnectUserInfoInput

"""The access token for authentication"""
accessToken: String

"""The refresh token for authentication"""
refreshToken: String
}

input ConnectUserInfoInput {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,19 +74,6 @@ export class MyServersConfig {
@IsString()
regWizTime!: string;

// Authentication Tokens
@Field(() => String)
@IsString()
accesstoken!: string;

@Field(() => String)
@IsString()
idtoken!: string;

@Field(() => String)
@IsString()
refreshtoken!: string;

// Remote Access Settings
@Field(() => DynamicRemoteAccessType)
@IsEnum(DynamicRemoteAccessType)
Expand Down Expand Up @@ -211,9 +198,6 @@ export const emptyMyServersConfig = (): MyServersConfig => ({
username: '',
avatar: '',
regWizTime: '',
accesstoken: '',
idtoken: '',
refreshtoken: '',
dynamicRemoteAccessType: DynamicRemoteAccessType.DISABLED,
});

Expand Down
15 changes: 0 additions & 15 deletions packages/unraid-api-plugin-connect/src/model/connect.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,28 +93,13 @@ export class ConnectSignInInput {
@MinLength(5)
apiKey!: string;

@Field(() => String, { nullable: true, description: 'The ID token for authentication' })
@IsString()
@IsOptional()
idToken?: string;

@Field(() => ConnectUserInfoInput, {
nullable: true,
description: 'User information for the sign-in',
})
@ValidateNested()
@IsOptional()
userInfo?: ConnectUserInfoInput;

@Field(() => String, { nullable: true, description: 'The access token for authentication' })
@IsString()
@IsOptional()
accessToken?: string;

@Field(() => String, { nullable: true, description: 'The refresh token for authentication' })
@IsString()
@IsOptional()
refreshToken?: string;
}

@InputType()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,4 @@ export class ConnectResolver {
public async settings(): Promise<ConnectSettings> {
return {} as ConnectSettings;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ export class ConnectConfigPersister implements OnModuleInit, OnModuleDestroy {
// Persist changes to the config.
this.configService.changes$.pipe(bufferTime(25)).subscribe({
next: async (changes) => {
const connectConfigChanged = changes.some(({ path }) => path.startsWith('connect.config'));
const connectConfigChanged = changes.some(({ path }) =>
path.startsWith('connect.config')
);
if (connectConfigChanged) {
await this.persist();
}
Expand Down Expand Up @@ -150,7 +152,7 @@ export class ConnectConfigPersister implements OnModuleInit, OnModuleDestroy {
* @throws {Error} - If the legacy config file does not exist.
* @throws {Error} - If the legacy config file is not parse-able.
*/
public async convertLegacyConfig(config:LegacyConfig): Promise<MyServersConfig> {
public async convertLegacyConfig(config: LegacyConfig): Promise<MyServersConfig> {
return this.validate({
...config.api,
...config.local,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class ConnectApiKeyService implements ApiKeyService {

constructor(
@Inject(API_KEY_SERVICE_TOKEN)
private readonly apiKeyService: ApiKeyService,
private readonly apiKeyService: ApiKeyService
) {}

async findById(id: string): Promise<ApiKey | null> {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ export class ConnectSettingsService {
async signIn(input: ConnectSignInInput) {
const status = this.configService.get('store.emhttp.status');
if (status === 'LOADED') {
const userInfo = input.idToken ? decodeJwt(input.idToken) : (input.userInfo ?? null);
const userInfo = input.userInfo ?? null;

if (
!userInfo ||
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import { ConfigService } from '@nestjs/config';

import { beforeEach, describe, expect, it, vi } from 'vitest';

import { ConnectConfigPersister } from '../service/config.persistence.js';
import { ConfigType } from '../model/connect-config.model.js';
import { ConnectConfigPersister } from '../service/config.persistence.js';

describe('ConnectConfigPersister', () => {
let service: ConnectConfigPersister;
Expand Down Expand Up @@ -79,8 +80,8 @@ ssoSubIds="user1,user2"
idtoken: '',
refreshtoken: '',
dynamicRemoteAccessType: 'DISABLED',
ssoSubIds: ''
}
ssoSubIds: '',
},
} as any;

const result = await service.convertLegacyConfig(legacyConfig);
Expand All @@ -106,8 +107,8 @@ ssoSubIds="user1,user2"
idtoken: '',
refreshtoken: '',
dynamicRemoteAccessType: 'DISABLED',
ssoSubIds: ''
}
ssoSubIds: '',
},
} as any;

const result = await service.convertLegacyConfig(legacyConfig);
Expand All @@ -133,8 +134,8 @@ ssoSubIds="user1,user2"
idtoken: '',
refreshtoken: '',
dynamicRemoteAccessType: 'DISABLED',
ssoSubIds: ''
}
ssoSubIds: '',
},
} as any;

const result = await service.convertLegacyConfig(legacyConfig);
Expand All @@ -161,8 +162,8 @@ ssoSubIds="user1,user2"
idtoken: '',
refreshtoken: '',
dynamicRemoteAccessType: 'DISABLED',
ssoSubIds: ''
}
ssoSubIds: '',
},
} as any;

const result = await service.convertLegacyConfig(legacyConfig);
Expand All @@ -188,8 +189,8 @@ ssoSubIds="user1,user2"
idtoken: '',
refreshtoken: '',
dynamicRemoteAccessType: 'DISABLED',
ssoSubIds: ''
}
ssoSubIds: '',
},
} as any;

const result = await service.convertLegacyConfig(legacyConfig);
Expand All @@ -215,21 +216,23 @@ ssoSubIds="user1,user2"
idtoken: '',
refreshtoken: '',
dynamicRemoteAccessType: 'DISABLED',
ssoSubIds: ''
}
ssoSubIds: '',
},
} as any;

const result = await service.convertLegacyConfig(legacyConfig);

expect(result.apikey).toBe('unraid_sfHboeSNzTzx24816QBssqi0A3nIT0f4Xg4c9Ht49WQfQKLMojU81Sb3f');
expect(result.localApiKey).toBe('101d204832d24fc7e5d387f6fce47067ba230f8aa0ac3bcc6c12a415aa27dbd9');
expect(result.apikey).toBe(
'unraid_sfHboeSNzTzx24816QBssqi0A3nIT0f4Xg4c9Ht49WQfQKLMojU81Sb3f'
);
expect(result.localApiKey).toBe(
'101d204832d24fc7e5d387f6fce47067ba230f8aa0ac3bcc6c12a415aa27dbd9'
);
expect(result.email).toBe('pujitm2009@gmail.com');
expect(result.username).toBe('pujitm2009@gmail.com');
expect(result.avatar).toBe('');
});



it('should merge all sections (api, local, remote) into single config object', async () => {
const legacyConfig = {
api: { version: '4.8.0+9485809', extraOrigins: 'https://example.com' },
Expand All @@ -248,8 +251,8 @@ ssoSubIds="user1,user2"
idtoken: 'id_token_value',
refreshtoken: 'refresh_token_value',
dynamicRemoteAccessType: 'UPNP',
ssoSubIds: 'sub1,sub2'
}
ssoSubIds: 'sub1,sub2',
},
} as any;

const result = await service.convertLegacyConfig(legacyConfig);
Expand All @@ -263,9 +266,6 @@ ssoSubIds="user1,user2"
expect(result.username).toBe('testuser');
expect(result.avatar).toBe('https://avatar.url');
expect(result.regWizTime).toBe('2023-01-01T00:00:00Z');
expect(result.accesstoken).toBe('access_token_value');
expect(result.idtoken).toBe('id_token_value');
expect(result.refreshtoken).toBe('refresh_token_value');
expect(result.dynamicRemoteAccessType).toBe('UPNP');
});

Expand All @@ -287,8 +287,8 @@ ssoSubIds="user1,user2"
idtoken: '',
refreshtoken: '',
dynamicRemoteAccessType: 'DISABLED',
ssoSubIds: ''
}
ssoSubIds: '',
},
} as any;

await expect(service.convertLegacyConfig(legacyConfig)).rejects.toThrow();
Expand Down Expand Up @@ -320,7 +320,7 @@ ssoSubIds="sub1,sub2"

// Parse the INI content
const legacyConfig = service.parseLegacyConfig(iniContent);

// Convert to new format
const result = await service.convertLegacyConfig(legacyConfig);

Expand All @@ -330,4 +330,4 @@ ssoSubIds="sub1,sub2"
expect(result.upnpEnabled).toBe(true);
});
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,9 @@ describe('UrlResolverService', () => {

const result = service.getServerIps();
expect(result.errors.length).toBeGreaterThan(0);
expect(result.errors.some(error => error.message.includes('Failed to parse URL'))).toBe(true);
expect(result.errors.some((error) => error.message.includes('Failed to parse URL'))).toBe(
true
);
});

it('should handle SSL mode variations', () => {
Expand Down Expand Up @@ -159,7 +161,9 @@ describe('UrlResolverService', () => {
const result = service.getServerIps();

if (testCase.shouldError) {
expect(result.errors.some(error => error.message.includes('SSL mode auto'))).toBe(true);
expect(result.errors.some((error) => error.message.includes('SSL mode auto'))).toBe(
true
);
} else {
const lanUrl = result.urls.find(
(url) => url.type === URL_TYPE.LAN && url.name === 'LAN IPv4'
Expand Down
12 changes: 3 additions & 9 deletions web/composables/gql/graphql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -487,14 +487,8 @@ export type ConnectSettingsValues = {
};

export type ConnectSignInInput = {
/** The access token for authentication */
accessToken?: InputMaybe<Scalars['String']['input']>;
/** The API key for authentication */
apiKey: Scalars['String']['input'];
/** The ID token for authentication */
idToken?: InputMaybe<Scalars['String']['input']>;
/** The refresh token for authentication */
refreshToken?: InputMaybe<Scalars['String']['input']>;
/** User information for the sign-in */
userInfo?: InputMaybe<ConnectUserInfoInput>;
};
Expand Down Expand Up @@ -1599,9 +1593,9 @@ export enum Temperature {
export type Theme = {
__typename?: 'Theme';
/** The background color of the header */
headerBackgroundColor: Scalars['String']['output'];
headerBackgroundColor?: Maybe<Scalars['String']['output']>;
/** The text color of the header */
headerPrimaryTextColor: Scalars['String']['output'];
headerPrimaryTextColor?: Maybe<Scalars['String']['output']>;
/** The secondary text color of the header */
headerSecondaryTextColor?: Maybe<Scalars['String']['output']>;
/** The theme name */
Expand Down Expand Up @@ -2218,7 +2212,7 @@ export type ServerStateQuery = { __typename?: 'Query', cloud: (
export type GetThemeQueryVariables = Exact<{ [key: string]: never; }>;


export type GetThemeQuery = { __typename?: 'Query', publicTheme: { __typename?: 'Theme', name: ThemeName, showBannerImage: boolean, showBannerGradient: boolean, headerBackgroundColor: string, showHeaderDescription: boolean, headerPrimaryTextColor: string, headerSecondaryTextColor?: string | null } };
export type GetThemeQuery = { __typename?: 'Query', publicTheme: { __typename?: 'Theme', name: ThemeName, showBannerImage: boolean, showBannerGradient: boolean, headerBackgroundColor?: string | null, showHeaderDescription: boolean, headerPrimaryTextColor?: string | null, headerSecondaryTextColor?: string | null } };

export const ApiKeyFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApiKey"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApiKey"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"roles"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"resource"}},{"kind":"Field","name":{"kind":"Name","value":"actions"}}]}}]}}]} as unknown as DocumentNode<ApiKeyFragment, unknown>;
export const ApiKeyWithKeyFragmentDoc = {"kind":"Document","definitions":[{"kind":"FragmentDefinition","name":{"kind":"Name","value":"ApiKeyWithKey"},"typeCondition":{"kind":"NamedType","name":{"kind":"Name","value":"ApiKeyWithSecret"}},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"id"}},{"kind":"Field","name":{"kind":"Name","value":"key"}},{"kind":"Field","name":{"kind":"Name","value":"name"}},{"kind":"Field","name":{"kind":"Name","value":"description"}},{"kind":"Field","name":{"kind":"Name","value":"createdAt"}},{"kind":"Field","name":{"kind":"Name","value":"roles"}},{"kind":"Field","name":{"kind":"Name","value":"permissions"},"selectionSet":{"kind":"SelectionSet","selections":[{"kind":"Field","name":{"kind":"Name","value":"resource"}},{"kind":"Field","name":{"kind":"Name","value":"actions"}}]}}]}}]} as unknown as DocumentNode<ApiKeyWithKeyFragment, unknown>;
Expand Down
Loading