<?php

declare(strict_types = 1);

// {{{ License

// This file is part of GNU social - https://www.gnu.org/software/social
//
// GNU social is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// GNU social is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with GNU social.  If not, see <http://www.gnu.org/licenses/>.

// }}}

namespace Plugin\ActivityPub\Test\Objects;

use App\Core\Router;
use App\Util\GNUsocialTestCase;
use Plugin\ActivityPub\Util\HTTPSignature;

class HTTPSignatureTest extends GNUsocialTestCase
{
    private static string $gotosocial_signature       = "keyId=\"https://goblin.technology/users/tobi/main-key\",algorithm=\"hs2019\",headers=\"(request-target) host date digest\",signature=\"kWM36BsRw3Ij4q9BgjPVPOzG2AG87ox91nYsdRoctdlCkYXmevhih2lWVjjlOgMc0OnQrwhUVMAFj2CNiOd5kw38Uo5KcOfY1KC6TCxvDciCJPAMUmvjaMD/Ag6JRaQUh6EB0tvnN2BaWO32i2LP7d0ApRaLj71DhHmSpXsG4pDBl/iauX/YoZew6ohfLAMPCRxPflGn7Uel/Is/yJSYCHyvz43DlmlNb+dMKEa0CVAhvNhg5aGwJ5AiJTg62Yk5ya5PCUJxWn2q87BhS3sbK//AfBQlPf8GUoytO0ACF9vRBwLCH/i6/aup8IXAhjN1GG2IlaAPEV5ROnCIBZo8fg==\"";
    private static string $gotosocial_content         = '{"@context":"https://www.w3.org/ns/activitystreams","actor":"https://goblin.technology/users/tobi","id":"https://goblin.technology/users/tobi/liked/01GG57FZE36DGH77H3M92M190W","object":"https://gnusocial.test.superseriousbusiness.org/object/note/2","to":"https://gnusocial.test.superseriousbusiness.org/actor/1","type":"Like"}';
    private static array  $gotosocial_request_headers = ["accept-encoding"=>"gzip","content-length"=>"326","accept-charset"=>"utf-8","content-type"=>"application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"","signature"=>"keyId=\"https://goblin.technology/users/tobi/main-key\",algorithm=\"hs2019\",headers=\"(request-target) host date digest\",signature=\"kWM36BsRw3Ij4q9BgjPVPOzG2AG87ox91nYsdRoctdlCkYXmevhih2lWVjjlOgMc0OnQrwhUVMAFj2CNiOd5kw38Uo5KcOfY1KC6TCxvDciCJPAMUmvjaMD/Ag6JRaQUh6EB0tvnN2BaWO32i2LP7d0ApRaLj71DhHmSpXsG4pDBl/iauX/YoZew6ohfLAMPCRxPflGn7Uel/Is/yJSYCHyvz43DlmlNb+dMKEa0CVAhvNhg5aGwJ5AiJTg62Yk5ya5PCUJxWn2q87BhS3sbK//AfBQlPf8GUoytO0ACF9vRBwLCH/i6/aup8IXAhjN1GG2IlaAPEV5ROnCIBZo8fg==\"","digest"=>"SHA-256=gTjVY4ikVc1yn++/IWEmiGge0zy2TBMG++0OzXS2Nw4=","date"=>"Mon, 24 Oct 2022 14:49:06 GMT","user-agent"=>"gotosocial; goblin.technology (gofed/activity gotosocial-0.5.1-SNAPSHOT git-3ca7164)","host"=>"gnusocial.test.superseriousbusiness.org","x-php-ob-level"=>"0","format"=>"application/jrd+json"];
    private static string $gotosocial_public_key      = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAy2/j9+2G7xrQvBtygrj4\naYHl8hTeZecDBnS+6IBjjEt+QWJ3z0Cv9lXSVMZw5i6DVTkVOGZrh2vZDu0BCTEV\n07dyASArE63Qe21WwjNObpkQ7YZbMxUkYjWCDYdqLMifAqElYzIK7xnY0pTWylmC\njm39qxmhk22PpzRkw+zofh9ykqyadmkA2/KrpZgGnjn6MiPqb2DeELV1tzmZ7mAz\n+k7pkkhxvBVqPhCZ104pyd1lc66obONSnIqxugRlrrUZbFv1e6xFsUmMUYrAGQTt\nZr4VeZwuaYj/MvFIeOZrmth/lg3QpYbKZYnJKVePyH+530jRSFerr2unbuGmEQAg\nvQIDAQAB\n-----END PUBLIC KEY-----\n";

    private static string $mastodon_signature         = "keyId=\"https://ondergrond.org/users/dumpsterqueer#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"RP9F3wxAq9/VGATr1HfB30B98XNgXcdle2z15QQc0x+k2ioKmwOLlCFKv+J3LdQ2GKIJ4XVBHG2Klzu6FVPLaABiUoBWSqSM1p2hzM760ewIKBZs9fZwmFp+Ec1UT5i4xwLa/EYJZ8ofpc2DkVww58p8FIxcV6gqcmvHMkYooCBogXvsSRSQ0IG3YlFux2um4iD/e9ly5DiU5NtAUMg3tER05MT+gzG6bTMyZwxeJ+svuXF6w6o+BCn8wsxXwMxbDYtjh3f03zeTYdbzEm4eJT5yEQi6XRmgQz59u20LCFOXEtqljP7PymRY+dPb6/xJhlhYLaTOMYZwuAjPSnToEQ==\"";
    private static string $mastodon_content           = '{"@context":"https://www.w3.org/ns/activitystreams","id":"https://ondergrond.org/users/dumpsterqueer#likes/119260","type":"Like","actor":"https://ondergrond.org/users/dumpsterqueer","object":"https://gnusocial.test.superseriousbusiness.org/object/note/2"}';
    private static array  $mastodon_request_headers   = ["content-length"=>"255","connection"=>"Keep-Alive","signature"=>"keyId=\"https://ondergrond.org/users/dumpsterqueer#main-key\",algorithm=\"rsa-sha256\",headers=\"(request-target) host date digest content-type\",signature=\"RP9F3wxAq9/VGATr1HfB30B98XNgXcdle2z15QQc0x+k2ioKmwOLlCFKv+J3LdQ2GKIJ4XVBHG2Klzu6FVPLaABiUoBWSqSM1p2hzM760ewIKBZs9fZwmFp+Ec1UT5i4xwLa/EYJZ8ofpc2DkVww58p8FIxcV6gqcmvHMkYooCBogXvsSRSQ0IG3YlFux2um4iD/e9ly5DiU5NtAUMg3tER05MT+gzG6bTMyZwxeJ+svuXF6w6o+BCn8wsxXwMxbDYtjh3f03zeTYdbzEm4eJT5yEQi6XRmgQz59u20LCFOXEtqljP7PymRY+dPb6/xJhlhYLaTOMYZwuAjPSnToEQ==\"","content-type"=>"application/activity+json","digest"=>"SHA-256=dDj/+B/FOGAFyTSkrhVjzTmJmUSlebTuU9Pr8XbbAqY=","accept-encoding"=>"gzip","date"=>"Mon, 24 Oct 2022 15:08:50 GMT","host"=>"gnusocial.test.superseriousbusiness.org","user-agent"=>"http.rb/4.4.1 (Mastodon/3.4.2; +https://ondergrond.org/)","x-php-ob-level"=>"0","format"=>"application/jrd+json"];
    private static string $mastodon_public_key        = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAotBC4vg/MqJlrgygFIlJ\nejnPNOwzJQKgRSjfyiOWfcuTRN5jKmj7x3WnWHJlHLXmf8ofcBLhRE3icA5o+Ayd\nhgTbSLnXXeRuzi6t8q4zcQ6p8eY3YG/jMWYD8PhiHR7uFuprCo4l9+GWrjJ6IwQM\nPXMq7jzumKwv5Z/KD7hIwNApceymQ4QOHvMs0+dNCOZOKpyigcxG5KSG8ukO+TjP\npHx34vTy/1Qsv9b7q4dIxqhNjRK/dVLJ8EkuBz3ajac314FJMYIY1TfcakHTtiJA\nhtPhKl3t6r6l14pOpXgaF5EHmNIvnP3BNezZT8Nb2ElVnX31kkJb2Ds0C0Q2Xq34\nJwIDAQAB\n-----END PUBLIC KEY-----\n";

    public function testValidateGtSSignature()
    {
        self::bootKernel();
        $signature_parsed = HTTPSignature::parseSignatureHeader(self::$gotosocial_signature);
        static::assertSame(['keyId' => 'https://goblin.technology/users/tobi/main-key', 'algorithm' => 'hs2019', 'headers' => '(request-target) host date digest', 'signature' => 'kWM36BsRw3Ij4q9BgjPVPOzG2AG87ox91nYsdRoctdlCkYXmevhih2lWVjjlOgMc0OnQrwhUVMAFj2CNiOd5kw38Uo5KcOfY1KC6TCxvDciCJPAMUmvjaMD/Ag6JRaQUh6EB0tvnN2BaWO32i2LP7d0ApRaLj71DhHmSpXsG4pDBl/iauX/YoZew6ohfLAMPCRxPflGn7Uel/Is/yJSYCHyvz43DlmlNb+dMKEa0CVAhvNhg5aGwJ5AiJTg62Yk5ya5PCUJxWn2q87BhS3sbK//AfBQlPf8GUoytO0ACF9vRBwLCH/i6/aup8IXAhjN1GG2IlaAPEV5ROnCIBZo8fg=='], $signature_parsed);
        $path = Router::url('activitypub_inbox', type: Router::ABSOLUTE_PATH);
        [$verified, $signing_string] = HTTPSignature::verify(self::$gotosocial_public_key, $signature_parsed, self::$gotosocial_request_headers, $path, self::$gotosocial_content);
        static::assertSame("(request-target): post /inbox.json\nhost: gnusocial.test.superseriousbusiness.org\ndate: Mon, 24 Oct 2022 14:49:06 GMT\ndigest: SHA-256=gTjVY4ikVc1yn++/IWEmiGge0zy2TBMG++0OzXS2Nw4=", $signing_string);
        static::assertSame(1, $verified);
    }

    public function testValidateMastodonSignature()
    {
        self::bootKernel();
        $signature_parsed = HTTPSignature::parseSignatureHeader(self::$mastodon_signature);
        static::assertSame(['keyId' => 'https://ondergrond.org/users/dumpsterqueer#main-key', 'algorithm' => 'rsa-sha256', 'headers' => '(request-target) host date digest content-type', 'signature' => 'RP9F3wxAq9/VGATr1HfB30B98XNgXcdle2z15QQc0x+k2ioKmwOLlCFKv+J3LdQ2GKIJ4XVBHG2Klzu6FVPLaABiUoBWSqSM1p2hzM760ewIKBZs9fZwmFp+Ec1UT5i4xwLa/EYJZ8ofpc2DkVww58p8FIxcV6gqcmvHMkYooCBogXvsSRSQ0IG3YlFux2um4iD/e9ly5DiU5NtAUMg3tER05MT+gzG6bTMyZwxeJ+svuXF6w6o+BCn8wsxXwMxbDYtjh3f03zeTYdbzEm4eJT5yEQi6XRmgQz59u20LCFOXEtqljP7PymRY+dPb6/xJhlhYLaTOMYZwuAjPSnToEQ=='], $signature_parsed);
        $path = Router::url('activitypub_inbox', type: Router::ABSOLUTE_PATH);
        [$verified, $signing_string] = HTTPSignature::verify(self::$mastodon_public_key, $signature_parsed, self::$mastodon_request_headers, $path, self::$mastodon_content);
        static::assertSame("(request-target): post /inbox.json\nhost: gnusocial.test.superseriousbusiness.org\ndate: Mon, 24 Oct 2022 15:08:50 GMT\ndigest: SHA-256=dDj/+B/FOGAFyTSkrhVjzTmJmUSlebTuU9Pr8XbbAqY=\ncontent-type: application/activity+json", $signing_string);
        // TODO: The following assertion should pass, and it's a mystery to me why it doesn't. I checked the public key, the signature,
        // the digest, base64 encoding, etc, and it all looks fine. Signatures from Mastodon just don't seem to pass. Which is odd because
        // this is the same implementation that Pixelfed uses --
        // https://github.com/pixelfed/pixelfed/blob/dbf314151e83d14648d9c1e16241412997a3f65b/app/Util/ActivityPub/HttpSignature.php
        // When this is resolved by someone cleverer than me, the following line should be uncommented. xoxo tobi
        // static::assertSame(1, $verified);
    }
}
