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

zopefoundation / Products.Sessions / 16399689495

05 Apr 2025 07:12AM UTC coverage: 94.731%. Remained the same
16399689495

push

github

dataflake
- vb [ci skip]

146 of 180 branches covered (81.11%)

Branch coverage included in aggregate %.

1526 of 1585 relevant lines covered (96.28%)

0.96 hits per line

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

99.66
/src/Products/Sessions/tests/testBrowserIdManager.py
1
##############################################################################
2
#
3
# Copyright (c) 2002 Zope Foundation and Contributors.
4
#
5
# This software is subject to the provisions of the Zope Public License,
6
# Version 2.1 (ZPL).  A copy of the ZPL should accompany this distribution.
7
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
8
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
9
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
10
# FOR A PARTICULAR PURPOSE
11
#
12
##############################################################################
13
"""
14
Test suite for session id manager.
15
"""
16

17
import unittest
1✔
18

19
import Testing.ZopeTestCase
1✔
20

21
from ..interfaces import BrowserIdManagerErr
1✔
22

23

24
class TestBrowserIdManager(unittest.TestCase):
1✔
25

26
    def _getTargetClass(self):
1✔
27
        from ..BrowserIdManager import BrowserIdManager
1✔
28
        return BrowserIdManager
1✔
29

30
    def _makeOne(self, request=None, name='browser_id_manager'):
1✔
31
        bid = self._getTargetClass()(name)
1✔
32
        if request is not None:
1✔
33
            bid.REQUEST = request
1✔
34
        return bid
1✔
35

36
    def test_hasBrowserId_already_set_on_request_invalid(self):
1✔
37
        request = DummyRequest(browser_id_='xxx')
1✔
38
        mgr = self._makeOne(request)
1✔
39
        self.assertFalse(mgr.hasBrowserId())
1✔
40

41
    def test_hasBrowserId_already_set_on_request(self):
1✔
42
        from ..BrowserIdManager import getNewBrowserId
1✔
43
        request = DummyRequest(browser_id_=getNewBrowserId())
1✔
44
        mgr = self._makeOne(request)
1✔
45
        self.assertTrue(mgr.hasBrowserId())
1✔
46

47
    def test_hasBrowserId_namespace_hit(self):
1✔
48
        from ..BrowserIdManager import getNewBrowserId
1✔
49
        request = DummyRequest(cookies={'bid': getNewBrowserId()})
1✔
50
        mgr = self._makeOne(request)
1✔
51
        mgr.setBrowserIdName('bid')
1✔
52
        self.assertTrue(mgr.hasBrowserId())
1✔
53

54
    def test_hasBrowserId_namespace_miss(self):
1✔
55
        request = DummyRequest()
1✔
56
        mgr = self._makeOne(request)
1✔
57
        self.assertFalse(mgr.hasBrowserId())
1✔
58
        self.assertRaises(AttributeError, getattr, request, 'browser_id_')
1✔
59
        self.assertRaises(AttributeError, getattr, request, 'browser_id_ns_')
1✔
60

61
    def test_getBrowserId_already_set_on_request_invalid_raises(self):
1✔
62
        request = DummyRequest(browser_id_='xxx')
1✔
63
        mgr = self._makeOne(request)
1✔
64
        self.assertRaises(ValueError, mgr.getBrowserId)
1✔
65

66
    def test_getBrowserId_already_set_on_request(self):
1✔
67
        from ..BrowserIdManager import getNewBrowserId
1✔
68
        bid = getNewBrowserId()
1✔
69
        request = DummyRequest(browser_id_=bid)
1✔
70
        mgr = self._makeOne(request)
1✔
71
        self.assertEqual(mgr.getBrowserId(), bid)
1✔
72

73
    def test_getBrowserId_namespace_hit(self):
1✔
74
        from ..BrowserIdManager import getNewBrowserId
1✔
75
        bid = getNewBrowserId()
1✔
76
        request = DummyRequest(cookies={'bid': bid})
1✔
77
        mgr = self._makeOne(request)
1✔
78
        mgr.setBrowserIdName('bid')
1✔
79
        self.assertTrue(mgr.hasBrowserId())
1✔
80
        self.assertEqual(request.browser_id_, bid)
1✔
81
        self.assertEqual(request.browser_id_ns_, 'cookies')
1✔
82

83
    def test_getBrowserId_namespace_miss_no_create(self):
1✔
84
        request = DummyRequest()
1✔
85
        mgr = self._makeOne(request)
1✔
86
        mgr.setBrowserIdName('bid')
1✔
87
        self.assertEqual(mgr.getBrowserId(create=False), None)
1✔
88
        self.assertRaises(AttributeError, getattr, request, 'browser_id_')
1✔
89
        self.assertRaises(AttributeError, getattr, request, 'browser_id_ns_')
1✔
90

91
    def test_getBrowserId_namespace_miss_w_create_no_cookies(self):
1✔
92
        from ..BrowserIdManager import isAWellFormedBrowserId
1✔
93
        request = DummyRequest()
1✔
94
        mgr = self._makeOne(request)
1✔
95
        mgr.setBrowserIdName('bid')
1✔
96
        mgr.setBrowserIdNamespaces(())
1✔
97
        bid = mgr.getBrowserId()
1✔
98
        self.assertTrue(isAWellFormedBrowserId(bid))
1✔
99
        self.assertEqual(request.browser_id_, bid)
