def ListExamsInServer(socket, key, staffID, examRepoAdminID):

    # Construct the Header of Payload
    PayloadToSendHeader = UploadHeader()
    PayloadToSendHeader.requestType = 'L'
    PayloadToSendHeader.requesterID = examRepoAdminID  # Server Repo Admin for an examiner uploading to the server.
    PayloadToSendHeader.modCode = ''
    PayloadToSendHeader.uploaderID = staffID

    # Construct the final payload!
    FinalPayload = (PayloadToSendHeader, 'None')
    SendTupleWithAES(socket, key, FinalPayload)

    # Should Recieve a successful response!
    request = RecieveTupleWithAES(socket, key)
    if not request:
        print('No Files To List\nTerminating...')
        exit(-1)

    SendWithAES(b'SuccessfullyRecievedExamList')

    print('File List:')
    for row in request:
        print(row)

    print('Thank You and Goodbye!\nTerminating...')
    exit(-1)
def DownloadRequestFromClient(socket, key, RecievedHeader):
    # Determine if Admin or Examiner
    SenderID = RecievedHeader.uploaderID
    SenderRole = CheckUserRole(SenderID)
    ModuleCode = RecievedHeader.modCode

    #(ExamMetaData, EncryptedExam, EncryptedSoln, keys)
    ExamData = GetExamData(ModuleCode)

    SendTupleWithAES(socket, key, ExamData)

    LogMessage('Sent Data to Client')
def EstablishSecureClientConnection(repoOwnerID, clientID, passwordHash,
                                    socket, ClientKeyFolder,
                                    ServerPublicKeyFolder):
    # Generate Session Key
    SessionKey = GenerateAESKey()

    # Encrypt Session Key with Public Key of Server
    ServerPublicKey = ReadRSAPublicKeyFromDisk(ServerPublicKeyFolder)
    TempPayload = EncryptWithRSA(ServerPublicKey, SessionKey)

    sendMsg(socket, TempPayload)

    # Use Session Key to Descrypt and Encrypt from this point onwards.

    # Recieve request for client identity
    request = RecieveWithAES(socket, SessionKey)
    if request != b'RequestClientIdentity':
        print('Recieved Unknown Request\nTerminating...')
        exit(-1)

    # Send Clients UserID and Password Hash
    clientIdentity = Login(clientID, passwordHash)

    SendTupleWithAES(socket, SessionKey, clientIdentity)

    # Recieve Repo Owner ID and Password Hash (Also a random challenge string)
    # Compare with Local Database
    #ServerPasswordHash = 'e541fc35f5a53d83b815042a21af51fba903c03321c61f7ca1d883f9bf52df63'
    ServerPasswordHash = GetUserPasswordHash(repoOwnerID)
    RecievedPayload = RecieveTupleWithAES(socket, SessionKey)
    EncryptedChallengeString = RecievedPayload[0]
    ServerIdentity = RecievedPayload[1]
    if len(ServerIdentity) != 2:
        print('Recieved Unknown Request\nTerminating...')
        exit(-1)

    # Encrypt Challenge String with Private Key.
    ClientKey = ReadRSAKeysFromDisk(ClientKeyFolder)
    ChallengeString = DecryptWithRSA(ClientKey[0], EncryptedChallengeString)

    # Send to Server
    SendWithAES(socket, SessionKey, ChallengeString)

    # Recieve successful response.
    response = RecieveWithAES(socket, SessionKey)
    if response != b'Success':
        print('Recieved Unknown Request\nTerminating...')
        exit(-1)

    # Secure Connection Established
    print('\nSecure Connection Established!\n')

    return (SessionKey)
