levix-bot 3.0.0-beta → 3.1.1-beta
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.
- package/app.cjs +6 -0
- package/package.json +1 -1
- package/src/bootstrap/panel.js +30 -6
- package/src/index.js +8 -1
- package/src/utils/requestOrigin.cjs +4 -1
package/app.cjs
CHANGED
|
@@ -292,6 +292,12 @@ app.get("/", noStore, (req, res) => {
|
|
|
292
292
|
return res.render("login", { error: null });
|
|
293
293
|
});
|
|
294
294
|
|
|
295
|
+
app.get("/login", noStore, (req, res) => {
|
|
296
|
+
if (!secrets.hasDashboardPassword()) return res.redirect("/setup");
|
|
297
|
+
if (req.session.loggedIn) return res.redirect("/");
|
|
298
|
+
return res.render("login", { error: null });
|
|
299
|
+
});
|
|
300
|
+
|
|
295
301
|
app.post("/login", (req, res, next) => {
|
|
296
302
|
if (!secrets.hasDashboardPassword()) return res.redirect("/setup");
|
|
297
303
|
|
package/package.json
CHANGED
package/src/bootstrap/panel.js
CHANGED
|
@@ -7,10 +7,21 @@
|
|
|
7
7
|
import { createRequire } from "module";
|
|
8
8
|
|
|
9
9
|
const require = createRequire(import.meta.url);
|
|
10
|
+
const fs = require("node:fs");
|
|
10
11
|
const logger = require("../utils/logger.cjs");
|
|
11
12
|
const settings = require("../config/settings.cjs");
|
|
13
|
+
const paths = require("../config/paths.cjs");
|
|
12
14
|
const { attach } = require("./events.cjs");
|
|
13
15
|
|
|
16
|
+
/** Unix socket path for the Android host. Bionic Node cannot bind TCP. */
|
|
17
|
+
export function androidPanelSocketPath() {
|
|
18
|
+
return paths.dataPath("panel.sock");
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export function isAndroidHost() {
|
|
22
|
+
return process.env.LEVIX_ANDROID === "1";
|
|
23
|
+
}
|
|
24
|
+
|
|
14
25
|
/**
|
|
15
26
|
* Start the panel and bind its port.
|
|
16
27
|
*
|
|
@@ -55,6 +66,7 @@ export async function bootstrapPanel({ core } = {}) {
|
|
|
55
66
|
|
|
56
67
|
const port = settings.get("port");
|
|
57
68
|
const host = resolveBindAddress();
|
|
69
|
+
const androidSock = isAndroidHost() ? androidPanelSocketPath() : null;
|
|
58
70
|
|
|
59
71
|
await new Promise((resolve, reject) => {
|
|
60
72
|
// "EADDRINUSE" plus a stack trace is not an answer anyone can act on, and
|
|
@@ -72,10 +84,19 @@ export async function bootstrapPanel({ core } = {}) {
|
|
|
72
84
|
}
|
|
73
85
|
reject(error);
|
|
74
86
|
});
|
|
75
|
-
|
|
87
|
+
if (androidSock) {
|
|
88
|
+
try {
|
|
89
|
+
fs.unlinkSync(androidSock);
|
|
90
|
+
} catch {
|
|
91
|
+
// first run has no leftover socket
|
|
92
|
+
}
|
|
93
|
+
server.listen(androidSock, resolve);
|
|
94
|
+
} else {
|
|
95
|
+
server.listen(port, host, resolve);
|
|
96
|
+
}
|
|
76
97
|
});
|
|
77
98
|
|
|
78
|
-
return { port, host, server };
|
|
99
|
+
return { port, host, server, socketPath: androidSock };
|
|
79
100
|
}
|
|
80
101
|
|
|
81
102
|
/**
|
|
@@ -89,15 +110,18 @@ export async function bootstrapPanel({ core } = {}) {
|
|
|
89
110
|
export function resolveBindAddress() {
|
|
90
111
|
const configured = settings.get("bind_address");
|
|
91
112
|
if (configured) return configured;
|
|
92
|
-
//
|
|
93
|
-
//
|
|
94
|
-
|
|
113
|
+
// Desktop / Docker: every interface. Android never reaches this — it
|
|
114
|
+
// binds a unix socket instead (see androidPanelSocketPath). The WebView
|
|
115
|
+
// still opens http://127.0.0.1:port and the host serves that over the socket.
|
|
95
116
|
return "0.0.0.0";
|
|
96
117
|
}
|
|
97
118
|
|
|
98
119
|
/** The address a person should type, given how this install is reachable. */
|
|
99
120
|
export function panelUrl({ port, firstRun = false } = {}) {
|
|
100
121
|
const domain = settings.get("public_domain");
|
|
101
|
-
const
|
|
122
|
+
const host =
|
|
123
|
+
domain ||
|
|
124
|
+
(isAndroidHost() ? "127.0.0.1" : "localhost");
|
|
125
|
+
const base = domain ? `https://${host}` : `http://${host}:${port}`;
|
|
102
126
|
return firstRun ? `${base}/setup` : base;
|
|
103
127
|
}
|
package/src/index.js
CHANGED
|
@@ -194,9 +194,16 @@ async function startWithPanel({ open }) {
|
|
|
194
194
|
try {
|
|
195
195
|
panel = await bootstrapPanel({ core });
|
|
196
196
|
} catch (error) {
|
|
197
|
-
if (error.code === "EADDRINUSE") {
|
|
197
|
+
if (error.code === "EADDRINUSE" || error.code === "ECONNREFUSED") {
|
|
198
198
|
console.error(`\n ${error.message}\n`);
|
|
199
199
|
logger.error(error.message);
|
|
200
|
+
if (process.env.LEVIX_ANDROID === "1") {
|
|
201
|
+
// WhatsApp still works without the panel. process.exit here also
|
|
202
|
+
// trips pino's sonic-boom ("not ready yet") as a second crash.
|
|
203
|
+
console.log("Panel failed " + (error.code || error.message));
|
|
204
|
+
console.log("Levix ready");
|
|
205
|
+
return { ...core, panel: null, url: null };
|
|
206
|
+
}
|
|
200
207
|
process.exit(1);
|
|
201
208
|
}
|
|
202
209
|
throw error;
|
|
@@ -78,7 +78,10 @@ function hasForwardingHeader(headers = {}) {
|
|
|
78
78
|
* the right key for rate limiting a password or setup-code guess.
|
|
79
79
|
*/
|
|
80
80
|
function clientAddress(req) {
|
|
81
|
-
|
|
81
|
+
const addr = req?.socket?.remoteAddress || req?.connection?.remoteAddress;
|
|
82
|
+
if (addr) return addr;
|
|
83
|
+
if (process.env.LEVIX_ANDROID === "1") return "127.0.0.1";
|
|
84
|
+
return "";
|
|
82
85
|
}
|
|
83
86
|
|
|
84
87
|
/**
|