UNPKG

blockstack

Version:

The Blockstack Javascript library for authentication, identity, and storage.

1,041 lines (878 loc) 44.1 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _slicedToArray = function () { function sliceIterator(arr, i) { var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"]) _i["return"](); } finally { if (_d) throw _e; } } return _arr; } return function (arr, i) { if (Array.isArray(arr)) { return arr; } else if (Symbol.iterator in Object(arr)) { return sliceIterator(arr, i); } else { throw new TypeError("Invalid attempt to destructure non-iterable instance"); } }; }(); exports.runStorageTests = runStorageTests; var _tape = require('tape'); var _tape2 = _interopRequireDefault(_tape); var _fetchMock = require('fetch-mock'); var _fetchMock2 = _interopRequireDefault(_fetchMock); var _proxyquire18 = require('proxyquire'); var _proxyquire19 = _interopRequireDefault(_proxyquire18); var _sinon = require('sinon'); var _sinon2 = _interopRequireDefault(_sinon); var _jsontokens = require('jsontokens'); var _hub = require('../../../lib/storage/hub'); var _storage = require('../../../lib/storage'); var _keys = require('../../../lib/keys'); var _lib = require('../../../lib'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // class LocalStorage { // constructor() { // this.data = {} // } // // setItem(k, v) { // this.data[k] = v // } // // removeItem(k) { // delete this.data[k] // } // // getItem(k) { // return this.data[k] // } // } // const localStorage = new LocalStorage() // global.localStorage = localStorage // global.window = {} // global.window.localStorage = localStorage // global.window.location = {} // global.window.location.origin = 'https://myApp.blockstack.org' function runStorageTests() { (0, _tape2.default)('getFile unencrypted, unsigned', function (t) { t.plan(2); var path = 'file.json'; var gaiaHubConfig = { address: '1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U', server: 'https://hub.blockstack.org', token: '', url_prefix: 'gaia.testblockstack.org/hub/' }; var fullReadUrl = 'https://gaia.testblockstack.org/hub/1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U/file.json'; var fileContent = { test: 'test' }; var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:3000'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); var getOrSetLocalGaiaHubConnection = _sinon2.default.stub().resolves(gaiaHubConfig); var getFullReadUrl = _sinon2.default.stub().resolves(fullReadUrl); // eslint-disable-line no-shadow var _proxyquire = (0, _proxyquire19.default)('../../../lib/storage', { // eslint-disable-line no-shadow './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection, getFullReadUrl: getFullReadUrl } }), getFileImpl = _proxyquire.getFileImpl; _fetchMock2.default.get(fullReadUrl, fileContent); var options = { decrypt: false }; getFileImpl(blockstack, path, options).then(function (file) { t.ok(file, 'Returns file content'); t.same(JSON.parse(file), fileContent); }); }); (0, _tape2.default)('getFile unencrypted, unsigned - multi-reader', function (t) { t.plan(6); var path = 'file.json'; var gaiaHubConfig = { address: '1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U', server: 'https://hub.blockstack.org', token: '', url_prefix: 'gaia.testblockstack.org/hub/' }; var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:8080'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); var fullReadUrl = 'https://gaia.testblockstack.org/hub/1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U/file.json'; var fileContent = { test: 'test' }; var getOrSetLocalGaiaHubConnection = _sinon2.default.stub().resolves(gaiaHubConfig); var getFullReadUrl2 = _sinon2.default.stub().resolves(fullReadUrl); var _proxyquire2 = (0, _proxyquire19.default)('../../../lib/storage', { // eslint-disable-line no-shadow './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection, getFullReadUrl2: getFullReadUrl2 } }), getFileImpl = _proxyquire2.getFileImpl; _fetchMock2.default.get(fullReadUrl, fileContent); var nameLookupUrl = 'https://core.blockstack.org/v1/names/yukan.id'; var nameRecord = { status: 'registered', zonefile: '$ORIGIN yukan.id\n$TTL 3600\n_http._tcp URI 10 1 "https://gaia.blockstack.org/hub/16zVUoP7f15nfTiHw2UNiX8NT5SWYqwNv3/0/profile.json"\n', expire_block: 581432, blockchain: 'bitcoin', last_txid: 'f7fa811518566b1914a098c3bd61a810aee56390815bd608490b0860ac1b5b4d', address: '16zVUoP7f15nfTiHw2UNiX8NT5SWYqwNv3', zonefile_hash: '98f42e11026d42d394b3424d4d7f0cccd6f376e2' }; var nameRecordContent = JSON.stringify(nameRecord); _fetchMock2.default.get(nameLookupUrl, nameRecordContent); var profileUrl = 'https://gaia.blockstack.org/hub/16zVUoP7f15nfTiHw2UNiX8NT5SWYqwNv3/0/profile.json'; /* eslint-disable */ var profileContent = [{ 'token': 'eyJ0eXAiOiJKV1QiLCJhbGciOiJFUzI1NksifQ.eyJqdGkiOiJjNDhmOTQ0OC1hMGZlLTRiOWUtOWQ2YS1mYzA5MzhjOGUyNzAiLCJpYXQiOiIyMDE4LTAxLTA4VDE4OjIyOjI0Ljc5NloiLCJleHAiOiIyMDE5LTAxLTA4VDE4OjIyOjI0Ljc5NloiLCJzdWJqZWN0Ijp7InB1YmxpY0tleSI6IjAyNDg3YTkxY2Q5NjZmYWVjZWUyYWVmM2ZkZTM3MjgwOWI0NmEzNmVlMTkyNDhjMDFmNzJiNjQ1ZjQ0Y2VmMmUyYyJ9LCJpc3N1ZXIiOnsicHVibGljS2V5IjoiMDI0ODdhOTFjZDk2NmZhZWNlZTJhZWYzZmRlMzcyODA5YjQ2YTM2ZWUxOTI0OGMwMWY3MmI2NDVmNDRjZWYyZTJjIn0sImNsYWltIjp7IkB0eXBlIjoiUGVyc29uIiwiQGNvbnRleHQiOiJodHRwOi8vc2NoZW1hLm9yZyIsImltYWdlIjpbeyJAdHlwZSI6IkltYWdlT2JqZWN0IiwibmFtZSI6ImF2YXRhciIsImNvbnRlbnRVcmwiOiJodHRwczovL3d3dy5kcm9wYm94LmNvbS9zL2oxaDBrdHMwbTdhYWRpcC9hdmF0YXItMD9kbD0xIn1dLCJnaXZlbk5hbWUiOiIiLCJmYW1pbHlOYW1lIjoiIiwiZGVzY3JpcHRpb24iOiIiLCJhY2NvdW50IjpbeyJAdHlwZSI6IkFjY291bnQiLCJwbGFjZWhvbGRlciI6ZmFsc2UsInNlcnZpY2UiOiJoYWNrZXJOZXdzIiwiaWRlbnRpZmllciI6Inl1a2FubCIsInByb29mVHlwZSI6Imh0dHAiLCJwcm9vZlVybCI6Imh0dHBzOi8vbmV3cy55Y29tYmluYXRvci5jb20vdXNlcj9pZD15dWthbmwifSx7IkB0eXBlIjoiQWNjb3VudCIsInBsYWNlaG9sZGVyIjpmYWxzZSwic2VydmljZSI6ImdpdGh1YiIsImlkZW50aWZpZXIiOiJ5a25sIiwicHJvb2ZUeXBlIjoiaHR0cCIsInByb29mVXJsIjoiaHR0cHM6Ly9naXN0LmdpdGh1Yi5jb20veWtubC8xZjcwMThiOThmNzE2ZjAxNWE2Y2Y0NGZkYTA4MDZkNyJ9LHsiQHR5cGUiOiJBY2NvdW50IiwicGxhY2Vob2xkZXIiOmZhbHNlLCJzZXJ2aWNlIjoidHdpdHRlciIsImlkZW50aWZpZXIiOiJ5dWthbmwiLCJwcm9vZlR5cGUiOiJodHRwIiwicHJvb2ZVcmwiOiJodHRwczovL3R3aXR0ZXIuY29tL3l1a2FuTC9zdGF0dXMvOTE2NzQwNzQ5MjM2MTAxMTIwIn1dLCJuYW1lIjoiS2VuIExpYW8iLCJhcHBzIjp7Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MCI6Imh0dHBzOi8vZ2FpYS5ibG9ja3N0YWNrLm9yZy9odWIvMUREVXFmS3RRZ1lOdDcyMnd1QjRaMmZQQzdhaU5HUWE1Ui8ifX19.UyQNZ02kBFHEovbwiGaS-VQd57w9kcwn1Nt3QbW3afEMArg1OndmeplB7lzjMuRCLAi-88lkpQLkFw7LwKZ31Q', 'decodedToken': { 'header': { 'typ': 'JWT', 'alg': 'ES256K' }, 'payload': { 'jti': 'c48f9448-a0fe-4b9e-9d6a-fc0938c8e270', 'iat': '2018-01-08T18:22:24.796Z', 'exp': '2019-01-08T18:22:24.796Z', 'subject': { 'publicKey': '02487a91cd966faecee2aef3fde372809b46a36ee19248c01f72b645f44cef2e2c' }, 'issuer': { 'publicKey': '02487a91cd966faecee2aef3fde372809b46a36ee19248c01f72b645f44cef2e2c' }, 'claim': { '@type': 'Person', '@context': 'http://schema.org', 'image': [{ '@type': 'ImageObject', 'name': 'avatar', 'contentUrl': 'https://www.dropbox.com/s/j1h0kts0m7aadip/avatar-0?dl=1' }], 'givenName': '', 'familyName': '', 'description': '', 'account': [{ '@type': 'Account', 'placeholder': false, 'service': 'hackerNews', 'identifier': 'yukanl', 'proofType': 'http', 'proofUrl': 'https://news.ycombinator.com/user?id=yukanl' }, { '@type': 'Account', 'placeholder': false, 'service': 'github', 'identifier': 'yknl', 'proofType': 'http', 'proofUrl': 'https://gist.github.com/yknl/1f7018b98f716f015a6cf44fda0806d7' }, { '@type': 'Account', 'placeholder': false, 'service': 'twitter', 'identifier': 'yukanl', 'proofType': 'http', 'proofUrl': 'https://twitter.com/yukanL/status/916740749236101120' }], 'name': 'Ken Liao', 'apps': { 'http://localhost:8080': 'https://gaia.blockstack.org/hub/1DDUqfKtQgYNt722wuB4Z2fPC7aiNGQa5R/' } } }, 'signature': 'UyQNZ02kBFHEovbwiGaS-VQd57w9kcwn1Nt3QbW3afEMArg1OndmeplB7lzjMuRCLAi-88lkpQLkFw7LwKZ31Q' } }]; /* eslint-enable */ _fetchMock2.default.get(profileUrl, profileContent); var fileUrl = 'https://gaia.blockstack.org/hub/1DDUqfKtQgYNt722wuB4Z2fPC7aiNGQa5R/file.json'; var fileContents = JSON.stringify({ key: 'value' }); _fetchMock2.default.get(fileUrl, fileContents); var options = { username: 'yukan.id', app: 'http://localhost:8080', decrypt: false }; getFileImpl(blockstack, path, options).then(function (file) { t.ok(file, 'Returns file content'); t.same(JSON.parse(file), JSON.parse(fileContents)); }); var optionsNameLookupUrl = { username: 'yukan.id', app: 'http://localhost:8080', zoneFileLookupURL: 'https://potato/v1/names', decrypt: false }; _fetchMock2.default.get('https://potato/v1/names/yukan.id', nameRecordContent); getFileImpl(blockstack, path, optionsNameLookupUrl).then(function (file) { t.ok(file, 'Returns file content'); t.same(JSON.parse(file), JSON.parse(fileContents)); }); var optionsNoApp = { username: 'yukan.id', decrypt: false }; getFileImpl(blockstack, path, optionsNoApp).then(function (file) { t.ok(file, 'Returns file content'); t.same(JSON.parse(file), JSON.parse(fileContents)); }); }); (0, _tape2.default)('encrypt & decrypt content', function (t) { t.plan(2); var privateKey = 'a5c61c6ca7b3e7e55edee68566aeab22e4da26baa285c7bd10e8d2218aa3b229'; var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:3000'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); blockstack.store.getSessionData().userData = { appPrivateKey: privateKey // manually set private key for testing };var content = 'yellowsubmarine'; var ciphertext = blockstack.encryptContent(content); t.ok(ciphertext); var deciphered = blockstack.decryptContent(ciphertext); t.equal(content, deciphered); }); (0, _tape2.default)('encrypt & decrypt content -- specify key', function (t) { t.plan(2); var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:3000'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); var privateKey = '896adae13a1bf88db0b2ec94339b62382ec6f34cd7e2ff8abae7ec271e05f9d8'; var publicKey = (0, _keys.getPublicKeyFromPrivate)(privateKey); var content = 'we-all-live-in-a-yellow-submarine'; var ciphertext = blockstack.encryptContent(content, { publicKey: publicKey }); t.ok(ciphertext); var deciphered = blockstack.decryptContent(ciphertext, { privateKey: privateKey }); t.equal(content, deciphered); }); (0, _tape2.default)('putFile unencrypted, not signed', function (t) { t.plan(1); var path = 'file.json'; var gaiaHubConfig = { address: '1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U', server: 'https://hub.blockstack.org', token: '', url_prefix: 'gaia.testblockstack.org/hub/' }; var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:3000'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); var fullReadUrl = 'https://gaia.testblockstack.org/hub/1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U/file.json'; var fileContent = { test: 'test' }; var getOrSetLocalGaiaHubConnection = _sinon2.default.stub().resolves(gaiaHubConfig); var uploadToGaiaHub = _sinon2.default.stub().resolves(fullReadUrl); // eslint-disable-line no-shadow var _proxyquire3 = (0, _proxyquire19.default)('../../../lib/storage', { './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection, uploadToGaiaHub: uploadToGaiaHub } }), putFileImpl = _proxyquire3.putFileImpl; var options = { encrypt: false }; putFileImpl(blockstack, path, fileContent, options).then(function (publicURL) { t.ok(publicURL, fullReadUrl); }); }); (0, _tape2.default)('putFile & getFile unencrypted, not signed, with contentType', function (t) { t.plan(3); var path = 'file.html'; var gaiaHubConfig = { address: '1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U', server: 'https://hub.blockstack.org', token: '', url_prefix: 'gaia.testblockstack.org/hub/' }; var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:3000'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); var fullReadUrl = 'https://gaia.testblockstack.org/hub/1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U/file.html'; var fileContent = '<!DOCTYPE html><html><head><title>Title</title></head><body>Blockstack</body></html>'; var getOrSetLocalGaiaHubConnection = _sinon2.default.stub().resolves(gaiaHubConfig); var uploadToGaiaHub = _sinon2.default.stub().resolves(fullReadUrl); // eslint-disable-line no-shadow var getFullReadUrl = _sinon2.default.stub().resolves(fullReadUrl); // eslint-disable-line no-shadow var _proxyquire4 = (0, _proxyquire19.default)('../../../lib/storage', { './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection, uploadToGaiaHub: uploadToGaiaHub } }), putFileImpl = _proxyquire4.putFileImpl; var _proxyquire5 = (0, _proxyquire19.default)('../../../lib/storage', { // eslint-disable-line no-shadow './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection, getFullReadUrl: getFullReadUrl } }), getFileImpl = _proxyquire5.getFileImpl; var config = { status: 200, body: fileContent, headers: { 'Content-Type': 'text/html' } }; _fetchMock2.default.get(fullReadUrl, config); var options = { encrypt: false, contentType: 'text/html' }; putFileImpl(blockstack, path, fileContent, options).then(function (publicURL) { t.ok(publicURL, fullReadUrl); }).then(function () { var decryptOptions = { decrypt: false }; getFileImpl(blockstack, path, decryptOptions).then(function (readContent) { t.equal(readContent, fileContent); t.ok(typeof readContent === 'string'); }); }); }); (0, _tape2.default)('putFile & getFile encrypted, not signed', function (t) { t.plan(2); var privateKey = 'a5c61c6ca7b3e7e55edee68566aeab22e4da26baa285c7bd10e8d2218aa3b229'; var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:3000'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); blockstack.store.getSessionData().userData = { appPrivateKey: privateKey // manually set private key for testing };var path = 'file.json'; var gaiaHubConfig = { address: '1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U', server: 'https://hub.blockstack.org', token: '', url_prefix: 'gaia.testblockstack.org/hub/' }; var fullReadUrl = 'https://gaia.testblockstack.org/hub/1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8A/file.json'; var fileContent = JSON.stringify({ test: 'test' }); var getOrSetLocalGaiaHubConnection = _sinon2.default.stub().resolves(gaiaHubConfig); var uploadToGaiaHub = _sinon2.default.stub().resolves(fullReadUrl); // eslint-disable-line no-shadow var getFullReadUrl = _sinon2.default.stub().resolves(fullReadUrl); // eslint-disable-line no-shadow var _proxyquire6 = (0, _proxyquire19.default)('../../../lib/storage', { './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection, uploadToGaiaHub: uploadToGaiaHub } }), putFileImpl = _proxyquire6.putFileImpl; var _proxyquire7 = (0, _proxyquire19.default)('../../../lib/storage', { // eslint-disable-line no-shadow './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection, getFullReadUrl: getFullReadUrl } }), getFileImpl = _proxyquire7.getFileImpl; _fetchMock2.default.get(fullReadUrl, (0, _storage.encryptContentImpl)(blockstack, fileContent)); var encryptOptions = { encrypt: true }; var decryptOptions = { decrypt: true // put and encrypt the file };putFileImpl(blockstack, path, fileContent, encryptOptions).then(function (publicURL) { t.ok(publicURL, fullReadUrl); }).then(function () { // read and decrypt the file getFileImpl(blockstack, path, decryptOptions).then(function (readContent) { t.equal(readContent, fileContent); // put back whatever was inside before }); }); }); (0, _tape2.default)('putFile encrypt/no-sign using specifying public key & getFile decrypt', function (t) { t.plan(2); var privateKey = 'a5c61c6ca7b3e7e55edee68566aeab22e4da26baa285c7bd10e8d2218aa3b229'; var publicKey = (0, _keys.getPublicKeyFromPrivate)(privateKey); var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:3000'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); blockstack.store.getSessionData().userData = { appPrivateKey: privateKey // manually set private key for testing };var path = 'file.json'; var gaiaHubConfig = { address: '1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U', server: 'https://hub.blockstack.org', token: '', url_prefix: 'gaia.testblockstack.org/hub/' }; var fullReadUrl = 'https://gaia.testblockstack.org/hub/1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8A/file.json'; var fileContent = JSON.stringify({ test: 'test' }); var getOrSetLocalGaiaHubConnection = _sinon2.default.stub().resolves(gaiaHubConfig); var uploadToGaiaHub = _sinon2.default.stub().resolves(fullReadUrl); // eslint-disable-line no-shadow var getFullReadUrl = _sinon2.default.stub().resolves(fullReadUrl); // eslint-disable-line no-shadow var _proxyquire8 = (0, _proxyquire19.default)('../../../lib/storage', { './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection, uploadToGaiaHub: uploadToGaiaHub } }), putFileImpl = _proxyquire8.putFileImpl; var _proxyquire9 = (0, _proxyquire19.default)('../../../lib/storage', { // eslint-disable-line no-shadow './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection, getFullReadUrl: getFullReadUrl } }), getFileImpl = _proxyquire9.getFileImpl; _fetchMock2.default.get(fullReadUrl, (0, _storage.encryptContentImpl)(blockstack, fileContent)); var encryptOptions = { encrypt: publicKey }; var decryptOptions = { decrypt: true // put and encrypt the file };putFileImpl(blockstack, path, fileContent, encryptOptions).then(function (publicURL) { t.ok(publicURL, fullReadUrl); }).then(function () { // read and decrypt the file getFileImpl(blockstack, path, decryptOptions).then(function (readContent) { t.equal(readContent, fileContent); }); }); }); (0, _tape2.default)('putFile & getFile encrypted, signed', function (t) { var privateKey = 'a5c61c6ca7b3e7e55edee68566aeab22e4da26baa285c7bd10e8d2218aa3b229'; var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:3000'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); blockstack.store.getSessionData().userData = { appPrivateKey: privateKey // manually set private key for testing };var gaiaHubConfig = { address: '1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U', server: 'https://hub.blockstack.org', token: '', url_prefix: 'gaia.testblockstack2.org/hub/' }; var readPrefix = 'https://gaia.testblockstack8.org/hub/1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U'; var fullReadUrl = readPrefix + '/file.json'; var urlBadPK = readPrefix + '/badPK.json'; var urlBadSig = readPrefix + '/badSig.json'; var fileContent = JSON.stringify({ test: 'test' }); var badPK = '0288580b020800f421d746f738b221d384f098e911b81939d8c94df89e74cba776'; var getOrSetLocalGaiaHubConnection = _sinon2.default.stub().resolves(gaiaHubConfig); var putFiledContents = ''; var uploadToGaiaHub = _sinon2.default.stub().callsFake( // eslint-disable-line no-shadow function (fname, contents) { putFiledContents = contents; return Promise.resolve(readPrefix + '/' + fname); }); var getFullReadUrl = _sinon2.default.stub().callsFake( // eslint-disable-line no-shadow function (path) { return Promise.resolve(readPrefix + '/' + path); }); var lookupProfile = _sinon2.default.stub().callsFake(function (username) { t.equal(username, 'applejacks.id', 'Unexpected user lookup request'); return Promise.resolve({ apps: { origin: readPrefix } }); }); var _proxyquire10 = (0, _proxyquire19.default)('../../../lib/storage', { './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection, uploadToGaiaHub: uploadToGaiaHub } }), putFileImpl = _proxyquire10.putFileImpl; var _proxyquire11 = (0, _proxyquire19.default)('../../../lib/storage', { // eslint-disable-line no-shadow './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection, getFullReadUrl: getFullReadUrl }, '../profiles': { lookupProfile: lookupProfile } }), getFileImpl = _proxyquire11.getFileImpl; var encryptOptions = { encrypt: true, sign: true }; var decryptOptions = { decrypt: true, verify: true // put and encrypt the file };putFileImpl(blockstack, 'doesnt-matter.json', fileContent, encryptOptions).then(function (publicURL) { t.ok(publicURL, fullReadUrl); _fetchMock2.default.get(fullReadUrl, putFiledContents); var contentsObj = JSON.parse(putFiledContents); _fetchMock2.default.get(urlBadPK, JSON.stringify({ signature: contentsObj.signature, publicKey: badPK, cipherText: contentsObj.cipherText })); _fetchMock2.default.get(urlBadSig, JSON.stringify({ signature: contentsObj.signature, publicKey: contentsObj.publicKey, cipherText: 'potato potato potato' })); }).then(function () { return getFileImpl(blockstack, 'file.json', decryptOptions).then(function (readContent) { t.equal(readContent, fileContent); }); }).then(function () { return getFileImpl(blockstack, 'file.json', { decrypt: true, verify: true, username: 'applejacks.id', app: 'origin' }).then(function (readContent) { t.equal(readContent, fileContent); }); }).then(function () { return getFileImpl(blockstack, 'badPK.json', decryptOptions).then(function () { return t.true(false, 'Should not successfully decrypt file'); }).catch(function (err) { return t.ok(err.message.indexOf('doesn\'t match gaia address') >= 0, 'Should fail with complaint about mismatch PK: ' + err.message); }); }).then(function () { return getFileImpl(blockstack, 'badPK.json', { decrypt: true, verify: true, username: 'applejacks.id', app: 'origin' }).then(function () { return t.true(false, 'Should not successfully decrypt file'); }).catch(function (err) { return t.ok(err.message.indexOf('doesn\'t match gaia address') >= 0, 'Should fail with complaint about mismatch PK: ' + err.message); }); }).then(function () { return getFileImpl(blockstack, 'badSig.json', decryptOptions).then(function () { return t.true(false, 'Should not successfully decrypt file'); }).catch(function (err) { return t.ok(err.message.indexOf('do not match ECDSA') >= 0, 'Should fail with complaint about bad signature'); }); }).catch(function (err) { return console.log(err.stack); }).then(function () { t.end(); }); }); (0, _tape2.default)('putFile & getFile unencrypted, signed', function (t) { var privateKey = 'a5c61c6ca7b3e7e55edee68566aeab22e4da26baa285c7bd10e8d2218aa3b229'; var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:3000'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); blockstack.store.getSessionData().userData = { appPrivateKey: privateKey // manually set private key for testing };var gaiaHubConfig = { address: '1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U', server: 'https://hub.blockstack.org', token: '', url_prefix: 'gaia.testblockstack2.org/hub/' }; var readPrefix = 'https://gaia.testblockstack4.org/hub/1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U'; var goodPath = 'file.json'; var badPKPath = 'badPK.json'; var badSigPath = 'badSig.json'; var noSigPath = 'noSig.json'; var fileContent = JSON.stringify({ test: 'test' }); var badPK = '0288580b020800f421d746f738b221d384f098e911b81939d8c94df89e74cba776'; var getOrSetLocalGaiaHubConnection = _sinon2.default.stub().resolves(gaiaHubConfig); var putFiledContents = []; var pathToReadUrl = function pathToReadUrl(fname) { return readPrefix + '/' + fname; }; var uploadToGaiaHub = _sinon2.default.stub().callsFake( // eslint-disable-line no-shadow function (fname, contents) { putFiledContents.push([fname, contents]); if (!fname.endsWith('.sig')) { t.equal(contents, fileContent); } return Promise.resolve(pathToReadUrl(fname)); }); var getFullReadUrl = _sinon2.default.stub().callsFake( // eslint-disable-line no-shadow function (path) { return Promise.resolve(pathToReadUrl(path)); }); var lookupProfile = _sinon2.default.stub().callsFake(function (username) { t.equal(username, 'applejacks.id', 'Unexpected user lookup request'); return Promise.resolve({ apps: { origin: readPrefix } }); }); var _proxyquire12 = (0, _proxyquire19.default)('../../../lib/storage', { './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection, uploadToGaiaHub: uploadToGaiaHub } }), putFileImpl = _proxyquire12.putFileImpl; var _proxyquire13 = (0, _proxyquire19.default)('../../../lib/storage', { // eslint-disable-line no-shadow './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection, getFullReadUrl: getFullReadUrl }, '../profiles': { lookupProfile: lookupProfile } }), getFileImpl = _proxyquire13.getFileImpl; var encryptOptions = { encrypt: false, sign: true }; var decryptOptions = { decrypt: false, verify: true }; var multiplayerDecryptOptions = { username: 'applejacks.id', decrypt: false, verify: true, app: 'origin' // put and encrypt the file };putFileImpl(blockstack, goodPath, fileContent, encryptOptions).then(function (publicURL) { t.equal(publicURL, pathToReadUrl(goodPath)); t.equal(putFiledContents.length, 2); var sigContents = ''; // good path mocks putFiledContents.forEach(function (_ref) { var _ref2 = _slicedToArray(_ref, 2), path = _ref2[0], contents = _ref2[1]; _fetchMock2.default.get(pathToReadUrl(path), contents); if (path.endsWith('.sig')) { sigContents = contents; } }); var sigObject = JSON.parse(sigContents); // bad sig mocks _fetchMock2.default.get(pathToReadUrl(badSigPath), 'hello world, this is inauthentic.'); _fetchMock2.default.get(pathToReadUrl(badSigPath + '.sig'), sigContents); // no sig mocks _fetchMock2.default.get(pathToReadUrl(noSigPath), 'hello world, this is inauthentic.'); _fetchMock2.default.get(pathToReadUrl(noSigPath + '.sig'), { status: 404, body: 'nopers.' }); // bad pk mocks _fetchMock2.default.get(pathToReadUrl(badPKPath), fileContent); _fetchMock2.default.get(pathToReadUrl(badPKPath + '.sig'), JSON.stringify({ signature: sigObject.signature, publicKey: badPK })); }).then(function () { return getFileImpl(blockstack, goodPath, decryptOptions).then(function (readContent) { t.equal(readContent, fileContent, 'should read the file'); }); }).then(function () { return getFileImpl(blockstack, badSigPath, decryptOptions).then(function () { return t.fail('Should have failed to read file.'); }).catch(function (err) { return t.ok(err.message.indexOf('do not match ECDSA') >= 0, 'Should fail with complaint about bad signature'); }); }).then(function () { return getFileImpl(blockstack, noSigPath, decryptOptions).then(function () { return t.fail('Should have failed to read file.'); }).catch(function (err) { return t.ok(err.message.indexOf('obtain signature for file') >= 0, 'Should fail with complaint about missing signature'); }); }).then(function () { return getFileImpl(blockstack, badPKPath, decryptOptions).then(function () { return t.fail('Should have failed to read file.'); }).catch(function (err) { return t.ok(err.message.indexOf('match gaia address') >= 0, 'Should fail with complaint about matching addresses'); }); }).then(function () { return getFileImpl(blockstack, goodPath, multiplayerDecryptOptions).then(function (readContent) { t.equal(readContent, fileContent, 'should read the file'); }); }).then(function () { return getFileImpl(blockstack, badSigPath, multiplayerDecryptOptions).then(function () { return t.fail('Should have failed to read file.'); }).catch(function (err) { return t.ok(err.message.indexOf('do not match ECDSA') >= 0, 'Should fail with complaint about bad signature'); }); }).then(function () { return getFileImpl(blockstack, noSigPath, multiplayerDecryptOptions).then(function () { return t.fail('Should have failed to read file.'); }).catch(function (err) { return t.ok(err.message.indexOf('obtain signature for file') >= 0, 'Should fail with complaint about missing signature'); }); }).then(function () { return getFileImpl(blockstack, badPKPath, multiplayerDecryptOptions).then(function () { return t.fail('Should have failed to read file.'); }).catch(function (err) { return t.ok(err.message.indexOf('match gaia address') >= 0, 'Should fail with complaint about matching addresses'); }); }).catch(function (err) { console.log(err.stack); t.fail('Unexpected error!'); }).then(function () { t.end(); }); }); (0, _tape2.default)('promises reject', function (t) { t.plan(2); var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:3000'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); var path = 'file.json'; var fullReadUrl = 'https://hub.testblockstack.org/store/1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U/file.json'; var gaiaHubConfig = { address: '1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U', server: 'https://hub.testblockstack.org', token: '', url_prefix: 'gaia.testblockstack.org/hub/' }; var getOrSetLocalGaiaHubConnection = _sinon2.default.stub().resolves(gaiaHubConfig); var setLocalGaiaHubConnection = _sinon2.default.stub().resolves(gaiaHubConfig); var _proxyquire14 = (0, _proxyquire19.default)('../../../lib/storage', { './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection, setLocalGaiaHubConnection: setLocalGaiaHubConnection } }), putFileImpl = _proxyquire14.putFileImpl; _fetchMock2.default.post('' + fullReadUrl, { status: 404, body: 'Not found.' }); putFileImpl(blockstack, path, 'hello world', { encrypt: false }).then(function () { return t.ok(false, 'Should not have returned'); }).catch(function () { return t.ok(true, 'Should have rejected promise'); }); var gaiaHubUrl = 'https://potato.hub.farm'; var signer = '01010101'; _fetchMock2.default.get('https://potato.hub.farm/hub_info', { status: 421, body: 'Nope.' }); (0, _hub.connectToGaiaHub)(gaiaHubUrl, signer).then(function () { return t.ok(false, 'Should not have returned'); }).catch(function () { return t.ok(true, 'Should have rejected promise'); }); }); (0, _tape2.default)('putFile gets a new gaia config and tries again', function (t) { t.plan(3); var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:3000'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); var path = 'file.json'; var fullWriteUrl = 'https://hub.testblockstack.org/store/1NZNxhoxobqwsNvTb16pdeiqvFvce3Yabc/file.json'; var invalidHubConfig = { address: '1NZNxhoxobqwsNvTb16pdeiqvFvce3Yabc', server: 'https://hub.testblockstack.org', token: '', url_prefix: 'gaia.testblockstack.org/hub/' }; var validHubConfig = Object.assign({}, invalidHubConfig, { token: 'valid' }); var getOrSetLocalGaiaHubConnection = _sinon2.default.stub().resolves(invalidHubConfig); var setLocalGaiaHubConnection = _sinon2.default.stub().resolves(validHubConfig); var _proxyquire15 = (0, _proxyquire19.default)('../../../lib/storage', { './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection, setLocalGaiaHubConnection: setLocalGaiaHubConnection } }), putFileImpl = _proxyquire15.putFileImpl; _fetchMock2.default.post(fullWriteUrl, function (url, _ref3) { var headers = _ref3.headers; console.log(url, headers); if (headers.Authorization === 'bearer ') { t.ok(true, 'tries with invalid token'); return 401; } else if (headers.Authorization === 'bearer valid') { t.ok(true, 'Tries with valid hub config'); return { status: 200, body: JSON.stringify({ publicURL: 'readURL' }) }; } return 401; }); putFileImpl(blockstack, path, 'hello world', { encrypt: false }).then(function () { return t.ok(true, 'Request should pass'); }); }); (0, _tape2.default)('fetch404null', function (t) { t.plan(2); var config = { address: '19MoWG8u88L6t766j7Vne21Mg4wHsCQ7vk', url_prefix: 'gaia.testblockstack.org/hub/', token: '', server: 'hub.testblockstack.org' }; var privateKey = 'a5c61c6ca7b3e7e55edee68566aeab22e4da26baa285c7bd10e8d2218aa3b229'; var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:3000'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); blockstack.store.getSessionData().userData = { appPrivateKey: privateKey, gaiaHubConfig: config // manually set for testing };_fetchMock2.default.get('' + config.url_prefix + config.address + '/foo.json', { status: 404 }); var optionsNoDecrypt = { decrypt: false }; (0, _storage.getFileImpl)(blockstack, 'foo.json', optionsNoDecrypt).then(function (x) { return t.equal(x, null, '404 should return null'); }); var optionsDecrypt = { decrypt: true }; (0, _storage.getFileImpl)(blockstack, 'foo.json', optionsDecrypt).then(function (x) { return t.equal(x, null, '404 should return null, even if we try to decrypt'); }); }); (0, _tape2.default)('uploadToGaiaHub', function (t) { t.plan(2); var config = { address: '19MoWG8u88L6t766j7Vne21Mg4wHsCQ7vk', url_prefix: 'gaia.testblockstack.org', token: '', server: 'hub.testblockstack.org' }; _fetchMock2.default.post(config.server + '/store/' + config.address + '/foo.json', JSON.stringify({ publicURL: config.url_prefix + '/' + config.address + '/foo.json' })); (0, _hub.uploadToGaiaHub)('foo.json', 'foo the bar', config).then(function (url) { t.ok(url, 'URL returned'); t.equal(url, config.url_prefix + '/' + config.address + '/foo.json'); }); }); (0, _tape2.default)('getFullReadUrl', function (t) { t.plan(1); var config = { address: '19MoWG8u88L6t766j7Vne21Mg4wHsCQ7vk', url_prefix: 'gaia.testblockstack.org', token: '', server: 'hub.testblockstack.org' }; var outUrl = (0, _hub.getFullReadUrl)('foo.json', config); t.equal('' + config.url_prefix + config.address + '/foo.json', outUrl); }); (0, _tape2.default)('connectToGaiaHub', function (t) { t.plan(6); var hubServer = 'hub.testblockstack.org'; var hubInfo = { read_url_prefix: 'gaia.testblockstack.org', challenge_text: 'please-sign', latest_auth_version: 'v1' }; var privateKey = 'a5c61c6ca7b3e7e55edee68566aeab22e4da26baa285c7bd10e8d2218aa3b229'; var address = '1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U'; var publicKey = '027d28f9951ce46538951e3697c62588a87f1f1f295de4a14fdd4c780fc52cfe69'; _fetchMock2.default.get(hubServer + '/hub_info', JSON.stringify(hubInfo)); var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:3000'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); blockstack.store.getSessionData().userData = { appPrivateKey: privateKey // manually set for testing };(0, _hub.connectToGaiaHub)(hubServer, privateKey).then(function (config) { t.ok(config, 'Config returned by connectToGaiaHub()'); t.equal(hubInfo.read_url_prefix, config.url_prefix); t.equal(address, config.address); t.equal(hubServer, config.server); var jsonTokenPart = config.token.slice('v1:'.length); var verified = new _jsontokens.TokenVerifier('ES256K', publicKey).verify(jsonTokenPart); t.ok(verified, 'Verified token'); t.equal(hubServer, (0, _jsontokens.decodeToken)(jsonTokenPart).payload.hubUrl, 'Intended hubUrl'); }); }); (0, _tape2.default)('connectToGaiaHub with an association token', function (t) { t.plan(7); var hubServer = 'hub.testblockstack.org'; var hubInfo = { read_url_prefix: 'gaia.testblockstack.org', challenge_text: 'please-sign', latest_auth_version: 'v1' }; var privateKey = 'a5c61c6ca7b3e7e55edee68566aeab22e4da26baa285c7bd10e8d2218aa3b229'; var address = '1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U'; var publicKey = '027d28f9951ce46538951e3697c62588a87f1f1f295de4a14fdd4c780fc52cfe69'; var identityPrivateKey = '4dea04fe440d760664d96f1fd219e7a73324fc8faa28c7babd1a7813d05970aa01'; var identityPublicKey = '0234f3c7aec9fe13190aede94d1eaa0a7d2b48d18fd86b9651fc3996a5f467fc73'; var FOUR_MONTH_SECONDS = 60 * 60 * 24 * 31 * 4; var salt = '00000000000000000000000000000'; var associationTokenClaim = { childToAssociate: publicKey, iss: identityPublicKey, exp: FOUR_MONTH_SECONDS + new Date() / 1000, salt: salt }; var gaiaAssociationToken = new _jsontokens.TokenSigner('ES256K', identityPrivateKey).sign(associationTokenClaim); _fetchMock2.default.get(hubServer + '/hub_info', JSON.stringify(hubInfo)); var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:3000'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); blockstack.store.getSessionData().userData = { appPrivateKey: privateKey // manually set for testing };(0, _hub.connectToGaiaHub)(hubServer, privateKey, gaiaAssociationToken).then(function (config) { t.ok(config, 'Config returned by connectToGaiaHub()'); t.equal(hubInfo.read_url_prefix, config.url_prefix); t.equal(address, config.address); t.equal(hubServer, config.server); var jsonTokenPart = config.token.slice('v1:'.length); var verified = new _jsontokens.TokenVerifier('ES256K', publicKey).verify(jsonTokenPart); t.ok(verified, 'Verified token'); t.equal(hubServer, (0, _jsontokens.decodeToken)(jsonTokenPart).payload.hubUrl, 'Intended hubUrl'); t.equal(gaiaAssociationToken, (0, _jsontokens.decodeToken)(jsonTokenPart).payload.associationToken, 'Intended association token'); }); }); (0, _tape2.default)('getBucketUrl', function (t) { t.plan(2); var hubServer = 'hub2.testblockstack.org'; var hubInfo = { read_url_prefix: 'https://gaia.testblockstack.org/hub/', challenge_text: 'please-sign', latest_auth_version: 'v1' }; var privateKey = 'a5c61c6ca7b3e7e55edee68566aeab22e4da26baa285c7bd10e8d2218aa3b229'; var address = '1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U'; _fetchMock2.default.get(hubServer + '/hub_info', JSON.stringify(hubInfo)); (0, _hub.getBucketUrl)(hubServer, privateKey).then(function (bucketUrl) { t.ok(bucketUrl, 'App index file URL returned by getBucketUrl'); t.equal(bucketUrl, '' + hubInfo.read_url_prefix + address + '/'); }); }); (0, _tape2.default)('getUserAppFileUrl', function (t) { t.plan(2); var path = 'file.json'; var name = 'test.id'; var appOrigin = 'testblockstack.org'; var profile = { apps: { 'testblockstack.org': 'https://gaia.testblockstack.org/hub/1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U/' } }; var fileUrl = 'https://gaia.testblockstack.org/hub/1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U/file.json'; var lookupProfile = _sinon2.default.stub().resolves(profile); var _proxyquire16 = (0, _proxyquire19.default)('../../../lib/storage', { '../profiles': { lookupProfile: lookupProfile } }), getUserAppFileUrl = _proxyquire16.getUserAppFileUrl; getUserAppFileUrl(path, name, appOrigin).then(function (url) { t.ok(url, 'Returns user app file url'); t.equals(url, fileUrl); }); }); (0, _tape2.default)('listFiles', function (t) { t.plan(3); var path = 'file.json'; var gaiaHubConfig = { address: '1NZNxhoxobqwsNvTb16pdeiqvFvce3Yg8U', server: 'https://hub.blockstack.org', token: '', url_prefix: 'gaia.testblockstack.org/hub/' }; var privateKey = 'a5c61c6ca7b3e7e55edee68566aeab22e4da26baa285c7bd10e8d2218aa3b229'; var appConfig = new _lib.AppConfig(['store_write'], 'http://localhost:3000'); var blockstack = new _lib.UserSession({ appConfig: appConfig }); blockstack.store.getSessionData().userData = { appPrivateKey: privateKey, gaiaHubConfig: gaiaHubConfig // manually set for testing };var callCount = 0; _fetchMock2.default.post(gaiaHubConfig.server + '/list-files/' + gaiaHubConfig.address, function () { callCount += 1; if (callCount === 1) { return { entries: [path], page: callCount }; } else if (callCount === 2) { return { entries: [], page: callCount }; } else { throw new Error('Called too many times'); } }); var getOrSetLocalGaiaHubConnection = _sinon2.default.stub().resolves(gaiaHubConfig); var _proxyquire17 = (0, _proxyquire19.default)('../../../lib/storage', { './hub': { getOrSetLocalGaiaHubConnection: getOrSetLocalGaiaHubConnection } }), listFilesImpl = _proxyquire17.listFilesImpl; var files = []; listFilesImpl(blockstack, function (name) { files.push(name); return true; }).then(function (count) { t.equal(files.length, 1, 'Got one file back'); t.equal(files[0], 'file.json', 'Got the right file back'); t.equal(count, 1, 'Count matches number of files'); }); }); }