1✔
100
        self.assertEqual(request.browser_id_ns_, None)
1✔
101

102
    def test_getBrowserId_namespace_miss_w_create_w_cookies(self):
1✔
103
        from ..BrowserIdManager import isAWellFormedBrowserId
1✔
104
        response = DummyResponse(cookies={})
1✔
105
        request = DummyRequest(RESPONSE=response)
1✔
106
        mgr = self._makeOne(request)
1✔
107
        mgr.setBrowserIdName('bid')
1✔
108
        mgr.setBrowserIdNamespaces(('cookies',))
1✔
109
        bid = mgr.getBrowserId()
1✔
110
        self.assertTrue(isAWellFormedBrowserId(bid))
1✔
111
        self.assertEqual(request.browser_id_, bid)
1✔
112
        self.assertEqual(request.browser_id_ns_, None)
1✔
113
        self.assertEqual(response.cookies['bid'],
1✔
114
                         {'path': '/', 'value': bid, 'SameSite': 'Lax'})
115

116
    def test_getBrowserId_considers_replaced_characters_well_formed(self):
1✔
117
        bid = '92778276A8eYSMj-.iI'
1✔
118
        request = DummyRequest(browser_id_=bid)
1✔
119
        mgr = self._makeOne(request)
1✔
120
        self.assertTrue(mgr.hasBrowserId())
1✔
121
        self.assertEqual(bid, mgr.getBrowserId())
1✔
122

123
    def test_isBrowserIdNew_nonesuch_raises(self):
1✔
124
        request = DummyRequest()
1✔
125
        mgr = self._makeOne(request)
1✔
126
        self.assertRaises(ValueError, mgr.isBrowserIdNew)
1✔
127

128
    def test_isBrowserIdNew_no_ns(self):
1✔
129
        from ..BrowserIdManager import getNewBrowserId
1✔
130
        bid = getNewBrowserId()
1✔
131
        request = DummyRequest(browser_id_=bid, browser_id_ns_=None)
1✔
132
        mgr = self._makeOne(request)
1✔
133
        self.assertTrue(mgr.isBrowserIdNew())
1✔
134

135
    def test_isBrowserIdNew_w_ns(self):
1✔
136
        from ..BrowserIdManager import getNewBrowserId
1✔
137
        bid = getNewBrowserId()
1✔
138
        request = DummyRequest(browser_id_=bid, browser_id_ns_='url')
1✔
139
        mgr = self._makeOne(request)
1✔
140
        self.assertFalse(mgr.isBrowserIdNew())
1✔
141

142
    def test_isBrowserIdFromCookie_nonesuch_raises(self):
1✔
143
        request = DummyRequest()
1✔
144
        mgr = self._makeOne(request)
1✔
145
        self.assertRaises(ValueError, mgr.isBrowserIdFromCookie)
1✔
146

147
    def test_isBrowserIdFromCookie_wrong_ns(self):
1✔
148
        from ..BrowserIdManager import getNewBrowserId
1✔
149
        bid = getNewBrowserId()
1✔
150
        request = DummyRequest(browser_id_=bid, browser_id_ns_='url')
1✔
151
        mgr = self._makeOne(request)
1✔
152
        self.assertFalse(mgr.isBrowserIdFromCookie())
1✔
153

154
    def test_isBrowserIdFromCookie_right_ns(self):
1✔
155
        from ..BrowserIdManager import getNewBrowserId
1✔
156
        bid = getNewBrowserId()
1✔
157
        request = DummyRequest(browser_id_=bid, browser_id_ns_='cookies')
1✔
158
        mgr = self._makeOne(request)
1✔
159
        self.assertTrue(mgr.isBrowserIdFromCookie())
1✔
160

161
    def test_isBrowserIdFromForm_nonesuch_raises(self):
1✔
162
        request = DummyRequest()
1✔
163
        mgr = self._makeOne(request)
1✔
164
        self.assertRaises(ValueError, mgr.isBrowserIdFromForm)
1✔
165

166
    def test_isBrowserIdFromForm_wrong_ns(self):
1✔
167
        from ..BrowserIdManager import getNewBrowserId
1✔
168
        bid = getNewBrowserId()
1✔
169
        request = DummyRequest(browser_id_=bid, browser_id_ns_='url')
1✔
170
        mgr = self._makeOne(request)
1✔
171
        self.assertFalse(mgr.isBrowserIdFromForm())
1✔
172

173
    def test_isBrowserIdFromForm_right_ns(self):
1✔
174
        from ..BrowserIdManager import getNewBrowserId
1✔
175
        bid = getNewBrowserId()
1✔
176
        request = DummyRequest(browser_id_=bid, browser_id_ns_='form')
1✔
177
        mgr = self._makeOne(request)
1✔
178
        self.assertTrue(mgr.isBrowserIdFromForm())
1✔
179

180
    def test_isBrowserIdFromUrl_nonesuch_raises(self):
1✔
181
        request = DummyRequest()
1✔
182
        mgr = self._makeOne(request)
1✔
183
        self.assertRaises(ValueError, mgr.isBrowserIdFromUrl)
1✔
184

185
    def test_isBrowserIdFromUrl_wrong_ns(self):
1✔
186
        from ..BrowserIdManager import getNewBrowserId
1✔
187
        bid = getNewBrowserId()
