Skip to content

Commit

Permalink
Pass config variables rather than reading file from disc.
Browse files Browse the repository at this point in the history
This allows the calling application to choose how it handles configuration.

Particularly useful for applications following the 12 factor methodology.
  • Loading branch information
davidbanham committed Mar 8, 2017
1 parent 0f44ca7 commit 01fa26d
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 85 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Expand Up @@ -7,4 +7,4 @@
.nyc_output/
.DS_Store
.vscode
*config.json
testing_config.json
23 changes: 23 additions & 0 deletions example_testing_config.json
@@ -0,0 +1,23 @@
{
"APPTYPE": "PARTNER",
"partner": {
"AuthorizeCallbackUrl": null,
"ConsumerKey": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
"PrivateKeyPath": "/some/path/to/privatekey.pem",
"UserAgent": "Tester (PARTNER) - Application for testing Xero",
"XeroPassword": "XXXXXXXXXX",
"XeroUsername": "foo@example.com"
},
"private": {
"ConsumerKey": "AAAAAAAAAAAAAAAAAA",
"ConsumerSecret": "BBBBBBBBBBBBBBBBBBBB",
"PrivateKeyPath": "/some/path/to/privatekey.pem",
"UserAgent": "Tester (PRIVATE) - Application for testing Xero"
},
"public": {
"AuthorizeCallbackUrl": "https://example.com/xerocallback",
"ConsumerKey": "AAAAAAAAAAAAAAAAAA",
"ConsumerSecret": "BBBBBBBBBBBBBBBBBBBB",
"UserAgent": "Tester (PUBLIC) - Application for testing Xero"
}
}
61 changes: 19 additions & 42 deletions lib/application.js
Expand Up @@ -2,7 +2,6 @@ var _ = require('lodash'),
logger = require('./logger'),
OAuth = require('./oauth/oauth').OAuth,
OAuthEcho = require('./oauth/oauth').OAuthEcho,
fs = require('fs'),
extend = require('./misc/extend'),
dateformat = require('dateformat'),
querystring = require('querystring'),
Expand Down Expand Up @@ -421,50 +420,28 @@ _.extend(Application.prototype, {
}
})

