diff --git a/exec/load/acmev2.js b/exec/load/acmev2.js index 3e30e1d54b17fdebf528e16b505d2c352e151dd8..ade5c3f41a1952c01c508f2aa9ec6dcada0fc7d0 100644 --- a/exec/load/acmev2.js +++ b/exec/load/acmev2.js @@ -77,7 +77,11 @@ ACMEv2.prototype.get_terms_of_service = function() ACMEv2.prototype.get_directory = function() { if (this.directory === undefined) { - this.directory = JSON.parse(this.ua.Get("https://"+this.host+this.dir_path)); + var ret = this.ua.Get("https://"+this.host+this.dir_path); + if (this.get_response_code() != 200) + throw("Error fetching directory"); + this.store_headers(true); + this.directory = JSON.parse(ret); } return this.directory; } @@ -88,7 +92,15 @@ ACMEv2.prototype.FULL_JWT_METHODS = [ ]; ACMEv2.prototype.create_new_account = function(opts) { - return this.post('newAccount', opts); + var ret = this.post('newAccount', opts); + + if (this.get_response_code() != 201) + throw("newAccount did not return a 201 status!"); + + if (this.last_headers['Location'] === undefined) + throw("No Location header in 201 response."); + this.key_id = this.last_headers['Location'][0]; + return JSON.parse(ret); } ACMEv2.prototype.create_new_order = function(opts) @@ -98,24 +110,35 @@ ACMEv2.prototype.create_new_order = function(opts) if (opts.identifiers === undefined) throw("create_new_order() requires an identifier in opts"); ret = JSON.parse(this.post('newOrder', opts)); - if (this.last_headers.Location !== undefined && this.last_headers.Location[0] !== undefined) { - ret.Location=this.last_headers.Location[0]; - print("Location: "+ret.Location); + if (this.get_response_code() != 201) { + log(LOG_DEBUG, JSON.stringify(ret)); + throw("newOrder responded with "+this.get_response_code()+" not 201"); } + + if (this.last_headers['Location'] === undefined) + throw("No Location header in 201 response."); + ret.Location=this.last_headers.Location[0]; + return ret; } ACMEv2.prototype.accept_challenge = function(challenge) { var opts={keyAuthorization:challenge.token+"."+this.thumbprint()}; - - return JSON.parse(this.post_url(challenge.url, opts)); + var ret = this.post_url(challenge.url, opts) + if (this.get_response_code() != 200) + throw("accept_challenge did not return 200"); + return JSON.parse(ret); } ACMEv2.prototype.poll_authorization = function(auth) { var ret = JSON.parse(this.ua.Get(auth)); + if (this.get_response_code() != 200) + return false; + this.store_headers(true); + for (var challenge in ret.challenges) { if (ret.challenges[challenge].status == 'valid') return true; @@ -134,7 +157,12 @@ ACMEv2.prototype.finalize_order = function(order, csr) if (typeof(csr) != 'object' || csr.export === undefined) throw("Invalid csr"); opts.csr = this.base64url(csr.export(CryptCert.FORMAT.CERTIFICATE)); - return JSON.parse(this.post_url(order.finalize, opts)); + + var ret = this.post_url(order.finalize, opts) + if (this.get_response_code() != 200) + throw("finalize_order did not return 200"); + + return JSON.parse(ret); } ACMEv2.prototype.poll_order = function(order) @@ -142,7 +170,12 @@ ACMEv2.prototype.poll_order = function(order) var loc = order.Location; if (loc === undefined) throw("No order location!"); - var ret = JSON.parse(this.ua.Get(loc)); + var ret = this.ua.Get(loc) + if (this.get_response_code() != 200) + throw("order poll did not return 200"); + this.store_headers(true); + + ret = JSON.parse(ret); ret.Location = loc; return ret; } @@ -152,6 +185,9 @@ ACMEv2.prototype.get_cert = function(order) if (order.certificate === undefined) throw("Order has no certificate!"); var cert = this.ua.Get(order.certificate); + if (this.get_response_code() != 200) + throw("get_cert request did not return 200"); + this.store_headers(true); return new CryptCert(cert); } @@ -184,7 +220,13 @@ ACMEv2.prototype.get_nonce = function() ACMEv2.prototype.get_authorization = function(url) { - return JSON.parse(this.ua.Get(url)); + var ret = this.ua.Get(url); + + if (this.get_response_code() != 200) + throw("get_authorization request did not return 200"); + this.store_headers(true); + + return JSON.parse(ret); } ACMEv2.prototype.base64url = function(string) @@ -219,6 +261,17 @@ ACMEv2.prototype.hash_thing = function(data) return this.key.decrypt(D); } +// TODO: Should this be in http.js? +ACMEv2.prototype.get_response_code = function() +{ + if (this.ua.status_line === undefined) + throw("No status line in response!"); + var m = this.ua.status_line.match(/^HTTP\/[0-9]+\.[0-9]+ ([0-9]{3})/); + if (m === null) + throw("Unable to parse status line '"+this.ua.status_line+"'"); + return parseInt(m[1], 10); +} + // TODO: Should this be in http.js? ACMEv2.prototype.store_headers = function(update_nonce) { @@ -262,8 +315,6 @@ ACMEv2.prototype.post_url = function(url, data, post_method) if (post_method === undefined) post_method = 'post_key_id'; -print("URL: "+url); -print("Method: "+post_method); switch(post_method) { case 'post_key_id': protected.nonce = this.get_nonce(); @@ -288,8 +339,9 @@ print("Method: "+post_method); body = body.replace(/:{/g, ': {'); body = body.replace(/,"/g, ', "'); ret = this.ua.Post(url, body); - this.store_headers(true); - if (this.last_headers['Location'] !== undefined && this.key_id === undefined) - this.key_id = this.last_headers['Location'][0]; + var resp = this.get_response_code(); + /* We leave error handling to the caller */ + if (resp == 200 || resp == 201) + this.store_headers(true); return ret; }