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(`Hi
102 %s, Welcome to Flounder! You can now log into your account at
103 https://flounder.online/login -- For more information about
104 Flounder, check out https://admin.flounder.online/
105
106 Let me know if you have any questions, and have fun!
107
108 Alex
109 `, username))
110 }
111 return nil
112}
113
114func renameUser(oldUsername string, newUsername string) error {
115 err := isOkUsername(newUsername)
116 if err != nil {
117 return err
118 }
119 res, err := DB.Exec("UPDATE user set username = ? WHERE username = ?", newUsername, oldUsername)
120 if err != nil {
121 return err
122 }
123 rowsAffected, err := res.RowsAffected()
124 if rowsAffected != 1 {
125 return fmt.Errorf("No User updated %s %s", oldUsername, newUsername)
126 } else if err != nil {
127 return err
128 }
129 userFolder := path.Join(c.FilesDirectory, oldUsername)
130 newUserFolder := path.Join(c.FilesDirectory, newUsername)
131 err = os.Rename(userFolder, newUserFolder)
132 if err != nil {
133 // This would be bad. User in broken, insecure state.
134 // TODO some sort of better handling?
135 return err
136 }
137 log.Printf("Changed username from %s to %s", oldUsername, newUsername)
138 return nil
139}
140
141func deleteUser(username string) error {
142 _, err := DB.Exec("DELETE FROM user WHERE username = $1", username)
143 if err != nil {
144 return err
145 }
146 username = filepath.Clean(username)
147 err = os.RemoveAll(path.Join(c.FilesDirectory, username))
148 if err != nil {
149 // bad state
150 return err
151 }
152 log.Println("Deleted user", username)
153 return nil
154}