import * as b64 from 'base64-url' ; import { Address , PrivateKey , Signature , SignatureScheme } from '../crypto' ; import RestClient from '../network/rest/restClient' ; import { WebsocketClient } from '../network/websocket/websocketClient' ; import { buildCommitRecordTx , buildGetRecordStatusTx , buildRevokeRecordTx } from '../smartcontract/neovm/attestClaimTxBuilder' ; import { signTransactionAsync } from '../transaction/transactionBuilder' ; import { hexstr2str , StringReader } from '../utils' ; import { AttestNotifyEvent } from './attestNotifyEvent' ; import { ClaimProof } from './claimProof' ; import { Message , Metadata } from './message' ; /**
 * Type of revocation.
 */ export enum RevocationType { AttestContract = 'AttestContract' , RevocationList = 'RevocationList' } /**
 * Revocation definition.
 */ export interface Revocation { /**
     * Type of revocation.
     */ type : RevocationType ; /**
     * Url of revocation list if type is RevocationList
     */ url ? : string ; /**
     * Address of attest contract if type is AttestContract
     */ addr ? : string ; } /**
 * Verifiable claim.
 *
 * TODO: override verify to add claim proof verification.
 */ export class Claim extends Message { static deserialize ( jwt ) { return super . deserializeInternal ( jwt , ( m , s , u ) => new Claim ( m , s , u ) ) ; } version : string ; context : string ; content : any ; revocation ? : Revocation ; useProof : boolean ; proof ? : ClaimProof ; constructor ( metadata , signature ? , useProof ? ) { super ( metadata , signature ) ; this . useProof = useProof === true ; } param url param checkAttest async verify ( url , checkAttest = true ) { const result = await super . verify ( url ) ; if ( result && checkAttest ) { return this . getStatus ( url ) ; } else { return result ; } } /**
     * Serializes the claim into JWT/JWT-X format.
     *
     * Override default implementation by adding proof if available.
     */ serialize ( ) { if ( this . useProof ) { const jwt = super . serialize ( ) ; const proof = this . serializeProof ( ) ; return jwt + '.' + proof ; } else { return super . serialize ( ) ; } } param url param privateKey param gasPrice param gasLimit param payer async attest ( url , gasPrice , gasLimit , payer , privateKey ) { const attesterId = this . metadata . issuer ; const subjectId = this . metadata . subject ; const claimId = this . metadata . messageId ; if ( claimId === undefined ) { throw new Error ( 'Claim id not specified.' ) ; } const client = new WebsocketClient ( url ) ; const tx = buildCommitRecordTx ( claimId , attesterId , subjectId , gasPrice , gasLimit , payer ) ; await signTransactionAsync ( tx , privateKey ) ; const response = await client . sendRawTransaction ( tx . serialize ( ) , false , true ) ; const event = AttestNotifyEvent . deserialize ( response ) ; console . log ( JSON . stringify ( event ) ) ; return event ; } param gas param payer param privateKey param url param gasPrice param gasLimit param payer async revoke ( url , gasPrice , gasLimit , payer , privateKey ) { const attesterId = this . metadata . issuer ; const claimId = this . metadata . messageId ; if ( claimId === undefined ) { throw new Error ( 'Claim id not specified.' ) ; } const client = new WebsocketClient ( url ) ; const tx = buildRevokeRecordTx ( claimId , attesterId , gasPrice , gasLimit , payer ) ; await signTransactionAsync ( tx , privateKey ) ; const response = await client . sendRawTransaction ( tx . serialize ( ) , false , true ) ; const event = AttestNotifyEvent . deserialize ( response ) ; return event . Result . Notify [ 0 ] . States [ 0 ] === 'Push' ; } param url async getStatus ( url ) { const attesterId = this . metadata . issuer ; const claimId = this . metadata . messageId ; if ( claimId === undefined ) { throw new Error ( 'Claim id not specified.' ) ; } const client = new RestClient ( url ) ; const tx = buildGetRecordStatusTx ( claimId ) ; const response = await client . sendRawTransaction ( tx . serialize ( ) , true ) ; const result = GetStatusResponse . deserialize ( response ) ; return result . status === Status . ATTESTED && result . issuerId === attesterId ; } protected payloadToJSON ( ) { return { 'ver' : this . version , '@context' : this . context , 'clm' : this . content , 'clm-rev' : this . revocation } ; } protected payloadFromJSON ( json ) { this . version = json . ver ; this . context = json [ '@context' ] ; this . content = json . clm ; this . revocation = json [ 'clm-rev' ] ; } param algorithm param publicKeyId protected serializeHeader ( algorithm , publicKeyId ) { if ( this . useProof ) { if ( algorithm === undefined || publicKeyId === undefined ) { throw new Error ( 'Signature is needed fow JWT-X.' ) ; } else { const header = { alg : algorithm . labelJWS , typ : 'JWT-X' , kid : publicKeyId } ; const stringified = JSON . stringify ( header ) ; return b64 . encode ( stringified , 'utf-8' ) ; } } else { return super . serializeHeader ( algorithm , publicKeyId ) ; } } /**
     * Serializes the proof into JWT-X.
     */ protected serializeProof ( ) { const stringified = JSON . stringify ( this . proof ) ; return b64 . encode ( stringified , 'utf-8' ) ; } } /**
 * Helper class for deserializing GetStatus response.
 * fixme: Ontology node changed the response
 */ export class GetStatusResponse { static deserialize ( r ) { const response = new GetStatusResponse ( ) ; if ( r . Result !== undefined && r . Result . Result === '' ) { response . status = Status . NOTFOUND ; return response ; } const sr = new StringReader ( r . Result . Result ) ; sr . read ( 1 ) ; sr . readNextLen ( ) ; sr . read ( 1 ) ; const claimId = hexstr2str ( sr . readNextBytes ( ) ) ; sr . read ( 1 ) ; const issuerId = hexstr2str ( sr . readNextBytes ( ) ) ; sr . read ( 1 ) ; const subjectId = hexstr2str ( sr . readNextBytes ( ) ) ; sr . read ( 1 ) ; let status = sr . readNextBytes ( ) ; response . claimId = claimId ; response . issuerId = issuerId ; response . subjectId = subjectId ; if ( ! status ) { status = '00' ; } response . status = status as Status ; return response ; } claimId : string ; issuerId : string ; subjectId : string ; status : Status ; } export enum Status { REVOKED = '00' , ATTESTED = '01' , NOTFOUND = '-1' }