• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

cypht-org / cypht / 30095700391

24 Jul 2026 01:08PM UTC coverage: 87.092% (-0.2%) from 87.271%
30095700391

push

travis-ci

web-flow
Merge pull request #2045 from IrAlfred/fix-proxy-login-session-origin-cookie-domain

fix(other): fix proxy-related login loop and cookie domain mismatch

21 of 37 new or added lines in 3 files covered. (56.76%)

5816 of 6678 relevant lines covered (87.09%)

11.66 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.24
/lib/session_php.php
1
<?php
2

3
/**
4
 * Session handling
5
 * @package framework
6
 * @subpackage session
7
 */
8

9
trait Hm_Session_Auth {
10

11
    /**
12
     * Lazy loader for the auth mech so modules can define their own
13
     * overrides
14
     * @return void
15
     */
16
    abstract protected function load_auth_mech();
17

18
    /**
19
     * Call the configured authentication method to check user credentials
20
     * @param string $user username
21
     * @param string $pass password
22
     * @return bool true if the authentication was successful
23
     */
24
    public function auth($user, $pass) {
2✔
25
        $this->load_auth_mech();
2✔
26
        return $this->auth_mech->check_credentials($user, $pass);
2✔
27
    }
28

29
    /**
30
     * Save auth detail if it's needed (mech specific)
31
     * @return void
32
     */
33
    public function save_auth_detail() {
2✔
34
        $this->auth_mech->save_auth_detail($this);
2✔
35
    }
36

37
    /**
38
     * Call the configuration authentication method to change the user password
39
     * @param string $user username
40
     * @param string $pass password
41
     * @return bool true if the password was changed
42
     */
43
    public function change_pass($user, $pass) {
1✔
44
        $this->load_auth_mech();
1✔
45
        return $this->auth_mech->change_pass($user, $pass);
1✔
46
    }
47

48
    /**
49
     * Call the configuration authentication method to create an account
50
     * @param string $user username
51
     * @param string $pass password
52
     * @return bool true if the account was created
53
     */
54
    public function create($user, $pass) {
1✔
55
        $this->load_auth_mech();
1✔
56
        return $this->auth_mech->create($user, $pass);
1✔
57
    }
58
}
59

60
/**
61
 * PHP session data methods
62
 * @package framework
63
 * @subpackage session
64
 */
65
abstract class Hm_PHP_Session_Data extends Hm_Session {
66

67
    /**
68
     * @param Hm_Request $request request details
69
     * @return void
70
     */
71
    protected function validate_session_data($request) {
6✔
72
        if ($this->existing && count($this->data) == 0) {
6✔
73
            $this->destroy($request);
2✔
74
        } else {
75
            Hm_Debug::add('LOGGED IN', 'success');
6✔
76
            $this->active = true;
6✔
77
        }
78
    }
79

80
    /**
81
     * @param Hm_Request $request request details
82
     * @return void
83
     */
84
    protected function start_session_data($request) {
6✔
85
        if (array_key_exists('data', $_SESSION)) {
6✔
86
            $data = $this->plaintext($_SESSION['data']);
6✔
87
            if (is_array($data)) {
6✔
88
                $this->data = $data;
1✔
89
            } elseif (!$this->loaded) {
6✔
90
                $this->destroy($request);
5✔
91
                Hm_Debug::add('Mismatched session level encryption key', 'warning');
5✔
92
            }
93
        }
94
    }
95

96
    /**
97
     * Return a session value, or a user settings value stored in the session
98
     * @param string $name session value name to return
99
     * @param mixed $default value to return if $name is not found
100
     * @param bool $user if true, only search the user_data section of the session
101
     * @return mixed the value if found, otherwise $default
102
     */
103
    public function get($name, $default = false, $user = false) {
10✔
104
        if ($user) {
10✔
105
            return array_key_exists('user_data', $this->data) && array_key_exists($name, $this->data['user_data']) ? $this->data['user_data'][$name] : $default;
1✔
106
        } else {
107
            return array_key_exists($name, $this->data) ? $this->data[$name] : $default;
10✔
108
        }
109
    }
110

111
    /**
112
     * Save a value in the session
113
     * @param string $name the name to save
114
     * @param string $value the value to save
115
     * @param bool $user if true, save in the user_data section of the session
116
     * @return void
117
     */
118
    public function set($name, $value, $user = false) {
30✔
119
        if ($user) {
30✔
120
            $this->data['user_data'][$name] = $value;
1✔
121
        } else {
122
            $this->data[$name] = $value;
30✔
123
        }
124
    }
125

126
    /**
127
     * Delete a value from the session
128
     * @param string $name name of value to delete
129
     * @return void
130
     */
131
    public function del($name) {
1✔
132
        if (array_key_exists($name, $this->data)) {
1✔
133
            unset($this->data[$name]);
1✔
134
            return true;
1✔
135
        }
136
        return false;
1✔
137
    }
138

139
    /**
140
     * Save session data
141
     * @return void
142
     */
143
    public function save_data() {
3✔
144
        $enc_data = $this->ciphertext($this->data);
3✔
145
        $_SESSION = array('data' => $enc_data);
3✔
146
        session_write_close();
3✔
147
        $_SESSION = array();
3✔
148
    }
149
}
150

