finish rudimentary auth flow

This commit is contained in:
41666 2017-12-10 05:26:56 -06:00
parent 90f302c103
commit cfc623b228
10 changed files with 101 additions and 15 deletions

View file

@ -51,6 +51,10 @@ module.exports = (R, $) => {
}) })
R.get('/api/auth/redirect', ctx => { R.get('/api/auth/redirect', ctx => {
ctx.redirect($.discord.getAuthUrl()) ctx.body = { url: $.discord.getAuthUrl() }
})
R.post('/api/auth/logout', ctx => {
ctx.session = null
}) })
} }

View file

@ -92,6 +92,10 @@ class DiscordService extends Service {
async getUser (authToken) { async getUser (authToken) {
const url = 'https://discordapp.com/api/v6/users/@me' const url = 'https://discordapp.com/api/v6/users/@me'
try { try {
if (authToken == null || authToken === '') {
throw new Error('not logged in')
}
const rsp = const rsp =
await superagent await superagent
.get(url) .get(url)

View file

@ -20,6 +20,18 @@ export const userInit = async dispatch => {
dispatch(fetchServers) dispatch(fetchServers)
} catch (e) { } catch (e) {
console.log(e) if (!window.location.pathname.startsWith('/oauth')) {
window.location.href = '/oauth/flow'
} }
} }
}
export const userLogout = async dispatch => {
await superagent.post('/api/auth/logout')
dispatch({
type: Symbol.for('reset user')
})
window.location.href = '/'
}

View file

@ -1,7 +1,10 @@
import React, { Component } from 'react' import React, { Component } from 'react'
import { Redirect } from 'react-router-dom' import { Redirect } from 'react-router-dom'
import superagent from 'superagent' import superagent from 'superagent'
import { connect } from 'react-redux'
import { fetchServers } from '../../actions'
@connect()
class OauthCallback extends Component { class OauthCallback extends Component {
state = { state = {
notReady: true, notReady: true,
@ -18,14 +21,35 @@ class OauthCallback extends Component {
return return
} }
this.props.history.replace(this.props.location.pathname) this.props.history.replace(this.props.location.pathname)
let counter = 0
const retry = async () => {
try {
const rsp = await superagent.get('/api/auth/user')
this.setState({ notReady: false })
this.props.dispatch({
type: Symbol.for('set user'),
data: rsp.body
})
this.props.dispatch(fetchServers)
} catch (e) {
counter++
if (counter > 12) {
this.setState({ message: "i couldn't log you in. :c" })
} else {
setTimeout(() => { retry() }, 250)
}
}
}
// pass token to backend, await it to finish it's business. // pass token to backend, await it to finish it's business.
try { try {
const rsp = await superagent.post('/api/auth/token').send({ token }) await superagent.post('/api/auth/token').send({ token })
this.setState({ notReady: false }) // this.props.onLogin(rsp.body)
this.props.onLogin(rsp.body)
retry()
} catch (e) { } catch (e) {
console.error('token pass error', e) console.error('token pass error', e)
this.setState({ message: 'g-gomen nasai... i broke it...' }) this.setState({ message: 'g-gomen nasai... i broke it...' })

View file

@ -0,0 +1,34 @@
import React, { Component } from 'react'
import { Redirect } from 'react-router-dom'
import superagent from 'superagent'
import { connect } from 'react-redux'
import { fetchServers } from '../../actions'
@connect()
class OauthCallback extends Component {
state = {
notReady: true,
message: 'chotto matte kudasai...'
}
async componentDidMount () {
const { body: { url } } = await superagent.get('/api/auth/redirect')
try {
const rsp = await superagent.get('/api/auth/user')
this.props.dispatch({
type: Symbol.for('set user'),
data: rsp.body
})
this.props.dispatch(fetchServers)
this.setState({ notReady: false })
} catch (e) {
window.location.href = url
}
}
render () {
return (this.state.notReady) ? this.state.message : <Redirect to='/s' />
}
}
export default OauthCallback

View file

@ -1,8 +1,11 @@
import React, { Component } from 'react' import React, { Component } from 'react'
import ImmutablePropTypes from 'react-immutable-proptypes' import ImmutablePropTypes from 'react-immutable-proptypes'
import { NavLink } from 'react-router-dom' import { NavLink } from 'react-router-dom'
import { connect } from 'react-redux'
import * as Actions from '../../actions'
import './UserCard.sass' import './UserCard.sass'
@connect()
class UserCard extends Component { class UserCard extends Component {
static propTypes = { static propTypes = {
user: ImmutablePropTypes.map user: ImmutablePropTypes.map
@ -33,7 +36,7 @@ class UserCard extends Component {
</div> </div>
<div className='user-card__actions'> <div className='user-card__actions'>
<ul className='uk-iconnav uk-iconnav-vertical'> <ul className='uk-iconnav uk-iconnav-vertical'>
<li><NavLink uk-tooltip='' title='Sign out' uk-icon='icon: sign-out' to='/auth/signout' activeClassName='uk-active' /></li> <li><a uk-tooltip='' title='Sign out' uk-icon='icon: sign-out' onClick={() => { this.props.dispatch(Actions.userLogout) }} /></li>
{ {
(this.props.user.isRoot === true) (this.props.user.isRoot === true)
? <li><NavLink uk-tooltip='' title='Root' uk-icon='icon: bolt' to='/root/' activeClassName='uk-active' /></li> ? <li><NavLink uk-tooltip='' title='Root' uk-icon='icon: bolt' to='/root/' activeClassName='uk-active' /></li>

View file

@ -1,7 +1,6 @@
import React, { Component } from 'react' import React, { Component } from 'react'
import { Route } from 'react-router-dom' import { Route } from 'react-router-dom'
import { connect } from 'react-redux' import { connect } from 'react-redux'
import superagent from 'superagent'
import './index.sass' import './index.sass'
import Navigation from './Navigation' import Navigation from './Navigation'

View file

@ -1,6 +1,5 @@
import React, { Component } from 'react' import React, { Component } from 'react'
import { Link } from 'react-router-dom' import { Link } from 'react-router-dom'
import Radium from 'radium'
import Logotype from '../logotype' import Logotype from '../logotype'
import styles from './styles' import styles from './styles'
import './wrapper.css' import './wrapper.css'
@ -22,11 +21,13 @@ class Wrapper extends Component {
</div> </div>
</nav> </nav>
<main> <main>
{this.props.children} {
this.props.children
}
</main> </main>
</div> </div>
</div> </div>
} }
} }
export default Radium(Wrapper) export default Wrapper

View file

@ -1,6 +1,7 @@
import { Map } from 'immutable' import { Map } from 'immutable'
const initialState = Map({ const initialState = Map({
isLoggedIn: false,
username: 'あたし', username: 'あたし',
discriminator: '0001', discriminator: '0001',
id: '', id: '',
@ -9,9 +10,11 @@ const initialState = Map({
export default (state = initialState, { type, data }) => { export default (state = initialState, { type, data }) => {
switch (type) { switch (type) {
case Symbol.for('set user'): case Symbol.for('set user'):
return Map(data) return Map({...data, isLoggedIn: true})
case Symbol.for('reset user'):
return initialState
default: default:
return state return state

View file

@ -3,6 +3,7 @@ import { Route } from 'react-router-dom'
import Servers from '../components/servers' import Servers from '../components/servers'
import OauthCallback from '../components/oauth-callback' import OauthCallback from '../components/oauth-callback'
import OauthFlow from '../components/oauth-flow'
const aaa = (props) => (<div>{ JSON.stringify(props) }</div>) const aaa = (props) => (<div>{ JSON.stringify(props) }</div>)
@ -13,6 +14,7 @@ export default class AppRouter extends Component {
<Route path='/s' component={Servers} /> <Route path='/s' component={Servers} />
<Route path='/root' component={aaa} /> <Route path='/root' component={aaa} />
<Route path='/oauth/callback' component={OauthCallback} /> <Route path='/oauth/callback' component={OauthCallback} />
<Route path='/oauth/flow' component={OauthFlow} />
</Fragment> </Fragment>
} }
} }