<div x-data="alpineExfilled()" x-init="initPage()">
    <div x-ref="headerFiles">
        <h2>Exfilled Files</h2>
        <p>
            Exfilled files are uploaded from an agent on a host to the server during an operation are by default stored on the server at <span x-text="exfilDir"></span>.
            <br>
            If an operation has exfilled files, you can view and download the files here.
        </p>
    </div>
    <hr>
    <div>
        <div class="buttons" x-show="numFiles !== 0">
            <button class="button is-primary is-small" @click="toggleAllFiles(selectedFiles.length < numFiles)">
                <span x-text="selectedFiles.length < numFiles ? 'Select' : 'Unselect'"></span>&nbsp;All Files
            </button>
            <button class="button is-primary is-small" x-bind:disabled="!selectedFiles.length" @click="downloadFiles">
                <span class="icon"><i class="fas fa-save"></i></span>
                <span>Download</span>
            </button>
        </div>
        <p x-show="numFiles === 0">
            The exfill directory (<span x-text="exfilDir"></span>) is empty.
        </p>
        <ul class="tree" x-show="numFiles !== 0">
            <li class="root">
                <span class="icon is-small"><i class="far fa-folder-open"></i></span>
                <span x-text="exfilDir"></span>
            </li>
            <template x-for="agentName of Object.keys(files)" :key="agentName">
                <li class="root-child">
                    <span class="icon is-small"><i class="far fa-folder-open"></i></span>
                    <span x-text="agentName"></span>
                        <template x-for="operation of Object.keys(files[agentName])" :key="operation">
                            <ul class="tree">
                                <li class="agentName-child">
                                    <span class="icon is-small"><i class="fas fa-dragon"></i></span>
                                    <span x-text="operation"></span>
                                    <ul class="tree">
                                        <template x-for="filename of Object.keys(files[agentName][operation])" :key="filename">
                                            <li class="agent-child">
                                                <label class="checkbox">
                                                    <input type="checkbox" class="file-checkbox" x-bind:value="files[agentName][operation][filename]" @click="toggleFile($el, files[agentName][operation][filename])">
                                                    <span class="icon is-small"><i class="far fa-file-alt"></i></span>
                                                    <span x-text="filename"></span>
                                                </label>
                                            </li>
                                        </template>
                                        <li class="agent-child" x-show="!Object.keys(files[agentName][operation]).length">
                                            (none)
                                        </li>
                                    </ul>     
                                </li>
                            </ul>    
                        </template>
                </li>
            </template>
        </ul>  
    </div>
</div>

<script>
    function alpineExfilled() {
        return {
            exfilDir: '',
            operations: [],
            selectedOperationId: '',
            files: {},
            numFiles: 0,
            selectedFiles: [],

            initPage() {
                apiV2('GET', '/api/v2/config/main').then((config) => {
                    this.exfilDir = config.exfil_dir;
                    return apiV2('GET', '/api/v2/operations');
                }).then(async (operations) => {
                    this.operations = operations;
                    this.loadFiles();

                     // While the agents tab is open, keep checking for new/killed agents
                     while (this.$refs.headerFiles) {
                        await sleep(3000);
                        this.loadFiles();
                    }
                }).catch((error) => {
                    toast('Error loading page', false);
                    console.error(error);
                });
            },

            loadFiles() {
                restRequest('POST', { index: 'exfil_files', operation_id: this.selectedOperationId }, (files) => {
                    this.files = JSON.parse(files);
                    this.numFiles = 0;
                    if (this.selectedOperationId) {
                        let validHosts = [];
                        this.operations.filter((operation) => operation.id === this.selectedOperationId).forEach((operation) => {
                            operation.host_group.forEach((host) => {
                                validHosts.push(`${host.host}-${host.paw}`);
                            });
                        });

                        Object.keys(this.files).forEach((host) => {
                            if (!validHosts.includes(host)) {
                                this.files[host] = {};
                            }
                        });
                    }

                    Object.keys(this.files).forEach((agent) => {
                        Object.keys(this.files[agent]).forEach((filename) => this.numFiles++);
                    });
                });
            },

            toggleFile(el, filePath) {
                if (el.checked) {
                    this.selectedFiles.push(filePath);
                } else {
                    let index = this.selectedFiles.indexOf(filePath);
                    this.selectedFiles.splice(index, 1);
                }
            },

            toggleAllFiles(selectAll) {
                let inputs = Array.from(document.querySelectorAll('.file-checkbox'));

                if (inputs.every((input) => input.checked)) {
                    inputs.forEach((input) => {
                        input.checked = false;
                    });
                    this.selectedFiles = [];
                } else {
                    inputs.forEach((input) => {
                        input.checked = true;
                    });
                    this.selectedFiles = inputs.map((input) => input.value);
                }
            },

            downloadFiles() {
                this.selectedFiles.forEach((filePath) => {
                    let filename = filePath.split(/[\/\\]/);
                    filename = filename[filename.length - 1];
                    let uri = `/file/download_exfil?file=${btoa(filePath)}`;
                    let downloadAnchorNode = document.createElement('a');
                    downloadAnchorNode.setAttribute('href', uri);
                    downloadAnchorNode.setAttribute('download', filename);
                    document.body.appendChild(downloadAnchorNode);
                    downloadAnchorNode.click();
                    downloadAnchorNode.remove();
                });
            }
        };
    }

    // # sourceURL=exfilled_files.js
</script>

<style scoped>
    #select-operation {
        max-width: 800px;
        margin: 0 auto;
    }
    
    ul.tree {
	 margin: 0px 0px 0px 20px;
	 list-style: none !important;
	 line-height: 2em;
	 font-family: Arial;
    }
    ul.tree li {
        font-size: 16px;
        position: relative;
    }
    ul.tree li:before {
        position: absolute;
        left: -15px;
        top: -10px;
        content: '';
        display: block;
        border-left: 1px solid #ddd;
        height: 1.7em;
        border-bottom: 1px solid #ddd;
        width: 10px;
    }
    ul.tree li:after {
        position: absolute;
        left: -15px;
        bottom: -7px;
        content: '';
        display: block;
        border-left: 1px solid #ddd;
        height: 100%;
    }
    ul.tree li.root {
        margin: 0px 0px 0px -20px;
    }
    ul.tree li.root:before {
        display: none;
    }
    ul.tree li.root:after {
        display: none;
    }
    ul.tree li.root-child:last-child:after {
        display: none;
    }
    ul.tree li.agentName-child:after{
        display: none;
    }
    ul.tree li.agent-child:nth-last-child(2):after {
        display: none;
    }
    ul.tree li:last-child:after {
        display: none;
    }

</style>
