Browse Source

login and token system

master
mortie 7 years ago
parent
commit
497e604755
3 changed files with 113 additions and 18 deletions
  1. 58
    12
      js/admin.js
  2. 26
    2
      web/admin/lib.js
  3. 29
    4
      web/admin/view.js

+ 58
- 12
js/admin.js View File

@@ -2,9 +2,12 @@ var querystring = require("querystring");
var fs = require("fs");
var pathlib = require("path");
var formidable = require("formidable");
var crypto = require("crypto");

var basepath = "/admin/api/";

var tokens = {};

// Used in every method handler to make sure the correct arguments are provided
function hasargs(query, respond, expected) {
var missing = [];
@@ -134,23 +137,46 @@ var methods = {

exports.canServe = function(parts) {
// Temporary, while working on stuff
return false;
return methods[parts.pathname.replace(basepath, "")] !== undefined;
var name = parts.pathname.replace(basepath, "");
return methods[name] !== undefined || name === "login";
}

exports.serve = function(parts, conf, req, res) {
var fn = methods[parts.pathname.replace(basepath, "")];
if (!fn) {
res.writeHead(404);
res.end();
return;
}
var sessTokens = [];
function loginHandler(conf, req, respond) {
var pass = req.headers["session-pass"];
if (!conf.password)
return respond(null, false);
if (!pass)
return respond(null, false);
if (pass !== conf.password)
return respond(null, false);

var token = crypto.randomBytes(16).toString("hex");
var id = sessTokens.length;
sessTokens[id] = token;
respond(null, token);

// Time out after 30 minutes
setTimeout(() => {
tokens[id] = undefined;
}, 30 * 60 * 1000);
}
function validateToken(req) {
var token = req.headers["session-token"];
if (!token)
return false;

var query = querystring.parse(parts.query);
for (var i in query) {
query[i] = decodeURIComponent(query[i]);
for (var i = 0; i < sessTokens.length; ++i) {
if (sessTokens[i] && sessTokens[i] === token)
return true;
}

return false;
}

exports.serve = function(parts, conf, req, res) {
var name = parts.pathname.replace(basepath, "");

// Better than manually doing res.end(JSON.stringify(obj)) everywhere
function respond(err, obj) {
var result = {
@@ -166,6 +192,26 @@ exports.serve = function(parts, conf, req, res) {
res.end(JSON.stringify(result));
}

// Special login handler
if (name === "login")
return loginHandler(conf, req, respond);

// Verify token
if (!validateToken(req))
return respond("Invalid token");

var fn = methods[name];
if (!fn) {
res.writeHead(404);
res.end();
return;
}

var query = querystring.parse(parts.query);
for (var i in query) {
query[i] = decodeURIComponent(query[i]);
}

// Finally, call method handler
fn(query, conf, req, respond);
}

+ 26
- 2
web/admin/lib.js View File

@@ -1,11 +1,35 @@
var sessToken = "";

function apiLogin(pass, cb) {
var extraHeads = [ [ "Session-Pass", pass ] ];

api("login", {}, (err, token) => {
if (token) {
sessToken = token;
cb(true);
} else {
cb(false);
}
}, extraHeads);
}

function argstr(args) {
return "?" + Object.keys(args).map(function(key) {
return encodeURIComponent(key)+"="+encodeURIComponent(args[key]);
}).join("&");
}

function api(method, args, cb) {
fetch("/admin/api/"+method+argstr(args), { method: "POST" })
function api(method, args, cb, extraHeads) {
var heads = new Headers();
heads.append("Session-Token", sessToken);
if (extraHeads)
extraHeads.forEach(h => heads.append(h[0], h[1]));

var opts = {
method: "POST",
headers: heads
};
fetch("/admin/api/"+method+argstr(args), opts)
.then(response => response.json())
.then(res => cb(res.err, res.obj));
}

+ 29
- 4
web/admin/view.js View File

@@ -3,19 +3,44 @@
var root = $$("#root");

var views = {
login: viewLogin,
main: viewMain,
edit: viewEdit
}

function setView(name, args) {
location.hash = name+"/"+args.join("/");
if (args)
location.hash = name+"/"+args.join("/");
else
location.hash = name+"/";
}

function viewLogin(root) {
function login(first) {
var pass;
do {
if (first)
pass = prompt("Password?");
else
pass = prompt("Incorrect password.");
} while (!pass);

apiLogin(pass, success => {
if (success)
setView("main");
else
login(false);
});
}

login(true);
}

function viewMain(root) {
// Get a list of the slides
api("list_slides", {}, (err, slides) => {
if (err)
return error(msg);
return error(err);

slides.forEach(function(s) {

@@ -176,9 +201,9 @@
name = args[0];
args.splice(0, 1);
if (!views[name])
name = "main"
name = "login"
} else {
name = "main";
name = "login";
}

args = args || [];

Loading…
Cancel
Save