144 lines
5.5 KiB
PHP
Executable File
144 lines
5.5 KiB
PHP
Executable File
<?php
|
||
/**
|
||
* Cloudflare 域名自动化回归(CLI 输出 JSON,Mock HTTP)
|
||
*/
|
||
$root = dirname(__DIR__);
|
||
require_once $root . '/cong.php';
|
||
require_once $root . '/lib/Cloak/DomainRepository.php';
|
||
require_once $root . '/lib/Cloak/CloudflareConfig.php';
|
||
require_once $root . '/lib/Cloak/CloudflareClient.php';
|
||
require_once $root . '/lib/Cloak/DomainProvisioningService.php';
|
||
|
||
class MockCloudflareClient extends CloudflareClient
|
||
{
|
||
public $zoneStatus = 'pending';
|
||
public $deleteCalled = false;
|
||
public $upsertCalls = [];
|
||
|
||
public function __construct()
|
||
{
|
||
}
|
||
|
||
public function createZone($hostname)
|
||
{
|
||
return [
|
||
'ok' => true,
|
||
'result' => [
|
||
'id' => 'zone_mock_' . md5($hostname),
|
||
'name_servers' => ['ada.ns.cloudflare.com', 'bob.ns.cloudflare.com'],
|
||
],
|
||
];
|
||
}
|
||
|
||
public function getZone($zoneId)
|
||
{
|
||
return [
|
||
'ok' => true,
|
||
'result' => [
|
||
'id' => $zoneId,
|
||
'status' => $this->zoneStatus,
|
||
'name_servers' => ['ada.ns.cloudflare.com', 'bob.ns.cloudflare.com'],
|
||
],
|
||
];
|
||
}
|
||
|
||
public function deleteZone($zoneId)
|
||
{
|
||
$this->deleteCalled = true;
|
||
return ['ok' => true, 'result' => ['id' => $zoneId]];
|
||
}
|
||
|
||
public function upsertARecord($zoneId, $fqdn, $ip, $proxied = true)
|
||
{
|
||
$this->upsertCalls[] = compact('zoneId', 'fqdn', 'ip', 'proxied');
|
||
return ['ok' => true, 'result' => ['id' => 'rec_' . md5($fqdn)]];
|
||
}
|
||
|
||
public function setSslFlexible($zoneId)
|
||
{
|
||
return ['ok' => true];
|
||
}
|
||
|
||
public function setAlwaysHttps($zoneId)
|
||
{
|
||
return ['ok' => true];
|
||
}
|
||
}
|
||
|
||
$tests = [];
|
||
$host = 'cf-mock-' . substr(md5((string) microtime(true)), 0, 8) . '.test';
|
||
|
||
try {
|
||
$pdo = DomainRepository::pdo();
|
||
DomainRepository::ensureTable($pdo);
|
||
|
||
// 未启用 CF:添加后 cf_status=local
|
||
CloudflareConfig::clearTestOverrides();
|
||
DomainProvisioningService::clearClientOverride();
|
||
$addLocal = DomainProvisioningService::provisionOnAdd($pdo, $host);
|
||
$rowLocal = DomainRepository::findById($pdo, (int) ($addLocal['id'] ?? 0));
|
||
$tests['add_local_cf_status'] = ($addLocal['ok'] ?? false) === true
|
||
&& ($addLocal['cf_status'] ?? '') === 'local'
|
||
&& ($rowLocal['cf_status'] ?? '') === 'local';
|
||
DomainRepository::deleteById($pdo, (int) $addLocal['id']);
|
||
|
||
// Mock:pending_ns → ready
|
||
CloudflareConfig::setTestOverrides(['enabled' => true, 'server_ip' => '203.0.113.10']);
|
||
$mock = new MockCloudflareClient();
|
||
DomainProvisioningService::setClientOverride($mock);
|
||
|
||
$addCf = DomainProvisioningService::provisionOnAdd($pdo, $host);
|
||
$domainId = (int) ($addCf['id'] ?? 0);
|
||
$tests['add_cf_pending_ns'] = ($addCf['ok'] ?? false) === true
|
||
&& ($addCf['cf_status'] ?? '') === 'pending_ns'
|
||
&& count($addCf['nameservers'] ?? []) === 2;
|
||
|
||
$pending = DomainProvisioningService::checkAndProvision($pdo, $domainId);
|
||
$tests['check_pending_ns'] = ($pending['ok'] ?? false) === true
|
||
&& ($pending['status'] ?? '') === 'pending_ns';
|
||
|
||
$mock->zoneStatus = 'active';
|
||
$ready = DomainProvisioningService::checkAndProvision($pdo, $domainId);
|
||
$rowReady = DomainRepository::findById($pdo, $domainId);
|
||
$tests['check_ready'] = ($ready['ok'] ?? false) === true
|
||
&& ($ready['status'] ?? '') === 'ready'
|
||
&& ($rowReady['cf_status'] ?? '') === 'ready'
|
||
&& count($mock->upsertCalls) === 2;
|
||
|
||
$del = DomainProvisioningService::deleteWithCloudflare($pdo, $domainId);
|
||
$tests['delete_calls_zone'] = ($del['ok'] ?? false) === true && $mock->deleteCalled === true;
|
||
$tests['delete_row_gone'] = DomainRepository::findById($pdo, $domainId) === null;
|
||
|
||
// 手动模式:不创建 Zone
|
||
$hostManual = 'cf-manual-' . substr(md5((string) microtime(true)), 0, 8) . '.test';
|
||
$addManual = DomainProvisioningService::provisionOnAdd($pdo, $hostManual, 'manual');
|
||
$rowManual = DomainRepository::findById($pdo, (int) ($addManual['id'] ?? 0));
|
||
$tests['add_manual_cf_status'] = ($addManual['ok'] ?? false) === true
|
||
&& ($addManual['cf_status'] ?? '') === 'manual'
|
||
&& ($rowManual['cf_status'] ?? '') === 'manual'
|
||
&& trim((string) ($rowManual['cf_zone_id'] ?? '')) === '';
|
||
$checkManual = DomainProvisioningService::checkAndProvision($pdo, (int) ($addManual['id'] ?? 0));
|
||
$tests['check_manual_skipped'] = ($checkManual['ok'] ?? false) === false;
|
||
DomainRepository::deleteById($pdo, (int) ($addManual['id'] ?? 0));
|
||
|
||
// 批量添加
|
||
$batchText = "batch-a.test\nbatch-b.test, batch-c.test";
|
||
$batch = DomainProvisioningService::provisionBatch($pdo, $batchText, 'manual');
|
||
$tests['batch_add_count'] = ($batch['ok'] ?? false) === true && count($batch['added'] ?? []) === 3;
|
||
foreach ($batch['added'] ?? [] as $item) {
|
||
DomainRepository::deleteById($pdo, (int) ($item['id'] ?? 0));
|
||
}
|
||
|
||
$parsed = DomainRepository::parseHostnameBatch("a.test\nb.test\nc.test,d.test");
|
||
$tests['parse_hostname_batch'] = $parsed === ['a.test', 'b.test', 'c.test', 'd.test'];
|
||
} catch (Throwable $e) {
|
||
$tests['exception'] = false;
|
||
$tests['error'] = $e->getMessage();
|
||
} finally {
|
||
CloudflareConfig::clearTestOverrides();
|
||
DomainProvisioningService::clearClientOverride();
|
||
}
|
||
|
||
$ok = !in_array(false, $tests, true) && !isset($tests['error']);
|
||
echo json_encode(['ok' => $ok, 'tests' => $tests], JSON_UNESCAPED_UNICODE) . "\n";
|