#  _  __
# | |/ /___ ___ _ __  ___ _ _ ®
# | ' </ -_) -_) '_ \/ -_) '_|
# |_|\_\___\___| .__/\___|_|
#              |_|
#
# Keeper Secrets Manager
# Copyright 2021 Keeper Security Inc.
# Contact: <EMAIL>
#

from ansible.plugins.action import ActionBase
from keeper_secrets_manager_ansible import KeeperAnsible
from keeper_secrets_manager_core.configkeys import ConfigKeys
from ansible.errors import AnsibleError
from distutils.util import strtobool
import json
import yaml
import re

DOCUMENTATION = r'''
---
module: keeper_init

short_description: Initialize a Keeper configuration using the one-time access token.

version_added: "1.0.1"

description:
    - Use the extra variable 'keeper_token' to pass in the one time access token.
    - The token can only be used once, so there is not reason to put it into any configuration file.
    - The configuration file output location can be set using the extra variable 'keeper_config_file'.
    - If 'keeper_config_file' is not defined, the configuration file will be written to the current directory.
    - By default, the configuration file will be a YAML file. If the extension of the 'keeper_config_file' is JSON, a 
      JSON file will be created.
author:
    - <NAME>
options:
  token:
    description:
    - The one-time access token.
    - This token can only be used once.
    - Hard coding the token into a role or playbook is not advised.
    - Best to set via extra variable passed to the playbook.
    type: str
    required: yes
  filename:
    description:
    - File path and name where to write the configuration file.
    - By default, a YAML file is created with key used by Ansible.
    - If the extension is JSON, the standard JSON config will be created.
    - If not set, a YAML configuration 
    type: str
    required: no
  show_config:
    description:
    - File path and name where to write the configuration file.
    - By default, a YAML file is created with key used by Ansible.
    - If the extension is JSON, the standard JSON config will be created.
    - If not set, a YAML configuration 
    type: str
    required: no    
'''

EXAMPLES = r'''
- name: Init the token
  keeper_init:
    token: <KEY>
    keeper_config_file: /tmp/keeper_config.yml
'''

RETURN = r'''
keeper_client_id:
  description: Client ID for the application.
  returned: success
  sample: i31TDFtdZE .... oiCQ
keeper_private_key:
  description: Private key for the application.
  returned: success
  sample: MIGHAgEAMB .... JMJRzpE
keeper_app_key:
  description: Application key for the application.
  returned: success
  sample: zhLwB .... LPGY
keeper_app_owner_public_key:
  description: Public key that allows creation of records.
  returned: success
  version_added: '1.1.2' 
  sample: zhLwB .... LPGY
keeper_server_public_key_id:
  description: Id of the public key to use when sending request.
  returned: success
  sample: 10
keeper_hostname:
  description: Hostname to use ending request.
  returned: success
  sample: keepersecurity.com
'''


class ActionModule(ActionBase):

    @staticmethod
    def make_config(config, filename=None):

        config_dict = {}
        for enum_key, ansible_key in {"clientId": "keeper_client_id", "appKey": "keeper_app_key",
                                      "privateKey": "keeper_private_key",
                                      "serverPublicKeyId": "keeper_server_public_key_id",
                                      "appOwnerPublicKey": "keeper_app_owner_public_key",
                                      "hostname": "keeper_hostname"}.items():
            e = ConfigKeys.get_enum(enum_key)
            if config.contains(e):
                config_dict[ansible_key] = str(config.get(e))

        # If the file name is set, then save the config into a file. A JSON extension will make the standard
        # JSON config file that is usable across SDKs and integrations. Anything else will make a YAML file
        # with a config that has keys that Ansible can use.
        if filename is not None and filename != "":
            # If this a JSON file.
            if re.search(r'json$', filename) is not None:
                config_json_dict = {}
                for e in ConfigKeys:
                    if config.contains(e):
                        config_json_dict[e.value] = config.get(e)
                with open(filename, "w") as fh:
                    fh.write(json.dumps(config_json_dict, indent=4))
                    fh.close()
            # Else write the YAML file.
            else:
                with open(filename, "w") as fh:
                    fh.write(yaml.dump(config_dict))
                    fh.close()

        return config_dict

    def run(self, tmp=None, task_vars=None):
        super(ActionModule, self).run(tmp, task_vars)

        if task_vars is None:
            task_vars = {}

        # Only get the values from the values passed in with option.

        # We need the one time access token.
        token = self._task.args.get("token")
        if token is None or token == "":
            raise AnsibleError("The token is not set. Either set keeper_token extra vars or token on the action.")

        # If there is no filename, don't create a file
        config_file = self._task.args.get("filename")

        # Remove keeper_ keys from task vars. We only want to accept from other variables, like existing
        # configurations.
        for key in list(task_vars.keys()):
            if re.search("^{}".format(KeeperAnsible.KEY_PREFIX), key) is not None:
                task_vars.pop(key, None)

        if ":" in token:
            task_vars[KeeperAnsible.keeper_key(KeeperAnsible.HOSTNAME_KEY)], \
                task_vars[KeeperAnsible.keeper_key(KeeperAnsible.TOKEN_KEY)] = token.split(":")
        else:
            task_vars[KeeperAnsible.keeper_key(KeeperAnsible.TOKEN_KEY)] = token

        # We don't want a JSON, force the config to be in memory.
        keeper = KeeperAnsible(task_vars=task_vars, force_in_memory=True)

        # Don't load the entire vault, make a bad UID.
        try:
            keeper.client.get_secrets()
        except Exception as err:
            raise AnsibleError(str(err))

        config_dict = self.make_config(keeper.client.config, config_file)

        # Do we want to see the config in the ansible debug. By default, this is disabled.
        show_config = bool(strtobool(str(self._task.args.get("show_config", False))))
        if show_config is True:
            return config_dict
        else:
            return {}

