Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
94 commits
Select commit Hold shift + click to select a range
83a8712
refactor:
Oct 28, 2024
08ebc9d
refactor: update basePath resolution for development and production
Oct 29, 2024
cafc7e3
refactor: add key folder with test key json file
Oct 29, 2024
4b2a4c0
refactor: update comment in env.development
Oct 29, 2024
68983f0
refactor: cleanup module imports
Oct 30, 2024
c09df28
refactor: integrate with header and cookie strategy, add key path, an…
Oct 30, 2024
071d727
refactor: revert myservers-base to original state
Oct 30, 2024
67ebd79
fix: use original configuration for super and key string
Oct 30, 2024
fed11a1
refactor: remove config from super
Oct 30, 2024
6ded943
test: add tests for auth service methods and update paths test
Oct 31, 2024
c940212
Merge branch 'main' into refactor/permissions-system-rewrite
Oct 31, 2024
22a1be3
test: add tests for the api-key service
Nov 1, 2024
978bdc4
test: add auth resolver tests
Nov 1, 2024
4e48056
refactor: remove un-needed api-key entity
Nov 1, 2024
1f81a0d
fix: fix linting error
Nov 1, 2024
e6f4194
refactor: add better error handling to header strategy and fix model …
Nov 1, 2024
62a3e9e
refactor: check for valid user in validateCookiesCasbin
Nov 1, 2024
fc25e1b
refactor: add additional check for existence of roles
Nov 1, 2024
42bd3df
refactor: add error handling to syncApiKeyRoles
Nov 1, 2024
ddd4ffd
refactor: add input validation to addRoleToApiKey and removeRoleToApiKey
Nov 4, 2024
c1247e4
refactor: add role validation and error handling to addRoleToUser
Nov 4, 2024
060d28c
refactor: Add input validation and duplicate checking for permission …
Nov 4, 2024
567ceb0
refactor: handle undefined roles in validateApiKeyCasbin method
Nov 4, 2024
d024bd4
refactor: add error handling to ensureUserRoles method
Nov 4, 2024
ba4d1f5
refactor: add consistent error handling to all menthods in auth.service
Nov 4, 2024
5348d75
refactor: update addRoleToApiKey and removeRoleFromApiKey to fix fail…
Nov 4, 2024
4bd1902
refactor: update error handling to propagate correctly
Nov 4, 2024
1163afd
refacter: remove key from ApiKey response and add ApiKeyWithSecret ty…
Nov 5, 2024
9686677
refactor: handle errors when reading the API key directory
Nov 5, 2024
24cff2c
refactor: use async file system methods in api-key.service and update…
Nov 5, 2024
61d1719
refactor: use GraphQLError instead of internalServerErrorException
Nov 5, 2024
c8840c6
fix: use correct import for import GraphQLError
Nov 5, 2024
c1c31f8
refactor: use named imports for fs
Nov 6, 2024
a9df921
test: fix the mocked named imports
Nov 6, 2024
ef3a230
refactor: implement atomic role synchronization
Nov 6, 2024
f235e4d
test: use beforeEach instead of beforeAll
Nov 6, 2024
549b429
refactor: differentiate between not found and read error in findById
Nov 6, 2024
d80de68
feat: add nestjs/throttler package and apply rate limit to auth resol…
Nov 6, 2024
fdc2d5d
test: add additional tests for file read errors
Nov 6, 2024
dc640a1
refactor: remove apikey.graphql and refactor for new api key types
Nov 7, 2024
a8627cc
refactor: improve ENOENT error detection
Nov 7, 2024
cd6b82f
refactor: add Roles enum to auth.graphql
Nov 7, 2024
058d312
refactor: address issue with enum values in tests and update findByKey
Nov 7, 2024
2074cba
refactor: update all tests to use Role enum and remove UsersService
Nov 7, 2024
0ba6d3c
refactor: add role enum to input types
Nov 7, 2024
20bcace
fix: use update instead of create for add permission resolver
Nov 7, 2024
467d679
refactor: add enums for possession, action, and resources
Nov 8, 2024
c2236b3
refactor: use mockResolvedValue for async getSessionUser method.
Nov 8, 2024
43d491c
refactor: add Action to AddPermissionInput
Nov 8, 2024
5b214e0
refactor: add security enhancements to api-key service and use ID in …
Nov 8, 2024
71f1725
Merge branch 'main' into refactor/permissions-system-rewrite
Nov 8, 2024
5eff4ee
fix: update header.strategy to work with config passed to super
Nov 8, 2024
124003e
refactor: sanitize error logging in header.strategy
Nov 8, 2024
2c65e4e
fix: get auth module back to iriginal state before conflict
Nov 8, 2024
17c3aaf
chore: add generated files including package lock
Nov 12, 2024
fd3c66d
Merge branch 'main' into refactor/permissions-system-rewrite
elibosley Nov 12, 2024
ab4f249
fix: remove unused reflector decorator
elibosley Nov 12, 2024
18864c5
feat: remove useGuard call
elibosley Nov 12, 2024
5f3272d
fix: remove ACGuard from auth module as global provider and remove u…
Nov 12, 2024
c03d724
fix: throw exceptions for failed validations in header.strategy
Nov 12, 2024
92f73bf
feat: add custom fastify throttler and use in app.module
Nov 13, 2024
598745f
fix: update vite.config and fastify imports to fix nestjs dependency …
Nov 13, 2024
98bfcf7
fix: issue with undefined user and permisisons not working
Nov 13, 2024
c314997
refactor: add possession to usePermissions decorator in auth resolver
Nov 14, 2024
cc65302
fix: update AuthZModule initializer to handle the action:possession f…
Nov 14, 2024
1321176
refactor: Improve user context extraction robustness
Nov 14, 2024
0cb3f46
refactor: Remove resolver-level error handling to maintain consistency
Nov 14, 2024
a373279
refactor: trim name and use in api ket create method
Nov 15, 2024
e17b9c0
refactor: use lowercase enums and builtins to match authz defaults an…
Nov 18, 2024
a755045
refactor: address comments and update tests to match changes
Nov 19, 2024
256cc74
refactor: replace UseRole with UsePermissions in resolvers
Nov 20, 2024
b0e07d4
refactor: address comments and create casbin service and module
Nov 21, 2024
144e487
refactor: standardize auth error handling, add casbin files and remov…
Nov 21, 2024
65c455a
refactor: update error handling for coderabbit suggestions
Nov 21, 2024
61dd6fd
refactor: remove redundant coderabbit suggestion
Nov 21, 2024
32f9dc5
fix: move catch block to correct location
Nov 22, 2024
7fdd132
refactor: add sanitization, remove included string to handleAuthError…
Nov 22, 2024
a88c68e
Merge branch 'main' into refactor/permissions-system-rewrite
Nov 22, 2024
bb9b3f3
feat: Add local API key listener module
Nov 26, 2024
72bd918
feat: Add local API key listener with axios HTTP request to NestJS se…
Nov 26, 2024
208e5d5
refactor: add localApiKey creation during connect sign in and add lis…
Dec 2, 2024
74f3e6d
test: update tests with new localApiKey property
Dec 3, 2024
1602b0a
test: add localApiKey property to config test
Dec 3, 2024
5a24bde
refactor: add possession own to connect role
Dec 3, 2024
4bf4111
refactor: utilize the updateObject function within handleAuthError
Dec 4, 2024
5f19c5a
refactor: ensure localApiKey is valid before proceeding
Dec 5, 2024
51a08de
refactor: add input sanitization for the name parameter
Dec 5, 2024
dfe7a70
refactor: address code review comments
Dec 6, 2024
da4a2f3
fix: update own possession to any to work around nestjs-authz bug
Dec 13, 2024
8566a29
fix: add development env check to key validation in listener and add …
Dec 13, 2024
770e982
refactor: check for exsisting localApiKey to prevent multiple key cre…
Dec 16, 2024
4e5e50f
Merge branch 'main' into refactor/permissions-system-rewrite
Dec 16, 2024
7d525bf
fix: remove extra imports from conflict
Dec 16, 2024
86f0b32
fix: use appropriate error type and use structuredClone in utilty met…
Dec 16, 2024
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ typings/

