import re

def ssh_key_default_option(ssh_keys_s, option, searchstring):
    # If searchstring is not found in option, then prepend the key with option
    # there could be multiple ssh keys separated by '\n'
    ssh_keys = []
    for ssh_key in ssh_keys_s.split('\n'):
        # capture existing options in group 1, scan for ssh- or ecdsa-, and make
        # sure there's a base64 string with len >= 80 following
        # match = re.match(r'^(.*)( ssh|ecdsa)-[^ ]* [A-Za-z0-9+=\/]{80,}.*$',
        # FIXED: ssh-ed25519 has less then 80 chars
        # example: 'no-pty,permitopen="127.0.0.1:1" ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILWZi2xUodKJbSNXjLGxkgxSCr7HE3zHpLz67WtEJ9Ft perfact@susi'
        match = re.match(r'^(.*)( ssh| ecdsa)-[^ ]* [A-Za-z0-9+=\/]{60,}.*$',
            ssh_key)
        ## debug
        #print( ssh_key )
        #print( option )
        if not match:
            ssh_key = option + ' ' + ssh_key
        elif searchstring not in match.group(1):
            ssh_key = option + ',' + ssh_key

        ssh_keys.append(ssh_key)

    return '\n'.join(ssh_keys)

class FilterModule:
    # TODO this should move to the respective role but, since code sharing
    # between plugins is restricted, that would require re-structuring ssh key
    # option compilation. perhaps working with (key, [dict of options]).
    #
    # extracts the phonehome SSH key from the configuration
    # if the port is part of the configuration, limit -R to localhost:$port
    # (unless permitlisten is already specified)
    def extract_phonehome_ssh_keys(self, phonehome_configs):
        def set_permitlisten_with_port(phonehome_config):
            ssh_keys = phonehome_config['ssh-key']


            if 'port' in phonehome_config:
                ssh_keys = ssh_key_default_option(
                    ssh_keys,
                    # limit every key to the specified phonehome-port (-R)
                    'permitlisten="localhost:{}"'.format(phonehome_config['port']),
                    'permitlisten=',
                )

            return ssh_keys

        return list(map(set_permitlisten_with_port, phonehome_configs))

    # TODO remove when all machines have the phonehome update.
    def ssh_key_phonehome_rescue(self, ssh_keys):
        '''Always allow listening on port 10225.
        Necessary to allow the phonehome update.
        '''

        option = 'permitlisten="localhost:10225"'

        def add_rescue_option(ssh_key_s):
            match = re.match(
                r'^(.*)( ssh| ecdsa)-[^ ]* [A-Za-z0-9+=\/]{60,}.*$',
                ssh_key_s)
            if not match:
                return option + ' ' + ssh_key_s
            else:
                return option + ',' + ssh_key_s

        return list(map(add_rescue_option, ssh_keys))

    def ssh_key_enforce_no_pty(self, ssh_keys):
        def enforce_no_pty(ssh_key_s):
            return ssh_key_default_option(ssh_key_s, 'no-pty', 'no-pty')

        return list(map(enforce_no_pty, ssh_keys))

    # This filter forbinds any -R / remote-port-forwading instead localhost:*
    def ssh_key_enforce_permitlisten(self, ssh_keys):
        def enforce_permitlisten(ssh_key_s):
            # if any permitlisten is given in the key, leave it , else use default
            return ssh_key_default_option(ssh_key_s, 'permitlisten="localhost:*"', 'permitlisten=')

        return list(map(enforce_permitlisten, ssh_keys))

    # This filter forbinds any -L / local-port-forwading instead 127.0.0.1:1
    def ssh_key_enforce_permitopen(self, ssh_keys):
        def enforce_permitopen(ssh_key_s):
            # if any permitopen is given in the key, leave it , else use default
            return ssh_key_default_option(ssh_key_s, 'permitopen="127.0.0.1:1"', 'permitopen=')

        return list(map(enforce_permitopen, ssh_keys))

    def filters(self):
        return {
            'extract_phonehome_ssh_keys': self.extract_phonehome_ssh_keys,
            'ssh_key_enforce_permitopen': self.ssh_key_enforce_permitopen,
            'ssh_key_enforce_no_pty': self.ssh_key_enforce_no_pty,
            'ssh_key_enforce_permitlisten': self.ssh_key_enforce_permitlisten,
            'ssh_key_phonehome_rescue': self.ssh_key_phonehome_rescue,
        }
