secret = $secret; $this->targetBranch = $targetBranch; $this->deployExecutor = $deployExecutor; } public function handle(array $server, array $get, string $rawBody): array { // 1. 验证权限 (支持 Header 明文 Token、URL Token 以及 HMAC-SHA256 签名) if (!$this->verifyAuth($server, $get, $rawBody)) { return ['code' => 403, 'data' => ['status' => 'error', 'message' => 'Invalid token']]; } // 2. 验证 HTTP 请求方式 $method = strtoupper($server['REQUEST_METHOD'] ?? 'GET'); if ($method !== 'POST') { return ['code' => 405, 'data' => ['status' => 'error', 'message' => 'Method not allowed']]; } // 3. 处理 Ping / Test 事件 $event = strtolower($server['HTTP_X_GITEA_EVENT'] ?? $server['HTTP_X_GIT_EVENT'] ?? $server['HTTP_X_GITHUB_EVENT'] ?? ''); if ($event === 'ping') { return ['code' => 200, 'data' => ['status' => 'success', 'message' => 'pong']]; } // 4. 解析分支并过滤 $payload = json_decode($rawBody, true) ?: []; $ref = $payload['ref'] ?? ''; $branch = str_replace('refs/heads/', '', $ref); if ($branch !== $this->targetBranch) { return [ 'code' => 200, 'data' => [ 'status' => 'skipped', 'message' => "Branch {$branch} ignored, target is {$this->targetBranch}" ] ]; } // 5. 触发部署执行 $output = ''; if (is_callable($this->deployExecutor)) { $output = call_user_func($this->deployExecutor, $payload); } return [ 'code' => 200, 'data' => [ 'status' => 'success', 'message' => 'Deployment triggered', 'branch' => $branch, 'output' => $output ] ]; } private function verifyAuth(array $server, array $get, string $rawBody): bool { // A. 明文 Token 校验 $token = $server['HTTP_X_GITEA_TOKEN'] ?? $server['HTTP_X_GIT_TOKEN'] ?? $server['HTTP_X_GITLAB_TOKEN'] ?? ($get['token'] ?? ''); if ($token !== '' && hash_equals($this->secret, $token)) { return true; } // B. HMAC-SHA256 签名校验 (Gitea / GitHub) $signature = $server['HTTP_X_GITEA_SIGNATURE'] ?? $server['HTTP_X_HUB_SIGNATURE_256'] ?? ''; if ($signature !== '') { if (strpos($signature, 'sha256=') === 0) { $signature = substr($signature, 7); } $expected = hash_hmac('sha256', $rawBody, $this->secret); if (hash_equals($expected, $signature)) { return true; } } return false; } }