Skip to content

Commit

Permalink
ENH PHP 8.1 compatibility
Browse files Browse the repository at this point in the history
  • Loading branch information
emteknetnz committed Apr 13, 2022
1 parent e970aa9 commit 7c4c2fc
Show file tree
Hide file tree
Showing 19 changed files with 51 additions and 46 deletions.
4 changes: 2 additions & 2 deletions src/BackupCode/RegisterHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,14 @@ public function start(StoreInterface $store): array
$method,
array_map(function (BackupCode $backupCode) {
return json_encode($backupCode);
}, $codes)
}, $codes ?? [])
);

// Return un-hashed codes for the front-end UI
return [
'codes' => array_map(function (BackupCode $backupCode) {
return $backupCode->getCode();
}, $codes),
}, $codes ?? []),
];
}

Expand Down
10 changes: 5 additions & 5 deletions src/BackupCode/VerifyHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ public function start(StoreInterface $store, RegisteredMethod $method): array
*/
public function verify(HTTPRequest $request, StoreInterface $store, RegisteredMethod $registeredMethod): Result
{
$bodyJSON = json_decode($request->getBody(), true);
$bodyJSON = json_decode($request->getBody() ?? '', true);

if (!isset($bodyJSON['code'])) {
throw new RuntimeException(
Expand All @@ -69,10 +69,10 @@ public function verify(HTTPRequest $request, StoreInterface $store, RegisteredMe

$code = $bodyJSON['code'];

$candidates = json_decode($registeredMethod->Data, true);
$candidates = json_decode($registeredMethod->Data ?? '', true);

foreach ($candidates as $index => $candidate) {
$candidateData = json_decode($candidate, true) ?? [];
$candidateData = json_decode($candidate ?? '', true) ?? [];
$backupCode = BackupCode::create(
$code,
$candidateData['hash'] ?? '',
Expand All @@ -85,15 +85,15 @@ public function verify(HTTPRequest $request, StoreInterface $store, RegisteredMe


// Remove the verified code from the valid list of codes
array_splice($candidates, $index, 1);
array_splice($candidates, $index ?? 0, 1);
$registeredMethod->Data = json_encode($candidates);
$registeredMethod->write();
$this->notification->send(
$registeredMethod->Member(),
'SilverStripe/MFA/Email/Notification_backupcodeused',
[
'subject' => _t(self::class . '.MFAREMOVED', 'A recovery code was used to access your account'),
'CodesRemaining' => count($candidates),
'CodesRemaining' => count($candidates ?? []),
]
);
return Result::create();
Expand Down
2 changes: 1 addition & 1 deletion src/Extension/MemberExtension.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ public function getRegisteredMethodNames(): string
{
$arr = array_map(function ($method) {
return $method->getMethod()->getName();
}, $this->owner->RegisteredMFAMethods()->toArray());
}, $this->owner->RegisteredMFAMethods()->toArray() ?? []);
return implode(', ', $arr);
}

Expand Down
2 changes: 1 addition & 1 deletion src/Report/EnabledMembers.php
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ public function formatMethodsColumn($_, Member $record): string

return implode(', ', array_map(function (RegisteredMethod $method) {
return $method->getMethod()->getName();
}, $methods->filter('MemberID', $record->ID)->toArray()));
}, $methods->filter('MemberID', $record->ID)->toArray() ?? []));
}

/**
Expand Down
5 changes: 3 additions & 2 deletions src/RequestHandler/VerificationHandlerTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -133,10 +133,11 @@ protected function isVerificationComplete(StoreInterface $store): bool
$successfulMethods = $store->getVerifiedMethods();

// Zero is "not complete". There's different config for optional MFA
if (!is_array($successfulMethods) || !count($successfulMethods)) {
if (!is_array($successfulMethods) || !count($successfulMethods ?? [])) {
return false;
}

return count($successfulMethods) >= Config::inst()->get(EnforcementManager::class, 'required_mfa_methods');
$requiredMethods = Config::inst()->get(EnforcementManager::class, 'required_mfa_methods');
return count($successfulMethods ?? []) >= $requiredMethods;
}
}
10 changes: 5 additions & 5 deletions src/Service/BackupCodeGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,10 +46,10 @@ public function generate(): array
$charset = $this->getCharacterSet();

$codes = [];
while (count($codes) < $codeCount) {
while (count($codes ?? []) < $codeCount) {
$code = $this->generateCode($charset, $codeLength);

if (!in_array($code, $codes)) {
if (!in_array($code, $codes ?? [])) {
$hashData = Security::encrypt_password($code);
$codes[] = BackupCode::create($code, $hashData['password'], $hashData['algorithm'], $hashData['salt']);
}
Expand Down Expand Up @@ -77,11 +77,11 @@ public function getCharacterSet(): array
protected function generateCode(array $charset, int $codeLength): string
{
$characters = [];
$numberOfOptions = count($charset);
while (count($characters) < $codeLength) {
$numberOfOptions = count($charset ?? []);
while (count($characters ?? []) < $codeLength) {
$key = random_int(0, $numberOfOptions - 1); // zero based array
$characters[] = $charset[$key];
}
return implode($characters);
return implode($characters ?? '');
}
}
2 changes: 1 addition & 1 deletion src/Service/EnforcementManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ protected function isEnabled(): bool
$methodRegistry = MethodRegistry::singleton();
$methods = $methodRegistry->getMethods();
// If there are no methods available excluding backup codes, do not redirect
if (!count($methods) || (count($methods) === 1 && $methodRegistry->getBackupMethod() !== null)) {
if (!count($methods ?? []) || (count($methods ?? []) === 1 && $methodRegistry->getBackupMethod() !== null)) {
return false;
}

Expand Down
16 changes: 8 additions & 8 deletions src/Service/MethodRegistry.php
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ public function getMethods(): array
}

$configuredMethods = (array) $this->config()->get('methods');
$configuredMethods = array_filter($configuredMethods);
$configuredMethods = array_filter($configuredMethods ?? []);
$this->ensureNoDuplicateMethods($configuredMethods);

$allMethods = [];
Expand Down Expand Up @@ -89,7 +89,7 @@ public function getMethods(): array
*/
public function hasMethods(): bool
{
return count($this->getMethods()) > 0;
return count($this->getMethods() ?? []) > 0;
}

/**
Expand All @@ -101,7 +101,7 @@ public function hasMethods(): bool
public function isBackupMethod(MethodInterface $method): bool
{
$configuredBackupMethod = $this->config()->get('default_backup_method');
return is_string($configuredBackupMethod) && is_a($method, $configuredBackupMethod);
return is_string($configuredBackupMethod) && is_a($method, $configuredBackupMethod ?? '');
}

/**
Expand Down Expand Up @@ -145,14 +145,14 @@ public function getMethodByURLSegment(string $segment): ?MethodInterface
*/
private function ensureNoDuplicateMethods(array $configuredMethods): void
{
$uniqueMethods = array_unique($configuredMethods);
$uniqueMethods = array_unique($configuredMethods ?? []);
if ($uniqueMethods === $configuredMethods) {
return;
}

// Get the method class names that were added more than once and format them into a string so we can
// tell the developer which classes were incorrectly configured
$duplicates = array_unique(array_diff_key($configuredMethods, $uniqueMethods));
$duplicates = array_unique(array_diff_key($configuredMethods ?? [], $uniqueMethods));
$methodNames = implode('; ', $duplicates);
throw new UnexpectedValueException(
'Cannot register MFA methods more than once. Check your config: ' . $methodNames
Expand All @@ -169,15 +169,15 @@ private function ensureNoDuplicateURLSegments(array $allMethods): void
{
$allURLSegments = array_map(function (MethodInterface $method) {
return $method->getURLSegment();
}, $allMethods);
$uniqueURLSegments = array_unique($allURLSegments);
}, $allMethods ?? []);
$uniqueURLSegments = array_unique($allURLSegments ?? []);
if ($allURLSegments === $uniqueURLSegments) {
return;
}

// Get the method URL segments that were added more than once and format them into a string so we can
// tell the developer which classes were incorrectly configured
$duplicates = array_unique(array_diff_key($allURLSegments, $uniqueURLSegments));
$duplicates = array_unique(array_diff_key($allURLSegments ?? [], $uniqueURLSegments));
$urlSegments = implode('; ', $duplicates);
throw new UnexpectedValueException(
'Cannot register multiple MFA methods with the same URL segment: ' . $urlSegments
Expand Down
2 changes: 1 addition & 1 deletion src/Service/Notification.php
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ public function send(Member $member, string $template, array $data = []): bool

foreach (['to', 'from', 'subject'] as $header) {
if (isset($data[$header])) {
$method = 'set' . ucwords($header);
$method = 'set' . ucwords($header ?? '');
$email->$method($data[$header]);
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/Service/SchemaGenerator.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ public function getSchema(Member $member)
// Skip registration details if the user has already registered this method
$exclude = array_map(function (RegisteredMethodDetailsInterface $methodDetails) {
return $methodDetails->jsonSerialize()['urlSegment'];
}, $registeredMethods);
}, $registeredMethods ?? []);

// Also skip the backup method
$backupMethod = MethodRegistry::singleton()->getBackupMethod();
Expand Down Expand Up @@ -80,7 +80,7 @@ public function getAvailableMethods(array $exclude = [])
// Compile details for methods that aren't already registered to the user
foreach ($allMethods as $method) {
// Omit specified exclusions or methods that are configured as back-up methods
if (in_array($method->getURLSegment(), $exclude)) {
if (in_array($method->getURLSegment(), $exclude ?? [])) {
continue;
}
$availableMethods[] = Injector::inst()->create(AvailableMethodDetailsInterface::class, $method);
Expand Down
6 changes: 3 additions & 3 deletions src/Store/SessionStore.php
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public function getMethod(): ?string
*/
public function setMethod(?string $method): StoreInterface
{
if (in_array($method, $this->getVerifiedMethods())) {
if (in_array($method, $this->getVerifiedMethods() ?? [])) {
throw new InvalidMethodException('You cannot verify with a method you have already verified');
}

Expand Down Expand Up @@ -144,7 +144,7 @@ public function addState(array $state): StoreInterface

public function addVerifiedMethod(string $method): StoreInterface
{
if (!in_array($method, $this->verifiedMethods)) {
if (!in_array($method, $this->verifiedMethods ?? [])) {
$this->verifiedMethods[] = $method;
}

Expand Down Expand Up @@ -228,7 +228,7 @@ public function serialize(): string

public function unserialize($serialized): void
{
$state = json_decode($serialized, true);
$state = json_decode($serialized ?? '', true);

if (is_array($state) && $state['member']) {
$this->memberID = $state['member'];
Expand Down
2 changes: 1 addition & 1 deletion tests/php/Authenticator/ChangePasswordHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ public function testGetSchema()
$response = $this->get('Security/changepassword/mfa/schema');

$this->assertSame('application/json', $response->getHeader('Content-Type'));
$schema = json_decode($response->getBody(), true);
$schema = json_decode($response->getBody() ?? '', true);

$this->assertArrayHasKey('endpoints', $schema);
$this->assertArrayHasKey('verify', $schema['endpoints']);
Expand Down
8 changes: 4 additions & 4 deletions tests/php/Authenticator/LoginHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ public function testMFASchemaEndpointReturnsMethodDetails()

$result = $this->get(Controller::join_links(Security::login_url(), 'default/mfa/schema'));

$response = json_decode($result->getBody(), true);
$response = json_decode($result->getBody() ?? '', true);

$this->assertArrayHasKey('registeredMethods', $response);
$this->assertArrayHasKey('availableMethods', $response);
Expand Down Expand Up @@ -164,7 +164,7 @@ public function testMFASchemaEndpointShowsRegisteredMethodsIfSetUp()

$result = $this->get(Controller::join_links(Security::login_url(), 'default/mfa/schema'));

$response = json_decode($result->getBody(), true);
$response = json_decode($result->getBody() ?? '', true);

$this->assertArrayHasKey('registeredMethods', $response);
$this->assertArrayHasKey('availableMethods', $response);
Expand Down Expand Up @@ -194,7 +194,7 @@ public function testMFASchemaEndpointProvidesDefaultMethodIfSet()

$result = $this->get(Controller::join_links(Security::login_url(), 'default/mfa/schema'));

$response = json_decode($result->getBody(), true);
$response = json_decode($result->getBody() ?? '', true);

$this->assertArrayHasKey('registeredMethods', $response);
$this->assertArrayHasKey('availableMethods', $response);
Expand Down Expand Up @@ -331,7 +331,7 @@ public function testStartVerificationIncludesACSRFToken()
$request = new HTTPRequest('GET', '/');
$request->setSession(new Session([]));
$request->setRouteParams(['Method' => 'basic-math']);
$response = json_decode($handler->startVerification($request)->getBody());
$response = json_decode($handler->startVerification($request)->getBody() ?? '');

$this->assertNotNull($response->SecurityID);
$this->assertTrue(SecurityToken::inst()->check($response->SecurityID));
Expand Down
10 changes: 7 additions & 3 deletions tests/php/BackupCode/RegisterHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ public function testStartReturnsPlainTextCodes()
$props = $handler->start($store);

$this->assertArrayHasKey('codes', $props, 'Codes are returned from the start method');
$this->assertGreaterThan(0, count($props['codes']), 'At least one code is provided');
$this->assertGreaterThan(0, count($props['codes'] ?? []), 'At least one code is provided');
}

public function testStartStoresHashesOfBackupCodesOnMember()
Expand Down Expand Up @@ -81,9 +81,13 @@ public function testStartStoresHashesOfBackupCodesOnMember()
$this->assertJson($registeredMethod->Data, 'Backup codes are stored as valid JSON');

// Parse the stored codes on the member to compare with what was given to the UI
$storedCodes = json_decode($registeredMethod->Data, true);
$storedCodes = json_decode($registeredMethod->Data ?? '', true);

$this->assertCount(count($codes), $storedCodes, 'Stored code count matches that of those returned to the UI');
$this->assertCount(
count($codes ?? []),
$storedCodes,
'Stored code count matches that of those returned to the UI'
);

foreach ($codes as $code) {
$this->assertNotContains($code, $storedCodes, 'Codes returned to UI are plaintext (different from stored)');
Expand Down
2 changes: 1 addition & 1 deletion tests/php/BackupCode/VerifyHandlerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function testVerifyInvalidatesCodesThatHaveBeenUsed()
$this->assertTrue($handler->verify($request, $store, $method)->isSuccessful());

$method = DataObject::get_by_id(RegisteredMethod::class, $method->ID);
$codes = json_decode($method->Data, true);
$codes = json_decode($method->Data ?? '', true);

$this->assertCount(3, $codes, 'Only 3 codes remain against the method');

Expand Down
2 changes: 1 addition & 1 deletion tests/php/Service/BackupCodeGeneratorTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ public function testGenerate()
foreach ($result as $backupCode) {
$this->assertSame(
6,
strlen($backupCode->getCode()),
strlen($backupCode->getCode() ?? ''),
'Generated codes are of configured length'
);
}
Expand Down
2 changes: 1 addition & 1 deletion tests/php/Service/RegisteredMethodManagerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public function testRegisterForMemberWritesToExistingRegisteredMethod()
RegisteredMethodManager::singleton()->registerForMember($member, $method, ['foo' => 'bar']);

$this->assertCount(1, $member->RegisteredMFAMethods());
$this->assertSame(['foo' => 'bar'], json_decode($member->RegisteredMFAMethods()->first()->Data, true));
$this->assertSame(['foo' => 'bar'], json_decode($member->RegisteredMFAMethods()->first()->Data ?? '', true));
}

public function testRegisterForMemberCreatesNewMethod()
Expand Down
4 changes: 2 additions & 2 deletions tests/php/Stub/BasicMath/MethodRegisterHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,9 @@ public function start(StoreInterface $store): array
*/
public function register(HTTPRequest $request, StoreInterface $store): Result
{
$parameters = json_decode($request->getBody(), true);
$parameters = json_decode($request->getBody() ?? '', true);

if (!array_key_exists('number', $parameters)) {
if (!array_key_exists('number', $parameters ?? [])) {
return Result::create(false, 'The required user input was not provided to register this method');
}

Expand Down
4 changes: 2 additions & 2 deletions tests/php/Stub/BasicMath/MethodVerifyHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ public function start(StoreInterface $store, RegisteredMethod $registeredMethod)
}

$store->setState([
'answer' => array_sum($numbers),
'answer' => array_sum($numbers ?? []),
]);

return [
Expand All @@ -57,7 +57,7 @@ public function start(StoreInterface $store, RegisteredMethod $registeredMethod)
*/
public function verify(HTTPRequest $request, StoreInterface $store, RegisteredMethod $registeredMethod): Result
{
$body = json_decode($request->getBody(), true);
$body = json_decode($request->getBody() ?? '', true);

if (!$body['answer']) {
return Result::create(false, 'Answer was missing');
Expand Down

0 comments on commit 7c4c2fc

Please sign in to comment.