feat: remove sso user command

This commit is contained in:
Eli Bosley
2025-01-23 13:00:32 -05:00
parent 3867dfacb2
commit f30292484d
6 changed files with 84 additions and 9 deletions

View File

@@ -1,5 +1,4 @@
import { F_OK } from 'constants'; import { F_OK } from 'constants';
import { randomBytes } from 'crypto';
import { writeFileSync } from 'fs'; import { writeFileSync } from 'fs';
import { access } from 'fs/promises'; import { access } from 'fs/promises';
@@ -24,7 +23,6 @@ import { setupRemoteAccessThunk } from '@app/store/actions/setup-remote-access';
import { FileLoadStatus } from '@app/store/types'; import { FileLoadStatus } from '@app/store/types';
import { type RecursivePartial } from '@app/types'; import { type RecursivePartial } from '@app/types';
import { type MyServersConfig, type MyServersConfigMemory } from '@app/types/my-servers-config'; import { type MyServersConfig, type MyServersConfigMemory } from '@app/types/my-servers-config';
import { isFulfilled } from '@app/utils';
export type SliceState = { export type SliceState = {
status: FileLoadStatus; status: FileLoadStatus;
@@ -219,7 +217,18 @@ export const config = createSlice({
const stateAsArray = state.remote.ssoSubIds.split(','); const stateAsArray = state.remote.ssoSubIds.split(',');
stateAsArray.push(action.payload); stateAsArray.push(action.payload);
state.remote.ssoSubIds = stateAsArray.join(','); state.remote.ssoSubIds = stateAsArray.join(',');
} },
removeSsoUser(state, action: PayloadAction<string | null>) {
if (action.payload === null) {
state.remote.ssoSubIds = '';
return;
}
if (!state.remote.ssoSubIds.includes(action.payload)) {
return;
}
const stateAsArray = state.remote.ssoSubIds.split(',').filter((id) => id !== action.payload);
state.remote.ssoSubIds = stateAsArray.join(',');
},
}, },
extraReducers(builder) { extraReducers(builder) {
builder.addCase(loadConfigFile.pending, (state) => { builder.addCase(loadConfigFile.pending, (state) => {
@@ -300,12 +309,14 @@ export const {
setUpnpState, setUpnpState,
setWanPortToValue, setWanPortToValue,
setWanAccess, setWanAccess,
removeSsoUser,
} = actions; } = actions;
/** /**
* Actions that should trigger a flash write * Actions that should trigger a flash write
*/ */
export const configUpdateActionsFlash = isAnyOf( export const configUpdateActionsFlash = isAnyOf(
addSsoUser,
updateUserConfig, updateUserConfig,
updateAccessTokens, updateAccessTokens,
updateAllowedOrigins, updateAllowedOrigins,
@@ -314,7 +325,8 @@ export const configUpdateActionsFlash = isAnyOf(
setWanAccess, setWanAccess,
setupRemoteAccessThunk.fulfilled, setupRemoteAccessThunk.fulfilled,
logoutUser.fulfilled, logoutUser.fulfilled,
loginUser.fulfilled loginUser.fulfilled,
removeSsoUser
); );
/** /**

View File

@@ -17,11 +17,15 @@ import { StatusCommand } from '@app/unraid-api/cli/status.command';
import { StopCommand } from '@app/unraid-api/cli/stop.command'; import { StopCommand } from '@app/unraid-api/cli/stop.command';
import { SwitchEnvCommand } from '@app/unraid-api/cli/switch-env.command'; import { SwitchEnvCommand } from '@app/unraid-api/cli/switch-env.command';
import { VersionCommand } from '@app/unraid-api/cli/version.command'; import { VersionCommand } from '@app/unraid-api/cli/version.command';
import { RemoveSSOUserCommand } from '@app/unraid-api/cli/sso/remove-sso-user.command';
import { RemoveSSOUserQuestionSet } from '@app/unraid-api/cli/sso/remove-sso-user.questions';
@Module({ @Module({
providers: [ providers: [
AddSSOUserCommand, AddSSOUserCommand,
AddSSOUserQuestionSet, AddSSOUserQuestionSet,
RemoveSSOUserCommand,
RemoveSSOUserQuestionSet,
LogService, LogService,
StartCommand, StartCommand,
StopCommand, StopCommand,

View File

@@ -1,10 +1,6 @@
import { Question, QuestionSet } from 'nest-commander'; import { Question, QuestionSet } from 'nest-commander';
import { v4 as uuidv4 } from 'uuid'; import { v4 as uuidv4 } from 'uuid';
@QuestionSet({ name: 'add-user' }) @QuestionSet({ name: 'add-user' })
export class AddSSOUserQuestionSet { export class AddSSOUserQuestionSet {
static name = 'add-user'; static name = 'add-user';

View File

@@ -0,0 +1,34 @@
import { Injectable } from '@nestjs/common';
import { CommandRunner, InquirerService, Option, OptionChoiceFor, SubCommand } from 'nest-commander';
import { store } from '@app/store/index';
import { loadConfigFile, removeSsoUser } from '@app/store/modules/config';
import { LogService } from '@app/unraid-api/cli/log.service';
import { RemoveSSOUserQuestionSet } from '@app/unraid-api/cli/sso/remove-sso-user.questions';
interface RemoveSSOUserCommandOptions {
username: string;
}
@Injectable()
@SubCommand({
name: 'remove-user',
aliases: ['remove', 'r'],
description: 'Remove a user (or all users) from SSO',
})
export class RemoveSSOUserCommand extends CommandRunner {
constructor(
private readonly logger: LogService,
private readonly inquirerService: InquirerService
) {
super();
}
public async run(_input: string[], options: RemoveSSOUserCommandOptions): Promise<void> {
await store.dispatch(loadConfigFile());
console.log('options', options);
options = await this.inquirerService.prompt(RemoveSSOUserQuestionSet.name, options);
store.dispatch(removeSsoUser(options.username === 'all' ? null : options.username));
this.logger.info('User/s removed ' + options.username);
}
}

View File

@@ -0,0 +1,28 @@
import { ChoicesFor, Question, QuestionSet, } from 'nest-commander';
import { store } from '@app/store/index';
import { loadConfigFile } from '@app/store/modules/config';
@QuestionSet({ name: 'remove-user' })
export class RemoveSSOUserQuestionSet {
static name = 'remove-user';
@Question({
message: `Please select from the following list of users to remove from SSO, or enter all to remove all users from SSO.\n`,
name: 'username',
type: 'list',
})
parseName(val: string) {
return val;
}
@ChoicesFor({ name: 'username' })
async choicesForUsername() {
await store.dispatch(loadConfigFile());
const users = store.getState().config.remote.ssoSubIds.split(',').filter((user) => user !== '');
users.push('all');
return users;
}
}

View File

@@ -5,12 +5,13 @@ import { Command, CommandRunner } from 'nest-commander';
import { LogService } from '@app/unraid-api/cli/log.service'; import { LogService } from '@app/unraid-api/cli/log.service';
import { ValidateTokenCommand } from '@app/unraid-api/cli/sso/validate-token.command'; import { ValidateTokenCommand } from '@app/unraid-api/cli/sso/validate-token.command';
import { AddSSOUserCommand } from '@app/unraid-api/cli/sso/add-sso-user.command'; import { AddSSOUserCommand } from '@app/unraid-api/cli/sso/add-sso-user.command';
import { RemoveSSOUserCommand } from '@app/unraid-api/cli/sso/remove-sso-user.command';
@Injectable() @Injectable()
@Command({ @Command({
name: 'sso', name: 'sso',
description: 'Main Command to Configure / Validate SSO Tokens', description: 'Main Command to Configure / Validate SSO Tokens',
subCommands: [ValidateTokenCommand, AddSSOUserCommand], subCommands: [ValidateTokenCommand, AddSSOUserCommand, RemoveSSOUserCommand],
}) })
export class SSOCommand extends CommandRunner { export class SSOCommand extends CommandRunner {
constructor(private readonly logger: LogService) { constructor(private readonly logger: LogService) {