@@ -333,7 +333,7 @@ plugin.getSubmissions = function(problem, cb) {
333333
334334 // FIXME: this only return the 1st 20 submissions, we should get next if necessary.
335335 const submissions = JSON . parse ( body ) . submissions_dump ;
336- for ( let submission of submissions )
336+ for ( const submission of submissions )
337337 submission . id = _ . last ( _ . compact ( submission . url . split ( '/' ) ) ) ;
338338
339339 return cb ( null , submissions ) ;
@@ -471,8 +471,8 @@ plugin.deleteSession = function(session, cb) {
471471} ;
472472
473473plugin . signin = function ( user , cb ) {
474- log . debug ( 'running leetcode.signin' ) ;
475- const spin = h . spin ( 'Signing in leetcode.com' ) ;
474+ const isCN = config . app === ' leetcode.cn' ;
475+ const spin = isCN ? h . spin ( 'Signing in leetcode-cn.com' ) : h . spin ( 'Signing in leetcode.com' ) ;
476476 request ( config . sys . urls . login , function ( e , resp , body ) {
477477 spin . stop ( ) ;
478478 e = plugin . checkError ( e , resp , 200 ) ;
@@ -538,11 +538,18 @@ plugin.login = function(user, cb) {
538538 } ) ;
539539} ;
540540
541- function parseCookie ( cookie , cb ) {
541+ function parseCookie ( cookie , body , cb ) {
542+ const isCN = config . app === 'leetcode.cn' ;
542543 const SessionPattern = / L E E T C O D E _ S E S S I O N = ( .+ ?) ( ; | $ ) / ;
543- const csrfPattern = / c s r f t o k e n = ( .+ ?) ( ; | $ ) / ;
544+ let csrfPattern ;
545+ // leetcode-cn.com Cookie is not the same as leetcode.com in third parties
546+ if ( isCN ) {
547+ csrfPattern = / n a m e = " c s r f m i d d l e w a r e t o k e n " v a l u e = " ( .* ?) " / ;
548+ } else {
549+ csrfPattern = / c s r f t o k e n = ( .+ ?) ( ; | $ ) / ;
550+ }
544551 const reSessionResult = SessionPattern . exec ( cookie ) ;
545- const reCsrfResult = csrfPattern . exec ( cookie ) ;
552+ const reCsrfResult = csrfPattern . exec ( isCN ? body : cookie ) ;
546553 if ( reSessionResult === null || reCsrfResult === null ) {
547554 return cb ( 'invalid cookie?' ) ;
548555 }
@@ -552,11 +559,18 @@ function parseCookie(cookie, cb) {
552559 } ;
553560}
554561
555- function saveAndGetUser ( user , cb , cookieData ) {
556- user . sessionId = cookieData . sessionId ;
557- user . sessionCSRF = cookieData . sessionCSRF ;
558- session . saveUser ( user ) ;
559- plugin . getUser ( user , cb ) ;
562+ function requestLeetcodeAndSave ( request , leetcodeUrl , user , cb ) {
563+ request . get ( { url : leetcodeUrl } , function ( e , resp , body ) {
564+ const redirectUri = resp . request . uri . href ;
565+ if ( redirectUri !== config . sys . urls . leetcode_redirect ) {
566+ return cb ( 'Login failed. Please make sure the credential is correct.' ) ;
567+ }
568+ const cookieData = parseCookie ( resp . request . headers . cookie , body , cb ) ;
569+ user . sessionId = cookieData . sessionId ;
570+ user . sessionCSRF = cookieData . sessionCSRF ;
571+ session . saveUser ( user ) ;
572+ plugin . getUser ( user , cb ) ;
573+ } ) ;
560574}
561575
562576plugin . cookieLogin = function ( user , cb ) {
@@ -568,15 +582,16 @@ plugin.cookieLogin = function(user, cb) {
568582} ;
569583
570584plugin . githubLogin = function ( user , cb ) {
571- const leetcodeUrl = config . sys . urls . github_login ;
585+ const urls = config . sys . urls ;
586+ const leetcodeUrl = urls . github_login ;
572587 const _request = request . defaults ( { jar : true } ) ;
573- _request ( 'https://github.com/login' , function ( e , resp , body ) {
588+ _request ( urls . github_login_request , function ( e , resp , body ) {
574589 const authenticityToken = body . match ( / n a m e = " a u t h e n t i c i t y _ t o k e n " v a l u e = " ( .* ?) " / ) ;
575590 if ( authenticityToken === null ) {
576591 return cb ( 'Get GitHub token failed' ) ;
577592 }
578593 const options = {
579- url : 'https://github.com/session' ,
594+ url : urls . github_session_request ,
580595 method : 'POST' ,
581596 headers : {
582597 'Content-Type' : 'application/x-www-form-urlencoded' ,
@@ -594,27 +609,48 @@ plugin.githubLogin = function(user, cb) {
594609 if ( resp . statusCode !== 200 ) {
595610 return cb ( 'GitHub login failed' ) ;
596611 }
597- _request . get ( { url : leetcodeUrl } , function ( e , resp , body ) {
598- const redirectUri = resp . request . uri . href ;
599- if ( redirectUri !== 'https://leetcode.com/' ) {
600- return cb ( 'GitHub login failed or GitHub did not link to LeetCode' ) ;
612+ if ( resp . request . uri . href !== urls . github_tf_redirect ) {
613+ return requestLeetcodeAndSave ( _request , leetcodeUrl , user , cb ) ;
614+ }
615+ // read two-factor code must be sync.
616+ const twoFactorcode = require ( 'prompt-sync' ) ( ) ( 'Please enter your two-factor code: ' ) ;
617+ const authenticityTokenTwoFactor = body . match ( / n a m e = " a u t h e n t i c i t y _ t o k e n " v a l u e = " ( .* ?) " / ) ;
618+ if ( authenticityTokenTwoFactor === null ) {
619+ return cb ( 'Get GitHub two-factor token failed' ) ;
620+ }
621+ const optionsTwoFactor = {
622+ url : urls . github_tf_session_request ,
623+ method : 'POST' ,
624+ headers : {
625+ 'Content-Type' : 'application/x-www-form-urlencoded' ,
626+ } ,
627+ followAllRedirects : true ,
628+ form : {
629+ 'otp' : twoFactorcode ,
630+ 'authenticity_token' : authenticityTokenTwoFactor [ 1 ] ,
631+ 'utf8' : encodeURIComponent ( '✓' ) ,
632+ } ,
633+ } ;
634+ _request ( optionsTwoFactor , function ( e , resp , body ) {
635+ if ( resp . request . uri . href === urls . github_tf_session_request ) {
636+ return cb ( 'Invalid two-factor code please check' ) ;
601637 }
602- const cookieData = parseCookie ( resp . request . headers . cookie , cb ) ;
603- saveAndGetUser ( user , cb , cookieData ) ;
638+ requestLeetcodeAndSave ( _request , leetcodeUrl , user , cb ) ;
604639 } ) ;
605640 } ) ;
606641 } ) ;
607642} ;
608643
609644plugin . linkedinLogin = function ( user , cb ) {
610- const leetcodeUrl = config . sys . urls . linkedin_login ;
645+ const urls = config . sys . urls ;
646+ const leetcodeUrl = urls . linkedin_login ;
611647 const _request = request . defaults ( {
612648 jar : true ,
613649 headers : {
614650 'User-Agent' : 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_14_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'
615651 }
616652 } ) ;
617- _request ( 'https://www.linkedin.com' , function ( e , resp , body ) {
653+ _request ( urls . linkedin_login_request , function ( e , resp , body ) {
618654 if ( resp . statusCode !== 200 ) {
619655 return cb ( 'Get LinkedIn session failed' ) ;
620656 }
@@ -623,7 +659,7 @@ plugin.linkedinLogin = function(user, cb) {
623659 return cb ( 'Get LinkedIn token failed' ) ;
624660 }
625661 const options = {
626- url : 'https://www.linkedin.com/uas/login-submit' ,
662+ url : urls . linkedin_session_request ,
627663 method : 'POST' ,
628664 headers : {
629665 'Content-Type' : 'application/x-www-form-urlencoded' ,
@@ -640,14 +676,7 @@ plugin.linkedinLogin = function(user, cb) {
640676 if ( resp . statusCode !== 200 ) {
641677 return cb ( 'LinkedIn login failed' ) ;
642678 }
643- _request . get ( { url : leetcodeUrl } , function ( e , resp , body ) {
644- const redirectUri = resp . request . uri . href ;
645- if ( redirectUri !== 'https://leetcode.com/' ) {
646- return cb ( 'LinkedIn login failed or LinkedIn did not link to LeetCode' ) ;
647- }
648- const cookieData = parseCookie ( resp . request . headers . cookie , cb ) ;
649- saveAndGetUser ( user , cb , cookieData ) ;
650- } ) ;
679+ requestLeetcodeAndSave ( _request , leetcodeUrl , user , cb ) ;
651680 } ) ;
652681 } ) ;
653682} ;
0 commit comments