BTAS

Blue Team Auxiliary Script

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey, το Greasemonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Violentmonkey για να εγκαταστήσετε αυτόν τον κώδικα.

θα χρειαστεί να εγκαταστήσετε μια επέκταση όπως το Tampermonkey ή το Userscripts για να εγκαταστήσετε αυτόν τον κώδικα.

You will need to install an extension such as Tampermonkey to install this script.

Θα χρειαστεί να εγκαταστήσετε μια επέκταση διαχείρισης κώδικα χρήστη για να εγκαταστήσετε αυτόν τον κώδικα.

(Έχω ήδη έναν διαχειριστή κώδικα χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Έχω ήδη έναν διαχειριστή στυλ χρήστη, επιτρέψτε μου να τον εγκαταστήσω!)

// ==UserScript==
// @name         BTAS
// @namespace    https://github.com/Mr-Tree-S/BTAS
// @homepageURL  https://github.com/Mr-Tree-S/BTAS
// @version      3.8.6
// @description  Blue Team Auxiliary Script
// @author       Barry, Jack, Xingyu, Mike
// @license      Apache-2.0
// @match        https://login.microsoftonline.com/*
// @match        https://security.microsoft.com/*
// @include        https://caas*.com/*
// @include        https://mss*mss.com/*
// @icon         https://avatars.githubusercontent.com/u/42169240?v=4
// @require      https://code.jquery.com/jquery-3.6.4.min.js
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/clipboard.min.js
// @require      https://unpkg.com/@popperjs/core@2/dist/umd/popper.min.js
// @require      https://unpkg.com/tippy.js@6/dist/tippy-bundle.umd.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/dompurify/3.0.6/purify.min.js
// @grant        GM_registerMenuCommand
// @grant        GM_unregisterMenuCommand
// @grant        GM_xmlhttpRequest
// @grant        GM_openInTab
// @grant        GM_getValue
// @grant        GM_setValue
// @connect      raw.githubusercontent.com
// @connect      myqcloud.com
// @connect      172.18.4.200
// @run-at       document-idle
// @grant        GM_addStyle
// ==/UserScript==

var $ = window.jQuery;

/**
 * This function creates and displays a flag using AJS.flag function
 * @param {string} type - The type of flag, can be one of the following: "success", "info", "warning", "error"
 * @param {string} title - The title of the flag
 * @param {string} body - The body of the flag
 * @param {string} close - The close of flag, can be one of the following: "auto", "manual", "never"
 */
function security_microsoft() {
    var queryString = window.location.search;
    var urlParams = new URLSearchParams(queryString);
    var current_domain = urlParams.get('current');
    var customers = {};
    const cachedWebsiteContent = GM_getValue('cachedWebsiteContent', null);
    console.log(cachedWebsiteContent);
    cachedWebsiteContent.forEach((item, index) => {
        if (item && item['category'] == 'mde' && item['url']) {
            customers[item['name']] = item['url'];
        }
    });
    var customer = customers[current_domain];
    if (customer) {
        console.log('account11', customer);
    } else {
        customer = current_domain;
    }
    if (current_domain == 'none') {
        let urls = localStorage.getItem('urls').toString().split(',');
        for (var i = 0; i < urls.length; i++) {
            if (i == 0) {
                window.location.href = urls[i];
            } else {
                GM_openInTab(urls[i], {
                    active: false, // 设置为 false,以在后台打开,不激活新标签页
                    insert: true // 设置为 true,将新标签页插入到当前标签页之后
                });
            }
        }
        localStorage.removeItem('urls');
    }
    setTimeout(() => {
        document.getElementById('O365_MainLink_Me').click();
        console.log('account1');
    }, 9000);
    setTimeout(() => {
        var account = document.getElementById('mectrl_currentAccount_secondary').textContent;
        console.log(account, customer);
        if (
            !account.includes(customer) &&
            !customer.includes(account.split('@')[1].split('.')[0]) &&
            current_domain != 'none'
        ) {
            let urls = [];
            urlParams.forEach(function (value, key) {
                if (key.includes('url')) {
                    urls.push(value);
                }
            });
            localStorage.setItem('urls', urls);
            document.getElementById('mectrl_body_signOut').click();
        } else {
            urlParams.forEach(function (value, key) {
                if (key.includes('url')) {
                    GM_openInTab(value, {
                        active: false, // 设置为 false,以在后台打开,不激活新标签页
                        insert: true // 设置为 true,将新标签页插入到当前标签页之后
                    });
                }
            });
            window.close();
        }
    }, 9900);
}

function switch_user_microsoft() {
    console.log('login.microsoft', $('#idDiv_SAOTCC_Title').text().trim());
    if ($('#login_workload_logo_text').text().trim() == '您已注销帐户') {
        window.location.href = 'https://security.microsoft.com/homepage?&current=none';
    }
    if (document.title == '登录到您的帐户' && $('#idDiv_SAOTCC_Title').text().trim() != '输入验证码') {
        setTimeout(() => {
            var inputElement = document.querySelectorAll('.form-control')[0];
            inputElement.addEventListener('input', function (event) {
                var inputValue = inputElement.value;
                if (inputValue.includes('@')) {
                    $('#idSIButton9').click();
                    setTimeout(() => {
                        $('#idSIButton9').click();
                    }, 1500);
                }
            });
        }, 1600);
    } else {
        setTimeout(() => {
            var inputElement = document.querySelectorAll('.form-control')[0];
            inputElement.addEventListener('keyup', function (event) {
                var inputValue = inputElement.value;
                console.log(inputValue); // 打印当输入框的内容在元素失去焦点时的值
                if (inputValue.length == 6) {
                    $('#idSubmit_SAOTCC_Continue').click();
                }
            });
        }, 800);
    }
}

function addCss() {
    const ss = $(`
	    <style> 
            .red_highlight{
                color:red;
                font-weight: bold;
            }
            .black_highlight{
                color:black;
                font-weight: bold;
            }
            .aui-dropdown2{
                max-width: 550px !important;
            }
            .aui-dropdown2 .aui-dropdown2-checkbox, .aui-dropdown2 .aui-dropdown2-radio, .aui-dropdown2 .aui-icon-container {
                padding-top: 10px;
                padding-left: 35px;
            }
            #reply{
                column-count: 2;
            }
            .aui-flag{
                  border: 4px solid rgb(222,184,135) ;
            }
            .fix-button{
                background-color: rgb(222,184,135);
                color:white;
				z-index: 100;
                margin-right: 12px;
			}
         
	    </style>
	    `);
    $('head').append(ss);

    function hideAllFlag() {
        $('.aui-flag').toggle();
    }
    const button = $('<div>')
        .attr('id', 'hide-reminder')
        .addClass('aui-button toolbar-trigger  fix-button aui-button-primary')
        .append($('<span>').addClass('trigger-label').text('NOTICE'))
        .click(hideAllFlag);

    const checkExist = setInterval(function () {
        const targetDiv = document.getElementById('aui-flag-container');
        const toolbar = $('.aui-header-secondary');

        if (targetDiv) {
            toolbar.prepend(button);
            clearInterval(checkExist); // 停止检查
        }
    }, 100); // 每100毫秒检查一次
}

function showFlag(type, title, body, close) {
    AJS.flag({
        type: type,
        title: DOMPurify.sanitize(title),
        body: DOMPurify.sanitize(body),
        close: close
    });

    // addButton('hide-reminder', 'Hide Reminder', hideAllFlag);

    // 为 flag 的内容区域添加滚动条样式
    const flagBody = $('#aui-flag-container > div > div');
    flagBody.css({
        'overflow': 'auto',
        'max-height': '150px' // 添加最大高度,超出部分将出现滚动条
    });

    // 为 flag 的container区域添加滚动条样式
    const flagContainer = $('#aui-flag-container');
    flagContainer.css({
        'overflow': 'auto',
        'overflow-x': 'hidden', //隐藏水平滚动条
        'max-height': '90%' // 添加最大高度,超出部分将出现滚动条
    });
}

/**
 * This function shows alert message in dialog and create a copy button
 * @param {string} body - Alert Message String
 */
function showDialog(body) {
    // avoid editor treat double backslash as breakline and avoid xss attack
    body = DOMPurify.sanitize(body.replace(/\\\\/g, '\\'));

    // Create custom dialog style
    const customDialogContent = AJS.$(`<section
            id="custom-dialog"
            class="aui-dialog2 aui-dialog2-large aui-layer"
            role="dialog"
            tabindex="-1"
            data-aui-modal="true"
            data-aui-remove-on-hide="true"
            aria-labelledby="dialog-show-button--heading"
            aria-describedby="dialog-show-button--description"
            hidden
        >
            <header class="aui-dialog2-header">
                <h2 class="aui-dialog2-header-main" id="dialog-show-button--heading">Description</h2>
            </header>
            <div class="aui-dialog2-content" id="dialog-show-button--description">
                <p style="word-wrap: break-word; white-space: pre-line">${body}</p>
            </div>
            <footer class="aui-dialog2-footer">
                <div class="aui-dialog2-footer-actions">
                    <button id="dialog-copy-button" class="aui-button aui-button-primary">Copy</button>
                    <button id="dialog-close-button" class="aui-button aui-button-link">Close</button>
                </div>
            </footer>
        </section>`);

    // Show the dialog
    AJS.dialog2(customDialogContent).show();

    // Close the dialog
    AJS.$('#dialog-close-button').on('click', function (e) {
        e.preventDefault();
        AJS.dialog2(customDialogContent).hide();
        //tippy.destroy();
    });

    // Init tippy instance
    tippy('#dialog-copy-button', {
        content: 'Copy Success',
        placement: 'bottom',
        trigger: 'click'
    });

    // Copy description text
    AJS.$('#dialog-copy-button').on('click', function () {
        const textToCopy = customDialogContent.find('#dialog-show-button--description').text().trim();

        // Create Clipboard instance
        const clipboard = new ClipboardJS('#dialog-copy-button', {
            text: function () {
                return textToCopy;
            }
        });

        // Copy success
        clipboard.on('success', function (e) {
            clipboard.destroy();
            e.clearSelection();
        });
    });
}

/**
 * This function registers a Tampermonkey search menu command
 * @param {Array} searchEngines - Search engines array containing the Jira, VT, AbuseIPDB
 */
function registerSearchMenu() {
    console.log('#### Code registerSearchMenu run ####');
    const LogSourceDomain = $('#customfield_10223-val').text().trim() || '*';
    const Host = function () {
        let search = {
            'Source IP(s) and Hostname(s)': $('#customfield_10206-val').text().trim(),
            'Destination IP(s) and Hostname(s)': $('#customfield_10208-val').text().trim()
        };
        if (search['Source IP(s) and Hostname(s)']) {
            return `AND 'Source IP(s) and Hostname(s)' ~ '${search['Source IP(s) and Hostname(s)']}'`;
        } else if (search['Destination IP(s) and Hostname(s)']) {
            return `AND 'Destination IP(s) and Hostname(s)' ~ '${search['Destination IP(s) and Hostname(s)']}'`;
        } else {
            return '';
        }
    };
    let cachedEntry = GM_getValue('cachedEntry', null);

    let url = `${
        cachedEntry['hk']
    }/issues/?jql=text ~ "%s" AND "Log Source Domain" ~ "%D" ${Host()} ORDER BY created DESC`;
    if (window.location.href.includes(cachedEntry['macao'].split('//')[1])) {
        url = `${cachedEntry['macao']}/issues/?jql=text ~ "%s" ORDER BY created DESC`;
    }
    console.log('===url', url);

    const searchEngines = [
        {
            name: 'Jira',
            url: url
        },
        { name: 'VT', url: 'https://www.virustotal.com/gui/search/%s' },
        { name: 'AbuseIPDB', url: 'https://www.abuseipdb.com/check/%s' },
        {
            name: 'Base64 Decode',
            url: `https://icyberchef.com/#recipe=From_Base64('A-Za-z0-9%2B/%3D',true,false)&input=%b`
        }
    ];
    searchEngines.forEach((engine) => {
        GM_registerMenuCommand(engine.name, () => {
            const selectedText = window.getSelection().toString();
            const searchURL = engine.url
                .replace('%s', selectedText)
                .replace('%D', LogSourceDomain)
                .replace('%b', btoa(selectedText));
            if (selectedText.length === 0) {
                showFlag('error', 'No text selected', 'Please select some text and try again', 'auto');
            } else {
                window.open(searchURL, '_blank');
            }
        });
    });
}

/**
 * This function registers custom add/remove quick reply menus in Tampermonkey
 * Add custom reply: input custom reply and store in local
 * Remove quick reply: remove all local storage custom replies
 */
function registerCustomQuickReplyMenu() {
    GM_registerMenuCommand('Add Custom Quick Reply', () => {
        const userInput_name = prompt('Enter saved quick reply name (the name should be unique)').toString();
        const userInput_reply = prompt('Enter a custom quick reply (<br> is used for line break)').toString();
        if (userInput_name !== null && userInput_reply !== null) {
            const key = `customReply_${userInput_name}`;
            // local save
            localStorage.setItem(key, userInput_reply);
        }
    });

    GM_registerMenuCommand('Remove Custom Quick Reply', () => {
        for (let i = 0; i < localStorage.length; i++) {
            const key = localStorage.key(i);
            if (key.startsWith('customReply_')) {
                localStorage.removeItem(key);
            }
        }
        showFlag('success', 'Cleared All Custom Replies', '', 'auto');
    });
    GM_registerMenuCommand('MDE Assist', () => {
        let MDE_Assist_ = localStorage.getItem('MDE_Assist');
        const MDE_Assist = prompt(
            'Whether MDE Assist is enabled(Example:enable  1, disable   0)',
            MDE_Assist_
        ).toString();
        localStorage.setItem('MDE_Assist', MDE_Assist);
    });
}

/**
 * This function create a Quick Reply button in editor
 */
function QuickReply() {
    const replyButton = `<button class="aui-button aui-dropdown2-trigger" aria-controls="is-radio-checked">Quick Reply</button>
    <aui-dropdown-menu id="is-radio-checked">
    <aui-section id="reply">
       <aui-item-radio interactive>Close ticket</aui-item-radio>
        <aui-item-radio interactive>Monitor ticket</aui-item-radio>
        <aui-item-radio interactive>Waiting ticket</aui-item-radio>
        <aui-item-radio interactive>Waiting Full Scan</aui-item-radio>
        <aui-item-radio interactive>Ask for Whitelist</aui-item-radio>
        <aui-item-radio interactive>Whitelist Done</aui-item-radio>
		<aui-item-radio interactive>Agent recover</aui-item-radio>
        <aui-item-radio interactive>Leaked Credentials</aui-item-radio>
		<aui-item-radio interactive>Compromised Accounts</aui-item-radio>
		<aui-item-radio interactive>Log resume</aui-item-radio>
		<aui-item-radio interactive>关闭工单</aui-item-radio> 
		<aui-item-radio interactive>Haeco high severity</aui-item-radio>
        <aui-item-radio interactive>Haeco medium severity</aui-item-radio>
        <aui-item-radio interactive>Haeco low severity</aui-item-radio>
    </aui-section>
    </aui-dropdown-menu>`;
    const commentBar = $($('.aui-toolbar2-primary')[1]);
    commentBar.append(replyButton);

    const commentBarSection = document.querySelector('aui-section#reply');
    const replyComment = {
        'Close ticket': 'Dear Customer,<br>Thanks for your reply, we will close this ticket.<br>Best Regards.',
        'Monitor ticket': 'Dear Customer,<br>Thanks for your reply, we will keep monitor.<br>Best Regards.',
        'Waiting ticket': 'Dear Customer,<br>Thanks, we look forward to hearing from you.',
        'Waiting Full Scan':
            'Dear Customer,<br>Full scan have been triggered , if suspicious files detected new MDE alert/ticket will be created.',
        'Ask for Whitelist': 'Dear Customer,<br>Can we add the ticket to white list?<br>Best Regards.',
        'Whitelist Done':
            'Dear Customer,<br>We have informed the relevant parties to add this ticket to the white list and will close this ticket<br>Best Regards.',
        'Haeco high severity':
            '<h2><strong><span style="color: red;" data-mce-style="color: red;"><samp>[The ticket is escalated to High Severity]</samp></span></strong></h2><br>',
        'Haeco medium severity':
            '<h2><span style="color: rgb(255, 171, 0);" data-mce-style="color: #ffab00;"><strong><samp>[The ticket is escalated to Medium Severity]</samp></strong></span></h2><br>',
        'Haeco low severity':
            '<h2><span style="color: rgb(76, 154, 255);" data-mce-style="color: #4c9aff;"><strong><samp>[The ticket is de-escalated to Low Severity]</samp></strong></span></h2><br>',
        'Leaked Credentials':
            '<p>Dear Client,</p><p>Our Cyber Threat Intelligence investigated the incident and found &lt;Number&gt; leaked credentials related to your organization exposed in dark web. The credentials are listed below:</p><table width="962" class="mce-item-table"><tbody><tr><td width="137"><div><p><strong>EMAIL/USERNAME</strong></p></div></td><td width="137"><div><p><strong>PASSWORD TYPE</strong></p></div></td><td width="137"><div><p><strong>PASSWORD</strong></p></div></td><td width="137"><div><p><strong>SOURCE</strong></p></div></td><td width="137"><div><p><strong>PRICE</strong></p></div></td><td width="137"><div><p><strong>POSTED DATE</strong></p></div></td><td width="137"><div><p><strong>SERVICE</strong></p></div></td></tr><tr><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td></tr></tbody></table><p>[Source Detail from Kela]</p><p>&lt;SOURCE Details/Description&gt;</p><p>[Service if disclose need check]</p><p>As per our open-source investigation through passive means, we observe that:</p><p>&lt; SERVICE&gt; appear to be &lt;SERVICE USAGE&gt;</p><p>[Recommendation]</p><p>We recommend confirming that the service coverage is to customers only, or whether it also includes staff and/or third-party, and evaluate if accounts with administrative privileges require a password change. &nbsp;We also recommend to heighten monitoring of customer login to indicate anomalies in location or timing, and review password policies and evaluate if there is a need to strengthen (e.g., mandate password rotation regularly). A further recommendation is to reach out to these account holders if the accounts are still active, and request that they change their passwords.</p><p>Please do not hesitate to reach out to us if you have any queries. Thank you.</p><p>Best Regards,<br>Cyber Threat Intelligence Team</p>',
        'Compromised Accounts':
            '<p>Dear Client,</p><p>Our Cyber Threat Intelligence investigated the incident and found&nbsp;&lt;Number&gt; compromised accounts related to your organisation exposed in dark web. The credentials are listed below:</p><table width="962" class="mce-item-table"><tbody><tr><td width="137"><div><p><strong>EMAIL/USERNAME</strong></p></div></td><td width="137"><div><p><strong>PASSWORD TYPE</strong></p></div></td><td width="137"><div><p><strong>PASSWORD</strong></p></div></td><td width="137"><div><p><strong>SOURCE</strong></p></div></td><td width="137"><div><p><strong>PRICE</strong></p></div></td><td width="137"><div><p><strong>POSTED DATE</strong></p></div></td><td width="137"><div><p><strong>SERVICE</strong></p></div></td></tr><tr><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td><td width="137"><br data-mce-bogus="1"></td></tr></tbody></table><p>[Source Detail from Kela]</p><p>&lt;SOURCE Details/Description&gt;</p><p>[Service if disclose need check]</p><p>As per our open-source investigation through passive means, we observe that:</p><p>&lt; SERVICE&gt; appear to be &lt;SERVICE USAGE&gt;&nbsp;</p><p>[Recommendation]</p><p>We recommend confirming that the service coverage is to customers only, or whether it also includes staff and/or third-party, and evaluate if accounts with administrative privileges require a password change. &nbsp;We also recommend to heighten monitoring of customer login to indicate anomalies in location or timing, and review password policies and evaluate if there is a need to strengthen (e.g., mandate password rotation regularly). A further recommendation is to reach out to these account holders if the accounts are still active, and request that they change their passwords.</p><p>Please do not hesitate to reach out to us if you have any queries. Thank you.</p><p>Best Regards,<br>Cyber Threat Intelligence Team</p>',
        'Log resume':
            'Dear Customer,<br>Thanks for your reply, <br>Log resumed, we will close this ticket.<br>Best Regards.',
        'Agent recover':
            'Dear Customer,<br>Thanks for your reply,<br>The agent is now active and we will close this case<br>Best Regards.',
        '关闭工单': '尊敬的客户,<br>感谢您的回复,我们将关闭此工单。 <br>祝您生活愉快。<br>'
    };

    // Check local storage at initialization time
    function getAllCustomReply() {
        for (let i = 0; i < localStorage.length; i++) {
            const key = localStorage.key(i);
            if (key.startsWith('customReply_')) {
                const storedReply = localStorage.getItem(key).toString();
                const storeReplyName = key.split('_')[1].toString();
                replyComment[storeReplyName] = storedReply;
                $('#reply').append(`<aui-item-radio interactive>${storeReplyName}</aui-item-radio>`);
            }
        }
    }
    getAllCustomReply();

    try {
        if (commentBarSection !== null) {
            commentBarSection.addEventListener('change', function (e) {
                if (e.target.hasAttribute('checked')) {
                    tinymce.activeEditor.setContent('');
                    let replyValue = replyComment[e.target.textContent];
                    tinymce.activeEditor.execCommand('mceInsertContent', false, replyValue);
                }
            });
        }
    } catch (error) {
        console.error(error);
    }
}

/**jsonView */
function jsonToTree(data) {
    let flag = false;
    let html = '<ul class="code-java" style="list-style-type: none;margin-top: 0px;padding-left: 20px;">';
    if (Array.isArray(data)) {
        let temp = '[';
        data.forEach((element) => {
            temp += jsonToTree(element);
        });
        html += temp + '],';
    } else if (data != null && typeof data === 'object' && Object.keys(data).length !== 0) {
        flag = true;
        for (let key in data) {
            if (data.hasOwnProperty(key)) {
                html += '<li class="code-quote">"' + key + '": ';
                if (Array.isArray(data[key])) {
                    let temp = '[';
                    data[key].forEach((element) => {
                        temp += jsonToTree(element);
                    });
                    html += temp + '],';
                } else if (typeof data[key] === 'object') {
                    try {
                        if (Object.keys(data[key]).length == 0) {
                            html += '{},';
                        } else {
                            const str = jsonToTree(data[key]);
                            html += str;
                        }
                    } catch (TypeError) {
                        html += '"",';
                    }
                } else {
                    html += '"' + data[key].toString() + '",';
                }
                html += '</li>';
            }
        }
    } else {
        html += '"' + data.toString() + '",';
    }
    if (flag === true) {
        html = '{' + html + '},';
    }
    html += '</ul>';
    return html;
}

