Files
WingetRepoServer/packages.go

276 lines
7.3 KiB
Go

package main
import (
"crypto/sha256"
"database/sql"
"fmt"
"log/slog"
"net/http"
"os"
"os/exec"
"encoding/hex"
"regexp"
"runtime"
"strconv"
"strings"
"html/template"
_ "modernc.org/sqlite"
)
type jsonStruct struct {
Identifier string
Version string
Type string
Location string
Checksum string
Url string
}
// packages struct represents a package with its details.
type packages struct {
Id string
Name string
Version string
ExtraCommand *string
Tag string
Warning bool
Element *elements
}
// ConvertStringsToPackage converts a slice of strings to a packages struct.
// It returns an error if the input slice does not have exactly 6 elements or if the Warning value cannot be parsed as a boolean.
func ConvertStringsToPackage(strs []string) (packages, error) {
var pkg packages
if len(strs) != 6 {
return pkg, fmt.Errorf("input slice must have exactly 6 elements")
}
warning, err := strconv.ParseBool(strs[5])
if err != nil {
return pkg, fmt.Errorf("error parsing Warning value: %s", err)
}
return packages{
Id: strs[0],
Name: strs[1],
Version: strs[2],
ExtraCommand: &strs[3],
Tag: strs[4],
Warning: warning,
}, nil
}
// elements struct represents the elements of a the webpage.
type elements struct {
Title string
Header string
Help string
Packagename string
Packageversion string
Allow string
Warning string
Explain string
}
// DownloadElements struct represents the elements to be downloaded.
type DownloadElements struct {
ID string
Version *string
Counter int
}
// Printer struct is an empty struct. Its purpose is not clear from the provided code.
type Printer struct{}
func getDataFromFile(path string) jsonStruct {
slog.Debug(regexp.MustCompile(`\.\w+$`).FindString(path))
switch extention := regexp.MustCompile(`\.\w+$`).FindString(path); extention {
case ".exe":
return getParamsFromExif(path)
case ".msi":
return getParamsFromMsi(path)
}
return jsonStruct{}
}
// getParamsFromExif extracts EXIF parameters from a file at the given path using the exiftool command.
// It returns a map where the keys are the EXIF parameter names and the values are the corresponding EXIF parameter values.
func getParamsFromExif(path string) jsonStruct {
exiftool := os.Getenv("exiftool")
e, _ := exec.Command(exiftool, "-f", path).Output()
data := splitData(e)
data["Extention"] = data["File Type Extension"]
data["Path"] = path
return createObject(data)
}
func splitData(commandOutput []byte) map[string]string {
tags := make(map[string]string)
spliter := regexp.MustCompile(`\r?\n`)
crop := spliter.Split(string(commandOutput), -1)
head := regexp.MustCompile(`\t|(\s+:\s?)`)
for _, c := range crop {
if len(c) > 1 {
data := head.Split(c, -1)
slog.Debug("My Raw Data: ", c)
tags[data[0]] = data[1]
}
}
slog.Debug(fmt.Sprint(tags))
return tags
}
func getParamsFromMsi(path string) jsonStruct {
if runtime.GOOS == "windows" {
// orca :=os.Getenv("orca")
// err:=os.Mkdir("tmpdir/extract", os.ModeAppend)
// if err != nil {
// log.Println("There was an error", err)
// }
// run:=exec.Command(orca, "-q", "-s", path, "-x", "tmpdir/extract")
// run.
} else {
msiinfo := os.Getenv("msiinfo")
e, _ := exec.Command(msiinfo, "export", path, "Property").Output()
data := splitData(e)
data["Extention"] = "msi"
data["Path"] = path
return createObject(data)
}
return jsonStruct{}
}
func getVendor(data map[string]string) string {
for key, val := range data {
switch key {
case "Author":
return strings.ToLower(strings.Replace(val," ","",-1))
case "Company Name":
return strings.ToLower(strings.Replace(val," ","",-1))
case "Publisher":
return strings.ToLower(strings.Replace(val," ","",-1))
}
}
return ""
}
func getProgram(data map[string]string) string {
for key, val := range data {
switch key {
case "Title":
return strings.ToLower(strings.Replace(val," ","",-1))
case "Product Name":
return strings.ToLower(strings.Replace(val," ","",-1))
case "Subject":
return strings.ToLower(strings.Replace(val," ","",-1))
}
}
return ""
}
func getVersion(data map[string]string) string {
replacer:=regexp.MustCompile(`[, ]+`)
for key, val := range data {
switch key {
case "Version":
return replacer.ReplaceAllString(val,".")
case "Product Version":
return replacer.ReplaceAllString(val,".")
case "ProductVersion":
return replacer.ReplaceAllString(val,".")
case "File Version":
return replacer.ReplaceAllString(val,".")
case "FileVersion":
return replacer.ReplaceAllString(val,".")
}
}
return ""
}
func detectProblems(data map[string]string) bool {
exe, err := data["Extention"]
mime, _ := data["MIME Type"]
if !err || (exe == "exe" && !(mime == "application/octet-stream")) {
return false
}
if (exe != "msi" && exe != "exe" && exe != "zip") {
return false
}
return true
}
func getInstallerType(data map[string]string) string {
for _, val := range data {
if val == "msi" {
return "msi"
}
if strings.Contains(strings.ToLower(val), "nullsoft") {
return "nullsoft"
}
if strings.Contains(strings.ToLower(val), "inno") {
return "inno"
}
}
return "exe"
}
func moveToNewLocationAndName(data map[string]string) string {
newLoc := os.Getenv("installationDirectory") + "/"
newFileLoc := getVendor(data) + "." + getProgram(data) + ".v."
newFileLoc += getVersion(data) + "."
newFileLoc += data["Extention"]
newLoc += newFileLoc
file, _ := os.OpenFile(newLoc, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
defer file.Close()
oldFile, _ := os.ReadFile(data["Path"])
file.Write(oldFile)
return newFileLoc
}
func createObject(object map[string]string) jsonStruct {
if detectProblems(object) {
prop := jsonStruct{
Identifier: getVendor(object) + "." + getProgram(object),
Version: getVersion(object),
Type: getInstallerType(object),
}
loc, _ := os.ReadFile(object["Directory"] + "/" + object["File Name"])
chksum:=sha256.Sum256(loc)
prop.Checksum = hex.EncodeToString(chksum[:])
lc := moveToNewLocationAndName(object)
prop.Url = os.Getenv("uri") + lc
prop.Location = os.Getenv("installationDirectory") + "/" + lc
newJson(prop)
return prop
}
return jsonStruct{}
}
func newJson(object jsonStruct) {
sqldb, err := sql.Open("sqlite", "file:progs.db")
if err != nil {
slog.Error(err.Error())
}
sqldb.Exec("INSERT OR IGNORE INTO newapps(identifier, version, type, location, checksum, url) values (?,?,?,?,?,?)", object.Identifier, object.Version, object.Type, object.Location, object.Checksum, object.Url)
}
func getJson(sqldb *sql.DB) http.Handler {
return http.HandlerFunc(func(res http.ResponseWriter, req *http.Request) {
quer := generateSQL("newapps", []string{"identifier", "version", "type", "location", "checksum", "url"}) + " ORDER BY ROWID DESC LIMIT 1"
data := sqldb.QueryRow(quer)
jsonelement := jsonStruct{}
err := data.Scan(&jsonelement.Identifier, &jsonelement.Version, &jsonelement.Type, &jsonelement.Location, &jsonelement.Checksum, &jsonelement.Url)
if err != nil {
slog.Error(err.Error())
}
temp,err:=template.ParseFiles("html/lastob.json")
if err != nil {
slog.Error(err.Error())
}
err=temp.ExecuteTemplate(res, "main", jsonelement)
if err != nil {
slog.Error(err.Error())
}
})
}