@chenbihao/pomasa-dashboard 1.0.2 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +99 -16
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -57,6 +57,7 @@ var init_paths = __esm({
57
57
  // server/setup.ts
58
58
  import express from "express";
59
59
  import cors from "cors";
60
+ import crypto from "crypto";
60
61
  import path7 from "path";
61
62
  import { fileURLToPath as fileURLToPath2 } from "url";
62
63
  import { createServer } from "http";
@@ -147,9 +148,23 @@ function spawnShell(ws, cwd, cols, rows) {
147
148
  }
148
149
  return spawnWithChildProcess(ws, cwd);
149
150
  }
150
- function setupTerminalWebSocket(server) {
151
+ function setupTerminalWebSocket(server, accessToken = null) {
151
152
  const wss = new WebSocketServer({ server, path: "/api/terminal" });
152
- wss.on("connection", (ws) => {
153
+ wss.on("connection", (ws, req) => {
154
+ if (accessToken) {
155
+ const cookieHeader = req.headers.cookie || "";
156
+ const cookies = {};
157
+ for (const pair of cookieHeader.split(";")) {
158
+ const [key, ...rest] = pair.split("=");
159
+ if (key && rest.length) {
160
+ cookies[key.trim()] = rest.join("=").trim();
161
+ }
162
+ }
163
+ if (cookies.pomasa_access !== accessToken) {
164
+ ws.close(4001, "Unauthorized");
165
+ return;
166
+ }
167
+ }
153
168
  let shellProcess = null;
154
169
  ws.on("message", (data) => {
155
170
  try {
@@ -975,16 +990,78 @@ var mas_default = router4;
975
990
 
976
991
  // server/setup.ts
977
992
  var __dirname2 = path7.dirname(fileURLToPath2(import.meta.url));
978
- function createApp() {
993
+ function generateToken() {
994
+ return crypto.randomBytes(24).toString("hex");
995
+ }
996
+ function denyAccess(req, res) {
997
+ const accept = req.headers.accept || "";
998
+ if (accept.includes("text/html")) {
999
+ res.status(401).send(`<!DOCTYPE html>
1000
+ <html><head><meta charset="utf-8"><title>POMASA Dashboard</title>
1001
+ <style>
1002
+ body { font-family: -apple-system, sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; margin: 0; background: #f5f5f5; }
1003
+ .box { text-align: center; padding: 2rem; background: #fff; border-radius: 8px; box-shadow: 0 2px 8px rgba(0,0,0,0.1); }
1004
+ h2 { color: #333; margin-bottom: 0.5rem; }
1005
+ p { color: #666; }
1006
+ code { background: #eee; padding: 2px 6px; border-radius: 3px; font-size: 0.9em; }
1007
+ </style></head>
1008
+ <body><div class="box">
1009
+ <h2>\u{1F512} \u9700\u8981\u8BBF\u95EE\u4EE4\u724C</h2>
1010
+ <p>\u8BF7\u4F7F\u7528\u542F\u52A8\u65F6\u8F93\u51FA\u7684\u5E26\u6709 <code>?token=...</code> \u7684 URL \u8BBF\u95EE</p>
1011
+ </div></body></html>`);
1012
+ } else {
1013
+ res.status(401).json({ error: "Unauthorized", message: "Access token required. Use ?token=... in URL." });
1014
+ }
1015
+ }
1016
+ function createApp(options = {}) {
1017
+ const { token: enableToken = true } = options;
979
1018
  const app = express();
980
1019
  const server = createServer(app);
1020
+ const accessToken = enableToken ? generateToken() : null;
981
1021
  app.use(cors());
982
1022
  app.use(express.json({ limit: "10mb" }));
1023
+ app.use((req, _res, next) => {
1024
+ if (!req.cookies) {
1025
+ req.cookies = {};
1026
+ const cookieHeader = req.headers.cookie;
1027
+ if (cookieHeader) {
1028
+ for (const pair of cookieHeader.split(";")) {
1029
+ const [key, ...rest] = pair.split("=");
1030
+ if (key && rest.length) {
1031
+ req.cookies[key.trim()] = rest.join("=").trim();
1032
+ }
1033
+ }
1034
+ }
1035
+ }
1036
+ next();
1037
+ });
1038
+ if (accessToken) {
1039
+ app.use((req, res, next) => {
1040
+ const queryToken = req.query.token;
1041
+ if (queryToken) {
1042
+ if (queryToken === accessToken) {
1043
+ res.cookie("pomasa_access", accessToken, {
1044
+ httpOnly: true,
1045
+ sameSite: "lax",
1046
+ path: "/"
1047
+ });
1048
+ const cleanUrl = req.path;
1049
+ return res.redirect(302, cleanUrl);
1050
+ }
1051
+ return denyAccess(req, res);
1052
+ }
1053
+ const cookieToken = req.cookies?.pomasa_access;
1054
+ if (cookieToken === accessToken) {
1055
+ return next();
1056
+ }
1057
+ return denyAccess(req, res);
1058
+ });
1059
+ }
983
1060
  app.use("/api/projects", projects_default);
984
1061
  app.use("/api/framework", framework_default);
985
1062
  app.use("/api/fs", filesystem_default);
986
1063
  app.use("/api/mas", mas_default);
987
- setupTerminalWebSocket(server);
1064
+ setupTerminalWebSocket(server, accessToken);
988
1065
  const distDir = path7.resolve(__dirname2, "../dist");
989
1066
  app.use(express.static(distDir));
990
1067
  app.use("/api", (_req, res) => {
@@ -993,25 +1070,22 @@ function createApp() {
993
1070
  app.get("/{*splat}", (_req, res) => {
994
1071
  res.sendFile(path7.join(distDir, "index.html"));
995
1072
  });
996
- return { app, server };
1073
+ return { app, server, accessToken };
997
1074
  }
998
- function startServer(port2, host2 = "127.0.0.1", maxRetries = 10) {
999
- const { server } = createApp();
1075
+ function startServer(port2, host2 = "0.0.0.0", options = {}, maxRetries = 10) {
1076
+ const { server, accessToken } = createApp(options);
1000
1077
  return new Promise((resolve, reject) => {
1001
1078
  server.on("error", (err) => {
1002
1079
  if (err.code === "EADDRINUSE" && maxRetries > 0) {
1003
1080
  console.log(`Port ${port2} in use, trying ${port2 + 1}...`);
1004
1081
  server.removeAllListeners("error");
1005
- startServer(port2 + 1, host2, maxRetries - 1).then(resolve).catch(reject);
1082
+ startServer(port2 + 1, host2, options, maxRetries).then(resolve).catch(reject);
1006
1083
  } else {
1007
1084
  reject(err);
1008
1085
  }
1009
1086
  });
1010
1087
  server.listen(port2, host2, () => {
1011
- console.log(`POMASA Dashboard running at http://localhost:${port2}`);
1012
- console.log(`API at http://localhost:${port2}/api`);
1013
- console.log(`WebSocket terminal at ws://localhost:${port2}/api/terminal`);
1014
- resolve(server);
1088
+ resolve({ server, accessToken });
1015
1089
  });
1016
1090
  });
1017
1091
  }
@@ -1030,20 +1104,29 @@ if (portArg !== -1 && process.argv[portArg + 1]) {
1030
1104
  } else if (process.env.PORT) {
1031
1105
  port = parseInt(process.env.PORT, 10);
1032
1106
  }
1033
- var host = "127.0.0.1";
1107
+ var host = "0.0.0.0";
1034
1108
  var hostArg = process.argv.indexOf("--host");
1035
1109
  if (hostArg !== -1 && process.argv[hostArg + 1]) {
1036
1110
  host = process.argv[hostArg + 1];
1037
1111
  } else if (process.env.HOST) {
1038
1112
  host = process.env.HOST;
1039
1113
  }
1040
- startServer(port, host).then(async () => {
1114
+ var noToken = process.argv.includes("--no-token") || !!process.env.NO_TOKEN;
1115
+ startServer(port, host, { token: !noToken }).then(async ({ accessToken }) => {
1041
1116
  const displayHost = host === "0.0.0.0" ? "localhost" : host;
1042
- const url = `http://${displayHost}:${port}`;
1117
+ const baseUrl = `http://${displayHost}:${port}`;
1118
+ const url = accessToken ? `${baseUrl}/?token=${accessToken}` : baseUrl;
1119
+ console.log(`POMASA Dashboard running at ${baseUrl}`);
1120
+ if (accessToken) {
1121
+ console.log(`Access token: ${accessToken}`);
1122
+ console.log(`Full URL (with token): ${url}`);
1123
+ }
1124
+ console.log(`API at ${baseUrl}/api`);
1125
+ console.log(`WebSocket terminal at ws://${displayHost}:${port}/api/terminal`);
1043
1126
  try {
1044
1127
  const open = (await import("open")).default;
1045
1128
  await open(url);
1046
- console.log(`Opened ${url} in browser`);
1129
+ console.log(`Opened in browser`);
1047
1130
  } catch {
1048
1131
  console.log(`Please open ${url} in your browser`);
1049
1132
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chenbihao/pomasa-dashboard",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "POMASA Multi-Agent System Dashboard",
5
5
  "repository": {
6
6
  "type": "git",