Skip to content

Commit 18f1264

Browse files
committed
fix(email): strip quotes from Google OAuth refresh tokens and verify gmail.compose scope
1 parent 09687f7 commit 18f1264

1 file changed

Lines changed: 37 additions & 10 deletions

File tree

‎apps/site/src/lib/email.ts‎

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -69,24 +69,41 @@ function buildMimeMessage(opts: {
6969
return lines.join("\r\n");
7070
}
7171

72+
function cleanSecret(val: string | undefined): string {
73+
return (val || "").trim().replace(/^["']|["']$/g, "");
74+
}
75+
7276
async function getGoogleGmailAccessToken(): Promise<string | null> {
7377
const workerEnv = (env ?? {}) as unknown as Record<
7478
string,
7579
string | undefined
7680
>;
77-
const clientId = workerEnv.GOOGLE_CLIENT_ID || process.env.GOOGLE_CLIENT_ID;
78-
const clientSecret =
79-
workerEnv.GOOGLE_CLIENT_SECRET || process.env.GOOGLE_CLIENT_SECRET;
80-
const refreshTokens = [
81-
workerEnv.GOOGLE_REFRESH_TOKEN || process.env.GOOGLE_REFRESH_TOKEN,
82-
workerEnv.GOOGLE_WORKSPACE_REFRESH_TOKEN ||
83-
process.env.GOOGLE_WORKSPACE_REFRESH_TOKEN,
84-
].filter(Boolean) as string[];
81+
const clientId = cleanSecret(
82+
workerEnv.GOOGLE_CLIENT_ID || process.env.GOOGLE_CLIENT_ID,
83+
);
84+
const clientSecret = cleanSecret(
85+
workerEnv.GOOGLE_CLIENT_SECRET || process.env.GOOGLE_CLIENT_SECRET,
86+
);
87+
const refreshTokens = Array.from(
88+
new Set(
89+
[
90+
cleanSecret(
91+
workerEnv.GOOGLE_WORKSPACE_REFRESH_TOKEN ||
92+
process.env.GOOGLE_WORKSPACE_REFRESH_TOKEN,
93+
),
94+
cleanSecret(
95+
workerEnv.GOOGLE_REFRESH_TOKEN || process.env.GOOGLE_REFRESH_TOKEN,
96+
),
97+
].filter(Boolean),
98+
),
99+
);
85100

86101
if (!clientId || !clientSecret || refreshTokens.length === 0) {
87102
return null;
88103
}
89104

105+
let fallbackToken: string | null = null;
106+
90107
for (const refreshToken of refreshTokens) {
91108
try {
92109
const res = await fetch("https://oauth2.googleapis.com/token", {
@@ -105,14 +122,24 @@ async function getGoogleGmailAccessToken(): Promise<string | null> {
105122
scope?: string;
106123
};
107124
if (data.access_token) {
108-
return data.access_token;
125+
if (
126+
data.scope &&
127+
(data.scope.includes("gmail.compose") ||
128+
data.scope.includes("gmail.send") ||
129+
data.scope.includes("mail.google.com"))
130+
) {
131+
return data.access_token;
132+
}
133+
if (!fallbackToken) {
134+
fallbackToken = data.access_token;
135+
}
109136
}
110137
} catch {
111138
// try next token
112139
}
113140
}
114141

115-
return null;
142+
return fallbackToken;
116143
}
117144

118145
async function sendViaGmailApi(rawMime: string): Promise<boolean> {

0 commit comments

Comments
 (0)