diff --git a/src/Site/Lib/Activitypub.php b/src/Site/Lib/Activitypub.php index 5d69897..489f124 100644 --- a/src/Site/Lib/Activitypub.php +++ b/src/Site/Lib/Activitypub.php @@ -16,6 +16,7 @@ class ActivityPub { private string $desc; private string $icon; private array $posts = []; + private string $https; /** * コンストラクタ @@ -23,11 +24,13 @@ class ActivityPub { * @param array $posts 投稿データの配列 */ public function __construct(array $posts = []) { - $this->domain = $_SERVER['SERVER_NAME']; + if (!ACTIVITYPUB_ENABLED) return; + $this->https = 'http'.((!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 's' : '').'://'; + $this->domain = $this->https.($_SERVER['SERVER_NAME'] ?? '127.0.0.1:8000'); $this->actor = FEDIINFO['actor']; $this->actorNick = FEDIINFO['actorNick']; $this->desc = FEDIINFO['desc']; - $this->icon = "https://{$this->domain}".FEDIINFO['icon']; + $this->icon = "{$this->domain}".FEDIINFO['icon']; $this->posts = $posts; } @@ -38,6 +41,7 @@ class ActivityPub { * @throws \Exception 公開鍵の読み込みに失敗した場合 */ public function getActor(): string { + if (!ACTIVITYPUB_ENABLED) return ''; $pubkey = file_get_contents(FEDIINFO['pubkey']); if ($pubkey === false) { throw new \Exception('公開鍵の受取に失敗。パス:'.FEDIINFO['pubkey']); @@ -48,7 +52,7 @@ class ActivityPub { 'https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1', ], - 'id' => "https://{$this->domain}/ap/actor", + 'id' => "{$this->domain}/ap/actor", 'name' => $this->actorNick, 'summary' => $this->desc, 'manuallyApprovesFollowers' => false, @@ -59,22 +63,21 @@ class ActivityPub { ], 'image' => [ 'type' => 'Image', - 'url' => - "https://{$this->domain}/static/article/o_53803618dc1691.28179609.jpg", + 'url' => "{$this->domain}/static/article/o_53803618dc1691.28179609.jpg", 'mediaType' => 'image/jpeg', ], 'type' => 'Person', - 'url' => "https://{$this->domain}", + 'url' => "{$this->domain}", 'preferredUsername' => $this->actor, - 'inbox' => "https://{$this->domain}/ap/inbox", - 'outbox' => "https://{$this->domain}/ap/outbox", - 'followers' => "https://{$this->domain}/ap/followers", - 'following' => "https://{$this->domain}/ap/following", + 'inbox' => "{$this->domain}/ap/inbox", + 'outbox' => "{$this->domain}/ap/outbox", + 'followers' => "{$this->domain}/ap/followers", + 'following' => "{$this->domain}/ap/following", 'published' => '2025-03-28T18:00:00Z', 'updated' => gmdate('c'), 'publicKey' => [ - 'id' => "https://{$this->domain}/ap/actor#main-key", - 'owner' => "https://{$this->domain}/ap/actor", + 'id' => "{$this->domain}/ap/actor#main-key", + 'owner' => "{$this->domain}/ap/actor", 'publicKeyPem' => $pubkey, ], ]; @@ -89,6 +92,7 @@ class ActivityPub { * @return string JSONエンコードされたアクティビティデータ */ public function getActivity(string $uuid): string { + if (!ACTIVITYPUB_ENABLED) return ''; $items = []; foreach ($this->posts as $post) { @@ -107,28 +111,27 @@ class ActivityPub { 'toot' => 'http://joinmastodon.org/ns#', ], ], - 'id' => "https://{$this->domain}/ap/activities/create/{$post['uuid']}", + 'id' => "{$this->domain}/ap/activities/create/{$post['uuid']}", 'type' => 'Create', - 'actor' => "https://{$this->domain}/ap/actor", + 'actor' => "{$this->domain}/ap/actor", 'cc' => [ - "https://{$this->domain}/ap/followers", + "{$this->domain}/ap/followers", ], 'published' => date("Y-m-d\TH:i:s.u\Z", strtotime($post['date'])), 'to' => ['https://www.w3.org/ns/activitystreams#Public'], 'object' => [ - 'id' => "https://{$this->domain}/ap/objects/{$post['uuid']}", + 'id' => "{$this->domain}/ap/objects/{$post['uuid']}", 'type' => 'Note', 'name' => $post['title'], - 'attributedTo' => "https://{$this->domain}/ap/actor", + 'attributedTo' => "{$this->domain}/ap/actor", 'cc' => [ - "https://{$this->domain}/ap/followers", + "{$this->domain}/ap/followers", ], 'to' => ['https://www.w3.org/ns/activitystreams#Public'], - 'content' => - $post['preview']."

domain}/blog/{$post['slug']}\">読み続き", - 'url' => "https://{$this->domain}/blog/{$post['slug']}", + 'content' => $post['preview']."

domain}/blog/{$post['slug']}\">読み続き", + 'url' => "{$this->domain}/blog/{$post['slug']}", 'published' => date("Y-m-d\TH:i:s.u\Z", strtotime($post['date'])), - 'replies' => "https://{$this->domain}/ap/objects/{$uuid}/replies", + 'replies' => "{$this->domain}/ap/objects/{$uuid}/replies", 'sensitive' => false, ], ]; @@ -141,7 +144,7 @@ class ActivityPub { } if (isset($post['thumbnail']) && $post['thumbnail'] != '') { - $imgurl = "https://technicalsuwako.moe/static/article/{$post['thumbnail']}"; + $imgurl = "{$this->domain}/static/article/{$post['thumbnail']}"; $imgpath = ROOT."/public/static/article/{$post['thumbnail']}"; $imgraw = file_get_contents($imgpath); @@ -167,6 +170,7 @@ class ActivityPub { * @return string JSONエンコードされたアウトボックスデータ */ public function getOutbox(): string { + if (!ACTIVITYPUB_ENABLED) return ''; $items = []; $counter = 0; @@ -186,28 +190,27 @@ class ActivityPub { 'toot' => 'http://joinmastodon.org/ns#', ], ], - 'id' => "https://{$this->domain}/ap/activities/create/{$uid}", + 'id' => "{$this->domain}/ap/activities/create/{$uid}", 'type' => 'Create', - 'actor' => "https://{$this->domain}/ap/actor", + 'actor' => "{$this->domain}/ap/actor", 'cc' => [ - "https://{$this->domain}/ap/followers", + "{$this->domain}/ap/followers", ], 'published' => date("Y-m-d\TH:i:s.u\Z", strtotime($post['date'])), 'to' => ['https://www.w3.org/ns/activitystreams#Public'], 'object' => [ - 'id' => "https://{$this->domain}/ap/objects/{$uid}", + 'id' => "{$this->domain}/ap/objects/{$uid}", 'type' => 'Note', 'name' => $post['title'], - 'attributedTo' => "https://{$this->domain}/ap/actor", + 'attributedTo' => "{$this->domain}/ap/actor", 'cc' => [ - "https://{$this->domain}/ap/followers", + "{$this->domain}/ap/followers", ], 'to' => ['https://www.w3.org/ns/activitystreams#Public'], - 'content' => - $post['preview']."

domain}/blog/{$post['slug']}\">読み続き", - 'url' => "https://{$this->domain}/blog/{$post['slug']}", + 'content' => $post['preview']."

domain}/blog/{$post['slug']}\">読み続き", + 'url' => "{$this->domain}/blog/{$post['slug']}", 'published' => date("Y-m-d\TH:i:s.u\Z", strtotime($post['date'])), - 'replies' => "https://{$this->domain}/ap/objects/{$uid}/replies", + 'replies' => "{$this->domain}/ap/objects/{$uid}/replies", 'sensitive' => false, ], ]; @@ -220,7 +223,7 @@ class ActivityPub { } if (isset($post['thumbnail']) && $post['thumbnail'] != '') { - $imgurl = "https://technicalsuwako.moe/static/article/{$post['thumbnail']}"; + $imgurl = "{$this->domain}/static/article/{$post['thumbnail']}"; $imgpath = ROOT."/public/static/article/{$post['thumbnail']}"; $imgraw = file_get_contents($imgpath); @@ -242,7 +245,7 @@ class ActivityPub { 'https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1', ], - 'id' => "https://{$this->domain}/ap/outbox", + 'id' => "{$this->domain}/ap/outbox", 'type' => 'OrderedCollection', 'totalItems' => count($items), 'orderedItems' => $items, @@ -257,13 +260,14 @@ class ActivityPub { * @return string JSONエンコードされたWebFingerデータ */ public function getWebfinger(): string { + if (!ACTIVITYPUB_ENABLED) return ''; $webfinger = [ 'subject' => "acct:{$this->actor}@{$this->domain}", 'links' => [ [ 'rel' => 'self', 'type' => 'application/activity+json', - 'href' => "https://{$this->domain}/ap/actor", + 'href' => "{$this->domain}/ap/actor", ], ], ]; @@ -277,6 +281,7 @@ class ActivityPub { * @return string JSONエンコードされたフォロワーのリスト */ public function getFollowers(): string { + if (!ACTIVITYPUB_ENABLED) return ''; $f = array_filter(explode("\n", file_get_contents(ROOT.'/data/followers.txt'))); $followers = [ @@ -284,7 +289,7 @@ class ActivityPub { 'https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1', ], - 'id' => "https://{$this->domain}/ap/followers", + 'id' => "{$this->domain}/ap/followers", 'type' => 'OrderredCollection', 'totalItems' => count($f), 'orderedItems' => $f, @@ -299,6 +304,7 @@ class ActivityPub { * @return string JSONエンコードされたフォローリスト */ public function getFollowing(): string { + if (!ACTIVITYPUB_ENABLED) return ''; $f = array_filter(explode("\n", file_get_contents(ROOT.'/data/following.txt'))); $following = [ @@ -306,7 +312,7 @@ class ActivityPub { 'https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1', ], - 'id' => "https://{$this->domain}/ap/following", + 'id' => "{$this->domain}/ap/following", 'type' => 'OrderredCollection', 'totalItems' => count($f), 'orderedItems' => $f, @@ -322,6 +328,7 @@ class ActivityPub { * @return void */ public function postInbox(array $activity): void { + if (!ACTIVITYPUB_ENABLED) return; switch ($activity['type']) { case 'Follow': $this->acceptFollower($activity); @@ -329,8 +336,7 @@ class ActivityPub { default: header('HTTP/1.1 501 Not Implemented'); header('Content-Type: application/activity+json'); - echo json_encode(['error' => - '未対応なアクティビティタイプ: '.$activity['type']]); + echo json_encode(['error' => '未対応なアクティビティタイプ: '.$activity['type']]); exit; } @@ -346,14 +352,15 @@ class ActivityPub { * @return string JSONエンコードされた更新アクティビティ */ public function update(): string { + if (!ACTIVITYPUB_ENABLED) return ''; $update = [ '@context' => [ 'https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1', ], - 'id' => "https://{$this->domain}/ap/activities/update/".uuid(), + 'id' => "{$this->domain}/ap/activities/update/".uuid(), 'type' => 'Update', - 'actor' => "https://{$this->domain}/ap/actor", + 'actor' => "{$this->domain}/ap/actor", 'to' => ['https://www.w3.org/ns/activitystreams#Public'], 'object' => json_decode($this->getActor(), true), ]; @@ -368,14 +375,13 @@ class ActivityPub { * @return void */ public function sendActorUpdate(array $params): void { + if (!ACTIVITYPUB_ENABLED) return; $f = array_filter(explode("\n", file_get_contents(ROOT.'/data/followers.txt'))); $ap = new Activitypub(); $inboxes = implode("\n", $f); $update = json_decode($ap->update(), true); - foreach ($f as $inbox) { - $this->sendActivity($inbox, $update); - } + foreach ($f as $inbox) $this->sendActivity($inbox, $update); } // 機能性メソッド @@ -410,9 +416,7 @@ class ActivityPub { 'Digest' => "SHA-256=$digest", ]; - $stringToSign = "host: {$headers['Host']}\n" - ."date: {$headers['Date']}\n" - ."digest: {$headers['Digest']}"; + $stringToSign = "host: {$headers['Host']}\n"."date: {$headers['Date']}\n"."digest: {$headers['Digest']}"; logger(\LogType::ActivityPub, "署名対象: {$stringToSign}"); if (!openssl_sign($stringToSign, $signature, $priv, OPENSSL_ALGO_SHA256)) { @@ -425,18 +429,16 @@ class ActivityPub { } $sigValue = base64_encode($signature); - $headers['Signature'] = "keyId=\"https://{$this->domain}/ap/actor#main-key\","; + $headers['Signature'] = "keyId=\"{$this->domain}/ap/actor#main-key\","; $headers['Signature'] .= 'algorithm="rsa-sha256",'; $headers['Signature'] .= 'headers="host date digest",'; $headers['Signature'] .= 'signature="'.$sigValue.'"'; - logger(\LogType::ActivityPub, - "署名: {$headers['Signature']}\n送信データ: {$body}"); + logger(\LogType::ActivityPub, "署名: {$headers['Signature']}\n送信データ: {$body}"); $curl = new Curl($inboxUrl); $curl->setMethod('POST') ->setPostRaw($body) - ->setHeaders(array_map(fn($k, $v) => "$k: $v", - array_keys($headers), $headers)) + ->setHeaders(array_map(fn($k, $v) => "$k: $v", array_keys($headers), $headers)) ->setCaInfo('/etc/ssl/cert.pem') ->setVerbose(true) ->setStderr(fopen(ROOT.'/log/ap_log.txt', 'a')); @@ -447,8 +449,7 @@ class ActivityPub { $err = $curl->getError(); var_dump(print_r($res)); - logger(\LogType::ActivityPub, - "アクティビティは「{$inboxUrl}」に送信しました: HTTP {$code}"); + logger(\LogType::ActivityPub, "アクティビティは「{$inboxUrl}」に送信しました: HTTP {$code}"); logger(\LogType::ActivityPub, "エラー: {$err}"); logger(\LogType::ActivityPub, "レスポンス: {$res}"); } @@ -483,9 +484,9 @@ class ActivityPub { 'https://www.w3.org/ns/activitystreams', 'https://w3id.org/security/v1', ], - 'id' => "https://{$this->domain}/ap/activities/".uniqid(), + 'id' => "{$this->domain}/ap/activities/".uniqid(), 'type' => 'Accept', - 'actor' => "https://{$this->domain}/ap/actor", + 'actor' => "{$this->domain}/ap/actor", 'object' => $activity, ]; @@ -506,9 +507,7 @@ class ActivityPub { } $followers = $this->getFollowersList(); - if (!in_array($followerActor, $followers)) { - file_put_contents($file, "$followerActor\n", FILE_APPEND); - } + if (!in_array($followerActor, $followers)) file_put_contents($file, "$followerActor\n", FILE_APPEND); } /** @@ -519,8 +518,7 @@ class ActivityPub { private function getFollowersList(): array { $file = ROOT.'/data/followers.txt'; $f = array_filter(explode("\n", file_get_contents($file))); - return file_exists($file) - ? array_filter(explode("\n", file_get_contents($file))) : []; + return file_exists($file) ? array_filter(explode("\n", file_get_contents($file))) : []; } /** diff --git a/src/Site/Lib/Auth.php b/src/Site/Lib/Auth.php index e3700c1..5bf26e9 100644 --- a/src/Site/Lib/Auth.php +++ b/src/Site/Lib/Auth.php @@ -89,6 +89,7 @@ class Auth { $json = json_encode($userData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); if (file_put_contents($path, $json) === false) { + logger(\LogType::Auth, '【setToken】JSONファイルにユーザーデータを保存出来なかった。パス:'.$path); return \Result::error('エラー:ユーザーデータの保存に失敗。'); } @@ -100,6 +101,7 @@ class Auth { 'httponly' => true, 'samesite' => 'Strict' ])) { + logger(\LogType::Auth, '【setToken】クッキーを設定出来なかった。トークン:'.$token); return \Result::error('エラー:クッキーを設定に失敗。'); } @@ -147,7 +149,7 @@ class Auth { if ($username === $user) return \Result::Success("ユーザー「{$username}」は既に存在します。"); } - return \Result::Error("エラー:ユーザー「{$username}」は存在しません。"); + return \Result::Error(''); } public function mkUser(?string $username = null, #[SensitiveParameter] ?string $password = null, ?string $passwordVerify = null, ?string $email = null): \Result { @@ -167,6 +169,7 @@ class Auth { $err = ''; if (!mkdir($this->assDir.$username, 0755)) { + logger(\LogType::Auth, '【mkUser】アセットディレクトリを作成出来なかった。chownをご確認下さい。パス:'.$this->assDir.$username); return \Result::Error('エラー:ユーザーのアイコンディレクトリの作成に失敗。'); } @@ -203,6 +206,7 @@ class Auth { $json = json_encode($user, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); if (file_put_contents($path, $json) === false) { + logger(\LogType::Auth, '【mkUser】JSONファイルを作成出来なかった。パス:'.$path); rmdir($this->assDir.$username); return \Result::Error('エラー:ユーザーデータの保存に失敗。'); } @@ -225,6 +229,7 @@ class Auth { $json = json_encode($userData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); if (file_put_contents($path, $json) === false) { + logger(\LogType::Auth, '【verifyLogin】JSONファイルを変更出来なかった。chownをご確認下さい。パス:'.$path); return \Result::Error('エラー:ユーザーデータの保存に失敗。'); } } @@ -244,6 +249,7 @@ class Auth { $json = json_encode($userData, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES); if (file_put_contents($path, $json) === false) { + logger(\LogType::Auth, '【purgeOldTokens】JSONファイルを変更出来なかった。chownをご確認下さい。パス:'.$path); return \Result::Error('エラー:ユーザーデータの保存に失敗。'); } diff --git a/src/Site/Lib/Curl.php b/src/Site/Lib/Curl.php index 893e31b..a02a98d 100644 --- a/src/Site/Lib/Curl.php +++ b/src/Site/Lib/Curl.php @@ -37,6 +37,7 @@ class Curl { * @param string|null $url リクエスト先のURL */ public function __construct(?string $url = null) { + if (!CURL_ENABLED) return; if ($url !== null) { $this->url = $url; } @@ -247,12 +248,13 @@ class Curl { /** * リクエストを実行する * - * @return bool 成功または失敗 + * @return Result 成功または失敗 */ - public function execute(): bool { + public function execute(): \Result { + if (!CURL_ENABLED) return \Result::Error('エラー:認証システムは無効です。'); if (empty($this->url)) { $this->responseError = 'URLがありません'; - return false; + return \Result::Error($this->responseError); } // レスポンスデータのリセット @@ -286,7 +288,7 @@ class Curl { $parsed = parse_url($currentUrl); if (!$parsed) { $this->responseError = "無効なURL: {$currentUrl}"; - return false; + return \Result::Error($this->responseError); } $scheme = isset($parsed['scheme']) ? strtolower($parsed['scheme']) : 'http'; @@ -403,7 +405,7 @@ class Curl { if ($this->verbose && $this->stderr) { fwrite($this->stderr, "* エラー: {$this->responseError}\n"); } - return false; + return \Result::Error($this->responseError); } // タイムアウトを設定 @@ -523,7 +525,7 @@ class Curl { $this->method = $originalMethod; $this->info['total_time'] = microtime(true) - $startTime; - return true; + return \Result::Success(); } /** diff --git a/src/Site/Test/LibCurl.php b/src/Site/Test/LibCurl.php index f08c62c..43037f5 100644 --- a/src/Site/Test/LibCurl.php +++ b/src/Site/Test/LibCurl.php @@ -65,7 +65,7 @@ if (CURL_ENABLED) { $curl = new Curl('https://076.moe'); $result = $curl->execute(); - $test->assertTrue($result); + $test->assertTrue($result->isSuccess); $test->assertEquals(200, $curl->getResponseCode()); $test->assertNotNull($curl->getResponseBody()); $test->assertStringContains('getResponseBody()); @@ -81,7 +81,7 @@ if (CURL_ENABLED) { ]); $result = $curl->execute(); - $test->assertTrue($result); + $test->assertTrue($result->isSuccess); $test->assertEquals(200, $curl->getResponseCode()); $responseBody = $curl->getResponseBody(); diff --git a/tester.php b/tester.php index 26e286e..8ec4d4a 100644 --- a/tester.php +++ b/tester.php @@ -1,8 +1,9 @@