mirror of
https://github.com/MengMengCode/VoCat.git
synced 2026-08-13 03:13:43 +08:00
- Implemented `telegramAPIURL` and `validateTelegramAPIURL` functions for constructing and validating Telegram API URLs. - Added semantic versioning utilities in `version.go` to compare versions and validate semantic version formats. - Created tests for version comparison logic in `version_test.go`. - Introduced IMS call handling in `call_runtime.go`, including methods for dialing, answering, and hanging up calls. - Added tests for incoming call handling and validation in `call_runtime_test.go`. - Developed a new `PluginsCard` component for managing plugins via URL or file upload in the web interface. - Implemented plugin management functions in `extensions.ts` and created an `ExtensionPage` for displaying plugin contributions.
101 lines
2.7 KiB
Go
101 lines
2.7 KiB
Go
package extensions
|
|
|
|
import (
|
|
"archive/zip"
|
|
"bytes"
|
|
"io"
|
|
"log/slog"
|
|
"strings"
|
|
"testing"
|
|
)
|
|
|
|
func TestInstallListDisableAndUninstall(t *testing.T) {
|
|
manager, err := NewManager(t.TempDir(), slog.New(slog.NewTextHandler(io.Discard, nil)))
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer manager.Close()
|
|
archive := testPackage(t, map[string]string{
|
|
ManifestFilename: `{
|
|
"schema_version":1,"id":"test-plugin","name":"Test","version":"1.0.0",
|
|
"permissions":["devices.read"],
|
|
"contributions":[{"id":"test-page","label":"Test","location":"sidebar","entry":"web/index.html"}]
|
|
}`,
|
|
"web/index.html": "<h1>test</h1>",
|
|
})
|
|
plugin, err := manager.Install(bytes.NewReader(archive), "")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if plugin.ID != "test-plugin" || !plugin.Enabled || len(manager.List()) != 1 {
|
|
t.Fatalf("unexpected installed plugin: %#v", plugin)
|
|
}
|
|
if _, err := manager.SetEnabled(plugin.ID, false); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if manager.List()[0].Enabled {
|
|
t.Fatal("plugin remained enabled")
|
|
}
|
|
if err := manager.Uninstall(plugin.ID); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if len(manager.List()) != 0 {
|
|
t.Fatal("plugin remained installed")
|
|
}
|
|
}
|
|
|
|
func TestInstallRejectsPathTraversal(t *testing.T) {
|
|
manager, err := NewManager(t.TempDir(), nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer manager.Close()
|
|
archive := testPackage(t, map[string]string{
|
|
ManifestFilename: `{
|
|
"schema_version":1,"id":"bad-plugin","name":"Bad","version":"1",
|
|
"contributions":[{"id":"bad-page","label":"Bad","location":"sidebar","entry":"web/index.html"}]
|
|
}`,
|
|
"../escaped": "bad",
|
|
})
|
|
if _, err := manager.Install(bytes.NewReader(archive), ""); err == nil || !strings.Contains(err.Error(), "unsafe path") {
|
|
t.Fatalf("Install traversal error = %v", err)
|
|
}
|
|
}
|
|
|
|
func TestInstallVerifiesSHA256(t *testing.T) {
|
|
manager, err := NewManager(t.TempDir(), nil)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer manager.Close()
|
|
archive := testPackage(t, map[string]string{
|
|
ManifestFilename: `{
|
|
"schema_version":1,"id":"hash-plugin","name":"Hash","version":"1",
|
|
"contributions":[{"id":"hash-page","label":"Hash","location":"sidebar","entry":"web/index.html"}]
|
|
}`,
|
|
"web/index.html": "ok",
|
|
})
|
|
if _, err := manager.Install(bytes.NewReader(archive), strings.Repeat("0", 64)); err == nil {
|
|
t.Fatal("Install accepted incorrect SHA-256")
|
|
}
|
|
}
|
|
|
|
func testPackage(t *testing.T, files map[string]string) []byte {
|
|
t.Helper()
|
|
var output bytes.Buffer
|
|
writer := zip.NewWriter(&output)
|
|
for name, content := range files {
|
|
entry, err := writer.Create(name)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
if _, err := entry.Write([]byte(content)); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
}
|
|
if err := writer.Close(); err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
return output.Bytes()
|
|
}
|