Skip to content

Commit fd892d8

Browse files
committed
gogogo, login done, ugly code...
1 parent 6335e63 commit fd892d8

File tree

7 files changed

+154
-19
lines changed

7 files changed

+154
-19
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,17 +10,17 @@
1010
### Development
1111

1212
```bash
13-
$ npm install
13+
$ npm install(recommend: yarn install)
1414
$ npm run dev
1515
```
1616

17-
Node.js >= 7.6.0 required(async & await native supported).
17+
Node.js >= 7.6.0 required(support native async & await).
1818

1919
## Features
2020

2121
- ✔︎ Full APIs Wrapped
2222
- ✔︎ RESTful Style
23-
- ✔︎ 100% Unit Test
23+
- ✔︎ 30+ Case, 100% Unit Test(`BDD`)
2424

2525
### Unit Test
2626

app/controller/auth.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
/**
2+
* @Controller
3+
* @Module auth
4+
* ---------------------------------------------
5+
* Author : IndexXuan(https://github.com/IndexXuan)
6+
* Mail : indexxuan@gmail.com
7+
* Date : Tue 14 Mar 2017 03:15:19 PM CST
8+
*/
9+
10+
module.exports = app => {
11+
return class AuthController extends app.Controller {
12+
13+
async signin (ctx) {
14+
ctx.body = await ctx.service.auth.signin()
15+
}
16+
17+
} // /.class=>AuthController
18+
}

app/middleware/error_handler.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,15 @@ module.exports = app => {
1919
// 生产环境 500 错误的详细错误内容不返回给客户端,因为可能包含敏感信息
2020
const error = status === 500 && ctx.app.config.env === 'prod'
2121
? 'Internal Server Error'
22-
: err.message
22+
: `from: middleware, msg: ${err.message}`
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============')
3031
} // /.catch
3132
} // /. async function
3233

app/router.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,11 @@
1010
module.exports = app => {
1111

1212
// Todo
13-
// 1. find way to set prefix
14-
// 2. 多个API貌似没有分页
13+
// 1. find way to set router prefix
14+
// 2. 多个API貌似没有分页参数
15+
16+
// @auth
17+
app.get('v2ex', '/api/v2/auth/signin', 'auth.signin')
1518

1619
// @site
1720
app.get('v2ex', '/api/v2/site/info', 'site.info')

app/service/auth.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
/**
2+
* @Service
3+
* @Module auth
4+
* ---------------------------------------------
5+
* Author : IndexXuan(https://github.com/IndexXuan)
6+
* Mail : indexxuan@gmail.com
7+
* Date : Tue 14 Mar 2017 03:19:07 PM CST
8+
*/
9+
10+
const setCookieParser = require('set-cookie-parser')
11+
12+
module.exports = app => {
13+
return class AuthService extends app.Service {
14+
15+
constructor (ctx) {
16+
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 = ''
23+
}
24+
25+
async request (url, opts) {
26+
opts = Object.assign({
27+
timeout: [ '30s', '30s' ],
28+
}, opts)
29+
30+
return await this.ctx.curl(url, opts)
31+
}
32+
33+
getKeys (content) {
34+
const re = /class="sl"\s*name=\"(\w*)/g
35+
const onceRe = /type="hidden"\s*value="(\w*)\s*/
36+
const matches = content && content.match(re)
37+
this.userKey = matches[0].match(/name="(\w*)/)[1]
38+
this.passKey = matches[1].match(/name="(\w*)/)[1]
39+
this.once = content.match(onceRe)[1]
40+
}
41+
42+
async getAuthPrepare () {
43+
const result = await this.request(this.url, {
44+
method: 'GET',
45+
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+
}
52+
})
53+
this.setCookiestr = result.headers['set-cookie'][0]
54+
const cs = setCookieParser(result)
55+
this.cookies = cs
56+
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)
67+
}
68+
69+
async signin (ctx) {
70+
71+
await this.getAuthPrepare()
72+
73+
const opts = {
74+
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+
},
83+
data: {
84+
[this.userKey]: "your username",
85+
[this.passKey]: "your password",
86+
"once": this.once,
87+
"next": "/"
88+
}
89+
}
90+
91+
const result = await this.request(this.url, opts)
92+
93+
const cs = setCookieParser(result)
94+
// set cookies for client
95+
cs.forEach(c => {
96+
this.ctx.cookies.set(c.name, c.value, {
97+
domain: '',
98+
path: c.path,
99+
expires: c.expires,
100+
httpOnly: c.httpOnly
101+
})
102+
})
103+
104+
// return all cookies to client
105+
return cs.concat(this.cookies.filter(item => item.name === 'PB3_SESSION'))
106+
}
107+
108+
} // /.class=>AuthService
109+
}

package.json

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,14 @@
33
"version": "1.0.0",
44
"description": "V2EX APIs powered by egg(Node.js >= 7.6) with full unit test",
55
"private": true,
6+
"scripts": {
7+
"start": "node index.js",
8+
"dev": "egg-bin dev",
9+
"test": "egg-bin test"
10+
},
611
"dependencies": {
7-
"egg": "^1.0.0-rc.2"
12+
"egg": "^1.0.0-rc.2",
13+
"set-cookie-parser": "^2.0.0"
814
},
915
"devDependencies": {
1016
"egg-bin": "^2.2.3",
@@ -14,15 +20,15 @@
1420
"engines": {
1521
"node": ">=7.6.0"
1622
},
17-
"scripts": {
18-
"start": "node index.js",
19-
"dev": "egg-bin dev",
20-
"test": "egg-bin test"
21-
},
2223
"repository": {
2324
"type": "git",
2425
"url": "https://github.com/IndexXuan/v2ex-api"
2526
},
27+
"keywords": [
28+
"v2ex",
29+
"egg",
30+
"async-await"
31+
],
2632
"author": "indexxuan",
2733
"license": "MIT"
2834
}

yarn.lock

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1857,6 +1857,10 @@ serialize-json@^1.0.1:
18571857
is-type-of "^1.0.0"
18581858
utility "^1.9.0"
18591859

1860+
set-cookie-parser@^2.0.0:
1861+
version "2.0.0"
1862+
resolved "https://registry.yarnpkg.com/set-cookie-parser/-/set-cookie-parser-2.0.0.tgz#b6d75f2128e12303c217e2e154c5b2f15f6c4949"
1863+
18601864
setprototypeof@1.0.3:
18611865
version "1.0.3"
18621866
resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04"
@@ -2037,19 +2041,13 @@ uglify-to-browserify@~1.0.0:
20372041
version "1.0.2"
20382042
resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7"
20392043

2040-
uid-safe@2.1.3:
2044+
uid-safe@2.1.3, uid-safe@^2.1.3:
20412045
version "2.1.3"
20422046
resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.3.tgz#077e264a00b3187936b270bb7376a26473631071"
20432047
dependencies:
20442048
base64-url "1.3.3"
20452049
random-bytes "~1.0.0"
20462050

2047-
uid-safe@^2.1.3:
2048-
version "2.1.4"
2049-
resolved "https://registry.yarnpkg.com/uid-safe/-/uid-safe-2.1.4.tgz#3ad6f38368c6d4c8c75ec17623fb79aa1d071d81"
2050-
dependencies:
2051-
random-bytes "~1.0.0"
2052-
20532051
universal-deep-strict-equal@^1.2.1:
20542052
version "1.2.2"
20552053
resolved "https://registry.yarnpkg.com/universal-deep-strict-equal/-/universal-deep-strict-equal-1.2.2.tgz#0da4ac2f73cff7924c81fa4de018ca562ca2b0a7"

0 commit comments

Comments
 (0)