[WIP] new account
This commit is contained in:
parent
a5c448902e
commit
7f49650c48
|
@ -404,8 +404,78 @@ controllers.newNonce = function (req, res) {
|
||||||
};
|
};
|
||||||
controllers.newAccount = function (req, res) {
|
controllers.newAccount = function (req, res) {
|
||||||
controllers._requireNonce(req, res, function () {
|
controllers._requireNonce(req, res, function () {
|
||||||
|
// TODO clean up error messages to be similar to ACME
|
||||||
|
|
||||||
|
// check if there's a public key
|
||||||
|
if (!req.jws || !req.jws.header.kid || !req.jws.header.jwk) {
|
||||||
|
res.statusCode = 422;
|
||||||
|
res.send({ error: { message: "jws body was not present or could not be validated" } });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO mx record email validation
|
||||||
|
if (!Array.isArray(req.body.contact) || !req.body.contact.length) {
|
||||||
|
// req.body.contact: [ 'mailto:email' ]
|
||||||
|
res.statusCode = 422;
|
||||||
|
res.send({ error: { message: "jws signed payload should contain a valid mailto:email in the contact array" } });
|
||||||
|
}
|
||||||
|
if (!req.body.termsOfServiceAgreed) {
|
||||||
|
// req.body.termsOfServiceAgreed: true
|
||||||
|
res.statusCode = 422;
|
||||||
|
res.send({ error: { message: "jws signed payload should have termsOfServiceAgreed: true" } });
|
||||||
|
}
|
||||||
|
|
||||||
|
// We verify here regardless of whether or not it was verified before,
|
||||||
|
// because it needs to be signed by the presenter of the public key,
|
||||||
|
// not just a trusted key
|
||||||
|
return verifyJws(req.jws.header.jwk, req.jws).then(function (verified) {
|
||||||
|
if (!verified) {
|
||||||
|
res.statusCode = 422;
|
||||||
|
res.send({ error: { message: "jws body was not present or could not be validated" } });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Note: we can get any number of account requests
|
||||||
|
// and these need to be stored for some space of time
|
||||||
|
// to await verification.
|
||||||
|
// we'll have to expire them somehow and prevent DoS
|
||||||
|
|
||||||
|
// check if this account already exists
|
||||||
|
DB.accounts.some(function (/*jwk*/) {
|
||||||
|
// calculate thumbprint from jwk
|
||||||
|
// find a key with matching jwk
|
||||||
|
});
|
||||||
|
// TODO fail if onlyReturnExisting is not false
|
||||||
|
// req.body.onlyReturnExisting: false
|
||||||
|
|
||||||
res.statusCode = 500;
|
res.statusCode = 500;
|
||||||
res.end("not implemented yet");
|
res.send({
|
||||||
|
error: { message: "not implemented" },
|
||||||
|
"id": 0, // 5937234,
|
||||||
|
"key": req.jws.header.jwk, // TODO trim to basics
|
||||||
|
/*{
|
||||||
|
"kty": "EC",
|
||||||
|
"crv": "P-256",
|
||||||
|
"x": "G7kuV4JiqZs-GztrzpsmUM7Raf9tDUELWt5O337sTqw",
|
||||||
|
"y": "n5SFz9z2i-ZF_zu5aoS9t9O8y_g2qfonXv3Cna2e39k"
|
||||||
|
},*/
|
||||||
|
"contact": req.body.contact, // [ "mailto:john.doe@gmail.com" ],
|
||||||
|
// I'm not sure if we have the real IP through telebit's network wrapper at this point
|
||||||
|
// TODO we also need to set X-Forwarded-Addr as a proxy
|
||||||
|
"initialIp": req.connection.remoteAddress, //"128.187.116.28",
|
||||||
|
"createdAt": (new Date()).toISOString(), // "2018-04-17T21:29:10.833305103Z",
|
||||||
|
"status": "invalid" //"valid"
|
||||||
|
});
|
||||||
|
/*
|
||||||
|
Cache-Control: max-age=0, no-cache, no-store
|
||||||
|
Content-Type: application/json
|
||||||
|
Expires: Tue, 17 Apr 2018 21:29:10 GMT
|
||||||
|
Link: <https://letsencrypt.org/documents/LE-SA-v1.2-November-15-2017.pdf>;rel="terms-of-service"
|
||||||
|
Location: https://acme-staging-v02.api.letsencrypt.org/acme/acct/5937234
|
||||||
|
Pragma: no-cache
|
||||||
|
Replay-nonce: DKxX61imF38y_qkKvVcnWyo9oxQlHll0t9dMwGbkcxw
|
||||||
|
*/
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -472,6 +542,7 @@ function jwtEggspress(req, res, next) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO verify if possible
|
// TODO verify if possible
|
||||||
|
console.warn("[warn] JWT is not verified yet");
|
||||||
next();
|
next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -487,11 +558,14 @@ function verifyJws(jwk, jws) {
|
||||||
}
|
}
|
||||||
|
|
||||||
function jwsEggspress(req, res, next) {
|
function jwsEggspress(req, res, next) {
|
||||||
|
// Check to see if this looks like a JWS
|
||||||
// TODO check header application/jose+json ??
|
// TODO check header application/jose+json ??
|
||||||
if (!req.body || !(req.body.protected && req.body.payload && req.body.signature)) {
|
if (!req.body || !(req.body.protected && req.body.payload && req.body.signature)) {
|
||||||
next();
|
next();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Decode it a bit
|
||||||
req.jws = req.body;
|
req.jws = req.body;
|
||||||
req.jws.header = JSON.parse(Buffer.from(req.jws.protected, 'base64'));
|
req.jws.header = JSON.parse(Buffer.from(req.jws.protected, 'base64'));
|
||||||
req.body = Buffer.from(req.jws.payload, 'base64');
|
req.body = Buffer.from(req.jws.payload, 'base64');
|
||||||
|
@ -499,27 +573,40 @@ function jwsEggspress(req, res, next) {
|
||||||
req.body = JSON.parse(req.body);
|
req.body = JSON.parse(req.body);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if this is a key we already trust
|
||||||
var vjwk;
|
var vjwk;
|
||||||
DB.pubs.some(function (jwk) {
|
DB.pubs.some(function (jwk) {
|
||||||
if (jwk.kid === req.jws.header.kid) {
|
if (jwk.kid === req.jws.header.kid) {
|
||||||
vjwk = jwk;
|
vjwk = jwk;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Check if there aren't any keys that we trust
|
||||||
|
// and this has signed itself, then make it a key we trust
|
||||||
|
// (TODO: move this all to the new account function)
|
||||||
if ((0 === DB.pubs.length && req.jws.header.jwk)) {
|
if ((0 === DB.pubs.length && req.jws.header.jwk)) {
|
||||||
vjwk = req.jws.header.jwk;
|
vjwk = req.jws.header.jwk;
|
||||||
if (!vjwk.kid) { throw Error("Impossible: no key id"); }
|
if (!vjwk.kid) { throw Error("Impossible: no key id"); }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't verify if it can't be verified
|
||||||
|
if (!vjwk) {
|
||||||
|
next();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Run the verification
|
||||||
return verifyJws(vjwk, req.jws).then(function (verified) {
|
return verifyJws(vjwk, req.jws).then(function (verified) {
|
||||||
if (true !== verified) {
|
if (true !== verified) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// Mark as verified
|
||||||
req.jws.verified = verified;
|
req.jws.verified = verified;
|
||||||
|
|
||||||
if (0 !== DB.pubs.length) {
|
// (double check) DO NOT save if there are existing pubs
|
||||||
return;
|
if (0 !== DB.pubs.length) { return; }
|
||||||
}
|
|
||||||
return keystore.set(vjwk.kid + '.pub.jwk.json', vjwk);
|
return keystore.set(vjwk.kid + PUBEXT, vjwk);
|
||||||
}).then(function () {
|
}).then(function () {
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
@ -1414,6 +1501,7 @@ state.net = state.net || {
|
||||||
|
|
||||||
var DB = {};
|
var DB = {};
|
||||||
DB.pubs = [];
|
DB.pubs = [];
|
||||||
|
DB.accounts = [];
|
||||||
var token;
|
var token;
|
||||||
var tokenname = "access_token.jwt";
|
var tokenname = "access_token.jwt";
|
||||||
try {
|
try {
|
||||||
|
|
Loading…
Reference in New Issue