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

feat: Issuance and Verification Out-of-Band Functionality #188

Merged
merged 50 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
af16ab0
Merge pull request #178 from credebl/release-main-2.0-ecosystem
nishad-ayanworks Oct 19, 2023
d07c91f
fixed ecosystem invitations (#182)
nishad-ayanworks Oct 19, 2023
7f0e702
Support indicio:demonet and indicio:testnet
Oct 21, 2023
15a26a8
Add API for Organization profile
Oct 23, 2023
89ea4c9
Error handling in the org profile
Oct 23, 2023
a168a34
Connection image url add
Oct 23, 2023
dfc5c4a
Orgnization logo setup in the connection service
Oct 23, 2023
e8c727c
Merge pull request #185 from credebl/support-indicio-demonet-mainnet
nishad-ayanworks Oct 23, 2023
ee97135
feat: refactor api for passkey module
bhavanakarwade Oct 13, 2023
94505e5
fix: Added validation for schema and cred-def and updated payload for…
KulkarniShashank Oct 13, 2023
6dd1927
fix: removed unused orgId
tipusinghaw Oct 13, 2023
8dd6678
resolved sonar lint checks
bhavanakarwade Oct 16, 2023
4e60d56
feat: Schema and cred-def auto sign and submit endorsement transactio…
KulkarniShashank Oct 13, 2023
1d31e6e
refactor: api for passkey module
bhavanakarwade Oct 16, 2023
8008c5e
fix: decline endorsement request
tipusinghaw Oct 16, 2023
c0a0636
refactor: Implemented org validation for create and invite ecosystem
tipusinghaw Oct 16, 2023
49897b6
refactor: ecosystem lead details included ecosystem dashboard (#156)
nishad-ayanworks Oct 16, 2023
bbea365
remove unnecessary code
bhavanakarwade Oct 17, 2023
dd908a8
refactor return type
bhavanakarwade Oct 17, 2023
1c1c5ea
refactor: Implemented auto flag handling within the ecosystem and int…
KulkarniShashank Oct 17, 2023
f49d744
feat: Out-Of-Band issuance
Oct 19, 2023
afc8bcc
fix: implemented request body in credential definition request
tipusinghaw Oct 18, 2023
9a4bd28
fix: added attributes as array of string
tipusinghaw Oct 18, 2023
e0f181d
refactor: send ecosystem invitations link
bhavanakarwade Oct 18, 2023
b814757
fix: send invitation flow for organization & ecosystem (#179)
nishad-ayanworks Oct 19, 2023
d0548a0
feat: cred-def list by schemaId for verification (#180)
KulkarniShashank Oct 19, 2023
f9ba022
Request payload changes in the issuance
Oct 19, 2023
0949e94
Solved the credential-def bug in endorsement (#181)
KulkarniShashank Oct 19, 2023
878af7b
Bulk out of band issuance function
Oct 21, 2023
64b8111
Out of band verification with bulk emailIds
Oct 21, 2023
0affdf1
fixed ecosystem invitations (#182)
nishad-ayanworks Oct 19, 2023
52fcdc5
Support indicio:demonet and indicio:testnet
Oct 21, 2023
3ee0eec
Add API for Organization profile
Oct 23, 2023
e6403c3
Error handling in the org profile
Oct 23, 2023
62e775c
Connection image url add
Oct 23, 2023
919234b
Orgnization logo setup in the connection service
Oct 23, 2023
0f29ee8
Added the emailId and attribute in the issuance oob payload
Oct 23, 2023
2249606
Added the API for get oob verification qr code
Oct 25, 2023
1079435
Merge branch 'develop' of https://github.com/credebl/credebl-platform…
Oct 25, 2023
1007a4f
Removed duplication error in the issuance and verification service
Oct 25, 2023
9ca8dcb
Removed duplication error in the issuance and verification service
Oct 25, 2023
e2dc8c9
Added await for natsCall function and solved the error in sona cloud
Oct 25, 2023
478c9aa
Merge branch 'main' of https://github.com/credebl/credebl-platform in…
Oct 25, 2023
2a30c40
Solved connection image url
Oct 25, 2023
b4a3ba3
Merge pull request #190 from credebl/shell-script-modifications
Sheetal-ayanworks Oct 25, 2023
915157a
Merge branch 'develop' of https://github.com/credebl/credebl-platform…
Oct 25, 2023
8d14505
Merge branch 'main' of https://github.com/credebl/credebl-platform in…
Oct 25, 2023
dad1609
Solved fixes in the issuance and verification
Oct 25, 2023
9bc7771
Solved qr code image url in issuance and verification
Oct 26, 2023
f6a38bc
Merge branch 'develop' of https://github.com/credebl/credebl-platform…
Oct 26, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 6 additions & 1 deletion apps/agent-service/src/agent-service.controller.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { Controller } from '@nestjs/common';
import { MessagePattern } from '@nestjs/microservices';
import { AgentServiceService } from './agent-service.service';
import { GetCredDefAgentRedirection, GetSchemaAgentRedirection, IAgentSpinupDto, IIssuanceCreateOffer, ITenantCredDef, ITenantDto, ITenantSchema } from './interface/agent-service.interface';
import { GetCredDefAgentRedirection, GetSchemaAgentRedirection, IAgentSpinupDto, IIssuanceCreateOffer, ITenantCredDef, ITenantDto, ITenantSchema, OutOfBandCredentialOffer } from './interface/agent-service.interface';
import { IConnectionDetails, IUserRequestInterface } from './interface/agent-service.interface';
import { ISendProofRequestPayload } from './interface/agent-service.interface';
import { user } from '@prisma/client';
Expand Down Expand Up @@ -124,4 +124,9 @@ export class AgentServiceController {
async submitTransaction(payload: { url: string, apiKey: string, submitEndorsementPayload:object }): Promise<object> {
return this.agentServiceService.sumbitTransaction(payload.url, payload.apiKey, payload.submitEndorsementPayload);
}

@MessagePattern({ cmd: 'agent-out-of-band-credential-offer' })
async outOfBandCredentialOffer(payload: { outOfBandIssuancePayload: OutOfBandCredentialOffer, url: string, apiKey: string }): Promise<object> {
return this.agentServiceService.outOfBandCredentialOffer(payload.outOfBandIssuancePayload, payload.url, payload.apiKey);
}
}
17 changes: 14 additions & 3 deletions apps/agent-service/src/agent-service.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import * as dotenv from 'dotenv';
import * as fs from 'fs';
import { catchError, map } from 'rxjs/operators';
dotenv.config();
import { GetCredDefAgentRedirection, IAgentSpinupDto, IStoreOrgAgentDetails, ITenantCredDef, ITenantDto, ITenantSchema, IWalletProvision, ISendProofRequestPayload, IIssuanceCreateOffer } from './interface/agent-service.interface';
import { GetCredDefAgentRedirection, IAgentSpinupDto, IStoreOrgAgentDetails, ITenantCredDef, ITenantDto, ITenantSchema, IWalletProvision, ISendProofRequestPayload, IIssuanceCreateOffer, OutOfBandCredentialOffer } from './interface/agent-service.interface';
import { AgentType, OrgAgentType } from '@credebl/enum/enum';
import { IConnectionDetails, IUserRequestInterface } from './interface/agent-service.interface';
import { AgentServiceRepository } from './repositories/agent-service.repository';
Expand Down Expand Up @@ -133,7 +133,7 @@ export class AgentServiceService {

agentSpinupDto.agentType = agentSpinupDto.agentType ? agentSpinupDto.agentType : 1;
agentSpinupDto.tenant = agentSpinupDto.tenant ? agentSpinupDto.tenant : false;
agentSpinupDto.ledgerId = !agentSpinupDto.ledgerId || 0 === agentSpinupDto.ledgerId.length ? [3] : agentSpinupDto.ledgerId;
agentSpinupDto.ledgerId = !agentSpinupDto.ledgerId || 0 === agentSpinupDto.ledgerId?.length ? [3] : agentSpinupDto.ledgerId;


const platformConfig: platform_config = await this.agentServiceRepository.getPlatformConfigDetails();
Expand Down Expand Up @@ -487,7 +487,7 @@ export class AgentServiceService {
async _createTenant(payload: ITenantDto, user: IUserRequestInterface): Promise<void> {
try {

payload.ledgerId = !payload.ledgerId || 0 === payload.ledgerId.length ? [3] : payload.ledgerId;
payload.ledgerId = !payload.ledgerId || 0 === payload.ledgerId?.length ? [3] : payload.ledgerId;

const ledgerDetails: ledgers[] = await this.agentServiceRepository.getGenesisUrl(payload.ledgerId);
const sharedAgentSpinUpResponse = new Promise(async (resolve, _reject) => {
Expand Down Expand Up @@ -944,5 +944,16 @@ export class AgentServiceService {
}
}

async outOfBandCredentialOffer(outOfBandIssuancePayload: OutOfBandCredentialOffer, url: string, apiKey: string): Promise<object> {
try {
const sendOutOfbandCredentialOffer = await this.commonService
.httpPost(url, outOfBandIssuancePayload, { headers: { 'x-api-key': apiKey } })
.then(async response => response);
return sendOutOfbandCredentialOffer;
} catch (error) {
this.logger.error(`Error in out-of-band credential in agent service : ${JSON.stringify(error)}`);
throw new RpcException(error);
}
}
}

13 changes: 11 additions & 2 deletions apps/agent-service/src/interface/agent-service.interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,15 @@ export interface IAgentSpinupDto {
tenant?: boolean;
}

export interface OutOfBandCredentialOffer {
emailId: string;
attributes: Attributes[];
credentialDefinitionId: string;
comment: string;
protocolVersion?: string;
orgId: number;
}

export interface ITenantDto {
label: string;
seed: string;
Expand Down Expand Up @@ -231,10 +240,10 @@ export interface ICredentialFormats {
}

export interface IIndy {
attributes: IAttributes[];
attributes: Attributes[];
}

export interface IAttributes {
export interface Attributes {
name: string;
value: string;
}
Expand Down
51 changes: 48 additions & 3 deletions apps/api-gateway/src/issuance/dtos/issuance.dto.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { IsArray, IsNotEmpty, IsOptional, IsString } from 'class-validator';
import { IsArray, IsNotEmpty, IsOptional, IsString, IsEmail } from 'class-validator';
import { ApiProperty } from '@nestjs/swagger';

interface attribute {
interface CredentialOffer {
emailId: string;
attributes: Attribute[];
}

interface Attribute {
name: string;
value: string;
}
Expand All @@ -11,7 +16,7 @@ export class IssueCredentialDto {
@ApiProperty({ example: [{ 'value': 'string', 'name': 'string' }] })
@IsNotEmpty({ message: 'Please provide valid attributes' })
@IsArray({ message: 'attributes should be array' })
attributes: attribute[];
attributes: Attribute[];

@ApiProperty({ example: 'string' })
@IsNotEmpty({ message: 'Please provide valid credentialDefinitionId' })
Expand Down Expand Up @@ -98,3 +103,43 @@ export class CredentialAttributes {
value: string;
}

export class OutOfBandCredentialDto {

@ApiProperty({ example: [{ 'emailId': 'abc@example.com', 'attribute': [{ 'value': 'string', 'name': 'string' }] }] })
@IsNotEmpty({ message: 'Please provide valid attributes' })
@IsArray({ message: 'attributes should be array' })
@IsOptional()
credentialOffer: CredentialOffer[];

@ApiProperty({ example: 'awqx@getnada.com' })
@IsEmail()
@IsNotEmpty({ message: 'Please provide valid email' })
@IsString({ message: 'email should be string' })
@IsOptional()
emailId: string;

@ApiProperty({ example: [{ 'value': 'string', 'name': 'string' }] })
@IsNotEmpty({ message: 'Please provide valid attributes' })
@IsArray({ message: 'attributes should be array' })
@IsOptional()
attributes: Attribute[];

@ApiProperty({ example: 'string' })
@IsNotEmpty({ message: 'Please provide valid credential definition id' })
@IsString({ message: 'credential definition id should be string' })
credentialDefinitionId: string;

@ApiProperty({ example: 'string' })
@IsNotEmpty({ message: 'Please provide valid comment' })
@IsString({ message: 'comment should be string' })
@IsOptional()
comment: string;

@ApiProperty({ example: 'v1' })
@IsOptional()
@IsNotEmpty({ message: 'Please provide valid protocol version' })
@IsString({ message: 'protocol version should be string' })
protocolVersion?: string;

orgId: number;
}
51 changes: 50 additions & 1 deletion apps/api-gateway/src/issuance/issuance.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ import { CommonService } from '@credebl/common/common.service';
import { Response } from 'express';
import IResponseType from '@credebl/common/interfaces/response.interface';
import { IssuanceService } from './issuance.service';
import { IssuanceDto, IssueCredentialDto } from './dtos/issuance.dto';
import { IssuanceDto, IssueCredentialDto, OutOfBandCredentialDto } from './dtos/issuance.dto';
import { IUserRequest } from '@credebl/user-request/user-request.interface';
import { User } from '../authz/decorators/user.decorator';
import { ResponseMessages } from '@credebl/common/response-messages';
Expand All @@ -43,6 +43,7 @@ import { Roles } from '../authz/decorators/roles.decorator';
import { OrgRoles } from 'libs/org-roles/enums';
import { OrgRolesGuard } from '../authz/guards/org-roles.guard';
import { CustomExceptionFilter } from 'apps/api-gateway/common/exception-handler';
import { ImageServiceService } from '@credebl/image-service';
import { FileExportResponse } from './interfaces';

@Controller()
Expand All @@ -54,11 +55,23 @@ import { FileExportResponse } from './interfaces';
export class IssuanceController {
constructor(
private readonly issueCredentialService: IssuanceService,
private readonly imageServiceService: ImageServiceService,
private readonly commonService: CommonService

) { }
private readonly logger = new Logger('IssuanceController');

@Get('/issuance/oob/qr/:base64Image')
@ApiOperation({ summary: 'Out-Of-Band issuance QR', description: 'Out-Of-Band issuance QR' })
@ApiResponse({ status: 200, description: 'Success', type: ApiResponseDto })
@ApiExcludeEndpoint()
async getQrCode(@Param('base64Image') base64Image: string, @Res() res: Response): Promise<Response> {

const getImageBuffer = await this.imageServiceService.getBase64Image(base64Image);
res.setHeader('Content-Type', 'image/png');
return res.send(getImageBuffer);
}

/**
* Description: Get all issued credentials
* @param user
Expand Down Expand Up @@ -185,6 +198,42 @@ export class IssuanceController {
return res.status(HttpStatus.CREATED).json(finalResponse);
}

/**
* Description: credential issuance out-of-band
* @param user
* @param outOfBandCredentialDto
* @param orgId
* @param res
* @returns
*/
@Post('/orgs/:orgId/credentials/oob')
@UseGuards(AuthGuard('jwt'))
@ApiOperation({
summary: `Create out-of-band credential offer`,
description: `Create out-of-band credential offer`
})
@ApiResponse({ status: 201, description: 'Success', type: ApiResponseDto })
@ApiBearerAuth()
@UseGuards(AuthGuard('jwt'), OrgRolesGuard)
@Roles(OrgRoles.OWNER, OrgRoles.ADMIN, OrgRoles.ISSUER)
async outOfBandCredentialOffer(
@User() user: IUserRequest,
@Body() outOfBandCredentialDto: OutOfBandCredentialDto,
@Param('orgId') orgId: number,
@Res() res: Response
): Promise<Response> {

outOfBandCredentialDto.orgId = orgId;
const getCredentialDetails = await this.issueCredentialService.outOfBandCredentialOffer(user, outOfBandCredentialDto);

const finalResponse: IResponseType = {
statusCode: HttpStatus.CREATED,
message: ResponseMessages.issuance.success.fetch,
data: getCredentialDetails.response
};
return res.status(HttpStatus.CREATED).json(finalResponse);
}

/**
* Description: webhook Save issued credential details
* @param user
Expand Down
3 changes: 2 additions & 1 deletion apps/api-gateway/src/issuance/issuance.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { IssuanceController } from './issuance.controller';
import { IssuanceService } from './issuance.service';
import { CommonService } from '@credebl/common';
import { HttpModule } from '@nestjs/axios';
import { ImageServiceService } from '@credebl/image-service';

@Module({
imports: [
Expand All @@ -19,6 +20,6 @@ import { HttpModule } from '@nestjs/axios';
])
],
controllers: [IssuanceController],
providers: [IssuanceService, CommonService]
providers: [IssuanceService, ImageServiceService, CommonService]
})
export class IssuanceModule { }
17 changes: 12 additions & 5 deletions apps/api-gateway/src/issuance/issuance.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Injectable, Inject } from '@nestjs/common';
import { ClientProxy } from '@nestjs/microservices';
import { BaseService } from 'libs/service/base.service';
import { IUserRequest } from '@credebl/user-request/user-request.interface';
import { IssuanceDto, IssueCredentialDto } from './dtos/issuance.dto';
import { IssuanceDto, IssueCredentialDto, OutOfBandCredentialDto } from './dtos/issuance.dto';
import { FileExportResponse } from './interfaces';

@Injectable()
Expand Down Expand Up @@ -51,10 +51,17 @@ export class IssuanceService extends BaseService {
return this.sendNats(this.issuanceProxy, 'webhook-get-issue-credential', payload);
}

outOfBandCredentialOffer(user: IUserRequest, outOfBandCredentialDto: OutOfBandCredentialDto): Promise<{
KulkarniShashank marked this conversation as resolved.
Show resolved Hide resolved
response: object;
}> {
const payload = { user, outOfBandCredentialDto };
return this.sendNats(this.issuanceProxy, 'out-of-band-credential-offer', payload);
}

async exportSchemaToCSV(credentialDefinitionId: string
): Promise<FileExportResponse> {
const payload = {credentialDefinitionId};
return (await this.sendNats(this.issuanceProxy, 'export-schema-to-csv-by-credDefId', payload)).response;
}
): Promise<FileExportResponse> {
const payload = { credentialDefinitionId };
return (await this.sendNats(this.issuanceProxy, 'export-schema-to-csv-by-credDefId', payload)).response;
}

}
8 changes: 5 additions & 3 deletions apps/api-gateway/src/organization/organization.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import { UpdateOrganizationDto } from './dtos/update-organization-dto';
import { CustomExceptionFilter } from 'apps/api-gateway/common/exception-handler';
import { IUserRequestInterface } from '../interfaces/IUserRequestInterface';
import { GetAllUsersDto } from '../user/dto/get-all-users.dto';
import { ImageServiceService } from '@credebl/image-service';

@UseFilters(CustomExceptionFilter)
@Controller('orgs')
Expand All @@ -38,6 +39,7 @@ export class OrganizationController {

constructor(
private readonly organizationService: OrganizationService,
private readonly imageServiceService: ImageServiceService,
private readonly commonService: CommonService
) { }

Expand All @@ -47,11 +49,11 @@ export class OrganizationController {
async getOgPofile(@Param('orgId') orgId: number, @Res() res: Response): Promise<Response> {
const orgProfile = await this.organizationService.getOgPofile(orgId);

const base64Data = orgProfile.response["logoUrl"].replace(/^data:image\/\w+;base64,/, '');
const base64Data = orgProfile.response["logoUrl"];
const getImageBuffer = await this.imageServiceService.getBase64Image(base64Data);

const imageBuffer = Buffer.from(base64Data, 'base64');
res.setHeader('Content-Type', 'image/png');
return res.send(imageBuffer);
return res.send(getImageBuffer);
}

/**
Expand Down
3 changes: 2 additions & 1 deletion apps/api-gateway/src/organization/organization.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { HttpModule } from '@nestjs/axios';
import { Module } from '@nestjs/common';
import { OrganizationController } from './organization.controller';
import { OrganizationService } from './organization.service';
import { ImageServiceService } from '@credebl/image-service';

@Module({
imports: [
Expand All @@ -23,7 +24,7 @@ import { OrganizationService } from './organization.service';
])
],
controllers: [OrganizationController],
providers: [OrganizationService, CommonService]
providers: [OrganizationService, CommonService, ImageServiceService]
})
export class OrganizationModule { }

15 changes: 5 additions & 10 deletions apps/api-gateway/src/verification/dto/request-proof.dto.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IsArray, IsEmail, IsNotEmpty, IsObject, IsOptional, IsString, MaxLength } from 'class-validator';
import { IsArray, IsNotEmpty, IsObject, IsOptional, IsString, MaxLength } from 'class-validator';
import { toLowerCase, trim } from '@credebl/common/cast.helper';
import { ApiProperty } from '@nestjs/swagger';
import { Transform } from 'class-transformer';
Expand Down Expand Up @@ -85,15 +85,10 @@ export class OutOfBandRequestProof {
@IsNotEmpty({ message: 'please provide valid attributes' })
attributes: ProofRequestAttribute[];

@ApiProperty({ example: 'string' })
@IsNotEmpty({ message: 'Please provide valid emailId' })
@Transform(({ value }) => trim(value))
@Transform(({ value }) => toLowerCase(value))
@IsNotEmpty({ message: 'Email is required.' })
@MaxLength(256, { message: 'Email must be at most 256 character.' })
@IsEmail()
emailId: string;

@ApiProperty()
@IsString({ each: true, message: 'Each emailId in the array should be a string' })
emailId: string | string[];

@ApiProperty()
@IsOptional()
comment: string;
Expand Down
Loading