119 lines
2.3 KiB
JavaScript
119 lines
2.3 KiB
JavaScript
'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);
|
|
};
|