package main import ( "archive/zip" "context" "crypto/rand" "database/sql" "encoding/base64" "fmt" _ "github.com/mattn/go-sqlite3" "golang.org/x/crypto/bcrypt" "io" "net/http" "os" "path/filepath" "github.com/google/go-github/github" ) func GenerateRandomBytes(n int) ([]byte, error) { b := make([]byte, n) _, err := rand.Read(b) if err != nil { return nil, err } return b, nil } // GenerateRandomString returns a URL-safe, base64 encoded // securely generated random string. func GenerateRandomString(s int) (string, error) { b, err := GenerateRandomBytes(s) return base64.URLEncoding.EncodeToString(b), err } func Setup() { defer LockFile() // Create users SQLite3 file fmt.Println("Initializing the database") os.MkdirAll("assets/config/", 0755) os.Mkdir("podcasts", 0755) os.Create("assets/config/users.db") db, err := sql.Open("sqlite3", "assets/config/users.db") if err != nil { fmt.Println("Problem opening database file! %v", err) } _, err = db.Exec("CREATE TABLE IF NOT EXISTS `users` ( `id` INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT UNIQUE, `username` TEXT UNIQUE, `hash` TEXT, `realname` TEXT, `email` TEXT, `permissions` INTEGER )") if err != nil { fmt.Println("Problem creating database! %v", err) } text, err := GenerateRandomString(12) if err != nil { fmt.Println("Error randomly generating password", err) } fmt.Println("Admin password: ", text) hash, err := bcrypt.GenerateFromPassword([]byte(text), 4) if err != nil { fmt.Println("Error generating hash", err) } if bcrypt.CompareHashAndPassword(hash, []byte(text)) == nil { fmt.Println("Password hashed") } _, err = db.Exec("INSERT INTO users(id,username,hash,realname,email,permissions) VALUES (0,'admin','" + string(hash) + "','Administrator','admin@localhost',2)") if err != nil { fmt.Println("Problem creating database! %v", err) } defer db.Close() // Download web assets fmt.Println("Downloading web assets") os.MkdirAll("assets/web/", 0755) client := github.NewClient(nil).Repositories ctx := context.Background() res, _, err := client.GetLatestRelease(ctx, "gmemstr", "pogo-vue") if err != nil { fmt.Println("Problem getting latest pogo-vue release! %v", err) } for i := 0; i < len(res.Assets); i++ { if res.Assets[i].GetName() == "webassets.zip" { download := res.Assets[i] fmt.Println("Release found: %v", download.GetBrowserDownloadURL()) tmpfile, err := os.Create(download.GetName()) if err != nil { fmt.Println("Problem creating webassets file! %v", err) } var j io.Reader = (*os.File)(tmpfile) defer tmpfile.Close() j, s, err := client.DownloadReleaseAsset(ctx, "gmemstr", "pogo-vue", download.GetID()) if err != nil { fmt.Println("Problem downloading webassets! %v", err) } if j == nil { resp, err := http.Get(s) defer resp.Body.Close() _, err = io.Copy(tmpfile, resp.Body) if err != nil { fmt.Println("Problem creating webassets file! %v", err) } fmt.Println("Download complete\nUnzipping") err = Unzip(download.GetName(), "assets/web") defer os.Remove(download.GetName()) // Remove zip } else { fmt.Println("Unexpected error, please open an issue!") } } } } func LockFile() { lock, err := os.Create(".lock") if err != nil { fmt.Println("Error: %v", err) } lock.Write([]byte("This file left intentionally empty")) defer lock.Close() } // From https://stackoverflow.com/questions/20357223/easy-way-to-unzip-file-with-golang 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) 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 }