Project

General

Profile

Download (5.02 KB) Statistics
| Branch: | Tag: | Revision:

haketilo / test / profiles.py @ c699b640

1
# SPDX-License-Identifier: GPL-3.0-or-later
2

    
3
"""
4
Browser profiles and Selenium driver initialization
5
"""
6

    
7
# This file is part of Haketilo.
8
#
9
# Copyright (C) 2021 Wojtek Kosior <koszko@koszko.org>
10
#
11
# This program is free software: you can redistribute it and/or modify
12
# it under the terms of the GNU General Public License as published by
13
# the Free Software Foundation, either version 3 of the License, or
14
# (at your option) any later version.
15
#
16
# This program is distributed in the hope that it will be useful,
17
# but WITHOUT ANY WARRANTY; without even the implied warranty of
18
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19
# GNU General Public License for more details.
20
#
21
# You should have received a copy of the GNU General Public License
22
# along with this program.  If not, see <https://www.gnu.org/licenses/>.
23
#
24
# I, Wojtek Kosior, thereby promise not to sue for violation of this file's
25
# license. Although I request that you do not make use this code in a
26
# proprietary program, I am not going to enforce this in court.
27

    
28
from selenium import webdriver
29
from selenium.webdriver.firefox.options import Options
30
import json
31
from shutil import rmtree
32

    
33
from .misc_constants import *
34

    
35
class HaketiloFirefox(webdriver.Firefox):
36
    """
37
    This wrapper class around selenium.webdriver.Firefox adds a `loaded_scripts`
38
    instance property that gets resetted to an empty array every time the
39
    `get()` method is called and also facilitates removing the temporary
40
    profile directory after Firefox quits.
41
    """
42
    def __init__(self, *args, **kwargs):
43
        super().__init__(*args, **kwargs)
44
        self.reset_loaded_scripts()
45

    
46
    def reset_loaded_scripts(self):
47
        self.loaded_scripts = []
48

    
49
    def get(self, *args, **kwargs):
50
        self.reset_loaded_scripts()
51
        super().get(*args, **kwargs)
52

    
53
    def quit(self, *args, **kwargs):
54
        profile_path = self.firefox_profile.path
55
        super().quit(*args, **kwargs)
56
        rmtree(profile_path, ignore_errors=True)
57

    
58
def set_profile_proxy(profile, proxy_host, proxy_port):
59
    """
60
    Create a Firefox profile that uses the specified HTTP proxy for all
61
    protocols.
62
    """
63
    # proxy type 1 designates "manual"
64
    profile.set_preference('network.proxy.type',                 1)
65
    profile.set_preference('network.proxy.no_proxies_on',        '')
66
    profile.set_preference('network.proxy.share_proxy_settings', True)
67

    
68
    for proto in ['http', 'ftp', 'socks', 'ssl']:
69
        profile.set_preference(f'network.proxy.{proto}',             proxy_host)
70
        profile.set_preference(f'network.proxy.{proto}_port',        proxy_port)
71
        profile.set_preference(f'network.proxy.backup.{proto}',      '')
72
        profile.set_preference(f'network.proxy.backup.{proto}_port', 0)
73

    
74
def set_profile_console_logging(profile):
75
    profile.set_preference('devtools.console.stdout.content', True)
76

    
77
# The function below seems not to work for extensions that are
78
# temporarily-installed in Firefox safe mode. Testing is needed to see if it
79
# works with non-temporary extensions (without safe mode).
80
def set_webextension_uuid(profile, extension_id, uuid=default_extension_uuid):
81
    """
82
    Firefox would normally assign a unique, random UUID to installed extension.
83
    This UUID is needed to easily navigate to extension's settings page (and
84
    other extension's pages). Since there's no way to learn such UUID with
85
    current WebDriver implementation, this function works around this by telling
86
    Firefox to use a predefined UUID for a certain extension.
87
    """
88
    profile.set_preference('extensions.webextensions.uuids',
89
                           json.dumps({extension_id: uuid}))
90

    
91
def firefox_safe_mode(firefox_binary=default_firefox_binary,
92
                      proxy_host=default_proxy_host,
93
                      proxy_port=default_proxy_port):
94
    """
95
    Initialize a Firefox instance controlled by selenium. The instance is
96
    started in safe mode.
97
    """
98
    profile = webdriver.FirefoxProfile()
99
    set_profile_proxy(profile, proxy_host, proxy_port)
100
    set_profile_console_logging(profile)
101

    
102
    options = Options()
103
    options.add_argument('--safe-mode')
104

    
105
    return HaketiloFirefox(options=options, firefox_profile=profile,
106
                           firefox_binary=firefox_binary)
107

    
108
def firefox_with_profile(firefox_binary=default_firefox_binary,
109
                         profile_dir=default_clean_profile_dir,
110
                         proxy_host=default_proxy_host,
111
                         proxy_port=default_proxy_port):
112
    """
113
    Initialize a Firefox instance controlled by selenium. The instance is
114
    started using an empty profile (either the default one or the one passed to
115
    `configure` script). The empty profile is meant to make Firefox start with
116
    globally-installed extensions disabled.
117
    """
118
    profile = webdriver.FirefoxProfile(profile_dir)
119
    set_profile_proxy(profile, proxy_host, proxy_port)
120
    set_profile_console_logging(profile)
121
    set_webextension_uuid(profile, default_haketilo_id)
122

    
123
    return HaketiloFirefox(firefox_profile=profile,
124
                           firefox_binary=firefox_binary)
(5-5/9)