all repos — flounder @ 58678be13fb73c3cd85f9d5afada9614f2d5c8fc

A small site builder for the Gemini protocol

admin.go (view raw)

  1package main
  2
  3// Commands for administering your instance
  4// reset user password -> generate link
  5// delete user
  6
  7// Run some scripts to setup your instance
  8
  9import (
 10	"flag"
 11	"fmt"
 12	"golang.org/x/crypto/ssh/terminal"
 13	"io/ioutil"
 14	"log"
 15	"os"
 16	"path"
 17	"path/filepath"
 18	"syscall"
 19)
 20
 21// TODO improve cli
 22func runAdminCommand() {
 23	args := flag.Args() // again?
 24	if len(args) < 3 {
 25		fmt.Println("Expected subcommand with parameter activate-user|delete-user|make-admin|rename-user")
 26		os.Exit(1)
 27	}
 28	var err error
 29	switch args[1] {
 30	case "activate-user":
 31		username := args[2]
 32		err = activateUser(username)
 33	case "delete-user":
 34		username := args[2]
 35		// TODO add confirmation
 36		err = deleteUser(username)
 37	case "make-admin":
 38		username := args[2]
 39		err = makeAdmin(username)
 40	case "rename-user":
 41		username := args[2]
 42		newUsername := args[3]
 43		err = renameUser(username, newUsername)
 44	case "set-password": // TODO FIX -- broken atm
 45		username := args[2]
 46		fmt.Print("Enter New Password: ")
 47		bytePassword, err := terminal.ReadPassword(int(syscall.Stdin))
 48		if err != nil {
 49			setPassword(username, bytePassword)
 50		}
 51	}
 52	if err != nil {
 53		log.Fatal(err)
 54	}
 55	// reset password
 56
 57}
 58
 59func makeAdmin(username string) error {
 60	_, err := DB.Exec("UPDATE user SET admin = true WHERE username = $1", username)
 61	if err != nil {
 62		return err
 63	}
 64	log.Println("Made admin user", username)
 65	return nil
 66}
 67
 68func setPassword(username string, newPass []byte) error {
 69	return nil
 70}
 71
 72func activateUser(username string) error {
 73	// Not ideal here
 74	row := DB.QueryRow("SELECT email FROM user where username = ?", username)
 75	var email string
 76	err := row.Scan(&email)
 77	if err != nil {
 78		return err
 79	}
 80	_, err = DB.Exec("UPDATE user SET active = true WHERE username = ?", username)
 81	if err != nil {
 82		// TODO verify 1 row updated
 83		return err
 84	}
 85	log.Println("Activated user", username)
 86	baseIndex := `# Welcome to Flounder!
 87## About
 88Welcome to an ultra-lightweight platform for making and sharing small websites. You can get started by editing this page -- remove this content and replace it with whatever you like! It will be live at <your-name>.flounder.online. You can go there right now to see what this page currently looks like. Here is a link to a page which will give you more information about using flounder:
 89=> //admin.flounder.online
 90
 91And here's a guide to the text format that Flounder uses to create pages, Gemini. These pages are converted into HTML so they can be displayed in a web browser.
 92=> //admin.flounder.online/gemini_text_guide.gmi
 93
 94Have fun!`
 95	// Redundant filepath.Clean call just in case.
 96	username = filepath.Clean(username)
 97	os.Mkdir(path.Join(c.FilesDirectory, username), os.ModePerm)
 98	ioutil.WriteFile(path.Join(c.FilesDirectory, username, "index.gmi"), []byte(baseIndex), 0644)
 99	os.Mkdir(path.Join(c.FilesDirectory, username), os.ModePerm)
100	if c.SMTPUsername != "" {
101		SendEmail(email, "Welcome to Flounder!", fmt.Sprintf(`
102Hi %s, Welcome to Flounder! You can now log into your account at
103https://flounder.online/login -- For more information about
104Flounder, check out https://admin.flounder.online/
105
106Let me know if you have any questions, and have fun!`, username))
107	}
108	return nil
109}
110
111func renameUser(oldUsername string, newUsername string) error {
112	err := isOkUsername(newUsername)
113	if err != nil {
114		return err
115	}
116	res, err := DB.Exec("UPDATE user set username = ? WHERE username = ?", newUsername, oldUsername)
117	if err != nil {
118		return err
119	}
120	rowsAffected, err := res.RowsAffected()
121	if rowsAffected != 1 {
122		return fmt.Errorf("No User updated %s %s", oldUsername, newUsername)
123	} else if err != nil {
124		return err
125	}
126	userFolder := path.Join(c.FilesDirectory, oldUsername)
127	newUserFolder := path.Join(c.FilesDirectory, newUsername)
128	err = os.Rename(userFolder, newUserFolder)
129	if err != nil {
130		// This would be bad. User in broken, insecure state.
131		// TODO some sort of better handling?
132		return err
133	}
134	log.Printf("Changed username from %s to %s", oldUsername, newUsername)
135	return nil
136}
137
138func deleteUser(username string) error {
139	_, err := DB.Exec("DELETE FROM user WHERE username = $1", username)
140	if err != nil {
141		return err
142	}
143	username = filepath.Clean(username)
144	err = os.RemoveAll(path.Join(c.FilesDirectory, username))
145	if err != nil {
146		// bad state
147		return err
148	}
149	log.Println("Deleted user", username)
150	return nil
151}