rougail/doc/variable/getting_starting.md
2023-11-02 22:17:26 +01:00

13 KiB

Table of Contents

Construire une liste d'options

La configuration du proxy type Mozilla Firefox

L'objectif de ce première exemple est de reproduire cette page de paramètres de Mozilla Firefox :

Firefox parameters page

Les variables vont être créées dans plusieurs fichiers dans un but didactique. Bien évidement toutes les options pourront être mise dans le même fichier.

La famille proxy

Nous allons classer toutes ces variables dans une famille. Cette famille s'appelera proxy. Créons le premier fichier dict/00-proxy.yml

---
version: '1.0'
proxy:
  description: Configure Proxy Access to the Internet

Le type de proxy

Il est possible de définir plusieurs modes de configuration du proxy (de pas de proxy à la configuration d'un fichier de configuration automatique).

Nous allons donc créer une première variable dans cette famille dont la description est "Proxy mode". Créons le deuxième fichier dict/01-proxy_mode.yml

---
version: '1.0'
proxy:
  proxy_mode:
    description: Proxy mode
    type: choice
    choices:
      - No proxy
      - Auto-detect proxy settings for this network
      - Use system proxy settings
      - Manual proxy configuration
      - Automatic proxy configuration URL
    default: No proxy
    mandatory: true

Cette variable nécessite une valeur (la valeur None n'est pas acceptable), elle est donc obligatoire (mandatory).

Si l'utilisateur ne précise pas de valeurs, la valeur de cette variable sera "No proxy" (default).

La variable est à choix (type: choice) donc la liste des valeurs disponible est contrainte (choices), seul les valeurs suivantes sont autorisés :

  • No proxy
  • Auto-detect proxy settings for this network
  • Use system proxy settings
  • Manual proxy configuration
  • Automatic proxy configuration URL

Testons nos deux premiers dictionnaires :

from rougail import Rougail, RougailConfig
from pprint import pprint
 
RougailConfig['dictionaries_dir'] = ['dict']
rougail = Rougail()
config = rougail.get_config()
config.property.read_only()
pprint(config.value.dict(), sort_dicts=False)

Donne :

{'rougail.proxy.proxy_mode': 'No proxy'}

Le mode manuel

Si l'utilisateur choisi le mode de proxy "Manual proxy configuration", on veut voir apparaitre (disabled) une nouvelle sous-famille appelé manual. Créons le fichier dict/02-proxy_manual.yml

---
version: '1.0'
proxy:
  manual:
    description: Manual proxy configuration
    disabled:
      type: jinja
      jinja: |
        {% if rougail.proxy.proxy_mode == 'Manual proxy configuration' %}
        false
        {% else %}
        true
        {% endif %}        

La configuration du proxy HTTP

Dans cette famille ajoutons une sous-famille http_proxy contenant les variables http_address et http_port. Créons le fichier dict/03-proxy_manual_http_proxy.yml

---
version: '1.0'
proxy:
  manual:
    http_proxy:
      description: HTTP Proxy
      http_address:
        description: HTTP address
        type: domainname
        mandatory: true
      http_port:
        description: HTTP Port
        type: port
        default: '8080'

Les deux variables ont des types particulier (domainname ou port) pour valider les valeurs configurer par l'utilisateur.

Dupliquer la configuration HTTPS

On veux proposer à l'utilisateur la possiblité de renseigner le même proxy pour les requêtes HTTPS. Créons le fichier dict/04-proxy_manual_http_use_for_https.yml :

version: '1.0'
proxy:
  manual:
    use_for_https:
      description: Also use this proxy for HTTPS
      type: boolean

Cette variable est de type boolean. Sa valeur par défaut est True.

La configuration du proxy HTTPS

Ajoutons une nouvelle sous-famille ssl\_proxy avec les variables ssl_address et ssl_port. Créons le fichier dict/05-proxy_manual_ssl_proxy.yml :

version: '1.0'
proxy:
  manual:
    ssl_proxy:
      description: HTTPS Proxy
      hidden:
        type: variable
        variable: rougail.proxy.manual.use_for_https
      ssl_address:
        description: HTTPS address
        type: domainname
        default:
          type: jinja
          jinja: |
            {% if rougail.proxy.manual.use_for_https %}
            {{ rougail.proxy.manual.http_proxy.http_address }}
            {% endif %}            
        mandatory: true
      ssl_port:
        description: HTTPS Port
        type: port
        default:
          type: jinja
          jinja: |
            {% if rougail.proxy.manual.use_for_https %}
            {{ rougail.proxy.manual.http_proxy.http_port }}
            {% endif %}            
        mandatory: true

Suivant la valeur de la variable use\_for\_https cette famille apparaitra ou disparaitra. Contrairement à tout à l'heure, la famille n'est pas désactivé (disabled) parce que les variables devront rester accessible en mode lecture seule.

Testons ce point précis :

>>> from rougail import Rougail, RougailConfig
>>> from pprint import pprint
>>>  
>>> RougailConfig['dictionaries_dir'] = ['dict']
>>> rougail = Rougail()
>>> config = rougail.get_config()
>>> config.property.read_only()
>>> pprint(config.value.dict(), sort_dicts=False)
{'rougail.proxy.proxy_mode': 'No proxy'}
>>> config.property.read_write()
>>> config.option('rougail.proxy.proxy_mode').value.set('Manual proxy configuration')
>>> config.option('rougail.proxy.manual.http_proxy.http_address').value.set('proxy.example')
>>> pprint(config.value.dict(), sort_dicts=False)
{'rougail.proxy.proxy_mode': 'Manual proxy configuration',
 'rougail.proxy.manual.http_proxy.http_address': 'proxy.example',
 'rougail.proxy.manual.http_proxy.http_port': '8080',
 'rougail.proxy.manual.use_for_https': True}
>>> config.property.read_only()
>>> pprint(config.value.dict(), sort_dicts=False)
{'rougail.proxy.proxy_mode': 'Manual proxy configuration',
 'rougail.proxy.manual.http_proxy.http_address': 'proxy.example',
 'rougail.proxy.manual.http_proxy.http_port': '8080',
 'rougail.proxy.manual.use_for_https': True,
 'rougail.proxy.manual.ssl_proxy.ssl_address': 'proxy.example',
 'rougail.proxy.manual.ssl_proxy.ssl_port': '8080'}

Alors que la famille rougail.proxy.manual n'était pas présente lors que rougail.proxy.proxy_mode est à No proxy, la famille rougail.proxy.manual.ssl_proxy devient visible en mode lecture seule (et uniquement en mode lecture seule) si rougail.proxy.manual.use\_for\_https est à 'True'.

On voit bien également que les valeurs des variables de rougail.http_proxy on bien été copié dans rougail.ssl_proxy. Ces valeurs ne seront copié que si use\_for\_https est à "True" comme précisé dans les valeurs par défaut des variables.

La configuration du proxy SOCKS

Ajoutons une nouvelle sous-famille socks\_proxy avec les variables socks\_address, socks\_port et socks\_version. Créons le fichier dict/06-proxy_manual_socks_proxy.yml :

version: '1.0'
proxy:
  manual:
    socks_proxy:
      description: SOCKS Proxy
      socks_address:
        description: SOCKS Address
        type: domainname
      socks_port:
        description: SOCKS Port
        type: port
      socks_version:
        description: SOCKS host version used by proxy
        type: choice
        choices:
          - v4
          - v5
        default: v5

Le mode détection automatique

Ajoutons une nouvelle sous-variable auto. Créons le fichier dict/07-proxy_auto.yml :

version: '1.0'
proxy:
  auto:
    type: web_address
    description: Automatic proxy configuration URL
    mandatory: true
    disabled:
      type: jinja
      jinja: |
        {% if rougail.proxy.proxy_mode == 'Automatic proxy configuration URL' %}
        false
        {% else %}
        true
        {% endif %}        

Le type web_address impose une valeur qui commence par http:// ou https://.

Les exceptions au proxy

Enfin ajoutons une variable contenant les exceptions au proxy. Pour cela créons le fichier dict/07-proxy_no_proxy.yml :

version: '1.0'
proxy:
  no_proxy:
    description: Address for which proxy will be desactivated
    multi: true
    disabled:
      type: jinja
      jinja: |
        {% if rougail.proxy.proxy_mode == 'No proxy' %}
        true
        {% else %}
        false
        {% endif %}        
    validators:
      - type: jinja
        jinja: '{{ rougail.no_proxy | valid_no_proxy }}'

Il peut y avoir plusieurs exceptions au proxy au proxy, la variable est donc multi. Cette varible n'est pas accessible uniquement si aucun proxy n'est défini.

Enfin, on veut valider le contenu de la variable. Il n'y a pas de type correspond dans Rougail, donc on fait la fonction de validation suivante dans le fichier functions.py :

from tiramisu import DomainnameOption 


def valid_no_proxy(value: str):
    try:   
        DomainnameOption('',
                         '',
                         value,
                         allow_ip=True,
                         allow_cidr_network=True,
                         allow_without_dot=True,
                         allow_startswith_dot=True,
                         )
    except ValueError as err:
        return err

Pour tester :

from rougail import Rougail, RougailConfig
RougailConfig['functions_file'] = 'functions.py'
from pprint import pprint
 
RougailConfig['dictionaries_dir'] = ['dict']
rougail = Rougail()
config = rougail.get_config()
config.property.read_only()
pprint(config.value.dict(), sort_dicts=False)

La demande d'authentification

Rien de particulier à la création de la demande d'authentification. Pour cela créons le fichier dict/08-proxy_prompt_authentication.yml :

version: '1.0'
proxy:
  prompt_authentication:
    description: Prompt for authentication if password is saved
    type: boolean
    default: true
    disabled:
      type: jinja
      jinja: |
        {% if rougail.proxy.proxy_mode == 'No proxy' %}
        true
        {% else %}
        false
        {% endif %}        

Le DNS du proxy SOCKS v5

La question sur le DNS pour le proxy SOCKS v5 n'apparait que si le proxy est configuré et que la version du proxy SOCKS sélectionné est bien la "v5".

Créons le fichier dict.09-proxy_proxy_dns_socks5.yml :

version: '1.0'
proxy:
  proxy_dns_socks5:
    description: Use proxy DNS when using SOCKS v5
    type: boolean
    default: false
    disabled:
      type: jinja
      params:
        socks_version:
          type: variable
          variable: rougail.proxy.manual.socks_proxy.socks_version
          propertyerror: false
      jinja: |
        {% if rougail.proxy.proxy_mode == 'No proxy' %}
        true
        {% elif socks_version is undefined or socks_version == 'v4' %}
        true
        {% else %}
        false
        {% endif %}        

La difficulté c'est que la variable rougail.proxy.manual.socks_proxy.socks_version peut être désactivé (et donc non utilisable dans un calcul). Dans ce cas, nous allons ajouter un paramètre (ici appelé socks_version) qui contiendra, s'il n'y a pas d'erreur de propriété, la valeur de la variable. Sinon le paramètre ne sera pas passé au template Jinja. C'est pourquoi il faut tester dans le template Jinja si la variable socks_version existe bien.

Le DNS à travers HTTPS

Enfin nous allons configurer le DNS à travers HTTPS dans le fichier 10-proxy_dns_over_https.yml :

version: '1.0'
proxy:
  dns_over_https:
    description: DNS over HTTPS
    enable_dns_over_https:
      description: Enable DNS over HTTPS
      type: boolean
      default: false
    provider:
      description: Use Provider
      type: choice
      choices:
        - Cloudflare
        - NextDNS
        - Custom
      default: Cloudflare
      disabled:
        type: jinja
        jinja: |
          {% if rougail.proxy.dns_over_https.enable_dns_over_https %}
          false
          {% else %}
          true
          {% endif %}          
    custom_dns_url:
      description: Custom DNS URL
      type: web_address
      mandatory: true
      disabled:
        type: jinja
        params:
          provider:
            type: variable
            variable: rougail.proxy.dns_over_https.provider
            propertyerror: false
        jinja: |
          {% if provider is defined and provider == 'Custom' %}
          false
          {% else %}
          true
          {% endif %}          
      validators:
        - type: jinja
          jinja: |
            {% if rougail.proxy.dns_over_https.custom_dns_url.startswith('http://') %}
            only https is allowed
            {% endif %}            

La seule particularité ici c'est qu'on a ajouté une validation supplémentaire à la variable custom_dns_url. Seul une adresse commençant par https:// est autorisé (pas http://).