aboutsummaryrefslogtreecommitdiffstats
path: root/src/server/HttpServer.hx
diff options
context:
space:
mode:
Diffstat (limited to 'src/server/HttpServer.hx')
-rw-r--r--src/server/HttpServer.hx138
1 files changed, 99 insertions, 39 deletions
diff --git a/src/server/HttpServer.hx b/src/server/HttpServer.hx
index f7c6d8c..f0f565b 100644
--- a/src/server/HttpServer.hx
+++ b/src/server/HttpServer.hx
@@ -1,6 +1,7 @@
package server;
import Types.UploadResponse;
+import haxe.crypto.Sha256;
import haxe.io.Path;
import js.node.Buffer;
import js.node.Fs.Fs;
@@ -24,10 +25,15 @@ private class HttpServerConfig {
public final cache:Cache = null;
}
-typedef SetupAdminRequest = {
+typedef GateRequest = {
+ password:String,
+}
+
+typedef AdminRegisterRequest = {
name:String,
password:String,
passwordConfirmation:String,
+ token:String,
}
class HttpServer {
@@ -100,8 +106,10 @@ class HttpServer {
}
}
switch url.pathname {
- case "/setup":
- finishSetup(req, res);
+ case "/gate":
+ verifyGate(req, res);
+ case "/admin-register":
+ registerAdmin(req, res);
}
return;
}
@@ -121,8 +129,8 @@ class HttpServer {
return;
}
- if (url.pathname == "/setup") {
- if (main.hasAdmins()) {
+ if (url.pathname == "/gate") {
+ if (!hasGatePassword() || hasValidGateCookie(req)) {
res.redirect("/");
return;
}
@@ -135,6 +143,23 @@ class HttpServer {
return;
}
+ if (url.pathname == "/admin-register") {
+ if (!hasAdminToken()) {
+ res.redirect("/");
+ return;
+ }
+ Fs.readFile('$dir/admin-register.html', (err:Dynamic, data:Buffer) -> {
+ if (err != null) {
+ readFileError(err, res, '$dir/admin-register.html');
+ return;
+ }
+ data = Buffer.from(localizeHtml(data.toString(), req.headers["accept-language"]));
+ res.setHeader("content-type", getMimeType("html"));
+ res.end(data);
+ });
+ return;
+ }
+
if (url.pathname == "/proxy") {
if (!proxyUrl(req, res)) res.end('Proxy error: ${req.url}');
return;
@@ -158,8 +183,8 @@ class HttpServer {
}
if (ext == "html") {
- if (!main.isNoState && !main.hasAdmins()) {
- res.redirect("/setup");
+ if (hasGatePassword() && !hasValidGateCookie(req)) {
+ res.redirect("/gate");
return;
}
// replace ${textId} to localized strings
@@ -244,8 +269,8 @@ class HttpServer {
});
}
- function finishSetup(req:IncomingMessage, res:ServerResponse) {
- if (main.hasAdmins()) {
+ function verifyGate(req:IncomingMessage, res:ServerResponse) {
+ if (!hasGatePassword()) {
return res.redirect("/");
}
@@ -257,52 +282,87 @@ class HttpServer {
req.on("end", () -> {
final body = Buffer.concat(bodyChunks).toString();
- final jsonParser = new JsonParser<SetupAdminRequest>();
+ final jsonParser = new JsonParser<GateRequest>();
+ final jsonData = jsonParser.fromJson(body);
+ if (jsonParser.errors.length > 0) {
+ res.status(400).json({success: false});
+ return;
+ }
+ final password = jsonData.password;
+ if (password == main.config.gatePassword) {
+ final token = getGateToken();
+ res.setHeader("set-cookie", 'gate_auth=$token; Path=/; HttpOnly; SameSite=Strict');
+ res.status(200).json({success: true});
+ } else {
+ res.status(401).json({success: false});
+ }
+ });
+ }
+
+ function hasGatePassword():Bool {
+ final gp = main.config.gatePassword;
+ return gp != null && gp.length > 0;
+ }
+
+ function hasValidGateCookie(req:IncomingMessage):Bool {
+ final cookieHeader:String = req.headers["cookie"];
+ if (cookieHeader == null) return false;
+ final token = getGateToken();
+ final needle = 'gate_auth=$token';
+ for (cookie in cookieHeader.split(";")) {
+ if (cookie.trim() == needle) return true;
+ }
+ return false;
+ }
+
+ function getGateToken():String {
+ return Sha256.encode('gate_${main.config.gatePassword}_${main.config.salt}');
+ }
+
+ function hasAdminToken():Bool {
+ final t = main.config.adminToken;
+ return t != null && t.length > 0;
+ }
+
+ function registerAdmin(req:IncomingMessage, res:ServerResponse) {
+ if (!hasAdminToken()) {
+ res.status(403).json({success: false, error: "Admin registration is disabled"});
+ return;
+ }
+
+ final bodyChunks:Array<Buffer> = [];
+ req.on("data", chunk -> bodyChunks.push(chunk));
+ req.on("end", () -> {
+ final body = Buffer.concat(bodyChunks).toString();
+ final jsonParser = new JsonParser<AdminRegisterRequest>();
final jsonData = jsonParser.fromJson(body);
if (jsonParser.errors.length > 0) {
- final errors = ErrorUtils.convertErrorArray(jsonParser.errors);
- trace(errors);
- res.status(400).json({success: false, errors: []});
+ res.status(400).json({success: false, error: "Invalid request"});
return;
}
- final name = jsonData.name;
+ final name = jsonData.name.trim();
final password = jsonData.password;
final passwordConfirmation = jsonData.passwordConfirmation;
- final lang = req.headers["accept-language"] ?? "en";
- final errors:Array<{type:String, error:String}> = [];
+ final token = jsonData.token;
+ if (token != main.config.adminToken) {
+ res.status(401).json({success: false, error: "Invalid admin token"});
+ return;
+ }
if (main.isBadClientName(name)) {
- final error = Lang.get(lang, "usernameError")
- .replace("$MAX", '${main.config.maxLoginLength}');
- errors.push({
- type: "name",
- error: error
- });
+ res.status(400).json({success: false, error: "Invalid username"});
+ return;
}
-
final min = Main.MIN_PASSWORD_LENGTH;
final max = Main.MAX_PASSWORD_LENGTH;
if (password.length < min || password.length > max) {
- final error = Lang.get(lang, "passwordError")
- .replace("$MIN", '$min').replace("$MAX", '$max');
- errors.push({
- type: "password",
- error: error
- });
+ res.status(400).json({success: false, error: 'Password must be $min-$max characters'});
+ return;
}
-
if (password != passwordConfirmation) {
- errors.push({
- type: "password",
- error: Lang.get(lang, "passwordsMismatchError")
- });
- }
-
- if (errors.length > 0) {
- res.status(400).json({success: false, errors: errors});
+ res.status(400).json({success: false, error: "Passwords do not match"});
return;
}
-
main.addAdmin(name, password);
res.status(200).json({success: true});
});
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage