mirror of
https://github.com/roleypoly/roleypoly-v1.git
synced 2025-04-25 12:19:10 +00:00
auth: add slugs and auth redirects
This commit is contained in:
parent
f7d1f578ad
commit
1a7b042351
3 changed files with 79 additions and 10 deletions
12
api/auth.js
12
api/auth.js
|
@ -57,11 +57,13 @@ export default (R: Router, $: AppContext) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
R.get('/api/auth/redirect', async (ctx: Context) => {
|
R.get('/api/auth/redirect', async (ctx: Context) => {
|
||||||
|
const { r } = ctx.query
|
||||||
// check if already authed
|
// check if already authed
|
||||||
if (await $.auth.isLoggedIn(ctx, { refresh: true })) {
|
if (await $.auth.isLoggedIn(ctx, { refresh: true })) {
|
||||||
return ctx.redirect('/')
|
return ctx.redirect(r || '/')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctx.session.oauthRedirect = r
|
||||||
const url = $.discord.getAuthUrl(ksuid.randomSync().string)
|
const url = $.discord.getAuthUrl(ksuid.randomSync().string)
|
||||||
if (ctx.query.url === '✔️') {
|
if (ctx.query.url === '✔️') {
|
||||||
ctx.body = { url }
|
ctx.body = { url }
|
||||||
|
@ -72,11 +74,13 @@ export default (R: Router, $: AppContext) => {
|
||||||
})
|
})
|
||||||
|
|
||||||
R.get('/api/oauth/callback', async (ctx: Context) => {
|
R.get('/api/oauth/callback', async (ctx: Context) => {
|
||||||
|
const { code, state } = ctx.query
|
||||||
|
const { oauthRedirect: r } = ctx.session
|
||||||
|
delete ctx.session.oauthRedirect
|
||||||
if (await $.auth.isLoggedIn(ctx)) {
|
if (await $.auth.isLoggedIn(ctx)) {
|
||||||
return ctx.redirect('/')
|
return ctx.redirect(r || '/')
|
||||||
}
|
}
|
||||||
|
|
||||||
const { code, state } = ctx.query
|
|
||||||
if (code == null) {
|
if (code == null) {
|
||||||
ctx.status = 400
|
ctx.status = 400
|
||||||
return
|
return
|
||||||
|
@ -95,7 +99,7 @@ export default (R: Router, $: AppContext) => {
|
||||||
const tokens = await $.discord.getAuthToken(code)
|
const tokens = await $.discord.getAuthToken(code)
|
||||||
const user = await $.discord.getUserFromToken(tokens.access_token)
|
const user = await $.discord.getUserFromToken(tokens.access_token)
|
||||||
$.auth.injectSessionFromOAuth(ctx, tokens, user.id)
|
$.auth.injectSessionFromOAuth(ctx, tokens, user.id)
|
||||||
return ctx.redirect('/')
|
return ctx.redirect(r || '/')
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
log.error('token and auth fetch failure', e)
|
log.error('token and auth fetch failure', e)
|
||||||
ctx.status = 400
|
ctx.status = 400
|
||||||
|
|
|
@ -3,8 +3,17 @@ import * as React from 'react'
|
||||||
import Head from 'next/head'
|
import Head from 'next/head'
|
||||||
import type { PageProps } from '../../types'
|
import type { PageProps } from '../../types'
|
||||||
import SocialCards from '../../components/social-cards'
|
import SocialCards from '../../components/social-cards'
|
||||||
|
import redirect from '../../lib/redirect'
|
||||||
|
|
||||||
export default class Server extends React.Component<PageProps> {
|
export default class Server extends React.Component<PageProps> {
|
||||||
|
static async getInitialProps (ctx: *, rpc: *, router: *) {
|
||||||
|
if (ctx.user == null) {
|
||||||
|
redirect(ctx, `/auth/login?r=${router.asPath}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.robots = 'NOINDEX, NOFOLLOW'
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -5,16 +5,27 @@ import MediaQuery from '../../kit/media'
|
||||||
import DiscordButton from '../../components/discord-button'
|
import DiscordButton from '../../components/discord-button'
|
||||||
import RPC from '../../config/rpc'
|
import RPC from '../../config/rpc'
|
||||||
import redirect from '../../lib/redirect'
|
import redirect from '../../lib/redirect'
|
||||||
|
import dynamic from 'next/dynamic'
|
||||||
|
import type { PageProps, ServerSlug } from '../../types'
|
||||||
|
|
||||||
type AuthLoginState = {
|
type AuthLoginState = {
|
||||||
humanCode: string,
|
humanCode: string,
|
||||||
waiting: boolean
|
waiting: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type AuthLoginProps = PageProps & {
|
||||||
|
redirect: ?string,
|
||||||
|
redirectSlug: ?ServerSlug
|
||||||
|
}
|
||||||
|
|
||||||
const Wrapper = styled.div`
|
const Wrapper = styled.div`
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding-top: 3em;
|
padding-top: 3em;
|
||||||
|
width: 400px;
|
||||||
|
max-width: calc(98vw - 10px);
|
||||||
|
margin: 0 auto;
|
||||||
|
text-align: center;
|
||||||
${() => MediaQuery({
|
${() => MediaQuery({
|
||||||
md: `
|
md: `
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
|
@ -76,16 +87,60 @@ const HiderButton = styled.button`
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
const SlugWrapper = styled.div`
|
||||||
|
padding-bottom: 2em;
|
||||||
|
text-align: center;
|
||||||
|
`
|
||||||
|
|
||||||
export default class AuthLogin extends React.Component<{}, AuthLoginState> {
|
const DiscordGuildPic = dynamic(() => import('../../components/discord-guild-pic'))
|
||||||
|
const StyledDGP = styled(DiscordGuildPic)`
|
||||||
|
border-radius: 100%;
|
||||||
|
border: 2px solid rgba(0,0,0,0.2);
|
||||||
|
height: 4em;
|
||||||
|
margin-top: 1em;
|
||||||
|
`
|
||||||
|
|
||||||
|
const ServerName = styled.span`
|
||||||
|
font-weight: bold;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
width: 370px;
|
||||||
|
display: block;
|
||||||
|
`
|
||||||
|
|
||||||
|
const Slug = (slug: ServerSlug) => <SlugWrapper>
|
||||||
|
<StyledDGP {...slug} />
|
||||||
|
<br />Hey there.<br /><ServerName>{slug.name}</ServerName> uses Roleypoly to manage its roles.
|
||||||
|
</SlugWrapper>
|
||||||
|
|
||||||
|
export default class AuthLogin extends React.Component<AuthLoginProps, AuthLoginState> {
|
||||||
state = {
|
state = {
|
||||||
humanCode: '',
|
humanCode: '',
|
||||||
waiting: false
|
waiting: false
|
||||||
}
|
}
|
||||||
|
|
||||||
static async getInitialProps (ctx, rpc) {
|
static async getInitialProps (ctx: *, rpc: typeof RPC, router: *) {
|
||||||
|
let { r } = (router.query: { r: string })
|
||||||
|
|
||||||
if (ctx.user != null) {
|
if (ctx.user != null) {
|
||||||
redirect(ctx, '/')
|
redirect(ctx, r || '/')
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx.robots = 'NOINDEX, NOFOLLOW'
|
||||||
|
|
||||||
|
if (r != null) {
|
||||||
|
let redirectSlug = null
|
||||||
|
if (r.startsWith('/s/') && r !== '/s/add') {
|
||||||
|
redirectSlug = await rpc.getServerSlug(r.replace('/s/', ''))
|
||||||
|
}
|
||||||
|
return { redirect: r, redirectSlug }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount () {
|
||||||
|
if (this.props.redirect != null) {
|
||||||
|
this.props.router.replace(this.props.router.pathname)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -98,9 +153,9 @@ export default class AuthLogin extends React.Component<{}, AuthLoginState> {
|
||||||
try {
|
try {
|
||||||
const result = await RPC.checkAuthChallenge(this.state.humanCode)
|
const result = await RPC.checkAuthChallenge(this.state.humanCode)
|
||||||
if (result === true) {
|
if (result === true) {
|
||||||
redirect(null, '/')
|
redirect(null, this.props.redirect || '/')
|
||||||
}
|
}
|
||||||
} finally {
|
} catch (e) {
|
||||||
this.setState({ waiting: false })
|
this.setState({ waiting: false })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +163,8 @@ export default class AuthLogin extends React.Component<{}, AuthLoginState> {
|
||||||
render () {
|
render () {
|
||||||
return <Wrapper>
|
return <Wrapper>
|
||||||
<div>
|
<div>
|
||||||
<DiscordButton href='/api/auth/redirect'>Sign in with Discord</DiscordButton>
|
{(this.props.redirectSlug != null) ? <Slug {...this.props.redirectSlug} /> : null}
|
||||||
|
<DiscordButton href={`/api/auth/redirect?r=${this.props.redirect || '/'}`}>Sign in with Discord</DiscordButton>
|
||||||
<Line />
|
<Line />
|
||||||
<div>
|
<div>
|
||||||
<i>Or, send a DM to <b>roleypoly</b>#3712 saying: login</i>
|
<i>Or, send a DM to <b>roleypoly</b>#3712 saying: login</i>
|
||||||
|
|
Loading…
Add table
Reference in a new issue