fix: 收敛NapCat运行态检查脚本边界
This commit is contained in:
parent
bfb10c50cb
commit
2a890d894d
@ -26,7 +26,7 @@ export class QqbotNapcatAccountRuntimeService implements QqbotAccountNapcatRunti
|
|||||||
/**
|
/**
|
||||||
* Creates the account-list runtime adapter that joins persisted bindings, container status, and optional profile summaries.
|
* Creates the account-list runtime adapter that joins persisted bindings, container status, and optional profile summaries.
|
||||||
* @param accountNapcatRepository - Binding repository used to pick the primary NapCat container for each QQBot account.
|
* @param accountNapcatRepository - Binding repository used to pick the primary NapCat container for each QQBot account.
|
||||||
* @param napcatContainerRepository - Container repository used for cached Docker/WebUI status and non-secret metadata.
|
* @param napcatContainerRepository - Container repository used for cached runtime/WebUI status and non-secret metadata.
|
||||||
* @param napcatContainerService - Runtime integration service for bounded NapCat/WebUI status probes and auto-login.
|
* @param napcatContainerService - Runtime integration service for bounded NapCat/WebUI status probes and auto-login.
|
||||||
* @param toolsService - Shared helpers for status text normalization and NapCat offline-message classification.
|
* @param toolsService - Shared helpers for status text normalization and NapCat offline-message classification.
|
||||||
* @param runtimeProfileInspector - Optional profile reader that enriches list rows without changing login state.
|
* @param runtimeProfileInspector - Optional profile reader that enriches list rows without changing login state.
|
||||||
|
|||||||
@ -1,8 +1,9 @@
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable, Optional } from '@nestjs/common';
|
||||||
import { ConfigService } from '@nestjs/config';
|
import { ConfigService } from '@nestjs/config';
|
||||||
import { InjectRepository } from '@nestjs/typeorm';
|
import { InjectRepository } from '@nestjs/typeorm';
|
||||||
import { In, Repository } from 'typeorm';
|
import { In, Repository } from 'typeorm';
|
||||||
import { ToolsService } from '@/common';
|
import { ToolsService } from '@/common';
|
||||||
|
import { NapcatRuntimeProfileInspectionScriptService } from '../../infrastructure/integration/container/napcat-runtime-profile-inspection-script.service';
|
||||||
import { NapcatProtocolProfile } from '../../infrastructure/persistence/napcat-protocol-profile.entity';
|
import { NapcatProtocolProfile } from '../../infrastructure/persistence/napcat-protocol-profile.entity';
|
||||||
import { NapcatRuntimeProfile } from '../../infrastructure/persistence/napcat-runtime-profile.entity';
|
import { NapcatRuntimeProfile } from '../../infrastructure/persistence/napcat-runtime-profile.entity';
|
||||||
|
|
||||||
@ -22,11 +23,12 @@ export type NapcatRuntimeProfileSummary = {
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class NapcatRuntimeProfileInspectorService {
|
export class NapcatRuntimeProfileInspectorService {
|
||||||
/**
|
/**
|
||||||
* Initializes runtime inspection over the existing SSH-managed container model.
|
* Initializes runtime inspection over the existing remote-managed runtime model.
|
||||||
* @param runtimeProfileRepository - Runtime profile repository updated with latest Docker and desktop evidence.
|
* @param runtimeProfileRepository - Runtime profile repository updated with latest container and desktop evidence.
|
||||||
* @param protocolProfileRepository - Protocol profile repository updated with config hashes and drift state.
|
* @param protocolProfileRepository - Protocol profile repository updated with config hashes and drift state.
|
||||||
* @param configService - Runtime config provider used for SSH target and inspection timeout defaults.
|
* @param configService - Runtime config provider used for inspection timeout defaults.
|
||||||
* @param toolsService - Shared helper used to normalize string evidence before redaction.
|
* @param toolsService - Shared helper used to normalize string evidence before redaction.
|
||||||
|
* @param inspectionScriptService - Infrastructure helper that owns remote script construction.
|
||||||
*/
|
*/
|
||||||
constructor(
|
constructor(
|
||||||
@InjectRepository(NapcatRuntimeProfile)
|
@InjectRepository(NapcatRuntimeProfile)
|
||||||
@ -35,25 +37,26 @@ export class NapcatRuntimeProfileInspectorService {
|
|||||||
private readonly protocolProfileRepository: Repository<NapcatProtocolProfile>,
|
private readonly protocolProfileRepository: Repository<NapcatProtocolProfile>,
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
private readonly toolsService: ToolsService,
|
private readonly toolsService: ToolsService,
|
||||||
) {}
|
@Optional()
|
||||||
|
private readonly inspectionScriptService?: NapcatRuntimeProfileInspectionScriptService,
|
||||||
|
) {
|
||||||
|
this.inspectionScriptService =
|
||||||
|
inspectionScriptService ||
|
||||||
|
new NapcatRuntimeProfileInspectionScriptService();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds the remote inspection script for Docker and in-container profile evidence.
|
* Delegates remote profile evidence script creation to the infrastructure helper.
|
||||||
* @param containerName - Docker container name selected from the persisted NapCat container row.
|
* @param containerName - Runtime container name selected from the persisted NapCat container row.
|
||||||
* @returns Shell script that collects runtime evidence without reading secret env values.
|
* @returns Read-only profile evidence script without secret environment reads.
|
||||||
*/
|
*/
|
||||||
buildInspectScript(containerName: string) {
|
buildInspectScript(containerName: string) {
|
||||||
return `
|
return this.inspectionScriptService.buildInspectScript(containerName);
|
||||||
set -eu
|
|
||||||
NAME=${this.sh(containerName)}
|
|
||||||
docker inspect "$NAME"
|
|
||||||
docker exec "$NAME" sh -lc 'locale -a; locale; date +%Z; fc-match "Noto Sans CJK SC"; test ! -e /.dockerenv; cat /proc/1/cgroup; id; ps -eo user,args | grep -E "qq|NapCat|Xvfb" | grep -v grep || true'
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redacts secrets before evidence is stored, logged, or returned to Admin.
|
* Redacts secrets before evidence is stored, logged, or returned to Admin.
|
||||||
* @param value - Evidence object or primitive produced by Docker, NapCat, or config writers.
|
* @param value - Evidence object or primitive produced by runtime, NapCat, or config writers.
|
||||||
* @returns Evidence with sensitive keys and token query values replaced by placeholders.
|
* @returns Evidence with sensitive keys and token query values replaced by placeholders.
|
||||||
*/
|
*/
|
||||||
sanitizeEvidence(value: unknown): unknown {
|
sanitizeEvidence(value: unknown): unknown {
|
||||||
@ -140,7 +143,7 @@ docker exec "$NAME" sh -lc 'locale -a; locale; date +%Z; fc-match "Noto Sans CJK
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Reads the bounded runtime profile inspection timeout.
|
* Reads the bounded runtime profile inspection timeout.
|
||||||
* @returns Positive timeout in milliseconds for future SSH inspection calls.
|
* @returns Positive timeout in milliseconds for future remote inspection calls.
|
||||||
*/
|
*/
|
||||||
private getInspectionTimeoutMs() {
|
private getInspectionTimeoutMs() {
|
||||||
const value = Number(
|
const value = Number(
|
||||||
@ -173,13 +176,4 @@ docker exec "$NAME" sh -lc 'locale -a; locale; date +%Z; fc-match "Noto Sans CJK
|
|||||||
private redactString(value: string) {
|
private redactString(value: string) {
|
||||||
return value.replace(/token=[^&\s]+/gi, 'token=[REDACTED]');
|
return value.replace(/token=[^&\s]+/gi, 'token=[REDACTED]');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Quotes shell literals used by read-only inspection scripts.
|
|
||||||
* @param value - Container name selected from trusted persistence.
|
|
||||||
* @returns POSIX-safe single-quoted shell literal.
|
|
||||||
*/
|
|
||||||
private sh(value: string) {
|
|
||||||
return `'${`${value}`.replace(/'/g, `'\\''`)}'`;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import type { NapcatRuntimeProfileSnapshot } from '../../domain/runtime/napcat-p
|
|||||||
@Injectable()
|
@Injectable()
|
||||||
export class NapcatRuntimeProfileService {
|
export class NapcatRuntimeProfileService {
|
||||||
/**
|
/**
|
||||||
* Initializes the profile resolver used before Docker script generation.
|
* Initializes the profile resolver used before managed runtime script generation.
|
||||||
* @param configService - Nest config provider that supplies image ref, UID/GID, shm size, and profile version.
|
* @param configService - Nest config provider that supplies image ref, UID/GID, shm size, and profile version.
|
||||||
*/
|
*/
|
||||||
constructor(private readonly configService: ConfigService) {}
|
constructor(private readonly configService: ConfigService) {}
|
||||||
@ -13,7 +13,7 @@ export class NapcatRuntimeProfileService {
|
|||||||
/**
|
/**
|
||||||
* Resolves the runtime profile for an account-owned NapCat container.
|
* Resolves the runtime profile for an account-owned NapCat container.
|
||||||
* @param input - Account, container, data directory, and device identity ids that tie generated profile evidence to persistence.
|
* @param input - Account, container, data directory, and device identity ids that tie generated profile evidence to persistence.
|
||||||
* @returns Runtime profile snapshot used by Docker script generation and later persistence.
|
* @returns Runtime profile snapshot used by managed runtime script generation and later persistence.
|
||||||
*/
|
*/
|
||||||
resolveRuntimeProfile(input: {
|
resolveRuntimeProfile(input: {
|
||||||
accountId: string;
|
accountId: string;
|
||||||
@ -49,7 +49,7 @@ export class NapcatRuntimeProfileService {
|
|||||||
* Reads a trimmed string config value for profile generation.
|
* Reads a trimmed string config value for profile generation.
|
||||||
* @param key - Environment key that controls NapCat runtime profile generation.
|
* @param key - Environment key that controls NapCat runtime profile generation.
|
||||||
* @param defaultValue - Value used when the key is absent from runtime config.
|
* @param defaultValue - Value used when the key is absent from runtime config.
|
||||||
* @returns Trimmed string value consumed by Docker script generation.
|
* @returns Trimmed string value consumed by managed runtime script generation.
|
||||||
*/
|
*/
|
||||||
private getString(key: string, defaultValue: string) {
|
private getString(key: string, defaultValue: string) {
|
||||||
return `${this.configService.get<string>(key) || defaultValue}`.trim();
|
return `${this.configService.get<string>(key) || defaultValue}`.trim();
|
||||||
|
|||||||
@ -41,7 +41,7 @@ export class NapcatSessionBehaviorService {
|
|||||||
/**
|
/**
|
||||||
* Converts housekeeping failure into an evidence-only action.
|
* Converts housekeeping failure into an evidence-only action.
|
||||||
* @param input - Account and failure summary from a low-side-effect housekeeping call.
|
* @param input - Account and failure summary from a low-side-effect housekeeping call.
|
||||||
* @returns Decision that disables behavior extensions without resetting login, retrying password, recreating Docker, or refreshing QR.
|
* @returns Decision that disables behavior extensions without resetting login, retrying password, recreating runtime, or refreshing QR.
|
||||||
*/
|
*/
|
||||||
handleHousekeepingFailure(input: {
|
handleHousekeepingFailure(input: {
|
||||||
accountId: string;
|
accountId: string;
|
||||||
|
|||||||
@ -28,7 +28,7 @@ export const NAPCAT_REJECTED_VIRTUAL_OUI_PREFIXES = [
|
|||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks whether a generated MAC starts with a Docker or VM-style prefix.
|
* Checks whether a generated MAC starts with a container or VM-style prefix.
|
||||||
* @param macAddress - Stable MAC candidate generated from account/device seed.
|
* @param macAddress - Stable MAC candidate generated from account/device seed.
|
||||||
* @returns True when the prefix belongs to a rejected container or virtualization range.
|
* @returns True when the prefix belongs to a rejected container or virtualization range.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@ -19,4 +19,5 @@ export * from './application/runtime/napcat-login-event.service';
|
|||||||
export * from './application/runtime/napcat-runtime-profile-inspector.service';
|
export * from './application/runtime/napcat-runtime-profile-inspector.service';
|
||||||
export * from './application/runtime/napcat-session-behavior.service';
|
export * from './application/runtime/napcat-session-behavior.service';
|
||||||
export * from './infrastructure/persistence';
|
export * from './infrastructure/persistence';
|
||||||
|
export * from './infrastructure/integration/container/napcat-runtime-profile-inspection-script.service';
|
||||||
export * from './infrastructure/integration/container/qqbot-napcat-container.service';
|
export * from './infrastructure/integration/container/qqbot-napcat-container.service';
|
||||||
|
|||||||
@ -0,0 +1,27 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class NapcatRuntimeProfileInspectionScriptService {
|
||||||
|
/**
|
||||||
|
* Builds the remote inspection script for Docker and in-container profile evidence.
|
||||||
|
* @param containerName - Docker container name selected from the persisted NapCat container row.
|
||||||
|
* @returns Shell script that collects runtime evidence without reading secret environment values.
|
||||||
|
*/
|
||||||
|
buildInspectScript(containerName: string) {
|
||||||
|
return `
|
||||||
|
set -eu
|
||||||
|
NAME=${this.sh(containerName)}
|
||||||
|
docker inspect "$NAME"
|
||||||
|
docker exec "$NAME" sh -lc 'locale -a; locale; date +%Z; fc-match "Noto Sans CJK SC"; test ! -e /.dockerenv; cat /proc/1/cgroup; id; ps -eo user,args | grep -E "qq|NapCat|Xvfb" | grep -v grep || true'
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quotes shell literals used by read-only inspection scripts.
|
||||||
|
* @param value - Container name selected from trusted persistence.
|
||||||
|
* @returns POSIX-safe single-quoted shell literal.
|
||||||
|
*/
|
||||||
|
private sh(value: string) {
|
||||||
|
return `'${`${value}`.replace(/'/g, `'\\''`)}'`;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -14,6 +14,7 @@ import { NapcatRuntimeProfileService } from './application/runtime/napcat-runtim
|
|||||||
import { NapcatSessionBehaviorService } from './application/runtime/napcat-session-behavior.service';
|
import { NapcatSessionBehaviorService } from './application/runtime/napcat-session-behavior.service';
|
||||||
import { QqbotNapcatLoginController } from './contract/qqbot-napcat-login.controller';
|
import { QqbotNapcatLoginController } from './contract/qqbot-napcat-login.controller';
|
||||||
import { QqbotNapcatRuntimeController } from './contract/qqbot-napcat-runtime.controller';
|
import { QqbotNapcatRuntimeController } from './contract/qqbot-napcat-runtime.controller';
|
||||||
|
import { NapcatRuntimeProfileInspectionScriptService } from './infrastructure/integration/container/napcat-runtime-profile-inspection-script.service';
|
||||||
import { QqbotNapcatContainerService } from './infrastructure/integration/container/qqbot-napcat-container.service';
|
import { QqbotNapcatContainerService } from './infrastructure/integration/container/qqbot-napcat-container.service';
|
||||||
import { NapcatDeviceIdentityService } from './infrastructure/integration/device/napcat-device-identity.service';
|
import { NapcatDeviceIdentityService } from './infrastructure/integration/device/napcat-device-identity.service';
|
||||||
import { NAPCAT_RUNTIME_ENTITIES } from './infrastructure/persistence';
|
import { NAPCAT_RUNTIME_ENTITIES } from './infrastructure/persistence';
|
||||||
@ -32,6 +33,7 @@ export const QQBOT_NAPCAT_PROVIDERS = [
|
|||||||
NapcatLoginStateStoreService,
|
NapcatLoginStateStoreService,
|
||||||
NapcatLoginEventService,
|
NapcatLoginEventService,
|
||||||
NapcatRuntimeProfileInspectorService,
|
NapcatRuntimeProfileInspectorService,
|
||||||
|
NapcatRuntimeProfileInspectionScriptService,
|
||||||
NapcatRuntimeProfileService,
|
NapcatRuntimeProfileService,
|
||||||
NapcatSessionBehaviorService,
|
NapcatSessionBehaviorService,
|
||||||
QqbotNapcatAccountRuntimeService,
|
QqbotNapcatAccountRuntimeService,
|
||||||
|
|||||||
@ -9,6 +9,7 @@ import { JwtAuthGuard } from '../../../../src/modules/admin/identity/auth/jwt-au
|
|||||||
import { NapcatConfigWriterService } from '../../../../src/modules/qqbot/napcat/application/runtime/napcat-config-writer.service';
|
import { NapcatConfigWriterService } from '../../../../src/modules/qqbot/napcat/application/runtime/napcat-config-writer.service';
|
||||||
import { NapcatRuntimeProfileService } from '../../../../src/modules/qqbot/napcat/application/runtime/napcat-runtime-profile.service';
|
import { NapcatRuntimeProfileService } from '../../../../src/modules/qqbot/napcat/application/runtime/napcat-runtime-profile.service';
|
||||||
import { NapcatRuntimeProfileInspectorService } from '../../../../src/modules/qqbot/napcat/application/runtime/napcat-runtime-profile-inspector.service';
|
import { NapcatRuntimeProfileInspectorService } from '../../../../src/modules/qqbot/napcat/application/runtime/napcat-runtime-profile-inspector.service';
|
||||||
|
import { NapcatRuntimeProfileInspectionScriptService } from '../../../../src/modules/qqbot/napcat/infrastructure/integration/container/napcat-runtime-profile-inspection-script.service';
|
||||||
import { QqbotNapcatRuntimeController } from '../../../../src/modules/qqbot/napcat/contract/qqbot-napcat-runtime.controller';
|
import { QqbotNapcatRuntimeController } from '../../../../src/modules/qqbot/napcat/contract/qqbot-napcat-runtime.controller';
|
||||||
import {
|
import {
|
||||||
NapcatLoginEvent,
|
NapcatLoginEvent,
|
||||||
@ -178,12 +179,7 @@ describe('NapCat runtime profile generation', () => {
|
|||||||
|
|
||||||
describe('NapCat runtime profile inspector', () => {
|
describe('NapCat runtime profile inspector', () => {
|
||||||
it('builds a bounded SSH inspection script without exposing secrets', () => {
|
it('builds a bounded SSH inspection script without exposing secrets', () => {
|
||||||
const service = new NapcatRuntimeProfileInspectorService(
|
const service = new NapcatRuntimeProfileInspectionScriptService();
|
||||||
{} as any,
|
|
||||||
{} as any,
|
|
||||||
{} as any,
|
|
||||||
new ToolsService(),
|
|
||||||
) as any;
|
|
||||||
|
|
||||||
const script = service.buildInspectScript('kt-qqbot-napcat-10001');
|
const script = service.buildInspectScript('kt-qqbot-napcat-10001');
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user