157 lines
4.2 KiB
TypeScript
157 lines
4.2 KiB
TypeScript
import { getResponseBodyOrError } from '$lib/api/utils';
|
|
import { readUser } from '$lib/api/endpoints';
|
|
import jwt_decode from 'jwt-decode';
|
|
import { writable } from 'svelte/store';
|
|
|
|
/**
|
|
* Svelte store to hold the current StoredUser object.
|
|
*/
|
|
export const storedUser = writable();
|
|
|
|
// Name of the key holding the auth JWT in localstorage
|
|
const jwtKey = 'jwt';
|
|
|
|
// Name of the key holding the authenticated user in localstorage
|
|
const userKey = 'user';
|
|
export type StoredUser = {
|
|
id: number,
|
|
email: string,
|
|
isAdmin: boolean,
|
|
sessionExpires: Date
|
|
}
|
|
|
|
/**
|
|
* Saves the specified token in localstorage.
|
|
*
|
|
* @param {string} token - The token to save in localstorage.
|
|
*/
|
|
function saveTokenToLocalstorage(token: string): void {
|
|
localStorage.setItem(jwtKey, token);
|
|
}
|
|
|
|
/**
|
|
* Retrieves and returns the token, if present, from localstorage.
|
|
*/
|
|
export function getTokenFromLocalstorage(): string | null {
|
|
return localStorage.getItem(jwtKey);
|
|
}
|
|
|
|
/**
|
|
* Removes the saved token from localstorage.
|
|
*/
|
|
function clearTokenInLocalstorage(): void {
|
|
localStorage.removeItem(jwtKey);
|
|
}
|
|
|
|
/**
|
|
* Saves the specified StoredUser object in localstorage.
|
|
*
|
|
* @param {StoredUser} user - The user to write to localstorage.
|
|
*/
|
|
function saveUserToLocalstorage(user: StoredUser): void {
|
|
localStorage.setItem(userKey, JSON.stringify(user));
|
|
}
|
|
|
|
/**
|
|
* Retrieves and returns the user, if present, from localstorage.
|
|
*/
|
|
function getUserFromLocalstorage(): StoredUser | null {
|
|
let item: string | null = localStorage.getItem(userKey);
|
|
if (typeof item !== 'string') {
|
|
return null;
|
|
}
|
|
return JSON.parse(item) as StoredUser;
|
|
}
|
|
|
|
/**
|
|
* Removes the saved user from localstorage.
|
|
*/
|
|
function clearUserInLocalstorage(): void {
|
|
localStorage.removeItem(userKey);
|
|
}
|
|
|
|
/**
|
|
* Sends an API request containing the specified login credentials to the backend,
|
|
* and returns the JWT retrieved from the response on sucess.
|
|
*
|
|
* @param {string} email - The email address of the user whose JWT to retrieve.
|
|
* @param {string} password - The password used to authenticate the user whose JWT is being retrieved.
|
|
* @throws {Error} - If the API request failed or the supplied credentials were invalid.
|
|
*/
|
|
async function requestJwt(email: string, password: string): Promise<string> {
|
|
type Token = {
|
|
token: string
|
|
}
|
|
|
|
const response = await fetch('/api/auth/login', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Accept': 'application/json',
|
|
'Content-Type': 'application/json',
|
|
},
|
|
body: JSON.stringify({
|
|
email: email,
|
|
password: password,
|
|
})
|
|
});
|
|
|
|
const responseBody = await getResponseBodyOrError(response) as Token;
|
|
return responseBody.token;
|
|
}
|
|
|
|
/**
|
|
* Loads the user currently saved in localstorage into the storedUser
|
|
* svelte store.
|
|
*/
|
|
export function loadUserIntoStore(): void {
|
|
storedUser.set(getUserFromLocalstorage());
|
|
}
|
|
|
|
/**
|
|
* Clears the storedUser svelte store.
|
|
*/
|
|
function clearUserFromStore(): void {
|
|
storedUser.set(null);
|
|
}
|
|
|
|
/**
|
|
* Sends an API request to retrieve the specified user's JWT from the backend,
|
|
* and stores the retrieved token in localstorage. Then, retrieves the authenticated
|
|
* user's basic account information (StoredUser), saves it in localsotrage and in the
|
|
* currentUser svelte store.
|
|
*
|
|
* @param {string} email - The email address of the user whose token and information to retrieve.
|
|
* @param {string} password - The password used to authenticate the user whose token is being retrieved.
|
|
* @throws {Error} - If any API request fails or the supplied credentials were invalid.
|
|
*/
|
|
export async function login(email: string, password: string): Promise<void> {
|
|
const token = await requestJwt(email, password);
|
|
|
|
interface Token {
|
|
sub: number,
|
|
exp: number
|
|
}
|
|
const parsedToken = jwt_decode(token) as Token;
|
|
const userId = parsedToken.sub;
|
|
|
|
const user = await readUser(userId, token);
|
|
|
|
saveTokenToLocalstorage(token);
|
|
saveUserToLocalstorage({
|
|
id: user.id,
|
|
email: user.email,
|
|
isAdmin: user.is_admin,
|
|
sessionExpires: new Date(parsedToken.exp),
|
|
});
|
|
loadUserIntoStore();
|
|
}
|
|
|
|
/**
|
|
* Purges the currently logged in user's information and token from localstorage
|
|
* and the svelte store.
|
|
*/
|
|
export function logout(): void {
|
|
clearUserFromStore();
|
|
clearUserInLocalstorage();
|
|
clearTokenInLocalstorage();
|
|
}
|