mirror of
https://github.com/wavetermdev/waveterm.git
synced 2025-01-02 18:39:05 +01:00
simple authkey based authentication between electron and local-server
This commit is contained in:
parent
f0b9bc6eb8
commit
71980589bb
@ -60,7 +60,7 @@ node_modules/.bin/webpack --config webpack.electron.prod.js
|
||||
(cd ../mshell; GOOS=darwin GOARCH=arm64 go build -ldflags="-s -w" -o ../sh2/bin/mshell/mshell-v0.2-darwin.arm64 main-mshell.go)
|
||||
(cd ../mshell; GOOS=linux GOARCH=amd64 go build -ldflags="-s -w" -o ../sh2/bin/mshell/mshell-v0.2-linux.amd64 main-mshell.go)
|
||||
(cd ../mshell; GOOS=linux GOARCH=arm64 go build -ldflags="-s -w" -o ../sh2/bin/mshell/mshell-v0.2-linux.arm64 main-mshell.go)
|
||||
(cd ../sh2-server; GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w" -o ../sh2/bin/scripthaus-local-server cmd/main-server.go)
|
||||
(cd ../sh2-server; GOOS=darwin GOARCH=amd64 go build -ldflags="-s -w" -o ../sh2/bin/prompt-local-server cmd/main-server.go)
|
||||
node_modules/.bin/electron-forge make
|
||||
```
|
||||
|
||||
|
37
src/emain.ts
37
src/emain.ts
@ -9,12 +9,15 @@ import {handleJsonFetchResponse} from "./util";
|
||||
import * as winston from "winston";
|
||||
import * as util from "util";
|
||||
import {sprintf} from "sprintf-js";
|
||||
import {v4 as uuidv4} from "uuid";
|
||||
|
||||
const PromptAppPathVarName = "PROMPT_APP_PATH";
|
||||
const AuthKeyFile = "prompt.authkey";
|
||||
let isDev = (process.env.PROMPT_DEV != null);
|
||||
let scHome = getPromptHomeDir();
|
||||
ensureDir(scHome);
|
||||
let DistDir = (isDev ? "dist-dev" : "dist");
|
||||
let GlobalAuthKey = "";
|
||||
|
||||
// these are either "darwin/amd64" or "darwin/arm64"
|
||||
// normalize darwin/x64 to darwin/amd64 for GOARCH compatibility
|
||||
@ -94,6 +97,22 @@ function ensureDir(dir) {
|
||||
fs.mkdirSync(dir, {recursive: true, mode: 0o700});
|
||||
}
|
||||
|
||||
function readAuthKey() {
|
||||
let homeDir = getPromptHomeDir();
|
||||
let authKeyFileName = path.join(homeDir, AuthKeyFile);
|
||||
if (!fs.existsSync(authKeyFileName)) {
|
||||
let authKeyStr = String(uuidv4());
|
||||
fs.writeFileSync(authKeyFileName, authKeyStr, 0o600);
|
||||
return authKeyStr;
|
||||
}
|
||||
let authKeyData = fs.readFileSync(authKeyFileName);
|
||||
let authKeyStr = String(authKeyData);
|
||||
if (authKeyStr == null || authKeyStr == "") {
|
||||
throw new Error("cannot read authkey");
|
||||
}
|
||||
return authKeyStr.trim();
|
||||
}
|
||||
|
||||
let app = electron.app;
|
||||
app.setName("Prompt");
|
||||
|
||||
@ -248,7 +267,8 @@ function mainResizeHandler(e) {
|
||||
console.log("resize/move", win.getBounds());
|
||||
let winSize = {width: bounds.width, height: bounds.height, top: bounds.y, left: bounds.x};
|
||||
let url = "http://localhost:8080/api/set-winsize";
|
||||
fetch(url, {method: "post", body: JSON.stringify(winSize)}).then((resp) => handleJsonFetchResponse(url, resp)).catch((err) => {
|
||||
let fetchHeaders = getFetchHeaders();
|
||||
fetch(url, {method: "post", body: JSON.stringify(winSize), headers: fetchHeaders}).then((resp) => handleJsonFetchResponse(url, resp)).catch((err) => {
|
||||
console.log("error setting winsize", err)
|
||||
});
|
||||
}
|
||||
@ -302,6 +322,11 @@ electron.ipcMain.on("get-id", (event) => {
|
||||
return;
|
||||
});
|
||||
|
||||
electron.ipcMain.on("get-authkey", (event) => {
|
||||
event.returnValue = GlobalAuthKey;
|
||||
return;
|
||||
});
|
||||
|
||||
electron.ipcMain.on("local-server-status", (event) => {
|
||||
event.returnValue = (localServerProc != null);
|
||||
return;
|
||||
@ -327,9 +352,16 @@ function getContextMenu() : any {
|
||||
return menu;
|
||||
}
|
||||
|
||||
function getFetchHeaders() {
|
||||
return {
|
||||
"x-authkey": GlobalAuthKey,
|
||||
};
|
||||
}
|
||||
|
||||
function getClientData() {
|
||||
let url = "http://localhost:8080/api/get-client-data";
|
||||
return fetch(url).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
|
||||
let fetchHeaders = getFetchHeaders();
|
||||
return fetch(url, {headers: fetchHeaders}).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
|
||||
if (data == null) {
|
||||
return null;
|
||||
}
|
||||
@ -422,6 +454,7 @@ async function sleep(ms) {
|
||||
// ====== MAIN ====== //
|
||||
|
||||
(async () => {
|
||||
GlobalAuthKey = readAuthKey();
|
||||
try {
|
||||
await runLocalServer();
|
||||
}
|
||||
|
@ -298,7 +298,8 @@ class LineCmd extends React.Component<{sw : ScreenWindow, line : LineType, width
|
||||
this.rtnStateDiffFetched = true;
|
||||
let usp = new URLSearchParams({sessionid: line.sessionid, cmdid: line.cmdid});
|
||||
let url = "http://localhost:8080/api/rtnstate?" + usp.toString();
|
||||
fetch(url).then((resp) => {
|
||||
let fetchHeaders = GlobalModel.getFetchHeaders();
|
||||
fetch(url, {headers: fetchHeaders}).then((resp) => {
|
||||
if (!resp.ok) {
|
||||
throw new Error(sprintf("Bad fetch response for /api/rtnstate: %d %s", resp.status, resp.statusText));
|
||||
}
|
||||
|
17
src/model.ts
17
src/model.ts
@ -92,6 +92,7 @@ type KeyModsType = {
|
||||
|
||||
type ElectronApi = {
|
||||
getId : () => string,
|
||||
getAuthKey : () => string,
|
||||
getLocalServerStatus : () => boolean,
|
||||
restartLocalServer : () => boolean,
|
||||
onTCmd : (callback : (mods : KeyModsType) => void) => void,
|
||||
@ -1543,10 +1544,12 @@ class Model {
|
||||
debugCmds : number = 0;
|
||||
debugSW : OV<boolean> = mobx.observable.box(false);
|
||||
localServerRunning : OV<boolean>;
|
||||
authKey : string;
|
||||
|
||||
constructor() {
|
||||
this.clientId = getApi().getId();
|
||||
this.ws = new WSControl(this.clientId, (message : any) => this.runUpdate(message, false));
|
||||
this.authKey = getApi().getAuthKey();
|
||||
this.ws = new WSControl(this.clientId, this.authKey, (message : any) => this.runUpdate(message, false));
|
||||
this.ws.reconnect();
|
||||
this.inputModel = new InputModel();
|
||||
let isLocalServerRunning = getApi().getLocalServerStatus();
|
||||
@ -1565,6 +1568,12 @@ class Model {
|
||||
document.addEventListener("keydown", this.docKeyDownHandler.bind(this));
|
||||
}
|
||||
|
||||
getFetchHeaders() : Record<string, string> {
|
||||
return {
|
||||
"x-authkey": this.authKey,
|
||||
};
|
||||
}
|
||||
|
||||
docKeyDownHandler(e : any) {
|
||||
if (isModKeyPress(e)) {
|
||||
return;
|
||||
@ -1979,7 +1988,8 @@ class Model {
|
||||
}
|
||||
}
|
||||
let url = sprintf("http://localhost:8080/api/run-command");
|
||||
fetch(url, {method: "post", body: JSON.stringify(cmdPk)}).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
|
||||
let fetchHeaders = this.getFetchHeaders();
|
||||
fetch(url, {method: "post", body: JSON.stringify(cmdPk), headers: fetchHeaders}).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
|
||||
mobx.action(() => {
|
||||
let update = data.data;
|
||||
if (update != null) {
|
||||
@ -2062,7 +2072,8 @@ class Model {
|
||||
this.windows.set(newWin.sessionId + "/" + newWin.windowId, newWin);
|
||||
let usp = new URLSearchParams({sessionid: newWin.sessionId, windowid: newWin.windowId});
|
||||
let url = new URL("http://localhost:8080/api/get-window?" + usp.toString());
|
||||
fetch(url).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
|
||||
let fetchHeaders = GlobalModel.getFetchHeaders();
|
||||
fetch(url, {headers: fetchHeaders}).then((resp) => handleJsonFetchResponse(url, resp)).then((data) => {
|
||||
if (data.data == null) {
|
||||
console.log("null window returned from get-window");
|
||||
return;
|
||||
|
@ -2,6 +2,7 @@ let {contextBridge, ipcRenderer} = require("electron");
|
||||
|
||||
contextBridge.exposeInMainWorld("api", {
|
||||
getId: () => ipcRenderer.sendSync("get-id"),
|
||||
getAuthKey: () => ipcRenderer.sendSync("get-authkey"),
|
||||
getLocalServerStatus: () => ipcRenderer.sendSync("local-server-status"),
|
||||
restartLocalServer: () => ipcRenderer.sendSync("restart-server"),
|
||||
onTCmd: (callback) => ipcRenderer.on("t-cmd", callback),
|
||||
|
@ -4,7 +4,6 @@ import {createRoot} from 'react-dom/client';
|
||||
import {sprintf} from "sprintf-js";
|
||||
import {Terminal} from 'xterm';
|
||||
import {Main} from "./main";
|
||||
import {WSControl} from "./ws";
|
||||
import {GlobalModel} from "./model";
|
||||
import {v4 as uuidv4} from "uuid";
|
||||
|
||||
@ -43,4 +42,4 @@ document.addEventListener("DOMContentLoaded", () => {
|
||||
(window as any).mobx = mobx;
|
||||
(window as any).sprintf = sprintf;
|
||||
|
||||
console.log("SCRIPTHAUS", VERSION)
|
||||
console.log("PROMPT", VERSION)
|
||||
|
@ -245,7 +245,8 @@ class TermWrap {
|
||||
this.terminal.reset();
|
||||
let url = this._getReloadUrl();
|
||||
let ptyOffset = 0;
|
||||
fetch(url).then((resp) => {
|
||||
let fetchHeaders = GlobalModel.getFetchHeaders();
|
||||
fetch(url, {headers: fetchHeaders}).then((resp) => {
|
||||
if (!resp.ok) {
|
||||
mobx.action(() => { this.loadError.set(true); })();
|
||||
this.dataUpdates = [];
|
||||
|
@ -203,6 +203,7 @@ type WatchScreenPacketType = {
|
||||
sessionid : string,
|
||||
screenid : string,
|
||||
connect : boolean,
|
||||
authkey : string,
|
||||
};
|
||||
|
||||
type TermWinSize = {
|
||||
|
@ -15,10 +15,12 @@ class WSControl {
|
||||
watchSessionId : string = null;
|
||||
watchScreenId : string = null;
|
||||
wsLog : mobx.IObservableArray<string> = mobx.observable.array([], {name: "wsLog"})
|
||||
authKey : string;
|
||||
|
||||
constructor(clientId : string, messageCallback : (any) => void) {
|
||||
constructor(clientId : string, authKey : string, messageCallback : (any) => void) {
|
||||
this.messageCallback = messageCallback;
|
||||
this.clientId = clientId;
|
||||
this.authKey = authKey;
|
||||
this.open = mobx.observable.box(false, {name: "WSOpen"});
|
||||
setInterval(this.sendPing, 5000);
|
||||
}
|
||||
@ -174,7 +176,7 @@ class WSControl {
|
||||
}
|
||||
|
||||
sendWatchScreenPacket(connect : boolean) {
|
||||
let pk : WatchScreenPacketType = {"type": "watchscreen", connect: connect, sessionid: null, screenid: null};
|
||||
let pk : WatchScreenPacketType = {"type": "watchscreen", connect: connect, sessionid: null, screenid: null, authkey: this.authKey};
|
||||
if (this.watchSessionId != null) {
|
||||
pk.sessionid = this.watchSessionId;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user