Skip to content

Commit

Permalink
Fix/issuer-integration (#235)
Browse files Browse the repository at this point in the history
* Fix for the case when user wasn't able to authorize with jwz token after state transition
  • Loading branch information
Kolezhniuk authored May 29, 2024
1 parent 856bf6d commit d6cf985
Show file tree
Hide file tree
Showing 14 changed files with 243 additions and 99 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@0xpolygonid/js-sdk",
"version": "1.14.1",
"version": "1.15.0",
"description": "SDK to work with Polygon ID",
"main": "dist/node/cjs/index.js",
"module": "dist/node/esm/index.js",
Expand Down
3 changes: 3 additions & 0 deletions src/iden3comm/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,3 +72,6 @@ export const SUPPORTED_PUBLIC_KEY_TYPES = {
'JsonWebKey2020'
]
};

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

import {
StateVerificationOpts,
AuthorizationRequestMessage,
AuthorizationResponseMessage,
BasicMessage,
Expand Down Expand Up @@ -64,19 +65,17 @@ export function createAuthorizationRequestWithMessage(
};
return request;
}

/**
*
* Options to pass to auth response handler
*
* @public
* @interface AuthResponseHandlerOptions
*/
export interface AuthResponseHandlerOptions {
// acceptedStateTransitionDelay is the period of time in milliseconds that a revoked state remains valid.
acceptedStateTransitionDelay?: number;
export type AuthResponseHandlerOptions = StateVerificationOpts & {
// 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
14 changes: 9 additions & 5 deletions src/iden3comm/handlers/credential-proposal.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { PROTOCOL_MESSAGE_TYPE } from '../constants';
import { MediaType } from '../constants';
import { PROTOCOL_MESSAGE_TYPE, MediaType } from '../constants';
import {
BasicMessage,
CredentialOffer,
Expand Down Expand Up @@ -214,17 +213,22 @@ export class CredentialProposalHandler
throw new Error(`failed request. no 'credentials' in body`);
}

const senderDID = DID.parse(proposalRequest.from);

let credOfferMessage: CredentialsOfferMessage | undefined = undefined;
let proposalMessage: ProposalMessage | undefined = undefined;

for (let i = 0; i < proposalRequest.body.credentials.length; i++) {
const cred = proposalRequest.body.credentials[i];

// check if there is credentials in the wallet
let credsFromWallet: W3CCredential[] = [];

try {
credsFromWallet = await this._identityWallet.findOwnedCredentialsByDID(senderDID, {
credsFromWallet = await this._identityWallet.credentialWallet.findByQuery({
credentialSubject: {
id: {
$eq: proposalRequest.from
}
},
type: cred.type,
context: cred.context
});
Expand Down
21 changes: 17 additions & 4 deletions src/iden3comm/handlers/message-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,9 @@ import { AuthMessageHandlerOptions } from './auth';
import { RevocationStatusMessageHandlerOptions } from './revocation-status';
import { ContractMessageHandlerOptions } from './contract-request';
import { PaymentHandlerOptions, PaymentRequestMessageHandlerOptions } from './payment';
import { MediaType } from '../constants';
import { proving } from '@iden3/js-jwz';
import { DID } from '@iden3/js-iden3-core';
/**
* iden3 Protocol message handler interface
*/
Expand Down Expand Up @@ -120,7 +123,7 @@ export class MessageHandler {
| RevocationStatusMessageHandlerOptions
| PaymentRequestMessageHandlerOptions
| PaymentHandlerOptions
| { [key: string]: unknown }
| { senderDID?: DID; [key: string]: unknown }
): Promise<Uint8Array | null> {
const { unpackedMediaType, unpackedMessage: message } =
await this._params.packageManager.unpack(bytes);
Expand All @@ -131,10 +134,20 @@ export class MessageHandler {

const response = await this.messageHandler.handle(message, context);

if (response) {
return this._params.packageManager.packMessage(unpackedMediaType, response, {});
if (!response) {
return null;
}

return null;
let packerParams = {};
const senderDID = (context as { senderDID?: DID })?.senderDID;
if (unpackedMediaType === MediaType.ZKPMessage && senderDID) {
packerParams = {
senderDID,
provingMethodAlg: proving.provingMethodGroth16AuthV2Instance.methodAlg
};
return this._params.packageManager.packMessage(unpackedMediaType, response, packerParams);
}

return this._params.packageManager.packMessage(MediaType.PlainMessage, response, packerParams);
}
}
54 changes: 33 additions & 21 deletions src/iden3comm/packers/zkp.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
StateVerificationOpts,
AuthDataPrepareFunc,
BasicMessage,
IPacker,
Expand All @@ -9,7 +10,7 @@ import {
} from '../types';
import { Token, Header, ProvingMethodAlg, proving } from '@iden3/js-jwz';
import { AuthV2PubSignals, CircuitId } from '../../circuits/index';
import { DID, Id } from '@iden3/js-iden3-core';
import { BytesHelper, DID } from '@iden3/js-iden3-core';
import { bytesToProtocolMessage } from '../utils/envelope';
import {
ErrNoProvingMethodAlg,
Expand All @@ -21,6 +22,7 @@ import {
} from '../errors';
import { MediaType } from '../constants';
import { byteDecoder, byteEncoder } from '../../utils';
import { DEFAULT_AUTH_VERIFY_DELAY } from '../constants';

const { getProvingMethod } = proving;

Expand Down Expand Up @@ -70,8 +72,8 @@ export class VerificationHandlerFunc {
* @param {Array<string>} pubSignals - signals that must contain user id and state
* @returns `Promise<boolean>`
*/
verify(id: string, pubSignals: Array<string>): Promise<boolean> {
return this.stateVerificationFunc(id, pubSignals);
verify(id: string, pubSignals: Array<string>, opts?: StateVerificationOpts): Promise<boolean> {
return this.stateVerificationFunc(id, pubSignals, opts);
}
}

Expand All @@ -89,8 +91,11 @@ export class ZKPPacker implements IPacker {
* @param {Map<string, VerificationParams>} verificationParamsMap - string is derived by JSON.parse(ProvingMethodAlg)
*/
constructor(
public provingParamsMap: Map<string, ProvingParams>,
public verificationParamsMap: Map<string, VerificationParams>
public readonly provingParamsMap: Map<string, ProvingParams>,
public readonly verificationParamsMap: Map<string, VerificationParams>,
private readonly _opts: StateVerificationOpts = {
acceptedStateTransitionDelay: DEFAULT_AUTH_VERIFY_DELAY
}
) {}

/**
Expand Down Expand Up @@ -150,8 +155,10 @@ export class ZKPPacker implements IPacker {

const verificationResult = await verificationParams?.verificationFn?.verify(
token.circuitId,
token.zkProof.pub_signals
token.zkProof.pub_signals,
this._opts
);

if (!verificationResult) {
throw new Error(ErrStateVerificationFailed);
}
Expand All @@ -169,26 +176,31 @@ export class ZKPPacker implements IPacker {
}
}

const verifySender = (token: Token, msg: BasicMessage): void => {
const verifySender = async (token: Token, msg: BasicMessage): Promise<void> => {
switch (token.circuitId) {
case CircuitId.AuthV2:
if (!msg.from || !verifyAuthV2Sender(msg.from, token.zkProof.pub_signals)) {
throw new Error(ErrSenderNotUsedTokenCreation);
{
if (!msg.from) {
throw new Error(ErrSenderNotUsedTokenCreation);
}
const authSignals = new AuthV2PubSignals().pubSignalsUnmarshal(
byteEncoder.encode(JSON.stringify(token.zkProof.pub_signals))
);
const did = DID.parseFromId(authSignals.userID);

const msgHash = await token.getMessageHash();
const challenge = BytesHelper.bytesToInt(msgHash.reverse());

if (challenge !== authSignals.challenge) {
throw new Error(ErrSenderNotUsedTokenCreation);
}

if (msg.from !== did.string()) {
throw new Error(ErrSenderNotUsedTokenCreation);
}
}
break;
default:
throw new Error(ErrUnknownCircuitID);
}
};

const verifyAuthV2Sender = (from: string, pubSignals: Array<string>): boolean => {
const authSignals = new AuthV2PubSignals();

const pubSig = authSignals.pubSignalsUnmarshal(byteEncoder.encode(JSON.stringify(pubSignals)));
return pubSig.userID ? checkSender(from, pubSig.userID) : false;
};

const checkSender = (from: string, id: Id): boolean => {
const did = DID.parseFromId(id);
return from === did.string();
};
1 change: 1 addition & 0 deletions src/iden3comm/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ export * from './protocol/proposal-request';
export * from './protocol/payment';

export * from './packer';
export * from './models';
export * from './packageManager';
7 changes: 7 additions & 0 deletions src/iden3comm/types/models.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
/**
* State verification options
*/
export type StateVerificationOpts = {
// acceptedStateTransitionDelay is the period of time in milliseconds that a revoked state remains valid.
acceptedStateTransitionDelay?: number;
};
7 changes: 6 additions & 1 deletion src/iden3comm/types/packer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { ProvingMethodAlg } from '@iden3/js-jwz';
import { CircuitId } from '../../circuits';
import { MediaType } from '../constants';
import { DIDDocument, VerificationMethod } from 'did-resolver';
import { StateVerificationOpts } from './models';
/**
* Protocol message type
*/
Expand Down Expand Up @@ -79,7 +80,11 @@ export type AuthDataPrepareFunc = (
/**
* signature of state function verifier
*/
export type StateVerificationFunc = (id: string, pubSignals: Array<string>) => Promise<boolean>;
export type StateVerificationFunc = (
id: string,
pubSignals: Array<string>,
opts?: StateVerificationOpts
) => Promise<boolean>;

/**
* Defines method that must be implemented by any packer
Expand Down
12 changes: 12 additions & 0 deletions src/identity/identity-wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,14 @@ export interface IIdentityWallet {
*/
createIdentity(opts: IdentityCreationOptions): Promise<{ did: DID; credential: W3CCredential }>;

/**
* Credential wallet getter
*
* @returns {ICredentialWallet}
* @memberof IIdentityWallet
*/
get credentialWallet(): ICredentialWallet;

/**
* Create Identity based in Ethereum address and it provides an identifier in DID form.
*
Expand Down Expand Up @@ -496,6 +504,10 @@ export class IdentityWallet implements IIdentityWallet {
this._transactionService = new TransactionService(_storage.states.getRpcProvider());
}

get credentialWallet(): ICredentialWallet {
return this._credentialWallet;
}

private getCredentialStatusPublisherRegistry(
_opts:
| { credentialStatusPublisherRegistry?: CredentialStatusPublisherRegistry | undefined }
Expand Down
Loading

0 comments on commit d6cf985

Please sign in to comment.