The client sends it every HTTP request and its IMQ connection; it makes them with current TLS and certificates, upgrades IMVU's plain-HTTP hosts to HTTPS, and refuses IMVU's reporting endpoints. CI tests it and publishes t5de-proxy.exe as nightlies and tagged releases. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
commit
2551888ed6
19 files changed
+1498
No files matched your search
@@ -0,0 +1,100 @@
|
||||
// Command t5de-proxy is T5DE's local proxy for IMVU Classic (see internal/proxy). The client starts one as it
|
||||
// starts, and it exits with the client:
|
||||
//
|
||||
// t5de-proxy -parent <pid> -ready <file> [-log <file>] [-trace]
|
||||
//
|
||||
// It listens on a free port of 127.0.0.1 and, once it's listening, writes {"address", "token"} to the ready file
|
||||
// (written whole, by renaming), which the client reads.
|
||||
package main
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"encoding/json"
|
||||
"flag"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"git.t5de.dev/t5de/t5de-proxy/internal/buildinfo"
|
||||
"git.t5de.dev/t5de/t5de-proxy/internal/parent"
|
||||
"git.t5de.dev/t5de/t5de-proxy/internal/proxy"
|
||||
)
|
||||
|
||||
func main() {
|
||||
listen := flag.String("listen", "127.0.0.1:0", "address to listen on")
|
||||
ready := flag.String("ready", "", "file to write the address and token to once listening")
|
||||
parentPID := flag.Int("parent", 0, "exit when this process exits")
|
||||
logFile := flag.String("log", "", "log file (default: standard error)")
|
||||
trace := flag.Bool("trace", false, "log full URLs and every IMQ frame")
|
||||
version := flag.Bool("version", false, "print the version and exit")
|
||||
flag.Parse()
|
||||
if *version {
|
||||
fmt.Println(buildinfo.Version)
|
||||
return
|
||||
}
|
||||
|
||||
var out io.Writer = os.Stderr
|
||||
if *logFile != "" {
|
||||
f, err := os.Create(*logFile)
|
||||
if err != nil {
|
||||
os.Exit(1)
|
||||
}
|
||||
defer f.Close()
|
||||
out = f
|
||||
}
|
||||
logger := log.New(out, "", log.Ldate|log.Ltime|log.Lmicroseconds)
|
||||
if err := run(logger, *listen, *ready, *parentPID, *trace); err != nil {
|
||||
logger.Printf("t5de-proxy: %v", err)
|
||||
os.Exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
func run(logger *log.Logger, listen, ready string, parentPID int, trace bool) error {
|
||||
secret := make([]byte, 24)
|
||||
if _, err := rand.Read(secret); err != nil {
|
||||
return err
|
||||
}
|
||||
token := hex.EncodeToString(secret)
|
||||
|
||||
ln, err := net.Listen("tcp", listen)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
logger.Printf("t5de-proxy %s listening on %s (client process %d)", buildinfo.Version, ln.Addr(), parentPID)
|
||||
if ready != "" {
|
||||
if err := writeReady(ready, ln.Addr().String(), token); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if parentPID != 0 {
|
||||
go func() {
|
||||
err := parent.Wait(parentPID)
|
||||
logger.Printf("client process %d exited (%v); exiting", parentPID, err)
|
||||
os.Exit(0)
|
||||
}()
|
||||
}
|
||||
server := &http.Server{
|
||||
Handler: &proxy.Server{Token: token, Log: logger, Trace: trace},
|
||||
ReadHeaderTimeout: 30 * time.Second,
|
||||
IdleTimeout: 2 * time.Minute,
|
||||
ErrorLog: logger,
|
||||
}
|
||||
return server.Serve(ln)
|
||||
}
|
||||
|
||||
func writeReady(path, address, token string) error {
|
||||
data, err := json.Marshal(map[string]string{"address": address, "token": token})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
tmp := path + ".tmp"
|
||||
if err := os.WriteFile(tmp, data, 0o600); err != nil {
|
||||
return err
|
||||
}
|
||||
return os.Rename(tmp, path)
|
||||
}
|
||||
Reference in new issue
Block a user