Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Version 1.0.0 #13

Merged
merged 14 commits into from
Feb 13, 2021
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ual-anchor",
"version": "0.5.1",
"version": "1.0.0",
"main": "dist/index.js",
"license": "MIT",
"author": {
Expand All @@ -19,8 +19,9 @@
"test": "jest"
},
"dependencies": {
"anchor-link": "^2.1.0",
"anchor-link-browser-transport": "^2.1.0",
"@greymass/eosio": "^0.2.5",
"anchor-link": "^3.0.3",
"anchor-link-browser-transport": "^3.0.0",
"elliptic": "6.5.2",
"eosjs": "^20.0.3",
"universal-authenticator-library": "0.3.0"
Expand Down
44 changes: 37 additions & 7 deletions src/Anchor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {

import AnchorLink from 'anchor-link'
import { JsonRpc } from 'eosjs'
import { APIClient, FetchProvider } from '@greymass/eosio'
import { Name } from './interfaces'
import { AnchorUser } from './AnchorUser'
import { AnchorLogo } from './AnchorLogo'
Expand All @@ -14,6 +15,8 @@ import AnchorLinkBrowserTransport from 'anchor-link-browser-transport'
export interface UALAnchorOptions {
// The app name, required by anchor-link. Short string identifying the app
appName: string
// A APIClient object from @greymass/eosio. If not specified, it'll be created using the JsonRpc endpoint
client?: APIClient
// Either a JsonRpc instance from eosjs or the url for an API to connect a new JsonRpc instance to
rpc?: JsonRpc
// The callback service URL to use, defaults to https://cb.anchor.link
Expand All @@ -22,11 +25,17 @@ export interface UALAnchorOptions {
disableGreymassFuel?: boolean
// A flag to enable the Anchor Link UI request status, defaults to false (disabled)
requestStatus?: boolean
// An account name to use as the referral account for Fuel
fuelReferrer?: string
// Whether anchor-link should be configured to verify identity proofs in the browser for the app
verifyProofs?: boolean
}

export class Anchor extends Authenticator {
// a JsonRpc instance that can be utilized
public rpc: JsonRpc
// a APIClient instance that can be utilized
public client: APIClient
// Storage for AnchorUser instances
private users: AnchorUser[] = []
// The app name, required by anchor-link
Expand All @@ -41,6 +50,10 @@ export class Anchor extends Authenticator {
private disableGreymassFuel: boolean = false
// display the request status returned by anchor-link, defaults to false (ual has it's own)
private requestStatus: boolean = false
// The referral account used in Fuel transactions
private fuelReferrer: string = 'teamgreymass'
// Whether anchor-link should be configured to verify identity proofs in the browser for the app
private verifyProofs: boolean = false

/**
* Anchor Constructor.
Expand Down Expand Up @@ -71,6 +84,13 @@ export class Anchor extends Authenticator {
// otherwise just return a generic rpc instance for this endpoint
this.rpc = new JsonRpc(`${rpc.protocol}://${rpc.host}:${rpc.port}`)
}
// Allow overriding the APIClient via options
if (options && options.client) {
this.client = options.client
} else {
const provider = new FetchProvider(`${rpc.protocol}://${rpc.host}:${rpc.port}`)
this.client = new APIClient({ provider })
}
// Allow passing a custom service URL to process callbacks
if (options.service) {
this.service = options.service
Expand All @@ -83,6 +103,14 @@ export class Anchor extends Authenticator {
if (options && options.requestStatus) {
this.requestStatus = options.requestStatus
}
// Allow specifying a Fuel referral account
if (options && options.fuelReferrer) {
this.fuelReferrer = options.fuelReferrer
}
// Allow overriding the proof verification option
if (options && options.verifyProofs) {
this.verifyProofs = options.verifyProofs
}
}

/**
Expand All @@ -91,20 +119,22 @@ export class Anchor extends Authenticator {
public async init() {
// establish anchor-link
this.link = new AnchorLink({
chainId: this.chainId,
rpc: this.rpc,
chains: [{
chainId: this.chainId,
nodeUrl: this.client,
}],
service: this.service,
transport: new AnchorLinkBrowserTransport({
// default: disable browser transport UI status messages, ual has its own
requestStatus: this.requestStatus,
// default: do not disable fuel by default
disableGreymassFuel: this.disableGreymassFuel,
fuelReferrer: this.fuelReferrer,
}),
verifyProofs: this.verifyProofs,
})
// attempt to restore any existing session for this app
const session = await this.link.restoreSession(this.appName)
if (session) {
this.users = [new AnchorUser(this.rpc, { session })]
this.users = [new AnchorUser(this.rpc, this.client, { session })]
}
}

Expand Down Expand Up @@ -201,7 +231,7 @@ export class Anchor extends Authenticator {
// some changes to UAL are going to be required to support multiple users
if (this.users.length === 0) {
const identity = await this.link.login(this.appName)
this.users = [new AnchorUser(this.rpc, identity)]
this.users = [new AnchorUser(this.rpc, this.client, identity)]
}
} catch (e) {
throw new UALAnchorError(
Expand All @@ -221,7 +251,7 @@ export class Anchor extends Authenticator {
// retrieve the auth from the current user
const { session: { auth } } = user
// remove the session from anchor-link
await this.link.removeSession(this.appName, auth)
await this.link.removeSession(this.appName, auth, this.chainId)
// reset the authenticator
this.reset()
}
Expand Down
27 changes: 18 additions & 9 deletions src/AnchorUser.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { SignTransactionResponse, User, UALErrorType } from 'universal-authenticator-library'
import { APIClient, PackedTransaction, SignedTransaction } from '@greymass/eosio'
import { JsonRpc } from 'eosjs'

import { UALAnchorError } from './UALAnchorError'

export class AnchorUser extends User {
public client: APIClient
public rpc: JsonRpc
public session: any

Expand All @@ -16,32 +17,40 @@ export class AnchorUser extends User {
private accountName: string = ''
private requestPermission: string = ''

constructor(rpc, identity) {
constructor(rpc, client, identity) {
super()
const { session } = identity
this.accountName = session.auth.actor
this.chainId = session.link.chainId
this.accountName = String(session.auth.actor)
this.chainId = String(session.chainId)
if (identity.signatures) {
[this.signerProof] = identity.signatures
}
if (identity.signerKey) {
this.signerKey = identity.signerKey
}
if (identity.serializedTransaction) {
this.signerRequest = identity.serializedTransaction
if (identity.resolvedTransaction) {
this.signerRequest = identity.transaction
}
this.requestPermission = session.auth.permission
this.requestPermission = String(session.auth.permission)
this.session = session
this.client = client
this.rpc = rpc
}

objectify(data: any) {
return JSON.parse(JSON.stringify(data))
}

public async signTransaction(transaction, options): Promise<SignTransactionResponse> {
try {
const completedTransaction = await this.session.transact(transaction, options)
const wasBroadcast = (options.broadcast !== false)
const serializedTransaction = PackedTransaction.fromSigned(SignedTransaction.from(completedTransaction.transaction))
return this.returnEosjsTransaction(wasBroadcast, {
...completedTransaction,
transaction_id: completedTransaction.payload.tx,
...completedTransaction
serializedTransaction: serializedTransaction.packed_trx.array,
signatures: this.objectify(completedTransaction.signatures),
})
} catch (e) {
const message = e.message ? e.message : 'Unable to sign transaction'
Expand Down Expand Up @@ -88,7 +97,7 @@ export class AnchorUser extends User {

public async isAccountValid() {
try {
const account = this.rpc && await this.rpc.get_account(this.accountName)
const account = this.client && await this.client.v1.chain.get_account(this.accountName)
const actualKeys = this.extractAccountKeys(account)
const authorizationKeys = await this.getKeys()

Expand Down
Loading