FOFA view

Send the current website to FOFA

// ==UserScript==
// @name         FOFA view
// @namespace    http://tampermonkey.net/
// @version      0.5
// @description  Send the current website to FOFA
// @author       0cat
// @match        http://*/*
// @match        https://*/*
// @grant        GM_registerMenuCommand
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @connect      *
// @license MIT
// ==/UserScript==

GM_registerMenuCommand("FOFA Login", openLoginForm, "l");
GM_registerMenuCommand("FOFA 识别结果", FofaFind, "s");

// 创建自定义输入表单
function openLoginForm() {
    const body = document.getElementsByTagName('body')[0];
    const loginDiv = document.createElement('div');
    loginDiv.innerHTML = `
    <div style="position:fixed; top:50%; left:50%; transform:translate(-50%, -50%); background-color:white; padding:20px; border-radius:10px; box-shadow:0 0 10px rgba(0, 0, 0, 0.5); z-index:100000;">
        <h3>Login to FOFA</h3>
        <label>Username (一般是邮箱): 
            <input type="text" id="fofaUsername" style="width:100%;" placeholder="e.g., 1234567890" />
        </label><br/><br/>
        <label>Fofa Key: 
            <input type="password" id="fofaKey" style="width:100%;" />
        </label><br/><br/>
        <button id="loginSubmit">Submit</button>
        <button id="loginCancel">Cancel</button>
    </div>
    `;
    body.appendChild(loginDiv);

    document.getElementById('loginSubmit').onclick = function() {
        const username = document.getElementById('fofaUsername').value;
        const FofaKey = document.getElementById('fofaKey').value;
        if (username && FofaKey) {
            GM_setValue("username", username);
            GM_setValue("FofaKey", FofaKey);
            alert("Login successful!");
            body.removeChild(loginDiv);  // Remove form after login
        } else {
            alert("Please fill in both fields.");
        }
    };

    document.getElementById('loginCancel').onclick = function() {
        body.removeChild(loginDiv);
    };
}

