# Copyright 2018 AT&T Intellectual Property.  All other rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging

from pegleg.engine.catalogs.base_catalog import BaseCatalog
from pegleg.engine.catalogs import passphrase_profiles
from pegleg.engine import exceptions

LOG = logging.getLogger(__name__)
KIND = 'PassphraseCatalog'
P_DOCUMENT_NAME = 'document_name'
P_LENGTH = 'length'
P_DESCRIPTION = 'description'
P_ENCRYPTED = 'encrypted'
P_CLEARTEXT = 'cleartext'
P_TYPE = 'type'
P_REGENERABLE = 'regenerable'
P_PROMPT = 'prompt'
P_DEFAULT_LENGTH = 24
P_DEFAULT_STORAGE_POLICY = 'encrypted'
P_DEFAULT_TYPE = 'passphrase'
P_DEFAULT_REGENERABLE = True
P_DEFAULT_PROMPT = False
VALID_PASSPHRASE_TYPES = ['passphrase', 'base64', 'uuid']
VALID_BOOLEAN_FIELDS = [True, False]
P_PROFILE = 'profile'
P_DEFAULT_PROFILE = 'default'

__all__ = ['PassphraseCatalog']


class PassphraseCatalog(BaseCatalog):
    """Passphrase Catalog class.

    The object containing methods and attributes to ingest and manage the site
    passphrase catalog documents.

    """
    def __init__(self, sitename, documents=None):
        """
        Parse the site passphrase catalog documents and capture the
        passphrase catalog data.

        :param str sitename: Name of the environment
        :param list documents: Environment configuration documents
        :raises PassphraseCatalogNotFoundException: If it cannot find a
        ``pegleg/passphraseCatalog/v1`` document.
        """
        super(PassphraseCatalog, self).__init__(KIND, sitename, documents)
        if not self._catalog_docs:
            raise exceptions.PassphraseCatalogNotFoundException()

    @property
    def get_passphrase_names(self):
        """Return the list of passphrases in the catalog."""
        return (
            passphrase[P_DOCUMENT_NAME] for catalog in self._catalog_docs
            for passphrase in catalog['data']['passphrases'])

    def get_length(self, passphrase_name):
        """
        Return the length of the ``passphrase_name``. If the catalog
        does not specify a length for the ``passphrase_name``, return the
        default passphrase length, 24.
        """

        for c_doc in self._catalog_docs:
            for passphrase in c_doc['data']['passphrases']:
                if passphrase[P_DOCUMENT_NAME] == passphrase_name:
                    return passphrase.get(P_LENGTH, P_DEFAULT_LENGTH)

    def get_storage_policy(self, passphrase_name):
        """
        Return the storage policy of the ``passphrase_name``.
        If the passphrase catalog does not specify a storage policy for
        this passphrase, return the default storage policy, "encrypted".
        """

        for c_doc in self._catalog_docs:
            for passphrase in c_doc['data']['passphrases']:
                if passphrase[P_DOCUMENT_NAME] == passphrase_name:
                    if P_ENCRYPTED in passphrase and not passphrase[
                            P_ENCRYPTED]:
                        return P_CLEARTEXT
                    else:
                        return P_DEFAULT_STORAGE_POLICY

    def get_passphrase_type(self, passphrase_name):
        """Return the type of the ``passphrase_name``.

        Determine what type of secret this passphrase name is. Valid options:
        1. passphrase (a randomly generated passphrase)
        2. base64 (a randomly generated passphrase, encoded with base64)
        3. uuid (a randomly generated UUID)

        If an invalid option is specified, raise an exception. If a valid
        option is specified, return it. If no option is specified, default to
        passphrase.
        """

        for c_doc in self._catalog_docs:
            for passphrase in c_doc['data']['passphrases']:
                if passphrase[P_DOCUMENT_NAME] == passphrase_name:
                    passphrase_type = passphrase.get(P_TYPE,
                                                     P_DEFAULT_TYPE).lower()
                    if passphrase_type not in VALID_PASSPHRASE_TYPES:
                        raise exceptions.InvalidPassphraseType(
                            ptype=passphrase_type,
                            pname=passphrase_name,
                            validvalues=VALID_PASSPHRASE_TYPES)
                    else:
                        return passphrase_type

    def is_passphrase_regenerable(self, passphrase_name):
        """Return the regenerable field of the ``passphrase_name``.

        Determines if this passphrase name is regenerable.
        Valid options: True, False.
        If no option is specified, default to True. If an invalid option is
        specified, raise an exception

        """
        # UUIDs should not be regenerated
        if self.get_passphrase_type(passphrase_name) == 'uuid':
            return False

        # All other types can be regenerated
        for c_doc in self._catalog_docs:
            for passphrase in c_doc['data']['passphrases']:
                if passphrase[P_DOCUMENT_NAME] == passphrase_name:
                    passphrase_regenerable = passphrase.get(
                        P_REGENERABLE, P_DEFAULT_REGENERABLE)
                    if passphrase_regenerable not in VALID_BOOLEAN_FIELDS:
                        raise exceptions.InvalidPassphraseRegeneration(
                            pregen=passphrase_regenerable,
                            pname=passphrase_name,
                            validvalues=VALID_BOOLEAN_FIELDS)
                    else:
                        return passphrase_regenerable

    def is_passphrase_prompt(self, passphrase_name):
        """Return the prompt field of the ``passphrase_name``.

        Determines if this passphrase name should be generated interactively.
        Valid options: True, False.
        If no option is specified, default to False. If an invalid option is
        specified, raise an exception

        """

        for c_doc in self._catalog_docs:
            for passphrase in c_doc['data']['passphrases']:
                if passphrase[P_DOCUMENT_NAME] == passphrase_name:
                    passphrase_prompt = passphrase.get(
                        P_PROMPT, P_DEFAULT_PROMPT)
                    if passphrase_prompt not in VALID_BOOLEAN_FIELDS:
                        raise exceptions.InvalidPassphrasePrompt(
                            pprompt=passphrase_prompt,
                            pname=passphrase_name,
                            validvalues=VALID_BOOLEAN_FIELDS)
                    else:
                        return passphrase_prompt

    def get_passphrase_profile(self, passphrase_name):
        """Return the profile field of the ``passphrase_name``.

        Determine which profile this passphrase should use when selecting
        the pool to generate passphrase from.
        If no option is specified, use default profile.  See
        pegleg.engine.catalogs.passphrase_profiles for default and valid
        options.
        """

        for c_doc in self._catalog_docs:
            for passphrase in c_doc['data']['passphrases']:
                if passphrase[P_DOCUMENT_NAME] == passphrase_name:
                    profile = passphrase.get(P_PROFILE,
                                             P_DEFAULT_PROFILE).lower()
                    if profile not in passphrase_profiles.VALID_PROFILES:
                        raise exceptions.InvalidPassphraseProfile(
                            pprofile=profile,
                            validvalues=passphrase_profiles.VALID_PROFILES)
                    else:
                        return profile

