207 lines
4.1 KiB
Go
207 lines
4.1 KiB
Go
package app
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/base64"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"io"
|
|
"log"
|
|
"net/http"
|
|
"strconv"
|
|
|
|
"github.com/go-chi/chi/v5"
|
|
)
|
|
|
|
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
|
|
}
|
|
|
|
rep := NewUserRepository(db)
|
|
user, err := rep.AddUser(req.Username, 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
|
|
}
|
|
|
|
rep := NewUserRepository(db)
|
|
err = rep.DeleteUser(req.ID)
|
|
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
|
|
}
|
|
|
|
rep := NewUserRepository(db)
|
|
users, err := rep.GetUsers()
|
|
if err != nil {
|
|
WriteError(w, err)
|
|
return
|
|
}
|
|
WriteResponse(w, users)
|
|
}
|
|
|
|
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
|
|
}
|
|
|
|
rep := NewUserRepository(db)
|
|
user, err := rep.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,
|
|
hysteriaCfg.Listen,
|
|
hysteriaCfg.Obfs.Salamander.Password,
|
|
cfg.SNI,
|
|
formatConfigName(cfg.NameFormat, user),
|
|
)
|
|
WriteResponse(w, u)
|
|
}
|
|
|
|
func Sub(w http.ResponseWriter, r *http.Request) {
|
|
idS := chi.URLParam(r, "id")
|
|
id, err := strconv.Atoi(idS)
|
|
if err != nil {
|
|
WriteError(w, err)
|
|
return
|
|
}
|
|
|
|
rep := NewUserRepository(db)
|
|
user, err := rep.GetById(id)
|
|
if err != nil {
|
|
WriteError(w, err)
|
|
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,
|
|
hysteriaCfg.Listen,
|
|
hysteriaCfg.Obfs.Salamander.Password,
|
|
cfg.SNI,
|
|
formatConfigName(cfg.NameFormat, user),
|
|
)
|
|
w.Write([]byte(base64.StdEncoding.EncodeToString([]byte(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)
|
|
log.Println(err)
|
|
return
|
|
}
|
|
|
|
rep := NewUserRepository(db)
|
|
user, err := rep.GetById(reqUser.ID)
|
|
if err != nil {
|
|
if errors.Is(err, sql.ErrNoRows) {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
log.Println(err)
|
|
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)
|
|
}
|
|
}
|