@@ -122,11 +122,46 @@ 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+ [ 0 , 10 , 1799999 , 604800001 , 605800000 ] . forEach ( ( ttlMillis ) => {
145+ it ( 'should throw given options with ttl < 30 minutes or ttl > 7 days:' + JSON . stringify ( ttlMillis ) , ( ) => {
146+ expect ( ( ) => {
147+ tokenGenerator . createCustomToken ( APP_ID , { ttlMillis } ) ;
148+ } ) . to . throw ( FirebaseAppCheckError ) . with . property (
149+ 'message' , 'ttlMillis must be a duration in milliseconds between 30 minutes and 7 days (inclusive).' ) ;
150+ } ) ;
151+ } ) ;
152+
153+ it ( 'should be fulfilled with a Firebase Custom JWT with only an APP ID' , ( ) => {
126154 return tokenGenerator . createCustomToken ( APP_ID )
127155 . should . eventually . be . a ( 'string' ) . and . not . be . empty ;
128156 } ) ;
129157
158+ [ 1800000 , 1800001 , 172800000 , 604799999 , 604800000 ] . forEach ( ( ttlMillis ) => {
159+ it ( 'should be fulfilled with a Firebase Custom JWT with a valid custom ttl' + JSON . stringify ( ttlMillis ) , ( ) => {
160+ return tokenGenerator . createCustomToken ( APP_ID , { ttlMillis } )
161+ . should . eventually . be . a ( 'string' ) . and . not . be . empty ;
162+ } ) ;
163+ } ) ;
164+
130165 it ( 'should be fulfilled with a JWT with the correct decoded payload' , ( ) => {
131166 clock = sinon . useFakeTimers ( 1000 ) ;
132167
@@ -147,6 +182,53 @@ describe('AppCheckTokenGenerator', () => {
147182 } ) ;
148183 } ) ;
149184
185+ [ { } , { ttlMillis : undefined } , { a : 123 } ] . forEach ( ( options ) => {
186+ it ( 'should be fulfilled with no ttl in the decoded payload when ttl is not provided in options' , ( ) => {
187+ clock = sinon . useFakeTimers ( 1000 ) ;
188+
189+ return tokenGenerator . createCustomToken ( APP_ID , options )
190+ . then ( ( token ) => {
191+ const decoded = jwt . decode ( token ) ;
192+ const expected : { [ key : string ] : any } = {
193+ // eslint-disable-next-line @typescript-eslint/camelcase
194+ app_id : APP_ID ,
195+ iat : 1 ,
196+ exp : ONE_HOUR_IN_SECONDS + 1 ,
197+ aud : FIREBASE_APP_CHECK_AUDIENCE ,
198+ iss : mocks . certificateObject . client_email ,
199+ sub : mocks . certificateObject . client_email ,
200+ } ;
201+
202+ expect ( decoded ) . to . deep . equal ( expected ) ;
203+ } ) ;
204+ } ) ;
205+ } ) ;
206+
207+ [ [ 1800000.000001 , '1800.000000001s' ] , [ 1800000.001 , '1800.000001000s' ] , [ 172800000 , '172800s' ] ,
208+ [ 604799999 , '604799.999000000s' ] , [ 604800000 , '604800s' ]
209+ ] . forEach ( ( ttl ) => {
210+ it ( 'should be fulfilled with a JWT with custom ttl in decoded payload' , ( ) => {
211+ clock = sinon . useFakeTimers ( 1000 ) ;
212+
213+ return tokenGenerator . createCustomToken ( APP_ID , { ttlMillis : ttl [ 0 ] as number } )
214+ . then ( ( token ) => {
215+ const decoded = jwt . decode ( token ) ;
216+ const expected : { [ key : string ] : any } = {
217+ // eslint-disable-next-line @typescript-eslint/camelcase
218+ app_id : APP_ID ,
219+ iat : 1 ,
220+ exp : ONE_HOUR_IN_SECONDS + 1 ,
221+ aud : FIREBASE_APP_CHECK_AUDIENCE ,
222+ iss : mocks . certificateObject . client_email ,
223+ sub : mocks . certificateObject . client_email ,
224+ ttl : ttl [ 1 ] ,
225+ } ;
226+
227+ expect ( decoded ) . to . deep . equal ( expected ) ;
228+ } ) ;
229+ } ) ;
230+ } ) ;
231+
150232 it ( 'should be fulfilled with a JWT with the correct header' , ( ) => {
151233 clock = sinon . useFakeTimers ( 1000 ) ;
152234
@@ -225,7 +307,7 @@ describe('AppCheckTokenGenerator', () => {
225307 expect ( appCheckError ) . to . be . an . instanceof ( FirebaseAppCheckError ) ;
226308 expect ( appCheckError ) . to . have . property ( 'code' , 'app-check/unknown-error' ) ;
227309 expect ( appCheckError ) . to . have . property ( 'message' ,
228- 'Error returned from server while siging a custom token: server error.' ) ;
310+ 'Error returned from server while signing a custom token: server error.' ) ;
229311 } ) ;
230312
231313 it ( 'should convert CryptoSignerError HttpError with no error.message to FirebaseAppCheckError' , ( ) => {
@@ -240,7 +322,7 @@ describe('AppCheckTokenGenerator', () => {
240322 expect ( appCheckError ) . to . be . an . instanceof ( FirebaseAppCheckError ) ;
241323 expect ( appCheckError ) . to . have . property ( 'code' , 'app-check/unknown-error' ) ;
242324 expect ( appCheckError ) . to . have . property ( 'message' ,
243- 'Error returned from server while siging a custom token: ' +
325+ 'Error returned from server while signing a custom token: ' +
244326 '{"status":500,"headers":{},"data":{"error":{}},"text":"{\\"error\\":{}}"}' ) ;
245327 } ) ;
246328
0 commit comments