Refactor: daemon auth func

This commit is contained in:
unitwk 2024-02-23 15:06:42 +08:00
parent 774362c726
commit 7752ddff5f
6 changed files with 81 additions and 61 deletions

View File

@ -5,11 +5,10 @@ import { globalConfiguration } from "../entity/config";
import logger from "../service/log";
import RouterContext from "../entity/ctx";
import { IGNORE } from "../const";
import { LOGIN_BY_TOP_LEVEL, loginSuccessful } from "../service/mission_passport";
// latest verification time
const AUTH_TIMEOUT = 6000;
// authentication type identifier
const TOP_LEVEL = "TOP_LEVEL";
// Top-level authority authentication middleware (this is the first place for any authority authentication middleware)
routerApp.use(async (event, ctx, _, next) => {
@ -21,7 +20,7 @@ routerApp.use(async (event, ctx, _, next) => {
if (!ctx.session) throw new Error("Session does not exist in authentication middleware.");
if (
ctx.session.key === globalConfiguration.config.key &&
ctx.session.type === TOP_LEVEL &&
ctx.session.type === LOGIN_BY_TOP_LEVEL &&
ctx.session.login &&
ctx.session.id
) {
@ -37,19 +36,6 @@ routerApp.use(async (event, ctx, _, next) => {
return protocol.error(ctx, "error", IGNORE);
});
// log output middleware
// routerApp.use((event, ctx, data, next) => {
// try {
// const socket = ctx.socket;
// logger.info(`Received ${event} command from ${socket.id}(${socket.handshake.address}).`);
// logger.info(` - data: ${JSON.stringify(data)}.`);
// } catch (err) {
// logger.error("Logging error:", err);
// } finally {
// next();
// }
// });
// authentication controller
routerApp.on("auth", (ctx, data) => {
if (data === globalConfiguration.config.key) {
@ -82,12 +68,3 @@ routerApp.on("connection", (ctx) => {
}
}, AUTH_TIMEOUT);
});
// This function must be executed after successful login
function loginSuccessful(ctx: RouterContext, data: string) {
ctx.session.key = data;
ctx.session.login = true;
ctx.session.id = ctx.socket.id;
ctx.session.type = TOP_LEVEL;
return ctx.session;
}

View File

@ -1,11 +1,14 @@
import { $t } from "../i18n";
import * as protocol from "../service/protocol";
import { routerApp } from "../service/router";
import { missionPassport } from "../service/mission_passport";
import {
LOGIN_FROM_STREAM,
missionPassport,
streamLoginSuccessful
} from "../service/mission_passport";
import InstanceSubsystem from "../service/system_instance";
import logger from "../service/log";
import SendCommand from "../entity/commands/cmd";
import SendInput from "../entity/commands/input";
import { IGNORE } from "../const";
// Authorization authentication middleware
@ -14,7 +17,11 @@ routerApp.use(async (event, ctx, data, next) => {
if (event === "stream/auth") return next();
// Check other routes for data flow
if (event.startsWith("stream")) {
if (ctx.session.stream && ctx.session.stream.check === true && ctx.session.type === "STREAM") {
if (
ctx.session.stream &&
ctx.session?.stream?.check === true &&
ctx.session.type === LOGIN_FROM_STREAM
) {
return await next();
}
return protocol.error(ctx, "error", IGNORE);
@ -40,13 +47,8 @@ routerApp.on("stream/auth", (ctx, data) => {
address: ctx.socket.handshake.address
})
);
ctx.session.id = ctx.socket.id;
ctx.session.login = true;
ctx.session.type = "STREAM";
ctx.session.stream = {
check: true,
instanceUuid: instance.instanceUuid
};
streamLoginSuccessful(ctx, instance.instanceUuid);
// Start forwarding output stream data to this Socket
InstanceSubsystem.forward(instance.instanceUuid, ctx.socket);
@ -80,9 +82,8 @@ routerApp.on("stream/auth", (ctx, data) => {
// Get instance details
routerApp.on("stream/detail", async (ctx) => {
try {
const instanceUuid = ctx.session.stream.instanceUuid;
const instanceUuid = ctx.session?.stream?.instanceUuid;
const instance = InstanceSubsystem.getInstance(instanceUuid);
// const processInfo = await instance. forceExec(new ProcessInfoCommand());
protocol.response(ctx, {
instanceUuid: instance.instanceUuid,
started: instance.startCount,
@ -100,7 +101,7 @@ routerApp.on("stream/detail", async (ctx) => {
routerApp.on("stream/input", async (ctx, data) => {
try {
const command = data.command;
const instanceUuid = ctx.session.stream.instanceUuid;
const instanceUuid = ctx.session?.stream?.instanceUuid;
const instance = InstanceSubsystem.getInstance(instanceUuid);
await instance.exec(new SendCommand(command));
} catch (error) {
@ -113,7 +114,7 @@ routerApp.on("stream/input", async (ctx, data) => {
routerApp.on("stream/write", async (ctx, data) => {
try {
const buf = data.input;
const instanceUuid = ctx.session.stream.instanceUuid;
const instanceUuid = ctx.session?.stream?.instanceUuid;
const instance = InstanceSubsystem.getInstance(instanceUuid);
// run without command execution
if (instance.process) instance.process.write(buf);
@ -126,7 +127,7 @@ routerApp.on("stream/write", async (ctx, data) => {
// handle terminal resize
routerApp.on("stream/resize", async (ctx, data) => {
try {
const instanceUuid = ctx.session.stream.instanceUuid;
const instanceUuid = ctx.session?.stream?.instanceUuid;
const instance = InstanceSubsystem.getInstance(instanceUuid);
if (instance.config.processType === "docker") await instance.execPreset("resize", data);
} catch (error) {

View File

@ -1,3 +1,5 @@
import RouterContext from "../entity/ctx";
// task interface
interface IMission {
name: string;
@ -42,6 +44,37 @@ class MissionPassport {
}
}
const LOGIN_BY_TOP_LEVEL = "TOP_LEVEL";
const LOGIN_FROM_STREAM = "STREAM";
// This function must be executed after successful login
function loginSuccessful(ctx: RouterContext, key: string) {
ctx.session.key = key;
ctx.session.login = true;
ctx.session.id = ctx.socket.id;
ctx.session.type = LOGIN_BY_TOP_LEVEL;
ctx.session.stream = {};
return ctx.session;
}
function streamLoginSuccessful(ctx: RouterContext, instanceUuid: string) {
ctx.session.id = ctx.socket.id;
ctx.session.login = true;
ctx.session.type = LOGIN_FROM_STREAM;
ctx.session.stream = {
check: true,
instanceUuid
};
return ctx.session;
}
const missionPassport = new MissionPassport();
export { missionPassport, IMission };
export {
missionPassport,
IMission,
LOGIN_BY_TOP_LEVEL,
LOGIN_FROM_STREAM,
loginSuccessful,
streamLoginSuccessful
};

View File

@ -12,15 +12,15 @@ export function isNumberValidator(value: any) {
}
export function getValidatorErrorMsg(error: any, def: string = "") {
if (error === null || error === undefined || Object.keys(error).length === 0) {
return def;
}
if (error instanceof Error) {
return String(error.message);
if (error.message) {
return error.message;
}
if (error.errorFields instanceof Array) {
return String(error.errorFields[0]?.errors[0] || "");
}
if (error === null || error === undefined) {
return def;
}
return String(error);
}

View File

@ -33,6 +33,7 @@ import { INSTANCE_STATUS } from "@/types/const";
import { message } from "ant-design-vue";
import connectErrorImage from "@/assets/daemon_connection_error.png";
import { Terminal } from "xterm";
import { reportError } from "@/tools/validator";
const props = defineProps<{
card: LayoutCard;
@ -73,13 +74,17 @@ const quickOperations = computed(() =>
{
title: t("TXT_CODE_57245e94"),
icon: PlayCircleOutlined,
click: () => {
openInstance().execute({
params: {
uuid: instanceId || "",
daemonId: daemonId || ""
}
});
click: async () => {
try {
await openInstance().execute({
params: {
uuid: instanceId || "",
daemonId: daemonId || ""
}
});
} catch (error) {
reportError(error);
}
},
props: {},
condition: () => isStopped.value
@ -87,13 +92,17 @@ const quickOperations = computed(() =>
{
title: t("TXT_CODE_b1dedda3"),
icon: PauseCircleOutlined,
click: () => {
stopInstance().execute({
params: {
uuid: instanceId || "",
daemonId: daemonId || ""
}
});
click: async () => {
try {
await stopInstance().execute({
params: {
uuid: instanceId || "",
daemonId: daemonId || ""
}
});
} catch (error) {
reportError(error);
}
},
props: {
danger: true

View File

@ -306,7 +306,7 @@ defineExpose({
</a-typography-title>
<a-typography-paragraph>
<a-typography-text type="secondary" :class="!isPhone && 'two-line-height'">
{{ t("TXT_CODE_1e1dfbbe") }}
{{ t("不同的类型会在某些功能上有细微的差别") }}
</a-typography-text>
</a-typography-paragraph>
<a-select