Skip to content

Commit

Permalink
Merge with master
Browse files Browse the repository at this point in the history
  • Loading branch information
Kolezhniuk committed Nov 29, 2024
2 parents df4d171 + 339a4cc commit 96d0bbb
Show file tree
Hide file tree
Showing 44 changed files with 2,877 additions and 953 deletions.
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ module.exports = {
...spellcheckerRule,
cspell: {
...cspellConfig,
ignoreWords: ['unmarshal', 'JUvpllMEYUZ2joO59UNui_XYDqxVqiFLLAJ8klWuPBw', 'gdwj', 'fwor']
ignoreWords: ['unmarshal', 'JUvpllMEYUZ2joO59UNui_XYDqxVqiFLLAJ8klWuPBw', 'gdwj', 'fwor', 'multichain', "ETHWEI", "ETHGWEI"]
}
}
]
Expand Down
1,238 changes: 585 additions & 653 deletions package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@0xpolygonid/js-sdk",
"version": "1.22.0",
"version": "1.23.1",
"description": "SDK to work with Polygon ID",
"main": "dist/node/cjs/index.js",
"module": "dist/node/esm/index.js",
Expand Down Expand Up @@ -51,7 +51,6 @@
"homepage": "https://github.com/0xPolygonID/js-sdk#readme",
"devDependencies": {
"@cspell/eslint-plugin": "^8.14.2",
"@gr2m/fetch-mock": "9.11.0-pull-request-644.1",
"@iden3/eslint-config": "https://github.com/iden3/eslint-config",
"@microsoft/api-documenter": "^7.8.20",
"@microsoft/api-extractor": "^7.9.0",
Expand Down Expand Up @@ -80,6 +79,7 @@
"eslint-config-prettier": "^8.8.0",
"eslint-plugin-prettier": "^4.2.1",
"mocha": "10.2.0",
"nock": "^14.0.0-beta.15",
"prettier": "^2.7.1",
"rimraf": "^5.0.5",
"rollup": "^4.14.3",
Expand Down
4 changes: 2 additions & 2 deletions rollup.config.mjs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import commonJS from '@rollup/plugin-commonjs';
import { nodeResolve } from '@rollup/plugin-node-resolve';
import typescript from '@rollup/plugin-typescript';
import packageJson from './package.json' assert { type: 'json' };
import tsConfig from './tsconfig.json' assert { type: 'json' };
import packageJson from './package.json' with { type: 'json' };
import tsConfig from './tsconfig.json' with { type: 'json' };
import virtual from '@rollup/plugin-virtual';
import json from '@rollup/plugin-json';
const empty = 'export default {}';
Expand Down
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
111 changes: 91 additions & 20 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 @@ -12,43 +12,62 @@ import {
ZeroKnowledgeProofRequest,
JSONObject
} from '../types';
import { DID } from '@iden3/js-iden3-core';
import { DID, getUnixTimestamp } from '@iden3/js-iden3-core';
import { proving } from '@iden3/js-jwz';

import * as uuid from 'uuid';
import { ProofQuery } from '../../verifiable';
import { byteDecoder, byteEncoder } from '../../utils';
import { processZeroKnowledgeProofRequests } from './common';
import { processZeroKnowledgeProofRequests, verifyExpiresTime } from './common';
import { CircuitId } from '../../circuits';
import { AbstractMessageHandler, IProtocolMessageHandler } from './message-handler';
import {
AbstractMessageHandler,
BasicHandlerOptions,
IProtocolMessageHandler
} from './message-handler';
import { parseAcceptProfile } from '../utils';

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

/**
* 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,11 +77,14 @@ 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: getUnixTimestamp(new Date()),
expires_time: opts?.expires_time ? getUnixTimestamp(opts.expires_time) : undefined
};
return request;
}
Expand All @@ -73,10 +95,11 @@ export function createAuthorizationRequestWithMessage(
*
* @public
*/
export type AuthResponseHandlerOptions = StateVerificationOpts & {
// acceptedProofGenerationDelay is the period of time in milliseconds that a generated proof remains valid.
acceptedProofGenerationDelay?: number;
};
export type AuthResponseHandlerOptions = StateVerificationOpts &
BasicHandlerOptions & {
// acceptedProofGenerationDelay is the period of time in milliseconds that a generated proof remains valid.
acceptedProofGenerationDelay?: number;
};

/**
* Interface that allows the processing of the authorization request in the raw format for given identifier
Expand Down Expand Up @@ -154,10 +177,10 @@ export type AuthMessageHandlerOptions = AuthReqOptions | AuthRespOptions;
* @public
* @interface AuthHandlerOptions
*/
export interface AuthHandlerOptions {
export type AuthHandlerOptions = BasicHandlerOptions & {
mediaType: MediaType;
packerOptions?: JWSPackerParams;
}
};

/**
*
Expand Down Expand Up @@ -228,16 +251,20 @@ export class AuthHandler
if (authRequest.type !== PROTOCOL_MESSAGE_TYPE.AUTHORIZATION_REQUEST_MESSAGE_TYPE) {
throw new Error('Invalid message type for authorization request');
}

// 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 @@ -250,8 +277,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 All @@ -275,7 +302,9 @@ export class AuthHandler
authResponse: AuthorizationResponseMessage;
}> {
const authRequest = await this.parseAuthorizationRequest(request);

if (!opts?.allowExpiredMessages) {
verifyExpiresTime(authRequest);
}
if (!opts) {
opts = {
mediaType: MediaType.ZKPMessage
Expand Down Expand Up @@ -408,6 +437,9 @@ export class AuthHandler
request: AuthorizationRequestMessage;
response: AuthorizationResponseMessage;
}> {
if (!opts?.allowExpiredMessages) {
verifyExpiresTime(response);
}
const authResp = (await this.handleAuthResponse(response, {
request,
acceptedStateTransitionDelay: opts?.acceptedStateTransitionDelay,
Expand Down Expand Up @@ -450,4 +482,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;
}
}
14 changes: 13 additions & 1 deletion src/iden3comm/handlers/common.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { getRandomBytes } from '@iden3/js-crypto';
import {
BasicMessage,
JsonDocumentObject,
JWSPackerParams,
ZeroKnowledgeProofQuery,
Expand All @@ -8,7 +9,7 @@ import {
} from '../types';
import { mergeObjects } from '../../utils';
import { RevocationStatus, W3CCredential } from '../../verifiable';
import { DID } from '@iden3/js-iden3-core';
import { DID, getUnixTimestamp } from '@iden3/js-iden3-core';
import { IProofService } from '../../proof';
import { CircuitId } from '../../circuits';
import { MediaType } from '../constants';
Expand Down Expand Up @@ -134,3 +135,14 @@ export const processZeroKnowledgeProofRequests = async (

return zkpResponses;
};

/**
* Verifies that the expires_time field of a message is not in the past. Throws an error if it is.
*
* @param message - Basic message to verify.
*/
export const verifyExpiresTime = (message: BasicMessage) => {
if (message?.expires_time && message.expires_time < getUnixTimestamp(new Date())) {
throw new Error('Message expired');
}
};
19 changes: 13 additions & 6 deletions src/iden3comm/handlers/contract-request.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,15 @@ import { IProofService } from '../../proof/proof-service';
import { PROTOCOL_MESSAGE_TYPE } from '../constants';
import { BasicMessage, IPackageManager, ZeroKnowledgeProofResponse } from '../types';
import { ContractInvokeRequest, ContractInvokeResponse } from '../types/protocol/contract-request';
import { DID, ChainIds } from '@iden3/js-iden3-core';
import { DID, ChainIds, getUnixTimestamp } from '@iden3/js-iden3-core';
import { FunctionSignatures, IOnChainZKPVerifier } from '../../storage';
import { Signer } from 'ethers';
import { processZeroKnowledgeProofRequests } from './common';
import { AbstractMessageHandler, IProtocolMessageHandler } from './message-handler';
import { processZeroKnowledgeProofRequests, verifyExpiresTime } from './common';
import {
AbstractMessageHandler,
BasicHandlerOptions,
IProtocolMessageHandler
} from './message-handler';
import { prepareAuthV2ZeroKnowledgeResponse } from '../utils';
/**
* Interface that allows the processing of the contract request
Expand Down Expand Up @@ -40,7 +44,7 @@ export interface IContractRequestHandler {
}

/** ContractInvokeHandlerOptions represents contract invoke handler options */
export type ContractInvokeHandlerOptions = {
export type ContractInvokeHandlerOptions = BasicHandlerOptions & {
ethSigner: Signer;
challenge?: bigint;
};
Expand Down Expand Up @@ -211,7 +215,8 @@ export class ContractRequestHandler
body: {
transaction_data: request.body.transaction_data,
scope: []
}
},
created_time: getUnixTimestamp(new Date())
};
for (const [txHash, zkpResponses] of txHashToZkpResponseMap) {
for (const zkpResponse of zkpResponses) {
Expand Down Expand Up @@ -240,7 +245,9 @@ export class ContractRequestHandler
opts: ContractInvokeHandlerOptions
): Promise<Map<string, ZeroKnowledgeProofResponse>> {
const ciRequest = await this.parseContractInvokeRequest(request);

if (!opts.allowExpiredMessages) {
verifyExpiresTime(ciRequest);
}
if (ciRequest.body.transaction_data.method_id !== FunctionSignatures.SubmitZKPResponseV1) {
throw new Error(`please use handle method to work with other method ids`);
}
Expand Down
Loading

0 comments on commit 96d0bbb

Please sign in to comment.