A full application

The firefox network configuration

Now we are going to resume everything we have seen with a concrete example. We’re going to take an example based on the Mozilla Firefox proxy’s configuration, like what is required when you open the network settings in the General configuration’s firefox page:

_images/firefox_preferences.png

The tiramisu’s configuration

Build the Config

First, let’s create our options :

 1from tiramisu import BoolOption, ChoiceOption, DomainnameOption, PortOption, URLOption, \
 2                     OptionDescription, Calculation, Params, ParamOption, ParamValue, \
 3                     Config, calc_value, calc_value_property_help
 4proxy_mode = ChoiceOption('proxy_mode',
 5                          'Proxy\'s config mode',
 6                          ('No proxy',
 7                           'Auto-detect proxy settings for this network',
 8                           'Use system proxy settings',
 9                           'Manual proxy configuration',
10                           'Automatic proxy configuration URL'),
11                          default = 'No proxy',
12                          properties=('mandatory',))

This first option is the most important one : its value will determine which other options are disabled and which are not. The same thing will happen with other options later. Here are the others options we’ll be using :

  1http_address = DomainnameOption('http_address',
  2                                'Address',
  3                                allow_ip=True,
  4                                properties=('mandatory',))
  5http_port = PortOption('http_port',
  6                       'Port',
  7                       default='8080',
  8                       properties=('mandatory',))
  9http_proxy = OptionDescription('http_proxy',
 10                               'HTTP Proxy',
 11                               [http_address, http_port])
 12
 13use_for_all_protocols = BoolOption('use_for_all_protocols',
 14                                   'Use HTTP IP and Port for all protocols',
 15                                   default=True)
 16
 17
 18# if this option is valued with 'True', set all the others IP and port values to the same as HTTP IP and port.
 19ssl_address = DomainnameOption('ssl_address',
 20                               'Address',
 21                               Calculation(protocols_settings,
 22                                           Params((ParamOption(use_for_all_protocols), ParamOption(http_address)))),
 23                               allow_ip=True,
 24                               properties=('mandatory', 'force_default_on_freeze',
 25                                           Calculation(calc_value,
 26                                                       Params(ParamValue('frozen'),
 27                                                              kwargs={'condition': ParamOption(use_for_all_protocols, todict=True),
 28                                                                      'expected': ParamValue(True)}),
 29                                                       calc_value_property_help)))
 30ssl_port = PortOption('ssl_port',
 31                      'Port',
 32                      Calculation(protocols_settings,
 33                                  Params((ParamOption(use_for_all_protocols), ParamOption(http_port)))),
 34                      properties=('mandatory', 'force_default_on_freeze',
 35                                  Calculation(calc_value,
 36                                              Params(ParamValue('frozen'),
 37                                                     kwargs={'condition': ParamOption(use_for_all_protocols, todict=True),
 38                                                             'expected': ParamValue(True)}),
 39                                              calc_value_property_help)))
 40ssl_proxy = OptionDescription('ssl_proxy',
 41                              'SSL Proxy',
 42                              [ssl_address, ssl_port],
 43                              properties=(Calculation(calc_value,
 44                                                      Params(ParamValue('hidden'),
 45                                                             kwargs={'condition': ParamOption(use_for_all_protocols, todict=True),
 46                                                                     'expected': ParamValue(True)}),
 47                                                      calc_value_property_help),))
 48
 49ftp_address = DomainnameOption('ftp_address',
 50                               'Address',
 51                               Calculation(protocols_settings,
 52                                           Params((ParamOption(use_for_all_protocols), ParamOption(http_address)))),
 53                               allow_ip=True,
 54                               properties=('mandatory', 'force_default_on_freeze',
 55                                           Calculation(calc_value,
 56                                                       Params(ParamValue('frozen'),
 57                                                              kwargs={'condition': ParamOption(use_for_all_protocols, todict=True),
 58                                                                      'expected': ParamValue(True)}),
 59                                                       calc_value_property_help)))
 60ftp_port = PortOption('ftp_port',
 61                      'Port',
 62                      Calculation(protocols_settings,
 63                                  Params((ParamOption(use_for_all_protocols), ParamOption(http_port)))),
 64                      properties=('force_default_on_freeze',
 65                                  Calculation(calc_value,
 66                                              Params(ParamValue('frozen'),
 67                                                     kwargs={'condition': ParamOption(use_for_all_protocols, todict=True),
 68                                                             'expected': ParamValue(True)}),
 69                                              calc_value_property_help)))
 70ftp_proxy = OptionDescription('ftp_proxy',
 71                              'FTP Proxy',
 72                              [ftp_address, ftp_port],
 73                              properties=(Calculation(calc_value,
 74                                                      Params(ParamValue('hidden'),
 75                                                             kwargs={'condition': ParamOption(use_for_all_protocols, todict=True),
 76                                                                     'expected': ParamValue(True)}),
 77                                                      calc_value_property_help),))
 78
 79socks_address = DomainnameOption('socks_address',
 80                                 'Address',
 81                                 Calculation(protocols_settings,
 82                                             Params((ParamOption(use_for_all_protocols), ParamOption(http_address)))),
 83                                 allow_ip=True,
 84                                 properties=('mandatory', 'force_default_on_freeze',
 85                                             Calculation(calc_value,
 86                                                         Params(ParamValue('frozen'),
 87                                                                kwargs={'condition': ParamOption(use_for_all_protocols, todict=True),
 88                                                                        'expected': ParamValue(True)}),
 89                                                         calc_value_property_help)))
 90socks_port = PortOption('socks_port',
 91                        'Port',
 92                        Calculation(protocols_settings,
 93                                    Params((ParamOption(use_for_all_protocols), ParamOption(http_port)))),
 94                        properties=('mandatory', 'force_default_on_freeze',
 95                                    Calculation(calc_value,
 96                                                Params(ParamValue('frozen'),
 97                                                       kwargs={'condition': ParamOption(use_for_all_protocols, todict=True),
 98                                                               'expected': ParamValue(True)}),
 99                                                calc_value_property_help)))
