From 4a3cb7815f3e4ac2ae7dc83d14c85d27a7a3cce9 Mon Sep 17 00:00:00 2001 From: "Kalle (Sendou)" <38327916+Sendouc@users.noreply.github.com> Date: Wed, 17 Nov 2021 01:06:30 +0200 Subject: [PATCH] Add auth --- .env.example | 2 + package-lock.json | 217 +++++++++++++++++++++++++++++++++++++++++++ package.json | 4 + server.ts | 57 +++++++----- utils/trpc-client.ts | 1 + utils/trpc-server.ts | 11 ++- 6 files changed, 265 insertions(+), 27 deletions(-) diff --git a/.env.example b/.env.example index 06ffa2df5..c5a374ac4 100644 --- a/.env.example +++ b/.env.example @@ -6,5 +6,7 @@ DATABASE_URL=postgresql://sendou@localhost:5432/sendou_ink?schema=public DISCORD_CLIENT_ID= DISCORD_CLIENT_SECRET= DISCORD_CALLBACK_URL=http://localhost:3001/auth/discord/callback +COOKIE_SECRET= +FRONTEND_URL=http://localhost:3000 VITE_BACKEND_URL=http://localhost:3001 diff --git a/package-lock.json b/package-lock.json index 192303143..7cad261b9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,9 +12,11 @@ "@prisma/client": "^3.4.2", "@trpc/client": "^9.14.0", "@trpc/server": "^9.14.0", + "cookie-parser": "^1.4.5", "cors": "^2.8.5", "dotenv": "^10.0.0", "express": "^4.17.1", + "express-session": "^1.17.2", "normalize.css": "^8.0.1", "passport": "^0.5.0", "passport-discord": "^0.1.4", @@ -23,8 +25,10 @@ "zod": "^3.11.6" }, "devDependencies": { + "@types/cookie-parser": "^1.4.2", "@types/cors": "^2.8.12", "@types/express": "^4.17.13", + "@types/express-session": "^1.17.4", "@types/faker": "^5.5.9", "@types/node": "^16.11.7", "@types/passport": "^1.0.7", @@ -591,6 +595,15 @@ "@types/node": "*" } }, + "node_modules/@types/cookie-parser": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.2.tgz", + "integrity": "sha512-uwcY8m6SDQqciHsqcKDGbo10GdasYsPCYkH3hVegj9qAah6pX5HivOnOuI3WYmyQMnOATV39zv/Ybs0bC/6iVg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/cors": { "version": "2.8.12", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", @@ -620,6 +633,15 @@ "@types/range-parser": "*" } }, + "node_modules/@types/express-session": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.17.4.tgz", + "integrity": "sha512-7cNlSI8+oOBUHTfPXMwDxF/Lchx5aJ3ho7+p9jJZYVg9dVDJFh3qdMXmJtRsysnvS+C6x46k9DRYmrmCkE+MVg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, "node_modules/@types/faker": { "version": "5.5.9", "resolved": "https://registry.npmjs.org/@types/faker/-/faker-5.5.9.tgz", @@ -1051,6 +1073,18 @@ "node": ">= 0.6" } }, + "node_modules/cookie-parser": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", + "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", + "dependencies": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6" + }, + "engines": { + "node": ">= 0.8.0" + } + }, "node_modules/cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -1489,6 +1523,72 @@ "node": ">= 0.10.0" } }, + "node_modules/express-session": { + "version": "1.17.2", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz", + "integrity": "sha512-mPcYcLA0lvh7D4Oqr5aNJFMtBMKPLl++OKKxkHzZ0U0oDq1rpKBnkR5f5vCHR26VeArlTOEF9td4x5IjICksRQ==", + "dependencies": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.1", + "uid-safe": "~2.1.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/express-session/node_modules/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/express-session/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express-session/node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express-session/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/express-session/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/express/node_modules/debug": { "version": "2.6.9", "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", @@ -1925,6 +2025,14 @@ "node": ">= 0.8" } }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -2061,6 +2169,14 @@ "node": ">=0.6" } }, + "node_modules/random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -2417,6 +2533,17 @@ "node": ">=4.2.0" } }, + "node_modules/uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "dependencies": { + "random-bytes": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/uid2": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.4.tgz", @@ -3023,6 +3150,15 @@ "@types/node": "*" } }, + "@types/cookie-parser": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@types/cookie-parser/-/cookie-parser-1.4.2.tgz", + "integrity": "sha512-uwcY8m6SDQqciHsqcKDGbo10GdasYsPCYkH3hVegj9qAah6pX5HivOnOuI3WYmyQMnOATV39zv/Ybs0bC/6iVg==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, "@types/cors": { "version": "2.8.12", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.12.tgz", @@ -3052,6 +3188,15 @@ "@types/range-parser": "*" } }, + "@types/express-session": { + "version": "1.17.4", + "resolved": "https://registry.npmjs.org/@types/express-session/-/express-session-1.17.4.tgz", + "integrity": "sha512-7cNlSI8+oOBUHTfPXMwDxF/Lchx5aJ3ho7+p9jJZYVg9dVDJFh3qdMXmJtRsysnvS+C6x46k9DRYmrmCkE+MVg==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, "@types/faker": { "version": "5.5.9", "resolved": "https://registry.npmjs.org/@types/faker/-/faker-5.5.9.tgz", @@ -3403,6 +3548,15 @@ "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz", "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" }, + "cookie-parser": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.5.tgz", + "integrity": "sha512-f13bPUj/gG/5mDr+xLmSxxDsB9DQiTIfhJS/sqjrmfAWiAN+x2O4i/XguTL9yDZ+/IFDanJ+5x7hC4CXT9Tdzw==", + "requires": { + "cookie": "0.4.0", + "cookie-signature": "1.0.6" + } + }, "cookie-signature": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", @@ -3705,6 +3859,51 @@ } } }, + "express-session": { + "version": "1.17.2", + "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.17.2.tgz", + "integrity": "sha512-mPcYcLA0lvh7D4Oqr5aNJFMtBMKPLl++OKKxkHzZ0U0oDq1rpKBnkR5f5vCHR26VeArlTOEF9td4x5IjICksRQ==", + "requires": { + "cookie": "0.4.1", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-headers": "~1.0.2", + "parseurl": "~1.3.3", + "safe-buffer": "5.2.1", + "uid-safe": "~2.1.5" + }, + "dependencies": { + "cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, "faker": { "version": "5.5.3", "resolved": "https://registry.npmjs.org/faker/-/faker-5.5.3.tgz", @@ -4016,6 +4215,11 @@ "ee-first": "1.1.1" } }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, "parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -4111,6 +4315,11 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==" }, + "random-bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz", + "integrity": "sha1-T2ih3Arli9P7lYSMMDJNt11kNgs=" + }, "range-parser": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", @@ -4381,6 +4590,14 @@ "integrity": "sha512-DqGhF5IKoBl8WNf8C1gu8q0xZSInh9j1kJJMqT3a94w1JzVaBU4EXOSMrz9yDqMT0xt3selp83fuFMQ0uzv6qA==", "dev": true }, + "uid-safe": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.5.tgz", + "integrity": "sha512-KPHm4VL5dDXKz01UuEd88Df+KzynaohSL9fBh096KWAxSKZQDI2uBrVqtvRM4rwrIrRRKsdLNML/lnaaVSRioA==", + "requires": { + "random-bytes": "~1.0.0" + } + }, "uid2": { "version": "0.0.4", "resolved": "https://registry.npmjs.org/uid2/-/uid2-0.0.4.tgz", diff --git a/package.json b/package.json index c84b50d9d..44607a980 100644 --- a/package.json +++ b/package.json @@ -18,9 +18,11 @@ "@prisma/client": "^3.4.2", "@trpc/client": "^9.14.0", "@trpc/server": "^9.14.0", + "cookie-parser": "^1.4.5", "cors": "^2.8.5", "dotenv": "^10.0.0", "express": "^4.17.1", + "express-session": "^1.17.2", "normalize.css": "^8.0.1", "passport": "^0.5.0", "passport-discord": "^0.1.4", @@ -29,8 +31,10 @@ "zod": "^3.11.6" }, "devDependencies": { + "@types/cookie-parser": "^1.4.2", "@types/cors": "^2.8.12", "@types/express": "^4.17.13", + "@types/express-session": "^1.17.4", "@types/faker": "^5.5.9", "@types/node": "^16.11.7", "@types/passport": "^1.0.7", diff --git a/server.ts b/server.ts index 716bf0ac1..353f51ab0 100644 --- a/server.ts +++ b/server.ts @@ -3,6 +3,8 @@ config(); import cors from "cors"; import express from "express"; +import session from "express-session"; +import cookieParser from "cookie-parser"; import passport from "passport"; import { Strategy as DiscordStrategy } from "passport-discord"; import { tournament as tournamentRouter } from "./scenes/tournament/router"; @@ -13,20 +15,9 @@ import { upsertUser } from "./scenes/layout/service"; const PORT = 3001; export const appRouter = createRouter().merge("tournament.", tournamentRouter); - export type AppRouter = typeof appRouter; async function main() { - const app = express(); - - app.use(cors()); - - app.use((req, _res, next) => { - console.log("⬅️ ", req.method, req.path, req.body ?? req.query); - - next(); - }); - passport.use( new DiscordStrategy( { @@ -36,7 +27,7 @@ async function main() { scope: ["identify", "connections"], }, function (_accessToken, refreshToken, loggedInUser, cb) { - upsertUser({ loggedInUser, refreshToken: refreshToken }) + upsertUser({ loggedInUser, refreshToken }) .then((user) => { return cb(null, { id: user.id, @@ -50,12 +41,41 @@ async function main() { ); passport.serializeUser(function (user, done) { - console.log("user", user); done(null, user); }); passport.deserializeUser(function (user, done) { - done(null, user as any); + // @ts-expect-error it is guaranteed it's of a certain shape without an extra check + done(null, user); + }); + + const app = express(); + + app.use(cors({ origin: process.env.FRONTEND_URL, credentials: true })); + + app.use(cookieParser()); + app.use( + session({ + secret: process.env.COOKIE_SECRET!, + resave: true, + saveUninitialized: true, + }) + ); + app.use(passport.initialize()); + app.use(passport.session()); + app.post("/auth/discord", passport.authenticate("discord")); + app.get( + "/auth/discord/callback", + passport.authenticate("discord", { + failureRedirect: "/login", + successRedirect: process.env.FRONTEND_URL, + }) + ); + + app.use((req, _res, next) => { + console.log("⬅️ ", req.method, req.path, req.body ?? req.query); + + next(); }); app.use( @@ -66,15 +86,6 @@ async function main() { }) ); - app.use(passport.initialize()); - app.get("/auth/discord", passport.authenticate("discord")).get( - "/auth/discord/callback", - passport.authenticate("discord", { - failureRedirect: "/login", - successRedirect: "http://localhost:3000/", - }) - ); - app.listen(PORT, () => { console.log(`listening on port ${PORT}`); }); diff --git a/utils/trpc-client.ts b/utils/trpc-client.ts index 78cc1d987..fd567d33e 100644 --- a/utils/trpc-client.ts +++ b/utils/trpc-client.ts @@ -4,6 +4,7 @@ import type { AppRouter } from "../server"; export const trpcClient = createTRPCClient({ url: `${import.meta.env.VITE_BACKEND_URL}/trpc`, + fetch: (input, init) => fetch(input, { ...init, credentials: "include" }), }); export type InferQueryOutput< diff --git a/utils/trpc-server.ts b/utils/trpc-server.ts index c5932f664..42f70997d 100644 --- a/utils/trpc-server.ts +++ b/utils/trpc-server.ts @@ -6,11 +6,14 @@ export const createContext = ({ res, }: trpcExpress.CreateExpressContextOptions) => { const getUser = () => { - if (req.headers.authorization !== "secret") { - return null; + console.log("req.user", req.user); + if (req.user !== "secret") { + return; } - return { - name: "alex", + return req.user as { + id: number; + discordId: string; + discordAvatar?: string; }; };