138 lines
6.6 KiB
Go
138 lines
6.6 KiB
Go
-- 消息加密密钥管理。
|
||
-- 可重复执行。根 KEK 只在首次执行时生成,重复执行不会覆盖已有值。
|
||
|
||
SET NAMES utf8mb4;
|
||
SET @now := NOW();
|
||
|
||
SET @im_sql = IF(
|
||
(SELECT COUNT(*) FROM information_schema.COLUMNS
|
||
WHERE TABLE_SCHEMA = DATABASE() AND TABLE_NAME = 'im_tenant'
|
||
AND COLUMN_NAME = 'message_encryption_enabled') = 0,
|
||
'ALTER TABLE `im_tenant` ADD COLUMN `message_encryption_enabled` TINYINT(1) NOT NULL DEFAULT 0 COMMENT ''是否启用消息加密'' AFTER `local_moderation_enabled`',
|
||
'SELECT 1'
|
||
);
|
||
PREPARE im_stmt FROM @im_sql;
|
||
EXECUTE im_stmt;
|
||
DEALLOCATE PREPARE im_stmt;
|
||
|
||
CREATE TABLE IF NOT EXISTS `im_message_encryption_keys` (
|
||
`id` bigint NOT NULL AUTO_INCREMENT,
|
||
`tenant_id` bigint NOT NULL COMMENT '商户ID',
|
||
`key_version` int unsigned NOT NULL COMMENT '密钥版本',
|
||
`algorithm` varchar(32) NOT NULL DEFAULT 'AES-256-GCM' COMMENT '数据加密算法',
|
||
`encrypted_dek` blob NOT NULL COMMENT '由根KEK包裹后的商户DEK',
|
||
`dek_nonce` varbinary(12) NOT NULL COMMENT '包裹DEK使用的随机nonce',
|
||
`status` varchar(16) NOT NULL DEFAULT 'pending' COMMENT 'pending/active/retired/disabled',
|
||
`activated_at` datetime DEFAULT NULL,
|
||
`retired_at` datetime DEFAULT NULL,
|
||
`remark` varchar(255) NOT NULL DEFAULT '',
|
||
`created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||
`created_by` bigint NOT NULL DEFAULT 0,
|
||
`updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||
`updated_by` bigint NOT NULL DEFAULT 0,
|
||
PRIMARY KEY (`id`),
|
||
UNIQUE KEY `uk_im_message_key_tenant_version` (`tenant_id`, `key_version`),
|
||
KEY `idx_im_message_key_tenant_status` (`tenant_id`, `status`)
|
||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='商户消息加密密钥版本';
|
||
|
||
INSERT INTO `hg_sys_dict_type`
|
||
(`pid`, `name`, `type`, `sort`, `remark`, `status`, `created_at`, `updated_at`)
|
||
SELECT 0, 'IM内部安全材料', 'im_internal_secret', 9999,
|
||
'仅供服务端读取,通用字典接口禁止查询和维护', 1, @now, @now
|
||
WHERE NOT EXISTS (
|
||
SELECT 1 FROM `hg_sys_dict_type` WHERE `type` = 'im_internal_secret'
|
||
);
|
||
|
||
INSERT INTO `hg_sys_dict_data`
|
||
(`label`, `value`, `value_type`, `type`, `list_class`, `is_default`, `sort`, `remark`, `status`, `created_at`, `updated_at`)
|
||
SELECT 'core_material_01', TO_BASE64(RANDOM_BYTES(32)), 'string', 'im_internal_secret',
|
||
'', 2, 1, '消息DEK包裹根密钥KEK,请勿通过后台展示或修改', 1, @now, @now
|
||
WHERE NOT EXISTS (
|
||
SELECT 1 FROM `hg_sys_dict_data`
|
||
WHERE `type` = 'im_internal_secret' AND `label` = 'core_material_01'
|
||
);
|
||
|
||
SET @imRootId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imManager' LIMIT 1);
|
||
SET @settingsId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imSystemSettings' LIMIT 1);
|
||
|
||
INSERT INTO `hg_admin_menu`
|
||
(`pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`,
|
||
`permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`,
|
||
`frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`,
|
||
`status`, `created_at`, `updated_at`)
|
||
SELECT @settingsId, '消息密钥管理', 'imMessageEncryptionIndex', 'message-encryption/index',
|
||
'KeyOutlined', 2, '', '/imMessageEncryption/list', '', '/imMessageEncryption/index',
|
||
1, 'imManager', 0, 0, '', 0, 0, 0, 3,
|
||
CONCAT('tr_', @imRootId, ' tr_', @settingsId, ' '), 80,
|
||
'商户消息加密开关及密钥版本管理', 1, @now, @now
|
||
WHERE @settingsId IS NOT NULL
|
||
AND NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imMessageEncryptionIndex');
|
||
|
||
SET @keyMenuId := (SELECT `id` FROM `hg_admin_menu` WHERE `name` = 'imMessageEncryptionIndex' LIMIT 1);
|
||
|
||
UPDATE `hg_admin_menu`
|
||
SET `pid` = @settingsId,
|
||
`title` = '消息密钥管理',
|
||
`path` = 'message-encryption/index',
|
||
`icon` = 'KeyOutlined',
|
||
`permissions` = '/imMessageEncryption/list',
|
||
`component` = '/imMessageEncryption/index',
|
||
`active_menu` = 'imManager',
|
||
`level` = 3,
|
||
`tree` = CONCAT('tr_', @imRootId, ' tr_', @settingsId, ' '),
|
||
`sort` = 80,
|
||
`hidden` = 0,
|
||
`status` = 1,
|
||
`updated_at` = @now
|
||
WHERE `id` = @keyMenuId;
|
||
|
||
INSERT INTO `hg_admin_menu`
|
||
(`pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`,
|
||
`permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`,
|
||
`frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`,
|
||
`status`, `created_at`, `updated_at`)
|
||
SELECT @keyMenuId, '初始化密钥', 'imMessageEncryptionInitialize', '', '', 3, '',
|
||
'/imMessageEncryption/initialize', '', '', 1, '', 0, 0, '', 0, 1, 0, 4,
|
||
CONCAT('tr_', @imRootId, ' tr_', @settingsId, ' tr_', @keyMenuId, ' '), 10, '', 1, @now, @now
|
||
WHERE @keyMenuId IS NOT NULL
|
||
AND NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imMessageEncryptionInitialize');
|
||
|
||
INSERT INTO `hg_admin_menu`
|
||
(`pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`,
|
||
`permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`,
|
||
`frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`,
|
||
`status`, `created_at`, `updated_at`)
|
||
SELECT @keyMenuId, '轮换密钥', 'imMessageEncryptionRotate', '', '', 3, '',
|
||
'/imMessageEncryption/rotate', '', '', 1, '', 0, 0, '', 0, 1, 0, 4,
|
||
CONCAT('tr_', @imRootId, ' tr_', @settingsId, ' tr_', @keyMenuId, ' '), 20, '', 1, @now, @now
|
||
WHERE @keyMenuId IS NOT NULL
|
||
AND NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imMessageEncryptionRotate');
|
||
|
||
INSERT INTO `hg_admin_menu`
|
||
(`pid`, `title`, `name`, `path`, `icon`, `type`, `redirect`, `permissions`,
|
||
`permission_name`, `component`, `always_show`, `active_menu`, `is_root`, `is_frame`,
|
||
`frame_src`, `keep_alive`, `hidden`, `affix`, `level`, `tree`, `sort`, `remark`,
|
||
`status`, `created_at`, `updated_at`)
|
||
SELECT @keyMenuId, '切换消息加密', 'imMessageEncryptionSwitch', '', '', 3, '',
|
||
'/imMessageEncryption/switch', '', '', 1, '', 0, 0, '', 0, 1, 0, 4,
|
||
CONCAT('tr_', @imRootId, ' tr_', @settingsId, ' tr_', @keyMenuId, ' '), 30, '', 1, @now, @now
|
||
WHERE @keyMenuId IS NOT NULL
|
||
AND NOT EXISTS (SELECT 1 FROM `hg_admin_menu` WHERE `name` = 'imMessageEncryptionSwitch');
|
||
|
||
UPDATE `hg_admin_menu`
|
||
SET `level` = 4,
|
||
`tree` = CONCAT('tr_', @imRootId, ' tr_', @settingsId, ' tr_', @keyMenuId, ' '),
|
||
`updated_at` = @now
|
||
WHERE `pid` = @keyMenuId AND `type` = 3;
|
||
|
||
INSERT IGNORE INTO `hg_admin_role_menu` (`role_id`, `menu_id`)
|
||
SELECT 1, `id` FROM `hg_admin_menu`
|
||
WHERE `name` IN (
|
||
'imManager',
|
||
'imSystemSettings',
|
||
'imMessageEncryptionIndex',
|
||
'imMessageEncryptionInitialize',
|
||
'imMessageEncryptionRotate',
|
||
'imMessageEncryptionSwitch'
|
||
);
|