forked from tildetown/bbj2
todo
parent
38854d5461
commit
77b65feb29
|
@ -35,7 +35,7 @@ type iostreams struct {
|
||||||
Out io.Writer
|
Out io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
type Opts struct {
|
type options struct {
|
||||||
ConfigPath string
|
ConfigPath string
|
||||||
IO iostreams
|
IO iostreams
|
||||||
Log func(string)
|
Log func(string)
|
||||||
|
@ -53,7 +53,7 @@ func main() {
|
||||||
Err: os.Stderr,
|
Err: os.Stderr,
|
||||||
Out: os.Stdout,
|
Out: os.Stdout,
|
||||||
}
|
}
|
||||||
opts := &Opts{
|
opts := &options{
|
||||||
ConfigPath: *configFlag,
|
ConfigPath: *configFlag,
|
||||||
Reset: *resetFlag,
|
Reset: *resetFlag,
|
||||||
IO: io,
|
IO: io,
|
||||||
|
@ -75,7 +75,7 @@ func main() {
|
||||||
|
|
||||||
type Teardown func()
|
type Teardown func()
|
||||||
|
|
||||||
func setupDB(opts *Opts) (Teardown, error) {
|
func setupDB(opts *options) (Teardown, error) {
|
||||||
db, err := sql.Open("sqlite3", opts.Config.DBPath)
|
db, err := sql.Open("sqlite3", opts.Config.DBPath)
|
||||||
fmt.Printf("DBG %#v\n", db)
|
fmt.Printf("DBG %#v\n", db)
|
||||||
|
|
||||||
|
@ -84,7 +84,7 @@ func setupDB(opts *Opts) (Teardown, error) {
|
||||||
return func() { db.Close() }, err
|
return func() { db.Close() }, err
|
||||||
}
|
}
|
||||||
|
|
||||||
func _main(opts *Opts) error {
|
func _main(opts *options) error {
|
||||||
cfg, err := parseConfig(opts.ConfigPath)
|
cfg, err := parseConfig(opts.ConfigPath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "could not read config file '%s'", opts.ConfigPath)
|
fmt.Fprintf(os.Stderr, "could not read config file '%s'", opts.ConfigPath)
|
||||||
|
@ -115,7 +115,7 @@ func _main(opts *Opts) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func ensureSchema(opts Opts) error {
|
func ensureSchema(opts options) error {
|
||||||
db := opts.DB
|
db := opts.DB
|
||||||
|
|
||||||
if opts.Reset {
|
if opts.Reset {
|
||||||
|
@ -150,7 +150,7 @@ func ensureSchema(opts Opts) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func handler(opts Opts, f http.HandlerFunc) http.HandlerFunc {
|
func handler(opts options, f http.HandlerFunc) http.HandlerFunc {
|
||||||
// TODO make this more real
|
// TODO make this more real
|
||||||
return func(w http.ResponseWriter, req *http.Request) {
|
return func(w http.ResponseWriter, req *http.Request) {
|
||||||
opts.Log(req.URL.Path)
|
opts.Log(req.URL.Path)
|
||||||
|
@ -188,24 +188,56 @@ func writeErrorResponse(w http.ResponseWriter, code int, resp BBJResponse) {
|
||||||
|
|
||||||
// NB breaking: i'm not just returning 200 always but using http status codes
|
// NB breaking: i'm not just returning 200 always but using http status codes
|
||||||
|
|
||||||
func setupAPI(opts Opts) {
|
type AuthInfo struct {
|
||||||
|
Username string
|
||||||
http.HandleFunc("/instance_info", handler(opts, func(w http.ResponseWriter, req *http.Request) {
|
Hash string
|
||||||
|
|
||||||
type instanceInfo struct {
|
|
||||||
InstanceName string `json:"instance_name"`
|
|
||||||
AllowAnon bool `json:"allow_anon"`
|
|
||||||
Admins []string
|
|
||||||
}
|
}
|
||||||
writeResponse(w, BBJResponse{
|
|
||||||
Data: instanceInfo{
|
|
||||||
InstanceName: opts.Config.InstanceName,
|
|
||||||
AllowAnon: opts.Config.AllowAnon,
|
|
||||||
Admins: opts.Config.Admins,
|
|
||||||
},
|
|
||||||
})
|
|
||||||
}))
|
|
||||||
|
|
||||||
|
func getAuthInfo(opts options, req *http.Request) (ai AuthInfo, err error) {
|
||||||
|
ai.Username = req.Header.Get("User")
|
||||||
|
ai.Hash = req.Header.Get("Auth")
|
||||||
|
if ai.Username == "" {
|
||||||
|
err = errors.New("no User header set")
|
||||||
|
}
|
||||||
|
|
||||||
|
if ai.Username == "anon" {
|
||||||
|
if !opts.Config.AllowAnon {
|
||||||
|
err = errors.New("anonymous access disabled")
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = checkAuth(opts, ai)
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func checkAuth(opts options, ai AuthInfo) error {
|
||||||
|
db := opts.DB
|
||||||
|
stmt, err := db.Prepare("select auth_hash from users where user_name = ?")
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("db error: %w", err)
|
||||||
|
}
|
||||||
|
defer stmt.Close()
|
||||||
|
|
||||||
|
opts.Logf("querying for %s", ai.Username)
|
||||||
|
|
||||||
|
var authHash string
|
||||||
|
if err = stmt.QueryRow(ai.Username).Scan(&authHash); err != nil {
|
||||||
|
if strings.Contains(err.Error(), "no rows in result") {
|
||||||
|
return errors.New("no such user")
|
||||||
|
}
|
||||||
|
return fmt.Errorf("db error: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if authHash != ai.Hash {
|
||||||
|
return errors.New("bad credentials")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func setupAPI(opts options) {
|
||||||
serverErr := func(w http.ResponseWriter, err error) {
|
serverErr := func(w http.ResponseWriter, err error) {
|
||||||
opts.Logf(err.Error())
|
opts.Logf(err.Error())
|
||||||
writeErrorResponse(w, 500, BBJResponse{
|
writeErrorResponse(w, 500, BBJResponse{
|
||||||
|
@ -228,6 +260,21 @@ func setupAPI(opts Opts) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
http.HandleFunc("/instance_info", handler(opts, func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
type instanceInfo struct {
|
||||||
|
InstanceName string `json:"instance_name"`
|
||||||
|
AllowAnon bool `json:"allow_anon"`
|
||||||
|
Admins []string
|
||||||
|
}
|
||||||
|
writeResponse(w, BBJResponse{
|
||||||
|
Data: instanceInfo{
|
||||||
|
InstanceName: opts.Config.InstanceName,
|
||||||
|
AllowAnon: opts.Config.AllowAnon,
|
||||||
|
Admins: opts.Config.Admins,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}))
|
||||||
|
|
||||||
http.HandleFunc("/user_register", handler(opts, func(w http.ResponseWriter, req *http.Request) {
|
http.HandleFunc("/user_register", handler(opts, func(w http.ResponseWriter, req *http.Request) {
|
||||||
if req.Method != "POST" {
|
if req.Method != "POST" {
|
||||||
badMethod(w)
|
badMethod(w)
|
||||||
|
@ -236,7 +283,7 @@ func setupAPI(opts Opts) {
|
||||||
|
|
||||||
type AuthArgs struct {
|
type AuthArgs struct {
|
||||||
Username string `json:"user_name"`
|
Username string `json:"user_name"`
|
||||||
AuthHash string `json:"auth_hash"`
|
Hash string `json:"auth_hash"`
|
||||||
}
|
}
|
||||||
|
|
||||||
var args AuthArgs
|
var args AuthArgs
|
||||||
|
@ -245,44 +292,34 @@ func setupAPI(opts Opts) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
if args.AuthHash == "" || args.Username == "" {
|
if args.Hash == "" || args.Username == "" {
|
||||||
invalidArgs(w)
|
invalidArgs(w)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
db := opts.DB
|
|
||||||
stmt, err := db.Prepare("select auth_hash from users where user_name = ?")
|
|
||||||
if err != nil {
|
|
||||||
serverErr(w, err)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
defer stmt.Close()
|
|
||||||
|
|
||||||
opts.Logf("querying for %s", args.Username)
|
opts.Logf("querying for %s", args.Username)
|
||||||
|
|
||||||
var authHash string
|
if err := checkAuth(opts, AuthInfo{args.Username, args.Hash}); err == nil {
|
||||||
err = stmt.QueryRow(args.Username).Scan(&authHash)
|
|
||||||
if err == nil {
|
|
||||||
opts.Logf("found %s", args.Username)
|
opts.Logf("found %s", args.Username)
|
||||||
// code 4 apparently
|
// code 4 apparently
|
||||||
writeErrorResponse(w, 403, BBJResponse{
|
writeErrorResponse(w, 403, BBJResponse{
|
||||||
Error: true,
|
Error: true,
|
||||||
Data: "user already exists",
|
Data: "user already exists",
|
||||||
})
|
})
|
||||||
return
|
} else if err.Error() != "no such user" {
|
||||||
} else if err != nil && !strings.Contains(err.Error(), "no rows in result") {
|
|
||||||
serverErr(w, err)
|
serverErr(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
stmt, err = db.Prepare(`INSERT INTO users VALUES (?, ?, ?, "", "", 0, 0, ?)`)
|
db := opts.DB
|
||||||
|
stmt, err := db.Prepare(`INSERT INTO users VALUES (?, ?, ?, "", "", 0, 0, ?)`)
|
||||||
id, err := uuid.NewRandom()
|
id, err := uuid.NewRandom()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
serverErr(w, err)
|
serverErr(w, err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = stmt.Exec(id, args.Username, args.AuthHash, time.Now())
|
_, err = stmt.Exec(id, args.Username, args.Hash, time.Now())
|
||||||
if err != nil {
|
if err != nil {
|
||||||
serverErr(w, err)
|
serverErr(w, err)
|
||||||
}
|
}
|
||||||
|
@ -375,7 +412,29 @@ func setupAPI(opts Opts) {
|
||||||
}))
|
}))
|
||||||
|
|
||||||
http.HandleFunc("/thread_create", handler(opts, func(w http.ResponseWriter, req *http.Request) {
|
http.HandleFunc("/thread_create", handler(opts, func(w http.ResponseWriter, req *http.Request) {
|
||||||
|
if req.Method != "POST" {
|
||||||
|
badMethod(w)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
authInfo, err := getAuthInfo(opts, req)
|
||||||
|
if err != nil {
|
||||||
|
writeErrorResponse(w, 403, BBJResponse{
|
||||||
|
Error: true,
|
||||||
|
Data: err.Error(),
|
||||||
|
})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
fmt.Printf("DBG %#v\n", authInfo)
|
||||||
|
|
||||||
|
type threadCreateArgs struct {
|
||||||
|
Title string
|
||||||
|
Body string
|
||||||
|
}
|
||||||
|
|
||||||
// TODO
|
// TODO
|
||||||
|
|
||||||
writeResponse(w, BBJResponse{Data: "TODO"})
|
writeResponse(w, BBJResponse{Data: "TODO"})
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue