153 lines
3.9 KiB
Go
153 lines
3.9 KiB
Go
package main
|
|
|
|
import (
|
|
"archive/zip"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"os"
|
|
"path/filepath"
|
|
"strings"
|
|
)
|
|
|
|
type Author struct {
|
|
Login string `json:"login"`
|
|
ID int `json:"id"`
|
|
NodeID string `json:"node_id"`
|
|
AvatarURL string `json:"avatar_url"`
|
|
GravatarID string `json:"gravatar_id"`
|
|
URL string `json:"url"`
|
|
HTMLURL string `json:"html_url"`
|
|
FollowersURL string `json:"followers_url"`
|
|
FollowingURL string `json:"following_url"`
|
|
GistsURL string `json:"gists_url"`
|
|
StarredURL string `json:"starred_url"`
|
|
SubscriptionsURL string `json:"subscriptions_url"`
|
|
OrganizationsURL string `json:"organizations_url"`
|
|
ReposURL string `json:"repos_url"`
|
|
EventsURL string `json:"events_url"`
|
|
ReceivedEventsURL string `json:"received_events_url"`
|
|
Type string `json:"type"`
|
|
SiteAdmin bool `json:"site_admin"`
|
|
}
|
|
|
|
// Define a struct for the Release
|
|
type Release struct {
|
|
URL string `json:"url"`
|
|
AssetsURL string `json:"assets_url"`
|
|
UploadURL string `json:"upload_url"`
|
|
HTMLURL string `json:"html_url"`
|
|
ID int `json:"id"`
|
|
Author Author `json:"author"`
|
|
NodeID string `json:"node_id"`
|
|
TagName string `json:"tag_name"`
|
|
TargetCommitish string `json:"target_commitish"`
|
|
Name string `json:"name"`
|
|
Draft bool `json:"draft"`
|
|
Prerelease bool `json:"prerelease"`
|
|
CreatedAt string `json:"created_at"`
|
|
PublishedAt string `json:"published_at"`
|
|
Assets []interface{} `json:"assets"` // Assuming assets is an array of unknown types
|
|
TarballURL string `json:"tarball_url"`
|
|
ZipballURL string `json:"zipball_url"`
|
|
Body string `json:"body"`
|
|
}
|
|
|
|
func Unzip(src, dest string) error {
|
|
r, err := zip.OpenReader(src)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
if err := r.Close(); err != nil {
|
|
panic(err)
|
|
}
|
|
}()
|
|
|
|
os.MkdirAll(dest, 0755)
|
|
|
|
// Closure to address file descriptors issue with all the deferred .Close() methods
|
|
extractAndWriteFile := func(f *zip.File) error {
|
|
rc, err := f.Open()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
if err := rc.Close(); err != nil {
|
|
panic(err)
|
|
}
|
|
}()
|
|
|
|
path := filepath.Join(dest, f.Name)
|
|
|
|
// Check for ZipSlip (Directory traversal)
|
|
if !strings.HasPrefix(path, filepath.Clean(dest)+string(os.PathSeparator)) {
|
|
return fmt.Errorf("illegal file path: %s", path)
|
|
}
|
|
|
|
if f.FileInfo().IsDir() {
|
|
os.MkdirAll(path, f.Mode())
|
|
} else {
|
|
os.MkdirAll(filepath.Dir(path), f.Mode())
|
|
f, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, f.Mode())
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer func() {
|
|
if err := f.Close(); err != nil {
|
|
panic(err)
|
|
}
|
|
}()
|
|
|
|
_, err = io.Copy(f, rc)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
for _, f := range r.File {
|
|
err := extractAndWriteFile(f)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func getLatestVersion(repoU string) (string, error) {
|
|
jsonBody := []byte("")
|
|
res := sendRequest(http.MethodGet, fmt.Sprintf("https://api.github.com/repos%s/releases/latest", repoU), jsonBody)
|
|
var release Release
|
|
err := json.Unmarshal([]byte(string(res.Body)), &release)
|
|
if err != nil || res.StatusCode != 200 {
|
|
return "", err
|
|
}
|
|
return release.TagName, nil
|
|
}
|
|
|
|
func downloadPackage(repoU, tag string) error {
|
|
resp, err := http.Get(fmt.Sprintf("https://github.com/%s/archive/refs/tags/%s.zip", strings.Trim(repoU, "/"), tag))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
out, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil {
|
|
fmt.Println("Error reading body:", err)
|
|
return err
|
|
}
|
|
|
|
err = ioutil.WriteFile("temp.zip", out, 0644)
|
|
if err != nil {
|
|
fmt.Println("Error writing file:", err)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|