diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..dd9a2b5 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.{yml,yaml}] +indent_size = 2 diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..9c13f44 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,20 @@ +# Path-based git attributes +# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html + +# Ignore all test and documentation with "export-ignore". +/.github export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/phpunit.xml.dist export-ignore +/art export-ignore +/docs export-ignore +/tests export-ignore +/.editorconfig export-ignore +/.php_cs.dist.php export-ignore +/psalm.xml export-ignore +/psalm.xml.dist export-ignore +/testbench.yaml export-ignore +/UPGRADING.md export-ignore +/CHANGELOG.md export-ignore +/phpstan.neon.dist export-ignore +/phpstan-baseline.neon export-ignore diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml new file mode 100644 index 0000000..fe4cfe6 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -0,0 +1,66 @@ +name: Bug Report +description: Report an Issue or Bug with the Package +title: "[Bug]: " +labels: ["bug"] +body: + - type: markdown + attributes: + value: | + We're sorry to hear you have a problem. Can you help us solve it by providing the following details. + - type: textarea + id: what-happened + attributes: + label: What happened? + description: What did you expect to happen? + placeholder: I cannot currently do X thing because when I do, it breaks X thing. + validations: + required: true + - type: textarea + id: how-to-reproduce + attributes: + label: How to reproduce the bug + description: How did this occur, please add any config values used and provide a set of reliable steps if possible. + placeholder: When I do X I see Y. + validations: + required: true + - type: input + id: package-version + attributes: + label: Package Version + description: What version of our Package are you running? Please be as specific as possible + placeholder: 2.0.0 + validations: + required: true + - type: input + id: php-version + attributes: + label: PHP Version + description: What version of PHP are you running? Please be as specific as possible + placeholder: 8.2.0 + validations: + required: true + - type: input + id: laravel-version + attributes: + label: Laravel Version + description: What version of Laravel are you running? Please be as specific as possible + placeholder: 9.0.0 + validations: + required: true + - type: dropdown + id: operating-systems + attributes: + label: Which operating systems does with happen with? + description: You may select more than one. + multiple: true + options: + - macOS + - Windows + - Linux + - type: textarea + id: notes + attributes: + label: Notes + description: Use this field to provide any other notes that you feel might be relevant to the issue. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..03a94fb --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,11 @@ +blank_issues_enabled: false +contact_links: + - name: Ask a question + url: https://github.com/trovster/laravel-webfinger/discussions/new?category=q-a + about: Ask the community for help + - name: Request a feature + url: https://github.com/trovster/laravel-webfinger/discussions/new?category=ideas + about: Share ideas for new features + - name: Report a security issue + url: https://github.com/trovster/laravel-webfinger/security/policy + about: Learn how to notify us for sensitive bugs diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..30c8a49 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +# Please see the documentation for all configuration options: +# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates + +version: 2 +updates: + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + labels: + - "dependencies" \ No newline at end of file diff --git a/.github/workflows/code-style.yml b/.github/workflows/code-style.yml new file mode 100644 index 0000000..8c42828 --- /dev/null +++ b/.github/workflows/code-style.yml @@ -0,0 +1,74 @@ +name: Code Style & Static Analysis + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + phpstan: + name: Static Analysis + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + coverage: none + tools: composer, phpstan, phpcs + + - name: Install composer dependencies + run: composer install --prefer-dist --no-interaction --no-suggest + + - name: List installed dependencies + run: composer show -D + + - name: Run PHPStan + run: ./vendor/bin/phpstan --error-format=github + + phpcs: + name: PHP Code Style + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + coverage: none + tools: composer, phpcs + + - name: Install composer dependencies + run: composer install --prefer-dist --no-interaction --no-suggest + + - name: List installed dependencies + run: composer show -D + + - name: Run PHP Code Sniffer + run: ./vendor/bin/phpcs -s + + insights: + name: PHP Insights + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: '8.1' + coverage: none + tools: composer + + - name: Install composer dependencies + run: composer install --prefer-dist --no-interaction --no-suggest + + - name: List installed dependencies + run: composer show -D + + - name: Run PHP Insights + run: ./vendor/bin/phpinsights analyse --no-interaction --disable-security-check -n --ansi --format=github-action diff --git a/.github/workflows/dependabot-auto-merge.yml b/.github/workflows/dependabot-auto-merge.yml new file mode 100644 index 0000000..32f7754 --- /dev/null +++ b/.github/workflows/dependabot-auto-merge.yml @@ -0,0 +1,32 @@ +name: dependabot-auto-merge +on: pull_request_target + +permissions: + pull-requests: write + contents: write + +jobs: + dependabot: + runs-on: ubuntu-latest + if: ${{ github.actor == 'dependabot[bot]' }} + steps: + + - name: Dependabot metadata + id: metadata + uses: dependabot/fetch-metadata@v1.3.6 + with: + github-token: "${{ secrets.GITHUB_TOKEN }}" + + - name: Auto-merge Dependabot PRs for semver-minor updates + if: ${{steps.metadata.outputs.update-type == 'version-update:semver-minor'}} + run: gh pr merge --auto --merge "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} + + - name: Auto-merge Dependabot PRs for semver-patch updates + if: ${{steps.metadata.outputs.update-type == 'version-update:semver-patch'}} + run: gh pr merge --auto --merge "$PR_URL" + env: + PR_URL: ${{github.event.pull_request.html_url}} + GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}} diff --git a/.github/workflows/run-tests.yml b/.github/workflows/run-tests.yml new file mode 100644 index 0000000..59eb449 --- /dev/null +++ b/.github/workflows/run-tests.yml @@ -0,0 +1,53 @@ +name: Run Test Suite + +on: + push: + branches: [main] + pull_request: + branches: [main] + +jobs: + test: + runs-on: ${{ matrix.os }} + strategy: + fail-fast: true + matrix: + os: [ubuntu-latest] + php: [8.1, 8.2] + laravel: [9.*, 10.*] + stability: [prefer-lowest, prefer-stable] + include: + - laravel: 9.* + testbench: 7.* + - laravel: 10.* + testbench: 8.* + + name: P${{ matrix.php }} - L${{ matrix.laravel }} - ${{ matrix.stability }} - ${{ matrix.os }} + + steps: + - name: Checkout code + uses: actions/checkout@v3 + + - name: Setup PHP + uses: shivammathur/setup-php@v2 + with: + php-version: ${{ matrix.php }} + extensions: dom, curl, libxml, mbstring, zip, pcntl, pdo, sqlite, pdo_sqlite, bcmath, soap, intl, gd, exif, iconv, imagick, fileinfo + coverage: pcov + tools: composer, phpunit + + - name: Setup problem matchers + run: | + echo "::add-matcher::${{ runner.tool_cache }}/php.json" + echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json" + + - name: Install dependencies + run: | + composer require "laravel/framework:${{ matrix.laravel }}" "orchestra/testbench:${{ matrix.testbench }}" --no-interaction --no-update + composer update --${{ matrix.stability }} --prefer-dist --no-interaction --no-suggest + + - name: List installed dependencies + run: composer show -D + + - name: Run the tests + run: ./vendor/bin/phpunit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..8dec555 --- /dev/null +++ b/.gitignore @@ -0,0 +1,12 @@ +.idea +.phpunit.result.cache +code-analysis +composer.lock +coverage +docs +phpunit.xml +phpstan.neon +testbench.yaml +vendor +node_modules +.DS_Store diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 0000000..977bb14 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,3 @@ +# Changelog + +All notable changes to `laravel-webfinger` will be documented in this file. diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..88e0075 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) trovster + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100644 index 0000000..82baede --- /dev/null +++ b/README.md @@ -0,0 +1,47 @@ +# Create an ActivityPub webfinger + +This creates a webfinger URL which denotes your profile on ActivityPub. + +Once installed you should see your JSON webfinger profile at `/.well-known/webfinger`. + + +## Installation + +You can install the package via composer: + +```bash +composer require surface/laravel-webfinger +``` + +You must add the configuration to your `.env` file: + +```bash +WEBFINGER_INSTANCE=activityPub.instance +WEBFINGER_USERNAME=your-username +``` + +You can publish the config file with: + +```bash +php artisan vendor:publish --provider="Surface\LaravelWebfinger\LaravelWebfingerServiceProvider" +``` + +## Testing + +```bash +composer test +``` + +## Changelog + +Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed +recently. + +## Credits + +- [Trevor Morris](https://github.com/trovster) + +## License + +The MIT License (MIT). Please see [License File](LICENSE.md) for more +information. diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..4252537 --- /dev/null +++ b/composer.json @@ -0,0 +1,76 @@ +{ + "name": "surface/laravel-webfinger", + "description": "A Laravel package to create an ActivityPub webfinger", + "version": "1.0.0", + "keywords": [ + "trovster", + "laravel", + "laravel-webfinger", + "webfinger", + "ActivityPub", + "Mastodon" + ], + "homepage": "https://github.com/trovster/laravel-webfinger", + "license": "MIT", + "authors": [ + { + "name": "Trevor Morris", + "email": "code@trovster.com", + "role": "Developer" + } + ], + "require": { + "php": "^8.1", + "illuminate/contracts": "^9.0|^10.0", + "illuminate/http": "^9.0|^10.0", + "illuminate/support": "^9.0|^10.0" + }, + "require-dev": { + "nunomaduro/collision": "^6.4", + "nunomaduro/larastan": "^2.4", + "nunomaduro/phpinsights": "^2.7", + "orchestra/testbench": "^7.0|^8.0", + "phpro/grumphp": "^1.15", + "phpstan/phpstan": "^1.9", + "phpunit/phpunit": "^9.6", + "slevomat/coding-standard": "^8.8", + "squizlabs/php_codesniffer": "^3.7" + }, + "autoload": { + "psr-4": { + "Surface\\LaravelWebfinger\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Surface\\LaravelWebfinger\\Tests\\": "tests" + } + }, + "scripts": { + "post-autoload-dump": "@php ./vendor/bin/testbench package:discover --ansi", + "post-install-cmd": "@php ./vendor/bin/grumphp git:init", + "grum": "@php ./vendor/bin/grumphp run", + "sniff": "@grum --tasks=phpcs", + "analyse": "@grum --tasks=phpstan", + "insights": "./vendor/bin/phpinsights analyse", + "test": "./vendor/bin/phpunit" + }, + "config": { + "sort-packages": true, + "optimize-autoloader": true, + "allow-plugins": { + "dealerdirect/phpcodesniffer-composer-installer": true, + "phpro/grumphp": true, + "phpstan/extension-installer": true + } + }, + "extra": { + "laravel": { + "providers": [ + "Surface\\LaravelWebfinger\\LaravelWebfingerServiceProvider" + ] + } + }, + "minimum-stability": "dev", + "prefer-stable": true +} diff --git a/config/webfinger.php b/config/webfinger.php new file mode 100644 index 0000000..fa3bbc0 --- /dev/null +++ b/config/webfinger.php @@ -0,0 +1,18 @@ + env('WEBFINGER_INSTANCE', ''), + 'username' => env('WEBFINGER_USERNAME', ''), +]; diff --git a/grumphp.yml b/grumphp.yml new file mode 100644 index 0000000..f9ef4a2 --- /dev/null +++ b/grumphp.yml @@ -0,0 +1,10 @@ +grumphp: + tasks: + phpstan: + phpcs: + phpunit: + composer_script: + script: insights + clover_coverage: + clover_file: ./code-analysis/logs/clover.xml + level: 100 diff --git a/phpcs.xml b/phpcs.xml new file mode 100644 index 0000000..8d728ef --- /dev/null +++ b/phpcs.xml @@ -0,0 +1,40 @@ + + + Code Sniffer, including PSR 12 and Slevomat Coding Standard. + + + config/ + routes/ + src/ + tests/ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/phpinsights.php b/phpinsights.php new file mode 100644 index 0000000..d22a436 --- /dev/null +++ b/phpinsights.php @@ -0,0 +1,153 @@ + 'default', + + /* + |-------------------------------------------------------------------------- + | IDE + |-------------------------------------------------------------------------- + | + | This options allow to add hyperlinks in your terminal to quickly open + | files in your favorite IDE while browsing your PhpInsights report. + | + | Supported: "textmate", "macvim", "emacs", "sublime", "phpstorm", + | "atom", "vscode". + | + | If you have another IDE that is not in this list but which provide an + | url-handler, you could fill this config with a pattern like this: + | + | myide://open?url=file://%f&line=%l + | + */ + + 'ide' => null, + + /* + |-------------------------------------------------------------------------- + | Configuration + |-------------------------------------------------------------------------- + | + | Here you may adjust all the various `Insights` that will be used by PHP + | Insights. You can either add, remove or configure `Insights`. Keep in + | mind, that all added `Insights` must belong to a specific `Metric`. + | + */ + + 'exclude' => [ + 'code-analysis/', + 'vendor/', + ], + + 'add' => [], + + 'remove' => [ + ForbiddenNormalClasses::class, + ], + + 'config' => [ + UnusedParameterSniff::class => [ + 'exclude' => [ + 'src/Http/Resources/Webfinger.php', + ], + ], + + ParameterTypeHintSniff::class => [ + 'exclude' => [ + 'src/Http/Resources/Webfinger.php', + ], + ], + + PropertyTypeHintSniff::class => [ + 'exclude' => [ + 'src/Http/Resources/Webfinger.php', + ], + ], + + ForbiddenPublicPropertySniff::class => [ + 'exclude' => [ + 'src/Http/Resources/Webfinger.php', + ], + ], + + OrderedClassElementsFixer::class => [ + 'order' => [ + 'constant_public', + 'constant_protected', + 'constant_private', + 'property_public', + 'property_protected', + 'property_private', + 'method_abstract', + 'construct', + 'destruct', + 'phpunit', + 'method_public', + 'method_protected', + 'method_private', + 'magic', + ], + ], + + LineLengthSniff::class => [ + 'lineLimit' => 100, + ], + ], + + /* + |-------------------------------------------------------------------------- + | Requirements + |-------------------------------------------------------------------------- + | + | Here you may define a level you want to reach per `Insights` category. + | When a score is lower than the minimum level defined, then an error + | code will be returned. This is optional and individually defined. + | + */ + + 'requirements' => [ + 'min-quality' => 100, + 'min-complexity' => 100, + 'min-architecture' => 100, + 'min-style' => 100, + 'disable-security-check' => false, + ], + + /* + |-------------------------------------------------------------------------- + | Threads + |-------------------------------------------------------------------------- + | + | Here you may adjust how many threads (core) PHPInsights can use to perform + | the analysis. This is optional, don't provide it and the tool will guess + | the max core number available. It accepts null value or integer > 0. + | + */ + + 'threads' => null, + +]; diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon new file mode 100644 index 0000000..bc4b323 --- /dev/null +++ b/phpstan-baseline.neon @@ -0,0 +1,11 @@ +parameters: + ignoreErrors: + - + message: "#^Only iterables can be unpacked, mixed given in argument \\#1\\.$#" + count: 1 + path: src/LaravelWebfingerServiceProvider.php + + - + message: "#^Parameter \\#1 \\$instance of class Surface\\\\LaravelWebfinger\\\\Service\\\\Webfinger constructor expects string, mixed given\\.$#" + count: 1 + path: src/LaravelWebfingerServiceProvider.php diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..d462830 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,17 @@ +includes: + - phpstan-baseline.neon + +parameters: + level: 9 + paths: + - config + - routes + - src + - tests + tmpDir: code-analysis/phpstan + ignoreErrors: + - + message: '#Class PHP_CodeSniffer\\[a-zA-Z0-9\\_]+ not found#' + path: ./phpinsights.php + count: 1 + diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..9ca032e --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,39 @@ + + + + + tests + + + + + ./src + + + + + + + + + + + diff --git a/routes/web.php b/routes/web.php new file mode 100644 index 0000000..8438615 --- /dev/null +++ b/routes/web.php @@ -0,0 +1,11 @@ +group(static function (Router $router): void { + $router->get('/webfinger', WebfingerController::class)->name('webfinger'); +}); diff --git a/src/Http/Controllers/Wellknown/WebfingerController.php b/src/Http/Controllers/Wellknown/WebfingerController.php new file mode 100644 index 0000000..627293d --- /dev/null +++ b/src/Http/Controllers/Wellknown/WebfingerController.php @@ -0,0 +1,23 @@ +service->toArray())->toResponse($request); + } +} diff --git a/src/Http/Resources/Webfinger.php b/src/Http/Resources/Webfinger.php new file mode 100644 index 0000000..619e5ea --- /dev/null +++ b/src/Http/Resources/Webfinger.php @@ -0,0 +1,71 @@ +|string>|string> + */ + public function toArray($request): array + { + return [ + 'subject' => $this->subject($request), + 'aliases' => $this->aliases($request), + 'links' => $this->links($request), + ]; + } + + public function subject(Request $request): string + { + $instanceName = $this->instance->ltrim('https://')->rtrim('/'); + + return "acct:{$this->username}@{$instanceName}"; + } + + /** @return array */ + public function aliases(Request $request): array + { + return [ + "{$this->instance}@{$this->username}", + "{$this->instance}users/{$this->username}", + ]; + } + + /** @return array> */ + public function links(Request $request): array + { + return [ + [ + 'rel' => 'http://webfinger.net/rel/profile-page', + 'type' => 'text/html', + 'href' => "{$this->instance}@{$this->username}", + ], + [ + 'rel' => 'self', + 'type' => 'application/activity+json', + 'href' => "{$this->instance}users/{$this->username}", + ], + [ + 'rel' => 'http://ostatus.org/schema/1.0/subscribe', + 'template' => "{$this->instance}authorize_interaction?uri={uri}", + ], + ]; + } +} diff --git a/src/LaravelWebfingerServiceProvider.php b/src/LaravelWebfingerServiceProvider.php new file mode 100644 index 0000000..156a5b0 --- /dev/null +++ b/src/LaravelWebfingerServiceProvider.php @@ -0,0 +1,41 @@ +bootConfig(); + $this->bootRoutes(); + $this->bindService(); + } + + protected function bootConfig(): void + { + $this->mergeConfigFrom(__DIR__ . '/../config/webfinger.php', 'webfinger'); + + $this->publishes([ + __DIR__ . '/../config/webfinger.php' => config_path('webfinger.php'), + ]); + } + + protected function bootRoutes(): void + { + $this->loadRoutesFrom(__DIR__ . '/../routes/web.php'); + } + + protected function bindService(): void + { + $this->app->bind( + Webfinger::class, + static fn () => new Webfinger(...Config::get('webfinger', [])) + ); + } +} diff --git a/src/Service/Webfinger.php b/src/Service/Webfinger.php new file mode 100755 index 0000000..e991572 --- /dev/null +++ b/src/Service/Webfinger.php @@ -0,0 +1,38 @@ +instance = Str::of($instance)->finish('/')->start('https://'); + $this->username = Str::of($username)->ltrim('@'); + } + + /** @return array */ + public function toArray(): array + { + return [ + 'instance' => $this->instance, + 'username' => $this->username, + ]; + } + + public function __get(string $key): Stringable + { + return $this->{$key}; + } +} diff --git a/tests/Http/Controllers/Wellknown/WebfingerControllerTest.php b/tests/Http/Controllers/Wellknown/WebfingerControllerTest.php new file mode 100644 index 0000000..894d19c --- /dev/null +++ b/tests/Http/Controllers/Wellknown/WebfingerControllerTest.php @@ -0,0 +1,49 @@ +app->make(Request::class); + $this->assertInstanceOf(Request::class, $request); + + $controller = $this->app->make(Controller::class); + $this->assertInstanceOf(Controller::class, $controller); + + $response = $this->app->call($controller, [ + 'request' => $request, + ]); + + $this->assertInstanceOf(JsonResponse::class, $response); + } + + /** @test */ + public function isOk(): void + { + $this->get('/.well-known/webfinger') + ->assertOk() + ->assertJson(static fn (AssertableJson $json): AssertableJson => $json + ->where('subject', 'acct:username@activitypub.instance') + ->hasAll([ + 'subject', + 'aliases' => 2, + 'links' => 3, + ]) + ->whereAllType([ + 'subject' => 'string', + 'aliases' => 'array', + 'links' => 'array', + ])); + } +} diff --git a/tests/Http/Resources/WebfingerTest.php b/tests/Http/Resources/WebfingerTest.php new file mode 100644 index 0000000..a098d0c --- /dev/null +++ b/tests/Http/Resources/WebfingerTest.php @@ -0,0 +1,71 @@ +app->make(Request::class); + $this->assertInstanceOf(Request::class, $request); + + $service = new Service($instance, $username); + + $resource = new Resource($service->instance, $service->username); + $array = $resource->toArray($request); + + $this->assertIsArray($array); + $this->assertArrayHasKey('subject', $array); + $this->assertArrayHasKey('aliases', $array); + $this->assertArrayHasKey('links', $array); + + $this->assertIsString($array['subject']); + $this->assertIsArray($array['aliases']); + $this->assertIsArray($array['links']); + } + + /** + * @test + * @param array $aliases + * @dataProvider resourceProvider + */ + public function resourceSubjectAndAliases(string $instance, string $username, string $subject, array $aliases): void + { + $request = $this->app->make(Request::class); + $this->assertInstanceOf(Request::class, $request); + + $service = new Service($instance, $username); + + $resource = new Resource($service->instance, $service->username); + $array = $resource->toArray($request); + + $this->assertSame($array['subject'], $subject); + $this->assertSame($array['aliases'], $aliases); + } + + /** @return array|string>> */ + public static function resourceProvider(): iterable + { + return [ + yield ['mastodon.social', 'username', 'acct:username@mastodon.social', [ + 'https://mastodon.social/@username', + 'https://mastodon.social/users/username', + ]], + yield ['https://mastodon.social/', '@username', 'acct:username@mastodon.social', [ + 'https://mastodon.social/@username', + 'https://mastodon.social/users/username', + ]], + ]; + } +} diff --git a/tests/Service/WebfingerTest.php b/tests/Service/WebfingerTest.php new file mode 100644 index 0000000..c8885ec --- /dev/null +++ b/tests/Service/WebfingerTest.php @@ -0,0 +1,60 @@ +toArray(); + + $this->assertIsArray($array); + $this->assertArrayHasKey('instance', $array); + $this->assertArrayHasKey('username', $array); + + $this->assertInstanceOf(Stringable::class, $array['instance']); + $this->assertInstanceOf(Stringable::class, $array['username']); + + $this->assertTrue($array['instance']->is($actualInstance)); + $this->assertTrue($array['username']->is($actualUsername)); + } + + /** + * @test + * @dataProvider serviceProvider + */ + public function getter(string $instance, string $username, string $actualInstance, string $actualUsername,): void + { + $service = new Service($instance, $username); + + $this->assertInstanceOf(Stringable::class, $service->instance); + $this->assertInstanceOf(Stringable::class, $service->username); + + $this->assertTrue($service->instance->is($actualInstance)); + $this->assertTrue($service->username->is($actualUsername)); + } + + /** @return array> */ + public static function serviceProvider(): iterable + { + return [ + yield ['mastodon.social', 'username', 'https://mastodon.social/', 'username'], + yield ['https://mastodon.social', 'username', 'https://mastodon.social/', 'username'], + yield ['https://mastodon.social/', 'username', 'https://mastodon.social/', 'username'], + yield ['mastodon.social', '@username', 'https://mastodon.social/', 'username'], + yield ['https://mastodon.social', '@username', 'https://mastodon.social/', 'username'], + yield ['https://mastodon.social/', '@username', 'https://mastodon.social/', 'username'], + ]; + } +} diff --git a/tests/TestCase.php b/tests/TestCase.php new file mode 100644 index 0000000..0918aab --- /dev/null +++ b/tests/TestCase.php @@ -0,0 +1,33 @@ + + */ + protected function getPackageProviders($app): array + { + return [ + LaravelWebfingerServiceProvider::class, + ]; + } +}