package cmd import ( "fmt" "time" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/urfave/cli/v2" "codeberg.org/codeberg/pages/server/database" ) var Certs = &cli.Command{ Name: "certs", Usage: "manage certs manually", Subcommands: []*cli.Command{ { Name: "list", Usage: "list all certificates in the database", Action: listCerts, }, { Name: "remove", Usage: "remove a certificate from the database", Action: removeCert, }, { Name: "migrate", Usage: "migrate from \"pogreb\" driver to dbms driver", Action: migrateCerts, }, }, Flags: []cli.Flag{ // Cert Storage // TODO: remove in next version &cli.StringFlag{ // DEPRICATED Name: "db-pogreb", Value: "key-database.pogreb", EnvVars: []string{"DB_POGREB"}, }, &cli.StringFlag{ Name: "db-type", Value: "", // TODO: "sqlite3" in next version EnvVars: []string{"DB_TYPE"}, }, &cli.StringFlag{ Name: "db-conn", Value: "certs.sqlite", EnvVars: []string{"DB_CONN"}, }, &cli.BoolFlag{ Name: "verbose", Usage: "print trace info", EnvVars: []string{"VERBOSE"}, Value: false, }, }, } func migrateCerts(ctx *cli.Context) error { dbType := ctx.String("db-type") if dbType == "" { dbType = "sqlite3" } dbConn := ctx.String("db-conn") dbPogrebConn := ctx.String("db-pogreb") verbose := ctx.Bool("verbose") log.Level(zerolog.InfoLevel) if verbose { log.Level(zerolog.TraceLevel) } xormDB, err := database.NewXormDB(dbType, dbConn) if err != nil { return fmt.Errorf("could not connect to database: %w", err) } defer xormDB.Close() pogrebDB, err := database.NewPogreb(dbPogrebConn) if err != nil { return fmt.Errorf("could not open database: %w", err) } defer pogrebDB.Close() fmt.Printf("Start migration from \"%s\" to \"%s:%s\" ...\n", dbPogrebConn, dbType, dbConn) certs, err := pogrebDB.Items(0, 0) if err != nil { return err } for _, cert := range certs { if err := xormDB.Put(cert.Domain, cert.Raw()); err != nil { return err } } fmt.Println("... done") return nil } func listCerts(ctx *cli.Context) error { certDB, err := openCertDB(ctx) if err != nil { return err } items, err := certDB.Items(0, 0) if err != nil { return err } fmt.Printf("Domain\tValidTill\n\n") for _, cert := range items { if cert.Domain[0] == '.' { cert.Domain = "*" + cert.Domain } fmt.Printf("%s\t%s\n", cert.Domain, time.Unix(cert.ValidTill, 0).Format(time.RFC3339)) } return nil } func removeCert(ctx *cli.Context) error { if ctx.Args().Len() < 1 { return fmt.Errorf("'certs remove' requires at least one domain as an argument") } domains := ctx.Args().Slice() certDB, err := openCertDB(ctx) if err != nil { return err } for _, domain := range domains { fmt.Printf("Removing domain %s from the database...\n", domain) if err := certDB.Delete(domain); err != nil { return err } } if err := certDB.Close(); err != nil { return err } return nil } func openCertDB(ctx *cli.Context) (certDB database.CertDB, err error) { if ctx.String("db-type") != "" { certDB, err = database.NewXormDB(ctx.String("db-type"), ctx.String("db-conn")) if err != nil { return nil, fmt.Errorf("could not connect to database: %w", err) } } else { // TODO: remove in next version fmt.Println(` ###################### ## W A R N I N G !!! # ###################### You use "pogreb" witch is deprecated and will be removed in the next version. Please switch to sqlite, mysql or postgres !!! The simplest way is, to use './pages certs migrate' and set environment var DB_TYPE to 'sqlite' on next start. `) log.Error().Msg("depricated \"pogreb\" used\n") certDB, err = database.NewPogreb(ctx.String("db-pogreb")) if err != nil { return nil, fmt.Errorf("could not create database: %w", err) } } return certDB, nil }