# Copyright 2018 AT&T Intellectual Property.  All other rights reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

import logging

from pegleg.engine.catalogs.base_catalog import BaseCatalog
from pegleg.engine.catalogs import passphrase_profiles
from pegleg.engine import exceptions

LOG = logging.getLogger(__name__)
KIND = 'PassphraseCatalog'
P_DOCUMENT_NAME = 'document_name'
P_LENGTH = 'length'
P_DESCRIPTION = 'description'
P_ENCRYPTED = 'encrypted'
P_CLEARTEXT = 'cleartext'
P_TYPE = 'type'
P_REGENERABLE = 'regenerable'
P_PROMPT = 'prompt'
P_DEFAULT_LENGTH = 24
P_DEFAULT_STORAGE_POLICY = 'encrypted'
P_DEFAULT_TYPE = 'passphrase'
P_DEFAULT_REGENERABLE = True
P_DEFAULT_PROMPT = False
VALID_PASSPHRASE_TYPES = ['passphrase', 'base64', 'uuid']
VALID_BOOLEAN_FIELDS = [True, False]
P_PROFILE = 'profile'
P_DEFAULT_PROFILE = 'default'

__all__ = ['PassphraseCatalog']


class PassphraseCatalog(BaseCatalog):
    """Passphrase Catalog class.

    The object containing methods and attributes to ingest and manage the site
    passphrase catalog documents.

    """
    def __init__(self, sitename, documents=None):
        """
        Parse the site passphrase catalog documents and capture the
        passphrase catalog data.

        :param str sitename: Name of the environment
        :param list documents: Environment configuration documents
        :raises PassphraseCatalogNotFoundException: If it cannot find a
        ``pegleg/passphraseCatalog/v1`` document.
        """
        super(PassphraseCatalog, self).__init__(KIND, sitename, documents)
        if not self._catalog_docs:
            raise exceptions.PassphraseCatalogNotFoundException()

    @property
    def get_passphrase_names(self):
        """Return the list of passphrases in the catalog."""
        return (
            passphrase[P_DOCUMENT_NAME] for catalog in self._catalog_docs
            for passphrase in catalog['data']['passphrases'])

    def get_length(self, passphrase_name):
        """
        Return the length of the ``passphrase_name``. If the catalog
        does not specify a length for the ``passphrase_name``, return the
        default passphrase length, 24.
        """

        for c_doc in self._catalog_docs:
            for passphrase in c_doc['data']['passphrases']:
                if passphrase[P_DOCUMENT_NAME] == passphrase_name:
                    return passphrase.get(P_LENGTH, P_DEFAULT_LENGTH)

    def get_storage_policy(self, passphrase_name):
        """
        Return the storage policy of the ``passphrase_name``.
        If the passphrase catalog does not specify a storage policy for
        this passphrase, return the default storage policy, "encrypted".
        """

        for c_doc in self._catalog_docs:
            for passphrase in c_doc['data']['passphrases']:
                if passphrase[P_DOCUMENT_NAME] == passphrase_name:
                    if P_ENCRYPTED in passphrase and not passphrase[
                            P_ENCRYPTED]:
                        return P_CLEARTEXT
                    else:
                        return P_DEFAULT_STORAGE_POLICY

    def get_passphrase_type(self, passphrase_name):
        """Return the type of the ``passphrase_name``.

        Determine what type of secret this passphrase name is. Valid options:
        1. passphrase (a randomly generated passphrase)
        2. base64 (a randomly generated passphrase, encoded with base64)
        3. uuid (a randomly generated UUID)

        If an invalid option is specified, raise an exception. If a valid
        option is specified, return it. If no option is specified, default to
        passphrase.
        """

        for c_doc in self._catalog_docs:
            for passphrase in c_doc['data']['passphrases']:
                if passphrase[P_DOCUMENT_NAME] == passphrase_name:
                    passphrase_type = passphrase.get(P_TYPE,
                                                     P_DEFAULT_TYPE).lower()
                    if passphrase_type not in VALID_PASSPHRASE_TYPES:
                        raise exceptions.InvalidPassphraseType(
                            ptype=passphrase_type,
                            pname=passphrase_name,
                            validvalues=VALID_PASSPHRASE_TYPES)
                    else:
                        return passphrase_type

    def is_passphrase_regenerable(self, passphrase_name):
        """Return the regenerable field of the ``passphrase_name``.

        Determines if this passphrase name is regenerable.
        Valid options: True, False.
        If no option is specified, default to True. If an invalid option is
        specified, raise an exception

        """
        # UUIDs should not be regenerated
        if self.get_passphrase_type(passphrase_name) == 'uuid':
            return False

        # All other types can be regenerated
        for c_doc in self._catalog_docs:
            for passphrase in c_doc['data']['passphrases']:
                if passphrase[P_DOCUMENT_NAME] == passphrase_name:
                    passphrase_regenerable = passphrase.get(
                        P_REGENERABLE, P_DEFAULT_REGENERABLE)
                    if passphrase_regenerable not in VALID_BOOLEAN_FIELDS:
                        raise exceptions.InvalidPassphraseRegeneration(
                            pregen=passphrase_regenerable,
                            pname=passphrase_name,
                            validvalues=VALID_BOOLEAN_FIELDS)
                    else:
                        return passphrase_regenerable

    def is_passphrase_prompt(self, passphrase_name):
        """Return the prompt field of the ``passphrase_name``.

        Determines if this passphrase name should be generated interactively.
        Valid options: True, False.
        If no option is specified, default to False. If an invalid option is
        specified, raise an exception

        """

        for c_doc in self._catalog_docs:
            for passphrase in c_doc['data']['passphrases']:
                if passphrase[P_DOCUMENT_NAME] == passphrase_name:
                    passphrase_prompt = passphrase.get(
                        P_PROMPT, P_DEFAULT_PROMPT)
                    if passphrase_prompt not in VALID_BOOLEAN_FIELDS:
                        raise exceptions.InvalidPassphrasePrompt(
                            pprompt=passphrase_prompt,
                            pname=passphrase_name,
                            validvalues=VALID_BOOLEAN_FIELDS)
                    else:
                        return passphrase_prompt

    def get_passphrase_profile(self, passphrase_name):
        """Return the profile field of the ``passphrase_name``.

        Determine which profile this passphrase should use when selecting
        the pool to generate passphrase from.
        If no option is specified, use default profile.  See
        pegleg.engine.catalogs.passphrase_profiles for default and valid
        options.
        """

        for c_doc in self._catalog_docs:
            for passphrase in c_doc['data']['passphrases']:
                if passphrase[P_DOCUMENT_NAME] == passphrase_name:
                    profile = passphrase.get(P_PROFILE,
                                             P_DEFAULT_PROFILE).lower()
                    if profile not in passphrase_profiles.VALID_PROFILES:
                        raise exceptions.InvalidPassphraseProfile(
                            pprofile=profile,
                            validvalues=passphrase_profiles.VALID_PROFILES)
                    else:
                        return profile

