forked from tildetown/bbj2
		
	todo
This commit is contained in:
		
							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 | ||||||
|  | 	Hash     string | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 	http.HandleFunc("/instance_info", handler(opts, func(w http.ResponseWriter, req *http.Request) { | func getAuthInfo(opts options, req *http.Request) (ai AuthInfo, err error) { | ||||||
| 
 | 	ai.Username = req.Header.Get("User") | ||||||
| 		type instanceInfo struct { | 	ai.Hash = req.Header.Get("Auth") | ||||||
| 			InstanceName string `json:"instance_name"` | 	if ai.Username == "" { | ||||||
| 			AllowAnon    bool   `json:"allow_anon"` | 		err = errors.New("no User header set") | ||||||
| 			Admins       []string |  | ||||||
| 	} | 	} | ||||||
| 		writeResponse(w, BBJResponse{ |  | ||||||
| 			Data: instanceInfo{ |  | ||||||
| 				InstanceName: opts.Config.InstanceName, |  | ||||||
| 				AllowAnon:    opts.Config.AllowAnon, |  | ||||||
| 				Admins:       opts.Config.Admins, |  | ||||||
| 			}, |  | ||||||
| 		}) |  | ||||||
| 	})) |  | ||||||
| 
 | 
 | ||||||
|  | 	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…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user