Skip to content

Commit

Permalink
Merge branch 'main' into feat/expires_time
Browse files Browse the repository at this point in the history
  • Loading branch information
volodymyr-basiuk committed Nov 22, 2024
2 parents 8dcad86 + d55d5e7 commit 5ef322f
Show file tree
Hide file tree
Showing 16 changed files with 545 additions and 41 deletions.
27 changes: 27 additions & 0 deletions src/iden3comm/constants.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { AcceptProfile } from './types';

const IDEN3_PROTOCOL = 'https://iden3-communication.io/';
/**
* Constants for Iden3 protocol
Expand Down Expand Up @@ -79,5 +81,30 @@ export const SUPPORTED_PUBLIC_KEY_TYPES = {
]
};

export enum ProtocolVersion {
V1 = 'iden3comm/v1'
}

export enum AcceptAuthCircuits {
AuthV2 = 'authV2',
AuthV3 = 'authV3'
}

export enum AcceptJwzAlgorithms {
Groth16 = 'groth16'
}

export enum AcceptJwsAlgorithms {
ES256K = 'ES256K',
ES256KR = 'ES256K-R'
}

export const defaultAcceptProfile: AcceptProfile = {
protocolVersion: ProtocolVersion.V1,
env: MediaType.ZKPMessage,
circuits: [AcceptAuthCircuits.AuthV2],
alg: [AcceptJwzAlgorithms.Groth16]
};

export const DEFAULT_PROOF_VERIFY_DELAY = 1 * 60 * 60 * 1000; // 1 hour
export const DEFAULT_AUTH_VERIFY_DELAY = 5 * 60 * 1000; // 5 minutes
75 changes: 67 additions & 8 deletions src/iden3comm/handlers/auth.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { MediaType } from '../constants';
import { MediaType, ProtocolVersion } from '../constants';
import { IProofService } from '../../proof/proof-service';
import { PROTOCOL_MESSAGE_TYPE } from '../constants';

Expand All @@ -21,34 +21,48 @@ import { byteDecoder, byteEncoder } from '../../utils';
import { processZeroKnowledgeProofRequests, verifyExpiresTime } from './common';
import { CircuitId } from '../../circuits';
import { AbstractMessageHandler, IProtocolMessageHandler } from './message-handler';
import { parseAcceptProfile } from '../utils';

/**
* Options to pass to createAuthorizationRequest function
* @public
*/
export type AuthorizationRequestCreateOptions = {
accept?: string[];
scope?: ZeroKnowledgeProofRequest[];
};

