Skip to content

Commit

Permalink
Todays Progress
Browse files Browse the repository at this point in the history
  • Loading branch information
d3rpp committed Aug 24, 2024
1 parent 3a43135 commit 4c2d260
Show file tree
Hide file tree
Showing 26 changed files with 289 additions and 142 deletions.
3 changes: 3 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,6 @@ DATABASE_FILE=./database.db

GITHUB_CLIENT_ID=""
GITHUB_CLIENT_SECRET=""

# Set this to 1 or true to enable query logging
LOGGER_ENABLED=""
Binary file modified bun.lockb
Binary file not shown.
4 changes: 2 additions & 2 deletions drizzle/0001_premium_khan.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ CREATE TABLE `oauth_connections` (
`type` text NOT NULL,
`oauth_identifier` text NOT NULL,
`user_id` text NOT NULL,
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade
);
--> statement-breakpoint
CREATE TABLE `sessions` (
`id` text NOT NULL,
`user_id` text NOT NULL,
`expires_at` integer NOT NULL,
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE no action
FOREIGN KEY (`user_id`) REFERENCES `users`(`id`) ON UPDATE no action ON DELETE cascade
);
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"lucide-svelte": "^0.428.0",
"mode-watcher": "^0.4.1",
"svelte-radix": "^1.1.0",
"svelte-sonner": "^0.3.27",
"tailwind-merge": "^2.5.2",
"tailwind-variants": "^0.2.1",
"trpc-svelte-query-adapter": "^2.3.14",
Expand Down
169 changes: 87 additions & 82 deletions src/lib/client/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,30 +5,21 @@ export * from "./errors";
import { InvalidKeyError } from "./errors";
import { getContext, setContext } from "svelte";

const private_key_usages: KeyUsage[] = [
"decrypt",
"unwrapKey",
];
const private_key_usages: KeyUsage[] = ["decrypt", "unwrapKey"];

const public_key_usages: KeyUsage[] = [
"wrapKey",
"encrypt",
];
const public_key_usages: KeyUsage[] = ["wrapKey", "encrypt"];

const key_usages = [
...private_key_usages,
...public_key_usages
];
const key_usages = [...private_key_usages, ...public_key_usages];

const runtime_client_context_key = "$$_theAmalgamation";

export const setRuntimeClientContext = (client: TheAmalgamation) => {
setContext(runtime_client_context_key, client);
}
setContext(runtime_client_context_key, client);
};

export const getRuntimeClientContext = () => {
return getContext(runtime_client_context_key) as TheAmalgamation;
}
return getContext(runtime_client_context_key) as TheAmalgamation;
};

