feat: improve operations diagnostics and channel management

This commit is contained in:
hectorzhao
2026-08-09 14:27:19 +08:00
parent 44352aeb2f
commit 4724b9db6a
65 changed files with 1211 additions and 293 deletions
@@ -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) {