Skip to content

Commit

Permalink
Migrates to stateful Auth
Browse files Browse the repository at this point in the history
  • Loading branch information
mrharpo committed Jan 6, 2024
1 parent 7db0134 commit bda5260
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 152 deletions.
20 changes: 11 additions & 9 deletions web/src/Actions.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ export const range = (start, end) =>

export const State = () => ({
auth: null,
loggedIn: Stream(false),
user: {
username: null,
profile: null,
},
theme: 'dark',
input: null,
output: null,
Expand Down Expand Up @@ -96,17 +101,14 @@ export const OnlineActions = (state, actions) => ({
m.redraw()
// send to lichess api
let move_uci = uci(move)
auth(
'https://lichess.org/api/board/game/' +
m.route.param('id') +
'/move/' +
move_uci,
let body = state.auth.fetchBody('https://lichess.org/api/board/game/' +
m.route.param('id') +
'/move/' +
move_uci,
{
method: 'post',
}
).then(e => {
console.log('played move', move_uci, e)
})
})
console.log('played move', move_uci, body)
},
afterInit: () => {
console.log('initing online actions')
Expand Down
78 changes: 40 additions & 38 deletions web/src/Auth.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import m from 'mithril'
import { HttpClient, OAuth2AuthCodePKCE } from '@bity/oauth2-auth-code-pkce';
import { readStream } from './ndJsonStream';
import { User } from './User'

export const lichessHost = 'https://lichess.org';
// export const lichessHost = 'http://l.org';
Expand All @@ -15,78 +15,80 @@ export interface Me {
perfs: { [key: string]: any };
}

export class Auth {
oauth = new OAuth2AuthCodePKCE({
export const Auth = (state, actions) => ({
oauth: new OAuth2AuthCodePKCE({
authorizationUrl: `${lichessHost}/oauth`,
tokenUrl: `${lichessHost}/api/token`,
clientId,
scopes,
redirectUrl: clientUrl,
onAccessTokenExpiry: refreshAccessToken => refreshAccessToken(),
onInvalidGrant: console.warn,
});
me?: Me;
}),
// me?: Me,

async init() {
init: async () => {
try {
const accessContext = await this.oauth.getAccessToken();
if (accessContext) await this.authenticate();
const accessContext = await state.auth.oauth.getAccessToken();
if (accessContext) await state.auth.authenticate();
} catch (err) {
console.error(err);
}
if (!this.me) {
if (!state.loggedIn()) {
try {
const hasAuthCode = await this.oauth.isReturningFromAuthServer();
if (hasAuthCode) await this.authenticate();
const hasAuthCode = await state.auth.oauth.isReturningFromAuthServer();
if (hasAuthCode) await state.auth.authenticate();
} catch (err) {
console.error(err);
}
}
}
},

async login() {
await this.oauth.fetchAuthorizationCode();
}
login: async () => {
await state.auth.oauth.fetchAuthorizationCode();
},

async logout() {
if (this.me) await this.me.httpClient(`${lichessHost}/api/token`, { method: 'DELETE' });
logout: async () => {
if (state.loggedIn()) await state.user.httpClient(`${lichessHost}/api/token`, { method: 'DELETE' });
localStorage.clear();
this.me = undefined;
}
state.user = {};
},

private authenticate = async () => {
const httpClient = this.oauth.decorateFetchHTTPClient(window.fetch);
authenticate: async () => {
const httpClient = state.auth.oauth.decorateFetchHTTPClient(window.fetch);
const res = await httpClient(`${lichessHost}/api/account`);
if (res.error) throw res.error;
const profile = await res.json()
const me = {
...profile,
username: profile.username,
profile,
httpClient,
};
if (me.error) throw me.error;
this.me = me;
User.username = me.username;
User.loggedIn = true;
User.profile = profile
};
state.user = me;
state.loggedIn(true);
localStorage.setItem('me', JSON.stringify(me));
console.log('Authenticated as', me.username);
m.redraw();
},

openStream = async (path: string, config: any, handler: (_: any) => void) => {
const stream = await this.fetchResponse(path, config);
openStream: async (path: string, config: any, handler: (_: any) => void) => {
const stream = await state.auth.fetchResponse(path, config);
return readStream(`STREAM ${path}`, stream, handler);
};
},

fetchBody = async (path: string, config: any = {}) => {
const res = await this.fetchResponse(path, config);
fetchBody: async (path: string, config: any = {}) => {
const res = await state.auth.fetchResponse(path, config);
const body = await res.json();
return body;
};
},

private fetchResponse = async (path: string, config: any = {}) => {
const res = await (this.me?.httpClient || window.fetch)(`${lichessHost}${path}`, config);
fetchResponse: async (path: string, config: any = {}) => {
const res = await (state.user.httpClient || window.fetch)(`${lichessHost}${path}`, config);
if (res.error || !res.ok) {
const err = `${res.error} ${res.status} ${res.statusText}`;
alert(err);
throw err;
}
return res;
};
}
},
})
8 changes: 3 additions & 5 deletions web/src/Games.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import m from 'mithril'
import { User, auth } from './User'
import { LICHESS_API_URL } from './config'
import { streamJson } from './ndjson'
import { Chessground } from 'chessground'
import { Chess } from 'chess.js'
import { Board } from './Board'
import { Toolbar, OnlineToolbar } from './Toolbar'
import '../node_modules/material-design-icons-iconfont/dist/material-design-icons.css'
Expand All @@ -18,7 +16,7 @@ export const getGames = (state, actions) => ({
.then(resolve)
}),
streamGames: () => {
streamJson(LICHESS_API_URL + 'stream/event', User.token, res => {
streamJson(LICHESS_API_URL + 'stream/event', state.user.token, res => {
console.log('new lichess event', res)
if (res.type == 'gameStart' && state.games().length == 0) {
console.log('auto starting game')
Expand Down Expand Up @@ -53,7 +51,7 @@ export const Games = (state, actions) => {
return {
listener: null,
oninit: vnode => {
if (!User.loggedIn) {
if (!state.loggedIn) {
m.route.set('/login')
}
state.invert(false)
Expand Down Expand Up @@ -175,7 +173,7 @@ export const GamePage = (state, actions) => ({
m('.gamePage', {}, [Toolbar(state, actions), Game(state, actions)]),
})

export const Player = () => m('.me', {}, User.username)
export const Player = () => m('.me', {}, state.user.username)
export const Opponent = state =>
state.opponent ? m('.opponent', {}, JSON.stringify(state.opponent)) : null

Expand Down
1 change: 0 additions & 1 deletion web/src/LaunchGame.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { Chess } from 'chess.js'
import { NOTE_ON, CONTROL_CHANGE, COLORS } from './Launchpad'
import { streamJson } from './ndjson'
import { LICHESS_API_URL } from './config'
import { User, auth } from './User'
import { calculateInfluence, fenForOtherSide } from './ChessMaths'
import { toDests, toColor, playOtherSide, setBoard } from './utils'

Expand Down
18 changes: 6 additions & 12 deletions web/src/Login.js
Original file line number Diff line number Diff line change
@@ -1,21 +1,15 @@
import m from 'mithril'
import { Auth } from './Auth'

export const Login = (state, actions) => {
return {
oninit: vnode => {
if (state.loggedIn()) {
console.log('already logged in. Not sure how we got here.')
m.route.set('/')
}
},
view: vnode => {
return m('', { onclick: actions.login }, m('i', {}, 'Login with lichess'))
},
}
}

export const LoginActions = (state, actions) => ({
login: () => {
console.log('logging in')
state.auth.login()
},
initLogin: () => {
state.auth = new Auth()
state.auth.init()
}
})
19 changes: 9 additions & 10 deletions web/src/Menu.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import m from 'mithril'
import { User } from './User'
import { StatusIcon } from './Toolbar'
import { message } from 'alertifyjs'
import { Switch } from 'construct-ui'
Expand Down Expand Up @@ -28,16 +27,16 @@ export const Links = state => [
},
}),
// ,
User.username
? m(Link, { href: '/profile' }, User.username)
state.user.username
? m(Link, { href: '/profile' }, state.user.username)
: m(
Link,
{
href: '/login',
id: 'loginButton',
},
'Login'
),
Link,
{
href: '/login',
id: 'loginButton',
},
'Login'
),
]

export const Menu = state => [
Expand Down
9 changes: 4 additions & 5 deletions web/src/Profile.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import m from 'mithril'
import { User } from './User'
import { defaults, confirm, message } from 'alertifyjs'
import '../node_modules/alertifyjs/build/css/alertify.min.css'
import '../node_modules/alertifyjs/build/css/themes/semantic.css'
Expand All @@ -11,19 +10,19 @@ defaults.theme.ok = 'ui positive button'
defaults.theme.cancel = 'ui black button'
defaults.notifier.delay = 10

export function ProfilePage() {
export function ProfilePage(state, actions) {
return {
view: vnode => {
return [
m(Profile, {}, User.profile),
m(Profile, {}, state.user.profile),
m(
'i',
{
onclick: e => {
confirm(
'Are you sure you want to deauthorize this device?',
affirm => {
User.logout()
state.actions.logout()
m.route.set('/')
message('logged out', 3)
},
Expand All @@ -47,7 +46,7 @@ export function Profile() {
'table.profile',
vnode.attrs,
Object.keys(vnode.children[0]).map((k, i) => {
console.log(k, i)
// console.log(k, i)
return m('tr.entry', {}, [
m('td.key', {}, k),
// m('td.seperator', {}, ' - '),
Expand Down
Loading

0 comments on commit bda5260

Please sign in to comment.