1✔
188
        request = DummyRequest(browser_id_=bid, browser_id_ns_='form')
1✔
189
        mgr = self._makeOne(request)
1✔
190
        self.assertFalse(mgr.isBrowserIdFromUrl())
1✔
191

192
    def test_isBrowserIdFromUrl_right_ns(self):
1✔
193
        from ..BrowserIdManager import getNewBrowserId
1✔
194
        bid = getNewBrowserId()
1✔
195
        request = DummyRequest(browser_id_=bid, browser_id_ns_='url')
1✔
196
        mgr = self._makeOne(request)
1✔
197
        self.assertTrue(mgr.isBrowserIdFromUrl())
1✔
198

199
    def test_flushBrowserIdCookie_wrong_ns_raises(self):
1✔
200
        mgr = self._makeOne()
1✔
201
        mgr.setBrowserIdNamespaces(('url', 'form'))
1✔
202
        self.assertRaises(ValueError, mgr.flushBrowserIdCookie)
1✔
203

204
    def test_flushBrowserIdCookie_ok(self):
1✔
205
        response = DummyResponse(cookies={})
1✔
206
        request = DummyRequest(RESPONSE=response)
1✔
207
        mgr = self._makeOne(request)
1✔
208
        mgr.setBrowserIdName('bid')
1✔
209
        mgr.setBrowserIdNamespaces(('cookies',))
1✔
210
        mgr.flushBrowserIdCookie()
1✔
211
        self.assertEqual(
1✔
212
            response.cookies['bid'],
213
            {
214
                'path': '/',
215
                'expires': 'Sun, 10-May-1971 11:59:00 GMT',
216
                'value': 'deleted',
217
                'SameSite': 'Lax',
218
            }
219
        )
220

221
    def test_setBrowserIdCookieByForce_wrong_ns_raises(self):
1✔
222
        from ..BrowserIdManager import getNewBrowserId
1✔
223
        bid = getNewBrowserId()
1✔
224
        mgr = self._makeOne()
1✔
225
        mgr.setBrowserIdNamespaces(('url', 'form'))
1✔
226
        self.assertRaises(ValueError, mgr.setBrowserIdCookieByForce, bid)
1✔
227

228
    def test_setBrowserIdCookieByForce_ok(self):
1✔
229
        from ..BrowserIdManager import getNewBrowserId
1✔
230
        bid = getNewBrowserId()
1✔
231
        response = DummyResponse(cookies={})
1✔
232
        request = DummyRequest(RESPONSE=response)
1✔
233
        mgr = self._makeOne(request)
1✔
234
        mgr.setBrowserIdName('bid')
1✔
235
        mgr.setBrowserIdNamespaces(('cookies',))
1✔
236
        mgr.setBrowserIdCookieByForce(bid)
1✔
237
        self.assertEqual(response.cookies['bid'],
1✔
238
                         {'path': '/', 'value': bid, 'SameSite': 'Lax'})
239

240
    def test_getHiddenFormField(self):
1✔
241
        from ..BrowserIdManager import getNewBrowserId
1✔
242
        bid = getNewBrowserId()
1✔
243
        request = DummyRequest(browser_id_=bid)
1✔
244
        mgr = self._makeOne(request)
1✔
245
        mgr.setBrowserIdName('bid')
1✔
246
        self.assertEqual(
1✔
247
            mgr.getHiddenFormField(),
248
            '<input type="hidden" name="bid" value="%s" />' % bid
249
        )
250

251
    def test_encodeUrl_no_create_no_bid_raises(self):
1✔
252
        URL = 'http://example.com/'
1✔
253
        request = DummyRequest()
1✔
254
        mgr = self._makeOne(request)
1✔
255
        self.assertRaises(ValueError, mgr.encodeUrl, URL, create=False)
1✔
256

257
    def test_encodeUrl_no_create_w_bid_querystring_style(self):
1✔
258
        from ..BrowserIdManager import getNewBrowserId
1✔
259
        URL = 'http://example.com/'
1✔
260
        bid = getNewBrowserId()
1✔
261
        request = DummyRequest(browser_id_=bid)
1✔
262
        mgr = self._makeOne(request)
1✔
263
        mgr.setBrowserIdName('bid')
1✔
264
        munged = mgr.encodeUrl(URL, create=False)
1✔
265
        self.assertEqual(munged, f'{URL}?bid={bid}')
1✔
266

267
    def test_encodeUrl_no_create_w_bid_querystring_style_existing_qs(self):
1✔
268
        from ..BrowserIdManager import getNewBrowserId
1✔
269
        URL = 'http://example.com/'
1✔
270
        QS = 'foo=bar'
1✔
271
        bid = getNewBrowserId()
1✔
272
        request = DummyRequest(browser_id_=bid)
1✔
273
        mgr = self._makeOne(request)
1✔
274
        mgr.setBrowserIdName('bid')
1✔
275
        munged = mgr.encodeUrl(f'{URL}?{QS}', create=False)
1✔
276
        self.assertEqual(munged, f'{URL}?{QS}&amp;bid={bid}')
1✔
277

278
    def test_encodeUrl_no_create_w_bid_inline_style(self):
1✔
279
        from ..BrowserIdManager import getNewBrowserId
1✔
280
        NETHOST = 'http://example.com'
1✔
281
        PATH_INFO = 'path/to/page'
1✔
282
        URL = f'{NETHOST}/{PATH_INFO}'
