Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
SeleniumHQ
GitHub Repository: SeleniumHQ/Selenium
Path: blob/trunk/py/selenium/webdriver/common/bidi/storage.py
4014 views
1
# Licensed to the Software Freedom Conservancy (SFC) under one
2
# or more contributor license agreements. See the NOTICE file
3
# distributed with this work for additional information
4
# regarding copyright ownership. The SFC licenses this file
5
# to you under the Apache License, Version 2.0 (the
6
# "License"); you may not use this file except in compliance
7
# with the License. You may obtain a copy of the License at
8
#
9
# http://www.apache.org/licenses/LICENSE-2.0
10
#
11
# Unless required by applicable law or agreed to in writing,
12
# software distributed under the License is distributed on an
13
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14
# KIND, either express or implied. See the License for the
15
# specific language governing permissions and limitations
16
# under the License.
17
from __future__ import annotations
18
19
from typing import TYPE_CHECKING, Any
20
21
from selenium.webdriver.common.bidi.common import command_builder
22
23
if TYPE_CHECKING:
24
from selenium.webdriver.remote.websocket_connection import WebSocketConnection
25
26
27
class SameSite:
28
"""Represents the possible same site values for cookies."""
29
30
STRICT = "strict"
31
LAX = "lax"
32
NONE = "none"
33
DEFAULT = "default"
34
35
36
class BytesValue:
37
"""Represents a bytes value."""
38
39
TYPE_BASE64 = "base64"
40
TYPE_STRING = "string"
41
42
def __init__(self, type: str, value: str):
43
self.type = type
44
self.value = value
45
46
def to_dict(self) -> dict[str, str]:
47
"""Converts the BytesValue to a dictionary.
48
49
Returns:
50
A dictionary representation of the BytesValue.
51
"""
52
return {"type": self.type, "value": self.value}
53
54
55
class Cookie:
56
"""Represents a cookie."""
57
58
def __init__(
59
self,
60
name: str,
61
value: BytesValue,
62
domain: str,
63
path: str | None = None,
64
size: int | None = None,
65
http_only: bool | None = None,
66
secure: bool | None = None,
67
same_site: str | None = None,
68
expiry: int | None = None,
69
):
70
self.name = name
71
self.value = value
72
self.domain = domain
73
self.path = path
74
self.size = size
75
self.http_only = http_only
76
self.secure = secure
77
self.same_site = same_site
78
self.expiry = expiry
79
80
@classmethod
81
def from_dict(cls, data: dict[str, Any]) -> Cookie:
82
"""Creates a Cookie instance from a dictionary.
83
84
Args:
85
data: A dictionary containing the cookie information.
86
87
Returns:
88
A new instance of Cookie.
89
"""
90
# Validation for empty strings
91
name = data.get("name")
92
if not name:
93
raise ValueError("name is required and cannot be empty")
94
domain = data.get("domain")
95
if not domain:
96
raise ValueError("domain is required and cannot be empty")
97
98
value = BytesValue(data.get("value", {}).get("type"), data.get("value", {}).get("value"))
99
return cls(
100
name=str(name),
101
value=value,
102
domain=str(domain),
103
path=data.get("path"),
104
size=data.get("size"),
105
http_only=data.get("httpOnly"),
106
secure=data.get("secure"),
107
same_site=data.get("sameSite"),
108
expiry=data.get("expiry"),
109
)
110
111
112
class CookieFilter:
113
"""Represents a filter for cookies."""
114
115
def __init__(
116
self,
117
name: str | None = None,
118
value: BytesValue | None = None,
119
domain: str | None = None,
120
path: str | None = None,
121
size: int | None = None,
122
http_only: bool | None = None,
123
secure: bool | None = None,
124
same_site: str | None = None,
125
expiry: int | None = None,
126
):
127
self.name = name
128
self.value = value
129
self.domain = domain
130
self.path = path
131
self.size = size
132
self.http_only = http_only
133
self.secure = secure
134
self.same_site = same_site
135
self.expiry = expiry
136
137
def to_dict(self) -> dict[str, Any]:
138
"""Converts the CookieFilter to a dictionary.
139
140
Returns:
141
A dictionary representation of the CookieFilter.
142
"""
143
result: dict[str, Any] = {}
144
if self.name is not None:
145
result["name"] = self.name
146
if self.value is not None:
147
result["value"] = self.value.to_dict()
148
if self.domain is not None:
149
result["domain"] = self.domain
150
if self.path is not None:
151
result["path"] = self.path
152
if self.size is not None:
153
result["size"] = self.size
154
if self.http_only is not None:
155
result["httpOnly"] = self.http_only
156
if self.secure is not None:
157
result["secure"] = self.secure
158
if self.same_site is not None:
159
result["sameSite"] = self.same_site
160
if self.expiry is not None:
161
result["expiry"] = self.expiry
162
return result
163
164
165
class PartitionKey:
166
"""Represents a storage partition key."""
167
168
def __init__(self, user_context: str | None = None, source_origin: str | None = None):
169
self.user_context = user_context
170
self.source_origin = source_origin
171
172
@classmethod
173
def from_dict(cls, data: dict[str, Any]) -> PartitionKey:
174
"""Creates a PartitionKey instance from a dictionary.
175
176
Args:
177
data: A dictionary containing the partition key information.
178
179
Returns:
180
A new instance of PartitionKey.
181
"""
182
return cls(
183
user_context=data.get("userContext"),
184
source_origin=data.get("sourceOrigin"),
185
)
186
187
188
class BrowsingContextPartitionDescriptor:
189
"""Represents a browsing context partition descriptor."""
190
191
def __init__(self, context: str):
192
self.type = "context"
193
self.context = context
194
195
def to_dict(self) -> dict[str, str]:
196
"""Converts the BrowsingContextPartitionDescriptor to a dictionary.
197
198
Returns:
199
Dict: A dictionary representation of the BrowsingContextPartitionDescriptor.
200
"""
201
return {"type": self.type, "context": self.context}
202
203
204
class StorageKeyPartitionDescriptor:
205
"""Represents a storage key partition descriptor."""
206
207
def __init__(self, user_context: str | None = None, source_origin: str | None = None):
208
self.type = "storageKey"
209
self.user_context = user_context
210
self.source_origin = source_origin
211
212
def to_dict(self) -> dict[str, str]:
213
"""Converts the StorageKeyPartitionDescriptor to a dictionary.
214
215
Returns:
216
Dict: A dictionary representation of the StorageKeyPartitionDescriptor.
217
"""
218
result = {"type": self.type}
219
if self.user_context is not None:
220
result["userContext"] = self.user_context
221
if self.source_origin is not None:
222
result["sourceOrigin"] = self.source_origin
223
return result
224
225
226
class PartialCookie:
227
"""Represents a partial cookie for setting."""
228
229
def __init__(
230
self,
231
name: str,
232
value: BytesValue,
233
domain: str,
234
path: str | None = None,
235
http_only: bool | None = None,
236
secure: bool | None = None,
237
same_site: str | None = None,
238
expiry: int | None = None,
239
):
240
self.name = name
241
self.value = value
242
self.domain = domain
243
self.path = path
244
self.http_only = http_only
245
self.secure = secure
246
self.same_site = same_site
247
self.expiry = expiry
248
249
def to_dict(self) -> dict[str, Any]:
250
"""Converts the PartialCookie to a dictionary.
251
252
Returns:
253
-------
254
Dict: A dictionary representation of the PartialCookie.
255
"""
256
result: dict[str, Any] = {
257
"name": self.name,
258
"value": self.value.to_dict(),
259
"domain": self.domain,
260
}
261
if self.path is not None:
262
result["path"] = self.path
263
if self.http_only is not None:
264
result["httpOnly"] = self.http_only
265
if self.secure is not None:
266
result["secure"] = self.secure
267
if self.same_site is not None:
268
result["sameSite"] = self.same_site
269
if self.expiry is not None:
270
result["expiry"] = self.expiry
271
return result
272
273
274
class GetCookiesResult:
275
"""Represents the result of a getCookies command."""
276
277
def __init__(self, cookies: list[Cookie], partition_key: PartitionKey):
278
self.cookies = cookies
279
self.partition_key = partition_key
280
281
@classmethod
282
def from_dict(cls, data: dict[str, Any]) -> GetCookiesResult:
283
"""Creates a GetCookiesResult instance from a dictionary.
284
285
Args:
286
data: A dictionary containing the get cookies result information.
287
288
Returns:
289
A new instance of GetCookiesResult.
290
"""
291
cookies = [Cookie.from_dict(cookie) for cookie in data.get("cookies", [])]
292
partition_key = PartitionKey.from_dict(data.get("partitionKey", {}))
293
return cls(cookies=cookies, partition_key=partition_key)
294
295
296
class SetCookieResult:
297
"""Represents the result of a setCookie command."""
298
299
def __init__(self, partition_key: PartitionKey):
300
self.partition_key = partition_key
301
302
@classmethod
303
def from_dict(cls, data: dict[str, Any]) -> SetCookieResult:
304
"""Creates a SetCookieResult instance from a dictionary.
305
306
Args:
307
data: A dictionary containing the set cookie result information.
308
309
Returns:
310
A new instance of SetCookieResult.
311
"""
312
partition_key = PartitionKey.from_dict(data.get("partitionKey", {}))
313
return cls(partition_key=partition_key)
314
315
316
class DeleteCookiesResult:
317
"""Represents the result of a deleteCookies command."""
318
319
def __init__(self, partition_key: PartitionKey):
320
self.partition_key = partition_key
321
322
@classmethod
323
def from_dict(cls, data: dict[str, Any]) -> DeleteCookiesResult:
324
"""Creates a DeleteCookiesResult instance from a dictionary.
325
326
Args:
327
data: A dictionary containing the delete cookies result information.
328
329
Returns:
330
A new instance of DeleteCookiesResult.
331
"""
332
partition_key = PartitionKey.from_dict(data.get("partitionKey", {}))
333
return cls(partition_key=partition_key)
334
335
336
class Storage:
337
"""BiDi implementation of the storage module."""
338
339
def __init__(self, conn: WebSocketConnection) -> None:
340
self.conn = conn
341
342
def get_cookies(
343
self,
344
filter: CookieFilter | None = None,
345
partition: BrowsingContextPartitionDescriptor | StorageKeyPartitionDescriptor | None = None,
346
) -> GetCookiesResult:
347
"""Gets cookies matching the specified filter.
348
349
Args:
350
filter: Optional filter to specify which cookies to retrieve.
351
partition: Optional partition key to limit the scope of the operation.
352
353
Returns:
354
A GetCookiesResult containing the cookies and partition key.
355
356
Example:
357
result = await storage.get_cookies(
358
filter=CookieFilter(name="sessionId"),
359
partition=PartitionKey(...)
360
)
361
"""
362
params = {}
363
if filter is not None:
364
params["filter"] = filter.to_dict()
365
if partition is not None:
366
params["partition"] = partition.to_dict()
367
368
result = self.conn.execute(command_builder("storage.getCookies", params))
369
return GetCookiesResult.from_dict(result)
370
371
def set_cookie(
372
self,
373
cookie: PartialCookie,
374
partition: BrowsingContextPartitionDescriptor | StorageKeyPartitionDescriptor | None = None,
375
) -> SetCookieResult:
376
"""Sets a cookie in the browser.
377
378
Args:
379
cookie: The cookie to set.
380
partition: Optional partition descriptor.
381
382
Returns:
383
The result of the set cookie command.
384
"""
385
params = {"cookie": cookie.to_dict()}
386
if partition is not None:
387
params["partition"] = partition.to_dict()
388
389
result = self.conn.execute(command_builder("storage.setCookie", params))
390
return SetCookieResult.from_dict(result)
391
392
def delete_cookies(
393
self,
394
filter: CookieFilter | None = None,
395
partition: BrowsingContextPartitionDescriptor | StorageKeyPartitionDescriptor | None = None,
396
) -> DeleteCookiesResult:
397
"""Deletes cookies that match the given parameters.
398
399
Args:
400
filter: Optional filter to match cookies to delete.
401
partition: Optional partition descriptor.
402
403
Returns:
404
The result of the delete cookies command.
405
"""
406
params = {}
407
if filter is not None:
408
params["filter"] = filter.to_dict()
409
if partition is not None:
410
params["partition"] = partition.to_dict()
411
412
result = self.conn.execute(command_builder("storage.deleteCookies", params))
413
return DeleteCookiesResult.from_dict(result)
414
415