updated context

This commit is contained in:
lnn0q 2025-03-23 21:27:14 +02:00
parent 04b606b7fa
commit 40c35bda13
7 changed files with 67 additions and 25 deletions

1
.gitignore vendored
View file

@ -13,6 +13,7 @@ dist-ssr
*.local *.local
.env .env
__generated__/ __generated__/
vite.config.ts.timestamp-*.mjs
# Editor directories and files # Editor directories and files

View file

@ -1,9 +1,14 @@
import { IdentityContext } from '@app/server/identity';
import { prisma } from '@app/server/prisma/client'; import { prisma } from '@app/server/prisma/client';
import { MutationLoginArgs, Session } from '@generated/types'; import { MutationLoginArgs, Session } from '@generated/types';
import bcrypt from 'bcrypt'; import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken'; import jwt from 'jsonwebtoken';
export async function LoginResolver(_: any, { input }: MutationLoginArgs): Promise<Session> { export async function LoginResolver(
_: any,
{ input }: MutationLoginArgs,
{ identity }: IdentityContext
): Promise<Session> {
const error = 'Invalid username or password'; const error = 'Invalid username or password';
const user = await prisma.user.findUnique({ const user = await prisma.user.findUnique({

View file

@ -1,8 +1,13 @@
import { IdentityContext } from '@app/server/identity';
import { prisma, uuid } from '@app/server/prisma/client'; import { prisma, uuid } from '@app/server/prisma/client';
import { RegisterInput } from '@generated/types'; import { RegisterInput } from '@generated/types';
import bcrypt from 'bcrypt'; import bcrypt from 'bcrypt';
export async function SignUpResolver(_: any, input: RegisterInput): Promise<void> { export async function SignUpResolver(
_: any,
input: RegisterInput,
{ identity }: IdentityContext
): Promise<void> {
const existingUsername = await prisma.user.findUnique({ const existingUsername = await prisma.user.findUnique({
where: { username: input.username }, where: { username: input.username },
select: { id: true } select: { id: true }

View file

@ -1,7 +1,12 @@
import { IdentityContext } from '@app/server/identity';
import { Book, QueryBookOneArgs } from '@generated/types'; import { Book, QueryBookOneArgs } from '@generated/types';
import { books } from './booksManyResolver'; import { books } from './booksManyResolver';
export async function BookOneResolver(_: any, { id }: QueryBookOneArgs): Promise<Book> { export async function BookOneResolver(
_: any,
{ id }: QueryBookOneArgs,
{ identity }: IdentityContext
): Promise<Book> {
const book = books.filter(item => item.id === id)[0]; const book = books.filter(item => item.id === id)[0];
return book; return book;

View file

@ -1,3 +1,4 @@
import { IdentityContext } from '@app/server/identity';
import { Book } from '@generated/types'; import { Book } from '@generated/types';
export const books = [ export const books = [
@ -13,6 +14,10 @@ export const books = [
} }
]; ];
export async function BooksManyResolver(_: any): Promise<Book[]> { export async function BooksManyResolver(
_: any,
__: any,
{ identity }: IdentityContext
): Promise<Book[]> {
return books; return books;
} }

39
app/server/identity.ts Normal file
View file

@ -0,0 +1,39 @@
import 'dotenv/config';
import { Request, Response } from 'express';
import jwt from 'jsonwebtoken';
import { prisma } from './prisma/client';
export interface IdentityContext {
identity?: {
id: string;
username: string;
};
}
export async function getIdentityContext({
req,
res
}: {
req: Request;
res: Response;
}): Promise<IdentityContext> {
const authHeader = req.headers.authorization;
if (authHeader == null) return {};
const token = authHeader.split(' ')[1];
const accessTokenSecret = process.env.ACCESS_TOKEN_SECRET;
if (accessTokenSecret == null) throw new Error('No `accessToken`.');
const decoded = jwt.verify(token, accessTokenSecret) as { userId: string };
const identity = await prisma.user.findUnique({
where: { id: decoded.userId },
select: {
id: true,
email: true,
username: true
}
});
if (identity == null) throw new Error("Couldn't find the user.");
return { identity };
}

View file

@ -3,15 +3,14 @@ import { expressMiddleware } from '@apollo/server/express4';
import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer'; import { ApolloServerPluginDrainHttpServer } from '@apollo/server/plugin/drainHttpServer';
import cors from 'cors'; import cors from 'cors';
import 'dotenv/config'; import 'dotenv/config';
import express, { Request, Response } from 'express'; import express from 'express';
import fs from 'fs'; import fs from 'fs';
import http from 'http'; import http from 'http';
import jwt from 'jsonwebtoken';
import path from 'path'; import path from 'path';
import ViteExpress from 'vite-express'; import ViteExpress from 'vite-express';
import { getIdentityContext, IdentityContext } from './identity';
import { Mutation, Query } from './graphql/graphql'; import { Mutation, Query } from './graphql/graphql';
import { prisma } from './prisma/client';
const __dirname = import.meta.dirname; const __dirname = import.meta.dirname;
const HOST = process.env.VITE_HOST || 'localhost'; const HOST = process.env.VITE_HOST || 'localhost';
@ -29,10 +28,6 @@ const resolvers = {
// Subscription, // Subscription,
}; };
interface IdentityContext {
authScope?: String;
}
const apollo = new ApolloServer<IdentityContext>({ const apollo = new ApolloServer<IdentityContext>({
typeDefs, typeDefs,
resolvers, resolvers,
@ -46,7 +41,7 @@ app.use(
cors<cors.CorsRequest>(), cors<cors.CorsRequest>(),
express.json(), express.json(),
expressMiddleware(apollo, { expressMiddleware(apollo, {
context: getUser context: getIdentityContext
}) })
); );
@ -55,16 +50,3 @@ await new Promise<void>(resolve => server.listen({ hostname: HOST, port: PORT },
process.stdout.write(MOTD); process.stdout.write(MOTD);
ViteExpress.bind(app, server); ViteExpress.bind(app, server);
async function getUser({ req, res }: { req: Request; res: Response }) {
const authHeader = req.headers.authorization;
if (!authHeader) return { identity: null };
const token = authHeader.split(' ')[1];
const accessTokenSecret = process.env.ACCESS_TOKEN_SECRET;
if (accessTokenSecret == null) throw Error('No `accessToken`');
const decoded = jwt.verify(token, accessTokenSecret) as { userId: string };
const identity = await prisma.user.findUnique({ where: { id: decoded.userId } });
return { identity };
}