diff --git a/src/app/Traits/UserConfigTrait.php b/src/app/Traits/UserConfigTrait.php --- a/src/app/Traits/UserConfigTrait.php +++ b/src/app/Traits/UserConfigTrait.php @@ -47,24 +47,11 @@ } elseif ($key == 'guam_enabled') { $this->setSetting($key, $value ? 'true' : null); } elseif ($key == 'limit_geo') { - if (!is_array($value)) { - $errors[$key] = \trans('validation.invalid-limit-geo'); + if ($error = $this->validateLimitGeo($value)) { + $errors[$key] = $error; continue; } - foreach ($value as $idx => $country) { - if (!preg_match('/^[a-zA-Z]{2}$/', $country)) { - $errors[$key] = \trans('validation.invalid-limit-geo'); - continue 2; - } - - $value[$idx] = \strtoupper($country); - } - - if (count($value) > 250) { - $errors[$key] = \trans('validation.invalid-limit-geo'); - } - $this->setSetting($key, !empty($value) ? json_encode($value) : null); } elseif ($key == 'max_password_age') { $this->setSetting($key, intval($value) > 0 ? ((string) intval($value)) : null); @@ -140,4 +127,39 @@ return null; } + + /** + * Validates limit_geo value + * + * @param mixed $value Geo-lock input + * + * @return ?string An error message on error, Null otherwise + */ + protected function validateLimitGeo(&$value): ?string + { + if (!is_array($value)) { + return \trans('validation.invalid-limit-geo'); + } + + foreach ($value as $idx => $country) { + if (!preg_match('/^[a-zA-Z]{2}$/', $country)) { + return \trans('validation.invalid-limit-geo'); + } + + $value[$idx] = \strtoupper($country); + } + + if (count($value) > 250) { + return \trans('validation.invalid-limit-geo'); + } elseif (count($value)) { + // There MUST be country of the current connection included + $currentCountry = \App\Utils::countryForRequest(); + + if (!in_array($currentCountry, $value)) { + return \trans('validation.invalid-limit-geo-missing-current', ['code' => $currentCountry]); + } + } + + return null; + } } diff --git a/src/resources/lang/en/validation.php b/src/resources/lang/en/validation.php --- a/src/resources/lang/en/validation.php +++ b/src/resources/lang/en/validation.php @@ -169,6 +169,7 @@ 'nameinvalid' => 'The specified name is invalid.', 'password-policy-error' => 'Specified password does not comply with the policy.', 'invalid-limit-geo' => 'Specified configuration is invalid. Expected a list of two-letter country codes.', + 'invalid-limit-geo-missing-current' => 'Specified configuration is invalid. Missing country of the current connection (:code).', 'invalid-password-policy' => 'Specified password policy is invalid.', 'password-policy-min-len-error' => 'Minimum password length cannot be less than :min.', 'password-policy-max-len-error' => 'Maximum password length cannot be more than :max.', diff --git a/src/tests/Browser/UsersTest.php b/src/tests/Browser/UsersTest.php --- a/src/tests/Browser/UsersTest.php +++ b/src/tests/Browser/UsersTest.php @@ -444,14 +444,14 @@ ->assertSeeIn('div.row:nth-child(3) label', 'Geo-lockin') ->with(new CountrySelect('#limit_geo'), function ($browser) { $browser->assertCountries([]) - ->setCountries(['DE', 'PL']) - ->assertCountries(['DE', 'PL']); + ->setCountries(['CH', 'PL']) + ->assertCountries(['CH', 'PL']); }) ->click('div.row:nth-child(2) input') ->click('button[type=submit]') ->assertToast(Toast::TYPE_SUCCESS, 'User settings updated successfully.'); - $this->assertSame('["DE","PL"]', $john->getSetting('limit_geo')); + $this->assertSame('["CH","PL"]', $john->getSetting('limit_geo')); $this->assertSame('true', $john->getSetting('guam_enabled')); $browser diff --git a/src/tests/Feature/UserTest.php b/src/tests/Feature/UserTest.php --- a/src/tests/Feature/UserTest.php +++ b/src/tests/Feature/UserTest.php @@ -618,9 +618,14 @@ $result = $user->setConfig(['limit_geo' => ['US', 'ru']]); + $err = 'Specified configuration is invalid. Missing country of the current connection (CH).'; + $this->assertSame(['limit_geo' => $err], $result); + + $result = $user->setConfig(['limit_geo' => ['US', 'ch']]); + $this->assertSame([], $result); - $this->assertSame(['US', 'RU'], $user->getConfig()['limit_geo']); - $this->assertSame('["US","RU"]', $user->getSetting('limit_geo')); + $this->assertSame(['US', 'CH'], $user->getConfig()['limit_geo']); + $this->assertSame('["US","CH"]', $user->getSetting('limit_geo')); } /**