New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

anchor-link

Package Overview
Dependencies
Maintainers
2
Versions
63
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

anchor-link - npm Package Compare versions

Comparing version 0.1.0 to 0.2.0

lib/console-transport.d.ts

53

lib/errors.js
"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. */
class CancelError extends Error {
constructor(reason) {
super(`User canceled request ${reason ? '(' + reason + ')' : ''}`);
this.code = 'E_CANCEL';
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;
}
}
return CancelError;
}(Error));
exports.CancelError = CancelError;
/** Error that is thrown if an identity request fails to verify. */
class IdentityError extends Error {
constructor(reason) {
super(`Unable to verify identity ${reason ? '(' + reason + ')' : ''}`);
this.code = 'E_IDENTITY';
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;
}
}
return IdentityError;
}(Error));
exports.IdentityError = IdentityError;
/** Error that is thrown by session transport. */
class SessionError extends Error {
constructor(reason, code) {
super(reason);
this.code = code;
var SessionError = /** @class */ (function (_super) {
__extends(SessionError, _super);
function SessionError(reason, code) {
var _this = _super.call(this, reason) || this;
_this.code = code;
return _this;
}
}
return SessionError;
}(Error));
exports.SessionError = SessionError;
//# sourceMappingURL=errors.js.map

@@ -9,1 +9,2 @@ "use strict";

__export(require("./errors"));
//# sourceMappingURL=index.js.map

@@ -6,2 +6,6 @@ import { ChainName } from 'eosio-signing-request';

/**
* Link transport responsible for presenting signing requests to user, required.
*/
transport: LinkTransport;
/**
* ChainID or esr chain name alias for which the link is valid.

@@ -17,3 +21,3 @@ * Defaults to EOS (aca376f206b8fc25a6ed44dbdc66547c36c6c33e3a119ffbeaef943642f0e906).

/**
* URL to link service.
* URL to link callback service.
* Defaults to https://cb.anchor.link.

@@ -23,6 +27,2 @@ */

/**
* Link transport, defaults to a console transport if omitted.
*/
transport?: LinkTransport;
/**
* Text encoder, only needed in old browsers or if used in node.js versions prior to v13.

@@ -29,0 +29,0 @@ */

@@ -8,1 +8,2 @@ "use strict";

};
//# sourceMappingURL=link-options.js.map

@@ -1,6 +0,39 @@

