@@ -122,11 +122,49 @@ describe('AppCheckTokenGenerator', () => {
122122 } ) . to . throw ( FirebaseAppCheckError ) . with . property ( 'code' , 'app-check/invalid-argument' ) ;
123123 } ) ;
124124
125- it ( 'should be fulfilled with a Firebase Custom JWT' , ( ) => {
125+ const invalidOptions = [ null , NaN , 0 , 1 , true , false , [ ] , _ . noop ] ;
126+ invalidOptions . forEach ( ( invalidOption ) => {
127+ it ( 'should throw given an invalid options: ' + JSON . stringify ( invalidOption ) , ( ) => {
128+ expect ( ( ) => {
129+ tokenGenerator . createCustomToken ( APP_ID , invalidOption as any ) ;
130+ } ) . to . throw ( FirebaseAppCheckError ) . with . property ( 'message' , 'AppCheckTokenOptions must be a non-null object.' ) ;
131+ } ) ;
132+ } ) ;
133+
134+ const invalidTtls = [ null , NaN , '0' , 'abc' , '' , - 100 , - 1 , true , false , [ ] , { } , { a : 1 } , _ . noop ] ;
135+ invalidTtls . forEach ( ( invalidTtl ) => {
136+ it ( 'should throw given an options object with invalid ttl: ' + JSON . stringify ( invalidTtl ) , ( ) => {
137+ expect ( ( ) => {
138+ tokenGenerator . createCustomToken ( APP_ID , { ttlMillis : invalidTtl as any } ) ;
139+ } ) . to . throw ( FirebaseAppCheckError ) . with . property ( 'message' ,
140+ 'ttlMillis must be a non-negative duration in milliseconds.' ) ;
141+ } ) ;
142+ } ) ;
143+
144+ const THIRTY_MIN_IN_MS = 1800000 ;
145+ const SEVEN_DAYS_IN_MS = 604800000 ;
146+ [ 0 , 10 , THIRTY_MIN_IN_MS - 1 , SEVEN_DAYS_IN_MS + 1 , SEVEN_DAYS_IN_MS * 2 ] . forEach ( ( ttlMillis ) => {
147+ it ( 'should throw given options with ttl < 30 minutes or ttl > 7 days:' + JSON . stringify ( ttlMillis ) , ( ) => {
148+ expect ( ( ) => {
149+ tokenGenerator . createCustomToken ( APP_ID , { ttlMillis } ) ;
150+ } ) . to . throw ( FirebaseAppCheckError ) . with . property (
151+ 'message' , 'ttlMillis must be a duration in milliseconds between 30 minutes and 7 days (inclusive).' ) ;
152+ } ) ;
153+ } ) ;
154+
155+ it ( 'should be fulfilled with a Firebase Custom JWT with only an APP ID' , ( ) => {
126156 return tokenGenerator . createCustomToken ( APP_ID )
127157 . should . eventually . be . a ( 'string' ) . and . not . be . empty ;
128158 } ) ;
129159
160+ [ THIRTY_MIN_IN_MS , THIRTY_MIN_IN_MS + 1 , SEVEN_DAYS_IN_MS / 2 , SEVEN_DAYS_IN_MS - 1 , SEVEN_DAYS_IN_MS ]
161+ . forEach ( ( ttlMillis ) => {
162+ it ( 'should be fulfilled with a Firebase Custom JWT with a valid custom ttl' + JSON . stringify ( ttlMillis ) , ( ) => {
163+ return tokenGenerator . createCustomToken ( APP_ID , { ttlMillis } )
164+ . should . eventually . be . a ( 'string' ) . and . not . be . empty ;
165+ } ) ;
166+ } ) ;
167+
130168 it ( 'should be fulfilled with a JWT with the correct decoded payload' , ( ) => {
131169 clock = sinon . useFakeTimers ( 1000 ) ;
132170
@@ -147,6 +185,53 @@ describe('AppCheckTokenGenerator', () => {
147185 } ) ;
148186 } ) ;
149187
188+ [ { } , { ttlMillis : undefined } , { a : 123 } ] . forEach ( ( options ) => {
189+ it ( 'should be fulfilled with no ttl in the decoded payload when ttl is not provided in options' , ( ) => {
190+ clock = sinon . useFakeTimers ( 1000 ) ;
191+
192+ return tokenGenerator . createCustomToken ( APP_ID , options )
193+ . then ( ( token ) => {
194+ const decoded = jwt . decode ( token ) ;
195+ const expected : { [ key : string ] : any } = {
196+ // eslint-disable-next-line @typescript-eslint/camelcase
197+ app_id : APP_ID ,
198+ iat : 1 ,
199+ exp : ONE_HOUR_IN_SECONDS + 1 ,
200+ aud : FIREBASE_APP_CHECK_AUDIENCE ,
201+ iss : mocks . certificateObject . client_email ,
202+ sub : mocks . certificateObject . client_email ,
203+ } ;
204+
205+ expect ( decoded ) . to . deep . equal ( expected ) ;
206+ } ) ;
207+ } ) ;
208+ } ) ;
209+
210+ [ [ 1800000.000001 , '1800.000000001s' ] , [ 1800000.001 , '1800.000001000s' ] , [ 172800000 , '172800s' ] ,
211+ [ 604799999 , '604799.999000000s' ] , [ 604800000 , '604800s' ]
212+ ] . forEach ( ( ttl ) => {
213+ it ( 'should be fulfilled with a JWT with custom ttl in decoded payload' , ( ) => {
214+ clock = sinon . useFakeTimers ( 1000 ) ;
215+
216+ return tokenGenerator . createCustomToken ( APP_ID , { ttlMillis : ttl [ 0 ] as number } )
217+ . then ( ( token ) => {
218+ const decoded = jwt . decode ( token ) ;
219+ const expected : { [ key : string ] : any } = {
220+ // eslint-disable-next-line @typescript-eslint/camelcase
221+ app_id : APP_ID ,
222+ iat : 1 ,
223+ exp : ONE_HOUR_IN_SECONDS + 1 ,
224+ aud : FIREBASE_APP_CHECK_AUDIENCE ,
225+ iss : mocks . certificateObject . client_email ,
226+ sub : mocks . certificateObject . client_email ,
227+ ttl : ttl [ 1 ] ,
228+ } ;
229+
230+ expect ( decoded ) . to . deep . equal ( expected ) ;
231+ } ) ;
232+ } ) ;
233+ } ) ;
234+
150235 it ( 'should be fulfilled with a JWT with the correct header' , ( ) => {
151236 clock = sinon . useFakeTimers ( 1000 ) ;
152237
@@ -225,7 +310,7 @@ describe('AppCheckTokenGenerator', () => {
225310 expect ( appCheckError ) . to . be . an . instanceof ( FirebaseAppCheckError ) ;
226311 expect ( appCheckError ) . to . have . property ( 'code' , 'app-check/unknown-error' ) ;
227312 expect ( appCheckError ) . to . have . property ( 'message' ,
228- 'Error returned from server while siging a custom token: server error.' ) ;
313+ 'Error returned from server while signing a custom token: server error.' ) ;
229314 } ) ;
230315
231316 it ( 'should convert CryptoSignerError HttpError with no error.message to FirebaseAppCheckError' , ( ) => {
@@ -240,7 +325,7 @@ describe('AppCheckTokenGenerator', () => {
240325 expect ( appCheckError ) . to . be . an . instanceof ( FirebaseAppCheckError ) ;
241326 expect ( appCheckError ) . to . have . property ( 'code' , 'app-check/unknown-error' ) ;
242327 expect ( appCheckError ) . to . have . property ( 'message' ,
243- 'Error returned from server while siging a custom token: ' +
328+ 'Error returned from server while signing a custom token: ' +
244329 '{"status":500,"headers":{},"data":{"error":{}},"text":"{\\"error\\":{}}"}' ) ;
245330 } ) ;
246331
0 commit comments