@stacks/cli
Version:
Stacks command line tool
191 lines • 9.16 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getGaiaAddressFromProfile = exports.getGaiaAddressFromURL = exports.gaiaUploadProfileAll = exports.gaiaUploadProfile = exports.gaiaConnect = exports.gaiaAuth = exports.makeAssociationToken = void 0;
const blockstack = __importStar(require("blockstack"));
const URL = __importStar(require("url"));
const crypto = __importStar(require("crypto"));
const jsontokens = __importStar(require("jsontokens"));
const ZoneFile = require('zone-file');
const utils_1 = require("./utils");
const common_1 = require("./common");
const storage_1 = require("@stacks/storage");
function makeFakeAuthResponseToken(appPrivateKey, hubURL, associationToken) {
const ownerPrivateKey = '24004db06ef6d26cdd2b0fa30b332a1b10fa0ba2b07e63505ffc2a9ed7df22b4';
const transitPrivateKey = 'f33fb466154023aba2003c17158985aa6603db68db0f1afc0fcf1d641ea6c2cb';
const transitPublicKey = '0496345da77fb5e06757b9c4fd656bf830a3b293f245a6cc2f11f8334ebb690f1' +
'9582124f4b07172eb61187afba4514828f866a8a223e0d5c539b2e38a59ab8bb3';
window.localStorage.setItem('blockstack-transit-private-key', transitPrivateKey);
const authResponse = blockstack.makeAuthResponse(ownerPrivateKey, { type: '@Person', accounts: [] }, null, {}, null, appPrivateKey, undefined, transitPublicKey, hubURL, blockstack.config.network.blockstackAPIUrl, associationToken);
return authResponse;
}
function makeAssociationToken(appPrivateKey, identityKey) {
const appPublicKey = (0, utils_1.getPublicKeyFromPrivateKey)(`${(0, utils_1.canonicalPrivateKey)(appPrivateKey)}01`);
const FOUR_MONTH_SECONDS = 60 * 60 * 24 * 31 * 4;
const salt = crypto.randomBytes(16).toString('hex');
const identityPublicKey = (0, utils_1.getPublicKeyFromPrivateKey)(identityKey);
const associationTokenClaim = {
childToAssociate: appPublicKey,
iss: identityPublicKey,
exp: FOUR_MONTH_SECONDS + new Date().getTime() / 1000,
salt,
};
const associationToken = new jsontokens.TokenSigner('ES256K', identityKey).sign(associationTokenClaim);
return associationToken;
}
exports.makeAssociationToken = makeAssociationToken;
function gaiaAuth(network, appPrivateKey, hubUrl, ownerPrivateKey) {
if (!network.isMainnet()) {
throw new Error('Gaia only works with mainnet networks.');
}
let associationToken;
if (ownerPrivateKey && appPrivateKey) {
associationToken = makeAssociationToken(appPrivateKey, ownerPrivateKey);
}
const authSessionToken = makeFakeAuthResponseToken(appPrivateKey, hubUrl, associationToken);
const nameLookupUrl = `${network.legacyNetwork.blockstackAPIUrl}/v1/names/`;
const transitPrivateKey = 'f33fb466154023aba2003c17158985aa6603db68db0f1afc0fcf1d641ea6c2cb';
return blockstack.handlePendingSignIn(nameLookupUrl, authSessionToken, transitPrivateKey);
}
exports.gaiaAuth = gaiaAuth;
function gaiaConnect(network, gaiaHubUrl, privateKey, ownerPrivateKey) {
const addressMainnet = network.coerceMainnetAddress((0, common_1.getPrivateKeyAddress)(network, `${(0, utils_1.canonicalPrivateKey)(privateKey)}01`));
const addressMainnetCanonical = network.coerceMainnetAddress((0, common_1.getPrivateKeyAddress)(network, (0, utils_1.canonicalPrivateKey)(privateKey)));
let associationToken;
if (ownerPrivateKey) {
associationToken = makeAssociationToken(privateKey, ownerPrivateKey);
}
return (0, storage_1.connectToGaiaHub)(gaiaHubUrl, (0, utils_1.canonicalPrivateKey)(privateKey), associationToken).then(hubConfig => {
if (network.coerceMainnetAddress(hubConfig.address) === addressMainnet) {
hubConfig.address = addressMainnet;
}
else if (network.coerceMainnetAddress(hubConfig.address) === addressMainnetCanonical) {
hubConfig.address = addressMainnetCanonical;
}
else {
throw new Error('Invalid private key: ' +
`${network.coerceMainnetAddress(hubConfig.address)} is neither ` +
`${addressMainnet} or ${addressMainnetCanonical}`);
}
return hubConfig;
});
}
exports.gaiaConnect = gaiaConnect;
function gaiaFindProfileName(network, hubConfig, blockstackID) {
if (!blockstackID || blockstackID === null || blockstackID === undefined) {
return Promise.resolve().then(() => 'profile.json');
}
else {
return network.getNameInfo(blockstackID).then((nameInfo) => {
let profileUrl;
try {
const zonefileJSON = ZoneFile.parseZoneFile(nameInfo.zonefile);
if (zonefileJSON.uri && zonefileJSON.hasOwnProperty('$origin')) {
profileUrl = blockstack.getTokenFileUrl(zonefileJSON);
}
}
catch (e) {
throw new Error(`Could not determine profile URL for ${String(blockstackID)}: could not parse zone file`);
}
if (profileUrl === null || profileUrl === undefined) {
throw new Error(`Could not determine profile URL for ${String(blockstackID)}: no URL in zone file`);
}
const gaiaReadPrefix = `${hubConfig.url_prefix}${hubConfig.address}`;
const gaiaReadUrlPath = String(URL.parse(gaiaReadPrefix).path);
const profileUrlPath = String(URL.parse(profileUrl).path);
if (!profileUrlPath.startsWith(gaiaReadUrlPath)) {
throw new Error(`Could not determine profile URL for ${String(blockstackID)}: wrong Gaia hub` +
` (${gaiaReadPrefix} does not correspond to ${profileUrl})`);
}
const profilePath = profileUrlPath.substring(gaiaReadUrlPath.length + 1);
return profilePath;
});
}
}
function gaiaUploadProfile(network, gaiaHubURL, gaiaData, privateKey, blockstackID) {
let hubConfig;
return gaiaConnect(network, gaiaHubURL, privateKey)
.then((hubconf) => {
hubConfig = hubconf;
return gaiaFindProfileName(network, hubConfig, blockstackID);
})
.then((profilePath) => {
return blockstack.uploadToGaiaHub(profilePath, gaiaData, hubConfig);
});
}
exports.gaiaUploadProfile = gaiaUploadProfile;
function gaiaUploadProfileAll(network, gaiaUrls, gaiaData, privateKey, blockstackID) {
const sanitizedGaiaUrls = gaiaUrls
.map(gaiaUrl => {
const urlInfo = URL.parse(gaiaUrl);
if (!urlInfo.protocol) {
return '';
}
if (!urlInfo.host) {
return '';
}
return `${String(urlInfo.protocol)}//${String(urlInfo.host)}`;
})
.filter(gaiaUrl => gaiaUrl.length > 0);
const uploadPromises = sanitizedGaiaUrls.map(gaiaUrl => gaiaUploadProfile(network, gaiaUrl, gaiaData, privateKey, blockstackID));
return Promise.all(uploadPromises)
.then(publicUrls => {
return { error: null, dataUrls: publicUrls };
})
.catch(e => {
return { error: `Failed to upload: ${e.message}`, dataUrls: null };
});
}
exports.gaiaUploadProfileAll = gaiaUploadProfileAll;
function getGaiaAddressFromURL(appUrl) {
const matches = appUrl.match(/([13][a-km-zA-HJ-NP-Z0-9]{26,35})/);
if (!matches) {
throw new Error('Failed to parse gaia address');
}
return matches[matches.length - 1];
}
exports.getGaiaAddressFromURL = getGaiaAddressFromURL;
function getGaiaAddressFromProfile(network, profile, appOrigin) {
if (!profile) {
throw new Error('No profile');
}
if (!profile.apps) {
throw new Error('No profile apps');
}
if (!profile.apps[appOrigin]) {
throw new Error(`No app entry for ${appOrigin}`);
}
const appUrl = profile.apps[appOrigin];
let existingAppAddress;
try {
existingAppAddress = network.coerceMainnetAddress(getGaiaAddressFromURL(appUrl));
}
catch (e) {
throw new Error(`Failed to parse app URL ${appUrl}`);
}
return existingAppAddress;
}
exports.getGaiaAddressFromProfile = getGaiaAddressFromProfile;
//# sourceMappingURL=data.js.map