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}