// 识别功能
function FofaFind() {
    var username = GM_getValue("username");
    var FofaKey = GM_getValue("FofaKey");

    if (!username || !FofaKey) {
        console.error("No username or FofaKey found");
        return;
    }
    const body = document.getElementsByTagName('body')[0];
    const div = document.createElement('div');
    div.innerHTML = `<div style="font-size:14px;color:rgba(0,0,0,0.65);box-shadow: 0 2px 12px 0 rgba(0,0,0,0.1) ;background-color: #fff;border-radius: 5px;border: 1px solid #ebebeb;left:20px;top:20px;position: fixed;z-index: 1000000">
        <div style="display: flex;justify-content: flex-end;margin-right: 8px;">
          <div id="expandBtn" style="color:rgb(24, 36, 127);cursor: pointer;margin-left: 8px;margin-top: 4px;font-size: 12px;margin-bottom: 4px;display: none">FOFA展开</div>
          <div id="hideBtn" style="cursor: pointer;font-size: 12px;margin-top: 2px;color:rgb(96, 98, 102);">隐藏</div>
        </div>
        <div id="contentDiv" class="plugs_content_fofa" style="padding-bottom: 10px;">
          <div style="margin-left: 4px;border-radius: 2px;display: inline-block;padding: 8px;padding-right: 40px;">
            <div style="margin-bottom: 4px;display: flex">
              <div style="margin-right: 6px;white-space: nowrap">RDAP_IP_CIDR:</div>
              <div class="rdap_cidr" style="word-wrap:break-word;word-break:normal;overflow: hidden;">N/A</div>
            </div>
            <div style="margin-bottom: 4px;display: flex">
              <div style="margin-right: 6px;white-space: nowrap">RDAP_描述:</div>
              <div class="rdap_description" style="word-wrap:break-word;word-break:normal;overflow: hidden;">N/A</div>
            </div>
            <div style="margin-bottom: 4px;display: flex">
              <div style="margin-right: 6px;white-space: nowrap">地区:</div>
              <div class="area_fofa" style="word-wrap:break-word;word-break:normal;overflow: hidden;">null</div>
            </div>
            <div style="margin-bottom: 4px;display: flex">
              <div style="margin-right: 6px;white-space: nowrap">运营商和org:</div>
              <div class="org_fofa" style="word-wrap:break-word;word-break:normal;overflow: hidden;">null</div>
            </div>
            <div style="margin-bottom: 4px;display: flex">
              <div style="margin-right: 6px;white-space: nowrap">ICP:</div>
              <div class="icp_fofa" style="word-wrap:break-word;word-break:normal;overflow: hidden;">null</div>
            </div>
            <div style="margin-bottom: 4px;display: flex">
              <div style="margin-right: 6px;white-space: nowrap">协议:</div>
              <div class="protocol_fofa" style="word-wrap:break-word;word-break:normal;overflow: hidden;">null</div>
            </div>
            <div style="margin-bottom: 4px;display: flex">
              <div style="margin-right: 6px;white-space: nowrap">端口:</div>
              <div class="port_fofa">null</div>
            </div>
          </div>
          <div class="copy-text-data" style="cursor: pointer;display: flex;margin-top: 8px;border-top:1px solid #ebebeb;justify-content: flex-end;padding-right: 4px;">复制</div>
          <ul class="demo1" style="width: 100%;max-height: 350px;max-width: 600px; overflow: auto;">
            <div style="display: flex;margin-top: 8px;">
              <div style="padding: 0 10px;">
                <div class="table_title_fofa">null</div>
              </div>
              <div style="padding: 0 10px;">
                <div class="table_protocol_fofa">null</div>
              </div>
              <div style="padding: 0 10px;">
                <div class="table_port_fofa">null</div>
              </div>
              <div style="padding: 0 10px;">
                <div class="table_server_fofa">null</div>
              </div>
              <div style="padding: 0 10px;">
                <div class="table_url_fofa">
                  <div>
                    <a href="" class="url1" style="color: #1890ff;text-decoration: none">url</a>
                  </div>
                </div>
              </div>
            </div>
          </ul>
        </div>
      </div>`;
    body.appendChild(div);
    // 隐藏/展开功能
    const hideBtn = document.getElementById('hideBtn');
    const expandBtn = document.getElementById('expandBtn');
    const contentDiv = document.getElementById('contentDiv');

    hideBtn.onclick = function() {
        contentDiv.style.display = 'none';
        hideBtn.style.display = 'none';
        expandBtn.style.display = 'block';
    };

    expandBtn.onclick = function() {
        contentDiv.style.display = 'block';
        hideBtn.style.display = 'block';
        expandBtn.style.display = 'none';
    };

    var target = window.location.hostname;
    var isValidIP_reg = /(\d{1,3}\.){3}\d{1,3}/;

    // 如果是 IP,则执行 RDAP 查询
    if (isValidIP_reg.test(target)) {
        // 发起 RDAP 请求
        var rdap_url = `https://rdap.apnic.net/ip/${target}`;
        GM_xmlhttpRequest({
            method: "GET",
            url: rdap_url,
            onload: function(xhr) {
                
                if (xhr.status !== 200) {
                    console.error("RDAP Request failed, status code:", xhr.status);
                    return;
                }
                const rdap_res = JSON.parse(xhr.responseText);
                // 提取 CIDR 和描述
                const handle = rdap_res.handle;
                const cidr = rdap_res.cidr0_cidrs[0].v4prefix + "/" + rdap_res.cidr0_cidrs[0].length;
                const description = rdap_res.remarks[0].description[0] || 'N/A';

                // 将 CIDR 和描述信息填充到小卡片中
                const rdap_cidr_element = document.getElementsByClassName('rdap_cidr')[0];
                const rdap_description_element = document.getElementsByClassName('rdap_description')[0];
                rdap_cidr_element.textContent = cidr || 'N/A';
                rdap_description_element.textContent = description || 'N/A';
            },
            onerror: function(xhr) {
                console.error("RDAP Request error:", xhr);
            }
        });
    }

    var Fofa_url = "https://fofa.info/api/v1/search/all?email=" + username + "&key=" + FofaKey + "&fields=country,province,city,isp,as_organization,ip,title,protocol,port,host,server,icp&qbase64=";

    var search, url;

    if (isValidIP_reg.test(target)) {
        search = btoa('ip=="' + target + '"');
        url = Fofa_url + search;
    } else {
        search = btoa('host=="' + target + '"');
        url = Fofa_url + search;
    }
    if (!url) {
        console.error("URL generation failed.");
        return;
    }

    // 发起 FOFA 查询请求
    try {
        GM_xmlhttpRequest({
            method: "GET",
            url: url,
            onload: function(xhr) {
                
                if (xhr.status !== 200) {
                    console.error("FOFA Request failed, status code:", xhr.status);
                    return;
                }
                const res = JSON.parse(xhr.responseText);

                const target_data = res.results || [];
                if (target_data.length === 0) {
                    
                    return;
                }
                // 获取 HTML 元素
                const area = document.getElementsByClassName('area_fofa')[0];
                const org = document.getElementsByClassName('org_fofa')[0];
                const protocol = document.getElementsByClassName('protocol_fofa')[0];
                const port = document.getElementsByClassName('port_fofa')[0];
                const icp = document.getElementsByClassName('icp_fofa')[0];

                const table_title = document.getElementsByClassName('table_title_fofa')[0];
                const table_protocol = document.getElementsByClassName('table_protocol_fofa')[0];
                const table_port = document.getElementsByClassName('table_port_fofa')[0];
                const table_server = document.getElementsByClassName('table_server_fofa')[0];
                const table_url = document.getElementsByClassName('table_url_fofa')[0];

                // 遍历数据并展示到页面
                let title_innerHTML = `<div style='white-space: nowrap'>标题</div>`;
                let protocol_innerHTML = `<div style='white-space: nowrap'>协议</div>`;
                let port_innerHTML = `<div style='white-space: nowrap'>端口</div>`;
                let server_innerHTML = `<div style='white-space: nowrap'>server</div>`;
                let url_innerHTML = `<div style='white-space: nowrap'>url</div>`;

                target_data.forEach(item => {
                    title_innerHTML += `<div style="white-space: nowrap;height: 20px">${item[6] || 'N/A'}</div>`;
                    protocol_innerHTML += `<div style="white-space: nowrap;height: 20px">${item[7] || 'N/A'}</div>`;
                    if (item[7] === "http" || item[7] === "https") {
                        var urlNoProtocol = item[9].replace(/^https?\:\/\//i, "");
                        var urlProtocol = item[7] + "://" + urlNoProtocol;
                        url_innerHTML += `<div style="white-space: nowrap;height: 20px"><a href="${urlProtocol}" target='_blank' style="color: #1890ff;text-decoration: none">${urlProtocol}</a></div>`;
                    } else {
                        url_innerHTML += `<div style="white-space: nowrap;height: 20px"><a href="" target='_blank' style="color: #1890ff;text-decoration: none"></a></div>`;
                    }
                    port_innerHTML += `<div style="white-space: nowrap;height: 20px">${item[8] || 'N/A'}</div>`;
                    server_innerHTML += `<div style="white-space: nowrap;height: 20px">${item[10] || 'N/A'}</div>`;
                });

                table_title.innerHTML = title_innerHTML;
                table_protocol.innerHTML = protocol_innerHTML;
                table_port.innerHTML = port_innerHTML;
                table_server.innerHTML = server_innerHTML;
                table_url.innerHTML = url_innerHTML;
                const target_location = target_data[0] || {};
                area.textContent = [target_location[0] || '', target_location[1] || '', target_location[2] || ''].filter(item => item).join('-') || 'N/A';
                org.textContent = [target_location[3] || '', target_location[4] || ''].filter(item => item).join(',') || 'N/A';
                icp.textContent = Array.from(new Set(target_data.filter(item => item[11]).map(item => item[11]))).join(',') || 'N/A';
                protocol.textContent = Array.from(new Set(target_data.filter(item => item[7]).map(item => item[7]))).join(',') || 'N/A';
                port.textContent = Array.from(new Set(target_data.filter(item => item[8]).map(item => item[8]))).join(',') || 'N/A';
            },
            onerror: function(xhr) {
                console.error("FOFA Request error:", xhr);
            }
        });
    } catch (e) {
        console.error("Error while sending request:", e);
    }
}