100socks_version = ChoiceOption('socks_version',
101                             'SOCKS host version used by proxy',
102                             ('v4', 'v5'),
103                             default='v5',
104                             properties=('force_default_on_freeze',
105                                         Calculation(calc_value,
106                                                     Params(ParamValue('frozen'),
107                                                            kwargs={'condition': ParamOption(use_for_all_protocols, todict=True),
108                                                                    'expected': ParamValue(True)}),
109                                                     calc_value_property_help)))
110socks_proxy = OptionDescription('socks_proxy',
111                                'Socks host proxy',
112                                [socks_address, socks_port, socks_version],
113                                properties=(Calculation(calc_value,
114                                                        Params(ParamValue('hidden'),
115                                                               kwargs={'condition': ParamOption(use_for_all_protocols, todict=True),
116                                                                       'expected': ParamValue(True)}),
117                                                        calc_value_property_help),))
118protocols = OptionDescription('protocols',
119                              'Protocols parameters',
120                              [http_proxy,
121                               use_for_all_protocols,
122                               ssl_proxy,
123                               ftp_proxy,
124                               socks_proxy],
125                              properties=(Calculation(calc_value,
126                                                      Params(ParamValue('disabled'),
127                                                             kwargs={'condition': ParamOption(proxy_mode, todict=True),
128                                                                     'expected': ParamValue('Manual proxy configuration'),
129                                                                     'reverse_condition': ParamValue(True)}),
130                                                      calc_value_property_help),))
131
132auto_config_url = URLOption('auto_config_url',
133                            'Proxy\'s auto config URL',
134                            allow_ip=True,
135                            properties=('mandatory',
136                                        Calculation(calc_value,
137                                                    Params(ParamValue('disabled'),
138                                                           kwargs={'condition': ParamOption(proxy_mode, todict=True),
139                                                                   'expected': ParamValue('Automatic proxy configuration URL'),
140                                                                   'reverse_condition': ParamValue(True)}),
141                                                    calc_value_property_help),))
142
143no_proxy = DomainnameOption('no_proxy',
144                            'Address for which proxy will be desactivated',
145                            multi=True,
146                            allow_ip=True,
147                            allow_cidr_network=True,
148                            allow_without_dot=True,
149                            allow_startswith_dot=True,
150                            properties=(Calculation(calc_value,
151                                                    Params(ParamValue('disabled'),
152                                                           kwargs={'condition': ParamOption(proxy_mode, todict=True),
153                                                                   'expected': ParamValue('No proxy')}),
154                                                    calc_value_property_help),))
155
156prompt_authentication = BoolOption('prompt_authentication',
157                                   'Prompt for authentication if password is saved',
158                                   default=False,
159                                   properties=(Calculation(calc_value,
160                                                           Params(ParamValue('disabled'),
161                                                                  kwargs={'condition': ParamOption(proxy_mode, todict=True),
162                                                                          'expected': ParamValue('No proxy')}),
163                                                           calc_value_property_help),))
164proxy_dns_socks5 = BoolOption('proxy_dns_socks5',
165                              'Use Proxy DNS when using SOCKS v5',
166                              default=False,
167                              properties=(Calculation(calc_value,
168                                                      Params(ParamValue('disabled'),
169                                                             kwargs={'condition_1': ParamOption(socks_version,
170                                                                                                raisepropertyerror=True),
171                                                                     'expected_1': ParamValue('v4'),
172                                                                     'condition_2': ParamOption(proxy_mode, todict=True),
173                                                                     'expected_2': ParamValue('No proxy'),
174                                                                     'condition_operator': ParamValue('OR')}),
175                                                      calc_value_property_help),))
176enable_dns_over_https = BoolOption('enable_dns_over_https',
177                                   'Enable DNS over HTTPS',
178                                   default=False)
179
180used_dns = ChoiceOption('used_dns',
181                        'Used DNS',
182                        ('default', 'custom'),
183                        properties=(Calculation(calc_value,
184                                                Params(ParamValue('disabled'),
185                                                       kwargs={'condition': ParamOption(enable_dns_over_https, todict=True),
186                                                               'expected': ParamValue(False)}),
187                                                calc_value_property_help),))
188
189custom_dns_url = URLOption('custom_dns_url',
190                           'Custom DNS URL',
191                           properties=(Calculation(calc_value,
192                                                   Params(ParamValue('disabled'),
193                                                          kwargs={'condition': ParamOption(used_dns, todict=True,
194                                                                                           raisepropertyerror=True),
195                                                                  'expected': ParamValue('default')}),
196                                                   calc_value_property_help),))
197dns_over_https = OptionDescription('dns_over_https',
198                                   'DNS over HTTPS',
199                                   [enable_dns_over_https, used_dns, custom_dns_url])

