UNPKG

@stacks/profile

Version:

Library for Stacks profiles

323 lines 11.4 kB
"use strict"; 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.resolveZoneFileToProfile = exports.getTokenFileUrl = exports.makeProfileZoneFile = exports.Person = exports.Profile = void 0; const profileTokens_1 = require("./profileTokens"); const profileSchemas_1 = require("./profileSchemas"); const personUtils_1 = require("./profileSchemas/personUtils"); const zone_file_1 = require("zone-file"); const inspector = __importStar(require("schema-inspector")); const common_1 = require("@stacks/common"); const network_1 = require("@stacks/network"); const schemaDefinition = { type: 'object', properties: { '@context': { type: 'string', optional: true }, '@type': { type: 'string' }, }, }; class Profile { constructor(profile = {}) { this._profile = Object.assign({}, { '@context': 'http://schema.org/', }, profile); } toJSON() { return Object.assign({}, this._profile); } toToken(privateKey) { return (0, profileTokens_1.signProfileToken)(this.toJSON(), privateKey); } static validateSchema(profile, strict = false) { schemaDefinition.strict = strict; return inspector.validate(schemaDefinition, profile); } static fromToken(token, publicKeyOrAddress = null) { const profile = (0, profileTokens_1.extractProfile)(token, publicKeyOrAddress); return new Profile(profile); } static makeZoneFile(domainName, tokenFileURL) { return makeProfileZoneFile(domainName, tokenFileURL); } } exports.Profile = Profile; const personSchemaDefinition = { type: 'object', strict: false, properties: { '@context': { type: 'string', optional: true }, '@type': { type: 'string' }, '@id': { type: 'string', optional: true }, name: { type: 'string', optional: true }, givenName: { type: 'string', optional: true }, familyName: { type: 'string', optional: true }, description: { type: 'string', optional: true }, image: { type: 'array', optional: true, items: { type: 'object', properties: { '@type': { type: 'string' }, name: { type: 'string', optional: true }, contentUrl: { type: 'string', optional: true }, }, }, }, website: { type: 'array', optional: true, items: { type: 'object', properties: { '@type': { type: 'string' }, url: { type: 'string', optional: true }, }, }, }, account: { type: 'array', optional: true, items: { type: 'object', properties: { '@type': { type: 'string' }, service: { type: 'string', optional: true }, identifier: { type: 'string', optional: true }, proofType: { type: 'string', optional: true }, proofUrl: { type: 'string', optional: true }, proofMessage: { type: 'string', optional: true }, proofSignature: { type: 'string', optional: true }, }, }, }, worksFor: { type: 'array', optional: true, items: { type: 'object', properties: { '@type': { type: 'string' }, '@id': { type: 'string', optional: true }, }, }, }, knows: { type: 'array', optional: true, items: { type: 'object', properties: { '@type': { type: 'string' }, '@id': { type: 'string', optional: true }, }, }, }, address: { type: 'object', optional: true, properties: { '@type': { type: 'string' }, streetAddress: { type: 'string', optional: true }, addressLocality: { type: 'string', optional: true }, postalCode: { type: 'string', optional: true }, addressCountry: { type: 'string', optional: true }, }, }, birthDate: { type: 'string', optional: true }, taxID: { type: 'string', optional: true }, }, }; class Person extends Profile { constructor(profile = { '@type': 'Person' }) { super(profile); this._profile = Object.assign({}, { '@type': 'Person', }, this._profile); } static validateSchema(profile, strict = false) { personSchemaDefinition.strict = strict; return inspector.validate(schemaDefinition, profile); } static fromToken(token, publicKeyOrAddress = null) { const profile = (0, profileTokens_1.extractProfile)(token, publicKeyOrAddress); return new Person(profile); } static fromLegacyFormat(legacyProfile) { const profile = (0, profileSchemas_1.getPersonFromLegacyFormat)(legacyProfile); return new Person(profile); } toJSON() { return { profile: this.profile(), name: this.name(), givenName: this.givenName(), familyName: this.familyName(), description: this.description(), avatarUrl: this.avatarUrl(), verifiedAccounts: this.verifiedAccounts(), address: this.address(), birthDate: this.birthDate(), connections: this.connections(), organizations: this.organizations(), }; } profile() { return Object.assign({}, this._profile); } name() { return (0, personUtils_1.getName)(this.profile()); } givenName() { return (0, personUtils_1.getGivenName)(this.profile()); } familyName() { return (0, personUtils_1.getFamilyName)(this.profile()); } description() { return (0, personUtils_1.getDescription)(this.profile()); } avatarUrl() { return (0, personUtils_1.getAvatarUrl)(this.profile()); } verifiedAccounts(verifications) { return (0, personUtils_1.getVerifiedAccounts)(this.profile(), verifications); } address() { return (0, personUtils_1.getAddress)(this.profile()); } birthDate() { return (0, personUtils_1.getBirthDate)(this.profile()); } connections() { return (0, personUtils_1.getConnections)(this.profile()); } organizations() { return (0, personUtils_1.getOrganizations)(this.profile()); } } exports.Person = Person; function makeProfileZoneFile(origin, tokenFileUrl) { if (!tokenFileUrl.includes('://')) { throw new Error('Invalid token file url'); } const urlScheme = tokenFileUrl.split('://')[0]; const urlParts = tokenFileUrl.split('://')[1].split('/'); const domain = urlParts[0]; const pathname = `/${urlParts.slice(1).join('/')}`; const zoneFile = { $origin: origin, $ttl: 3600, uri: [ { name: '_http._tcp', priority: 10, weight: 1, target: `${urlScheme}://${domain}${pathname}`, }, ], }; const zoneFileTemplate = '{$origin}\n{$ttl}\n{uri}\n'; return (0, zone_file_1.makeZoneFile)(zoneFile, zoneFileTemplate); } exports.makeProfileZoneFile = makeProfileZoneFile; function getTokenFileUrl(zoneFileJson) { if (!zoneFileJson.hasOwnProperty('uri')) { return null; } if (!Array.isArray(zoneFileJson.uri)) { return null; } if (zoneFileJson.uri.length < 1) { return null; } const validRecords = zoneFileJson.uri.filter((record) => record.hasOwnProperty('target') && record.name === '_http._tcp'); if (validRecords.length < 1) { return null; } const firstValidRecord = validRecords[0]; if (!firstValidRecord.hasOwnProperty('target')) { return null; } let tokenFileUrl = firstValidRecord.target; if (tokenFileUrl.startsWith('https')) { } else if (tokenFileUrl.startsWith('http')) { } else { tokenFileUrl = `https://${tokenFileUrl}`; } return tokenFileUrl; } exports.getTokenFileUrl = getTokenFileUrl; function resolveZoneFileToProfile(opts) { const network = (0, network_1.networkFrom)(opts.network ?? 'mainnet'); const client = Object.assign({}, (0, network_1.clientFromNetwork)(network), opts.client); return new Promise((resolve, reject) => { let zoneFileJson = null; try { zoneFileJson = (0, zone_file_1.parseZoneFile)(opts.zoneFile); if (!zoneFileJson.hasOwnProperty('$origin')) { zoneFileJson = null; } } catch (e) { reject(e); } let tokenFileUrl = null; if (zoneFileJson && Object.keys(zoneFileJson).length > 0) { tokenFileUrl = getTokenFileUrl(zoneFileJson); } else { try { return resolve(Person.fromLegacyFormat(JSON.parse(opts.zoneFile)).profile()); } catch (error) { return reject(error); } } if (tokenFileUrl) { client .fetch(tokenFileUrl) .then(response => response.text()) .then(responseText => JSON.parse(responseText)) .then(responseJson => { const tokenRecords = responseJson; const profile = (0, profileTokens_1.extractProfile)(tokenRecords[0].token, opts.publicKeyOrAddress); resolve(profile); }) .catch(error => { common_1.Logger.error(`resolveZoneFileToProfile: error fetching token file ${tokenFileUrl}: ${error}`); reject(error); }); } else { common_1.Logger.debug('Token file url not found. Resolving to blank profile.'); resolve({}); } }); } exports.resolveZoneFileToProfile = resolveZoneFileToProfile; //# sourceMappingURL=profile.js.map