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";
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;
const result = singleRow(
await queryObject<Token>(
@ -174,8 +180,20 @@ export async function createToken(
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> {
const digest = base64.decode(token);
const digest = sha256(base64.decode(token));
return singleRow(
await queryObject(
`
@ -202,6 +220,7 @@ export async function getUser(
export async function getUserFromNonExpiredLoginToken(
token: TokenDigest,
): Promise<User | null> {
// TODO: if the token has expired, return a specific error?
const digest = sha256(base64.decode(token));
return singleRow(
await queryObject<User>(
@ -210,7 +229,7 @@ export async function getUserFromNonExpiredLoginToken(
left join "user" u on u.id = ut.user_id
where ut."digest" = $1
and ut."data"->>'type' = 'login'
and now() < (ut.created_at + '7 days'::interval)
and now() < (ut.created_at + '14 days'::interval)
`,
[digest],
),

View file

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

View file

@ -2,7 +2,8 @@
"imports": {
"@/": "./",
"$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-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 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 =
"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) {
console.log("AppProps:", props);
export default function App(
{ Component, contextState }: AppProps<ContextState>,
) {
return (
<div class="relative min-h-screen flex flex-col">
<header class="flex justify-start items-center">
@ -64,11 +53,11 @@ export default function App({ Component, ...props }: MyAppProps) {
<h1 class="text-2xl">LyricScreen</h1>
</a>
<a tabIndex={11} href="/note" class={NAV_ITEM_CLASSES}>Notes</a>
{props.user ? UserNavItems() : LoginNavItems()}
{contextState.user ? UserNavItems() : LoginNavItems()}
</nav>
</header>
<main class="p-2">
<Component></Component>
<Component />
</main>
<footer class={`p-2 w-full mt-auto ${HEADER_CLASSES}`}>
"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 { getUserFromNonExpiredLoginToken } from "@/db/mod.ts";
import { type ContextState, type PublicUser, type User } from "@/types.ts";
@ -14,10 +14,22 @@ function toPublicUser(user: User): 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(
request: Request,
context: MiddlewareHandlerContext<ContextState>,
) {
context.layout = Layout;
let hasBadAuthCookie = false;
const { lsauth } = getCookies(request.headers);
log.debug("lsauth cookie:", lsauth);
@ -46,7 +58,16 @@ export async function serverHeader(
return resp;
}
export async function someState(
_request: Request,
context: MiddlewareHandlerContext<ContextState>,
) {
context.state.something = "I said something!";
return await context.next();
}
export const handler = [
someState,
currentUser,
serverHeader,
];

View file

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

View file

@ -1,10 +1,15 @@
import { Handlers } from "$fresh/server.ts";
// import { getToken, getUser } from "@/db/mod.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> = {
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();
deleteCookie(response.headers, "lsauth");
return response;

View file

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