2017-12-04 00:26:09 +00:00
package main
import (
2017-12-04 03:30:38 +00:00
"archive/zip"
"context"
2017-12-19 16:40:23 +00:00
"crypto/rand"
2017-12-04 00:26:09 +00:00
"database/sql"
2017-12-19 16:40:23 +00:00
"encoding/base64"
2018-01-01 07:34:26 +00:00
"encoding/json"
2017-12-04 00:26:09 +00:00
"fmt"
2017-12-04 03:30:38 +00:00
_ "github.com/mattn/go-sqlite3"
2017-12-05 01:39:33 +00:00
"golang.org/x/crypto/bcrypt"
2017-12-04 00:26:09 +00:00
"io"
2018-01-01 07:34:26 +00:00
"io/ioutil"
2017-12-04 00:26:09 +00:00
"net/http"
"os"
2017-12-04 03:30:38 +00:00
"path/filepath"
2017-12-04 00:26:09 +00:00
2017-12-04 03:30:38 +00:00
"github.com/google/go-github/github"
2017-12-04 00:26:09 +00:00
)
2018-01-01 07:34:26 +00:00
type Configuration struct {
Name string ` json:"Name" `
Host string ` json:"Host" `
Email string ` json:"Email" `
Description string ` json:"Description" `
Image string ` json:"Image" `
PodcastUrl string ` json:"PodcastUrl" `
2017-12-07 18:36:52 +00:00
}
2017-12-04 03:30:38 +00:00
func Setup ( ) {
2018-01-01 07:34:26 +00:00
// Create directories
2017-12-04 00:26:09 +00:00
os . MkdirAll ( "assets/config/" , 0755 )
2017-12-04 03:31:42 +00:00
os . Mkdir ( "podcasts" , 0755 )
2017-12-04 03:30:38 +00:00
2018-01-01 07:34:26 +00:00
// Write basic configuration file
WriteSkeletonConfig ( )
2017-12-04 03:30:38 +00:00
2018-01-01 07:34:26 +00:00
// Generate neccesary feed files
2022-03-19 13:39:17 +00:00
GenerateRss ( )
2017-12-05 01:39:33 +00:00
2018-01-01 07:34:26 +00:00
// Create "first run" lockfile when function exits
2022-03-19 13:30:42 +00:00
// defer LockFile()
2018-01-01 07:34:26 +00:00
// Create users SQLite3 file
CreateDatabase ( )
2017-12-04 03:30:38 +00:00
// Download web assets
2018-01-01 07:34:26 +00:00
GetWebAssets ( )
}
func GetWebAssets ( ) {
2017-12-04 03:30:38 +00:00
fmt . Println ( "Downloading web assets" )
os . MkdirAll ( "assets/web/" , 0755 )
client := github . NewClient ( nil ) . Repositories
ctx := context . Background ( )
2017-12-19 05:42:11 +00:00
res , _ , err := client . GetLatestRelease ( ctx , "gmemstr" , "pogo-vue" )
2017-12-04 03:30:38 +00:00
if err != nil {
2017-12-19 16:40:23 +00:00
fmt . Println ( "Problem getting latest pogo-vue release! %v" , err )
2017-12-04 03:30:38 +00:00
}
for i := 0 ; i < len ( res . Assets ) ; i ++ {
if res . Assets [ i ] . GetName ( ) == "webassets.zip" {
download := res . Assets [ i ]
2022-03-19 12:59:56 +00:00
fmt . Printf ( "Release found: %v\n" , download . GetBrowserDownloadURL ( ) )
2017-12-04 03:30:38 +00:00
tmpfile , err := os . Create ( download . GetName ( ) )
if err != nil {
2022-03-19 12:59:56 +00:00
fmt . Printf ( "Problem creating webassets file! %v\n" , err )
2017-12-04 03:30:38 +00:00
}
var j io . Reader = ( * os . File ) ( tmpfile )
defer tmpfile . Close ( )
2017-12-19 05:42:11 +00:00
j , s , err := client . DownloadReleaseAsset ( ctx , "gmemstr" , "pogo-vue" , download . GetID ( ) )
2017-12-04 03:30:38 +00:00
if err != nil {
2022-03-19 12:59:56 +00:00
fmt . Printf ( "Problem downloading webassets! %v\n" , err )
2017-12-04 03:30:38 +00:00
}
if j == nil {
resp , err := http . Get ( s )
defer resp . Body . Close ( )
_ , err = io . Copy ( tmpfile , resp . Body )
if err != nil {
2022-03-19 12:59:56 +00:00
fmt . Printf ( "Problem creating webassets file! %v\n" , err )
2017-12-04 03:30:38 +00:00
}
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!" )
}
}
}
}
2018-01-01 07:34:26 +00:00
func CreateDatabase ( ) {
fmt . Println ( "Initializing the database" )
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 ( )
}
2017-12-04 03:30:38 +00:00
func LockFile ( ) {
2022-03-19 13:30:42 +00:00
lock , err := os . Create ( ".lock" )
2017-12-04 03:30:38 +00:00
if err != nil {
fmt . Println ( "Error: %v" , err )
}
2017-12-05 01:39:33 +00:00
lock . Write ( [ ] byte ( "This file left intentionally empty" ) )
2017-12-04 03:30:38 +00:00
defer lock . Close ( )
2017-12-04 00:26:09 +00:00
}
2018-01-01 07:34:26 +00:00
func WriteSkeletonConfig ( ) {
fmt . Println ( "Writing basic config file to disk" )
os . Create ( "assets/config/config.json" )
config := Configuration {
"Pogo Podcast" ,
"John Doe" ,
"johndoe@localhost" ,
"A Podcast About Stuff" ,
2018-01-09 18:21:56 +00:00
"localhost:3000/assets/podcastimage.png" ,
2018-01-01 07:34:26 +00:00
"http://localhost:3000" ,
}
c , err := json . Marshal ( config )
filename := "config.json"
err = ioutil . WriteFile ( "./assets/config/" + filename , c , 0644 )
if err != nil {
fmt . Println ( "Error: " , err )
}
}
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
}
2017-12-04 03:30:38 +00:00
// 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
}
}
2017-12-04 00:26:09 +00:00
2017-12-04 03:30:38 +00:00
return nil
2017-12-04 00:26:09 +00:00
}