peermap: add map exporter api

This commit is contained in:
rkonfj
2024-03-27 21:30:53 +08:00
parent 7325647a35
commit eba2c1a6da
5 changed files with 98 additions and 26 deletions

2
.gitignore vendored
View File

@@ -1,6 +1,6 @@
*.exe *.exe
pgcli-* pgcli-*
pgserve-* pgmap-*
wintun/ wintun/
*.zip *.zip
*.dll *.dll

View File

@@ -4,6 +4,7 @@ import (
"context" "context"
"errors" "errors"
"fmt" "fmt"
"log/slog"
"net/http" "net/http"
"os" "os"
"os/signal" "os/signal"
@@ -24,6 +25,14 @@ func main() {
Version: fmt.Sprintf("%s, commit %s", Version, Commit), Version: fmt.Sprintf("%s, commit %s", Version, Commit),
Short: "Run a peermap server daemon", Short: "Run a peermap server daemon",
SilenceUsage: true, SilenceUsage: true,
PreRunE: func(cmd *cobra.Command, args []string) error {
verbose, err := cmd.Flags().GetInt("verbose")
if err != nil {
return err
}
slog.SetLogLoggerLevel(slog.Level(verbose))
return nil
},
Args: cobra.NoArgs, Args: cobra.NoArgs,
RunE: run, RunE: run,
} }

47
peermap/exporter/auth.go Normal file
View File

@@ -0,0 +1,47 @@
package exporter
import (
"crypto/sha256"
"encoding/base64"
"encoding/json"
"github.com/rkonfj/peerguard/secure"
"github.com/rkonfj/peerguard/secure/aescbc"
)
var algo secure.SymmAlgo
func SetSecretKey(key string) {
sum := sha256.Sum256([]byte(key))
algo = aescbc.New(func(pubKey string) ([]byte, error) {
return sum[:], nil
})
}
type Instruction struct {
}
func CheckToken(token string) (*Instruction, error) {
b, err := base64.StdEncoding.DecodeString(token)
if err != nil {
return nil, err
}
plain, err := algo.Decrypt(b, "")
if err != nil {
return nil, err
}
var ins Instruction
return &ins, json.Unmarshal(plain, &ins)
}
func GenerateToken(ins Instruction) (string, error) {
b, err := json.Marshal(ins)
if err != nil {
return "", err
}
chiper, err := algo.Encrypt(b, "")
if err != nil {
return "", err
}
return base64.StdEncoding.EncodeToString(chiper), nil
}

View File

@@ -0,0 +1,12 @@
package exporter
type NetworkHead struct {
ID string `json:"n"`
PeersCount int `json:"c"`
CreateTime string `json:"t"`
}
type Network struct {
ID string `json:"n"`
Peers []string `json:"p"`
}

View File

