Files
H2Node/app/routes.go
2026-03-05 12:21:32 +03:00

253 lines
5.0 KiB
Go

package app
import (
"database/sql"
"encoding/base64"
"encoding/json"
"errors"
"fmt"
"io"
"log"
"net/http"
"strconv"
"github.com/go-chi/chi/v5"
)
func GetConfig(w http.ResponseWriter, _ *http.Request) {
res := map[string]any{
"config": cfg,
"hysteria": hysteriaCfg,
}
WriteResponse(w, res)
}
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)
}
func GetUser(w http.ResponseWriter, r *http.Request) {
fmt.Println("GetUser called")
if !CheckToken(r) {
WriteError(w, errors.New("token required"))
return
}
id := chi.URLParam(r, "id")
userId, err := strconv.Atoi(id)
if err != nil {
WriteError(w, err)
return
}
rep := NewUserRepository(db)
user, err := rep.GetById(userId)
WriteResponseOrError(w, user, err)
}
func GetUserKey(w http.ResponseWriter, r *http.Request) {
fmt.Println("GetUserKey called")
if !CheckToken(r) {
WriteError(w, errors.New("token required"))
return
}
id := chi.URLParam(r, "id")
userId, err := strconv.Atoi(id)
if err != nil {
WriteError(w, err)
return
}
rep := NewUserRepository(db)
user, err := rep.GetById(userId)
if err != nil {
WriteError(w, err)
return
}
WriteResponse(w, encodeURL(user))
}
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)
}
}