Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ PackingProof 官方扩展登记仓库,负责公开协议、发布者和扩展

- `userscript`:由 PackingProof 导入到现有油猴脚本管理流程
- `external-adapter`:PackingProof 校验并解包后展示说明和所在目录,永不自动执行
- GitHub/Gitee 主发布源与可选镜像;主发布源发现失败时,更新机器人尝试镜像发现
- 官方扩展优先使用 Gitee 主发布源和 GitHub 镜像;主发布源发现失败时,更新机器人尝试镜像发现
- 只有稳定 SemVer 版本;不收录 draft、prerelease 或 Raw 文件
- 官方与第三方两级来源标识;市场收录不代表安全保证

Expand Down
3 changes: 2 additions & 1 deletion docs/PROTOCOL_V1.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@ Publisher ID 是与托管平台账号分离的稳定身份。GitHub/Gitee 用户
- 只接受 GitHub/Gitee Release Asset
- Asset 名称固定为 `<extension-id>-<version>.ppx`
- 不接受 Raw、分支文件、自建 CDN、draft 或 prerelease
- 主源可以是 GitHub 或 Gitee;镜像存在时必须使用另一平台
- 官方扩展优先使用 Gitee 主源、GitHub 镜像;第三方扩展可按实际托管情况选择主源
- 镜像存在时必须使用另一平台
- 主源和镜像必须是同一字节流
- 更新机器人先检查主发布源;主源发现请求失败后检查镜像发布源
- 每个版本的 `primary` 指向本次实际可验证的登记源;另一可用来源记录为 `mirror`
Expand Down
5 changes: 5 additions & 0 deletions extensions/packingproof.qqbot/extension.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,11 @@
},
"categories": ["chatbot", "recording"],
"releaseSources": [
{
"provider": "gitee",
"owner": "PackingProof",
"name": "PackingProof-QQBot"
},
{
"provider": "github",
"owner": "PackingProof",
Expand Down
57 changes: 57 additions & 0 deletions extensions/packingproof.qqbot/versions/0.0.4.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{
"$schema": "../../../schemas/version.v1.schema.json",
"access": {
"packingProofCapabilities": [],
"packingProofPermissions": [
"recordings.search",
"recordings.download",
"recordings.delivery"
],
"systemAccess": [
{
"id": "network",
"reason": "连接 QQ 官方接口与用户配置的 PackingProof 主机"
},
{
"id": "filesystem.read",
"reason": "读取 QQBot 本机配置、加密凭据和运行状态"
},
{
"id": "filesystem.write",
"reason": "保存本机配置、加密凭据、日志和待发送的临时录像"
},
{
"id": "other",
"reason": "用户启用开机自动启动时写入当前 Windows 用户的启动项"
}
]
},
"compatibility": {
"minPackingProofVersion": "0.0.62",
"platforms": {
"windows": [
"x64"
]
}
},
"downloads": {
"mirror": {
"provider": "github",
"url": "https://github.com/PackingProof/PackingProof-QQBot/releases/download/v0.0.4/packingproof.qqbot-0.0.4.ppx"
},
"primary": {
"provider": "gitee",
"url": "https://gitee.com/PackingProof/PackingProof-QQBot/releases/download/v0.0.4/packingproof.qqbot-0.0.4.ppx"
}
},
"extensionId": "packingproof.qqbot",
"publishedAt": "2026-08-29T18:00:17+08:00",
"schemaVersion": 1,
"sha256": "9fbe13acb06bf160cd91114c82af88497f6717d79fb2d7e39299912bbd45b138",
"size": 72514406,
"source": {
"commit": "bddd99595e538589d2b643ac65ea6b236bd278a8",
"tag": "v0.0.4"
},
"version": "0.0.4"
}
6 changes: 3 additions & 3 deletions registry/catalog.v1.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
{
"details": "extensions/packingproof.qqbot.json",
"id": "packingproof.qqbot",
"latestVersion": "0.0.3",
"latestVersion": "0.0.4",
"name": "PackingProof QQBot",
"publisher": {
"displayName": "PackingProof",
Expand All @@ -15,6 +15,6 @@
}
],
"schemaVersion": 1,
"sourceDigest": "aa55ae9fae7a9199ed11fc55cf7362307df7395295d13605101704fa68ad0f1c",
"updatedAt": "2026-08-29T09:37:09Z"
"sourceDigest": "b61f4cd9e7ad7fb1cee7e4336576836244fbcfd42391906e3fb83c239ef10aee",
"updatedAt": "2026-08-29T18:00:17+08:00"
}
65 changes: 65 additions & 0 deletions registry/extensions/packingproof.qqbot.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
"name": "PackingProof QQBot",
"publisherId": "packingproof",
"releaseSources": [
{
"name": "PackingProof-QQBot",
"owner": "PackingProof",
"provider": "gitee"
},
{
"name": "PackingProof-QQBot",
"owner": "PackingProof",
Expand Down Expand Up @@ -42,6 +47,66 @@
"schemaVersion": 1,
"trust": "official",
"versions": [
{
"advisory": null,
"release": {
"access": {
"packingProofCapabilities": [],
"packingProofPermissions": [
"recordings.search",
"recordings.download",
"recordings.delivery"
],
"systemAccess": [
{
"id": "network",
"reason": "连接 QQ 官方接口与用户配置的 PackingProof 主机"
},
{
"id": "filesystem.read",
"reason": "读取 QQBot 本机配置、加密凭据和运行状态"
},
{
"id": "filesystem.write",
"reason": "保存本机配置、加密凭据、日志和待发送的临时录像"
},
{
"id": "other",
"reason": "用户启用开机自动启动时写入当前 Windows 用户的启动项"
}
]
},
"compatibility": {
"minPackingProofVersion": "0.0.62",
"platforms": {
"windows": [
"x64"
]
}
},
"downloads": {
"mirror": {
"provider": "github",
"url": "https://github.com/PackingProof/PackingProof-QQBot/releases/download/v0.0.4/packingproof.qqbot-0.0.4.ppx"
},
"primary": {
"provider": "gitee",
"url": "https://gitee.com/PackingProof/PackingProof-QQBot/releases/download/v0.0.4/packingproof.qqbot-0.0.4.ppx"
}
},
"extensionId": "packingproof.qqbot",
"publishedAt": "2026-08-29T18:00:17+08:00",
"schemaVersion": 1,
"sha256": "9fbe13acb06bf160cd91114c82af88497f6717d79fb2d7e39299912bbd45b138",
"size": 72514406,
"source": {
"commit": "bddd99595e538589d2b643ac65ea6b236bd278a8",
"tag": "v0.0.4"
},
"version": "0.0.4"
},
"status": "available"
},
{
"advisory": null,
"release": {
Expand Down
28 changes: 27 additions & 1 deletion tests/package-validator.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,38 @@ import { mkdtemp, readFile, rm, writeFile } from "node:fs/promises";
import os from "node:os";
import path from "node:path";
import test from "node:test";
import { validatePackage } from "../tools/lib/package-validator.mjs";
import { downloadPackage, validatePackage } from "../tools/lib/package-validator.mjs";
import { createSchemaValidator } from "../tools/lib/schemas.mjs";
import { externalManifest, userscriptManifest, writeZip } from "./helpers.mjs";

const rootDirectory = path.resolve(import.meta.dirname, "..");

test("allows Gitee release redirects to its current asset host", async () => {
const temporary = await mkdtemp(path.join(os.tmpdir(), "ppx-gitee-download-"));
const originalFetch = globalThis.fetch;
try {
globalThis.fetch = async () => {
const response = new Response(Buffer.from("ppx"), {
status: 200,
headers: { "content-length": "3" },
});
Object.defineProperty(response, "url", {
value: "https://foruda.gitee.com/attach_file/example/sample.ppx",
});
return response;
};
const destination = path.join(temporary, "sample.ppx");
assert.equal(await downloadPackage(
"https://gitee.com/SampleOrg/Demo/releases/download/v1.0.0/sample.ppx",
destination,
), 3);
assert.equal(await readFile(destination, "utf8"), "ppx");
} finally {
globalThis.fetch = originalFetch;
await rm(temporary, { recursive: true, force: true });
}
});

test("validates userscript package and normalizes X.Y metadata version", async () => {
const temporary = await mkdtemp(path.join(os.tmpdir(), "ppx-userscript-"));
try {
Expand Down
6 changes: 3 additions & 3 deletions tests/releases.test.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ test("falls back to the mirror release API when primary discovery fails", async
const requested = [];
globalThis.fetch = async (url) => {
requested.push(String(url));
if (String(url).includes("api.github.com")) throw new Error("primary unavailable");
if (String(url).includes("gitee.com")) throw new Error("primary unavailable");
return {
ok: true,
json: async () => [{
Expand All @@ -28,10 +28,10 @@ test("falls back to the mirror release API when primary discovery fails", async
};
try {
const result = await discoverWithFallback([
{ provider: "github", owner: "SampleOrg", name: "Demo" },
{ provider: "gitee", owner: "SampleOrg", name: "Demo" },
{ provider: "github", owner: "SampleOrg", name: "Demo" },
]);
assert.equal(result.source.provider, "gitee");
assert.equal(result.source.provider, "github");
assert.equal(result.releases[0].tag, "v1.2.0");
assert.equal(requested.length, 2);
} finally {
Expand Down
2 changes: 1 addition & 1 deletion tools/lib/package-validator.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ function assertAllowedRedirect(originalUrl, finalUrl) {
const finalHost = new URL(finalUrl).hostname.toLowerCase();
const allowed = originalHost === "github.com"
? new Set(["github.com", "objects.githubusercontent.com", "release-assets.githubusercontent.com"])
: new Set(["gitee.com", "files.gitee.com"]);
: new Set(["gitee.com", "files.gitee.com", "foruda.gitee.com"]);
if (!allowed.has(finalHost)) throw new Error(`下载重定向到了未授权域名:${finalHost}`);
}

Expand Down
Loading