diff --git a/.env.example b/.env.example index e69de29..435b3ca 100644 --- a/.env.example +++ b/.env.example @@ -0,0 +1,9 @@ +AUTH_SECRET= + +MYSQL_HOST= +MYSQL_USERNAME= +MYSQL_PASSWORD= + +KEYCLOAK_CLIENT_ID= +KEYCLOAK_CLIENT_SECRET= +KEYCLOAK_CLIENT_ISSUER= \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 664bd14..3fdee6c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -31,5 +31,4 @@ COPY --from=build /usr/src/app/package.json . COPY --from=build /usr/src/app/build/ . EXPOSE 3000/tcp -CMD [ "node", "index.js" ] - +CMD [ "node", "index.js" ] \ No newline at end of file diff --git a/README.md b/README.md index 3ef1d2b..86416e7 100644 --- a/README.md +++ b/README.md @@ -5,3 +5,11 @@ [![forthebadge](https://forthebadge.com/images/badges/license-mit.svg)](https://forthebadge.com) [![forthebadge](https://forthebadge.com/images/badges/designed-in-ms-paint.svg)](https://forthebadge.com) [![forthebadge](https://forthebadge.com/images/badges/gluten-free.svg)](https://forthebadge.com) [![forthebadge](https://forthebadge.com/images/badges/powered-by-black-magic.svg)](https://forthebadge.com) A file uploading website. + +## Developing + +You can start a development SQL server with Docker: + +```sh +sudo docker run -e MYSQL_ROOT_PASSWORD=development -e MYSQL_DATABASE=fileuploader -d mysql:latest +``` diff --git a/drizzle.config.js b/drizzle.config.js new file mode 100644 index 0000000..ba983af --- /dev/null +++ b/drizzle.config.js @@ -0,0 +1,11 @@ +/** @type { import("drizzle-kit").Config } */ +export default { + schema: 'src/lib/server/database/schema.js', + driver: 'mysql2', + dbCredentials: { + host: process.env.MYSQL_HOST, + user: process.env.MYSQL_USERNAME, + password: process.env.MYSQL_PASSWORD, + database: 'fileuploader' + } +}; diff --git a/package.json b/package.json index b35a293..497513c 100644 --- a/package.json +++ b/package.json @@ -25,6 +25,9 @@ }, "type": "module", "dependencies": { + "@auth/core": "^0.28.0", + "@auth/drizzle-adapter": "^0.8.0", + "@auth/sveltekit": "^0.14.0", "drizzle-orm": "^0.30.2", "lucide-svelte": "^0.358.0", "mysql2": "^3.9.2", diff --git a/src/hooks.server.js b/src/hooks.server.js index 93f91a4..fbb46ba 100644 --- a/src/hooks.server.js +++ b/src/hooks.server.js @@ -1,12 +1,25 @@ +// import { redirect } from '@sveltejs/kit'; +import { sequence } from '@sveltejs/kit/hooks'; +import { handle as authenticationHandle } from '$lib/server/auth.js'; + +async function authorizationHandle({ event, resolve }) { + // if (event.url.pathname.startsWith('/(app)')) { + // const session = await event.locals.auth(); + // if (!session) { + // throw redirect(303, '/auth/signin'); + // } + // } + + return resolve(event); +} + +export const handle = sequence(authenticationHandle, authorizationHandle); + /** @type {import('@sveltejs/kit').HandleServerError} */ export async function handleError({ error, event, status, message }) { - - console.log(error) - - const id = crypto.randomUUID(); + console.log(error); return { - id, status, message }; diff --git a/src/lib/components/LoggedOut.svelte b/src/lib/components/LoggedOut.svelte new file mode 100644 index 0000000..4a9e398 --- /dev/null +++ b/src/lib/components/LoggedOut.svelte @@ -0,0 +1,30 @@ + + +
+
+
+
+ +
+

Currently hosting 0 files.

+

Elon musk found dead in a pool

+
+ +
+ + + +
+
+
diff --git a/src/lib/server/auth.js b/src/lib/server/auth.js new file mode 100644 index 0000000..2ac5ac2 --- /dev/null +++ b/src/lib/server/auth.js @@ -0,0 +1,23 @@ +import { SvelteKitAuth } from '@auth/sveltekit'; +import Keycloak from '@auth/core/providers/keycloak'; +import { DrizzleAdapter } from '@auth/drizzle-adapter'; +import { db } from '$lib/server/database'; +import { env } from '$env/dynamic/private'; + +export const { handle, signIn, signOut } = SvelteKitAuth({ + adapter: DrizzleAdapter(db), + providers: [ + Keycloak({ + clientId: env.KEYCLOAK_CLIENT_ID, + clientSecret: env.KEYCLOAK_CLIENT_SECRET, + issuer: env.KEYCLOAK_ISSUER, + profile(profile) { + return { + id: profile.sub, + name: profile.preferred_username, + email: profile.email + }; + } + }) + ] +}); diff --git a/src/lib/server/database/index.js b/src/lib/server/database/index.js new file mode 100644 index 0000000..e9902bc --- /dev/null +++ b/src/lib/server/database/index.js @@ -0,0 +1,13 @@ +import { drizzle } from 'drizzle-orm/mysql2'; +import mysql from 'mysql2/promise'; +import { env } from '$env/dynamic/private'; +import * as schema from './schema'; + +const connection = await mysql.createConnection({ + host: env.MYSQL_HOST, + user: env.MYSQL_USERNAME, + password: env.MYSQL_PASSWORD, + database: 'fileuploader' +}); + +export const db = drizzle(connection, { schema, mode: 'default' }); diff --git a/src/lib/server/database/schema.js b/src/lib/server/database/schema.js new file mode 100644 index 0000000..614ee8e --- /dev/null +++ b/src/lib/server/database/schema.js @@ -0,0 +1,53 @@ +import { int, timestamp, mysqlTable, primaryKey, varchar } from 'drizzle-orm/mysql-core'; + +export const users = mysqlTable('user', { + id: varchar('id', { length: 255 }).notNull().primaryKey(), + name: varchar('name', { length: 255 }), + email: varchar('email', { length: 255 }).notNull(), + emailVerified: timestamp('emailVerified', { mode: 'date', fsp: 3 }).defaultNow(), + image: varchar('image', { length: 255 }) +}); + +export const accounts = mysqlTable( + 'account', + { + userId: varchar('userId', { length: 255 }) + .notNull() + .references(() => users.id, { onDelete: 'cascade' }), + type: varchar('type', { length: 255 }).notNull(), + provider: varchar('provider', { length: 255 }).notNull(), + providerAccountId: varchar('providerAccountId', { length: 255 }).notNull(), + refresh_token: varchar('refresh_token', { length: 2048 }), + access_token: varchar('access_token', { length: 2048 }), + expires_at: int('expires_at'), + token_type: varchar('token_type', { length: 255 }), + scope: varchar('scope', { length: 255 }), + id_token: varchar('id_token', { length: 2048 }), + session_state: varchar('session_state', { length: 255 }) + }, + (account) => ({ + compoundKey: primaryKey({ + columns: [account.provider, account.providerAccountId] + }) + }) +); + +export const sessions = mysqlTable('session', { + sessionToken: varchar('sessionToken', { length: 255 }).notNull().primaryKey(), + userId: varchar('userId', { length: 255 }) + .notNull() + .references(() => users.id, { onDelete: 'cascade' }), + expires: timestamp('expires', { mode: 'date' }).notNull() +}); + +export const verificationTokens = mysqlTable( + 'verificationToken', + { + identifier: varchar('identifier', { length: 255 }).notNull(), + token: varchar('token', { length: 255 }).notNull(), + expires: timestamp('expires', { mode: 'date' }).notNull() + }, + (vt) => ({ + compoundKey: primaryKey({ columns: [vt.identifier, vt.token] }) + }) +); diff --git a/src/lib/server/db/index.js b/src/lib/server/db/index.js deleted file mode 100644 index e595849..0000000 --- a/src/lib/server/db/index.js +++ /dev/null @@ -1,10 +0,0 @@ -import { drizzle } from 'drizzle-orm/mysql2'; -import mysql from 'mysql2/promise'; - -const connection = await mysql.createConnection({ - host: process.env.DATABASE_HOST, - user: process.env.DATABASE_USER, - password: process.env.DATABASE_PASSWORD -}); - -export default drizzle(connection); diff --git a/src/lib/server/db/schema.js b/src/lib/server/db/schema.js deleted file mode 100644 index 7cb9355..0000000 --- a/src/lib/server/db/schema.js +++ /dev/null @@ -1,7 +0,0 @@ -import { int, mysqlTable, text } from 'drizzle-orm/mysql-core'; - -export const users = mysqlTable('users', { - id: int('id').autoincrement().primaryKey(), - username: text('username').unique().notNull(), - password: text('password').notNull() -}); diff --git a/src/routes/+layout.server.js b/src/routes/+layout.server.js new file mode 100644 index 0000000..1722a47 --- /dev/null +++ b/src/routes/+layout.server.js @@ -0,0 +1,5 @@ +export const load = async ({ locals }) => { + return { + session: await locals.getSession() + }; +}; diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 14609cc..5348a3f 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -2,8 +2,10 @@ import '../app.css'; import { Toaster } from 'svelte-sonner'; + import { page } from '$app/stores'; import { darkMode } from '$lib/stores.js'; + import LoggedOut from '$lib/components/LoggedOut.svelte'; import ThemeHandler from '$lib/components/ThemeHandler.svelte'; import PageMeta from '$lib/components/PageMeta.svelte'; @@ -12,6 +14,10 @@ -
- -
+{#if $page.data.session?.user} +
+ +
+{:else} + +{/if} diff --git a/src/routes/+page.svelte b/src/routes/+page.svelte index a111283..76a4b2d 100644 --- a/src/routes/+page.svelte +++ b/src/routes/+page.svelte @@ -1,45 +1,16 @@ -
-
-
-
- -
-

Currently hosting 0 files.

-

Elon musk found dead in a pool

-
+

+ + {JSON.stringify($page.data?.session, null, 4)} + +

-
- - - - -

Login

- - - - -

Register

- -
- -
- -
-
-
+ diff --git a/src/routes/login/+page.svelte b/src/routes/login/+page.svelte deleted file mode 100644 index 38d75bc..0000000 --- a/src/routes/login/+page.svelte +++ /dev/null @@ -1,36 +0,0 @@ - - -
-
-
- -
-
-
- - - - - - -
- - -
-
-
-
-
diff --git a/src/routes/register/+page.svelte b/src/routes/register/+page.svelte deleted file mode 100644 index 65d10c6..0000000 --- a/src/routes/register/+page.svelte +++ /dev/null @@ -1,47 +0,0 @@ - - -
-
-
- -
-
-
- - - - - - - - - - - - -
- - -
-
-
-
-
diff --git a/yarn.lock b/yarn.lock index de20266..5d4b76b 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,6 +15,34 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" +"@auth/core@0.28.0", "@auth/core@^0.28.0": + version "0.28.0" + resolved "https://registry.yarnpkg.com/@auth/core/-/core-0.28.0.tgz#3e3aa723062e3f1daf28eb47688db622bf119396" + integrity sha512-/fh/tb/L4NMSYcyPoo4Imn8vN6MskcVfgESF8/ndgtI4fhD/7u7i5fTVzWgNRZ4ebIEGHNDbWFRxaTu1NtQgvA== + dependencies: + "@panva/hkdf" "^1.1.1" + "@types/cookie" "0.6.0" + cookie "0.6.0" + jose "^5.1.3" + oauth4webapi "^2.4.0" + preact "10.11.3" + preact-render-to-string "5.2.3" + +"@auth/drizzle-adapter@^0.8.0": + version "0.8.0" + resolved "https://registry.yarnpkg.com/@auth/drizzle-adapter/-/drizzle-adapter-0.8.0.tgz#a2d5a84528d0398d7853a0dde6d661a58b40b2d5" + integrity sha512-cwLMOJHf+R8VeHYFzdA5DReKelidWSx8bz9kJ6hydPjUugHate2F7u9XHoCOu7zXIA5azSPb3b2WR9C0Fjq7eA== + dependencies: + "@auth/core" "0.28.0" + +"@auth/sveltekit@^0.14.0": + version "0.14.0" + resolved "https://registry.yarnpkg.com/@auth/sveltekit/-/sveltekit-0.14.0.tgz#4d410f67b53fe398a2e5df121c7438d2f8c13d89" + integrity sha512-I4ec4hcL4BTHgebJ1KvjX/8VclLuJAkcJdPwH0BOGt20qlu+wipI7EQjJy6EG2s4p0cAEWaIGGKFhMZIUfb+1Q== + dependencies: + "@auth/core" "0.28.0" + set-cookie-parser "^2.6.0" + "@drizzle-team/studio@^0.0.39": version "0.0.39" resolved "https://registry.yarnpkg.com/@drizzle-team/studio/-/studio-0.0.39.tgz#70e9155503f7343e8f1917d316f93e64c23760e1" @@ -328,6 +356,11 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" +"@panva/hkdf@^1.1.1": + version "1.1.1" + resolved "https://registry.yarnpkg.com/@panva/hkdf/-/hkdf-1.1.1.tgz#ab9cd8755d1976e72fc77a00f7655a64efe6cd5d" + integrity sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA== + "@pkgjs/parseargs@^0.11.0": version "0.11.0" resolved "https://registry.yarnpkg.com/@pkgjs/parseargs/-/parseargs-0.11.0.tgz#a77ea742fab25775145434eb1d2328cf5013ac33" @@ -498,7 +531,7 @@ svelte-hmr "^0.15.3" vitefu "^0.2.5" -"@types/cookie@^0.6.0": +"@types/cookie@0.6.0", "@types/cookie@^0.6.0": version "0.6.0" resolved "https://registry.yarnpkg.com/@types/cookie/-/cookie-0.6.0.tgz#eac397f28bf1d6ae0ae081363eca2f425bedf0d5" integrity sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA== @@ -712,7 +745,7 @@ commondir@^1.0.1: resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" integrity sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg== -cookie@^0.6.0: +cookie@0.6.0, cookie@^0.6.0: version "0.6.0" resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051" integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw== @@ -1257,6 +1290,11 @@ jiti@^1.19.1: resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d" integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q== +jose@^5.1.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/jose/-/jose-5.2.3.tgz#071c87f9fe720cff741a403c8080b69bfe13164a" + integrity sha512-KUXdbctm1uHVL8BYhnyHkgp3zDX5KW8ZhAKVFEfUbU2P8Alpzjb+48hHvjOdQIyPshoblhzsuqOwEEAbtHVirA== + json-diff@0.9.0: version "0.9.0" resolved "https://registry.yarnpkg.com/json-diff/-/json-diff-0.9.0.tgz#e7c536798053cb409113d7403c774849e8a0d7ff" @@ -1470,6 +1508,11 @@ normalize-range@^0.1.2: resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" integrity sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA== +oauth4webapi@^2.4.0: + version "2.10.3" + resolved "https://registry.yarnpkg.com/oauth4webapi/-/oauth4webapi-2.10.3.tgz#8e6d5a8a984a297dd80276a6c52634359319d034" + integrity sha512-9FkXEXfzVKzH63GUOZz1zMr3wBaICSzk6DLXx+CGdrQ10ItNk2ePWzYYc1fdmKq1ayGFb2aX97sRCoZ2s0mkDw== + object-assign@^4.0.1: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -1587,6 +1630,18 @@ postcss@^8.4.23, postcss@^8.4.35: picocolors "^1.0.0" source-map-js "^1.0.2" +preact-render-to-string@5.2.3: + version "5.2.3" + resolved "https://registry.yarnpkg.com/preact-render-to-string/-/preact-render-to-string-5.2.3.tgz#23d17376182af720b1060d5a4099843c7fe92fe4" + integrity sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA== + dependencies: + pretty-format "^3.8.0" + +preact@10.11.3: + version "10.11.3" + resolved "https://registry.yarnpkg.com/preact/-/preact-10.11.3.tgz#8a7e4ba19d3992c488b0785afcc0f8aa13c78d19" + integrity sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg== + prettier-plugin-svelte@^3.1.2: version "3.2.2" resolved "https://registry.yarnpkg.com/prettier-plugin-svelte/-/prettier-plugin-svelte-3.2.2.tgz#df576c8a92088dc0aaec8e27fce8a7d9683de93c" @@ -1597,6 +1652,11 @@ prettier@^3.1.1: resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368" integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A== +pretty-format@^3.8.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-3.8.0.tgz#bfbed56d5e9a776645f4b1ff7aa1a3ac4fa3c385" + integrity sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew== + queue-microtask@^1.2.2: version "1.2.3" resolved "https://registry.yarnpkg.com/queue-microtask/-/queue-microtask-1.2.3.tgz#4929228bbc724dfac43e0efb058caf7b6cfb6243"