# Visual Studio Code workspace
.vscode/sftp.json
.history/

# OSX
.DS_Store
Expand Down
1 change: 1 addition & 0 deletions api/.env.development
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
PATHS_UNRAID_DATA=./dev/data # Where we store plugin data (e.g. permissions.json)
PATHS_STATES=./dev/states # Where .ini files live (e.g. vars.ini)
PATHS_AUTH_KEY=./dev/keys # Auth key directory
PATHS_DYNAMIX_BASE=./dev/dynamix # Dynamix's data directory
PATHS_DYNAMIX_CONFIG_DEFAULT=./dev/dynamix/default.cfg # Dynamix's default config file, which ships with unraid
PATHS_DYNAMIX_CONFIG=./dev/dynamix/dynamix.cfg # Dynamix's config file
Expand Down
8 changes: 8 additions & 0 deletions api/dev/keys/10f356da-1e9e-43b8-9028-a26a645539a6.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"id": "10f356da-1e9e-43b8-9028-a26a645539a6",
"key": "73717ca0-8c15-40b9-bcca-8d85656d1438",
"name": "Test API Key",
"description": "Testing API key creation",
"roles": ["guest", "upc"],
"createdAt": "2024-10-29T19:59:12.569Z"
}
71 changes: 46 additions & 25 deletions api/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
"@nestjs/passport": "^10.0.3",
"@nestjs/platform-fastify": "^10.4.7",
"@nestjs/schedule": "^4.1.1",
"@nestjs/throttler": "^6.2.1",
"@reduxjs/toolkit": "^2.3.0",
"@reflet/cron": "^1.3.1",
"@runonflux/nat-upnp": "^1.0.2",
Expand All @@ -64,6 +65,7 @@
"bytes": "^3.1.2",
"cacheable-lookup": "^7.0.0",
"camelcase-keys": "^9.1.3",
"casbin": "^5.32.0",
"catch-exit": "^1.2.2",
"chokidar": "^4.0.1",
"cli-table": "^0.3.11",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import 'reflect-metadata';

