feat(updates): include SHA256 from sidecar files in Joomla updates.xml
Read the .sha256 sidecar attachment (generated by GenerateReleaseChecksums) and populate the <sha256> element in the update XML. This matches the pattern used by Akeeba (sha512) and JCE (sha256 + sha384 + sha512) for integrity verification. Also fix zip attachment filter to skip .sha256 sidecar files when selecting the download URL. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,12 +7,14 @@ import (
|
||||
"context"
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/db"
|
||||
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/licenses"
|
||||
repo_model "code.mokoconsulting.tech/MokoConsulting/MokoGitea/models/repo"
|
||||
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/storage"
|
||||
"code.mokoconsulting.tech/MokoConsulting/MokoGitea/modules/setting"
|
||||
)
|
||||
|
||||
@@ -246,14 +248,25 @@ func GenerateJoomlaXML(ctx context.Context, repo *repo_model.Repository, require
|
||||
continue
|
||||
}
|
||||
|
||||
// Find the first .zip attachment as the download URL.
|
||||
var downloadURL string
|
||||
// Find the first .zip attachment as the download URL, and its SHA256 sidecar.
|
||||
var downloadURL, sha256Hash string
|
||||
var zipName string
|
||||
for _, att := range rel.Attachments {
|
||||
if strings.HasSuffix(strings.ToLower(att.Name), ".zip") {
|
||||
if strings.HasSuffix(strings.ToLower(att.Name), ".zip") && !strings.HasSuffix(att.Name, ".sha256") {
|
||||
downloadURL = fmt.Sprintf("%s/releases/download/%s/%s", repoLink, rel.TagName, att.Name)
|
||||
zipName = att.Name
|
||||
break
|
||||
}
|
||||
}
|
||||
// Look for the SHA256 sidecar file.
|
||||
if zipName != "" {
|
||||
for _, att := range rel.Attachments {
|
||||
if att.Name == zipName+".sha256" {
|
||||
sha256Hash = readSHA256FromSidecar(ctx, att)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
// Fall back to the release tag archive if no zip attachment.
|
||||
if downloadURL == "" {
|
||||
downloadURL = fmt.Sprintf("%s/archive/%s.zip", repoLink, rel.TagName)
|
||||
@@ -302,6 +315,7 @@ func GenerateJoomlaXML(ctx context.Context, repo *repo_model.Repository, require
|
||||
Maintainer: maintainer,
|
||||
MaintainerURL: maintainerURL,
|
||||
PHPMinimum: phpMinimum,
|
||||
SHA256: sha256Hash,
|
||||
TargetPlatform: xmlTargetPlat{
|
||||
Name: "joomla",
|
||||
Version: targetVersion,
|
||||
@@ -354,3 +368,25 @@ func channelSuffix(channel string) string {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
// readSHA256FromSidecar reads the SHA256 hash from a .sha256 sidecar attachment.
|
||||
// The sidecar format is: "<hex> <filename>\n"
|
||||
func readSHA256FromSidecar(_ context.Context, att *repo_model.Attachment) string {
|
||||
fr, err := storage.Attachments.Open(att.RelativePath())
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
defer fr.Close()
|
||||
|
||||
data, err := io.ReadAll(io.LimitReader(fr, 256))
|
||||
if err != nil {
|
||||
return ""
|
||||
}
|
||||
|
||||
content := strings.TrimSpace(string(data))
|
||||
// Format: "hexhash filename"
|
||||
if idx := strings.Index(content, " "); idx > 0 {
|
||||
return content[:idx]
|
||||
}
|
||||
return content
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user