@microsoft/useragent-sdk
Version:
SDK for building decentralized identity wallets and enterprise agents.
205 lines (176 loc) • 6.33 kB
text/typescript
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import Identifier from "../Identifier";
import UserAgentError from "../UserAgentError";
import JwsToken from "../crypto/protocols/jose/jws/JwsToken";
/**
* Type to describe a claim description.
*/
export type ClaimDescription = { header: string, body: string };
/**
* Type to describe a claim key-value pair.
*/
export type Claim = {[key: string]: string};
/**
* Class that represents a ClaimObject
* @class
*/
export default class ClaimObject {
/**
* Pointer to the claimClass that is tied to this claimObject.
*/
public claimClass: string;
/**
* Context of the specific claim object
*/
public context: string;
/**
* Type of the Claim Object.
*/
public type: string;
/**
* Identifier of the entity that issued ClaimObject
*/
public issuer: string;
/**
* A list of claim descriptions that will define each claim.
*/
public claimDescriptions: ClaimDescription[];
/**
* A list of claims that are contained in this claimObject.
*/
public claimDetails: Claim[];
/**
* The Claim Details if they have been signed.
*/
public signedClaimDetails?: string;
/**
* Instantiates a new ClaimObject.
* @param claimClass Pointer to the claimClass that is tied to this claimObject.
* @param claimDescriptions A list of claim descriptions that will define each claim.
* @param claimDetails A list of claims that are contained in this claimObject.
*/
constructor(claimClass: string,
context: string,
type: string,
issuer: string,
claimDescriptions: ClaimDescription[],
claimDetails: Claim[],
signedClaimDetails?: string) {
this.claimClass = claimClass;
this.issuer = issuer;
this.claimDescriptions = claimDescriptions;
this.claimDetails = claimDetails;
this.signedClaimDetails = signedClaimDetails;
this.context = context;
this.type = type;
}
/**
* Sign the claim details with signer.
* @param signer Identifier that will sign the claim details.
*/
public async signClaimDetails(signer: Identifier, keyReference: string) {
if (signer.id !== this.issuer) {
throw new UserAgentError(`Signer ID: ${signer.id} does not match issuer ID: ${this.issuer}`);
}
this.signedClaimDetails = await signer.sign(this.claimDetails, keyReference);
console.log(`${signer.id} signed claim details`);
}
/**
* If details are signed, return signed claim details.
* Else return unsigned claim details.
*/
public getClaimDetails() {
if (this.signedClaimDetails) {
return this.signedClaimDetails;
}
return this.claimDetails;
}
/**
* Add a claim to the claim details.
* @param {Claim} claim Claim to be added to claimDetails.
* @param {ClaimDescription} claimDescription Optional parameter if want to also add a corresponding claim description.
*/
public async addClaim(claim: Claim, claimDescription?: ClaimDescription) {
this.claimDetails.push(claim);
if (claimDescription) {
this.claimDescriptions.push(claimDescription);
}
}
/**
* Stringify ClaimObject.
* @returns A Stringified ClaimObject in the correct format
*/
public serialize(): string {
let claimDetails = {};
if (this.signedClaimDetails) {
claimDetails = {
type: 'jws',
data: this.signedClaimDetails
};
} else {
claimDetails = {
type: 'unsigned',
data: this.claimDetails
}
}
const claimObject = {
claimClass: this.claimClass,
'@context': this.context,
'@type': this.type,
claimDescriptions: this.claimDescriptions,
claimIssuer: this.issuer,
claimDetails
};
return JSON.stringify(claimObject);
}
/**
* Create new ClaimObject from stringified JSON.
* @param object Stringifed JSON object
* @returns a ClaimObject
*/
public static async deserialize(object: any): Promise<ClaimObject> {
let claimObject;
if (typeof(object) === 'string') {
claimObject = JSON.parse(object);
} else {
claimObject = object;
}
if (!claimObject.claimDetails) {
throw new UserAgentError(`Claim Object does not contain parameter claimDetails`);
}
if (!claimObject.claimClass) {
throw new UserAgentError(`Claim Object does not contain parameter claimClass`);
}
if (!claimObject.claimDescriptions) {
throw new UserAgentError(`Claim Object does not contain parameter claimDescriptions`);
}
if (!claimObject.claimIssuer) {
throw new UserAgentError(`Claim Object does not contain parameter claimIssuer`);
}
if (!claimObject['@context'] || !claimObject['@type']) {
throw new UserAgentError(`Claim Object is missing context`);
}
const claimDetails = claimObject.claimDetails;
if (claimDetails.type === 'unsigned') {
return new ClaimObject(claimObject.claimClass,
claimObject['@context'],
claimObject['@type'],
claimObject.claimIssuer,
claimObject.claimDescriptions,
claimDetails.data);
} else {
const token : JwsToken = await JwsToken.deserialize(claimDetails.data);
const parsedClaimDetails = JSON.parse(token.payload.toString());
return new ClaimObject(claimObject.claimClass,
claimObject['@context'],
claimObject['@type'],
claimObject.claimIssuer,
claimObject.claimDescriptions,
parsedClaimDetails,
claimDetails.data);
}
}
}