blockstack
Version:
The Blockstack Javascript library for authentication, identity, and storage.
392 lines (297 loc) • 16.5 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.runAuthTests = runAuthTests;
var _tape = require('tape-promise/tape');
var _tape2 = _interopRequireDefault(_tape);
var _jsontokens = require('jsontokens');
var _fetchMock = require('fetch-mock');
var _fetchMock2 = _interopRequireDefault(_fetchMock);
var _lib = require('../../../lib');
var _authConstants = require('../../../lib/auth/authConstants');
var _sampleData = require('./sampleData');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
// import test from 'tape'
global.window = {};
function runAuthTests() {
var privateKey = 'a5c61c6ca7b3e7e55edee68566aeab22e4da26baa285c7bd10e8d2218aa3b229';
var publicKey = '027d28f9951ce46538951e3697c62588a87f1f1f295de4a14fdd4c780fc52cfe69';
var nameLookupURL = 'https://explorer-api.appartisan.com/get_name_blockchain_record/';
(0, _tape2.default)('makeAuthRequest && verifyAuthRequest', function (t) {
t.plan(15);
global.window.location = {
origin: 'http://localhost:3000',
hostname: 'localhost',
host: 'localhost:3000',
href: 'http://localhost:3000/signin'
};
var authRequest = (0, _lib.makeAuthRequest)(privateKey);
t.ok(authRequest, 'auth request should have been created');
console.log(authRequest);
var decodedToken = (0, _jsontokens.decodeToken)(authRequest);
t.ok(decodedToken, 'auth request token should have been decoded');
console.log(JSON.stringify(decodedToken, null, 2));
var address = (0, _lib.publicKeyToAddress)(publicKey);
var referenceDID = (0, _lib.makeDIDFromAddress)(address);
var origin = 'http://localhost:3000';
t.equal(decodedToken.payload.iss, referenceDID, 'auth request issuer should include the public key');
t.equal(decodedToken.payload.domain_name, origin, 'auth request domain_name should be origin');
t.equal(decodedToken.payload.redirect_uri, 'http://localhost:3000/', 'auth request redirects to correct uri');
t.equal(decodedToken.payload.manifest_uri, 'http://localhost:3000/manifest.json', 'auth request manifest is correct uri');
t.equal(JSON.stringify(decodedToken.payload.scopes), '["store_write"]', 'auth request scopes should be store_write');
(0, _lib.verifyAuthRequest)(authRequest).then(function (verified) {
t.true(verified, 'auth request should be verified');
});
t.true((0, _lib.isExpirationDateValid)(authRequest), 'Expiration date should be valid');
t.true((0, _lib.isIssuanceDateValid)(authRequest), 'Issuance date should be valid');
t.true((0, _lib.doSignaturesMatchPublicKeys)(authRequest), 'Signatures should match the public keys');
t.true((0, _lib.doPublicKeysMatchIssuer)(authRequest), 'Public keys should match the issuer');
t.true((0, _lib.isManifestUriValid)(authRequest), 'Manifest URI should be on the app origin');
t.true((0, _lib.isRedirectUriValid)(authRequest), 'Redirect URL should be to app origin');
var manifiestUrl = 'http://localhost:3000/manifest.json';
var manifest = {
name: 'App',
start_url: 'http://localhost:3000/',
description: 'A simple todo app build on blockstack',
icons: [{
src: 'http://localhost:3000/logo.png',
sizes: '400x400',
type: 'image/png'
}]
};
var manifestString = JSON.stringify(manifest);
_fetchMock2.default.get(manifiestUrl, manifestString);
(0, _lib.verifyAuthRequestAndLoadManifest)(authRequest).then(function (appManifest) {
console.log(appManifest);
t.equal(appManifest.name, 'App', 'should fetch manifest for valid auth request');
});
});
(0, _tape2.default)('make and verify auth request with extraParams', function (t) {
t.plan(4);
global.window.location = {
origin: 'http://localhost:3000',
hostname: 'localhost',
host: 'localhost:3000',
href: 'http://localhost:3000/signin'
};
var authRequest = (0, _lib.makeAuthRequest)(privateKey, undefined, undefined, undefined, undefined, undefined, { myCustomParam: 'asdf' });
t.ok(authRequest, 'auth request should have been created');
var decodedToken = (0, _jsontokens.decodeToken)(authRequest);
t.ok(decodedToken, 'auth request token should have been decoded');
t.equal(decodedToken.payload.myCustomParam, 'asdf', 'custom param from extraParams is included in payload');
(0, _lib.verifyAuthRequest)(authRequest).then(function (verified) {
t.true(verified, 'auth request should be verified');
});
});
(0, _tape2.default)('invalid auth request - signature not verified', function (t) {
t.plan(3);
var authRequest = (0, _lib.makeAuthRequest)(privateKey, 'http://localhost:3000');
var invalidAuthRequest = authRequest.substring(0, authRequest.length - 1);
t.equal((0, _lib.doSignaturesMatchPublicKeys)(invalidAuthRequest), false, 'Signatures should not match the public keys');
(0, _lib.verifyAuthRequest)(invalidAuthRequest).then(function (verified) {
t.equal(verified, false, 'auth request should be unverified');
});
(0, _lib.verifyAuthRequestAndLoadManifest)(invalidAuthRequest).then(function () {
// no op
}, function () {
t.pass('invalid auth request rejected');
});
});
(0, _tape2.default)('invalid auth request - invalid redirect uri', function (t) {
t.plan(3);
var invalidAuthRequest = (0, _lib.makeAuthRequest)(privateKey, 'https://example.com');
t.equal((0, _lib.isRedirectUriValid)(invalidAuthRequest), false, 'Redirect URI should be invalid since it does not match origin');
(0, _lib.verifyAuthRequest)(invalidAuthRequest).then(function (verified) {
t.equal(verified, false, 'auth request should be unverified');
});
(0, _lib.verifyAuthRequestAndLoadManifest)(invalidAuthRequest).then(function () {
// no op
}, function () {
t.pass('invalid auth request rejected');
});
});
(0, _tape2.default)('invalid auth request - invalid manifest uri', function (t) {
t.plan(2);
var invalidAuthRequest = (0, _lib.makeAuthRequest)(privateKey, 'http://localhost:3000', 'https://example.com/manifest.json');
t.equal((0, _lib.isManifestUriValid)(invalidAuthRequest), false, 'Manifest URI should be invalid since it does not match origin');
(0, _lib.verifyAuthRequest)(invalidAuthRequest).then(function (verified) {
t.equal(verified, false, 'auth request should be unverified');
});
});
(0, _tape2.default)('makeAuthResponse && verifyAuthResponse', function (t) {
t.plan(11);
var authResponse = (0, _lib.makeAuthResponse)(privateKey, _sampleData.sampleProfiles.ryan);
t.ok(authResponse, 'auth response should have been created');
var decodedToken = (0, _jsontokens.decodeToken)(authResponse);
t.ok(decodedToken, 'auth response should have been decoded');
// console.log(JSON.stringify(decodedToken, null, 2))
var address = (0, _lib.publicKeyToAddress)(publicKey);
var referenceDID = (0, _lib.makeDIDFromAddress)(address);
t.equal(decodedToken.payload.iss, referenceDID, 'auth response issuer should include the public key');
t.equal(JSON.stringify(decodedToken.payload.profile), JSON.stringify(_sampleData.sampleProfiles.ryan), 'auth response profile should equal the reference value');
t.equal(decodedToken.payload.username, null, 'auth response username should be null');
// const verified = verifyAuthResponse(authResponse)
// t.equal(verified, true, 'auth response should be verified')
(0, _lib.verifyAuthResponse)(authResponse, nameLookupURL).then(function (verifiedResult) {
t.true(verifiedResult, 'auth response should be verified');
});
t.true((0, _lib.isExpirationDateValid)(authResponse), 'Expiration date should be valid');
t.true((0, _lib.isIssuanceDateValid)(authResponse), 'Issuance date should be valid');
t.true((0, _lib.doSignaturesMatchPublicKeys)(authResponse), 'Signatures should match the public keys');
t.true((0, _lib.doPublicKeysMatchIssuer)(authResponse), 'Public keys should match the issuer');
(0, _lib.doPublicKeysMatchUsername)(authResponse, nameLookupURL).then(function (verifiedResult) {
t.true(verifiedResult, 'Public keys should match the username');
});
});
(0, _tape2.default)('auth response with username', function (t) {
t.plan(2);
var url = nameLookupURL + 'ryan.id';
// console.log(`URL: ${url}`)
_fetchMock2.default.get(url, _sampleData.sampleNameRecords.ryan);
var authResponse = (0, _lib.makeAuthResponse)(privateKey, _sampleData.sampleProfiles.ryan, 'ryan.id');
// console.log(decodeToken(authResponse))
(0, _lib.doPublicKeysMatchUsername)(authResponse, nameLookupURL).then(function (verified) {
t.true(verified, 'Public keys should match the username');
});
(0, _lib.verifyAuthResponse)(authResponse, nameLookupURL).then(function (verifiedResult) {
t.true(verifiedResult, 'auth response should be verified');
});
});
(0, _tape2.default)('auth response with invalid private key', function (t) {
t.plan(2);
var url = nameLookupURL + 'ryan.id';
// console.log(`URL: ${url}`)
_fetchMock2.default.get(url, _sampleData.sampleNameRecords.ryan);
var appPrivateKey = (0, _lib.makeECPrivateKey)();
var transitPrivateKey = (0, _lib.makeECPrivateKey)();
var transitPublicKey = (0, _lib.getPublicKeyFromPrivate)(transitPrivateKey);
var badTransitPrivateKey = (0, _lib.makeECPrivateKey)();
var metadata = {};
var authResponse = (0, _lib.makeAuthResponse)(privateKey, _sampleData.sampleProfiles.ryan, 'ryan.id', metadata, undefined, appPrivateKey, undefined, transitPublicKey);
// console.log(decodeToken(authResponse))
global.window = Object.assign({}, global.window, {
location: {
search: 'authResponse=' + authResponse
}
});
global.location = global.window.location;
global.localStorage.setItem(_authConstants.BLOCKSTACK_APP_PRIVATE_KEY_LABEL, badTransitPrivateKey);
(0, _lib.handlePendingSignIn)(nameLookupURL).then(function () {
t.fail('Should have failed to decrypt auth response');
}).catch(function (err) {
console.log(err);
t.pass('Should fail to decrypt auth response');
}).then(function () {
global.window.localStorage.setItem(_authConstants.BLOCKSTACK_APP_PRIVATE_KEY_LABEL, transitPrivateKey);
return (0, _lib.handlePendingSignIn)(nameLookupURL);
}).then(function () {
t.pass('Should correctly sign in with correct transit key');
}).catch(function (err) {
console.log(err.stack);
t.fail('Should not error');
});
});
(0, _tape2.default)('signUserOut with redirect', function (t) {
t.plan(1);
var startURL = 'https://example.com';
var redirectURL = 'https://example.com/redirect';
window.location = startURL;
(0, _lib.signUserOut)(redirectURL);
t.equal(redirectURL, window.location, 'User should be redirected to the redirectURL');
});
(0, _tape2.default)('signUserOut without redirect', function (t) {
t.plan(1);
var startURL = 'https://example.com';
window.location = startURL;
(0, _lib.signUserOut)();
t.equal(startURL, window.location, 'User should not be redirected');
});
(0, _tape2.default)('handlePendingSignIn with authResponseToken', function (t) {
t.plan(1);
var url = nameLookupURL + 'ryan.id';
_fetchMock2.default.get(url, _sampleData.sampleNameRecords.ryan);
var appPrivateKey = (0, _lib.makeECPrivateKey)();
var transitPrivateKey = (0, _lib.makeECPrivateKey)();
var transitPublicKey = (0, _lib.getPublicKeyFromPrivate)(transitPrivateKey);
var metadata = {};
var authResponse = (0, _lib.makeAuthResponse)(privateKey, _sampleData.sampleProfiles.ryan, 'ryan.id', metadata, undefined, appPrivateKey, undefined, transitPublicKey);
global.window.localStorage.setItem(_authConstants.BLOCKSTACK_APP_PRIVATE_KEY_LABEL, transitPrivateKey);
(0, _lib.handlePendingSignIn)(nameLookupURL, authResponse).then(function () {
t.pass('Should correctly sign in with auth response');
}).catch(function (err) {
console.log(err.stack);
t.fail('Should not error');
});
});
(0, _tape2.default)('handlePendingSignIn with authResponseToken and transit key', function (t) {
t.plan(1);
var url = nameLookupURL + 'ryan.id';
_fetchMock2.default.get(url, _sampleData.sampleNameRecords.ryan);
var appPrivateKey = (0, _lib.makeECPrivateKey)();
var transitPrivateKey = (0, _lib.makeECPrivateKey)();
var transitPublicKey = (0, _lib.getPublicKeyFromPrivate)(transitPrivateKey);
var metadata = {};
var authResponse = (0, _lib.makeAuthResponse)(privateKey, _sampleData.sampleProfiles.ryan, 'ryan.id', metadata, undefined, appPrivateKey, undefined, transitPublicKey);
(0, _lib.handlePendingSignIn)(nameLookupURL, authResponse, transitPrivateKey).then(function () {
t.pass('Should correctly sign in with auth response');
}).catch(function (err) {
console.log(err.stack);
t.fail('Should not error');
});
});
(0, _tape2.default)('handlePendingSignIn with authResponseToken, transit key and custom Blockstack API URL', function (t) {
t.plan(2);
var customBlockstackAPIUrl = 'https://test.name.lookups';
var oldBlockstackAPIUrl = _lib.config.network.blockstackAPIUrl;
var url = customBlockstackAPIUrl + '/v1/names/ryan.id';
_fetchMock2.default.get(url, _sampleData.sampleNameRecords.ryan);
var appPrivateKey = (0, _lib.makeECPrivateKey)();
var transitPrivateKey = (0, _lib.makeECPrivateKey)();
var transitPublicKey = (0, _lib.getPublicKeyFromPrivate)(transitPrivateKey);
var metadata = {};
var authResponse = (0, _lib.makeAuthResponse)(privateKey, _sampleData.sampleProfiles.ryan, 'ryan.id', metadata, undefined, appPrivateKey, undefined, transitPublicKey, undefined, customBlockstackAPIUrl);
(0, _lib.handlePendingSignIn)(null, authResponse, transitPrivateKey).then(function () {
t.pass('Should correctly sign in with auth response');
t.equal(_lib.config.network.blockstackAPIUrl, customBlockstackAPIUrl, 'Should override global Blockstack API URL');
_lib.config.network.blockstackAPIUrl = oldBlockstackAPIUrl;
}).catch(function (err) {
console.log(err.stack);
t.fail('Should not error');
});
});
(0, _tape2.default)('handlePendingSignIn with authResponseToken, transit key, ' + 'Blockstack API URL, and Gaia association token', function (t) {
t.plan(3);
var customBlockstackAPIUrl = 'https://test.name.lookups';
var oldBlockstackAPIUrl = _lib.config.network.blockstackAPIUrl;
var url = customBlockstackAPIUrl + '/v1/names/ryan.id';
_fetchMock2.default.get(url, _sampleData.sampleNameRecords.ryan);
var appPrivateKey = (0, _lib.makeECPrivateKey)();
var identityPrivateKey = (0, _lib.makeECPrivateKey)();
var transitPrivateKey = (0, _lib.makeECPrivateKey)();
var transitPublicKey = (0, _lib.getPublicKeyFromPrivate)(transitPrivateKey);
var metadata = {};
var appPublicKey = (0, _lib.getPublicKeyFromPrivate)(appPrivateKey);
var FOUR_MONTH_SECONDS = 60 * 60 * 24 * 31 * 4;
var salt = '00000000000000000000000000000';
var identityPublicKey = (0, _lib.getPublicKeyFromPrivate)(identityPrivateKey);
var associationTokenClaim = {
childToAssociate: appPublicKey,
iss: identityPublicKey,
exp: FOUR_MONTH_SECONDS + new Date() / 1000,
salt: salt
};
var gaiaAssociationToken = new _jsontokens.TokenSigner('ES256K', identityPrivateKey).sign(associationTokenClaim);
var authResponse = (0, _lib.makeAuthResponse)(privateKey, _sampleData.sampleProfiles.ryan, 'ryan.id', metadata, undefined, appPrivateKey, undefined, transitPublicKey, undefined, customBlockstackAPIUrl, gaiaAssociationToken);
(0, _lib.handlePendingSignIn)(null, authResponse, transitPrivateKey).then(function () {
t.pass('Should correctly sign in with auth response');
t.equal(_lib.config.network.blockstackAPIUrl, customBlockstackAPIUrl, 'Should override global Blockstack API URL');
t.equal((0, _lib.loadUserData)().gaiaAssociationToken, gaiaAssociationToken, 'Should have Gaia association token');
// restore
_lib.config.network.blockstackAPIUrl = oldBlockstackAPIUrl;
}).catch(function (err) {
console.log(err.stack);
t.fail('Should not error');
});
});
}