From 9031f22a8e380616673c3d15b40c1cbe126597d7 Mon Sep 17 00:00:00 2001 From: gmemstr Date: Sun, 3 Dec 2017 16:26:09 -0800 Subject: [PATCH 01/21] Beginning work on setup process --- setup.go | 20 ++++++++++++++++++++ webserver.go | 9 +++++++++ 2 files changed, 29 insertions(+) create mode 100644 setup.go diff --git a/setup.go b/setup.go new file mode 100644 index 0000000..b2e453f --- /dev/null +++ b/setup.go @@ -0,0 +1,20 @@ +package main + +import ( + "database/sql" + "fmt" + "io" + "net/http" + "os" + + _ "github.com/mattn/go-sqlite3" +) + +func setup() { + fmt.Println("Initializing the database") + os.MkdirAll("assets/config/", 0755) +} + +func Unzip(file string, dest string) { + +} diff --git a/webserver.go b/webserver.go index 5d3fc2e..0c15df5 100644 --- a/webserver.go +++ b/webserver.go @@ -10,12 +10,21 @@ import ( "fmt" "log" "net/http" + "os" "github.com/gmemstr/pogo/router" ) // Main function that defines routes func main() { + // Check if this is the first time Pogo has been run + // with a lockfile + + if _, err := os.Stat("run.lockfile"); os.IsNotExist(err) { + fmt.Println("This looks like your first time running Pogo,\ngive me a second to set myself up.") + setup() + } + // Start the watch() function in generate_rss.go, which // watches for file changes and regenerates the feed go watch() From 7ca122c02bfe0be0409bbd14d83ed819d147bed1 Mon Sep 17 00:00:00 2001 From: gmemstr Date: Sun, 3 Dec 2017 19:30:38 -0800 Subject: [PATCH 02/21] New setup process when lockfile not found Automatically creates the SQLite3 databse and *will* download the "webassets.zip" file that will be uploaded alongside the binaries containing the frontend files. --- setup.go | 135 +++++++++++++++++++++++++++++++++++++++++++++++++-- webserver.go | 2 +- 2 files changed, 132 insertions(+), 5 deletions(-) diff --git a/setup.go b/setup.go index b2e453f..ce9bcd5 100644 --- a/setup.go +++ b/setup.go @@ -1,20 +1,147 @@ package main import ( + "archive/zip" + "context" "database/sql" "fmt" + _ "github.com/mattn/go-sqlite3" "io" "net/http" "os" + "path/filepath" - _ "github.com/mattn/go-sqlite3" + "github.com/google/go-github/github" ) -func setup() { +func Setup() { + defer LockFile() + // Create users SQLite3 file fmt.Println("Initializing the database") + os.MkdirAll("assets/config/", 0755) + os.Create("assets/config/users.db") + + db, err := sql.Open("sqlite3", "assets/config/users.db") + if err != nil { + fmt.Sprintf("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.Sprintf("Problem creating database! %v", err) + } + + 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") + if err != nil { + fmt.Sprintf("Problem creating database! %v", err) + } + for i := 0; i < len(res.Assets); i++ { + if res.Assets[i].GetName() == "webassets.zip" { + download := res.Assets[i] + fmt.Sprintf("Release found: %v", download.GetBrowserDownloadURL()) + tmpfile, err := os.Create(download.GetName()) + if err != nil { + fmt.Sprintf("Problem creating webassets file! %v", err) + } + var j io.Reader = (*os.File)(tmpfile) + defer tmpfile.Close() + + j, s, err := client.DownloadReleaseAsset(ctx, "gmemstr", "pogo", download.GetID()) + if err != nil { + fmt.Sprintf("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.Sprintf("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 Unzip(file string, dest string) { - +func LockFile() { + lock, err := os.Create("run.lockfile") + if err != nil { + fmt.Println("Error: %v", err) + } + lock.Write([]byte("# You can leave this file emtpy, it simply tells Pogo you're set up!")) + 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 } diff --git a/webserver.go b/webserver.go index 0c15df5..cee6f52 100644 --- a/webserver.go +++ b/webserver.go @@ -22,7 +22,7 @@ func main() { if _, err := os.Stat("run.lockfile"); os.IsNotExist(err) { fmt.Println("This looks like your first time running Pogo,\ngive me a second to set myself up.") - setup() + Setup() } // Start the watch() function in generate_rss.go, which From beab199ad2b148cdc39ef6cd6ac9df4df836a37a Mon Sep 17 00:00:00 2001 From: gmemstr Date: Sun, 3 Dec 2017 19:31:02 -0800 Subject: [PATCH 03/21] Add lockfile to gitignore --- .gitignore | 2 ++ assets/config/users.db | Bin 32768 -> 0 bytes 2 files changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index ef02ecd..fb5b8a0 100644 --- a/.gitignore +++ b/.gitignore @@ -22,3 +22,5 @@ feed\.rss vendor/ assets/config/users\.db + +run\.lockfile diff --git a/assets/config/users.db b/assets/config/users.db index 7b050883d0c3c268b48459f01dfa11c210cffd68..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 100644 GIT binary patch literal 0 HcmV?d00001 literal 32768 zcmeI)%}?8A90%~nu?Yz%ait3R(2G?ejfgHJkU)E=geeBnyg-6O5~Pthi6I6%X>4a9 zNITH|3)^+l{+-?X5A?bVmu{CG=EsDW?1e_FItltUJTbPPJTIT;F~Y<@@8&bQqlt$d z%Tyh4i98|9ACqWsE);r4xX?5S{}h@I+u<$# zNBVWgyKo2s5P$##AOHafKmY;{PvGrWfk~lMV!r>{QR{|gcMbP1@w(ON+nQCiw6sQCmBBtevC>53MRL(6wE9Vrkm`ml0@-z31J-5xY!L^_wmv0|vsdnpfC(UMQs&SKz z?$JzDH*PY#(JWK9ZN1aBuUj$|39m9SK@ga?riVZ)v%MGpNKc=7`=0*So}6#GRnh(|ZSlQU{1v#LnW@O4QycGVeN^fAQ zi{6Th1V5fN?qy|nIKMDI&s1*B{i>~Xds@3OJYTLiCq|~iu+vw0=jfz+=59p@VIFyd z{PHhTX>^di32p!Vq|p6-;q%MtF6O7!vN+cGaUpl?*zh~|oBx4-{_uXuqDK&b00bZa z0SG_<0uX=z1R(Gr1rFFrvdVUyTxRF!R#Cst%Ta^pRO-uPpxPn8tpkoL2HyGT7Xx|s?lkvMyq2xK9_Ev3y_&} zZYC0RG}{^05MN&&=*t5mmZ?Z;&r*w>R-zw0%EXt_($4YTO0#fw(kV&iN`E)yD1*jE zyt^`>@2Bae{9`sio}6=$g}{+ow{*=I7XNA|-+X>%MUN6na(&QURIKL7k)}AWTc;=W_th)q*m)HOA3I99)EB~I*e{Eoa00bZa0SG_< z0uX=z1Rwwb2teT82?W>~hTdPmO|ws!;phKsfE9w?T@Cd9e}?}+_z(Oq_pWPbFa#g~ z0SG_<0uX=z1Rwwb2teSA6Ns>Ei5V;C-xp+Afw_Db1HJxtANoi5pZVk$M}`hV00Izz z00bZa0SG_<0uX=z1nv?z_R#?SiO2#O4bV?pt^Ig+dE?FYX4j5w?4`4nRzA9>RJ6VF znbSVDvM&ntbTn4)rQ+LLhvpzBOM{OD=znwdECcdco@GGq|M#x{-T42zx{PBGfB*y_ z009U<00Izz00bZa0SMeT0UH1B^U?VKVasXU|D>Dz_pK*rF9aX}0SG_<0uX=z1Rwwb S2tWV=BLcVL|9#i-|9=7+)@E4% From 920e471428d67e7bf0be47e65a6287abdfae299e Mon Sep 17 00:00:00 2001 From: gmemstr Date: Sun, 3 Dec 2017 19:31:42 -0800 Subject: [PATCH 04/21] Create podcast folder during setup --- setup.go | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.go b/setup.go index ce9bcd5..2e504c5 100644 --- a/setup.go +++ b/setup.go @@ -20,6 +20,7 @@ func Setup() { 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") From 63df507c131e51b29f776264dee0413f3ae6ed22 Mon Sep 17 00:00:00 2001 From: gmemstr Date: Sun, 3 Dec 2017 19:39:32 -0800 Subject: [PATCH 05/21] Refresh Godeps --- Godeps/Godeps.json | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index f0b066d..1428fae 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -8,6 +8,14 @@ "Comment": "v1.4.2-6-g4da3e2c", "Rev": "4da3e2cfbabc9f751898f250b49f2439785783a1" }, + { + "ImportPath": "github.com/google/go-github/github", + "Rev": "fbfee053c26dab3772adfc7799d995eed379133e" + }, + { + "ImportPath": "github.com/google/go-querystring/query", + "Rev": "53e6ce116135b80d037921a7fdd5138cf32d7a8a" + }, { "ImportPath": "github.com/gorilla/feeds", "Comment": "v1.0.0", From 15232d24a981811ee71ed0dc5ee917f1dcb99e51 Mon Sep 17 00:00:00 2001 From: gmemstr Date: Mon, 4 Dec 2017 07:36:07 -0800 Subject: [PATCH 06/21] Remove old legacy "setup" web interface --- assets/web/setup.html | 30 ------------------------------ router/router.go | 33 --------------------------------- 2 files changed, 63 deletions(-) delete mode 100644 assets/web/setup.html diff --git a/assets/web/setup.html b/assets/web/setup.html deleted file mode 100644 index ecdc99d..0000000 --- a/assets/web/setup.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - Pogo Setup - - - -