def EstablishSecureServerConnection(ownerID, passwordHash, socket, ServerKeyFolder, ClientPublicKeyFolder, data):

    # Recieve a session key which is decrypted using server private key.
    ServerKey = ReadRSAKeysFromDisk(ServerKeyFolder)
    EncryptedSessionKey = data
    SessionKey = DecryptWithRSA(ServerKey[0], EncryptedSessionKey)

    # Use Session Key to Descrypt and Encrypt from this point onwards.

    # Request Client Identity
    SendWithAES(socket, SessionKey, 'RequestClientIdentity')

    # Receive Client Identity, Compare UserID and Password Hash with server database.
    #ClientPasswordHash = '073f9dd9d134206828ea34f8d1c81b5150973fe7c470358f4e59528f8bc284a8'
    clientIdentity = RecieveTupleWithAES(socket, SessionKey)

    if len(clientIdentity) != 2:
        print('Recieved Unknown Request\nTerminating...')
        exit(-1)

    
    ClientPasswordHash = GetUserPasswordHash(clientIdentity[0])
    ClientPublicKeyFilePath = ClientPublicKeyFolder + clientIdentity[0]
    ClientPublicKey = ReadRSAPublicKeyFromDisk(ClientPublicKeyFilePath)

    # Send Server Repo Owner ID, Password Hash, Random Challenge String
    serverIdentity = Login(ownerID, passwordHash)

    # Challenge String
    challengeString = pickle.dumps(GenerateRandomSalt(16))
    encryptedChallengeString = EncryptWithRSA(ClientPublicKey, challengeString)

    payload = (encryptedChallengeString, serverIdentity)
    SendTupleWithAES(socket, SessionKey, payload)

    # Decrypt challenge string verify the challenge string matches.
    RecievedChallengeString = RecieveWithAES(socket, SessionKey)
    if challengeString != RecievedChallengeString:
        print('Recieved Bad Challenge String\nTerminating...')
        exit(-1)

    # Secure Connection Established
    SendWithAES(socket, SessionKey, b'Success')
    print('\nSecure Connection Established!\n')
    LogMessage('Secure Connection Established with Client')

    return (SessionKey)
def  ListRequestFromClient(socket, key, RecievedHeader):
    # Determine if Admin or Examiner
    SenderID = RecievedHeader.uploaderID
    SenderRole = CheckUserRole(SenderID)

    DirectoryList = os.listdir(ExamPath)
    ModuleList = []


    if SenderRole == 'Examiner':
        # Examiner
        UserModules = GetUserModules(SenderID)
        for item in DirectoryList:
        # Ignore if not module folder
            if item[0] == 'S':
                # Check if match userModules
                if item[0] in UserModules:
                    ModuleList.append(item)
        
    else:
        #Admin or Backup Admin
        # List all the files in database
        for item in DirectoryList:
        # Ignore if not module folder
            if item[0] == 'S':
                ModuleList.append(item)

    ModuleDataList = []
    for module in ModuleList:
        MetaData = GetExamMetaData(module)
        TimeStamp = datetime.fromtimestamp(MetaData[0])
        RepoContent = "Module Code:({}) \tUploaded By:({}) \tLast_Modified:({})\n".format(MetaData[2], MetaData[1], TimeStamp)
        ModuleDataList.append(RepoContent)

    SendTupleWithAES(socket, key, ModuleDataList)

    # Should Recieve a successful response!
    request = RecieveWithAES(socket, key)
    if request != b'SuccessfullyRecievedExamList':
        print('Recieved Unknown Request\nTerminating...')
    LogMessage('Client Successfully Recieved Exam List')
