package mockupdateserver import ( "archive/zip" "bytes" "crypto/sha256" "encoding/hex" "encoding/json" "net/http" "runtime" "github.com/Eriyc/rules_wails/pkg/wails3kit/updates" ) const BearerToken = "test-token" func NewHandler() http.Handler { mux := http.NewServeMux() mux.HandleFunc("/manifest.json", manifest) mux.HandleFunc("/artifacts/updater-example_0.2.0.zip", artifact) mux.HandleFunc("/artifacts/updater-example_0.2.0.zip.sha256", checksum) return http.HandlerFunc(func(writer http.ResponseWriter, request *http.Request) { if request.Header.Get("Authorization") != "Bearer "+BearerToken { http.Error(writer, "unauthorized", http.StatusUnauthorized) return } mux.ServeHTTP(writer, request) }) } func manifest(writer http.ResponseWriter, request *http.Request) { _, checksumValue, err := archiveWithChecksum() if err != nil { http.Error(writer, err.Error(), http.StatusInternalServerError) return } document := map[string]any{ "schemaVersion": 1, "productID": "com.eriyc.updater-example", "releases": []any{ map[string]any{ "id": "0.2.0", "version": "0.2.0", "channel": "stable", "publishedAt": "2026-03-01T03:10:56Z", "notesMarkdown": "Adds a staged resource update and relaunch flow.", "artifacts": []any{ map[string]any{ "os": runtime.GOOS, "arch": runtime.GOARCH, "kind": updates.ArtifactKindBundleArchive, "format": updates.ArtifactFormatZip, "url": baseURL(request) + "/artifacts/updater-example_0.2.0.zip", "sha256": checksumValue, }, }, }, }, } writer.Header().Set("Content-Type", "application/json") _ = json.NewEncoder(writer).Encode(document) } func artifact(writer http.ResponseWriter, _ *http.Request) { archive, err := buildArchive() if err != nil { http.Error(writer, err.Error(), http.StatusInternalServerError) return } writer.Header().Set("Content-Type", "application/zip") _, _ = writer.Write(archive) } func checksum(writer http.ResponseWriter, _ *http.Request) { _, checksumValue, err := archiveWithChecksum() if err != nil { http.Error(writer, err.Error(), http.StatusInternalServerError) return } _, _ = writer.Write([]byte(checksumValue + " updater-example_0.2.0.zip")) } func buildArchive() ([]byte, error) { buffer := bytes.NewBuffer(nil) archive := zip.NewWriter(buffer) bundleFile, err := archive.Create("bundle.json") if err != nil { return nil, err } bundle := updates.BundleManifest{ SchemaVersion: 1, EntryPoint: entryPoint(), Files: []updates.BundleFile{ {Path: resourcePath(), Mode: "0644"}, }, } if err := json.NewEncoder(bundleFile).Encode(bundle); err != nil { return nil, err } resourceFile, err := archive.Create(resourcePath()) if err != nil { return nil, err } if _, err := resourceFile.Write([]byte(`{"version":"0.2.0","status":"downloaded"}`)); err != nil { return nil, err } if err := archive.Close(); err != nil { return nil, err } return buffer.Bytes(), nil } func archiveWithChecksum() ([]byte, string, error) { archive, err := buildArchive() if err != nil { return nil, "", err } sum := sha256.Sum256(archive) return archive, hex.EncodeToString(sum[:]), nil } func entryPoint() string { if runtime.GOOS == "darwin" { return "Contents/MacOS/updater-example" } if runtime.GOOS == "windows" { return "updater-example.exe" } return "updater-example" } func resourcePath() string { if runtime.GOOS == "darwin" { return "Contents/Resources/update.json" } return "resources/update.json" } func baseURL(request *http.Request) string { scheme := "http" if request.TLS != nil { scheme = "https" } return scheme + "://" + request.Host }