Let's get Pogo setup

- -
- - - - - - - - - - - - - - - -
- - - \ No newline at end of file diff --git a/router/router.go b/router/router.go index 550ec70..185f989 100644 --- a/router/router.go +++ b/router/router.go @@ -122,10 +122,6 @@ func Init() *mux.Router { admin.ListUsers(), )).Methods("GET") - r.Handle("/setup", Handle( - serveSetup(), - )).Methods("GET", "POST") - return r } @@ -244,32 +240,3 @@ func adminHandler() common.Handler { return common.ReadAndServeFile("assets/web/admin.html", w) } } - -// Serve setup.html and config parameters -func serveSetup() common.Handler { - return func(rc *common.RouterContext, w http.ResponseWriter, r *http.Request) *common.HTTPError { - if r.Method == "GET" { - return common.ReadAndServeFile("assets/web/setup.html", w) - } - r.ParseMultipartForm(32 << 20) - - // Parse form and convert to JSON - cnf := NewConfig{ - strings.Join(r.Form["podcastname"], ""), // Podcast name - strings.Join(r.Form["podcasthost"], ""), // Podcast host - strings.Join(r.Form["podcastemail"], ""), // Podcast host email - "", // Podcast image - "", // Podcast location - "", // Podcast location - } - - b, err := json.Marshal(cnf) - if err != nil { - panic(err) - } - - ioutil.WriteFile("assets/config/config.json", b, 0644) - w.Write([]byte("Done")) - return nil - } -} From 58b25d1d7ea0fbf7083682e7943952b2bd66e72d Mon Sep 17 00:00:00 2001 From: gmemstr Date: Mon, 4 Dec 2017 08:26:27 -0800 Subject: [PATCH 07/21] Remove unused router imports --- router/router.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/router/router.go b/router/router.go index 185f989..5aedc94 100644 --- a/router/router.go +++ b/router/router.go @@ -2,13 +2,10 @@ package router import ( "database/sql" - "encoding/json" "fmt" "golang.org/x/crypto/bcrypt" - "io/ioutil" "log" "net/http" - "strings" _ "github.com/mattn/go-sqlite3" From 7197959500e3e5d319fe3988854bb8273c8e8480 Mon Sep 17 00:00:00 2001 From: gmemstr Date: Mon, 4 Dec 2017 17:39:33 -0800 Subject: [PATCH 08/21] Add Admin account creationg to setup --- setup.go | 14 ++++++++++++-- webserver.go | 8 ++++++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/setup.go b/setup.go index 2e504c5..d24e609 100644 --- a/setup.go +++ b/setup.go @@ -2,10 +2,12 @@ package main import ( "archive/zip" + "bufio" "context" "database/sql" "fmt" _ "github.com/mattn/go-sqlite3" + "golang.org/x/crypto/bcrypt" "io" "net/http" "os" @@ -32,6 +34,14 @@ func Setup() { if err != nil { fmt.Sprintf("Problem creating database! %v", err) } + // Insert default admin user + reader := bufio.NewReader(os.Stdin) + fmt.Print("Administrator password: ") + text, err := reader.ReadString('\n') + + hash, err := bcrypt.GenerateFromPassword(text) + + _, err = db.Exec("INSERT INTO users(id,username,hash,realname,email,permissions) VALUES (0,`admin`,?,`Administrator`,`admin@localhost`,2", hash) db.Close() @@ -79,11 +89,11 @@ func Setup() { } func LockFile() { - lock, err := os.Create("run.lockfile") + lock, err := os.Create(".lock") if err != nil { fmt.Println("Error: %v", err) } - lock.Write([]byte("# You can leave this file emtpy, it simply tells Pogo you're set up!")) + lock.Write([]byte("This file left intentionally empty")) defer lock.Close() } diff --git a/webserver.go b/webserver.go index cee6f52..2c69ac7 100644 --- a/webserver.go +++ b/webserver.go @@ -15,12 +15,16 @@ import ( "github.com/gmemstr/pogo/router" ) +func GetPogoVersion() { + return "2.0.0" +} + // Main function that defines routes func main() { + // Check if this is the first time Pogo has been run // with a lockfile - - if _, err := os.Stat("run.lockfile"); os.IsNotExist(err) { + if _, err := os.Stat(".lock"); os.IsNotExist(err) { fmt.Println("This looks like your first time running Pogo,\ngive me a second to set myself up.") Setup() } From 531aadef61b8f4185ccf251e61080931629d4e8b Mon Sep 17 00:00:00 2001 From: gmemstr Date: Mon, 4 Dec 2017 17:41:23 -0800 Subject: [PATCH 09/21] Add rounds to password generation --- setup.go | 2 +- webserver.go | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/setup.go b/setup.go index d24e609..8737981 100644 --- a/setup.go +++ b/setup.go @@ -39,7 +39,7 @@ func Setup() { fmt.Print("Administrator password: ") text, err := reader.ReadString('\n') - hash, err := bcrypt.GenerateFromPassword(text) + hash, err := bcrypt.GenerateFromPassword(text, 8) _, err = db.Exec("INSERT INTO users(id,username,hash,realname,email,permissions) VALUES (0,`admin`,?,`Administrator`,`admin@localhost`,2", hash) diff --git a/webserver.go b/webserver.go index 2c69ac7..b1f981e 100644 --- a/webserver.go +++ b/webserver.go @@ -15,10 +15,6 @@ import ( "github.com/gmemstr/pogo/router" ) -func GetPogoVersion() { - return "2.0.0" -} - // Main function that defines routes func main() { From b2ee790b32b501a0a35c38f1aae6804a761af5a1 Mon Sep 17 00:00:00 2001 From: gmemstr Date: Mon, 4 Dec 2017 17:42:15 -0800 Subject: [PATCH 10/21] Password to []byte --- setup.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.go b/setup.go index 8737981..963ed18 100644 --- a/setup.go +++ b/setup.go @@ -39,7 +39,7 @@ func Setup() { fmt.Print("Administrator password: ") text, err := reader.ReadString('\n') - hash, err := bcrypt.GenerateFromPassword(text, 8) + hash, err := bcrypt.GenerateFromPassword([]byte(password), 8) _, err = db.Exec("INSERT INTO users(id,username,hash,realname,email,permissions) VALUES (0,`admin`,?,`Administrator`,`admin@localhost`,2", hash) From 05d12a162ed0c609c41642409918ea2fe646ec7e Mon Sep 17 00:00:00 2001 From: gmemstr Date: Mon, 4 Dec 2017 17:42:45 -0800 Subject: [PATCH 11/21] Fix typo --- setup.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.go b/setup.go index 963ed18..5098fc2 100644 --- a/setup.go +++ b/setup.go @@ -39,7 +39,7 @@ func Setup() { fmt.Print("Administrator password: ") text, err := reader.ReadString('\n') - hash, err := bcrypt.GenerateFromPassword([]byte(password), 8) + hash, err := bcrypt.GenerateFromPassword([]byte(text), 8) _, err = db.Exec("INSERT INTO users(id,username,hash,realname,email,permissions) VALUES (0,`admin`,?,`Administrator`,`admin@localhost`,2", hash) From 17cc31b3a39e76db97a29ad19085a184801fb189 Mon Sep 17 00:00:00 2001 From: gmemstr Date: Mon, 4 Dec 2017 17:48:27 -0800 Subject: [PATCH 12/21] Prepare then execute --- setup.go | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.go b/setup.go index 5098fc2..8bff2d1 100644 --- a/setup.go +++ b/setup.go @@ -41,7 +41,8 @@ func Setup() { hash, err := bcrypt.GenerateFromPassword([]byte(text), 8) - _, err = db.Exec("INSERT INTO users(id,username,hash,realname,email,permissions) VALUES (0,`admin`,?,`Administrator`,`admin@localhost`,2", hash) + q, err = db.Prepare("INSERT INTO users(id,username,hash,realname,email,permissions) VALUES (0,`admin`,?,`Administrator`,`admin@localhost`,2") + q.Exec(hash) db.Close() From 584e513492536e28ae745317dbccc17eb9135586 Mon Sep 17 00:00:00 2001 From: gmemstr Date: Mon, 4 Dec 2017 17:48:58 -0800 Subject: [PATCH 13/21] Add missing := --- setup.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.go b/setup.go index 8bff2d1..7d02ee7 100644 --- a/setup.go +++ b/setup.go @@ -41,7 +41,7 @@ func Setup() { hash, err := bcrypt.GenerateFromPassword([]byte(text), 8) - q, err = db.Prepare("INSERT INTO users(id,username,hash,realname,email,permissions) VALUES (0,`admin`,?,`Administrator`,`admin@localhost`,2") + q, err := db.Prepare("INSERT INTO users(id,username,hash,realname,email,permissions) VALUES (0,`admin`,?,`Administrator`,`admin@localhost`,2") q.Exec(hash) db.Close() From d9a64821532a98a58d12fb9716e5d930cfd5f01d Mon Sep 17 00:00:00 2001 From: gmemstr Date: Tue, 5 Dec 2017 10:52:22 -0800 Subject: [PATCH 14/21] Attempting to fix setup script's password hashing debacle --- assets/config/users.db | Bin 0 -> 20480 bytes router/router.go | 6 +++--- setup.go | 21 +++++++++++++++------ 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/assets/config/users.db b/assets/config/users.db index e69de29bb2d1d6434b8b29ae775ad8c2e48c5391..edfb057814372d9d6a756221717b126970af14b0 100644 GIT binary patch literal 20480 zcmeI)zi!h&90%~bI4uULHJjHPB9SOn)da+bR1+Cw#c|uzp>db^(p(w~|Dm=6tYzi_ zn0X&wfyZbW7`R+0g)ZF~lJ8Hx*mwEe#lMfdoMh$r$c;+Drdgiwl07Al38iG8F+xa1 zwhh^Cg362PO-G&={rjRqb|2Qaj31=B{h4fkH@+EP%L-+JlV>`rby<%!slGaHu{ePEg< z{lwLp^Fri>`l$RfKU8BOtFthggv{}L`?cL?-ht1&f$OrvzSFb%0qfcUvj+ZwEel}#jJ^X8Y#*5iQl zo8}9Xk|>>skH0JB^D?Rx2ZE~b0#hc~afZ8tb|P9kfuKva}DFSA^&wjXC_Jf3AmS$QPuqQ*}m z4+I1t009U<00Izz00bZa0SG_<0xKw>X}Z4L|6dd1dIbwaNf3Yl1Rwwb2tWV=5P$## zAOL~&7SJ_QSFZvr-~YcN#?^X*pn3>E00Izz00bZa0SG_<0uX?}>Ivvn?*G*v0sI1$ Ce6WcC literal 0 HcmV?d00001 diff --git a/router/router.go b/router/router.go index 5aedc94..1039b43 100644 --- a/router/router.go +++ b/router/router.go @@ -157,9 +157,9 @@ func loginHandler() common.Handler { password := r.Form.Get("password") rows, err := statement.Query(username) - if username == "" || password == "" { + if username == "" || password == "" || err != nil { return &common.HTTPError{ - Message: "username or password is empty", + Message: "username or password is invalid", StatusCode: http.StatusBadRequest, } } @@ -180,7 +180,7 @@ func loginHandler() common.Handler { } // Create a cookie here because the credentials are correct - if dbun == username && bcrypt.CompareHashAndPassword([]byte(dbhsh), []byte(password)) == nil { + if bcrypt.CompareHashAndPassword([]byte(dbhsh), []byte(password)) == nil { c, err := auth.CreateSession(&common.User{ Username: username, }) diff --git a/setup.go b/setup.go index 7d02ee7..264161d 100644 --- a/setup.go +++ b/setup.go @@ -12,6 +12,7 @@ import ( "net/http" "os" "path/filepath" + "strings" "github.com/google/go-github/github" ) @@ -38,13 +39,21 @@ func Setup() { reader := bufio.NewReader(os.Stdin) fmt.Print("Administrator password: ") text, err := reader.ReadString('\n') + text = strings.Replace(text, "\n", "", -1) + if err != nil { + fmt.Sprintf("Problem reading password input! %v", err) + } + fmt.Println(text) - hash, err := bcrypt.GenerateFromPassword([]byte(text), 8) - - q, err := db.Prepare("INSERT INTO users(id,username,hash,realname,email,permissions) VALUES (0,`admin`,?,`Administrator`,`admin@localhost`,2") - q.Exec(hash) - - db.Close() + hash, err := bcrypt.GenerateFromPassword([]byte(text), 4) + 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',?,'Administrator','admin@localhost',2)", hash) + if err != nil { + fmt.Sprintf("Problem creating database! %v", err) + } + defer db.Close() // Download web assets fmt.Println("Downloading web assets") From b18279c39373d6b0f26e3406a324c4e80890069f Mon Sep 17 00:00:00 2001 From: gmemstr Date: Thu, 7 Dec 2017 10:36:52 -0800 Subject: [PATCH 15/21] Change from asking for admin password to randomly generating one --- .gitignore | 2 ++ assets/web/admin.html | 2 +- assets/web/static/app.js | 5 +++++ setup.go | 45 ++++++++++++++++++++++------------------ 4 files changed, 33 insertions(+), 21 deletions(-) diff --git a/.gitignore b/.gitignore index fb5b8a0..5e8318f 100644 --- a/.gitignore +++ b/.gitignore @@ -24,3 +24,5 @@ vendor/ assets/config/users\.db run\.lockfile + +\.lock diff --git a/assets/web/admin.html b/assets/web/admin.html index e10fac4..932e768 100644 --- a/assets/web/admin.html +++ b/assets/web/admin.html @@ -10,7 +10,7 @@
+ Publish Episodes Theme Users

