Files
c0eda46354 feat(mail): withhold new Gmail consents on hosted unless the company is allowlisted (#2320)
Every Gmail consent shows "Google hasn't verified this app" until the
restricted-scope review closes, and a prospect bounced on it today. Jakob's
call: remove the connector in the meantime rather than explain the screen.

New consents are gated by GOOGLE_MAIL_CONNECT_COMPANY_IDS on hosted: unset
means nobody (the default from this deploy on), `*` means everybody (set once
Google approves), a comma list means those companies (the reviewer's demo
company, the company the video is recorded in). Enforced in /oauth/start
(403 connect_disabled) and mirrored as connectEnabled on /connections, so the
settings page drops its connect button and the inbox start card falls back to
plain upload. Existing mailboxes stay listed, keep being searched and can be
disconnected. Self-hosted installs run their own Google app and are never
gated.


Claude-Session: https://claude.ai/code/session_01UD3HsDX8hnJEqpt35azxBJ

Co-authored-by: Jakob Wennberg <311770904+jakobwennberg-oss@users.noreply.github.com>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
2026-09-05 17:51:45 +02:00

40 lines
1.5 KiB
TypeScript

/**
* Who may start a new Gmail consent.
*
* While Google's restricted-scope review is open, every consent on the hosted
* app shows "Google hasn't verified this app", and prospects bounce off it
* (Lumaro AB, 2026-09-05). The connect button is therefore withheld on hosted
* unless the company is on `GOOGLE_MAIL_CONNECT_COMPANY_IDS`:
*
* unset or empty nobody can start a consent (the default while in review)
* `*` everybody (set this once Google has approved the scope)
* `id1,id2` only those companies (the reviewer's demo company, the
* company the demo video is recorded in)
*
* Existing connections are untouched: the hunt keeps searching mailboxes that
* were connected before, and disconnecting still works. Self-hosted installs
* run their own Google app with their own verification status, so the gate
* does not apply there.
*/
import { isSelfHosted } from '@/lib/env/public-flags'
export const MAIL_CONNECT_ALLOWLIST_ENV = 'GOOGLE_MAIL_CONNECT_COMPANY_IDS'
function allowlist(raw: string | undefined): string[] {
if (!raw) return []
return raw
.split(',')
.map((id) => id.trim())
.filter((id) => id.length > 0)
}
export function isMailConnectEnabled(
companyId: string,
raw: string | undefined = process.env[MAIL_CONNECT_ALLOWLIST_ENV],
): boolean {
if (isSelfHosted()) return true
const ids = allowlist(raw)
if (ids.includes('*')) return true
return ids.includes(companyId)
}