anchor-link
Advanced tools
Comparing version 1.0.0 to 1.0.1
@@ -0,0 +0,0 @@ /** Error that is thrown if a LinkPresenter calls the cancel callback. */ |
@@ -1,49 +0,22 @@ | ||
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
/** Error that is thrown if a LinkPresenter calls the cancel callback. */ | ||
var CancelError = /** @class */ (function (_super) { | ||
__extends(CancelError, _super); | ||
function CancelError(reason) { | ||
var _this = _super.call(this, "User canceled request " + (reason ? '(' + reason + ')' : '')) || this; | ||
_this.code = 'E_CANCEL'; | ||
return _this; | ||
export class CancelError extends Error { | ||
constructor(reason) { | ||
super(`User canceled request ${reason ? '(' + reason + ')' : ''}`); | ||
this.code = 'E_CANCEL'; | ||
} | ||
return CancelError; | ||
}(Error)); | ||
exports.CancelError = CancelError; | ||
} | ||
/** Error that is thrown if an identity request fails to verify. */ | ||
var IdentityError = /** @class */ (function (_super) { | ||
__extends(IdentityError, _super); | ||
function IdentityError(reason) { | ||
var _this = _super.call(this, "Unable to verify identity " + (reason ? '(' + reason + ')' : '')) || this; | ||
_this.code = 'E_IDENTITY'; | ||
return _this; | ||
export class IdentityError extends Error { | ||
constructor(reason) { | ||
super(`Unable to verify identity ${reason ? '(' + reason + ')' : ''}`); | ||
this.code = 'E_IDENTITY'; | ||
} | ||
return IdentityError; | ||
}(Error)); | ||
exports.IdentityError = IdentityError; | ||
} | ||
/** Error that is thrown by session transport. */ | ||
var SessionError = /** @class */ (function (_super) { | ||
__extends(SessionError, _super); | ||
function SessionError(reason, code) { | ||
var _this = _super.call(this, reason) || this; | ||
_this.code = code; | ||
return _this; | ||
export class SessionError extends Error { | ||
constructor(reason, code) { | ||
super(reason); | ||
this.code = code; | ||
} | ||
return SessionError; | ||
}(Error)); | ||
exports.SessionError = SessionError; | ||
} | ||
//# sourceMappingURL=errors.js.map |
@@ -0,0 +0,0 @@ export * from './link'; |
@@ -1,9 +0,4 @@ | ||
"use strict"; | ||
function __export(m) { | ||
for (var p in m) if (!exports.hasOwnProperty(p)) exports[p] = m[p]; | ||
} | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
__export(require("./link")); | ||
__export(require("./link-session")); | ||
__export(require("./errors")); | ||
export * from './link'; | ||
export * from './link-session'; | ||
export * from './errors'; | ||
//# sourceMappingURL=index.js.map |
@@ -0,0 +0,0 @@ declare const _default: { |
@@ -1,4 +0,2 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.default = { | ||
export default { | ||
version: 'eosio::abi/1.1', | ||
@@ -5,0 +3,0 @@ types: [], |
@@ -0,0 +0,0 @@ import { ChainName } from 'eosio-signing-request'; |
@@ -1,4 +0,2 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.defaults = { | ||
export const defaults = { | ||
chainId: 'aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906', | ||
@@ -5,0 +3,0 @@ rpc: 'https://eos.greymass.com', |
@@ -0,0 +0,0 @@ import { ApiInterfaces } from 'eosjs'; |
@@ -1,29 +0,3 @@ | ||
"use strict"; | ||
var __extends = (this && this.__extends) || (function () { | ||
var extendStatics = function (d, b) { | ||
extendStatics = Object.setPrototypeOf || | ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || | ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; | ||
return extendStatics(d, b); | ||
}; | ||
return function (d, b) { | ||
extendStatics(d, b); | ||
function __() { this.constructor = d; } | ||
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); | ||
}; | ||
})(); | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var errors_1 = require("./errors"); | ||
var utils_1 = require("./utils"); | ||
import { SessionError } from './errors'; | ||
import { abiEncode, sealMessage } from './utils'; | ||
/** | ||
@@ -33,7 +7,5 @@ * Type describing a link session that can create a eosjs compatible | ||
*/ | ||
var LinkSession = /** @class */ (function () { | ||
function LinkSession() { | ||
} | ||
export class LinkSession { | ||
/** Restore a previously serialized session. */ | ||
LinkSession.restore = function (link, data) { | ||
static restore(link, data) { | ||
switch (data.type) { | ||
@@ -47,42 +19,42 @@ case 'channel': | ||
} | ||
}; | ||
return LinkSession; | ||
}()); | ||
exports.LinkSession = LinkSession; | ||
} | ||
} | ||
/** | ||
* Link session that pushes requests over a channel. | ||
*/ | ||
var LinkChannelSession = /** @class */ (function (_super) { | ||
__extends(LinkChannelSession, _super); | ||
function LinkChannelSession(link, data, metadata) { | ||
var _this = _super.call(this) || this; | ||
_this.type = 'channel'; | ||
_this.timeout = 2 * 60 * 1000; // ms | ||
_this.link = link; | ||
_this.auth = data.auth; | ||
_this.publicKey = data.publicKey; | ||
_this.channel = data.channel; | ||
_this.encrypt = function (request) { | ||
return utils_1.sealMessage(request.encode(true, false), data.requestKey, data.channel.key); | ||
export class LinkChannelSession extends LinkSession { | ||
constructor(link, data, metadata) { | ||
super(); | ||
this.type = 'channel'; | ||
this.timeout = 2 * 60 * 1000; // ms | ||
this.link = link; | ||
this.auth = data.auth; | ||
this.publicKey = data.publicKey; | ||
this.channel = data.channel; | ||
this.encrypt = (request) => { | ||
return sealMessage(request.encode(true, false), data.requestKey, data.channel.key); | ||
}; | ||
_this.metadata = __assign(__assign({}, (metadata || {})), { timeout: _this.timeout, name: _this.channel.name }); | ||
_this.serialize = function () { return ({ | ||
this.metadata = { | ||
...(metadata || {}), | ||
timeout: this.timeout, | ||
name: this.channel.name, | ||
}; | ||
this.serialize = () => ({ | ||
type: 'channel', | ||
data: data, | ||
metadata: _this.metadata, | ||
}); }; | ||
return _this; | ||
data, | ||
metadata: this.metadata, | ||
}); | ||
} | ||
LinkChannelSession.prototype.onSuccess = function (request, result) { | ||
onSuccess(request, result) { | ||
if (this.link.transport.onSuccess) { | ||
this.link.transport.onSuccess(request, result); | ||
} | ||
}; | ||
LinkChannelSession.prototype.onFailure = function (request, error) { | ||
} | ||
onFailure(request, error) { | ||
if (this.link.transport.onFailure) { | ||
this.link.transport.onFailure(request, error); | ||
} | ||
}; | ||
LinkChannelSession.prototype.onRequest = function (request, cancel) { | ||
var info = { | ||
} | ||
onRequest(request, cancel) { | ||
const info = { | ||
expiration: new Date(Date.now() + this.timeout).toISOString().slice(0, -1), | ||
@@ -93,8 +65,8 @@ }; | ||
} | ||
setTimeout(function () { | ||
cancel(new errors_1.SessionError('Wallet did not respond in time', 'E_TIMEOUT')); | ||
setTimeout(() => { | ||
cancel(new SessionError('Wallet did not respond in time', 'E_TIMEOUT')); | ||
}, this.timeout + 500); | ||
request.data.info.push({ | ||
key: 'link', | ||
value: utils_1.abiEncode(info, 'link_info'), | ||
value: abiEncode(info, 'link_info'), | ||
}); | ||
@@ -109,5 +81,5 @@ this.link.rpc | ||
}) | ||
.then(function (response) { | ||
.then((response) => { | ||
if (response.status !== 200) { | ||
cancel(new errors_1.SessionError('Unable to push message', 'E_DELIVERY')); | ||
cancel(new SessionError('Unable to push message', 'E_DELIVERY')); | ||
} | ||
@@ -118,45 +90,41 @@ else { | ||
}) | ||
.catch(function (error) { | ||
cancel(new errors_1.SessionError("Unable to reach link service (" + (error.message || String(error)) + ")", 'E_DELIVERY')); | ||
.catch((error) => { | ||
cancel(new SessionError(`Unable to reach link service (${error.message || String(error)})`, 'E_DELIVERY')); | ||
}); | ||
}; | ||
LinkChannelSession.prototype.makeSignatureProvider = function () { | ||
} | ||
makeSignatureProvider() { | ||
return this.link.makeSignatureProvider([this.publicKey], this); | ||
}; | ||
LinkChannelSession.prototype.makeAuthorityProvider = function () { | ||
} | ||
makeAuthorityProvider() { | ||
return this.link.makeAuthorityProvider(); | ||
}; | ||
LinkChannelSession.prototype.transact = function (args) { | ||
} | ||
transact(args) { | ||
return this.link.transact(args, this); | ||
}; | ||
return LinkChannelSession; | ||
}(LinkSession)); | ||
exports.LinkChannelSession = LinkChannelSession; | ||
var LinkFallbackSession = /** @class */ (function (_super) { | ||
__extends(LinkFallbackSession, _super); | ||
function LinkFallbackSession(link, data, metadata) { | ||
var _this = _super.call(this) || this; | ||
_this.type = 'fallback'; | ||
_this.link = link; | ||
_this.auth = data.auth; | ||
_this.publicKey = data.publicKey; | ||
_this.metadata = metadata || {}; | ||
_this.serialize = function () { return ({ | ||
type: _this.type, | ||
data: data, | ||
metadata: _this.metadata, | ||
}); }; | ||
return _this; | ||
} | ||
LinkFallbackSession.prototype.onSuccess = function (request, result) { | ||
} | ||
export class LinkFallbackSession extends LinkSession { | ||
constructor(link, data, metadata) { | ||
super(); | ||
this.type = 'fallback'; | ||
this.link = link; | ||
this.auth = data.auth; | ||
this.publicKey = data.publicKey; | ||
this.metadata = metadata || {}; | ||
this.serialize = () => ({ | ||
type: this.type, | ||
data, | ||
metadata: this.metadata, | ||
}); | ||
} | ||
onSuccess(request, result) { | ||
if (this.link.transport.onSuccess) { | ||
this.link.transport.onSuccess(request, result); | ||
} | ||
}; | ||
LinkFallbackSession.prototype.onFailure = function (request, error) { | ||
} | ||
onFailure(request, error) { | ||
if (this.link.transport.onFailure) { | ||
this.link.transport.onFailure(request, error); | ||
} | ||
}; | ||
LinkFallbackSession.prototype.onRequest = function (request, cancel) { | ||
} | ||
onRequest(request, cancel) { | ||
if (this.link.transport.onSessionRequest) { | ||
@@ -168,15 +136,13 @@ this.link.transport.onSessionRequest(this, request, cancel); | ||
} | ||
}; | ||
LinkFallbackSession.prototype.makeSignatureProvider = function () { | ||
} | ||
makeSignatureProvider() { | ||
return this.link.makeSignatureProvider([this.publicKey], this); | ||
}; | ||
LinkFallbackSession.prototype.makeAuthorityProvider = function () { | ||
} | ||
makeAuthorityProvider() { | ||
return this.link.makeAuthorityProvider(); | ||
}; | ||
LinkFallbackSession.prototype.transact = function (args) { | ||
} | ||
transact(args) { | ||
return this.link.transact(args, this); | ||
}; | ||
return LinkFallbackSession; | ||
}(LinkSession)); | ||
exports.LinkFallbackSession = LinkFallbackSession; | ||
} | ||
} | ||
//# sourceMappingURL=link-session.js.map |
@@ -0,0 +0,0 @@ import { SigningRequest } from 'eosio-signing-request'; |
@@ -1,3 +0,1 @@ | ||
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
//# sourceMappingURL=link-transport.js.map |
@@ -0,0 +0,0 @@ import * as esr from 'eosio-signing-request'; |
618
lib/link.js
@@ -1,77 +0,18 @@ | ||
"use strict"; | ||
var __assign = (this && this.__assign) || function () { | ||
__assign = Object.assign || function(t) { | ||
for (var s, i = 1, n = arguments.length; i < n; i++) { | ||
s = arguments[i]; | ||
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) | ||
t[p] = s[p]; | ||
} | ||
return t; | ||
}; | ||
return __assign.apply(this, arguments); | ||
}; | ||
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { | ||
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } | ||
return new (P || (P = Promise))(function (resolve, reject) { | ||
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } | ||
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } | ||
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } | ||
step((generator = generator.apply(thisArg, _arguments || [])).next()); | ||
}); | ||
}; | ||
var __generator = (this && this.__generator) || function (thisArg, body) { | ||
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; | ||
return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; | ||
function verb(n) { return function (v) { return step([n, v]); }; } | ||
function step(op) { | ||
if (f) throw new TypeError("Generator is already executing."); | ||
while (_) try { | ||
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; | ||
if (y = 0, t) op = [op[0] & 2, t.value]; | ||
switch (op[0]) { | ||
case 0: case 1: t = op; break; | ||
case 4: _.label++; return { value: op[1], done: false }; | ||
case 5: _.label++; y = op[1]; op = [0]; continue; | ||
case 7: op = _.ops.pop(); _.trys.pop(); continue; | ||
default: | ||
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } | ||
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } | ||
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } | ||
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } | ||
if (t[2]) _.ops.pop(); | ||
_.trys.pop(); continue; | ||
} | ||
op = body.call(thisArg, _); | ||
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } | ||
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; | ||
} | ||
}; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var esr = __importStar(require("eosio-signing-request")); | ||
var eosjs_1 = require("eosjs"); | ||
var ecc = __importStar(require("eosjs-ecc")); | ||
var fetch_ponyfill_1 = __importDefault(require("fetch-ponyfill")); | ||
var zlib = __importStar(require("pako")); | ||
var uuid_1 = require("uuid"); | ||
var ws_1 = __importDefault(require("ws")); | ||
var errors_1 = require("./errors"); | ||
var link_options_1 = require("./link-options"); | ||
var link_session_1 = require("./link-session"); | ||
var utils_1 = require("./utils"); | ||
var fetch = fetch_ponyfill_1.default().fetch; | ||
var Link = /** @class */ (function () { | ||
function Link(options) { | ||
import * as esr from 'eosio-signing-request'; | ||
import { JsonRpc } from 'eosjs'; | ||
import * as ecc from 'eosjs-ecc'; | ||
import makeFetch from 'fetch-ponyfill'; | ||
import WebSocket from 'isomorphic-ws'; | ||
import zlib from 'pako'; | ||
import { v4 as uuid } from 'uuid'; | ||
import { CancelError, IdentityError } from './errors'; | ||
import { defaults } from './link-options'; | ||
import { LinkChannelSession, LinkFallbackSession } from './link-session'; | ||
import { abiEncode, normalizePublicKey, publicKeyEqual } from './utils'; | ||
const { fetch } = makeFetch(); | ||
export class Link { | ||
constructor(options) { | ||
this.abiCache = new Map(); | ||
if (options.rpc === undefined || typeof options.rpc === 'string') { | ||
this.rpc = new eosjs_1.JsonRpc(options.rpc || link_options_1.defaults.rpc, { fetch: fetch }); | ||
this.rpc = new JsonRpc(options.rpc || defaults.rpc, { fetch: fetch }); | ||
} | ||
@@ -81,4 +22,4 @@ else { | ||
} | ||
this.chainId = options.chainId || link_options_1.defaults.chainId; | ||
this.serviceAddress = (options.service || link_options_1.defaults.service).trim().replace(/\/$/, ''); | ||
this.chainId = options.chainId || defaults.chainId; | ||
this.serviceAddress = (options.service || defaults.service).trim().replace(/\/$/, ''); | ||
this.transport = options.transport; | ||
@@ -89,143 +30,103 @@ this.requestOptions = { | ||
textEncoder: options.textEncoder || new TextEncoder(), | ||
zlib: zlib, | ||
zlib, | ||
}; | ||
} | ||
Link.prototype.getAbi = function (account) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var rv; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
rv = this.abiCache.get(account); | ||
if (!!rv) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, this.rpc.get_abi(account)]; | ||
case 1: | ||
rv = (_a.sent()).abi; | ||
if (rv) { | ||
this.abiCache.set(account, rv); | ||
} | ||
_a.label = 2; | ||
case 2: return [2 /*return*/, rv]; | ||
} | ||
async getAbi(account) { | ||
let rv = this.abiCache.get(account); | ||
if (!rv) { | ||
rv = (await this.rpc.get_abi(account)).abi; | ||
if (rv) { | ||
this.abiCache.set(account, rv); | ||
} | ||
} | ||
return rv; | ||
} | ||
createCallbackUrl() { | ||
return `${this.serviceAddress}/${uuid()}`; | ||
} | ||
async createRequest(args) { | ||
// generate unique callback url | ||
const request = await esr.SigningRequest.create({ | ||
...args, | ||
chainId: this.chainId, | ||
broadcast: false, | ||
callback: { | ||
url: this.createCallbackUrl(), | ||
background: true, | ||
}, | ||
}, this.requestOptions); | ||
return request; | ||
} | ||
async sendRequest(request, transport) { | ||
const t = transport || this.transport; | ||
try { | ||
const linkUrl = request.data.callback; | ||
if (!linkUrl.startsWith(this.serviceAddress)) { | ||
throw new Error('Request must have a link callback'); | ||
} | ||
if (request.data.flags !== 2) { | ||
throw new Error('Invalid request flags'); | ||
} | ||
// wait for callback or user cancel | ||
const ctx = {}; | ||
const socket = waitForCallback(linkUrl, ctx); | ||
const cancel = new Promise((resolve, reject) => { | ||
t.onRequest(request, (reason) => { | ||
if (ctx.cancel) { | ||
ctx.cancel(); | ||
} | ||
if (typeof reason === 'string') { | ||
reject(new CancelError(reason)); | ||
} | ||
else { | ||
reject(reason); | ||
} | ||
}); | ||
}); | ||
}); | ||
}; | ||
Link.prototype.createCallbackUrl = function () { | ||
return this.serviceAddress + "/" + uuid_1.v4(); | ||
}; | ||
Link.prototype.createRequest = function (args) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var request; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, esr.SigningRequest.create(__assign(__assign({}, args), { chainId: this.chainId, broadcast: false, callback: { | ||
url: this.createCallbackUrl(), | ||
background: true, | ||
} }), this.requestOptions)]; | ||
case 1: | ||
request = _a.sent(); | ||
return [2 /*return*/, request]; | ||
} | ||
const payload = await Promise.race([socket, cancel]); | ||
const signer = { | ||
actor: payload.sa, | ||
permission: payload.sp, | ||
}; | ||
const signatures = Object.keys(payload) | ||
.filter((key) => key.startsWith('sig') && key !== 'sig0') | ||
.map((key) => payload[key]); | ||
// recreate transaction from request response | ||
const resolved = await esr.ResolvedSigningRequest.fromPayload(payload, this.requestOptions); | ||
const { serializedTransaction, transaction } = resolved; | ||
const result = { | ||
request: resolved.request, | ||
serializedTransaction, | ||
transaction, | ||
signatures, | ||
payload, | ||
signer, | ||
}; | ||
if (t.onSuccess) { | ||
t.onSuccess(request, result); | ||
} | ||
return result; | ||
} | ||
catch (error) { | ||
if (t.onFailure) { | ||
t.onFailure(request, error); | ||
} | ||
throw error; | ||
} | ||
} | ||
async transact(args, transport) { | ||
const t = transport || this.transport; | ||
const request = await this.createRequest(args); | ||
const result = await this.sendRequest(request, t); | ||
// broadcast transaction if requested | ||
const broadcast = args.broadcast || false; | ||
if (broadcast) { | ||
const res = await this.rpc.push_transaction({ | ||
signatures: result.signatures, | ||
serializedTransaction: result.serializedTransaction, | ||
}); | ||
}); | ||
}; | ||
Link.prototype.sendRequest = function (request, transport) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var t, linkUrl, ctx_1, socket, cancel, payload_1, signer, signatures, resolved, serializedTransaction, transaction, result, error_1; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
t = transport || this.transport; | ||
_a.label = 1; | ||
case 1: | ||
_a.trys.push([1, 4, , 5]); | ||
linkUrl = request.data.callback; | ||
if (!linkUrl.startsWith(this.serviceAddress)) { | ||
throw new Error('Request must have a link callback'); | ||
} | ||
if (request.data.flags !== 2) { | ||
throw new Error('Invalid request flags'); | ||
} | ||
ctx_1 = {}; | ||
socket = waitForCallback(linkUrl, ctx_1); | ||
cancel = new Promise(function (resolve, reject) { | ||
t.onRequest(request, function (reason) { | ||
if (ctx_1.cancel) { | ||
ctx_1.cancel(); | ||
} | ||
if (typeof reason === 'string') { | ||
reject(new errors_1.CancelError(reason)); | ||
} | ||
else { | ||
reject(reason); | ||
} | ||
}); | ||
}); | ||
return [4 /*yield*/, Promise.race([socket, cancel])]; | ||
case 2: | ||
payload_1 = _a.sent(); | ||
signer = { | ||
actor: payload_1.sa, | ||
permission: payload_1.sp, | ||
}; | ||
signatures = Object.keys(payload_1) | ||
.filter(function (key) { return key.startsWith('sig') && key !== 'sig0'; }) | ||
.map(function (key) { return payload_1[key]; }); | ||
return [4 /*yield*/, esr.ResolvedSigningRequest.fromPayload(payload_1, this.requestOptions)]; | ||
case 3: | ||
resolved = _a.sent(); | ||
serializedTransaction = resolved.serializedTransaction, transaction = resolved.transaction; | ||
result = { | ||
request: resolved.request, | ||
serializedTransaction: serializedTransaction, | ||
transaction: transaction, | ||
signatures: signatures, | ||
payload: payload_1, | ||
signer: signer, | ||
}; | ||
if (t.onSuccess) { | ||
t.onSuccess(request, result); | ||
} | ||
return [2 /*return*/, result]; | ||
case 4: | ||
error_1 = _a.sent(); | ||
if (t.onFailure) { | ||
t.onFailure(request, error_1); | ||
} | ||
throw error_1; | ||
case 5: return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
}; | ||
Link.prototype.transact = function (args, transport) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var t, request, result, broadcast, res; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
t = transport || this.transport; | ||
return [4 /*yield*/, this.createRequest(args)]; | ||
case 1: | ||
request = _a.sent(); | ||
return [4 /*yield*/, this.sendRequest(request, t) | ||
// broadcast transaction if requested | ||
]; | ||
case 2: | ||
result = _a.sent(); | ||
broadcast = args.broadcast || false; | ||
if (!broadcast) return [3 /*break*/, 4]; | ||
return [4 /*yield*/, this.rpc.push_transaction({ | ||
signatures: result.signatures, | ||
serializedTransaction: result.serializedTransaction, | ||
})]; | ||
case 3: | ||
res = _a.sent(); | ||
result.processed = res.processed; | ||
_a.label = 4; | ||
case 4: return [2 /*return*/, result]; | ||
} | ||
}); | ||
}); | ||
}; | ||
result.processed = res.processed; | ||
} | ||
return result; | ||
} | ||
/** | ||
@@ -236,109 +137,86 @@ * Create a identity request. | ||
*/ | ||
Link.prototype.identify = function (requestPermission, info) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var request, res, message, signer, signerKey, account, permission, auth, keyAuth; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, this.createRequest({ | ||
identity: { permission: requestPermission || null }, | ||
info: info, | ||
})]; | ||
case 1: | ||
request = _a.sent(); | ||
return [4 /*yield*/, this.sendRequest(request)]; | ||
case 2: | ||
res = _a.sent(); | ||
if (!res.request.isIdentity()) { | ||
throw new errors_1.IdentityError("Unexpected response"); | ||
} | ||
message = Buffer.concat([ | ||
Buffer.from(request.getChainId(), 'hex'), | ||
Buffer.from(res.serializedTransaction), | ||
Buffer.alloc(32), | ||
]); | ||
signer = res.signer; | ||
signerKey = ecc.recover(res.signatures[0], message); | ||
return [4 /*yield*/, this.rpc.get_account(signer.actor)]; | ||
case 3: | ||
account = _a.sent(); | ||
if (!account) { | ||
throw new errors_1.IdentityError("Signature from unknown account: " + signer.actor); | ||
} | ||
permission = account.permissions.find(function (_a) { | ||
var perm_name = _a.perm_name; | ||
return perm_name === signer.permission; | ||
}); | ||
if (!permission) { | ||
throw new errors_1.IdentityError(signer.actor + " signed for unknown permission: " + signer.permission); | ||
} | ||
auth = permission.required_auth; | ||
keyAuth = auth.keys.find(function (_a) { | ||
var key = _a.key; | ||
return utils_1.publicKeyEqual(key, signerKey); | ||
}); | ||
if (!keyAuth) { | ||
throw new errors_1.IdentityError(formatAuth(signer) + " has no key matching id signature"); | ||
} | ||
if (auth.threshold > keyAuth.weight) { | ||
throw new errors_1.IdentityError(formatAuth(signer) + " signature does not reach auth threshold"); | ||
} | ||
if (requestPermission) { | ||
if ((requestPermission.actor !== esr.PlaceholderName && | ||
requestPermission.actor !== signer.actor) || | ||
(requestPermission.permission !== esr.PlaceholderPermission && | ||
requestPermission.permission !== signer.permission)) { | ||
throw new errors_1.IdentityError("Unexpected identity proof from " + formatAuth(signer) + ", expected " + formatAuth(requestPermission) + " "); | ||
} | ||
} | ||
return [2 /*return*/, __assign(__assign({}, res), { account: account, | ||
signerKey: signerKey })]; | ||
} | ||
}); | ||
async identify(requestPermission, info) { | ||
const request = await this.createRequest({ | ||
identity: { permission: requestPermission || null }, | ||
info, | ||
}); | ||
}; | ||
const res = await this.sendRequest(request); | ||
if (!res.request.isIdentity()) { | ||
throw new IdentityError(`Unexpected response`); | ||
} | ||
const message = Buffer.concat([ | ||
Buffer.from(request.getChainId(), 'hex'), | ||
Buffer.from(res.serializedTransaction), | ||
Buffer.alloc(32), | ||
]); | ||
const { signer } = res; | ||
const signerKey = ecc.recover(res.signatures[0], message); | ||
const account = await this.rpc.get_account(signer.actor); | ||
if (!account) { | ||
throw new IdentityError(`Signature from unknown account: ${signer.actor}`); | ||
} | ||
const permission = account.permissions.find(({ perm_name }) => perm_name === signer.permission); | ||
if (!permission) { | ||
throw new IdentityError(`${signer.actor} signed for unknown permission: ${signer.permission}`); | ||
} | ||
const auth = permission.required_auth; | ||
const keyAuth = auth.keys.find(({ key }) => publicKeyEqual(key, signerKey)); | ||
if (!keyAuth) { | ||
throw new IdentityError(`${formatAuth(signer)} has no key matching id signature`); | ||
} | ||
if (auth.threshold > keyAuth.weight) { | ||
throw new IdentityError(`${formatAuth(signer)} signature does not reach auth threshold`); | ||
} | ||
if (requestPermission) { | ||
if ((requestPermission.actor !== esr.PlaceholderName && | ||
requestPermission.actor !== signer.actor) || | ||
(requestPermission.permission !== esr.PlaceholderPermission && | ||
requestPermission.permission !== signer.permission)) { | ||
throw new IdentityError(`Unexpected identity proof from ${formatAuth(signer)}, expected ${formatAuth(requestPermission)} `); | ||
} | ||
} | ||
return { | ||
...res, | ||
account, | ||
signerKey, | ||
}; | ||
} | ||
/** | ||
* Login and create a persistent session. | ||
*/ | ||
Link.prototype.login = function (sessionName) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var privateKey, requestKey, createInfo, res, metadata, session; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, ecc.randomKey()]; | ||
case 1: | ||
privateKey = _a.sent(); | ||
requestKey = ecc.privateToPublic(privateKey); | ||
createInfo = { | ||
session_name: sessionName, | ||
request_key: requestKey, | ||
}; | ||
return [4 /*yield*/, this.identify(undefined, { | ||
link: utils_1.abiEncode(createInfo, 'link_create'), | ||
})]; | ||
case 2: | ||
res = _a.sent(); | ||
metadata = { sameDevice: res.request.getRawInfo()['return_path'] !== undefined }; | ||
if (res.payload.link_ch && res.payload.link_key && res.payload.link_name) { | ||
session = new link_session_1.LinkChannelSession(this, { | ||
auth: res.signer, | ||
publicKey: res.signerKey, | ||
channel: { | ||
url: res.payload.link_ch, | ||
key: res.payload.link_key, | ||
name: res.payload.link_name, | ||
}, | ||
requestKey: privateKey, | ||
}, metadata); | ||
} | ||
else { | ||
session = new link_session_1.LinkFallbackSession(this, { | ||
auth: res.signer, | ||
publicKey: res.signerKey, | ||
}, metadata); | ||
} | ||
return [2 /*return*/, __assign(__assign({}, res), { session: session })]; | ||
} | ||
}); | ||
async login(sessionName) { | ||
const privateKey = await ecc.randomKey(); | ||
const requestKey = ecc.privateToPublic(privateKey); | ||
const createInfo = { | ||
session_name: sessionName, | ||
request_key: requestKey, | ||
}; | ||
const res = await this.identify(undefined, { | ||
link: abiEncode(createInfo, 'link_create'), | ||
}); | ||
}; | ||
const metadata = { sameDevice: res.request.getRawInfo()['return_path'] !== undefined }; | ||
let session; | ||
if (res.payload.link_ch && res.payload.link_key && res.payload.link_name) { | ||
session = new LinkChannelSession(this, { | ||
auth: res.signer, | ||
publicKey: res.signerKey, | ||
channel: { | ||
url: res.payload.link_ch, | ||
key: res.payload.link_key, | ||
name: res.payload.link_name, | ||
}, | ||
requestKey: privateKey, | ||
}, metadata); | ||
} | ||
else { | ||
session = new LinkFallbackSession(this, { | ||
auth: res.signer, | ||
publicKey: res.signerKey, | ||
}, metadata); | ||
} | ||
return { | ||
...res, | ||
session, | ||
}; | ||
} | ||
/** | ||
@@ -348,60 +226,40 @@ * Create an eosjs signature provider using this link. | ||
*/ | ||
Link.prototype.makeSignatureProvider = function (availableKeys, transport) { | ||
var _this = this; | ||
makeSignatureProvider(availableKeys, transport) { | ||
return { | ||
getAvailableKeys: function () { return __awaiter(_this, void 0, void 0, function () { return __generator(this, function (_a) { | ||
return [2 /*return*/, availableKeys]; | ||
}); }); }, | ||
sign: function (args) { return __awaiter(_this, void 0, void 0, function () { | ||
var request, signatures; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
request = esr.SigningRequest.fromTransaction(args.chainId, args.serializedTransaction, this.requestOptions); | ||
request.setCallback(this.createCallbackUrl(), true); | ||
request.setBroadcast(false); | ||
return [4 /*yield*/, this.sendRequest(request, transport)]; | ||
case 1: | ||
signatures = (_a.sent()).signatures; | ||
return [2 /*return*/, __assign(__assign({}, args), { signatures: signatures })]; | ||
} | ||
}); | ||
}); }, | ||
getAvailableKeys: async () => availableKeys, | ||
sign: async (args) => { | ||
const request = esr.SigningRequest.fromTransaction(args.chainId, args.serializedTransaction, this.requestOptions); | ||
request.setCallback(this.createCallbackUrl(), true); | ||
request.setBroadcast(false); | ||
const { signatures } = await this.sendRequest(request, transport); | ||
return { | ||
...args, | ||
signatures, | ||
}; | ||
}, | ||
}; | ||
}; | ||
} | ||
/** | ||
* Create an eosjs authority provider using this link. | ||
*/ | ||
Link.prototype.makeAuthorityProvider = function () { | ||
var rpc = this.rpc; | ||
makeAuthorityProvider() { | ||
const { rpc } = this; | ||
return { | ||
getRequiredKeys: function (args) { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var availableKeys, transaction, result; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
availableKeys = args.availableKeys, transaction = args.transaction; | ||
return [4 /*yield*/, rpc.fetch('/v1/chain/get_required_keys', { | ||
transaction: transaction, | ||
available_keys: availableKeys.map(utils_1.normalizePublicKey), | ||
})]; | ||
case 1: | ||
result = _a.sent(); | ||
return [2 /*return*/, result.required_keys.map(utils_1.normalizePublicKey)]; | ||
} | ||
}); | ||
async getRequiredKeys(args) { | ||
const { availableKeys, transaction } = args; | ||
const result = await rpc.fetch('/v1/chain/get_required_keys', { | ||
transaction, | ||
available_keys: availableKeys.map(normalizePublicKey), | ||
}); | ||
return result.required_keys.map(normalizePublicKey); | ||
}, | ||
}; | ||
}; | ||
return Link; | ||
}()); | ||
exports.Link = Link; | ||
} | ||
} | ||
function waitForCallback(url, ctx) { | ||
return new Promise(function (resolve, reject) { | ||
var active = true; | ||
var retries = 0; | ||
var socketUrl = url.replace(/^http/, 'ws'); | ||
var handleResponse = function (response) { | ||
return new Promise((resolve, reject) => { | ||
let active = true; | ||
let retries = 0; | ||
const socketUrl = url.replace(/^http/, 'ws'); | ||
const handleResponse = (response) => { | ||
try { | ||
@@ -415,25 +273,25 @@ resolve(JSON.parse(response)); | ||
}; | ||
var connect = function () { | ||
var socket = new ws_1.default(socketUrl); | ||
ctx.cancel = function () { | ||
const connect = () => { | ||
const socket = new WebSocket(socketUrl); | ||
ctx.cancel = () => { | ||
active = false; | ||
if (socket.readyState === ws_1.default.OPEN || | ||
socket.readyState === ws_1.default.CONNECTING) { | ||
if (socket.readyState === WebSocket.OPEN || | ||
socket.readyState === WebSocket.CONNECTING) { | ||
socket.close(); | ||
} | ||
}; | ||
socket.onmessage = function (event) { | ||
socket.onmessage = (event) => { | ||
active = false; | ||
if (socket.readyState === ws_1.default.OPEN) { | ||
if (socket.readyState === WebSocket.OPEN) { | ||
socket.close(); | ||
} | ||
if (typeof Blob !== 'undefined' && event.data instanceof Blob) { | ||
var reader_1 = new FileReader(); | ||
reader_1.onload = function () { | ||
handleResponse(reader_1.result); | ||
const reader = new FileReader(); | ||
reader.onload = () => { | ||
handleResponse(reader.result); | ||
}; | ||
reader_1.onerror = function (error) { | ||
reader.onerror = (error) => { | ||
reject(error); | ||
}; | ||
reader_1.readAsText(event.data); | ||
reader.readAsText(event.data); | ||
} | ||
@@ -449,7 +307,7 @@ else { | ||
}; | ||
socket.onopen = function () { | ||
socket.onopen = () => { | ||
retries = 0; | ||
}; | ||
socket.onerror = function (error) { }; | ||
socket.onclose = function (close) { | ||
socket.onerror = (error) => { }; | ||
socket.onclose = (close) => { | ||
if (active) { | ||
@@ -472,3 +330,3 @@ setTimeout(connect, backoff(retries++)); | ||
function formatAuth(auth) { | ||
var actor = auth.actor, permission = auth.permission; | ||
let { actor, permission } = auth; | ||
if (actor === esr.PlaceholderName) { | ||
@@ -480,4 +338,4 @@ actor = '<any>'; | ||
} | ||
return actor + "@" + permission; | ||
return `${actor}@${permission}`; | ||
} | ||
//# sourceMappingURL=link.js.map |
@@ -0,0 +0,0 @@ import { Bytes } from './link-abi'; |
@@ -1,34 +0,21 @@ | ||
"use strict"; | ||
var __importStar = (this && this.__importStar) || function (mod) { | ||
if (mod && mod.__esModule) return mod; | ||
var result = {}; | ||
if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) result[k] = mod[k]; | ||
result["default"] = mod; | ||
return result; | ||
}; | ||
var __importDefault = (this && this.__importDefault) || function (mod) { | ||
return (mod && mod.__esModule) ? mod : { "default": mod }; | ||
}; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var eosjs_1 = require("eosjs"); | ||
var ecc = __importStar(require("eosjs-ecc")); | ||
var link_abi_data_1 = __importDefault(require("./link-abi-data")); | ||
var types = eosjs_1.Serialize.getTypesFromAbi(eosjs_1.Serialize.createInitialTypes(), link_abi_data_1.default); | ||
function abiEncode(value, typeName) { | ||
var type = types.get(typeName); | ||
import { Numeric, Serialize } from 'eosjs'; | ||
import * as ecc from 'eosjs-ecc'; | ||
import linkAbi from './link-abi-data'; | ||
const types = Serialize.getTypesFromAbi(Serialize.createInitialTypes(), linkAbi); | ||
export function abiEncode(value, typeName) { | ||
let type = types.get(typeName); | ||
if (!type) { | ||
throw new Error("No such type: " + typeName); | ||
throw new Error(`No such type: ${typeName}`); | ||
} | ||
var buf = new eosjs_1.Serialize.SerialBuffer(); | ||
let buf = new Serialize.SerialBuffer(); | ||
type.serialize(buf, value); | ||
return buf.asUint8Array(); | ||
} | ||
exports.abiEncode = abiEncode; | ||
function abiDecode(data, typeName) { | ||
var type = types.get(typeName); | ||
export function abiDecode(data, typeName) { | ||
let type = types.get(typeName); | ||
if (!type) { | ||
throw new Error("No such type: " + typeName); | ||
throw new Error(`No such type: ${typeName}`); | ||
} | ||
if (typeof data === 'string') { | ||
data = eosjs_1.Serialize.hexToUint8Array(data); | ||
data = Serialize.hexToUint8Array(data); | ||
} | ||
@@ -38,3 +25,3 @@ else if (!(data instanceof Uint8Array)) { | ||
} | ||
var buf = new eosjs_1.Serialize.SerialBuffer({ | ||
let buf = new Serialize.SerialBuffer({ | ||
array: data, | ||
@@ -44,6 +31,5 @@ }); | ||
} | ||
exports.abiDecode = abiDecode; | ||
function sealMessage(message, privateKey, publicKey) { | ||
var res = ecc.Aes.encrypt(privateKey, publicKey, message); | ||
var data = { | ||
export function sealMessage(message, privateKey, publicKey) { | ||
const res = ecc.Aes.encrypt(privateKey, publicKey, message); | ||
const data = { | ||
from: ecc.privateToPublic(privateKey), | ||
@@ -56,16 +42,13 @@ nonce: res.nonce.toString(), | ||
} | ||
exports.sealMessage = sealMessage; | ||
/** Ensure public key is in new PUB_ format. */ | ||
function normalizePublicKey(key) { | ||
export function normalizePublicKey(key) { | ||
if (key.startsWith('PUB_')) { | ||
return key; | ||
} | ||
return eosjs_1.Numeric.publicKeyToString(eosjs_1.Numeric.stringToPublicKey('EOS' + key.substr(-50))); | ||
return Numeric.publicKeyToString(Numeric.stringToPublicKey('EOS' + key.substr(-50))); | ||
} | ||
exports.normalizePublicKey = normalizePublicKey; | ||
/** Return true if given public keys are equal. */ | ||
function publicKeyEqual(keyA, keyB) { | ||
export function publicKeyEqual(keyA, keyB) { | ||
return normalizePublicKey(keyA) === normalizePublicKey(keyB); | ||
} | ||
exports.publicKeyEqual = publicKeyEqual; | ||
//# sourceMappingURL=utils.js.map |
{ | ||
"name": "anchor-link", | ||
"version": "1.0.0", | ||
"version": "1.0.1", | ||
"description": "Library for authenticating and signing transactions using the Anchor Link protocol", | ||
"license": "MIT", | ||
"main": "./lib/index", | ||
"typings": "./lib/index", | ||
"browser": { | ||
"ws": "./ws-browser.js" | ||
}, | ||
"main": "lib/index.es5.js", | ||
"module": "lib/index.js", | ||
"unpkg": "lib/bundle.js", | ||
"types": "lib/index.d.ts", | ||
"source": "src/index.ts", | ||
"scripts": { | ||
"prepare": "make lib" | ||
"prepare": "make" | ||
}, | ||
@@ -36,2 +36,3 @@ "directories": { | ||
"fetch-ponyfill": "^6.1.0", | ||
"isomorphic-ws": "^4.0.1", | ||
"pako": "^1.0.10", | ||
@@ -42,2 +43,6 @@ "uuid": "^7.0.3", | ||
"devDependencies": { | ||
"@rollup/plugin-commonjs": "^11.0.2", | ||
"@rollup/plugin-json": "^4.0.2", | ||
"@rollup/plugin-node-resolve": "^7.1.1", | ||
"@rollup/plugin-typescript": "^4.0.0", | ||
"@types/node": "^13.9.8", | ||
@@ -49,2 +54,6 @@ "@types/pako": "^1.0.1", | ||
"prettier": "^2.0.2", | ||
"rollup": "^2.3.2", | ||
"rollup-plugin-node-polyfills": "^0.2.1", | ||
"rollup-plugin-terser": "^5.3.0", | ||
"rollup-plugin-typescript2": "^0.27.0", | ||
"ts-node": "^8.8.1", | ||
@@ -51,0 +60,0 @@ "tslint": "^6.1.0", |
@@ -5,5 +5,5 @@ import * as esr from 'eosio-signing-request' | ||
import makeFetch from 'fetch-ponyfill' | ||
import * as zlib from 'pako' | ||
import WebSocket from 'isomorphic-ws' | ||
import zlib from 'pako' | ||
import {v4 as uuid} from 'uuid' | ||
import WebSocket from 'ws' | ||
@@ -10,0 +10,0 @@ import {CancelError, IdentityError} from './errors' |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
1794711
41
3695
8
19
2
+ Addedisomorphic-ws@^4.0.1
+ Addedisomorphic-ws@4.0.1(transitive)