{{ header }}

diff --git a/assets/web/static/app.js b/assets/web/static/app.js index b87fab0..27b3bdf 100644 --- a/assets/web/static/app.js +++ b/assets/web/static/app.js @@ -376,4 +376,9 @@ function get(url,callback) { } xmlHttp.open("GET", url, true); xmlHttp.send(null); +} + +function logout() { + document.cookie = "POGO_SESSION=;expires=Thu, 01 Jan 1970 00:00:01 GMT"; + window.location = "/"; } \ No newline at end of file diff --git a/setup.go b/setup.go index 264161d..a467876 100644 --- a/setup.go +++ b/setup.go @@ -2,21 +2,30 @@ package main import ( "archive/zip" - "bufio" "context" "database/sql" "fmt" _ "github.com/mattn/go-sqlite3" "golang.org/x/crypto/bcrypt" "io" + "math/rand" "net/http" "os" "path/filepath" - "strings" "github.com/google/go-github/github" ) +func RandomString(n int) string { + var letter = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-={}[]") + + b := make([]rune, n) + for i := range b { + b[i] = letter[rand.Intn(len(letter))] + } + return string(b) +} + func Setup() { defer LockFile() // Create users SQLite3 file @@ -28,30 +37,26 @@ func Setup() { db, err := sql.Open("sqlite3", "assets/config/users.db") if err != nil { - fmt.Sprintf("Problem opening database file! %v", err) + 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.Sprintf("Problem creating database! %v", err) + fmt.Println("Problem creating database! %v", err) } - // Insert default admin user - reader := bufio.NewReader(os.Stdin) - fmt.Print("Administrator password: ") - text, err := reader.ReadString('\n') - text = strings.Replace(text, "\n", "", -1) - if err != nil { - fmt.Sprintf("Problem reading password input! %v", err) - } - fmt.Println(text) + text := RandomString(14) + 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',?,'Administrator','admin@localhost',2)", hash) + _, 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.Sprintf("Problem creating database! %v", err) + fmt.Println("Problem creating database! %v", err) } defer db.Close() @@ -64,29 +69,29 @@ func Setup() { ctx := context.Background() res, _, err := client.GetLatestRelease(ctx, "gmemstr", "pogo") if err != nil { - fmt.Sprintf("Problem creating database! %v", err) + fmt.Println("Problem creating database! %v", err) } for i := 0; i < len(res.Assets); i++ { if res.Assets[i].GetName() == "webassets.zip" { download := res.Assets[i] - fmt.Sprintf("Release found: %v", download.GetBrowserDownloadURL()) + fmt.Println("Release found: %v", download.GetBrowserDownloadURL()) tmpfile, err := os.Create(download.GetName()) if err != nil { - fmt.Sprintf("Problem creating webassets file! %v", err) + 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", download.GetID()) if err != nil { - fmt.Sprintf("Problem downloading webassets! %v", err) + 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.Sprintf("Problem creating webassets file! %v", err) + fmt.Println("Problem creating webassets file! %v", err) } fmt.Println("Download complete\nUnzipping") err = Unzip(download.GetName(), "assets/web") From 296a0309970b9ef34de3a30fe414e15f7a4e79bc Mon Sep 17 00:00:00 2001 From: gmemstr Date: Mon, 18 Dec 2017 21:32:27 -0800 Subject: [PATCH 16/21] Moving from using /assets to /static Compensating for how webpack builds the new frontend. --- router/router.go | 1 + 1 file changed, 1 insertion(+) diff --git a/router/router.go b/router/router.go index 1039b43..e1cae5b 100644 --- a/router/router.go +++ b/router/router.go @@ -49,6 +49,7 @@ func Init() *mux.Router { // "Static" paths r.PathPrefix("/assets/").Handler(http.StripPrefix("/assets/", http.FileServer(http.Dir("assets/web/static")))) + r.PathPrefix("/static/").Handler(http.StripPrefix("/static/", http.FileServer(http.Dir("assets/web/static")))) r.PathPrefix("/download/").Handler(http.StripPrefix("/download/", http.FileServer(http.Dir("podcasts")))) // Paths that require specific handlers From 324211b4c128e0abddaa991fd5f380041bcc9c8a Mon Sep 17 00:00:00 2001 From: gmemstr Date: Mon, 18 Dec 2017 21:33:22 -0800 Subject: [PATCH 17/21] Tweaked README #runnig --- README.md | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 99aadc1..940614e 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Podcast RSS feed generator and CMS in Go. There are a couple options for getting Pogo up and running. -- [Download the latest release](https://github.com/gmemstr/pogo/releases/latest) +- [Download the latest release](#running) - [Clone the repo and build](#building) ## Status @@ -29,11 +29,9 @@ There are a couple options for getting Pogo up and running. 1. [Download the latest release](https://github.com/gmemstr/pogo/releases/latest) 2. Unzip somewhere safe -3. [Edit the config](https://github.com/gmemstr/pogo/wiki/Configuration) -4. Run `pogo` -5. Navigate to your instance (`localhost:3000` by default) -6. Login to the admin interface (default: **admin**, **password1**) -7. **CHANGE YOUR PASSWORD** +3. Run `pogo` +4. Navigate to your instance (`localhost:3000` by default) +5. Login to the admin interface (your credentials are generated on the first run) ## Building From 7ccba66a11f5b648c170d3d0f8cd436e79c0f999 Mon Sep 17 00:00:00 2001 From: gmemstr Date: Mon, 18 Dec 2017 21:42:11 -0800 Subject: [PATCH 18/21] Pointing webassets directory to new pogo-vue repository --- setup.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.go b/setup.go index a467876..e0a7f7e 100644 --- a/setup.go +++ b/setup.go @@ -67,7 +67,7 @@ func Setup() { client := github.NewClient(nil).Repositories ctx := context.Background() - res, _, err := client.GetLatestRelease(ctx, "gmemstr", "pogo") + res, _, err := client.GetLatestRelease(ctx, "gmemstr", "pogo-vue") if err != nil { fmt.Println("Problem creating database! %v", err) } @@ -82,7 +82,7 @@ func Setup() { var j io.Reader = (*os.File)(tmpfile) defer tmpfile.Close() - j, s, err := client.DownloadReleaseAsset(ctx, "gmemstr", "pogo", download.GetID()) + j, s, err := client.DownloadReleaseAsset(ctx, "gmemstr", "pogo-vue", download.GetID()) if err != nil { fmt.Println("Problem downloading webassets! %v", err) } From 7375d2846a353e80931aa62cb395c038beba8c03 Mon Sep 17 00:00:00 2001 From: gmemstr Date: Tue, 19 Dec 2017 08:40:23 -0800 Subject: [PATCH 19/21] Added crypto-secure password generation, old method was _not_ random --- assets/config/users.db | Bin 20480 -> 0 bytes setup.go | 31 +++++++++++++++++++++---------- 2 files changed, 21 insertions(+), 10 deletions(-) delete mode 100644 assets/config/users.db diff --git a/assets/config/users.db b/assets/config/users.db deleted file mode 100644 index edfb057814372d9d6a756221717b126970af14b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20480 zcmeI)zi!h&90%~bI4uULHJjHPB9SOn)da+bR1+Cw#c|uzp>db^(p(w~|Dm=6tYzi_ zn0X&wfyZbW7`R+0g)ZF~lJ8Hx*mwEe#lMfdoMh$r$c;+Drdgiwl07Al38iG8F+xa1 zwhh^Cg362PO-G&={rjRqb|2Qaj31=B{h4fkH@+EP%L-+JlV>`rby<%!slGaHu{ePEg< z{lwLp^Fri>`l$RfKU8BOtFthggv{}L`?cL?-ht1&f$OrvzSFb%0qfcUvj+ZwEel}#jJ^X8Y#*5iQl zo8}9Xk|>>skH0JB^D?Rx2ZE~b0#hc~afZ8tb|P9kfuKva}DFSA^&wjXC_Jf3AmS$QPuqQ*}m z4+I1t009U<00Izz00bZa0SG_<0xKw>X}Z4L|6dd1dIbwaNf3Yl1Rwwb2tWV=5P$## zAOL~&7SJ_QSFZvr-~YcN#?^X*pn3>E00Izz00bZa0SG_<0uX?}>Ivvn?*G*v0sI1$ Ce6WcC diff --git a/setup.go b/setup.go index e0a7f7e..ab4cd08 100644 --- a/setup.go +++ b/setup.go @@ -3,12 +3,13 @@ package main import ( "archive/zip" "context" + "crypto/rand" "database/sql" + "encoding/base64" "fmt" _ "github.com/mattn/go-sqlite3" "golang.org/x/crypto/bcrypt" "io" - "math/rand" "net/http" "os" "path/filepath" @@ -16,14 +17,21 @@ import ( "github.com/google/go-github/github" ) -func RandomString(n int) string { - var letter = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!@#$%^&*()_+-={}[]") - - b := make([]rune, n) - for i := range b { - b[i] = letter[rand.Intn(len(letter))] +func GenerateRandomBytes(n int) ([]byte, error) { + b := make([]byte, n) + _, err := rand.Read(b) + if err != nil { + return nil, err } - return string(b) + + 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() { @@ -45,7 +53,10 @@ func Setup() { fmt.Println("Problem creating database! %v", err) } - text := RandomString(14) + 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 { @@ -69,7 +80,7 @@ func Setup() { ctx := context.Background() res, _, err := client.GetLatestRelease(ctx, "gmemstr", "pogo-vue") if err != nil { - fmt.Println("Problem creating database! %v", err) + 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" { From 793cb0e650615014e0e708416ce5a2889d67e31d Mon Sep 17 00:00:00 2001 From: gmemstr Date: Tue, 19 Dec 2017 09:07:06 -0800 Subject: [PATCH 20/21] remove newline from setup intro --- webserver.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/webserver.go b/webserver.go index b1f981e..81a3315 100644 --- a/webserver.go +++ b/webserver.go @@ -21,7 +21,7 @@ func main() { // Check if this is the first time Pogo has been run // with a lockfile if _, err := os.Stat(".lock"); os.IsNotExist(err) { - fmt.Println("This looks like your first time running Pogo,\ngive me a second to set myself up.") + fmt.Println("This looks like your first time running Pogo, give me a second to set myself up.") Setup() } From b082d0de05475694b20d197ae2d43ecc4cdc8806 Mon Sep 17 00:00:00 2001 From: gmemstr Date: Tue, 19 Dec 2017 09:18:19 -0800 Subject: [PATCH 21/21] Added configuration edit step to readme --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 940614e..97b6182 100644 --- a/README.md +++ b/README.md @@ -29,9 +29,10 @@ There are a couple options for getting Pogo up and running. 1. [Download the latest release](https://github.com/gmemstr/pogo/releases/latest) 2. Unzip somewhere safe -3. Run `pogo` -4. Navigate to your instance (`localhost:3000` by default) -5. Login to the admin interface (your credentials are generated on the first run) +3. [Edit the configuration](https://github.com/gmemstr/pogo/wiki/Configuration) +4. Run `pogo` +5. Navigate to your instance (`localhost:3000` by default) +6. Login to the admin interface (your credentials are generated on the first run) ## Building