package main import ( "crypto/sha256" "database/sql" "encoding/hex" "fmt" "html/template" "log/slog" "net/http" "os" "os/exec" "regexp" "runtime" "strconv" "strings" _ "modernc.org/sqlite" ) type jsonStruct struct { Vendor string Package 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 } type yaml struct { PID string VER string TYPE string URL string HASH string PUB string NAME string INIT string LOCATION string FILELOCATION string } // 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 "Manufacturer": 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 "ProductName": 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{ Vendor: getVendor(object), Package: 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(vendor, package, version, type, location, checksum, url) values (?,?,?,?,?,?,?)", object.Vendor, object.Package, 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{"vendor", "package", "version", "type", "location", "checksum", "url"}) + " ORDER BY ROWID DESC LIMIT 1" data := sqldb.QueryRow(quer) jsonelement := jsonStruct{} err := data.Scan(&jsonelement.Vendor, &jsonelement.Package, &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()) } }) }