package main import ( "context" "fmt" _ "github.com/go-sql-driver/mysql" "github.com/gocraft/dbr/v2" "github.com/thanhpk/randstr" "io/ioutil" "net/http" "os" "os/signal" "strconv" "strings" "tiktak/db" "tiktak/keygen" "tiktak/server" "tiktak/server/auth" "tiktak/video" "time" ) func main() { // Rotated DB password. Must stay in sync with MYSQL_ROOT_PASSWORD in // docker-compose.yml AND with the actual MySQL user (ALTER USER) when the // ./db_data volume already exists. conn, err := dbr.Open( "mysql", "root:cRazy_P4ssw0rd_MeOw_Me0W_676767676767@tcp(db:3306)/tiktak", nil) if err != nil { panic(err) } defer conn.Close() storage := db.New(conn) auth.SetSalt(randstr.Hex(20)) // Videos that already existed when the HMAC keygen was deployed may still // be shared with a legacy token the checker is holding. Freeze that cutoff // on first boot and persist it, so a container restart cannot widen the // window (a wider window means more videos accepting forgeable tokens). keygen.SetLegacyCutoff(legacyCutoff(storage)) config := server.Config{ StaticFolder: "public/static", VttFolder: "public/vtt", TemplatesFolder: "templates", } srv := server.NewServer(storage, &video.Storage{Directory: "public/video"}, config) // Start server go func() { if err := http.ListenAndServe(":4000", srv); err != nil { fmt.Println("shutting down the server") } }() // Graceful shutdown quit := make(chan os.Signal) signal.Notify(quit, os.Interrupt) <-quit ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() if err := srv.Shutdown(ctx); err != nil { panic(err) } } // legacyCutoffFile lives on the ./public volume so it survives restarts. const legacyCutoffFile = "public/.legacy_cutoff" func legacyCutoff(storage *db.Storage) int { if b, err := ioutil.ReadFile(legacyCutoffFile); err == nil { if n, err := strconv.Atoi(strings.TrimSpace(string(b))); err == nil { fmt.Println("legacy token cutoff (pinned):", n) return n } } id, err := storage.MaxVideoID(context.Background()) if err != nil { // Fail closed: no legacy tokens rather than an unbounded window. fmt.Println("cannot read max video id, legacy tokens disabled:", err) return 0 } if err := ioutil.WriteFile(legacyCutoffFile, []byte(strconv.FormatInt(id, 10)), 0644); err != nil { fmt.Println("cannot pin legacy cutoff:", err) } fmt.Println("legacy token cutoff (fresh):", id) return int(id) }