diff --git a/README.md b/README.md index 98fe8f2..90cd44a 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,28 @@ datResolve(link, function (err, key) { Link can be string or buffer. -Resolution order: + +### `datResolve(link, options, callback(err, { key, version, path }))` + +Link can be string or buffer. + +Options an object that supports the ```verbose``` key. If ```true```, the +callback is called with an object. You can also directly set ```options``` +to ```true``` for the same effect. Otherwise, the callback is called with ```keys``` +as usual. + +For example: + +```js +// same as datResolve('beakerbrowser.com+54/path', { verbose: true }, ...) +datResolve('beakerbrowser.com+54/path', true, function (err, response) { + // response.key = 87ed2e3b160f261a032af03921a3bd09227d0a4cde73466c17114816cae43336 + // response.version = 54 (as an integer) + // response.path = /path +}) +``` + +## Resolution order: 1. Validate buffers or any strings with 64 character hashes in them via [dat-encoding](https://github.com/juliangruber/dat-encoding) 2. Check headers in http request diff --git a/index.js b/index.js index 810ced5..c508610 100644 --- a/index.js +++ b/index.js @@ -6,8 +6,25 @@ var debug = require('debug')('dat-link-resolve') module.exports = resolve -function resolve (link, cb) { +function parseUrl (key, link, named) { + var response = { key: key, link: link } + var matches = link.match(new RegExp((named ? '' : key) + '(\\+[0-9]+)?(/.*)?$')) + if (matches) { + if (matches[1]) { response.version = parseInt(matches[1], 10) } + if (matches[2]) { response.path = matches[2] } + } + return response +} + +function resolve (link, options, cb) { assert.ok(link, 'dat-link-resolve: link required') + if (!cb && options) { + cb = options + options = {} + } else if (typeof options === 'boolean') { + options = { verbose: options } + } + assert.equal(typeof options, 'object', 'dat-link-resolve: options must be an object') assert.equal(typeof cb, 'function', 'dat-link-resolve: callback required') var key = null @@ -16,7 +33,11 @@ function resolve (link, cb) { // validates + removes dat:// // also works for http urls with keys in them key = stringKey(link) - cb(null, key) + if (options.verbose) { + cb(null, parseUrl(key, link)) + } else { + cb(null, key) + } } catch (e) { lookup() } @@ -28,8 +49,15 @@ function resolve (link, cb) { function resolveName () { datDns.resolveName(urlLink, function (err, key) { debug('resolveName', urlLink, err, key) - if (key) return cb(null, key) - if (err) debug('datDns.resolveName() error') + if (key) { + if (options.verbose) { + cb(null, parseUrl(key, link, true)) + } else { + cb(null, key) + } + return + } + debug('datDns.resolveName() error', err) cb(err) }) } @@ -45,14 +73,26 @@ function resolve (link, cb) { key = resp.headers['hyperdrive-key'] || resp.headers['dat-key'] if (key) { debug('Received key from http header:', key) - return cb(null, key) + if (options.verbose) { + cb(null, { key: key }) + } else { + cb(null, key) + } + return } // else fall back to parsing the body try { key = stringKey(body.url) debug('Received key via json:', key, typeof body, body && typeof body.url) - if (key) return cb(null, key) + if (key) { + if (options.verbose) { + cb(null, { key: key }) + } else { + cb(null, key) + } + return + } } catch (e) { // fall back to datDns resolveName() diff --git a/test/index.js b/test/index.js index fb6080b..cec5fa6 100644 --- a/test/index.js +++ b/test/index.js @@ -118,3 +118,95 @@ test('resolve beaker browser dat', function (t) { t.end() }) }) + +test('resolve beaker browser dat v2', function (t) { + datResolve('dat://beakerbrowser.com', true, function (err, response) { + t.error(err, 'no error') + t.ok(response && response.key, 'got key') + t.end() + }) +}) + +test('resolve beaker browser dat v3', function (t) { + datResolve('dat://beakerbrowser.com', false, function (err, key) { + t.error(err, 'no error') + t.ok(key, 'got key') + t.end() + }) +}) + +test('resolve beaker browser dat v4', function (t) { + datResolve('dat://beakerbrowser.com', { verbose: true }, function (err, response) { + t.error(err, 'no error') + t.ok(response && response.key, 'got key') + t.end() + }) +}) + +test('resolve beaker browser dat v5', function (t) { + datResolve('dat://beakerbrowser.com', {}, function (err, key) { + t.error(err, 'no error') + t.ok(key, 'got key') + t.end() + }) +}) + +test('resolve key with path (verbose)', function (t) { + datResolve('87ed2e3b160f261a032af03921a3bd09227d0a4cde73466c17114816cae43336/path', true, function (err, response) { + t.notOk(err, 'not expected error') + t.is(response && response.key, '87ed2e3b160f261a032af03921a3bd09227d0a4cde73466c17114816cae43336', 'is a key') + t.is(response && response.path, '/path', 'with path') + t.notOk(response && response.version, 'no unexpected version') + t.end() + }) +}) + +test('resolve key with version (verbose)', function (t) { + datResolve('87ed2e3b160f261a032af03921a3bd09227d0a4cde73466c17114816cae43336+54', true, function (err, response) { + t.notOk(err, 'not expected error') + t.is(response && response.key, '87ed2e3b160f261a032af03921a3bd09227d0a4cde73466c17114816cae43336', 'is a key') + t.is(response && response.version, 54, 'with version') + t.notOk(response && response.path, 'no unexpected path') + t.end() + }) +}) + +test('resolve key with version and path (verbose)', function (t) { + datResolve('87ed2e3b160f261a032af03921a3bd09227d0a4cde73466c17114816cae43336+54/path', true, function (err, response) { + t.notOk(err, 'not expected error') + t.is(response && response.key, '87ed2e3b160f261a032af03921a3bd09227d0a4cde73466c17114816cae43336', 'is a key') + t.is(response && response.version, 54, 'with version') + t.is(response && response.path, '/path', 'with path') + t.end() + }) +}) + +test('resolve beaker browser with path (verbose)', function (t) { + datResolve('beakerbrowser.com/path', true, function (err, response) { + t.notOk(err, 'not expected error') + t.is(response && response.key, '87ed2e3b160f261a032af03921a3bd09227d0a4cde73466c17114816cae43336', 'is a key') + t.is(response && response.path, '/path', 'with path') + t.notOk(response && response.version, 'no unexpected version') + t.end() + }) +}) + +test('resolve beaker browser with version (verbose)', function (t) { + datResolve('beakerbrowser.com+54', true, function (err, response) { + t.notOk(err, 'not expected error') + t.is(response && response.key, '87ed2e3b160f261a032af03921a3bd09227d0a4cde73466c17114816cae43336', 'is a key') + t.is(response && response.version, 54, 'with version') + t.notOk(response && response.path, 'no unexpected path') + t.end() + }) +}) + +test('resolve beaker browser with version and path (verbose)', function (t) { + datResolve('beakerbrowser.com+54/path', true, function (err, response) { + t.notOk(err, 'not expected error') + t.is(response && response.key, '87ed2e3b160f261a032af03921a3bd09227d0a4cde73466c17114816cae43336', 'is a key') + t.is(response && response.version, 54, 'with version') + t.is(response && response.path, '/path', 'with path') + t.end() + }) +})