jwt in http cookie remove menu

pull/3415/head
Sander Hahn 6 years ago
parent 8f30793c58
commit ad6fe57e6d

@ -2,7 +2,7 @@ import polka from 'polka';
import devalue from 'devalue'; import devalue from 'devalue';
import send from '@polka/send'; import send from '@polka/send';
import { get, post } from 'httpie'; import { get, post } from 'httpie';
import { parse, stringify } from 'querystring'; import { parse, stringify, unescape, escape } from 'querystring';
import { decode, sign, verify } from './token'; import { decode, sign, verify } from './token';
import { find, query } from '../utils/db'; import { find, query } from '../utils/db';
@ -25,13 +25,28 @@ function onError(err, req, res) {
res.headersSent || send(res, code, { error }); res.headersSent || send(res, code, { error });
} }
function cookies(req) {
if (!req.headers.hasOwnProperty("cookie")) {
return {};
}
return req.headers.cookie.split("; ").map((cookie) => {
const index = cookie.indexOf("=");
return [cookie.substring(0, index), cookie.substring(index+1)];
}).reduce((agg, [key, value]) => {
agg[unescape(key)] = unescape(value);
return agg;
}, {});
}
/** /**
* Middleware to determine User validity * Middleware to determine User validity
*/ */
export async function isUser(req, res) { export async function isUser(req, res) {
const abort = exit.bind(null, res, 401); const abort = exit.bind(null, res, 401);
const auth = req.headers.authorization; const jwt_token = cookies(req).jwt_token
const auth = req.headers.authorization || (jwt_token && `Bearer ${jwt_token}`);
if (!auth) return abort('Missing Authorization header'); if (!auth) return abort('Missing Authorization header');
const [scheme, token] = auth.split(' '); const [scheme, token] = auth.split(' ');
@ -112,14 +127,16 @@ export function API() {
returning * returning *
`, [id, name, login, avatar_url, access_token]); `, [id, name, login, avatar_url, access_token]);
const user_props = toUser(user);
send(res, 200, ` send(res, 200, `
<script> <script>
window.opener.postMessage({ window.opener.postMessage({
user: ${devalue(toUser(user))} user: ${devalue(user_props)}
}, window.location.origin); }, window.location.origin);
</script> </script>
`, { `, {
'Content-Type': 'text/html; charset=utf-8' 'Content-Type': 'text/html; charset=utf-8',
'Set-Cookie': `jwt_token=${escape(user_props.token)}; path=/; MaxAge=${30 * 24 * 60 * 60}; HttpOnly`
}); });
} catch (err) { } catch (err) {
console.error('GET /auth/callback', err); console.error('GET /auth/callback', err);
@ -129,6 +146,12 @@ export function API() {
}); });
} }
}); });
app.delete('/logout', async (req, res) => {
send(res, 204, ``, {
'Set-Cookie': `jwt_token=; MaxAge=0; HttpOnly`
});
});
} else { } else {
// Print "Misconfigured" error // Print "Misconfigured" error
app.get('/auth/login', (req, res) => { app.get('/auth/login', (req, res) => {

@ -1,8 +1,6 @@
<script> <script>
import { user, logout } from '../../../../../user.js'; import { user, logout } from '../../../../../user.js';
export let load;
let showMenu = false; let showMenu = false;
let name; let name;
@ -15,7 +13,6 @@
{#if showMenu} {#if showMenu}
<div class="menu"> <div class="menu">
<button on:click={load}>Archive</button>
<button on:click={logout}>Log out</button> <button on:click={logout}>Log out</button>
</div> </div>
{/if} {/if}
@ -75,8 +72,6 @@
z-index: 99; z-index: 99;
text-align: left; text-align: left;
border-radius: 0.4rem; border-radius: 0.4rem;
display: flex;
flex-direction: column;
} }
.menu button { .menu button {
@ -84,7 +79,6 @@
font-family: var(--font); font-family: var(--font);
font-size: 1.6rem; font-size: 1.6rem;
/* opacity: 0.7; */ /* opacity: 0.7; */
padding: 0.4rem 0;
} }
.menu button:hover { .menu button:hover {

@ -142,58 +142,6 @@
saving = false; saving = false;
} }
async function load() {
const periodFormatter = new Intl.DateTimeFormat(undefined, {
year: "numeric",
month: "long",
});
function sections(gists) {
const grouped = gists.reduce((agg, gist) => {
const key = periodFormatter.format(new Date(gist.updated_at));
if (!agg.hasOwnProperty(key)) {
agg[key] = [];
}
agg[key].push(gist);
return agg;
}, {});
return Object.entries(grouped).map(([title, archive]) => {
return {
title,
archive,
};
});
}
try {
const r = await fetch(`../repl/archive.json`, {
method: 'GET',
headers: { Authorization },
});
if (r.status < 200 || r.status >= 300) {
const { error } = await r.json();
throw new Error(`Received an HTTP ${r.status} response: ${error}`);
}
const gists = await r.json();
for (const section of sections(gists)) {
console.log(section.title);
for (const repl of section.archive) {
console.log(" " + repl.name);
console.log(" " + location.origin + "/repl/" + repl.uid);
}
}
} catch (err) {
if (navigator.onLine) {
alert(err.message);
} else {
alert(`It looks like you're offline! Find the internet and try again`);
}
}
}
async function download() { async function download() {
downloading = true; downloading = true;
@ -268,7 +216,7 @@ export default app;` });
</button> </button>
{#if $user} {#if $user}
<UserMenu {load} /> <UserMenu />
{:else} {:else}
<button class="icon" on:click={login}> <button class="icon" on:click={login}>
<Icon name="log-in" /> <Icon name="log-in" />

@ -2,6 +2,10 @@ import send from '@polka/send';
import { query } from '../../utils/db'; import { query } from '../../utils/db';
import { isUser } from '../../backend/auth'; import { isUser } from '../../backend/auth';
const {
BASEURL,
} = process.env;
export async function get(req, res) { export async function get(req, res) {
const user = await isUser(req, res); const user = await isUser(req, res);
if (!user) return; // response already sent if (!user) return; // response already sent
@ -16,5 +20,10 @@ export async function get(req, res) {
offset $2 offset $2
`, [user.id, offset]); `, [user.id, offset]);
send(res, 200, rows); send(res, 200, rows.map((row) => {
return {
url: `${BASEURL}/repl/${row.uid}`,
...row,
}
}));
} }

@ -30,4 +30,7 @@ if (process.browser) {
export function logout() { export function logout() {
user.set(null); user.set(null);
fetch('/logout', {
method: 'DELETE',
});
} }

Loading…
Cancel
Save