chore: Fixes final changes.
This commit is contained in:
parent
19aadc20c0
commit
7fa789691c
2 changed files with 43 additions and 28 deletions
|
@ -4,35 +4,45 @@ import ssh2 from "ssh2";
|
||||||
import { readFromKeyboard } from "./libs/readFromKeyboard.js";
|
import { readFromKeyboard } from "./libs/readFromKeyboard.js";
|
||||||
import type { ClientKeys } from "./index.js";
|
import type { ClientKeys } from "./index.js";
|
||||||
|
|
||||||
export async function runCopyID(username: string, password: string, keys: ClientKeys, stream: ssh2.ServerChannel) {
|
export async function runCopyID(
|
||||||
stream.write("Hey there! I think you're using ssh-copy-id. If this is an error, you may close this terminal.\n");
|
username: string,
|
||||||
|
password: string,
|
||||||
|
keys: ClientKeys,
|
||||||
|
stream: ssh2.ServerChannel,
|
||||||
|
) {
|
||||||
|
stream.write(
|
||||||
|
"Hey there! I think you're using ssh-copy-id. If this is an error, you may close this terminal.\n",
|
||||||
|
);
|
||||||
|
|
||||||
stream.write("Please wait...\n");
|
stream.write("Please wait...\n");
|
||||||
|
|
||||||
const keyData = await readFromKeyboard(stream, true);
|
const keyData = await readFromKeyboard(stream, true);
|
||||||
stream.write("Parsing key...\n");
|
stream.write("Parsing key...\n");
|
||||||
|
|
||||||
const parsedKey = ssh2.utils.parseKey(keyData);
|
const parsedKey = ssh2.utils.parseKey(keyData);
|
||||||
|
|
||||||
if (parsedKey instanceof Error) {
|
if (parsedKey instanceof Error) {
|
||||||
stream.write(parsedKey.message + "\n");
|
stream.write(parsedKey.message + "\n");
|
||||||
return stream.close();
|
return stream.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.write("Passed checks. Writing changes...\n");
|
stream.write("Passed checks. Writing changes...\n");
|
||||||
|
|
||||||
keys.push({
|
keys.push({
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
publicKey: keyData
|
publicKey: keyData,
|
||||||
});
|
});
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await writeFile("../keys/clients.json", JSON.stringify(keys, null, 2));
|
await writeFile("../keys/clients.json", JSON.stringify(keys, null, 2));
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e);
|
console.log(e);
|
||||||
return stream.write("ERROR: Failed to save changes! If you're the administrator, view the console for details.\n");
|
return stream.write(
|
||||||
|
"ERROR: Failed to save changes! If you're the administrator, view the console for details.\n",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
stream.write("Success!\n");
|
stream.write("Success!\n");
|
||||||
return stream.close();
|
return stream.close();
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,16 +11,16 @@ import { commands } from "./commands.js";
|
||||||
import { runCopyID } from "./copyID.js";
|
import { runCopyID } from "./copyID.js";
|
||||||
|
|
||||||
export type ClientKeys = {
|
export type ClientKeys = {
|
||||||
publicKey: string,
|
publicKey: string;
|
||||||
username: string,
|
username: string;
|
||||||
password: string,
|
password: string;
|
||||||
}[];
|
}[];
|
||||||
|
|
||||||
function checkValue(input: Buffer, allowed: Buffer): boolean {
|
function checkValue(input: Buffer, allowed: Buffer): boolean {
|
||||||
const autoReject = (input.length !== allowed.length);
|
const autoReject = input.length !== allowed.length;
|
||||||
if (autoReject) allowed = input;
|
if (autoReject) allowed = input;
|
||||||
const isMatch = timingSafeEqual(input, allowed);
|
const isMatch = timingSafeEqual(input, allowed);
|
||||||
return (!autoReject && isMatch);
|
return !autoReject && isMatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
let serverKeyFile: Buffer | string | undefined;
|
let serverKeyFile: Buffer | string | undefined;
|
||||||
|
@ -43,7 +43,9 @@ try {
|
||||||
try {
|
try {
|
||||||
serverKeyFile = await readFile("../keys/host.key");
|
serverKeyFile = await readFile("../keys/host.key");
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("ERROR: Failed to read the host key file! Creating new keypair...");
|
console.log(
|
||||||
|
"ERROR: Failed to read the host key file! Creating new keypair...",
|
||||||
|
);
|
||||||
await mkdir("../keys").catch(() => null);
|
await mkdir("../keys").catch(() => null);
|
||||||
|
|
||||||
const keyPair: { private: string; public: string } = await new Promise(
|
const keyPair: { private: string; public: string } = await new Promise(
|
||||||
|
@ -60,11 +62,9 @@ try {
|
||||||
if (!serverKeyFile) throw new Error("Somehow failed to fetch the key file!");
|
if (!serverKeyFile) 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: [
|
hostKeys: [serverKeyFile],
|
||||||
serverKeyFile
|
|
||||||
],
|
|
||||||
|
|
||||||
banner: "NextNet-LOM (c) NextNet project et al."
|
banner: "NextNet-LOM (c) NextNet project et al.",
|
||||||
});
|
});
|
||||||
|
|
||||||
server.on("connection", client => {
|
server.on("connection", client => {
|
||||||
|
@ -95,12 +95,12 @@ server.on("connection", client => {
|
||||||
} else if (auth.method == "publickey") {
|
} else if (auth.method == "publickey") {
|
||||||
const userData = {
|
const userData = {
|
||||||
username: "",
|
username: "",
|
||||||
password: ""
|
password: "",
|
||||||
};
|
};
|
||||||
|
|
||||||
for (const rawKey of clientKeys) {
|
for (const rawKey of clientKeys) {
|
||||||
const key = ssh2.utils.parseKey(rawKey.publicKey);
|
const key = ssh2.utils.parseKey(rawKey.publicKey);
|
||||||
|
|
||||||
if (key instanceof Error) {
|
if (key instanceof Error) {
|
||||||
console.log(key);
|
console.log(key);
|
||||||
continue;
|
continue;
|
||||||
|
@ -109,25 +109,27 @@ server.on("connection", client => {
|
||||||
console.log(auth.signature, auth.blob);
|
console.log(auth.signature, auth.blob);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
rawKey.username == auth.username &&
|
(rawKey.username == auth.username &&
|
||||||
auth.key.algo == key.type &&
|
auth.key.algo == key.type &&
|
||||||
auth.key.data == key.getPublicSSH() &&
|
checkValue(auth.key.data, key.getPublicSSH())) ||
|
||||||
auth.signature && key.verify(auth.blob as Buffer, auth.signature, auth.key.algo)
|
(auth.signature &&
|
||||||
|
key.verify(auth.blob as Buffer, auth.signature, auth.key.algo))
|
||||||
) {
|
) {
|
||||||
console.log(" -- VERIFIED PUBLIC KEY --");
|
console.log(" -- VERIFIED PUBLIC KEY --");
|
||||||
userData.username = rawKey.username;
|
userData.username = rawKey.username;
|
||||||
userData.password = rawKey.password;
|
userData.password = rawKey.password;
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!userData.username || !userData.password) return auth.reject(["password", "publickey"]);
|
if (!userData.username || !userData.password)
|
||||||
|
return auth.reject(["password", "publickey"]);
|
||||||
|
|
||||||
const response = await axios.post("/api/v1/users/login", userData);
|
const response = await axios.post("/api/v1/users/login", userData);
|
||||||
|
|
||||||
if (response.status == 403) {
|
if (response.status == 403) {
|
||||||
return auth.reject(["password", "publickey"]);
|
return auth.reject(["password", "publickey"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
token = response.data.token;
|
token = response.data.token;
|
||||||
|
|
||||||
username = userData.username;
|
username = userData.username;
|
||||||
|
@ -146,7 +148,10 @@ server.on("connection", client => {
|
||||||
conn.on("exec", async (accept, reject, info) => {
|
conn.on("exec", async (accept, reject, info) => {
|
||||||
const stream = accept();
|
const stream = accept();
|
||||||
|
|
||||||
if (info.command.includes(".ssh/authorized_keys") && info.command.startsWith("exec sh -c")) {
|
if (
|
||||||
|
info.command.includes(".ssh/authorized_keys") &&
|
||||||
|
info.command.startsWith("exec sh -c")
|
||||||
|
) {
|
||||||
return await runCopyID(username, password, clientKeys, stream);
|
return await runCopyID(username, password, clientKeys, stream);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue