Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

discovery-protocol handler #294

Merged
merged 13 commits into from
Dec 20, 2024
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', 'multichain', "ETHWEI", "ETHGWEI"]
ignoreWords: ['unmarshal', 'JUvpllMEYUZ2joO59UNui_XYDqxVqiFLLAJ8klWuPBw', 'gdwj', 'fwor', 'multichain', "ETHWEI", "ETHGWEI", "didcomm"]
}
}
]
Expand Down
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.25.0",
"version": "1.26.0",
"description": "SDK to work with Polygon ID",
"main": "dist/node/cjs/index.js",
"module": "dist/node/esm/index.js",
Expand Down
9 changes: 8 additions & 1 deletion src/iden3comm/constants.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { AcceptProfile } from './types';

const IDEN3_PROTOCOL = 'https://iden3-communication.io/';
const DIDCOMM_PROTOCOL = 'https://didcomm.org/';
/**
* Constants for Iden3 protocol
*/
Expand Down Expand Up @@ -48,7 +49,13 @@ export const PROTOCOL_MESSAGE_TYPE = Object.freeze({
// PaymentRequestMessageType is type for payment-request message
PAYMENT_REQUEST_MESSAGE_TYPE: `${IDEN3_PROTOCOL}credentials/0.1/payment-request` as const,
// PaymentMessageType is type for payment message
PAYMENT_MESSAGE_TYPE: `${IDEN3_PROTOCOL}credentials/0.1/payment` as const
PAYMENT_MESSAGE_TYPE: `${IDEN3_PROTOCOL}credentials/0.1/payment` as const,
// DiscoveryProtocolQueriesMessageType is type for didcomm discovery protocol queries
DISCOVERY_PROTOCOL_QUERIES_MESSAGE_TYPE:
`${DIDCOMM_PROTOCOL}discover-features/2.0/queries` as const,
// DiscoveryProtocolDiscloseMessageType is type for didcomm discovery protocol disclose
DISCOVERY_PROTOCOL_DISCLOSE_MESSAGE_TYPE:
`${DIDCOMM_PROTOCOL}discover-features/2.0/disclose` as const
});

/**
Expand Down
204 changes: 204 additions & 0 deletions src/iden3comm/handlers/discovery-protocol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
import { PROTOCOL_MESSAGE_TYPE } from '../constants';

import { BasicMessage, IPackageManager } from '../types';

import * as uuid from 'uuid';
import {
DiscoverFeatureDiscloseMessage,
DiscoverFeatureDisclosure,
DiscoverFeatureQueriesMessage,
DiscoverFeatureQueryType,
DiscoveryProtocolFeatureType
} from '../types/protocol/discovery-protocol';
import {
AbstractMessageHandler,
BasicHandlerOptions,
IProtocolMessageHandler
} from './message-handler';
import { getUnixTimestamp } from '@iden3/js-iden3-core';
import { verifyExpiresTime } from './common';

/**
* @beta
* DiscoveryProtocolOptions contains options for DiscoveryProtocolHandler
* @public
* @interface DiscoveryProtocolOptions
*/
export interface DiscoveryProtocolOptions {
packageManager: IPackageManager;
}

/**
*
* Options to pass to discovery-protocol handler
*
* @beta
* @public
* @type DiscoveryProtocolHandlerOptions
*/
export type DiscoveryProtocolHandlerOptions = BasicHandlerOptions & {
disclosureExpiresDate?: Date;
};

/**
* @beta
* createDiscoveryFeatureQueryMessage is a function to create didcomm protocol discovery-feature query message
* @param opts - discovery-feature query options
* @returns `DiscoverFeatureQueriesMessage`
*/
export function createDiscoveryFeatureQueryMessage(opts?: {
featureTypes?: DiscoveryProtocolFeatureType[];
from?: string;
to?: string;
expires_time?: number;
}): DiscoverFeatureQueriesMessage {
const uuidv4 = uuid.v4();
return {
id: uuidv4,
thid: uuidv4,
type: PROTOCOL_MESSAGE_TYPE.DISCOVERY_PROTOCOL_QUERIES_MESSAGE_TYPE,
body: {
queries: opts?.featureTypes?.length
? opts.featureTypes.map((featureType) => ({
[DiscoverFeatureQueryType.FeatureType]: featureType
}))
: [
{
[DiscoverFeatureQueryType.FeatureType]: DiscoveryProtocolFeatureType.Accept
}
]
},
from: opts?.from,
to: opts?.to,
created_time: getUnixTimestamp(new Date()),
expires_time: opts?.expires_time
};
}

/**
* @beta
* createDiscoveryFeatureDiscloseMessage is a function to create didcomm protocol discovery-feature disclose message
* @param {DiscoverFeatureDisclosure[]} disclosures - array of disclosures
* @param opts - basic message options
* @returns `DiscoverFeatureQueriesMessage`
*/
export function createDiscoveryFeatureDiscloseMessage(
disclosures: DiscoverFeatureDisclosure[],
opts?: {
from?: string;
to?: string;
expires_time?: number;
}
): DiscoverFeatureDiscloseMessage {
const uuidv4 = uuid.v4();
return {
id: uuidv4,
thid: uuidv4,
type: PROTOCOL_MESSAGE_TYPE.DISCOVERY_PROTOCOL_DISCLOSE_MESSAGE_TYPE,
body: {
disclosures
},
from: opts?.from,
to: opts?.to,
created_time: getUnixTimestamp(new Date()),
expires_time: opts?.expires_time
};
}

/**
* Interface to work with discovery protocol handler
*
* @beta
* @public
* @interface IDiscoveryProtocolHandler
*/
export interface IDiscoveryProtocolHandler {
/**
* handle discovery query message
*
* @param {DiscoverFeatureQueriesMessage} message - discover feature queries message
* @param {{ expires_time?: number}} opts - discover feature handle options
* @returns {Promise<DiscoverFeatureDiscloseMessage>} - discover feature disclose message
*/
handleDiscoveryQuery(
message: DiscoverFeatureQueriesMessage,
opts?: DiscoveryProtocolHandlerOptions
): Promise<DiscoverFeatureDiscloseMessage>;
}

/**
*
* Handler for discovery protocol
*
* @public
* @beta
* @class DiscoveryProtocolHandler
* @implements implements DiscoveryProtocolHandler interface
*/
export class DiscoveryProtocolHandler
extends AbstractMessageHandler
implements IDiscoveryProtocolHandler, IProtocolMessageHandler
{
/**
* Creates an instance of DiscoveryProtocolHandler.
* @param {DiscoveryProtocolOptions} _options - discovery protocol options
*/
constructor(private readonly _options: DiscoveryProtocolOptions) {
super();
}

/**
* @inheritdoc IProtocolMessageHandler#handle
*/
public async handle(
message: BasicMessage,
context: { [key: string]: unknown }
): Promise<BasicMessage | null> {
switch (message.type) {
case PROTOCOL_MESSAGE_TYPE.DISCOVERY_PROTOCOL_QUERIES_MESSAGE_TYPE:
return await this.handleDiscoveryQuery(message as DiscoverFeatureQueriesMessage, context);
default:
return super.handle(message, context as { [key: string]: unknown });
}
}

/**
* @inheritdoc IDiscoveryProtocolHandler#handleDiscoveryQuery
*/
async handleDiscoveryQuery(
message: DiscoverFeatureQueriesMessage,
opts?: DiscoveryProtocolHandlerOptions
): Promise<DiscoverFeatureDiscloseMessage> {
if (!opts?.allowExpiredMessages) {
verifyExpiresTime(message);
}

if (message.body.queries.length !== 1) {
throw new Error('Invalid number of queries. Only one query is supported');
}

if (
message.body.queries[0][DiscoverFeatureQueryType.FeatureType] !==
DiscoveryProtocolFeatureType.Accept
) {
throw new Error('Invalid feature-type. Only "accept" is supported');
}

const disclosures = [
{
[DiscoverFeatureQueryType.FeatureType]: DiscoveryProtocolFeatureType.Accept,
accept: this._options.packageManager.getSupportedProfiles()
}
];

return Promise.resolve(
createDiscoveryFeatureDiscloseMessage(disclosures, {
to: message.from,
from: message.to,
expires_time: opts?.disclosureExpiresDate
? getUnixTimestamp(opts.disclosureExpiresDate)
: undefined
})
);
}
}
1 change: 1 addition & 0 deletions src/iden3comm/handlers/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './common';
export * from './credential-proposal';
export * from './message-handler';
export * from './payment';
export * from './discovery-protocol';
13 changes: 13 additions & 0 deletions src/iden3comm/packageManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,19 @@ export class PackageManager implements IPackageManager {
this.packers = new Map<MediaType, IPacker>();
}