151
/**
152
 * PHP Sessions that extend the base session class
153
 * @package framework
154
 * @subpackage session
155
 */
156
class Hm_PHP_Session extends Hm_PHP_Session_Data {
157

158
    use Hm_Session_Auth;
159

160
    /* data store connection used by classes that extend this */
161
    public $conn;
162

163
    /* flag to indicate an existing session */
164
    protected $existing = false;
165

166
    /**
167
     * Setup newly authenticated session
168
     * @param Hm_Request $request
169
     * @param boolean $fingerprint
170
     * @return null
171
     */
172
    protected function authed($request, $fingerprint) {
2✔
173
        $this->set_key($request);
2✔
174
        $this->loaded = true;
2✔
175
        $this->start($request);
2✔
176
        if ($fingerprint) {
2✔
177
            $this->set_fingerprint($request);
2✔
178
        }
179
        else {
180
            $this->set('fingerprint', '');
1✔
181
        }
182
        $this->save_auth_detail();
2✔
183
        $this->just_started();
2✔
184
    }
185

186
    /**
187
     * Check for an existing session or a new user/pass login request
188
     * @param object $request request details
189
     * @param string $user username
190
     * @param string $pass password
191
     * @return bool
192
     */
193
    public function check($request, $user = false, $pass = false, $fingerprint = true) {
3✔
194
        if ($user !== false && $pass !== false) {
3✔
195
            if ($this->auth($user, $pass)) {
2✔
196
                $this->authed($request, $fingerprint);
2✔
197
            }
198
        } elseif (array_key_exists($this->cname, $request->cookie)) {
2✔
199
            $this->get_key($request);
2✔
200
            $this->existing = true;
2✔
201
            $this->start($request);
2✔
202
            // Only enforce fingerprint for active sessions.
203
            if ($this->is_active()) {
2✔
NEW
204
                $this->check_fingerprint($request);
×
205
            }
206
            $this->restore_long_session($request);
2✔
207
        }
208
        return $this->is_active();
3✔
209
    }
210

211
    /**
212
     * Start the session. This could be an existing session or a new login
213
     * @param Hm_Request $request request details
214
     * @return void
215
     */
216
    public function start($request) {
6✔
217
        if (array_key_exists($this->cname, $request->cookie)) {
6✔
218
            session_id($request->cookie[$this->cname]);
2✔
219
        }
220
        list($secure, $path, $domain) = $this->set_session_params($request);
6✔
221
        if (ini_get('session.use_cookies')) {
6✔
222
            session_set_cookie_params($this->lifetime, $path, $domain, $secure);
×
223
        }
224
        Hm_Functions::session_start();
6✔
225
        $this->session_key = session_id();
6✔
226
        $this->start_session_data($request);
6✔
227
        $this->validate_session_data($request);
6✔
228
    }
229

230
    /**
231
     * Setup the cookie params for a session cookie
232
     * @param Hm_Request $request request details
233
     * @return array list of cookie fields
234
     */
235
    public function set_session_params($request) {
8✔
236
        $path = false;
8✔
237
        if ($request->tls) {
8✔
238
            $secure = true;
1✔
239
        } else {
240
            $secure = false;
8✔
241
        }
242
        if (isset($request->path)) {
8✔
243
            $path = $request->path;
8✔
244
        }
245
        $domain = $this->site_config->get('cookie_domain', false);
8✔
246
        if (!$domain && array_key_exists('HTTP_X_FORWARDED_HOST', $request->server)) {
8✔
247
            $domain = trim(explode(',', $request->server['HTTP_X_FORWARDED_HOST'])[0]);
1✔
248
        }
249
        if (!$domain && array_key_exists('HTTP_HOST', $request->server)) {
8✔
250
            $host = parse_url($request->server['HTTP_HOST'], PHP_URL_HOST);
3✔
251
            if (trim((string) $host)) {
3✔
252
                $domain = $host;
×
253
            } else {
254
                $domain = $request->server['HTTP_HOST'];
3✔
255
            }
256
        }
257
        if ($domain) {
8✔
258
            $host = parse_url($domain, PHP_URL_HOST);
4✔
259
            if (trim((string) $host)) {
4✔
260
                $domain = $host;
1✔
261
            }
262
            if (preg_match('/:\d+$/', $domain, $matches)) {
4✔
NEW
263
                $domain = str_replace($matches[0], '', $domain);
×
264
            }
265
        }
266
        if ($domain == 'none') {
8✔
267
            $domain = '';
1✔
268
        }
269
        return array($secure, $path, $domain);
8✔
270
    }
271

272
    /**
273
     * Restore long session settings for existing sessions
274
     * @param Hm_Request $request request details
275
     * @return void
276
     */
277
    protected function restore_long_session($request) {
4✔
278
        if ($this->get('long_session_enabled', false)) {
4✔
279
            $stored_lifetime = $this->get('long_session_lifetime', 0);
1✔
280
            if ($stored_lifetime > 0) {
1✔
281
                $this->lifetime = $stored_lifetime;
1✔
282
                $this->refresh_session_cookie($request);
1✔
283
            }
284
        }
285
    }
286

287
    /**
288
     * Refresh the session cookie with the current lifetime
289
     * @param Hm_Request $request request details
290
     * @return void
291
     */
292
    protected function refresh_session_cookie($request) {
1✔
293
        if ($this->active && $this->session_key) {
1✔
294
            list($secure, $path, $domain) = $this->set_session_params($request);
×
295
            $params = session_get_cookie_params();
×
296
            // Calculate expiration time: 0 for session-only, or timestamp for long session
297
            $expire = ($this->lifetime > 0) ? $this->lifetime : 0;
×
298
            Hm_Functions::setcookie(
×
299
                $this->cname,
×
300
                $this->session_key,
×
301
                $expire,
×
302
                $path,
×
303
                $domain,
×
304
                $secure,
×
305
                true
×
306
            );
×
307
        }
308
    }
309

310
    /**
311
     * Write session data to avoid locking, keep session active, but don't allow writing
312
     * @return void
313
     */
314
    public function close_early() {
1✔
315
        $this->session_closed = true;
1✔
316
        $this->save_data();
1✔
317
    }
318

319
    /**
320
     * Destroy a session for good
321
     * @param Hm_Request $request request details
322
     * @return void
323
     */
324
    public function destroy($request) {
18✔
325
        if (function_exists('delete_uploaded_files')) {
18✔
326
            delete_uploaded_files($this);
18✔
327
        }
328
        session_unset();
18✔
329
        Hm_Functions::session_destroy();
18✔
330
        $params = session_get_cookie_params();
18✔
331
        $this->delete_cookie($request, $this->cname, $params['path'], $params['domain']);
18✔
332
        $this->delete_cookie($request, 'hm_id');
18✔
333
        $this->delete_cookie($request, 'hm_reload_folders');
18✔
334
        $this->delete_cookie($request, 'hm_msgs');
18✔
335
        $this->active = false;
18✔
336
    }
337

338
    /**
339
     * End a session after a page request is complete. This only closes the session and
340
     * does not destroy it
341
     * @return void
342
     */
343
    public function end() {
7✔
344
        if ($this->active) {
7✔
345
            if (!$this->session_closed) {
1✔
346
                $this->save_data();
1✔
347
            }
348
            $this->active = false;
1✔
349
        }
350
    }
351
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc