config.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. #!/usr/bin/env python
  2. import copy
  3. import json
  4. import base64
  5. from dataclasses import dataclass, InitVar
  6. from constants import METRICS_PORT, PROXY_DNS_PORT
  7. # frozen=True raises exception when assigning to fields. This emulates immutability
  8. @dataclass(frozen=True)
  9. class BaseConfig:
  10. cloudflared_binary: str
  11. no_autoupdate: bool = True
  12. metrics: str = f'localhost:{METRICS_PORT}'
  13. def merge_config(self, additional):
  14. config = copy.copy(additional)
  15. config['no-autoupdate'] = self.no_autoupdate
  16. config['metrics'] = self.metrics
  17. return config
  18. @dataclass(frozen=True)
  19. class NamedTunnelBaseConfig(BaseConfig):
  20. # The attributes of the parent class are ordered before attributes in this class,
  21. # so we have to use default values here and check if they are set in __post_init__
  22. tunnel: str = None
  23. credentials_file: str = None
  24. ingress: list = None
  25. hostname: str = None
  26. def __post_init__(self):
  27. if self.tunnel is None:
  28. raise TypeError("Field tunnel is not set")
  29. if self.credentials_file is None:
  30. raise TypeError("Field credentials_file is not set")
  31. if self.ingress is None:
  32. raise TypeError("Field ingress is not set")
  33. def merge_config(self, additional):
  34. config = super(NamedTunnelBaseConfig, self).merge_config(additional)
  35. if 'tunnel' not in config:
  36. config['tunnel'] = self.tunnel
  37. if 'credentials-file' not in config:
  38. config['credentials-file'] = self.credentials_file
  39. # In some cases we want to override default ingress, such as in config tests
  40. if 'ingress' not in config:
  41. config['ingress'] = self.ingress
  42. return config
  43. @dataclass(frozen=True)
  44. class NamedTunnelConfig(NamedTunnelBaseConfig):
  45. full_config: dict = None
  46. additional_config: InitVar[dict] = {}
  47. def __post_init__(self, additional_config):
  48. # Cannot call set self.full_config because the class is frozen, instead, we can use __setattr__
  49. # https://docs.python.org/3/library/dataclasses.html#frozen-instances
  50. object.__setattr__(self, 'full_config',
  51. self.merge_config(additional_config))
  52. def get_url(self):
  53. return "https://" + self.hostname
  54. def base_config(self):
  55. config = self.full_config.copy()
  56. # removes the tunnel reference
  57. del(config["tunnel"])
  58. del(config["credentials-file"])
  59. return config
  60. def get_tunnel_id(self):
  61. return self.full_config["tunnel"]
  62. def get_token(self):
  63. creds = self.get_credentials_json()
  64. token_dict = {"a": creds["AccountTag"], "t": creds["TunnelID"], "s": creds["TunnelSecret"]}
  65. token_json_str = json.dumps(token_dict)
  66. return base64.b64encode(token_json_str.encode('utf-8'))
  67. def get_credentials_json(self):
  68. with open(self.credentials_file) as json_file:
  69. return json.load(json_file)
  70. @dataclass(frozen=True)
  71. class QuickTunnelConfig(BaseConfig):
  72. full_config: dict = None
  73. additional_config: InitVar[dict] = {}
  74. def __post_init__(self, additional_config):
  75. # Cannot call set self.full_config because the class is frozen, instead, we can use __setattr__
  76. # https://docs.python.org/3/library/dataclasses.html#frozen-instances
  77. object.__setattr__(self, 'full_config',
  78. self.merge_config(additional_config))
  79. @dataclass(frozen=True)
  80. class ProxyDnsConfig(BaseConfig):
  81. full_config = {
  82. "port": PROXY_DNS_PORT,
  83. "no-autoupdate": True,
  84. }