Skip to content

Commit fc1de33

Browse files
committed
signin rush, but not done...
1 parent fd892d8 commit fc1de33

File tree

4 files changed

+122
-51
lines changed

4 files changed

+122
-51
lines changed

app/controller/auth.js

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,12 @@
1010
module.exports = app => {
1111
return class AuthController extends app.Controller {
1212

13+
async login (ctx) {
14+
ctx.body = await ctx.service.auth.login(ctx.query)
15+
}
16+
1317
async signin (ctx) {
14-
ctx.body = await ctx.service.auth.signin()
18+
ctx.body = await ctx.service.auth.signin(ctx.query)
1519
}
1620

1721
} // /.class=>AuthController

app/middleware/error_handler.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,15 +19,15 @@ module.exports = app => {
1919
// 生产环境 500 错误的详细错误内容不返回给客户端,因为可能包含敏感信息
2020
const error = status === 500 && ctx.app.config.env === 'prod'
2121
? 'Internal Server Error'
22-
: `from: middleware, msg: ${err.message}`
22+
: `from: middleware, \n msg: ${err.message}, \n stacks ${err.stack}`
2323
// 从 error 对象上读出各个属性,设置到响应中
2424
ctx.body = { error }
2525
// 422 Unprocessable Entity
2626
if (status === 422) {
2727
ctx.body.detail = err.errors
2828
}
2929
ctx.status = status
30-
console.log('-============middleware============')
30+
// app.logger.info('========== middleware catched error ==========')
3131
} // /.catch
3232
} // /. async function
3333

