123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- package main
- import (
- "bytes"
- "fmt"
- "io/ioutil"
- "regexp"
- "syscall"
- "github.com/lib/pq"
- uuid "github.com/satori/go.uuid"
- "github.com/jmoiron/sqlx"
- "github.com/knadh/goyesql"
- "github.com/knadh/listmonk/models"
- "github.com/spf13/viper"
- "golang.org/x/crypto/bcrypt"
- "golang.org/x/crypto/ssh/terminal"
- )
- // install runs the first time setup of creating and
- // migrating the database and creating the super user.
- func install(app *App, qMap goyesql.Queries) {
- var (
- email, pw, pw2 []byte
- err error
- // Pseudo e-mail validation using Regexp, well ...
- emRegex, _ = regexp.Compile("(.+?)@(.+?)")
- )
- fmt.Println("** First time installation. **")
- fmt.Println("** IMPORTANT: This will wipe existing listmonk tables and types. **")
- fmt.Println("\n")
- for len(email) == 0 {
- fmt.Print("Enter the superadmin login e-mail: ")
- if _, err = fmt.Scanf("%s", &email); err != nil {
- logger.Fatalf("Error reading e-mail from the terminal: %v", err)
- }
- if !emRegex.Match(email) {
- logger.Println("Please enter a valid e-mail")
- email = []byte{}
- }
- }
- for len(pw) < 8 {
- fmt.Print("Enter the superadmin password (min 8 chars): ")
- if pw, err = terminal.ReadPassword(int(syscall.Stdin)); err != nil {
- logger.Fatalf("Error reading password from the terminal: %v", err)
- }
- fmt.Println("")
- if len(pw) < 8 {
- logger.Println("Password should be min 8 characters")
- pw = []byte{}
- }
- }
- for len(pw2) < 8 {
- fmt.Print("Repeat the superadmin password: ")
- if pw2, err = terminal.ReadPassword(int(syscall.Stdin)); err != nil {
- logger.Fatalf("Error reading password from the terminal: %v", err)
- }
- fmt.Println("")
- if len(pw2) < 8 {
- logger.Println("Password should be min 8 characters")
- pw2 = []byte{}
- }
- }
- // Validate.
- if !bytes.Equal(pw, pw2) {
- logger.Fatalf("Passwords don't match")
- }
- // Hash the password.
- hash, err := bcrypt.GenerateFromPassword(pw, bcrypt.DefaultCost)
- if err != nil {
- logger.Fatalf("Error hashing password: %v", err)
- }
- // Migrate the tables.
- err = installMigrate(app.DB)
- if err != nil {
- logger.Fatalf("Error migrating DB schema: %v", err)
- }
- // Load the queries.
- var q Queries
- if err := scanQueriesToStruct(&q, qMap, app.DB.Unsafe()); err != nil {
- logger.Fatalf("error loading SQL queries: %v", err)
- }
- // Create the superadmin user.
- if _, err := q.CreateUser.Exec(
- string(email),
- models.UserTypeSuperadmin, // name
- string(hash),
- models.UserTypeSuperadmin,
- models.UserStatusEnabled,
- ); err != nil {
- logger.Fatalf("Error creating superadmin user: %v", err)
- }
- // Sample list.
- var listID int
- if err := q.CreateList.Get(&listID,
- uuid.NewV4().String(),
- "Default list",
- models.ListTypePublic,
- pq.StringArray{"test"},
- ); err != nil {
- logger.Fatalf("Error creating superadmin user: %v", err)
- }
- // Sample subscriber.
- name := bytes.Split(email, []byte("@"))
- if _, err := q.UpsertSubscriber.Exec(
- uuid.NewV4(),
- email,
- bytes.Title(name[0]),
- `{"type": "known", "good": true}`,
- pq.Int64Array{int64(listID)},
- ); err != nil {
- logger.Fatalf("Error creating subscriber: %v", err)
- }
- // Default template.
- tplBody, err := ioutil.ReadFile("default-template.html")
- if err != nil {
- tplBody = []byte(tplTag)
- }
- var tplID int
- if err := q.CreateTemplate.Get(&tplID,
- "Default template",
- string(tplBody),
- ); err != nil {
- logger.Fatalf("Error creating default template: %v", err)
- }
- if _, err := q.SetDefaultTemplate.Exec(tplID); err != nil {
- logger.Fatalf("Error setting default template: %v", err)
- }
- logger.Printf("Setup complete")
- logger.Printf(`Run the program and login with the username "superadmin" and your password at %s`,
- viper.GetString("server.address"))
- }
- // installMigrate executes the SQL schema and creates the necessary tables and types.
- func installMigrate(db *sqlx.DB) error {
- q, err := ioutil.ReadFile("schema.sql")
- if err != nil {
- return err
- }
- _, err = db.Query(string(q))
- if err != nil {
- return err
- }
- return nil
- }
|