来试试在油猴上使用Sekiro

写在前面

本文基于因体科技提供的测试服务撰写,如果你需要使用自己搭建的服务端,并且需要教程帮助,可以参考这篇文档:https://iinti.cn/sekiro-article/sekiro-js-4/

本文选用了一个 http 站点作为测试,如果您的目标站点是 https,请修改wswss并自行配置证书,参考 https://iinti.cn/sekiro-doc/02_advance/03_sslForWebsocket.html#%E9%85%8D%E7%BD%AE%E5%9F%9F%E5%90%8D%E5%88%97%E8%A1%A8 也可以直接咨询我们,可以提供 Saas ~

如果大家觉得 Sekiro 非常好用,欢迎联系我们合作~

编写油猴脚本

首先先创建一个新的油猴脚本 img.png

然后引入关键函数SekiroClient()

function SekiroClient(e) {
  if (((this.wsURL = e), (this.handlers = {}), (this.socket = {}), !e))
    throw new Error("wsURL can not be empty!!");
  (this.webSocketFactory = this.resolveWebSocketFactory()), this.connect();
}
(SekiroClient.prototype.resolveWebSocketFactory = function () {
  if ("object" == typeof window) {
    var e = window.WebSocket ? window.WebSocket : window.MozWebSocket;
    return function (o) {
      function t(o) {
        this.mSocket = new e(o);
      }
      return (
        (t.prototype.close = function () {
          this.mSocket.close();
        }),
        (t.prototype.onmessage = function (e) {
          this.mSocket.onmessage = e;
        }),
        (t.prototype.onopen = function (e) {
          this.mSocket.onopen = e;
        }),
        (t.prototype.onclose = function (e) {
          this.mSocket.onclose = e;
        }),
        (t.prototype.send = function (e) {
          this.mSocket.send(e);
        }),
        new t(o)
      );
    };
  }
  if ("object" == typeof weex)
    try {
      console.log("test webSocket for weex");
      var o = weex.requireModule("webSocket");
      return (
        console.log("find webSocket for weex:" + o),
        function (e) {
          try {
            o.close();
          } catch (e) {}
          return o.WebSocket(e, ""), o;
        }
      );
    } catch (e) {
      console.log(e);
    }
  if ("object" == typeof WebSocket)
    return function (o) {
      return new e(o);
    };
  throw new Error("the js environment do not support websocket");
}),
  (SekiroClient.prototype.connect = function () {
    console.log("sekiro: begin of connect to wsURL: " + this.wsURL);
    var e = this;
    try {
      this.socket = this.webSocketFactory(this.wsURL);
    } catch (o) {
      return (
        console.log("sekiro: create connection failed,reconnect after 2s:" + o),
        void setTimeout(function () {
          e.connect();
        }, 2e3)
      );
    }
    this.socket.onmessage(function (o) {
      e.handleSekiroRequest(o.data);
    }),
      this.socket.onopen(function (e) {
        console.log("sekiro: open a sekiro client connection");
      }),
      this.socket.onclose(function (o) {
        console.log("sekiro: disconnected ,reconnection after 2s"),
          setTimeout(function () {
            e.connect();
          }, 2e3);
      });
  }),
  (SekiroClient.prototype.handleSekiroRequest = function (e) {
    console.log("receive sekiro request: " + e);
    var o = JSON.parse(e),
      t = o.__sekiro_seq__;
    if (o.action) {
      var n = o.action;
      if (this.handlers[n]) {
        var s = this.handlers[n],
          i = this;
        try {
          s(
            o,
            function (e) {
              try {
                i.sendSuccess(t, e);
              } catch (e) {
                i.sendFailed(t, "e:" + e);
              }
            },
            function (e) {
              i.sendFailed(t, e);
            }
          );
        } catch (e) {
          console.log("error: " + e), i.sendFailed(t, ":" + e);
        }
      } else this.sendFailed(t, "no action handler: " + n + " defined");
    } else this.sendFailed(t, "need request param {action}");
  }),
  (SekiroClient.prototype.sendSuccess = function (e, o) {
    var t;
    if ("string" == typeof o)
      try {
        t = JSON.parse(o);
      } catch (e) {
        (t = {}).data = o;
      }
    else "object" == typeof o ? (t = o) : ((t = {}).data = o);
    (Array.isArray(t) || "string" == typeof t) && (t = { data: t, code: 0 }),
      t.code ? (t.code = 0) : (t.status, (t.status = 0)),
      (t.__sekiro_seq__ = e);
    var n = JSON.stringify(t);
    console.log("response :" + n), this.socket.send(n);
  }),
  (SekiroClient.prototype.sendFailed = function (e, o) {
    "string" != typeof o && (o = JSON.stringify(o));
    var t = {};
    (t.message = o), (t.status = -1), (t.__sekiro_seq__ = e);
    var n = JSON.stringify(t);
    console.log("sekiro: response :" + n), this.socket.send(n);
  }),
  (SekiroClient.prototype.registerAction = function (e, o) {
    if ("string" != typeof e) throw new Error("an action must be string");
    if ("function" != typeof o) throw new Error("a handler must be function");
    return (
      console.log("sekiro: register action: " + e), (this.handlers[e] = o), this
    );
  });

