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
10 changes: 10 additions & 0 deletions .env.sample
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,16 @@ INDICIO_TEST_GENESIS=`{"reqSignature":{},"txn":{"data":{"data":{"alias":"OpsNode
{"reqSignature":{},"txn":{"data":{"data":{"alias":"lorica-identity-node1","blskey":"wUh24sVCQ8PHDgSb343g2eLxjD5vwxsrETfuV2sbwMNnYon9nhbaK5jcWTekvXtyiwxHxuiCCoZwKS97MQEAeC2oLbbMeKjYm212QwSnm7aKLEqTStXht35VqZvZLT7Q3mPQRYLjMGixdn4ocNHrBTMwPUQYycEqwaHWgE1ncDueXY","blskey_pop":"R2sMwF7UW6AaD4ALa1uB1YVPuP6JsdJ7LsUoViM9oySFqFt34C1x1tdHDysS9wwruzaaEFui6xNPqJ8eu3UBqcFKkoWhdsMqCALwe63ytxPwvtLtCffJLhHAcgrPC7DorXYdqhdG2cevdqc5oqFEAaKoFDBf12p5SsbbM4PYWCmVCb","client_ip":"35.225.220.151","client_port":"9702","node_ip":"35.224.26.110","node_port":"9701","services":["VALIDATOR"]},"dest":"k74ZsZuUaJEcB8RRxMwkCwdE5g1r9yzA3nx41qvYqYf"},"metadata":{"from":"Ex6hzsJFYzNJ7kzbfncNeU"},"type":"0"},"txnMetadata":{"seqNo":6,"txnId":"6880673ce4ae4a2352f103d2a6ae20469dd070f2027283a1da5e62a64a59d688"},"ver":"1"}
{"reqSignature":{},"txn":{"data":{"data":{"alias":"cysecure-itn","blskey":"GdCvMLkkBYevRFi93b6qaj9G2u1W6Vnbg8QhRD1chhrWR8vRE8x9x7KXVeUBPFf6yW5qq2JCfA2frc8SGni2RwjtTagezfwAwnorLhVJqS5ZxTi4pgcw6smebnt4zWVhTkh6ugDHEypHwNQBcw5WhBZcEJKgNbyVLnHok9ob6cfr3u","blskey_pop":"RbH9mY7M5p3UB3oj4sT1skYwMkxjoUnja8eTYfcm83VcNbxC9zR9pCiRhk4q1dJT3wkDBPGNKnk2p83vaJYLcgMuJtzoWoJAWAxjb3Mcq8Agf6cgQpBuzBq2uCzFPuQCAhDS4Kv9iwA6FsRnfvoeFTs1hhgSJVxQzDWMVTVAD9uCqu","client_ip":"35.169.19.171","client_port":"9702","node_ip":"54.225.56.21","node_port":"9701","services":["VALIDATOR"]},"dest":"4ETBDmHzx8iDQB6Xygmo9nNXtMgq9f6hxGArNhQ6Hh3u"},"metadata":{"from":"uSXXXEdBicPHMMhr3ddNF"},"type":"0"},"txnMetadata":{"seqNo":7,"txnId":"3c21718b07806b2f193b35953dda5b68b288efd551dce4467ce890703d5ba549"},"ver":"1"}`

PLATFORM_BASE_URL= #CREDEBL BASE URL
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 .env assignment syntax for PLATFORM_BASE_URL.

The inline comment is currently part of the value, which can produce an invalid URL at runtime.

🧩 Suggested patch
-PLATFORM_BASE_URL=        `#CREDEBL` BASE URL
+# CREDEBL BASE URL
+PLATFORM_BASE_URL=
📝 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
PLATFORM_BASE_URL= #CREDEBL BASE URL
# CREDEBL BASE URL
PLATFORM_BASE_URL=
🧰 Tools
🪛 dotenv-linter (4.0.0)

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

(SpaceCharacter)


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

(ValueWithoutQuotes)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.env.sample at line 45, The PLATFORM_BASE_URL entry currently includes an
inline comment as part of its value; update the .env line so PLATFORM_BASE_URL
has only the URL (or is empty) and move the explanatory comment to its own line
prefixed with # (e.g., add a separate comment line mentioning "CRED EBL BASE
URL") so the env value is not polluted by the comment; locate and edit the
PLATFORM_BASE_URL line to remove the inline comment and ensure only a valid URL
or empty assignment remains.

