@@ -51,7 +51,7 @@ plugin.checkError = function(e, resp, expectedStatus) {
5151
5252plugin . init = function ( ) {
5353 config . app = 'leetcode' ;
54- }
54+ } ;
5555
5656plugin . getProblems = function ( cb ) {
5757 log . debug ( 'running leetcode.getProblems' ) ;
@@ -95,7 +95,7 @@ plugin.getCategoryProblems = function(category, cb) {
9595 }
9696
9797 const problems = json . stat_status_pairs
98- . filter ( p => ! p . stat . question__hide )
98+ . filter ( ( p ) => ! p . stat . question__hide )
9999 . map ( function ( p ) {
100100 return {
101101 state : p . status || 'None' ,
@@ -167,7 +167,7 @@ plugin.getProblem = function(problem, cb) {
167167 problem . testable = q . enableRunCode ;
168168 problem . templateMeta = JSON . parse ( q . metaData ) ;
169169 // @si -yao: seems below property is never used.
170- //problem.discuss = q.discussCategoryId;
170+ // problem.discuss = q.discussCategoryId;
171171
172172 return cb ( null , problem ) ;
173173 } ) ;
@@ -254,9 +254,9 @@ function formatResult(result) {
254254 } ;
255255
256256 x . error = _ . chain ( result )
257- . pick ( ( v , k ) => / _ e r r o r $ / . test ( k ) && v . length > 0 )
258- . values ( )
259- . value ( ) ;
257+ . pick ( ( v , k ) => / _ e r r o r $ / . test ( k ) && v . length > 0 )
258+ . values ( )
259+ . value ( ) ;
260260
261261 if ( / [ r u n c o d e | i n t e r p r e t ] .* / . test ( result . submission_id ) ) {
262262 // It's testing
@@ -374,8 +374,8 @@ plugin.starProblem = function(problem, starred, cb) {
374374 } ;
375375 } else {
376376 opts . url = config . sys . urls . favorite_delete
377- . replace ( '$hash' , user . hash )
378- . replace ( '$id' , problem . id ) ;
377+ . replace ( '$hash' , user . hash )
378+ . replace ( '$id' , problem . id ) ;
379379 opts . method = 'DELETE' ;
380380 }
381381
@@ -508,7 +508,7 @@ plugin.signin = function(user, cb) {
508508plugin . getUser = function ( user , cb ) {
509509 plugin . getFavorites ( function ( e , favorites ) {
510510 if ( ! e ) {
511- const f = favorites . favorites . private_favorites . find ( f => f . name === 'Favorite' ) ;
511+ const f = favorites . favorites . private_favorites . find ( ( f ) => f . name === 'Favorite' ) ;
512512 if ( f ) {
513513 user . hash = f . id_hash ;
514514 user . name = favorites . user_name ;
@@ -538,19 +538,118 @@ plugin.login = function(user, cb) {
538538 } ) ;
539539} ;
540540
541- plugin . cookieLogin = function ( user , cb ) {
542- // re pattern for cookie chrome or firefox
541+ function parseCookie ( cookie , cb ) {
543542 const SessionPattern = / L E E T C O D E _ S E S S I O N = ( .+ ?) ( ; | $ ) / ;
544543 const csrfPattern = / c s r f t o k e n = ( .+ ?) ( ; | $ ) / ;
545- const reSessionResult = SessionPattern . exec ( user . cookie ) ;
546- const reCsrfResult = csrfPattern . exec ( user . cookie ) ;
544+ const reSessionResult = SessionPattern . exec ( cookie ) ;
545+ const reCsrfResult = csrfPattern . exec ( cookie ) ;
547546 if ( reSessionResult === null || reCsrfResult === null ) {
548- return cb ( 'invalid cookie?' )
547+ return cb ( 'invalid cookie?' ) ;
549548 }
550- user . sessionId = reSessionResult [ 1 ] ;
551- user . sessionCSRF = reCsrfResult [ 1 ] ;
549+ return {
550+ sessionId : reSessionResult [ 1 ] ,
551+ sessionCSRF : reCsrfResult [ 1 ] ,
552+ } ;
553+ }
554+
555+ function saveAndGetUser ( user , cb , cookieData ) {
556+ user . sessionId = cookieData . sessionId ;
557+ user . sessionCSRF = cookieData . sessionCSRF ;
552558 session . saveUser ( user ) ;
553559 plugin . getUser ( user , cb ) ;
554560}
555561
562+ plugin . cookieLogin = function ( user , cb ) {
563+ const cookieData = parseCookie ( user . cookie , cb ) ;
564+ user . sessionId = cookieData . sessionId ;
565+ user . sessionCSRF = cookieData . sessionCSRF ;
566+ session . saveUser ( user ) ;
567+ plugin . getUser ( user , cb ) ;
568+ } ;
569+
570+ plugin . githubLogin = function ( user , cb ) {
571+ const leetcodeUrl = config . sys . urls . github_login ;
572+ const _request = request . defaults ( { jar : true } ) ;
573+ _request ( 'https://github.com/login' , function ( e , resp , body ) {
574+ 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 = " ( .* ?) " / ) ;
575+ if ( authenticityToken === null ) {
576+ return cb ( 'Get GitHub token failed' ) ;
577+ }
578+ const options = {
579+ url : 'https://github.com/session' ,
580+ method : 'POST' ,
581+ headers : {
582+ 'Content-Type' : 'application/x-www-form-urlencoded' ,
583+ } ,
584+ followAllRedirects : true ,
585+ form : {
586+ 'login' : user . login ,
587+ 'password' : user . pass ,
588+ 'authenticity_token' : authenticityToken [ 1 ] ,
589+ 'utf8' : encodeURIComponent ( '✓' ) ,
590+ 'commit' : encodeURIComponent ( 'Sign in' )
591+ } ,
592+ } ;
593+ _request ( options , function ( e , resp , body ) {
594+ if ( resp . statusCode !== 200 ) {
595+ return cb ( 'GitHub login failed' ) ;
596+ }
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' ) ;
601+ }
602+ const cookieData = parseCookie ( resp . request . headers . cookie , cb ) ;
603+ saveAndGetUser ( user , cb , cookieData ) ;
604+ } ) ;
605+ } ) ;
606+ } ) ;
607+ } ;
608+
609+ plugin . linkedinLogin = function ( user , cb ) {
610+ const leetcodeUrl = config . sys . urls . linkedin_login ;
611+ const _request = request . defaults ( {
612+ jar : true ,
613+ headers : {
614+ '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'
615+ }
616+ } ) ;
617+ _request ( 'https://www.linkedin.com' , function ( e , resp , body ) {
618+ if ( resp . statusCode !== 200 ) {
619+ return cb ( 'Get LinkedIn session failed' ) ;
620+ }
621+ const authenticityToken = body . match ( / i n p u t n a m e = " l o g i n C s r f P a r a m " v a l u e = " ( .* ) " / ) ;
622+ if ( authenticityToken === null ) {
623+ return cb ( 'Get LinkedIn token failed' ) ;
624+ }
625+ const options = {
626+ url : 'https://www.linkedin.com/uas/login-submit' ,
627+ method : 'POST' ,
628+ headers : {
629+ 'Content-Type' : 'application/x-www-form-urlencoded' ,
630+ } ,
631+ followAllRedirects : true ,
632+ form : {
633+ 'session_key' : user . login ,
634+ 'session_password' : user . pass ,
635+ 'loginCsrfParam' : authenticityToken [ 1 ] ,
636+ 'trk' : 'guest_homepage-basic_sign-in-submit'
637+ } ,
638+ } ;
639+ _request ( options , function ( e , resp , body ) {
640+ if ( resp . statusCode !== 200 ) {
641+ return cb ( 'LinkedIn login failed' ) ;
642+ }
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+ } ) ;
651+ } ) ;
652+ } ) ;
653+ } ;
654+
556655module . exports = plugin ;
0 commit comments