Sessions!

This commit is contained in:
Daniel Flanagan 2022-10-12 03:31:26 -05:00
parent f34ead505b
commit 7af220de2e
Signed by untrusted user: lytedev-divvy
GPG key ID: 6D69CEEE4ABBCD82
8 changed files with 60 additions and 25 deletions

View file

@ -159,6 +159,12 @@ export async function createToken(
if (!(digest instanceof Uint8Array)) throw "token digest was non-brinary"; if (!(digest instanceof Uint8Array)) throw "token digest was non-brinary";
intermediateToken.digest = digest; intermediateToken.digest = digest;
} }
log.debug(
`intermediateToken bytes: ${base64.encode(intermediateToken.bytes)}`,
);
log.debug(
`intermediateToken digest: ${base64.encode(intermediateToken.digest)}`,
);
if (!intermediateToken.data) intermediateToken.data = null; if (!intermediateToken.data) intermediateToken.data = null;
const result = singleRow( const result = singleRow(
await queryObject<Token>( await queryObject<Token>(
@ -174,8 +180,20 @@ export async function createToken(
return null; return null;
} }
export async function deleteToken(
token: TokenDigest,
) {
const digest = sha256(base64.decode(token));
return await queryObject(
`
delete from user_token where digest = $1
`,
[digest],
);
}
export async function getToken(token: TokenDigest): Promise<Token | null> { export async function getToken(token: TokenDigest): Promise<Token | null> {
const digest = base64.decode(token); const digest = sha256(base64.decode(token));
return singleRow( return singleRow(
await queryObject( await queryObject(
` `
@ -202,6 +220,7 @@ export async function getUser(
export async function getUserFromNonExpiredLoginToken( export async function getUserFromNonExpiredLoginToken(
token: TokenDigest, token: TokenDigest,
): Promise<User | null> { ): Promise<User | null> {
// TODO: if the token has expired, return a specific error?
const digest = sha256(base64.decode(token)); const digest = sha256(base64.decode(token));
return singleRow( return singleRow(
await queryObject<User>( await queryObject<User>(
@ -210,7 +229,7 @@ export async function getUserFromNonExpiredLoginToken(
left join "user" u on u.id = ut.user_id left join "user" u on u.id = ut.user_id
where ut."digest" = $1 where ut."digest" = $1
and ut."data"->>'type' = 'login' and ut."data"->>'type' = 'login'
and now() < (ut.created_at + '7 days'::interval) and now() < (ut.created_at + '14 days'::interval)
`, `,
[digest], [digest],
), ),

View file

@ -7,7 +7,7 @@ import * as $0 from "./routes/[name].tsx";
import * as $1 from "./routes/_404.tsx"; import * as $1 from "./routes/_404.tsx";
import * as $2 from "./routes/_500.tsx"; import * as $2 from "./routes/_500.tsx";
import * as $3 from "./routes/_app.tsx"; import * as $3 from "./routes/_app.tsx";
import * as $4 from "./routes/_middleware.ts"; import * as $4 from "./routes/_middleware.tsx";
import * as $5 from "./routes/about.tsx"; import * as $5 from "./routes/about.tsx";
import * as $6 from "./routes/api/joke.ts"; import * as $6 from "./routes/api/joke.ts";
import * as $7 from "./routes/api/random-uuid.ts"; import * as $7 from "./routes/api/random-uuid.ts";
@ -33,7 +33,7 @@ const manifest = {
"./routes/_404.tsx": $1, "./routes/_404.tsx": $1,
"./routes/_500.tsx": $2, "./routes/_500.tsx": $2,
"./routes/_app.tsx": $3, "./routes/_app.tsx": $3,
"./routes/_middleware.ts": $4, "./routes/_middleware.tsx": $4,
"./routes/about.tsx": $5, "./routes/about.tsx": $5,
"./routes/api/joke.ts": $6, "./routes/api/joke.ts": $6,
"./routes/api/random-uuid.ts": $7, "./routes/api/random-uuid.ts": $7,

View file

@ -2,7 +2,8 @@
"imports": { "imports": {
"@/": "./", "@/": "./",
"$std/": "https://deno.land/std@0.158.0/", "$std/": "https://deno.land/std@0.158.0/",
"$fresh/": "https://deno.land/x/fresh@1.1.2/", "$freshbranch/": "https://raw.githubusercontent.com/lytedev/fresh/v1.1.2-df/",
"$fresh/": "../fresh/",
"preact": "https://esm.sh/preact@10.11.0", "preact": "https://esm.sh/preact@10.11.0",
"preact/": "https://esm.sh/preact@10.11.0/", "preact/": "https://esm.sh/preact@10.11.0/",
"preact-render-to-string": "https://esm.sh/*preact-render-to-string@5.2.4", "preact-render-to-string": "https://esm.sh/*preact-render-to-string@5.2.4",

View file

@ -2,18 +2,6 @@ import { type AppProps, Handlers } from "$fresh/server.ts";
import { type PublicUser } from "@/types.ts"; import { type PublicUser } from "@/types.ts";
import { type ContextState } from "@/types.ts"; import { type ContextState } from "@/types.ts";
interface MyAppProps extends AppProps {
user?: PublicUser;
}
export const handler: Handlers<MyAppProps, ContextState> = {
async GET(request: Request, context) {
console.error("\n\nYO\n\n");
console.log("AppHandler:", request, context);
return await context.render({ user: context.state.user });
},
};
const NAV_ITEM_CLASSES = const NAV_ITEM_CLASSES =
"flex justify-center items-center px-4 py-2 hover:bg-gray-300 dark:hover:bg-gray-700"; "flex justify-center items-center px-4 py-2 hover:bg-gray-300 dark:hover:bg-gray-700";
@ -50,8 +38,9 @@ export function UserNavItems() {
); );
} }
export default function App({ Component, ...props }: MyAppProps) { export default function App(
console.log("AppProps:", props); { Component, contextState }: AppProps<ContextState>,
) {
return ( return (
<div class="relative min-h-screen flex flex-col"> <div class="relative min-h-screen flex flex-col">
<header class="flex justify-start items-center"> <header class="flex justify-start items-center">
@ -64,11 +53,11 @@ export default function App({ Component, ...props }: MyAppProps) {
<h1 class="text-2xl">LyricScreen</h1> <h1 class="text-2xl">LyricScreen</h1>
</a> </a>
<a tabIndex={11} href="/note" class={NAV_ITEM_CLASSES}>Notes</a> <a tabIndex={11} href="/note" class={NAV_ITEM_CLASSES}>Notes</a>
{props.user ? UserNavItems() : LoginNavItems()} {contextState.user ? UserNavItems() : LoginNavItems()}
</nav> </nav>
</header> </header>
<main class="p-2"> <main class="p-2">
<Component></Component> <Component />
</main> </main>
<footer class={`p-2 w-full mt-auto ${HEADER_CLASSES}`}> <footer class={`p-2 w-full mt-auto ${HEADER_CLASSES}`}>
"It's a bit much, really..." "It's a bit much, really..."

View file

@ -1,4 +1,4 @@
import { MiddlewareHandlerContext } from "$fresh/server.ts"; import { LayoutProps, MiddlewareHandlerContext } from "$fresh/server.ts";
import { deleteCookie, getCookies } from "$std/http/cookie.ts"; import { deleteCookie, getCookies } from "$std/http/cookie.ts";
import { getUserFromNonExpiredLoginToken } from "@/db/mod.ts"; import { getUserFromNonExpiredLoginToken } from "@/db/mod.ts";
import { type ContextState, type PublicUser, type User } from "@/types.ts"; import { type ContextState, type PublicUser, type User } from "@/types.ts";
@ -14,10 +14,22 @@ function toPublicUser(user: User): PublicUser {
return publicUser; return publicUser;
} }
function Layout({ state, Component }: LayoutProps<ContextState>) {
return (
<>
{state.something
? <p>Oh my! You said something!</p>
: <p>You aren't saying anything.</p>}
<Component />
</>
);
}
async function currentUser( async function currentUser(
request: Request, request: Request,
context: MiddlewareHandlerContext<ContextState>, context: MiddlewareHandlerContext<ContextState>,
) { ) {
context.layout = Layout;
let hasBadAuthCookie = false; let hasBadAuthCookie = false;
const { lsauth } = getCookies(request.headers); const { lsauth } = getCookies(request.headers);
log.debug("lsauth cookie:", lsauth); log.debug("lsauth cookie:", lsauth);
@ -46,7 +58,16 @@ export async function serverHeader(
return resp; return resp;
} }
export async function someState(
_request: Request,
context: MiddlewareHandlerContext<ContextState>,
) {
context.state.something = "I said something!";
return await context.next();
}
export const handler = [ export const handler = [
someState,
currentUser, currentUser,
serverHeader, serverHeader,
]; ];

View file

@ -10,7 +10,6 @@ export const handler: Handlers<unknown, ContextState> = {
}; };
export default function Dashboard({ data }: PageProps) { export default function Dashboard({ data }: PageProps) {
console.log(data);
if (data) { if (data) {
return You(data); return You(data);
} else { } else {

View file

@ -1,10 +1,15 @@
import { Handlers } from "$fresh/server.ts"; import { Handlers } from "$fresh/server.ts";
// import { getToken, getUser } from "@/db/mod.ts"; // import { getToken, getUser } from "@/db/mod.ts";
// import * as base64 from "$std/encoding/base64.ts"; // import * as base64 from "$std/encoding/base64.ts";
import { deleteCookie } from "$std/http/cookie.ts"; import { deleteCookie, getCookies } from "$std/http/cookie.ts";
import { deleteToken } from "@/db/mod.ts";
export const handler: Handlers<unknown> = { export const handler: Handlers<unknown> = {
async GET(_request: Request, context) { async GET(request: Request, context) {
const { lsauth } = getCookies(request.headers);
if (lsauth) {
console.log("deleteToken:", await deleteToken(lsauth));
}
const response = await context.render(); const response = await context.render();
deleteCookie(response.headers, "lsauth"); deleteCookie(response.headers, "lsauth");
return response; return response;

View file

@ -50,4 +50,5 @@ export type TokenDigest = string;
export interface ContextState { export interface ContextState {
user?: PublicUser; user?: PublicUser;
something?: string;
} }