# -*- coding: utf-8 -*-
'''
    :codeauthor: Erik Johnson <erik@saltstack.com>
'''

# Import Python libs
from __future__ import absolute_import
import copy
import errno
import logging
import os
import shutil
import textwrap
import subprocess

# Import Salt Testing libs
from tests.support.case import ModuleCase
from tests.support.paths import TMP, TMP_CONF_DIR
from tests.support.unit import skipIf
from tests.support.helpers import requires_system_grains

# Import salt libs
import salt.utils.files
import salt.utils.path
import salt.utils.stringutils
import salt.utils.yaml
import salt.pillar as pillar

log = logging.getLogger(__name__)


GPG_HOMEDIR = os.path.join(TMP_CONF_DIR, 'gpgkeys')
PILLAR_BASE = os.path.join(TMP, 'test-decrypt-pillar', 'pillar')
TOP_SLS = os.path.join(PILLAR_BASE, 'top.sls')
GPG_SLS = os.path.join(PILLAR_BASE, 'gpg.sls')
DEFAULT_OPTS = {
    'cachedir': os.path.join(TMP, 'rootdir', 'cache'),
    'config_dir': TMP_CONF_DIR,
    'optimization_order': [0, 1, 2],
    'extension_modules': os.path.join(TMP,
                                      'test-decrypt-pillar',
                                      'extmods'),
    'pillar_roots': {'base': [PILLAR_BASE]},
    'ext_pillar_first': False,
    'ext_pillar': [],
    'decrypt_pillar_default': 'gpg',
    'decrypt_pillar_delimiter': ':',
    'decrypt_pillar_renderers': ['gpg'],
}
ADDITIONAL_OPTS = (
    'conf_file',
    'file_roots',
    'state_top',
    'renderer',
    'renderer_whitelist',
    'renderer_blacklist',
)

TEST_KEY = '''\
-----BEGIN PGP PRIVATE KEY BLOCK-----

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
=06Tz
-----END PGP PRIVATE KEY BLOCK-----
'''

GPG_PILLAR_YAML = '''\
secrets:
  vault:
    foo: |
      -----BEGIN PGP MESSAGE-----

      hQEMAw2B674HRhwSAQgAhTrN8NizwUv/VunVrqa4/X8t6EUulrnhKcSeb8sZS4th
      W1Qz3K2NjL4lkUHCQHKZVx/VoZY7zsddBIFvvoGGfj8+2wjkEDwFmFjGE4DEsS74
      ZLRFIFJC1iB/O0AiQ+oU745skQkU6OEKxqavmKMrKo3rvJ8ZCXDC470+i2/Hqrp7
      +KWGmaDOO422JaSKRm5D9bQZr9oX7KqnrPG9I1+UbJyQSJdsdtquPWmeIpamEVHb
      VMDNQRjSezZ1yKC4kCWm3YQbBF76qTHzG1VlLF5qOzuGI9VkyvlMaLfMibriqY73
      zBbPzf6Bkp2+Y9qyzuveYMmwS4sEOuZL/PetqisWe9JGAWD/O+slQ2KRu9hNww06
      KMDPJRdyj5bRuBVE4hHkkP23KrYr7SuhW2vpe7O/MvWEJ9uDNegpMLhTWruGngJh
      iFndxegN9w==
      =bAuo
      -----END PGP MESSAGE-----
    bar: this was unencrypted already
    baz: |
      -----BEGIN PGP MESSAGE-----

      hQEMAw2B674HRhwSAQf+Ne+IfsP2IcPDrUWct8sTJrga47jQvlPCmO+7zJjOVcqz
      gLjUKvMajrbI/jorBWxyAbF+5E7WdG9WHHVnuoywsyTB9rbmzuPqYCJCe+ZVyqWf
      9qgJ+oUjcvYIFmH3h7H68ldqbxaAUkAOQbTRHdr253wwaTIC91ZeX0SCj64HfTg7
      Izwk383CRWonEktXJpientApQFSUWNeLUWagEr/YPNFA3vzpPF5/Ia9X8/z/6oO2
      q+D5W5mVsns3i2HHbg2A8Y+pm4TWnH6mTSh/gdxPqssi9qIrzGQ6H1tEoFFOEq1V
      kJBe0izlfudqMq62XswzuRB4CYT5Iqw1c97T+1RqENJCASG0Wz8AGhinTdlU5iQl
      JkLKqBxcBz4L70LYWyHhYwYROJWjHgKAywX5T67ftq0wi8APuZl9olnOkwSK+wrY
      1OZi
      =7epf
      -----END PGP MESSAGE-----
    qux:
      - foo
      - bar
      - |
        -----BEGIN PGP MESSAGE-----

        hQEMAw2B674HRhwSAQgAg1YCmokrweoOI1c9HO0BLamWBaFPTMblOaTo0WJLZoTS
        ksbQ3OJAMkrkn3BnnM/djJc5C7vNs86ZfSJ+pvE8Sp1Rhtuxh25EKMqGOn/SBedI
        gR6N5vGUNiIpG5Tf3DuYAMNFDUqw8uY0MyDJI+ZW3o3xrMUABzTH0ew+Piz85FDA
        YrVgwZfqyL+9OQuu6T66jOIdwQNRX2NPFZqvon8liZUPus5VzD8E5cAL9OPxQ3sF
        f7/zE91YIXUTimrv3L7eCgU1dSxKhhfvA2bEUi+AskMWFXFuETYVrIhFJAKnkFmE
        uZx+O9R9hADW3hM5hWHKH9/CRtb0/cC84I9oCWIQPdI+AaPtICxtsD2N8Q98hhhd
        4M7I0sLZhV+4ZJqzpUsOnSpaGyfh1Zy/1d3ijJi99/l+uVHuvmMllsNmgR+ZTj0=
        =LrCQ
        -----END PGP MESSAGE-----
'''

