Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make API token optional for user api routes #159

Merged
merged 7 commits into from
Feb 6, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,6 @@ MAILGUN_ENDPOINT=api.mailgun.net
MAILGUN_SECRET=

# AspirePress Related Configuration
API_AUTHENTICATION_ENABLED=true
DOWNLOAD_BASE=https://api.aspiredev.org/download/
# DOWNLOAD_BASE=https://fastly.api.aspiredev.org/download/
DOWNLOAD_CACHE_SECONDS=864000
21 changes: 21 additions & 0 deletions app/Http/Middleware/AuthOptional.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?php

declare(strict_types=1);

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpKernel\Exception\UnauthorizedHttpException;

class AuthOptional
{
public function handle(Request $request, Closure $next, string $gate)
{
if ($request->bearerToken()) {
$user = auth($gate)->user() or throw new UnauthorizedHttpException('Invalid authentication token');
auth($gate)->setUser($user);
}
return $next($request);
}
}
4 changes: 3 additions & 1 deletion bootstrap/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,13 @@
// CacheApiResponse::class // replaced with laravels cache.headers in api.php
]);

// https://spatie.be/docs/laravel-permission/v6/basic-usage/middleware
$middleware->alias([
// https://spatie.be/docs/laravel-permission/v6/basic-usage/middleware
'role' => \Spatie\Permission\Middleware\RoleMiddleware::class,
'permission' => \Spatie\Permission\Middleware\PermissionMiddleware::class,
'role_or_permission' => \Spatie\Permission\Middleware\RoleOrPermissionMiddleware::class,

'auth.optional' => App\Http\Middleware\AuthOptional::class,
]);

})
Expand Down
1 change: 0 additions & 1 deletion config/app.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
//// AspirePress Configuration

