CCrypto VPN public website https://vpn.ccrypto.org/
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

178 lines
5.3 KiB

  1. from datetime import timedelta, datetime
  2. import lcoreapi
  3. from django.conf import settings
  4. import logging
  5. cluster_messages = settings.LAMBDAINST_CLUSTER_MESSAGES
  6. lcore_settings = settings.LCORE
  7. LCORE_BASE_URL = lcore_settings.get('BASE_URL')
  8. LCORE_API_KEY = lcore_settings['API_KEY']
  9. LCORE_API_SECRET = lcore_settings['API_SECRET']
  10. LCORE_SOURCE_ADDR = lcore_settings.get('SOURCE_ADDRESS')
  11. LCORE_INST_SECRET = lcore_settings['INST_SECRET']
  12. LCORE_TIMEOUT = lcore_settings.get('TIMEOUT', 10)
  13. # The default is to log the exception and only raise it if we cannot show
  14. # the previous value or a default value instead.
  15. LCORE_RAISE_ERRORS = bool(lcore_settings.get('RAISE_ERRORS', False))
  16. LCORE_CACHE_TTL = lcore_settings.get('CACHE_TTL', 60)
  17. if isinstance(LCORE_CACHE_TTL, int):
  18. LCORE_CACHE_TTL = timedelta(seconds=LCORE_CACHE_TTL)
  19. assert isinstance(LCORE_CACHE_TTL, timedelta)
  20. VPN_AUTH_STORAGE = settings.VPN_AUTH_STORAGE
  21. assert VPN_AUTH_STORAGE in ('core', 'inst')
  22. core_api = lcoreapi.API(LCORE_API_KEY, LCORE_API_SECRET, LCORE_BASE_URL,
  23. timeout=LCORE_TIMEOUT)
  24. class APICache:
  25. """ Cache data for a time, try to update and silence errors.
  26. Outdated data is not a problem.
  27. """
  28. def __init__(self, ttl=None, initial=None):
  29. self.cache_date = datetime.fromtimestamp(0)
  30. self.ttl = ttl or LCORE_CACHE_TTL
  31. self.has_cached_value = initial is not None
  32. self.cached = initial() if initial else None
  33. def query(self, wrapped, *args, **kwargs):
  34. try:
  35. return wrapped(*args, **kwargs)
  36. except lcoreapi.APIError:
  37. logger = logging.getLogger('django.request')
  38. logger.exception("core api error")
  39. if LCORE_RAISE_ERRORS:
  40. raise
  41. if not self.has_cached_value:
  42. # We only return a default value if we were given one.
  43. # Prevents returning an unexpected None.
  44. raise
  45. # Return previous value
  46. return self.cached
  47. def __call__(self, wrapped):
  48. def wrapper(*args, **kwargs):
  49. if self.cache_date > (datetime.now() - self.ttl):
  50. return self.cached
  51. self.cached = self.query(wrapped, *args, **kwargs)
  52. # New results *and* errors are cached
  53. self.cache_date = datetime.now()
  54. return self.cached
  55. return wrapper
  56. @APICache(initial=lambda: 0)
  57. def current_active_sessions():
  58. return core_api.get(core_api.info['current_instance'] + '/sessions', active=True)['total_count']
  59. @APICache(initial=lambda: [])
  60. def get_locations():
  61. gateways = core_api.get('/gateways/', enabled=True)
  62. locations = {}
  63. for gw in gateways.list_iter():
  64. cc = gw['cluster_name']
  65. if cc not in locations:
  66. locations[cc] = dict(
  67. servers=0,
  68. bandwidth=0,
  69. hostname='gw.' + cc + '.204vpn.net',
  70. country_code=cc,
  71. message=cluster_messages.get(cc),
  72. )
  73. locations[cc]['servers'] += 1
  74. locations[cc]['bandwidth'] += gw['bandwidth']
  75. locations = sorted(locations.items(), key=lambda x: x[1]['country_code'])
  76. return locations
  77. @APICache(initial=lambda: [])
  78. def get_gateway_exit_ips():
  79. gateways = core_api.get('/gateways/', enabled=True)
  80. ipv4_list = []
  81. ipv6_list = []
  82. for gw in gateways.list_iter():
  83. ma = gw['main_addr']
  84. if ma.get('ipv4'):
  85. ipv4_list.append(ma['ipv4'])
  86. if ma.get('ipv6'):
  87. ipv6_list.append(ma['ipv6'])
  88. # TODO: IPv6 support
  89. return ipv4_list
  90. def is_vpn_gateway(ip):
  91. addresses = get_gateway_exit_ips()
  92. return ip in addresses
  93. def create_user(username, cleartext_password):
  94. """ The password will be hashed and stored safely on the core,
  95. so we have to send it clearly here.
  96. """
  97. path = core_api.info['current_instance'] + '/users/'
  98. core_api.post(path, data={
  99. 'username': username,
  100. 'password': cleartext_password,
  101. 'expiration_date': datetime(1, 1, 1).isoformat(), # Expired.
  102. })
  103. def update_user_expiration(user):
  104. path = core_api.info['current_instance'] + '/users/' + user.username
  105. try:
  106. if not user.is_active:
  107. core_api.patch(path, data={
  108. 'expiration_date': datetime(1, 1, 1).isoformat(), # Expired.
  109. })
  110. return
  111. core_api.patch(path, data={
  112. 'expiration_date': user.vpnuser.expiration,
  113. })
  114. except lcoreapi.APIError:
  115. # User can't do anything to this, we should just report it
  116. logger = logging.getLogger('django.request')
  117. logger.exception("core api error, missing user (exp update)")
  118. def update_user_password(user, cleartext_password):
  119. path = core_api.info['current_instance'] + '/users/' + user.username
  120. try:
  121. core_api.patch(path, data={
  122. 'password': cleartext_password,
  123. })
  124. except lcoreapi.APINotFoundError:
  125. # This time we can try fix it!
  126. create_user(user.username, cleartext_password)
  127. except lcoreapi.APIError:
  128. # and maybe fail.
  129. logger = logging.getLogger('django.request')
  130. logger.exception("core api error (password update)")
  131. def delete_user(username):
  132. path = core_api.info['current_instance'] + '/users/' + username
  133. core_api.delete(path)