1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
|
package main
import (
"os"
"fmt"
"flag"
"errors"
"net/http"
"encoding/json"
"sanine.net/git/phlox/config"
"sanine.net/git/phlox/auth"
"sanine.net/git/phlox/page"
log "github.com/sirupsen/logrus"
)
func main() {
configFile := parseFlags()
conf := loadConfig(configFile)
sessions := auth.NewSessionContainer()
pages := loadPages(conf)
users := getUsers(conf)
// add phlox endpoints
http.HandleFunc("/phlox/login", func(w http.ResponseWriter, r *http.Request) {
Login(w, r, users, sessions, pages)
})
http.HandleFunc("/phlox/logout", func(w http.ResponseWriter, r *http.Request) {
Logout(w, r, sessions)
})
// add reverse proxy endpoints
for _, e := range conf.Endpoints {
addEndpoint(sessions, pages, e)
}
log.Infof("listening on %v", conf.ListenAddress)
log.Fatal(http.ListenAndServe(conf.ListenAddress, nil))
}
func parseFlags() string {
var configFile string
var username string
var passwd string
flag.StringVar(&configFile, "c", "./config.json", "the configuration file to use")
flag.StringVar(&passwd, "passwd", "", "hash a password")
flag.StringVar(&username, "user", "", "optional username for the JSON output of --passwd")
flag.Parse()
if passwd != "" {
// generate a user JSON block with the password hash
// and random salt, then exit without launching the
// phlox daemon
showHash(username, passwd)
os.Exit(0)
}
return configFile
}
func showHash(username, passwd string) {
salt, err := auth.GenerateSalt()
if err != nil {
fmt.Fprintf(os.Stderr, "failed to generate salt: %v\n", err.Error())
}
user := config.User{
Name: username,
PasswordHash: auth.HashPassword(passwd, salt),
Salt: salt,
}
blob, err := json.MarshalIndent(user, "", "\t")
if err != nil {
fmt.Fprintf(os.Stderr, "failed to generate JSON: %v\n", err.Error())
}
fmt.Println(string(blob))
}
func loadConfig(filename string) config.Config {
conf, err := config.Load(filename)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to load configuration file: %v\n", err.Error())
os.Exit(1)
}
return conf
}
func loadPages(c config.Config) page.Pages {
pages, err := page.LoadPages(c)
if err != nil {
fmt.Fprintf(os.Stderr, "failed to load html pages: %v\n", err.Error())
os.Exit(1)
}
return pages
}
func getUsers(c config.Config) map[string]config.User {
users := make(map[string]config.User)
for _, user := range c.Users {
users[user.Name] = user
}
return users
}
func authenticateRequest(r *http.Request, s *auth.Sessions) bool {
cookie, err := r.Cookie("phlox-session")
if errors.Is(err, http.ErrNoCookie) {
return false
}
id := cookie.Value
valid := s.IsSessionValid(id)
if !valid {
return false
}
s.TouchSession(id)
return true
}
|