package main import ( "context" "encoding/json" "fmt" "io" "net/http" "strings" "time" ) // releaseURL ist der Endpunkt des Versionschecks. Er wird nur abgefragt, // wenn portal.update_check ausdrücklich eingeschaltet ist (Default: aus). const releaseURL = "https://git.ravensburg.dev/api/v1/repos/cabele/opnsense-portal/releases/latest" // checkForUpdate fragt read-only die neueste Version ab und liefert einen // Hinweistext, falls sich die veröffentlichte Version unterscheidet. // Jeder Fehler führt zu einer leeren Rückgabe — der Check darf den Start // unter keinen Umständen stören. func checkForUpdate(ctx context.Context, enabled bool, url, current string, client *http.Client) string { if !enabled { return "" } if client == nil { client = &http.Client{Timeout: 5 * time.Second} } ctx, cancel := context.WithTimeout(ctx, 5*time.Second) defer cancel() req, err := http.NewRequestWithContext(ctx, http.MethodGet, url, nil) if err != nil { return "" } req.Header.Set("Accept", "application/json") req.Header.Set("User-Agent", "vpnportal/"+current) resp, err := client.Do(req) if err != nil { return "" } defer resp.Body.Close() if resp.StatusCode != http.StatusOK { return "" } var release struct { TagName string `json:"tag_name"` } raw, err := io.ReadAll(io.LimitReader(resp.Body, 1<<20)) if err != nil || json.Unmarshal(raw, &release) != nil { return "" } // Reiner Gleichheitsvergleich, keine Semver-Ordnung: das Portal meldet nur, // dass sich die veröffentlichte Version unterscheidet, und urteilt nicht // selbst über Versionsordnungen. latest := strings.TrimPrefix(strings.TrimSpace(release.TagName), "v") if latest == "" || latest == strings.TrimPrefix(strings.TrimSpace(current), "v") { return "" } return fmt.Sprintf("Hinweis: Version %s ist verfügbar (installiert: %s).", latest, current) }