编写 sekiro 启动函数,其中需要注意的是:

  • 您可以先使用测试服务
    • http://sekiro.iinti.cn/ 登陆测试用户
    • 用户名:sekiro
    • 密码:sekiro
function start_sekiro() {
  // 根据ip和port进行配置,创建client
  var client = new SekiroClient(
    "ws://sekiro.iinti.cn:5612/business/register?group=demo-ws&clientId=" +
      Math.random()
  ); // 修改成自己的group
  // 注册分组
  client.registerAction("testAction", function (request, resolve, reject) {
    var param = request["param"]; // 接收传递的参数
    if (!param) {
      reject("need param{param}");
      return;
    }
    console.log(`testAction:${param}`);
    try {
      var result = document.cookie; // 获取页面cookie
      resolve(result); // 将cookie传递出去
    } catch (e) {
      reject(`error:${e}`); // 异常处理
    }
  });
}

最后,在浏览器刷新目标网站页面,让油猴脚本生效 打开控制台可以看到顺利建立了连接~ img_1.png

完整代码如下:

// ==UserScript==
// @name         sekiro-test
// @namespace    http://tampermonkey.net/
// @version      2024-01-13
// @description  try to take over the world!
// @author       You
// @match        https://*
// @icon         https://www.google.com/s2/favicons?sz=64&domain=xiaohongshu.com
// @grant        none
// ==/UserScript==

