731b60863a
Tunnel method now requires Bearer JWT (HMAC-HS256) in gRPC metadata.
- internal/auth: pure-stdlib verifier + issuer + revoked-jti list
- internal/tunnel: per-target rate limiter + egress allowlist with
wildcard support + crypto/rand frame padding to {1KB, 4KB, 16KB}
- cmd/server reads /etc/stats-gateway/{jwt.key,tunnel.yaml,revoked.txt}
via --config-dir flag
- cmd/issue-token Go binary wraps auth.Issue
- configs/tunnel.yaml example with projectshitpost wildcard
Tests: 13 PASS across 5 packages.
72 lines
1.9 KiB
Go
72 lines
1.9 KiB
Go
package main
|
|
|
|
import (
|
|
"bytes"
|
|
"flag"
|
|
"log"
|
|
"net"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"google.golang.org/grpc"
|
|
"gopkg.in/yaml.v3"
|
|
|
|
statsv1 "github.com/bergabruh/stats-gateway/gen/stats/v1"
|
|
"github.com/bergabruh/stats-gateway/internal/auth"
|
|
"github.com/bergabruh/stats-gateway/internal/service"
|
|
"github.com/bergabruh/stats-gateway/internal/storage"
|
|
"github.com/bergabruh/stats-gateway/internal/tunnel"
|
|
)
|
|
|
|
func main() {
|
|
addr := flag.String("addr", "127.0.0.1:50051", "listen address")
|
|
dbPath := flag.String("db", "/var/lib/stats-gateway/stats.db", "sqlite path")
|
|
cfgDir := flag.String("config-dir", "/etc/stats-gateway", "config dir (jwt.key, tunnel.yaml, revoked.txt)")
|
|
flag.Parse()
|
|
|
|
st, err := storage.Open(*dbPath)
|
|
if err != nil {
|
|
log.Fatalf("storage: %v", err)
|
|
}
|
|
defer st.Close()
|
|
|
|
secret, err := os.ReadFile(filepath.Join(*cfgDir, "jwt.key"))
|
|
if err != nil {
|
|
log.Fatalf("read jwt.key: %v", err)
|
|
}
|
|
secret = bytes.TrimSpace(secret)
|
|
|
|
cfgBytes, err := os.ReadFile(filepath.Join(*cfgDir, "tunnel.yaml"))
|
|
if err != nil {
|
|
log.Fatalf("read tunnel.yaml: %v", err)
|
|
}
|
|
var tunnelCfg struct {
|
|
Egress tunnel.EgressConfig `yaml:"egress"`
|
|
}
|
|
if err := yaml.Unmarshal(cfgBytes, &tunnelCfg); err != nil {
|
|
log.Fatalf("parse tunnel.yaml: %v", err)
|
|
}
|
|
|
|
revoked, err := auth.LoadRevokedFile(filepath.Join(*cfgDir, "revoked.txt"))
|
|
if err != nil {
|
|
log.Fatalf("load revoked: %v", err)
|
|
}
|
|
|
|
verifier := auth.NewVerifier(secret, revoked)
|
|
handler := tunnel.NewHandler(tunnelCfg.Egress)
|
|
|
|
lis, err := net.Listen("tcp", *addr)
|
|
if err != nil {
|
|
log.Fatalf("listen: %v", err)
|
|
}
|
|
|
|
srv := grpc.NewServer()
|
|
statsv1.RegisterSpeedStatusServer(srv, service.New(st, verifier, handler))
|
|
|
|
log.Printf("stats-gateway listening on %s (egress=%d targets, rate=%.0fmbps)",
|
|
*addr, len(tunnelCfg.Egress.Allowed), tunnelCfg.Egress.RateMbps)
|
|
if err := srv.Serve(lis); err != nil {
|
|
log.Fatalf("serve: %v", err)
|
|
}
|
|
}
|