herlina-kit
Version:
protocol untuk menghubungkan DApp Vexanium ke dompet Herlina
163 lines (143 loc) • 4.68 kB
JavaScript
import {Base64u, IdentityProof, SigningRequest} from "@wharfkit/signing-request";
import {Serializer} from "@wharfkit/antelope";
import {Peer} from "peerjs";
import zlib from "pako";
import {WalletSession} from "./WalletSession.js";
import {loadSession, saveSession} from "./session-store.js";
/**
* Membuat sambungan dengan signal server.
* Dapatkan WalletSession
*/
export class Herlina {
/**
* @type {Peer}
*/
#peer;
#peerOptions = {};
#peerId;
#listeners = new Map();
#identityArgs = {};
constructor() {
this.#peerOptions.config = {
iceServers: [
{urls: "stun:stun.l.google.com:19302"},
{urls: "stun:stun1.l.google.com:3478"},
{urls: "stun:stun.relay.metered.ca:80"},
{
urls: "turn:asia.relay.metered.ca:80",
username: "b66cd40a117bddb5cde924ab",
credential: "4jRmuTehVCZ2a/S+"
}
],
sdpSemantics: "unified-plan"
};
this.#identityArgs.scope = "vexanium";
this.#identityArgs.chainId = WalletSession.ChainID;
}
/**
* tambah stun atau turn server
* @param {RTCIceServer} server
*/
addIceServer(server) {
this.#peerOptions.config.iceServers.push(server);
}
/**
* setel alamat signal server
* @param host
* @param port
*/
setServer(host, port) {
this.#peerOptions.host = host;
if (port) this.#peerOptions.port = port;
}
/**
* Setel listeners untuk peer events
* @param {string} event open, close, disconnected, error, session
* @param {Function} func
*/
on(event, func) {
this.#listeners.set(event, func);
}
/**
* buat sambungan dengan signal server.
* jawaban dari wallet bisa didengarkan dengan event session
*
* @see on
* @see createLoginRequest
*/
async connect() {
if (!this.#peerId) {
const session = loadSession();
this.#peerId = session ? session.peerID : `VEX-${window.crypto.randomUUID()}`;
}
this.#peer = new Peer(this.#peerId, this.#peerOptions);
this.#peer.on("connection", this.#onConnection.bind(this));
this.#listeners.forEach((func, key) => {
this.#peer.on(key, func);
});
}
disconnect() {
if (this.#peer) this.#peer.disconnect();
}
destroy() {
if (this.#peer) this.#peer.destroy();
}
reconnect() {
if (this.#peer) this.#peer.reconnect();
}
isDisconnected() {
return (this.#peer) ? this.#peer.disconnected : true;
}
isDestroyed() {
return (this.#peer) ? this.#peer.destroyed : true;
}
/**
* membuat vsr untuk login.
* @param {string} name nama aplikasi
* @param {string} icon url icon aplikasi
* @return {string} vsr yang bisa dipakai untuk data kode qr atau query url
*/
createLoginRequest(name, icon) {
this.#peerId = `VEX-${window.crypto.randomUUID()}`;
const session = loadSession();
if (session) {
const [actor, perm] = session.permission.split("@");
this.#identityArgs.account = actor;
this.#identityArgs.permission = perm;
this.#peerId = session.peerID;
}
const request = SigningRequest.identity(this.#identityArgs, {zlib});
request.setInfoKey("pi", this.#peerId);
request.setInfoKey("na", name);
request.setInfoKey("ic", icon);
request.setInfoKey("do", window.location.origin);
if (session) {
request.setInfoKey("auth", session.auth);
}
return request.encode(true, false, "vsr:");
}
/**
*
* @param {import('peerjs').DataConnection} conn
*/
#onConnection(conn) {
conn.once("data", payload => {
if (payload.code === 'LOGIN_OK') {
const auth = payload.result.auth;
const proof = Serializer.decode({data: Base64u.decode(auth), type: IdentityProof});
const session = new WalletSession(conn);
session.permissionLevel = proof.signer;
// simpan session
saveSession({
peerID: this.#peerId,
permission: proof.signer.toString(),
expiration: proof.expiration,
auth
});
// kirim notify
const func = this.#listeners.get("session");
if (func) func(session, proof);
}
});
}
}