Bläddra i källkod

Add logging in page

ghorsington 3 år sedan
förälder
incheckning
e96ebbc850

+ 2 - 0
web/package.json

@@ -29,6 +29,7 @@
 	"dependencies": {
 		"@improbable-eng/grpc-web-node-http-transport": "^0.13.0",
 		"compression": "^1.7.4",
+		"cookie-session": "^1.4.0",
 		"dotenv": "^8.2.0",
 		"express": "^4.17.1",
 		"google-protobuf": "^3.13.0",
@@ -58,6 +59,7 @@
 		"@rollup/plugin-replace": "^2.3.3",
 		"@rollup/plugin-typescript": "^5.0.2",
 		"@types/compression": "^1.7.0",
+		"@types/cookie-session": "^2.0.41",
 		"@types/express": "^4.17.7",
 		"@types/node-fetch": "^2.5.7",
 		"@types/nodemailer": "^6.4.0",

+ 5 - 2
web/rollup.config.js

@@ -48,6 +48,11 @@ export default {
                 browser: true,
                 dedupe: ["svelte"],
             }),
+            alias({
+                entries: [
+                    { find: "@shared", replacement: path.join(__dirname, "../shared/lib/src") },
+                ],
+            }),
             commonjs(),
             typescript(),
             json(),
@@ -132,5 +137,3 @@ export default {
         onwarn,
     },
 };
-
-console.log(path.join(__dirname, "../shared/lib/src"));

+ 5 - 0
web/src/cookie.d.ts

@@ -0,0 +1,5 @@
+declare namespace CookieSessionInterfaces {
+    interface CookieSessionObject {
+        authTokenCode?: string;
+    }
+}

+ 0 - 28
web/src/routes/auth.ts

@@ -1,28 +0,0 @@
-import { Request as ExpressRequest, Response as ExpressResponse } from "express";
-import { OAuth2 } from "src/utils/util";
-import { ENVIRONMENT } from "src/utils/environment";
-import { logger } from "src/utils/logging";
-
-interface CodeResponse {
-    code?: string;
-}
-
-export const get = async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
-    const data = req.query as CodeResponse;
-    if (!data.code) {
-        res.redirect("/");
-        return;
-    }
-    const result = await OAuth2.getToken({
-        client_id: ENVIRONMENT.clientId,
-        client_secret: ENVIRONMENT.clientSecret,
-        grant_type: "authorization_code",
-        code: data.code,
-        scope: "identify",
-        redirect_uri: ENVIRONMENT.redirectUrl,
-    });
-    if (result.ok) {
-        logger.info("Got result: %s", result);
-    }
-    res.redirect("/");
-};

+ 1 - 1
web/src/routes/index.svelte

@@ -10,7 +10,7 @@
 	<div class="bg-gray-800 rounded-sm text-center px-20 py-5 shadow-lg">
 		<h1 class="text-white text-4xl font-light">Login</h1>
 		<p class="px-10 py-5">
-			<a class="text-sm bg-blue-700 hover:bg-blue-800 p-2 text-white hover:text-gray-100 rounded-sm" href="/login">
+			<a class="text-sm bg-blue-700 hover:bg-blue-800 p-2 text-white hover:text-gray-100 rounded-sm" href="/login/discord">
 				<Icon data={discordIcon} /> Login with Discord
 			</a>
 		</p>

+ 0 - 12
web/src/routes/login.ts

@@ -1,12 +0,0 @@
-import { Request as ExpressRequest, Response as ExpressResponse } from "express";
-import { OAuth2 } from "src/utils/util";
-import { ENVIRONMENT } from "src/utils/environment";
-
-export const get = async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
-    res.redirect(OAuth2.getAuthUrl({
-        client_id: ENVIRONMENT.clientId,
-        redirect_url: ENVIRONMENT.redirectUrl,
-        response_type: "code",
-        scope: "identify",
-    }));
-};

+ 49 - 0
web/src/routes/login/discord.ts

