Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .env.demo
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ UTILITIES_NKEY_SEED=
CLOUD_WALLET_NKEY_SEED=
GEOLOCATION_NKEY_SEED=
NOTIFICATION_NKEY_SEED=
X509_NKEY_SEED=

KEYCLOAK_DOMAIN=http://localhost:8080/
KEYCLOAK_ADMIN_URL=http://localhost:8080
Expand Down
1 change: 1 addition & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ CREDENTAILDEFINITION_NKEY_SEED= xxxxxxxxxxxxx // Please provide Nkeys secret for
SCHEMA_NKEY_SEED= xxxxxxxxxxxxx // Please provide Nkeys secret for schema service
UTILITIES_NKEY_SEED= xxxxxxxxxxxxx // Please provide Nkeys secret for utilities service
GEOLOCATION_NKEY_SEED= xxxxxxxxxxx // Please provide Nkeys secret for geo-location service
X509_NKEY_SEED= xxxxxxxxxxx // Please provide Nkeys secret for x509 service
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor

Fix formatting issues.

The line has formatting issues flagged by static analysis:

  1. Extra space before the value
  2. Missing quotes around the placeholder value

Based on static analysis hints.

Apply this diff to fix the formatting:

-X509_NKEY_SEED= xxxxxxxxxxx // Please provide Nkeys secret for x509 service
+X509_NKEY_SEED=xxxxxxxxxxx # Please provide Nkeys secret for x509 service

Note: Also changed // to # for consistency with shell-style comments used in other parts of the file (lines 29, 137-143).

Committable suggestion skipped: line range outside the PR's diff.

🧰 Tools
🪛 dotenv-linter (3.3.0)

[warning] 124-124: [SpaceCharacter] The line has spaces around equal sign

(SpaceCharacter)


[warning] 124-124: [ValueWithoutQuotes] This value needs to be surrounded in quotes

(ValueWithoutQuotes)

🤖 Prompt for AI Agents
In .env.sample around line 124 the X509_NKEY_SEED entry has an extra space
before the value, missing quotes around the placeholder, and uses '//' for the
comment; remove the leading space after the '=', wrap the placeholder value in
double quotes (e.g. "xxxxxxxxxxx"), and replace the '//' comment with a
shell-style '#' comment so the line follows the file's formatting conventions.


AFJ_AGENT_TOKEN_PATH=/apps/agent-provisioning/AFJ/token/

Expand Down
32 changes: 32 additions & 0 deletions apps/agent-service/src/agent-service.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ import { user } from '@prisma/client';
import { InvitationMessage } from '@credebl/common/interfaces/agent-service.interface';
import { AgentSpinUpStatus } from '@credebl/enum/enum';
import { SignDataDto } from '../../api-gateway/src/agent-service/dto/agent-service.dto';
import {
IX509ImportCertificateOptionsDto,
x509CertificateDecodeDto,
X509CreateCertificateOptions
} from '@credebl/common/interfaces/x509.interface';

