blocktrail-sdk-backup-generator
Version:
Backup Generator for BlockTrail's Developer Friendly API binding for NodeJS
394 lines (340 loc) • 14.3 kB
JavaScript
var async = require('async');
var _ = require('lodash');
var fs = require('fs');
var brandingLogo = require('./branding-logo');
var QRCode = require('./qrCode-browser');
var PdfWriter = require('./pdf_writer');
var bowser = require('bowser');
/**
* @param identifier string identifier
* @param backupInfo object
* @param extraInfo array
* @param options
* @constructor
*/
var BackupGenerator = function(identifier, backupInfo, extraInfo, options) {
var self = this;
backupInfo = backupInfo || {};
extraInfo = extraInfo || {};
options = options || {};
self.identifier = identifier;
self.backupInfo = backupInfo;
self.extraInfo = extraInfo;
self.network = options.network || "Bitcoin";
self.options = _.merge({page1: true, page2: true, page3: true, brandingLogo: brandingLogo}, options);
self.blocktrailPublicKeys = [];
if (backupInfo.blocktrailPublicKeys) {
_.each(backupInfo.blocktrailPublicKeys, function(pubKey, keyIndex) {
self.blocktrailPublicKeys.push({
keyIndex: keyIndex,
pubKey: pubKey,
path: "M/" + keyIndex + "'"
});
});
}
};
/**
* determine if current browser supports the saveAs for the PDF backup
*
* @return {boolean}
*/
BackupGenerator.saveAsSupported = function() {
// a whole bunch of mobile OSs that are unsupported
if (bowser.browser.ios || bowser.browser.blackberry || bowser.browser.firefoxos ||
bowser.browser.webos || bowser.browser.bada || bowser.browser.tizen || bowser.browser.sailfish) {
return false;
}
if (bowser.browser.android) {
if (!bowser.browser.chrome) {
return false;
}
if (bowser.browser.version.split('.')[0] < 41) {
return false;
}
// not sure if this is required if the chrome version is >= 41
if (bowser.browser.osversion.split('.')[0] <= 4) {
return false;
}
}
return true;
};
/**
* create an HTML version of the backup document
*
*/
BackupGenerator.prototype.generateHTML = function(cb) {
var self = this;
var data = {
identifier: self.identifier,
backupInfo: self.backupInfo,
totalPubKeys: self.blocktrailPublicKeys.length,
pubKeysHtml: "",
extraInfo: _.map(self.extraInfo, function(value, key) {
if (typeof value !== "string") {
return value;
} else {
return {
title: key,
value: value
};
}
}),
options: self.options
};
async.forEach(Object.keys(self.blocktrailPublicKeys), function(keyIndex, cb) {
var pubKey = self.blocktrailPublicKeys[keyIndex];
QRCode.toDataURL(pubKey.pubKey.toBase58(), {
errorCorrectLevel: 'medium'
}, function(err, dataURI) {
pubKey.qr = dataURI;
cb(err);
});
}, function(err) {
if (err) {
return cb(err);
}
_.each(self.blocktrailPublicKeys, function(pubKey) {
data.pubKeysHtml += "<figure><img src='" + pubKey.qr + "' /><figcaption>";
data.pubKeysHtml += "<span>KeyIndex: " + pubKey.keyIndex + " </span> ";
data.pubKeysHtml += "<span>Path: " + pubKey.path + "</span>";
data.pubKeysHtml += "</figcaption></figure>";
});
//load and compile the html
var compiledHtml;
try {
compiledHtml = _.template(fs.readFileSync(__dirname + "/resources/backup_info_template.html", {encoding: 'utf8'}));
} catch (e) {
return cb(e);
}
cb(null, compiledHtml(data));
});
};
/**
* create a PDF version of the backup document
*/
BackupGenerator.prototype.generatePDF = function(callback) {
/* jshint -W101 */
var self = this;
var pdf = new PdfWriter();
var pageTop = function() {
pdf.YAXIS(30); // top margin
pdf.IMAGE(
brandingLogo,
'jpeg',
154,
30
);
};
try {
pdf.setFont('helvetica'); // default font
pageTop();
async.series([
/**
* page 1
*/
function(callback) {
if (self.options.page1) {
pdf.FONT_SIZE_HEADER(function() {
pdf.TEXT(self.network + " Wallet Recovery Data Sheet");
});
pdf.TEXT(
"This document holds the information and instructions required for you to recover your BTC Wallet should anything happen. \n" +
"Print it out and keep it in a safe location; if you lose these details you will never be able to recover your wallet."
);
pdf.FONT_SIZE_HEADER(function() {
pdf.TEXT("Wallet Identifier (" + self.backupInfo.walletVersion + ")");
pdf.HR(0, 0);
});
pdf.FONT_SIZE_SUBHEADER(function() {
pdf.TEXT_COLOR_GREY(function() {
pdf.TEXT(self.identifier);
});
});
pdf.FONT_SIZE_HEADER(function() {
pdf.TEXT("Backup Info");
pdf.HR(0, 0);
});
if (self.backupInfo.primaryMnemonic) {
pdf.FONT_SIZE_SUBHEADER(function() {
pdf.TEXT_COLOR_GREY(function() {
pdf.TEXT("Primary Mnemonic");
});
pdf.YAXIS(5);
pdf.FONT_SIZE_NORMAL(function() {
pdf.TEXT(self.backupInfo.primaryMnemonic);
});
});
}
if (self.backupInfo.backupMnemonic) {
pdf.FONT_SIZE_SUBHEADER(function() {
pdf.TEXT_COLOR_GREY(function() {
pdf.TEXT("Backup Mnemonic");
});
pdf.YAXIS(5);
pdf.FONT_SIZE_NORMAL(function() {
pdf.TEXT(self.backupInfo.backupMnemonic);
});
});
}
if (self.backupInfo.encryptedPrimarySeed) {
pdf.FONT_SIZE_SUBHEADER(function() {
pdf.TEXT_COLOR_GREY(function() {
pdf.TEXT("Encrypted Primary Seed");
});
pdf.YAXIS(5);
pdf.FONT_SIZE_NORMAL(function() {
pdf.TEXT(self.backupInfo.encryptedPrimarySeed);
});
});
}
if (self.backupInfo.backupSeed) {
pdf.FONT_SIZE_SUBHEADER(function() {
pdf.TEXT_COLOR_GREY(function() {
pdf.TEXT("Backup Seed");
});
pdf.YAXIS(5);
pdf.FONT_SIZE_NORMAL(function() {
pdf.TEXT(self.backupInfo.backupSeed);
});
});
}
if (self.backupInfo.recoveryEncryptedSecret) {
pdf.FONT_SIZE_SUBHEADER(function() {
pdf.TEXT_COLOR_GREY(function() {
pdf.TEXT("Encrypted Recovery Secret");
});
pdf.YAXIS(5);
pdf.FONT_SIZE_NORMAL(function() {
pdf.TEXT(self.backupInfo.recoveryEncryptedSecret);
});
});
}
pdf.NEXT_PAGE();
pageTop();
pdf.YAXIS(10); // need a little extra margin for QR codes
pdf.FONT_SIZE_SUBHEADER(function() {
pdf.TEXT_COLOR_GREY(function() {
pdf.TEXT("BTC Wallet Public Keys");
});
pdf.FONT_SIZE_NORMAL(function() {
pdf.TEXT(self.blocktrailPublicKeys.length + " in total");
});
});
pdf.YAXIS(20);
async.forEach(Object.keys(self.blocktrailPublicKeys), function(keyIndex, cb) {
var pubKey = self.blocktrailPublicKeys[keyIndex];
QRCode.toDataURL(pubKey.pubKey.toBase58(), {
errorCorrectLevel: 'medium'
}, function(err, dataURI) {
pubKey.qr = dataURI;
cb(err);
});
}, function(err) {
if (err) {
return callback(err);
}
var qrSize = 180;
var qrSubtitleheight = 20;
Object.keys(self.blocktrailPublicKeys).forEach(function(keyIndex, i) {
var pubKey = self.blocktrailPublicKeys[i];
var x = i % 3;
// move the yPos back up
if (i > 0 && x !== 0) {
pdf.YAXIS(-qrSize);
pdf.YAXIS(-3);
}
pdf.IMAGE(pubKey.qr, 'jpeg', qrSize, qrSize, x * qrSize);
pdf.YAXIS(3);
pdf.FONT_SIZE_SMALL(function() {
pdf.TEXT("KeyIndex: " + pubKey.keyIndex + " Path: " + pubKey.path, (x * qrSize) + 20, false);
});
});
pdf.YAXIS(qrSubtitleheight);
if (self.extraInfo) {
_.each(self.extraInfo, function(value, key) {
var title;
var subtitle;
if (typeof value !== "string") {
title = value.title;
subtitle = value.subtitle;
value = value.value;
} else {
title = key;
// value = value;
}
pdf.FONT_SIZE_SUBHEADER(function() {
pdf.TEXT_COLOR_GREY(function() {
pdf.TEXT(title);
});
if (subtitle) {
pdf.FONT_SIZE_SMALL(function() {
pdf.TEXT_COLOR_LIGHT_GREY(function() {
pdf.TEXT(subtitle);
});
});
}
pdf.YAXIS(3);
pdf.FONT_SIZE_NORMAL(function() {
pdf.TEXT(value);
});
});
});
}
callback();
});
} else {
callback();
}
},
function(callback) {
if (self.backupInfo.encryptedSecret && self.options.page2) {
if (self.options.page1) {
pdf.NEXT_PAGE();
pageTop();
}
pdf.FONT_SIZE_HEADER(function() {
pdf.TEXT("Backup Info - part 2");
pdf.HR(0, 0);
});
pdf.TEXT("This page needs to be replaced / updated when wallet password is changed!");
pdf.FONT_SIZE_SUBHEADER(function() {
pdf.TEXT_COLOR_GREY(function() {
pdf.TEXT("Password Encrypted Secret");
});
pdf.YAXIS(5);
pdf.FONT_SIZE_NORMAL(function() {
pdf.TEXT(self.backupInfo.encryptedSecret);
});
});
}
callback();
},
function(callback) {
if (self.options.page3) {
// save some paper
// pdf.NEXT_PAGE();
// pageTop();
pdf.FONT_SIZE_HEADER(function() {
pdf.TEXT("Wallet Recovery Instructions");
pdf.HR(0, 0);
});
pdf.TEXT(
"You can recover the bitcoins in your wallet on https://recovery.blocktrail.com using this backup sheet.\n" +
"For a more technical aproach on how to recover your wallet yourself, " +
"see the 'wallet_recovery_example.php' script in the examples folder of the Blocktrail SDK."
);
}
callback();
}
], function(err) {
if (err) {
return callback(err);
}
callback(null, pdf.doc);
});
} catch (e) {
callback(e);
return;
}
};
module.exports = BackupGenerator;