checkpoint 3
This commit is contained in:
parent
494919f9aa
commit
5ca038c736
4 changed files with 78 additions and 8 deletions
|
@ -24,12 +24,32 @@ fastify.get('/', async (request, reply) => {
|
||||||
return IDENTITY_API_LANDING_MESSAGE;
|
return IDENTITY_API_LANDING_MESSAGE;
|
||||||
})
|
})
|
||||||
|
|
||||||
|
fastify.get('/auth/account', {
|
||||||
|
async handler(request, reply) {
|
||||||
|
let jwt = request.headers['authorization'].replace('Bearer', '').trim()
|
||||||
|
let { payload } = await Jose.jwtVerify(jwt, JWT_SECRET)
|
||||||
|
|
||||||
|
let user = users[payload.email]
|
||||||
|
user.password = undefined
|
||||||
|
return user
|
||||||
|
},
|
||||||
|
schema: {
|
||||||
|
headers: {
|
||||||
|
type: 'object',
|
||||||
|
properties: {
|
||||||
|
authorization: { type: 'string' },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
fastify.post('/auth/login', {
|
fastify.post('/auth/login', {
|
||||||
async handler(request, reply) {
|
async handler(request, reply) {
|
||||||
let user = users[request.body.email];
|
let user = users[request.body.email];
|
||||||
if (user != null && user.password == request.body.password) {
|
if (user != null && user.password == request.body.password) {
|
||||||
let token = await new Jose.SignJWT({
|
let token = await new Jose.SignJWT({
|
||||||
uid: user.uid,
|
uid: user.uid,
|
||||||
|
email: request.body.email,
|
||||||
name: user.name,
|
name: user.name,
|
||||||
})
|
})
|
||||||
.setProtectedHeader({ alg: JWT_ALG })
|
.setProtectedHeader({ alg: JWT_ALG })
|
||||||
|
@ -70,6 +90,7 @@ fastify.post('/auth/register', {
|
||||||
let user = users[request.body.email]
|
let user = users[request.body.email]
|
||||||
let token = await new Jose.SignJWT({
|
let token = await new Jose.SignJWT({
|
||||||
uid: user.uid,
|
uid: user.uid,
|
||||||
|
email: request.body.email,
|
||||||
name: user.name,
|
name: user.name,
|
||||||
})
|
})
|
||||||
.setProtectedHeader({ alg: JWT_ALG })
|
.setProtectedHeader({ alg: JWT_ALG })
|
||||||
|
|
|
@ -4,6 +4,11 @@ export type Credentials = {
|
||||||
token: string,
|
token: string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type Account = {
|
||||||
|
uid: string,
|
||||||
|
name: string,
|
||||||
|
}
|
||||||
|
|
||||||
function sendRequest(path: string, request: RequestInit = {}, credentials?: Credentials) {
|
function sendRequest(path: string, request: RequestInit = {}, credentials?: Credentials) {
|
||||||
if (typeof request !== "string" && credentials != null) {
|
if (typeof request !== "string" && credentials != null) {
|
||||||
request.headers = { 'Authorization': `Bearer ${credentials.token}`, ...request.headers }
|
request.headers = { 'Authorization': `Bearer ${credentials.token}`, ...request.headers }
|
||||||
|
@ -21,11 +26,10 @@ async function asJson<R>(request: Promise<Response>): Promise<R> {
|
||||||
return (await req.json() as R)
|
return (await req.json() as R)
|
||||||
}
|
}
|
||||||
|
|
||||||
export type LoginResponse = { token: string, } | { error: string, }
|
|
||||||
export function login(credentials: {
|
export function login(credentials: {
|
||||||
email: string,
|
email: string,
|
||||||
password: string,
|
password: string,
|
||||||
}): Promise<LoginResponse> {
|
}): Promise<{ token: string, } | { error: string, }> {
|
||||||
return asJson(sendRequest('/auth/login', {
|
return asJson(sendRequest('/auth/login', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -35,12 +39,11 @@ export function login(credentials: {
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
export type RegisterResponse = { token: string, } | { error: string, }
|
|
||||||
export function register(credentials: {
|
export function register(credentials: {
|
||||||
name: string,
|
name: string,
|
||||||
email: string,
|
email: string,
|
||||||
password: string,
|
password: string,
|
||||||
}): Promise<RegisterResponse> {
|
}): Promise<{ token: string, } | { error: string, }> {
|
||||||
return asJson(sendRequest('/auth/register', {
|
return asJson(sendRequest('/auth/register', {
|
||||||
method: 'POST',
|
method: 'POST',
|
||||||
headers: {
|
headers: {
|
||||||
|
@ -49,3 +52,7 @@ export function register(credentials: {
|
||||||
body: JSON.stringify(credentials),
|
body: JSON.stringify(credentials),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function accountData(credentials: Credentials): Promise<Account | { error: string }> {
|
||||||
|
return asJson(sendRequest('/auth/account', undefined, credentials))
|
||||||
|
}
|
|
@ -1,5 +1,5 @@
|
||||||
import { writable } from "svelte/store";
|
import { writable } from "svelte/store";
|
||||||
import type { Credentials } from "./api";
|
import { accountData, type Account, type Credentials } from "./api";
|
||||||
|
|
||||||
const CREDENTIALS_KEY = 'v0:credentials'
|
const CREDENTIALS_KEY = 'v0:credentials'
|
||||||
|
|
||||||
|
@ -10,10 +10,26 @@ credentials.subscribe((value) => {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
export function initializeStores() {
|
export const account = writable<Account | null>()
|
||||||
|
|
||||||
|
export async function initializeStores() {
|
||||||
let rawCredentials = localStorage.getItem(CREDENTIALS_KEY)
|
let rawCredentials = localStorage.getItem(CREDENTIALS_KEY)
|
||||||
|
let parsedCredentials
|
||||||
if (rawCredentials != null && rawCredentials.length > 0) {
|
if (rawCredentials != null && rawCredentials.length > 0) {
|
||||||
try { credentials.set(JSON.parse(rawCredentials)) }
|
try {
|
||||||
|
parsedCredentials = JSON.parse(rawCredentials)
|
||||||
|
credentials.set(parsedCredentials)
|
||||||
|
}
|
||||||
catch (e) { localStorage.removeItem(CREDENTIALS_KEY) }
|
catch (e) { localStorage.removeItem(CREDENTIALS_KEY) }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parsedCredentials != null) {
|
||||||
|
let data = await accountData(parsedCredentials)
|
||||||
|
if ('error' in data) {
|
||||||
|
credentials.set(null)
|
||||||
|
localStorage.removeItem(CREDENTIALS_KEY)
|
||||||
|
} else {
|
||||||
|
account.set(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -1 +1,27 @@
|
||||||
<h1>Dashboard</h1>
|
<script>
|
||||||
|
import { account } from "$lib/stores";
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="mt-3.5 justify-center flex ">
|
||||||
|
<div class="w-[60%] flex flex-col">
|
||||||
|
<h1 class="text-2xl pb-3.5">Welcome back, <span class="font-bold">{$account?.name}</span>.</h1>
|
||||||
|
<div class="flex gap-2">
|
||||||
|
<div class="p-6 border border-gray-200 rounded-lg shadow w-full">
|
||||||
|
<h2 class="text-xl">Latest activity</h2>
|
||||||
|
<div class="pt-2">
|
||||||
|
<p>New song: <span class="font-bold">Takin' what's not yours</span></p>
|
||||||
|
<p>New song: <span class="font-bold">Lovers Rock</span></p>
|
||||||
|
<p>New memory: <a href="#memory" class="font-bold text-violet-600 hover:underline">§ At the sunflower field with Ms. Violet</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="p-6 border border-gray-200 rounded-lg shadow w-full">
|
||||||
|
<h2 class="text-xl">Memories from the past</h2>
|
||||||
|
<div class="pt-2">
|
||||||
|
<p><time class="pr-2.5 font-mono" datetime="2024-04-13">13/04/2024</time> <a href="#memory" class="font-bold text-violet-600 hover:underline">§ 2024 Birthday</a></p>
|
||||||
|
<p><time class="pr-2.5 font-mono" datetime="2024-04-01">01/04/2024</time> New song: <span class="font-bold">KMAG YOYO</span></p>
|
||||||
|
<p><time class="pr-2.5 font-mono" datetime="2024-03-20">20/03/2024</time> <a href="#memory" class="font-bold text-violet-600 hover:underline">§ A new era</a></p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
Loading…
Reference in a new issue