1✔
283
        bid = getNewBrowserId()
1✔
284
        request = DummyRequest(browser_id_=bid)
1✔
285
        mgr = self._makeOne(request)
1✔
286
        mgr.setBrowserIdName('bid')
1✔
287
        munged = mgr.encodeUrl(URL, style='inline', create=False)
1✔
288
        self.assertEqual(munged, f'{NETHOST}/bid/{bid}/{PATH_INFO}')
1✔
289

290
    def test_setBrowserIdName_empty_string_raises(self):
1✔
291
        mgr = self._makeOne()
1✔
292
        self.assertRaises(ValueError, mgr.setBrowserIdName, '')
1✔
293

294
    def test_setBrowserIdName_non_string_raises(self):
1✔
295
        mgr = self._makeOne()
1✔
296
        self.assertRaises(ValueError, mgr.setBrowserIdName, 1)
1✔
297

298
    def test_setBrowserIdName_normal(self):
1✔
299
        mgr = self._makeOne()
1✔
300
        mgr.setBrowserIdName('foo')
1✔
301
        self.assertEqual(mgr.getBrowserIdName(), 'foo')
1✔
302

303
    def test_setBrowserIdNamespaces_invalid_raises(self):
1✔
304
        mgr = self._makeOne()
1✔
305
        self.assertRaises(
1✔
306
            ValueError,
307
            mgr.setBrowserIdNamespaces,
308
            ('gummy', 'froopy')
309
        )
310

311
    def test_setBrowserIdNamespaces_normal(self):
1✔
312
        NAMESPACES = ('cookies', 'url', 'form')
1✔
313
        mgr = self._makeOne()
1✔
314
        mgr.setBrowserIdNamespaces(NAMESPACES)
1✔
315
        self.assertEqual(mgr.getBrowserIdNamespaces(), NAMESPACES)
1✔
316

317
    def test_setCookiePath_invalid_raises(self):
1✔
318
        mgr = self._makeOne()
1✔
319
        self.assertRaises(ValueError, mgr.setCookiePath, '/;')
1✔
320

321
    def test_setCookiePath_normal(self):
1✔
322
        mgr = self._makeOne()
1✔
323
        mgr.setCookiePath('/foo')
1✔
324
        self.assertEqual(mgr.getCookiePath(), '/foo')
1✔
325

326
    def test_setCookieLifeDays_invalid_raises(self):
1✔
327
        mgr = self._makeOne()
1✔
328
        self.assertRaises(ValueError, mgr.setCookieLifeDays, '')
1✔
329

330
    def test_setCookieLifeDays_normal(self):
1✔
331
        mgr = self._makeOne()
1✔
332
        mgr.setCookieLifeDays(1)
1✔
333
        self.assertEqual(mgr.getCookieLifeDays(), 1)
1✔
334

335
    def test_setCookieDomain_non_string_raises(self):
1✔
336
        mgr = self._makeOne()
1✔
337
        self.assertRaises(ValueError, mgr.setCookieDomain, {1: 1})
1✔
338

339
    def test_setCookieDomain_no_dots_raises(self):
1✔
340
        mgr = self._makeOne()
1✔
341
        self.assertRaises(ValueError, mgr.setCookieDomain, 'gubble')
1✔
342

343
    def test_setCookieDomain_one_dot_raises(self):
1✔
344
        mgr = self._makeOne()
1✔
345
        self.assertRaises(ValueError, mgr.setCookieDomain, 'zope.org')
1✔
346

347
    def test_setCookieDomain_trailing_semicolon_raises(self):
1✔
348
        mgr = self._makeOne()
1✔
349
        self.assertRaises(ValueError, mgr.setCookieDomain, '.zope.org;')
1✔
350

351
    def test_setCookieDomain_empty_OK(self):
1✔
352
        mgr = self._makeOne()
1✔
353
        mgr.setCookieDomain('')
1✔
354
        self.assertEqual(mgr.getCookieDomain(), '')
1✔
355

356
    def test_setCookieDomain_two_dots(self):
1✔
357
        mgr = self._makeOne()
1✔
358
        mgr.setCookieDomain('.zope.org')
1✔
359
        self.assertEqual(mgr.getCookieDomain(), '.zope.org')
1✔
360

361
    def test_setCookieDomain_three_dots(self):
1✔
362
        mgr = self._makeOne()
1✔
363
        mgr.setCookieDomain('.dev.zope.org')
1✔
364
        self.assertEqual(mgr.getCookieDomain(), '.dev.zope.org')
1✔
365

366
    def test_setCookieSecure_int(self):
1✔
367
        mgr = self._makeOne()
1✔
368
        mgr.setCookieSecure(1)
1✔
369
        self.assertTrue(mgr.getCookieSecure())
1✔
370
        mgr.setCookieSecure(0)
1✔
371
        self.assertFalse(mgr.getCookieSecure())
1✔
372

373
    def test_setCookieSecure_bool(self):
1✔
374
        mgr = self._makeOne()
1✔
375
        mgr.setCookieSecure(True)
1✔
376
        self.assertTrue(mgr.getCookieSecure())
1✔
377
        mgr.setCookieSecure(False)
1✔
378
        self.assertFalse(mgr.getCookieSecure())
1✔
379

380
    def test_setCookieHTTPOnly_bool(self):
1✔
381
        mgr = self._makeOne()
