Skip to content
Snippets Groups Projects
Select Git revision
  • 023cf9af325052f9d648a25e146d66c1a8242dbd
  • test default
  • main protected
3 results

tailwind.config.js

Blame
  • security.py 5.79 KiB
    """
    Helios Security -- mostly access control
    
    Ben Adida (ben@adida.net)
    """
    
    import urllib.parse
    # nicely update the wrapper function
    from functools import update_wrapper
    
    from django.conf import settings
    from django.core.exceptions import PermissionDenied
    from django.http import Http404
    from django.http import HttpResponseRedirect
    from django.urls import reverse
    
    import helios
    from helios_auth.security import get_user
    from .models import Voter, Trustee, Election
    
    
    class HSTSMiddleware:
        def __init__(self, get_response):
            self.get_response = get_response
            # One-time configuration and initialization.
    
        def __call__(self, request):
            # Code to be executed for each request before
            # the view (and later middleware) are called.
    
            response = self.get_response(request)
    
            # Code to be executed for each request/response after
            # the view is called.
    
            if settings.STS:
              response['Strict-Transport-Security'] = "max-age=31536000; includeSubDomains; preload"
            return response
    
    # current voter
    def get_voter(request, user, election):
      """
      return the current voter
      """
      voter = None
      if 'CURRENT_VOTER_ID' in request.session:
        voter = Voter.objects.get(id=request.session['CURRENT_VOTER_ID'])
        if voter.election != election:
          voter = None
    
      if not voter:
        if user:
          voter = Voter.get_by_election_and_user(election, user)
      
      return voter
    
    # a function to check if the current user is a trustee
    HELIOS_TRUSTEE_UUID = 'helios_trustee_uuid'
    def get_logged_in_trustee(request):
      if HELIOS_TRUSTEE_UUID in request.session:
        return Trustee.get_by_uuid(request.session[HELIOS_TRUSTEE_UUID])
      else:
        return None
    
    def set_logged_in_trustee(request, trustee):
      request.session[HELIOS_TRUSTEE_UUID] = trustee.uuid
    
    #
    # some common election checks
    #
    def do_election_checks(election, props):
      # frozen
      if 'frozen' in props:
        frozen = props['frozen']
      else:
        frozen = None
      
      # newvoters (open for registration)
      if 'newvoters' in props:
        newvoters = props['newvoters']
      else:
        newvoters = None
      
      # frozen check
      if frozen is not None:
        if frozen and not election.frozen_at:
          raise PermissionDenied()
        if not frozen and election.frozen_at:
          raise PermissionDenied()
        
      # open for new voters check
      if newvoters is not None:
        if election.can_add_voters() != newvoters:
          raise PermissionDenied()
    
      
    def get_election_by_uuid(uuid):
      if not uuid:
        raise Exception("no election ID")
          
      return Election.get_by_uuid(uuid)
      
    # decorator for views that pertain to an election
    # takes parameters:
    # frozen - is the election frozen
    # newvoters - does the election accept new voters
    def election_view(**checks):
      
      def election_view_decorator(func):
        def election_view_wrapper(request, election_uuid=None, *args, **kw):
          election = get_election_by_uuid(election_uuid)
    
          if not election:
            raise Http404
    
          # do checks
          do_election_checks(election, checks)
    
          # if private election, only logged in voters
          if election.private_p and not checks.get('allow_logins',False):
            from .views import password_voter_login
            if not user_can_see_election(request, election):
              return_url = request.get_full_path()
              return HttpResponseRedirect("%s?%s" % (reverse(password_voter_login, args=[election.uuid]), urllib.parse.urlencode({
                      'return_url' : return_url
                      })))
        
          return func(request, election, *args, **kw)
    
        return update_wrapper(election_view_wrapper, func)
        
      return election_view_decorator
    
    def user_can_admin_election(user, election):
      if not user:
        return False
    
      # election or site administrator
      return election.admin == user or user.admin_p
      
    def user_can_see_election(request, election):
      user = get_user(request)
    
      if not election.private_p:
        return True
    
      # election is private
      
      # but maybe this user is the administrator?
      if user_can_admin_election(user, election):
        return True
    
      # or maybe this is a trustee of the election?
      trustee = get_logged_in_trustee(request)
      if trustee and trustee.election.uuid == election.uuid:
        return True
    
      # then this user has to be a voter
      return get_voter(request, user, election) is not None
    
    
    def api_client_can_admin_election(api_client, election):
      return election.api_client == api_client and api_client is not None
    
    
    # decorator for checking election admin access, and some properties of the election
    # frozen - is the election frozen
    # newvoters - does the election accept new voters
    def election_admin(**checks):
      
      def election_admin_decorator(func):
        def election_admin_wrapper(request, election_uuid=None, *args, **kw):
          election = get_election_by_uuid(election_uuid)
    
          user = get_user(request)
          if not user_can_admin_election(user, election):
            raise PermissionDenied()
            
          # do checks
          do_election_checks(election, checks)
            
          return func(request, election, *args, **kw)
    
        return update_wrapper(election_admin_wrapper, func)
        
      return election_admin_decorator
      
    def trustee_check(func):
      def trustee_check_wrapper(request, election_uuid, trustee_uuid, *args, **kwargs):
        election = get_election_by_uuid(election_uuid)
        
        trustee = Trustee.get_by_election_and_uuid(election, trustee_uuid)
        
        if trustee == get_logged_in_trustee(request):
          return func(request, election, trustee, *args, **kwargs)
        else:
          raise PermissionDenied()
      
      return update_wrapper(trustee_check_wrapper, func)
    
    def can_create_election(request):
      user = get_user(request)
      if not user:
        return False
        
      if helios.ADMIN_ONLY:
        return user.admin_p
      else:
        return user.can_create_election()
      
    def user_can_feature_election(user, election):
      if not user:
        return False
        
      return user.admin_p