feat: improve operations diagnostics and channel management
This commit is contained in:
@@ -59,31 +59,77 @@ export class SendInboundEntryService {
|
||||
|
||||
|
||||
async authenticateInboundApplication(data: GatewayInboundAuthDto) {
|
||||
const application = await this.facade.findInboundApplication(data.account);
|
||||
if (!application || !['active', 'disabling'].includes(application.status) || application.tenant.status !== 'active') {
|
||||
throw new BadRequestException('CMPP account is invalid or disabled');
|
||||
let tenantId: string | undefined;
|
||||
let applicationId: string | undefined;
|
||||
try {
|
||||
const application = await this.facade.findInboundApplication(data.account);
|
||||
tenantId = application?.tenantId;
|
||||
applicationId = application?.id;
|
||||
if (!application || !['active', 'disabling'].includes(application.status) || application.tenant.status !== 'active') {
|
||||
throw new BadRequestException('CMPP account is invalid or disabled');
|
||||
}
|
||||
if (!application.interfaceEnabled) {
|
||||
throw new BadRequestException('CMPP interface is disabled for this application');
|
||||
}
|
||||
if (application.tenant.certificationStatus !== 'approved') {
|
||||
throw new BadRequestException('Enterprise certification is not approved');
|
||||
}
|
||||
if (!matchesApplicationSecret(data, application.secretHash)) {
|
||||
throw new BadRequestException('CMPP account or password is invalid');
|
||||
}
|
||||
if (data.remoteIp && !isIpAllowed(data.remoteIp, application.ipAllowlist.map((item) => item.ipCidr))) {
|
||||
throw new BadRequestException('CMPP source IP is not in application allowlist');
|
||||
}
|
||||
await this.recordInboundConnectRequest(data, { tenantId, applicationId, result: 'authenticated' });
|
||||
return {
|
||||
applicationId: application.id,
|
||||
tenantId: application.tenantId,
|
||||
account: application.cmppAccount,
|
||||
enterpriseCode: application.cmppEnterpriseCode,
|
||||
passwordCipher: application.secretHash,
|
||||
maxConnections: application.cmppMaxConnections,
|
||||
status: 'authenticated',
|
||||
};
|
||||
} catch (error) {
|
||||
await this.recordInboundConnectRequest(data, {
|
||||
tenantId,
|
||||
applicationId,
|
||||
result: 'failed',
|
||||
error: error instanceof Error ? error.message : 'unknown error',
|
||||
});
|
||||
throw error;
|
||||
}
|
||||
if (!application.interfaceEnabled) {
|
||||
throw new BadRequestException('CMPP interface is disabled for this application');
|
||||
}
|
||||
if (application.tenant.certificationStatus !== 'approved') {
|
||||
throw new BadRequestException('Enterprise certification is not approved');
|
||||
}
|
||||
if (!matchesApplicationSecret(data, application.secretHash)) {
|
||||
throw new BadRequestException('CMPP account or password is invalid');
|
||||
}
|
||||
if (data.remoteIp && !isIpAllowed(data.remoteIp, application.ipAllowlist.map((item) => item.ipCidr))) {
|
||||
throw new BadRequestException('CMPP source IP is not in application allowlist');
|
||||
}
|
||||
return {
|
||||
applicationId: application.id,
|
||||
tenantId: application.tenantId,
|
||||
account: application.cmppAccount,
|
||||
enterpriseCode: application.cmppEnterpriseCode,
|
||||
passwordCipher: application.secretHash,
|
||||
maxConnections: application.cmppMaxConnections,
|
||||
status: 'authenticated',
|
||||
};
|
||||
}
|
||||
|
||||
private recordInboundConnectRequest(
|
||||
data: GatewayInboundAuthDto,
|
||||
outcome: { tenantId?: string; applicationId?: string; result: 'authenticated' | 'failed'; error?: string },
|
||||
) {
|
||||
return this.prisma.operationLog.create({
|
||||
data: {
|
||||
tenantId: outcome.tenantId,
|
||||
action: 'cmpp_connection.connect_requested',
|
||||
resource: 'cmpp_downstream_connection',
|
||||
resourceId: outcome.applicationId ?? data.account,
|
||||
ipAddress: data.remoteIp?.trim() || undefined,
|
||||
detail: {
|
||||
direction: 'client_to_platform',
|
||||
result: outcome.result,
|
||||
applicationId: outcome.applicationId ?? null,
|
||||
request: {
|
||||
remoteIp: data.remoteIp?.trim() || null,
|
||||
account: data.account,
|
||||
// Standard CMPP sends AuthenticatorSource rather than a plaintext password; keep both fields truthful.
|
||||
password: data.password ?? null,
|
||||
authSource: data.authSource ?? null,
|
||||
timestamp: data.timestamp ?? null,
|
||||
version: data.version ?? null,
|
||||
requestedVersion: data.requestedVersion ?? null,
|
||||
},
|
||||
error: outcome.error ?? null,
|
||||
} as Prisma.InputJsonValue,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
async submitInboundMessage(data: GatewayInboundSubmitDto) {
|
||||
|
||||
Reference in New Issue
Block a user