1✔
382
        mgr.setCookieHTTPOnly(True)
1✔
383
        self.assertTrue(mgr.getCookieHTTPOnly())
1✔
384
        mgr.setCookieHTTPOnly(False)
1✔
385
        self.assertFalse(mgr.getCookieHTTPOnly())
1✔
386

387
    def test_setCookieSameSite(self):
1✔
388
        mgr = self._makeOne()
1✔
389

390
        # Test the default first
391
        self.assertEqual(mgr.getCookieSameSite(), 'Lax')
1✔
392

393
        mgr.setCookieSameSite('Strict')
1✔
394
        self.assertEqual(mgr.getCookieSameSite(), 'Strict')
1✔
395

396
        # Empty value set the flag to None
397
        mgr.setCookieSameSite(None)
1✔
398
        self.assertEqual(mgr.getCookieSameSite(), None)
1✔
399
        mgr.setCookieSameSite('')
1✔
400
        self.assertEqual(mgr.getCookieSameSite(), None)
1✔
401

402
        # Reset to a known value for the following tests
403
        mgr.setCookieSameSite('Strict')
1✔
404

405
        # Invalid values raise an error
406
        with self.assertRaises(BrowserIdManagerErr):
1✔
407
            mgr.setCookieSameSite('foobar')
1✔
408
        self.assertEqual(mgr.getCookieSameSite(), 'Strict')
1✔
409

410
        # When specifying None the Secure flag must be set as well
411
        mgr.setCookieSecure(False)
1✔
412
        with self.assertRaises(BrowserIdManagerErr):
1✔
413
            mgr.setCookieSameSite('None')
1✔
414
        self.assertEqual(mgr.getCookieSameSite(), 'Strict')
1✔
415
        mgr.setCookieSecure(True)
1✔
416
        mgr.setCookieSameSite('None')
1✔
417
        self.assertEqual(mgr.getCookieSameSite(), 'None')
1✔
418

419
    def test_setAutoUrlEncoding_bool(self):
1✔
420
        mgr = self._makeOne()
1✔
421
        mgr.setAutoUrlEncoding(True)
1✔
422
        self.assertTrue(mgr.getAutoUrlEncoding())
1✔
423
        mgr.setAutoUrlEncoding(False)
1✔
424
        self.assertFalse(mgr.getAutoUrlEncoding())
1✔
425

426
    def test_isUrlInBidNamespaces(self):
1✔
427
        mgr = self._makeOne()
1✔
428
        mgr.setBrowserIdNamespaces(('cookies', 'url', 'form'))
1✔
429
        self.assertTrue(mgr.isUrlInBidNamespaces())
1✔
430
        mgr.setBrowserIdNamespaces(('cookies', 'form'))
1✔
431
        self.assertFalse(mgr.isUrlInBidNamespaces())
1✔
432

433
    def test__setCookie_remove(self):
1✔
434
        response = DummyResponse(cookies={})
1✔
435
        request = DummyRequest(RESPONSE=response)
1✔
436
        mgr = self._makeOne(request)
1✔
437
        mgr.setBrowserIdName('bid')
1✔
438
        mgr._setCookie('xxx', request, remove=True)
1✔
439
        self.assertEqual(
1✔
440
            response.cookies['bid'],
441
            {
442
                'path': '/',
443
                'value': 'xxx',
444
                'expires': 'Sun, 10-May-1971 11:59:00 GMT',
445
                'SameSite': 'Lax',
446
            }
447
        )
448

449
    def test__setCookie_cookie_life_days(self):
1✔
450
        response = DummyResponse(cookies={})
1✔
451
        request = DummyRequest(RESPONSE=response)
1✔
452
        mgr = self._makeOne(request)
1✔
453
        mgr.setBrowserIdName('bid')
1✔
454
        mgr.setCookieLifeDays(1)
1✔
455
        mgr._setCookie(
1✔
456
            'xxx', request,
457
            now=lambda: 1,
458
            strftime=lambda x, y: 'Seconds: %d' % y,
459
            gmtime=lambda x: x
460
        )
461
        self.assertEqual(
1✔
462
            response.cookies['bid'],
463
            {
464
                'path': '/',
465
                'value': 'xxx',
466
                'expires': 'Seconds: 86401',
467
                'SameSite': 'Lax',
468
            }
469
        )
470

471
    def test__setCookie_cookie_secure_no_URL1_sets_no_cookie(self):
1✔
472
        request = DummyRequest()
1✔
473
        mgr = self._makeOne(request)
1✔
474
        mgr.setBrowserIdName('bid')
1✔
475
        mgr.setCookieSecure(True)
1✔
476
        mgr._setCookie('xxx', request)  # no response, doesn't blow up
1✔
477

478
    def test__setCookie_cookie_secure_not_https_sets_no_cookie(self):
1✔
479
        request = DummyRequest(URL1='http://example.com/')
1✔
480
        mgr = self._makeOne(request)
1✔
481
        mgr.setBrowserIdName('bid')
1✔
482
        mgr.setCookieSecure(True)
1✔
483
        mgr._setCookie('xxx', request)  # no response, doesn't blow up
1✔
484

485
    def test__setCookie_cookie_secure_is_https(self):
1✔
486
        response = DummyResponse(cookies={})
1✔
487
        request = DummyRequest(RESPONSE=response, URL1='https://example.com/')
