feature: Adds user command.
This commit is contained in:
parent
2f7f2088cd
commit
ee6556adb6
7 changed files with 157 additions and 6 deletions
|
@ -8,6 +8,7 @@ import type {
|
||||||
SessionToken,
|
SessionToken,
|
||||||
RouteOptions,
|
RouteOptions,
|
||||||
} from "./libs/types.js";
|
} from "./libs/types.js";
|
||||||
|
|
||||||
import type { BackendBaseClass } from "./backendimpl/base.js";
|
import type { BackendBaseClass } from "./backendimpl/base.js";
|
||||||
|
|
||||||
import { route as getPermissions } from "./routes/getPermissions.js";
|
import { route as getPermissions } from "./routes/getPermissions.js";
|
||||||
|
|
|
@ -60,6 +60,7 @@ export function route(routeOptions: RouteOptions) {
|
||||||
return {
|
return {
|
||||||
success: true,
|
success: true,
|
||||||
data: users.map(i => ({
|
data: users.map(i => ({
|
||||||
|
id: i.id,
|
||||||
name: i.name,
|
name: i.name,
|
||||||
email: i.email,
|
email: i.email,
|
||||||
isServiceAccount: i.isRootServiceAccount,
|
isServiceAccount: i.isRootServiceAccount,
|
||||||
|
|
|
@ -5,12 +5,14 @@ import { run as backends } from "./commands/backends.js";
|
||||||
import { run as users } from "./commands/users.js";
|
import { run as users } from "./commands/users.js";
|
||||||
|
|
||||||
export type PrintLine = (...str: any[]) => void;
|
export type PrintLine = (...str: any[]) => void;
|
||||||
|
export type KeyboardRead = (disableEcho?: boolean) => Promise<string>;
|
||||||
|
|
||||||
type Command = (
|
type Command = (
|
||||||
args: string[],
|
args: string[],
|
||||||
println: PrintLine,
|
println: PrintLine,
|
||||||
axios: Axios,
|
axios: Axios,
|
||||||
apiKey: string,
|
apiKey: string,
|
||||||
|
keyboardRead: KeyboardRead
|
||||||
) => Promise<void>;
|
) => Promise<void>;
|
||||||
|
|
||||||
type Commands = {
|
type Commands = {
|
||||||
|
|
|
@ -88,4 +88,5 @@ export async function run(
|
||||||
program.addCommand(lookupBackend);
|
program.addCommand(lookupBackend);
|
||||||
|
|
||||||
program.parse(argv);
|
program.parse(argv);
|
||||||
|
await new Promise((resolve) => program.onExit(resolve));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,29 @@
|
||||||
import type { Axios } from "axios";
|
import type { Axios } from "axios";
|
||||||
|
|
||||||
import { SSHCommand } from "../libs/patchCommander.js";
|
import { SSHCommand } from "../libs/patchCommander.js";
|
||||||
import type { PrintLine } from "../commands.js";
|
import type { PrintLine, KeyboardRead } from "../commands.js";
|
||||||
|
|
||||||
|
type UserLookupSuccess = {
|
||||||
|
success: true;
|
||||||
|
data: {
|
||||||
|
id: number,
|
||||||
|
isServiceAccount: boolean,
|
||||||
|
username: string,
|
||||||
|
name: string,
|
||||||
|
email: string
|
||||||
|
}[];
|
||||||
|
};
|
||||||
|
|
||||||
export async function run(
|
export async function run(
|
||||||
argv: string[],
|
argv: string[],
|
||||||
println: PrintLine,
|
println: PrintLine,
|
||||||
axios: Axios,
|
axios: Axios,
|
||||||
apiKey: string,
|
apiKey: string,
|
||||||
|
readKeyboard: KeyboardRead
|
||||||
) {
|
) {
|
||||||
const program = new SSHCommand(println);
|
const program = new SSHCommand(println);
|
||||||
program.description("Manages users for NextNet");
|
program.description("Manages users for NextNet");
|
||||||
program.version("v0.1.0-preprod");
|
program.version("v1.0.0-testing");
|
||||||
|
|
||||||
const addCommand = new SSHCommand(println, "add");
|
const addCommand = new SSHCommand(println, "add");
|
||||||
addCommand.description("Create a new user");
|
addCommand.description("Create a new user");
|
||||||
|
@ -25,21 +37,155 @@ export async function run(
|
||||||
"Asks for a password. Hides output",
|
"Asks for a password. Hides output",
|
||||||
);
|
);
|
||||||
|
|
||||||
|
addCommand.action(async(username: string, email: string, name: string, options: {
|
||||||
|
password?: string,
|
||||||
|
askPassword?: boolean
|
||||||
|
}) => {
|
||||||
|
if (!options.password && !options.askPassword) {
|
||||||
|
println("No password supplied, and askpass has not been supplied.\n");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let password: string = "";
|
||||||
|
|
||||||
|
if (options.askPassword) {
|
||||||
|
let passwordConfirmOne = "a";
|
||||||
|
let passwordConfirmTwo = "b";
|
||||||
|
|
||||||
|
while (passwordConfirmOne != passwordConfirmTwo) {
|
||||||
|
println("Password: ");
|
||||||
|
passwordConfirmOne = await readKeyboard(true);
|
||||||
|
|
||||||
|
println("\nConfirm password: ");
|
||||||
|
passwordConfirmTwo = await readKeyboard(true);
|
||||||
|
|
||||||
|
println("\n");
|
||||||
|
|
||||||
|
if (passwordConfirmOne != passwordConfirmTwo) {
|
||||||
|
println("Passwords do not match! Try again.\n\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
password = passwordConfirmOne;
|
||||||
|
} else {
|
||||||
|
// From the first check we do, we know this is safe (you MUST specify a password)
|
||||||
|
// @ts-ignore
|
||||||
|
password = options.password;
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await axios.post("/api/v1/users/create", {
|
||||||
|
name,
|
||||||
|
username,
|
||||||
|
email,
|
||||||
|
password
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status != 200) {
|
||||||
|
if (process.env.NODE_ENV != "production") console.log(response);
|
||||||
|
|
||||||
|
if (response.data.error) {
|
||||||
|
println(`Error: ${response.data.error}\n`);
|
||||||
|
} else {
|
||||||
|
println("Error requesting connections!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
println("User created successfully.\n");
|
||||||
|
})
|
||||||
|
|
||||||
const removeCommand = new SSHCommand(println, "rm");
|
const removeCommand = new SSHCommand(println, "rm");
|
||||||
removeCommand.description("Remove a user");
|
removeCommand.description("Remove a user");
|
||||||
removeCommand.argument("<uid>", "ID of user to remove");
|
removeCommand.argument("<uid>", "ID of user to remove");
|
||||||
|
|
||||||
|
removeCommand.action(async(uidStr: string) => {
|
||||||
|
const uid = parseInt(uidStr);
|
||||||
|
|
||||||
|
if (Number.isNaN(uid)) {
|
||||||
|
println("UID (%s) is not a number.\n", uid);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let response = await axios.post("/api/v1/users/remove", {
|
||||||
|
token: apiKey,
|
||||||
|
uid
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status != 200) {
|
||||||
|
if (process.env.NODE_ENV != "production") console.log(response);
|
||||||
|
|
||||||
|
if (response.data.error) {
|
||||||
|
println(`Error: ${response.data.error}\n`);
|
||||||
|
} else {
|
||||||
|
println("Error deleting user!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
println("User has been successfully deleted.\n");
|
||||||
|
});
|
||||||
|
|
||||||
const lookupCommand = new SSHCommand(println, "find");
|
const lookupCommand = new SSHCommand(println, "find");
|
||||||
lookupCommand.description("Find a user");
|
lookupCommand.description("Find a user");
|
||||||
lookupCommand.option("-i, --id <id>", "UID of User");
|
lookupCommand.option("-i, --id <id>", "UID of User");
|
||||||
lookupCommand.option("-n, --name <name>", "Name of User");
|
lookupCommand.option("-n, --name <name>", "Name of User");
|
||||||
lookupCommand.option("-u, --username <username>", "Username of User");
|
lookupCommand.option("-u, --username <username>", "Username of User");
|
||||||
lookupCommand.option("-e, --email <email>", "Email of User");
|
lookupCommand.option("-e, --email <email>", "Email of User");
|
||||||
lookupCommand.option("-s, --service", "The User is a service account");
|
lookupCommand.option("-s, --service", "The user is a service account");
|
||||||
|
|
||||||
|
lookupCommand.action(async(options) => {
|
||||||
|
// FIXME: redundant parseInt calls
|
||||||
|
|
||||||
|
if (options.id) {
|
||||||
|
const uid = parseInt(options.id);
|
||||||
|
|
||||||
|
if (Number.isNaN(uid)) {
|
||||||
|
println("UID (%s) is not a number.\n", uid);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const response = await axios.post("/api/v1/users/lookup", {
|
||||||
|
token: apiKey,
|
||||||
|
id: options.id ? parseInt(options.id) : undefined,
|
||||||
|
name: options.name,
|
||||||
|
username: options.username,
|
||||||
|
email: options.email,
|
||||||
|
service: Boolean(options.service)
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status != 200) {
|
||||||
|
if (process.env.NODE_ENV != "production") console.log(response);
|
||||||
|
|
||||||
|
if (response.data.error) {
|
||||||
|
println(`Error: ${response.data.error}\n`);
|
||||||
|
} else {
|
||||||
|
println("Error finding user!\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const { data }: UserLookupSuccess = response.data;
|
||||||
|
|
||||||
|
data.forEach((user) => {
|
||||||
|
println("UID: %s%s:\n", user.id, (user.isServiceAccount ? " (service)" : ""));
|
||||||
|
println("- Username: %s\n", user.username);
|
||||||
|
println("- Name: %s\n", user.name);
|
||||||
|
println("- Email: %s\n", user.email);
|
||||||
|
|
||||||
|
println("\n");
|
||||||
|
});
|
||||||
|
|
||||||
|
println("%s users found.\n", response.data.data.length);
|
||||||
|
})
|
||||||
|
|
||||||
program.addCommand(addCommand);
|
program.addCommand(addCommand);
|
||||||
program.addCommand(removeCommand);
|
program.addCommand(removeCommand);
|
||||||
program.addCommand(lookupCommand);
|
program.addCommand(lookupCommand);
|
||||||
|
|
||||||
program.parse(argv);
|
program.parse(argv);
|
||||||
|
await new Promise((resolve) => program.onExit(resolve));
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,8 +108,8 @@ server.on("connection", client => {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
await command.run(argv, println, axios, token);
|
await command.run(argv, println, axios, token, (disableEcho) => readFromKeyboard(stream, disableEcho));
|
||||||
stream.write(`~$ `);
|
stream.write("~$ ");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -25,7 +25,7 @@ export class SSHCommand extends Command {
|
||||||
this.configureOutput({
|
this.configureOutput({
|
||||||
writeOut: str => println(str),
|
writeOut: str => println(str),
|
||||||
writeErr: str => {
|
writeErr: str => {
|
||||||
if (str.includes("--help") || str.includes("-h")) return;
|
if (this.hasRecievedExitSignal) return;
|
||||||
println(str);
|
println(str);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue