Merge pull request #1570 from garyhgohoos/22824
[xtuple] / node-datasource / routes / generate_oauth_key.js
1 /*jshint node:true, indent:2, curly:false, eqeqeq:true, immed:true, latedef:true, newcap:true, noarg:true,
2 regexp:true, undef:true, strict:true, trailing:true, white:true */
3 /*global X:true, _:true, SYS:true */
4
5 // https://localhost/dev/oauth/generate-key?id=7
6
7 (function () {
8   "use strict";
9
10   var ursa = require("ursa"),
11     exec = require("child_process").exec,
12     forge = require("node-forge"),
13     spawn = require("child_process").spawn,
14     async = require("async"),
15     path = require("path"),
16     fs = require("fs");
17
18   /**
19     Fetch the requested oauth2client model, validate the request,
20     generate a keypair whose public key will be saved with the
21     model and whose private key is returned to the browser.
22    */
23   exports.generateKey = function (req, res) {
24     var clientModel = new SYS.Oauth2client(),
25       id = req.query.id,
26       // generic error function for both the fetch and the save
27       error = function (model, err) {
28         console.log("oauth2client error ", arguments);
29         res.send({isError: true, error: err});
30       },
31       genKey = function (model, result) {
32         /**
33           * This is REALLY slow in pure javascript. ursa is much faster.
34           * @See: https://github.com/digitalbazaar/forge/issues/125
35         forge.pki.rsa.generateKeyPair({bits: 2048, workers: 2}, function(err, keypair) {
36           if (err) {
37             res.send({isError: true, message: "Error generating keypair: " + err.message, error: err});
38             return;
39           }
40
41           fetchSuccess(model, result, keypair);
42         });
43         */
44
45         // Use ursa for the key gen and then convert to forge's format.
46         var keypair = ursa.generatePrivateKey();
47         var keys = {
48           privateKey: forge.pki.privateKeyFromPem(keypair.toPrivatePem().toString()),
49           publicKey: forge.pki.publicKeyFromPem(keypair.toPublicPem().toString())
50         };
51
52         fetchSuccess(model, result, keys);
53       },
54       sendP12 = function (keys) {
55         // It's possible and much easier to generate the p12 file without a
56         // cert. This example shows how to generate a cert if we actually need
57         // to, but OAuth is working without.
58         // @see: https://github.com/digitalbazaar/forge/blob/master/tests/nodejs-create-pkcs12.js#L11
59         //var p12Asn1 = forge.pkcs12.toPkcs12Asn1(keys.privateKey, [cert], 'notasecret'),
60         var p12Asn1 = forge.pkcs12.toPkcs12Asn1(keys.privateKey, null, 'notasecret'),
61           p12Der = forge.asn1.toDer(p12Asn1).getBytes(),
62           buffer = new Buffer(p12Der, 'binary');
63
64         res.attachment(clientModel.get('clientName') + '.p12');
65         res.send(new Buffer(buffer, 'base64'));
66       },
67       fetchSuccess = function (model, result, keys) {
68         var publicKey = forge.pki.publicKeyToPem(keys.publicKey),
69           saveSuccess = function (model, result) {
70             sendP12(keys);
71           };
72
73         // Cursory validation: this should be a jwt bearer and the
74         // public key field should not have already been set.
75         if (clientModel.get("clientType" !== "jwt bearer") ||
76             clientModel.get("clientX509PubCert")) {
77           res.send({isError: true, message: "Invalid request"});
78           return;
79         }
80
81         clientModel.set("clientX509PubCert", publicKey);
82         clientModel.save(null, {
83           error: error,
84           username: req.session.passport.user.username,
85           database: req.session.passport.user.organization,
86           success: saveSuccess
87         });
88       };
89
90     clientModel.fetch({
91       id: id,
92       username: req.session.passport.user.username,
93       database: req.session.passport.user.organization,
94       error: error,
95       success: genKey
96     });
97
98   };
99 }());