Make auth use JWTs.

git-svn-id: https://www.unprompted.com/svn/projects/tildefriends/trunk@3991 ed5197a5-7fde-0310-b194-c3ffbd925b24
This commit is contained in:
2022-09-28 23:52:44 +00:00
parent 5b3ae3f006
commit 113a82b382
4 changed files with 232 additions and 36 deletions

View File

@ -5,38 +5,66 @@ import * as form from './form.js';
var gTokens = {};
var gDatabase = new Database("auth");
const kRefreshInterval = 1 * 60 * 60 * 1000;
function b64url(value) {
value = value.replaceAll('+', '-').replaceAll('/', '_');
let equals = value.indexOf('=');
if (equals !== -1) {
return value.substring(0, equals);
} else {
return value;
}
}
function unb64url(value) {
value = value.replaceAll('-', '+').replaceAll('_', '/');
let remainder = value.length % 4;
if (remainder == 3) {
return value + '=';
} else if (remainder == 2) {
return value + '==';
} else {
return value;
}
}
function makeJwt(payload) {
let ids = ssb.getIdentities(':auth');
let id;
if (ids?.length) {
id = ids[0];
} else {
id = ssb.createIdentity(':auth');
}
let final_payload = b64url(base64Encode(JSON.stringify(Object.assign({}, payload, {exp: (new Date().valueOf()) + kRefreshInterval}))));
let jwt = [b64url(base64Encode(JSON.stringify({alg: 'HS256', typ: 'JWT'}))), final_payload, b64url(ssb.hmacsha256sign(final_payload, ':auth', id))].join('.');
return jwt;
}
function readSession(session) {
var result = session ? gDatabase.get("session:" + session) : null;
if (result) {
result = JSON.parse(result);
let kRefreshInterval = 1 * 60 * 60 * 1000;
let now = Date.now();
if (!result.lastAccess || result.lastAccess < now - kRefreshInterval) {
result.lastAccess = now;
writeSession(session, result);
let jwt_parts = session?.split('.');
if (jwt_parts?.length === 3) {
let [header, payload, signature] = jwt_parts;
header = JSON.parse(base64Decode(unb64url(header)));
if (header.typ === 'JWT' && header.alg === 'HS256') {
signature = unb64url(signature);
let id = ssb.getIdentities(':auth');
if (id?.length && ssb.hmacsha256verify(id[0], payload, signature)) {
let result = JSON.parse(base64Decode(unb64url(payload)));
if ((new Date()).valueOf() < result.exp) {
return result;
} else {
print('JWT expired.');
}
} else {
print('JWT verification failed.');
}
} else {
print('Invalid JWT header.');
}
}
return result;
}
function writeSession(session, value) {
gDatabase.set("session:" + session, JSON.stringify(value));
}
function removeSession(session, value) {
gDatabase.remove("session:" + session);
}
function newSession() {
var alphabet = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var result = "";
for (var i = 0; i < 32; i++) {
result += alphabet.charAt(Math.floor(Math.random() * alphabet.length));
}
return result;
}
function verifyPassword(password, hash) {
@ -92,7 +120,6 @@ function handler(request, response) {
var formData = form.decodeForm(request.query);
if (request.method == "POST" || formData.submit) {
session = newSession();
sessionIsNew = true;
formData = form.decodeForm(utf8Decode(request.body), formData);
if (formData.submit == "Login") {
@ -114,7 +141,7 @@ function handler(request, response) {
if (users !== users_original) {
gDatabase.set('users', users);
}
writeSession(session, {name: formData.name});
session = makeJwt({name: formData.name});
account = {password: hashPassword(formData.password)};
gDatabase.set("user:" + formData.name, JSON.stringify(account));
if (noAdministrator()) {
@ -127,7 +154,7 @@ function handler(request, response) {
if (account &&
account.password &&
verifyPassword(formData.password, account.password)) {
writeSession(session, {name: formData.name});
session = makeJwt({name: formData.name});
if (noAdministrator()) {
makeAdministrator(formData.name);
}
@ -137,7 +164,7 @@ function handler(request, response) {
}
} else {
// Proceed as Guest
writeSession(session, {name: "guest"});
session = makeJwt({name: 'guest'});
}
}
@ -191,7 +218,6 @@ function handler(request, response) {
});
}
} else if (request.uri == "/login/logout") {
removeSession(session);
response.writeHead(303, {"Set-Cookie": "session=; path=/; secure; SameSite=Strict; expires=Thu, 01 Jan 1970 00:00:00 GMT", "Location": "/login" + (request.query ? "?" + request.query : "")});
response.end();
} else {