feat: 新增NapCat运行态Profile持久化
This commit is contained in:
parent
d8d722e92a
commit
38cc5fb5bf
@ -141,6 +141,118 @@ CREATE TABLE IF NOT EXISTS `napcat_runtime_cleanup` (
|
|||||||
KEY `idx_napcat_runtime_cleanup_session` (`session_id`)
|
KEY `idx_napcat_runtime_cleanup_session` (`session_id`)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `napcat_runtime_profile` (
|
||||||
|
`id` bigint NOT NULL,
|
||||||
|
`account_id` bigint NOT NULL,
|
||||||
|
`container_id` bigint DEFAULT NULL,
|
||||||
|
`device_identity_id` bigint DEFAULT NULL,
|
||||||
|
`profile_version` varchar(64) NOT NULL,
|
||||||
|
`image_ref` varchar(255) NOT NULL,
|
||||||
|
`image_digest` varchar(255) DEFAULT NULL,
|
||||||
|
`base_image_digest` varchar(255) DEFAULT NULL,
|
||||||
|
`desktop_profile_version` varchar(64) DEFAULT NULL,
|
||||||
|
`locale_available` tinyint(1) NOT NULL DEFAULT 0,
|
||||||
|
`fontconfig_evidence` json DEFAULT NULL,
|
||||||
|
`timezone_evidence` json DEFAULT NULL,
|
||||||
|
`runtime_uid` int DEFAULT NULL,
|
||||||
|
`runtime_gid` int DEFAULT NULL,
|
||||||
|
`shm_size` varchar(32) DEFAULT NULL,
|
||||||
|
`locale` varchar(64) DEFAULT NULL,
|
||||||
|
`xdg_config_home` varchar(255) DEFAULT NULL,
|
||||||
|
`xdg_cache_home` varchar(255) DEFAULT NULL,
|
||||||
|
`xdg_data_home` varchar(255) DEFAULT NULL,
|
||||||
|
`persist_cache` tinyint(1) NOT NULL DEFAULT 1,
|
||||||
|
`persist_local_share` tinyint(1) NOT NULL DEFAULT 1,
|
||||||
|
`persist_logs` tinyint(1) NOT NULL DEFAULT 1,
|
||||||
|
`hostname_strategy` varchar(64) NOT NULL,
|
||||||
|
`mac_strategy` varchar(64) NOT NULL,
|
||||||
|
`migrate_device_identity` tinyint(1) NOT NULL DEFAULT 0,
|
||||||
|
`profile_status` varchar(32) NOT NULL,
|
||||||
|
`last_check_evidence` json DEFAULT NULL,
|
||||||
|
`last_checked_at` datetime DEFAULT NULL,
|
||||||
|
`create_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||||
|
`update_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_napcat_runtime_profile_account` (`account_id`),
|
||||||
|
KEY `idx_napcat_runtime_profile_container` (`container_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `napcat_protocol_profile` (
|
||||||
|
`id` bigint NOT NULL,
|
||||||
|
`account_id` bigint NOT NULL,
|
||||||
|
`container_id` bigint DEFAULT NULL,
|
||||||
|
`profile_version` varchar(64) NOT NULL,
|
||||||
|
`packet_backend` varchar(64) NOT NULL,
|
||||||
|
`packet_server` varchar(255) NOT NULL DEFAULT '',
|
||||||
|
`o3_hook_mode` int NOT NULL DEFAULT 1,
|
||||||
|
`o3_hook_gray_enabled` tinyint(1) NOT NULL DEFAULT 0,
|
||||||
|
`onebot_config_hash` varchar(128) DEFAULT NULL,
|
||||||
|
`onebot_config_json` json DEFAULT NULL,
|
||||||
|
`napcat_config_hash` varchar(128) DEFAULT NULL,
|
||||||
|
`napcat_config_json` json DEFAULT NULL,
|
||||||
|
`profile_status` varchar(32) NOT NULL,
|
||||||
|
`last_check_evidence` json DEFAULT NULL,
|
||||||
|
`last_checked_at` datetime DEFAULT NULL,
|
||||||
|
`create_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||||
|
`update_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_napcat_protocol_profile_account` (`account_id`),
|
||||||
|
KEY `idx_napcat_protocol_profile_container` (`container_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `napcat_session_behavior_profile` (
|
||||||
|
`id` bigint NOT NULL,
|
||||||
|
`account_id` bigint NOT NULL,
|
||||||
|
`profile_version` varchar(64) NOT NULL,
|
||||||
|
`enabled` tinyint(1) NOT NULL DEFAULT 1,
|
||||||
|
`cold_start_until` datetime DEFAULT NULL,
|
||||||
|
`housekeeping_enabled` tinyint(1) NOT NULL DEFAULT 0,
|
||||||
|
`housekeeping_interval_ms` int DEFAULT NULL,
|
||||||
|
`next_housekeeping_at` datetime DEFAULT NULL,
|
||||||
|
`last_housekeeping_at` datetime DEFAULT NULL,
|
||||||
|
`last_housekeeping_result` json DEFAULT NULL,
|
||||||
|
`presence_enabled` tinyint(1) NOT NULL DEFAULT 0,
|
||||||
|
`presence_strategy` varchar(64) DEFAULT NULL,
|
||||||
|
`last_presence_event_at` datetime DEFAULT NULL,
|
||||||
|
`next_presence_event_at` datetime DEFAULT NULL,
|
||||||
|
`auto_capability_stage` varchar(32) NOT NULL,
|
||||||
|
`last_behavior_evidence` json DEFAULT NULL,
|
||||||
|
`create_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||||
|
`update_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_napcat_session_behavior_profile_account` (`account_id`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `napcat_login_event` (
|
||||||
|
`id` bigint NOT NULL,
|
||||||
|
`account_id` bigint NOT NULL,
|
||||||
|
`container_id` bigint DEFAULT NULL,
|
||||||
|
`event_kind` varchar(64) NOT NULL,
|
||||||
|
`event_source` varchar(32) NOT NULL,
|
||||||
|
`event_status` varchar(32) NOT NULL,
|
||||||
|
`evidence` json DEFAULT NULL,
|
||||||
|
`create_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||||
|
`update_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
KEY `idx_napcat_login_event_account` (`account_id`, `create_time`),
|
||||||
|
KEY `idx_napcat_login_event_container` (`container_id`, `create_time`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS `napcat_risk_mode` (
|
||||||
|
`id` bigint NOT NULL,
|
||||||
|
`account_id` bigint NOT NULL,
|
||||||
|
`risk_mode` varchar(32) NOT NULL,
|
||||||
|
`reason` varchar(255) DEFAULT NULL,
|
||||||
|
`source_event` varchar(64) DEFAULT NULL,
|
||||||
|
`expires_at` datetime DEFAULT NULL,
|
||||||
|
`last_evidence` json DEFAULT NULL,
|
||||||
|
`create_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6),
|
||||||
|
`update_time` datetime(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6) ON UPDATE CURRENT_TIMESTAMP(6),
|
||||||
|
PRIMARY KEY (`id`),
|
||||||
|
UNIQUE KEY `uk_napcat_risk_mode_account` (`account_id`),
|
||||||
|
KEY `idx_napcat_risk_mode_mode` (`risk_mode`)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS `qqbot_config` (
|
CREATE TABLE IF NOT EXISTS `qqbot_config` (
|
||||||
`id` bigint NOT NULL,
|
`id` bigint NOT NULL,
|
||||||
`config_key` varchar(120) NOT NULL,
|
`config_key` varchar(120) NOT NULL,
|
||||||
|
|||||||
@ -1016,3 +1016,110 @@ CREATE TABLE IF NOT EXISTS napcat_runtime_cleanup (
|
|||||||
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
KEY idx_napcat_runtime_cleanup_session (session_id)
|
KEY idx_napcat_runtime_cleanup_session (session_id)
|
||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS napcat_runtime_profile (
|
||||||
|
id BIGINT NOT NULL PRIMARY KEY,
|
||||||
|
account_id BIGINT NOT NULL,
|
||||||
|
container_id BIGINT NULL,
|
||||||
|
device_identity_id BIGINT NULL,
|
||||||
|
profile_version VARCHAR(64) NOT NULL,
|
||||||
|
image_ref VARCHAR(255) NOT NULL,
|
||||||
|
image_digest VARCHAR(255) NULL,
|
||||||
|
base_image_digest VARCHAR(255) NULL,
|
||||||
|
desktop_profile_version VARCHAR(64) NULL,
|
||||||
|
locale_available TINYINT NOT NULL DEFAULT 0,
|
||||||
|
fontconfig_evidence JSON NULL,
|
||||||
|
timezone_evidence JSON NULL,
|
||||||
|
runtime_uid INT NULL,
|
||||||
|
runtime_gid INT NULL,
|
||||||
|
shm_size VARCHAR(32) NULL,
|
||||||
|
locale VARCHAR(64) NULL,
|
||||||
|
xdg_config_home VARCHAR(255) NULL,
|
||||||
|
xdg_cache_home VARCHAR(255) NULL,
|
||||||
|
xdg_data_home VARCHAR(255) NULL,
|
||||||
|
persist_cache TINYINT NOT NULL DEFAULT 1,
|
||||||
|
persist_local_share TINYINT NOT NULL DEFAULT 1,
|
||||||
|
persist_logs TINYINT NOT NULL DEFAULT 1,
|
||||||
|
hostname_strategy VARCHAR(64) NOT NULL,
|
||||||
|
mac_strategy VARCHAR(64) NOT NULL,
|
||||||
|
migrate_device_identity TINYINT NOT NULL DEFAULT 0,
|
||||||
|
profile_status VARCHAR(32) NOT NULL,
|
||||||
|
last_check_evidence JSON NULL,
|
||||||
|
last_checked_at DATETIME NULL,
|
||||||
|
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
KEY idx_napcat_runtime_profile_account (account_id),
|
||||||
|
KEY idx_napcat_runtime_profile_container (container_id)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS napcat_protocol_profile (
|
||||||
|
id BIGINT NOT NULL PRIMARY KEY,
|
||||||
|
account_id BIGINT NOT NULL,
|
||||||
|
container_id BIGINT NULL,
|
||||||
|
profile_version VARCHAR(64) NOT NULL,
|
||||||
|
packet_backend VARCHAR(64) NOT NULL,
|
||||||
|
packet_server VARCHAR(255) NOT NULL DEFAULT '',
|
||||||
|
o3_hook_mode INT NOT NULL DEFAULT 1,
|
||||||
|
o3_hook_gray_enabled TINYINT NOT NULL DEFAULT 0,
|
||||||
|
onebot_config_hash VARCHAR(128) NULL,
|
||||||
|
onebot_config_json JSON NULL,
|
||||||
|
napcat_config_hash VARCHAR(128) NULL,
|
||||||
|
napcat_config_json JSON NULL,
|
||||||
|
profile_status VARCHAR(32) NOT NULL,
|
||||||
|
last_check_evidence JSON NULL,
|
||||||
|
last_checked_at DATETIME NULL,
|
||||||
|
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
KEY idx_napcat_protocol_profile_account (account_id),
|
||||||
|
KEY idx_napcat_protocol_profile_container (container_id)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS napcat_session_behavior_profile (
|
||||||
|
id BIGINT NOT NULL PRIMARY KEY,
|
||||||
|
account_id BIGINT NOT NULL,
|
||||||
|
profile_version VARCHAR(64) NOT NULL,
|
||||||
|
enabled TINYINT NOT NULL DEFAULT 1,
|
||||||
|
cold_start_until DATETIME NULL,
|
||||||
|
housekeeping_enabled TINYINT NOT NULL DEFAULT 0,
|
||||||
|
housekeeping_interval_ms INT NULL,
|
||||||
|
next_housekeeping_at DATETIME NULL,
|
||||||
|
last_housekeeping_at DATETIME NULL,
|
||||||
|
last_housekeeping_result JSON NULL,
|
||||||
|
presence_enabled TINYINT NOT NULL DEFAULT 0,
|
||||||
|
presence_strategy VARCHAR(64) NULL,
|
||||||
|
last_presence_event_at DATETIME NULL,
|
||||||
|
next_presence_event_at DATETIME NULL,
|
||||||
|
auto_capability_stage VARCHAR(32) NOT NULL,
|
||||||
|
last_behavior_evidence JSON NULL,
|
||||||
|
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
KEY idx_napcat_session_behavior_profile_account (account_id)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS napcat_login_event (
|
||||||
|
id BIGINT NOT NULL PRIMARY KEY,
|
||||||
|
account_id BIGINT NOT NULL,
|
||||||
|
container_id BIGINT NULL,
|
||||||
|
event_kind VARCHAR(64) NOT NULL,
|
||||||
|
event_source VARCHAR(32) NOT NULL,
|
||||||
|
event_status VARCHAR(32) NOT NULL,
|
||||||
|
evidence JSON NULL,
|
||||||
|
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
KEY idx_napcat_login_event_account (account_id, create_time),
|
||||||
|
KEY idx_napcat_login_event_container (container_id, create_time)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|
||||||
|
CREATE TABLE IF NOT EXISTS napcat_risk_mode (
|
||||||
|
id BIGINT NOT NULL PRIMARY KEY,
|
||||||
|
account_id BIGINT NOT NULL,
|
||||||
|
risk_mode VARCHAR(32) NOT NULL,
|
||||||
|
reason VARCHAR(255) NULL,
|
||||||
|
source_event VARCHAR(64) NULL,
|
||||||
|
expires_at DATETIME NULL,
|
||||||
|
last_evidence JSON NULL,
|
||||||
|
create_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
update_time DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||||
|
UNIQUE KEY uk_napcat_risk_mode_account (account_id),
|
||||||
|
KEY idx_napcat_risk_mode_mode (risk_mode)
|
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||||
|
|||||||
@ -11,6 +11,11 @@ SELECT 'napcat_account_binding' AS table_name, COUNT(*) AS row_count FROM napcat
|
|||||||
SELECT 'napcat_login_session' AS table_name, COUNT(*) AS row_count FROM napcat_login_session;
|
SELECT 'napcat_login_session' AS table_name, COUNT(*) AS row_count FROM napcat_login_session;
|
||||||
SELECT 'napcat_login_challenge' AS table_name, COUNT(*) AS row_count FROM napcat_login_challenge;
|
SELECT 'napcat_login_challenge' AS table_name, COUNT(*) AS row_count FROM napcat_login_challenge;
|
||||||
SELECT 'napcat_runtime_cleanup' AS table_name, COUNT(*) AS row_count FROM napcat_runtime_cleanup;
|
SELECT 'napcat_runtime_cleanup' AS table_name, COUNT(*) AS row_count FROM napcat_runtime_cleanup;
|
||||||
|
SELECT 'napcat_runtime_profile' AS table_name, COUNT(*) AS row_count FROM napcat_runtime_profile;
|
||||||
|
SELECT 'napcat_protocol_profile' AS table_name, COUNT(*) AS row_count FROM napcat_protocol_profile;
|
||||||
|
SELECT 'napcat_session_behavior_profile' AS table_name, COUNT(*) AS row_count FROM napcat_session_behavior_profile;
|
||||||
|
SELECT 'napcat_login_event' AS table_name, COUNT(*) AS row_count FROM napcat_login_event;
|
||||||
|
SELECT 'napcat_risk_mode' AS table_name, COUNT(*) AS row_count FROM napcat_risk_mode;
|
||||||
SELECT 'qqbot_plugin_task' AS table_name, COUNT(*) AS row_count FROM qqbot_plugin_task;
|
SELECT 'qqbot_plugin_task' AS table_name, COUNT(*) AS row_count FROM qqbot_plugin_task;
|
||||||
SELECT 'qqbot_plugin_task_run' AS table_name, COUNT(*) AS row_count FROM qqbot_plugin_task_run;
|
SELECT 'qqbot_plugin_task_run' AS table_name, COUNT(*) AS row_count FROM qqbot_plugin_task_run;
|
||||||
|
|
||||||
@ -111,6 +116,60 @@ WHERE table_schema = DATABASE()
|
|||||||
AND table_name = 'napcat_runtime_cleanup'
|
AND table_name = 'napcat_runtime_cleanup'
|
||||||
AND index_name = 'idx_napcat_runtime_cleanup_session';
|
AND index_name = 'idx_napcat_runtime_cleanup_session';
|
||||||
|
|
||||||
|
SELECT 'index_napcat_runtime_profile_account' AS check_name, COUNT(*) AS matched_rows
|
||||||
|
FROM information_schema.statistics
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'napcat_runtime_profile'
|
||||||
|
AND index_name = 'idx_napcat_runtime_profile_account';
|
||||||
|
|
||||||
|
SELECT 'index_napcat_runtime_profile_container' AS check_name, COUNT(*) AS matched_rows
|
||||||
|
FROM information_schema.statistics
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'napcat_runtime_profile'
|
||||||
|
AND index_name = 'idx_napcat_runtime_profile_container';
|
||||||
|
|
||||||
|
SELECT 'index_napcat_protocol_profile_account' AS check_name, COUNT(*) AS matched_rows
|
||||||
|
FROM information_schema.statistics
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'napcat_protocol_profile'
|
||||||
|
AND index_name = 'idx_napcat_protocol_profile_account';
|
||||||
|
|
||||||
|
SELECT 'index_napcat_protocol_profile_container' AS check_name, COUNT(*) AS matched_rows
|
||||||
|
FROM information_schema.statistics
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'napcat_protocol_profile'
|
||||||
|
AND index_name = 'idx_napcat_protocol_profile_container';
|
||||||
|
|
||||||
|
SELECT 'index_napcat_session_behavior_profile_account' AS check_name, COUNT(*) AS matched_rows
|
||||||
|
FROM information_schema.statistics
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'napcat_session_behavior_profile'
|
||||||
|
AND index_name = 'idx_napcat_session_behavior_profile_account';
|
||||||
|
|
||||||
|
SELECT 'index_napcat_login_event_account' AS check_name, COUNT(*) AS matched_rows
|
||||||
|
FROM information_schema.statistics
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'napcat_login_event'
|
||||||
|
AND index_name = 'idx_napcat_login_event_account';
|
||||||
|
|
||||||
|
SELECT 'index_napcat_login_event_container' AS check_name, COUNT(*) AS matched_rows
|
||||||
|
FROM information_schema.statistics
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'napcat_login_event'
|
||||||
|
AND index_name = 'idx_napcat_login_event_container';
|
||||||
|
|
||||||
|
SELECT 'index_napcat_risk_mode_account' AS check_name, COUNT(*) AS matched_rows
|
||||||
|
FROM information_schema.statistics
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'napcat_risk_mode'
|
||||||
|
AND index_name = 'uk_napcat_risk_mode_account';
|
||||||
|
|
||||||
|
SELECT 'index_napcat_risk_mode_mode' AS check_name, COUNT(*) AS matched_rows
|
||||||
|
FROM information_schema.statistics
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = 'napcat_risk_mode'
|
||||||
|
AND index_name = 'idx_napcat_risk_mode_mode';
|
||||||
|
|
||||||
SELECT 'column_napcat_login_challenge_session_id_varchar' AS check_name, COUNT(*) AS matched_rows
|
SELECT 'column_napcat_login_challenge_session_id_varchar' AS check_name, COUNT(*) AS matched_rows
|
||||||
FROM information_schema.columns
|
FROM information_schema.columns
|
||||||
WHERE table_schema = DATABASE()
|
WHERE table_schema = DATABASE()
|
||||||
|
|||||||
@ -2,8 +2,13 @@ import { NapcatAccountBinding } from './napcat-account-binding.entity';
|
|||||||
import { NapcatContainer } from './napcat-container.entity';
|
import { NapcatContainer } from './napcat-container.entity';
|
||||||
import { NapcatDeviceIdentity } from './napcat-device-identity.entity';
|
import { NapcatDeviceIdentity } from './napcat-device-identity.entity';
|
||||||
import { NapcatLoginChallengeEntity } from './napcat-login-challenge.entity';
|
import { NapcatLoginChallengeEntity } from './napcat-login-challenge.entity';
|
||||||
|
import { NapcatLoginEvent } from './napcat-login-event.entity';
|
||||||
import { NapcatLoginSession } from './napcat-login-session.entity';
|
import { NapcatLoginSession } from './napcat-login-session.entity';
|
||||||
|
import { NapcatProtocolProfile } from './napcat-protocol-profile.entity';
|
||||||
|
import { NapcatRiskMode } from './napcat-risk-mode.entity';
|
||||||
import { NapcatRuntimeCleanup } from './napcat-runtime-cleanup.entity';
|
import { NapcatRuntimeCleanup } from './napcat-runtime-cleanup.entity';
|
||||||
|
import { NapcatRuntimeProfile } from './napcat-runtime-profile.entity';
|
||||||
|
import { NapcatSessionBehaviorProfile } from './napcat-session-behavior-profile.entity';
|
||||||
|
|
||||||
export const NAPCAT_RUNTIME_DOMAIN_CONTRACT = {
|
export const NAPCAT_RUNTIME_DOMAIN_CONTRACT = {
|
||||||
tables: [
|
tables: [
|
||||||
@ -13,6 +18,11 @@ export const NAPCAT_RUNTIME_DOMAIN_CONTRACT = {
|
|||||||
'napcat_login_session',
|
'napcat_login_session',
|
||||||
'napcat_login_challenge',
|
'napcat_login_challenge',
|
||||||
'napcat_runtime_cleanup',
|
'napcat_runtime_cleanup',
|
||||||
|
'napcat_runtime_profile',
|
||||||
|
'napcat_protocol_profile',
|
||||||
|
'napcat_session_behavior_profile',
|
||||||
|
'napcat_login_event',
|
||||||
|
'napcat_risk_mode',
|
||||||
],
|
],
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
@ -23,4 +33,17 @@ export const NAPCAT_RUNTIME_ENTITIES = [
|
|||||||
NapcatLoginChallengeEntity,
|
NapcatLoginChallengeEntity,
|
||||||
NapcatLoginSession,
|
NapcatLoginSession,
|
||||||
NapcatRuntimeCleanup,
|
NapcatRuntimeCleanup,
|
||||||
|
NapcatRuntimeProfile,
|
||||||
|
NapcatProtocolProfile,
|
||||||
|
NapcatSessionBehaviorProfile,
|
||||||
|
NapcatLoginEvent,
|
||||||
|
NapcatRiskMode,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export {
|
||||||
|
NapcatLoginEvent,
|
||||||
|
NapcatProtocolProfile,
|
||||||
|
NapcatRiskMode,
|
||||||
|
NapcatRuntimeProfile,
|
||||||
|
NapcatSessionBehaviorProfile,
|
||||||
|
};
|
||||||
|
|||||||
@ -0,0 +1,76 @@
|
|||||||
|
import { BeforeInsert, Column, Entity, Index, PrimaryColumn } from 'typeorm';
|
||||||
|
import {
|
||||||
|
ensureSnowflakeId,
|
||||||
|
KtCreateDateColumn,
|
||||||
|
KtDateTime,
|
||||||
|
KtUpdateDateColumn,
|
||||||
|
} from '@/common';
|
||||||
|
|
||||||
|
export type NapcatLoginEventKind =
|
||||||
|
| 'captcha_required'
|
||||||
|
| 'container_recreate'
|
||||||
|
| 'container_restart'
|
||||||
|
| 'manual_qr_created'
|
||||||
|
| 'manual_qr_scanned'
|
||||||
|
| 'new_device_required'
|
||||||
|
| 'password_attempt'
|
||||||
|
| 'quick_attempt'
|
||||||
|
| 'recovery_suspended';
|
||||||
|
|
||||||
|
export type NapcatLoginEventSource =
|
||||||
|
| 'admin'
|
||||||
|
| 'runtime'
|
||||||
|
| 'system'
|
||||||
|
| 'watchdog';
|
||||||
|
|
||||||
|
export type NapcatLoginEventStatus =
|
||||||
|
| 'blocked'
|
||||||
|
| 'failed'
|
||||||
|
| 'pending'
|
||||||
|
| 'skipped'
|
||||||
|
| 'success';
|
||||||
|
|
||||||
|
@Entity('napcat_login_event')
|
||||||
|
@Index('idx_napcat_login_event_account', ['accountId', 'createTime'])
|
||||||
|
@Index('idx_napcat_login_event_container', ['containerId', 'createTime'])
|
||||||
|
export class NapcatLoginEvent {
|
||||||
|
@PrimaryColumn({ type: 'bigint' })
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Column({ name: 'account_id', type: 'bigint' })
|
||||||
|
accountId: string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
name: 'container_id',
|
||||||
|
nullable: true,
|
||||||
|
type: 'bigint',
|
||||||
|
})
|
||||||
|
containerId: null | string;
|
||||||
|
|
||||||
|
@Column({ length: 64, name: 'event_kind' })
|
||||||
|
eventKind: NapcatLoginEventKind;
|
||||||
|
|
||||||
|
@Column({ length: 32, name: 'event_source' })
|
||||||
|
eventSource: NapcatLoginEventSource;
|
||||||
|
|
||||||
|
@Column({ length: 32, name: 'event_status' })
|
||||||
|
eventStatus: NapcatLoginEventStatus;
|
||||||
|
|
||||||
|
@Column({ default: null, nullable: true, type: 'json' })
|
||||||
|
evidence: null | Record<string, unknown>;
|
||||||
|
|
||||||
|
@KtCreateDateColumn({ name: 'create_time' })
|
||||||
|
createTime: KtDateTime;
|
||||||
|
|
||||||
|
@KtUpdateDateColumn({ name: 'update_time' })
|
||||||
|
updateTime: KtDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns a stable Snowflake id before persisting a login-side risk event.
|
||||||
|
*/
|
||||||
|
@BeforeInsert()
|
||||||
|
createId() {
|
||||||
|
ensureSnowflakeId(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,112 @@
|
|||||||
|
import { BeforeInsert, Column, Entity, Index, PrimaryColumn } from 'typeorm';
|
||||||
|
import {
|
||||||
|
ensureSnowflakeId,
|
||||||
|
KtCreateDateColumn,
|
||||||
|
KtDateTime,
|
||||||
|
KtDateTimeColumn,
|
||||||
|
KtUpdateDateColumn,
|
||||||
|
} from '@/common';
|
||||||
|
|
||||||
|
export type NapcatProtocolProfileStatus =
|
||||||
|
| 'drifted'
|
||||||
|
| 'failed'
|
||||||
|
| 'pending'
|
||||||
|
| 'synced';
|
||||||
|
|
||||||
|
@Entity('napcat_protocol_profile')
|
||||||
|
@Index('idx_napcat_protocol_profile_account', ['accountId'])
|
||||||
|
@Index('idx_napcat_protocol_profile_container', ['containerId'])
|
||||||
|
export class NapcatProtocolProfile {
|
||||||
|
@PrimaryColumn({ type: 'bigint' })
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Column({ name: 'account_id', type: 'bigint' })
|
||||||
|
accountId: string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
name: 'container_id',
|
||||||
|
nullable: true,
|
||||||
|
type: 'bigint',
|
||||||
|
})
|
||||||
|
containerId: null | string;
|
||||||
|
|
||||||
|
@Column({ length: 64, name: 'profile_version' })
|
||||||
|
profileVersion: string;
|
||||||
|
|
||||||
|
@Column({ length: 64, name: 'packet_backend' })
|
||||||
|
packetBackend: string;
|
||||||
|
|
||||||
|
@Column({ default: '', length: 255, name: 'packet_server' })
|
||||||
|
packetServer: string;
|
||||||
|
|
||||||
|
@Column({ default: 1, name: 'o3_hook_mode', type: 'int' })
|
||||||
|
o3HookMode: number;
|
||||||
|
|
||||||
|
@Column({ default: false, name: 'o3_hook_gray_enabled' })
|
||||||
|
o3HookGrayEnabled: boolean;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
length: 128,
|
||||||
|
name: 'onebot_config_hash',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
onebotConfigHash: null | string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
name: 'onebot_config_json',
|
||||||
|
nullable: true,
|
||||||
|
type: 'json',
|
||||||
|
})
|
||||||
|
onebotConfigJson: null | Record<string, unknown>;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
length: 128,
|
||||||
|
name: 'napcat_config_hash',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
napcatConfigHash: null | string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
name: 'napcat_config_json',
|
||||||
|
nullable: true,
|
||||||
|
type: 'json',
|
||||||
|
})
|
||||||
|
napcatConfigJson: null | Record<string, unknown>;
|
||||||
|
|
||||||
|
@Column({ length: 32, name: 'profile_status' })
|
||||||
|
profileStatus: NapcatProtocolProfileStatus;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
name: 'last_check_evidence',
|
||||||
|
nullable: true,
|
||||||
|
type: 'json',
|
||||||
|
})
|
||||||
|
lastCheckEvidence: null | Record<string, unknown>;
|
||||||
|
|
||||||
|
@KtDateTimeColumn({
|
||||||
|
default: null,
|
||||||
|
name: 'last_checked_at',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
lastCheckedAt: KtDateTime | null;
|
||||||
|
|
||||||
|
@KtCreateDateColumn({ name: 'create_time' })
|
||||||
|
createTime: KtDateTime;
|
||||||
|
|
||||||
|
@KtUpdateDateColumn({ name: 'update_time' })
|
||||||
|
updateTime: KtDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns a stable Snowflake id before persisting protocol-profile evidence.
|
||||||
|
*/
|
||||||
|
@BeforeInsert()
|
||||||
|
createId() {
|
||||||
|
ensureSnowflakeId(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,60 @@
|
|||||||
|
import { BeforeInsert, Column, Entity, Index, PrimaryColumn } from 'typeorm';
|
||||||
|
import {
|
||||||
|
ensureSnowflakeId,
|
||||||
|
KtCreateDateColumn,
|
||||||
|
KtDateTime,
|
||||||
|
KtDateTimeColumn,
|
||||||
|
KtUpdateDateColumn,
|
||||||
|
} from '@/common';
|
||||||
|
|
||||||
|
export type NapcatRiskModeValue = 'cooldown' | 'manual_only' | 'normal';
|
||||||
|
|
||||||
|
@Entity('napcat_risk_mode')
|
||||||
|
@Index('uk_napcat_risk_mode_account', ['accountId'], { unique: true })
|
||||||
|
@Index('idx_napcat_risk_mode_mode', ['riskMode'])
|
||||||
|
export class NapcatRiskMode {
|
||||||
|
@PrimaryColumn({ type: 'bigint' })
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Column({ name: 'account_id', type: 'bigint' })
|
||||||
|
accountId: string;
|
||||||
|
|
||||||
|
@Column({ length: 32, name: 'risk_mode' })
|
||||||
|
riskMode: NapcatRiskModeValue;
|
||||||
|
|
||||||
|
@Column({ default: null, length: 255, nullable: true })
|
||||||
|
reason: null | string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
length: 64,
|
||||||
|
name: 'source_event',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
sourceEvent: null | string;
|
||||||
|
|
||||||
|
@KtDateTimeColumn({ default: null, name: 'expires_at', nullable: true })
|
||||||
|
expiresAt: KtDateTime | null;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
name: 'last_evidence',
|
||||||
|
nullable: true,
|
||||||
|
type: 'json',
|
||||||
|
})
|
||||||
|
lastEvidence: null | Record<string, unknown>;
|
||||||
|
|
||||||
|
@KtCreateDateColumn({ name: 'create_time' })
|
||||||
|
createTime: KtDateTime;
|
||||||
|
|
||||||
|
@KtUpdateDateColumn({ name: 'update_time' })
|
||||||
|
updateTime: KtDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns a stable Snowflake id before persisting account risk-mode state.
|
||||||
|
*/
|
||||||
|
@BeforeInsert()
|
||||||
|
createId() {
|
||||||
|
ensureSnowflakeId(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,171 @@
|
|||||||
|
import { BeforeInsert, Column, Entity, Index, PrimaryColumn } from 'typeorm';
|
||||||
|
import {
|
||||||
|
ensureSnowflakeId,
|
||||||
|
KtCreateDateColumn,
|
||||||
|
KtDateTime,
|
||||||
|
KtDateTimeColumn,
|
||||||
|
KtUpdateDateColumn,
|
||||||
|
} from '@/common';
|
||||||
|
|
||||||
|
export type NapcatRuntimeProfileStatus =
|
||||||
|
| 'drifted'
|
||||||
|
| 'failed'
|
||||||
|
| 'pending'
|
||||||
|
| 'synced';
|
||||||
|
|
||||||
|
@Entity('napcat_runtime_profile')
|
||||||
|
@Index('idx_napcat_runtime_profile_account', ['accountId'])
|
||||||
|
@Index('idx_napcat_runtime_profile_container', ['containerId'])
|
||||||
|
export class NapcatRuntimeProfile {
|
||||||
|
@PrimaryColumn({ type: 'bigint' })
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Column({ name: 'account_id', type: 'bigint' })
|
||||||
|
accountId: string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
name: 'container_id',
|
||||||
|
nullable: true,
|
||||||
|
type: 'bigint',
|
||||||
|
})
|
||||||
|
containerId: null | string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
name: 'device_identity_id',
|
||||||
|
nullable: true,
|
||||||
|
type: 'bigint',
|
||||||
|
})
|
||||||
|
deviceIdentityId: null | string;
|
||||||
|
|
||||||
|
@Column({ length: 64, name: 'profile_version' })
|
||||||
|
profileVersion: string;
|
||||||
|
|
||||||
|
@Column({ length: 255, name: 'image_ref' })
|
||||||
|
imageRef: string;
|
||||||
|
|
||||||
|
@Column({ default: null, length: 255, name: 'image_digest', nullable: true })
|
||||||
|
imageDigest: null | string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
length: 255,
|
||||||
|
name: 'base_image_digest',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
baseImageDigest: null | string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
length: 64,
|
||||||
|
name: 'desktop_profile_version',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
desktopProfileVersion: null | string;
|
||||||
|
|
||||||
|
@Column({ default: false, name: 'locale_available' })
|
||||||
|
localeAvailable: boolean;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
name: 'fontconfig_evidence',
|
||||||
|
nullable: true,
|
||||||
|
type: 'json',
|
||||||
|
})
|
||||||
|
fontconfigEvidence: null | Record<string, unknown>;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
name: 'timezone_evidence',
|
||||||
|
nullable: true,
|
||||||
|
type: 'json',
|
||||||
|
})
|
||||||
|
timezoneEvidence: null | Record<string, unknown>;
|
||||||
|
|
||||||
|
@Column({ default: null, name: 'runtime_uid', nullable: true, type: 'int' })
|
||||||
|
runtimeUid: null | number;
|
||||||
|
|
||||||
|
@Column({ default: null, name: 'runtime_gid', nullable: true, type: 'int' })
|
||||||
|
runtimeGid: null | number;
|
||||||
|
|
||||||
|
@Column({ default: null, length: 32, name: 'shm_size', nullable: true })
|
||||||
|
shmSize: null | string;
|
||||||
|
|
||||||
|
@Column({ default: null, length: 64, nullable: true })
|
||||||
|
locale: null | string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
length: 255,
|
||||||
|
name: 'xdg_config_home',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
xdgConfigHome: null | string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
length: 255,
|
||||||
|
name: 'xdg_cache_home',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
xdgCacheHome: null | string;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
length: 255,
|
||||||
|
name: 'xdg_data_home',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
xdgDataHome: null | string;
|
||||||
|
|
||||||
|
@Column({ default: true, name: 'persist_cache' })
|
||||||
|
persistCache: boolean;
|
||||||
|
|
||||||
|
@Column({ default: true, name: 'persist_local_share' })
|
||||||
|
persistLocalShare: boolean;
|
||||||
|
|
||||||
|
@Column({ default: true, name: 'persist_logs' })
|
||||||
|
persistLogs: boolean;
|
||||||
|
|
||||||
|
@Column({ length: 64, name: 'hostname_strategy' })
|
||||||
|
hostnameStrategy: string;
|
||||||
|
|
||||||
|
@Column({ length: 64, name: 'mac_strategy' })
|
||||||
|
macStrategy: string;
|
||||||
|
|
||||||
|
@Column({ default: false, name: 'migrate_device_identity' })
|
||||||
|
migrateDeviceIdentity: boolean;
|
||||||
|
|
||||||
|
@Column({ length: 32, name: 'profile_status' })
|
||||||
|
profileStatus: NapcatRuntimeProfileStatus;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
name: 'last_check_evidence',
|
||||||
|
nullable: true,
|
||||||
|
type: 'json',
|
||||||
|
})
|
||||||
|
lastCheckEvidence: null | Record<string, unknown>;
|
||||||
|
|
||||||
|
@KtDateTimeColumn({
|
||||||
|
default: null,
|
||||||
|
name: 'last_checked_at',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
lastCheckedAt: KtDateTime | null;
|
||||||
|
|
||||||
|
@KtCreateDateColumn({ name: 'create_time' })
|
||||||
|
createTime: KtDateTime;
|
||||||
|
|
||||||
|
@KtUpdateDateColumn({ name: 'update_time' })
|
||||||
|
updateTime: KtDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns a stable Snowflake id before persisting runtime-profile evidence.
|
||||||
|
*/
|
||||||
|
@BeforeInsert()
|
||||||
|
createId() {
|
||||||
|
ensureSnowflakeId(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,120 @@
|
|||||||
|
import { BeforeInsert, Column, Entity, Index, PrimaryColumn } from 'typeorm';
|
||||||
|
import {
|
||||||
|
ensureSnowflakeId,
|
||||||
|
KtCreateDateColumn,
|
||||||
|
KtDateTime,
|
||||||
|
KtDateTimeColumn,
|
||||||
|
KtUpdateDateColumn,
|
||||||
|
} from '@/common';
|
||||||
|
|
||||||
|
export type NapcatAutoCapabilityStage =
|
||||||
|
| 'automatic'
|
||||||
|
| 'image_commands'
|
||||||
|
| 'manual_only'
|
||||||
|
| 'text_commands';
|
||||||
|
|
||||||
|
@Entity('napcat_session_behavior_profile')
|
||||||
|
@Index('idx_napcat_session_behavior_profile_account', ['accountId'])
|
||||||
|
export class NapcatSessionBehaviorProfile {
|
||||||
|
@PrimaryColumn({ type: 'bigint' })
|
||||||
|
id: string;
|
||||||
|
|
||||||
|
@Column({ name: 'account_id', type: 'bigint' })
|
||||||
|
accountId: string;
|
||||||
|
|
||||||
|
@Column({ length: 64, name: 'profile_version' })
|
||||||
|
profileVersion: string;
|
||||||
|
|
||||||
|
@Column({ default: true })
|
||||||
|
enabled: boolean;
|
||||||
|
|
||||||
|
@KtDateTimeColumn({
|
||||||
|
default: null,
|
||||||
|
name: 'cold_start_until',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
coldStartUntil: KtDateTime | null;
|
||||||
|
|
||||||
|
@Column({ default: false, name: 'housekeeping_enabled' })
|
||||||
|
housekeepingEnabled: boolean;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
name: 'housekeeping_interval_ms',
|
||||||
|
nullable: true,
|
||||||
|
type: 'int',
|
||||||
|
})
|
||||||
|
housekeepingIntervalMs: null | number;
|
||||||
|
|
||||||
|
@KtDateTimeColumn({
|
||||||
|
default: null,
|
||||||
|
name: 'next_housekeeping_at',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
nextHousekeepingAt: KtDateTime | null;
|
||||||
|
|
||||||
|
@KtDateTimeColumn({
|
||||||
|
default: null,
|
||||||
|
name: 'last_housekeeping_at',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
lastHousekeepingAt: KtDateTime | null;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
name: 'last_housekeeping_result',
|
||||||
|
nullable: true,
|
||||||
|
type: 'json',
|
||||||
|
})
|
||||||
|
lastHousekeepingResult: null | Record<string, unknown>;
|
||||||
|
|
||||||
|
@Column({ default: false, name: 'presence_enabled' })
|
||||||
|
presenceEnabled: boolean;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
length: 64,
|
||||||
|
name: 'presence_strategy',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
presenceStrategy: null | string;
|
||||||
|
|
||||||
|
@KtDateTimeColumn({
|
||||||
|
default: null,
|
||||||
|
name: 'last_presence_event_at',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
lastPresenceEventAt: KtDateTime | null;
|
||||||
|
|
||||||
|
@KtDateTimeColumn({
|
||||||
|
default: null,
|
||||||
|
name: 'next_presence_event_at',
|
||||||
|
nullable: true,
|
||||||
|
})
|
||||||
|
nextPresenceEventAt: KtDateTime | null;
|
||||||
|
|
||||||
|
@Column({ length: 32, name: 'auto_capability_stage' })
|
||||||
|
autoCapabilityStage: NapcatAutoCapabilityStage;
|
||||||
|
|
||||||
|
@Column({
|
||||||
|
default: null,
|
||||||
|
name: 'last_behavior_evidence',
|
||||||
|
nullable: true,
|
||||||
|
type: 'json',
|
||||||
|
})
|
||||||
|
lastBehaviorEvidence: null | Record<string, unknown>;
|
||||||
|
|
||||||
|
@KtCreateDateColumn({ name: 'create_time' })
|
||||||
|
createTime: KtDateTime;
|
||||||
|
|
||||||
|
@KtUpdateDateColumn({ name: 'update_time' })
|
||||||
|
updateTime: KtDateTime;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Assigns a stable Snowflake id before persisting session-behavior profile state.
|
||||||
|
*/
|
||||||
|
@BeforeInsert()
|
||||||
|
createId() {
|
||||||
|
ensureSnowflakeId(this);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,7 +1,8 @@
|
|||||||
# QQBot NapCat Schema
|
# QQBot NapCat Schema
|
||||||
|
|
||||||
NapCat owns container runtime, account binding, device identity, login session,
|
NapCat owns container runtime, account binding, device identity, login session,
|
||||||
challenge, and cleanup persistence through the v3 `napcat_*` tables.
|
challenge, cleanup, runtime/profile evidence, login-event, and risk-mode
|
||||||
|
persistence through the v3 `napcat_*` tables.
|
||||||
|
|
||||||
- `napcat_container`
|
- `napcat_container`
|
||||||
- `napcat_device_identity`
|
- `napcat_device_identity`
|
||||||
@ -9,6 +10,11 @@ challenge, and cleanup persistence through the v3 `napcat_*` tables.
|
|||||||
- `napcat_login_session`
|
- `napcat_login_session`
|
||||||
- `napcat_login_challenge`
|
- `napcat_login_challenge`
|
||||||
- `napcat_runtime_cleanup`
|
- `napcat_runtime_cleanup`
|
||||||
|
- `napcat_runtime_profile`
|
||||||
|
- `napcat_protocol_profile`
|
||||||
|
- `napcat_session_behavior_profile`
|
||||||
|
- `napcat_login_event`
|
||||||
|
- `napcat_risk_mode`
|
||||||
|
|
||||||
Verification SQL:
|
Verification SQL:
|
||||||
|
|
||||||
@ -16,4 +22,9 @@ Verification SQL:
|
|||||||
SELECT COUNT(*) FROM napcat_container WHERE is_deleted = 0;
|
SELECT COUNT(*) FROM napcat_container WHERE is_deleted = 0;
|
||||||
SELECT COUNT(*) FROM napcat_device_identity;
|
SELECT COUNT(*) FROM napcat_device_identity;
|
||||||
SELECT COUNT(*) FROM napcat_account_binding WHERE is_deleted = 0;
|
SELECT COUNT(*) FROM napcat_account_binding WHERE is_deleted = 0;
|
||||||
|
SELECT COUNT(*) FROM napcat_runtime_profile;
|
||||||
|
SELECT COUNT(*) FROM napcat_protocol_profile;
|
||||||
|
SELECT COUNT(*) FROM napcat_session_behavior_profile;
|
||||||
|
SELECT COUNT(*) FROM napcat_login_event;
|
||||||
|
SELECT COUNT(*) FROM napcat_risk_mode;
|
||||||
```
|
```
|
||||||
|
|||||||
90
test/modules/qqbot/napcat/runtime-protocol-profile.spec.ts
Normal file
90
test/modules/qqbot/napcat/runtime-protocol-profile.spec.ts
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
import { getMetadataArgsStorage } from 'typeorm';
|
||||||
|
import {
|
||||||
|
NapcatLoginEvent,
|
||||||
|
NapcatProtocolProfile,
|
||||||
|
NapcatRiskMode,
|
||||||
|
NapcatRuntimeProfile,
|
||||||
|
NapcatSessionBehaviorProfile,
|
||||||
|
NAPCAT_RUNTIME_DOMAIN_CONTRACT,
|
||||||
|
NAPCAT_RUNTIME_ENTITIES,
|
||||||
|
} from '../../../../src/modules/qqbot/napcat';
|
||||||
|
import { readRefactorV3SqlSchema } from '../../../helpers/sql-schema.helper';
|
||||||
|
|
||||||
|
type EntityClass = new (...args: never[]) => unknown;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a TypeORM entity table name from decorator metadata.
|
||||||
|
* @param entity - Entity class selected by the test to compare against SQL schema ownership.
|
||||||
|
*/
|
||||||
|
const getEntityTableName = (entity: EntityClass) =>
|
||||||
|
getMetadataArgsStorage().tables.find((table) => table.target === entity)
|
||||||
|
?.name;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads entity column names as they are persisted in MySQL.
|
||||||
|
* @param entity - Entity class whose decorator column metadata must match refactor-v3 SQL.
|
||||||
|
*/
|
||||||
|
const getEntityColumnNames = (entity: EntityClass) =>
|
||||||
|
getMetadataArgsStorage()
|
||||||
|
.columns.filter((column) => column.target === entity)
|
||||||
|
.map((column) => `${column.options.name || column.propertyName}`);
|
||||||
|
|
||||||
|
describe('NapCat runtime and protocol profile persistence', () => {
|
||||||
|
const schema = readRefactorV3SqlSchema();
|
||||||
|
|
||||||
|
it('declares runtime profile tables as NapCat-owned domain tables', () => {
|
||||||
|
expect(NAPCAT_RUNTIME_DOMAIN_CONTRACT.tables).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
'napcat_runtime_profile',
|
||||||
|
'napcat_protocol_profile',
|
||||||
|
'napcat_session_behavior_profile',
|
||||||
|
'napcat_login_event',
|
||||||
|
'napcat_risk_mode',
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.each([
|
||||||
|
[NapcatRuntimeProfile, 'napcat_runtime_profile'],
|
||||||
|
[NapcatProtocolProfile, 'napcat_protocol_profile'],
|
||||||
|
[NapcatSessionBehaviorProfile, 'napcat_session_behavior_profile'],
|
||||||
|
[NapcatLoginEvent, 'napcat_login_event'],
|
||||||
|
[NapcatRiskMode, 'napcat_risk_mode'],
|
||||||
|
])('maps %p to %s in the v3 SQL schema', (entity, tableName) => {
|
||||||
|
expect(NAPCAT_RUNTIME_ENTITIES).toContain(entity);
|
||||||
|
expect(getEntityTableName(entity)).toBe(tableName);
|
||||||
|
schema.expectTableColumns(tableName, getEntityColumnNames(entity));
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps login-event fields separate from send budget fields', () => {
|
||||||
|
const loginEventColumns = getEntityColumnNames(NapcatLoginEvent);
|
||||||
|
expect(loginEventColumns).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
'account_id',
|
||||||
|
'container_id',
|
||||||
|
'event_kind',
|
||||||
|
'event_source',
|
||||||
|
'event_status',
|
||||||
|
'evidence',
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
expect(loginEventColumns.join(' ')).not.toMatch(
|
||||||
|
/hour|daily|quota|budget|limit_count/i,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('keeps risk mode separate from account send budgets', () => {
|
||||||
|
const riskColumns = getEntityColumnNames(NapcatRiskMode);
|
||||||
|
expect(riskColumns).toEqual(
|
||||||
|
expect.arrayContaining([
|
||||||
|
'account_id',
|
||||||
|
'risk_mode',
|
||||||
|
'reason',
|
||||||
|
'source_event',
|
||||||
|
'expires_at',
|
||||||
|
'last_evidence',
|
||||||
|
]),
|
||||||
|
);
|
||||||
|
expect(riskColumns.join(' ')).not.toMatch(/daily|hour|budget|quota/i);
|
||||||
|
});
|
||||||
|
});
|
||||||
Loading…
Reference in New Issue
Block a user