@0xpolygonid/js-sdk
Version:
SDK to work with Polygon ID
130 lines (105 loc) • 3.79 kB
text/typescript
import { Resolvable } from 'did-resolver';
import { byteDecoder, byteEncoder } from '../../utils';
import {
AcceptJweKEKAlgorithms,
MediaType,
ProtocolVersion,
VerificationMethodType
} from '../constants';
import { BasicMessage, DIDDocument, IPacker, PackerParams } from '../types';
import { getRecipientsJWKs, parseAcceptProfile } from '../utils';
import { DID } from '@iden3/js-iden3-core';
import { JoseService } from '../services';
import { FlattenedJWE, GeneralJWE } from 'jose';
export type RecipientInfo = {
did: DID;
didDocument?: DIDDocument;
keyType?: VerificationMethodType;
alg?: AcceptJweKEKAlgorithms;
};
export type JWEPackerParams = PackerParams & {
enc: string;
recipients: RecipientInfo[];
};
export class AnonCryptPacker implements IPacker {
private readonly _supportedProtocolVersions = [ProtocolVersion.V1];
private _supportedAlgorithms = [
AcceptJweKEKAlgorithms.RSA_OAEP_256,
AcceptJweKEKAlgorithms.ECDH_ES_A256KW
];
constructor(
private readonly _joseService: JoseService,
private readonly _documentResolver: Resolvable
) {}
packMessage(msg: BasicMessage, param: JWEPackerParams): Promise<Uint8Array> {
return this.packInternal(msg, param);
}
getSupportedAlgorithms(): AcceptJweKEKAlgorithms[] {
return this._supportedAlgorithms;
}
registerSupportedAlgorithm(algorithm: AcceptJweKEKAlgorithms): void {
this._supportedAlgorithms = [...new Set([...this._supportedAlgorithms, algorithm])];
}
/**
* creates JSON Web Signature token
*
* @param {Uint8Array} payload - serialized message
* @param {PackerParams} params - sender id and proving alg are required
* @returns `Promise<Uint8Array>`
*/
async pack(payload: Uint8Array, params: JWEPackerParams): Promise<Uint8Array> {
const message = JSON.parse(byteDecoder.decode(payload));
return this.packInternal(message, params);
}
async unpack(envelope: Uint8Array): Promise<BasicMessage> {
const { plaintext } = await this._joseService.decrypt(
JSON.parse(byteDecoder.decode(envelope)) as GeneralJWE | FlattenedJWE
);
return JSON.parse(byteDecoder.decode(plaintext)) as BasicMessage;
}
mediaType(): MediaType {
return MediaType.EncryptedMessage;
}
/** {@inheritDoc IPacker.getSupportedProfiles} */
getSupportedProfiles(): string[] {
return this._supportedProtocolVersions.map(
(v) => `${v};env=${this.mediaType()};alg=${this._supportedAlgorithms.join(',')}`
);
}
/** {@inheritDoc IPacker.isProfileSupported} */
isProfileSupported(profile: string): boolean {
const { protocolVersion, env, circuits, alg } = parseAcceptProfile(profile);
if (!this._supportedProtocolVersions.includes(protocolVersion)) {
return false;
}
if (env !== this.mediaType()) {
return false;
}
if (circuits) {
throw new Error(`Circuits are not supported for ${env} media type`);
}
return Boolean(
alg?.some((a) => this._supportedAlgorithms.includes(a as AcceptJweKEKAlgorithms))
);
}
private async packInternal(message: BasicMessage, params: JWEPackerParams): Promise<Uint8Array> {
const { enc, recipients } = params;
if (!enc) {
throw new Error('Missing encryption algorithm');
}
if (!recipients.length) {
throw new Error('Missing recipients');
}
if (!message.to) {
throw new Error('Missing recipient DID');
}
const recipientsJwks = await getRecipientsJWKs(recipients, this._documentResolver);
const msg = byteEncoder.encode(JSON.stringify(message));
const jwe = await this._joseService.encrypt(msg, {
enc,
typ: MediaType.EncryptedMessage,
recipients: recipientsJwks
});
return byteEncoder.encode(JSON.stringify(jwe));
}
}