anchor-link
Advanced tools
Comparing version 1.0.2 to 1.0.3
@@ -244,2 +244,23 @@ 'use strict'; | ||
} | ||
/** | ||
* Generate a random private key. | ||
* Uses browser crypto if available, otherwise falls back to slow eosjs-ecc. | ||
* @internal | ||
*/ | ||
function generatePrivateKey() { | ||
return __awaiter(this, void 0, void 0, function () { | ||
var data; | ||
return __generator(this, function (_a) { | ||
switch (_a.label) { | ||
case 0: | ||
if (!(window && window.crypto)) return [3 /*break*/, 1]; | ||
data = new Uint32Array(32); | ||
window.crypto.getRandomValues(data); | ||
return [2 /*return*/, ecc.PrivateKey.fromBuffer(Buffer.from(data))]; | ||
case 1: return [4 /*yield*/, ecc.randomKey()]; | ||
case 2: return [2 /*return*/, _a.sent()]; | ||
} | ||
}); | ||
}); | ||
} | ||
@@ -572,3 +593,14 @@ /** | ||
}; | ||
/** Sign and optionally broadcast a EOSIO transaction, action or actions. */ | ||
/** | ||
* Sign and optionally broadcast a EOSIO transaction, action or actions. | ||
* | ||
* Example: | ||
* | ||
* ```ts | ||
* let result = await myLink.transact({transaction: myTx}) | ||
* ``` | ||
* | ||
* @param args The transact arguments. | ||
* @param transport Transport override, for internal use. | ||
*/ | ||
Link.prototype.transact = function (args, transport) { | ||
@@ -594,5 +626,6 @@ return __awaiter(this, void 0, void 0, function () { | ||
/** | ||
* Create a identity request. | ||
* Send an identity request and verify the identity proof. | ||
* @param requestPermission Optional request permission if the request is for a specific account or permission. | ||
* @param info Metadata to add to the request. | ||
* @note This is for advanced use-cases, you probably want to use [[Link.login]] instead. | ||
*/ | ||
@@ -664,3 +697,3 @@ Link.prototype.identify = function (requestPermission, info) { | ||
* @param identifier The session identifier, an EOSIO name (`[a-z1-5]{1,12}`). | ||
* Should be set to the contract account applicable. | ||
* Should be set to the contract account if applicable. | ||
*/ | ||
@@ -672,3 +705,3 @@ Link.prototype.login = function (identifier) { | ||
switch (_a.label) { | ||
case 0: return [4 /*yield*/, ecc.randomKey()]; | ||
case 0: return [4 /*yield*/, generatePrivateKey()]; | ||
case 1: | ||
@@ -675,0 +708,0 @@ privateKey = _a.sent(); |
@@ -45,2 +45,3 @@ import { ApiInterfaces } from 'eosjs'; | ||
} | ||
/** @internal */ | ||
interface ChannelInfo { | ||
@@ -47,0 +48,0 @@ /** Public key requests are encrypted to. */ |
@@ -45,2 +45,18 @@ import * as esr from 'eosio-signing-request'; | ||
/** | ||
* The result of a [[Link.identify]] call. | ||
*/ | ||
export interface IdentifyResult extends TransactResult { | ||
/** The identified account. */ | ||
account: object; | ||
/** The public key that signed the identity proof. */ | ||
signerKey: string; | ||
} | ||
/** | ||
* The result of a [[Link.login]] call. | ||
*/ | ||
export interface LoginResult extends IdentifyResult { | ||
/** The session created by the login. */ | ||
session: LinkSession; | ||
} | ||
/** | ||
* Main class, also exposed as the default export of the library. | ||
@@ -93,57 +109,30 @@ * | ||
sendRequest(request: esr.SigningRequest, transport?: LinkTransport, broadcast?: boolean): Promise<TransactResult>; | ||
/** Sign and optionally broadcast a EOSIO transaction, action or actions. */ | ||
/** | ||
* Sign and optionally broadcast a EOSIO transaction, action or actions. | ||
* | ||
* Example: | ||
* | ||
* ```ts | ||
* let result = await myLink.transact({transaction: myTx}) | ||
* ``` | ||
* | ||
* @param args The transact arguments. | ||
* @param transport Transport override, for internal use. | ||
*/ | ||
transact(args: TransactArgs, transport?: LinkTransport): Promise<TransactResult>; | ||
/** | ||
* Create a identity request. | ||
* Send an identity request and verify the identity proof. | ||
* @param requestPermission Optional request permission if the request is for a specific account or permission. | ||
* @param info Metadata to add to the request. | ||
* @note This is for advanced use-cases, you probably want to use [[Link.login]] instead. | ||
*/ | ||
identify(requestPermission?: esr.abi.PermissionLevel, info?: { | ||
[key: string]: string | Uint8Array; | ||
}): Promise<{ | ||
account: any; | ||
signerKey: any; | ||
/** The signing request that was sent. */ | ||
request: esr.SigningRequest; | ||
/** The transaction signatures. */ | ||
signatures: string[]; | ||
/** The callback payload. */ | ||
payload: esr.CallbackPayload; | ||
/** The signer authority. */ | ||
signer: esr.abi.PermissionLevel; | ||
/** The resulting transaction. */ | ||
transaction: esr.abi.Transaction; | ||
/** Serialized version of transaction. */ | ||
serializedTransaction: Uint8Array; | ||
/** Push transaction response from api node, only present if transaction was broadcast. */ | ||
processed?: { | ||
[key: string]: any; | ||
} | undefined; | ||
}>; | ||
}): Promise<IdentifyResult>; | ||
/** | ||
* Login and create a persistent session. | ||
* @param identifier The session identifier, an EOSIO name (`[a-z1-5]{1,12}`). | ||
* Should be set to the contract account applicable. | ||
* Should be set to the contract account if applicable. | ||
*/ | ||
login(identifier: string): Promise<{ | ||
session: LinkSession; | ||
account: any; | ||
signerKey: any; | ||
/** The signing request that was sent. */ | ||
request: esr.SigningRequest; | ||
/** The transaction signatures. */ | ||
signatures: string[]; | ||
/** The callback payload. */ | ||
payload: esr.CallbackPayload; | ||
/** The signer authority. */ | ||
signer: esr.abi.PermissionLevel; | ||
/** The resulting transaction. */ | ||
transaction: esr.abi.Transaction; | ||
/** Serialized version of transaction. */ | ||
serializedTransaction: Uint8Array; | ||
/** Push transaction response from api node, only present if transaction was broadcast. */ | ||
processed?: { | ||
[key: string]: any; | ||
} | undefined; | ||
}>; | ||
login(identifier: string): Promise<LoginResult>; | ||
/** | ||
@@ -150,0 +139,0 @@ * Restore previous session, see [[Link.login]] to create a new session. |
@@ -11,3 +11,3 @@ import * as esr from 'eosio-signing-request'; | ||
import { LinkChannelSession, LinkFallbackSession, LinkSession, } from './link-session'; | ||
import { abiEncode, normalizePublicKey, publicKeyEqual } from './utils'; | ||
import { abiEncode, normalizePublicKey, publicKeyEqual, generatePrivateKey } from './utils'; | ||
/** @internal */ | ||
@@ -163,3 +163,14 @@ const fetch = makeFetch().fetch; | ||
} | ||
/** Sign and optionally broadcast a EOSIO transaction, action or actions. */ | ||
/** | ||
* Sign and optionally broadcast a EOSIO transaction, action or actions. | ||
* | ||
* Example: | ||
* | ||
* ```ts | ||
* let result = await myLink.transact({transaction: myTx}) | ||
* ``` | ||
* | ||
* @param args The transact arguments. | ||
* @param transport Transport override, for internal use. | ||
*/ | ||
async transact(args, transport) { | ||
@@ -173,5 +184,6 @@ const t = transport || this.transport; | ||
/** | ||
* Create a identity request. | ||
* Send an identity request and verify the identity proof. | ||
* @param requestPermission Optional request permission if the request is for a specific account or permission. | ||
* @param info Metadata to add to the request. | ||
* @note This is for advanced use-cases, you probably want to use [[Link.login]] instead. | ||
*/ | ||
@@ -227,6 +239,6 @@ async identify(requestPermission, info) { | ||
* @param identifier The session identifier, an EOSIO name (`[a-z1-5]{1,12}`). | ||
* Should be set to the contract account applicable. | ||
* Should be set to the contract account if applicable. | ||
*/ | ||
async login(identifier) { | ||
const privateKey = await ecc.randomKey(); | ||
const privateKey = await generatePrivateKey(); | ||
const requestKey = ecc.privateToPublic(privateKey); | ||
@@ -233,0 +245,0 @@ const createInfo = { |
@@ -27,1 +27,7 @@ import { Bytes } from './link-abi'; | ||
export declare function publicKeyEqual(keyA: string, keyB: string): boolean; | ||
/** | ||
* Generate a random private key. | ||
* Uses browser crypto if available, otherwise falls back to slow eosjs-ecc. | ||
* @internal | ||
*/ | ||
export declare function generatePrivateKey(): Promise<any>; |
@@ -70,2 +70,17 @@ import { Numeric, Serialize } from 'eosjs'; | ||
} | ||
/** | ||
* Generate a random private key. | ||
* Uses browser crypto if available, otherwise falls back to slow eosjs-ecc. | ||
* @internal | ||
*/ | ||
export async function generatePrivateKey() { | ||
if (window && window.crypto) { | ||
const data = new Uint32Array(32); | ||
window.crypto.getRandomValues(data); | ||
return ecc.PrivateKey.fromBuffer(Buffer.from(data)); | ||
} | ||
else { | ||
return await ecc.randomKey(); | ||
} | ||
} | ||
//# sourceMappingURL=utils.js.map |
{ | ||
"name": "anchor-link", | ||
"version": "1.0.2", | ||
"version": "1.0.3", | ||
"description": "Library for authenticating and signing transactions using the Anchor Link protocol", | ||
@@ -28,4 +28,3 @@ "license": "MIT", | ||
"lib/*", | ||
"src/*", | ||
"ws-browser.js" | ||
"src/*" | ||
], | ||
@@ -32,0 +31,0 @@ "dependencies": { |
132
README.md
@@ -6,23 +6,13 @@ # Anchor Link [](https://www.npmjs.com/package/anchor-link)  | ||
Key features: | ||
- Persistent sessions | ||
- Cross device signing | ||
- End to end encryption | ||
- Cross device signing | ||
- Persistent sessions | ||
- Open standard | ||
Take it for a spin: [Anchor Link Demo](#todo) | ||
Resources: | ||
- [API Documentation](https://greymass.github.io/anchor-link) | ||
- [Protocol specification](#todo) | ||
- [Protocol specification](./protocol.md) | ||
- [Usage examples](./examples) | ||
- [Developer chat](#todo) | ||
- [Developer chat](https://t.me/anchor_link) | ||
## Protocol | ||
The Anchor Link protocol uses EEP-7 identity requests to establish a channel to compatible wallets using an untrusted HTTP POST to WebSocket forwarder (see [buoy node.js](https://github.com/greymass/buoy-nodejs) and [buoy golang](https://github.com/greymass/buoy-golang)). | ||
A session key and unique channel URL is generated by the client which is attached to the identity request and sent to the wallet (see [transports](#transports)). The wallet signs the identity proof and sends it back along with its own channel URL and session key. Subsequent signature requests can now be encrypted to a shared secret derived from the two keys and pushed directly to the wallet channel. | ||
[📘 Full Protocol specification](./docs/protocol.md) | ||
## Installation | ||
@@ -49,4 +39,2 @@ | ||
Jump to [basic usage](#basic-usage). | ||
### Browser using a pre-built bundle | ||
@@ -65,10 +53,61 @@ | ||
Using node.js or bundler (e.g. webpack) **recommended** | ||
Using node.js | ||
``` | ||
yarn add anchor-link | ||
yarn add anchor-link anchor-link-console-transport | ||
# or | ||
npm install --save anchor-link anchor-link-console-transport | ||
``` | ||
Import them into your project: | ||
```js | ||
const AnchorLink = require('anchor-link') | ||
const AnchorLinkConsoleTransport = require('anchor-link-browser-transport') | ||
``` | ||
## Basic usage | ||
First you need to instantiate your transport and the link. | ||
```ts | ||
const transport = new AnchorLinkBrowserTransport() | ||
const link = new AnchorLink({transport}) | ||
``` | ||
Now you're ready to create signing requests for EOS main-net (see [options](#options) for how to use it on other networks). | ||
```ts | ||
const action = { | ||
account: 'eosio', | ||
name: 'voteproducer', | ||
authorization: [{ | ||
actor: '............1', // ............1 will be resolved to the signing accounts permission | ||
permission: '............2' // ............2 will be resolved to the signing accounts authority | ||
}], | ||
data: { | ||
voter: '............1', // same here | ||
proxy: 'greymassvote', | ||
producers: [], | ||
} | ||
} | ||
link.transact({action, broadcast: true}).then((result) => { | ||
console.log(`Transaction broadcast! Transaction id: ${ result.processed.id }`) | ||
}) | ||
``` | ||
See the [Link.transact API docs](https://greymass.github.io/anchor-link/classes/link.html#transact) for all options and return values. | ||
To create a persistent login session use [Link.login](https://greymass.github.io/anchor-link/classes/link.html#login), example: | ||
```ts | ||
link.login('mydapp').then(({session}) => { | ||
session.transact({action, broadcast: true}).then((result) => { | ||
console.log(`Transaction broadcast! Transaction id: ${ result.processed.id }`) | ||
}) | ||
}) | ||
``` | ||
You can find more examples in the [examples directory](./examples) in the root of this repository. | ||
## Transports | ||
@@ -87,57 +126,22 @@ | ||
## Installation | ||
## Protocol | ||
The Anchor Link protocol uses EEP-7 identity requests to establish a channel to compatible wallets using an untrusted HTTP POST to WebSocket forwarder (see [buoy node.js](https://github.com/greymass/buoy-nodejs) and [buoy golang](https://github.com/greymass/buoy-golang)). | ||
A session key and unique channel URL is generated by the client which is attached to the identity request and sent to the wallet (see [transports](#transports)). The wallet signs the identity proof and sends it back along with its own channel URL and session key. Subsequent signature requests can now be encrypted to a shared secret derived from the two keys and pushed directly to the wallet channel. | ||
[📘 Protocol specification](./protocol.md) | ||
## Developing | ||
You need [Make](https://www.gnu.org/software/make/), [node.js](https://nodejs.org/en/) and [yarn](https://classic.yarnpkg.com/en/docs/install) installed. | ||
Take it for a spin | ||
Clone the repository and run `make` to checkout all dependencies and build the project. See the [Makefile](./Makefile) for other useful targets. Before submitting a pull request make sure to run `make lint`. | ||
Download [Anchor](https://greymass.com/en/projects) | ||
## License | ||
Persistent signing sessions for [Anchor]* | ||
[MIT](./LICENSE.md) | ||
--- | ||
Persistent Session library for ESR | ||
EOSIO | ||
Example usage: | ||
```ts | ||
import {Link} from 'anchor-link' | ||
const link = new Link({ | ||
chainId: 'e70aaab8997e1dfce58fbfac80cbbb8fecec7b99cf982a9444273cbc64c41473', | ||
rpc: 'https://jungle.greymass.com', | ||
service: 'https://link.dirty.fish', | ||
}) | ||
link.transact({ | ||
broadcast: true, | ||
action: { | ||
account: 'eosio.token', | ||
name: 'transfer', | ||
authorization: [ | ||
{ | ||
actor: '............1', | ||
permission: '............1', | ||
}, | ||
], | ||
data: { | ||
from: '............1', | ||
to: 'teamgreymass', | ||
quantity: '0.0001 EOS', | ||
memo: 'nani', | ||
}, | ||
}, | ||
}) | ||
.then((result) => { | ||
console.log('success', result) | ||
}) | ||
.catch((error) => { | ||
console.log('error', error) | ||
}) | ||
``` | ||
Made with ☕️&❤️ by [team Greymass](https://greymass.com), if you find this useful please consider [supporting us](https://greymass.com/en/support). |
@@ -58,2 +58,3 @@ import {SigningRequest} from 'eosio-signing-request' | ||
/** @internal */ | ||
interface ChannelInfo { | ||
@@ -60,0 +61,0 @@ /** Public key requests are encrypted to. */ |
@@ -19,3 +19,3 @@ import * as esr from 'eosio-signing-request' | ||
import {LinkTransport} from './link-transport' | ||
import {abiEncode, normalizePublicKey, publicKeyEqual} from './utils' | ||
import {abiEncode, normalizePublicKey, publicKeyEqual, generatePrivateKey} from './utils' | ||
@@ -64,2 +64,20 @@ /** @internal */ | ||
/** | ||
* The result of a [[Link.identify]] call. | ||
*/ | ||
export interface IdentifyResult extends TransactResult { | ||
/** The identified account. */ | ||
account: object | ||
/** The public key that signed the identity proof. */ | ||
signerKey: string | ||
} | ||
/** | ||
* The result of a [[Link.login]] call. | ||
*/ | ||
export interface LoginResult extends IdentifyResult { | ||
/** The session created by the login. */ | ||
session: LinkSession | ||
} | ||
/** | ||
* Main class, also exposed as the default export of the library. | ||
@@ -236,3 +254,14 @@ * | ||
/** Sign and optionally broadcast a EOSIO transaction, action or actions. */ | ||
/** | ||
* Sign and optionally broadcast a EOSIO transaction, action or actions. | ||
* | ||
* Example: | ||
* | ||
* ```ts | ||
* let result = await myLink.transact({transaction: myTx}) | ||
* ``` | ||
* | ||
* @param args The transact arguments. | ||
* @param transport Transport override, for internal use. | ||
*/ | ||
public async transact(args: TransactArgs, transport?: LinkTransport): Promise<TransactResult> { | ||
@@ -247,5 +276,6 @@ const t = transport || this.transport | ||
/** | ||
* Create a identity request. | ||
* Send an identity request and verify the identity proof. | ||
* @param requestPermission Optional request permission if the request is for a specific account or permission. | ||
* @param info Metadata to add to the request. | ||
* @note This is for advanced use-cases, you probably want to use [[Link.login]] instead. | ||
*/ | ||
@@ -255,3 +285,3 @@ public async identify( | ||
info?: {[key: string]: string | Uint8Array} | ||
) { | ||
): Promise<IdentifyResult> { | ||
const request = await this.createRequest({ | ||
@@ -316,6 +346,6 @@ identity: {permission: requestPermission || null}, | ||
* @param identifier The session identifier, an EOSIO name (`[a-z1-5]{1,12}`). | ||
* Should be set to the contract account applicable. | ||
* Should be set to the contract account if applicable. | ||
*/ | ||
public async login(identifier: string) { | ||
const privateKey = await ecc.randomKey() | ||
public async login(identifier: string): Promise<LoginResult> { | ||
const privateKey = await generatePrivateKey() | ||
const requestKey = ecc.privateToPublic(privateKey) | ||
@@ -322,0 +352,0 @@ const createInfo: LinkCreate = { |
@@ -77,1 +77,16 @@ import {Numeric, Serialize} from 'eosjs' | ||
} | ||
/** | ||
* Generate a random private key. | ||
* Uses browser crypto if available, otherwise falls back to slow eosjs-ecc. | ||
* @internal | ||
*/ | ||
export async function generatePrivateKey() { | ||
if (window && window.crypto) { | ||
const data = new Uint32Array(32) | ||
window.crypto.getRandomValues(data) | ||
return ecc.PrivateKey.fromBuffer(Buffer.from(data)) | ||
} else { | ||
return await ecc.randomKey() | ||
} | ||
} |
Sorry, the diff of this file is too big to display
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
1861122
4434
144
40