Xshell for JumpServer

JumpServer自动打开Xshell

スクリプトをインストールするには、Tampermonkey, GreasemonkeyViolentmonkey のような拡張機能のインストールが必要です。

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

スクリプトをインストールするには、TampermonkeyViolentmonkey のような拡張機能のインストールが必要です。

スクリプトをインストールするには、TampermonkeyUserscripts のような拡張機能のインストールが必要です。

このスクリプトをインストールするには、Tampermonkeyなどの拡張機能をインストールする必要があります。

このスクリプトをインストールするには、ユーザースクリプト管理ツールの拡張機能をインストールする必要があります。

(ユーザースクリプト管理ツールは設定済みなのでインストール!)

Advertisement:

このスタイルをインストールするには、Stylusなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus などの拡張機能をインストールする必要があります。

このスタイルをインストールするには、Stylus tなどの拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

このスタイルをインストールするには、ユーザースタイル管理用の拡張機能をインストールする必要があります。

(ユーザースタイル管理ツールは設定済みなのでインストール!)

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();
  }
})();