# Copyright 2018 AT&T Intellectual Property.  All other rights reserved. # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # #     http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. Passphrase Catalog class.      The object containing methods and attributes to ingest and manage the site     passphrase catalog documents. Parse the site passphrase catalog documents and capture the         passphrase catalog data.          :param str sitename: Name of the environment         :param list documents: Environment configuration documents         :raises PassphraseCatalogNotFoundException: If it cannot find a         ``pegleg/passphraseCatalog/v1`` document. Return the list of passphrases in the catalog. Return the length of the ``passphrase_name``. If the catalog         does not specify a length for the ``passphrase_name``, return the         default passphrase length, 24. Return the storage policy of the ``passphrase_name``.         If the passphrase catalog does not specify a storage policy for         this passphrase, return the default storage policy, "encrypted". Return the type of the ``passphrase_name``.          Determine what type of secret this passphrase name is. Valid options:         1. passphrase (a randomly generated passphrase)         2. base64 (a randomly generated passphrase, encoded with base64)         3. uuid (a randomly generated UUID)          If an invalid option is specified, raise an exception. If a valid         option is specified, return it. If no option is specified, default to         passphrase. Return the regenerable field of the ``passphrase_name``.          Determines if this passphrase name is regenerable.         Valid options: True, False.         If no option is specified, default to True. If an invalid option is         specified, raise an exception # UUIDs should not be regenerated # All other types can be regenerated Return the prompt field of the ``passphrase_name``.          Determines if this passphrase name should be generated interactively.         Valid options: True, False.         If no option is specified, default to False. If an invalid option is         specified, raise an exception Return the profile field of the ``passphrase_name``.          Determine which profile this passphrase should use when selecting         the pool to generate passphrase from.         If no option is specified, use default profile.  See         pegleg.engine.catalogs.passphrase_profiles for default and valid         options.