<?php
/**
- * @copyright Copyright (C) 2020, Friendica
+ * @copyright Copyright (C) 2010-2021, the Friendica project
*
* @license GNU AGPL version 3 or any later version
*
use Friendica\DI;
use Friendica\Model\User;
use Friendica\Network\HTTPException;
-use Friendica\Repository\TwoFactor\TrustedBrowser;
+use Friendica\Security\TwoFactor\Repository\TrustedBrowser;
use Friendica\Util\DateTimeFormat;
use Friendica\Util\Network;
use Friendica\Util\Strings;
use LightOpenID;
use Friendica\Core\L10n;
+use Friendica\Core\Logger;
use Psr\Log\LoggerInterface;
/**
{
$record = null;
- $addon_auth = [
- 'username' => $username,
- 'password' => $password,
- 'authenticated' => 0,
- 'user_record' => null
- ];
-
- /*
- * An addon indicates successful login by setting 'authenticated' to non-zero value and returning a user record
- * Addons should never set 'authenticated' except to indicate success - as hooks may be chained
- * and later addons should not interfere with an earlier one that succeeded.
- */
- Hook::callAll('authenticate', $addon_auth);
-
try {
- if ($addon_auth['authenticated']) {
- $record = $addon_auth['user_record'];
-
- if (empty($record)) {
- throw new Exception($this->l10n->t('Login failed.'));
- }
- } else {
- $record = $this->dba->selectFirst(
- 'user',
- [],
- ['uid' => User::getIdFromPasswordAuthentication($username, $password)]
- );
- }
+ $record = $this->dba->selectFirst(
+ 'user',
+ [],
+ ['uid' => User::getIdFromPasswordAuthentication($username, $password)]
+ );
} catch (Exception $e) {
$this->logger->warning('authenticate: failed login attempt', ['action' => 'login', 'username' => Strings::escapeTags($username), 'ip' => $_SERVER['REMOTE_ADDR']]);
notice($this->l10n->t('Login failed. Please check your credentials.'));
$this->dba->update('user', ['login_date' => DateTimeFormat::utcNow()], ['uid' => $user_record['uid']]);
// Set the login date for all identities of the user
- $this->dba->update('user', ['login_date' => DateTimeFormat::utcNow()],
- ['parent-uid' => $masterUid, 'account_removed' => false]);
+ if (!empty($masterUid)) {
+ $this->dba->update('user', ['login_date' => DateTimeFormat::utcNow()],
+ ['parent-uid' => $masterUid, 'account_removed' => false]);
+ }
}
if ($login_initial) {
return;
}
- // Case 1: 2FA session present and valid: return
+ // Case 1a: 2FA session already present: return
if ($this->session->get('2fa')) {
return;
}
+ // Case 1b: Check for trusted browser
+ if ($this->cookie->get('trusted')) {
+ // Retrieve a trusted_browser model based on cookie hash
+ $trustedBrowserRepository = new TrustedBrowser($this->dba, $this->logger);
+ try {
+ $trustedBrowser = $trustedBrowserRepository->selectOneByHash($this->cookie->get('trusted'));
+ // Verify record ownership
+ if ($trustedBrowser->uid === $uid) {
+ // Update last_used date
+ $trustedBrowser->recordUse();
+
+ // Save it to the database
+ $trustedBrowserRepository->save($trustedBrowser);
+
+ // Set 2fa session key and return
+ $this->session->set('2fa', true);
+
+ return;
+ } else {
+ // Invalid trusted cookie value, removing it
+ $this->cookie->unset('trusted');
+ }
+ } catch (\Throwable $e) {
+ // Local trusted browser record was probably removed by the user, we carry on with 2FA
+ }
+ }
+
// Case 2: No valid 2FA session: redirect to code verification page
if ($this->mode->isAjax()) {
throw new HTTPException\ForbiddenException();