feature: Adds exec support.

This also lets us prepare for support for ssh-copy-id.
This commit is contained in:
greysoh 2024-05-09 13:19:56 -04:00
parent 95b79ca364
commit 47b707e8cd
Signed by: imterah
GPG key ID: 8FA7DD57BA6CEA37
2 changed files with 57 additions and 13 deletions

View file

@ -9,6 +9,7 @@ import type {
ParameterReturnedValue, ParameterReturnedValue,
BackendBaseClass, BackendBaseClass,
} from "../base.js"; } from "../base.js";
import { generateRandomData } from "../../libs/generateRandom.js"; import { generateRandomData } from "../../libs/generateRandom.js";
import { requestHandler } from "./socket.js"; import { requestHandler } from "./socket.js";
import { route } from "./routes.js"; import { route } from "./routes.js";

View file

@ -39,17 +39,17 @@ if (!keyFile) throw new Error("Somehow failed to fetch the key file!");
const server: ssh2.Server = new ssh2.Server({ const server: ssh2.Server = new ssh2.Server({
hostKeys: [keyFile], hostKeys: [keyFile],
banner: "NextNet-LOM (c) NextNet project et al."
banner: "NextNet-LOM (c) NextNet project et al.",
greeting: "NextNet LOM (beta)",
}); });
server.on("connection", client => { server.on("connection", client => {
let token: string = ""; let token: string = "";
client.on("authentication", async auth => { let username: string = "";
if (auth.method != "password") return auth.reject(["password"]); // We need to know the password to auth with the API let password: string = "";
client.on("authentication", async auth => {
if (auth.method == "password") {
const response = await axios.post("/api/v1/users/login", { const response = await axios.post("/api/v1/users/login", {
username: auth.username, username: auth.username,
password: auth.password, password: auth.password,
@ -60,13 +60,56 @@ server.on("connection", client => {
} }
token = response.data.token; token = response.data.token;
username = auth.username;
password = auth.password;
auth.accept(); auth.accept();
} else if (auth.method == "publickey") {
return auth.reject();
// todo
} else {
return auth.reject(["password", "publickey"]);
}
}); });
client.on("ready", () => { client.on("ready", () => {
client.on("session", (accept, reject) => { client.on("session", (accept, reject) => {
const conn = accept(); const conn = accept();
conn.on("exec", async (accept, reject, info) => {
const stream = accept();
// Matches on ; and &&
const commandsRecv = info.command.split(/;|&&/).map((i) => i.trim());
function println(...data: any[]) {
stream.write(format(...data).replaceAll("\n", "\r\n"));
};
for (const command of commandsRecv) {
const argv = parseArgsStringToArgv(command);
if (argv[0] == "exit") {
stream.close();
} else {
const command = commands.find(i => i.name == argv[0]);
if (!command) {
stream.write(
`Unknown command ${argv[0]}.\r\n`,
);
continue;
}
await command.run(argv, println, axios, token, (disableEcho) => readFromKeyboard(stream, disableEcho));
}
}
return stream.close();
});
// We're dumb. We don't really care. // We're dumb. We don't really care.
conn.on("pty", accept => accept()); conn.on("pty", accept => accept());
conn.on("window-change", accept => { conn.on("window-change", accept => {