implemented oauth state parameter

This commit is contained in:
Danny Coates 2018-09-21 14:16:56 -07:00
parent 135f40f65d
commit d34ff79fd7
No known key found for this signature in database
GPG Key ID: 4C442633C62E00CB
2 changed files with 12 additions and 4 deletions

View File

@ -80,7 +80,7 @@ module.exports = function() {
app.route('/signin', body(require('../pages/signin'))); app.route('/signin', body(require('../pages/signin')));
app.route('/api/fxa/oauth', async function(state, emit) { app.route('/api/fxa/oauth', async function(state, emit) {
try { try {
await state.user.finishLogin(state.query.code); await state.user.finishLogin(state.query.code, state.query.state);
emit('replaceState', '/'); emit('replaceState', '/');
} catch (e) { } catch (e) {
emit('replaceState', '/error'); emit('replaceState', '/error');

View File

@ -2,9 +2,10 @@
import assets from '../common/assets'; import assets from '../common/assets';
import { getFileList, setFileList } from './api'; import { getFileList, setFileList } from './api';
import { encryptStream, decryptStream } from './ece'; import { encryptStream, decryptStream } from './ece';
import { b64ToArray, streamToArrayBuffer } from './utils'; import { arrayToB64, b64ToArray, streamToArrayBuffer } from './utils';
import { blobStream } from './streams'; import { blobStream } from './streams';
import { getFileListKey, prepareScopedBundleKey, preparePkce } from './fxa'; import { getFileListKey, prepareScopedBundleKey, preparePkce } from './fxa';
import storage from './storage';
const textEncoder = new TextEncoder(); const textEncoder = new TextEncoder();
const textDecoder = new TextDecoder(); const textDecoder = new TextDecoder();
@ -54,6 +55,8 @@ export default class User {
} }
async login() { async login() {
const state = arrayToB64(crypto.getRandomValues(new Uint8Array(16)));
storage.set('oauthState', state);
const keys_jwk = await prepareScopedBundleKey(this.storage); const keys_jwk = await prepareScopedBundleKey(this.storage);
const code_challenge = await preparePkce(this.storage); const code_challenge = await preparePkce(this.storage);
const params = new URLSearchParams({ const params = new URLSearchParams({
@ -62,7 +65,7 @@ export default class User {
code_challenge_method: 'S256', code_challenge_method: 'S256',
response_type: 'code', response_type: 'code',
scope: 'profile https://identity.mozilla.com/apps/send', //TODO param scope: 'profile https://identity.mozilla.com/apps/send', //TODO param
state: 'todo', state,
keys_jwk keys_jwk
}); });
location.assign( location.assign(
@ -70,7 +73,12 @@ export default class User {
); );
} }
async finishLogin(code) { async finishLogin(code, state) {
const localState = storage.get('oauthState');
storage.remove('oauthState');
if (state !== localState) {
throw new Error('state mismatch');
}
const tokenResponse = await fetch(AUTH_CONFIG.token_endpoint, { const tokenResponse = await fetch(AUTH_CONFIG.token_endpoint, {
method: 'POST', method: 'POST',
headers: { headers: {