1✔
488
        mgr = self._makeOne(request)
1✔
489
        mgr.setBrowserIdName('bid')
1✔
490
        mgr.setCookieSecure(True)
1✔
491
        mgr._setCookie('xxx', request)
1✔
492
        self.assertEqual(
1✔
493
            response.cookies['bid'],
494
            {
495
                'path': '/',
496
                'value': 'xxx',
497
                'secure': True,
498
                'SameSite': 'Lax',
499
            }
500
        )
501

502
    def test__setCookie_domain(self):
1✔
503
        response = DummyResponse(cookies={})
1✔
504
        request = DummyRequest(RESPONSE=response)
1✔
505
        mgr = self._makeOne(request)
1✔
506
        mgr.setBrowserIdName('bid')
1✔
507
        mgr.setCookieDomain('.zope.org')
1✔
508
        mgr._setCookie('xxx', request)
1✔
509
        self.assertEqual(
1✔
510
            response.cookies['bid'],
511
            {
512
                'path': '/',
513
                'value': 'xxx',
514
                'domain': '.zope.org',
515
                'SameSite': 'Lax',
516
            }
517
        )
518

519
    def test__setCookie_path(self):
1✔
520
        response = DummyResponse(cookies={})
1✔
521
        request = DummyRequest(RESPONSE=response)
1✔
522
        mgr = self._makeOne(request)
1✔
523
        mgr.setBrowserIdName('bid')
1✔
524
        mgr.setCookiePath('/path/')
1✔
525
        mgr._setCookie('xxx', request)
1✔
526
        self.assertEqual(
1✔
527
            response.cookies['bid'],
528
            {
529
                'path': '/path/',
530
                'value': 'xxx',
531
                'SameSite': 'Lax',
532
            }
533
        )
534

535
    def test__setCookie_http_only(self):
1✔
536
        response = DummyResponse(cookies={})
1✔
537
        request = DummyRequest(RESPONSE=response, URL1='https://example.com/')
1✔
538
        mgr = self._makeOne(request)
1✔
539
        mgr.setBrowserIdName('bid')
1✔
540
        mgr.setCookieHTTPOnly(True)
1✔
541
        mgr._setCookie('xxx', request)
1✔
542
        self.assertEqual(
1✔
543
            response.cookies['bid'],
544
            {
545
                'path': '/',
546
                'value': 'xxx',
547
                'HttpOnly': True,
548
                'SameSite': 'Lax',
549
            }
550
        )
551

552
    def test__setCookie_http_only_missing_attr(self):
1✔
553
        # See https://bugs.launchpad.net/bugs/374816
554
        response = DummyResponse(cookies={})
1✔
555
        request = DummyRequest(RESPONSE=response, URL1='https://example.com/')
1✔
556
        mgr = self._makeOne(request)
1✔
557
        del mgr.cookie_http_only  # pre-2.12 instances didn't have this
1✔
558
        mgr.setBrowserIdName('bid')
1✔
559
        mgr._setCookie('xxx', request)
1✔
560
        self.assertEqual(
1✔
561
            response.cookies['bid'],
562
            {
563
                'path': '/',
564
                'value': 'xxx',
565
                'SameSite': 'Lax',
566
            }
567
        )
568

569
    def test__setId_same_id_noop(self):
1✔
570
        mgr = self._makeOne(name='foo')
1✔
571
        mgr._setId('foo')
1✔
572

573
    def test__setId_different_id_raises(self):
1✔
574
        mgr = self._makeOne(name='foo')
1✔
575
        self.assertRaises(ValueError, mgr._setId, 'bar')
1✔
576

577
    def test_setCookieSecure_non_HTTPS_doesnt_set_cookie(self):
1✔
578
        # Document the "feature" that 'setCookieSecure' allows returning
579
        # a browser ID even where the URL is not HTTPS, and therefor no
580
        # cookie is set.
581
        response = DummyResponse(cookies={})
1✔
582
        request = DummyRequest(RESPONSE=response, URL1='http://example.com/')
1✔
583
        mgr = self._makeOne(request)
1✔
584
        mgr.setCookieSecure(1)
1✔
585
        try:
1✔
586
            mgr.getBrowserId()  # doesn't raise
1✔
587
        except Exception:
×
588
            self.fail()
589
        self.assertEqual(len(response.cookies), 0)
1✔
590

591
    def test_hasTraversalHook_missing(self):
1✔
592
        mgr = self._makeOne()
1✔
593
        parent = DummyObject()
1✔
594
        self.assertFalse(mgr.hasTraversalHook(parent))
1✔
595

596
    def test_hasTraversalHook_present(self):
1✔
597
        mgr = self._makeOne()
1✔
598
        parent = DummyObject()
1✔
599
        parent.__before_traverse__ = {(0, 'BrowserIdManager'): object()}
1✔
600
        self.assertTrue(mgr.hasTraversalHook(parent))
1✔
601

602
    def test_updateTraversalData_w_url_ns(self):
1✔
603
        from Acquisition import Implicit
1✔
604
        from ZPublisher.BeforeTraverse import queryBeforeTraverse
1✔
605

606
        from ..BrowserIdManager import BrowserIdManagerTraverser
1✔
607

608
        class Parent(Implicit):
1✔
609
            pass
1✔
610

611
        mgr = self._makeOne()
1✔
612
        mgr.setBrowserIdNamespaces(('url',))
