204 lines
6.4 KiB
Go
204 lines
6.4 KiB
Go
package hvpnnode3
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"log/slog"
|
|
"net/http"
|
|
|
|
"github.com/felixge/httpsnoop"
|
|
"github.com/google/uuid"
|
|
|
|
"gitea.hbanafa.com/HeshamTB/hvpn-node3/proto"
|
|
)
|
|
|
|
type CtxKey string
|
|
const CtxReqID CtxKey = "request_id"
|
|
|
|
func HandleGetNodeInfo(wgLink *WGLink) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
reqID := r.Context().Value(CtxReqID).(uuid.UUID)
|
|
debug("Preparing node info for", reqID)
|
|
dev, err := wgLink.Device(wgLink.Name)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
json.NewEncoder(w).Encode(
|
|
proto.NodePublicInfo{
|
|
PublicKey: dev.PublicKey.String(),
|
|
UDPPort: dev.ListenPort,
|
|
Endpoint: wgLink.Endpoint,
|
|
// TODO: Send endpoint for clients to connect
|
|
},
|
|
)
|
|
}
|
|
}
|
|
|
|
func HandleGetPeer(wgLink *WGLink) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
reqID := r.Context().Value(CtxReqID).(uuid.UUID)
|
|
pubkey := r.PathValue("pubkey")
|
|
debug(pubkey, reqID)
|
|
peer, err := wgLink.GetPeer(pubkey)
|
|
if err != nil {
|
|
if errors.Is(err, proto.PeerDoesNotExist){
|
|
json.NewEncoder(w).Encode(
|
|
proto.ErrJSONResponse{Message: "Peer does not exist"},
|
|
)
|
|
w.WriteHeader(http.StatusNotFound)
|
|
return
|
|
}
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
return
|
|
}
|
|
err = json.NewEncoder(w).Encode(proto.WgPeerToPeer(*peer))
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
func HandleGetPeers(wgLink *WGLink) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
reqID := r.Context().Value(CtxReqID).(uuid.UUID)
|
|
debug("GET Peers for", reqID)
|
|
dev, err := wgLink.Device(wgLink.Name)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
slog.Error(err.Error())
|
|
return
|
|
}
|
|
var peers []proto.Peer
|
|
for _, peer := range dev.Peers {
|
|
p := proto.WgPeerToPeer(peer)
|
|
peers = append(peers, p)
|
|
}
|
|
err = json.NewEncoder(w).Encode(peers)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
}
|
|
return
|
|
}
|
|
}
|
|
|
|
func HandlePostPeer(wgLink *WGLink) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r* http.Request) {
|
|
reqID := r.Context().Value(CtxReqID).(uuid.UUID)
|
|
debug("POST Peer for", reqID)
|
|
peerRequest := proto.CreatePeerRequest{}
|
|
err := json.NewDecoder(r.Body).Decode(&peerRequest)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
json.NewEncoder(w).Encode(
|
|
&proto.ErrJSONResponse{Message: "Invalid request JSON"},
|
|
)
|
|
return
|
|
}
|
|
|
|
if valid := ValidKey(peerRequest.PublicKey); !valid {
|
|
w.WriteHeader(http.StatusBadRequest)
|
|
json.NewEncoder(w).Encode(
|
|
proto.ErrJSONResponse{Message: "Invalid public key"},
|
|
)
|
|
return
|
|
}
|
|
|
|
exists, err := wgLink.Exists(peerRequest.PublicKey)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
json.NewEncoder(w).Encode(
|
|
proto.ErrJSONResponse{Message: "Error while checking peer existance"},
|
|
)
|
|
return
|
|
}
|
|
if exists {
|
|
debugf("Peer %s already exists", reqID, peerRequest.PublicKey)
|
|
w.WriteHeader(http.StatusFound)
|
|
peer, err := wgLink.GetPeer(peerRequest.PublicKey)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
return
|
|
}
|
|
json.NewEncoder(w).Encode(
|
|
proto.WgPeerToPeer(*peer),
|
|
)
|
|
return
|
|
}
|
|
|
|
peer, err := wgLink.AddPeer(peerRequest.PublicKey)
|
|
if err != nil {
|
|
slog.Error(err.Error())
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
json.NewEncoder(w).Encode(
|
|
proto.ErrJSONResponse{Message: "Error while adding peer"},
|
|
)
|
|
return
|
|
}
|
|
debugf("Allocated IP: %s", reqID, peer.AllowedIPs[0].IP.String())
|
|
w.WriteHeader(http.StatusCreated)
|
|
json.NewEncoder(w).Encode(
|
|
proto.WgPeerToPeer(*peer),
|
|
)
|
|
}
|
|
}
|
|
|
|
func HandleDeletePeer(wg *WGLink) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
reqId := r.Context().Value(CtxReqID).(uuid.UUID)
|
|
pubkey := r.PathValue("pubkey")
|
|
debugf("DELETE Peer %s", reqId, pubkey)
|
|
exists, err := wg.Exists(pubkey)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
slog.Error(err.Error())
|
|
return
|
|
}
|
|
if !exists {
|
|
w.WriteHeader(http.StatusNotFound)
|
|
json.NewEncoder(w).Encode(
|
|
proto.ErrJSONResponse{Message: "Peer does not exist"},
|
|
)
|
|
return
|
|
}
|
|
err = wg.DeletePeer(pubkey)
|
|
if err != nil {
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
json.NewEncoder(w).Encode(
|
|
proto.ErrJSONResponse{Message: "Error while deleting peer"},
|
|
)
|
|
slog.Error(err.Error())
|
|
}
|
|
}
|
|
}
|
|
|
|
func HttpLogHandler2(h http.Handler) http.Handler {
|
|
// https://blog.kowalczyk.info/article/e00e89c3841e4f8c8c769a78b8a90b47/logging-http-requests-in-go.html
|
|
fn := func(w http.ResponseWriter, r* http.Request) {
|
|
reqID, _ := uuid.NewRandom()
|
|
rCtx := context.WithValue(r.Context(), CtxReqID, reqID)
|
|
r = r.WithContext(rCtx)
|
|
slog.Info(fmt.Sprintf("Starting request with ID: %s", reqID.String()))
|
|
m := httpsnoop.CaptureMetrics(h, w, r)
|
|
msg := fmt.Sprintf(
|
|
"[HTTP] %s %s %s %d %s %s", r.RemoteAddr, r.Method,
|
|
r.URL.String(),m.Code, m.Duration, reqID.String())
|
|
slog.Info(msg)
|
|
}
|
|
return http.HandlerFunc(fn)
|
|
}
|
|
|
|
func debugf(format string, reqID uuid.UUID, args ...any) {
|
|
format = format + " " + reqID.String()
|
|
slog.Debug(fmt.Sprintf(format, args...))
|
|
}
|
|
|
|
func debug(msg string, reqID uuid.UUID) {
|
|
msg = msg + " " + reqID.String()
|
|
debugf("%s", reqID, msg)
|
|
}
|