MAJOR: Updates for Authenticated Web UI and CLI #30
| @ -685,6 +685,7 @@ function parseConfig(err, text) { | ||||
|       , protected: { | ||||
|           // alg will be filled out automatically
 | ||||
|           jwk: state.pub | ||||
|         , kid: false | ||||
|         , nonce: nonce | ||||
|         , url: newAccountUrl | ||||
|         } | ||||
|  | ||||
| @ -590,9 +590,14 @@ function jwtEggspress(req, res, next) { | ||||
| 
 | ||||
|   // TODO verify if possible
 | ||||
|   console.warn("[warn] JWT is not verified yet"); | ||||
|   // A failed JWS should cause a failed JWT
 | ||||
|   if (false !== req.trusted) { | ||||
|     req.trusted = true; | ||||
|   } | ||||
|   next(); | ||||
| } | ||||
| 
 | ||||
| // TODO switch to Keypairs.js / Keyfetch.js
 | ||||
| function verifyJws(jwk, jws) { | ||||
|   return keypairs.export({ jwk: jwk }).then(function (pem) { | ||||
|     var alg = 'SHA' + jws.header.alg.replace(/[^\d]+/i, ''); | ||||
| @ -632,9 +637,8 @@ function jwsEggspress(req, res, next) { | ||||
|   } | ||||
|   if (req.jws.header.jwk) { | ||||
|     if (kid) { | ||||
|       // TODO kid and jwk are mutually exclusive
 | ||||
|       //res.send({ error: { message: "jws protected header must not include both 'kid' and 'jwk'" } });
 | ||||
|       //return;
 | ||||
|       res.send({ error: { message: "jws protected header must not include both 'kid' and 'jwk'" } }); | ||||
|       return; | ||||
|     } | ||||
|     kid = req.jws.header.jwk.kid; | ||||
|     p = Keypairs.thumbprint({ jwk: req.jws.header.jwk }).then(function (thumb) { | ||||
| @ -699,6 +703,10 @@ function jwsEggspress(req, res, next) { | ||||
|       }); | ||||
|     }); | ||||
|   }).then(function () { | ||||
|     // a failed JWT should cause a failed JWS
 | ||||
|     if (false !== req.trusted) { | ||||
|       req.trusted = req.jws.trusted; | ||||
|     } | ||||
|     next(); | ||||
|   }); | ||||
| } | ||||
| @ -1038,10 +1046,19 @@ function handleApi() { | ||||
|   app.head('/acme/new-nonce', controllers.newNonce); | ||||
|   app.get('/acme/new-nonce', controllers.newNonce); | ||||
|   app.post('/acme/new-acct', controllers.newAccount); | ||||
|   app.use(/\b(relay)\b/, controllers.relay); | ||||
|   app.get(/\b(config)\b/, getConfigOnly); | ||||
|   app.use(/\b(init|config)\b/, initOrConfig); | ||||
|   app.use(/\b(restart)\b/, restart); | ||||
|   function mustTrust(req, res, next) { | ||||
|     // TODO public routes should be explicitly marked
 | ||||
|     // trusted should be the default
 | ||||
|     if (req.trusted) { next(); } | ||||
|     res.statusCode = 400; | ||||
|     res.send({"error":{"message": "this type of requests must be encoded as a jws payload" | ||||
|       + " and signed by a trusted account holder"}}); | ||||
|     return; | ||||
|   } | ||||
|   app.use(/\b(relay)\b/, mustTrust, controllers.relay); | ||||
|   app.get(/\b(config)\b/, mustTrust, getConfigOnly); | ||||
|   app.use(/\b(init|config)\b/, mustTrust, initOrConfig); | ||||
|   app.use(/\b(restart)\b/, mustTrust, restart); | ||||
| 
 | ||||
|   // Position is important with eggspress
 | ||||
|   // This should stay here, right before the other methods
 | ||||
| @ -1050,14 +1067,14 @@ function handleApi() { | ||||
|   //
 | ||||
|   // With proper config
 | ||||
|   //
 | ||||
|   app.use(/\b(http)\b/, controllers.http); | ||||
|   app.use(/\b(tcp)\b/, controllers.tcp); | ||||
|   app.use(/\b(save|commit)\b/, saveAndCommit); | ||||
|   app.use(/\b(ssh)\b/, controllers.ssh); | ||||
|   app.use(/\b(enable)\b/, enable); | ||||
|   app.use(/\b(disable)\b/, disable); | ||||
|   app.use(/\b(status)\b/, getStatus); | ||||
|   app.use(/\b(list)\b/, listSuccess); | ||||
|   app.use(/\b(http)\b/, mustTrust, controllers.http); | ||||
|   app.use(/\b(tcp)\b/, mustTrust, controllers.tcp); | ||||
|   app.use(/\b(save|commit)\b/, mustTrust, saveAndCommit); | ||||
|   app.use(/\b(ssh)\b/, mustTrust, controllers.ssh); | ||||
|   app.use(/\b(enable)\b/, mustTrust, enable); | ||||
|   app.use(/\b(disable)\b/, mustTrust, disable); | ||||
|   app.use(/\b(status)\b/, mustTrust, getStatus); | ||||
|   app.use(/\b(list)\b/, mustTrust, listSuccess); | ||||
|   app.use('/', function (req, res) { | ||||
|     res.send({"error":{"message":"unrecognized rpc"}}); | ||||
|   }); | ||||
|  | ||||
| @ -160,6 +160,7 @@ module.exports.create = function (state) { | ||||
|     , protected: { | ||||
|         // alg will be filled out automatically
 | ||||
|         jwk: state.pub | ||||
|       , kid: false | ||||
|       , nonce: require('crypto').randomBytes(16).toString('hex') // TODO get from server
 | ||||
|         // TODO make localhost exceptional
 | ||||
|       , url: RC.resolve(reqOpts.path) | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user