Initial commit: plugin repository structure
Some checks failed
Sign Plugins / sign (push) Failing after 32s

- GitHub Actions workflows for signing and validation
- Example file-manager plugin
- Scripts for batch signing
This commit is contained in:
Flik
2025-12-29 18:53:30 +08:00
commit 6b38f133f4
9 changed files with 257 additions and 0 deletions

20
.github/workflows/release.yml vendored Normal file
View File

@@ -0,0 +1,20 @@
name: Release
on:
push:
tags:
- 'v*'
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Create Release
uses: softprops/action-gh-release@v1
with:
files: |
plugins/**/*.js
plugins/**/*.sig
plugins/**/manifest.json

43
.github/workflows/sign.yml vendored Normal file
View File

@@ -0,0 +1,43 @@
name: Sign Plugins
on:
push:
branches: [main]
paths:
- 'plugins/**/*.js'
- 'plugins/**/manifest.json'
workflow_dispatch:
jobs:
sign:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Go
uses: actions/setup-go@v5
with:
go-version: '1.21'
- name: Build signtool
run: |
git clone --depth 1 https://github.com/your-org/gotunnel.git /tmp/gotunnel
cd /tmp/gotunnel
go build -o /usr/local/bin/signtool ./cmd/signtool
- name: Sign plugins
env:
SIGNING_KEY: ${{ secrets.PLUGIN_SIGNING_KEY }}
run: |
echo "$SIGNING_KEY" > /tmp/private.key
chmod 600 /tmp/private.key
bash scripts/sign-all.sh /tmp/private.key
rm -f /tmp/private.key
- name: Commit signatures
run: |
git config user.name "GitHub Actions"
git config user.email "actions@github.com"
git add -A "plugins/**/*.sig"
git diff --staged --quiet || git commit -m "chore: update plugin signatures"
git push

16
.github/workflows/validate.yml vendored Normal file
View File

@@ -0,0 +1,16 @@
name: Validate PR
on:
pull_request:
branches: [main]
paths:
- 'plugins/**'
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate manifests
run: bash scripts/validate.sh

9
.gitignore vendored Normal file
View File

@@ -0,0 +1,9 @@
# Signatures (auto-generated)
*.sig
# OS
.DS_Store
# IDE
.idea/
.vscode/

25
README.md Normal file
View File

@@ -0,0 +1,25 @@
# GoTunnel Official Plugins
GoTunnel 官方插件仓库,所有插件均经过官方签名验证。
## 目录结构
```
plugins/
├── file-manager/ # 文件管理器插件
│ ├── plugin.js # 插件源码
│ ├── plugin.js.sig # 签名文件CI自动生成
│ └── manifest.json # 插件元数据
└── ...
```
## 插件开发
1.`plugins/` 下创建插件目录
2. 编写 `plugin.js``manifest.json`
3. 提交 PRCI 会自动验证格式
4. 合并后 CI 自动签名并发布
## 签名验证
所有插件由 GoTunnel 官方私钥签名,客户端内置公钥验证。

View File

@@ -0,0 +1,8 @@
{
"name": "file-manager",
"version": "1.0.0",
"description": "文件管理器插件,提供远程文件浏览和管理功能",
"author": "GoTunnel Official",
"run_at": "client",
"type": "app"
}

View File

@@ -0,0 +1,64 @@
// GoTunnel File Manager Plugin
function metadata() {
return {
name: "file-manager",
version: "1.0.0",
description: "文件管理器插件",
author: "GoTunnel Official",
type: "app",
run_at: "client"
};
}
function start() {
log("File Manager plugin started");
}
function stop() {
log("File Manager plugin stopped");
}
function handleConn(conn) {
http.serve(conn, handleRequest);
}
function handleRequest(req) {
var path = req.path;
var method = req.method;
if (path === "/api/list") {
return handleList(req);
}
if (path === "/api/read" && method === "POST") {
return handleRead(req);
}
return { status: 404, body: '{"error":"not found"}' };
}
function handleList(req) {
var dir = config("root_path") || ".";
var result = fs.readDir(dir);
if (result.error) {
return { status: 500, body: http.json({ error: result.error }) };
}
return { status: 200, body: http.json({ entries: result.entries }) };
}
function handleRead(req) {
var body = JSON.parse(req.body || "{}");
var path = body.path;
if (!path) {
return { status: 400, body: '{"error":"path required"}' };
}
var result = fs.readFile(path);
if (result.error) {
return { status: 500, body: http.json({ error: result.error }) };
}
return { status: 200, body: http.json({ content: result.data }) };
}

43
scripts/sign-all.sh Executable file
View File

@@ -0,0 +1,43 @@
#!/bin/bash
set -e
KEY_FILE="$1"
if [ -z "$KEY_FILE" ]; then
echo "Usage: $0 <private-key-file>"
exit 1
fi
if [ ! -f "$KEY_FILE" ]; then
echo "Error: Key file not found: $KEY_FILE"
exit 1
fi
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
REPO_ROOT="$(dirname "$SCRIPT_DIR")"
cd "$REPO_ROOT"
for manifest in plugins/*/manifest.json; do
if [ ! -f "$manifest" ]; then
continue
fi
dir=$(dirname "$manifest")
name=$(jq -r '.name' "$manifest")
version=$(jq -r '.version' "$manifest")
plugin_file="$dir/plugin.js"
if [ ! -f "$plugin_file" ]; then
echo "Warning: $plugin_file not found, skipping"
continue
fi
echo "Signing: $name v$version"
signtool sign -key "$KEY_FILE" \
-name "$name" \
-version "$version" \
"$plugin_file"
done
echo "Done!"

29
scripts/validate.sh Executable file
View File

@@ -0,0 +1,29 @@
#!/bin/bash
set -e
ERRORS=0
for manifest in plugins/*/manifest.json; do
[ -f "$manifest" ] || continue
dir=$(dirname "$manifest")
name=$(basename "$dir")
echo "Validating: $name"
# 检查必需字段
for field in name version description; do
val=$(jq -r ".$field" "$manifest")
if [ "$val" = "null" ] || [ -z "$val" ]; then
echo " Error: missing $field"
ERRORS=$((ERRORS + 1))
fi
done
# 检查 plugin.js 存在
if [ ! -f "$dir/plugin.js" ]; then
echo " Error: plugin.js not found"
ERRORS=$((ERRORS + 1))
fi
done
exit $ERRORS