3 * @copyright Copyright (C) 2020, Friendica
5 * @license GNU AGPL version 3 or any later version
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU Affero General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU Affero General Public License for more details.
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
22 namespace Friendica\Model\User;
25 use Friendica\Core\Config\IConfig;
28 * Interacting with the Friendica Cookie of a user
32 /** @var int Default expire duration in days */
33 const DEFAULT_EXPIRE = 7;
34 /** @var string The name of the Friendica cookie */
35 const NAME = 'Friendica';
36 /** @var string The path of the Friendica cookie */
38 /** @var string The domain name of the Friendica cookie */
40 /** @var bool True, if the cookie should only be accessible through HTTP */
41 const HTTPONLY = true;
43 /** @var string The remote address of this node */
44 private $remoteAddr = '0.0.0.0';
45 /** @var bool True, if the connection is ssl enabled */
46 private $sslEnabled = false;
47 /** @var string The private key of this Friendica node */
48 private $sitePrivateKey;
49 /** @var int The default cookie lifetime */
50 private $lifetime = self::DEFAULT_EXPIRE * 24 * 60 * 60;
51 /** @var array The $_COOKIE array */
54 public function __construct(IConfig $config, App\BaseURL $baseURL, array $server = [], array $cookie = [])
56 if (!empty($server['REMOTE_ADDR'])) {
57 $this->remoteAddr = $server['REMOTE_ADDR'];
60 $this->sslEnabled = $baseURL->getSSLPolicy() === App\BaseURL::SSL_POLICY_FULL;
61 $this->sitePrivateKey = $config->get('system', 'site_prvkey');
63 $authCookieDays = $config->get('system', 'auth_cookie_lifetime',
64 self::DEFAULT_EXPIRE);
65 $this->lifetime = $authCookieDays * 24 * 60 * 60;
66 $this->cookie = $cookie;
70 * Checks if the Friendica cookie is set for a user
72 * @param string $hash The cookie hash
73 * @param string $password The user password
74 * @param string $privateKey The private Key of the user
76 * @return boolean True, if the cookie is set
79 public function check(string $hash, string $password, string $privateKey)
82 $this->getHash($password, $privateKey),
88 * Set the Friendica cookie for a user
90 * @param int $uid The user id
91 * @param string $password The user password
92 * @param string $privateKey The user private key
93 * @param int|null $seconds optional the seconds
97 public function set(int $uid, string $password, string $privateKey, int $seconds = null)
99 if (!isset($seconds)) {
100 $seconds = $this->lifetime + time();
101 } elseif (isset($seconds) && $seconds != 0) {
102 $seconds = $seconds + time();
105 $value = json_encode([
107 'hash' => $this->getHash($password, $privateKey),
108 'ip' => $this->remoteAddr,
111 return $this->setCookie(self::NAME, $value, $seconds, $this->sslEnabled);
115 * Returns the data of the Friendicas user cookie
117 * @return mixed|null The JSON data, null if not set
119 public function getData()
121 // When the "Friendica" cookie is set, take the value to authenticate and renew the cookie.
122 if (isset($this->cookie[self::NAME])) {
123 $data = json_decode($this->cookie[self::NAME]);
133 * Clears the Friendica cookie of this user after leaving the page
135 public function clear()
137 // make sure cookie is deleted on browser close, as a security measure
138 return $this->setCookie(self::NAME, '', -3600, $this->sslEnabled);
142 * Calculate the hash that is needed for the Friendica cookie
144 * @param string $password The user password
145 * @param string $privateKey The private key of the user
147 * @return string Hashed data
149 private function getHash(string $password, string $privateKey)
153 hash_hmac('sha256', $password, $privateKey),
154 $this->sitePrivateKey
159 * Send a cookie - protected, internal function for test-mocking possibility
161 * @link https://php.net/manual/en/function.setcookie.php
163 * @param string $name
164 * @param string $value [optional]
165 * @param int $expire [optional]
166 * @param bool $secure [optional]
168 * @return bool If output exists prior to calling this function,
171 protected function setCookie(string $name, string $value = null, int $expire = null,
174 return setcookie($name, $value, $expire, self::PATH, self::DOMAIN, $secure, self::HTTPONLY);