import {IssuerBaseCls, IssuerOkpAlg} from '@kaytrust/did-base' import { interpretIdentifier, makeDidNear, privateKeyToSecretKey } from './helpers'; import { Account, keyStores, Near } from 'near-api-js'; import { Ed25519Signer } from './signer'; import { createJWT, JWTHeader, JWTVerified, verifyJWT, JWTVerifyOptions } from 'did-jwt'; import { Resolvable } from 'did-resolver'; type IssuerNear = IssuerBaseCls; interface IConfig extends Partial> { identifier?: string privateKey?: string networkId?: string contractId?: string secretKey?: Uint8Array // signer?: IssuerNear["signer"] // alg?: 'ES256K' | 'ES256K-R' // txSigner?: TxSigner // privateKey?: string rpcUrl?: string near?: Near // // eslint-disable-next-line @typescript-eslint/no-explicit-any // web3?: any } export class NearDID extends IssuerBaseCls { did: string; declare signer: IssuerNear["signer"]; declare alg?: 'EdDSA' | undefined; private near?: Near; private contractId?: string; constructor(conf: IConfig = {}) { super(); let { accountId, networkId, secretKey } = interpretIdentifier(conf.identifier, conf.secretKey || (conf.privateKey ? privateKeyToSecretKey(conf.privateKey) : undefined)) if (!networkId) networkId = conf.networkId; this.contractId = conf.contractId; if (conf.rpcUrl || conf.near) { const keyStore = new keyStores.InMemoryKeyStore(); const defaultNetworkId = networkId ?? "testnet"; this.near = conf.near ?? new Near({ networkId: defaultNetworkId, keyStore, nodeUrl: conf.rpcUrl!, headers: {}, }); if (!this.contractId && defaultNetworkId) this.contractId = `neardti.${defaultNetworkId}` } this.did = makeDidNear({accountId, networkId}); if (conf.signer) { this.signer = conf.signer; this.alg = conf.alg if (!this.alg) { console.warn( 'A JWT signer was specified but no algorithm was set. Please set the `alg` parameter when calling `new EthrDID()`' ) } } else if (secretKey) { this.signer = Ed25519Signer(secretKey) this.alg = 'EdDSA' } } async lookupOwner(cache = true): Promise { if (typeof this.near === 'undefined') { throw new Error('a near provider configuration is needed for network operations') } if (typeof this.contractId === 'undefined') { throw new Error('a contractId configuration is needed for network operations') } if (cache && this.owner) return this.owner const account: Account = await this.near.account(this.contractId); return await account.viewFunction({ contractId: this.contractId, methodName: "identity_owner", args: { identity: this.did }, }); } // eslint-disable-next-line async signJWT(payload: any, expiresIn?: number, header: Partial = {}): Promise { if (typeof this.signer !== 'function') { throw new Error('No signer configured') } const alg: IssuerOkpAlg = "EdDSA" const options = { signer: this.signer, alg: alg, issuer: this.did, } if (!header.alg) header.alg = alg; // eslint-disable-next-line @typescript-eslint/no-explicit-any if (expiresIn) (options)['expiresIn'] = expiresIn return createJWT(payload, options, header) } async verifyJWT(jwt: string, resolver: Resolvable, audience = this.did, options: Omit = {policies: {}}): Promise { return verifyJWT(jwt, { resolver, audience, ...options}) } }