@@ -51,7 +51,7 @@ plugin.checkError = function(e, resp, expectedStatus) {
51
51
52
52
plugin . init = function ( ) {
53
53
config . app = 'leetcode' ;
54
- }
54
+ } ;
55
55
56
56
plugin . getProblems = function ( cb ) {
57
57
log . debug ( 'running leetcode.getProblems' ) ;
@@ -95,7 +95,7 @@ plugin.getCategoryProblems = function(category, cb) {
95
95
}
96
96
97
97
const problems = json . stat_status_pairs
98
- . filter ( p => ! p . stat . question__hide )
98
+ . filter ( ( p ) => ! p . stat . question__hide )
99
99
. map ( function ( p ) {
100
100
return {
101
101
state : p . status || 'None' ,
@@ -167,7 +167,7 @@ plugin.getProblem = function(problem, cb) {
167
167
problem . testable = q . enableRunCode ;
168
168
problem . templateMeta = JSON . parse ( q . metaData ) ;
169
169
// @si -yao: seems below property is never used.
170
- //problem.discuss = q.discussCategoryId;
170
+ // problem.discuss = q.discussCategoryId;
171
171
172
172
return cb ( null , problem ) ;
173
173
} ) ;
@@ -254,9 +254,9 @@ function formatResult(result) {
254
254
} ;
255
255
256
256
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 ( ) ;
260
260
261
261
if ( / [ r u n c o d e | i n t e r p r e t ] .* / . test ( result . submission_id ) ) {
262
262
// It's testing
@@ -374,8 +374,8 @@ plugin.starProblem = function(problem, starred, cb) {
374
374
} ;
375
375
} else {
376
376
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 ) ;
379
379
opts . method = 'DELETE' ;
380
380
}
381
381
@@ -508,7 +508,7 @@ plugin.signin = function(user, cb) {
508
508
plugin . getUser = function ( user , cb ) {
509
509
plugin . getFavorites ( function ( e , favorites ) {
510
510
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' ) ;
512
512
if ( f ) {
513
513
user . hash = f . id_hash ;
514
514
user . name = favorites . user_name ;
@@ -538,19 +538,118 @@ plugin.login = function(user, cb) {
538
538
} ) ;
539
539
} ;
540
540
541
- plugin . cookieLogin = function ( user , cb ) {
542
- // re pattern for cookie chrome or firefox
541
+ function parseCookie ( cookie , cb ) {
543
542
const SessionPattern = / L E E T C O D E _ S E S S I O N = ( .+ ?) ( ; | $ ) / ;
544
543
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 ) ;
547
546
if ( reSessionResult === null || reCsrfResult === null ) {
548
- return cb ( 'invalid cookie?' )
547
+ return cb ( 'invalid cookie?' ) ;
549
548
}
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 ;
552
558
session . saveUser ( user ) ;
553
559
plugin . getUser ( user , cb ) ;
554
560
}
555
561
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
+
556
655
module . exports = plugin ;
0 commit comments