populateOptions = function(configFilePath) {
if (!configFilePath) {
//look for the config file in the user's home directory
var homedir, config;

homedir = process.env.HOME || process.env.USERPROFILE;
if (homedir) {
configFilePath = homedir + '/.xero/config.json';
} else {
var err = 'Couldn\'t find config.json in your home dir [' + homedir + '/.xero]. Exiting...';
console.error(err);
throw err;
}
}

populateOptions = function(config) {
var options = {};

try {
logger.debug('configFilePath: ' + configFilePath);

config = require(configFilePath);
options["consumerKey"] = config.ConsumerKey;
options["consumerSecret"] = config.ConsumerSecret;
options["privateKeyPath"] = config.PrivateKeyPath;
options["authorizeCallbackUrl"] = config.AuthorizeCallbackUrl;
options["userAgent"] = config.UserAgent || "Xero - Node.js SDK";
options["runscopeBucketId"] = config.RunscopeBucketId;
} catch (e) {
var err = 'Couldn\'t read config.json from [' + configFilePath + ']. Exiting...';
console.error(err);
}
options["consumerKey"] = config.ConsumerKey;
options["consumerSecret"] = config.ConsumerSecret;
options["privateKey"] = config.PrivateKey;
options["authorizeCallbackUrl"] = config.AuthorizeCallbackUrl;
options["userAgent"] = config.UserAgent || "Xero - Node.js SDK";
options["runscopeBucketId"] = config.RunscopeBucketId;

return options;
}

var PrivateApplication = Application.extend({
constructor: function(configFilePath, options) {
constructor: function(config) {
logger.debug('PrivateApplication::constructor');
var options = _.merge(populateOptions(configFilePath), options);
Application.call(this, _.extend({}, options, { type: 'private' }));
config = populateOptions(config);
Application.call(this, _.extend({}, config, { type: 'private' }));
},
init: function() {
Application.prototype.init.apply(this, arguments);
var rsaPrivateKey = fs.readFileSync(this.options.privateKeyPath, "utf8");
var rsaPrivateKey = this.options.privateKey;
this.oa = new OAuth(
null,
null,
Expand Down Expand Up @@ -533,10 +510,10 @@ var RequireAuthorizationApplication = Application.extend({


var PublicApplication = RequireAuthorizationApplication.extend({
constructor: function(configFilePath, args) {
constructor: function(config) {
logger.debug('PublicApplication::constructor');
var params = _.merge(populateOptions(configFilePath), args);
RequireAuthorizationApplication.call(this, _.extend({}, params, { type: 'public' }));
config = populateOptions(config);
RequireAuthorizationApplication.call(this, _.extend({}, config, { type: 'public' }));
},
init: function() {
RequireAuthorizationApplication.prototype.init.apply(this, arguments);
Expand All @@ -554,15 +531,15 @@ var PublicApplication = RequireAuthorizationApplication.extend({
});

var PartnerApplication = RequireAuthorizationApplication.extend({
constructor: function(configFilePath, options) {
constructor: function(config) {
logger.debug('PartnerApplication::constructor');
var options = _.merge(populateOptions(configFilePath), options);
RequireAuthorizationApplication.call(this, _.extend({}, options, { type: 'partner' }));
config = populateOptions(config);
RequireAuthorizationApplication.call(this, _.extend({}, config, { type: 'partner' }));
},

init: function() {
RequireAuthorizationApplication.prototype.init.apply(this, arguments);
var rsaPrivateKey = fs.readFileSync(this.options.privateKeyPath, "utf8");
var rsaPrivateKey = this.options.privateKey;
this.oa = new OAuth(
this.options.baseUrl + this.options.requestTokenUrl,
this.options.baseUrl + this.options.accessTokenUrl,
Expand All @@ -574,7 +551,7 @@ var PartnerApplication = RequireAuthorizationApplication.extend({
null, { 'User-Agent': this.options.userAgent }
);
//use SSL certificate
var keyCert = fs.readFileSync(this.options.privateKeyPath);
var keyCert = this.options.privateKey;
this.oa._createClient = function(port, hostname, method, path, headers, sslEnabled) {
var options = {
host: hostname,
Expand Down
3 changes: 1 addition & 2 deletions lib/logger.js
@@ -1,5 +1,4 @@
var log4js = require('log4js'),
fs = require('fs'),
path = require('path'),
dateFormat = require('dateformat'),
util = require('util'),
Expand Down Expand Up @@ -95,4 +94,4 @@ Logger.prototype = {
};

module.exports = new Logger() // default instance;
module.exports.Logger = Logger;
module.exports.Logger = Logger;
3 changes: 1 addition & 2 deletions lib/oauth/oauth.js
Expand Up @@ -3,7 +3,6 @@ var crypto = require('crypto'),
http = require('http'),
https = require('https'),
URL = require('url'),
fs = require('fs'),
querystring = require('querystring'),
OAuthUtils = require('./_utils'),
_ = require('lodash');
Expand Down Expand Up @@ -585,4 +584,4 @@ exports.OAuth.prototype.authHeader = function(url, oauth_token, oauth_token_secr

var orderedParameters = this._prepareParameters(oauth_token, oauth_token_secret, method, url, {});
return this._buildAuthorizationHeaders(orderedParameters);
};
};
54 changes: 16 additions & 38 deletions test/accountingtests.js
Expand Up @@ -5,36 +5,32 @@ var chai = require('chai'),
xero = require('..'),
util = require('util'),
Browser = require('zombie'),
uuid = require('uuid');
uuid = require('uuid'),
fs = require('fs'),
metaConfig = require('../testing_config.json');

process.on('uncaughtException', function(err) {
console.log('uncaught', err)
})

var currentApp;
var organisationCountry = "";
var organisationCountry = '';

var APPTYPE = "PRIVATE";
var privateConfigFile = "../private_app_config.json";
var publicConfigFile = "../public_app_config.json";
var partnerConfigFile = "../partner_app_config.json";
var configFile = "";
var APPTYPE = metaConfig.APPTYPE;
var config = metaConfig[APPTYPE.toLowerCase()];

before('init instance and set options', function(done) {
//This constructor looks in ~/.xero/config.json for settings
if (config.PrivateKeyPath && !config.PrivateKey) config.PrivateKey = fs.readFileSync(config.PrivateKeyPath);

before('init instance and set options', function(done) {
switch (APPTYPE) {
case "PRIVATE":
configFile = privateConfigFile;
currentApp = new xero.PrivateApplication(configFile);
currentApp = new xero.PrivateApplication(config);
break;
case "PUBLIC":
configFile = publicConfigFile;
currentApp = new xero.PublicApplication(publicConfigFile, { runscopeBucketId: "ei635hnc0fem" });
currentApp = new xero.PublicApplication(config);
break;
case "PARTNER":
configFile = partnerConfigFile;
currentApp = new xero.PartnerApplication(partnerConfigFile, { authorizedCallbackUrl: "" });
currentApp = new xero.PartnerApplication(config);
break;
default:
throw "No App Type Set!!"
Expand Down Expand Up @@ -100,28 +96,10 @@ describe('get access for public or partner application', function() {
});

describe('submits form', function() {
var options = {};

before(function(done) {

if (APPTYPE === "PRIVATE") {
this.skip();
}

try {
console.log('configFile: ' + configFile);

var config = require(configFile);
options["XeroUsername"] = config.XeroUsername;
options["XeroPassword"] = config.XeroPassword;
done();
} catch (e) {
var err = 'Couldn\'t read config.json from [' + configFile + ']. Exiting...';
console.log(err);
throw e;
}

});
var options = {
XeroUsername: config.XeroUsername,
XeroPassword: config.XeroPassword
};

it('should login', function(done) {
browser
Expand Down Expand Up @@ -1450,4 +1428,4 @@ function wrapError(err) {
return err;
else if (err.statusCode)
return new Error(err.statusCode + ': ' + err.exception.Message);
}
}

0 comments on commit 01fa26d

Please sign in to comment.