File tree Expand file tree Collapse file tree
Expand file tree Collapse file tree Original file line number Diff line number Diff line change 99IMAGE_UPLOAD_URL=
1010UPLOAD_BUCKET_NAME=
1111UPLOAD_SIZE_LIMIT=
12+ # Comma-separated full email addresses allowed in addition to @cornell.edu (case-insensitive)
13+ EMAIL_WHITELIST=
Original file line number Diff line number Diff line change 77import { firebaseAdmin } from "../../firebase" ;
88import { getManager } from "typeorm" ;
99import { UserModel } from "../../models/UserModel" ;
10+ import { isAllowedLoginEmail } from "../../utils/allowlistedEmail" ;
1011
1112export const FirebaseCurrentUserChecker = async (
1213 action : Action ,
@@ -25,9 +26,10 @@ export const FirebaseCurrentUserChecker = async (
2526 const decodedToken = await firebaseAdmin . auth ( ) . verifyIdToken ( token ) ;
2627 const userId = decodedToken . uid ;
2728 const email = decodedToken . email ;
28- // Enforce Cornell email domain restriction
29- if ( email && ! email . endsWith ( "@cornell.edu" ) ) {
30- throw new ForbiddenError ( "Only Cornell email addresses are allowed" ) ;
29+ if ( ! isAllowedLoginEmail ( email ) ) {
30+ throw new ForbiddenError (
31+ "Only Cornell email addresses or allowlisted emails are allowed" ,
32+ ) ;
3133 }
3234 // Fetch and return the user from the database
3335 const user = await getManager ( ) . findOne ( UserModel , {
Original file line number Diff line number Diff line change @@ -26,6 +26,7 @@ import resellConnection from './utils/DB';
2626import { ReportService } from './services/ReportService' ;
2727import { reportToString } from './utils/Requests' ;
2828import { startTransactionConfirmationCron } from './cron/transactionCron' ;
29+ import { isAllowedLoginEmail } from './utils/allowlistedEmail' ;
2930
3031// Setup dependency injection containers
3132routingUseContainer ( Container ) ;
@@ -56,13 +57,14 @@ async function main() {
5657 try {
5758 // Verify the token using Firebase Admin SDK
5859 const decodedToken = await admin . auth ( ) . verifyIdToken ( token ) ;
59- // Check if the email is a Cornell email
6060 const email = decodedToken . email ;
6161 const userId = decodedToken . uid ;
6262 action . request . email = email ;
6363 action . request . firebaseUid = userId ;
64- if ( ! email || ! email . endsWith ( "@cornell.edu" ) ) {
65- throw new ForbiddenError ( "Only Cornell email addresses are allowed" ) ;
64+ if ( ! isAllowedLoginEmail ( email ) ) {
65+ throw new ForbiddenError (
66+ "Only Cornell email addresses or allowlisted emails are allowed" ,
67+ ) ;
6668 }
6769 // Find or create user in your database using Firebase UID
6870 const manager = getManager ( ) ;
Original file line number Diff line number Diff line change 1+ const CORNELL_SUFFIX = "@cornell.edu" ;
2+
3+ function normalizeEmail ( email : string ) : string {
4+ return email . trim ( ) . toLowerCase ( ) ;
5+ }
6+
7+ /** Full addresses from EMAIL_WHITELIST (comma-separated), lowercased. */
8+ export function getEmailWhitelist ( ) : Set < string > {
9+ const raw = process . env . EMAIL_WHITELIST ?? "" ;
10+ const set = new Set < string > ( ) ;
11+ for ( const part of raw . split ( "," ) ) {
12+ const normalized = normalizeEmail ( part ) ;
13+ if ( normalized . length > 0 ) {
14+ set . add ( normalized ) ;
15+ }
16+ }
17+ return set ;
18+ }
19+
20+ /**
21+ * True if the Firebase user email may use the API: @cornell.edu or listed in EMAIL_WHITELIST.
22+ * When true, `email` is a non-empty string.
23+ */
24+ export function isAllowedLoginEmail (
25+ email : string | undefined ,
26+ whitelist : Set < string > = getEmailWhitelist ( ) ,
27+ ) : email is string {
28+ if ( ! email ) {
29+ return false ;
30+ }
31+ const e = normalizeEmail ( email ) ;
32+ if ( e . endsWith ( CORNELL_SUFFIX ) ) {
33+ return true ;
34+ }
35+ return whitelist . has ( e ) ;
36+ }
You can’t perform that action at this time.
0 commit comments