Fix various things

This commit is contained in:
Owen Schwartz 2024-12-07 22:07:02 -05:00
parent 6eac4b5147
commit 31692c03e8
No known key found for this signature in database
GPG key ID: 8271FDFFD9E0CCBD
4 changed files with 96 additions and 31 deletions

15
main.go
View file

@ -185,7 +185,7 @@ func main() {
logLevel string logLevel string
) )
flag.StringVar(&endpoint, "endpoint", "http://localhost:3000/api/v1", "Endpoint of your pangolin server") flag.StringVar(&endpoint, "endpoint", "", "Endpoint of your pangolin server")
flag.StringVar(&id, "id", "", "Newt ID") flag.StringVar(&id, "id", "", "Newt ID")
flag.StringVar(&secret, "secret", "", "Newt secret") flag.StringVar(&secret, "secret", "", "Newt secret")
flag.StringVar(&dns, "dns", "8.8.8.8", "DNS server to use") flag.StringVar(&dns, "dns", "8.8.8.8", "DNS server to use")
@ -204,10 +204,9 @@ func main() {
// Create a new client // Create a new client
client, err := websocket.NewClient( client, err := websocket.NewClient(
// the id and secret from the params id, // CLI arg takes precedence
id, secret, // CLI arg takes precedence
secret, endpoint,
websocket.WithBaseURL(endpoint), // TODO: save the endpoint in the config file so we dont have to pass it in every time
) )
if err != nil { if err != nil {
logger.Fatal("Failed to create client: %v", err) logger.Fatal("Failed to create client: %v", err)
@ -223,6 +222,8 @@ func main() {
// Register handlers for different message types // Register handlers for different message types
client.RegisterHandler("newt/wg/connect", func(msg websocket.WSMessage) { client.RegisterHandler("newt/wg/connect", func(msg websocket.WSMessage) {
logger.Info("Received registration message")
if connected { if connected {
logger.Info("Already connected! Put I will send a ping anyway...") logger.Info("Already connected! Put I will send a ping anyway...")
ping(tnet, wgData.ServerIP) ping(tnet, wgData.ServerIP)
@ -385,7 +386,7 @@ persistent_keepalive_interval=5`, fixKey(fmt.Sprintf("%s", privateKey)), fixKey(
defer client.Close() defer client.Close()
publicKey := privateKey.PublicKey() publicKey := privateKey.PublicKey()
logger.Info("Public key: %s", publicKey) logger.Debug("Public key: %s", publicKey)
// TODO: how to retry? // TODO: how to retry?
err = client.SendMessage("newt/wg/register", map[string]interface{}{ err = client.SendMessage("newt/wg/register", map[string]interface{}{
"publicKey": fmt.Sprintf("%s", publicKey), "publicKey": fmt.Sprintf("%s", publicKey),
@ -394,6 +395,8 @@ persistent_keepalive_interval=5`, fixKey(fmt.Sprintf("%s", privateKey)), fixKey(
logger.Info("Failed to send message: %v", err) logger.Info("Failed to send message: %v", err)
} }
logger.Info("Sent registration message")
// Wait for interrupt signal // Wait for interrupt signal
sigCh := make(chan os.Signal, 1) sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM) signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)

View file

@ -6,6 +6,8 @@ import (
"fmt" "fmt"
"net/http" "net/http"
"net/url" "net/url"
"newt/logger"
"strings"
"sync" "sync"
"github.com/gorilla/websocket" "github.com/gorilla/websocket"
@ -32,20 +34,21 @@ func WithBaseURL(url string) ClientOption {
} }
// NewClient creates a new Newt client // NewClient creates a new Newt client
func NewClient(newtID, secret string, opts ...ClientOption) (*Client, error) { func NewClient(newtID, secret string, endpoint string, opts ...ClientOption) (*Client, error) {
config := &Config{ config := &Config{
NewtID: newtID, NewtID: newtID,
Secret: secret, Secret: secret,
Endpoint: endpoint,
} }
client := &Client{ client := &Client{
config: config, config: config,
baseURL: "https://fossorial.io", // default value baseURL: endpoint, // default value
handlers: make(map[string]MessageHandler), handlers: make(map[string]MessageHandler),
done: make(chan struct{}), done: make(chan struct{}),
} }
// Apply options // Apply options before loading config
for _, opt := range opts { for _, opt := range opts {
opt(client) opt(client)
} }
@ -66,31 +69,48 @@ func (c *Client) Connect() error {
return fmt.Errorf("failed to get token: %w", err) return fmt.Errorf("failed to get token: %w", err)
} }
logger.Info("Using token: %s", token)
// Update config with new token and save // Update config with new token and save
c.config.Token = token c.config.Token = token
if err := c.saveConfig(); err != nil { if err := c.saveConfig(); err != nil {
return fmt.Errorf("failed to save config: %w", err) return fmt.Errorf("failed to save config: %w", err)
} }
// Connect to WebSocket // Parse the base URL to determine protocol and hostname
wsURL := fmt.Sprintf("wss://%s/ws", "fossorial.io") // Remove http:// prefix baseURL, err := url.Parse(c.baseURL)
if err != nil {
return fmt.Errorf("failed to parse base URL: %w", err)
}
// Determine WebSocket protocol based on HTTP protocol
wsProtocol := "wss"
if baseURL.Scheme == "http" {
wsProtocol = "ws"
}
// Create WebSocket URL using the hostname without path
wsURL := fmt.Sprintf("%s://%s/ws", wsProtocol, baseURL.Host)
u, err := url.Parse(wsURL) u, err := url.Parse(wsURL)
if err != nil { if err != nil {
return fmt.Errorf("failed to parse WebSocket URL: %w", err) return fmt.Errorf("failed to parse WebSocket URL: %w", err)
} }
// Add token to query parameters
q := u.Query() q := u.Query()
q.Set("token", token) q.Set("token", token)
u.RawQuery = q.Encode() u.RawQuery = q.Encode()
// Connect to WebSocket
conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil) conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
if err != nil { if err != nil {
return fmt.Errorf("failed to connect to WebSocket: %w", err) return fmt.Errorf("failed to connect to WebSocket: %w", err)
} }
logger.Info("Connected to WebSocket")
c.conn = conn c.conn = conn
go c.readPump() go c.readPump()
return nil return nil
} }
@ -149,6 +169,15 @@ func (c *Client) readPump() {
} }
func (c *Client) getToken() (string, error) { func (c *Client) getToken() (string, error) {
// Parse the base URL to ensure we have the correct hostname
baseURL, err := url.Parse(c.baseURL)
if err != nil {
return "", fmt.Errorf("failed to parse base URL: %w", err)
}
// Ensure we have the base URL without trailing slashes
baseEndpoint := strings.TrimRight(baseURL.String(), "/")
// If we already have a token, try to use it // If we already have a token, try to use it
if c.config.Token != "" { if c.config.Token != "" {
tokenCheckData := map[string]interface{}{ tokenCheckData := map[string]interface{}{
@ -156,19 +185,28 @@ func (c *Client) getToken() (string, error) {
"secret": c.config.Secret, "secret": c.config.Secret,
"token": c.config.Token, "token": c.config.Token,
} }
jsonData, _ := json.Marshal(tokenCheckData) jsonData, err := json.Marshal(tokenCheckData)
resp, err := http.Post(c.baseURL+"/auth/newt/get-token", "application/json", bytes.NewBuffer(jsonData))
if err != nil { if err != nil {
return "", err return "", fmt.Errorf("failed to marshal token check data: %w", err)
}
// Make request to validate existing token
resp, err := http.Post(
baseEndpoint+"/api/v1/auth/newt/get-token",
"application/json",
bytes.NewBuffer(jsonData),
)
if err != nil {
return "", fmt.Errorf("failed to check token validity: %w", err)
} }
defer resp.Body.Close() defer resp.Body.Close()
var tokenResp TokenResponse var tokenResp TokenResponse
if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil { if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
return "", err return "", fmt.Errorf("failed to decode token check response: %w", err)
} }
// If token is still valid, return it
if tokenResp.Success && tokenResp.Message == "Token session already valid" { if tokenResp.Success && tokenResp.Message == "Token session already valid" {
return c.config.Token, nil return c.config.Token, nil
} }
@ -179,22 +217,34 @@ func (c *Client) getToken() (string, error) {
"newtId": c.config.NewtID, "newtId": c.config.NewtID,
"secret": c.config.Secret, "secret": c.config.Secret,
} }
jsonData, _ := json.Marshal(tokenData) jsonData, err := json.Marshal(tokenData)
resp, err := http.Post(c.baseURL+"/auth/newt/get-token", "application/json", bytes.NewBuffer(jsonData))
if err != nil { if err != nil {
return "", err return "", fmt.Errorf("failed to marshal token request data: %w", err)
}
// Make request to get new token
resp, err := http.Post(
baseEndpoint+"/api/v1/auth/newt/get-token",
"application/json",
bytes.NewBuffer(jsonData),
)
if err != nil {
return "", fmt.Errorf("failed to request new token: %w", err)
} }
defer resp.Body.Close() defer resp.Body.Close()
var tokenResp TokenResponse var tokenResp TokenResponse
if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil { if err := json.NewDecoder(resp.Body).Decode(&tokenResp); err != nil {
return "", err return "", fmt.Errorf("failed to decode token response: %w", err)
} }
if !tokenResp.Success { if !tokenResp.Success {
return "", fmt.Errorf("failed to get token: %s", tokenResp.Message) return "", fmt.Errorf("failed to get token: %s", tokenResp.Message)
} }
if tokenResp.Data.Token == "" {
return "", fmt.Errorf("received empty token from server")
}
return tokenResp.Data.Token, nil return tokenResp.Data.Token, nil
} }

View file

@ -27,7 +27,7 @@ func getConfigPath() string {
} }
func (c *Client) loadConfig() error { func (c *Client) loadConfig() error {
if c.config.NewtID != "" && c.config.Secret != "" { if c.config.NewtID != "" && c.config.Secret != "" && c.config.Endpoint != "" {
return nil return nil
} }
@ -45,9 +45,20 @@ func (c *Client) loadConfig() error {
return err return err
} }
c.config.Token = config.Token // I think it always needs to get a new token if c.config.NewtID == "" {
c.config.NewtID = config.NewtID c.config.NewtID = config.NewtID
}
if c.config.Token == "" {
c.config.Token = config.Token
}
if c.config.Secret == "" {
c.config.Secret = config.Secret c.config.Secret = config.Secret
}
if c.config.Endpoint == "" {
c.config.Endpoint = config.Endpoint
c.baseURL = config.Endpoint
}
return nil return nil
} }

View file

@ -4,6 +4,7 @@ type Config struct {
NewtID string `json:"newtId"` NewtID string `json:"newtId"`
Secret string `json:"secret"` Secret string `json:"secret"`
Token string `json:"token"` Token string `json:"token"`
Endpoint string `json:"endpoint"`
} }
type TokenResponse struct { type TokenResponse struct {