OAuth2 / JWT / OpenID Connect for mocking auth... which isn't that different from doing it for real, actually. https://mock.pocketid.app
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

118 lines
2.3 KiB

'use strict';
var Keypairs = require('@root/keypairs');
var PocketId = module.exports;
var request = require('./request.js');
var keyJson = window.localStorage.getItem('private.jwk.json');
PocketId.signIdToken = async function (idToken) {
var pair = await Keypairs.parseOrGenerate({ key: keyJson });
var jwt = await Keypairs.signJwt({
jwk: pair.private,
iss: window.location.protocol + '//' + window.location.hostname,
exp: '15m',
claims: {
contact: ['google:' + idToken]
}
});
return jwt;
};
PocketId.auth = {};
PocketId.auth.meta = async function ({ email }) {
var loc = window.location;
var body = await request({
method: 'GET',
url:
loc.protocol +
'//' +
loc.hostname +
'/api/authn/meta?contact=' +
'mailto:' +
email
});
return body;
};
PocketId.auth.verify = async function ({ scheme, email }) {
if (!scheme) {
scheme = 'mailto:';
}
var loc = window.location;
var body = await request({
method: 'GET',
url:
loc.protocol +
'//' +
loc.hostname +
'/api/authn/verify?contact=' +
scheme +
email
});
return body;
};
PocketId.auth.consume = async function ({
email = '',
receipt = '',
secret = '',
count = 0
}) {
var loc = window.location;
var resp = await request({
method: 'GET',
url:
loc.protocol +
'//' +
loc.hostname +
'/api/authn/consume?contact=' +
(email ? 'mailto:' + email : '') +
'&receipt=' +
receipt +
'&secret=' +
secret
});
if (resp.body.success) {
// There should be a token here
// (or the pubkey should have been given beforehand)
return resp.body;
}
if (resp.body.error) {
// TODO special errors are hard failures
}
if (count > 600) {
throw new Error('abandoned login');
}
return timeout(5000).then(function () {
console.log('check otp again');
return PocketId.auth.consume({
email,
secret,
receipt,
count: count || 0
});
});
};
async function timeout(ms) {
return new Promise(function (resolve) {
setTimeout(resolve, ms);
});
}
var textEncoder = new TextEncoder();
PocketId.genKey = async function ({ email }) {
// Ideally we'd use PBKDF2 or better but... web standards...
// TODO put a random salt
var emailU8 = textEncoder.encode(email);
var salt = await crypto.subtle.digest('SHA-256', emailU8);
var u8 = textEncoder.encode(answer);
var hash = await crypto.subtle.digest('SHA-256', u8);
};