Skip to content

Commit 60e960c

Browse files
authored
Merge pull request r0x0r#1364 from r0x0r/clear-cookies
Clear cookies
2 parents f6e6fe6 + 068722e commit 60e960c

File tree

15 files changed

+158
-19
lines changed

15 files changed

+158
-19
lines changed

docs/guide/api.md

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -508,6 +508,19 @@ window.height
508508

509509
Get height of the window
510510

511+
### window.clear_cookies
512+
513+
``` python
514+
window.clear_cookies()
515+
```
516+
517+
Clear all the cookies including `HttpOnly` ones.
518+
519+
#### Example
520+
521+
* [Cookies](/examples/cookies.html)
522+
523+
511524
### window.create\_confirmation\_dialog
512525

513526
``` python
@@ -762,7 +775,7 @@ Get DOM document's window `window` as an `Element` object
762775

763776
## Window events
764777

765-
Window object exposes a number of lifecycle and window management events. To subscribe to an event, use the `+=` syntax, e.g. `window.events.loaded += func`. Duplicate subscriptions are ignored and function is invoked only once for duplicate subscribers. To unsubscribe, use the `-=` syntax, `window.events.loaded -= func`.
778+
Window object exposes a number of lifecycle and window management events. To subscribe to an event, use the `+=` syntax, e.g. `window.events.loaded += func`. Duplicate subscriptions are ignored and function is invoked only once for duplicate subscribers. To unsubscribe, use the `-=` syntax, `window.events.loaded -= func`. To access the window object from the event handler, you can supply `window` parameter as a first positional argument of the handler.
766779

767780
### window.events.closed
768781

@@ -810,20 +823,20 @@ Event fired when pywebview window is shown.
810823

811824
[Example](/examples/events.html)
812825

813-
814826
## DOM events
815827

816828
_pywebview_ exposes a `window.pywebviewready` DOM event that is fired after `window.pywebview` is created.
817829

818830
[Example](/examples/js_api.html)
819831

820-
821832
## Drag area
822833

823834
With a frameless _pywebview_ window, A window can be moved or dragged by adding a special class called `pywebview-drag-region` in your html
835+
824836
```html
825837
<div class='pywebview-drag-region'>This div element can be used to moved or drag your window like a native OS window</div>
826838
```
839+
827840
The magic class name can be overriden by re-assigning the `webview.DRAG_REGION_SELECTOR` constant.
828841

829842

examples/assets/cookies.html

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,9 @@ <h1>Cookies Example</h1>
2121
<p>Cookies: <span id='cookies'></span></p>
2222
<p>Local storage: <span id='localstorage'></span></p>
2323

24-
2524
<button onClick="setCookies()">Set cookies</button><br/>
25+
<button onClick="showCookies()">Read cookies</button><br/>
26+
<button onClick="clearCookies()">Clear cookies</button>
2627
<script>
2728
var cookieContainer = document.getElementById('cookies')
2829
var localStorageContainer = document.getElementById('localstorage')
@@ -39,6 +40,10 @@ <h1>Cookies Example</h1>
3940
cookieContainer.innerHTML = document.cookie
4041
localStorageContainer.innerHTML = localStorage.getItem('pywebview')
4142
}
43+
44+
function clearCookies() {
45+
pywebview.api.clearCookies().then(showCookies)
46+
}
4247
</script>
4348
</body>
4449
</html>

examples/cookies.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@ def read_cookies(window):
99
print(c.output())
1010

1111

12+
class Api:
13+
def clearCookies(self):
14+
window.clear_cookies()
15+
print('Cookies cleared')
16+
1217
if __name__ == '__main__':
13-
window = webview.create_window('Cookie example', 'assets/cookies.html')
18+
window = webview.create_window('Cookie example', 'assets/cookies.html', js_api=Api())
1419

1520
# We need to explicitly set a http port to persist cookies between sessions
1621
webview.start(read_cookies, window, private_mode=False, http_server=True, http_port=13377)

tests/assets/script.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
window.testResult = 80085
2+
document.cookie = 'pywebview=true'

tests/assets/test.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
<meta charset="utf-8">
55
<title>Test app</title>
66
<link rel="stylesheet" href="styles.css">
7-
<script src="script.js"></script>
7+
<script src="script.js"></script>
88
</head>
99
<body>
1010
<h1 id="heading">Hello there!</h1>

tests/test_cookies.py

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
import pytest
2+
3+
import webview
4+
from time import sleep
5+
from .util import run_test
6+
7+
8+
@pytest.fixture
9+
def window():
10+
return webview.create_window('Cookie test', 'assets/test.html')
11+
12+
13+
def test_get_cookies(window):
14+
run_test(webview, window, get_cookies_test)
15+
16+
17+
def test_clear_cookies(window):
18+
run_test(webview, window, clear_cookies_test)
19+
20+
21+
def get_cookies_test(window):
22+
cookies = window.get_cookies()
23+
assert len(cookies) == 1
24+
assert cookies[0].output() == 'Set-Cookie: pywebview=true; Domain=127.0.0.1; expires=None; Path=/; SameSite=None'
25+
26+
27+
def clear_cookies_test(window):
28+
window.clear_cookies()
29+
cookies = window.get_cookies()
30+
assert len(cookies) == 0

webview/platforms/android.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,11 @@ def _evaluate_js():
333333
lock.acquire()
334334
return js_result
335335

336+
def clear_cookies(_):
337+
def _cookies():
338+
CookieManager.getInstance().removeAllCookies(None)
339+
340+
Runnable(_cookies)()
336341

337342
def get_cookies(_):
338343
def _cookies():

webview/platforms/cef.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,11 @@ def evaluate_js(self, code, unique_id):
174174

175175
return result
176176

177+
def clear_cookies(self):
178+
self.loaded.wait()
179+
self.cookie_manager.DeleteCookies('', '')
180+
self.cookie_manager.FlushStore()
181+
177182
def get_cookies(self):
178183
self.loaded.wait()
179184
self.cookie_visitor.cookies = []
@@ -237,7 +242,7 @@ def wrapper(*args, **kwargs):
237242
uid = args[-1]
238243

239244
if uid not in instances:
240-
logger.error('CEF window with uid {0} does not exist'.format(uid))
245+
logger.error(f'CEF window with uid {uid} does not exist with {func}')
241246
return
242247

243248
return func(*args, **kwargs)
@@ -350,6 +355,12 @@ def evaluate_js(code, result, uid):
350355
return instance.evaluate_js(code, result)
351356

352357

358+
@_cef_call
359+
def clear_cookies(uid):
360+
instance = instances[uid]
361+
return instance.clear_cookies()
362+
363+
353364
@_cef_call
354365
def get_cookies(uid):
355366
instance = instances[uid]

webview/platforms/cocoa.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -524,11 +524,11 @@ def __init__(self, window):
524524
config.userContentController().addScriptMessageHandler_name_(
525525
self._browserDelegate, 'browserDelegate'
526526
)
527+
self.datastore = WebKit.WKWebsiteDataStore.defaultDataStore()
527528

528529
if _settings['private_mode']:
529530
# nonPersisentDataStore preserves cookies for some unknown reason. For this reason we use default datastore
530531
# and clear all the cookies beforehand
531-
self.datastore = WebKit.WKWebsiteDataStore.defaultDataStore()
532532

533533
def dummy_completion_handler():
534534
pass
@@ -540,7 +540,6 @@ def dummy_completion_handler():
540540
data_types, from_start, dummy_completion_handler
541541
)
542542
else:
543-
self.datastore = WebKit.WKWebsiteDataStore.defaultDataStore()
544543
config.setWebsiteDataStore_(self.datastore)
545544

546545
try:
@@ -728,6 +727,16 @@ def center(self):
728727

729728
self.window.setFrameOrigin_(window_frame.origin)
730729

730+
def clear_cookies(self):
731+
def clear():
732+
self.datastore.removeDataOfTypes_modifiedSince_completionHandler_(
733+
WebKit.WKWebsiteDataStore.allWebsiteDataTypes(),
734+
Foundation.NSDate.dateWithTimeIntervalSince1970_(0),
735+
lambda: None,
736+
)
737+
738+
AppHelper.callAfter(clear)
739+
731740
def get_cookies(self):
732741
def handler(cookies):
733742
for c in cookies:
@@ -1308,6 +1317,12 @@ def get_current_url(uid):
13081317
return i.get_current_url()
13091318

13101319

1320+
def clear_cookies(uid):
1321+
i = BrowserView.instances.get(uid)
1322+
if i:
1323+
i.clear_cookies()
1324+
1325+
13111326
def get_cookies(uid):
13121327
i = BrowserView.instances.get(uid)
13131328
if i:

webview/platforms/edgechromium.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,9 @@ def _callback(result):
9494
js_result.append(None)
9595
semaphore.release()
9696

97+
def clear_cookies(self):
98+
self.web_view.CoreWebView2.CookieManager.DeleteAllCookies()
99+
97100
def get_cookies(self, cookies, semaphore):
98101
def _callback(task):
99102
for c in task.Result:

webview/platforms/gtk.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,7 @@ def on_load_finish(self, webview, status):
307307
source_uri=None,
308308
cancellable=None,
309309
callback=None)
310-
310+
311311
self._set_js_api()
312312

313313
def on_download_started(self, session, download):
@@ -494,6 +494,12 @@ def _add_file_filters(self, dialog, file_types):
494494

495495
dialog.add_filter(f)
496496

497+
def clear_cookies(self):
498+
def _clear_cookies():
499+
self.cookie_manager.delete_all_cookies()
500+
501+
glib.idle_add(_clear_cookies)
502+
497503
def get_cookies(self):
498504
def _get_cookies():
499505
self.cookie_manager.get_cookies(self.webview.get_uri(), None, callback, None)
@@ -579,7 +585,7 @@ def create_bridge():
579585
source_uri=None,
580586
cancellable=None,
581587
callback=None)
582-
588+
583589
self.loaded.set()
584590

585591
glib.idle_add(create_bridge)
@@ -702,6 +708,12 @@ def restore(uid):
702708
glib.idle_add(i.restore)
703709

704710

711+
def clear_cookies(uid):
712+
i = BrowserView.instances.get(uid)
713+
if i:
714+
i.clear_cookies()
715+
716+
705717
def get_cookies(uid):
706718
i = BrowserView.instances.get(uid)
707719
if i:

webview/platforms/qt.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -223,7 +223,6 @@ def acceptNavigationRequest(self, url, type, is_main_frame):
223223

224224
class WebPage(QWebPage):
225225
def __init__(self, parent=None, profile=None):
226-
print(profile)
227226
if is_webengine and profile:
228227
super(BrowserView.WebPage, self).__init__(profile, parent.view)
229228
else:
@@ -686,6 +685,10 @@ def set_title(self, title):
686685
def get_cookies(self):
687686
return list(self.cookies.values())
688687

688+
def clear_cookies(self):
689+
self.cookies = {}
690+
self.profile.cookieStore().deleteAllCookies()
691+
689692
def get_current_url(self):
690693
self.loaded.wait()
691694
self.current_url_trigger.emit()
@@ -897,6 +900,12 @@ def set_title(title, uid):
897900
i.set_title(title)
898901

899902

903+
def clear_cookies(uid):
904+
i = BrowserView.instances.get(uid)
905+
if i:
906+
i.clear_cookies()
907+
908+
900909
def get_cookies(uid):
901910
i = BrowserView.instances.get(uid)
902911
if i:

webview/platforms/winforms.py

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ def edge_build(key_type, key, description=''):
122122
from . import mshtml as IE
123123

124124
logger.warning(
125-
'MSHTML is deprecated. See https://pywebview.flowrl.com/guide/renderer.html#web-engine on details how to use Edge Chromium'
125+
'MSHTML is deprecated. See https://pywebview.flowrl.com/guide/web_engine.html on details how to use Edge Chromium'
126126
)
127127
logger.debug('Using WinForms / MSHTML')
128128
IE._set_ie_mode()
@@ -265,9 +265,6 @@ def on_activated(self, *_):
265265
if not self.pywebview_window.focus:
266266
windll.user32.SetWindowLongW(self.Handle.ToInt32(), -20, windll.user32.GetWindowLongW(self.Handle.ToInt32(), -20) | 0x8000000)
267267

268-
if is_cef and self.pywebview_window.focus:
269-
CEF.focus(self.uid)
270-
271268
def on_shown(self, *_):
272269
if not is_cef:
273270
self.shown.set()
@@ -356,6 +353,16 @@ def _evaluate_js():
356353

357354
return self.browser.js_result
358355

356+
def clear_cookies(self):
357+
def _clear_cookies():
358+
self.browser.clear_cookies()
359+
360+
if not is_chromium:
361+
logger.error('clear_cookies() is not implemented for this platform')
362+
return
363+
364+
self.Invoke(Func[Type](_clear_cookies))
365+
359366
def get_cookies(self):
360367
def _get_cookies():
361368
self.browser.get_cookies(cookies, semaphore)
@@ -702,6 +709,15 @@ def create_file_dialog(dialog_type, directory, allow_multiple, save_filename, fi
702709
return None
703710

704711

712+
def clear_cookies(uid):
713+
if is_cef:
714+
CEF.clear_cookies(uid)
715+
i = BrowserView.instances.get(uid)
716+
717+
if i:
718+
i.clear_cookies()
719+
720+
705721
def get_cookies(uid):
706722
if is_cef:
707723
return CEF.get_cookies(uid)

webview/util.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,11 @@ def get_app_root() -> str:
6969
return os.path.dirname(sys.executable)
7070

7171
if 'pytest' in sys.modules:
72+
root_dir = [arg.split('=')[1] for arg in sys.argv if arg.startswith('--rootdir')]
73+
74+
if root_dir:
75+
return root_dir[0]
76+
7277
for arg in reversed(sys.argv):
7378
path = os.path.realpath(arg.split('::')[0])
7479
if os.path.exists(path):

0 commit comments

Comments
 (0)