|
1 | 1 | # -*- coding: utf-8 -*- |
2 | 2 | import datetime |
3 | | -from typing import Union |
| 3 | +import logging |
| 4 | +from typing import Dict, Union |
4 | 5 |
|
5 | 6 | from .cache import all_cookie_groups, get_cookie, get_cookie_group |
6 | 7 | from .conf import settings |
7 | 8 | from .models import ACTION_ACCEPTED, ACTION_DECLINED, LogItem |
8 | 9 |
|
| 10 | +logger = logging.getLogger(__name__) |
9 | 11 |
|
10 | | -def parse_cookie_str(cookie): |
11 | | - dic = {} |
| 12 | +COOKIE_GROUP_SEP = "|" |
| 13 | +KEY_VALUE_SEP = "=" |
| 14 | + |
| 15 | + |
| 16 | +def parse_cookie_str(cookie: str) -> Dict[str, str]: |
12 | 17 | if not cookie: |
13 | | - return dic |
14 | | - for c in cookie.split("|"): |
15 | | - key, value = c.split("=") |
16 | | - dic[key] = value |
17 | | - return dic |
| 18 | + return {} |
| 19 | + |
| 20 | + bits = cookie.split(COOKIE_GROUP_SEP) |
| 21 | + |
| 22 | + def _gen_pairs(): |
| 23 | + for possible_pair in bits: |
| 24 | + parts = possible_pair.split(KEY_VALUE_SEP) |
| 25 | + if len(parts) == 2: |
| 26 | + yield parts |
| 27 | + else: |
| 28 | + logger.debug("cookie_value_discarded", extra={"value": possible_pair}) |
| 29 | + |
| 30 | + return dict(_gen_pairs()) |
| 31 | + |
| 32 | + |
| 33 | +def _contains_invalid_characters(*inputs: str) -> bool: |
| 34 | + # = and | are special separators. They are unexpected characters in both |
| 35 | + # keys and values. |
| 36 | + for separator in (COOKIE_GROUP_SEP, KEY_VALUE_SEP): |
| 37 | + for value in inputs: |
| 38 | + if separator in value: |
| 39 | + logger.debug("skip_separator", extra={"value": value, "sep": separator}) |
| 40 | + return True |
| 41 | + return False |
| 42 | + |
| 43 | + |
| 44 | +def dict_to_cookie_str(dic) -> str: |
| 45 | + """ |
| 46 | + Serialize a dictionary of cookie-group metadata to a string. |
| 47 | +
|
| 48 | + The result is stored in a cookie itself. Note that the dictionary keys are expected |
| 49 | + to be cookie group ``varname`` fields, which are validated against a slug regex. The |
| 50 | + values are supposed to be ISO-8601 timestamps. |
| 51 | +
|
| 52 | + Invalid key/value pairs are dropped. |
| 53 | + """ |
18 | 54 |
|
| 55 | + def _gen_pairs(): |
| 56 | + for key, value in dic.items(): |
| 57 | + if _contains_invalid_characters(key, value): |
| 58 | + continue |
| 59 | + yield f"{key}={value}" |
19 | 60 |
|
20 | | -def dict_to_cookie_str(dic): |
21 | | - return "|".join(["%s=%s" % (k, v) for k, v in dic.items() if v]) |
| 61 | + return "|".join(_gen_pairs()) |
22 | 62 |
|
23 | 63 |
|
24 | 64 | def get_cookie_dict_from_request(request): |
@@ -171,6 +211,7 @@ def is_cookie_consent_enabled(request): |
171 | 211 | return enabled |
172 | 212 |
|
173 | 213 |
|
| 214 | +# Deprecated |
174 | 215 | def get_cookie_string(cookie_dic): |
175 | 216 | """ |
176 | 217 | Returns cookie in format suitable for use in javascript. |
|
0 commit comments