Skip to content

Commit

Permalink
feat(user): enforce session check (#646)
Browse files Browse the repository at this point in the history
  • Loading branch information
dipendraupreti committed Apr 25, 2024
1 parent d12f14c commit bc22242
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 58 deletions.
4 changes: 2 additions & 2 deletions packages/user/src/mercurius-auth/authPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import FastifyPlugin from "fastify-plugin";
import mercurius from "mercurius";
import mercuriusAuth from "mercurius-auth";
import emailVerificaiton from "supertokens-node/recipe/emailverification";
import emailVerification from "supertokens-node/recipe/emailverification";

import type { FastifyInstance } from "fastify";

Expand All @@ -18,7 +18,7 @@ const plugin = FastifyPlugin(async (fastify: FastifyInstance) => {

if (
fastify.config.user.features?.signUp?.emailVerification &&
!(await emailVerificaiton.isEmailVerified(context.user.id))
!(await emailVerification.isEmailVerified(context.user.id))
) {
// Added the claim validation errors to match with rest endpoint
// response for email verification
Expand Down
14 changes: 12 additions & 2 deletions packages/user/src/model/users/handlers/changePassword.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { createNewSession } from "supertokens-node/recipe/session";

import getUserService from "../../../lib/getUserService";

import type { ChangePasswordInput } from "../../../types";
Expand All @@ -23,9 +25,17 @@ const changePassword = async (request: SessionRequest, reply: FastifyReply) => {
request.dbSchema
);

const data = await service.changePassword(userId, oldPassword, newPassword);
const response = await service.changePassword(
userId,
oldPassword,
newPassword
);

if (response.status === "OK") {
await createNewSession(request, reply, userId);
}

reply.send(data);
reply.send(response);
} catch (error) {
request.log.error(error);
reply.status(500);
Expand Down
38 changes: 22 additions & 16 deletions packages/user/src/model/users/resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,26 +180,32 @@ const Mutation = {
},
context: MercuriusContext
) => {
const service = getUserService(
context.config,
context.database,
context.dbSchema
);
const { app, config, database, dbSchema, reply, user } = context;

const service = getUserService(config, database, dbSchema);

try {
return context.user?.id
? await service.changePassword(
context.user.id,
arguments_.oldPassword,
arguments_.newPassword
)
: {
status: "NOT_FOUND",
message: "User not found",
};
if (user) {
const response = await service.changePassword(
user.id,
arguments_.oldPassword,
arguments_.newPassword
);

if (response.status === "OK") {
await createNewSession(reply.request, reply, user.id);
}

return response;
} else {
return {
status: "NOT_FOUND",
message: "User not found",
};
}
} catch (error) {
// FIXME [OP 28 SEP 2022]
context.app.log.error(error);
app.log.error(error);

const mercuriusError = new mercurius.ErrorWithProps(
"Oops, Something went wrong"
Expand Down
48 changes: 24 additions & 24 deletions packages/user/src/model/users/service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,30 +18,6 @@ class UserService<
// eslint-disable-next-line prettier/prettier
implements Service<User, UserCreateInput, UserUpdateInput> {

get table() {
return this.config.user?.table?.name || TABLE_USERS;
}

get factory() {
if (!this.table) {
throw new Error(`Service table is not defined`);
}

if (!this._factory) {
this._factory = new UserSqlFactory<
User,
UserCreateInput,
UserUpdateInput
>(this);
}

return this._factory as UserSqlFactory<
User,
UserCreateInput,
UserUpdateInput
>;
}

changePassword = async (
userId: string,
oldPassword: string,
Expand Down Expand Up @@ -104,6 +80,30 @@ class UserService<
};
}
};

get table() {
return this.config.user?.table?.name || TABLE_USERS;
}

get factory() {
if (!this.table) {
throw new Error(`Service table is not defined`);
}

if (!this._factory) {
this._factory = new UserSqlFactory<
User,
UserCreateInput,
UserUpdateInput
>(this);
}

return this._factory as UserSqlFactory<
User,
UserCreateInput,
UserUpdateInput
>;
}
}

export default UserService;
26 changes: 26 additions & 0 deletions packages/user/src/supertokens/recipes/config/session/getSession.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import type { FastifyInstance } from "fastify";
import type { RecipeInterface } from "supertokens-node/recipe/session/types";

const getSession = (
originalImplementation: RecipeInterface,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
fastify: FastifyInstance
): RecipeInterface["getSession"] => {
return async (input) => {
if (originalImplementation.createNewSession === undefined) {
throw new Error("Should never come here");
}

input.options = {
checkDatabase:
fastify.config.user.supertokens.checkSessionInDatabase ?? true,
...input.options,
};

const originalResponse = await originalImplementation.getSession(input);

return originalResponse;
};
};

export default getSession;
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,12 @@ const verifySession = (
throw new Error("Should never come here");
}

input.verifySessionOptions = {
checkDatabase:
fastify.config.user.supertokens.checkSessionInDatabase ?? true,
...input.verifySessionOptions,
};

const originalResponse = await originalImplementation.verifySession(input);

if (originalResponse) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import createNewSession from "./session/createNewSession";
import getSession from "./session/getSession";
import verifySession from "./session/verifySession";

import type { SessionRecipe } from "../../types/sessionRecipe";
Expand Down Expand Up @@ -79,6 +80,7 @@ const getSessionRecipeConfig = (
...originalImplementation,
createNewSession: createNewSession(originalImplementation, fastify),
...recipeInterface,
getSession: getSession(originalImplementation, fastify),
};
},
openIdFeature: session.override?.openIdFeature,
Expand Down
4 changes: 4 additions & 0 deletions packages/user/src/supertokens/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@ interface SupertokensThirdPartyProvider {
}

interface SupertokensConfig {
/**
* @default true
*/
checkSessionInDatabase?: boolean;
connectionUri: string;
providers?: SupertokensThirdPartyProvider;
recipes?: SupertokensRecipes;
Expand Down
16 changes: 2 additions & 14 deletions packages/user/src/userContext.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import mercurius from "mercurius";
import { wrapResponse } from "supertokens-node/framework/fastify";
import { EmailVerificationClaim } from "supertokens-node/recipe/emailverification";
import Session from "supertokens-node/recipe/session";
Expand Down Expand Up @@ -31,20 +30,9 @@ const userContext = async (

userId = session === undefined ? undefined : session.getUserId();
} catch (error) {
if (Session.Error.isErrorFromSuperTokens(error)) {
throw new mercurius.ErrorWithProps(
"Session related error",
{
code: "UNAUTHENTICATED",
http: {
status: error.type === Session.Error.INVALID_CLAIMS ? 403 : 401,
},
},
error.type === Session.Error.INVALID_CLAIMS ? 403 : 401
);
if (!Session.Error.isErrorFromSuperTokens(error)) {
throw error;
}

throw error;
}

if (userId && !context.user) {
Expand Down

0 comments on commit bc22242

Please sign in to comment.