ZipFile

Zip a file and upload to war room.

python · Common Scripts

Source

import re
import shutil
from os.path import isfile

import demistomock as demisto
import pyzipper
from CommonServerPython import *

from CommonServerUserPython import *

ESCAPE_CHARACTERS = r'[/\<>"|?*]'


def test_compression_succeeded(zip_name: str, password: str = None):
    with pyzipper.AESZipFile(zip_name) as zf:
        # testing for file integrity
        if password:
            zf.setpassword(bytes(password, "utf-8"))
        ret = zf.testzip()
        if ret is not None:
            demisto.info("zf.testzip() failed")
            raise DemistoException("There was a problem with zipping the file: " + ret + " is corrupted")


def compress_multiple(file_names: List[str], zip_name: str, password: str = None):
    """
    Compress multiple files into a zip file.
    :param file_names: list of file names to compress
    :param zip_name: name of the zip file to create
    :param password: password to use for encryption
    """
    compression = pyzipper.ZIP_DEFLATED
    encryption = pyzipper.WZ_AES if password else None
    demisto.debug(f"zipping {file_names=}")
    with pyzipper.AESZipFile(zip_name, mode="w", compression=compression, encryption=encryption) as zf:
        zf.pwd = bytes(password, "utf-8") if password else None
        for file_name in file_names:
            zf.write(file_name)
    test_compression_succeeded(zip_name, password)
    zf.close()


def escape_illegal_characters_in_file_name(file_name: str) -> str:
    if file_name:
        file_name = re.sub(ESCAPE_CHARACTERS, "-", file_name)
        file_name = re.sub(r"-+", "-", file_name)  # prevent more than one consecutive dash in the file name

    return file_name


def main():
    try:
        args = demisto.args()
        zipName = None
        password = None
        fileEntryID = args.get("entryID")

        if "zipName" in args:
            zipName = escape_illegal_characters_in_file_name(demisto.args().get("zipName")) + ".zip"

        if "password" in args:
            password = demisto.args().get("password")

        if not fileEntryID:
            raise DemistoException("You must set an entryID when using the zip script")

        entry_ids = argToList(fileEntryID)
        file_names = []
        for entry_id in entry_ids:
            res = demisto.executeCommand("getFilePath", {"id": entry_id})

            if is_error(res):
                raise DemistoException(
                    "Failed to get the file path for entry: " + entry_id + " the error message was " + get_error(res)
                )

            filePath = res[0]["Contents"]["path"]
            fileCurrentName = escape_illegal_characters_in_file_name(res[0]["Contents"]["name"])

            if not isfile(filePath):  # in case that the user will send a directory
                raise DemistoException(entry_id + " is not a file. Please recheck your input.")

            # Handling duplicate names.
            if fileCurrentName in file_names:
                name, ext = os.path.splitext(fileCurrentName)
                i = 0
                while fileCurrentName in file_names:
                    i += 1
                    fileCurrentName = f"{name} {i}{ext}"
            # copying the file to current location
            shutil.copy(filePath, fileCurrentName)
            file_names.append(fileCurrentName)

        if not zipName:
            # Preserving old behaviour. If only one file provided - will use its name .zip
            # Else will use a uuid.
            if len(file_names) == 1:
                fileCurrentName = file_names[0]
            else:
                fileCurrentName = demisto.uniqueFile()
            zipName = fileCurrentName + ".zip"

        # zipping the file
        compress_multiple(file_names, zipName, password)

        with open(zipName, "rb") as f:
            file_data = f.read()

        demisto.results(fileResult(zipName, file_data))
        human_readable = tableToMarkdown("Zipped Files", [{"original name": file_names, "zipped file": zipName}])
        context: Dict[str, Any] = {"ZippedFiles": zipName, "ZipFile.ZippedFile": zipName}
        for entry_id in entry_ids:
            context[f"File(val.EntryID == {entry_id}).zipped"] = True
        raw_response = {"ZippedFiles": zipName}

        return_outputs(human_readable, context, raw_response)
    except Exception as exc:
        return_error(exc)


if __name__ in ("__main__", "__builtin__", "builtins"):
    main()

README

Zip a file and upload to war room

Supported Cortex XSOAR versions: 5.0.0 and later.

Script Data


Name Description
Script Type python3
Tags Utility, file
Cortex XSOAR Version 5.0.0

Inputs


Argument Name Description
entryID CSV list of entry ids for the files to zip.
zipName Name of the output file, for example: zipName=”test” would result in output file “test.zip”
password Used to create a password protected zip file. Example: password=”abcd”

Outputs


Path Description Type
ZipFile.ZippedFile The zipped file string
File.Name The full file name (including file extension). String
File.EntryID The ID for locating the file in the War Room. String
File.Size The size of the file in bytes. Number
File.MD5 The MD5 hash of the file. String
File.SHA1 The SHA1 hash of the file. String
File.SHA256 The SHA1 hash of the file. String
File.SHA512 The SHA512 hash of the file. String
File.SSDeep The ssdeep hash of the file (same as displayed in file entries). String
File.Extension The file extension, for example: ‘xls’. String
File.Type The file type, as determined by libmagic (same as displayed in file entries). String

Troubleshooting

Because of security reasons we support only AES encryption which is not supported on the Windows OS without 3rd party unzip applications. For more information about the encryption methods, see https://en.wikipedia.org/wiki/ZIP_(file_format)#Encryption.