package app import ( "encoding/json" "errors" "fmt" "io" "log" "net/http" ) type AddUserReq struct { Username string `json:"username"` Password string `json:"password"` } type AddUserRsp struct { ID int `json:"id"` Username string `json:"username"` } func AddUser(w http.ResponseWriter, r *http.Request) { log.Println("AddUser called") req, err := ReadBody[AddUserReq](r) if err != nil { WriteError(w, err) return } if !CheckToken(r) { WriteError(w, errors.New("token required")) return } provider, err := LoadProvider() if err != nil { WriteError(w, err) return } err = provider.AddUser(req.Username, req.Password) if err != nil { WriteError(w, err) return } err = provider.Save() if err != nil { WriteError(w, err) } user, err := provider.GetUser(req.Password) if err != nil { WriteError(w, err) return } WriteResponseCode(w, user, http.StatusCreated) } type DeleteUserReq struct { ID int `json:"id"` } func DeleteUser(w http.ResponseWriter, r *http.Request) { if !CheckToken(r) { WriteError(w, errors.New("token required")) return } req, err := ReadBody[DeleteUserReq](r) if err != nil { WriteError(w, err) return } provider, err := LoadProvider() if err != nil { WriteError(w, err) return } err = provider.DeleteUser(req.ID) if err != nil { WriteError(w, err) return } err = provider.Save() if err != nil { WriteError(w, err) return } w.WriteHeader(http.StatusNoContent) } func AllUsers(w http.ResponseWriter, r *http.Request) { fmt.Println("AllUsers called") if !CheckToken(r) { WriteError(w, errors.New("invalid token")) return } provider, err := LoadProvider() if err != nil { WriteError(w, err) return } WriteResponse(w, provider) } type GetConnectURLReq struct { ID int `json:"id"` Pass string `json:"pass"` } func GetUserURL(w http.ResponseWriter, r *http.Request) { req, err := ReadBody[GetConnectURLReq](r) if err != nil { WriteError(w, err) return } provider, err := LoadProvider() if err != nil { WriteError(w, err) return } user, err := provider.GetById(req.ID) if err != nil { WriteError(w, err) return } if user.Password != req.Pass { WriteError(w, errors.New("invalid password")) return } urlTemplate := "hysteria2://%s@%s:%s?obfs=salamander&obfs-password=%s&type=hysteria&mport&security=tls&sni=%s&alpn=h3&fp=chrome&allowInsecure=0#%s" authString := encodeURL(user) u := fmt.Sprintf(urlTemplate, authString, cfg.Host, cfg.Port, cfg.ObfsPassword, cfg.SNI, formatConfigName(cfg.NameFormat, user)) WriteResponse(w, u) } type AuthReq struct { Addr string `json:"addr"` Auth string `json:"auth"` Tx int `json:"tx"` } type AuthRsp struct { Ok bool `json:"ok"` ID string `json:"id"` } func DoAuth(w http.ResponseWriter, r *http.Request) { data, err := io.ReadAll(r.Body) if err != nil { w.WriteHeader(http.StatusBadRequest) log.Println(err) return } req := new(AuthReq) if err := json.Unmarshal(data, req); err != nil { w.WriteHeader(http.StatusBadRequest) log.Println(err) return } log.Printf("New auth request from %s, data %s", req.Addr, string(data)) reqUser, err := decodeURL(req.Auth) if err != nil { w.WriteHeader(http.StatusBadRequest) return } provider, err := LoadProvider() if err != nil { log.Println(err) w.WriteHeader(http.StatusBadRequest) return } user, err := provider.GetUser(reqUser.Password) if err != nil { w.WriteHeader(http.StatusBadRequest) return } res := &AuthRsp{true, user.Username} err = json.NewEncoder(w).Encode(res) if err != nil { w.WriteHeader(http.StatusBadRequest) } else { w.WriteHeader(http.StatusOK) } }