1
-
2
1
const router = require ( "koa-router" ) ( ) ;
3
2
const fetch = require ( "node-fetch" ) ;
3
+ const request = require ( 'request' ) ;
4
4
const {
5
5
leetcodeConfig : {
6
6
baseUrl,
7
+ loginUrl,
7
8
submitUrl,
8
9
_91UsernameCookieName,
9
10
_91PwdCookieName,
@@ -13,102 +14,93 @@ const {
13
14
} = require ( '../config/index' )
14
15
const { success, fail } = require ( '../utils/request' )
15
16
const { encrypt, decrypt } = require ( '../utils/crypto' )
16
- const { set91Cookie, getLcRequestData } = require ( './utils' )
17
17
18
18
// 用户上传lc的账号名与密码
19
19
router . post ( '/api/v1/lc/submitLcAccount' , async ( ctx ) => {
20
- const { login, password } = ctx . request . body
21
20
// 先提交给lc,账号密码是否正确
21
+ const { login, password } = ctx . request . body
22
22
let result = await getLcRequestData ( { login, password} )
23
23
if ( result . success ) {
24
- // 密码正确时,对密码进行加密
25
24
let encryptPwd = encrypt ( password )
26
- // 将加密后的密文 以及 sessionId、 csrftoken 写入cookie中
27
- sessionId = result [ lcSeesionCookieName ]
28
- csrftoken = result [ lcCsrftokenCookieName ]
29
- set91Cookie ( {
25
+ ctx . body = success ( {
26
+ isLogin : true ,
30
27
[ _91UsernameCookieName ] : login ,
31
28
[ _91PwdCookieName ] : encryptPwd ,
32
- [ lcSeesionCookieName ] : sessionId ,
33
- [ lcCsrftokenCookieName ] : csrftoken ,
34
- } , ctx )
35
- ctx . body = success ( { isLogin : true } )
29
+ [ lcSeesionCookieName ] : result [ lcSeesionCookieName ] ,
30
+ [ lcCsrftokenCookieName ] : result [ lcCsrftokenCookieName ] ,
31
+ } )
36
32
} else {
37
- ctx . body = fail ( { code : 302 , message : '提交失败 ' } )
33
+ ctx . body = fail ( { code : 302 , message : result . message || '登录失败 ' } )
38
34
}
39
35
} ) ;
40
36
41
37
// 用户提交题解
38
+ // 前置数据校验
42
39
router . post ( '/api/v1/lc/submitCode' , async ( ctx , next ) => {
43
- // 先校验cookie中是否有账号密码,没有就让用户先输入再提交
44
- const userName = ctx . cookies . get ( _91UsernameCookieName )
45
- const passwd = ctx . cookies . get ( _91PwdCookieName )
46
- if ( ! userName || ! passwd ) {
40
+ const {
41
+ login,
42
+ password,
43
+ [ lcSeesionCookieName . toLowerCase ( ) ] : sessionId ,
44
+ [ lcCsrftokenCookieName . toLowerCase ( ) ] : csrftoken
45
+ } = ctx . request . headers
46
+ // 如果有一个不存在,就提示用户重新提交一遍lc的账号密码
47
+ if ( ! login || ! password || ! sessionId || ! csrftoken ) {
47
48
return ctx . response . body = fail ( {
48
49
code : 403 ,
49
- message : "请先提交账号名与密码后再提交 "
50
+ message : "缺少字段或者cookie已过期,请重新提交账号名与密码后再提交 "
50
51
} ) ;
51
52
}
53
+ await next ( )
54
+ } )
55
+
56
+ // 题解提交逻辑
57
+ router . post ( '/api/v1/lc/submitCode' , async ( ctx ) => {
58
+ const {
59
+ login,
60
+ password,
61
+ [ lcSeesionCookieName . toLowerCase ( ) ] : sessionId ,
62
+ [ lcCsrftokenCookieName . toLowerCase ( ) ] : csrftoken
63
+ } = ctx . request . headers
64
+ const lcAccountData = {
65
+ login,
66
+ password,
67
+ }
52
68
53
- // 如果这俩cookie有一个不存在就提示用户重新提交一遍lc的账号密码
54
- let sessionId = ctx . cookies . get ( lcSeesionCookieName )
55
- let csrftoken = ctx . cookies . get ( lcCsrftokenCookieName )
69
+ // 先试着用旧值提交下看是否成功
70
+ const problemData = formateSubmitData ( ctx . request . body )
56
71
let requestData = {
57
72
[ lcSeesionCookieName ] : sessionId ,
58
73
[ lcCsrftokenCookieName ] : csrftoken
59
74
}
60
- if ( ! sessionId || ! csrftoken ) {
61
- return ctx . response . body = fail ( {
62
- code : 403 ,
63
- message : "提交失败,请重新输入账号名与密码后再提交!"
64
- } ) ;
65
- }
66
-
67
- // 先试着用cookie中的旧csrftoken提交下看是否成功
68
- const problemData = formateSubmitData ( ctx . request . body )
69
75
let result = ( await submitSolution ( problemData , requestData ) ) || { }
70
- if ( result . success ) {
71
- return ctx . body = success ( result . data )
76
+ if ( result . success && result . data . submission_id ) {
77
+ return ctx . response . body = success ( Object . assign ( requestData , result . data , lcAccountData ) )
72
78
}
73
79
74
80
// 如果403就用账号密码获取最新csrftoken,再提交一遍
75
81
if ( result . statusCode === 403 ) {
76
- // 获取最新csrftoken
77
- let newRequestData = await getLatestLcRequestData ( ctx )
82
+ const decryPwd = decrypt ( password )
83
+ let newRequestData = await getLcRequestData ( {
84
+ [ _91UsernameCookieName ] : login ,
85
+ [ _91PwdCookieName ] : decryPwd
86
+ } )
78
87
if ( ! newRequestData . success ) {
79
88
return ctx . response . body = fail ( {
80
89
code : 403 ,
81
90
message : newRequestData . message || "提交失败,请重新输入账号名与密码后再提交!"
82
91
} ) ;
83
92
}
84
- // 更新下91的cookie
85
- set91Cookie ( newRequestData , ctx )
86
-
87
- // 再提交一遍
88
93
let retryResult = await submitSolution ( problemData , newRequestData )
89
- if ( retryResult . success ) {
90
- return ctx . body = success ( retryResult . data )
94
+ if ( retryResult . success && retryResult . data . submission_id ) {
95
+ return ctx . body = success ( Object . assign ( newRequestData , retryResult . data , lcAccountData ) )
91
96
}
92
97
}
93
-
94
- // 如果还是失败,就提示用户重新输入账号名与密码
95
98
return ctx . response . body = fail ( {
96
99
code : 403 ,
97
100
message : "提交失败,请重新输入账号名与密码后再提交!"
98
101
} ) ;
99
102
} ) ;
100
103
101
- // 获取最新的的向leetcode发送请求的必要参数
102
- async function getLatestLcRequestData ( ctx ) {
103
- const userName = ctx . cookies . get ( _91UsernameCookieName )
104
- const encryptPassword = ctx . cookies . get ( _91PwdCookieName )
105
- const password = decrypt ( encryptPassword )
106
- return await getLcRequestData ( {
107
- [ _91UsernameCookieName ] : userName ,
108
- [ _91PwdCookieName ] : password
109
- } )
110
- }
111
-
112
104
async function submitSolution ( problem , requestData ) {
113
105
let statusCode = 403
114
106
const url = submitUrl . replace ( '$slug' , problem . slug ) ;
@@ -128,7 +120,6 @@ async function submitSolution(problem, requestData){
128
120
_delay : 1 , // in seconds
129
121
body : JSON . stringify ( problem || { } )
130
122
}
131
- console . log ( opt )
132
123
const result = await fetch ( url , opt ) . then ( ( res ) => {
133
124
statusCode = res . status
134
125
return res . json ( )
@@ -151,4 +142,50 @@ function formateSubmitData(problem = {}){
151
142
} )
152
143
}
153
144
145
+ // 从leetcode的请求中获取cookie值
146
+ function getCookieFromLc ( resp , key ) {
147
+ const cookies = resp . headers [ 'set-cookie' ] ;
148
+ if ( ! cookies ) return null ;
149
+
150
+ for ( let i = 0 ; i < cookies . length ; ++ i ) {
151
+ const sections = cookies [ i ] . split ( ';' ) ;
152
+ for ( let j = 0 ; j < sections . length ; ++ j ) {
153
+ const kv = sections [ j ] . trim ( ) . split ( '=' ) ;
154
+ if ( kv [ 0 ] === key ) return kv [ 1 ] ;
155
+ }
156
+ }
157
+ return null ;
158
+ } ;
159
+
160
+ // 从leetcode中获取 发送请求的必要参数 LEETCODE_SESSION、csrftoken
161
+ async function getLcRequestData ( options ) {
162
+ const opt = {
163
+ url : loginUrl ,
164
+ credentials : 'include' ,
165
+ headers : {
166
+ credentials : 'include' ,
167
+ Origin : baseUrl ,
168
+ Referer : loginUrl ,
169
+ } ,
170
+ form : {
171
+ [ _91UsernameCookieName ] : options [ _91UsernameCookieName ] ,
172
+ [ _91PwdCookieName ] : options [ _91PwdCookieName ]
173
+ }
174
+ }
175
+ return new Promise ( resolve => {
176
+ request . post ( opt , function ( e , resp , body ) {
177
+ if ( resp . statusCode !== 302 ) {
178
+ return resolve ( { success : false , message : 'pwd invaid' } )
179
+ }
180
+ sessionId = getCookieFromLc ( resp , lcSeesionCookieName ) ;
181
+ csrftoken = getCookieFromLc ( resp , lcCsrftokenCookieName ) ;
182
+ resolve ( {
183
+ success : true ,
184
+ [ lcSeesionCookieName ] : sessionId ,
185
+ [ lcCsrftokenCookieName ] :csrftoken
186
+ } )
187
+ } ) ;
188
+ } )
189
+ }
190
+
154
191
module . exports = router ;
0 commit comments