GPG_PILLAR_ENCRYPTED = {
    'secrets': {
        'vault': {
            'foo': '-----BEGIN PGP MESSAGE-----\n\nhQEMAw2B674HRhwSAQgAhTrN8NizwUv/VunVrqa4/X8t6EUulrnhKcSeb8sZS4th\nW1Qz3K2NjL4lkUHCQHKZVx/VoZY7zsddBIFvvoGGfj8+2wjkEDwFmFjGE4DEsS74\nZLRFIFJC1iB/O0AiQ+oU745skQkU6OEKxqavmKMrKo3rvJ8ZCXDC470+i2/Hqrp7\n+KWGmaDOO422JaSKRm5D9bQZr9oX7KqnrPG9I1+UbJyQSJdsdtquPWmeIpamEVHb\nVMDNQRjSezZ1yKC4kCWm3YQbBF76qTHzG1VlLF5qOzuGI9VkyvlMaLfMibriqY73\nzBbPzf6Bkp2+Y9qyzuveYMmwS4sEOuZL/PetqisWe9JGAWD/O+slQ2KRu9hNww06\nKMDPJRdyj5bRuBVE4hHkkP23KrYr7SuhW2vpe7O/MvWEJ9uDNegpMLhTWruGngJh\niFndxegN9w==\n=bAuo\n-----END PGP MESSAGE-----\n',
            'bar': 'this was unencrypted already',
            'baz': '-----BEGIN PGP MESSAGE-----\n\nhQEMAw2B674HRhwSAQf+Ne+IfsP2IcPDrUWct8sTJrga47jQvlPCmO+7zJjOVcqz\ngLjUKvMajrbI/jorBWxyAbF+5E7WdG9WHHVnuoywsyTB9rbmzuPqYCJCe+ZVyqWf\n9qgJ+oUjcvYIFmH3h7H68ldqbxaAUkAOQbTRHdr253wwaTIC91ZeX0SCj64HfTg7\nIzwk383CRWonEktXJpientApQFSUWNeLUWagEr/YPNFA3vzpPF5/Ia9X8/z/6oO2\nq+D5W5mVsns3i2HHbg2A8Y+pm4TWnH6mTSh/gdxPqssi9qIrzGQ6H1tEoFFOEq1V\nkJBe0izlfudqMq62XswzuRB4CYT5Iqw1c97T+1RqENJCASG0Wz8AGhinTdlU5iQl\nJkLKqBxcBz4L70LYWyHhYwYROJWjHgKAywX5T67ftq0wi8APuZl9olnOkwSK+wrY\n1OZi\n=7epf\n-----END PGP MESSAGE-----\n',
            'qux': [
                'foo',
                'bar',
                '-----BEGIN PGP MESSAGE-----\n\nhQEMAw2B674HRhwSAQgAg1YCmokrweoOI1c9HO0BLamWBaFPTMblOaTo0WJLZoTS\nksbQ3OJAMkrkn3BnnM/djJc5C7vNs86ZfSJ+pvE8Sp1Rhtuxh25EKMqGOn/SBedI\ngR6N5vGUNiIpG5Tf3DuYAMNFDUqw8uY0MyDJI+ZW3o3xrMUABzTH0ew+Piz85FDA\nYrVgwZfqyL+9OQuu6T66jOIdwQNRX2NPFZqvon8liZUPus5VzD8E5cAL9OPxQ3sF\nf7/zE91YIXUTimrv3L7eCgU1dSxKhhfvA2bEUi+AskMWFXFuETYVrIhFJAKnkFmE\nuZx+O9R9hADW3hM5hWHKH9/CRtb0/cC84I9oCWIQPdI+AaPtICxtsD2N8Q98hhhd\n4M7I0sLZhV+4ZJqzpUsOnSpaGyfh1Zy/1d3ijJi99/l+uVHuvmMllsNmgR+ZTj0=\n=LrCQ\n-----END PGP MESSAGE-----\n'
            ],
        },
    },
}

