diff --git a/app/Http/Controllers/Api/ApiV1Dot1Controller.php b/app/Http/Controllers/Api/ApiV1Dot1Controller.php index 59fb1c93e..dc34594e5 100644 --- a/app/Http/Controllers/Api/ApiV1Dot1Controller.php +++ b/app/Http/Controllers/Api/ApiV1Dot1Controller.php @@ -945,4 +945,64 @@ class ApiV1Dot1Controller extends Controller return $this->json($res); } + + public function accountUsernameToId(Request $request, $username) + { + abort_if(! $request->user() || ! $request->user()->token() || ! $username, 403); + abort_unless($request->user()->tokenCan('read'), 403); + + $rateLimiting = (bool) config_cache('api.rate-limits.v1Dot1.accounts.usernameToId.enabled'); + $ipRateLimiting = (bool) config_cache('api.rate-limits.v1Dot1.accounts.usernameToId.ip_enabled'); + if ($ipRateLimiting) { + $userLimit = (int) config_cache('api.rate-limits.v1Dot1.accounts.usernameToId.ip_limit'); + $userDecay = (int) config_cache('api.rate-limits.v1Dot1.accounts.usernameToId.ip_decay'); + $userKey = 'pf:apiv1.1:acctU2ID:byIp:'.$request->ip(); + + if (RateLimiter::tooManyAttempts($userKey, $userLimit)) { + $limits = [ + 'X-Rate-Limit-Limit' => $userLimit, + 'X-Rate-Limit-Remaining' => RateLimiter::remaining($userKey, $userLimit), + 'X-Rate-Limit-Reset' => RateLimiter::availableIn($userKey), + ]; + + return $this->json(['error' => 'Too many attempts!'], 429, $limits); + } + + RateLimiter::increment($userKey, $userDecay); + $limits = [ + 'X-Rate-Limit-Limit' => $userLimit, + 'X-Rate-Limit-Remaining' => RateLimiter::remaining($userKey, $userLimit), + 'X-Rate-Limit-Reset' => RateLimiter::availableIn($userKey), + ]; + } + if ($rateLimiting) { + $userLimit = (int) config_cache('api.rate-limits.v1Dot1.accounts.usernameToId.limit'); + $userDecay = (int) config_cache('api.rate-limits.v1Dot1.accounts.usernameToId.decay'); + $userKey = 'pf:apiv1.1:acctU2ID:byUid:'.$request->user()->id; + + if (RateLimiter::tooManyAttempts($userKey, $userLimit)) { + $limits = [ + 'X-Rate-Limit-Limit' => $userLimit, + 'X-Rate-Limit-Remaining' => RateLimiter::remaining($userKey, $userLimit), + 'X-Rate-Limit-Reset' => RateLimiter::availableIn($userKey), + ]; + + return $this->json(['error' => 'Too many attempts!'], 429, $limits); + } + + RateLimiter::increment($userKey, $userDecay); + $limits = [ + 'X-Rate-Limit-Limit' => $userLimit, + 'X-Rate-Limit-Remaining' => RateLimiter::remaining($userKey, $userLimit), + 'X-Rate-Limit-Reset' => RateLimiter::availableIn($userKey), + ]; + } + $accountId = AccountService::usernameToId($username, true); + if (! $accountId) { + return []; + } + $account = AccountService::get($accountId); + + return $this->json($account, 200, $rateLimiting ? $limits : []); + } } diff --git a/app/Http/Controllers/Api/ApiV2Controller.php b/app/Http/Controllers/Api/ApiV2Controller.php index ebdc851b8..9a46791ad 100644 --- a/app/Http/Controllers/Api/ApiV2Controller.php +++ b/app/Http/Controllers/Api/ApiV2Controller.php @@ -8,6 +8,7 @@ use App\Media; use App\UserSetting; use App\User; use Illuminate\Support\Facades\Cache; +use Illuminate\Support\Facades\Storage; use App\Services\AccountService; use App\Services\BouncerService; use App\Services\InstanceService; diff --git a/config/api.php b/config/api.php new file mode 100644 index 000000000..13003bc26 --- /dev/null +++ b/config/api.php @@ -0,0 +1,18 @@ + [ + 'v1Dot1' => [ + 'accounts' => [ + 'usernameToId' => [ + 'enabled' => env('PF_API_RL_V1DOT1_ACCT_U2ID_ENABLED', true), + 'limit' => env('PF_API_RL_V1DOT1_ACCT_U2ID_LIMIT', 30), + 'decay' => env('PF_API_RL_V1DOT1_ACCT_U2ID_DECAY', 120), + 'ip_enabled' => env('PF_API_RL_V1DOT1_ACCT_U2ID_BY_IP_ENABLED', false), + 'ip_limit' => env('PF_API_RL_V1DOT1_ACCT_U2ID_BY_IP_LIMIT', 30), + 'ip_decay' => env('PF_API_RL_V1DOT1_ACCT_U2ID_BY_IP_DECAY', 120), + ] + ] + ] + ] +]; diff --git a/routes/api.php b/routes/api.php index 7cee24869..9e4ced78c 100644 --- a/routes/api.php +++ b/routes/api.php @@ -124,6 +124,7 @@ Route::group(['prefix' => 'api'], function() use($middleware) { Route::get('emails-from-pixelfed', 'Api\ApiV1Dot1Controller@accountEmailsFromPixelfed')->middleware($middleware); Route::get('apps-and-applications', 'Api\ApiV1Dot1Controller@accountApps')->middleware($middleware); Route::get('mutuals/{id}', 'Api\ApiV1Dot1Controller@getMutualAccounts')->middleware($middleware); + Route::get('username/{username}', 'Api\ApiV1Dot1Controller@accountUsernameToId')->middleware($middleware); }); Route::group(['prefix' => 'collections'], function () use($middleware) {