def DownloadExamFromServer(socket, key, ClientKeyFolder, staffID,
                           examRepoAdminID, modCode):

    # Construct Request
    # Construct the Header of Payload
    PayloadToSendHeader = UploadHeader()
    PayloadToSendHeader.requestType = 'D'
    PayloadToSendHeader.requesterID = examRepoAdminID  # Server Repo Admin for an examiner uploading to the server.
    PayloadToSendHeader.modCode = modCode
    PayloadToSendHeader.uploaderID = staffID

    # Construct the final payload!
    FinalPayload = (PayloadToSendHeader, 'None')
    SendTupleWithAES(socket, key, FinalPayload)

    # Should Recieve a successful response!
    request = RecieveTupleWithAES(socket, key)
    if not request:
        print('Recieved Unknown Request\nTerminating...')
        exit(-1)

    ExamMetaData = request[0]
    EncryptedExam = pickle.loads(request[1])
    EncryptedSoln = pickle.loads(request[2])
    keys = pickle.loads(request[3])

    # Get the aes Key
    SealKey = ''
    for row in keys:
        # CHANGE TO staffID ASAP
        if row.staffID == 's23456':
            SealKey = row.encryptedKey
            break

    # ClientKey = ReadRSAKeysFromDisk(ClientKeyFolder)
    ClientKey = ReadRSAKeysFromDisk('../Common/Keys/s23456')

    if SealKey != '':
        SealKey = DecryptWithRSA(ClientKey[0], SealKey)

    else:
        print('Key Not Found\nTerminating...')
        exit(-1)

    ExamQnBytes = DecryptWithAES(SealKey, EncryptedExam[0], EncryptedExam[1])
    ExamSolnBytes = DecryptWithAES(SealKey, EncryptedSoln[0], EncryptedSoln[1])

    FolderPath = DownloadPath + modCode

    # Make the Folders
    if not os.path.exists(FolderPath):
        os.mkdir(FolderPath)
        print("Directory ", FolderPath, " Created ")
    else:
        print("Directory ", FolderPath, " already exists")

    FolderPath += '/'

    MetaFileLocation = FolderPath + 'META.info'
    WriteToMeta(MetaFileLocation, ExamMetaData)

    # Save Encrypted Exam and Encrypted Exam Solution
    ExamFileLocation = FolderPath + ExamMetaData[3]
    SolnFileLocation = FolderPath + ExamMetaData[4]
    WriteToFile(ExamFileLocation, ExamQnBytes)
    WriteToFile(SolnFileLocation, ExamSolnBytes)
def UploadExamToServer(socket, key, staffID, examRepoAdminID, modCode,
                       ExamFilePath, SolnFilePath):

    examFn = os.path.basename(ExamFilePath)
    solFn = os.path.basename(SolnFilePath)

    AdminList = GetAdminIDs()
    AdminKeys = []
    for admin in AdminList:
        tmp = PayloadKey()
        tmp.staffID = admin
        row = (tmp, GetUserKey(admin))
        AdminKeys.append(row)

    # Convert PDF to Bytes
    ExamQnBytes = open(ExamFilePath, 'rb').read()
    ExamSolnBytes = open(SolnFilePath, 'rb').read()

    # Generate a AES key to seal the files.
    SealKey = GenerateAESKey()

    # Format: (iv, cipherData)
    EncryptedExamQn = EncryptWithAES(SealKey, ExamQnBytes)
    EncryptedExamSoln = EncryptWithAES(SealKey, ExamSolnBytes)

    # Encrypt the aes keys with rsa for each admin.
    for row in AdminKeys:
        pubKey = row[1]
        newKey = EncryptWithRSA(pubKey, SealKey)
        row[0].encryptedKey = newKey

    HybridKeys = []
    for row in AdminKeys:
        HybridKeys.append(row[0])

    # Construct a Payload Object
    PayloadToSend = Payload()
    PayloadToSend.staffID = staffID
    PayloadToSend.modCode = modCode
    PayloadToSend.examFn = examFn
    PayloadToSend.solFn = solFn
    PayloadToSend.examQns = EncryptedExamQn
    PayloadToSend.examSol = EncryptedExamSoln
    PayloadToSend.hybridKeys = HybridKeys

    # Construct the Header of Payload
    PayloadToSendHeader = UploadHeader()
    PayloadToSendHeader.requestType = 'U'
    PayloadToSendHeader.requesterID = examRepoAdminID  # Server Repo Admin for an examiner uploading to the server.
    PayloadToSendHeader.modCode = modCode
    PayloadToSendHeader.uploaderID = staffID  # Examiner's ID

    # Construct the final payload!
    FinalPayload = (PayloadToSendHeader, PayloadToSend)
    SendTupleWithAES(socket, key, FinalPayload)

    # Should Recieve a successful response!
    request = RecieveWithAES(socket, key)
    if request != b'SuccessfullyRecievedExamPayload':
        print('Recieved Unknown Request\nTerminating...')
        exit(-1)

    print('Successfully Send Payload.\nThank You and Goodbye!\nTerminating...')
    exit(-1)