Verified Commit d68bafd0 authored by Jakob Moser's avatar Jakob Moser
Browse files

Add basic client-side account handling toolkit

parent 0917f4cd
Loading
Loading
Loading
Loading
+61 −0
Changes for portal/static/js/account.mjs: 61 added lines, 0 removed lines.
Original line number Diff line number Diff line
import { Base64 } from "/static/lib/base64-3.7.5/base64.mjs"

export function getKey() {
    return JSON.parse(localStorage.getItem("key"))
}

export function isExpired(key) {
    const now = new Date()
    return now > new Date(key.expiresAt)
}

export function isLoggedIn() {
    return getKey() !== null && !isExpired(getKey())
}

export async function login(username, password) {
    // We use a library to Base64 encode username and password to conform to RFC7671
    // (https://datatracker.ietf.org/doc/html/rfc7617#section-2.1) because the built-in
    // JavaScript function btoa cannot deal with Unicode characters properly.
    const encodedUsernamePassword = Base64.encode(`${username}:${password}`)

    const key = await m.request({
        method: "POST",
        url: "/api/v0/keys",
        headers: {
            Authorization: `Basic ${encodedUsernamePassword}`,
        },
    })

    localStorage.setItem("key", JSON.stringify(key))
}

export async function logout() {
    const key = getKey()

    // Remove the key from local storage. This way, the logout button will always reset the local session in the browser,
    // even if something weird happens immediately afterwards.
    localStorage.removeItem("key")

    if (!key) {
        throw new Error(`Tried to logout, but the key was falsy: key = ${key}`)
    }

    try {
        await m.request({
            method: "DELETE",
            url: `/api/v0/keys/${key.uuid}`,
            headers: {
                Authorization: `Bearer ${key.secret}`,
            },
        })
    } catch (e) {
        if (e.code === 401 && isExpired(key)) {
            // Expired keys are deleted automatically and are not authorized to do anything anymore,
            // so this error is expected. We do nothing in this case, but could show an info message.
        } else {
            // This should not happen, rethrow
            throw e
        }
    }
}