Xshell for JumpServer

JumpServer自动打开Xshell

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey, Greasemonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Violentmonkey.

Voor het installeren van scripts heb je een extensie nodig, zoals Tampermonkey of Userscripts.

Voor het installeren van scripts heb je een extensie nodig, zoals {tampermonkey_link:Tampermonkey}.

Voor het installeren van scripts heb je een gebruikersscriptbeheerder nodig.

(Ik heb al een user script manager, laat me het downloaden!)

Advertisement:

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een extensie nodig, zoals {stylus_link:Stylus}.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

Voor het installeren van gebruikersstijlen heb je een gebruikersstijlbeheerder nodig.

(Ik heb al een beheerder - laat me doorgaan met de installatie!)

Advertisement:

// ==UserScript==
// @name        Xshell for JumpServer
// @namespace   Violentmonkey Scripts
// @icon        http://10.21.1.10:20080/static/img/facio.ico
// @version     1.0.0
//
// @match       http://10.21.1.10:20080/luna/*
// @grant       none
// @license     MIT
//
// @author      vidda
// @description JumpServer自动打开Xshell
// ==/UserScript==
(function () {
  'use strict';

  // 点击查看密码按钮,显示密码
  function clickEyeIcon(contentDiv) {
    // 使用CSS选择器查找目标元素
    const eyeIcon = contentDiv.querySelector('.show-password .fa-eye');

    if (eyeIcon) {
      eyeIcon.click();
      return true;
    }
    return false;
  }

  // 获取密码
  function getPassword(contentDiv) {
    // 选择包含密码的span元素
    const passwordSpan = contentDiv.querySelector('.show-password span');

    if (passwordSpan) {
      // 获取文本内容并去除首尾空格
      const password = passwordSpan.textContent.trim();
      return password;
    } else {
      console.log('未找到密码元素');
      return null;
    }
  }

  function getSshCmd(contentDiv) {
    const commandPre = contentDiv.querySelector('.command pre');

    if (commandPre) {
      // 获取文本内容并去除首尾空格
      const command = commandPre.textContent.trim();
      return command;
    } else {
      console.log('未找到command元素');
      return null;
    }
  }

  function triggerContextMenu(element) {
    const event = new MouseEvent('contextmenu', {
      bubbles: true,
      cancelable: true,
      view: window,
      button: 2,
      buttons: 2,
      clientX: element.getBoundingClientRect().left,
      clientY: element.getBoundingClientRect().top
    });

    // 如果需要兼容极老浏览器,可以使用 initMouseEvent (现代浏览器一般不需要)
    return element.dispatchEvent(event);
  }

  function refreshTab(contentDiv) {
    const refreshMenu = document.querySelectorAll('div.view-menu table tr')[1].children[0];
    refreshMenu.click();
    setTimeout(() => {
      const commandEle = contentDiv.querySelector('.command');
      createButton(commandEle);
    }, 200);
  }

  function openXshell(contentDiv) {
    const password = getPassword(contentDiv);
    let src = 'xshell://';
    let command = getSshCmd(contentDiv);
    command = command.substring(2);
    command = command.replace('ssh ', 'ssh//');
    // 在 @ 符号前插入 ":pwd"
    command = command.replace(/@/, ':' + password + '@');
    command = command.replace(' -p ', ':');
    src += command;
    const iframe = document.createElement('iframe');
    iframe.style.display = 'none';
    iframe.src = src;
    document.body.appendChild(iframe);

    // 获取目标元素
    let tabActive = document.querySelector('elements-content-tab li.active');
    triggerContextMenu(tabActive);

    setTimeout(() => {
      clickEyeIcon(contentDiv);
      refreshTab(contentDiv);
    }, 100);
  }

  function loopContainer() {
    const targetElement = document.querySelector('#winContainer');
    const observer = new MutationObserver(function (mutations) {
      setTimeout(() => {
        const container = document.querySelectorAll('div.content');
        if (container) {
          container.forEach(function (parent) {
            const commandContainer = parent.children[1];
            const commandEle = commandContainer.querySelector('.command');
            createButton(commandEle);
          });
        }
      }, 100);
    });
    observer.observe(targetElement, { childList: true, subtree: false });
  }

  // 等待目标容器出现(如果是动态加载的页面)
  function waitForWindowContainer() {
    const container = document.querySelector('#winContainer');
    if (container) {
      loopContainer(container);
    } else {
      // 如果容器还没出现,用 MutationObserver 监听
      const observer = new MutationObserver(function (mutations) {
        const container = document.querySelector('#winContainer');
        if (container) {
          loopContainer();
          observer.disconnect(); // 找到后停止监听
        }
      });
      observer.observe(document.body, { childList: true, subtree: true });
      // 设置超时,避免无限等待
      setTimeout(() => observer.disconnect(), 10000);
    }
  }

  function createButton(container) {
    // 检查是否已存在,避免重复插入

    if (container.querySelector('.xshell-button')) {
      return;
    }

    // 创建圆形按钮
    const button = document.createElement('button');
    button.classList.add('xshell-button');
    button.textContent = 'X';
    button.title = '使用Xshell打开';
    button.style.cssText = `
      position: absolute;
      right: 46px;
      top: 4px;
      width: 35px;
      height: 35px;
      background: transparent;
      border-radius: 5px;
      border: 1px solid rgba(240, 246, 252, .1);
      color: #f74d38;
      font-size: 18px;
      font-weight: bold;
      cursor: pointer;
      display: inline-flex;
      align-items: center;
      justify-content: center;
      transition: all 0.3s ease;
    `;

    // 鼠标悬停效果
    button.addEventListener('mouseenter', () => {
      button.style.background = '#30363d';
      button.style.borderColor = '#8b949e';
    });
    button.addEventListener('mouseleave', () => {
      button.style.background = 'transparent';
      button.style.borderColor = 'rgba(240, 246, 252, .1)';
    });

    // 点击事件
    button.addEventListener('click', function () {
      clickEyeIcon(container.parentElement.parentElement);
      setTimeout(function () {
        openXshell(container.parentElement.parentElement);
      }, 100)
    });

    // 插入到容器最后一个子元素之后(即作为最后一个子元素)
    container.prepend(button);
  }

  // 页面加载完成后执行
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', waitForWindowContainer);
  } else {
    waitForWindowContainer();
  }
})();