@Controller()
export class AgentServiceController {
Expand Down Expand Up @@ -380,4 +385,31 @@ export class AgentServiceController {
async oidcDeleteCredentialOffer(payload: { url: string; orgId: string }): Promise<any> {
return this.agentServiceService.oidcDeleteCredentialOffer(payload.url, payload.orgId);
}

@MessagePattern({ cmd: 'agent-create-x509-certificate' })
async createX509Certificate(payload: {
options: X509CreateCertificateOptions;
url: string;
orgId: string;
}): Promise<object> {
return this.agentServiceService.createX509Certificate(payload.options, payload.url, payload.orgId);
}

@MessagePattern({ cmd: 'agent-decode-x509-certificate' })
async decodeX509Certificate(payload: {
options: x509CertificateDecodeDto;
url: string;
orgId: string;
}): Promise<object> {
return this.agentServiceService.decodeX509Certificate(payload.options, payload.url, payload.orgId);
}

@MessagePattern({ cmd: 'agent-import-x509-certificate' })
async importX509Certificate(payload: {
options: IX509ImportCertificateOptionsDto;
url: string;
orgId: string;
}): Promise<object> {
return this.agentServiceService.importX509Certificate(payload.options, payload.url, payload.orgId);
}
}
51 changes: 50 additions & 1 deletion apps/agent-service/src/agent-service.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ import { NATSClient } from '@credebl/common/NATSClient';
import { SignDataDto } from '../../api-gateway/src/agent-service/dto/agent-service.dto';
import { IVerificationMethod } from 'apps/organization/interfaces/organization.interface';
import { getAgentUrl } from '@credebl/common/common.utils';
import {
IX509ImportCertificateOptionsDto,
x509CertificateDecodeDto,
X509CreateCertificateOptions
} from '@credebl/common/interfaces/x509.interface';
@Injectable()
@WebSocketGateway()
export class AgentServiceService {
Expand All @@ -89,7 +94,6 @@ export class AgentServiceService {
private readonly agentServiceRepository: AgentServiceRepository,
private readonly prisma: PrismaService,
private readonly commonService: CommonService,
private readonly connectionService: ConnectionService,
@Inject('NATS_CLIENT') private readonly agentServiceProxy: ClientProxy,
@Inject(CACHE_MANAGER) private cacheService: Cache,
private readonly userActivityRepository: UserActivityRepository,
Expand Down Expand Up @@ -2221,4 +2225,49 @@ export class AgentServiceService {
throw error;
}
}

async createX509Certificate(options: X509CreateCertificateOptions, url: string, orgId: string): Promise<object> {
try {
this.logger.log('Start creating X509 certificate');
this.logger.debug('Creating X509 certificate with options', options);
const getApiKey = await this.getOrgAgentApiKey(orgId);
const x509Certificate = await this.commonService
.httpPost(url, options, { headers: { authorization: getApiKey } })
.then(async (response) => response);
return x509Certificate;
} catch (error) {
this.logger.error(`Error in creating x509 certificate in agent service : ${JSON.stringify(error)}`);
throw error;
}
}

Comment on lines +2229 to +2243
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not log certificate options; redact or remove debug

Logging entire options risks leaking private material. Also, Logger.debug’s second arg is a context string, not an object.

Apply to restrict logging:

