<?php
+
/**
* @file src/Model/User.php
* @brief This file includes the User class with user related database functions
*/
+
namespace Friendica\Model;
use DivineOmega\PasswordExposed;
use Friendica\Core\System;
use Friendica\Core\Worker;
use Friendica\Database\DBA;
-use Friendica\Model\Photo;
+use Friendica\Model\TwoFactor\AppSpecificPassword;
use Friendica\Object\Image;
use Friendica\Util\Crypto;
use Friendica\Util\DateTimeFormat;
+use Friendica\Util\Images;
use Friendica\Util\Network;
use Friendica\Util\Strings;
use Friendica\Worker\Delivery;
return DBA::selectFirst('user', $fields, ['uid' => $uid]);
}
+ /**
+ * Returns a user record based on it's GUID
+ *
+ * @param string $guid The guid of the user
+ * @param array $fields The fields to retrieve
+ * @param bool $active True, if only active records are searched
+ *
+ * @return array|boolean User record if it exists, false otherwise
+ * @throws Exception
+ */
+ public static function getByGuid(string $guid, array $fields = [], bool $active = true)
+ {
+ if ($active) {
+ $cond = ['guid' => $guid, 'account_expired' => false, 'account_removed' => false];
+ } else {
+ $cond = ['guid' => $guid];
+ }
+
+ return DBA::selectFirst('user', $fields, $cond);
+ }
+
/**
* @param string $nickname
* @param array $fields
* @return boolean|array
* @throws Exception
*/
- public static function getOwnerDataById($uid, $check_valid = true) {
- $r = DBA::fetchFirst("SELECT
+ public static function getOwnerDataById($uid, $check_valid = true)
+ {
+ $r = DBA::fetchFirst(
+ "SELECT
`contact`.*,
`user`.`prvkey` AS `uprvkey`,
`user`.`timezone`,
`user`.`page-flags`,
`user`.`account-type`,
`user`.`prvnets`,
- `user`.`account_removed`
+ `user`.`account_removed`,
+ `user`.`hidewall`
FROM `contact`
INNER JOIN `user`
ON `user`.`uid` = `contact`.`uid`
/**
* Authenticate a user with a clear text password
*
- * @brief Authenticate a user with a clear text password
- * @param mixed $user_info
+ * @brief Authenticate a user with a clear text password
+ * @param mixed $user_info
* @param string $password
+ * @param bool $third_party
* @return int|boolean
* @deprecated since version 3.6
- * @see User::getIdFromPasswordAuthentication()
+ * @see User::getIdFromPasswordAuthentication()
*/
- public static function authenticate($user_info, $password)
+ public static function authenticate($user_info, $password, $third_party = false)
{
try {
- return self::getIdFromPasswordAuthentication($user_info, $password);
+ return self::getIdFromPasswordAuthentication($user_info, $password, $third_party);
} catch (Exception $ex) {
return false;
}
* Returns the user id associated with a successful password authentication
*
* @brief Authenticate a user with a clear text password
- * @param mixed $user_info
+ * @param mixed $user_info
* @param string $password
+ * @param bool $third_party
* @return int User Id if authentication is successful
* @throws Exception
*/
- public static function getIdFromPasswordAuthentication($user_info, $password)
+ public static function getIdFromPasswordAuthentication($user_info, $password, $third_party = false)
{
$user = self::getAuthenticationInfo($user_info);
- if (strpos($user['password'], '$') === false) {
+ if ($third_party && PConfig::get($user['uid'], '2fa', 'verified')) {
+ // Third-party apps can't verify two-factor authentication, we use app-specific passwords instead
+ if (AppSpecificPassword::authenticateUser($user['uid'], $password)) {
+ return $user['uid'];
+ }
+ } elseif (strpos($user['password'], '$') === false) {
//Legacy hash that has not been replaced by a new hash yet
if (self::hashPasswordLegacy($password) === $user['password']) {
self::updatePasswordHashed($user['uid'], self::hashPassword($password));
$user = $user_info;
}
- if (!isset($user['uid'])
+ if (
+ !isset($user['uid'])
|| !isset($user['password'])
|| !isset($user['legacy_password'])
) {
}
} elseif (is_int($user_info) || is_string($user_info)) {
if (is_int($user_info)) {
- $user = DBA::selectFirst('user', ['uid', 'password', 'legacy_password'],
+ $user = DBA::selectFirst(
+ 'user',
+ ['uid', 'password', 'legacy_password'],
[
'uid' => $user_info,
'blocked' => 0,
);
} else {
$fields = ['uid', 'password', 'legacy_password'];
- $condition = ["(`email` = ? OR `username` = ? OR `nickname` = ?)
+ $condition = [
+ "(`email` = ? OR `username` = ? OR `nickname` = ?)
AND NOT `blocked` AND NOT `account_expired` AND NOT `account_removed` AND `verified`",
- $user_info, $user_info, $user_info];
+ $user_info, $user_info, $user_info
+ ];
$user = DBA::selectFirst('user', $fields, $condition);
}
*/
public static function generateNewPassword()
{
- return ucfirst(Strings::getRandomName(8)) . mt_rand(1000, 9999);
+ return ucfirst(Strings::getRandomName(8)) . random_int(1000, 9999);
}
/**
*
* @param string $password
* @return bool
+ * @throws Exception
*/
public static function isPasswordExposed($password)
{
'cacheDirectory' => get_temppath() . '/password-exposed-cache/',
]);
- $PasswordExposedCHecker = new PasswordExposed\PasswordExposedChecker(null, $cache);
+ try {
+ $passwordExposedChecker = new PasswordExposed\PasswordExposedChecker(null, $cache);
+
+ return $passwordExposedChecker->passwordExposed($password) === PasswordExposed\PasswordStatus::EXPOSED;
+ } catch (\Exception $e) {
+ Logger::error('Password Exposed Exception: ' . $e->getMessage(), [
+ 'code' => $e->getCode(),
+ 'file' => $e->getFile(),
+ 'line' => $e->getLine(),
+ 'trace' => $e->getTraceAsString()
+ ]);
- return $PasswordExposedCHecker->passwordExposed($password) === PasswordExposed\PasswordStatus::EXPOSED;
+ return false;
+ }
}
/**
}
}
+ /// @todo Check if this part is really needed. We should have fetched all this data in advance
if (empty($username) || empty($email) || empty($nickname)) {
if ($openid_url) {
if (!Network::isUrlValid($openid_url)) {
}
// Check existing and deleted accounts for this nickname.
- if (DBA::exists('user', ['nickname' => $nickname])
+ if (
+ DBA::exists('user', ['nickname' => $nickname])
|| DBA::exists('userd', ['username' => $nickname])
) {
throw new Exception(L10n::t('Nickname is already registered. Please choose another.'));
$filename = basename($photo);
$img_str = Network::fetchUrl($photo, true);
// guess mimetype from headers or filename
- $type = Image::guessType($photo, true);
+ $type = Images::guessType($photo, true);
$Image = new Image($img_str, $type);
if ($Image->isValid()) {
$Image->scaleToSquare(300);
- $hash = Photo::newResource();
+ $resource_id = Photo::newResource();
- $r = Photo::store($Image, $uid, 0, $hash, $filename, L10n::t('Profile Photos'), 4);
+ $r = Photo::store($Image, $uid, 0, $resource_id, $filename, L10n::t('Profile Photos'), 4);
if ($r === false) {
$photo_failure = true;
$Image->scaleDown(80);
- $r = Photo::store($Image, $uid, 0, $hash, $filename, L10n::t('Profile Photos'), 5);
+ $r = Photo::store($Image, $uid, 0, $resource_id, $filename, L10n::t('Profile Photos'), 5);
if ($r === false) {
$photo_failure = true;
$Image->scaleDown(48);
- $r = Photo::store($Image, $uid, 0, $hash, $filename, L10n::t('Profile Photos'), 6);
+ $r = Photo::store($Image, $uid, 0, $resource_id, $filename, L10n::t('Profile Photos'), 6);
if ($r === false) {
$photo_failure = true;
}
if (!$photo_failure) {
- Photo::update(['profile' => 1], ['resource-id' => $hash]);
+ Photo::update(['profile' => 1], ['resource-id' => $resource_id]);
}
}
}
*/
public static function sendRegisterPendingEmail($user, $sitename, $siteurl, $password)
{
- $body = Strings::deindent(L10n::t('
+ $body = Strings::deindent(L10n::t(
+ '
Dear %1$s,
Thank you for registering at %2$s. Your account is pending for approval by the administrator.
Login Name: %4$s
Password: %5$s
',
- $user['username'], $sitename, $siteurl, $user['nickname'], $password
+ $user['username'],
+ $sitename,
+ $siteurl,
+ $user['nickname'],
+ $password
));
return notification([
*/
public static function sendRegisterOpenEmail($user, $sitename, $siteurl, $password)
{
- $preamble = Strings::deindent(L10n::t('
- Dear %1$s,
+ $preamble = Strings::deindent(L10n::t(
+ '
+ Dear %1$s,
Thank you for registering at %2$s. Your account has been created.
- ',
- $user['username'], $sitename
+ ',
+ $user['username'],
+ $sitename
));
- $body = Strings::deindent(L10n::t('
+ $body = Strings::deindent(L10n::t(
+ '
The login details are as follows:
Site Location: %3$s
If you ever want to delete your account, you can do so at %3$s/removeme
Thank you and welcome to %2$s.',
- $user['nickname'], $sitename, $siteurl, $user['username'], $password
+ $user['nickname'],
+ $sitename,
+ $siteurl,
+ $user['username'],
+ $password
));
return notification([
if ($user['parent-uid'] == 0) {
// First add our own entry
- $identities = [['uid' => $user['uid'],
+ $identities = [[
+ 'uid' => $user['uid'],
'username' => $user['username'],
- 'nickname' => $user['nickname']]];
+ 'nickname' => $user['nickname']
+ ]];
// Then add all the children
- $r = DBA::select('user', ['uid', 'username', 'nickname'],
- ['parent-uid' => $user['uid'], 'account_removed' => false]);
+ $r = DBA::select(
+ 'user',
+ ['uid', 'username', 'nickname'],
+ ['parent-uid' => $user['uid'], 'account_removed' => false]
+ );
if (DBA::isResult($r)) {
$identities = array_merge($identities, DBA::toArray($r));
}
} else {
// First entry is our parent
- $r = DBA::select('user', ['uid', 'username', 'nickname'],
- ['uid' => $user['parent-uid'], 'account_removed' => false]);
+ $r = DBA::select(
+ 'user',
+ ['uid', 'username', 'nickname'],
+ ['uid' => $user['parent-uid'], 'account_removed' => false]
+ );
if (DBA::isResult($r)) {
$identities = DBA::toArray($r);
}
// Then add all siblings
- $r = DBA::select('user', ['uid', 'username', 'nickname'],
- ['parent-uid' => $user['parent-uid'], 'account_removed' => false]);
+ $r = DBA::select(
+ 'user',
+ ['uid', 'username', 'nickname'],
+ ['parent-uid' => $user['parent-uid'], 'account_removed' => false]
+ );
if (DBA::isResult($r)) {
$identities = array_merge($identities, DBA::toArray($r));
}
}
- $r = DBA::p("SELECT `user`.`uid`, `user`.`username`, `user`.`nickname`
+ $r = DBA::p(
+ "SELECT `user`.`uid`, `user`.`username`, `user`.`nickname`
FROM `manage`
INNER JOIN `user` ON `manage`.`mid` = `user`.`uid`
WHERE `user`.`account_removed` = 0 AND `manage`.`uid` = ?",
while ($user = DBA::fetch($userStmt)) {
$statistics['total_users']++;
- if ((strtotime($user['login_date']) > $halfyear) ||
- (strtotime($user['last-item']) > $halfyear)) {
+ if ((strtotime($user['login_date']) > $halfyear) || (strtotime($user['last-item']) > $halfyear)
+ ) {
$statistics['active_users_halfyear']++;
}
- if ((strtotime($user['login_date']) > $month) ||
- (strtotime($user['last-item']) > $month)) {
+ if ((strtotime($user['login_date']) > $month) || (strtotime($user['last-item']) > $month)
+ ) {
$statistics['active_users_monthly']++;
}
}