function ToWhitelist() {
    const summary = $('#summary-val').text().trim();
    var LogSourceDomain = $('#customfield_10223-val').text().trim();
    let DecoderName = $('#customfield_10807-val').text().trim().toLowerCase();
    let Component = 'Wazuh';
    if (DecoderName.includes('mde') || DecoderName.includes('m365')) {
        Component = 'MDE';
    }
    if (DecoderName.includes('cortex')) {
        Component = 'Cortex';
    }
    let whitelist = {
        summary: summary,
        LogSourceDomain: LogSourceDomain,
        Component: Component,
        MSS: window.location.href
    };
    localStorage.setItem('whitelist', JSON.stringify(whitelist));
    let cachedEntry = GM_getValue('cachedEntry', null);
    window.open(`${cachedEntry['hk']}/plugins/servlet/desk/portal/2/create/100`, '_blank');
}

/**
 * This function registers two Tampermonkey exception menu command
 * Add Exception: adds the currently selected text to an exception list stored in local storage
 * Clear Exception: clears the exception list from local storage
 */
let exceptionKey = localStorage.getItem('exceptionKey')?.split(',') || [];
let notifyKey = [...exceptionKey];
function registerExceptionMenu() {
    console.log('#### Code registerExceptionMenu run ####');
    GM_registerMenuCommand('Add Exception', () => {
        const selection = window.getSelection().toString().trim();
        if (!selection) {
            showFlag('error', 'No Issue Key selected', '', 'auto');
            return;
        }
        exceptionKey.push(selection);
        localStorage.setItem('exceptionKey', exceptionKey.toString());
        showFlag('success', '', `Added <strong>${selection}</strong> successfully`, 'auto');
    });

    GM_registerMenuCommand('Clear Exception', () => {
        localStorage.setItem('exceptionKey', '');
        exceptionKey = notifyKey = [];
        showFlag('success', 'Cleared All Issue Key', '', 'auto');
    });

    GM_registerMenuCommand('JsonViewer', () => {
        var isJson = function (str) {
            try {
                JSON.parse(str);
            } catch (e) {
                showFlag('error', 'Please select json format data', '', 'auto');
                return false;
            }
            return true;
        };
        let selection = window.getSelection().toString().trim();
        if (!selection) {
            showFlag('error', 'No Issue Key selected', '', 'auto');
            return;
        } else if (isJson(selection)) {
            var jsonData = jsonToTree(JSON.parse(selection));
            /**  var jsonView = document.createElement('pre');
            jsonView.textContent = JSON.stringify(jsonData,null,2);
            **/
            showDialog(jsonData, 'Json Format');
        }
    });
}

/**
 * This function creates audio and checkbox controls and adds them to the Jira share button's parent node
 * @returns {Object} Object containing references to the audio control and audio checkbox, keep checkbox, prompt checkbox
 */
// ## In the future, the alert sound will be migrated to another server, and more fun music will be added.
function createNotifyControls() {
    console.log('#### Code createNotifyControls run ####');
    const operationsBar = $('div.saved-search-operations.operations');
    const audioControl = $('<span></span>');

    function createAudioControl(parentNode) {
        const currentDate = new Date();
        const audioURL =
            currentDate.getHours() >= 9 && currentDate.getHours() < 21
                ? 'https://gitee.com/aspirepig/aspirepig/raw/master/12221.wav'
                : 'https://gitee.com/aspirepig/aspirepig/raw/master/alerts.wav';
        audioControl.html(`<audio id="myAudio" src="${audioURL}" type="audio/mpeg" controls></audio>`);
        parentNode.prepend(audioControl);
    }

    function createCheckbox(parentNode, localStorageKey, checkStatus) {
        const checkbox = $('<span></span>');
        const value = localStorage.getItem(localStorageKey);
        checkbox.html(
            `<input type="checkbox" name="${localStorageKey}" ${
                value == 'true' ? 'checked' : checkStatus ? 'checked' : ''
            }>${localStorageKey}`
        );
        checkbox.find('input').on('click', () => {
            localStorage.setItem(localStorageKey, checkbox.find('input').prop('checked'));
        });
        parentNode.prepend(checkbox);
        return checkbox;
    }
    createAudioControl(operationsBar);
    const audioCheckbox = createCheckbox(operationsBar, 'audioNotify', false);
    const keepCheckbox = createCheckbox(operationsBar, 'keepAudio', false);
    const promptCheckbox = createCheckbox(operationsBar, 'prompt', true);

    return { audioControl, audioCheckbox, keepCheckbox, promptCheckbox };
}

/**
 * Check for updates in the issues list and play a sound if new issues are found
 * @param {Object} NotifyControls - Object containing the audio control, audio checkbox, keep checkbox, prompt checkbox
 */
function checkupdate(NotifyControls) {
    console.log('#### Code checkupdate run ####');
    const { audioControl, audioCheckbox, keepCheckbox, promptCheckbox } = NotifyControls;
    const table = $('tbody');
    if (!table.length) return;
    let cachedEntry = GM_getValue('cachedEntry', null);

    let Tickets = '';
    table.find('tr').each(function () {
        const summary = $(this).find('.summary p').text().trim();
        const issuekey = $(this).find('.issuekey a.issue-link').attr('data-issue-key');
        if (!notifyKey.includes(issuekey)) {
            notifyKey.push(issuekey);
            Tickets += `${summary}==${issuekey}\n`;
        }
    });
    if (Tickets || keepCheckbox.find('input').prop('checked')) {
        if (audioCheckbox.find('input').prop('checked')) {
            audioControl.find('audio').get(0).currentTime = 0;
            audioControl.find('audio').get(0).play();
        }
    }

    $('.aui-banner').remove();
    let overdueTickets = '';
    table.find('tr').each(function () {
        const issuekey = $(this).find('.issuekey a.issue-link').attr('data-issue-key');
        const datetime = new Date($(this).find('.updated time').attr('datetime'));
        const currentTime = new Date();
        const diffMs = currentTime - datetime;
        const diffMinutes = Math.floor(diffMs / 60000);
        if (diffMinutes > 30 && diffMinutes < 120) {
            overdueTickets += `<a href="${cachedEntry['hk']}/browse/${issuekey}" target="_blank">${issuekey}</a>, `;
        }
    });
    if (overdueTickets && promptCheckbox.find('input').prop('checked')) {
        GM_addStyle(`
        .aui-banner.aui-banner-warning {
            background-color: #ffab00 !important;
            color: black !important;
        }
    `);
        AJS.banner({
            body: `Ticket: ${overdueTickets}<br>30 minutes have passed since the ticket's status changed, please handle it as soon as possible`,
            type: 'warning'
        });
    }
}

/**
 * This function checks for specific keywords within a string
 * Advises the user to double-check and contact L2 or TL if suspicious.
 */
function checkKeywords() {
    console.log('#### Code checkKeywords run ####');
    function check(keywords) {
        const rawLog = $('#customfield_10219-val').text().trim().toLowerCase();
        const summary = $('#summary-val').text().trim().toLowerCase();
        let Raw_Crotex_alert = $('.code-java').text().trim().toLowerCase();

        for (const keyword of keywords) {
            if (
                rawLog.includes(keyword['keyword'].toLowerCase()) ||
                Raw_Crotex_alert.includes(keyword['keyword'].toLowerCase()) ||
                summary.includes(keyword['keyword'].toLowerCase())
            ) {
                AJS.banner({
                    body: `\"${keyword['keyword']}\" was found in the ticket, it is maybe used for "${keyword['remark']}", please double-check and contact L2 or TL if suspicious.`
                });
            }
        }
    }
    function fetchData(url, apiKey) {
        const cachedKeywordsContent = GM_getValue('cachedKeywordsContent', null);
        const cachedWebsiteContent = GM_getValue('cachedWebsiteContent', null);
        const cachedWhitehashContent = GM_getValue('cachedWhitehashContent', null);
        GM_xmlhttpRequest({
            method: 'GET',
            url: url,
            headers: {
                'api-key': apiKey
            },
            timeout: 4000, // 超过4秒未获取到文件则使用缓存文件
            onload: function (response) {
                if (response.status === 200) {
                    const data = JSON.parse(response.responseText)['data'];

                    console.log(data);
                    if (cachedKeywordsContent == null) {
                        GM_setValue('cachedKeywordsContent', data['keywords']);
                    }
                    if (cachedWebsiteContent == null) {
                        GM_setValue('cachedWebsiteContent', data['website']);
                        let cachedEntry = {};
                        data['website'].forEach((item, index) => {
                            if (item && item['name'] == 'hk' && item['url']) {
                                cachedEntry['hk'] = item['url'];
                            }
                            if (item && item['name'] == 'macao' && item['url']) {
                                cachedEntry['macao'] = item['url'];
                            }
                            GM_setValue('cachedEntry', cachedEntry);
                        });
                    }
                    if (cachedWhitehashContent == null) {
                        GM_setValue('cachedWhitehashContent', data['whitehash']);
                    }
                } else {
                    console.error('Error fetching cachedContent:', response.status);
                }
            },
            ontimeout: function () {
                if (cachedKeywordsContent == null || cachedWebsiteContent == null || cachedWhitehashContent == null) {
                    showFlag('Error', 'BTAS缓存数据获取失败', '未连接到 VPN,请连接后刷新页面', 'auto');
                }
            },
            onerror: function (error) {
                console.error('Error:', error);
            }
        });
    }

    const url = 'https://172.18.4.200/api/7vVKD9hF/message/';
    const apiKey = 'Tnznjha3yhJgA7YG';
    const cachedKeywordsContent = GM_getValue('cachedKeywordsContent', null);
    if (cachedKeywordsContent == null) {
        fetchData(url, apiKey);
    }
    check(cachedKeywordsContent);
}

/**
 * This function is used for checking ATT&CK field
 */
function checkATTCK() {
    const status = $('#opsbar-transitions_more > span').text().trim();
    const attck = $('#rowForcustomfield_10220 > div > strong > label').text();
    if (status == 'Waiting for customer' && attck == '') {
        AJS.banner({ body: `The ATT&CK field is not filled in` });
    }
}

/**
 * This function is used for popping up MSS ticket considerations when clicked "Edit" and "Resolved" button or page loading.
 * Ticket Considerations file is store in cloud server
 * @param {Object} pageData - Gets the specified fields from the jira page
 */
function ticketNotify(pageData) {
    console.log('#### Code ticketNotify run ####');

    function fetchOrgNotifydict() {
        // 从本地存储获取缓存的文件内容和上次更新时间
        const cachedContent = GM_getValue('cachedFileContent', null);

        GM_xmlhttpRequest({
            method: 'GET',
            url: 'https://172.18.4.200/api/7vVKD9hF/notifys/',
            headers: {
                'api-key': 'Tnznjha3yhJgA7YG'
            },
            timeout: 4000, // 超过4秒未获取到文件则使用缓存文件
            onload: function (response) {
                if (response.status === 200) {
                    const data = JSON.parse(response.responseText)['data'];

                    // 本地无缓存,第一次获取文件保存到本地
                    if (cachedContent == null) {
                        // 更新本地存储中的文件内容和更新时间
                        GM_setValue('cachedFileContent', data);

                        checkNotify(data.items, pageData);
                    }

                    // 如果本地存储中有缓存,并且文件内容有变化
                    if (cachedContent !== null && JSON.stringify(cachedContent) !== JSON.stringify(data)) {
                        // 更新本地存储中的文件内容
                        GM_setValue('cachedFileContent', data);

                        // 使用最新文件
                        checkNotify(data.items, pageData);
                    }

                    // 本地存在缓存,且内容相同则使用缓存文件
                    if (cachedContent !== null && JSON.stringify(cachedContent) == JSON.stringify(data)) {
                        checkNotify(cachedContent.items, pageData);
                    }
                } else {
                    console.error('Error fetching orgNotifydict:', response.status);
                }
            },
            ontimeout: function () {
                if (cachedContent !== null) {
                    checkNotify(cachedContent.items, pageData);
                } else {
                    showFlag('Error', '文件获取失败', '未连接到 VPN,请连接后刷新页面', 'auto');
                }
            },
            onerror: function (error) {
                console.error('Error:', error);
            }
        });
    }
    fetchOrgNotifydict();

    function checkNotify(Notifydict, pageData) {
        // get button path
        const buttonMap = {
            Edit: '#edit-issue',
            Resolve: '#action_id_761',
            None: ''
        };
        const searchStrings = [];

        // 查找并高亮指定字符串的函数
        function highlightTextInElement(selector, searchStrings) {
            const element = $(selector);
            if (element.length === 0) {
                console.error('未找到指定的元素');
                return;
            }

            // 获取元素文本内容
            let text = element.text().trim();

            // 对每个字符串进行高亮处理
            searchStrings.forEach((searchString) => {
                // 在文本中查找并替换匹配的字符串
                text = text.replace(
                    new RegExp(searchString, 'gi'),
                    (match) => `<span style="background-color: yellow;">${match}</span>`
                );
            });

            // 将替换后的文本重新设置为元素的 HTML 内容
            element.html(text);
        }

        function checkProperties(properties, pageData, ticketname) {
            const condition = (property) => {
                const propertyArray = property.propertiesVal.split(',');
                let isAllConditionsMet = false;
                for (const val of propertyArray) {
                    try {
                        if (!property.conditionOptions) {
                            let isTrue = pageData[property.propertiesKey]
                                .toLowerCase()
                                .includes(val.trim().toLowerCase().replace('!', ''));
                            if (val.trim().toLowerCase().includes('!')) {
                                isTrue = !isTrue;
                            }
                            if (isTrue) {
                                if (property.propertiesKey == 'RawLog') {
                                    searchStrings.push(val.trim());
                                }
                                isAllConditionsMet = true; // 如果任何一个属性满足条件,返回 true
                            }
                        }
                        switch (property.conditionOptions) {
                            case 'contain':
                                if (pageData[property.propertiesKey].toLowerCase().includes(val.trim().toLowerCase())) {
                                    isAllConditionsMet = true;
                                }
                                break;
                            case 'not contain':
                                if (
                                    !pageData[property.propertiesKey].toLowerCase().includes(val.trim().toLowerCase())
                                ) {
                                    isAllConditionsMet = true;
                                }
                                break;
                            case 'equal':
                                if (pageData[property.propertiesKey].toLowerCase() === val.trim().toLowerCase()) {
                                    isAllConditionsMet = true;
                                }
                                break;
                            case 'not equal':
                                if (pageData[property.propertiesKey].toLowerCase() !== val.trim().toLowerCase()) {
                                    isAllConditionsMet = true;
                                }
                                break;
                            default:
                                console.log('Unknown.');
                        }
                    } catch (error) {
                        if (
                            error.name === 'TypeError' &&
                            error.message == "Cannot read properties of undefined (reading 'includes')"
                        ) {
                            console.warn(`${ticketname} 提醒未加条件,请检查配置`);
                        }
                    }
                }
                return isAllConditionsMet; // 如果所有属性都不满足条件,则返回 false
            };
            properties = JSON.parse(properties);
            return properties.reduce((acc, property) => {
                return acc && condition(property);
            }, true);
        }
        let cachedEntry = GM_getValue('cachedEntry', null);
        let projectMap = {};
        projectMap[cachedEntry['hk'].split('//')[1]] = 'HK';
        projectMap[cachedEntry['macao'].split('//')[1]] = 'MO';

        for (const notify of Notifydict) {
            const { ticketname, starttime, endtime, message, properties, button, status, project } = notify;
            const isInTimeRange =
                (!starttime || new Date() >= new Date(starttime)) && (!endtime || new Date() <= new Date(endtime));
            const clickButton = buttonMap[button];

            if (status == 'Disable' || !isInTimeRange || projectMap[window.location.host] !== project) {
                continue;
            }

            if (checkProperties(properties, pageData, ticketname)) {
                if (clickButton == '') {
                    showFlag('warning', `${ticketname}`, `${message.replace(/\r?\n/g, '<br>')}`, 'manual');
                } else {
                    $(clickButton).on('click', () => {
                        showFlag('warning', `${ticketname}`, `${message.replace(/\r?\n/g, '<br>')}`, 'manual');
                    });
                }

                let selector;
                if (project == 'HK') {
                    selector = '#field-customfield_10219 > div:first-child > div:nth-child(2)';
                } else if (project == 'MO') {
                    selector = '#field-customfield_10904 > div.twixi-wrap.verbose > div';
                }
                highlightTextInElement(selector, searchStrings);
            }
        }
    }
}
/**
 * Creates a new button and adds it to the DOM.
 * @param {string} id - The ID attribute for the new button element.
 * @param {string} text - The text content to display on the new button.
 * @param {string} onClick - The function to call when the button is clicked.
 */
function addButton(id, text, onClick) {
    console.log(`#### Add Button: ${text}  ####`);
    const toolbar = $('.aui-toolbar2-primary');
    // 重复添加的按钮不会被显示
    if ($('#' + id).length === 0) {
        const button = $('<a>')
            .attr('id', id)
            .addClass('aui-button toolbar-trigger')
            .append($('<span>').addClass('trigger-label').text(text))
            .click(onClick);
        toolbar.append($('<div>').addClass('aui-buttons pluggable-ops').append(button));
    }
}

function monitorList() {
    var summaryElements = document.querySelectorAll('.summary');
    summaryElements.forEach(function (element) {
        if (
            element.textContent.includes('WebAvailability') ||
            element.textContent.includes('SWIFT login activity and select activity detected')
        ) {
            var audio = document.getElementById('myAudio');
            audio.play();
        }
    });
    var time_to_first_response = document.querySelectorAll('.sla-tag.sla-tag-ongoing');
    time_to_first_response.forEach(function (element) {
        console.log(element.outerText.replace('min', ''), element.outerText.replace('min', '') < 30);
        if (element.outerText.includes('min') && element.outerText.replace('min', '') < 30) {
            var audio = document.getElementById('myAudio');
            audio.play();
            console.log('出现特殊情况');
        }
    });
}

/**
 * Creates three buttons on a JIRA issue page to handle Cortex XDR alerts
 * The buttons allow users to generate a description of the alerts, open the alert card page and timeline page
 */
