From b0a57eed59130fa648e221657a786e16d011f305 Mon Sep 17 00:00:00 2001 From: Compey Date: Fri, 25 Nov 2022 20:13:14 +0530 Subject: [PATCH] init: core structure & RootFS download mechanism --- go.mod | 17 +++++ go.sum | 37 ++++++++++ lib/checkers/verifySignature.go | 76 +++++++++++++++++++ lib/core/core.go | 125 ++++++++++++++++++++++++++++++++ src/main.go | 97 +++++++++++++++++++++++++ 5 files changed, 352 insertions(+) create mode 100644 go.mod create mode 100644 go.sum create mode 100644 lib/checkers/verifySignature.go create mode 100644 lib/core/core.go create mode 100644 src/main.go diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..8fad0e4 --- /dev/null +++ b/go.mod @@ -0,0 +1,17 @@ +module github.com/CompeyDev/wsl-archlinux-manager + +go 1.19 + +require ( + github.com/briandowns/spinner v1.19.0 + github.com/cavaliergopher/grab/v3 v3.0.1 + github.com/gookit/color v1.5.2 +) + +require ( + github.com/fatih/color v1.10.0 // indirect + github.com/mattn/go-colorable v0.1.8 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect + github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 // indirect + golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 // indirect +) diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..d7686fb --- /dev/null +++ b/go.sum @@ -0,0 +1,37 @@ +github.com/briandowns/spinner v1.19.0 h1:s8aq38H+Qju89yhp89b4iIiMzMm8YN3p6vGpwyh/a8E= +github.com/briandowns/spinner v1.19.0/go.mod h1:mQak9GHqbspjC/5iUx3qMlIho8xBS/ppAL/hX5SmPJU= +github.com/cavaliergopher/grab/v3 v3.0.1 h1:4z7TkBfmPjmLAAmkkAZNX/6QJ1nNFdv3SdIHXju0Fr4= +github.com/cavaliergopher/grab/v3 v3.0.1/go.mod h1:1U/KNnD+Ft6JJiYoYBAimKH2XrYptb8Kl3DFGmsjpq4= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= +github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg= +github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM= +github.com/gookit/color v1.5.2 h1:uLnfXcaFjlrDnQDT+NCBcfhrXqYTx/rcCa6xn01Y8yI= +github.com/gookit/color v1.5.2/go.mod h1:w8h4bGiHeeBpvQVePTutdbERIUf3oJE5lZ8HM0UgXyg= +github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= +github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8= +github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc= +github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= +github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= +github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0 h1:pSgiaMZlXftHpm5L7V1+rVB+AZJydKsMxsQBIJw4PKk= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778 h1:QldyIu/L63oPpyvQmHgvgickp1Yw510KJOqX7H24mg8= +github.com/xo/terminfo v0.0.0-20210125001918-ca9a967f8778/go.mod h1:2MuV+tbUrU1zIOPMxZ5EncGwgmMJsa+9ucAQZXxsObs= +golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6 h1:nonptSpoQ4vQjyraW20DXPAglgQfVnM9ZC6MmNLMR60= +golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/lib/checkers/verifySignature.go b/lib/checkers/verifySignature.go new file mode 100644 index 0000000..f2e725b --- /dev/null +++ b/lib/checkers/verifySignature.go @@ -0,0 +1,76 @@ +package checkers + +import ( + "fmt" + "os" + "os/exec" + "strings" + "time" + + "github.com/briandowns/spinner" + "github.com/cavaliergopher/grab/v3" + "github.com/gookit/color" +) + +// TODO: +func VerifySignature(mirrorUrl string) { + bar := spinner.New(spinner.CharSets[14], 100*time.Millisecond) + bar.Prefix = " " + bar.Suffix = " Verifying signature of RootFS..." + bar.Start() + + success, _ := pullSig(mirrorUrl) + + if !success { + color.Red.Println("\r ❎ Failed to download signature of RootFS. Refusing to continue.") + os.Exit(1) + } + + userHomeDir, homeDirErr := os.UserHomeDir() + + if homeDirErr != nil { + color.Red.Println("\r ❎ Failed to fetch installation directory, cannot verify authenticity of RootFS.") + os.Exit(1) + } + cwd, dirErr := os.Getwd() + + if dirErr != nil { + color.Red.Println("\r ❎ Failed to fetch installation directory, cannot verify authenticity of RootFS.") + os.Exit(1) + } + + unixWd := fmt.Sprintf("/mnt/c/%s", strings.ReplaceAll(strings.Split(userHomeDir, `C:\`)[1], `\`, "/")) + strings.ReplaceAll(strings.Split(cwd, userHomeDir)[1], `\`, "/") + + // does not work? + + getAuthenticity, authenticityErr := exec.Command("powershell.exe", fmt.Sprintf(`wsl bash -c "cd %s && gpg --keyserver-options auto-key-retrieve --verify archlinux-bootstrap-2022.11.01-x86_64.tar.gz.sig"`, unixWd)).Output() + + if authenticityErr != nil { + color.Red.Println("\r ❎ Failed to verify authenticity of RootFS. Refusing to continue.") + os.Exit(1) + } + + color.Green.Println("\r ✅ Successfully matched checksums and verified authenticity!") + bar.Stop() + + fmt.Println(strings.Trim(string(getAuthenticity), "\n\r")) +} + +func pullSig(url string) (isSuccessful bool, error error) { + bar := spinner.New(spinner.CharSets[14], 100*time.Millisecond) + bar.Prefix = " " + bar.Suffix = " Downloading Signature..." + + var version = strings.Split(strings.Split(url, "iso/")[1], "/")[0] + var structuredUrl = fmt.Sprintf("%s/archlinux-bootstrap-%s-x86_64.tar.gz.sig", url, version) + res, err := grab.Get(".", structuredUrl) + + if err != nil { + color.Red.Println("\r ❎ Failed to download Signature.") + return false, err + } + + color.Green.Println("\r ✅ Downloaded Signature", res.Filename) + + return true, nil +} diff --git a/lib/core/core.go b/lib/core/core.go new file mode 100644 index 0000000..23190e5 --- /dev/null +++ b/lib/core/core.go @@ -0,0 +1,125 @@ +package core + +import ( + "fmt" + "io" + "net/http" + "os" + "strings" + "time" + + "encoding/json" + + "github.com/CompeyDev/wsl-archlinux-manager/lib/checkers" + "github.com/briandowns/spinner" + "github.com/cavaliergopher/grab/v3" + "github.com/gookit/color" +) + +// TODO: + +func Build() { + fmt.Println("🔃 Setting up RootFS...") + bar := spinner.New(spinner.CharSets[14], 100*time.Millisecond) + bar.Prefix = " " + bar.Suffix = " Determining the fastest mirror..." + bar.Start() + userLocation, err := http.Get("http://ip-api.com/json/") + if err != nil { + print(err) + } + defer userLocation.Body.Close() + body, reqErr := io.ReadAll(userLocation.Body) + + if reqErr != nil { + color.Red.Println("\r ❎ An internal error occurred when attempting to pull the RootFS. This is probably a bug; you might want to report this.") + bar.Stop() + os.Exit(1) + } + + var resStruct struct { + Status string + Country string + CountryCode string + Region string + RegionName string + City string + Zip string + Lat float64 + Lon float64 + Timezone string + Isp string + Org string + As string + Query string + } + + parseErr := json.Unmarshal([]byte(body), &resStruct) + + if parseErr != nil { + color.Red.Println("\r ❎ Failed to parse response body! This is a probably a bug; you might want to report this.") + bar.Stop() + os.Exit(1) + } + mirror := getMirror(resStruct.Country) + bar.Suffix = fmt.Sprintf(" Using mirror %s...", mirror) + time.Sleep(time.Second * 5) + bar.Stop() + isSuccessful_1, _ := pullArchive(mirror) + + if !isSuccessful_1 { + color.Yellow.Println("\r ❎ Attempt #1 to pull RootFS failed, trying again with Worldwide...") + + bar.Suffix = " Attempt #1 to pull RootFS failed, trying again with Worldwide..." + + bar.Start() + + globalMirror := getMirror("Worldwide") + isSuccessful_2, _ := pullArchive(globalMirror) + + if !isSuccessful_2 { + color.Red.Println("\r ❎ Attempt #2 to pull RootFS failed. Please try again.") + bar.Stop() + os.Exit(1) + } else { + checkers.VerifySignature(globalMirror) + } + + } else { + checkers.VerifySignature(mirror) + } + +} + +func getMirror(country string) string { + resp, err := http.Get("https://archlinux.org/download/") + if err != nil { + color.Red.Println("❎ Failed to download RootFS.") + } + defer resp.Body.Close() + body, err := io.ReadAll(resp.Body) + if err != nil { + color.Red.Println("❎ An internal error occurred when attempting to pull the RootFS. This is probably a bug; you might want to report this.") + } + + mirrorLink := strings.Split(strings.Split(strings.Split(strings.Split(strings.Split(strings.Split(string(body), fmt.Sprintf(`title="%s"`, country))[1], `title="Download from`)[0], fmt.Sprintf(`> %s`, country))[1], `