As you can see, we’re using value, property and Calculation in the setting of our options, because we have many options which value or accessibility is depending on the value of other options.

Now we need to create OptionDescriptions and configs :

 1rootod = OptionDescription('proxy',
 2                           'Proxy parameters',
 3                           [proxy_mode,
 4                            protocols,
 5                            no_proxy,
 6                            auto_config_url,
 7                            prompt_authentication,
 8                            proxy_dns_socks5, dns_over_https])
 9proxy_config = Config(rootod)
10proxy_config.property.read_write()

Download the full code of this example.

As you can see, we regrouped a lot of options in ‘protocols’, so we can set a calculated disabled property that is apply to all those options. This way, we don’t have to put the instruction on every option one by one.

Let’s try

Now that we have our Config, it’s time to run some tests ! Here are a few code blocks you can test and the results you should get :

  1. Automatic proxy configuration URL:

>>> proxy_config.property.read_write()
>>> proxy_config.option('proxy_mode').value.set('Automatic proxy configuration URL')
>>> proxy_config.option('auto_config_url').value.set('http://192.168.1.1/wpad.dat')
>>> proxy_config.property.read_only()
>>> for path, value in proxy_config.value.get().items():
...     print(proxy_config.option(path).option.doc() + ': "' + str(value) + '"')
Proxy's config mode: "Automatic proxy configuration URL"
Address for which proxy will be desactivated: "[]"
Proxy's auto config URL: "http://192.168.1.1/wpad.dat"
Prompt for authentication if password is saved: "False"
Enable DNS over HTTPS: "False"
  1. Auto-detect proxy settings for this network:

>>> proxy_config.property.read_write()
>>> proxy_config.option('proxy_mode').value.set('Auto-detect proxy settings for this network')
>>> proxy_config.option('no_proxy').value.set(['localhost',
...                                            '127.0.0.1',
...                                            '192.16.10.150',
...                                            '192.168.5.101',
...                                            '192.168.56.101/32',
...                                            '192.168.20.0/24',
...                                            '.tiramisu.org',
...                                            'mozilla.org'])
>>> proxy_config.option('dns_over_https.enable_dns_over_https').value.set(True)
>>> proxy_config.option('dns_over_https.used_dns').value.set('default')
>>> proxy_config.property.read_only()
>>> for path, value in proxy_config.value.get().items():
...    print(proxy_config.option(path).option.doc() + ': "' + str(value) + '"')
Proxy's config mode: "Auto-detect proxy settings for this network"
Address for which proxy will be desactivated: "['localhost', '127.0.0.1', '192.16.10.150', '192.168.5.101', '192.168.56.101/32', '192.168.20.0/24', '.tiramisu.org', 'mozilla.org']"
Prompt for authentication if password is saved: "False"
Enable DNS over HTTPS: "True"
Used DNS: "default"

Set use_for_all_protocols to True:

>>> proxy_config.property.read_write()
>>> proxy_config.option('protocols.use_for_all_protocols').value.set(True)
>>> proxy_config.property.read_only()
>>> for path, value in proxy_config.value.get().items():
...     print(proxy_config.option(path).option.doc() + ': "' + str(value) + '"')
Proxy's config mode: "Manual proxy configuration"
Address: "192.168.20.1"
Port: "8080"
Use HTTP IP and Port for all protocols: "True"
Address: "192.168.20.1"
Port: "8080"
Address: "192.168.20.1"
Port: "8080"
Address: "192.168.20.1"
Port: "8080"
SOCKS host version used by proxy: "v5"
Address for which proxy will be desactivated: "[]"
Prompt for authentication if password is saved: "False"
Use Proxy DNS when using SOCKS v5: "False"
Enable DNS over HTTPS: "True"
Used DNS: "custom"
Custom DNS URL: "https://dns-url.com"