@@ -0,0 +1,49 @@
+import { Request as ExpressRequest, Response as ExpressResponse } from "express";
+import { OAuth2 } from "src/utils/util";
+import { ENVIRONMENT } from "src/utils/environment";
+import { Option } from "@shared/common/async_utils";
+import { logger } from "src/utils/logging";
+
+export const get = async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
+    res.redirect(OAuth2.getAuthUrl({
+        client_id: ENVIRONMENT.clientId,
+        redirect_url: ENVIRONMENT.redirectUrl,
+        response_type: "code",
+        scope: "identify",
+    }));
+};
+
+type AuthResult = Option<unknown, {error: string}>;
+
+export const post = async (req: ExpressRequest, res: ExpressResponse):
+                                Promise<ExpressResponse<AuthResult>> => {
+    if (!req.session) {
+        logger.error("WEB: req.session is not set up correctly!");
+        return res.json({
+            ok: false,
+            error: "No session is set up. This is a server error!",
+        });
+    }
+    if (!req.session.authTokenCode) {
+        logger.error("WEB: attempted to join with no authTokenCode set!");
+        return res.json({
+            ok: false,
+            error: "Authentication token is missing. Please try logging in again.",
+        });
+    }
+    const result = await OAuth2.getToken({
+        client_id: ENVIRONMENT.clientId,
+        client_secret: ENVIRONMENT.clientSecret,
+        grant_type: "authorization_code",
+        code: req.session.authTokenCode,
+        scope: "identify",
+        redirect_uri: ENVIRONMENT.redirectUrl,
+    });
+    if (!result.ok) {
+        return res.json(result);
+    }
+    req.sessionOptions.maxAge = result.expires_in;
+    return res.json({
+        ok: true,
+    });
+};

+ 36 - 0
web/src/routes/login/discord_auth.svelte

@@ -0,0 +1,36 @@
+<script lang="typescript">
+	import Icon from "svelte-awesome/components/Icon.svelte";
+	import { faSpinner } from "@fortawesome/free-solid-svg-icons";
+    import { onMount } from "svelte";
+    import { Option } from "@shared/common/async_utils";
+    import { goto } from "@sapper/app";
+
+    const spinner = faSpinner as unknown as undefined;
+    let error = "";
+    
+
+    onMount(
+        async () => {
+            const res = await fetch("/login/discord", {
+                method: "post"
+            });
+            const result = await res.json() as Option<unknown, {error: string}>;
+            if (!result.ok) {
+                result.error = error;
+            } else {
+                await goto("/");
+            }
+        }
+    );
+</script>
+
+<div class="flex items-center justify-center bg-gray-900 h-screen w-screen">
+	<div class="bg-gray-800 rounded-sm text-center px-20 py-5 shadow-lg">
+        <h1 class="text-white text-4xl font-light">Logging in</h1>
+        {#if !error}
+            <div class="text-white"><Icon data={spinner} spin scale={1.5} /></div>
+        {:else}
+            <div>Oh nooo!</div>
+        {/if}
+	</div>
+</div>

+ 13 - 0
web/src/routes/login/discord_callback.ts

@@ -0,0 +1,13 @@
+import { Request as ExpressRequest, Response as ExpressResponse } from "express";
+
+interface CodeResponse {
+    code?: string;
+}
+
+export const get = async (req: ExpressRequest, res: ExpressResponse): Promise<void> => {
+    const data = req.query as CodeResponse;
+    if (req.session) {
+        req.session.authTokenCode = data.code;
+    }
+    res.redirect("/login/discord_auth");
+};

+ 17 - 1
web/src/server.ts

@@ -3,6 +3,7 @@ import "src/utils/environment";
 import * as sapper from "@sapper/server"; // eslint-disable-line import/no-unresolved
 import compression from "compression";
 import express, { Express } from "express";
+import session from "cookie-session";
 // @ts-ignore -- doesn't package its own types until 1.0.0-next.6
 import sirv from "sirv";
 import { logger } from "./utils/logging";
@@ -14,13 +15,28 @@ const dev = process.env.NODE_ENV === "development";
 
 logger.info("Staring webserver");
 
+const key = process.env.WEB_COOKIE_KEY;
+
+if (!key) {
+    logger.error("WEB_COOKIE_KEY is not set, cannot run!");
+    process.exit();
+}
+
 const createSapperServer = async (): Promise<Express> => {
     const app = express();
 
     app.use(
+        session({
+            secret: key,
+            name: "session",
+        }),
         compression({ threshold: 0 }),
         sirv("static", { dev }),
-        sapper.middleware(),
+        sapper.middleware({
+            session: (req) => ({
+                userId: req.session?.userId,
+            }),
+        }),
     );
 
     return app;