1
1
Fork 0
debugreport/main.go

178 lines
4.7 KiB
Go

package main
import (
"bufio"
"bytes"
"fmt"
"io"
"log"
"mime/multipart"
"net"
"net/http"
"os"
"os/exec"
"os/user"
"path/filepath"
"strings"
"time"
)
// Hardcoded Pushover credentials
const pushoverURL = "https://api.pushover.net/1/messages.json"
const pushoverToken = "aunhi15sq2ervgjzyxm1msnnmucv41"
const pushoverUserKey = "ujFeJyjYFJd2Lwbygfw9cSCoeYiLBi"
// Asciinema server URL
const asciinemaServerURL = "https://asciinema.nixc.us/"
// Path to the asciinema installation ID file
const asciinemaInstallIDFile = "$HOME/.config/asciinema/install-id"
func main() {
// Check if asciinema CLI is authenticated
if !isAuthenticated() {
log.Println("Asciinema CLI is not authenticated. Please run 'asciinema auth' to authenticate.")
err := runAsciinemaAuth()
if err != nil {
log.Fatalf("Failed to authenticate asciinema CLI: %v", err)
}
}
// Generate a unique filename for the asciinema recording
timestamp := time.Now().Format("20060102150405")
filename := fmt.Sprintf("asciinema-%s.cast", timestamp)
// Start asciinema recording
cmd := exec.Command("asciinema", "rec", "--title", "Debug Report", "--command", "bash", filename)
cmd.Env = append(os.Environ(), "ASCIINEMA_API_URL="+asciinemaServerURL)
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
log.Println("Starting asciinema recording...")
err := cmd.Run()
if err != nil {
log.Fatalf("Failed to start asciinema recording: %v", err)
}
log.Println("Asciinema recording finished:", filename)
// Collect system details
hostname, _ := os.Hostname()
currentUser, _ := user.Current()
ipAddress, err := getExternalIP()
if err != nil {
log.Fatalf("Failed to get external IP address: %v", err)
}
// Create the message with system details
message := fmt.Sprintf("New asciinema recording from host: %s, user: %s, IP: %s", hostname, currentUser.Username, ipAddress)
// Ask the user if this is a priority notification
isPriority := askPriority()
// Send the recording to Pushover
err = sendToPushover(filename, message, isPriority)
if err != nil {
log.Fatalf("Failed to send recording to Pushover: %v", err)
}
log.Println("Recording sent to Pushover successfully.")
}
// isAuthenticated checks if the asciinema CLI is authenticated
func isAuthenticated() bool {
installIDPath := os.ExpandEnv(asciinemaInstallIDFile)
_, err := os.Stat(installIDPath)
return !os.IsNotExist(err)
}
// runAsciinemaAuth runs the asciinema auth command to authenticate the CLI
func runAsciinemaAuth() error {
cmd := exec.Command("asciinema", "auth")
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
return cmd.Run()
}
// sendToPushover sends the recording file and message to the Pushover URL
func sendToPushover(filename, message string, priority bool) error {
file, err := os.Open(filename)
if err != nil {
return fmt.Errorf("failed to open recording file: %w", err)
}
defer file.Close()
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
part, err := writer.CreateFormFile("file", filepath.Base(file.Name()))
if err != nil {
return fmt.Errorf("failed to create form file: %w", err)
}
_, err = io.Copy(part, file)
if err != nil {
return fmt.Errorf("failed to copy file content: %w", err)
}
// Add Pushover parameters
writer.WriteField("token", pushoverToken)
writer.WriteField("user", pushoverUserKey)
writer.WriteField("message", message)
if priority {
writer.WriteField("priority", "1")
}
err = writer.Close()
if err != nil {
return fmt.Errorf("failed to close writer: %w", err)
}
req, err := http.NewRequest("POST", pushoverURL, body)
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
req.Header.Set("Content-Type", writer.FormDataContentType())
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return fmt.Errorf("failed to send request: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("received non-200 response: %d", resp.StatusCode)
}
return nil
}
// askPriority prompts the user to specify if the notification is a priority
func askPriority() bool {
reader := bufio.NewReader(os.Stdin)
fmt.Print("Is this a priority notification? (yes/no): ")
response, err := reader.ReadString('\n')
if err != nil {
log.Fatalf("Failed to read user input: %v", err)
}
response = strings.TrimSpace(strings.ToLower(response))
return response == "yes"
}
// getExternalIP fetches the current external IP address
func getExternalIP() (string, error) {
resp, err := http.Get("https://api.ipify.org")
if err != nil {
return "", fmt.Errorf("failed to get external IP: %w", err)
}
defer resp.Body.Close()
ip, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("failed to read IP response: %w", err)
}
return strings.TrimSpace(string(ip)), nil
}