Add single use auth for terminal connect

This commit is contained in:
zhengyi59 2024-06-23 15:34:05 +08:00
parent c935c71cc2
commit 69fb282468
8 changed files with 114 additions and 6 deletions

View File

@ -12,13 +12,15 @@
"@homebridge/node-pty-prebuilt-multiarch": "^0.11.14",
"@types/koa": "^2.15.0",
"@types/koa-router": "^7.4.8",
"@types/uuid": "^10.0.0",
"events": "^3.3.0",
"koa": "^2.15.3",
"koa-body": "^6.0.1",
"koa-router": "^12.0.1",
"socket.io": "^4.7.5",
"systeminformation": "^5.22.11",
"typescript": "^5.4.5"
"typescript": "^5.4.5",
"uuid": "^10.0.0"
},
"devDependencies": {
"@types/node": "^20.14.6",

View File

@ -14,6 +14,9 @@ dependencies:
'@types/koa-router':
specifier: ^7.4.8
version: 7.4.8
'@types/uuid':
specifier: ^10.0.0
version: 10.0.0
events:
specifier: ^3.3.0
version: 3.3.0
@ -35,6 +38,9 @@ dependencies:
typescript:
specifier: ^5.4.5
version: 5.5.2
uuid:
specifier: ^10.0.0
version: 10.0.0
devDependencies:
'@types/node':
@ -246,6 +252,10 @@ packages:
'@types/send': 0.17.4
dev: false
/@types/uuid@10.0.0:
resolution: {integrity: sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==}
dev: false
/accepts@1.3.8:
resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==}
engines: {node: '>= 0.6'}
@ -1106,6 +1116,11 @@ packages:
resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==}
dev: false
/uuid@10.0.0:
resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==}
hasBin: true
dev: false
/v8-compile-cache-lib@3.0.1:
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
dev: true

View File

@ -0,0 +1,7 @@
import { response, routerApp } from "../service/router";
import SingleUseToken from "../service/single-use-token";
routerApp.on("auth/single-token", async (ctx, data) => {
const stringPromise = await SingleUseToken.createToken(data.permission, data.info);
response(ctx, stringPromise)
})

View File

@ -3,6 +3,7 @@ import { getSystemInfo } from "../service/system_info";
import { NodeInfo } from "../../../common/types/daemon";
import * as pty from "@homebridge/node-pty-prebuilt-multiarch";
import SingleUseToken from "../service/single-use-token";
routerApp.on("info", async (ctx, data) => {
@ -20,8 +21,27 @@ routerApp.on("info", async (ctx, data) => {
routerApp.on("terminal", async (ctx, data) => {
console.log("terminal data: ", data)
const token = await SingleUseToken.auth(data, "terminal")
if (!token) {
ctx.socket.disconnect();
return
}
let cmd = "";
let args = [];
// Start Command
if (token.info === "bash") {
cmd = "/bin/bash";
args = ["--login"]
} else {
ctx.socket.disconnect();
return
}
// create a process and send to client
const ptyProcess = pty.spawn("/bin/bash", ["--login"], {
const ptyProcess = pty.spawn(cmd, args, {
cols: 80,
rows: 24,
cwd: process.env.HOME, // 或你希望的起始目录

View File

@ -58,4 +58,5 @@ export function response(ctx: RouterCtx, data: any) {
ctx.socket.emit(ctx.event, respPacket);
}
import "../routers/overview"
import "../routers/overview"
import "../routers/auth-router"

View File

@ -0,0 +1,57 @@
import { v4 as uuidv4 } from "uuid";
type SingleToken = {
token: string;
expire: number;
permission: string;
info: string;
}
class SingleUseToken {
private readonly tokenList: Map<string, SingleToken>;
constructor() {
this.tokenList = new Map();
}
async addToken(token: string, expire: number, permission: string, info: string) {
this.tokenList.set(token, {
token: token,
expire: expire,
permission: permission,
info: info
});
}
async createToken(permission: string, info: string) {
const token = uuidv4().replace(/-/g, "");
const expire = Date.now() + 1000 * 60 * 60;
await this.addToken(token, expire, permission, info);
return token;
}
async auth(token: string, permission: string) {
const payload = this.tokenList.get(token);
if (payload) {
// Expire time
if (payload.expire < Date.now()) {
await this.removeToken(token);
return null;
}
// Permission
if (payload.permission === permission) {
await this.removeToken(token);
return payload;
}
return null;
} else {
return null;
}
}
async removeToken(token: string) {
this.tokenList.delete(token);
}
}
export default new SingleUseToken();

View File

@ -1,5 +1,6 @@
import Router from "koa-router";
import RemoteManage from "../services/remote_manage";
import RemoteRequest from "../services/remote_request";
const terminalRouter = new Router({
prefix: "/terminal"
@ -7,10 +8,15 @@ const terminalRouter = new Router({
terminalRouter.get("/:endpoint/:name", async (ctx) => {
const server = await RemoteManage.getServer(ctx.params.endpoint);
// Get Token
if (server) {
const resp = await new RemoteRequest(server).request("auth/single-token", {
permission: "terminal",
info: "bash"
})
ctx.body = {
socket: server.getSocketUrl(),
token: "1234567890"
token: resp
}
} else {
ctx.status = 404;

View File

@ -47,8 +47,8 @@ const BashTerminalModal: React.FC<BashTerminalModalProps> = (props) => {
terminal?.reset();
// auth
socket?.emit("terminal", {
uuid: "34567890",
data: {}
uuid: "",
data: res.data.token
})
})