decrypt($this->profile(), $password); return [ 'driver' => 'mysql', 'host' => $this->requiredString($profile, 'host'), 'port' => $this->requiredPort($profile), 'database' => $this->requiredString($profile, 'database'), 'mirror_database' => 'caiwu_business_mirror', 'username' => $this->requiredString($profile, 'username'), 'password' => $password, 'tls_required' => true, 'tls_verify_server_cert' => false, 'tls_ca' => '', ]; } /** * 仅供负责人轮换团队连接资料时生成新的密文,不输出明文密码。 */ public static function seal(array $profile, string $password): string { $salt = random_bytes(16); $iv = random_bytes(12); $key = hash_pbkdf2('sha256', $password, $salt, self::ITERATIONS, 32, true); $tag = ''; $plaintext = json_encode($profile, JSON_THROW_ON_ERROR | JSON_UNESCAPED_UNICODE); $ciphertext = openssl_encrypt( $plaintext, self::CIPHER, $key, OPENSSL_RAW_DATA, $iv, $tag ); if ($ciphertext === false) { throw new RuntimeException('团队系统数据库连接资料加密失败。'); } return base64_encode(json_encode([ 'v' => 1, 'salt' => base64_encode($salt), 'iv' => base64_encode($iv), 'tag' => base64_encode($tag), 'data' => base64_encode($ciphertext), ], JSON_THROW_ON_ERROR)); } private function profile(): string { $profile = trim((string) ( $this->encodedProfile ?? config('system_database.team_profile') )); return $profile !== '' ? $profile : self::EMBEDDED_PROFILE; } private function decrypt(string $encodedProfile, string $password): array { try { $envelope = json_decode( base64_decode($encodedProfile, true) ?: throw new RuntimeException(), true, 16, JSON_THROW_ON_ERROR ); $salt = base64_decode((string) ($envelope['salt'] ?? ''), true); $iv = base64_decode((string) ($envelope['iv'] ?? ''), true); $tag = base64_decode((string) ($envelope['tag'] ?? ''), true); $ciphertext = base64_decode((string) ($envelope['data'] ?? ''), true); if ( ($envelope['v'] ?? null) !== 1 || $salt === false || strlen($salt) !== 16 || $iv === false || strlen($iv) !== 12 || $tag === false || strlen($tag) !== 16 || $ciphertext === false ) { throw new RuntimeException(); } $key = hash_pbkdf2('sha256', $password, $salt, self::ITERATIONS, 32, true); $plaintext = openssl_decrypt( $ciphertext, self::CIPHER, $key, OPENSSL_RAW_DATA, $iv, $tag ); if ($plaintext === false) { throw new RuntimeException(); } $profile = json_decode($plaintext, true, 16, JSON_THROW_ON_ERROR); if (! is_array($profile)) { throw new RuntimeException(); } return $profile; } catch (\Throwable) { throw new RuntimeException('系统数据库密码不正确,请重新输入。'); } } private function requiredString(array $profile, string $key): string { $value = trim((string) ($profile[$key] ?? '')); if ($value === '' || preg_match('/[;\x00-\x1F]/', $value) === 1) { throw new RuntimeException('团队系统数据库连接资料不完整,请联系负责人更新代码。'); } return $value; } private function requiredPort(array $profile): int { $port = (int) ($profile['port'] ?? 0); if ($port < 1 || $port > 65535) { throw new RuntimeException('团队系统数据库连接资料不完整,请联系负责人更新代码。'); } return $port; } }