/** {@inheritDoc IPackageManager.getSupportedProfiles} */
getSupportedProfiles(): string[] {
const acceptProfiles: string[] = [];
const mediaTypes = this.getSupportedMediaTypes();
for (const mediaType of mediaTypes) {
const p = this.packers.get(mediaType);
if (p) {
acceptProfiles.push(...p.getSupportedProfiles());
}
}
return [...new Set(acceptProfiles)];
}

/** {@inheritDoc IPackageManager.isProfileSupported} */
isProfileSupported(mediaType: MediaType, profile: string): boolean {
const p = this.packers.get(mediaType);
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 @@ -7,6 +7,7 @@ export * from './protocol/contract-request';
export * from './protocol/proposal-request';
export * from './protocol/payment';
export * from './protocol/accept-profile';
export * from './protocol/discovery-protocol';

export * from './packer';
export * from './models';
Expand Down
7 changes: 7 additions & 0 deletions src/iden3comm/types/packageManager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ export interface IPackageManager {
*/
getSupportedMediaTypes(): MediaType[];

/**
* gets supported accept profiles by packer manager
*
* @returns string[]
*/
getSupportedProfiles(): string[];

/**
* returns true if media type and algorithms supported by packer manager
*
Expand Down
42 changes: 42 additions & 0 deletions src/iden3comm/types/protocol/discovery-protocol.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { PROTOCOL_MESSAGE_TYPE } from '../../constants';
import { BasicMessage } from '../packer';

/** @beta DiscoverFeatureQueryType is enum for query type fields */
export enum DiscoverFeatureQueryType {
FeatureType = 'feature-type'
}

/** @beta DiscoveryProtocolFeatureType is enum for supported feature-types */
export enum DiscoveryProtocolFeatureType {
Accept = 'accept'
}

/** @beta DiscoverFeatureQueriesMessage is struct the represents discover feature queries message */
export type DiscoverFeatureQueriesMessage = BasicMessage & {
body: DiscoverFeatureQueriesBody;
type: typeof PROTOCOL_MESSAGE_TYPE.DISCOVERY_PROTOCOL_QUERIES_MESSAGE_TYPE;
};

/** @beta DiscoverFeatureQueriesBody is struct the represents discover feature queries body */
export type DiscoverFeatureQueriesBody = {
queries: {
[DiscoverFeatureQueryType.FeatureType]: DiscoveryProtocolFeatureType;
}[];
};

/** @beta DiscoverFeatureDiscloseMessage is struct the represents discover feature disclose message */
export type DiscoverFeatureDiscloseMessage = BasicMessage & {
body: DiscoverFeatureDiscloseBody;
type: typeof PROTOCOL_MESSAGE_TYPE.DISCOVERY_PROTOCOL_DISCLOSE_MESSAGE_TYPE;
};

/** @beta DiscoverFeatureDiscloseBody is struct the represents discover feature disclose body */
export type DiscoverFeatureDiscloseBody = {
disclosures: DiscoverFeatureDisclosure[];
};

/** @beta DiscoverFeatureDisclosure is struct the represents discover feature disclosure */
export type DiscoverFeatureDisclosure = {
[DiscoverFeatureQueryType.FeatureType]: DiscoveryProtocolFeatureType;
accept: Array<string>;
};
Loading
Loading