/// <reference types="node" />
import { ApiInterfaces } from 'eosjs';
import { EventEmitter } from 'events';
import { Link, TransactArgs } from './link';
export interface LinkSessionData {
import { LinkTransport } from './link-transport';
/**
* Type describing a link session that can create a eosjs compatible
* signature provider and transact for a specific auth.
*/
export declare abstract class LinkSession {
/** The underlying link instance used by the session. */
abstract link: Link;
/** The public key the session can sign for. */
abstract publicKey: string;
/** The EOSIO auth (a.k.a. permission level) the session can sign for. */
abstract auth: {
actor: string;
permission: string;
};
/** Creates a eosjs compatible signature provider that can sign for the session public key. */
abstract makeSignatureProvider(): ApiInterfaces.SignatureProvider;
/**
* Transact using this session.
* @see Link#transact
*/
abstract transact(args: TransactArgs): any;
/** Returns a JSON-encodable object that can be passed to the constructor to recreate the session. */
abstract serialize(): any;
/** Restore a previously serialized session. */
static restore(link: Link, data: any): LinkSession;
}
interface ChannelInfo {
/** Public key requests are encrypted to. */
key: string;
/** The wallet given channel name, usually the device name. */
name: string;
/** The channel push url. */
url: string;
}
export interface LinkChannelSessionData {
/** Authenticated user permission. */

@@ -13,15 +46,11 @@ auth: {

publicKey: string;
/** The Wallet channel. */
channel: string;
/** The public key used to encrypt requests. */
channelKey: string;
/** The sequence number the channel is on. */
channelSequence: number;
/** The private key used to sign requests */
privateKey: string;
/** The wallet channel url. */
channel: ChannelInfo;
/** The private request key. */
requestKey: string;
}
/**
* Link session, emits 'info' event when sequence number advances.
* Link session that pushes requests over a channel.
*/
export declare class LinkSession extends EventEmitter {
export declare class LinkChannelSession extends LinkSession implements LinkTransport {
readonly link: Link;

@@ -33,8 +62,32 @@ readonly auth: {

readonly publicKey: string;
private transport;
private exporter;
constructor(link: Link, data: LinkSessionData);
export(): LinkSessionData;
serialize: () => LinkChannelSessionData;
private channel;
private timeout;
private encrypt;
constructor(link: Link, data: LinkChannelSessionData);
onSuccess(request: any, result: any): void;
onFailure(request: any, error: any): void;
onRequest(request: any, cancel: any): void;
makeSignatureProvider(): ApiInterfaces.SignatureProvider;
transact(args: TransactArgs): Promise<import("./link").TransactResult>;
}
export interface LinkFallbackSessionData {
auth: {
actor: string;
permission: string;
};
publicKey: string;
}
export declare class LinkFallbackSession extends LinkSession {
readonly link: Link;
readonly auth: {
actor: string;
permission: string;
};
readonly publicKey: string;
serialize: () => LinkFallbackSessionData;
constructor(link: Link, data: LinkFallbackSessionData);
transact(args: TransactArgs): Promise<import("./link").TransactResult>;
makeSignatureProvider(): ApiInterfaces.SignatureProvider;
}
export {};
"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 __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 });
const ecc = __importStar(require("eosjs-ecc"));
const events_1 = require("events");
const errors_1 = require("./errors");
const utils_1 = require("./utils");
function sealMessage(message, privateKey, publicKey) {
const res = ecc.Aes.encrypt(privateKey, publicKey, message);
const data = {
from: ecc.privateToPublic(privateKey),
nonce: res.nonce.toString(),
ciphertext: res.message,
checksum: res.checksum,
var errors_1 = require("./errors");
var utils_1 = require("./utils");
/**
* Type describing a link session that can create a eosjs compatible
* signature provider and transact for a specific auth.
*/
var LinkSession = /** @class */ (function () {
function LinkSession() {
}
/** Restore a previously serialized session. */
LinkSession.restore = function (link, data) {
switch (data.type) {
case 'channel':
return new LinkChannelSession(link, data);
case 'fallback':
return new LinkFallbackSession(link, data);
default:
throw new Error('Unable to restore, session data invalid');
}
};
return utils_1.abiEncode(data, 'sealed_message');
}
return LinkSession;
}());
exports.LinkSession = LinkSession;
/**
* Link session, emits 'info' event when sequence number advances.
* Link session that pushes requests over a channel.
*/
class LinkSession extends events_1.EventEmitter {
constructor(link, data) {
super();
this.link = link;
this.auth = data.auth;
this.publicKey = data.publicKey;
// private key never leaves closure unless exported explicitly
let seq = data.channelSequence;
this.exporter = () => ({ ...data, channelSequence: seq });
const { privateKey, channel, channelKey } = data;
const signatureProvider = {
sign(message) {
const signature = ecc.signHash(message, privateKey);
return { signer: '', signature };
},
var LinkChannelSession = /** @class */ (function (_super) {
__extends(LinkChannelSession, _super);
function LinkChannelSession(link, data) {
var _this = _super.call(this) || this;
_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);
};
this.transport = {
onSuccess: (request, result) => {
if (this.link.transport.onSuccess) {
this.link.transport.onSuccess(request, result);
}
_this.serialize = function () { return (__assign({ type: 'channel' }, data)); };
return _this;
}
LinkChannelSession.prototype.onSuccess = function (request, result) {
if (this.link.transport.onSuccess) {
this.link.transport.onSuccess(request, result);
}
};
LinkChannelSession.prototype.onFailure = function (request, error) {
if (this.link.transport.onFailure) {
this.link.transport.onFailure(request, error);
}
};
LinkChannelSession.prototype.onRequest = function (request, cancel) {
var info = {
expiration: new Date(Date.now() + this.timeout).toISOString().slice(0, -1),
};
if (this.link.transport.onSessionRequest) {
this.link.transport.onSessionRequest(this, request, this.timeout, this.channel.name, cancel);
}
setTimeout(function () {
cancel(new errors_1.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'),
});
this.link.rpc
.fetchBuiltin(this.channel.url, {
method: 'POST',
headers: {
'X-Buoy-Wait': (this.timeout / 1000).toFixed(0),
},
onFailure: (request, error) => {
if (this.link.transport.onFailure) {
this.link.transport.onFailure(request, error);
}
},
onRequest: (request, cancel) => {
seq++;
let info = { seq };
this.emit('info', info);
request.data.info.push({ key: 'link', value: utils_1.abiEncode(info, 'link_info') });
request.sign(signatureProvider);
this.link.rpc
.fetchBuiltin(channel, {
method: 'POST',
headers: {
'X-Buoy-Wait': '60',
},
body: sealMessage(request.encode(), privateKey, channelKey),
})
.then((response) => {
if (response.status !== 200) {
cancel(new errors_1.SessionError('Unable to push message', 'E_DELIVERY'));
}
else {
setTimeout(() => {
cancel(new errors_1.SessionError('Wallet did not respond in time', 'E_TIMEOUT'));
}, 30 * 1000);
}
})
.catch((error) => {
cancel(new errors_1.SessionError(`Unable to reach link service (${error.message || String(error)})`, 'E_DELIVERY'));
});
},
};
body: this.encrypt(request),
})
.then(function (response) {
if (response.status !== 200) {
cancel(new errors_1.SessionError('Unable to push message', 'E_DELIVERY'));
}
else {
// request delivered
}
})
.catch(function (error) {
cancel(new errors_1.SessionError("Unable to reach link service (" + (error.message || String(error)) + ")", 'E_DELIVERY'));
});
};
LinkChannelSession.prototype.makeSignatureProvider = function () {
return this.link.makeSignatureProvider([this.publicKey], this);
};
LinkChannelSession.prototype.transact = function (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) {
var _this = _super.call(this) || this;
_this.link = link;
_this.auth = data.auth;
_this.publicKey = data.publicKey;
_this.serialize = function () { return (__assign({ type: 'fallback' }, data)); };
return _this;
}
export() {
return this.exporter();
}
makeSignatureProvider() {
return this.link.makeSignatureProvider([this.publicKey], this.transport);
}
transact(args) {
return this.link.transact(args, this.transport);
}
}
exports.LinkSession = LinkSession;
LinkFallbackSession.prototype.transact = function (args) {
return this.link.transact(args);
};
LinkFallbackSession.prototype.makeSignatureProvider = function () {
return this.link.makeSignatureProvider([this.publicKey]);
};
return LinkFallbackSession;
}(LinkSession));
exports.LinkFallbackSession = LinkFallbackSession;
//# sourceMappingURL=link-session.js.map
import { SigningRequest } from 'eosio-signing-request';
import { TransactResult } from './link';
import { LinkSession } from './link-session';
/**

@@ -19,9 +20,10 @@ * Protocol link transports need to implement.

onFailure?(request: SigningRequest, error: Error): any;
/**
* Called when a session request is initiated.
* @param session Session where the request originated.
* @param request Signing request that will be sent over the session.
* @param timeout Number of milliseconds until session request expires.
* @param device Display name of linked device.
*/
onSessionRequest?(session: LinkSession, request: SigningRequest, timeout: number, device: string, cancel: (reason: string | Error) => void): any;
}
/**
* A signing request presenter that writes requests
* as URI strings and ASCII qr codes to console.log.
*/
export declare class ConsoleTransport implements LinkTransport {
onRequest(request: SigningRequest): void;
}
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const qrcode_terminal_1 = __importDefault(require("qrcode-terminal"));
/**
* A signing request presenter that writes requests
* as URI strings and ASCII qr codes to console.log.
*/
class ConsoleTransport {
onRequest(request) {
const uri = request.encode();
console.log(`Signing request\n${uri}`);
qrcode_terminal_1.default.setErrorLevel('L');
qrcode_terminal_1.default.generate(uri, { small: true }, (code) => {
console.log(code);
});
}
}
exports.ConsoleTransport = ConsoleTransport;
//# sourceMappingURL=link-transport.js.map

@@ -51,3 +51,3 @@ import * as esr from 'eosio-signing-request';

private abiCache;
constructor(options?: LinkOptions);
constructor(options: LinkOptions);
getAbi(account: string): Promise<any>;

@@ -54,0 +54,0 @@ createCallbackUrl(): string;

"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) {

@@ -13,17 +60,16 @@ if (mod && mod.__esModule) return mod;

Object.defineProperty(exports, "__esModule", { value: true });
const esr = __importStar(require("eosio-signing-request"));
const eosjs_1 = require("eosjs");
const ecc = __importStar(require("eosjs-ecc"));
const fetch_ponyfill_1 = __importDefault(require("fetch-ponyfill"));
const zlib = __importStar(require("pako"));
const v4_1 = __importDefault(require("uuid/v4"));
const ws_1 = __importDefault(require("ws"));
const errors_1 = require("./errors");
const link_options_1 = require("./link-options");
const link_session_1 = require("./link-session");
const link_transport_1 = require("./link-transport");
const utils_1 = require("./utils");
const { fetch } = fetch_ponyfill_1.default();
class Link {
constructor(options = {}) {
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 v4_1 = __importDefault(require("uuid/v4"));
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) {
this.abiCache = new Map();

@@ -38,3 +84,3 @@ if (options.rpc === undefined || typeof options.rpc === 'string') {

this.serviceAddress = (options.service || link_options_1.defaults.service).trim().replace(/\/$/, '');
this.transport = options.transport || new link_transport_1.ConsoleTransport();
this.transport = options.transport;
this.requestOptions = {

@@ -44,103 +90,143 @@ abiProvider: this,

textEncoder: options.textEncoder || new TextEncoder(),
zlib,
zlib: zlib,
};
}
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}/${v4_1.default()}`;
}
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 errors_1.CancelError(reason));
}
else {
reject(reason);
}
});
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];
}
});
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,
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.createCallbackUrl = function () {
return this.serviceAddress + "/" + v4_1.default();
};
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];
}
});
result.processed = res.processed;
}
return result;
}
});
};
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: 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];
}
});
});
};
/**

@@ -151,72 +237,100 @@ * Create a identity request.

*/
async identify(requestPermission, info) {
const request = await this.createRequest({
identity: { permission: requestPermission },
info,
Link.prototype.identify = function (requestPermission, info) {
return __awaiter(this, void 0, void 0, function () {
var request, res, serializedTransaction, 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 },
info: info,
})];
case 1:
request = _a.sent();
return [4 /*yield*/, this.sendRequest(request)];
case 2:
res = _a.sent();
return [4 /*yield*/, esr.ResolvedSigningRequest.fromPayload(res.payload, this.requestOptions)];
case 3:
serializedTransaction = (_a.sent()).serializedTransaction;
message = Buffer.concat([
Buffer.from(request.getChainId(), 'hex'),
Buffer.from(serializedTransaction),
Buffer.alloc(32),
]);
signer = res.signer;
signerKey = ecc.recover(res.signatures[0], message);
return [4 /*yield*/, this.rpc.get_account(signer.actor)];
case 4:
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 key === signerKey;
});
if (!keyAuth) {
throw new errors_1.IdentityError(signer.actor + "@" + signer.permission + " has no key matching id signature");
}
if (auth.threshold > keyAuth.weight) {
throw new errors_1.IdentityError(signer.actor + "@" + signer.permission + " signature does not reach auth threshold");
}
return [2 /*return*/, __assign(__assign({}, res), { account: account,
signerKey: signerKey })];
}
});
});
const res = await this.sendRequest(request);
const { serializedTransaction } = await esr.ResolvedSigningRequest.fromPayload(res.payload, this.requestOptions);
const message = Buffer.concat([
Buffer.from(request.getChainId(), 'hex'),
Buffer.from(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 errors_1.IdentityError(`Signature from unknown account: ${signer.actor}`);
}
const permission = account.permissions.find(({ perm_name }) => perm_name === signer.permission);
if (!permission) {
throw new errors_1.IdentityError(`${signer.actor} signed for unknown permission: ${signer.permission}`);
}
const auth = permission.required_auth;
const keyAuth = auth.keys.find(({ key }) => key === signerKey);
if (!keyAuth) {
throw new errors_1.IdentityError(`${signer.actor}@${signer.permission} has no key matching id signature`);
}
if (auth.threshold > keyAuth.weight) {
throw new errors_1.IdentityError(`${signer.actor}@${signer.permission} signature does not reach auth threshold`);
}
return {
...res,
account,
signerKey,
};
}
};
/**
* Login and create a persistent 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: utils_1.abiEncode(createInfo, 'link_create'),
Link.prototype.login = function (sessionName) {
return __awaiter(this, void 0, void 0, function () {
var privateKey, requestKey, createInfo, res, 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();
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,
});
}
else {
session = new link_session_1.LinkFallbackSession(this, {
auth: res.signer,
publicKey: res.signerKey,
});
}
return [2 /*return*/, __assign(__assign({}, res), { session: session })];
}
});
});
let session;
if (res.payload.link_ch && res.payload.link_key) {
let data = {
auth: res.signer,
publicKey: res.signerKey,
channel: res.payload.link_ch,
channelKey: res.payload.link_key,
channelSequence: 0,
privateKey,
};
session = new link_session_1.LinkSession(this, data);
}
else {
/// todo fallback session using current transport
throw new Error('User wallet not link compatible');
}
return {
...res,
session,
};
}
};
/**

@@ -226,25 +340,34 @@ * Create an eosjs signature provider using this link.

*/
makeSignatureProvider(availableKeys, transport) {
Link.prototype.makeSignatureProvider = function (availableKeys, transport) {
var _this = this;
return {
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,
};
},
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 })];
}
});
}); },
};
}
}
};
return Link;
}());
exports.Link = Link;
function waitForCallback(url, ctx) {
return new Promise((resolve, reject) => {
let active = true;
let retries = 0;
const socketUrl = url.replace(/^http/, 'ws');
const handleResponse = (response) => {
return new Promise(function (resolve, reject) {
var active = true;
var retries = 0;
var socketUrl = url.replace(/^http/, 'ws');
var handleResponse = function (response) {
try {

@@ -258,5 +381,5 @@ resolve(JSON.parse(response));

};
const connect = () => {
const socket = new ws_1.default(socketUrl);
ctx.cancel = () => {
var connect = function () {
var socket = new ws_1.default(socketUrl);
ctx.cancel = function () {
active = false;

@@ -268,3 +391,3 @@ if (socket.readyState === ws_1.default.OPEN ||

};
socket.onmessage = (event) => {
socket.onmessage = function (event) {
active = false;

@@ -275,10 +398,10 @@ if (socket.readyState === ws_1.default.OPEN) {

if (typeof Blob !== 'undefined' && event.data instanceof Blob) {
const reader = new FileReader();
reader.onload = () => {
handleResponse(reader.result);
var reader_1 = new FileReader();
reader_1.onload = function () {
handleResponse(reader_1.result);
};
reader.onerror = (error) => {
reader_1.onerror = function (error) {
reject(error);
};
reader.readAsText(event.data);
reader_1.readAsText(event.data);
}

@@ -294,7 +417,7 @@ else {

};
socket.onopen = () => {
socket.onopen = function () {
retries = 0;
};
socket.onerror = (error) => { };
socket.onclose = (close) => {
socket.onerror = function (error) { };
socket.onclose = function (close) {
if (active) {

@@ -315,1 +438,2 @@ setTimeout(connect, backoff(retries++));

}
//# sourceMappingURL=link.js.map
import { Bytes } from './link-abi';
export declare function abiEncode(value: any, typeName: string): Uint8Array;
export declare function abiDecode<T = any>(data: Bytes, typeName: string): T;
export declare function abiDecode<ResultType = any>(data: Bytes, typeName: string): ResultType;
export declare function sealMessage(message: string, privateKey: string, publicKey: string): Uint8Array;

@@ -9,12 +9,16 @@ "use strict";

};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
const eosjs_1 = require("eosjs");
const linkAbi = __importStar(require("./link-abi.json"));
const types = eosjs_1.Serialize.getTypesFromAbi(eosjs_1.Serialize.createInitialTypes(), linkAbi);
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) {
let type = types.get(typeName);
var type = types.get(typeName);
if (!type) {
throw new Error(`No such type: ${type}`);
throw new Error("No such type: " + typeName);
}
let buf = new eosjs_1.Serialize.SerialBuffer();
var buf = new eosjs_1.Serialize.SerialBuffer();
type.serialize(buf, value);

@@ -25,5 +29,5 @@ return buf.asUint8Array();

function abiDecode(data, typeName) {
let type = types.get(typeName);
var type = types.get(typeName);
if (!type) {
throw new Error(`No such type: ${type}`);
throw new Error("No such type: " + typeName);
}

@@ -36,3 +40,3 @@ if (typeof data === 'string') {

}
let buf = new eosjs_1.Serialize.SerialBuffer({
var buf = new eosjs_1.Serialize.SerialBuffer({
array: data,

@@ -43,1 +47,13 @@ });

exports.abiDecode = abiDecode;
function sealMessage(message, privateKey, publicKey) {
var res = ecc.Aes.encrypt(privateKey, publicKey, message);
var data = {
from: ecc.privateToPublic(privateKey),
nonce: res.nonce.toString(),
ciphertext: res.message,
checksum: res.checksum,
};
return abiEncode(data, 'sealed_message');
}
exports.sealMessage = sealMessage;
//# sourceMappingURL=utils.js.map
{
"name": "anchor-link",
"version": "0.1.0",
"version": "0.2.0",
"description": "Library for authenticating and signing transactions using the Anchor Link protocol",

@@ -14,2 +14,14 @@ "license": "MIT",

},
"directories": {
"lib": "lib"
},
"repository": {
"type": "git",
"url": "git+https://github.com/greymass/anchor-link.git"
},
"author": "",
"bugs": {
"url": "https://github.com/greymass/anchor-link/issues"
},
"homepage": "https://github.com/greymass/anchor-link#readme",
"files": [

@@ -20,3 +32,3 @@ "lib/*",

"dependencies": {
"eosio-signing-request": "1.0.0",
"eosio-signing-request": "1.0.1",
"eosjs": "^20.0.0",

@@ -31,6 +43,7 @@ "eosjs-ecc": "^4.0.7",

"devDependencies": {
"@types/node": "^12.12.21",
"@types/node": "^13.1.7",
"@types/pako": "^1.0.1",
"@types/uuid": "^3.4.6",
"@types/ws": "^6.0.4",
"@types/ws": "^7.2.0",
"eosio-abi2ts": "^1.2.2",
"prettier": "^1.19.1",

@@ -42,15 +55,3 @@ "ts-node": "^8.5.3",

"typescript": "^3.7.4"
},
"directories": {
"lib": "lib"
},
"repository": {
"type": "git",
"url": "git+https://github.com/greymass/anchor-link.git"
},
"author": "",
"bugs": {
"url": "https://github.com/greymass/anchor-link/issues"
},
"homepage": "https://github.com/greymass/anchor-link#readme"
}
}
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc