@@ -33,22 +33,66 @@ export const FirebaseProvider: Provider = {
3333 }
3434
3535 if ( ! admin . apps . length ) {
36- let credentialObj : any = null ;
36+ let credentialObj : any = null ;
3737
38- if ( envKey ) {
39- try {
40- credentialObj = JSON . parse ( envKey ) ;
41- } catch ( err ) {
42- console . error ( '[FirebaseProvider] FIREBASE_SERVICE_ACCOUNT_KEY is not valid JSON' , err ) ;
43- }
44- } else if ( envPath ) {
45- try {
46- const file = fs . readFileSync ( String ( envPath ) , 'utf8' ) ;
47- credentialObj = JSON . parse ( file ) ;
48- } catch ( err ) {
49- console . error ( '[FirebaseProvider] Failed to read/parse service account at path:' , String ( envPath ) , err ) ;
38+ const tryParse = ( raw : string | undefined ) : any | null => {
39+ if ( ! raw ) return null ;
40+ let s = raw . trim ( ) ;
41+ // Strip surrounding single/double quotes
42+ if ( ( s . startsWith ( "'" ) && s . endsWith ( "'" ) ) || ( s . startsWith ( '"' ) && s . endsWith ( '"' ) ) ) {
43+ s = s . slice ( 1 , - 1 ) ;
44+ }
45+ // Unescape newline sequences often present when JSON is stored in env vars
46+ s = s . replace ( / \\ n / g, '\n' ) ;
47+
48+ // If it looks like JSON, try parsing directly
49+ if ( s . startsWith ( '{' ) || s . startsWith ( '[' ) ) {
50+ try {
51+ return JSON . parse ( s ) ;
52+ } catch ( err ) {
53+ // continue to other attempts
54+ }
55+ }
56+
57+ // Try base64 decode (common when storing secrets in environment variables)
58+ try {
59+ const decoded = Buffer . from ( s , 'base64' ) . toString ( 'utf8' ) ;
60+ if ( decoded && ( decoded . trim ( ) . startsWith ( '{' ) || decoded . trim ( ) . startsWith ( '[' ) ) ) {
61+ try {
62+ return JSON . parse ( decoded ) ;
63+ } catch ( err ) {
64+ // fallthrough
65+ }
66+ }
67+ } catch ( _ ) {
68+ // not base64 or failed decode
69+ }
70+
71+ return null ;
72+ } ;
73+
74+ if ( envKey ) {
75+ const parsed = tryParse ( envKey ) ;
76+ if ( parsed ) {
77+ credentialObj = parsed ;
78+ } else {
79+ console . error ( '[FirebaseProvider] FIREBASE_SERVICE_ACCOUNT_KEY is not valid JSON or base64-encoded JSON. Sample (truncated):' ,
80+ String ( envKey ) . slice ( 0 , 200 ) + ( String ( envKey ) . length > 200 ? '...[truncated]' : '' )
81+ ) ;
82+ }
83+ } else if ( envPath ) {
84+ try {
85+ const file = fs . readFileSync ( String ( envPath ) , 'utf8' ) ;
86+ const parsed = tryParse ( file ) ?? tryParse ( file . replace ( / \\ n / g, '\n' ) ) ;
87+ if ( parsed ) {
88+ credentialObj = parsed ;
89+ } else {
90+ console . error ( '[FirebaseProvider] Service account file content is not valid JSON:' , String ( envPath ) ) ;
91+ }
92+ } catch ( err ) {
93+ console . error ( '[FirebaseProvider] Failed to read/parse service account at path:' , String ( envPath ) , err ) ;
94+ }
5095 }
51- }
5296
5397 if ( credentialObj ) {
5498 try {
0 commit comments