(function () {
  // 引入关键函数
  function SekiroClient(e) {
    if (((this.wsURL = e), (this.handlers = {}), (this.socket = {}), !e))
      throw new Error("wsURL can not be empty!!");
    (this.webSocketFactory = this.resolveWebSocketFactory()), this.connect();
  }
  (SekiroClient.prototype.resolveWebSocketFactory = function () {
    if ("object" == typeof window) {
      var e = window.WebSocket ? window.WebSocket : window.MozWebSocket;
      return function (o) {
        function t(o) {
          this.mSocket = new e(o);
        }
        return (
          (t.prototype.close = function () {
            this.mSocket.close();
          }),
          (t.prototype.onmessage = function (e) {
            this.mSocket.onmessage = e;
          }),
          (t.prototype.onopen = function (e) {
            this.mSocket.onopen = e;
          }),
          (t.prototype.onclose = function (e) {
            this.mSocket.onclose = e;
          }),
          (t.prototype.send = function (e) {
            this.mSocket.send(e);
          }),
          new t(o)
        );
      };
    }
    if ("object" == typeof weex)
      try {
        console.log("test webSocket for weex");
        var o = weex.requireModule("webSocket");
        return (
          console.log("find webSocket for weex:" + o),
          function (e) {
            try {
              o.close();
            } catch (e) {}
            return o.WebSocket(e, ""), o;
          }
        );
      } catch (e) {
        console.log(e);
      }
    if ("object" == typeof WebSocket)
      return function (o) {
        return new e(o);
      };
    throw new Error("the js environment do not support websocket");
  }),
    (SekiroClient.prototype.connect = function () {
      console.log("sekiro: begin of connect to wsURL: " + this.wsURL);
      var e = this;
      try {
        this.socket = this.webSocketFactory(this.wsURL);
      } catch (o) {
        return (
          console.log(
            "sekiro: create connection failed,reconnect after 2s:" + o
          ),
          void setTimeout(function () {
            e.connect();
          }, 2e3)
        );
      }
      this.socket.onmessage(function (o) {
        e.handleSekiroRequest(o.data);
      }),
        this.socket.onopen(function (e) {
          console.log("sekiro: open a sekiro client connection");
        }),
        this.socket.onclose(function (o) {
          console.log("sekiro: disconnected ,reconnection after 2s"),
            setTimeout(function () {
              e.connect();
            }, 2e3);
        });
    }),
    (SekiroClient.prototype.handleSekiroRequest = function (e) {
      console.log("receive sekiro request: " + e);
      var o = JSON.parse(e),
        t = o.__sekiro_seq__;
      if (o.action) {
        var n = o.action;
        if (this.handlers[n]) {
          var s = this.handlers[n],
            i = this;
          try {
            s(
              o,
              function (e) {
                try {
                  i.sendSuccess(t, e);
                } catch (e) {
                  i.sendFailed(t, "e:" + e);
                }
              },
              function (e) {
                i.sendFailed(t, e);
              }
            );
          } catch (e) {
            console.log("error: " + e), i.sendFailed(t, ":" + e);
          }
        } else this.sendFailed(t, "no action handler: " + n + " defined");
      } else this.sendFailed(t, "need request param {action}");
    }),
    (SekiroClient.prototype.sendSuccess = function (e, o) {
      var t;
      if ("string" == typeof o)
        try {
          t = JSON.parse(o);
        } catch (e) {
          (t = {}).data = o;
        }
      else "object" == typeof o ? (t = o) : ((t = {}).data = o);
      (Array.isArray(t) || "string" == typeof t) && (t = { data: t, code: 0 }),
        t.code ? (t.code = 0) : (t.status, (t.status = 0)),
        (t.__sekiro_seq__ = e);
      var n = JSON.stringify(t);
      console.log("response :" + n), this.socket.send(n);
    }),
    (SekiroClient.prototype.sendFailed = function (e, o) {
      "string" != typeof o && (o = JSON.stringify(o));
      var t = {};
      (t.message = o), (t.status = -1), (t.__sekiro_seq__ = e);
      var n = JSON.stringify(t);
      console.log("sekiro: response :" + n), this.socket.send(n);
    }),
    (SekiroClient.prototype.registerAction = function (e, o) {
      if ("string" != typeof e) throw new Error("an action must be string");
      if ("function" != typeof o) throw new Error("a handler must be function");
      return (
        console.log("sekiro: register action: " + e),
        (this.handlers[e] = o),
        this
      );
    });

  function start_sekiro() {
    // 根据ip和port进行配置,创建client
    var client = new SekiroClient(
      "ws://sekiro.iinti.cn:5612/business/register?group=demo-ws&clientId=" +
        Math.random()
    ); // 修改成自己的group
    // 注册分组
    client.registerAction("testAction", function (request, resolve, reject) {
      var param = request["param"]; // 接收传递的参数
      if (!param) {
        reject("need param{param}");
        return;
      }
      console.log(`testAction:${param}`);
      try {
        var result = document.cookie; // 获取页面cookie
        resolve(result); // 将cookie传递出去
      } catch (e) {
        reject(`error:${e}`); // 异常处理
      }
    });
  }
  setTimeout(start_sekiro, 2000); // 等待20s加载Sekiro客户端
})();

验证

在浏览器地址栏使用 get 请求进行验证: https://sekiro.iinti.cn/business/invoke?group=demo-ws&action=testAction&param=testparm

可以看到成功返回了我们的 cookie(油猴脚本中注册的 testAction 的逻辑 img_2.png

Sekiro 文档 && 测试账户登陆

文档地址:https://sekiro.iinti.cn/sekiro-doc/

登陆站点:http://sekiro.iinti.cn/

  • 测试账户用户名:sekiro
  • 密码:sekiro

用户在登陆后可以建立自己的分组 img_4.png

查看 group 级别监控、action 级别监控、客户端监控等 img_7.png img_6.png