#  _  __
# | |/ /___ ___ _ __  ___ _ _ ®
# | ' </ -_) -_) '_ \/ -_) '_|
# |_|\_\___\___| .__/\___|_|
#              |_|
#
# Keeper Secrets Manager
# Copyright 2021 Keeper Security Inc.
# Contact: <EMAIL>
#

from ansible.plugins.action import ActionBase
from keeper_secrets_manager_ansible import KeeperAnsible
from keeper_secrets_manager_core.configkeys import ConfigKeys
from ansible.errors import AnsibleError
from distutils.util import strtobool
import json
import yaml
import re

DOCUMENTATION = r'''
---
module: keeper_init

short_description: Initialize a Keeper configuration using the one-time access token.

version_added: "1.0.1"

description:
    - Use the extra variable 'keeper_token' to pass in the one time access token.
    - The token can only be used once, so there is not reason to put it into any configuration file.
    - The configuration file output location can be set using the extra variable 'keeper_config_file'.
    - If 'keeper_config_file' is not defined, the configuration file will be written to the current directory.
    - By default, the configuration file will be a YAML file. If the extension of the 'keeper_config_file' is JSON, a 
      JSON file will be created.
author:
    - <NAME>
options:
  token:
    description:
    - The one-time access token.
    - This token can only be used once.
    - Hard coding the token into a role or playbook is not advised.
    - Best to set via extra variable passed to the playbook.
    type: str
    required: yes
  filename:
    description:
    - File path and name where to write the configuration file.
    - By default, a YAML file is created with key used by Ansible.
    - If the extension is JSON, the standard JSON config will be created.
    - If not set, a YAML configuration 
    type: str
    required: no
  show_config:
    description:
    - File path and name where to write the configuration file.
    - By default, a YAML file is created with key used by Ansible.
    - If the extension is JSON, the standard JSON config will be created.
    - If not set, a YAML configuration 
    type: str
    required: no    
'''

EXAMPLES = r'''
- name: Init the token
  keeper_init:
    token: <KEY>
    keeper_config_file: /tmp/keeper_config.yml
'''

RETURN = r'''
keeper_client_id:
  description: Client ID for the application.
  returned: success
  sample: i31TDFtdZE .... oiCQ
keeper_private_key:
  description: Private key for the application.
  returned: success
  sample: MIGHAgEAMB .... JMJRzpE
keeper_app_key:
  description: Application key for the application.
  returned: success
  sample: zhLwB .... LPGY
keeper_app_owner_public_key:
  description: Public key that allows creation of records.
  returned: success
  version_added: '1.1.2' 
  sample: zhLwB .... LPGY
keeper_server_public_key_id:
  description: Id of the public key to use when sending request.
  returned: success
  sample: 10
keeper_hostname:
  description: Hostname to use ending request.
  returned: success
  sample: keepersecurity.com
'''


class ActionModule(ActionBase):

    @staticmethod
    def make_config(config, filename=None):

        config_dict = {}
        for enum_key, ansible_key in {"clientId": "keeper_client_id", "appKey": "keeper_app_key",
                                      "privateKey": "keeper_private_key",
                                      "serverPublicKeyId": "keeper_server_public_key_id",
                                      "appOwnerPublicKey": "keeper_app_owner_public_key",
                                      "hostname": "keeper_hostname"}.items():
            e = ConfigKeys.get_enum(enum_key)
            if config.contains(e):
                config_dict[ansible_key] = str(config.get(e))

        # If the file name is set, then save the config into a file. A JSON extension will make the standard
        # JSON config file that is usable across SDKs and integrations. Anything else will make a YAML file
        # with a config that has keys that Ansible can use.
        if filename is not None and filename != "":
            # If this a JSON file.
            if re.search(r'json$', filename) is not None:
                config_json_dict = {}
                for e in ConfigKeys:
                    if config.contains(e):
                        config_json_dict[e.value] = config.get(e)
                with open(filename, "w") as fh:
                    fh.write(json.dumps(config_json_dict, indent=4))
                    fh.close()
            # Else write the YAML file.
            else:
                with open(filename, "w") as fh:
                    fh.write(yaml.dump(config_dict))
                    fh.close()

        return config_dict

    def run(self, tmp=None, task_vars=None):
        super(ActionModule, self).run(tmp, task_vars)

        if task_vars is None:
            task_vars = {}

        # Only get the values from the values passed in with option.

        # We need the one time access token.
        token = self._task.args.get("token")
        if token is None or token == "":
            raise AnsibleError("The token is not set. Either set keeper_token extra vars or token on the action.")

        # If there is no filename, don't create a file
        config_file = self._task.args.get("filename")

        # Remove keeper_ keys from task vars. We only want to accept from other variables, like existing
        # configurations.
        for key in list(task_vars.keys()):
            if re.search("^{}".format(KeeperAnsible.KEY_PREFIX), key) is not None:
                task_vars.pop(key, None)

        if ":" in token:
            task_vars[KeeperAnsible.keeper_key(KeeperAnsible.HOSTNAME_KEY)], \
                task_vars[KeeperAnsible.keeper_key(KeeperAnsible.TOKEN_KEY)] = token.split(":")
        else:
            task_vars[KeeperAnsible.keeper_key(KeeperAnsible.TOKEN_KEY)] = token

        # We don't want a JSON, force the config to be in memory.
        keeper = KeeperAnsible(task_vars=task_vars, force_in_memory=True)

        # Don't load the entire vault, make a bad UID.
        try:
            keeper.client.get_secrets()
        except Exception as err:
            raise AnsibleError(str(err))

        config_dict = self.make_config(keeper.client.config, config_file)

        # Do we want to see the config in the ansible debug. By default, this is disabled.
        show_config = bool(strtobool(str(self._task.args.get("show_config", False))))
        if show_config is True:
            return config_dict
        else:
            return {}

#  _  __ # | |/ /___ ___ _ __  ___ _ _ ® # | ' </ -_) -_) '_ \/ -_) '_| # |_|\_\___\___| .__/\___|_| #              |_| # # Keeper Secrets Manager # Copyright 2021 Keeper Security Inc. # Contact: <EMAIL> # --- module: keeper_init  short_description: Initialize a Keeper configuration using the one-time access token.  version_added: "1.0.1"  description:     - Use the extra variable 'keeper_token' to pass in the one time access token.     - The token can only be used once, so there is not reason to put it into any configuration file.     - The configuration file output location can be set using the extra variable 'keeper_config_file'.     - If 'keeper_config_file' is not defined, the configuration file will be written to the current directory.     - By default, the configuration file will be a YAML file. If the extension of the 'keeper_config_file' is JSON, a        JSON file will be created. author:     - <NAME> options:   token:     description:     - The one-time access token.     - This token can only be used once.     - Hard coding the token into a role or playbook is not advised.     - Best to set via extra variable passed to the playbook.     type: str     required: yes   filename:     description:     - File path and name where to write the configuration file.     - By default, a YAML file is created with key used by Ansible.     - If the extension is JSON, the standard JSON config will be created.     - If not set, a YAML configuration      type: str     required: no   show_config:     description:     - File path and name where to write the configuration file.     - By default, a YAML file is created with key used by Ansible.     - If the extension is JSON, the standard JSON config will be created.     - If not set, a YAML configuration      type: str     required: no - name: Init the token   keeper_init:     token: <KEY>     keeper_config_file: /tmp/keeper_config.yml keeper_client_id:   description: Client ID for the application.   returned: success   sample: i31TDFtdZE .... oiCQ keeper_private_key:   description: Private key for the application.   returned: success   sample: MIGHAgEAMB .... JMJRzpE keeper_app_key:   description: Application key for the application.   returned: success   sample: zhLwB .... LPGY keeper_app_owner_public_key:   description: Public key that allows creation of records.   returned: success   version_added: '1.1.2'    sample: zhLwB .... LPGY keeper_server_public_key_id:   description: Id of the public key to use when sending request.   returned: success   sample: 10 keeper_hostname:   description: Hostname to use ending request.   returned: success   sample: keepersecurity.com # If the file name is set, then save the config into a file. A JSON extension will make the standard # JSON config file that is usable across SDKs and integrations. Anything else will make a YAML file # with a config that has keys that Ansible can use. # If this a JSON file. # Else write the YAML file. # Only get the values from the values passed in with option. # We need the one time access token. # If there is no filename, don't create a file # Remove keeper_ keys from task vars. We only want to accept from other variables, like existing # configurations. # We don't want a JSON, force the config to be in memory. # Don't load the entire vault, make a bad UID. # Do we want to see the config in the ansible debug. By default, this is disabled.