app/router.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ module.exports = app => {
1414
// 2. 多个API貌似没有分页参数
1515

1616
// @auth
17+
app.get('v2ex', '/api/v2/auth/login', 'auth.login')
1718
app.get('v2ex', '/api/v2/auth/signin', 'auth.signin')
1819

1920
// @site

app/service/auth.js

Lines changed: 114 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,29 @@ module.exports = app => {
1414

1515
constructor (ctx) {
1616
super(ctx)
17-
this.url = 'https://www.v2ex.com/signin'
18-
this.setCookiestr = '' // 供放在headers里使用
19-
this.cookies = '' // get到的cookie暂存,供合并给最终的cookies
20-
this.userKey = ''
21-
this.passKey = ''
22-
this.once = ''
17+
this.commonHeaders = {
18+
"Accept": "text/html,application/xhtml+xml,application/xml",
19+
"Origin": "https://www.v2ex.com",
20+
"Referer": "https://www.v2ex.com/massion",
21+
"User-Agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
22+
}
23+
24+
// sessionid
25+
this.sessionCookieName = 'PB3_SESSION'
26+
27+
// token cookie name
28+
this.tokenCookieName = 'A2'
29+
30+
// 获取登陆签名
31+
this.loginUrl = 'https://www.v2ex.com/signin'
32+
this.sessionCookie = '' // 供 `login`接口放在Header里 `Set-Cookie` 使用
33+
this.loginCookieArr = '' // get到的cookie暂存,供合并给最终的cookie
34+
this.userKey = '' // 用户名 输入框埋下的随机key
35+
this.passKey = '' // 密码 输入框埋下的随机key
36+
this.once = '' // input[type="hidden"][name="once"]的随机令牌值(5位数字目前)
37+
38+
// 签到领金币
39+
this.signinUrl = 'https://www.v2ex.com/mission/daily'
2340
}
2441

2542
async request (url, opts) {
@@ -30,7 +47,7 @@ module.exports = app => {
3047
return await this.ctx.curl(url, opts)
3148
}
3249

33-
getKeys (content) {
50+
getLoginTokens (content) {
3451
const re = /class="sl"\s*name=\"(\w*)/g
3552
const onceRe = /type="hidden"\s*value="(\w*)\s*/
3653
const matches = content && content.match(re)
@@ -39,71 +56,120 @@ module.exports = app => {
3956
this.once = content.match(onceRe)[1]
4057
}
4158

42-
async getAuthPrepare () {
43-
const result = await this.request(this.url, {
59+
/**
60+
* getLoginPrepare
61+
*
62+
*/
63+
async getLoginPrepare () {
64+
const result = await this.request(this.loginUrl, {
4465
method: 'GET',
4566
dataType: 'text',
46-
headers: {
47-
"accept": "text/html,application/xhtml+xml,application/xml",
48-
"origin": "https://www.v2ex.com",
49-
"referer": "https://www.v2ex.com/signin",
50-
"user-agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
51-
}
67+
headers: this.commonHeaders
5268
})
53-
this.setCookiestr = result.headers['set-cookie'][0]
69+
70+
this.sessionCookie = result.headers['set-cookie'][0]
71+
5472
const cs = setCookieParser(result)
55-
this.cookies = cs
5673

57-
// set cookies for client
58-
cs.forEach(c => {
59-
this.ctx.cookies.set(c.name, c.value, {
60-
domain: '',
61-
expires: c.expires,
62-
path: c.path,
63-
httpOnly: c.httpOnly
64-
})
65-
})
66-
return this.getKeys(result.data)
74+
// 设置到暂存对象中
75+
this.loginCookieArr = cs.filter(cookie => cookie.name !== 'V2EX_LANG')
76+
77+
return this.getLoginTokens(result.data)
6778
}
6879

69-
async signin (ctx) {
80+
/**
81+
* login
82+
* 登陆获取签名
83+
*
84+
* @param params
85+
*/
86+
async login (params) {
7087

71-
await this.getAuthPrepare()
88+
await this.getLoginPrepare()
89+
90+
const { username, password } = params
7291

7392
const opts = {
7493
method: 'POST',
75-
headers: {
76-
"method": "POST",
77-
"accept": "text/html,application/xhtml+xml,application/xml",
78-
"origin": "https://www.v2ex.com",
79-
"referer": "https://www.v2ex.com/signin",
80-
"Cookie": this.setCookiestr,
81-
"user-agent": "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36"
82-
},
94+
headers: Object.assign(this.commonHeaders, { Cookie: this.sessionCookie }),
8395
data: {
84-
[this.userKey]: "your username",
85-
[this.passKey]: "your password",
86-
"once": this.once,
87-
"next": "/"
96+
[this.userKey]: username,
97+
[this.passKey]: password,
98+
"once": this.once
8899
}
89100
}
90101

91-
const result = await this.request(this.url, opts)
102+
const result = await this.request(this.loginUrl, opts)
92103

93104
const cs = setCookieParser(result)
94-
// set cookies for client
95-
cs.forEach(c => {
105+
const tokens = cs.concat(this.loginCookieArr)
106+
let success = false
107+
tokens.forEach(c => {
108+
if (c.name === this.tokenCookieName) success = true
96109
this.ctx.cookies.set(c.name, c.value, {
110+
httpOnly: true,
97111
domain: '',
98112
path: c.path,
99-
expires: c.expires,
100-
httpOnly: c.httpOnly
113+
expires: c.expires
101114
})
102115
})
103116

104-
// return all cookies to client
105-
return cs.concat(this.cookies.filter(item => item.name === 'PB3_SESSION'))
117+
return {
118+
result: success,
119+
msg: success ? 'success' : 'sorry! Not get enough token for you',
120+
data: {
121+
username: username
122+
}
123+
}
124+
}
125+
126+
getSigninOnce (content) {
127+
// update this.once
128+
const onceResult = content.match(/once=(\w*)/g)[1]
129+
this.once = onceResult.match(/once=(\w*)/)[1]
130+
}
131+
132+
async getSigninPrepare () {
133+
const token = `A2=${this.ctx.cookies.get('A2')}`
134+
const result = await this.request(this.signinUrl, {
135+
method: 'GET',
136+
dataType: 'text',
137+
headers: Object.assign(this.commonHeaders, { Cookie: `${this.sessionCookie} ${token}` })
138+
})
139+
140+
return this.getSigninOnce(result.data)
141+
}
142+
143+
/**
144+
* signin
145+
* 签到领金币
146+
*
147+
* @param params
148+
*/
149+
async signin (params) {
150+
await this.getSigninPrepare()
151+
152+
const token = `${this.tokenCookieName}=${this.ctx.cookies.get(this.tokenCookieName)}`
153+
const session = `${this.sessionCookieName}=${this.ctx.cookies.get(this.sessionCookieName)}`
154+
const headers = Object.assign(this.commonHeaders, { Cookie: `${session}; ${token}` })
155+
console.log(headers, this.once)
156+
const opts = {
157+
dataType: 'text',
158+
method: 'get'
159+
}
160+
161+
const result = await this.request(`${this.signinUrl}/redeem`, Object.assign(opts, {
162+
headers: headers,
163+
data: {
164+
'once': this.once
165+
}
166+
}))
167+
const success = await this.request(`${this.signinUrl}`, Object.assign(opts, {
168+
headers: this.commonHeaders
169+
}))
170+
return success
106171
}
107172

108173
} // /.class=>AuthService
109174
}
175+

0 commit comments

Comments
 (0)