# Path: badwolf/utils.py
# class ObjectDict(dict):
#     """Makes a dictionary behave like an object, with attribute-style access.
#     """
#     def __getattr__(self, key):
#         if key in self:
#             return self[key]
#         return None
# 
#     def __setattr__(self, key, value):
#         self[key] = value
# 
# def to_text(value, encoding='utf-8', errors='ignore'):
#     """Convert value to unicode, default encoding is utf-8
# 
#     :param value: Value to be converted
#     :param encoding: Desired encoding
#     """
#     if not value:
#         return ''
#     if isinstance(value, str):
#         return value
#     if isinstance(value, bytes):
#         return value.decode(encoding, errors)
#     return str(value)
# 
# def to_binary(value, encoding='utf-8'):
#     """Convert value to binary string, default encoding is utf-8
# 
#     :param value: Value to be converted
#     :param encoding: Desired encoding
#     """
#     if not value:
#         return b''
#     if isinstance(value, bytes):
#         return value
#     if isinstance(value, str):
#         return value.encode(encoding)
#     return bytes(value)
# 
# Path: badwolf/security.py
# class SecureToken(object):
# 
#     @staticmethod
#     def encrypt(text):
#         fernet = Fernet(to_binary(current_app.config['SECURE_TOKEN_KEY']))
#         return fernet.encrypt(to_binary(text))
# 
#     @staticmethod
#     def decrypt(encrypted):
#         fernet = Fernet(to_binary(current_app.config['SECURE_TOKEN_KEY']))
#         text = fernet.decrypt(to_binary(encrypted))
#         return to_text(text)
# 
# def parse_secretfile(fd):
#     env = []
#     for line in fd:
#         line = line.strip()
#         if not line:
#             continue
#         if line.startswith('#'):
#             continue
#         elif line.startswith('>'):
#             # Write to file not supported for now
#             continue
#         else:
#             env.append(line)
#     return env
# 
# Path: badwolf/exceptions.py
# class InvalidSpecification(BadwolfException):
#     pass


import io
import base64
import logging
import shlex
import yaml
    from yaml import CLoader as _Loader
    from yaml import Loader as _Loader
from flask import render_template
from marshmallow import Schema, fields, pre_load, post_load, ValidationError, validate
from marshmallow.utils import is_collection
from marshmallow_oneofschema import OneOfSchema
from badwolf.utils import ObjectDict, to_text, to_binary
from badwolf.security import SecureToken, parse_secretfile
from badwolf.exceptions import InvalidSpecification
        from cryptography.fernet import InvalidToken

    @classmethod
    def parse_file(cls, path):
        try:
            if hasattr(path, 'read') and callable(path.read):
                # File-like obj
                conf = yaml.load(path.read(), Loader=_Loader)
            else:
                with io.open(path) as f:
                    conf = yaml.load(f.read(), Loader=_Loader)
        except yaml.error.MarkedYAMLError as e:
            raise InvalidSpecification(str(e))

        return cls.parse(conf)

    @classmethod
    def parse(cls, conf):
        schema = SpecificationSchema()
        try:
            data = schema.load(conf)
        except ValidationError as e:
            logger.exception('badwolf specification validation error')
            raise InvalidSpecification(str(e))
        spec = cls()
        for key, value in data.items():
            setattr(spec, key, value)
        return spec

    def parse_secretfile(self, path):
        if hasattr(path, 'read') and callable(path.read):

# Path: badwolf/utils.py
# class ObjectDict(dict):
#     """Makes a dictionary behave like an object, with attribute-style access.
#     """
#     def __getattr__(self, key):
#         if key in self:
#             return self[key]
#         return None
# 
#     def __setattr__(self, key, value):
#         self[key] = value
# 
# def to_text(value, encoding='utf-8', errors='ignore'):
#     """Convert value to unicode, default encoding is utf-8
# 
#     :param value: Value to be converted
#     :param encoding: Desired encoding
#     """
#     if not value:
#         return ''
#     if isinstance(value, str):
#         return value
#     if isinstance(value, bytes):
#         return value.decode(encoding, errors)
#     return str(value)
# 
# def to_binary(value, encoding='utf-8'):
#     """Convert value to binary string, default encoding is utf-8
# 
#     :param value: Value to be converted
#     :param encoding: Desired encoding
#     """
#     if not value:
#         return b''
#     if isinstance(value, bytes):
#         return value
#     if isinstance(value, str):
#         return value.encode(encoding)
#     return bytes(value)
# 
# Path: badwolf/security.py
# class SecureToken(object):
# 
#     @staticmethod
#     def encrypt(text):
#         fernet = Fernet(to_binary(current_app.config['SECURE_TOKEN_KEY']))
#         return fernet.encrypt(to_binary(text))
# 
#     @staticmethod
#     def decrypt(encrypted):
#         fernet = Fernet(to_binary(current_app.config['SECURE_TOKEN_KEY']))
#         text = fernet.decrypt(to_binary(encrypted))
#         return to_text(text)
# 
# def parse_secretfile(fd):
#     env = []
#     for line in fd:
#         line = line.strip()
#         if not line:
#             continue
#         if line.startswith('#'):
#             continue
#         elif line.startswith('>'):
#             # Write to file not supported for now
#             continue
#         else:
#             env.append(line)
#     return env
# 
# Path: badwolf/exceptions.py
# class InvalidSpecification(BadwolfException):
#     pass


# Path: badwolf/spec.py
import io
import base64
import logging
import shlex
import yaml
    from yaml import CLoader as _Loader
    from yaml import Loader as _Loader
from flask import render_template
from marshmallow import Schema, fields, pre_load, post_load, ValidationError, validate
from marshmallow.utils import is_collection
from marshmallow_oneofschema import OneOfSchema
from badwolf.utils import ObjectDict, to_text, to_binary
from badwolf.security import SecureToken, parse_secretfile
from badwolf.exceptions import InvalidSpecification
        from cryptography.fernet import InvalidToken


    @classmethod
    def parse_file(cls, path):
        try:
            if hasattr(path, 'read') and callable(path.read):
                # File-like obj
                conf = yaml.load(path.read(), Loader=_Loader)
            else:
                with io.open(path) as f:
                    conf = yaml.load(f.read(), Loader=_Loader)
        except yaml.error.MarkedYAMLError as e:
            raise InvalidSpecification(str(e))

        return cls.parse(conf)

    @classmethod
    def parse(cls, conf):
        schema = SpecificationSchema()
        try:
            data = schema.load(conf)
        except ValidationError as e:
            logger.exception('badwolf specification validation error')
            raise InvalidSpecification(str(e))
        spec = cls()
        for key, value in data.items():
            setattr(spec, key, value)
        return spec

    def parse_secretfile(self, path):
        if hasattr(path, 'read') and callable(path.read):

            envs = parse_secretfile(path)