#!/usr/bin/env python
"""This file contains utility classes related to maintenance used by GRR."""



import hashlib
import os


import logging

from grr.lib import access_control
from grr.lib import aff4
from grr.lib import build
from grr.lib import config_lib
from grr.lib import data_store
from grr.lib import rdfvalue
from grr.lib.rdfvalues import client as rdf_client
from grr.lib.rdfvalues import crypto as rdf_crypto


DIGEST_ALGORITHM = hashlib.sha256  # pylint: disable=invalid-name
DIGEST_ALGORITHM_STR = "sha256"

SUPPORTED_PLATFORMS = ["windows", "linux", "darwin"]
SUPPORTED_ARCHITECTURES = ["i386", "amd64"]


def UploadSignedConfigBlob(content, aff4_path, client_context=None,
                           limit=None, token=None):
  """Upload a signed blob into the datastore.

  Args:
    content: File content to upload.
    aff4_path: aff4 path to upload to.
    client_context: The configuration contexts to use.
    limit: The maximum size of the chunk to use.
    token: A security token.

  Raises:
    IOError: On failure to write.
  """
  if limit is None:
    limit = config_lib.CONFIG["Datastore.maximum_blob_size"]

  # Get the values of these parameters which apply to the client running on the
  # target platform.
  if client_context is None:
    # Default to the windows client.
    client_context = ["Platform:Windows", "Client Context"]

  config_lib.CONFIG.Validate(
      parameters="PrivateKeys.executable_signing_private_key")

  sig_key = config_lib.CONFIG.Get("PrivateKeys.executable_signing_private_key",
                                  context=client_context)

  ver_key = config_lib.CONFIG.Get("Client.executable_signing_public_key",
                                  context=client_context)
  with aff4.FACTORY.Create(
      aff4_path, "GRRSignedBlob", mode="w", token=token) as fd:

    for start_of_chunk in xrange(0, len(content), limit):
      chunk = content[start_of_chunk:start_of_chunk + limit]

      blob_rdf = rdf_crypto.SignedBlob()
      blob_rdf.Sign(chunk, sig_key, ver_key, prompt=True)
      fd.Add(blob_rdf)

  logging.info("Uploaded to %s", fd.urn)


def UploadSignedDriverBlob(content, aff4_path=None, client_context=None,
                           install_request=None, token=None):
  """Upload a signed blob into the datastore.

  Args:
    content: Content of the driver file to upload.

    aff4_path: aff4 path to upload to. If not specified, we use the config to
      figure out where it goes.

    client_context: The configuration contexts to use.

    install_request: A DriverInstallRequest rdfvalue describing the installation
      parameters for this driver. If None these are read from the config.

    token: A security token.

  Returns:
    String containing path the file was written to.

  Raises:
    IOError: On failure to write.
  """
  sig_key = config_lib.CONFIG.Get("PrivateKeys.driver_signing_private_key",
                                  context=client_context)

  ver_key = config_lib.CONFIG.Get("Client.driver_signing_public_key",
                                  context=client_context)

  if aff4_path is None:
    aff4_paths = config_lib.CONFIG.Get("MemoryDriver.aff4_paths",
                                       context=client_context)
    if not aff4_paths:
      raise IOError("Could not determine driver location.")
    if len(aff4_paths) > 1:
      logging.info("Possible driver locations: %s", aff4_paths)
      raise IOError("Ambiguous driver location, please specify.")
    aff4_path = aff4_paths[0]

  blob_rdf = rdf_crypto.SignedBlob()
  blob_rdf.Sign(content, sig_key, ver_key, prompt=True)

  with aff4.FACTORY.Create(
      aff4_path, "GRRMemoryDriver", mode="w", token=token) as fd:
    fd.Add(blob_rdf)

    if install_request is None:
      # Create install_request from the configuration.
      install_request = rdf_client.DriverInstallTemplate(
          device_path=config_lib.CONFIG.Get(
              "MemoryDriver.device_path", context=client_context),
          driver_display_name=config_lib.CONFIG.Get(
              "MemoryDriver.driver_display_name", context=client_context),
          driver_name=config_lib.CONFIG.Get(
              "MemoryDriver.driver_service_name", context=client_context))

    fd.Set(fd.Schema.INSTALLATION(install_request))

  logging.info("Uploaded to %s", fd.urn)

  return fd.urn


def GetConfigBinaryPathType(aff4_path):