/**
* Behold, the amalgamation, the client that does literally everything on the client.
Expand All @@ -38,32 +29,38 @@ export class TheAmalgamation {

constructor() {}

public initialise_from_localstorage = async () => {
this.key_pairs = [];
console.info("Initialising Runtime Client from Localhost");

for (let i = 0; i < window.localStorage.length; i++) {
const item_name = window.localStorage.key(i)!;
if (item_name.startsWith("cached_key-")) {
const cached_key_string = window.localStorage.getItem(item_name)!;
const parsed_cached_key = JSON.parse(cached_key_string);

const kid = item_name.replace("cached_key-", "");

if (
"publicKey" in parsed_cached_key && typeof parsed_cached_key.publicKey === "object" &&
"privateKey" in parsed_cached_key && typeof parsed_cached_key.privateKey === "object"
) {
const decoded_key = await this.decode_key_pair(parsed_cached_key.publicKey, parsed_cached_key.privateKey);

this.add_key_pair_to_client(kid, decoded_key);
console.info(`Imported Cached key of KID ${kid}`);
} else {
console.warn(`Cached key of KID ${kid} is invalid`);
}
}
}
}
public initialise_from_localstorage = async () => {
this.key_pairs = [];
console.info("Initialising Runtime Client from Localhost");

for (let i = 0; i < window.localStorage.length; i++) {
const item_name = window.localStorage.key(i)!;
if (item_name.startsWith("cached_key-")) {
const cached_key_string =
window.localStorage.getItem(item_name)!;
const parsed_cached_key = JSON.parse(cached_key_string);

const kid = item_name.replace("cached_key-", "");

if (
"publicKey" in parsed_cached_key &&
typeof parsed_cached_key.publicKey === "object" &&
"privateKey" in parsed_cached_key &&
typeof parsed_cached_key.privateKey === "object"
) {
const decoded_key = await this.decode_key_pair(
parsed_cached_key.publicKey,
parsed_cached_key.privateKey,
);

this.add_key_pair_to_client(kid, decoded_key);
console.info(`Imported Cached key of KID ${kid}`);
} else {
console.warn(`Cached key of KID ${kid} is invalid`);
}
}
}
};

private get_key = (kid: string): JailBirdKey | undefined => {
return this.key_pairs.find((val) => val.kid === kid);
Expand All @@ -75,51 +72,56 @@ export class TheAmalgamation {
key,
});

window.localStorage.setItem(`cached_key-${kid}`, JSON.stringify(await this.encode_key_pair(key)));
};
window.localStorage.setItem(
`cached_key-${kid}`,
JSON.stringify(await this.encode_key_pair(key)),
);
};

private encode_key_pair = async (key: CryptoKeyPair) => {
return {
publicKey: await window.crypto.subtle.exportKey(
private encode_key_pair = async (key: CryptoKeyPair) => {
return {
publicKey: await window.crypto.subtle.exportKey(
"jwk",
key.publicKey,
),
privateKey: await window.crypto.subtle.exportKey(
"jwk",
key.privateKey,
),
}
}

private decode_key_pair = async (public_key: object, private_key: object): Promise<CryptoKeyPair> => {
try {
return {
privateKey: await window.crypto.subtle.importKey(
"jwk",
private_key,
{ name: "ECDSA", namedCurve: "P-521" },
true,
private_key_usages,
),
publicKey: await window.crypto.subtle.importKey(
"jwk",
public_key,
{ name: "ECDSA", namedCurve: "P-521" },
true,
public_key_usages,
),
}
} catch (e) {
if (e instanceof TypeError || e instanceof SyntaxError) {
// Invalid Keys
throw new InvalidKeyError();
} else {
// Invalid Use of key usages
throw new InvalidKeyError()
}
}

}
};
};

private decode_key_pair = async (
public_key: object,
private_key: object,
): Promise<CryptoKeyPair> => {
try {
return {
privateKey: await window.crypto.subtle.importKey(
"jwk",
private_key,
{ name: "ECDSA", namedCurve: "P-521" },
true,
private_key_usages,
),
publicKey: await window.crypto.subtle.importKey(
"jwk",
public_key,
{ name: "ECDSA", namedCurve: "P-521" },
true,
public_key_usages,
),
};
} catch (e) {
if (e instanceof TypeError || e instanceof SyntaxError) {
// Invalid Keys
throw new InvalidKeyError();
} else {
// Invalid Use of key usages
throw new InvalidKeyError();
}
}
};

public export_key_for_download = async (
kid: string,
Expand All @@ -129,7 +131,7 @@ export class TheAmalgamation {

return JSON.stringify({
kid,
...this.encode_key_pair(key.key)
...this.encode_key_pair(key.key),
});
};

Expand All @@ -156,8 +158,11 @@ export class TheAmalgamation {
const public_key = deserialised_key.publicKey as JsonWebKey;
const private_key = deserialised_key.privateKey as JsonWebKey;

const decoded_key = await this.decode_key_pair(public_key, private_key);
if (!decoded_key) throw new InvalidKeyError();
const decoded_key = await this.decode_key_pair(
public_key,
private_key,
);
if (!decoded_key) throw new InvalidKeyError();

this.add_key_pair_to_client(kid, decoded_key);
} else {
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/account/account-header-component.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
interface Props {
user: UserType | null;
avatar_size: "default" | "smol";
avatar_size?: "default" | "smol";
}
const { user = null, avatar_size = "default" }: Props = $props();
Expand Down
2 changes: 1 addition & 1 deletion src/lib/components/headers/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import Icons from "../../icons";
import * as Icons from "../../icons";

export const APPLICATION_NAME = "Jail Bird";
export const APPLICATION_ICON = Icons.Lock;
Expand Down
1 change: 1 addition & 0 deletions src/lib/components/ui/sonner/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Toaster } from "./sonner.svelte";
25 changes: 25 additions & 0 deletions src/lib/components/ui/sonner/sonner.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<script lang="ts">
import {
Toaster as Sonner,
type ToasterProps as SonnerProps,
} from "svelte-sonner";
import { mode } from "mode-watcher";
const { ...rest }: SonnerProps = $props();
</script>

<Sonner
theme={$mode}
class="toaster group"
toastOptions={{
classes: {
toast: "group toast group-[.toaster]:bg-background group-[.toaster]:text-foreground group-[.toaster]:border-border group-[.toaster]:shadow-lg",
description: "group-[.toast]:text-muted-foreground",
actionButton:
"group-[.toast]:bg-primary group-[.toast]:text-primary-foreground",
cancelButton:
"group-[.toast]:bg-muted group-[.toast]:text-muted-foreground",
},
}}
{...rest}
/>
13 changes: 13 additions & 0 deletions src/lib/icons/AnimatedLoading.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<script lang="ts">
import { cn } from "$lib/utils";
import type { ClassValue } from "clsx";
import { LoaderCircle } from "lucide-svelte";
interface Props {
class?: ClassValue;
}
const { class: className = undefined }: Props = $props();
</script>

<LoaderCircle class={cn("h-4 w-4 animate-spin", className)} />
5 changes: 2 additions & 3 deletions src/lib/icons/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import Lock from "./lock.svelte";
import AnimatedLoading from "./AnimatedLoading.svelte";

export default {
Lock,
};
export { Lock, AnimatedLoading };

export interface IconProps {
size?: string;
Expand Down
2 changes: 1 addition & 1 deletion src/lib/server/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ sqlite.exec("PRAGMA journal_mode = WAL;");
sqlite.exec("PRAGMA foreign_keys = on;");

export const DB = drizzle(sqlite, {
logger: process.env.NODE_ENV == "development",
logger: process.env.NODE_ENV == "development" && ["1", "true"].includes(process.env.LOGGER_ENABLED ?? ""),
});

/**
Expand Down
4 changes: 4 additions & 0 deletions src/lib/server/trpc/context.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
import type { RequestEvent } from "@sveltejs/kit";

export const createContext = async (event: RequestEvent) => {
const { user, session } = event.locals;

return {
event,
user,
session,
};
};

Expand Down
23 changes: 23 additions & 0 deletions src/lib/server/trpc/middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import { experimental_standaloneMiddleware, TRPCError } from "@trpc/server";

import type { Context } from "./context";

export const authMiddleware = experimental_standaloneMiddleware<{
ctx: Context;
}>().create(async (opts) => {
const { user, session } = opts.ctx;

if (!user || !session) {
throw new TRPCError({
code: "UNAUTHORIZED",
});
} else {
return opts.next({
ctx: {
event: opts.ctx.event,
user,
session,
},
});
}
});
6 changes: 3 additions & 3 deletions src/lib/server/trpc/router/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ const checkAvailability = async (username: string) => {

export const authRouter = trpcInstance.router({
// #region Check Username
check_username_availability: trpcInstance.procedure
checkUsernameAvailability: trpcInstance.procedure
.input(USERNAME_SCHEMA)
.query(async (opts) => {
return {
Expand All @@ -34,7 +34,7 @@ export const authRouter = trpcInstance.router({
}),
// #endregion
// #region Sign Up
sign_up: trpcInstance.procedure
signUp: trpcInstance.procedure
.input(
z.object({
username: USERNAME_SCHEMA,
Expand Down Expand Up @@ -83,7 +83,7 @@ export const authRouter = trpcInstance.router({
}),
// #endregion
// #region Log In
log_in: trpcInstance.procedure
logIn: trpcInstance.procedure
.input(
z.object({
username: USERNAME_SCHEMA,
Expand Down
Loading

0 comments on commit 4c2d260

Please sign in to comment.