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
2 changes: 1 addition & 1 deletion api/.nvmrc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
18.3.0
18.5.0
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ vi.mock('fs/promises', () => ({
stat: vi.fn(async () => {
throw new Error('missing file');
}),
access: vi.fn(async () => {
throw new Error('missing file');
}),
}));

vi.mock('got', () => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ vi.mock('fs/promises', () => ({
stat: vi.fn(async () => {
throw new Error('missing file');
}),
access: vi.fn(async () => {
const fs = await vi.importActual<typeof import('fs')>('fs');
return fs.access;
}),
}));

vi.mock('got', () => ({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ vi.mock('fs/promises', () => ({
stat: vi.fn(async () => {
throw new Error('missing file');
}),
access: vi.fn(async () => {
throw new Error('missing file');
}),
}));

vi.mock('got', () => ({
Expand Down Expand Up @@ -118,7 +121,7 @@ test('Returns a pretty anonymised report by default', async () => {
ENVIRONMENT: THIS_WILL_BE_REPLACED_WHEN_BUILT
UNRAID_VERSION: unknown
UNRAID_API_VERSION: THIS_WILL_BE_REPLACED_WHEN_BUILT (stopped)
NODE_VERSION: v18.3.0
NODE_VERSION: v18.5.0
API_KEY: valid
MY_SERVERS: signed out
CLOUD: ok
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ vi.mock('fs/promises', () => ({
stat: vi.fn(async () => {
throw new Error('missing file');
}),
access: vi.fn(async () => {
throw new Error('missing file');
}),
}));

vi.mock('got', () => ({
Expand Down Expand Up @@ -137,7 +140,7 @@ test('Returns a pretty non-anonymised report with -v', async () => {
ENVIRONMENT: THIS_WILL_BE_REPLACED_WHEN_BUILT
UNRAID_VERSION: unknown
UNRAID_API_VERSION: THIS_WILL_BE_REPLACED_WHEN_BUILT (stopped)
NODE_VERSION: v18.3.0
NODE_VERSION: v18.5.0
API_KEY: valid
MY_SERVERS: signed out
CLOUD: ok [IP=52.40.54.163]
Expand Down Expand Up @@ -225,7 +228,7 @@ test('Returns a pretty non-anonymised report with -v [mothership restarting]', a
ENVIRONMENT: THIS_WILL_BE_REPLACED_WHEN_BUILT
UNRAID_VERSION: unknown
UNRAID_API_VERSION: THIS_WILL_BE_REPLACED_WHEN_BUILT (stopped)
NODE_VERSION: v18.3.0
NODE_VERSION: v18.5.0
API_KEY: valid
MY_SERVERS: signed out
CLOUD: Mothership is restarting
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ vi.mock('fs/promises', () => ({
stat: vi.fn(async () => {
throw new Error('missing file');
}),
access: vi.fn(async () => {
throw new Error('missing file');
}),
}));

vi.mock('got', () => ({
Expand Down Expand Up @@ -117,7 +120,7 @@ test('Returns a pretty non-anonymised report with -vv', async () => {
ENVIRONMENT: THIS_WILL_BE_REPLACED_WHEN_BUILT
UNRAID_VERSION: unknown
UNRAID_API_VERSION: THIS_WILL_BE_REPLACED_WHEN_BUILT (stopped)
NODE_VERSION: v18.3.0
NODE_VERSION: v18.5.0
API_KEY: valid
MY_SERVERS: signed out
CLOUD: ok [IP=52.40.54.163]
Expand Down
2 changes: 2 additions & 0 deletions api/src/__test__/store/modules/config.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ test('After init returns values from cfg file for all fields', async () => {
{
"api": {
"extraOrigins": "",
"version": "THIS_WILL_BE_REPLACED_WHEN_BUILT",
},
"local": {
"2Fa": "",
Expand Down Expand Up @@ -104,6 +105,7 @@ test('updateUserConfig merges in changes to current state', async () => {
{
"api": {
"extraOrigins": "",
"version": "THIS_WILL_BE_REPLACED_WHEN_BUILT",
},
"local": {
"2Fa": "",
Expand Down
43 changes: 34 additions & 9 deletions api/src/store/modules/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@ import { Serializer as IniSerializer } from 'multi-ini';
import { parseConfig } from '@app/core/utils/misc/parse-config';
import { MyServersConfig } from '@app/types/my-servers-config';
import { createAsyncThunk, createSlice, PayloadAction } from '@reduxjs/toolkit';
import { writeFile } from 'fs/promises';
import { access, writeFile } from 'fs/promises';
import merge from 'lodash.merge';
import { logger } from '@app/core/log';
import { FileLoadStatus } from '@app/store/types';
import { randomBytes } from 'crypto';
import { F_OK } from 'constants';

type SliceState = {
status: FileLoadStatus;
Expand Down Expand Up @@ -87,20 +88,44 @@ export const writeConfigToDisk = createAsyncThunk<void, string | undefined, { st
}
});

export const loadConfigFile = createAsyncThunk<MyServersConfig, string | undefined>('config/load-config-file', async filePath => {
const paths = await import('@app/store').then(_ => _.getters.paths());
const file = parseConfig<Partial<MyServersConfig>>({
filePath: filePath ?? paths['myservers-config'],
type LoadedConfig = Partial<MyServersConfig> & {
api: {
version: string;
};
upc: {
apikey: string;
};
notifier: {
apikey: string;
};
};

/**
* Load the myservers.cfg into the store.
*
* Note: If the file doesn't exist this will fallback to default values.
*/
export const loadConfigFile = createAsyncThunk<LoadedConfig, string | undefined>('config/load-config-file', async filePath => {
const store = await import('@app/store');
const paths = store.getters.paths();
const config = store.getters.config();
const path = filePath ?? paths['myservers-config'];
const fileExists = await access(path, F_OK).then(() => true).catch(() => false);
const file = fileExists ? parseConfig<Partial<MyServersConfig>>({
filePath: path,
type: 'ini',
});
}) : {};
return merge(file, {
api: {
version: config.version,
},
upc: {
apikey: file.upc?.apikey ?? `unupc_${randomBytes(58).toString('hex')}`.substring(0, 64),
apikey: file.upc?.apikey?.trim()?.length === 64 ? file.upc?.apikey : `unupc_${randomBytes(58).toString('hex')}`.substring(0, 64),
},
notifier: {
apikey: file.notifier?.apikey ?? `unnotify_${randomBytes(58).toString('hex')}`.substring(0, 64),
apikey: file.notifier?.apikey?.trim().length === 64 ? file.notifier?.apikey : `unnotify_${randomBytes(58).toString('hex')}`.substring(0, 64),
},
});
}) as LoadedConfig;
});

export const config = createSlice({
Expand Down