From 8e5a768a10b6b05ab8354e6439703e37cc986c91 Mon Sep 17 00:00:00 2001
From: chenzhenyu <402731062@qq.com>
Date: Fri, 12 Jul 2019 01:02:05 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E6=88=90=E7=9B=B4=E6=8E=A5=E8=B4=A6?=
=?UTF-8?q?=E5=8F=B7=E5=AF=86=E7=A0=81=E7=99=BB=E9=99=86=F0=9F=90=B1?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
app.json | 2 +-
components/input.js | 2 +-
navigations.js | 2 +-
navigations/index.js | 4 +-
screens/auth/index.js | 4 +-
screens/home/index.js | 5 +-
screens/login-v2/index.js | 616 ++++++++++++++++++++++++--------------
screens/login/index.js | 14 +-
utils/fetch.js | 10 +-
9 files changed, 415 insertions(+), 244 deletions(-)
diff --git a/app.json b/app.json
index 7208561dc..af8ed0450 100644
--- a/app.json
+++ b/app.json
@@ -31,4 +31,4 @@
"description": "A React Native App for https://bangumi.tv ",
"githubUrl": "https://github.com/czy0729/Bangumi"
}
-}
+}
\ No newline at end of file
diff --git a/components/input.js b/components/input.js
index 5786fa7f5..aa768fd97 100644
--- a/components/input.js
+++ b/components/input.js
@@ -3,7 +3,7 @@
* @Author: czy0729
* @Date: 2019-03-19 01:43:43
* @Last Modified by: czy0729
- * @Last Modified time: 2019-06-22 14:17:41
+ * @Last Modified time: 2019-07-11 22:36:08
*/
import React from 'react'
import {
diff --git a/navigations.js b/navigations.js
index fae974c15..e855c4eae 100644
--- a/navigations.js
+++ b/navigations.js
@@ -2,7 +2,7 @@
* @Author: czy0729
* @Date: 2019-06-02 14:42:28
* @Last Modified by: czy0729
- * @Last Modified time: 2019-07-08 23:52:21
+ * @Last Modified time: 2019-07-12 00:37:34
*/
export default {
initialRouteName: 'HomeTab', // HomeTab
diff --git a/navigations/index.js b/navigations/index.js
index 521d4329b..623abac07 100644
--- a/navigations/index.js
+++ b/navigations/index.js
@@ -2,7 +2,7 @@
* @Author: czy0729
* @Date: 2019-03-29 10:38:12
* @Last Modified by: czy0729
- * @Last Modified time: 2019-07-08 23:52:46
+ * @Last Modified time: 2019-07-11 22:15:31
*/
import React from 'react'
import { StyleSheet, View } from 'react-native'
@@ -81,7 +81,7 @@ const HomeStack = createStackNavigator(
Calendar,
Discovery,
HomeTab,
- Login: LoginV2,
+ Login,
LoginV2,
Mono,
Notify,
diff --git a/screens/auth/index.js b/screens/auth/index.js
index 272a5db8a..ecb81cd9f 100644
--- a/screens/auth/index.js
+++ b/screens/auth/index.js
@@ -2,7 +2,7 @@
* @Author: czy0729
* @Date: 2019-03-31 10:25:46
* @Last Modified by: czy0729
- * @Last Modified time: 2019-06-23 22:12:47
+ * @Last Modified time: 2019-07-12 00:37:52
*/
import React from 'react'
import { View } from 'react-native'
@@ -75,7 +75,7 @@ class Auth extends React.Component {
_.mt.md
]}
shadow
- onPress={() => navigation.push('Login')}
+ onPress={() => navigation.push('LoginV2')}
>
现在登录
diff --git a/screens/home/index.js b/screens/home/index.js
index 3acb15eb4..bbdb7be48 100644
--- a/screens/home/index.js
+++ b/screens/home/index.js
@@ -2,7 +2,7 @@
* @Author: czy0729
* @Date: 2019-03-13 08:34:37
* @Last Modified by: czy0729
- * @Last Modified time: 2019-06-25 19:50:56
+ * @Last Modified time: 2019-07-12 00:42:09
*/
import React from 'react'
import { StyleSheet, View } from 'react-native'
@@ -11,6 +11,7 @@ import PropTypes from 'prop-types'
import { observer } from 'mobx-react'
import { Image } from '@components'
import { IconTabBar, IconTabsHeader, ManageModal } from '@screens/_'
+import { userStore } from '@stores'
import { inject, withTabsHeader } from '@utils/decorators'
import { hm } from '@utils/fetch'
import { IOS } from '@constants'
@@ -74,7 +75,7 @@ class Home extends React.Component {
}
setTimeout(() => {
- hm(`?id=${$.userInfo.userId}`, title)
+ hm(`?id=${userStore.myUserId}`, title)
}, 4000)
}
diff --git a/screens/login-v2/index.js b/screens/login-v2/index.js
index ed5c5b86b..b1dd6a180 100644
--- a/screens/login-v2/index.js
+++ b/screens/login-v2/index.js
@@ -5,24 +5,59 @@
* @Author: czy0729
* @Date: 2019-06-30 15:48:46
* @Last Modified by: czy0729
- * @Last Modified time: 2019-07-11 00:41:38
+ * @Last Modified time: 2019-07-12 01:00:36
*/
import React from 'react'
-import { StyleSheet, View, Image } from 'react-native'
+import { StyleSheet, View, Image as RNImage } from 'react-native'
import { Constants } from 'expo'
import cheerio from 'cheerio-without-node-native'
-import { Input, Button } from '@components'
+import {
+ Flex,
+ Text,
+ Touchable,
+ Image,
+ Input,
+ Button,
+ KeyboardSpacer
+} from '@components'
import { StatusBar, StatusBarPlaceholder } from '@screens/_'
-// import { userStore } from '@stores'
+import { userStore } from '@stores'
import { urlStringify, getTimestamp } from '@utils'
-import { HOST } from '@constants'
+import { info } from '@utils/ui'
+import { HOST, APP_ID, OAUTH_REDIRECT_URL } from '@constants'
import _ from '@styles'
-// config
-const email = '402731062@qq.com'
-const password = '84783019'
-const clientId = 'bgm8885c4d524cd61fc'
-const clientSecret = '1da52e7834bbb73cca90302f9ddbc8dd'
+function xhr({ method = 'GET', url, data, headers = {}, responseType } = {}) {
+ return new Promise((resolve, reject) => {
+ const request = new XMLHttpRequest()
+ request.onreadystatechange = function() {
+ if (this.readyState === 4 && this.status === 200) {
+ resolve(this)
+ }
+ }
+ xhr.onerror = function() {
+ reject(new TypeError('Network request failed'))
+ }
+ xhr.ontimeout = function() {
+ reject(new TypeError('Network request failed'))
+ }
+ xhr.onabort = function() {
+ reject(new TypeError('AbortError'))
+ }
+
+ request.open(method, url, true)
+ request.withCredentials = false
+ if (responseType) {
+ request.responseType = responseType
+ }
+ Object.keys(headers).forEach(key => {
+ request.setRequestHeader(key, headers[key])
+ })
+
+ const body = data ? urlStringify(data) : null
+ request.send(body)
+ })
+}
export default class LoginV2 extends React.Component {
static navigationOptions = {
@@ -30,19 +65,23 @@ export default class LoginV2 extends React.Component {
}
state = {
- state: getTimestamp(),
+ clicked: false,
+ email: '',
+ password: '',
captcha: '',
- base64: ''
+ base64: '',
+ loading: false,
+ info: ''
}
userAgent = ''
formhash = ''
- code = ''
- accessToken = ''
cookie = {
chiiSid: '',
chiiAuth: ''
}
+ code = ''
+ accessToken = ''
async componentDidMount() {
this.userAgent = await Constants.getWebViewUserAgentAsync()
@@ -52,112 +91,95 @@ export default class LoginV2 extends React.Component {
await this.getCaptcha()
}
- logout = () =>
- new Promise(resolve => {
- console.log('logout')
- const request = new XMLHttpRequest()
+ onTour = () => {
+ const { navigation } = this.props
+ navigation.goBack()
+ }
- request.onreadystatechange = function() {
- if (this.readyState === 4 && this.status === 200) {
- resolve()
- }
- }
- request.withCredentials = false
- request.open('GET', `${HOST}/logout/7dd16c5e`, true)
- request.setRequestHeader('User-Agent', this.userAgent)
- request.send()
+ onLogin = () => {
+ this.setState({
+ clicked: true
})
+ }
- getFormHash = () =>
- new Promise(resolve => {
- console.log('getFormHash')
- const request = new XMLHttpRequest()
- const that = this
-
- request.onreadystatechange = function() {
- if (this.readyState === 4 && this.status === 200) {
- // set-cookie
- if (this.responseHeaders['Set-Cookie']) {
- const match = this.responseHeaders['Set-Cookie'].match(
- /chii_sid=(.+?);/
- )
- if (match) {
- that.cookie.chiiSid = match[1]
- }
- }
-
- // formhash
- const match = this._response.match(
- //
- )
- if (match) {
- that.formhash = match[1]
- }
-
- resolve()
- }
+ logout = () =>
+ xhr({
+ url: `${HOST}/logout/7dd16c5e`,
+ headers: {
+ 'User-Agent': this.userAgent
}
- request.withCredentials = false
- request.open('GET', `${HOST}/login`, true)
- request.setRequestHeader('User-Agent', this.userAgent)
- request.send()
})
- getCaptcha = () =>
- new Promise(resolve => {
- console.log('getCaptcha')
- const { state } = this.state
- const request = new XMLHttpRequest()
- const that = this
-
- request.onreadystatechange = function() {
- if (this.readyState === 4 && this.status === 200) {
- that.setState({
- base64: `data:image/gif;base64,${this._response}`
- })
- resolve()
- }
+ getFormHash = async () => {
+ const res = xhr({
+ url: `${HOST}/login`,
+ headers: {
+ 'User-Agent': this.userAgent
}
- request.withCredentials = false
- request.responseType = 'arraybuffer'
- request.open('GET', `${HOST}/signup/captcha?state=${state}`, true)
- request.setRequestHeader('Cookie', `; chii_sid=${this.cookie.chiiSid};`)
- request.setRequestHeader('User-Agent', this.userAgent)
- request.send()
})
- login = () =>
- new Promise(resolve => {
- console.log('login')
- const { captcha } = this.state
- const request = new XMLHttpRequest()
- const that = this
-
- request.onreadystatechange = function() {
- if (this.readyState === 4 && this.status === 200) {
- if (this.responseHeaders['Set-Cookie']) {
- const match = this.responseHeaders['Set-Cookie'].match(
- /chii_auth=(.+?);/
- )
- if (match) {
- that.cookie.chiiAuth = match[1]
- }
- }
-
- that.oauth()
- resolve()
- }
+ const { responseHeaders, _response } = await res
+ if (responseHeaders['Set-Cookie']) {
+ const match = responseHeaders['Set-Cookie'].match(/chii_sid=(.+?);/)
+ if (match) {
+ this.cookie.chiiSid = match[1]
}
- request.withCredentials = false
- request.open('POST', `${HOST}/FollowTheRabbit`, true)
- request.setRequestHeader(
- 'Content-Type',
- 'application/x-www-form-urlencoded'
- )
- request.setRequestHeader('Cookie', `; chii_sid=${this.cookie.chiiSid};`)
- request.setRequestHeader('User-Agent', this.userAgent)
- request.send(
- urlStringify({
+ }
+
+ const match = _response.match(
+ //
+ )
+ if (match) {
+ this.formhash = match[1]
+ }
+
+ return res
+ }
+
+ getCaptcha = async () => {
+ const res = xhr({
+ url: `${HOST}/signup/captcha?state=${getTimestamp()}`,
+ headers: {
+ Cookie: `; chii_sid=${this.cookie.chiiSid};`,
+ 'User-Agent': this.userAgent
+ },
+ responseType: 'arraybuffer'
+ })
+
+ const { _response } = await res
+ this.setState({
+ base64: `data:image/gif;base64,${_response}`
+ })
+
+ return res
+ }
+
+ login = async () => {
+ const { loading, email, password, captcha } = this.state
+ if (loading) {
+ return
+ }
+
+ if (!email || !password || !captcha) {
+ info('请填写以上字段')
+ return
+ }
+
+ this.setState({
+ loading: true,
+ info: '登陆请求中...'
+ })
+
+ try {
+ const { responseHeaders } = await xhr({
+ method: 'POST',
+ url: `${HOST}/FollowTheRabbit`,
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ Cookie: `; chii_sid=${this.cookie.chiiSid};`,
+ 'User-Agent': this.userAgent
+ },
+ data: {
formhash: this.formhash,
referer: '',
dreferer: '',
@@ -165,157 +187,305 @@ export default class LoginV2 extends React.Component {
password,
captcha_challenge_field: captcha,
loginsubmit: '登录'
+ }
+ })
+
+ if (responseHeaders['Set-Cookie']) {
+ const match = responseHeaders['Set-Cookie'].match(/chii_auth=(.+?);/)
+ if (match) {
+ this.cookie.chiiAuth = match[1]
+ }
+ }
+
+ if (!this.cookie.chiiAuth) {
+ this.setState({
+ loading: false,
+ info: '登陆失败, 请重试或点击这里前往旧版登陆 >'
})
- )
- })
+ return
+ }
- oauth = () =>
- new Promise(resolve => {
- console.log('oauth')
- const request = new XMLHttpRequest()
- const that = this
+ this.setState({
+ info: '获取授权表单码...'
+ })
+ await this.oauth()
- request.onreadystatechange = function() {
- if (this.readyState === 4 && this.status === 200) {
- that.updateFormhash(this._response)
- resolve()
- }
+ this.setState({
+ info: '授权中...'
+ })
+ await this.authorize()
+
+ this.setState({
+ info: '授权成功, 获取token中...'
+ })
+ await userStore.fetchAccessToken(this.code)
+
+ this.setState({
+ loading: false,
+ info: '登陆成功, 正在请求个人信息...'
+ })
+ this.inStore()
+ } catch (ex) {
+ this.setState({
+ loading: false,
+ info: '登陆失败, 请重试或点击这里前往旧版登陆 >'
+ })
+ }
+ }
+
+ oauth = async () => {
+ const res = xhr({
+ url: `${HOST}/oauth/authorize?client_id=${APP_ID}&response_type=code&redirect_uri=${OAUTH_REDIRECT_URL}`,
+ headers: {
+ Cookie: `; chii_sid=${this.cookie.chiiSid}; chii_auth=${
+ this.cookie.chiiAuth
+ };`,
+ 'User-Agent': this.userAgent
}
- request.withCredentials = false
- request.open(
- 'GET',
- `${HOST}/oauth/authorize?client_id=${clientId}&response_type=code&redirect_uri=code`,
- true
- )
- request.setRequestHeader(
- 'Cookie',
- `; chii_sid=${this.cookie.chiiSid}; chii_auth=${this.cookie.chiiAuth};`
- )
- request.setRequestHeader('User-Agent', this.userAgent)
- request.send(null)
})
- updateFormhash = html => {
- console.log('updateFormhash')
+ const { _response } = await res
this.formhash = cheerio
- .load(html)('input[name=formhash]')
+ .load(_response)('input[name=formhash]')
.attr('value')
- this.authorize()
+ return res
}
- authorize = () =>
- new Promise(resolve => {
- console.log('authorize')
- const request = new XMLHttpRequest()
- const that = this
-
- request.onreadystatechange = function() {
- if (this.readyState === 4 && this.status === 200) {
- that.code = this.responseURL
- .split('=')
- .slice(1)
- .join('=')
- that.getAccessToken()
- resolve()
- }
+ authorize = async () => {
+ const res = xhr({
+ method: 'POST',
+ url: `${HOST}/oauth/authorize?client_id=${APP_ID}&response_type=code&redirect_uri=${OAUTH_REDIRECT_URL}`,
+ headers: {
+ 'Content-Type': 'application/x-www-form-urlencoded',
+ Cookie: `; chii_sid=${this.cookie.chiiSid}; chii_auth=${
+ this.cookie.chiiAuth
+ };`,
+ 'User-Agent': this.userAgent
+ },
+ data: {
+ formhash: this.formhash,
+ redirect_uri: '',
+ client_id: APP_ID,
+ submit: '授权'
}
- request.withCredentials = false
- request.open(
- 'POST',
- `${HOST}/oauth/authorize?client_id=${clientId}&response_type=code&redirect_uri=code`,
- true
- )
- request.setRequestHeader(
- 'Content-Type',
- 'application/x-www-form-urlencoded'
- )
- request.setRequestHeader(
- 'Cookie',
- `; chii_sid=${this.cookie.chiiSid}; chii_auth=${this.cookie.chiiAuth};`
- )
- request.setRequestHeader('User-Agent', this.userAgent)
- request.send(
- urlStringify({
- formhash: this.formhash,
- redirect_uri: '',
- client_id: clientId,
- submit: '授权'
- })
- )
})
- getAccessToken = () =>
- new Promise(resolve => {
- console.log('getAccessToken')
- const request = new XMLHttpRequest()
+ const { responseURL } = await res
+ this.code = responseURL
+ .split('=')
+ .slice(1)
+ .join('=')
+ return res
+ }
- request.onreadystatechange = function() {
- if (this.readyState === 4 && this.status === 200) {
- log(this)
- resolve()
- }
- }
- request.withCredentials = false
- request.open('POST', `${HOST}/oauth/access_token`, true)
- request.setRequestHeader(
- 'Content-Type',
- 'application/x-www-form-urlencoded'
- )
- request.setRequestHeader('User-Agent', this.userAgent)
- request.send(
- urlStringify({
- grant_type: 'authorization_code',
- client_id: clientId,
- client_secret: clientSecret,
- code: this.code,
- redirect_uri: 'code',
- state: ''
- })
- )
+ // getAccessToken = () =>
+ // xhr({
+ // method: 'POST',
+ // url: `${HOST}/oauth/access_token`,
+ // headers: {
+ // 'Content-Type': 'application/x-www-form-urlencoded',
+ // 'User-Agent': this.userAgent
+ // },
+ // data: {
+ // grant_type: 'authorization_code',
+ // client_id: APP_ID,
+ // client_secret: clientSecret,
+ // code: this.code,
+ // redirect_uri: 'code',
+ // state: ''
+ // }
+ // })
+
+ inStore = async () => {
+ const { navigation } = this.props
+ userStore.updateUserCookie({
+ cookie: `; chii_sid=${this.cookie.chiiSid}; chii_auth=${
+ this.cookie.chiiAuth
+ };`,
+ userAgent: this.userAgent
})
+ await userStore.fetchUserInfo()
+ navigation.popToTop()
+ }
- onChange = evt => {
+ onChange = (evt, type) => {
const { nativeEvent } = evt
const { text } = nativeEvent
this.setState({
- captcha: text
+ [type]: text,
+ info: ''
})
}
+ renderPreview() {
+ return (
+
+
+
+
+
+
+
+ )
+ }
+
+ renderForm() {
+ const { email, password, captcha, base64, loading, info } = this.state
+ return (
+
+
+
+
+
+
+
+ this.onChange(evt, 'email')}
+ />
+
+
+
+
+ this.onChange(evt, 'password')}
+ />
+
+
+
+
+ this.onChange(evt, 'captcha')}
+ />
+
+
+ {!!base64 && (
+
+ )}
+
+
+
+ {
+ if (info.includes('登陆失败')) {
+ const { navigation } = this.props
+ navigation.push('Login')
+ }
+ }}
+ >
+ {info}
+
+
+
+ )
+ }
+
render() {
- const { captcha, base64 } = this.state
- console.log(base64)
+ const { clicked } = this.state
return (
- {!!base64 && (
-
+ {clicked ? this.renderForm() : this.renderPreview()}
+
+ {clicked ? (
+
+ 隐私策略: 我们十分尊重您的个人隐私, 这些信息仅存储于您的设备中,
+ 我们不会收集上述信息.
+
+ ) : (
+ {
+ const { navigation } = this.props
+ navigation.push('Login')
}}
- />
+ >
+ 旧版授权登陆
+
)}
-
-
+
)
}
}
const styles = StyleSheet.create({
+ gray: {
+ backgroundColor: 'rgb(251, 251, 251)'
+ },
+ old: {
+ position: 'absolute',
+ zIndex: 1,
+ bottom: _.bottom,
+ left: 0,
+ width: '100%',
+ padding: _.sm,
+ textAlign: 'center'
+ },
bottomContainer: {
- width: 200,
- height: 200
+ width: 280,
+ height: 420
},
- loading: {
- width: 200,
- height: 64
+ form: {
+ width: 280,
+ paddingBottom: 152
},
- gray: {
- backgroundColor: 'rgb(251, 251, 251)'
+ input: {
+ height: 44
+ },
+ captchaContainer: {
+ width: 118,
+ height: 44,
+ marginLeft: _.sm,
+ backgroundColor: _.colorBg
+ },
+ captcha: {
+ width: 118,
+ height: 44
},
ps: {
position: 'absolute',
diff --git a/screens/login/index.js b/screens/login/index.js
index 36c81991f..b1f2209f2 100644
--- a/screens/login/index.js
+++ b/screens/login/index.js
@@ -4,7 +4,7 @@
* @Author: czy0729
* @Date: 2019-03-31 11:21:32
* @Last Modified by: czy0729
- * @Last Modified time: 2019-06-23 00:24:39
+ * @Last Modified time: 2019-07-12 00:49:08
*/
import React from 'react'
import { StyleSheet, View } from 'react-native'
@@ -162,7 +162,7 @@ export default class Login extends React.Component {
/>