UNPKG

1password

Version:
393 lines (252 loc) 10 kB
# Cloud Keychain for Node.js (v0.2.1) This is a small library to make it easy to work with [1Password's](http://agilebits.com/onepassword) .cloudKeychain files. This implementation is based on the [official Agile Bits documentation](http://learn.agilebits.com/1Password4/Security/keychain-design.html) and also the python library [OnePasswordPy](http://github.com/roguelazer/onepasswordpy). *IMPORTANT NOTE*: I am not in any way affiliated with AgileBits, the makers of 1Password. Their software is awesome and you should probably go buy it. Currently supported: - Unlock keychain using Master Password - Load items from band_*.js files - Unlock item overview, keys and details - Create keychains and items Todo: - Find out how to calcuate the HMAC of items correctly - Actually do something with item data (instead of just handing back the raw JSON) - Get syncing working. - Add memoize pattern to opdata class to speed up item locking when no data has changed. ## Installation npm install 1password ## How to Use __Step 1: Open the keychain__ Keychain = require( '1password' ); keychain = new Keychain(); keychain.load( './1password.cloudkeychain', function( err ) { console.log( 'Keychain has loaded' ); }); __Step 2: Unlocking the keychain__ keychain.unlock( 'password' ); if ( keychain.unlocked ) { console.log( 'Successfully unlocked keychain' ); } else { console.log( 'Error: Could not unlock keychain' ); } __Step 3: Get items__ keychain.eachItem( function( item ) { console.log( item ); }); __Step 4: Decrypt item details__ item = keychain.findItems( 'Facebook' )[0]; item.unlockDetails(); console.log( item.details ); # Main Keychain Methods ## Keychain.create(password, settings) Returns an empty keychain encrypted using the password specified. keychain = Keychain.create( 'password', { passwordHint: 'hint' }); profile = keychain.exportProfile(); console.log( profile ); The `settings` parameter is an object and can overwrite any of the default values. However extra settings cannot be added. The default settings are: settings = { uuid: Crypto.generateUuid(), salt: Crypto.randomBytes(16), createdAt: currentTime, updatedAt: currentTime, iterations: 10000, profileName: 'default', passwordHint: '', lastUpdatedBy: 'Dropbox' }; This logs the following (indented and trimmed for readibility): var profile={ "lastUpdatedBy": "Dropbox", "updatedAt": 1362617665, "profileName": "default", "salt": "W0wV8jBiFnRWmqWDl3vaPA==", "passwordHint": "hint", "masterKey": "b3BkYXRhMDEAAQAAAAAAAGnpNQQJuFTg ..." "iterations": 20000, "uuid": "A2C1050B56C89557AC2A0FA230F90174", "overviewKey": "b3BkYXRhMDFAAAAAAAAAAAbP+65OIhYy ...", "createdAt": 1362617665 }; # Keychain Instance Methods ## Events Events are implemented using the NodeJS EventEmitter. The API is available on the [NodeJS.org website](http://nodejs.org/api/events.html). To use the EventEmitter: keychain = new Keychain(); keychain.event.on('event', function(args) { console.log('Event fired!', args); }); keychain.event.emit('event', 'random data'); ### Event: 'unlock' function() { } When the keychain is unlocked. ### Event: 'lock:before' function (autolock) { } When the keychain is locked. If the keychain was locked automatically by a timer, then `autolock` will be true. Used to run code before the keychain is locked. ### Event: 'lock:after' function (autolock) { } When the keychain is locked. If the keychain was locked automatically by the timer, then `autolock` will be true. Used to run code after the keychain has been locked. ## Loading data from files Load keychain data from a file on disk. ### load(filepath, callback) This is the main loading function and probably the only one you'll only ever need to use. `filepath` points to a `.cloudkeychain` folder and it will go through and load all files it finds using the other functions. keychain.load( './1password.cloudkeychain', function(err) { if ( err ) return console.log( err.message ); console.log( 'Successfully loaded keychain' ); }); ### loadProfile(filepath, rawData) Loads the `profile.js` file data into the keychain. If you already have profile.js then set `rawData` to `true`. filename = './1password.cloudkeychain/default/profile.js'; keychain.loadProfile( filename ); // Alternative profileData = readFileContents( filename ) keychain.loadProfile( profileData, true ) ### loadFolders(filepath) __Warning: Not yet implemented.__ Load the `folders.js` file data into the keychain. keychain.loadFolders( './1password.cloudkeychain/default/folders.js' ); ### loadBands(bands) `bands` is an array of filepaths pointing to each band file. keychain.loadBands([ './1password.cloudkeychain/default/band_0.js', './1password.cloudkeychain/default/band_1.js', './1password.cloudkeychain/default/band_2.js' ]); ### loadAttachment(attachments) __Warning: Not yet implemented__ `attachments` is an array of filepaths pointing to each band file. keychain.loadAttachments([ './1password.cloudkeychain/default/026AA7B7333B4F925F16DE9E21B912B7_5754B83288A34CD39DE64B45C2F05A9D.attachment', './1password.cloudkeychain/default/6F8CDF100CC99FD55053B77492D97487_072A1462CBDE4E2488FB2DA16D96B84B.attachment' ]); ## Unlocking data Handle the keychain unlocked status. ### unlock(password) Unlock the keychain's master and overview keys using `password`. It will automatically lock itself after 60 seconds, unless `rescheduleAutoLock` is called. status = keychain.unlock( 'password' ); console.log( 'Keychain was unlocked successfully: ' + status ); ### lock() Lock the keychain. This will dump the contents of all decrypted data, returning the state back to when the keychain was originally locked. keychain.lock(); ### rescheduleAutoLock() This will reschedule the autolock time. It should only be called when the user does something importantt in the app. keychain.rescheduleAutoLock() ### changePassword(currentPassword, newPassword) __Warning: Not yet tested__ This function will regenerate the master and overview keys using `newPassword`. The `currentPassword` is required, as it is not stored in memory for security reasons. keychain.changePassword( 'fred', 'phil' ); ## Items Working with items. ### createItem(data) Creates a new instance of an item using the information in `data`. It returns the item instance, but it does not add it to the keychain. Use `addItem()` to do that. item = keychain.createItem({ title: 'Github', username: 'wendyappleseed', password: 'password', url: 'github.com', notes: '' }); ### addItem(item) Adds an item to the keychain. If `item` is not an instance of an item, it is turned into one using `new Item(item)`. keychain.addItem(item); ### getItem(uuid) Get an item by its UUID. item = keychain.getItem('B1198E4C643E73A6226B89BB600371A9'); ### findItems(query) Search the keychain for an item by its name or location. Returns an array of items. items = keychain.findItems('github'); ### eachItem(fn) Loop through all the items in the keychain. Calls fn with the arguments `[item]`. keychain.eachItem(function(item) { console.log( item ); }); ## Exporting Data Export keychain data into stringified JSON. Ready for writing to disk. ### exportProfile() Export the profile.js file. profile = keychain.exportProfile(); writeFile('profile.js', profile); ### exportBands() Export the band files (which holds the item data). Returns an object. bands = keychain.exportBands() console.log( bands ); { "band_0.js": "ld({\n \"B1198E4C643E73A6226B89BB600371A9\": {\n \"category\": \"001\" ...", filename: filedata } # Item Instance Methods ### load(data) This is used to load the raw JSON data in a band file into an item. Fields such as `hmac`, `k`, `o` and `d` are converted from base64. item.load({ category: '106', created: 1361850113, d: 'b3BkYXRhMDHlAgAAAAAAANQpT0oUzF1E ...', hmac: '/Qzi7Gy37hIV18NgXffDMmt3iPZKVxIFlvvULxf5iCQ=', k: '3OoNrhpqKeBkeVAHTgwXPjlEL++QJAhx ...', o: 'b3BkYXRhMDElAAAAAAAAAEfvS1hvP9Ue …', tx: 1361857114, updated: 1361857114, uuid: 'F11FC7E27E3645D09D2670F04EF5F252' }); ### lock(type) Lock the item by deleting secure information such as the item keys, overview data and details. console.log( item.overview ); // {...} Overview data item.lock('overview'); console.log( item.overview ); // undefined ### unlock(type) Unlock the item by decrypting secure information such as the item keys, overview data and details. details = item.unlock('details') ### encrypt(type) Encrypt item details. item.unlock('details'); item.details.data = true; item.encrypt('details'); item.lock('details'); ### toJSON() Export an item into a JSON object that can be saved in a band file. json = item.toJSON(); ### match(query) Check if an item matches a query. Useful for searching through a keychain. It checks the title and URL of the item and is case insensitive. item.overview.title == 'Facebook'; item.match('facebook'); // true item.match('book'); // true item.match('skype'); // false ## Compiling To compile the coffeescript into javascript use `cake`: cake build ## Tests Tests are written in JavaScript using [Mocha](http://visionmedia.github.com/mocha/). To run the tests sudo npm install -g mocha mocha tests Or if you don't want to install mocha globally: npm install . cake tests _Also remember to recompile the coffeescript before testing!_ License ------- This work is licensed under the ISC license.