1✔
613
        parent = Parent()
1✔
614
        parent.browser_id_manager = mgr
1✔
615
        parent.browser_id_manager.updateTraversalData()  # needs wrapper
1✔
616
        hooks = queryBeforeTraverse(parent, 'BrowserIdManager')
1✔
617
        self.assertEqual(len(hooks), 1)
1✔
618
        self.assertEqual(hooks[0][0], 40)
1✔
619
        self.assertIsInstance(hooks[0][1], BrowserIdManagerTraverser)
1✔
620

621
    def test_updateTraversalData_not_url_ns(self):
1✔
622
        from Acquisition import Implicit
1✔
623
        from ZPublisher.BeforeTraverse import queryBeforeTraverse
1✔
624

625
        class Parent(Implicit):
1✔
626
            pass
1✔
627

628
        mgr = self._makeOne()
1✔
629
        mgr.setBrowserIdNamespaces(('cookies', 'form'))
1✔
630
        parent = Parent()
1✔
631
        parent.__before_traverse__ = {(0, 'BrowserIdManager'): object()}
1✔
632
        parent.browser_id_manager = mgr
1✔
633
        parent.browser_id_manager.updateTraversalData()  # needs wrapper
1✔
634
        self.assertFalse(queryBeforeTraverse(mgr, 'BrowserIdManager'))
1✔
635

636
    def test_registerTraversalHook_doesnt_replace_existing(self):
1✔
637
        from Acquisition import Implicit
1✔
638
        from ZPublisher.BeforeTraverse import queryBeforeTraverse
1✔
639

640
        class Parent(Implicit):
1✔
641
            pass
1✔
642

643
        mgr = self._makeOne()
1✔
644
        parent = Parent()
1✔
645
        hook = object()
1✔
646
        parent.__before_traverse__ = {(0, 'BrowserIdManager'): hook}
1✔
647
        parent.browser_id_manager = mgr
1✔
648
        parent.browser_id_manager.registerTraversalHook()  # needs wrapper
1✔
649
        hooks = queryBeforeTraverse(parent, 'BrowserIdManager')
1✔
650
        self.assertEqual(len(hooks), 1)
1✔
651
        self.assertEqual(hooks[0][0], 0)
1✔
652
        self.assertIs(hooks[0][1], hook)
1✔
653

654
    def test_registerTraversalHook_normal(self):
1✔
655
        from Acquisition import Implicit
1✔
656
        from ZPublisher.BeforeTraverse import queryBeforeTraverse
1✔
657

658
        from ..BrowserIdManager import BrowserIdManagerTraverser
1✔
659

660
        class Parent(Implicit):
1✔
661
            pass
1✔
662

663
        mgr = self._makeOne()
1✔
664
        parent = Parent()
1✔
665
        parent.browser_id_manager = mgr
1✔
666
        parent.browser_id_manager.registerTraversalHook()  # needs wrapper
1✔
667
        hooks = queryBeforeTraverse(parent, 'BrowserIdManager')
1✔
668
        self.assertEqual(len(hooks), 1)
1✔
669
        self.assertEqual(hooks[0][0], 40)
1✔
670
        self.assertIsInstance(hooks[0][1], BrowserIdManagerTraverser)
1✔
671

672
    def test_unregisterTraversalHook_nonesuch_doesnt_raise(self):
1✔
673
        from Acquisition import Implicit
1✔
674

675
        class Parent(Implicit):
1✔
676
            pass
1✔
677

678
        mgr = self._makeOne()
1✔
679
        parent = Parent()
1✔
680
        parent.browser_id_manager = mgr
1✔
681
        parent.browser_id_manager.unregisterTraversalHook()  # needs wrapper
1✔
682

683
    def test_unregisterTraversalHook_normal(self):
1✔
684
        from Acquisition import Implicit
1✔
685
        from ZPublisher.BeforeTraverse import queryBeforeTraverse
1✔
686

687
        class Parent(Implicit):
1✔
688
            pass
1✔
689

690
        mgr = self._makeOne()
1✔
691
        parent = Parent()
1✔
692
        parent.__before_traverse__ = {(0, 'BrowserIdManager'): object()}
1✔
693
        parent.browser_id_manager = mgr
1✔
694
        parent.browser_id_manager.unregisterTraversalHook()  # needs wrapper
1✔
695
        self.assertFalse(queryBeforeTraverse(mgr, 'BrowserIdManager'))
1✔
696

697
    def test_new_browser_id(self):
1✔
698
        from time import time
1✔
699

700
        from ..BrowserIdManager import getB64TStampToInt
1✔
701
        from ..BrowserIdManager import getBrowserIdPieces
1✔
702
        from ..BrowserIdManager import getNewBrowserId
1✔
703
        from ..BrowserIdManager import isAWellFormedBrowserId
1✔
704
        start = time()
1✔
705
        bid = getNewBrowserId()
1✔
706
        self.assertEqual(len(bid), 19)
1✔
707
        self.assertTrue(isAWellFormedBrowserId(bid))
1✔
708
        ri, ts = getBrowserIdPieces(bid)
1✔
709
        # we cannot expect to reconstruct ``start`` precisely
710
        # but usually, it should be reconstructable with a 1 s precision.
711
        # Under exceptional conditions, the check below may fail
712
        self.assertTrue(0 <= getB64TStampToInt(ts) - start <= 1)
1✔
713

