import re
import os
import base64
import hashlib

from django.conf import settings
from django.contrib.auth.models import User

class MoinMoinBackend:
    """
    Authenticate based on MoinMoin users.  Two settings control its function: 

    settings.MOIN_DATA_DIR: required
        Full path to a MoinMoin installation's data directory.  "user" and
        "pages" should be members of this directory.

    settings.MOIN_AUTH_GROUPS: optional
        List of groups to verify that a user is in before authenticating.  
        e.g. ["EditorGroup", "AdminGroup"]
    """

    def authenticate(self, username=None, password=None):
        base = os.path.join(settings.MOIN_DATA_DIR, "user")
        for filename in os.listdir(base):
            fh = open(os.path.join(base, filename))
            moin_user_file = fh.read()
            fh.close()
            if not re.search("^name=%s$" % username, moin_user_file, re.M):
                continue

            pw_enc = re.search("^enc_password=\{SSHA\}(.*)$", moin_user_file, re.M)
            if not pw_enc:
                continue

            # This logic taken from MoinMoin.user.User._validatePassword
            data = base64.decodestring(pw_enc.group(1))
            salt = data[20:]
            hash = hashlib.sha1(password)
            hash.update(salt)
            if hash.digest() != data[:20]:
                return None

            # Check that we're in the required groups, if any.
            for group in getattr(settings, 'MOIN_AUTH_GROUPS', []):
                fh = open(os.path.join(settings.MOIN_DATA_DIR, "pages", group, "current"))
                rev = fh.read().strip()
                fh.close()
                fh = open(os.path.join(settings.MOIN_DATA_DIR, "pages", group, "revisions", rev))
                group_members = fh.read()
                fh.close()
                if not re.search("(^|\s)%s(\s|$)" % username, group_members, re.M):
                    return None

            return User.objects.get_or_create(username=username)[0]

    def get_user(self, user_id):
        try:
            return User.objects.get(pk=user_id)
        except User.DoesNotExist:
            return None