<commit_before># -*- coding: utf-8 -*-

from __future__ import absolute_import

import logging
from functools import wraps
from nacl import secret, encoding, exceptions

from eduid_common.config.parsers.exceptions import SecretKeyException

__author__ = 'lundberg'


def decrypt(f):
    @wraps(f)
    def decrypt_decorator(*args, **kwargs):
        config_dict = f(*args, **kwargs)
        decrypted_config_dict = decrypt_config(config_dict)
        return decrypted_config_dict

    return decrypt_decorator


def read_secret_key(key_name):
    """
    :param key_name: Key file name
    :type key_name: six.string_types
    :return: 32 bytes of secret data
    :rtype: bytes
    """
    sanitized_key_name = "".join([c for c in key_name if c.isalpha() or c.isdigit() or c == '_'])
    fp = '/run/secrets/{}'.format(sanitized_key_name)
    with open(fp) as f:
        return encoding.URLSafeBase64Encoder.decode(f.readline())


def init_secret_box(key_name=None, secret_key=None):
    """
    :param key_name: Key file name
    :type key_name: six.string_types
    :param secret_key: 32 bytes of secret data
    :type secret_key: bytes
    :return: SecretBox
    :rtype: SecretBox
    """
    if not secret_key:
        try:
            secret_key = read_secret_key(key_name)
        except IOError as e:
            raise SecretKeyException(str(e))
    return secret.SecretBox(secret_key)


def decrypt_config(config_dict):
    """
    :param config_dict: Configuration dictionary
    :type config_dict: dict
    :return: Configuration dictionary
    :rtype: dict
    """
    boxes = {}
    for key, value in config_dict.items():
        if key.endswith('_ENCRYPTED'):
            for item in value:
                key_name = item['key_name']
                value = item['value']

                if not boxes.get(key_name):
                    try:
                        boxes[key_name] = init_secret_box(key_name=key_name)
                    except SecretKeyException as e:
                        logging.error(e)
                        continue  # Try next key
                try:
                    decrypted_value = boxes[key_name].decrypt(bytes(value).encode('ascii'),
                                                              encoder=encoding.URLSafeBase64Encoder)
                    config_dict[key.replace('_ENCRYPTED', '')] = decrypted_value
                    del config_dict[key]
                    break  # Decryption successful, do not try any more keys
                except exceptions.CryptoError as e:
                    logging.error(e)
                    continue  # Try next key<commit_msg>Only error log when decryption failed for all keys<commit_after># -*- coding: utf-8 -*-

from __future__ import absolute_import

import logging
from functools import wraps
from nacl import secret, encoding, exceptions

from eduid_common.config.parsers.exceptions import SecretKeyException

__author__ = 'lundberg'


def decrypt(f):
    @wraps(f)
    def decrypt_decorator(*args, **kwargs):
        config_dict = f(*args, **kwargs)
        decrypted_config_dict = decrypt_config(config_dict)
        return decrypted_config_dict

    return decrypt_decorator


def read_secret_key(key_name):
    """
    :param key_name: Key file name
    :type key_name: six.string_types
    :return: 32 bytes of secret data
    :rtype: bytes
    """
    sanitized_key_name = "".join([c for c in key_name if c.isalpha() or c.isdigit() or c == '_'])
    fp = '/run/secrets/{}'.format(sanitized_key_name)
    with open(fp) as f:
        return encoding.URLSafeBase64Encoder.decode(f.readline())


def init_secret_box(key_name=None, secret_key=None):
    """
    :param key_name: Key file name
    :type key_name: six.string_types
    :param secret_key: 32 bytes of secret data
    :type secret_key: bytes
    :return: SecretBox
    :rtype: SecretBox
    """
    if not secret_key:
        try:
            secret_key = read_secret_key(key_name)
        except IOError as e:
            raise SecretKeyException(str(e))
    return secret.SecretBox(secret_key)


def decrypt_config(config_dict):
    """
    :param config_dict: Configuration dictionary
    :type config_dict: dict
    :return: Configuration dictionary
    :rtype: dict
    """
    boxes = {}
    for key, value in config_dict.items():
        if key.endswith('_ENCRYPTED'):
            decrypted = False
            for item in value:
                key_name = item['key_name']
                encrypted_value = item['value']

                if not boxes.get(key_name):
                    try:
                        boxes[key_name] = init_secret_box(key_name=key_name)
                    except SecretKeyException as e:
                        logging.debug(e)
                        continue  # Try next key
                try:
                    decrypted_value = boxes[key_name].decrypt(bytes(encrypted_value).encode('ascii'),
                                                              encoder=encoding.URLSafeBase64Encoder)
                    config_dict[key.replace('_ENCRYPTED', '')] = decrypted_value
                    del config_dict[key]
                    decrypted = True
                    break  # Decryption successful, do not try any more keys
                except exceptions.CryptoError as e:
                    logging.debug(e)
                    continue  # Try next key
            if not decrypted:
                logging.error('Failed to decrypt {}:{}'.format(key, value))


{'fraction_non_alphanumeric': 0.08827812158718602, 'fraction_numerical': 0.0032763014197306154, 'mean_word_length': 2.0818844643858667, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3391799', 'n_tokens_mistral': 1605, 'n_tokens_neox': 1531, 'n_words': 395}