Skip to content

Commit 7a96e7b

Browse files
committed
sign cooies
1 parent fc25612 commit 7a96e7b

File tree

4 files changed

+52
-20
lines changed

4 files changed

+52
-20
lines changed

apps/api/src/controllers/gsc-oauth-callback.controller.ts

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -39,23 +39,51 @@ export async function gscGoogleCallback(
3939
}
4040

4141
const { code, state } = query.data;
42-
const storedState = req.cookies.gsc_oauth_state ?? null;
43-
const codeVerifier = req.cookies.gsc_code_verifier ?? null;
44-
const projectId = req.cookies.gsc_project_id ?? null;
45-
46-
const hasStoredState = storedState !== null;
47-
const hasCodeVerifier = codeVerifier !== null;
48-
const hasProjectId = projectId !== null;
49-
const hasAllCookies = hasStoredState && hasCodeVerifier && hasProjectId;
50-
if (!hasAllCookies) {
42+
43+
const rawStoredState = req.cookies.gsc_oauth_state ?? null;
44+
const rawCodeVerifier = req.cookies.gsc_code_verifier ?? null;
45+
const rawProjectId = req.cookies.gsc_project_id ?? null;
46+
47+
const storedStateResult =
48+
rawStoredState !== null ? req.unsignCookie(rawStoredState) : null;
49+
const codeVerifierResult =
50+
rawCodeVerifier !== null ? req.unsignCookie(rawCodeVerifier) : null;
51+
const projectIdResult =
52+
rawProjectId !== null ? req.unsignCookie(rawProjectId) : null;
53+
54+
if (
55+
!(
56+
storedStateResult?.value &&
57+
codeVerifierResult?.value &&
58+
projectIdResult?.value
59+
)
60+
) {
5161
throw new LogError('Missing GSC OAuth cookies', {
52-
storedState: !hasStoredState,
53-
codeVerifier: !hasCodeVerifier,
54-
projectId: !hasProjectId,
62+
storedState: !storedStateResult?.value,
63+
codeVerifier: !codeVerifierResult?.value,
64+
projectId: !projectIdResult?.value,
65+
});
66+
}
67+
68+
if (
69+
!(
70+
storedStateResult?.valid &&
71+
codeVerifierResult?.valid &&
72+
projectIdResult?.valid
73+
)
74+
) {
75+
throw new LogError('Invalid GSC OAuth cookies', {
76+
storedState: !storedStateResult?.value,
77+
codeVerifier: !codeVerifierResult?.value,
78+
projectId: !projectIdResult?.value,
5579
});
5680
}
5781

58-
if (state !== storedState) {
82+
const stateStr = storedStateResult?.value;
83+
const codeVerifierStr = codeVerifierResult?.value;
84+
const projectIdStr = projectIdResult?.value;
85+
86+
if (state !== stateStr) {
5987
throw new LogError('GSC OAuth state mismatch', {
6088
hasState: true,
6189
hasStoredState: true,
@@ -65,7 +93,7 @@ export async function gscGoogleCallback(
6593

6694
const tokens = await googleGsc.validateAuthorizationCode(
6795
code,
68-
codeVerifier
96+
codeVerifierStr
6997
);
7098

7199
const accessToken = tokens.accessToken();
@@ -79,18 +107,20 @@ export async function gscGoogleCallback(
79107
}
80108

81109
const project = await db.project.findUnique({
82-
where: { id: projectId },
110+
where: { id: projectIdStr },
83111
select: { id: true, organizationId: true },
84112
});
85113

86114
if (!project) {
87-
throw new LogError('Project not found for GSC connection', { projectId });
115+
throw new LogError('Project not found for GSC connection', {
116+
projectId: projectIdStr,
117+
});
88118
}
89119

90120
await db.gscConnection.upsert({
91-
where: { projectId },
121+
where: { projectId: projectIdStr },
92122
create: {
93-
projectId,
123+
projectId: projectIdStr,
94124
accessToken: encrypt(accessToken),
95125
refreshToken: encrypt(refreshToken),
96126
accessTokenExpiresAt,
@@ -111,7 +141,7 @@ export async function gscGoogleCallback(
111141

112142
const dashboardUrl =
113143
process.env.DASHBOARD_URL || process.env.NEXT_PUBLIC_DASHBOARD_URL!;
114-
const redirectUrl = `${dashboardUrl}/${project.organizationId}/${projectId}/settings/gsc`;
144+
const redirectUrl = `${dashboardUrl}/${project.organizationId}/${projectIdStr}/settings/gsc`;
115145
return reply.redirect(redirectUrl);
116146
} catch (error) {
117147
req.log.error(error);

packages/trpc/src/routers/gsc.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ export const gscRouter = createTRPCRouter({
9292
url.searchParams.set('access_type', 'offline');
9393
url.searchParams.set('prompt', 'consent');
9494

95-
const cookieOpts = { maxAge: 60 * 10 };
95+
const cookieOpts = { maxAge: 60 * 10, signed: true };
9696
ctx.setCookie('gsc_oauth_state', state, cookieOpts);
9797
ctx.setCookie('gsc_code_verifier', codeVerifier, cookieOpts);
9898
ctx.setCookie('gsc_project_id', input.projectId, cookieOpts);

packages/trpc/src/trpc.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ export async function createContext({ req, res }: CreateFastifyContextOptions) {
3737
// @ts-ignore
3838
res.setCookie(key, value, {
3939
maxAge: options.maxAge,
40+
signed: options.signed,
4041
...COOKIE_OPTIONS,
4142
});
4243
};

packages/validation/src/types.validation.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,5 +112,6 @@ export type ISetCookie = (
112112
sameSite?: 'lax' | 'strict' | 'none';
113113
secure?: boolean;
114114
httpOnly?: boolean;
115+
signed?: boolean;
115116
},
116117
) => void;

0 commit comments

Comments
 (0)