]> git.mxchange.org Git - friendica.git/blob - src/Model/User/Cookie.php
Refactor Session Handling (make it more simple & handler are now handler again)
[friendica.git] / src / Model / User / Cookie.php
1 <?php
2
3 namespace Friendica\Model\User;
4
5 use Friendica\App;
6 use Friendica\Core\Config\Configuration;
7
8 /**
9  * Interacting with the Friendica Cookie of a user
10  */
11 class Cookie
12 {
13         /** @var int Default expire duration in days */
14         const DEFAULT_EXPIRE = 7;
15         /** @var string The name of the Friendica cookie */
16         const NAME = 'Friendica';
17         /** @var string The path of the Friendica cookie */
18         const PATH = '/';
19         /** @var string The domain name of the Friendica cookie */
20         const DOMAIN = '';
21         /** @var bool True, if the cookie should only be accessible through HTTP */
22         const HTTPONLY = true;
23
24         /** @var string The remote address of this node */
25         private $remoteAddr = '0.0.0.0';
26         /** @var bool True, if the connection is ssl enabled */
27         private $sslEnabled = false;
28         /** @var string The private key of this Friendica node */
29         private $sitePrivateKey;
30         /** @var int The default cookie lifetime */
31         private $lifetime = self::DEFAULT_EXPIRE * 24 * 60 * 60;
32         /** @var array The $_COOKIE array */
33         private $cookie;
34
35         public function __construct(Configuration $config, App\BaseURL $baseURL, array $server = [], array $cookie = [])
36         {
37                 if (!empty($server['REMOTE_ADDR'])) {
38                         $this->remoteAddr = $server['REMOTE_ADDR'];
39                 }
40
41                 $this->sslEnabled     = $baseURL->getSSLPolicy() === App\BaseURL::SSL_POLICY_FULL;
42                 $this->sitePrivateKey = $config->get('system', 'site_prvkey');
43
44                 $authCookieDays = $config->get('system', 'auth_cookie_lifetime',
45                         self::DEFAULT_EXPIRE);
46                 $this->lifetime = $authCookieDays * 24 * 60 * 60;
47                 $this->cookie   = $cookie;
48         }
49
50         /**
51          * Checks if the Friendica cookie is set for a user
52          *
53          * @param string $hash       The cookie hash
54          * @param string $password   The user password
55          * @param string $privateKey The private Key of the user
56          *
57          * @return boolean True, if the cookie is set
58          *
59          */
60         public function check(string $hash, string $password, string $privateKey)
61         {
62                 return hash_equals(
63                         $this->getHash($password, $privateKey),
64                         $hash
65                 );
66         }
67
68         /**
69          * Set the Friendica cookie for a user
70          *
71          * @param int      $uid        The user id
72          * @param string   $password   The user password
73          * @param string   $privateKey The user private key
74          * @param int|null $seconds    optional the seconds
75          *
76          * @return bool
77          */
78         public function set(int $uid, string $password, string $privateKey, int $seconds = null)
79         {
80                 if (!isset($seconds)) {
81                         $seconds = $this->lifetime + time();
82                 } elseif (isset($seconds) && $seconds != 0) {
83                         $seconds = $seconds + time();
84                 }
85
86                 $value = json_encode([
87                         'uid'  => $uid,
88                         'hash' => $this->getHash($password, $privateKey),
89                         'ip'   => $this->remoteAddr,
90                 ]);
91
92                 return $this->setCookie(self::NAME, $value, $seconds, $this->sslEnabled);
93         }
94
95         /**
96          * Returns the data of the Friendicas user cookie
97          *
98          * @return mixed|null The JSON data, null if not set
99          */
100         public function getData()
101         {
102                 // When the "Friendica" cookie is set, take the value to authenticate and renew the cookie.
103                 if (isset($this->cookie[self::NAME])) {
104                         $data = json_decode($this->cookie[self::NAME]);
105                         if (!empty($data)) {
106                                 return $data;
107                         }
108                 }
109
110                 return null;
111         }
112
113         /**
114          * Clears the Friendica cookie of this user after leaving the page
115          */
116         public function clear()
117         {
118                 // make sure cookie is deleted on browser close, as a security measure
119                 return $this->setCookie(self::NAME, '', -3600, $this->sslEnabled);
120         }
121
122         /**
123          * Calculate the hash that is needed for the Friendica cookie
124          *
125          * @param string $password   The user password
126          * @param string $privateKey The private key of the user
127          *
128          * @return string Hashed data
129          */
130         private function getHash(string $password, string $privateKey)
131         {
132                 return hash_hmac(
133                         'sha256',
134                         hash_hmac('sha256', $password, $privateKey),
135                         $this->sitePrivateKey
136                 );
137         }
138
139         /**
140          * Send a cookie - protected, internal function for test-mocking possibility
141          *
142          * @link  https://php.net/manual/en/function.setcookie.php
143          *
144          * @param string $name
145          * @param string $value  [optional]
146          * @param int    $expire [optional]
147          * @param bool   $secure [optional]
148          *
149          * @return bool If output exists prior to calling this function,
150          *
151          */
152         protected function setCookie(string $name, string $value = null, int $expire = null,
153                                      bool $secure = null)
154         {
155                 return setcookie($name, $value, $expire, self::PATH, self::DOMAIN, $secure, self::HTTPONLY);
156         }
157 }