GPG_PILLAR_DECRYPTED = {
    'secrets': {
        'vault': {
            'foo': 'supersecret',
            'bar': 'this was unencrypted already',
            'baz': 'rosebud',
            'qux': ['foo', 'bar', 'baz'],
        },
    },
}


@skipIf(not salt.utils.path.which('gpg'), 'GPG is not installed')
class DecryptGPGPillarTest(ModuleCase):
    '''
    Tests for pillar decryption
    '''
    maxDiff = None

    @classmethod
    def setUpClass(cls):
        try:
            os.makedirs(GPG_HOMEDIR, mode=0o700)
        except Exception:
            cls.created_gpg_homedir = False
            raise
        else:
            cls.created_gpg_homedir = True
            cmd_prefix = ['gpg', '--homedir', GPG_HOMEDIR]

            cmd = cmd_prefix + ['--list-keys']
            log.debug('Instantiating gpg keyring using: %s', cmd)
            output = subprocess.Popen(cmd,
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.STDOUT,
                                      shell=False).communicate()[0]
            log.debug('Result:\n%s', output)

            cmd = cmd_prefix + ['--import', '--allow-secret-key-import']
            log.debug('Importing keypair using: %s', cmd)
            output = subprocess.Popen(cmd,
                                      stdin=subprocess.PIPE,
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.STDOUT,
                                      shell=False).communicate(input=salt.utils.stringutils.to_bytes(TEST_KEY))[0]
            log.debug('Result:\n%s', output)

            os.makedirs(PILLAR_BASE)
            with salt.utils.files.fopen(TOP_SLS, 'w') as fp_:
                fp_.write(textwrap.dedent('''\
                base:
                  '*':
                    - gpg
                '''))
            with salt.utils.files.fopen(GPG_SLS, 'w') as fp_:
                fp_.write(GPG_PILLAR_YAML)

    @classmethod
    def tearDownClass(cls):
        cmd = ['gpg-connect-agent', '--homedir', GPG_HOMEDIR]
        try:
            log.debug('Killing gpg-agent using: %s', cmd)
            output = subprocess.Popen(cmd,
                                      stdin=subprocess.PIPE,
                                      stdout=subprocess.PIPE,
                                      stderr=subprocess.STDOUT,
                                      shell=False).communicate(input=b'KILLAGENT')[0]
            log.debug('Result:\n%s', output)
        except OSError:
            log.debug('No need to kill: old gnupg doesn\'t start the agent.')

        if cls.created_gpg_homedir:
            try:
                shutil.rmtree(GPG_HOMEDIR)
            except OSError as exc:
                # GPG socket can disappear before rmtree gets to this point
                if exc.errno != errno.ENOENT:
                    raise
        shutil.rmtree(PILLAR_BASE)

    def _build_opts(self, opts):
        ret = copy.deepcopy(DEFAULT_OPTS)
        for item in ADDITIONAL_OPTS:
            ret[item] = self.master_opts[item]
        ret.update(opts)
        return ret

    @requires_system_grains
    def test_decrypt_pillar_default_renderer(self, grains=None):
        '''
        Test recursive decryption of secrets:vault as well as the fallback to
        default decryption renderer.
        '''
        decrypt_pillar_opts = salt.utils.yaml.safe_load(textwrap.dedent('''\
            decrypt_pillar:
              - 'secrets:vault'
            '''))
        opts = self._build_opts(decrypt_pillar_opts)
        pillar_obj = pillar.Pillar(opts, grains, 'test', 'base')
        ret = pillar_obj.compile_pillar()
        self.assertEqual(ret, GPG_PILLAR_DECRYPTED)

    @requires_system_grains
    def test_decrypt_pillar_alternate_delimiter(self, grains=None):
        '''
        Test recursive decryption of secrets:vault using a pipe instead of a
        colon as the nesting delimiter.
        '''
        decrypt_pillar_opts = salt.utils.yaml.safe_load(textwrap.dedent('''\
            decrypt_pillar_delimiter: '|'
            decrypt_pillar:
              - 'secrets|vault'
            '''))
        opts = self._build_opts(decrypt_pillar_opts)
        pillar_obj = pillar.Pillar(opts, grains, 'test', 'base')
        ret = pillar_obj.compile_pillar()
        self.assertEqual(ret, GPG_PILLAR_DECRYPTED)

    @requires_system_grains
    def test_decrypt_pillar_deeper_nesting(self, grains=None):
        '''
        Test recursive decryption, only with a more deeply-nested target. This
        should leave the other keys in secrets:vault encrypted.
        '''
        decrypt_pillar_opts = salt.utils.yaml.safe_load(textwrap.dedent('''\
            decrypt_pillar:
              - 'secrets:vault:qux'
            '''))
        opts = self._build_opts(decrypt_pillar_opts)
        pillar_obj = pillar.Pillar(opts, grains, 'test', 'base')
        ret = pillar_obj.compile_pillar()
        expected = copy.deepcopy(GPG_PILLAR_ENCRYPTED)
        expected['secrets']['vault']['qux'][-1] = \
            GPG_PILLAR_DECRYPTED['secrets']['vault']['qux'][-1]
        self.assertEqual(ret, expected)

    @requires_system_grains
    def test_decrypt_pillar_explicit_renderer(self, grains=None):
        '''
        Test recursive decryption of secrets:vault, with the renderer
        explicitly defined, overriding the default. Setting the default to a
        nonexistant renderer so we can be sure that the override happened.
        '''
        decrypt_pillar_opts = salt.utils.yaml.safe_load(textwrap.dedent('''\
            decrypt_pillar_default: asdf
            decrypt_pillar_renderers:
              - asdf
              - gpg
            decrypt_pillar:
              - 'secrets:vault': gpg
            '''))
        opts = self._build_opts(decrypt_pillar_opts)
        pillar_obj = pillar.Pillar(opts, grains, 'test', 'base')
        ret = pillar_obj.compile_pillar()
        self.assertEqual(ret, GPG_PILLAR_DECRYPTED)

    @requires_system_grains
    def test_decrypt_pillar_missing_renderer(self, grains=None):
        '''
        Test decryption using a missing renderer. It should fail, leaving the
        encrypted keys intact, and add an error to the pillar dictionary.
        '''
        decrypt_pillar_opts = salt.utils.yaml.safe_load(textwrap.dedent('''\
            decrypt_pillar_default: asdf
            decrypt_pillar_renderers:
              - asdf
            decrypt_pillar:
              - 'secrets:vault'
            '''))
        opts = self._build_opts(decrypt_pillar_opts)
        pillar_obj = pillar.Pillar(opts, grains, 'test', 'base')
        ret = pillar_obj.compile_pillar()
        expected = copy.deepcopy(GPG_PILLAR_ENCRYPTED)
        expected['_errors'] = [
            'Failed to decrypt pillar key \'secrets:vault\': Decryption '
            'renderer \'asdf\' is not available'
        ]
        self.assertEqual(ret, expected)

    @requires_system_grains
    def test_decrypt_pillar_invalid_renderer(self, grains=None):
        '''
        Test decryption using a renderer which is not permitted. It should
        fail, leaving the encrypted keys intact, and add an error to the pillar
        dictionary.
        '''
        decrypt_pillar_opts = salt.utils.yaml.safe_load(textwrap.dedent('''\
            decrypt_pillar_default: foo
            decrypt_pillar_renderers:
              - foo
              - bar
            decrypt_pillar:
              - 'secrets:vault': gpg
            '''))
        opts = self._build_opts(decrypt_pillar_opts)
        pillar_obj = pillar.Pillar(opts, grains, 'test', 'base')
        ret = pillar_obj.compile_pillar()
        expected = copy.deepcopy(GPG_PILLAR_ENCRYPTED)
        expected['_errors'] = [
            'Failed to decrypt pillar key \'secrets:vault\': \'gpg\' is '
            'not a valid decryption renderer. Valid choices are: foo, bar'
        ]
        self.assertEqual(ret, expected)