#if the agent is dedicated
PLATFORM_DEDICATED_CLIENT_ID=
PLATFORM_DEDICATED_CLIENT_SECRET=
#If the agent is shared
PLATFORM_SHARED_AGENT_CLIENT_ID=
PLATFORM_SHARED_AGENT_CLIENT_SECRET=
#Trust service url to fetch trusted certificates for TLS pinning
TRUST_SERVICE_URL=

APP_URL=
AGENT_HTTP_URL=
HOLDER_REDIRECT=
Expand Down
7 changes: 5 additions & 2 deletions src/cliAgent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,12 @@ const getModules = (
}),
openId4VcHolderModule: new OpenId4VcHolderModule(),
x509: new X509Module({
getTrustedCertificatesForVerification: async (_agentContext, { certificateChain, verification }) => {
getTrustedCertificatesForVerification: async (agentContext, { certificateChain: _certificateChain, verification: _verification }) => {
//TODO: We need to trust the certificate tenant wise, for that we need to fetch those details from platform
const certs: string[] = await getTrustedCerts()
const tenantId = agentContext.contextCorrelationId
console.log('[getTrustedCertificatesForVerification] tenantId from agentContext:', tenantId)
const certs: string[] = await getTrustedCerts(tenantId)

return certs
},
}),
Expand Down
64 changes: 64 additions & 0 deletions src/controllers/auth/AuthController.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import axios from 'axios'
import { Request as Req } from 'express'
import { Body, Controller, Get, Path, Post, Request, Route, Tags } from 'tsoa'
import { injectable } from 'tsyringe'

import { BadRequestError } from '../../errors'
import { fetchDedicatedX509Certificates, fetchSharedAgentX509Certificates } from '../../utils/helpers'
import { getTrustedCerts } from '../../utils/oid4vc-agent'

interface OrgTokenRequest {
clientId: string
clientSecret: string
}

interface OrgTokenResponse {
token: string
}

@Tags('Auth')
@Route('/v1/orgs')
@injectable()
export class AuthController extends Controller {
/**
* Generate an organization token by forwarding credentials to the platform
*/
// @Security('jwt', [SCOPES.UNPROTECTED])
@Post('/{orgId}/token')
public async getOrgToken(
@Request() _request: Req,
@Path('orgId') orgId: string,
@Body() body: OrgTokenRequest,
): Promise<OrgTokenResponse> {
const platformBaseUrl = process.env.PLATFORM_BASE_URL
if (!platformBaseUrl) {
throw new BadRequestError('PLATFORM_BASE_URL is not configured')
}

const response = await axios.post<OrgTokenResponse>(
`${platformBaseUrl}/v1/orgs/${orgId}/token`,
{ clientId: body.clientId, clientSecret: body.clientSecret },
{ headers: { 'Content-Type': 'application/json', accept: 'application/json' } },
)

return response.data
}
Comment on lines +38 to +45
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

Return the declared OrgTokenResponse shape explicitly.

The method returns raw upstream payload, but the API contract declares { token: string }. This can break clients and generated schema expectations.

📦 Suggested patch
-    const response = await axios.post<OrgTokenResponse>(
+    const response = await axios.post<{ token?: string; data?: { access_token?: string } }>(
       `${platformBaseUrl}/v1/orgs/${orgId}/token`,
       { clientId: body.clientId, clientSecret: body.clientSecret },
       { headers: { 'Content-Type': 'application/json', accept: 'application/json' } },
     )
-
-    return response.data
+    const token = response.data.token ?? response.data.data?.access_token
+    if (!token) throw new BadRequestError('Token not found in platform response')
+    return { token }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/controllers/auth/AuthController.ts` around lines 38 - 45, The method is
returning the raw upstream payload instead of the declared OrgTokenResponse
shape ({ token: string }); update the AuthController method that calls
axios.post<OrgTokenResponse> to explicitly construct and return an object
matching OrgTokenResponse (e.g., return { token: response.data.token }) and
ensure the function signature/return type is OrgTokenResponse so callers and
generated schemas receive the declared shape; if upstream uses a different field
name, map that field to token or validate its presence before returning.

// TODO: Remove these test endpoints after manual testing is done
@Get('/test/dedicated-x509-certificates')
public async testFetchDedicatedX509Certificates(@Request() _request: Req): Promise<string[]> {
return fetchDedicatedX509Certificates()
}

@Get('/test/shared-agent-x509-certificates')
public async testFetchSharedAgentX509Certificates(@Request() _request: Req): Promise<string[]> {
return fetchSharedAgentX509Certificates()
}

/**
* [TEMP] Manually trigger getTrustedCerts to test agent type detection and trust list fetch
*/
@Get('/test/trusted-certs')
public async testGetTrustedCerts(@Request() _request: Req): Promise<string[]> {
Comment on lines +46 to +61
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we remoev them?

Copy link
Contributor Author

@tipusinghaw tipusinghaw Mar 3, 2026

Choose a reason for hiding this comment

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

We will remove this after testing on the instance

return getTrustedCerts()
}
Comment on lines +46 to +63
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🔴 Critical

Protect or remove test certificate endpoints before release.

These endpoints are publicly reachable as declared and expose sensitive trust/certificate operations without authentication.

🛡️ Suggested patch
-import { Body, Controller, Get, Path, Post, Request, Route, Tags } from 'tsoa'
+import { Body, Controller, Get, Path, Post, Request, Route, Security, Tags } from 'tsoa'

@@
   `@Get`('/test/dedicated-x509-certificates')
+  `@Security`('jwt', ['tenant', 'dedicated'])
   public async testFetchDedicatedX509Certificates(`@Request`() _request: Req): Promise<string[]> {
     return fetchDedicatedX509Certificates()
   }

   `@Get`('/test/shared-agent-x509-certificates')
+  `@Security`('jwt', ['tenant', 'dedicated'])
   public async testFetchSharedAgentX509Certificates(`@Request`() _request: Req): Promise<string[]> {
     return fetchSharedAgentX509Certificates()
   }

@@
   `@Get`('/test/trusted-certs')
+  `@Security`('jwt', ['tenant', 'dedicated'])
   public async testGetTrustedCerts(`@Request`() _request: Req): Promise<string[]> {
     return getTrustedCerts()
   }
🧰 Tools
🪛 ESLint

[error] 46-46: Insert ··

(prettier/prettier)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/controllers/auth/AuthController.ts` around lines 46 - 63, Remove or
protect the three temporary public test endpoints that expose certificate/trust
operations: the controller methods testFetchDedicatedX509Certificates,
testFetchSharedAgentX509Certificates, and testGetTrustedCerts (which call
fetchDedicatedX509Certificates, fetchSharedAgentX509Certificates, and
getTrustedCerts respectively). Either delete these methods entirely before
release or restrict access by applying your authentication/authorization guard
(e.g., add the appropriate `@UseGuards`(...) and role-check decorator or
middleware) and ensure only privileged users can call them; update any tests or
documentation that reference these routes accordingly.

}
161 changes: 161 additions & 0 deletions src/routes/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ import { ConnectionController } from './../controllers/didcomm/connections/Conne
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
import { DidController } from './../controllers/did/DidController';
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
import { AuthController } from './../controllers/auth/AuthController';
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
import { AgentController } from './../controllers/agent/AgentController';
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
import { VerifierController } from './../controllers/openid4vc/verifiers/verifier.Controller';
Expand Down Expand Up @@ -1330,6 +1332,23 @@ const models: TsoaRoute.Models = {
"type": {"ref":"Record_string.unknown_","validators":{}},
},
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
"OrgTokenResponse": {
"dataType": "refObject",
"properties": {
"token": {"dataType":"string","required":true},
},
"additionalProperties": false,
},
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
"OrgTokenRequest": {
"dataType": "refObject",
"properties": {
"clientId": {"dataType":"string","required":true},
"clientSecret": {"dataType":"string","required":true},
},
"additionalProperties": false,
},
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
"AgentInfo": {
"dataType": "refObject",
"properties": {
Expand Down Expand Up @@ -3618,6 +3637,148 @@ export function RegisterRoutes(app: Router) {
}
});
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
const argsAuthController_getOrgToken: Record<string, TsoaRoute.ParameterSchema> = {
_request: {"in":"request","name":"_request","required":true,"dataType":"object"},
orgId: {"in":"path","name":"orgId","required":true,"dataType":"string"},
body: {"in":"body","name":"body","required":true,"ref":"OrgTokenRequest"},
};
app.post('/v1/orgs/:orgId/token',
...(fetchMiddlewares<RequestHandler>(AuthController)),
...(fetchMiddlewares<RequestHandler>(AuthController.prototype.getOrgToken)),

async function AuthController_getOrgToken(request: ExRequest, response: ExResponse, next: any) {

// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa

let validatedArgs: any[] = [];
try {
validatedArgs = templateService.getValidatedArgs({ args: argsAuthController_getOrgToken, request, response });

const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer;

const controller: any = await container.get<AuthController>(AuthController);
if (typeof controller['setStatus'] === 'function') {
controller.setStatus(undefined);
}

await templateService.apiHandler({
methodName: 'getOrgToken',
controller,
response,
next,
validatedArgs,
successStatus: undefined,
});
} catch (err) {
return next(err);
}
});
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
const argsAuthController_testFetchDedicatedX509Certificates: Record<string, TsoaRoute.ParameterSchema> = {
_request: {"in":"request","name":"_request","required":true,"dataType":"object"},
};
app.get('/v1/orgs/test/dedicated-x509-certificates',
...(fetchMiddlewares<RequestHandler>(AuthController)),
...(fetchMiddlewares<RequestHandler>(AuthController.prototype.testFetchDedicatedX509Certificates)),

async function AuthController_testFetchDedicatedX509Certificates(request: ExRequest, response: ExResponse, next: any) {

// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa

let validatedArgs: any[] = [];
try {
validatedArgs = templateService.getValidatedArgs({ args: argsAuthController_testFetchDedicatedX509Certificates, request, response });

const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer;

const controller: any = await container.get<AuthController>(AuthController);
if (typeof controller['setStatus'] === 'function') {
controller.setStatus(undefined);
}

await templateService.apiHandler({
methodName: 'testFetchDedicatedX509Certificates',
controller,
response,
next,
validatedArgs,
successStatus: undefined,
});
} catch (err) {
return next(err);
}
});
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
const argsAuthController_testFetchSharedAgentX509Certificates: Record<string, TsoaRoute.ParameterSchema> = {
_request: {"in":"request","name":"_request","required":true,"dataType":"object"},
};
app.get('/v1/orgs/test/shared-agent-x509-certificates',
...(fetchMiddlewares<RequestHandler>(AuthController)),
...(fetchMiddlewares<RequestHandler>(AuthController.prototype.testFetchSharedAgentX509Certificates)),

async function AuthController_testFetchSharedAgentX509Certificates(request: ExRequest, response: ExResponse, next: any) {

// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa

let validatedArgs: any[] = [];
try {
validatedArgs = templateService.getValidatedArgs({ args: argsAuthController_testFetchSharedAgentX509Certificates, request, response });

const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer;

const controller: any = await container.get<AuthController>(AuthController);
if (typeof controller['setStatus'] === 'function') {
controller.setStatus(undefined);
}

await templateService.apiHandler({
methodName: 'testFetchSharedAgentX509Certificates',
controller,
response,
next,
validatedArgs,
successStatus: undefined,
});
} catch (err) {
return next(err);
}
});
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
const argsAuthController_testGetTrustedCerts: Record<string, TsoaRoute.ParameterSchema> = {
_request: {"in":"request","name":"_request","required":true,"dataType":"object"},
};
app.get('/v1/orgs/test/trusted-certs',
...(fetchMiddlewares<RequestHandler>(AuthController)),
...(fetchMiddlewares<RequestHandler>(AuthController.prototype.testGetTrustedCerts)),

async function AuthController_testGetTrustedCerts(request: ExRequest, response: ExResponse, next: any) {

// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa

let validatedArgs: any[] = [];
try {
validatedArgs = templateService.getValidatedArgs({ args: argsAuthController_testGetTrustedCerts, request, response });

const container: IocContainer = typeof iocContainer === 'function' ? (iocContainer as IocContainerFactory)(request) : iocContainer;

const controller: any = await container.get<AuthController>(AuthController);
if (typeof controller['setStatus'] === 'function') {
controller.setStatus(undefined);
}

await templateService.apiHandler({
methodName: 'testGetTrustedCerts',
controller,
response,
next,
validatedArgs,
successStatus: undefined,
});
} catch (err) {
return next(err);
}
});
// WARNING: This file was auto-generated with tsoa. Please do not modify it. Re-run tsoa to re-generate this file: https://github.com/lukeautry/tsoa
const argsAgentController_getAgentInfo: Record<string, TsoaRoute.ParameterSchema> = {
request: {"in":"request","name":"request","required":true,"dataType":"object"},
};
Expand Down
Loading