/**
* createAuthorizationRequest is a function to create protocol authorization request
* @param {string} reason - reason to request proof
* @param {string} sender - sender did
* @param {string} callbackUrl - callback that user should use to send response
* @param {AuthorizationRequestCreateOptions} opts - authorization request options
* @returns `Promise<AuthorizationRequestMessage>`
*/
export function createAuthorizationRequest(
reason: string,
sender: string,
callbackUrl: string
callbackUrl: string,
opts?: AuthorizationRequestCreateOptions
): AuthorizationRequestMessage {
return createAuthorizationRequestWithMessage(reason, '', sender, callbackUrl);
return createAuthorizationRequestWithMessage(reason, '', sender, callbackUrl, opts);
}
/**
* createAuthorizationRequestWithMessage is a function to create protocol authorization request with explicit message to sign
* @param {string} reason - reason to request proof
* @param {string} message - message to sign in the response
* @param {string} sender - sender did
* @param {string} callbackUrl - callback that user should use to send response
* @param {AuthorizationRequestCreateOptions} opts - authorization request options
* @returns `Promise<AuthorizationRequestMessage>`
*/
export function createAuthorizationRequestWithMessage(
reason: string,
message: string,
sender: string,
callbackUrl: string
callbackUrl: string,
opts?: AuthorizationRequestCreateOptions
): AuthorizationRequestMessage {
const uuidv4 = uuid.v4();
const request: AuthorizationRequestMessage = {
Expand All @@ -58,10 +72,11 @@ export function createAuthorizationRequestWithMessage(
typ: MediaType.PlainMessage,
type: PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_REQUEST_MESSAGE_TYPE,
body: {
accept: opts?.accept,
reason: reason,
message: message,
callbackUrl: callbackUrl,
scope: []
scope: opts?.scope ?? []
},
created_time: Math.floor(Date.now() / 1000)
};
Expand Down Expand Up @@ -232,13 +247,18 @@ export class AuthHandler
verifyExpiresTime(authRequest);
// override sender did if it's explicitly specified in the auth request
const to = authRequest.to ? DID.parse(authRequest.to) : ctx.senderDid;
const mediaType = ctx.mediaType || MediaType.ZKPMessage;
const guid = uuid.v4();

if (!authRequest.from) {
throw new Error('auth request should contain from field');
}

const responseType = PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_RESPONSE_MESSAGE_TYPE;
const mediaType = this.getSupportedMediaTypeByProfile(
ctx,
responseType,
authRequest.body.accept
);
const from = DID.parse(authRequest.from);

const responseScope = await processZeroKnowledgeProofRequests(
Expand All @@ -251,8 +271,8 @@ export class AuthHandler

return {
id: guid,
typ: ctx.mediaType,
type: PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_RESPONSE_MESSAGE_TYPE,
typ: mediaType,
type: responseType,
thid: authRequest.thid ?? guid,
body: {
message: authRequest?.body?.message,
Expand Down Expand Up @@ -452,4 +472,43 @@ export class AuthHandler
}
}
}

private getSupportedMediaTypeByProfile(
ctx: AuthReqOptions,
responseType: string,
profile?: string[] | undefined
): MediaType {
let mediaType: MediaType;
if (profile?.length) {
const supportedMediaTypes: MediaType[] = [];
for (const acceptProfile of profile) {
// 1. check protocol version
const { protocolVersion, env } = parseAcceptProfile(acceptProfile);
const responseTypeVersion = Number(responseType.split('/').at(-2));
if (
protocolVersion !== ProtocolVersion.V1 ||
(protocolVersion === ProtocolVersion.V1 &&
(responseTypeVersion < 1 || responseTypeVersion >= 2))
) {
continue;
}
// 2. check packer support
if (this._packerMgr.isProfileSupported(env, acceptProfile)) {
supportedMediaTypes.push(env);
}
}

if (!supportedMediaTypes.length) {
throw new Error('no packer with profile which meets `accept` header requirements');
}

mediaType = supportedMediaTypes[0];
if (ctx.mediaType && supportedMediaTypes.includes(ctx.mediaType)) {
mediaType = ctx.mediaType;
}
} else {
mediaType = ctx.mediaType || MediaType.ZKPMessage;
}
return mediaType;
}
}
1 change: 1 addition & 0 deletions src/iden3comm/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ export * from './packers';
export * from './types';
export * from './handlers';
export * from './utils/did';
export * from './utils/accept-profile';

import * as PROTOCOL_CONSTANTS from './constants';
export { PROTOCOL_CONSTANTS };
15 changes: 15 additions & 0 deletions src/iden3comm/packageManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,21 @@ export class PackageManager implements IPackageManager {
this.packers = new Map<MediaType, IPacker>();
}

/** {@inheritDoc IPackageManager.isProfileSupported} */
isProfileSupported(mediaType: MediaType, profile: string): boolean {
const p = this.packers.get(mediaType);
if (!p) {
return false;
}

return p.isProfileSupported(profile);
}

/** {@inheritDoc IPackageManager.getSupportedMediaTypes} */
getSupportedMediaTypes(): MediaType[] {
return [...this.packers.keys()];
}

/** {@inheritDoc IPackageManager.registerPackers} */
registerPackers(packers: Array<IPacker>): void {
packers.forEach((p) => {
Expand Down
29 changes: 28 additions & 1 deletion src/iden3comm/packers/jws.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { BasicMessage, IPacker, JWSPackerParams } from '../types';
import { MediaType, SUPPORTED_PUBLIC_KEY_TYPES } from '../constants';
import { AcceptJwsAlgorithms, MediaType, SUPPORTED_PUBLIC_KEY_TYPES } from '../constants';
import { extractPublicKeyBytes, resolveVerificationMethods } from '../utils/did';
import { keyPath, KMS } from '../../kms/';

Expand All @@ -13,6 +13,7 @@ import {
decodeBase64url,
encodeBase64url
} from '../../utils';
import { parseAcceptProfile } from '../utils';

/**
* Packer that can pack message to JWZ token,
Expand Down Expand Up @@ -102,6 +103,32 @@ export class JWSPacker implements IPacker {
return MediaType.SignedMessage;
}

/** {@inheritDoc IPacker.getSupportedProfiles} */
getSupportedProfiles(): string[] {
return [`env=${this.mediaType()}&alg=${this.getSupportedAlgorithms().join(',')}`];
}

/** {@inheritDoc IPacker.isProfileSupported} */
isProfileSupported(profile: string) {
const { env, circuits, alg } = parseAcceptProfile(profile);
if (env !== this.mediaType()) {
return false;
}

if (circuits) {
throw new Error(`Circuits are not supported for ${env} media type`);
}

const supportedAlgArr = this.getSupportedAlgorithms();
const algSupported =
!alg?.length || alg.some((a) => supportedAlgArr.includes(a as AcceptJwsAlgorithms));
return algSupported;
}

private getSupportedAlgorithms(): AcceptJwsAlgorithms[] {
return [AcceptJwsAlgorithms.ES256K, AcceptJwsAlgorithms.ES256KR];
}

private async resolveDidDoc(from: string) {
let didDocument: DIDDocument;
try {
Expand Down
24 changes: 24 additions & 0 deletions src/iden3comm/packers/plain.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { BasicMessage, IPacker } from '../types';
import { MediaType } from '../constants';
import { byteDecoder, byteEncoder } from '../../utils';
import { parseAcceptProfile } from '../utils';

/**
* Plain packer just serializes bytes to JSON and adds media type
Expand Down Expand Up @@ -53,4 +54,27 @@ export class PlainPacker implements IPacker {
mediaType(): MediaType {
return MediaType.PlainMessage;
}

/** {@inheritDoc IPacker.getSupportedProfiles} */
getSupportedProfiles(): string[] {
return [`env=${this.mediaType()}`];
}

/** {@inheritDoc IPacker.isProfileSupported} */
isProfileSupported(profile: string) {
const { env, circuits, alg } = parseAcceptProfile(profile);
if (env !== this.mediaType()) {
return false;
}

if (circuits) {
throw new Error(`Circuits are not supported for ${env} media type`);
}

if (alg) {
throw new Error(`Algorithms are not supported for ${env} media type`);
}

return true;
}
}
37 changes: 36 additions & 1 deletion src/iden3comm/packers/zkp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,10 @@ import {
ErrStateVerificationFailed,
ErrUnknownCircuitID
} from '../errors';
import { MediaType } from '../constants';
import { AcceptAuthCircuits, AcceptJwzAlgorithms, MediaType } from '../constants';
import { byteDecoder, byteEncoder } from '../../utils';
import { DEFAULT_AUTH_VERIFY_DELAY } from '../constants';
import { parseAcceptProfile } from '../utils';

const { getProvingMethod } = proving;

Expand Down Expand Up @@ -174,6 +175,40 @@ export class ZKPPacker implements IPacker {
mediaType(): MediaType {
return MediaType.ZKPMessage;
}

/** {@inheritDoc IPacker.getSupportedProfiles} */
getSupportedProfiles(): string[] {
return [
`env=${this.mediaType()}&alg=${this.getSupportedAlgorithms().join(
','
)}&circuitIds=${this.getSupportedCircuitIds().join(',')}`
];
}

/** {@inheritDoc IPacker.isProfileSupported} */
isProfileSupported(profile: string) {
const { env, circuits, alg } = parseAcceptProfile(profile);
if (env !== this.mediaType()) {
return false;
}

const supportedCircuitIds = this.getSupportedCircuitIds();
const circuitIdSupported =
!circuits?.length || circuits.some((c) => supportedCircuitIds.includes(c));

const supportedAlgArr = this.getSupportedAlgorithms();
const algSupported =
!alg?.length || alg.some((a) => supportedAlgArr.includes(a as AcceptJwzAlgorithms));
return algSupported && circuitIdSupported;
}

private getSupportedAlgorithms(): AcceptJwzAlgorithms[] {
return [AcceptJwzAlgorithms.Groth16];
}

private getSupportedCircuitIds(): AcceptAuthCircuits[] {
return [AcceptAuthCircuits.AuthV2];
}
}

const verifySender = async (token: Token, msg: BasicMessage): Promise<void> => {
Expand Down
1 change: 1 addition & 0 deletions src/iden3comm/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export * from './protocol/revocation';
export * from './protocol/contract-request';
export * from './protocol/proposal-request';
export * from './protocol/payment';
export * from './protocol/accept-profile';

export * from './packer';
export * from './models';
Expand Down
16 changes: 16 additions & 0 deletions src/iden3comm/types/packageManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,22 @@ export interface IPackageManager {
* @returns MediaType
*/
getMediaType(envelope: string): MediaType;

/**
* gets supported media types by packer manager
*
* @returns MediaType[]
*/
getSupportedMediaTypes(): MediaType[];

/**
* returns true if media type and algorithms supported by packer manager
*
* @param {MediaType} mediaType
* @param {string} profile
* @returns {boolean}
*/
isProfileSupported(mediaType: MediaType, profile: string): boolean;
}
/**
* EnvelopeStub is used to stub the jwt based envelops
Expand Down
Loading

0 comments on commit 5ef322f

Please sign in to comment.