714

715
class TestBrowserIdManagerTraverser(unittest.TestCase):
1✔
716

717
    def _getTargetClass(self):
1✔
718
        from ..BrowserIdManager import BrowserIdManagerTraverser
1✔
719
        return BrowserIdManagerTraverser
1✔
720

721
    def _makeOne(self):
1✔
722
        return self._getTargetClass()()
1✔
723

724
    def test___call___no_mgr(self):
1✔
725
        traverser = self._makeOne()
1✔
726
        container = DummyObject()
1✔
727
        request = DummyRequest()
1✔
728
        traverser(container, request)  # doesn't raise
1✔
729

730
    def test___call___w_mgr_request_has_no_stack(self):
1✔
731
        traverser = self._makeOne()
1✔
732
        mgr = DummyBrowserIdManager()
1✔
733
        container = DummyObject(browser_id_manager=mgr)
1✔
734
        request = DummyRequest()
1✔
735
        traverser(container, request)  # doesn't raise
1✔
736

737
    def test___call___w_mgr_request_has_stack_no_auto_encode(self):
1✔
738
        from ..BrowserIdManager import getNewBrowserId
1✔
739
        bid = getNewBrowserId()
1✔
740
        traverser = self._makeOne()
1✔
741
        mgr = DummyBrowserIdManager()
1✔
742
        container = DummyObject(browser_id_manager=mgr)
1✔
743
        request = DummyRequest(
1✔
744
            TraversalRequestNameStack=[bid, 'bid']
745
        )
746
        traverser(container, request)
1✔
747
        self.assertEqual(request.browser_id_, bid)
1✔
748
        self.assertEqual(request.browser_id_ns_, 'url')
1✔
749
        self.assertEqual(len(request.TraversalRequestNameStack), 0)
1✔
750

751
    def test___call___w_mgr_request_has_stack_w_auto_encode(self):
1✔
752
        from ..BrowserIdManager import getNewBrowserId
1✔
753
        bid = getNewBrowserId()
1✔
754
        traverser = self._makeOne()
1✔
755
        mgr = DummyBrowserIdManager(True)
1✔
756
        container = DummyObject(browser_id_manager=mgr)
1✔
757
        request = DummyRequest(
1✔
758
            TraversalRequestNameStack=[bid, 'bid'],
759
            _script=[]
760
        )
761
        traverser(container, request)
1✔
762
        self.assertEqual(request.browser_id_, bid)
1✔
763
        self.assertEqual(request.browser_id_ns_, 'url')
1✔
764
        self.assertEqual(len(request.TraversalRequestNameStack), 0)
1✔
765
        self.assertEqual(len(request._script), 2)
1✔
766
        self.assertEqual(request._script[0], 'bid')
1✔
767
        self.assertEqual(request._script[1], bid)
1✔
768

769
    def test___call___w_mgr_request_empty_stack_w_auto_encode(self):
1✔
770
        from ..BrowserIdManager import isAWellFormedBrowserId
1✔
771
        traverser = self._makeOne()
1✔
772
        mgr = DummyBrowserIdManager(True)
1✔
773
        container = DummyObject(browser_id_manager=mgr)
1✔
774
        request = DummyRequest(TraversalRequestNameStack=[], _script=[])
1✔
775
        traverser(container, request)
1✔
776
        bid = request.browser_id_
1✔
777
        self.assertTrue(isAWellFormedBrowserId(bid))
1✔
778
        self.assertEqual(request.browser_id_ns_, None)
1✔
779
        self.assertEqual(len(request.TraversalRequestNameStack), 0)
1✔
780
        self.assertEqual(len(request._script), 2)
1✔
781
        self.assertEqual(request._script[0], 'bid')
1✔
782
        self.assertEqual(request._script[1], bid)
1✔
783

784

785
class TestBrowserIdManagerPublish(Testing.ZopeTestCase.FunctionalTestCase):
1✔
786

787
    def test_encodeUrl_safe(self):
1✔
788
        from ..BrowserIdManager import BrowserIdManager
1✔
789
        if not hasattr(self.app, 'browser_id_manager'):
1!
790
            bid = BrowserIdManager('browser_id_manager', 'Browser Id Manager')
1✔
791
            self.app._setObject('browser_id_manager', bid)
1✔
792

793
        res = self.publish(
1✔
794
            '/browser_id_manager/encodeUrl?url=%3Chtml%3EEVIL%2Fhtml%3E%3C!--'
795
        )
796
        self.assertNotIn(b"<html>EVIL/html>", res.getBody())
1✔
797

798

799
class DummyObject:
1✔
800

801
    def __init__(self, **kw):
1✔
802
        self.__dict__.update(kw)
1✔
803

804

805
class DummyResponse(DummyObject):
1✔
806
    pass
1✔
807

808

809
class DummyRequest(DummyObject):
1✔
810

811
    def __getitem__(self, key):
1✔
812
        return getattr(self, key)
1✔
813

814
    def get(self, key, default=None):
1✔
815
        return getattr(self, key, default)
1✔
816

817

818
class DummyBrowserIdManager:
1✔
819

820
    def __init__(self, auto=False):
1✔
821
        self._auto = auto
1✔
822

823
    def getBrowserIdName(self):
1✔
824
        return 'bid'
1✔
825

826
    def getAutoUrlEncoding(self):
1✔
827
        return self._auto
1✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc