#!/usr/bin/python3
import cgi, cgitb
import json
# import uuid
# from clientConfiguration import *
# from globalSettings import *
# from db import *
cgitb.enable()
import sqlite3

#print "Content-type:text/html\r\n\r\n"

#import required modules for unpacking

import subprocess
import os
import hashlib
import zipfile
import gnupg
import ConfigParser
import shutil

message = ''
status = 'fail'
ZIP_PASSPHRASE = 'd1v7a&n4v33n'

def createFolderIfnotExists(path):
    if not os.path.exists(path):
        os.makedirs(path, mode=0o777)
        #a = subprocess.check_output(["mkdir","-p","-m","777",path])

debugging=True
#debugging=False
def sprint(*args):
    if debugging:
        for a in args:
            print(a)

ISO_DEST_DIRECTORY = "/mnt/data/iso"  #intermediary folder to store files
dest_Directory = ""
ISO_FolderUploadPath = '/var/www/uploaded/'

GPG_HOMEVAR = '/home/sanuyi/gpguser/'
createFolderIfnotExists(GPG_HOMEVAR)

gpg = gnupg.GPG(gnupghome=GPG_HOMEVAR) #Stores the encryption keys. change according to the home directory



def recursiveFilePermissions(paths):
    for _dir in paths:
        a = subprocess.check_output(["chmod",'-R',"777",_dir])
        # for root, dirs, files in os.walk(_dir):
        #     for d in dirs:
        #         os.chmod(os.path.join(root, d), 0o777)
        #     for f in files:
        #         os.chmod(os.path.join(root, f), 0o777)

def removeFiles(fileList):
    for file in fileList:
        if not os.path.exists(file):
            sprint(str(file)+" doesnt exist")
            continue
        if os.path.isdir(file):
            shutil.rmtree(file)
        else:
            os.remove(file)


def unzipFile1(ZipFilePath):
    zipFileName = ZipFilePath.split("/")[-1]
    # sprint("B: ZipFileName",zipFileName)
    uploadCode = {}
    destFileName = zipFileName.split(".zip")[0]
    directory_to_extract_to = str(dest_Directory+destFileName)
    # sprint("C: Directory Extracting TO: ",directory_to_extract_to)
    
    with zipfile.ZipFile(os.path.join(ZipFilePath), 'r') as zip_ref:
        zip_ref.extractall(directory_to_extract_to)
    fileList = os.listdir(directory_to_extract_to)
    # sprint("D:Returning FileList from unzipFile:::",fileList)

    return fileList,directory_to_extract_to

def compare_md5CheckSum(destinationPath,isoFilename,shaFile):
    md5_hash = hashlib.md5()
    with open(destinationPath+"/"+isoFilename,"rb") as f:
        # Read and update hash in chunks of 4K
        for byte_block in iter(lambda: f.read(4096),b""):
            md5_hash.update(byte_block)

        checkSum_iso = md5_hash.hexdigest()

        shaFile = open(destinationPath+"/"+shaFile,"r").read()
        #shaFile = shaFile.split()[0]
        if checkSum_iso == shaFile:
            return "sha's are same we can upload the file"
        else:
            return "they are different"

def verifySHA(zipFile):
    uploadCode = {"iso":"","sha":""}
    md5=unzipFile1(zipFile)
    md5FileList = md5[0]
    directory_to_extract_to = md5[1]

    for file in md5FileList:
        checkExt = os.path.splitext(file)[-1]
        if checkExt==".md5":
            uploadCode["sha"]=file
        elif checkExt==".iso":
            uploadCode["iso"] = file
    if uploadCode["sha"]!="":
        # sprint(": Comparing Md5 CheckSum : ")
        #compare_md5CheckSum(destinationPath,zipFilename,shaFile)
        return [compare_md5CheckSum(directory_to_extract_to,uploadCode["iso"],uploadCode["sha"]),os.path.join(directory_to_extract_to,uploadCode["iso"])]
    else:
        return ['sha file not available',os.path.joi(directory_to_extract_to,uploadCode["zipFile"])]


def verifymasterGPG(masterZipFile):
    try:
        uploadCode = {}
        filesList = unzipFile1(masterZipFile)
        for file in filesList[0]:
            checkExt = os.path.splitext(file)[-1]
            if checkExt==".sig":
                uploadCode["sign"]=file
            elif checkExt==".zip":
                uploadCode["zipFile"] = file

        with open(os.path.join(filesList[1],uploadCode["sign"]),"rb")as f:
            # sprint("E: Verifying Signature For the Master")
            verified = gpg.verify_file(f)
            # sprint("F:",["Verified",filesList[1]+"/"+uploadCode["zipFile"]] if verified else ["Unverified",filesList[1]+"/"+uploadCode["zipFile"]])
            return ["Verified",filesList[1]+"/"+uploadCode["zipFile"]] if verified else ["Unverified",filesList[1]+"/"+uploadCode["zipFile"]]
    except Exception as e:
        # sprint("F:Exception")
        global message
        #message += '<br> Invalid File format ' 
        message += '<br> ' + str(e)
    return ["Unverified",' ']



def unpack(fileName,version):
    orgFileName = fileName
    os.system('sudo chmod -R 777 /mnt')
    createFolderIfnotExists(ISO_DEST_DIRECTORY)

    residualFiles = []

    global message
    global status
    message = ''
    status = 'fail'

    #pathToCopyIsoTo = os.path.join(os.path.join(ISO_DEST_DIRECTORY,version),'iso') #/mnt/data/uploads/version/iso/
    pathToCopyIsoTo = ISO_DEST_DIRECTORY #/mnt/data/uploads/version/iso/
    createFolderIfnotExists(pathToCopyIsoTo)

    outputFileFullPath = os.path.join(pathToCopyIsoTo, version) #/mnt/data/uploads/version/iso/version.iso
    createFolderIfnotExists(outputFileFullPath)
    inputFileFullPath = os.path.join(ISO_FolderUploadPath,fileName) #/var/www/uploaded/version.iso

    # to check if the zip is password protected or not
    try:
        # if zip is password protected
        encrypted_fileName = os.path.join(ISO_FolderUploadPath,fileName)
        residualFiles.append(encrypted_fileName)
        fileName = os.path.join(ISO_DEST_DIRECTORY,'decrypted_'+fileName)
        residualFiles.append(fileName)
        

        with open(encrypted_fileName, 'rb') as f:
            gpg_status = gpg.decrypt_file(f, passphrase=ZIP_PASSPHRASE, output=fileName)
            # sprint('ok: ', gpg_status.ok)
            # sprint('status: ', gpg_status.status)
            # sprint('stderr: ', gpg_status.stderr)
	    if str(gpg_status.status).strip() == "no data was provided":
		# sprint ("ZIP WITHOUT PASSWORD DETECTED")
	        raise " "
            elif not gpg_status.ok:
                message +=  " <br> FAILED: COULDN'T UNPACK ZIP ({}) ".format(str(gpg_status.status))
                # sprint("REMOVING RESIDUAL FILES: ",residualFiles)
                removeFiles(residualFiles)
                # sprint("Status: {} Message: {}".format(status,message))
                return status,message
    except:
        # if zip is not password protected
        residualFiles = []
        fileName = os.path.join(ISO_FolderUploadPath,orgFileName)
        # sprint("A1: Verifying Sign Of Master.zip: ")
        # verifySign = verifymasterGPG(fileName)
        residualFiles.append(fileName)


    # sprint("A2: Verifying Sign Of Master.zip: ")
    verifySign = verifymasterGPG(fileName)
    extractedMasterFilePath = verifySign[1]
    residualFiles.append(os.path.dirname(extractedMasterFilePath))

    if verifySign[0] == "Verified":
        #Digital Signature Verified - unzip and verify SHA of .iso
        verifySign = verifySHA(extractedMasterFilePath)
        if verifySign[0]=="sha's are same we can upload the file":
            # to copy .iso to mnt
            outputFileFullPath = os.path.join(outputFileFullPath, verifySign[1].split("/")[-1]) #/mnt/data/uploads/version/iso/version.iso
            shutil.copyfile(verifySign[1], outputFileFullPath)
            recursiveFilePermissions([outputFileFullPath])
            residualFiles.append(verifySign[1])
            message += " <br> File uploaded successfully"
            status = 'success'
        else:
            message += " <br> FAILED: COULDN'T VERIFY SHA OF .iso "
    else:
        message +=  " <br> FAILED: COULDN'T VERIFY SIGNATURE  "

    # shutil.copyfile(inputFileFullPath, outputFileFullPath)
    # recursiveFilePermissions([outputFileFullPath])
    # residualFiles.append(inputFileFullPath)
    # message += " <br> File uploaded successfully"
    # status = 'success'

    removeFiles(residualFiles)
    return status, message