function cortexAlertHandler(...kwargs) {
    console.log('#### Code cortexAlertHandler run ####');
    const { LogSourceDomain, summary } = kwargs[0];
    const rawLog = $('#field-customfield_10232 > div.twixi-wrap.verbose > div > div > div > pre').text();
    /**
     * Extracts the log information and organization name from the current JIRA issue page
     * @param {Object} orgDict - A dictionary that maps organization name to navigator name
     * @returns {Object} An object that contains the organization's name, organization's navigator URL, raw log information
     */
    let orgDict = {};
    const cachedWebsiteContent = GM_getValue('cachedWebsiteContent', null);
    console.log(cachedWebsiteContent);
    if (cachedWebsiteContent != null) {
        cachedWebsiteContent.forEach((item, index) => {
            if (item && item['category'] == 'cortex' && item['url']) {
                orgDict[item['name']] = item['url'];
            }
        });
        console.log('===orgDict', orgDict);
    } else {
        alert('cachedWebsiteContent is empty,please connect VPN get information');
    }
    const orgNavigator = orgDict[LogSourceDomain];

    /**
     * Parse the relevant information from the raw log data
     * @param {Array} rawLog - An array of JSON strings representing the raw log data
     * @returns {Array} An array of objects containing the alert relevant information
     */
    function parseLog(rawLog) {
        let alertInfo = [];
        try {
            const { timestamp, data, rule } = JSON.parse(rawLog);
            let rule_description = rule['description'].split(':')[-1];
            const { cortex_xdr } = data;
            const { source, alert_id, name, description } = cortex_xdr;
            const isPANNGFW = source === 'PAN NGFW';
            let dotIndex = timestamp.lastIndexOf('.');

            dateTimeStr = timestamp.slice(0, dotIndex) + '+0800';
            const alert = { source, alert_id, name, description, dateTimeStr, rule_description };
            if (isPANNGFW) {
                const {
                    action_local_ip,
                    action_local_port,
                    action_remote_ip,
                    action_remote_port,
                    action_pretty,
                    alert_link
                } = cortex_xdr;
                alertInfo.push({
                    ...alert,
                    action_local_ip,
                    action_local_port,
                    action_remote_ip,
                    action_remote_port,
                    action_pretty,
                    alert_link
                });
            } else {
                const {
                    action_local_ip,
                    action_file_macro_sha256,
                    action_file_name,
                    action_file_path,
                    action_file_sha256,
                    action_process_image_name,
                    action_process_image_sha256,
                    action_process_image_command_line,
                    action_external_hostname,
                    actor_process_image_name,
                    actor_process_image_path,
                    actor_process_image_sha256,
                    actor_process_command_line,
                    causality_actor_process_image_name,
                    causality_actor_process_command_line,
                    causality_actor_process_image_path,
                    causality_actor_process_image_sha256,
                    os_actor_process_image_name,
                    os_actor_process_image_path,
                    os_actor_process_command_line,
                    os_actor_process_image_sha256,
                    action_pretty,
                    host_name,
                    host_ip,
                    user_name,
                    alert_link
                } = cortex_xdr;
                const action_list = {
                    action_file_name,
                    action_file_path,
                    action_file_sha256,
                    action_process_image_name,
                    action_process_image_sha256,
                    action_process_image_command_line
                };
                const actor_list = {
                    actor_process_image_name,
                    actor_process_image_path,
                    actor_process_image_sha256,
                    actor_process_command_line
                };
                const causality_actor_list = {
                    causality_actor_process_image_name,
                    causality_actor_process_command_line,
                    causality_actor_process_image_path,
                    causality_actor_process_image_sha256
                };
                const os_actor_list = {
                    os_actor_process_image_name,
                    os_actor_process_image_path,
                    os_actor_process_command_line,
                    os_actor_process_image_sha256
                };

                function countValidProperties(obj) {
                    const validPropsCount = Object.keys(obj).reduce((count, key) => {
                        if (obj[key] !== undefined) {
                            count++;
                        }
                        return count;
                    }, 0);
                    return validPropsCount;
                }

                const actionPropsCount = countValidProperties(action_list) ? countValidProperties(action_list) + 1 : 0;
                const actorPropsCount = countValidProperties(actor_list);
                const causalityPropsCount = countValidProperties(causality_actor_list);
                const osPropsCount = countValidProperties(os_actor_list);
                const maxCount = Math.max(actionPropsCount, actorPropsCount, causalityPropsCount, osPropsCount);

                const action_cmd_length = action_process_image_command_line
                    ? action_process_image_command_line.length
                    : 0;
                const actor_cmd_length = actor_process_command_line ? actor_process_command_line.length : 0;
                const causality_cmd_length = causality_actor_process_command_line
                    ? causality_actor_process_command_line.length
                    : 0;
                const os_cmd_length = os_actor_process_command_line ? os_actor_process_command_line.length : 0;
                const lengths = [action_cmd_length, actor_cmd_length, causality_cmd_length, os_cmd_length];
                const maxLength = Math.max(...lengths);

                let filename;
                let filepath;
                let sha256;
                let cmd;

                if (action_cmd_length === maxLength && actionPropsCount === maxCount) {
                    if (!WhiteFilehash(action_file_sha256 || action_process_image_sha256)) {
                        sha256 = action_file_sha256 || action_process_image_sha256;
                    }
                    filename = action_file_name || action_process_image_name;
                    filepath = action_file_path;
                    cmd = action_process_image_command_line;
                } else if (actor_cmd_length === maxLength && actorPropsCount === maxCount) {
                    if (!WhiteFilehash(actor_process_image_sha256)) {
                        sha256 = actor_process_image_sha256;
                    }
                    filename = actor_process_image_name;
                    filepath = actor_process_image_path;
                    cmd = actor_process_command_line;
                } else if (causality_cmd_length === maxLength && causalityPropsCount === maxCount) {
                    if (!WhiteFilehash(causality_actor_process_image_sha256)) {
                        sha256 = causality_actor_process_image_sha256;
                    }
                    filename = causality_actor_process_image_name;
                    filepath = causality_actor_process_image_path;
                    cmd = causality_actor_process_command_line;
                } else if (os_actor_process_image_name && osPropsCount === maxCount) {
                    if (!WhiteFilehash(os_actor_process_image_sha256)) {
                        sha256 = os_actor_process_image_sha256;
                    }
                    filename = os_actor_process_image_name;
                    filepath = os_actor_process_image_path;
                    cmd = os_actor_process_command_line;
                }

                alertInfo.push({
                    ...alert,
                    host_name,
                    host_ip,
                    alert_link,
                    user_name,
                    filename,
                    filepath,
                    cmd,
                    sha256,
                    action_pretty,
                    action_local_ip,
                    action_file_macro_sha256,
                    action_external_hostname
                });
            }
        } catch (error) {
            console.error(`Error: ${error.message}`);
        }

        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);

    /**
     * Define three functions for handling alert information:
     * generateDescription creates a description for each alert, and displays the combined description in an alert box
     * openCard opens a new window to display the alert card page for each alert
     * openTimeline opens a new window to display the timeline page for each alert
     */
    function generateDescription() {
        const alertDescriptions = [];
        for (const info of alertInfo) {
            let {
                source,
                name,
                action_local_ip,
                action_local_port,
                action_remote_ip,
                action_remote_port,
                action_pretty,
                description,
                alert_link,
                rule_description,
                action_external_hostname
            } = info;
            let unPanNgfw = [
                'host_name',
                'host_ip',
                'sha256',
                'action_file_macro_sha256',
                'filepath',
                'filename',
                'cmd',
                'user_name',
                'action_local_ip'
            ];
            if (description && description.includes('xdr_data')) {
                console.log(rule_description);
                description = rule_description;
            }
            if (source === 'PAN NGFW') {
                const desc = `Observed ${name}\ntimestamp: ${dateTimeStr}\nSrcip: ${action_local_ip}   Srcport: ${action_local_port}\nDstip: ${action_remote_ip}   Dstport: ${action_remote_port}\nAction: ${action_pretty}\n${
                    LogSourceDomain === 'cityu' ? 'Cortex Portal: ' + alert_link + '\n' : ''
                }\n\nPlease help to verify if this activity is legitimate.\n`;
                alertDescriptions.push(desc);
            } else {
                let comment = '\nPlease help to verify if this activity is legitimate.\n';
                if (
                    summary.toLowerCase().includes('wildfire malware') ||
                    summary.toLowerCase().includes('local analysis malware')
                ) {
                    comment = '\nPlease verify if the File is legitimate.   IF NOT, please Remove the File.\n';
                }
                let desc = `Observed ${
                    description || name
                }\ntimestamp: ${dateTimeStr} \n<span class="red_highlight">action_external_hostname: ${action_external_hostname}\n</span>action: ${action_pretty}\n`;
                for (const key of unPanNgfw) {
                    console.log(key);
                    if (Object.hasOwnProperty.call(info, key)) {
                        const value = info[key];
                        console.log(key, value);
                        if (value !== undefined) {
                            if (key == 'event_evidence') {
                                desc += `${key}: ${value.replace(/</g, '&lt;').replace(/>/g, '&gt;')}\n`;
                            } else {
                                desc += `${key}: ${value}\n`;
                            }
                        }
                    }
                }
                if (info['action_file_macro_sha256'] || info['sha256']) {
                    desc += `<a href="https://www.virustotal.com/gui/file/${
                        info['action_file_macro_sha256'] || info['sha256']
                    }">https://www.virustotal.com/gui/file/${info['action_file_macro_sha256'] || info['sha256']}</a>\n`;
                }
                alertDescriptions.push(desc + comment);
            }
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    function openCard() {
        for (const info of alertInfo) {
            const { source, alert_id } = info;
            if (orgNavigator) {
                let cardURL;
                switch (source) {
                    case 'XDR Analytics':
                        cardURL = `${orgNavigator}card/analytics2/${alert_id}`;
                        break;
                    case 'Correlation':
                        cardURL = `${orgNavigator}alerts/${alert_id}`;
                        break;
                    default:
                        cardURL = `${orgNavigator}card/alert/${alert_id}`;
                        break;
                }
                window.open(cardURL, '_blank');
            } else {
                showFlag('error', '', `There is no <strong>${LogSourceDomain}</strong> Navigator on Cortex`, 'auto');
            }
        }
    }
    function openTimeline() {
        for (const info of alertInfo) {
            const { source, alert_id } = info;
            if (orgNavigator) {
                let timelineURL;
                switch (source) {
                    case 'Correlation':
                        showFlag(
                            'error',
                            '',
                            `Source of the Alert is <strong>${source}</strong>, There is no Timeline on Cortex`,
                            'auto'
                        );
                        break;
                    default:
                        timelineURL = `${orgNavigator}forensic-timeline/alert_id/${alert_id}`;
                        break;
                }
                timelineURL && window.open(timelineURL, '_blank');
            } else {
                showFlag('error', '', `There is no <strong>${LogSourceDomain}</strong> Navigator on Cortex`, 'auto');
            }
        }
    }
    addButton('generateDescription', 'Description', generateDescription);
    addButton('openCard', 'Card', openCard);
    addButton('openTimeline', 'Timeline', openTimeline);
}

function HTSCAlertHandler(...kwargs) {
    console.log('#### Code HTSCAlertHandler run ####');
    const { rawLog } = kwargs[0];
    function decodeHtml(encodedString) {
        const tmpElement = document.createElement('span');
        tmpElement.innerHTML = encodedString;
        return tmpElement.innerText;
    }

    const parseLog = (rawLog) => {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const formatJson = log.substring(log.indexOf('{')).trim();
                // const logObj = JSON.parse(formatJson);
                const logObj = JSON.parse(formatJson.replace(/\\\(n/g, '\\n('));
                const eventEvidence = decodeHtml(logObj.event_evidence).split('End time')[0];
                const alert = {
                    attackType: logObj.tag,
                    hostRisk: logObj.hostRisk,
                    srcIP: logObj.src_ip,
                    eventEvidence,
                    hostName: logObj.hostName,
                    dstIP: logObj.dst_ip
                };
                acc.push(alert);
            } catch (error) {
                console.error(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    };
    const alertInfo = parseLog(rawLog);
    // console.info(`alertInfo: ${alertInfo}`);

    function generateDescription() {
        const alertDescriptions = [];
        for (const info of alertInfo) {
            const { attackType, hostRisk, srcIP, hostName, dstIP, eventEvidence } = info;
            const desc = `Observed ${attackType} Attack\nhostRisk: ${hostRisk}\nSrc_IP: ${srcIP}\nhostname: ${hostName}\nDst_IP: ${dstIP}\nevent_evidence: ${eventEvidence}\n\nPlease help to verify if this activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }
    addButton('generateDescription', 'Description', generateDescription);
}

function VMCEFAlertHandler(...kwargs) {
    const { rawLog } = kwargs[0];

    function parseCefLog(rawLog) {
        function cefToJson(cefLog) {
            let json = {};
            let fields = cefLog.split(' ');

            for (let i = 0; i < fields.length; i++) {
                let field = fields[i].split('=');
                let key = field[0];
                let value = field.slice(1).join('=');

                if (value) {
                    if (key === 'filePath' || key === 'msg' || key === 'start' || key === 'rt') {
                        let nextFieldIndex = i + 1;
                        while (nextFieldIndex < fields.length && !fields[nextFieldIndex].includes('=')) {
                            value += ' ' + fields[nextFieldIndex];
                            nextFieldIndex++;
                        }
                    }
                    json[key] = value;
                }
            }
            return json;
        }

        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                // Determine whether the log is empty
                if (Object.keys(log).length !== 0) {
                    // Split CEF log
                    let cef_log = log.split('|');
                    // Parsing CEF Header
                    const cef_log_header = cef_log.slice(1, 7);
                    // Parsing CEF Extends
                    const cef_log_extends = cefToJson(cef_log[7]);

                    acc.push({
                        Summary: cef_log_header[4],
                        // for some like "server error" tickets
                        HostName: cef_log_extends.dhost ? cef_log_extends.dhost : cef_log_extends.dvchost,
                        HostIp: cef_log_extends.dst,
                        UserName: cef_log_extends.duser,
                        FileName: cef_log_extends.fname,
                        FilePath: cef_log_extends.filePath,
                        Sha256: cef_log_extends.fileHash,
                        Msg: cef_log_extends.msg
                    });
                }
                return acc;
            } catch (error) {
                console.error(`Error: ${error.message}`);
            }
        }, []);
        return alertInfo;
    }
    const alertInfo = parseCefLog(rawLog);

    function generateDescription() {
        const alertDescriptions = [];
        for (const info of alertInfo) {
            const { Summary } = info;
            let desc = `Observed ${Summary}\n`;
            Object.entries(info).forEach(([index, value]) => {
                if (value !== undefined && index != 'Summary' && index != 'CBlink') {
                    desc += `${index}: ${value}\n`;
                }
            });
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    addButton('generateDescription', 'Description', generateDescription);
}

function CBAlertHandler(...kwargs) {
    console.log('#### Code CBAlertHandler run ####');
    const { rawLog } = kwargs[0];

    function parseLeefLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            const cb_log = {};
            try {
                const log_obj = log.split('\t');
                log_obj.forEach((log_item) => {
                    try {
                        const [key, value] = log_item.split('=');
                        cb_log[key] = value;
                    } catch (error) {
                        console.error(`Error: ${error.message}`);
                    }
                });
                if (log.trim() !== '') {
                    acc.push({
                        Summary: cb_log.watchlist_name,
                        HostName: cb_log.computer_name,
                        HostIp: cb_log.interface_ip,
                        UserName: cb_log.username,
                        CmdLine: cb_log.cmdline,
                        CBlink: cb_log.link_process,
                        Filepath: cb_log.path,
                        Sha256: cb_log.process_sha256
                    });
                }
            } catch (error) {
                console.error(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }

    const alertInfo = parseLeefLog(rawLog);

    function generateDescription() {
        const alertDescriptions = [];
        for (const info of alertInfo) {
            const { Summary } = info;
            let desc = `Observed ${Summary}\n`;
            Object.entries(info).forEach(([index, value]) => {
                if (value !== undefined && index != 'Summary' && index != 'CBlink') {
                    desc += `${index}: ${value}\n`;
                }
            });
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    function openCB() {
        let CBURL = '';
        for (const info of alertInfo) {
            const { CBlink } = info;
            if (CBlink) {
                CBURL += `${CBlink}\n`;
            }
        }
        showFlag('info', 'CB URL:', `${CBURL}`, 'manual');
    }

    addButton('generateDescription', 'Description', generateDescription);
    addButton('openCB', 'CB', openCB);
}

function WineventAlertHandler(...kwargs) {
    console.log('#### Code WineventAlertHandler run ####');
    let { rawLog, summary } = kwargs[0];
    var raw_alert = 0;
    const num_alert = $('#customfield_10300-val').text().trim();
    summary = summary.replace(/[\[(].*?[\])]/g, '');
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const { win } = JSON.parse(log);
                raw_alert += 1;
                const { eventdata, system } = win;
                const alertHost = system.computer;
                const systemTime = system.systemTime;
                acc.push({ systemTime, summary, alertHost, eventdata });
            } catch (error) {
                console.error(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);

    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        for (const info of alertInfo) {
            let desc = `Observed${info.summary}\nHost: ${info.alertHost}\n`;
            const date = new Date(info.systemTime.split('.')[0]);
            date.setHours(date.getHours() + 16);
            desc += `systemTime(<span class="red_highlight">UTC+8</span>): ${date.toISOString().split('.')[0]}\n`;
            for (const key in info.eventdata) {
                if (Object.hasOwnProperty.call(info.eventdata, key)) {
                    const value = info.eventdata[key];
                    if (value !== undefined) {
                        desc += `${key}: ${value}\n`;
                    }
                }
            }
            desc += '\n' + 'Please help to verify if this activity is legitimate.' + '\n';
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    addButton('generateDescription', 'Description', generateDescription);
}

function FortigateAlertHandler(...kwargs) {
    let { rawLog, summary, LogSourceDomain } = kwargs[0];
    var raw_alert = 0;
    const num_alert = $('#customfield_10300-val').text().trim();
    summary = summary.split(']')[1].trim();
    function ParseFortigateLog(rawLog) {
        const alertInfos = rawLog.reduce((acc, log) => {
            if (log == '') {
                return acc;
            }
            let jsonData = {};
            const regex = /(\w+)=(["'].*?["']|\S+)/g;
            let matchresult;
            raw_alert += 1;
            while ((matchresult = regex.exec(log)) !== null) {
                let key = matchresult[1];
                let value = matchresult[2];
                if (value.startsWith('"') && value.endsWith('"')) {
                    value = value.slice(1, -1);
                } else if (value.startsWith("'") && value.endsWith("'")) {
                    value = value.slice(1, -1);
                }
                jsonData[key] = value;
            }
            acc.push(jsonData);
            return acc;
        }, []);
        return [...new Set(alertInfos)];
    }

    const alertInfos = ParseFortigateLog(rawLog);
    function ExtractAlertInfo(ExtractAlertInfo) {
        const extract_alert_infos = alertInfos.reduce((acc, alertInfo) => {
            const {
                date,
                time,
                srcip,
                srcport,
                srccountry,
                dstip,
                dstport,
                dstcountry,
                hostname,
                url,
                referralurl,
                action,
                devname,
                user,
                cfgattr,
                msg,
                forwardedfor,
                analyticscksum,
                from,
                to,
                remip
            } = alertInfo;
            let arr = [];
            if (summary.toLowerCase().includes('infected file detected in fortigate')) {
                let vt_url;
                if (url) {
                    vt_url = 'https://www.virustotal.com/gui/domain/' + url.split('/')[2];
                } else {
                    vt_url = 'https://www.virustotal.com/gui/ip-address/' + srcip;
                }
                let sum = 'https://www.virustotal.com/gui/search/' + analyticscksum;
                arr.push(`<a href="${vt_url}">${vt_url}</a>`);
                arr.push(`<a href="${sum}">${sum}</a>`);
            } else if (summary.toLowerCase().includes('connection attempt')) {
                let vt_url = 'https://www.virustotal.com/gui/ip-address/' + dstip;
                arr.push(`<a href="${vt_url}">${vt_url}</a>`);
            } else if (summary.toLowerCase().includes('connection to newly registered domain')) {
                let vt_url = 'https://www.virustotal.com/gui/domain/' + hostname;
                arr.push(`<a href="${vt_url}">${vt_url}</a>`);
            } else if (summary.toLowerCase().includes('non-office hour successful vpn login')) {
                let vt_url = 'https://www.virustotal.com/gui/ip-address/' + remip;
                arr.push(`<a href="${vt_url}">${vt_url}</a>`);
            }

            const extract_alert_info = {
                datetime: `${date} ${time}`,
                srcip: srcip ? `${srcip}:${srcport}[${srccountry}]` : undefined,
                dstip: dstip ? `${dstip}:${dstport}[${dstcountry}]` : undefined,
                hostname: hostname,
                devname: devname,
                user: user,
                url: url,
                action: action,
                cfgattr: cfgattr,
                msg: msg,
                referralurl: referralurl,
                forwardedfor: forwardedfor || undefined,
                analyticscksum: analyticscksum,
                from: from,
                to,
                remip: remip,
                VT: arr.length > 0 ? arr : undefined
            };
            acc.push(extract_alert_info);
            return acc;
        }, []);
        return extract_alert_infos;
    }
    function ExtractAlertInfo_sonicwall(ExtractAlertInfo) {
        const extract_alert_infos = alertInfos.reduce((acc, alertInfo) => {
            acc.push({
                time: alertInfo.time,
                msg: alertInfo.msg,
                src: alertInfo.src,
                srcZone: alertInfo.srcZone,
                natSrc: alertInfo.natSrc,
                dst: alertInfo.dst,
                dstZone: alertInfo.dstZone,
                natDst: alertInfo.natDst,
                proto: alertInfo.proto
            });
            return acc;
        }, []);
        return extract_alert_infos;
    }
    let extract_alert_infos = '';
    if (LogSourceDomain == 'miramar') {
        console.log('===miramar');
        extract_alert_infos = ExtractAlertInfo_sonicwall(alertInfos);
    } else {
        extract_alert_infos = ExtractAlertInfo(alertInfos);
    }

    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        for (const info of extract_alert_infos) {
            let desc = `Observed ${summary}\n`;
            Object.entries(info).forEach(([index, value]) => {
                if (value !== undefined) {
                    desc += `${index}: ${value}\n`;
                }
            });
            let comment = '\nPlease help to verify if this activity is legitimate.\n';
            if (summary.toLowerCase().includes('to malware ip(s)') || summary.toLowerCase().includes('to tor ip(s)')) {
                comment = '\nPlease verify if the IP is legitimate.   If NOT, please block the dst ip\n';
            }
            desc += comment;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    addButton('generateDescription', 'Description', generateDescription);
}

function CSAlertHandler(...kwargs) {
    let { rawLog } = kwargs[0];
    var raw_alert = 0;
    const num_alert = $('#customfield_10300-val').text().trim();
    function parseCefLog(rawLog) {
        function cefToJson(cefLog) {
            let json = {};
            let fields = cefLog.split(' ');

            for (let i = 0; i < fields.length; i++) {
                let field = fields[i].split('=');
                let key = field[0];
                let value = field.slice(1).join('=');

                if (value) {
                    if (key === 'filePath' || key === 'msg' || key === 'cs5' || key === 'start' || key === 'rt') {
                        let nextFieldIndex = i + 1;
                        while (nextFieldIndex < fields.length && !fields[nextFieldIndex].includes('=')) {
                            value += ' ' + fields[nextFieldIndex];
                            nextFieldIndex++;
                        }
                    }
                    json[key] = value;
                }
            }
            return json;
        }

        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                // Determine whether the log is empty
                if (Object.keys(log).length !== 0) {
                    // Split CEF log
                    let cef_log = log.split('|');
                    // Parsing CEF Header
                    const cef_log_header = cef_log.slice(1, 7);
                    // Parsing CEF Extends
                    const cef_log_extends = cefToJson(cef_log[7]);
                    raw_alert += 1;
                    acc.push({
                        CreateTime: cef_log[0].split(' localhost ')[0],
                        Summary: cef_log_header[4],
                        // for some like "server error" tickets
                        HostName: cef_log_extends.dhost ? cef_log_extends.dhost : cef_log_extends.dvchost,
                        HostIp: cef_log_extends.dst,
                        UserName: cef_log_extends.duser,
                        FileName: cef_log_extends.fname,
                        FilePath: cef_log_extends.filePath,
                        Command: cef_log_extends.cs5,
                        Sha256: cef_log_extends.fileHash,
                        Msg: cef_log_extends.msg,
                        CSLink: cef_log_extends.cs6 ? cef_log_extends.cs6 : cef_log_extends.cs1
                    });
                }
                return acc;
            } catch (error) {
                console.error(`Error: ${error.message}`);
            }
        }, []);
        return alertInfo;
    }

    const alertInfo = parseCefLog(rawLog);

    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        for (const info of alertInfo) {
            const { Summary } = info;
            let desc = `Observed ${Summary}\n`;
            Object.entries(info).forEach(([index, value]) => {
                if (value !== undefined && index != 'Summary' && index != 'CSLink') {
                    desc += `${index}: ${value}\n`;
                }
            });
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }
    function openCS() {
        let CSURL = '';
        let cs_url = [];
        for (const info of alertInfo) {
            const { CSLink } = info;
            if (CSLink && !cs_url.includes(CSLink)) {
                CSURL += `${CSLink.replace('hXXps', 'https').replace(/[\[\]]/g, '')}<br><br>`;
            }
            cs_url.push(CSLink);
        }
        showFlag('info', 'CS URL:', `${CSURL}`, 'manual');
    }
    addButton('generateDescription', 'Description', generateDescription);
    addButton('openCS', 'CS', openCS);
}

function SophosAlertHandler(...kwargs) {
    let { rawLog } = kwargs[0];
    var raw_alert = 0;
    const num_alert = $('#customfield_10300-val').text().trim();
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                log.replace(/[\[(].*?[\])]/g, '');
                const { sophos, logsource } = JSON.parse(log);
                raw_alert += 1;
                const summary = sophos.name;
                const createtime = sophos.rt.split('.')[0] + 'Z';
                const alertHost = sophos.dhost;
                const alertUser = sophos.suser;
                const alertID = sophos.id;
                const alertIP = sophos?.source_info?.ip || sophos?.data?.source_info?.ip || '';
                const alertExtraInfo = {
                    'Sha256': sophos.appSha256,
                    'Filename': sophos?.data?.fileName ? sophos.data.fileName : undefined,
                    'Processname': sophos?.data?.processName ? sophos.data.processName : undefined,
                    'Process': sophos?.data?.process ? sophos.data.process : undefined,
                    'Clean Up Result': sophos?.core_remedy_items?.items[0]?.result
                };
                acc.push({ summary, createtime, alertHost, alertIP, alertUser, alertID, logsource, alertExtraInfo });
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);

    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        for (const info of alertInfo) {
            let desc = `Observed ${info.summary}\nHost: ${info.alertHost} IP: ${info.alertIP || 'N/A'}\nUser: ${
                info.alertUser
            }\ncreatetime:(<span class="red_highlight">GMT</span>)${info.createtime}\n`;
            for (const key in info.alertExtraInfo) {
                if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
                    const value = info.alertExtraInfo[key];
                    if (value !== undefined) {
                        desc += `${key}: ${value}\n`;
                    }
                }
            }
            if (!info.summary.includes('Failed to protect computer')) {
                desc += '\n' + 'Please help to verify if this activity is legitimate.' + '\n';
            }
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    function openSophos() {
        let searchID = '';
        for (const info of alertInfo) {
            const { alertHost, alertID, logsource } = info;
            if (alertID || alertHost) {
                searchID += `<strong>[${logsource}] ${alertHost}</strong>:<br>${alertID}<br><br>`;
            }
        }
        showFlag('info', 'Host and Alert ID', `${searchID}`, 'manual');
        GM_openInTab('https://cloud.sophos.com/manage/enterprise/alerts-list', {
            active: false, // 设置为 false,以在后台打开,不激活新标签页
            insert: true // 设置为 true,将新标签页插入到当前标签页之后
        });
    }

    addButton('generateDescription', 'Description', generateDescription);
    addButton('openSophos', 'Open Sophos', openSophos);
}

function SpemAlertHandler(...kwargs) {
    const { rawLog, summary } = kwargs[0];

    function parseLog(rawLog) {
        let logObject = {};
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                logArray = log.split(',');
                logArray[10] = 'Action:' + logArray[10];
                for (const index of logArray) {
                    const [key, value] = index.split(/:(.+)/, 2);
                    logObject[key] = value;
                }
                acc.push({
                    'Summary': logObject['Event Description'] !== undefined ? logObject['Event Description'] : summary,
                    'User Name': logObject['User Name'],
                    'Local Host IP': logObject['Local Host IP'],
                    'Local Port': logObject['Local Port'],
                    'Remote Host IP': logObject['Remote Host IP'],
                    'Remote Port': logObject['Remote Port'],
                    'Application': logObject['Application'],
                    'SHA-256': logObject['SHA-256'],
                    'Intrusion URL': logObject['Intrusion URL'],
                    'Action': logObject['Action']
                });
            } catch (error) {
                console.log(`Error: ${error}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }

    const alertInfo = parseLog(rawLog);

    function generateDescription() {
        const alertDescriptions = [];
        for (const info of alertInfo) {
            let desc = `Observed ${info['Summary']}\n`;
            Object.entries(info).forEach(([index, value]) => {
                if (value !== undefined && value !== ' ' && index != 'Summary') {
                    desc += `${index}: ${value}\n`;
                }
            });
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    addButton('generateDescription', 'Description', generateDescription);
}

function AwsAlertHandler(...kwargs) {
    const { rawLog, summary } = kwargs[0];
    var raw_alert = 0;
    const DecoderName = $('#customfield_10807-val').text().trim().toLowerCase();
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const { aws } = JSON.parse(log);
                if (DecoderName == 'aws-guardduty') {
                    let EventTime = aws.service.eventFirstSeen.split('.')[0] + 'Z';
                    const action = aws.service.action;
                    if (action.actionType == 'AWS_API_CALL') {
                        acc.push({
                            EventTime: EventTime,
                            actionType: action.actionType,
                            Api_Name: action?.awsApiCallAction?.api,
                            userName: aws?.resource?.accessKeyDetails?.userName,
                            RemoteIP: action?.awsApiCallAction?.remoteIpDetails?.ipAddressV4,
                            RemoteIP_country: action?.awsApiCallAction?.remoteIpDetails?.country.countryName
                        });
                    } else if (action.actionType == 'KUBERNETES_API_CALL') {
                        acc.push({
                            EventTime: EventTime,
                            actionType: action.actionType,
                            userName: aws?.resource?.accessKeyDetails?.userName,
                            sourceIPs: action?.kubernetesApiCallAction?.sourceIPs,
                            requestUri: action?.kubernetesApiCallAction?.requestUri
                        });
                    } else if (action.actionType == 'PORT_PROBE') {
                        acc.push({
                            EventTime: EventTime,
                            actionType: action.actionType,
                            localPort: action?.portProbeAction?.portProbeDetails.localPortDetails.port,
                            RemoteIP: action?.portProbeAction?.portProbeDetails.remoteIpDetails.ipAddressV4,
                            RemoteIP_country:
                                action?.portProbeAction?.portProbeDetails.remoteIpDetails.country.countryName
                        });
                    } else if (action.actionType == 'NETWORK_CONNECTION') {
                        console.log('===', action);
                        acc.push({
                            EventTime: EventTime,
                            actionType: action.actionType,
                            localIp: action?.networkConnectionAction?.localIpDetails.ipAddressV4,
                            localPortDetails: action?.networkConnectionAction?.localPortDetails.port,
                            remoteIp: action?.networkConnectionAction?.remoteIpDetails.ipAddressV4,
                            remotePortDetails: action?.networkConnectionAction?.remotePortDetails.port,
                            instanceId: aws?.resource?.instanceDetails?.instanceId,
                            platform: aws?.resource?.instanceDetails?.platform,
                            remoteIpcountryName: action?.networkConnectionAction?.remoteIpDetails?.country?.countryName
                        });
                    }
                } else if (summary.toLowerCase().includes('multiple sms request for same source ip')) {
                    let headers = aws.logEvents.message.httpRequest.headers;
                    let host, content;
                    headers.forEach((item) => {
                        if (item.name === 'host') {
                            host = item.value;
                        }
                        if (item.name == 'content-type') {
                            content = item.value;
                        }
                    });
                    acc.push({
                        log_file: aws.log_info.log_file,
                        clientIp: aws.logEvents.message.httpRequest.clientIp,
                        httpMethod: aws.logEvents.message.httpRequest.httpMethod,
                        uri: aws.logEvents.message.httpRequest.uri,
                        host: host,
                        content_type: content
                    });
                } else {
                    acc.push({
                        EventTime: aws?.eventTime,
                        EventName: aws?.eventName,
                        SourceIP: aws?.sourceIPAddress || aws?.internal_ip,
                        ExternalIP: aws?.external_ip,
                        Domain: aws?.domain,
                        User: aws?.userIdentity?.arn,
                        UserAgent: aws?.userAgent,
                        PrincipalId: aws?.userIdentity?.principalId,
                        Result: aws?.errorCode,
                        QueryType: aws?.query_type,
                        Action: aws?.action,
                        requestParameters: JSON.stringify(aws?.requestParameters),
                        responseElements: JSON.stringify(aws?.responseElements)
                    });
                }
                raw_alert += 1;
            } catch (error) {
                console.log(`Error: ${error}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }

    const alertInfo = parseLog(rawLog);
    const num_alert = $('#customfield_10300-val').text().trim();
    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        for (const info of alertInfo) {
            let desc = `Observed ${summary.split(']')[1]}\n`;
            Object.entries(info).forEach(([index, value]) => {
                if (value !== undefined && value !== ' ' && index != 'Summary') {
                    if (index == 'EventTime') {
                        desc += `EventTime(<span class="red_highlight">GMT</span>): ${value}\n`;
                    } else {
                        desc += `${index}: ${value}\n`;
                    }
                }
            });
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    addButton('generateDescription', 'Description', generateDescription);
}

function AzureAlertHandler(...kwargs) {
    const { rawLog } = kwargs[0];

    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const { eventhub, azure } = JSON.parse(log);
                const { ExtendedProperties, Entities } = eventhub;
                let entities = {};
                if (Entities) {
                    Entities.forEach(function (entity) {
                        if (entity.Type === 'host') {
                            entities['host'] = entity['HostName'];
                        }
                        if (entity.Type === 'network-connection') {
                            entities['SourceIP'] = entity['SourceAddress']['Address'];
                        }
                    });
                }
                acc.push({
                    AlertType: eventhub['AlertType'],
                    StartTimeUtc: eventhub['StartTimeUtc'],
                    Severity: eventhub['Severity'],
                    Intent: eventhub['Intent'],
                    Description: eventhub['Description'],
                    summary: azure['ThreatDescription'] || eventhub['AlertDisplayName'],
                    Protocol: azure['Protocol'],
                    SourceIP: azure['SourceIp'],
                    SourcePort: azure['SourcePort'],
                    DestinationIp: azure['DestinationIp'],
                    DestinationPort: azure['DestinationPort'],
                    URL: azure['Url'],
                    Action: azure['Action'],
                    ExtendedProperties: JSON.stringify(ExtendedProperties, null, 4),
                    ...entities,
                    alerturi: eventhub['AlertUri']
                });
            } catch (error) {
                console.log(`Error: ${error}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }

    const alertInfo = parseLog(rawLog);

    function generateDescription() {
        const alertDescriptions = [];
        for (const info of alertInfo) {
            let desc = `Observed ${info.summary}\n`;
            Object.entries(info).forEach(([index, value]) => {
                if (value !== undefined && value !== '' && index !== 'summary') {
                    if (index == 'StartTimeUtc') {
                        desc += `StartTimeUtc(<span class="red_highlight">GMT</span>): ${value.split('.')[0]}\n`;
                    } else {
                        desc += `${index}: ${value}\n`;
                    }
                }
            });
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    function openAzure() {
        let AzureURL = '';
        for (const info of alertInfo) {
            const { alerturi } = info;
            if (alerturi) {
                AzureURL += `${alerturi.replace('hXXps', 'https').replace(/\[|\]/g, '')}<br><br>`;
            }
        }
        showFlag('info', 'Azure URL:', `${AzureURL}`, 'manual');
    }

    addButton('generateDescription', 'Description', generateDescription);
    addButton('openAzure', 'Azure', openAzure);
}

function paloaltoAlertHandler(...kwargs) {
    const { rawLog, summary } = kwargs[0];
    var raw_alert = 0;
    const num_alert = $('#customfield_10300-val').text().trim();
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                let logArray = log.split(',');
                let logType = logArray[3];
                if (logType == 'GLOBALPROTECT') {
                    acc.push({
                        'Createtime': logArray[1],
                        'src ip': logArray[15],
                        'user': logArray[12]
                    });
                }
                if (logType == 'TRAFFIC') {
                    acc.push({
                        'Createtime': logArray[1],
                        'Summary': summary.split(']')[1],
                        'Source IP': logArray[7],
                        'Destination IP': logArray[8],
                        'Destination Port': logArray[25],
                        'Destination Location': logArray[42] != 0 ? logArray[42] : logArray[39]
                    });
                }
                if (logType == 'THREAT') {
                    let really = false,
                        malware_potential = [];
                    for (let i = 0; i < logArray.length; i++) {
                        if (logArray[i].includes('"') && i > 100) {
                            if (really) {
                                malware_potential.push(logArray[i]);
                            }
                            really = !really;
                        }
                        if (really) {
                            malware_potential.push(logArray[i]);
                        }
                    }
                    let vt_url = 'https://www.virustotal.com/gui/search/' + logArray[31].replace('"', '').split('/')[0];
                    let description = `</br>Timestamp: ${logArray[0].split(' ').slice(0, 3).join(' ')}</br>
Device: ${logArray[0].split(' ').slice(3, 5).join(' ')}</br>
Log Details:
    <ul><li>Event Time: ${logArray[1]}</li>
    <li>Log ID: ${logArray[2]}</li>
    <li>Type: ${logArray[3]}(${logArray[4]})</li>
    <li>Severity: ${logArray[34]}</li>
    <li>Rule Triggered: ${logArray[11]}</li>
    <li>Vulnerability: ${logArray[32]}</li>
    <li>Threat ID: ${logArray[34]}</li></ul>
Network Information:
    <ul><li>Source IP: ${logArray[7]}</li>
    <li>Destination IP: ${logArray[8]}</li>
    <li>URL/filename : ${logArray[31]}</li>
    <li>VT : <a href="${vt_url}">${vt_url}</a></li>
    <li>Source Zone: ${logArray[16]}</li>
    <li>Destination Zone: ${logArray[17]}</li>
    <li>Ingress Interface: ${logArray[18]}</li>
    <li>Egress Interface: ${logArray[19]}</li></ul>
Traffic Details:
    <ul><li>Protocol: ${logArray[29]}</li>
    <li>Application: ${logArray[14]}</li>
    <li>Direction: ${logArray[35]}</li>
    <li>Session ID: ${logArray[36]}</li></ul>
Vulnerability Information:</br>
    <ul><li>Exploit Type: ${logArray[69]}</li>
    <li>Attack Vector: ${logArray[111]}</li>
    <li>Affected Technology: ${logArray[112]},${logArray[113]}</li>
    <li>Malware Potential:${malware_potential}</li>
                                                    </ul>`;
                    raw_alert += 1;
                    acc.push(description);
                }
            } catch (error) {
                console.error(`Error:${error}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }

    const alertInfo = parseLog(rawLog);

    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        for (const info of alertInfo) {
            let arr = summary.split(']');
            let desc = `Observed ${arr[arr.length - 1]}\n`;
            if (typeof info == 'string') {
                desc += info;
            } else {
                Object.entries(info).forEach(([index, value]) => {
                    if (value !== undefined && value !== '' && index !== 'Summary') {
                        desc += `${index}: ${value}\n`;
                    }
                });
            }
            let comment = '\nPlease help to verify if this activity is legitimate.\n</br>';
            if (summary.toLowerCase().includes('to malware ip(s)') || summary.toLowerCase().includes('to tor ip(s)')) {
                comment = '\nPlease verify if the IP is legitimate.   If NOT, please block the dst ip\n';
            }
            desc += comment;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    addButton('generateDescription', 'Description', generateDescription);
}

function ImpervaincCEFAlertHandler(...kwargs) {
    const { rawLog } = kwargs[0];

    function parseCefLog(rawLog) {
        function cefToJson(cefLog) {
            let json = {};
            let fields = cefLog.split(' ');

            for (let i = 0; i < fields.length; i++) {
                let field = fields[i].split('=');
                let key = field[0];
                let value = field.slice(1).join('=');

                if (value) {
                    if (key === 'filePath' || key === 'msg' || key === 'start' || key === 'rt' || key === 'cs1') {
                        let nextFieldIndex = i + 1;
                        while (nextFieldIndex < fields.length && !fields[nextFieldIndex].includes('=')) {
                            value += ' ' + fields[nextFieldIndex];
                            nextFieldIndex++;
                        }
                    }
                    if (value == 'n/a') {
                        json[key] = undefined;
                    } else {
                        json[key] = value;
                    }
                }
            }
            return json;
        }

        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                // Determine whether the log is empty
                if (Object.keys(log).length !== 0) {
                    // Split CEF log
                    let cef_log = log.split('|');
                    let createtime = cef_log[0].split('CEF:')[0];
                    // Parsing CEF Header
                    const cef_log_header = cef_log.slice(1, 7);
                    // Parsing CEF Extends
                    const cef_log_extends = cefToJson(cef_log[7]);

                    acc.push({
                        summary: cef_log_extends.cs1,
                        // for some like "server error" tickets
                        createtime: createtime,
                        username: cef_log_extends.duser,
                        srcIP: cef_log_extends.src,
                        dstIP: cef_log_extends.dst,
                        dstPort: cef_log_extends.dpt,
                        protocol: cef_log_extends.proto
                    });
                }
                return acc;
            } catch (error) {
                console.error(`Error: ${error.message}`);
            }
        }, []);
        return alertInfo;
    }
    const alertInfo = parseCefLog(rawLog);

    function generateDescription() {
        const alertDescriptions = [];
        for (const info of alertInfo) {
            const { summary } = info;
            let desc = `Observed ${summary}\n`;
            Object.entries(info).forEach(([index, value]) => {
                if (value !== undefined && index != 'summary' && index != 'CBlink') {
                    desc += `${index}: ${value}\n`;
                }
            });
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    addButton('generateDescription', 'Description', generateDescription);
}

function AzureGraphAlertHandler(...kwargs) {
    const { summary, rawLog } = kwargs[0];
    var raw_alert = 0;
    if (summary.toLowerCase().includes('successful azure/o365 login from malware-ip')) {
        return;
    }
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const { azure } = JSON.parse(log);
                let properties = {};
                raw_alert += 1;
                if (azure.targetResources) {
                    for (const resource of azure.targetResources) {
                        if (summary.toLowerCase().includes('conditional access policy updated')) {
                            const { initiatedBy, targetResources, activityDateTime, activityDisplayName, result } =
                                azure;

                            const alertExtraInfo = {
                                userPrincipalName: initiatedBy?.user?.userPrincipalName
                                    ? initiatedBy?.user?.userPrincipalName
                                    : undefined,
                                displayName: targetResources[0]?.displayName
                                    ? targetResources[0]?.displayName
                                    : undefined,
                                activityDateTime: activityDateTime ? activityDateTime : undefined,
                                activityDisplayName: activityDisplayName ? activityDisplayName : undefined,
                                result: result ? result : undefined
                            };
                            acc.push({ alertExtraInfo });
                        } else {
                            if (resource.type == 'User') {
                                const resourceProperties = { TargetUser: resource.userPrincipalName };
                                properties = { ...properties, ...resourceProperties };
                            }
                            for (const prop of resource.modifiedProperties) {
                                properties = { ...properties, [prop['displayName']]: prop['newValue'] };
                            }
                            const activityDateTime = azure.activityDateTime.split('.')[0] + 'Z';
                            acc.push({
                                activityDateTime: activityDateTime,
                                AppDisplayName: azure?.appDisplayName || azure?.initiatedBy?.app?.displayName,
                                SourceUser: azure?.userPrincipalName || azure?.initiatedBy?.user?.userPrincipalName,
                                IpAddress: azure?.ipAddress || azure?.initiatedBy?.user?.ipAddress,
                                Location:
                                    azure?.location?.countryOrRegion && azure?.location?.state && azure?.location?.city
                                        ? `${azure?.location?.countryOrRegion}\\${azure?.location?.state}\\${azure?.location?.city}`
                                        : undefined,
                                ...properties,
                                Result: azure?.status?.failureReason || azure.result,
                                AdditionalInfo: azure?.additionalDetails[0]?.value
                                    ? azure?.additionalDetails[0]?.value
                                    : undefined
                            });
                        }
                    }
                } else {
                    const activityDateTime = azure.createdDateTime;
                    acc.push({
                        activityDateTime: activityDateTime,
                        AppDisplayName: azure?.appDisplayName || azure?.initiatedBy?.app?.displayName,
                        SourceUser: azure?.userPrincipalName || azure?.initiatedBy?.user?.userPrincipalName,
                        IpAddress: azure?.ipAddress || azure?.initiatedBy?.user?.ipAddress,
                        Location:
                            azure?.location?.countryOrRegion && azure?.location?.state && azure?.location?.city
                                ? `${azure?.location?.countryOrRegion}\\${azure?.location?.state}\\${azure?.location?.city}`
                                : undefined,
                        ...properties,
                        DeviceName: azure.deviceDetail.displayName || 'N/A',
                        failureReason: azure?.status?.failureReason || azure.result
                    });
                }
            } catch (error) {
                console.log(`Error: ${error}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }

    const alertInfo = parseLog(rawLog);
    const num_alert = $('#customfield_10300-val').text().trim();
    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        if (summary.toLowerCase().includes('conditional access policy updated')) {
            for (const info of alertInfo) {
                console.log(info['alertExtraInfo']['userPrincipalName']);
                let desc = `Observed  the user "${
                    info['alertExtraInfo']['userPrincipalName']
                }" was on (<span class="red_highlight">GMT</span>)${
                    info['alertExtraInfo']['activityDateTime'].split('.')[0]
                }ZS Updated the conditional access policy "${info['alertExtraInfo']['displayName']}"\n\n`;
                for (const key in info.alertExtraInfo) {
                    if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
                        const value = info.alertExtraInfo[key];
                        if (
                            value !== undefined &&
                            key != 'userPrincipalName' &&
                            key != 'displayName' &&
                            key != 'activityDateTime'
                        ) {
                            desc += `${key}: ${value}\n`;
                        }
                    }
                }
                desc += `\nIt is recommended that you verify that the user has permission to change the conditional access policy and that the action is a legitimate update known to the user. Thanks!\n`;
                alertDescriptions.push(desc);
            }
        } else {
            for (const info of alertInfo) {
                let desc = `Observed ${summary.split(']')[1]}\n`;
                console.log(info);
                for (const key in info) {
                    if (Object.hasOwnProperty.call(info, key)) {
                        const value = info[key];
                        if (value !== undefined && value !== '' && key != 'summary' && key != 'alerturi') {
                            if (key == 'activityDateTime') {
                                desc += `activityDateTime(<span class="red_highlight">GMT</span>): ${value}\n`;
                            } else {
                                desc += `${key}: ${value}\n`;
                            }
                        }
                    }
                }
                desc += `\nPlease verify if the activity is legitimate.\n`;
                alertDescriptions.push(desc);
            }
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    addButton('generateDescription', 'Description', generateDescription);
}

function ProofpointAlertHandler(...kwargs) {
    const { summary, rawLog } = kwargs[0];
    var raw_alert = 0;
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const BraceIndex = log.toString().indexOf('{');
                const lastBraceIndex = log.toString().lastIndexOf('}');
                // If the braces are found
                if (BraceIndex !== -1) {
                    raw_alert += 1;
                    console.log(`${raw_alert} iteration 'is being processed`);
                    // Intercepts a substring from the beginning of the brace to the end of the string
                    json_text = log.toString().substr(BraceIndex, lastBraceIndex);
                    try {
                        let json_alert = JSON.parse(json_text);
                        if (json_alert.hasOwnProperty('messagesDelivered')) {
                            for (const message of json_alert['messagesDelivered']) {
                                const { subject, sender, senderIP, recipient } = message;
                                const alertExtraInfo = {
                                    subject: subject ? subject : undefined,
                                    sender: sender ? sender : undefined,
                                    recipient: recipient ? recipient : undefined,
                                    senderIP: senderIP ? senderIP : undefined
                                };
                                acc.push({ alertExtraInfo });
                            }
                        } else if (json_alert['sourcetype'].includes('clicksPermitted')) {
                            json_alert['clickTime'] = json_alert['clickTime'].split('.')[0];
                            json_alert['threatTime'] = json_alert['threatTime'].split('.')[0];
                            acc.push({ alertExtraInfo: json_alert });
                            console.log('hellO');
                        } else {
                            const {
                                subject,
                                sender,
                                senderIP,
                                recipient,
                                headerFrom,
                                messageTime,
                                threatsInfoMap,
                                sourcetype,
                                spamScore,
                                phishScore,
                                cluster,
                                completelyRewritten,
                                id,
                                QID,
                                GUID
                            } = json_alert;
                            let alertExtraInfo = {
                                sourcetype: sourcetype ? sourcetype : undefined,
                                messageTime: messageTime ? messageTime : undefined,
                                subject: subject ? subject : undefined,
                                senderIP: senderIP ? senderIP : undefined,
                                sender: sender ? sender : undefined,
                                recipient: recipient ? recipient : undefined,
                                headerFrom: headerFrom ? headerFrom : undefined,
                                spamScore: spamScore ? spamScore : undefined,
                                phishScore: phishScore ? phishScore : undefined,
                                cluster: cluster ? cluster : undefined,
                                completelyRewritten: completelyRewritten ? completelyRewritten : undefined,
                                id: id ? id : undefined,
                                QID: QID ? QID : undefined,
                                GUID: GUID ? GUID : undefined
                            };
                            alertExtraInfo = Object.assign({}, alertExtraInfo, threatsInfoMap[0]);
                            acc.push({ alertExtraInfo });
                        }
                    } catch (error) {
                        console.log('Unable to parse JSON data, handling exception: ' + error);
                        var split_str = json_text
                            .split('"messagesDelivered" :')[1]
                            .split('"messagesBlocked" :')[0]
                            .slice(1, -2);
                        const json_alerts = JSON.parse(split_str);
                        for (const alert of json_alerts) {
                            const { subject, sender, senderIP, recipient } = alert;
                            console.log(subject, recipient);
                            const alertExtraInfo = {
                                subject: subject ? subject : undefined,
                                sender: sender ? sender : undefined,
                                recipient: recipient ? recipient : undefined,
                                senderIP: senderIP ? senderIP : undefined
                            };
                            acc.push({ alertExtraInfo });
                        }
                    }
                }
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }

    const alertInfo = parseLog(rawLog);
    const num_alert = $('#customfield_10300-val').text().trim();
    console.log('reduce the methods iterated altogether' + num_alert + ' times');
    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        for (const info of alertInfo) {
            let desc = `Observed ${summary.split(']')[1]}\n`;
            for (const key in info.alertExtraInfo) {
                if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
                    const value = info.alertExtraInfo[key];
                    if (value !== undefined) {
                        if (key == 'messageTime' || key == 'clickTime' || key == 'threatTime') {
                            desc += `${key}(<span class="red_highlight">GMT</span>): ${value.split('.')[0]}\n`;
                        } else {
                            desc += `${key}: ${value}\n`;
                        }
                    }
                }
            }
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    addButton('generateDescription', 'Description', generateDescription);
}

function ZscalerAlertHandler(...kwargs) {
    const { summary, rawLog } = kwargs[0];
    var raw_alert = 0;
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const BraceIndex = log.toString().indexOf('{');
                const lastBraceIndex = log.toString().lastIndexOf('}');

                // If the braces are found
                if (BraceIndex !== -1) {
                    raw_alert += 1;
                    // Intercepts a substring from the beginning of the brace to the end of the string
                    json_text = log.toString().substr(BraceIndex, lastBraceIndex);
                    const json_alert = JSON.parse(json_text);
                    const { PrivateIP, PublicIP, Username, Customer, Hostname } = json_alert;
                    const alertExtraInfo = {
                        Hostname: Hostname ? Hostname : undefined,
                        PublicIP: PublicIP ? PublicIP : undefined,
                        PrivateIP: PrivateIP ? PrivateIP : undefined,
                        Username: Username ? Username : undefined,
                        Customer: Customer ? Customer : undefined
                    };
                    acc.push({ alertExtraInfo });
                }
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }

    const alertInfo = parseLog(rawLog);
    const num_alert = $('#customfield_10300-val').text().trim();
    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        for (const info of alertInfo) {
            let desc = `Observed ${summary.split(']')[1]}\n`;
            for (const key in info.alertExtraInfo) {
                if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
                    const value = info.alertExtraInfo[key];
                    if (value !== undefined) {
                        desc += `${key}: ${value}\n`;
                    }
                }
            }
            desc += `\nPlease verify if the ip is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n'); //Can achieve automatic deduplication
        showDialog(alertMsg);
    }
    addButton('generateDescription', 'Description', generateDescription);
}

function PulseAlertHandler(...kwargs) {
    var { summary, rawLog } = kwargs[0];
    var raw_alert = 0;
    if (rawLog == '') {
        var rawLog = $('#customfield_10219-val').text().trim().split('\n');
    }
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                if (log.includes('PulseSecure')) {
                    var firstIndex = log.indexOf('PulseSecure:');
                    let time_text = '';
                    if (summary.toLowerCase().includes('suspicious geolocation ip login success')) {
                        time_text = log.toString().substr(0, firstIndex);
                    } else {
                        time_text = log.toString().substr(firstIndex + 13);
                        const first_bar = time_text.indexOf(':');
                        time_text = time_text.toString().substr(0, first_bar + 6);
                    }
                    const lastIndex = log.toString().lastIndexOf('Vendor)');
                    let alert_text = log
                        .toString()
                        .substr(lastIndex + 7)
                        .replace('[][] -', '');
                    const lastIndex_ = alert_text.toString().lastIndexOf(' - ');
                    alert_text = alert_text.substr(lastIndex_ + 2);
                    let first = log.indexOf('- ');
                    let second = log.indexOf(' - [');
                    let vpn_name = log.toString().substring(first + 2, second) + ' ';
                    const alert_content = '\n' + vpn_name + alert_text + ' On ' + time_text + '\n';
                    acc.push(alert_content);
                    raw_alert += 1;
                }
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);
    const num_alert = $('#customfield_10300-val').text().trim();
    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        let desc = `Observed ${summary.split(']')[1]}\n`;
        desc += alertInfo;
        desc += `\n\nPlease verify if the login is legitimate.\n`;
        alertDescriptions.push(desc);
        const alertMsg = [...new Set(alertDescriptions)].join('\n'); //Can achieve automatic deduplication
        showDialog(alertMsg);
    }
    addButton('generateDescription', 'Description', generateDescription);
}

function Risky_Countries_AlertHandler(...kwargs) {
    var { summary, rawLog } = kwargs[0];
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const json_alert = JSON.parse(log);
                if (json_alert.hasOwnProperty('azure')) {
                    const {
                        createdDateTime,
                        userDisplayName,
                        userPrincipalName,
                        ipAddress,
                        appDisplayName,
                        deviceDetail,
                        status
                    } = json_alert['azure'];
                    const { failureReason, additionalDetails } = status;
                    const { displayName, operatingSystem } = deviceDetail;

                    const alertExtraInfo = {
                        createdEventDateTime: createdDateTime ? createdDateTime : undefined,
                        userDisplayName: userDisplayName ? userDisplayName : undefined,
                        userPrincipalName: userPrincipalName ? userPrincipalName : undefined,
                        appDisplayName: appDisplayName ? appDisplayName : undefined,
                        ipAddress: ipAddress ? ipAddress : undefined,
                        operatingSystem: operatingSystem ? operatingSystem : undefined,
                        DeviceName: displayName ? displayName : 'N/A',
                        failureReason: failureReason ? failureReason : undefined,
                        additionalDetails: additionalDetails ? additionalDetails : undefined
                    };
                    acc.push({ alertExtraInfo });
                }
                if (json_alert.hasOwnProperty('office_365')) {
                    let alertExtraInfo;
                    if (json_alert['office_365'].hasOwnProperty('Data')) {
                        console.log(JSON.parse(json_alert['office_365']['Data']));
                        let data = JSON.parse(json_alert['office_365']['Data']);
                        alertExtraInfo = {
                            CreationEventTime: data['wsrt'] ? data['wsrt'] : undefined,
                            Username: data['f3u'] ? data['f3u'] : undefined,
                            Workload: data['wl'] ? data['wl'] : undefined,
                            Reason: data['ad'] ? data['ad'] : undefined
                        };
                    } else if (!json_alert['office_365'].hasOwnProperty('ClientIP')) {
                        let data = json_alert['office_365'];
                        alertExtraInfo = {
                            CreationEventTime: data['CreationTime'] ? data['CreationTime'] : undefined,
                            Operation: data['Operation'] ? data['Operation'] : undefined,
                            ResultStatus: data['ResultStatus'] ? data['ResultStatus'] : undefined,
                            UserId: data['UserId'] ? data['UserId'] : undefined,
                            ObjectId: data['ObjectId'] ? data['ObjectId'] : undefined,
                            UserKey: data['UserKey'] ? data['UserKey'] : undefined
                        };
                    } else {
                        const {
                            CreationTime,
                            Operation,
                            Workload,
                            ClientIP,
                            UserId,
                            ResultStatusDetail,
                            UserAgent,
                            ActorIpAddress,
                            DeviceProperties,
                            UserKey
                        } = json_alert['office_365'];

                        let devicename = '';
                        DeviceProperties.forEach((item) => {
                            if (item.Name === 'DisplayName') {
                                devicename = item.Value;
                            }
                        });
                        alertExtraInfo = {
                            CreationEventTime: CreationTime ? CreationTime : undefined,
                            Operation: Operation ? Operation : undefined,
                            Workload: Workload ? Workload : undefined,
                            UserId: UserId ? UserId : undefined,
                            ClientIP: ClientIP ? ClientIP : undefined,
                            ActorIpAddress: ActorIpAddress ? ActorIpAddress : undefined,
                            UserAgent: UserAgent ? UserAgent : undefined,
                            DeviceName: devicename ? devicename : 'N/A',
                            UserKey: UserKey ? UserKey : undefined,
                            ResultStatusDetail: ResultStatusDetail ? ResultStatusDetail : undefined
                        };
                    }

                    acc.push({ alertExtraInfo });
                }
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);
    function generateDescription() {
        const alertDescriptions = [];
        console.log(alertInfo);
        for (const info of alertInfo) {
            const lastindex = summary.lastIndexOf(']');

            let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
            for (const key in info.alertExtraInfo) {
                if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
                    const value = info.alertExtraInfo[key];
                    if (value !== undefined) {
                        if (key == 'CreationEventTime') {
                            desc += `CreationEventTime(<span class="red_highlight">GMT</span>): ${value}\n`;
                        } else {
                            desc += `${key}: ${value}\n`;
                        }
                    }
                }
            }
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    addButton('generateDescription', 'Description', generateDescription);
}

function Agent_Disconnect_AlertHandler(...kwargs) {
    var { summary, rawLog } = kwargs[0];
    const LogSource = $('#customfield_10204-val').text().trim().split('\n');
    function parseLog(LogSource) {
        const alertInfo = LogSource.reduce((acc, log) => {
            try {
                log = log.replace(/\s/g, '');
                if (log == 'Show' || log == 'Hide' || log.length == 0) {
                    console.log('ss');
                } else {
                    acc.push(log);
                    console.log(log);
                }
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    let alertInfo = [...new Set(parseLog(LogSource))];
    function generateDescription() {
        const alertDescriptions = [];

        const lastindex = summary.lastIndexOf(']');
        let desc = `Observed ${summary.substr(lastindex + 1)}, kindly please help to check it.\n`;
        desc += `\nagent name:  ${alertInfo.join(',')}`;
        alertDescriptions.push(desc);
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }
    function openMDE() {
        let KQL = '';
        KQL += `name=${alertInfo.join(' or name=')} \n`;
        showFlag('info', 'KQL:', `${KQL}`, 'manual');
    }
    addButton('generateDescription', 'Description', generateDescription);
    addButton('openKQL', 'KQL', openMDE);
}

function MdbAlertHandler(...kwargs) {
    var { summary, rawLog } = kwargs[0];
    if (rawLog.length == 0 || rawLog.length == 1) {
        rawLog = $('#customfield_10219-val').text().trim().split('\n');
    }
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                if (log.length == 0) {
                    return acc;
                }
                if (summary.toLowerCase().includes('syslog: user missed the password more than one time')) {
                    let log_ = log.split(';')[1].split(' ');
                    let time_host = log.split(' sshd')[0].split(' ');
                    let user = '';
                    if (log_.length > 7) {
                        user = log_[8].split('=')[1];
                    }
                    let description = `Observed user<span class='black_highlight'> ${user}</span> multiple ssh login failed from ${
                        log_[6].split('=')[1]
                    }\nCreateTime: ${time_host
                        .slice(0, time_host.length - 1)
                        .join(' ')}\nHostname: <span class='black_highlight'> ${
                        time_host[time_host.length - 1]
                    }</span>\n`;

                    acc.push(description);
                }
                if (summary.toLowerCase().includes('sshd: insecure connection attempt')) {
                    let log_ = log.split(' ');
                    console.log('log', log_);
                    let description = `Observed insecure connection attempt from ${
                        log_[log_.length - 3]
                    }\nCreateTime: ${log_.slice(0, log_.length - 11).join(' ')}\n`;
                    acc.push(description);
                }
                if (
                    summary
                        .toLowerCase()
                        .includes('anomaly: suspected lateral movement - linux containing session opened')
                ) {
                    let log_ = log.split('>')[1] + '\n';
                    console.log('log', log_);
                    acc.push(log_);
                }
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);
    function generateDescription() {
        const alertDescriptions = [];
        if (summary.toLowerCase().includes('anomaly: suspected lateral movement - linux containing session opened')) {
            const Log_source = $('#customfield_10204-val').text().trim();
            alertDescriptions.push(`Observed  session opened on <span class='black_highlight'>${Log_source}</span>\n`);
        }
        for (const info of alertInfo) {
            alertDescriptions.push(info);
        }
        if (summary.toLowerCase().includes('sshd: insecure connection attempt')) {
            alertDescriptions.push('Kindly help to verify if the connection is legitimate\n');
        }
        if (summary.toLowerCase().includes('syslog: user missed the password more than one time')) {
            alertDescriptions.push('Kindly help to verify if the login is legitimate\n');
        }
        if (summary.toLowerCase().includes('anomaly: suspected lateral movement - linux containing session opened')) {
            alertDescriptions.push('Kindly help to verify if the session is legitimate\n');
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    addButton('generateDescription', 'Description', generateDescription);
}

function AlicloudAlertHandler(...kwargs) {
    var { summary, rawLog } = kwargs[0];
    var raw_alert = 0;
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const BraceIndex = log.toString().indexOf('{');
                const lastBraceIndex = log.toString().lastIndexOf('}');
                if (BraceIndex !== -1) {
                    raw_alert += 1;
                    // Intercepts a substring from the beginning of the brace to the end of the string
                    json_text = log.toString().substr(BraceIndex, lastBraceIndex);
                    let time_1 = log.toString().substr(0, BraceIndex).split(' ');
                    let time = time_1.slice(time_1.length - 4, time_1.length - 2).join(' ');
                    time = time_1[0] + ' ' + time;
                    try {
                        const json_alert = JSON.parse(json_text);
                        let {
                            eventId,
                            uuid,
                            eventName,
                            resourceName,
                            sourceIpAddress,
                            userIdentity,
                            intranet_ip,
                            internet_ip,
                            instance_id,
                            extend_content,
                            detail,
                            requestParameters,
                            responseElements
                        } = json_alert['alicloud'];
                        let alertExtraInfo = {
                            createTime: time,
                            eventId: eventId ? eventId : undefined,
                            uuid: uuid ? uuid : undefined,
                            eventName: eventName ? eventName : undefined,
                            InstanceId: resourceName ? resourceName : undefined,
                            sourceIpAddress: sourceIpAddress ? sourceIpAddress : undefined,
                            userName: userIdentity?.userName ? userIdentity?.userName : undefined,
                            internet_ip: internet_ip ? internet_ip : undefined,
                            intranet_ip: intranet_ip ? intranet_ip : undefined,
                            instance_id: instance_id ? instance_id : undefined,
                            extend_content: extend_content ? extend_content : undefined,
                            responseElements: responseElements ? JSON.stringify(responseElements) : undefined
                        };
                        console.log('===', requestParameters, time);

                        if (detail != undefined) {
                            detail = JSON.parse(detail);
                            alertExtraInfo = Object.assign({}, alertExtraInfo, detail);
                        }
                        if (requestParameters != undefined) {
                            alertExtraInfo = Object.assign({}, alertExtraInfo, requestParameters);
                        }

                        console.log(alertExtraInfo);
                        acc.push({ alertExtraInfo });
                    } catch (error) {
                        console.log('Unable to parse JSON data, handling exception: ' + error);
                    }
                }
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }

    const alertInfo = parseLog(rawLog);
    function generateDescription() {
        const alertDescriptions = [];
        for (const info of alertInfo) {
            const lastindex = summary.lastIndexOf(']');
            let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
            for (const key in info.alertExtraInfo) {
                if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
                    const value = info.alertExtraInfo[key];
                    if (value !== undefined) {
                        desc += `${key}: ${value}\n`;
                    }
                }
            }
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    addButton('generateDescription', 'Description', generateDescription);
}

function DstAlertHandler(...kwargs) {
    var rawLog = $('#field-customfield_10904').text().trim().split('\n');
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const json_alert = JSON.parse(log);
                const { system, eventdata } = json_alert['win'];
                const alertExtraInfo = {
                    computer: system?.computer ? system?.computer : undefined,
                    commandLine: eventdata?.commandLine ? eventdata?.commandLine : undefined
                };
                acc.push({ alertExtraInfo });
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);
    function generateDescription() {
        const alertDescriptions = [];
        for (const info of alertInfo) {
            let desc = ``;
            for (const key in info.alertExtraInfo) {
                if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
                    const value = info.alertExtraInfo[key];
                    if (value !== undefined) {
                        desc += `${key}: ${value}\n`;
                    }
                }
            }
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    addButton('generateDescription', 'Description', generateDescription);
}

function ThreatMatrixAlertHandler(...kwargs) {
    var { summary, rawLog } = kwargs[0];
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const json_alert = JSON.parse(log);
                console.log(json_alert['threatmatrix']);
                const {
                    account_telephone,
                    account_login,
                    application_name,
                    customer_event_type,
                    input_ip_address,
                    event_datetime,
                    input_ip_city,
                    input_ip_geo,
                    input_ip_isp,
                    input_ip_organization,
                    policy,
                    tmx_risk_rating,
                    request_result
                } = json_alert['threatmatrix'];
                const alertExtraInfo = {
                    account_telephone: account_telephone ? account_telephone : undefined,
                    account_login: account_login ? account_login : undefined,
                    application_name: application_name ? application_name : undefined,
                    customer_event_type: customer_event_type ? customer_event_type : undefined,
                    input_ip_address: input_ip_address ? input_ip_address : undefined,
                    input_ip_city: input_ip_city ? input_ip_city : undefined,
                    input_ip_geo: input_ip_geo ? input_ip_geo : undefined,
                    input_ip_isp: input_ip_isp ? input_ip_isp : undefined,
                    input_ip_organization: input_ip_organization ? input_ip_organization : undefined,
                    policy: policy ? policy : undefined,
                    tmx_risk_rating: tmx_risk_rating ? tmx_risk_rating : undefined,
                    request_result: request_result ? request_result : undefined,
                    event_datetime: event_datetime ? event_datetime.split('.')[0] : undefined
                };
                acc.push({ alertExtraInfo });
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);
    function generateDescription() {
        const alertDescriptions = [];
        for (const info of alertInfo) {
            const lastindex = summary.lastIndexOf(']');
            let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
            for (const key in info.alertExtraInfo) {
                if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
                    const value = info.alertExtraInfo[key];
                    if (value !== undefined) {
                        desc += `${key}: ${value}\n`;
                    }
                }
            }
            desc += `\nPlease verify if the login is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    addButton('generateDescription', 'Description', generateDescription);
}

function DarktraceAlertHandler(...kwargs) {
    var { summary, rawLog } = kwargs[0];
    var raw_alert = 0;
    var breach_Url;
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const BraceIndex = log.toString().indexOf('{');
                const lastBraceIndex = log.toString().lastIndexOf('}');
                const logarray = log.toString().split(' ');
                if (BraceIndex !== -1) {
                    raw_alert += 1;
                    // Intercepts a substring from the beginning of the brace to the end of the string
                    json_text = log.toString().substr(BraceIndex, lastBraceIndex);
                    const json_alert = JSON.parse(json_text);
                    let alertExtraInfo = {},
                        Resource_paths = [];
                    breach_Url = json_alert['breachUrl'] + '<br>' + json_alert['incidentEventUrl'];
                    let year = ' 20' + $('#created-val').text().trim().split('/')[2].split(' ')[0]; //动态产生工单的年份
                    let time_str = logarray.slice(0, 3).join(' ') + year;
                    if (!time_str.includes(':')) {
                        time_str = logarray.slice(0, 4).join(' ').replace('  ', ' ') + year;
                    }

                    if (json_alert.hasOwnProperty('model')) {
                        const { device, triggeredComponents, model } = json_alert;
                        let User_agent = '',
                            Message;
                        alertExtraInfo = {
                            AlertTime: formatCurrentDateTime(time_str),
                            hostname: device?.hostname ? device?.hostname : undefined,
                            ip: device?.ip ? device?.ip : undefined,
                            credentials: device?.credentials ? device?.credentials : undefined,
                            subnetlabel: device?.ips ? device?.ips[0].subnetlabel : undefined,
                            typename: device?.typename ? device?.typename : undefined,
                            User_agent: User_agent ? User_agent : undefined,
                            saas_info: device?.customFields?.saasinfo
                                ? device.customFields.saasinfo.saas_info
                                : undefined,
                            Message: Message ? Message : undefined,
                            description: model?.description ? model?.description.replace(/\\\n/g, ' ') : undefined
                        };
                        triggeredComponents[0]['triggeredFilters'].forEach((item) => {
                            if (item['filterType'] == 'User agent' && item['id'] == 'O') {
                                User_agent = item['arguments']['value'];
                                console.log('value', item['arguments']['value']);
                            } else if (item['id'] == 'C') {
                                Message = item['trigger']['value'];
                            } else if (
                                item['filterType'].includes('IP') ||
                                item['filterType'] == 'Resource Location' ||
                                item['filterType'] == 'Event' ||
                                item['filterType'] == 'Connection hostname'
                            ) {
                                alertExtraInfo[item['filterType']] = item['trigger']['value'];
                            }
                        });
                    } else {
                        const { summary, breachDevices, details } = json_alert;
                        let values;
                        alertExtraInfo = {
                            AlertTime: formatCurrentDateTime(time_str),
                            hostname: breachDevices[0]?.hostname ? breachDevices[0]?.hostname : undefined,
                            host_ip: breachDevices[0]?.ip ? breachDevices[0]?.ip : undefined,
                            summary: summary ? summary : undefined
                        };
                        details.forEach((item) => {
                            if (item[0].header == 'Endpoint Details') {
                                values = item[0].contents[0].values;
                                item[0].contents.forEach((i) => {
                                    if (i.key == 'IP addresses associated with hostnames') {
                                        console.log(i);
                                        alertExtraInfo[i.type] = JSON.stringify(i.values);
                                    }
                                });
                            }
                            item.forEach((ii) => {
                                if (
                                    ii.header == 'Activity Details' ||
                                    ii.header == 'Details of Accessing Users' ||
                                    ii.header == 'Resource Access Details'
                                ) {
                                    ii.contents.forEach((i) => {
                                        if (i['key'] == 'Resource paths include' || i['key'] == 'Resource path') {
                                            i['values'].forEach((iii) => {
                                                Resource_paths.push(iii);
                                            });
                                        } else if (
                                            i['key'].includes('Source IPs') ||
                                            i['key'].includes('Actors include')
                                        ) {
                                            alertExtraInfo[i.key] = JSON.stringify(i.values);
                                        }
                                    });
                                }
                            });
                        });
                        Resource_paths = [...new Set(Resource_paths)].join('\n');
                        alertExtraInfo['Resource_paths'] = Resource_paths ? Resource_paths : undefined;
                        alertExtraInfo['Endpoint Details'] = values ? values : undefined;
                    }
                    acc.push({ alertExtraInfo });
                }
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);
    const num_alert = $('#customfield_10300-val').text().trim();
    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        for (const info of alertInfo) {
            const lastindex = summary.lastIndexOf(']');
            let ss = summary.substr(lastindex + 1).split('::');
            let desc = `Observed ${ss[ss.length - 1]}\n\n`;
            for (const key in info.alertExtraInfo) {
                if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
                    const value = info.alertExtraInfo[key];
                    if (value !== undefined) {
                        desc += `${key}: ${value}\n`;
                    }
                }
            }
            desc += `\nPlease help to verify if this activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }
    function breachUrl() {
        showFlag('info', 'breach Url:', `${breach_Url.replace('hXXps[:]', 'https:')}`, 'manual');
    }
    addButton('generateDescription', 'Description', generateDescription);
    addButton('breachUrl', 'breachUrl', breachUrl);
}

function SangforAlertHandler(...kwargs) {
    var { summary, rawLog } = kwargs[0];
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                if (log.length == 0) {
                    return acc;
                }
                const regex = /(\b\w+=)([^=\s].*?)(?=\s+\w+=|$)/g;
                let match;
                const matches = {};
                while ((match = regex.exec(log)) !== null) {
                    let item = match[0].split('=');
                    matches[item[0]] = item.slice(1, item.length).join('=');
                }
                console.log(matches);
                var pattern = /event_evidence.*?(?=suffer_classify1_id_name)/g;
                console.log(log.match(pattern));
                let logArray = log.split(' ').filter((item) => item !== ''); //Remove extra whitespace from the string
                const DecoderName = $('#customfield_10807-val').text().trim().toLowerCase();
                if (DecoderName == 'cyberark_cef') {
                    let data_json = {
                        'Event time': logArray.slice(0, 3).join(' '),
                        'event_desc': matches.event_desc ? matches.event_desc : undefined,
                        'dhost': matches.dhost ? matches.dhost : undefined,
                        'dst': matches.dst ? matches.dst : undefined,
                        'duser': matches.duser ? matches.duser : undefined,
                        'shost': matches.shost ? matches.shost : undefined,
                        'src': matches.src ? matches.src : undefined,
                        'suser': matches.suser ? matches.suser : undefined
                    };
                    data_json[matches.cs3Label] = matches.cs3 ? matches.cs3 : undefined;
                    acc.push(data_json);
                } else if (DecoderName == 'trellix_cef') {
                    let data_json = {
                        filePath: matches.filePath ? matches.filePath : undefined,
                        rt: matches.rt ? matches.rt : undefined,
                        duser: matches.duser ? matches.duser : undefined,
                        msg: matches.msg ? matches.msg : undefined,
                        act: matches.act ? matches.act : undefined,
                        suser: matches.suser ? matches.suser.replace(/[<>]/g, '') : undefined,
                        fileType: matches.fileType ? matches.fileType : undefined,
                        subject: matches.subject ? matches.subject : undefined
                    };
                    data_json[matches.cs1Label] = matches.cs1 ? matches.cs1 : undefined;
                    data_json[matches.cs4Label] = matches.cs4 ? matches.cs4 : undefined;
                    data_json[matches.flexString2Label] = matches.flexString2 ? matches.flexString2 : undefined;
                    acc.push(data_json);
                } else if (DecoderName == 'impervainc_cef') {
                    console.log('===', matches);
                    console.log('===start ', formatCurrentDateTime(parseInt(matches.start), 'impervainc_cef'));
                    let data_json = {
                        start_time: matches.start
                            ? formatCurrentDateTime(parseInt(matches.start), 'impervainc_cef')
                            : undefined,
                        end_time: matches.end
                            ? formatCurrentDateTime(parseInt(matches.end), 'impervainc_cef')
                            : undefined,
                        dhost: matches.dhost ? matches.dhost : undefined,
                        AlertTime: matches.rt ? matches.rt : undefined,
                        src: matches.src ? matches.src : undefined,
                        sptPort: matches.spt ? matches.spt : undefined,
                        dstIP: matches.dst ? matches.dst : undefined,
                        dstPort: matches.dpt ? matches.dpt : undefined,
                        protocol: matches.proto ? matches.proto : undefined,
                        request: matches.request ? matches.request : undefined,
                        requestClientApplication: matches.requestClientApplication
                            ? matches.requestClientApplication
                            : undefined,
                        msg: matches.msg ? matches.msg : undefined
                    };
                    data_json[matches.cs1Label] = matches.cs1 ? matches.cs1 : undefined;
                    data_json[matches.cs2Label] = matches.cs2 ? matches.cs2 : undefined;
                    data_json[matches.cs3Label] = matches.cs3 ? matches.cs3 : undefined;
                    data_json[matches.cs4Label] = matches.cs4 ? matches.cs4 : undefined;
                    data_json[matches.cs5Label] = matches.cs5 ? matches.cs5 : undefined;
                    data_json[matches.cs6Label] = matches.cs6 ? matches.cs6 : undefined;
                    data_json[matches.cs7Label] = matches.cs7 ? matches.cs7 : undefined;
                    data_json[matches.cs8Label] = matches.cs8 ? matches.cs8 : undefined;
                    data_json[matches.cs9Label] = matches.cs9 ? matches.cs9 : undefined;

                    acc.push(data_json);
                } else if (DecoderName == 'checkpoint_cef') {
                    let data_json = {
                        Signature: matches.Signature ? matches.Signature : undefined,
                        cp_severity: matches.cp_severity ? matches.cp_severity : undefined,
                        src: matches.src ? matches.src : undefined,
                        dst: matches.dst ? matches.dst : undefined,
                        origin: matches.origin ? matches.origin : undefined
                    };
                    data_json[matches.cs2Label] = matches.cs2 ? matches.cs2 : undefined;
                    data_json[matches.cs3Label] = matches.cs3 ? matches.cs3 : undefined;
                    data_json[matches.cs4Label] = matches.cs4 ? matches.cs4 : undefined;
                    data_json[matches.flexNumber1Label] = matches.flexNumber1 ? matches.flexNumber1 : undefined;
                    data_json[matches.flexNumber2Label] = matches.flexNumber2 ? matches.flexNumber2 : undefined;
                    data_json[matches.flexString2Label] = matches.flexString2 ? matches.flexString2 : undefined;
                    acc.push(data_json);
                } else if (DecoderName == 'incapsula_cef') {
                    let data_json = {
                        requestClientApplication: matches.requestClientApplication
                            ? matches.requestClientApplication
                            : undefined,
                        request: matches.request ? matches.request : undefined,
                        requestMethod: matches.requestMethod ? matches.requestMethod : undefined,
                        postbody: matches.postbody ? matches.postbody : undefined,
                        qstr: matches.qstr ? matches.qstr : undefined,
                        act: matches.act ? matches.act : undefined,
                        sip: matches.sip ? matches.sip : undefined,
                        spt: matches.spt ? matches.spt : undefined,
                        xff: matches.xff ? matches.xff : undefined,
                        cpt: matches.cpt ? matches.cpt : undefined,
                        src: matches.src ? matches.src : undefined
                    };
                    data_json[matches.cs9Label] = matches.cs9 ? matches.cs9 : undefined;
                    acc.push(data_json);
                } else if (window.location.href.includes('macaumss')) {
                    acc.push({
                        'Event time': logArray.slice(0, 3).join(' '),
                        'event_desc': matches.event_desc ? matches.event_desc : undefined,
                        'dev_name': matches.dev_name ? matches.dev_name : undefined,
                        'attack_ip': matches.attack_ip ? matches.attack_ip : undefined,
                        'suffer_ip': matches.suffer_ip ? matches.suffer_ip : undefined,
                        'suffer_port': matches.suffer_port ? matches.suffer_port : undefined,
                        'status_code': matches.status_code ? matches.status_code : undefined,
                        'x_forwarded_for': matches.x_forwarded_for ? matches.x_forwarded_for : undefined,
                        'event_evidence': log.match(pattern) ? log.match(pattern)[0] : undefined,
                        'attack_type_name': matches.attack_type_name ? matches.attack_type_name : undefined
                    });
                } else {
                    acc.push({
                        'Event time': logArray.slice(0, 3).join(' '),
                        'event_desc': matches.event_desc ? matches.event_desc : undefined,
                        'dev_name': matches.dev_name ? matches.dev_name : undefined,
                        'suffer_ip': matches.suffer_ip ? matches.suffer_ip : undefined,
                        'attack_ip': matches.attack_ip ? matches.attack_ip : undefined,
                        'event_evidence': matches.event_evidence ? matches.event_evidence : undefined,
                        'url': matches.url ? matches.url : undefined,
                        'suggest': matches.suggest ? matches.suggest : undefined
                    });
                }
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);
    function generateDescription() {
        const alertDescriptions = [];
        for (const info of alertInfo) {
            const lastindex = summary.lastIndexOf(']');
            let desc;
            if (summary.includes('-')) {
                desc = `Observed ${summary.substr(lastindex + 1).split('-')[1]}\n`;
            } else {
                desc = `Observed ${summary.substr(lastindex + 1)}\n`;
            }
            for (const key in info) {
                if (Object.hasOwnProperty.call(info, key)) {
                    const value = info[key];
                    if (value !== undefined) {
                        if (key == 'event_evidence') {
                            desc += `${key}: ${value.replace(/</g, '&lt;').replace(/>/g, '&gt;')}\n`;
                        } else if (key == 'start_time' || key == 'end_time' || key == 'AlertTime') {
                            desc += `${key}(<span class="red_highlight">GMT+8</span>): ${value.split('.')[0]}\n`;
                        } else {
                            desc += `${key}: ${value}\n`;
                        }
                    }
                }
            }
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }
    addButton('generateDescription', 'Description', generateDescription);
}

function RadwareAlertHandler(...kwargs) {
    var { summary, rawLog } = kwargs[0];
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const json_alert = JSON.parse(log);
                const {
                    device_ip,
                    device_name,
                    device_abbr,
                    detected_by,
                    asset_name,
                    asset_type,
                    asset_ip,
                    account_uid,
                    account_name,
                    acc_site_name,
                    end_time,
                    start_time
                } = json_alert['radware'];

                alertExtraInfo = {
                    start_time: start_time._date_time ? start_time._date_time : undefined,
                    end_time: end_time._date_time ? end_time._date_time : undefined,
                    device_ip: device_ip ? device_ip : undefined,
                    device_name: device_name ? device_name : undefined,
                    device_abbr: device_abbr ? device_abbr : undefined,
                    detected_by: detected_by ? detected_by : undefined,
                    asset_name: asset_name ? asset_name : undefined,
                    asset_type: asset_type ? asset_type : undefined,
                    asset_ip: asset_ip ? asset_ip : undefined,
                    account_uid: account_uid ? account_uid : undefined,
                    account_name: account_name ? account_name : undefined,
                    acc_site_name: acc_site_name ? acc_site_name : undefined
                };
                acc.push({ alertExtraInfo });
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);
    function generateDescription() {
        const alertDescriptions = [];
        for (const info of alertInfo) {
            const lastindex = summary.lastIndexOf(']');
            let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
            for (const key in info.alertExtraInfo) {
                if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
                    const value = info.alertExtraInfo[key];
                    if (value !== undefined) {
                        if (key == 'start_time' || key == 'end_time') {
                            desc += `${key}(<span class="red_highlight">GMT</span>): ${value.split('.')[0] + 'Z'}\n`;
                        } else {
                            desc += `${key}: ${value}\n`;
                        }
                    }
                }
            }
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }
    addButton('generateDescription', 'Description', generateDescription);
}

function CarbonAlertHandler(...kwargs) {
    var { summary, rawLog } = kwargs[0];
    var raw_alert = 0;
    const num_alert = $('#customfield_10300-val').text().trim();
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const BraceIndex = log.toString().indexOf('{');
                const lastBraceIndex = log.toString().lastIndexOf('}');
                if (BraceIndex !== -1) {
                    json_text = log.toString().substr(BraceIndex, lastBraceIndex);
                    const json_alert = JSON.parse(json_text);
                    const {
                        reason,
                        device_os_version,
                        device_username,
                        device_location,
                        device_external_ip,
                        device_internal_ip,
                        device_name,
                        process_pid,
                        process_name,
                        process_sha256,
                        process_guid,
                        process_cmdline,
                        process_username,
                        netconn_remote_ip,
                        netconn_remote_port,
                        parent_guid,
                        parent_pid,
                        parent_name,
                        parent_sha256,
                        parent_username,
                        netconn_local_ip,
                        netconn_local_port,
                        first_event_timestamp
                    } = json_alert;
                    alertExtraInfo = {
                        EventTime: first_event_timestamp.split('.')[0],
                        device_name: device_name ? device_name : undefined,
                        device_os_version: device_os_version ? device_os_version : undefined,
                        device_username: device_username ? device_username : undefined,
                        device_location: device_location ? device_location : undefined,
                        device_external_ip: device_external_ip ? device_external_ip : undefined,
                        device_internal_ip: device_internal_ip ? device_internal_ip : undefined,
                        process_guid: process_guid ? process_guid : undefined,
                        process_pid: process_pid ? process_pid : undefined,
                        process_name: process_name ? process_name : undefined,
                        process_sha256: process_sha256 ? process_sha256 : undefined,
                        process_cmdline: process_cmdline ? process_cmdline : undefined,
                        process_username: process_username ? process_username : undefined,
                        parent_guid: parent_guid ? parent_guid : undefined,
                        parent_pid: parent_pid ? parent_pid : undefined,
                        parent_name: parent_name ? parent_name : undefined,
                        parent_sha256: parent_sha256 ? parent_sha256 : undefined,
                        parent_username: parent_username ? parent_username : undefined,
                        netconn_remote_ip: netconn_remote_ip ? netconn_remote_ip : undefined,
                        netconn_remote_port: netconn_remote_port ? netconn_remote_port : undefined,
                        netconn_local_ip: netconn_local_ip ? netconn_local_ip : undefined,
                        netconn_local_port: netconn_local_port ? netconn_local_port : undefined,
                        reason: reason ? reason : undefined
                    };
                    raw_alert += 1;
                    acc.push({ alertExtraInfo });
                }
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);
    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        for (const info of alertInfo) {
            const lastindex = summary.lastIndexOf(']');
            let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
            for (const key in info.alertExtraInfo) {
                if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
                    const value = info.alertExtraInfo[key];
                    if (key == 'EventTime') {
                        desc += `EventTime(<span class="red_highlight">GMT</span>): ${value + 'Z'}\n`;
                    } else if (value !== undefined) {
                        desc += `${key}: ${value}\n`;
                    }
                }
            }
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }

    addButton('generateDescription', 'Description', generateDescription);
}

function MultipleAccountAlertHandler(...kwargs) {
    var { summary, rawLog } = kwargs[0];
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const json_alert = JSON.parse(log)['win'];
                const { targetUserName, targetDomainName, subjectUserName, subjectDomainName, subjectLogonId } =
                    json_alert['eventdata'];
                const { systemTime, computer, message } = json_alert['system'];
                alertExtraInfo = {
                    Eventtime: systemTime ? systemTime : undefined,
                    computer: computer ? computer : undefined,
                    targetUserName: targetUserName ? targetUserName : undefined,
                    targetDomainName: targetDomainName ? targetDomainName : undefined,
                    subjectUserName: subjectUserName ? subjectUserName : undefined,
                    subjectDomainName: subjectDomainName ? subjectDomainName : undefined,
                    message: message ? message.split('\r\n\r\n')[0] : undefined
                };
                acc.push({ alertExtraInfo });
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);
    function generateDescription() {
        const alertDescriptions = [];
        const single = [];
        const lastindex = summary.lastIndexOf(']');
        let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
        for (const info of alertInfo) {
            let desc_ = '',
                single_ = '';
            for (const key in info.alertExtraInfo) {
                if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
                    const value = info.alertExtraInfo[key];
                    if (value !== undefined) {
                        if (key == 'Eventtime') {
                            desc_ += `${key}(<span class="red_highlight">GMT</span>): ${value.split('.')[0] + 'Z'}\n`;
                        } else if (
                            key == 'subjectUserName' ||
                            key == 'subjectDomainName' ||
                            key == 'computer' ||
                            key == 'message' ||
                            key == 'targetDomainName'
                        ) {
                            single_ += `${key}: ${value}\n`;
                        } else {
                            desc_ += `${key}: ${value}\n`;
                        }
                    }
                }
            }
            alertDescriptions.push(desc_);
            single.push(single_);
        }
        desc += [...new Set(single)].join('\n');
        desc += '\n';
        desc += [...new Set(alertDescriptions)].join('\n');
        desc += `Please verify if the activity is legitimate.\n`;
        showDialog(desc);
    }
    addButton('generateDescription', 'Description', generateDescription);
}

/**
 * Create Description and Open MDE and MDE365 button
 * @param  {...any} kwargs - Include LogSourceDomain, Labels, LogSource, TicketAutoEscalate, Status, RawLog, Summary fields
 */
function MDE365AlertHandler(...kwargs) {
    console.log('#### Code MDE365lertHandler run ####');
    const { rawLog, LogSourceDomain, summary } = kwargs[0];
    var raw_alert = 0;
    const num_alert = $('#customfield_10300-val').text().trim();
    let alertInfo_MDE = [],
        alertInfo_365 = [];
    function GMT8(params) {
        let date = new Date(params);
        date.setHours(date.getHours() + 16); // 获取当前的小时数并加上8小时
        const year = date.getUTCFullYear();
        const month = String(date.getUTCMonth() + 1).padStart(2, '0');
        const day = String(date.getUTCDate()).padStart(2, '0');
        const hours = String(date.getUTCHours()).padStart(2, '0');
        const minutes = String(date.getUTCMinutes()).padStart(2, '0');
        const seconds = String(date.getUTCSeconds()).padStart(2, '0');

        const formattedDate = `${year}-${month}-${day}T${hours}:${minutes}:${seconds}`;
        return formattedDate;
    }
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            let logObj = '';
            if (log != '') {
                try {
                    if (log.charAt(log.length - 1) == '}') {
                        const formatJson = log.substring(log.indexOf('{')).trim();
                        logObj = JSON.parse(formatJson.replace(/\\\(n/g, '\\n('));
                    } else {
                        const formatJson = log.substring(log.indexOf('{')).trim() + '"}]}}';
                        logObj = JSON.parse(formatJson.replace(/\\\(n/g, '\\n('));
                    }
                    if (logObj['integration'] == 'Wazuh-MDE') {
                        raw_alert += 1;
                        const { mde } = logObj;
                        const { title, id, computerDnsName, relatedUser, evidence, alertCreationTime } = mde;
                        let dotIndex = alertCreationTime.lastIndexOf('.');

                        let dateTimeStr = GMT8(alertCreationTime.slice(0, dotIndex));
                        const alert = { title, id, computerDnsName, dateTimeStr };
                        const userName = relatedUser ? relatedUser.userName : 'N/A';
                        let extrainfo = '';
                        let processCommandLine = '';
                        if (evidence) {
                            const tmp = [];
                            for (const evidenceItem of evidence) {
                                let description = '';

                                if (evidenceItem.entityType === 'File') {
                                    console.log('===', WhiteFilehash(evidenceItem.sha1));
                                    if (WhiteFilehash(evidenceItem.sha1) || WhiteFilehash(evidenceItem.sha256)) {
                                        description = `filename: ${evidenceItem.fileName}\nfilePath: ${evidenceItem.filePath}`;
                                        tmp.push(description);
                                    } else {
                                        description = `filename: ${evidenceItem.fileName}\nfilePath: ${evidenceItem.filePath}\nsha1: ${evidenceItem.sha1}`;
                                        tmp.push(description);
                                    }
                                }
                                if (evidenceItem.entityType === 'Process') {
                                    if (evidenceItem.processCommandLine !== undefined) {
                                        processCommandLine = evidenceItem.processCommandLine.replace(
                                            /\r\n\r\n+/g,
                                            '\n'
                                        );
                                        console.log(processCommandLine);
                                    }
                                    if (
                                        evidenceItem.processCommandLine !== undefined &&
                                        evidenceItem.processCommandLine.includes('EncodedCommand')
                                    ) {
                                        let cmd_length = evidenceItem.processCommandLine.split(' ').length;
                                        description = `Decode_Cmd: ${atob(
                                            evidenceItem.processCommandLine
                                                .split(' ')
                                                [cmd_length - 1].replace(/['"]/g, '')
                                        )}`;
                                        tmp.push(description);
                                    }
                                    if (WhiteFilehash(evidenceItem.sha1) || WhiteFilehash(evidenceItem.sha256)) {
                                        description = `cmd: ${processCommandLine}\naccount: ${evidenceItem.accountName}`;
                                        tmp.push(description);
                                    } else {
                                        description = `cmd: ${processCommandLine}\naccount: ${evidenceItem.accountName}\nsha1: ${evidenceItem.sha1}`;
                                        tmp.push(description);
                                    }
                                }
                                if (evidenceItem.entityType === 'Url') {
                                    description += `Url: ${evidenceItem.url}`;
                                    tmp.push(description);
                                }
                                if (evidenceItem.entityType === 'Ip') {
                                    description += `IP: ${evidenceItem.ipAddress}`;
                                    tmp.push(description);
                                }
                            }
                            const uniqueDescriptions = Array.from(new Set(tmp));
                            extrainfo = uniqueDescriptions.join('\n');
                        }
                        alertInfo_MDE.push({ ...alert, userName, extrainfo });
                    } else {
                        raw_alert += 1;
                        const alerts = logObj['incidents']['alerts'][0];
                        console.log(alerts);
                        let entities = {};
                        if (alerts !== undefined) {
                            alerts['entities'].forEach(function (entity) {
                                if (entity.processCommandLine !== undefined) {
                                    processCommandLine = entity.processCommandLine.replace(/\r\n\r\n+/g, '\n');
                                    console.log(processCommandLine);
                                }
                                if (entity['entityType'] == 'User' || entity['entityType'] == 'Mailbox') {
                                    entities['user'] = `${entity['domainName']}\\\\${entity['accountName']}`;
                                    entities['userPrincipalName'] = entity['userPrincipalName'];
                                }
                                if (entity['entityType'] == 'CloudApplication') {
                                    entities['applicationId'] = entity['applicationId'];
                                    entities['applicationName'] = entity['applicationName'];
                                }
                                if (entity['entityType'] == 'Process') {
                                    if (!entities['process']) {
                                        entities['process'] = [];
                                    }
                                    const fileEntry = {
                                        filename: entity['fileName'],
                                        filePath: entity['filePath'],
                                        cmd: processCommandLine
                                    };
                                    if (processCommandLine.includes('EncodedCommand')) {
                                        let cmd_length = processCommandLine.split(' ').length;
                                        fileEntry['Decode_Cmd'] = atob(
                                            processCommandLine.split(' ')[cmd_length - 1].replace(/['"]/g, '')
                                        );
                                    }
                                    if (
                                        Object.keys(entity).includes('sha256') &&
                                        (WhiteFilehash(entity['sha256']) || WhiteFilehash(entity['sha1']))
                                    ) {
                                        entities['process'].push(fileEntry);
                                    } else {
                                        fileEntry['sha256'] = entity['sha256'];
                                        entities['process'].push(fileEntry);
                                    }
                                }

                                if (entity['entityType'] == 'File') {
                                    if (!entities['file']) {
                                        entities['file'] = [];
                                    }
                                    const fileEntry = {
                                        filename: entity['fileName'],
                                        filePath: entity['filePath']
                                    };
                                    if (
                                        Object.keys(entity).includes('sha256') &&
                                        (WhiteFilehash(entity['sha256']) || WhiteFilehash(entity['sha1']))
                                    ) {
                                        entities['file'].push(fileEntry);
                                    } else {
                                        fileEntry['sha256'] = entity['sha256'];
                                        entities['file'].push(fileEntry);
                                    }
                                }

                                if (entity['entityType'] == 'Ip') {
                                    if (!entities['ip']) {
                                        entities['ip'] = [];
                                    }
                                    entities['ip'].push({
                                        ip: entity['ipAddress']
                                    });
                                }
                                if (entity['entityType'] == 'Url') {
                                    if (!entities['url']) {
                                        entities['url'] = [];
                                    }
                                    entities['url'].push({
                                        url: entity['url']
                                    });
                                }
                            });
                        }
                        let creationTime = GMT8(alerts.creationTime.split('.')[0]);
                        let title = alerts?.title;
                        if (summary.toLowerCase().includes(title.toLowerCase())) {
                            title = undefined;
                        }
                        alertInfo_365.push({
                            creationTime: creationTime,
                            Title: title,
                            summary: logObj['incidents'].incidentName,
                            host: alerts?.devices[0]?.deviceDnsName,
                            user: entities.user,
                            userPrincipalName: entities.userPrincipalName,
                            process: entities.process,
                            file: entities.file,
                            ip: entities.ip,
                            url: entities.url,
                            alertid: alerts?.alertId,
                            incidenturi: logObj['incidents'].incidentUri,
                            severity: logObj['incidents'].severity,
                            description: alerts['description'],
                            applicationId: entities.applicationId,
                            applicationName: entities.applicationName
                        });
                    }
                } catch (error) {
                    console.error(`Error: ${error.message}`);
                }
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertDescriptions = [];
    parseLog(rawLog);

    function generateDescription_MDE() {
        for (const info of alertInfo_MDE) {
            const { title, computerDnsName, userName, extrainfo, dateTimeStr } = info;
            const desc = `Observed ${title}\nalertCreationTime(<span class="red_highlight">GMT+8</span>): ${dateTimeStr}\nHost: ${computerDnsName}\nusername: ${userName}\n${extrainfo}\n\nPlease help to verify if it is legitimate.\n`;
            alertDescriptions.push(desc);
        }
    }
    function generateDescription_365() {
        if (summary.includes('M365 Defender High Severity Alerts: Logon from a risky country involving one user')) {
            const ticketnumber = $('#key-val').text();
            for (const info of alertInfo) {
                let desc = `Dear Customer,
	 
	            Reasons for escalating:
	             
	            Observed Logon from a risky country involving one user in [time]
	             
	            Here is information about this login:
	
	            creationTime(<span class="red_highlight"">GMT</span>): ${info.creationTime}
	             
	            source IP: ${info.ip[0].ip}
	             
	            user: ${info.user}
	             
	            active: Microsoft 365
	             
	            userPrincipalName: ${info.userPrincipalName}
	             
	            Device type:
	             
	            UserAgent:
	             
	            location:
	             
	            logging status:
	             
	            LoginStatus:
	             
	            MfaRequired:
	             
	            the user suddenly logged in from [Location1] but the user used to be logged in from [Location2], aberdeen. Please confirm whether the login behavior of the user is normal.if not, could block the ip.
	             
	             
	            Suggestion: We suggest to confirm whether the behavior of this customer logging in at ${info.ip[0].ip}: is normal or not, if not, we suggest to block the IP and change the user's password and perform a full scan on the user's commonly used PCs, thank you!
	             
	            Severity: ${info.severity}
	             
	            Correlation ticket: ${ticketnumber}
	            
	            `;
                alertDescriptions.push(desc);
            }
        } else {
            for (const info of alertInfo_365) {
                let desc = `Observed ${info.summary}\n`;
                try {
                    for (let key in info) {
                        if (info.hasOwnProperty(key)) {
                            if (Array.isArray(info[key])) {
                                info[key].forEach((item) => {
                                    for (let subKey in item) {
                                        if (item.hasOwnProperty(subKey) && item[subKey] !== '') {
                                            desc += `${subKey}: ${item[subKey]}\n`;
                                        }
                                    }
                                });
                            } else {
                                if (
                                    info[key] !== undefined &&
                                    info[key] !== ' ' &&
                                    key !== 'summary' &&
                                    key !== 'alertid' &&
                                    key !== 'incidenturi' &&
                                    key !== 'severity'
                                ) {
                                    if (key == 'creationTime') {
                                        desc += `creationTime(<span class="red_highlight">GMT+8</span>): ${info[key]}\n`;
                                    } else {
                                        desc += `${key}: ${info[key]}\n`;
                                    }
                                }
                            }
                        }
                    }
                } catch (error) {
                    console.error(`Error: ${error}`);
                }
                let MDEURL = '';
                if (LogSourceDomain == 'wkcda') {
                    if (info.alertid && !MDEURL.includes(info.alertid)) {
                        MDEURL += `https://security.microsoft.com/alerts/${info.alertid}<br>`;
                    }
                    if (info.incidenturi) {
                        let incident_url = info.incidenturi.replace('hXXps[:]', 'https:') + '<br>';
                        MDEURL += incident_url;
                    }
                    desc += `MDE URL: \n${MDEURL}\n`;
                }

                desc += `\nPlease verify if the activity is legitimate.\n`;
                alertDescriptions.push(desc);
            }
        }
    }
    function generateDescription() {
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        generateDescription_MDE();
        generateDescription_365();
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }
    function openMDE() {
        let MDEURL = '';
        for (const info of alertInfo_MDE) {
            const { id } = info;
            if (id) {
                MDEURL += `https://security.microsoft.com/alerts/${id}<br>`;
            }
        }
        for (const info of alertInfo_365) {
            const { alertid, incidenturi } = info;
            if (alertid && !MDEURL.includes(alertid)) {
                MDEURL += `https://security.microsoft.com/alerts/${alertid}<br>`;
            }
            if (incidenturi) {
                let incident_url = incidenturi.replace('hXXps[:]', 'https:') + '<br>';
                MDEURL += incident_url;
            }
        }
        showFlag('info', 'MDE URL:', `${MDEURL}`, 'manual');
        let url = 'https://security.microsoft.com/homepage?&current=';
        url += LogSourceDomain;
        for (let i = 0; i < MDEURL.length; i++) {
            let mde_url = `&url${i}=${MDEURL[i]}`;
            url += mde_url;
            console.log(MDEURL[i]);
        }
        let MDE_Assist_ = localStorage.getItem('MDE_Assist');
        if (MDE_Assist_ != 0) {
            GM_openInTab(url, {
                active: false, // 设置为 false,以在后台打开,不激活新标签页
                insert: true // 设置为 true,将新标签页插入到当前标签页之后
            });
        }
    }
    addButton('generateDescription', 'Description', generateDescription);
    addButton('openMDE', 'MDE', openMDE);
}

function WindowsSysAlertHandler(...kwargs) {
    var { summary, rawLog } = kwargs[0];
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                if (log != '') {
                    let log_data = {},
                        sub = '';
                    log.split('#010').forEach((element, index) => {
                        if (element.includes('#013')) {
                            element = element.replace(/#013/g, '');
                        }
                        if (element.includes('#009')) {
                            let e = element.replace(/#009/g, '').split(':');
                            log_data[e[0]] = e[1];
                        }
                        if (element.includes('=')) {
                            let e = element.replace(/#013/g, '').split('=');
                            log_data[e[0]] = e[1];
                        }
                        if (element.includes(':#013')) {
                            sub = element.split(':')[0];
                        }
                        if (
                            element.includes(':#009') &&
                            (element.includes('Account') ||
                                element.includes('Security ID') ||
                                element.includes('Logon ID'))
                        ) {
                            let e = element.replace(/#009/g, ' ').replace(/#013/g, '').split(': ');
                            log_data[sub + e[0].trim()] = e[1];
                        }
                        if (element.includes(':#009')) {
                            let e = element.replace(/#009/g, ' ').replace(/#013/g, '').split(': ');
                            log_data[e[0].trim()] = e[1];
                        }
                    });
                    const regex = /(\S+\s+\S+\s+\S+\s+\S+\s+)(.*)/g;
                    alertExtraInfo = {
                        Event_time: regex.exec(log.split('#010')[0])[2],
                        ComputerName: log_data.ComputerName ? log_data.ComputerName : undefined,
                        EventCode: log_data.EventCode ? log_data.EventCode : undefined,
                        SourceName: log_data.SourceName ? log_data.SourceName : undefined,
                        CreatorAccountDomain: log_data['Creator SubjectAccount Domain']
                            ? log_data['Creator SubjectAccount Domain']
                            : undefined,
                        CreatorAccountName: log_data['Creator SubjectAccount Name']
                            ? log_data['Creator SubjectAccount Name']
                            : undefined,
                        Type: log_data.Type ? log_data.Type : undefined,
                        Keywords: log_data.Keywords ? log_data.Keywords : undefined,
                        Message: log_data.Message ? log_data.Message : undefined,
                        CreatorProcessID: log_data['Creator Process ID'] ? log_data['Creator Process ID'] : undefined,
                        CreatorProcessName: log_data['Creator Process Name']
                            ? log_data['Creator Process Name']
                            : undefined,
                        NewProcessID: log_data['New Process ID'] ? log_data['New Process ID'] : undefined,
                        NewProcessName: log_data['New Process Name'] ? log_data['New Process Name'] : undefined,
                        ProcessCommandLine: log_data['Process Command Line']
                            ? log_data['Process Command Line']
                            : undefined,
                        ProcessCommandLine: log_data['Process Command Line']
                            ? log_data['Process Command Line']
                            : undefined,
                        SecurityID: log_data['Security ID'] ? log_data['Security ID'] : undefined,
                        ServiceAccount: log_data['Service Account'] ? log_data['Service Account'] : undefined,
                        ServiceFileName: log_data['Service File Name'] ? log_data['Service File Name'] : undefined,
                        ServiceName: log_data['Service Name'] ? log_data['Service Name'] : undefined,
                        ServiceStartType: log_data['Service Start Type'] ? log_data['Service Start Type'] : undefined,
                        ServiceType: log_data['Service Type'] ? log_data['Service Type'] : undefined
                    };
                    acc.push({ alertExtraInfo });
                }
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);
    function generateDescription() {
        const alertDescriptions = [];
        for (const info of alertInfo) {
            const lastindex = summary.lastIndexOf(']');
            let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
            for (const key in info.alertExtraInfo) {
                if (Object.hasOwnProperty.call(info.alertExtraInfo, key)) {
                    const value = info.alertExtraInfo[key];
                    if (value !== undefined) {
                        if (key == 'start_time' || key == 'end_time') {
                            desc += `${key}(<span class="red_highlight">GMT</span>): ${value.split('.')[0] + 'Z'}\n`;
                        } else {
                            desc += `${key}: ${value}\n`;
                        }
                    }
                }
            }
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }
    addButton('generateDescription', 'Description', generateDescription);
}

function ClarotyAlertHandler(...kwargs) {
    var { summary, rawLog } = kwargs[0];
    var raw_alert = 0;
    const num_alert = $('#customfield_10300-val').text().trim();
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                if (log.length == 0) {
                    return acc;
                }
                const regex = /(\b\w+=)([^=\s].*?)(?=\s+\w+=|$)/g;
                let match;
                const matches = {};
                while ((match = regex.exec(log)) !== null) {
                    let item = match[0].split('=');
                    matches[item[0]] = item.slice(1, item.length).join('=');
                }
                raw_alert += 1;
                console.log(matches);
                let logArray = log.split(' ').filter((item) => item !== ''); //Remove extra whitespace from the string
                acc.push({
                    'Event time': logArray.slice(0, 3).join(' '),
                    'Extra information': logArray.slice(3, 8).join(' '),
                    'CtdSourceIp': matches.CtdSourceIp ? matches.CtdSourceIp : undefined,
                    'CtdDestinationIp': matches.CtdDestinationIp ? matches.CtdDestinationIp : undefined,
                    'CtdMessage': matches.CtdMessage ? matches.CtdMessage : undefined,
                    'CtdCategory': matches.CtdCategory ? matches.CtdCategory : undefined,
                    'CtdSourceZone': matches.CtdSourceZone ? matches.CtdSourceZone : undefined,
                    'CtdDestinationZone': matches.CtdDestinationZone ? matches.CtdDestinationZone : undefined,
                    'CtdAlertLink': matches.CtdAlertLink ? matches.CtdAlertLink : undefined
                });
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);
    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        for (const info of alertInfo) {
            const lastindex = summary.lastIndexOf(']');
            let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
            for (const key in info) {
                if (Object.hasOwnProperty.call(info, key)) {
                    const value = info[key];
                    if (value !== undefined) {
                        desc += `${key}: ${value}\n`;
                    }
                }
            }
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }
    addButton('generateDescription', 'Description', generateDescription);
}

function FireeyeAlertHandler(...kwargs) {
    var { summary, rawLog } = kwargs[0];
    var raw_alert = 0;
    const num_alert = $('#customfield_10300-val').text().trim();
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                if (log.length == 0) {
                    return acc;
                }
                const regex = /(\b\w+=)([^=\s].*?)(?=\s+\w+=|$)/g;
                let match;
                const matches = {};
                while ((match = regex.exec(log)) !== null) {
                    let item = match[0].split('=');
                    matches[item[0]] = item.slice(1, item.length).join('=');
                }
                raw_alert += 1;
                let logArray = log.split(' ').filter((item) => item !== ''); //Remove extra whitespace from the string
                acc.push({
                    'Event time': logArray.slice(0, 3).join(' '),
                    'Vlan': matches.cn1 ? matches.cn1 : undefined,
                    'Sid': matches.cn2 ? matches.cn2 : undefined,
                    'CncHost': matches.cs5 ? matches.cs5 : undefined,
                    'CncPort': matches.cn3 ? matches.cn3 : undefined,
                    'Sname': matches.cs1 ? matches.cs1 : undefined,
                    'anomaly': matches.cs2 ? matches.cs2 : undefined,
                    'Link': matches.cs4 ? matches.cs4 : undefined,
                    'Channel': matches.cs6 ? matches.cs6 : undefined,
                    'request': matches.request ? matches.request : undefined,
                    'requestClientApplication': matches.requestClientApplication
                        ? matches.requestClientApplication
                        : undefined,
                    'requestMethod': matches.requestMethod ? matches.requestMethod : undefined,
                    'dst': matches.dst ? matches.dst : undefined,
                    'dpt': matches.dpt ? matches.dpt : undefined,
                    'src': matches.src ? matches.src : undefined,
                    'spt': matches.spt ? matches.spt : undefined,
                    'dvchost': matches.dvchost ? matches.dvchost : undefined,
                    'dvc': matches.dvc ? matches.dvc : undefined
                });
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);
    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        for (const info of alertInfo) {
            const lastindex = summary.lastIndexOf(']');
            let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
            for (const key in info) {
                if (Object.hasOwnProperty.call(info, key)) {
                    const value = info[key];
                    if (value !== undefined) {
                        desc += `${key}: ${value}\n`;
                    }
                }
            }
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }
    addButton('generateDescription', 'Description', generateDescription);
}

function WebAccesslogAlertHandler(...kwargs) {
    var { summary, rawLog } = kwargs[0];
    var raw_alert = 0;
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                if (log.length == 0) {
                    return acc;
                }
                const regex = /(\b\w+=)"([^"]*?)"/g;
                const regex_ = /"(.*?)"/g;
                let match;
                const matches = {};
                while ((match = regex.exec(log)) !== null) {
                    let item = match[0].split('=');
                    matches[item[0]] = item.slice(1, item.length).join('=');
                }
                let match_;
                const matches_ = [];
                while ((match_ = regex_.exec(log)) !== null) {
                    matches_.push(match_[0]);
                }
                console.log(matches);
                console.log(matches_);
                let logArray = log.split(' ').filter((item) => item !== ''); //Remove extra whitespace from the string
                console.log(logArray);
                acc.push({
                    'Event time': logArray.slice(3, 5).join(' '),
                    'Source_IP': logArray[0] ? logArray[0] : undefined,
                    // 'request_uri': matches.request_uri ? matches.request_uri : undefined,
                    'URL': matches_[0] ? matches_[0] : undefined,
                    'User-Agent': matches_[2] ? matches_[2] : undefined,
                    'upstream_status': logArray[8] ? logArray[8] : undefined,
                    'upstream_addr': matches.upstream_addr ? matches.upstream_addr : undefined,
                    'sn': matches.sn ? matches.sn : undefined,
                    'http_referrer': matches.http_referrer ? matches.http_referrer : undefined,
                    'http_cookie': matches.http_cookie ? matches.http_cookie : undefined,
                    'location': matches.location ? matches.location : undefined
                });
            } catch (error) {
                console.log(`Error: ${error.message}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }
    const alertInfo = parseLog(rawLog);
    console.log(alertInfo);
    function generateDescription() {
        const alertDescriptions = [];
        for (const info of alertInfo) {
            const lastindex = summary.lastIndexOf(']');
            let desc = `Observed ${summary.substr(lastindex + 1)}\n`;
            for (const key in info) {
                if (Object.hasOwnProperty.call(info, key)) {
                    const value = info[key];
                    if (value !== undefined && value !== '-' && value !== '"-"') {
                        desc += `${key}: ${value}\n`;
                    }
                }
            }
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }
    addButton('generateDescription', 'Description', generateDescription);
}

function FireeyeEtpAlertHandler(...kwargs) {
    const { rawLog, summary } = kwargs[0];
    var raw_alert = 0;
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                const { meta, alert, email } = JSON.parse(log)['fireeye'];
                acc.push({
                    timestamp: alert['timestamp'],
                    accepted: email['timestamp']['accepted'],
                    last_malware: meta['last_malware'],
                    alert_type: meta['alert_type'],
                    status: email['status'],
                    source_ip: email['source_ip'],
                    rcpt_to: email['smtp']['rcpt_to'],
                    mail_from: email['smtp']['mail_from'],
                    etp_message_id: email['etp_message_id'],
                    To: email['headers']['to'],
                    From: email['headers']['from'],
                    Subject: email['headers']['subject'],
                    attachment: email['attachment']
                });
                raw_alert += 1;
            } catch (error) {
                console.log(`Error: ${error}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }

    const alertInfo = parseLog(rawLog);
    const num_alert = $('#customfield_10300-val').text().trim();
    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        for (const info of alertInfo) {
            let desc = `Observed ${summary.split(']')[1]}\n`;
            Object.entries(info).forEach(([index, value]) => {
                if (value !== undefined && value !== ' ' && index != 'Summary') {
                    if (index == 'timestamp') {
                        desc += `timestamp(<span class="red_highlight">GMT</span>): ${value.split('.')[0]}Z\n`;
                    } else if (index == 'accepted') {
                        desc += `accepted(<span class="red_highlight">GMT</span>): ${value}Z\n`;
                    } else {
                        desc += `${index}: ${value}\n`;
                    }
                }
            });
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }
    addButton('generateDescription', 'Description', generateDescription);
}

function SentinelOneAlertHandler(...kwargs) {
    const { rawLog, summary } = kwargs[0];
    var raw_alert = 0;
    function parseLog(rawLog) {
        const alertInfo = rawLog.reduce((acc, log) => {
            try {
                console.log('===sentinel_one');
                const sentinel_one = JSON.parse(log)['sentinel_one'];
                acc.push({
                    timestamp: sentinel_one.threatInfo.createdAt.split('.')[0],
                    accountName: sentinel_one.accountName,
                    agentDomain: sentinel_one.agentDomain,
                    agentIpV4: sentinel_one.agentIpV4,
                    agentOsName: sentinel_one.agentOsName,
                    agentMitigationMode: sentinel_one.agentMitigationMode,
                    filePath: sentinel_one.threatInfo.filePath,
                    sha1: sentinel_one.threatInfo.sha1,
                    confidenceLevel: sentinel_one.threatInfo.filePath,
                    threatName: sentinel_one.threatInfo.threatName,
                    processUser: sentinel_one.threatInfo.processUser
                });
                raw_alert += 1;
            } catch (error) {
                console.log(`Error: ${error}`);
            }
            return acc;
        }, []);
        return alertInfo;
    }

    const alertInfo = parseLog(rawLog);
    const num_alert = $('#customfield_10300-val').text().trim();
    function generateDescription() {
        const alertDescriptions = [];
        if (raw_alert < num_alert) {
            let extra_message = `<span class="red_highlight">Number Of Alert : ${num_alert}, Raw Log Alert : ${raw_alert} Raw log information is Not Complete, Please Get More Alert Information From Elastic.</span>\n`;
            alertDescriptions.push(extra_message);
        }
        for (const info of alertInfo) {
            let desc = `Observed ${summary.split(']')[1]}\n`;
            Object.entries(info).forEach(([index, value]) => {
                if (value !== undefined && value !== ' ' && index != 'Summary') {
                    if (index == 'timestamp') {
                        desc += `timestamp(<span class="red_highlight">GMT</span>): ${value.split('.')[0]}Z\n`;
                    } else {
                        desc += `${index}: ${value}\n`;
                    }
                }
            });
            desc += `\nPlease verify if the activity is legitimate.\n`;
            alertDescriptions.push(desc);
        }
        const alertMsg = [...new Set(alertDescriptions)].join('\n');
        showDialog(alertMsg);
    }
    addButton('generateDescription', 'Description', generateDescription);
}

function LHG_CS_AlertHandler(DecoderName) {
    let ORG = $('#customfield_10002-val').text().trim();
    console.log(ORG.split(' ')[ORG.split(' ').length - 1]);
    const elements = document.querySelectorAll('.user-hover.user-avatar');
    const userList = ['kitty.li', 'anson.cho', 'ray.tan', 'philip.ng'];
    console.log(elements[0].textContent.toLowerCase()); // 对每个元素执行操作
    let ClientComment = false;
    for (const dataItem of userList) {
        if (elements[0].textContent.toLowerCase().includes(dataItem.toLowerCase())) {
            ClientComment = true;
            break;
        }
    }
    //判断工单是否升级,
    if (ORG.split(' ')[ORG.split(' ').length - 1] == 'None' && DecoderName == 'crowdstrike_cef') {
        $('#opsbar-opsbar-transitions').on('click', () => {
            let userConfirmed = confirm('LHG的所有 Crowdstrike 告警均需要升级,即使是误报也需要升级');
        });
    } else {
        if (!ClientComment) {
            $('#opsbar-opsbar-transitions').on('click', () => {
                let userConfirmed = confirm(
                    '只有这四个客户回复philip.ng,ray.tan,anson.cho,kitty.li,才可关单,若以上四个客户已允许close,可忽略此提示'
                );
            });
        }
    }
}

function RealMonitorMe() {
    let ORG = $('#customfield_10002-val').text().trim();
    let status = $('#opsbar-transitions_more').text().trim();
    if ($('#customfield_10302-val').text().trim().includes('\n')) {
        let rules = $('#customfield_10302-val').text().trim().split(' \n')[1].split('\n');
        if (rules.length - 1 >= 3 && status == 'Work in progress') {
            confirm(
                `检测到该工单的RuleName有${
                    rules.length - 1
                }个,(如果同一张tickets出现三个告警及以上,需要往cortex群里发,如果是误报请描述原因,谢谢)`
            );
        }
    }
    const intervalId = setInterval(() => {
        var element_one = document.getElementById('opsbar-opsbar-transitions');
        var first = element_one ? element_one.textContent || element_one.innerText : null;
        if (first == 'Resolved') {
            clearInterval(intervalId);
        }
        if (first == 'Waiting for customer' && ORG.split(' ')[ORG.split(' ').length - 1] == 'None') {
            console.log('===发生了改变', first);
            confirm('请注意,该工单变为Waiting for customer,请检查该工单是否已添加ORG');
            first = 'Waiting for customer';
            clearInterval(intervalId);
        }
    }, 500);
}

function formatCurrentDateTime(dateStr, decoder_name) {
    if (dateStr) {
        var date = new Date(dateStr);
        var localOffset = date.getTimezoneOffset();
        if (decoder_name == 'impervainc_cef') {
            var targetDate = new Date(date.getTime() + (480 + localOffset) * 60000);
        } else {
            var targetDate = new Date(date.getTime() + (960 + localOffset) * 60000);
        }
        var year = targetDate.getFullYear();
        var month = ('0' + (targetDate.getMonth() + 1)).slice(-2);
        var day = ('0' + targetDate.getDate()).slice(-2);
        var hours = ('0' + targetDate.getHours()).slice(-2);
        var minutes = ('0' + targetDate.getMinutes()).slice(-2);
        var seconds = ('0' + targetDate.getSeconds()).slice(-2);
        return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`;
    }
    const pad = (num) => (num < 10 ? '0' : '') + num;
    const months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'];
    const date_ = new Date();

    const day_ = date_.getDate();
    const month_ = months[date_.getMonth()];
    const year_ = date_.getFullYear().toString().slice(-2); // 取最后两位
    const hours_ = date_.getHours();
    const minutes_ = date_.getMinutes();
    const ampm = hours_ >= 12 ? 'PM' : 'AM';
    const hour = hours_ % 12 || 12; // Convert to 12-hour format and handle 0 case

    return `${pad(day_)}/${month_}/${year_} ${pad(hour)}:${pad(minutes_)} ${ampm}`;
}

function MonitorDev() {
    function formatDate() {
        const date = new Date();
        const day = String(date.getDate()).padStart(2, '0'); // 日期补齐两位数
        const month = date.toLocaleString('en-US', { month: 'short' }); // 获取月份缩写
        const year = String(date.getFullYear()).slice(-2); // 取年份的后两位

        let hours = date.getHours();
        const minutes = String(date.getMinutes()).padStart(2, '0');
        const ampm = hours >= 12 ? 'PM' : 'AM';

        hours = hours % 12; // 将24小时制转换为12小时制
        hours = hours ? hours : 12; // 如果是0点,将其转换为12
        hours = String(hours).padStart(2, '0'); // 补齐小时为两位数

        return `${day}/${month}/${year} ${hours}:${minutes} ${ampm}`;
    }
    let white = JSON.parse(localStorage.getItem('whitelist'));

    if (window.location.href.includes('/portal/2/create/100')) {
        const interval = setInterval(() => {
            var iframe = document.getElementById('rw_iframe');
            var iframeDocument = iframe.contentDocument || iframe.contentWindow.document;
            var element = iframeDocument.getElementById('summary');
            if (element) {
                let summary = 'Whitelist ' + white['summary'].replace('Wazuh', white['LogSourceDomain']);
                iframeDocument.getElementById('summary').value = summary;
                iframeDocument.getElementById('s2id_labels').innerHTML =
                    `<ul class="select2-choices">  <li class="select2-search-choice">    <div>` +
                    white['LogSourceDomain'] +
                    `</div>    <a href="#" class="select2-search-choice-close" tabindex="-1"></a></li><li class="select2-search-field">    <input type="text" autocomplete="off" autocorrect="off" autocapitalize="off" spellcheck="false" class="select2-input" id="s2id_autogen1" style="width: 10px;">  </li></ul>`;
                iframeDocument.getElementById('labels').value = white['LogSourceDomain'];
                iframeDocument.getElementById('customfield_14601').value = formatDate();
                iframeDocument.getElementById('customfield_14600').value = formatDate();
                iframeDocument.getElementById('customfield_14610').value = 'Yes';
                iframeDocument.getElementById('customfield_14609').value = 'Yes';
                iframeDocument.getElementById('customfield_14608').value = 'Yes';
                clearInterval(interval);
            }
        }, 600);
    }
    let cachedEntry = GM_getValue('cachedEntry', null);
    if (window.location.href.includes('/servlet/desk/portal/2') && window.location.href.includes('DEV')) {
        window.location.href = `${cachedEntry['hk']}/browse/` + window.location.href.split('portal/2/')[1];
        localStorage.setItem('Dev_link', window.location.href.split('portal/2/')[1]);
    }
    if (window.location.href.includes(localStorage.getItem('Dev_link'))) {
        document.getElementById('edit-issue').click();
        const interval = setInterval(() => {
            const components = document.querySelector('#components-textarea');
            if (components) {
                $('#components-textarea').val(white['Component']);
                $('#components-textarea').click();
                $('#issuelinks-issues-textarea').val(white['MSS'].split('browse/')[1]);
                $('#tab-0').click();
                localStorage.removeItem('Dev_link');
                clearInterval(interval);
            }
        }, 500);
    }
}

function WhiteFilehash(filehash) {
    if (filehash == undefined) {
        return 0;
    }
    const cachedWhitehashContent = GM_getValue('cachedWhitehashContent', null);
    for (const f of cachedWhitehashContent) {
        if (filehash.includes(f['hash'].toLowerCase())) {
            console.log('命中了', filehash);
            return true;
        }
    }
}

function RealTimeMonitoring() {
    // Filter page: audio control registration and regular issues table update
    if (
        (window.location.href.includes('filter=15200') ||
            window.location.href.includes('filter=26405') ||
            window.location.href.includes('filter=13300')) &&
        !window.location.href.includes('MSS')
    ) {
        console.log('#### Code includes filter run ####');
        const NotifyControls = createNotifyControls();
        if (window.location.href.includes('filter=15200') || window.location.href.includes('filter=26405')) {
            setInterval(() => {
                notifyKey = [];
                $('.aui-button.aui-button-primary.search-button').click();
                setTimeout(() => {
                    checkupdate(NotifyControls);
                }, 10000);
            }, 180000);
        }
        if (window.location.href.includes('filter=13300')) {
            setInterval(() => {
                notifyKey = [];
                $('.aui-button.aui-button-primary.search-button').click();
                setTimeout(() => {
                    monitorList();
                }, 10000);
            }, 60000);
        }
    }
    if (window.location.href.includes('login.microsoftonline.com')) {
        setTimeout(() => {
            switch_user_microsoft();
        }, 2000);
    }
    if (window.location.href.includes('security.microsoft.com/homepage?&current=')) {
        setTimeout(() => {
            security_microsoft();
        }, 3000);
    }
    // Issue page: Alert Handler
    const generation_description = setInterval(() => {
        var LogSourceDomain = $('#customfield_10223-val').text().trim();
        let rawLog = $('#field-customfield_10219 > div:first-child > div:nth-child(2)').text().trim().split('\n');
        if (rawLog == '') {
            rawLog = $('#field-customfield_10904 > div:first-child > div:nth-child(2)').text().trim().split('\n');
        }
        const summary = $('#summary-val').text().trim();
        if ($('#issue-content').length && !$('#generateDescription').length) {
            console.log('#### Code Issue page: Alert Handler ####');
            const handlers = {
                'cortex-xdr-json': cortexAlertHandler,
                'mde-api-json': MDE365AlertHandler,
                'sangfor-ccom-json': HTSCAlertHandler,
                'carbonblack': CBAlertHandler,
                'carbonblack_cef': VMCEFAlertHandler,
                'windows_eventchannel': WineventAlertHandler,
                'fortigate-firewall-v5': FortigateAlertHandler,
                'crowdstrike_cef': CSAlertHandler,
                'sophos': SophosAlertHandler,
                'sepm-security': SpemAlertHandler,
                'sepm-traffic': SpemAlertHandler,
                'vmwarecarbonblack_cef': VMCEFAlertHandler,
                'aws-cloudtrail': AwsAlertHandler,
                'aws-cisco-umbrella': AwsAlertHandler,
                'm365-defender-json': MDE365AlertHandler,
                'azureeventhub': AzureAlertHandler,
                'azuregraphapi-json': AzureGraphAlertHandler,
                'paloalto-firewall': paloaltoAlertHandler,
                'impervainc_cef': SangforAlertHandler,
                'proofpoint_tap': ProofpointAlertHandler,
                'zscaler-zpa-json': ZscalerAlertHandler,
                'pulse-secure': PulseAlertHandler,
                'aws-guardduty': AwsAlertHandler,
                'alicloud-json': AlicloudAlertHandler,
                'darktrace-json': DarktraceAlertHandler,
                'sangfor_cef': SangforAlertHandler,
                'cyberark_cef': SangforAlertHandler,
                'radware-json': RadwareAlertHandler,
                'carbonblack_cloud': CarbonAlertHandler,
                'windows-syslog': WindowsSysAlertHandler,
                'claroty_cef': ClarotyAlertHandler,
                'office-365': Risky_Countries_AlertHandler,
                'fireeye': FireeyeAlertHandler,
                'web-accesslog': WebAccesslogAlertHandler,
                'checkpoint_cef': SangforAlertHandler,
                'incapsula_cef': SangforAlertHandler,
                'fireeye-etp-json': FireeyeEtpAlertHandler,
                'sentinelone-json': SentinelOneAlertHandler,
                'sonicwall': FortigateAlertHandler,
                'trellix_cef': SangforAlertHandler
            };
            let DecoderName = $('#customfield_10807-val').text().trim().toLowerCase();
            if (DecoderName == '') {
                DecoderName = $('#customfield_10906-val').text().trim().toLowerCase();
            }
            if (DecoderName.includes('m365-defender-json')) {
                let decoder_name = [];
                DecoderName.split(' ').forEach((element, index) => {
                    if (element != 'hide\n' && element != '' && element != 'show\n' && element != '\n') {
                        decoder_name.push(element);
                    }
                });
                if (decoder_name[0].includes('m365-defender-json\n')) {
                    DecoderName = 'm365-defender-json';
                }
            }
            const handler = handlers[DecoderName];
            if (handler) {
                handler({ LogSourceDomain: LogSourceDomain, rawLog: rawLog, summary: summary });
            }
            const No_Decoder_handlers = {
                'detect aad, o365 sign-in from risky countries': Risky_Countries_AlertHandler,
                'successful azure/o365 login from malware-ip': Risky_Countries_AlertHandler,
                'rarely country signin from o365': Risky_Countries_AlertHandler,
                'agent disconnected': Agent_Disconnect_AlertHandler,
                'suspicious geolocation ip login success': PulseAlertHandler,
                'login success from malware ip(s)': ThreatMatrixAlertHandler,
                'multiple account being disabled or deleted in short period of time': MultipleAccountAlertHandler,
                'multiple sms request for same source ip': AwsAlertHandler
            };
            const Summary = $('#summary-val').text().trim();
            let No_Decoder_handler = null;
            Object.keys(No_Decoder_handlers).forEach((key) => {
                if (Summary.toLowerCase().includes(key)) {
                    No_Decoder_handler = No_Decoder_handlers[key];
                }
            });
            if (No_Decoder_handler !== null) {
                No_Decoder_handler({ LogSourceDomain: LogSourceDomain, rawLog: rawLog, summary: Summary });
            }
            if (LogSourceDomain == '') {
                LogSourceDomain = $('#customfield_10846-val').text().trim();
            }
            const Log_Domain_handlers = {
                mdb: MdbAlertHandler, //这里面有点工单为decoder name:sshd
                dst: DstAlertHandler
            };
            const Log_Domain_handler = Log_Domain_handlers[LogSourceDomain];
            if (Log_Domain_handler) {
                Log_Domain_handler({ LogSourceDomain: LogSourceDomain, rawLog: rawLog, summary: summary });
            }
            clearInterval(generation_description);
        }
    }, 1000);
    // Issue page: check Keywords and ATT&CK and Org
    setTimeout(() => {
        if ($('#issue-content').length && !$('.aui-banner-error').length) {
            console.log('#### Code Issue page: check Keywords ####');
            checkKeywords();
            checkATTCK();
        }
    }, 4500);

    // Issue page: Edit Notify
    setTimeout(() => {
        let LogSourceDomain,
            Source,
            Labels,
            LogSource,
            DecoderName,
            TicketAutoEscalate,
            Status,
            RawLog,
            Summary,
            AgentName;
        let cachedEntry = GM_getValue('cachedEntry', null);
        if (window.location.host === cachedEntry['hk'].split('//')[1]) {
            // for HK
            LogSourceDomain = $('#customfield_10223-val').text().trim();
            Source = $('#customfield_10113-val').text().trim();
            Labels = $('.labels-wrap .labels li a span').text();
            LogSource = $('#customfield_10204-val').text().trim();
            DecoderName = $('#customfield_10807-val').text().trim().toLowerCase();
            TicketAutoEscalate = $('#customfield_12202-val').text().trim();
            Status = $('#status-val > span').text().trim();
            RawLog =
                $('#field-customfield_10219 > div:first-child > div:nth-child(2)').text().trim() ||
                $('#customfield_10219-val').text().trim() ||
                $('#field-customfield_10232 > div.twixi-wrap.verbose > div > div > div > pre').text();
            Summary = $('#summary-val').text().trim();
            AgentName = $('#customfield_10805-val').text().trim();
        } else if (window.location.host === cachedEntry['macao'].split('//')[1]) {
            // for MO
            LogSourceDomain = $('#customfield_10846-val').text().trim();
            Source = $('#customfield_10872-val').text().trim();
            Labels = $('#labels-212244-value').text().trim();
            LogSource = $('#customfield_10854-val').text().trim();
            DecoderName = $('#customfield_10906-val').text().trim();
            TicketAutoEscalate = $('#customfield_10893-val').text().trim();
            Status = $('#status-value > span').text().trim();
            RawLog = $('#field-customfield_10904 > div.twixi-wrap.verbose > div').text().trim();
            Summary = $('#summary-val').text().trim();
            AgentName = $('#customfield_10802-val').text().trim();
        }

        const pageData = {
            LogSourceDomain,
            Source,
            Labels,
            LogSource,
            DecoderName,
            TicketAutoEscalate,
            Status,
            RawLog,
            Summary,
            AgentName
        };

        // If it pops up once, it will not be reminded again
        if (
            ($('#issue-content').length &&
                !$('#generateTicketNotify').length &&
                window.location.href.includes('MSS')) ||
            window.location.href.includes('OPS')
        ) {
            addButton('towhitelist', 'WhiteList', ToWhitelist);
            ticketNotify(pageData);
        }
    }, 1000);

    // Issue page: Norm Alert
    setTimeout(() => {
        var LogSourceDomain = $('#customfield_10223-val').text().trim();
        let DecoderName = $('#customfield_10807-val').text().trim().toLowerCase();
        if (DecoderName == '') {
            DecoderName = $('#customfield_10906-val').text().trim().toLowerCase();
        }
        if (LogSourceDomain.includes('lhg')) {
            LHG_CS_AlertHandler(DecoderName);
        }
    }, 3500);

    // Issue page: Quick Reply
    setInterval(() => {
        if (document.querySelector('#reply') == null) {
            QuickReply();
        }
    }, 3000);
}

(function () {
    ('use strict');
    RealTimeMonitoring();

    registerSearchMenu();
    registerExceptionMenu();
    registerCustomQuickReplyMenu();
    addCss();
    MonitorDev();
    AJS.whenIType('zv').execute(function () {
        document.getElementById('opsbar-transitions_more').click();
        const interval = setInterval(() => {
            const element = document.querySelector('#action_id_761');
            if (element) {
                document.getElementById('action_id_761').click();
                clearInterval(interval);
            }
        }, 100); // 每100毫秒检查一次
    });
    AJS.whenIType('zx').execute(function () {
        document.getElementById('edit-issue').click();
        const interval = setInterval(() => {
            const tabsMenu = document.querySelector('#horizontal');
            const elements = tabsMenu.querySelectorAll('*');
            const elementsArray = Array.from(elements);
            const reviewElement = elementsArray.find((element) => element.outerText.trim() === 'Review');
            if (reviewElement) {
                const menuItem = reviewElement.querySelector('.menu-item a');
                const idValue = menuItem.id;
                const element = document.querySelector('#' + idValue);
                if (element) {
                    document.getElementById(idValue).click();
                    $('#customfield_17201').val(formatCurrentDateTime());
                    const metaElement = document
                        .querySelector('meta[name="ajs-remote-user-fullname"]')
                        .getAttribute('content');
                    $('#customfield_17203-field').val(metaElement);
                    document.getElementById('customfield_17203-field').click();
                    clearInterval(interval);
                }
            }
        }, 500);
        const intervals = setInterval(() => {
            const element1 = document.querySelector('#showing-1-of-1-matching-users');
            console.log(element1);
            if (element1) {
                document.querySelector('#showing-1-of-1-matching-users li').click();
                clearInterval(intervals);
            }
        }, 500);
    });
    RealMonitorMe();
})();