Source code for onbasca.base.models.bridge

# SPDX-FileCopyrightText: 2022 The Tor Project, Inc.
#
# SPDX-License-Identifier: BSD-3-Clause
"""Bridge base model."""
import logging
import re

from django.db import models

from onbasca.bridgeline import parse_bridge_line

from . import BaseManager, BaseModel

logger = logging.getLogger(__name__)


[docs] def fingerprint_from_bridgeline(bridgeline): """ Obtain the bridge fingerprint from a bridge line. From ``7. Displaying Bridge Information`` (https://gitlab.torproject.org/tpo/core/torspec/-/blob/main/bridgedb-spec.txt#L357) Bridges are formatted as:: <address:port> NL Pluggable transports are formatted as:: <transportname> SP <address:port> [SP arglist] NL Example:: - with transport:: obfs4 <ip>:<port> <fingerprint> cert=<cert> iat-mode=<iat-mode> - without transport:: <ip>:<port> <fingerprint> """ # Regular expression from: # https://gitlab.torproject.org/tpo/anti-censorship/bridgestrap/-/blob/719bed120f6d01829d04c19e21a80fc9a04f393e/tor.go#L41 # noqa fp_re = re.compile("([A-F0-9]{40})") # Assume any line as ``(transport) <ip>:<port> (<fingerprint>)`` is valid. fp = re.findall(fp_re, bridgeline) if len(fp) == 1: logger.debug("bridgeline contains fingerprint.") return fp[0] # Regular expression from: # https://gitlab.torproject.org/tpo/anti-censorship/bridgestrap/-/blob/719bed120f6d01829d04c19e21a80fc9a04f393e/cache.go#L17 # noqa ip_port_re = re.compile("[0-9a-z\[\]\.:]+:[0-9]{1,5}") # noqa:W605 ip_port = re.findall(ip_port_re, bridgeline) if len(ip_port) == 1: logger.warning("Not found fingerprint in bridgeline but found ip:port") return ip_port[0] logger.warning("No fingerprint nor ip found in bridgeline") return None
[docs] class BridgeManagerBase(BaseManager):
[docs] def from_bridgeline(self, bridgeline): """Create a bridge from a bridgeline""" logger.debug("Creating bridge from bridgeline %s", bridgeline) bridgeline_kwargs = parse_bridge_line(bridgeline) if not bridgeline_kwargs: return "bridgeline is not valid.", False # if there're several `kwargs`, then the fingerprint is in the 2nd # position. if ( len([kwarg for kwarg in bridgeline_kwargs if kwarg is not None]) > 1 ): fingerprint = bridgeline_kwargs[1] # otherwise, use the addrport as the fingerprint, which is in the 1st # position. else: fingerprint = bridgeline_kwargs[0] bridge, created = self.update_or_create( fingerprint=fingerprint, defaults={"bridgeline": bridgeline}, ) logger.info("Bridge %s created %s", bridge, created) return bridge, created
[docs] class BridgeBase(BaseModel):
[docs] class Meta: abstract = True
objects = BridgeManagerBase() fingerprint = models.CharField(primary_key=True, max_length=40) # What's the max and min length?, 154? bridgeline = models.CharField(max_length=255, null=True, blank=True) def __str__(self): return "{}".format(self.fingerprint)