'aspirecloud' => [
'api_authentication_enable' => env('API_AUTHENTICATION_ENABLED', false),
'download' => [
'base' => env('DOWNLOAD_BASE', env('APP_URL') . '/download/'), # must have a trailing slash!
'cache_seconds' => env('DOWNLOAD_CACHE_SECONDS', 60 * 60 * 24 * 10),
Expand Down
4 changes: 2 additions & 2 deletions docker/cli/php.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ upload_max_filesize = 20M
max_file_uploads = 20


error_reporting = E_ALL
; error_reporting = E_ALL & ~E_DEPRECATED
; error_reporting = E_ALL
error_reporting = E_ALL & ~E_DEPRECATED

display_errors = Off
display_startup_errors = Off
Expand Down
4 changes: 2 additions & 2 deletions docker/webapp/php.ini
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ upload_max_filesize = 20M
max_file_uploads = 20


error_reporting = E_ALL
; error_reporting = E_ALL & ~E_DEPRECATED
; error_reporting = E_ALL
error_reporting = E_ALL & ~E_DEPRECATED

display_errors = Off
display_startup_errors = Off
Expand Down
22 changes: 9 additions & 13 deletions routes/api.php
Original file line number Diff line number Diff line change
Expand Up @@ -15,18 +15,12 @@

// https://codex.wordpress.org/WordPress.org_API

$middlewares = [
NormalizeWpOrgRequest::class,
'cache.headers:public;max_age=300,etag', // for the CDN's benefit: the WP user agent does not cache at all.
];
$routeDefinition = Route::prefix('/');

if (config('app.aspirecloud.api_authentication_enable')) {
$middlewares[] = 'auth:sanctum';
}

$routeDefinition
->middleware($middlewares)
Route::prefix('/')
->middleware([
'auth.optional:sanctum',
NormalizeWpOrgRequest::class,
'cache.headers:public;s_maxage=300,etag', // for the CDN's benefit: the WP user agent does not cache at all.
])
->group(function (Router $router) {
$router->get('/secret-key/{version}', [SecretKeyController::class, 'index'])->where(['version' => '1.[01]']);
$router->get('/secret-key/{version}/salt', [SecretKeyController::class, 'salt'])->where(['version' => '1.1']);
Expand All @@ -52,7 +46,9 @@
$router->get('/translations/themes/{version}', CatchAllController::class)->where(['version' => '1.0']);

$router->get('/themes/info/{version}', [ThemeController::class, 'info'])->where(['version' => '1.[012]']);
$router->match(['get', 'post'], '/themes/update-check/{version}', ThemeUpdatesController::class)->where(['version' => '1.[01]']);
$router->match(['get', 'post'], '/themes/update-check/{version}', ThemeUpdatesController::class)->where(
['version' => '1.[01]'],
);

$router->get('/plugins/info/1.2', PluginInformation_1_2_Controller::class);
$router->get('/plugins/info/{version}', CatchAllController::class)->where(['version' => '1.[01]']);
Expand Down
3 changes: 0 additions & 3 deletions routes/inc/download.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,9 @@
use Illuminate\Routing\Router;
use Illuminate\Support\Facades\Route;

// downloads can never require api keys, they're fetched by ordinary browser UI and by WP in places we don't hook.
// $auth_middleware = config('app.aspirecloud.api_authentication_enable') ? ['auth:sanctum'] : [];
$cache_seconds = config('app.aspirecloud.download.cache_seconds');
$middleware = [
"cache.headers:public;max_age=$cache_seconds", // we're streaming responses, so no etags
// ...$auth_middleware,
];

Route::prefix('/')
Expand Down
9 changes: 0 additions & 9 deletions routes/web.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,6 @@
use Illuminate\Support\Facades\Route;
use Inertia\Inertia;

// Route::get('/', function () {
// return Inertia::render('Welcome', [
// 'canLogin' => Route::has('login'),
// 'canRegister' => Route::has('register'),
// 'laravelVersion' => Application::VERSION,
// 'phpVersion' => PHP_VERSION,
// ]);
// });

Route::view('/', 'home');

Route::middleware([
Expand Down
14 changes: 8 additions & 6 deletions tests/Feature/API/WpOrg/ApiAuthenticationTest.php
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
<?php

it('should return 401 if the API authentication is enable', function () {
it('should return 200 when no auth token is present', function () {
$response = $this->getjson('/plugins/info/1.1?action=query_plugins');
$response->assertStatus(200);
});

it('should return 401 when an invalid auth token is present', function () {
$response = $this->getjson('/plugins/info/1.1?action=query_plugins', ['Authorization' => 'Bearer invalid-token']);
$response->assertStatus(401);
})->skip(fn() => !config('app.aspirecloud.api_authentication_enable'), 'API authentication is disabled');
});

it('should return 200 if the API authentication is disable', function () {
$response = $this->getjson('/plugins/info/1.1?action=query_plugins');
$response->assertStatus(200);
})->skip(fn() => config('app.aspirecloud.api_authentication_enable'), 'API authentication is enabled');
// TODO: write tests for real and and bad auth tokens
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
// TODO: write tests for real and and bad auth tokens
// TODO: write tests for real and bad auth tokens

Double "and". Possibly jittery from too much coffee 😉

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

☕️☕️☕️ + 🌲🌲 = 😳

Anyway I already tested a bad token so I just need to generate and use a real one, and hopefully I'll have that knocked out before I merge this (it's already getting deployed to .io before then)

22 changes: 6 additions & 16 deletions tests/Helpers/requests.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,29 +5,19 @@
use App\Models\User;
use Illuminate\Support\Str;

/**
* Helper function to make an authenticated request or not
* based on the configuration.
* @param mixed $method
* @param mixed $uri
* @param mixed $data
* @param mixed $headers
*/
function makeApiRequest($method, $uri, $data = [], $headers = [])

function makeApiRequest(string $method, string $uri, array $data = [], array $headers = [])
{
$isAuthEnabled = config('app.aspirecloud.api_authentication_enable');
$testCase = test();
$testCase = test();

if ($isAuthEnabled) {
$user = User::factory()->create();
$testCase = $testCase->actingAs($user);
}
$user = User::factory()->create();
$testCase = $testCase->actingAs($user);

if (Str::lower($method) === 'post') {
return $testCase->post($uri, $data, $headers);
}

// sent the header on get request too
// XXX shouldn't we be setting headers unconditionally?
if (!empty($headers)) {
return $testCase->withHeaders($headers)->get($uri);
}
Expand Down
Loading