import { test, expect } from 'vitest';
import { cloneDeep } from 'lodash-es';
import { expect, test } from 'vitest';

import { getWriteableConfig } from '@app/core/utils/files/config-file-normalizer';
import { initialState } from '@app/store/modules/config';
import { cloneDeep } from 'lodash-es';

test('it creates a FLASH config with NO OPTIONAL values', () => {
const basicConfig = initialState;
Expand All @@ -25,6 +26,7 @@ test('it creates a FLASH config with NO OPTIONAL values', () => {
"dynamicRemoteAccessType": "DISABLED",
"email": "",
"idtoken": "",
"localApiKey": "",
"refreshtoken": "",
"regWizTime": "",
"username": "",
Expand Down Expand Up @@ -62,6 +64,7 @@ test('it creates a MEMORY config with NO OPTIONAL values', () => {
"dynamicRemoteAccessType": "DISABLED",
"email": "",
"idtoken": "",
"localApiKey": "",
"refreshtoken": "",
"regWizTime": "",
"username": "",
Expand Down Expand Up @@ -105,6 +108,7 @@ test('it creates a FLASH config with OPTIONAL values', () => {
"dynamicRemoteAccessType": "DISABLED",
"email": "",
"idtoken": "",
"localApiKey": "",
"refreshtoken": "",
"regWizTime": "",
"upnpEnabled": "yes",
Expand Down Expand Up @@ -154,6 +158,7 @@ test('it creates a MEMORY config with OPTIONAL values', () => {
"dynamicRemoteAccessType": "DISABLED",
"email": "",
"idtoken": "",
"localApiKey": "",
"refreshtoken": "",
"regWizTime": "",
"upnpEnabled": "yes",
Expand Down
10 changes: 6 additions & 4 deletions api/src/__test__/store/modules/config.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { test, expect } from 'vitest';
import { expect, test } from 'vitest';

import { store } from '@app/store';

test('Before init returns default values for all fields', async () => {
Expand Down Expand Up @@ -30,6 +31,7 @@ test('Before init returns default values for all fields', async () => {
"dynamicRemoteAccessType": "DISABLED",
"email": "",
"idtoken": "",
"localApiKey": "",
"refreshtoken": "",
"regWizTime": "",
"upnpEnabled": "",
Expand Down Expand Up @@ -80,6 +82,7 @@ test('After init returns values from cfg file for all fields', async () => {
dynamicRemoteAccessType: 'DISABLED',
email: 'test@example.com',
idtoken: '',
localApiKey: '',
refreshtoken: '',
regWizTime: '1611175408732_0951-1653-3509-FBA155FA23C0',
upnpEnabled: 'no',
Expand All @@ -96,9 +99,7 @@ test('After init returns values from cfg file for all fields', async () => {
});

test('updateUserConfig merges in changes to current state', async () => {
const { loadConfigFile, updateUserConfig } = await import(
'@app/store/modules/config'
);
const { loadConfigFile, updateUserConfig } = await import('@app/store/modules/config');

// Load cfg into store
await store.dispatch(loadConfigFile());
Expand Down Expand Up @@ -138,6 +139,7 @@ test('updateUserConfig merges in changes to current state', async () => {
dynamicRemoteAccessType: 'DISABLED',
email: 'test@example.com',
idtoken: '',
localApiKey: '',
refreshtoken: '',
regWizTime: '1611175408732_0951-1653-3509-FBA155FA23C0',
upnpEnabled: 'no',
Expand Down
5 changes: 3 additions & 2 deletions api/src/__test__/store/modules/paths.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ import { expect, test } from 'vitest';
import { store } from '@app/store';

test('Returns paths', async () => {
const { paths } = store.getState();
expect(Object.keys(paths)).toMatchInlineSnapshot(`
const { paths } = store.getState();
expect(Object.keys(paths)).toMatchInlineSnapshot(`
[
"core",
"unraid-api-base",
Expand All @@ -26,6 +26,7 @@ test('Returns paths', async () => {
"log-base",
"var-run",
"auth-sessions",
"auth-keys",
]
`);
});
31 changes: 15 additions & 16 deletions api/src/cli/commands/report.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,21 @@
import ipRegex from 'ip-regex';
import { stdout } from 'process';
import readLine from 'readline';

import { ApolloClient, ApolloQueryResult, NormalizedCacheObject } from '@apollo/client/core/index.js';
import ipRegex from 'ip-regex';

import { setEnv } from '@app/cli/set-env';
import { isUnraidApiRunning } from '@app/core/utils/pm2/unraid-api-running';
import { cliLogger } from '@app/core/log';
import { isUnraidApiRunning } from '@app/core/utils/pm2/unraid-api-running';
import { API_VERSION } from '@app/environment';
import { MinigraphStatus } from '@app/graphql/generated/api/types';
import { getters, store } from '@app/store';
import { stdout } from 'process';
import { loadConfigFile } from '@app/store/modules/config';
import { getApiApolloClient } from '../../graphql/client/api/get-api-client';
import {
getCloudDocument,
getServersDocument,
type getServersQuery,
type getCloudQuery,
} from '../../graphql/generated/api/operations';
import { MinigraphStatus } from '@app/graphql/generated/api/types';
import { API_VERSION } from '@app/environment';
import { loadStateFiles } from '@app/store/modules/emhttp';
import { ApolloClient, ApolloQueryResult, NormalizedCacheObject } from '@apollo/client/core/index.js';

import type { getCloudQuery, getServersQuery } from '../../graphql/generated/api/operations';
import { getApiApolloClient } from '../../graphql/client/api/get-api-client';
import { getCloudDocument, getServersDocument } from '../../graphql/generated/api/operations';

type CloudQueryResult = NonNullable<ApolloQueryResult<getCloudQuery>['data']['cloud']>;
type ServersQueryResultServer = NonNullable<ApolloQueryResult<getServersQuery>['data']['servers']>[0];
Expand Down Expand Up @@ -263,7 +262,7 @@ export const report = async (...argv: string[]) => {
const { config, emhttp } = store.getState();
if (!config.upc.apikey) throw new Error('Missing UPC API key');

const client = getApiApolloClient({ upcApiKey: config.upc.apikey });
const client = getApiApolloClient({ localApiKey: config.remote.localApiKey || '' });
// Fetch the cloud endpoint
const cloud = await getCloudData(client);

Expand All @@ -288,7 +287,7 @@ export const report = async (...argv: string[]) => {
environment: process.env.ENVIRONMENT ?? 'THIS_WILL_BE_REPLACED_WHEN_BUILT',
nodeVersion: process.version,
},
apiKey: isApiKeyValid ? 'valid' : cloud?.apiKey.error ?? 'invalid',
apiKey: isApiKeyValid ? 'valid' : (cloud?.apiKey.error ?? 'invalid'),
...(servers ? { servers } : {}),
myServers: {
status: config?.remote?.username ? 'authenticated' : 'signed out',
Expand All @@ -304,7 +303,7 @@ export const report = async (...argv: string[]) => {
status: cloud?.minigraphql.status ?? MinigraphStatus.PRE_INIT,
timeout: cloud?.minigraphql.timeout ?? null,
error:
cloud?.minigraphql.error ?? !cloud?.minigraphql.status ? 'API Disconnected' : null,
(cloud?.minigraphql.error ?? !cloud?.minigraphql.status) ? 'API Disconnected' : null,
},
cloud: {
status: cloud?.cloud.status ?? 'error',
Expand Down
1 change: 1 addition & 0 deletions api/src/core/utils/files/config-file-normalizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ export const getWriteableConfig = <T extends ConfigType>(
wanport: remote.wanport ?? initialState.remote.wanport,
...(remote.upnpEnabled ? { upnpEnabled: remote.upnpEnabled } : {}),
apikey: remote.apikey ?? initialState.remote.apikey,
localApiKey: remote.localApiKey ?? initialState.remote.localApiKey,
email: remote.email ?? initialState.remote.email,
username: remote.username ?? initialState.remote.username,
avatar: remote.avatar ?? initialState.remote.avatar,
Expand Down
Loading
Loading