@@ -2,7 +2,6 @@ package peermap
import ( import (
"context" "context"
"crypto/md5"
"encoding/base64" "encoding/base64"
"encoding/json" "encoding/json"
"fmt" "fmt"
@@ -17,16 +16,11 @@ import (
cmap "github.com/orcaman/concurrent-map/v2" cmap "github.com/orcaman/concurrent-map/v2"
"github.com/rkonfj/peerguard/peer" "github.com/rkonfj/peerguard/peer"
"github.com/rkonfj/peerguard/peermap/auth" "github.com/rkonfj/peerguard/peermap/auth"
"github.com/rkonfj/peerguard/peermap/exporter"
"github.com/rkonfj/peerguard/peermap/oidc" "github.com/rkonfj/peerguard/peermap/oidc"
"golang.org/x/time/rate" "golang.org/x/time/rate"
) )
type Network struct {
ID string `json:"id"`
PeersCount int `json:"peersCount"`
CreateTime string `json:"createTime"`
}
type Peer struct { type Peer struct {
peerMap *PeerMap peerMap *PeerMap
secret auth.JSONSecret secret auth.JSONSecret
@@ -236,6 +230,7 @@ func New(cfg Config) (*PeerMap, error) {
if err := cfg.applyDefaults(); err != nil { if err := cfg.applyDefaults(); err != nil {
return nil, err return nil, err
} }
exporter.SetSecretKey(cfg.SecretKey)
mux := http.NewServeMux() mux := http.NewServeMux()
pm := PeerMap{ pm := PeerMap{
httpServer: &http.Server{Handler: mux, Addr: cfg.Listen}, httpServer: &http.Server{Handler: mux, Addr: cfg.Listen},
@@ -247,6 +242,7 @@ func New(cfg Config) (*PeerMap, error) {
mux.HandleFunc("/", pm.handleWebsocket) mux.HandleFunc("/", pm.handleWebsocket)
mux.HandleFunc("/networks", pm.handleQueryNetworks) mux.HandleFunc("/networks", pm.handleQueryNetworks)
mux.HandleFunc("/peers", pm.handleQueryNetworkPeers) mux.HandleFunc("/peers", pm.handleQueryNetworkPeers)
mux.HandleFunc("/network/token", oidc.HandleNotifyToken) mux.HandleFunc("/network/token", oidc.HandleNotifyToken)
mux.HandleFunc("/oidc/", oidc.RedirectAuthURL) mux.HandleFunc("/oidc/", oidc.RedirectAuthURL)
mux.HandleFunc("/oidc/authorize/", pm.handleOIDCAuthorize) mux.HandleFunc("/oidc/authorize/", pm.handleOIDCAuthorize)
@@ -254,10 +250,17 @@ func New(cfg Config) (*PeerMap, error) {
} }
func (pm *PeerMap) handleQueryNetworks(w http.ResponseWriter, r *http.Request) { func (pm *PeerMap) handleQueryNetworks(w http.ResponseWriter, r *http.Request) {
exporterToken := r.Header.Get("X-Token")
_, err := exporter.CheckToken(exporterToken)
if err != nil {
slog.Debug("ExporterAuthFailed", "details", err)
w.WriteHeader(http.StatusUnauthorized)
return
}
items := pm.networkMap.Items() items := pm.networkMap.Items()
networks := make([]Network, 0, len(items)) networks := make([]exporter.NetworkHead, 0, len(items))
for k, v := range items { for k, v := range items {
networks = append(networks, Network{ networks = append(networks, exporter.NetworkHead{
ID: k, ID: k,
PeersCount: v.Count(), PeersCount: v.Count(),
CreateTime: fmt.Sprintf("%d", v.createTime.UnixNano()), CreateTime: fmt.Sprintf("%d", v.createTime.UnixNano()),
@@ -267,22 +270,25 @@ func (pm *PeerMap) handleQueryNetworks(w http.ResponseWriter, r *http.Request) {
} }
func (pm *PeerMap) handleQueryNetworkPeers(w http.ResponseWriter, r *http.Request) { func (pm *PeerMap) handleQueryNetworkPeers(w http.ResponseWriter, r *http.Request) {
jsonSecret, err := pm.authenticator.ParseSecret(r.Header.Get("X-Network")) exporterToken := r.Header.Get("X-Token")
_, err := exporter.CheckToken(exporterToken)
if err != nil { if err != nil {
slog.Debug("Authenticate failed", "err", err, "network", r.Header.Get("X-Network")) slog.Debug("ExporterAuthFailed", "details", err)
w.WriteHeader(http.StatusForbidden) w.WriteHeader(http.StatusUnauthorized)
return return
} }
if networkContext, ok := pm.networkMap.Get(jsonSecret.Network); ok { var networks []exporter.Network
items := networkContext.Items() for item := range pm.networkMap.IterBuffered() {
peers := make([]string, 0, len(items)) var peers []string
for _, v := range items { for _, peer := range item.Val.Items() {
peers = append(peers, v.String()) peers = append(peers, peer.String())
} }
json.NewEncoder(w).Encode(peers) networks = append(networks, exporter.Network{
return ID: item.Key,
Peers: peers,
})
} }
w.WriteHeader(http.StatusNotFound) json.NewEncoder(w).Encode(networks)
} }
func (pm *PeerMap) handleOIDCAuthorize(w http.ResponseWriter, r *http.Request) { func (pm *PeerMap) handleOIDCAuthorize(w http.ResponseWriter, r *http.Request) {
@@ -298,9 +304,7 @@ func (pm *PeerMap) handleOIDCAuthorize(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusBadGateway) w.WriteHeader(http.StatusBadGateway)
return return
} }
networkB := md5.Sum([]byte(email)) secret, err := pm.generateSecret(email)
network := base64.URLEncoding.EncodeToString(networkB[:])
secret, err := pm.generateSecret(network)
if err != nil { if err != nil {
w.WriteHeader(http.StatusInternalServerError) w.WriteHeader(http.StatusInternalServerError)
return return