UNPKG

identifi-lib

Version:

Basic tools for reading and writing Identifi messages and identities.

339 lines (289 loc) 12.9 kB
'use strict'; exports.__esModule = true; var _identicon = require('identicon.js'); var _identicon2 = _interopRequireDefault(_identicon); var _attribute = require('./attribute'); var _attribute2 = _interopRequireDefault(_attribute); var _util = require('./util'); var _util2 = _interopRequireDefault(_util); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } /** * An Identifi identity profile. Usually you don't create them yourself, but get them * from Index methods such as search(). */ var Identity = function () { /** * @param {Object} gun node where the Identity data lives */ function Identity(gun, linkTo) { _classCallCheck(this, Identity); this.gun = gun; this.linkTo = linkTo; } Identity.create = async function create(gun, data) { if (!data.linkTo && !data.attrs) { throw new Error('You must specify either data.linkTo or data.attrs'); } if (data.linkTo && !data.attrs) { var linkTo = new _attribute2.default(data.linkTo); data.attrs = {}; if (!data.attrs.hasOwnProperty(linkTo.uri())) { data.attrs[linkTo.uri()] = linkTo; } } else { data.linkTo = Identity.getLinkTo(data.attrs); } await gun.put(data); return new Identity(gun, data.linkTo); }; Identity.getLinkTo = function getLinkTo(attrs) { var mva = Identity.getMostVerifiedAttributes(attrs); var keys = Object.keys(mva); var linkTo = void 0; for (var i = 0; i < keys.length; i++) { if (keys[i] === 'keyID') { linkTo = mva[keys[i]].attribute; break; } else if (_attribute2.default.isUniqueType(keys[i])) { linkTo = mva[keys[i]].attribute; } } return linkTo; }; Identity.getMostVerifiedAttributes = function getMostVerifiedAttributes(attrs) { var mostVerifiedAttributes = {}; Object.keys(attrs).forEach(function (k) { var a = attrs[k]; var keyExists = Object.keys(mostVerifiedAttributes).indexOf(a.type) > -1; a.conf = isNaN(a.conf) ? 1 : a.conf; a.ref = isNaN(a.ref) ? 0 : a.ref; if (a.conf * 2 > a.ref * 3 && (!keyExists || a.conf - a.ref > mostVerifiedAttributes[a.type].verificationScore)) { mostVerifiedAttributes[a.type] = { attribute: a, verificationScore: a.conf - a.ref }; if (a.verified) { mostVerifiedAttributes[a.type].verified = true; } } }); return mostVerifiedAttributes; }; /** * @param {string} attribute attribute type * @returns {string} most verified value of the param type */ Identity.prototype.verified = async function verified(attribute) { var attrs = await this.gun.get('attrs').then(); var mva = Identity.getMostVerifiedAttributes(attrs); return mva.hasOwnProperty(attribute) ? mva[attribute].attribute.value : undefined; }; /** * @param {Object} ipfs (optional) an IPFS instance that is used to fetch images * @returns {HTMLElement} profile card html element describing the identity */ Identity.prototype.profileCard = function profileCard(ipfs) { var _this = this; var card = document.createElement('div'); card.className = 'identifi-card'; var identicon = this.identicon(60, null, null, ipfs); identicon.style.order = 1; identicon.style.flexShrink = 0; identicon.style.marginRight = '15px'; var details = document.createElement('div'); details.style.padding = '5px'; details.style.order = 2; details.style.flexGrow = 1; var linkEl = document.createElement('span'); var links = document.createElement('small'); card.appendChild(identicon); card.appendChild(details); details.appendChild(linkEl); details.appendChild(links); this.gun.on(async function (data) { if (!data) { return; } var attrs = await new Promise(function (resolve) { _this.gun.get('attrs').load(function (r) { return resolve(r); }); }); var linkTo = await _this.gun.get('linkTo').then(); var link = 'https://identi.fi/#/identities/' + linkTo.type + '/' + linkTo.value; var mva = Identity.getMostVerifiedAttributes(attrs); linkEl.innerHTML = '<a href="' + link + '">' + (mva.type && mva.type.attribute.value || mva.nickname && mva.nickname.attribute.value || linkTo.type + ':' + linkTo.value) + '</a><br>'; linkEl.innerHTML += '<small>Received: <span class="identifi-pos">+' + (data.receivedPositive || 0) + '</span> / <span class="identifi-neg">-' + (data.receivedNegative || 0) + '</span></small><br>'; links.innerHTML = ''; Object.keys(attrs).forEach(function (k) { var a = attrs[k]; if (a.link) { links.innerHTML += a.type + ': <a href="' + a.link + '">' + a.value + '</a> '; } }); }); /* const template = ``` <tr ng-repeat="result in ids.list" id="result{$index}" ng-hide="!result.linkTo" ui-sref="identities.show({ type: result.linkTo.type, value: result.linkTo.value })" class="search-result-row" ng-class="{active: result.active}"> <td class="gravatar-col"><identicon id="result" border="3" width="46" positive-score="result.pos" negative-score="result.neg"></identicon></td> <td> <span ng-if="result.distance == 0" class="label label-default pull-right">viewpoint</span> <span ng-if="result.distance > 0" ng-bind="result.distance | ordinal" class="label label-default pull-right"></span> <a ng-bind-html="result.name|highlight:query.term" ui-sref="identities.show({ type: result.linkTo.type, value: result.linkTo.value })"></a> <small ng-if="!result.name" class="list-group-item-text"> <span ng-bind-html="result[0][0]|highlight:query.term"></span> </small><br> <small> <span ng-if="result.nickname && result.name != result.nickname" ng-bind-html="result.nickname|highlight:query.term" class="mar-right10"></span> <span ng-if="result.email" class="mar-right10"> <span class="glyphicon glyphicon-envelope"></span> <span ng-bind-html="result.email|highlight:query.term"></span> </span> <span ng-if="result.facebook" class="mar-right10"> <span class="fa fa-facebook"></span> <span ng-bind-html="result.facebook|highlight:query.term"></span> </span> <span ng-if="result.twitter" class="mar-right10"> <span class="fa fa-twitter"></span> <span ng-bind-html="result.twitter|highlight:query.term"></span> </span> <span ng-if="result.googlePlus" class="mar-right10"> <span class="fa fa-google-plus"></span> <span ng-bind-html="result.googlePlus|highlight:query.term"></span> </span> <span ng-if="result.bitcoin" class="mar-right10"> <span class="fa fa-bitcoin"></span> <span ng-bind-html="result.bitcoin|highlight:query.term"></span> </span> </small> </td> </tr> ```;*/ return card; }; /** * Appends a search widget to the given HTMLElement * @param {HTMLElement} parentElement element where the search widget is added and event listener attached * @param {Index} index index root to use for search */ Identity.appendSearchWidget = function appendSearchWidget(parentElement, index) { var form = document.createElement('form'); var input = document.createElement('input'); input.type = 'text'; input.placeholder = 'Search'; input.id = 'identifiSearchInput'; form.innerHTML += '<div id="identifiSearchResults"></div>'; var searchResults = document.createElement('div'); parentElement.appendChild(form); form.appendChild(input); form.appendChild(searchResults); input.addEventListener('keyup', async function () { var r = await index.search(input.value); searchResults.innerHTML = ''; r.sort(function (a, b) { return a.trustDistance - b.trustDistance; }); r.forEach(function (i) { searchResults.appendChild(i.profileCard()); }); }); }; Identity._ordinal = function _ordinal(n) { var s = ['th', 'st', 'nd', 'rd']; var v = n % 100; return n + (s[(v - 20) % 10] || s[v] || s[0]); }; /** * @param {number} width of the identicon * @param {number} border identicon border (aura) width * @param {boolean} showDistance whether to show web of trust distance ordinal * @param {Object} ipfs (optional) an IPFS instance that is used to fetch images * @returns {HTMLElement} identicon element that can be appended to DOM */ Identity.prototype.identicon = function identicon(width) { var border = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 4; var showDistance = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : true; var ipfs = arguments[3]; _util2.default.injectCss(); // some other way that is not called on each identicon generation? var identicon = document.createElement('div'); identicon.className = 'identifi-identicon'; identicon.style.width = width + 'px'; identicon.style.height = width + 'px'; var pie = document.createElement('div'); pie.className = 'identifi-pie'; pie.style.width = width + 'px'; var img = document.createElement('img'); img.alt = ''; img.width = width; img.height = width; img.style.borderWidth = border + 'px'; var distance = void 0; if (showDistance) { distance = document.createElement('span'); distance.className = 'identifi-distance'; distance.style.fontSize = width > 50 ? width / 4 + 'px' : '10px'; identicon.appendChild(distance); } identicon.appendChild(pie); identicon.appendChild(img); function setPie(data) { if (!data) { return; } // Define colors etc var bgColor = 'rgba(0,0,0,0.2)'; var bgImage = 'none'; var transform = ''; var boxShadow = '0px 0px 0px 0px #82FF84'; if (data.receivedPositive > data.receivedNegative * 20) { boxShadow = '0px 0px ' + border * data.receivedPositive / 50 + 'px 0px #82FF84'; } else if (data.receivedPositive < data.receivedNegative * 3) { boxShadow = '0px 0px ' + border * data.receivedNegative / 10 + 'px 0px #BF0400'; } if (data.receivedPositive + data.receivedNegative > 0) { if (data.receivedPositive > data.receivedNegative) { transform = 'rotate(' + (-data.receivedPositive / (data.receivedPositive + data.receivedNegative) * 360 - 180) / 2 + 'deg)'; bgColor = '#A94442'; bgImage = 'linear-gradient(' + data.receivedPositive / (data.receivedPositive + data.receivedNegative) * 360 + 'deg, transparent 50%, #3C763D 50%), linear-gradient(0deg, #3C763D 50%, transparent 50%)'; } else { transform = 'rotate(' + ((-data.receivedNegative / (data.receivedPositive + data.receivedNegative) * 360 - 180) / 2 + 180) + 'deg)'; bgColor = '#3C763D'; bgImage = 'linear-gradient(' + data.receivedNegative / (data.receivedPositive + data.receivedNegative) * 360 + 'deg, transparent 50%, #A94442 50%), linear-gradient(0deg, #A94442 50%, transparent 50%)'; } } pie.style.backgroundColor = bgColor; pie.style.backgroundImage = bgImage; pie.style.boxShadow = boxShadow; pie.style.transform = transform; pie.style.opacity = (data.receivedPositive + data.receivedNegative) / 10 * 0.5 + 0.35; if (showDistance) { distance.textContent = typeof data.trustDistance === 'number' ? Identity._ordinal(data.trustDistance) : '\u2715'; } } function setIdenticonImg(data) { var hash = _util2.default.getHash(encodeURIComponent(data.type) + ':' + encodeURIComponent(data.value), 'hex'); var identiconImg = new _identicon2.default(hash, { width: width, format: 'svg' }); img.src = img.src || 'data:image/svg+xml;base64,' + identiconImg.toString(); } if (this.linkTo) { setIdenticonImg(this.linkTo); } else { this.gun.get('linkTo').on(setIdenticonImg); } this.gun.on(setPie); if (ipfs) { this.gun.get('attrs').open(function (attrs) { var mva = Identity.getMostVerifiedAttributes(attrs); if (mva.profilePhoto) { var go = function go() { ipfs.cat(mva.profilePhoto.attribute.value).then(function (file) { var f = ipfs.types.Buffer.from(file).toString('base64'); img.src = 'data:image;base64,' + f; }); }; ipfs.isOnline() ? go() : ipfs.on('ready', go); } }); } return identicon; }; return Identity; }(); exports.default = Identity; module.exports = exports['default'];