   async createX509Certificate(options: X509CreateCertificateOptions, url: string, orgId: string): Promise<object> {
     try {
-      this.logger.log('Start creating X509 certificate');
-      this.logger.debug('Creating X509 certificate with options', options);
+      this.logger.log('Start creating X509 certificate');
+      this.logger.debug('Creating X509 certificate request'); // avoid logging payload
       const getApiKey = await this.getOrgAgentApiKey(orgId);
       const x509Certificate = await this.commonService
         .httpPost(url, options, { headers: { authorization: getApiKey } })
         .then(async (response) => response);
       return x509Certificate;
     } catch (error) {
       this.logger.error(`Error in creating x509 certificate in agent service : ${JSON.stringify(error)}`);
       throw error;
     }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async createX509Certificate(options: X509CreateCertificateOptions, url: string, orgId: string): Promise<object> {
try {
this.logger.log('Start creating X509 certificate');
this.logger.debug('Creating X509 certificate with options', options);
const getApiKey = await this.getOrgAgentApiKey(orgId);
const x509Certificate = await this.commonService
.httpPost(url, options, { headers: { authorization: getApiKey } })
.then(async (response) => response);
return x509Certificate;
} catch (error) {
this.logger.error(`Error in creating x509 certificate in agent service : ${JSON.stringify(error)}`);
throw error;
}
}
async createX509Certificate(options: X509CreateCertificateOptions, url: string, orgId: string): Promise<object> {
try {
this.logger.log('Start creating X509 certificate');
this.logger.debug('Creating X509 certificate request'); // avoid logging payload
const getApiKey = await this.getOrgAgentApiKey(orgId);
const x509Certificate = await this.commonService
.httpPost(url, options, { headers: { authorization: getApiKey } })
.then(async (response) => response);
return x509Certificate;
} catch (error) {
this.logger.error(`Error in creating x509 certificate in agent service : ${JSON.stringify(error)}`);
throw error;
}
}
🤖 Prompt for AI Agents
In apps/agent-service/src/agent-service.service.ts around lines 2229 to 2243,
remove the detailed logging of the certificate options (do not log the full
options object or stringify it) and replace it with a minimal, non-sensitive
message; if you must record something, log only a safe summary (e.g., orgId,
url, or a boolean/size indicator) after redacting any sensitive fields, and
ensure you call logger.debug with a proper string message (or the logger's
accepted signature) rather than passing the options object as the second
argument.

async decodeX509Certificate(options: x509CertificateDecodeDto, url: string, orgId: string): Promise<object> {
try {
this.logger.log('Start decoding X509 certificate');
this.logger.debug('Decoding X509 certificate with options', options);
const getApiKey = await this.getOrgAgentApiKey(orgId);
const x509Certificate = await this.commonService
.httpPost(url, options, { headers: { authorization: getApiKey } })
.then(async (response) => response);
return x509Certificate;
} catch (error) {
this.logger.error(`Error in decoding x509 certificate in agent service : ${JSON.stringify(error)}`);
throw error;
}
}
Comment on lines +2244 to +2257
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Redact decode options; Logger.debug misuse

Avoid logging full decode payload; keep message-only logs.

   async decodeX509Certificate(options: x509CertificateDecodeDto, url: string, orgId: string): Promise<object> {
     try {
-      this.logger.log('Start decoding X509 certificate');
-      this.logger.debug('Decoding X509 certificate with options', options);
+      this.logger.log('Start decoding X509 certificate');
+      this.logger.debug('Decoding X509 certificate request');
       const getApiKey = await this.getOrgAgentApiKey(orgId);
       const x509Certificate = await this.commonService
         .httpPost(url, options, { headers: { authorization: getApiKey } })
         .then(async (response) => response);
       return x509Certificate;
     } catch (error) {
       this.logger.error(`Error in decoding x509 certificate in agent service : ${JSON.stringify(error)}`);
       throw error;
     }
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async decodeX509Certificate(options: x509CertificateDecodeDto, url: string, orgId: string): Promise<object> {
try {
this.logger.log('Start decoding X509 certificate');
this.logger.debug('Decoding X509 certificate with options', options);
const getApiKey = await this.getOrgAgentApiKey(orgId);
const x509Certificate = await this.commonService
.httpPost(url, options, { headers: { authorization: getApiKey } })
.then(async (response) => response);
return x509Certificate;
} catch (error) {
this.logger.error(`Error in decoding x509 certificate in agent service : ${JSON.stringify(error)}`);
throw error;
}
}
async decodeX509Certificate(options: x509CertificateDecodeDto, url: string, orgId: string): Promise<object> {
try {
this.logger.log('Start decoding X509 certificate');
this.logger.debug('Decoding X509 certificate request');
const getApiKey = await this.getOrgAgentApiKey(orgId);
const x509Certificate = await this.commonService
.httpPost(url, options, { headers: { authorization: getApiKey } })
.then(async (response) => response);
return x509Certificate;
} catch (error) {
this.logger.error(`Error in decoding x509 certificate in agent service : ${JSON.stringify(error)}`);
throw error;
}
}
🤖 Prompt for AI Agents
In apps/agent-service/src/agent-service.service.ts around lines 2244 to 2257,
the debug log currently prints the full decode options object which may contain
sensitive data; change the debug call to only log a message (e.g., "Decoding
X509 certificate") and do not include or stringify the options payload. If you
need lightweight telemetry, log non-sensitive metadata only (like option keys or
payload size) or a redacted/hashed representation instead of the full options
object.


async importX509Certificate(options: IX509ImportCertificateOptionsDto, url: string, orgId: string): Promise<object> {
try {
this.logger.log('Start importing X509 certificate');
this.logger.debug(`Importing X509 certificate with options`, options.certificate);
const getApiKey = await this.getOrgAgentApiKey(orgId);
const x509Certificate = await this.commonService
.httpPost(url, options, { headers: { authorization: getApiKey } })
.then(async (response) => response);
return x509Certificate;
} catch (error) {
this.logger.error(`Error in creating x509 certificate in agent service : ${JSON.stringify(error)}`);
throw error;
}
}
Comment on lines +2229 to +2272
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not log certificate payloads; align error handling with RpcException

  • Debug logs print entire options/certificates (sensitive). Redact.
  • Wrap thrown errors as RpcException for consistency.

Apply this diff:

   async createX509Certificate(options: X509CreateCertificateOptions, url: string, orgId: string): Promise<object> {
     try {
       this.logger.log('Start creating X509 certificate');
-      this.logger.debug('Creating X509 certificate with options', options);
+      this.logger.debug('Creating X509 certificate (redacted)', {
+        keyType: options?.authorityKey?.keyType,
+        hasSubjectPublicKey: !!options?.subjectPublicKey
+      });
       const getApiKey = await this.getOrgAgentApiKey(orgId);
       const x509Certificate = await this.commonService
         .httpPost(url, options, { headers: { authorization: getApiKey } })
         .then(async (response) => response);
       return x509Certificate;
     } catch (error) {
       this.logger.error(`Error in creating x509 certificate in agent service : ${JSON.stringify(error)}`);
-      throw error;
+      throw new RpcException(error.response ?? error);
     }
   }

   async decodeX509Certificate(options: x509CertificateDecodeDto, url: string, orgId: string): Promise<object> {
     try {
       this.logger.log('Start decoding X509 certificate');
-      this.logger.debug('Decoding X509 certificate with options', options);
+      this.logger.debug('Decoding X509 certificate (payload redacted)');
       const getApiKey = await this.getOrgAgentApiKey(orgId);
       const x509Certificate = await this.commonService
         .httpPost(url, options, { headers: { authorization: getApiKey } })
         .then(async (response) => response);
       return x509Certificate;
     } catch (error) {
       this.logger.error(`Error in decoding x509 certificate in agent service : ${JSON.stringify(error)}`);
-      throw error;
+      throw new RpcException(error.response ?? error);
     }
   }

   async importX509Certificate(options: IX509ImportCertificateOptionsDto, url: string, orgId: string): Promise<object> {
     try {
       this.logger.log('Start importing X509 certificate');
-      this.logger.debug(`Importing X509 certificate with options`, options.certificate);
+      this.logger.debug('Importing X509 certificate (payload redacted)');
       const getApiKey = await this.getOrgAgentApiKey(orgId);
       const x509Certificate = await this.commonService
         .httpPost(url, options, { headers: { authorization: getApiKey } })
         .then(async (response) => response);
       return x509Certificate;
     } catch (error) {
       this.logger.error(`Error in creating x509 certificate in agent service : ${JSON.stringify(error)}`);
-      throw error;
+      throw new RpcException(error.response ?? error);
     }
   }

I can add a small redact helper if you prefer.

📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async createX509Certificate(options: X509CreateCertificateOptions, url: string, orgId: string): Promise<object> {
try {
this.logger.log('Start creating X509 certificate');
this.logger.debug('Creating X509 certificate with options', options);
const getApiKey = await this.getOrgAgentApiKey(orgId);
const x509Certificate = await this.commonService
.httpPost(url, options, { headers: { authorization: getApiKey } })
.then(async (response) => response);
return x509Certificate;
} catch (error) {
this.logger.error(`Error in creating x509 certificate in agent service : ${JSON.stringify(error)}`);
throw error;
}
}
async decodeX509Certificate(options: x509CertificateDecodeDto, url: string, orgId: string): Promise<object> {
try {
this.logger.log('Start decoding X509 certificate');
this.logger.debug('Decoding X509 certificate with options', options);
const getApiKey = await this.getOrgAgentApiKey(orgId);
const x509Certificate = await this.commonService
.httpPost(url, options, { headers: { authorization: getApiKey } })
.then(async (response) => response);
return x509Certificate;
} catch (error) {
this.logger.error(`Error in decoding x509 certificate in agent service : ${JSON.stringify(error)}`);
throw error;
}
}
async importX509Certificate(options: IX509ImportCertificateOptionsDto, url: string, orgId: string): Promise<object> {
try {
this.logger.log('Start importing X509 certificate');
this.logger.debug(`Importing X509 certificate with options`, options.certificate);
const getApiKey = await this.getOrgAgentApiKey(orgId);
const x509Certificate = await this.commonService
.httpPost(url, options, { headers: { authorization: getApiKey } })
.then(async (response) => response);
return x509Certificate;
} catch (error) {
this.logger.error(`Error in creating x509 certificate in agent service : ${JSON.stringify(error)}`);
throw error;
}
}
async createX509Certificate(options: X509CreateCertificateOptions, url: string, orgId: string): Promise<object> {
try {
this.logger.log('Start creating X509 certificate');
this.logger.debug('Creating X509 certificate (redacted)', {
keyType: options?.authorityKey?.keyType,
hasSubjectPublicKey: !!options?.subjectPublicKey
});
const getApiKey = await this.getOrgAgentApiKey(orgId);
const x509Certificate = await this.commonService
.httpPost(url, options, { headers: { authorization: getApiKey } })
.then(async (response) => response);
return x509Certificate;
} catch (error) {
this.logger.error(`Error in creating x509 certificate in agent service : ${JSON.stringify(error)}`);
throw new RpcException(error.response ?? error);
}
}
async decodeX509Certificate(options: x509CertificateDecodeDto, url: string, orgId: string): Promise<object> {
try {
this.logger.log('Start decoding X509 certificate');
this.logger.debug('Decoding X509 certificate (payload redacted)');
const getApiKey = await this.getOrgAgentApiKey(orgId);
const x509Certificate = await this.commonService
.httpPost(url, options, { headers: { authorization: getApiKey } })
.then(async (response) => response);
return x509Certificate;
} catch (error) {
this.logger.error(`Error in decoding x509 certificate in agent service : ${JSON.stringify(error)}`);
throw new RpcException(error.response ?? error);
}
}
async importX509Certificate(options: IX509ImportCertificateOptionsDto, url: string, orgId: string): Promise<object> {
try {
this.logger.log('Start importing X509 certificate');
this.logger.debug('Importing X509 certificate (payload redacted)');
const getApiKey = await this.getOrgAgentApiKey(orgId);
const x509Certificate = await this.commonService
.httpPost(url, options, { headers: { authorization: getApiKey } })
.then(async (response) => response);
return x509Certificate;
} catch (error) {
this.logger.error(`Error in creating x509 certificate in agent service : ${JSON.stringify(error)}`);
throw new RpcException(error.response ?? error);
}
}

Comment on lines +2259 to +2272
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Do not log base64 certificate material; fix error message text

Logging options.certificate leaks sensitive content. Error log says “creating” in import path.

   async importX509Certificate(options: IX509ImportCertificateOptionsDto, url: string, orgId: string): Promise<object> {
     try {
-      this.logger.log('Start importing X509 certificate');
-      this.logger.debug(`Importing X509 certificate with options`, options.certificate);
+      this.logger.log('Start importing X509 certificate');
+      this.logger.debug('Importing X509 certificate request'); // do not log cert
       const getApiKey = await this.getOrgAgentApiKey(orgId);
       const x509Certificate = await this.commonService
         .httpPost(url, options, { headers: { authorization: getApiKey } })
         .then(async (response) => response);
       return x509Certificate;
     } catch (error) {
-      this.logger.error(`Error in creating x509 certificate in agent service : ${JSON.stringify(error)}`);
+      this.logger.error(`Error in importing x509 certificate in agent service : ${JSON.stringify(error)}`);
       throw error;
     }
   }
🤖 Prompt for AI Agents
In apps/agent-service/src/agent-service.service.ts around lines 2259-2272, the
code currently logs options.certificate (leaking base64 sensitive data) and uses
an incorrect error message saying "creating" instead of "importing"; remove any
logging of the certificate or other sensitive payloads, change the debug log to
omit or redact the certificate (e.g., log only metadata such as certificate
length or a redacted placeholder), and update the catch logger to say "Error
importing x509 certificate" while logging only non-sensitive error details
(error.message and optional sanitized stack) rather than JSON.stringify of the
entire error or request payload.

}
4 changes: 3 additions & 1 deletion apps/api-gateway/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { LoggerModule } from '@credebl/logger/logger.module';
import { GlobalConfigModule } from '@credebl/config/global-config.module';
import { ConfigModule as PlatformConfig } from '@credebl/config/config.module';
import { Oid4vcIssuanceModule } from './oid4vc-issuance/oid4vc-issuance.module';
import { X509Module } from './x509/x509.module';

@Module({
imports: [
Expand Down Expand Up @@ -66,7 +67,8 @@ import { Oid4vcIssuanceModule } from './oid4vc-issuance/oid4vc-issuance.module';
CacheModule.register({ store: redisStore, host: process.env.REDIS_HOST, port: process.env.REDIS_PORT }),
GeoLocationModule,
CloudWalletModule,
Oid4vcIssuanceModule
Oid4vcIssuanceModule,
X509Module
],
controllers: [AppController],
providers: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,6 @@ import {
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
import { Type } from 'class-transformer';

/* ========= Enums ========= */
export enum CredentialFormat {
SdJwtVc = 'vc+sd-jwt',
Mdoc = 'mdoc'
}

/* ========= disclosureFrame custom validator ========= */
function isDisclosureFrameValue(v: unknown): boolean {
if ('boolean' === typeof v) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { BaseService } from 'libs/service/base.service';
import { oidc_issuer, user } from '@prisma/client';
import { CreateCredentialTemplateDto, UpdateCredentialTemplateDto } from './dtos/oid4vc-issuer-template.dto';
import {
CreateCredentialOfferD2ADto,
CreateOidcCredentialOfferDto,
GetAllCredentialOfferDto,
UpdateCredentialRequestDto
Expand Down Expand Up @@ -98,7 +99,10 @@ export class Oid4vcIssuanceService extends BaseService {
return this.natsClient.sendNatsMessage(this.issuanceProxy, 'oid4vc-create-credential-offer', payload);
}

async createOidcCredentialOfferD2A(oidcCredentialD2APayload, orgId: string): Promise<object> {
async createOidcCredentialOfferD2A(
oidcCredentialD2APayload: CreateCredentialOfferD2ADto,
orgId: string
): Promise<object> {
const payload = { oidcCredentialD2APayload, orgId };
return this.natsClient.sendNatsMessage(this.issuanceProxy, 'oid4vc-create-credential-offer-D2A', payload);
}
Expand Down
Loading