55import sinon from 'sinon' ;
66const Joi = require ( 'joi' ) ;
77const { Container } = require ( 'typedi' ) ;
8+ const ScopeSet = require ( 'fxa-shared' ) . oauth . scopes ;
89
910const {
1011 OAUTH_SCOPE_OLD_SYNC ,
@@ -24,14 +25,12 @@ const UID = 'eaf0';
2425const CLIENT_SECRET =
2526 'b93ef8a8f3e553a430d7e5b904c6132b2722633af9f03128029201d24a97f2a8' ;
2627const CLIENT_ID = '98e6508e88680e1b' ;
27- const CODE =
28- 'df6dcfe7bf6b54a65db5742cbcdce5c0a84a5da81a0bb6bdf5fc793eef041fc6' ;
28+ const CODE = 'df6dcfe7bf6b54a65db5742cbcdce5c0a84a5da81a0bb6bdf5fc793eef041fc6' ;
2929const REFRESH_TOKEN = CODE ;
3030const PKCE_CODE_VERIFIER = 'au3dqDz2dOB0_vSikXCUf4S8Gc-37dL-F7sGxtxpR3R' ;
3131const CODE_WITH_KEYS = 'afafaf' ;
3232const CODE_WITHOUT_KEYS = 'f0f0f0' ;
33- const GRANT_TOKEN_EXCHANGE =
34- 'urn:ietf:params:oauth:grant-type:token-exchange' ;
33+ const GRANT_TOKEN_EXCHANGE = 'urn:ietf:params:oauth:grant-type:token-exchange' ;
3534const SUBJECT_TOKEN_TYPE_REFRESH =
3635 'urn:ietf:params:oauth:token-type:refresh_token' ;
3736const FIREFOX_IOS_CLIENT_ID = '1b1a3e44c54fbb58' ;
@@ -58,10 +57,13 @@ const tokenRoutesDepMocks = {
5857 is : Joi . string ( ) . required ( ) ,
5958 then : Joi . forbidden ( ) ,
6059 } ) ,
61- clientSecret : Joi . string ( ) . hex ( ) . required ( ) . when ( '$headers.authorization' , {
62- is : Joi . string ( ) . required ( ) ,
63- then : Joi . forbidden ( ) ,
64- } ) ,
60+ clientSecret : Joi . string ( )
61+ . hex ( )
62+ . required ( )
63+ . when ( '$headers.authorization' , {
64+ is : Joi . string ( ) . required ( ) ,
65+ then : Joi . forbidden ( ) ,
66+ } ) ,
6567 } ,
6668 } ,
6769 '../../oauth/grant' : {
@@ -338,7 +340,51 @@ describe('/token POST', () => {
338340 sinon . assert . calledOnceWithExactly (
339341 mockGlean . oauth . tokenCreated ,
340342 request ,
341- { uid : UID , oauthClientId : CLIENT_ID , reason : 'authorization_code' }
343+ {
344+ uid : UID ,
345+ oauthClientId : CLIENT_ID ,
346+ reason : 'authorization_code' ,
347+ scopes : '' ,
348+ }
349+ ) ;
350+ } ) ;
351+
352+ it ( 'logs space-separated scopes from ScopeSet for the token created event' , async ( ) => {
353+ const SMARTWINDOW_SCOPES =
354+ 'https://identity.mozilla.com/apps/smartwindow profile:uid' ;
355+ resetAndMockDeps ( ) ;
356+ jest . doMock ( '../../oauth/grant' , ( ) => ( {
357+ generateTokens : tokenRoutesDepMocks [ '../../oauth/grant' ] . generateTokens ,
358+ validateRequestedGrant : ( ) => ( {
359+ offline : true ,
360+ userId : buf ( UID ) ,
361+ clientId : buf ( CLIENT_ID ) ,
362+ scope : ScopeSet . fromString ( SMARTWINDOW_SCOPES ) ,
363+ } ) ,
364+ } ) ) ;
365+ const mockGleanLocal = { oauth : { tokenCreated : sinon . stub ( ) } } ;
366+ const routes = require ( './token' ) ( {
367+ ...tokenRoutesArgMocks ,
368+ glean : mockGleanLocal ,
369+ } ) ;
370+ const request = {
371+ app : { } ,
372+ payload : {
373+ client_id : CLIENT_ID ,
374+ grant_type : 'fxa-credentials' ,
375+ } ,
376+ emitMetricsEvent : ( ) => { } ,
377+ } ;
378+ await routes [ 0 ] . config . handler ( request ) ;
379+ sinon . assert . calledOnceWithExactly (
380+ mockGleanLocal . oauth . tokenCreated ,
381+ request ,
382+ {
383+ uid : UID ,
384+ oauthClientId : CLIENT_ID ,
385+ reason : 'fxa-credentials' ,
386+ scopes : SMARTWINDOW_SCOPES ,
387+ }
342388 ) ;
343389 } ) ;
344390 } ) ;
@@ -540,7 +586,8 @@ describe('token exchange grant_type', () => {
540586 canGrant : true ,
541587 publicClient : true ,
542588 } ) ,
543- clientAuthValidators : tokenRoutesDepMocks [ '../../oauth/client' ] . clientAuthValidators ,
589+ clientAuthValidators :
590+ tokenRoutesDepMocks [ '../../oauth/client' ] . clientAuthValidators ,
544591 } ) ) ;
545592 jest . doMock ( '../../oauth/grant' , ( ) => ( {
546593 generateTokens : ( grant : any ) => {
@@ -677,8 +724,9 @@ describe('/oauth/token POST', () => {
677724 . rejects ( new Error ( 'should not be called' ) ) ;
678725 jest . resetModules ( ) ;
679726 jest . doMock ( '../../oauth/assertion' , ( ) => async ( ) => true ) ;
680- jest . doMock ( '../../oauth/client' , ( ) =>
681- tokenRoutesDepMocks [ '../../oauth/client' ]
727+ jest . doMock (
728+ '../../oauth/client' ,
729+ ( ) => tokenRoutesDepMocks [ '../../oauth/client' ]
682730 ) ;
683731 jest . doMock ( '../../oauth/grant' , ( ) => ( {
684732 generateTokens : ( grant : any ) => ( {
@@ -690,8 +738,9 @@ describe('/oauth/token POST', () => {
690738 } ) ,
691739 validateRequestedGrant : ( ) => ( { offline : true , scope : 'testo' } ) ,
692740 } ) ) ;
693- jest . doMock ( '../../oauth/util' , ( ) =>
694- tokenRoutesDepMocks [ '../../oauth/util' ]
741+ jest . doMock (
742+ '../../oauth/util' ,
743+ ( ) => tokenRoutesDepMocks [ '../../oauth/util' ]
695744 ) ;
696745 jest . doMock ( '../utils/oauth' , ( ) => ( {
697746 newTokenNotification : newTokenNotificationStub ,
@@ -758,8 +807,9 @@ describe('/oauth/token POST', () => {
758807 const newTokenNotificationStub = sinon . stub ( ) . resolves ( ) ;
759808 jest . resetModules ( ) ;
760809 jest . doMock ( '../../oauth/assertion' , ( ) => async ( ) => true ) ;
761- jest . doMock ( '../../oauth/client' , ( ) =>
762- tokenRoutesDepMocks [ '../../oauth/client' ]
810+ jest . doMock (
811+ '../../oauth/client' ,
812+ ( ) => tokenRoutesDepMocks [ '../../oauth/client' ]
763813 ) ;
764814 jest . doMock ( '../../oauth/grant' , ( ) => ( {
765815 generateTokens : ( grant : any ) => ( {
@@ -771,8 +821,9 @@ describe('/oauth/token POST', () => {
771821 } ) ,
772822 validateRequestedGrant : ( ) => ( { offline : true , scope : 'testo' } ) ,
773823 } ) ) ;
774- jest . doMock ( '../../oauth/util' , ( ) =>
775- tokenRoutesDepMocks [ '../../oauth/util' ]
824+ jest . doMock (
825+ '../../oauth/util' ,
826+ ( ) => tokenRoutesDepMocks [ '../../oauth/util' ]
776827 ) ;
777828 jest . doMock ( '../utils/oauth' , ( ) => ( {
778829 newTokenNotification : newTokenNotificationStub ,
@@ -838,20 +889,21 @@ describe('/oauth/token POST', () => {
838889 . rejects ( new Error ( 'should not be called' ) ) ;
839890 jest . resetModules ( ) ;
840891 jest . doMock ( '../../oauth/assertion' , ( ) => async ( ) => true ) ;
841- jest . doMock ( '../../oauth/client' , ( ) =>
842- tokenRoutesDepMocks [ '../../oauth/client' ]
892+ jest . doMock (
893+ '../../oauth/client' ,
894+ ( ) => tokenRoutesDepMocks [ '../../oauth/client' ]
843895 ) ;
844896 jest . doMock ( '../../oauth/grant' , ( ) => ( {
845- generateTokens :
846- tokenRoutesDepMocks [ '../../oauth/grant' ] . generateTokens ,
897+ generateTokens : tokenRoutesDepMocks [ '../../oauth/grant' ] . generateTokens ,
847898 validateRequestedGrant : ( ) => ( {
848899 offline : true ,
849900 scope : OAUTH_SCOPE_SESSION_TOKEN ,
850901 clientId : buf ( CLIENT_ID ) ,
851902 } ) ,
852903 } ) ) ;
853- jest . doMock ( '../../oauth/util' , ( ) =>
854- tokenRoutesDepMocks [ '../../oauth/util' ]
904+ jest . doMock (
905+ '../../oauth/util' ,
906+ ( ) => tokenRoutesDepMocks [ '../../oauth/util' ]
855907 ) ;
856908 jest . doMock ( '../utils/oauth' , ( ) => ( {
857909 newTokenNotification : newTokenNotificationStub ,
@@ -892,20 +944,21 @@ describe('/oauth/token POST', () => {
892944 const newTokenNotificationStub = sinon . stub ( ) . resolves ( ) ;
893945 jest . resetModules ( ) ;
894946 jest . doMock ( '../../oauth/assertion' , ( ) => async ( ) => true ) ;
895- jest . doMock ( '../../oauth/client' , ( ) =>
896- tokenRoutesDepMocks [ '../../oauth/client' ]
947+ jest . doMock (
948+ '../../oauth/client' ,
949+ ( ) => tokenRoutesDepMocks [ '../../oauth/client' ]
897950 ) ;
898951 jest . doMock ( '../../oauth/grant' , ( ) => ( {
899- generateTokens :
900- tokenRoutesDepMocks [ '../../oauth/grant' ] . generateTokens ,
952+ generateTokens : tokenRoutesDepMocks [ '../../oauth/grant' ] . generateTokens ,
901953 validateRequestedGrant : ( ) => ( {
902954 offline : true ,
903955 scope : 'testo' ,
904956 clientId : buf ( CLIENT_ID ) ,
905957 } ) ,
906958 } ) ) ;
907- jest . doMock ( '../../oauth/util' , ( ) =>
908- tokenRoutesDepMocks [ '../../oauth/util' ]
959+ jest . doMock (
960+ '../../oauth/util' ,
961+ ( ) => tokenRoutesDepMocks [ '../../oauth/util' ]
909962 ) ;
910963 jest . doMock ( '../utils/oauth' , ( ) => ( {
911964 newTokenNotification : newTokenNotificationStub ,
0 commit comments