mirror of
https://github.com/nestriness/nestri.git
synced 2025-12-12 08:45:38 +02:00
This adds a simple way to incorporate a centralized authentication flow. The idea is to have the user, API and SSH (for machine authentication) all in one place using `openauthjs` + `SST` We also have a database now :) > We are using InstantDB as it allows us to authenticate a use with just the email. Plus it is super simple simple to use _of course after the initial fumbles trying to design the db and relationships_
203 lines
4.7 KiB
Go
203 lines
4.7 KiB
Go
package machine
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"os/exec"
|
|
"regexp"
|
|
"strings"
|
|
|
|
"github.com/charmbracelet/log"
|
|
)
|
|
|
|
type Machine struct {
|
|
OperatingSystem string
|
|
Arch string
|
|
Kernel string
|
|
Virtualization string
|
|
Hostname string
|
|
}
|
|
|
|
func NewMachine() *Machine {
|
|
var OS string
|
|
var architecture string
|
|
var kernel string
|
|
var virtualisation string
|
|
var hostname string
|
|
|
|
output, _ := exec.Command("hostnamectl", "status").Output()
|
|
os := regexp.MustCompile(`Operating System:\s+(.*)`)
|
|
matchingOS := os.FindStringSubmatch(string(output))
|
|
if len(matchingOS) > 1 {
|
|
OS = matchingOS[1]
|
|
}
|
|
|
|
arch := regexp.MustCompile(`Architecture:\s+(\w+)`)
|
|
matchingArch := arch.FindStringSubmatch(string(output))
|
|
if len(matchingArch) > 1 {
|
|
architecture = matchingArch[1]
|
|
}
|
|
|
|
kern := regexp.MustCompile(`Kernel:\s+(.*)`)
|
|
matchingKernel := kern.FindStringSubmatch(string(output))
|
|
if len(matchingKernel) > 1 {
|
|
kernel = matchingKernel[1]
|
|
}
|
|
|
|
virt := regexp.MustCompile(`Virtualization:\s+(\w+)`)
|
|
matchingVirt := virt.FindStringSubmatch(string(output))
|
|
if len(matchingVirt) > 1 {
|
|
virtualisation = matchingVirt[1]
|
|
}
|
|
|
|
host := regexp.MustCompile(`Static hostname:\s+(.*)`)
|
|
matchingHost := host.FindStringSubmatch(string(output))
|
|
if len(matchingHost) > 1 {
|
|
hostname = matchingHost[1]
|
|
}
|
|
|
|
return &Machine{
|
|
OperatingSystem: OS,
|
|
Arch: architecture,
|
|
Kernel: kernel,
|
|
Virtualization: virtualisation,
|
|
Hostname: hostname,
|
|
}
|
|
}
|
|
|
|
func (m *Machine) GetOS() string {
|
|
if m.OperatingSystem != "" {
|
|
return m.OperatingSystem
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
func (m *Machine) GetArchitecture() string {
|
|
|
|
if m.Arch != "" {
|
|
return m.Arch
|
|
}
|
|
return "unknown"
|
|
|
|
}
|
|
|
|
func (m *Machine) GetKernel() string {
|
|
if m.Kernel != "" {
|
|
return m.Kernel
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
func (m *Machine) GetVirtualization() string {
|
|
if m.Virtualization != "" {
|
|
return m.Virtualization
|
|
}
|
|
return "none"
|
|
}
|
|
|
|
func (m *Machine) GetHostname() string {
|
|
if m.Hostname != "" {
|
|
return m.Hostname
|
|
}
|
|
return "unknown"
|
|
}
|
|
|
|
func (m *Machine) GetMachineID() string {
|
|
id, err := os.ReadFile("/etc/machine-id")
|
|
if err != nil {
|
|
log.Error("Error getting your machine's ID", "err", err)
|
|
os.Exit(1)
|
|
}
|
|
return strings.TrimSpace(string(id))
|
|
}
|
|
|
|
func (m *Machine) GPUInfo() (string, string, error) {
|
|
// The command for GPU information varies depending on the system and drivers.
|
|
// lshw is a good general-purpose tool, but might need adjustments for specific hardware.
|
|
output, err := exec.Command("lshw", "-C", "display").Output()
|
|
if err != nil {
|
|
return "", "", fmt.Errorf("failed to get GPU information: %w", err)
|
|
}
|
|
|
|
gpuType := ""
|
|
gpuSize := ""
|
|
|
|
// Regular expressions for extracting product and size information. These might need to be
|
|
// adapted based on the output of lshw on your specific system.
|
|
typeRegex := regexp.MustCompile(`product:\s+(.*)`)
|
|
sizeRegex := regexp.MustCompile(`size:\s+(\d+MiB)`) // Example: extracts size in MiB
|
|
|
|
typeMatch := typeRegex.FindStringSubmatch(string(output))
|
|
if len(typeMatch) > 1 {
|
|
gpuType = typeMatch[1]
|
|
}
|
|
|
|
sizeMatch := sizeRegex.FindStringSubmatch(string(output))
|
|
if len(sizeMatch) > 1 {
|
|
gpuSize = sizeMatch[1]
|
|
}
|
|
|
|
if gpuType == "" && gpuSize == "" {
|
|
return "", "", fmt.Errorf("could not parse GPU information using lshw")
|
|
}
|
|
|
|
return gpuType, gpuSize, nil
|
|
}
|
|
|
|
func (m *Machine) GetCPUInfo() (string, string, error) {
|
|
output, err := exec.Command("lscpu").Output()
|
|
if err != nil {
|
|
return "", "", fmt.Errorf("failed to get CPU information: %w", err)
|
|
}
|
|
|
|
cpuType := ""
|
|
cpuSize := "" // This will store the number of cores
|
|
|
|
typeRegex := regexp.MustCompile(`Model name:\s+(.*)`)
|
|
coresRegex := regexp.MustCompile(`CPU\(s\):\s+(\d+)`)
|
|
|
|
typeMatch := typeRegex.FindStringSubmatch(string(output))
|
|
if len(typeMatch) > 1 {
|
|
cpuType = typeMatch[1]
|
|
}
|
|
|
|
coresMatch := coresRegex.FindStringSubmatch(string(output))
|
|
if len(coresMatch) > 1 {
|
|
cpuSize = coresMatch[1]
|
|
}
|
|
|
|
if cpuType == "" && cpuSize == "" {
|
|
return "", "", fmt.Errorf("could not parse CPU information using lscpu")
|
|
}
|
|
|
|
return cpuType, cpuSize, nil
|
|
|
|
}
|
|
|
|
func (m *Machine) GetRAMSize() (string, error) {
|
|
output, err := exec.Command("free", "-h", "--si").Output() // Using -h for human-readable and --si for base-10 units
|
|
if err != nil {
|
|
return "", fmt.Errorf("failed to get RAM information: %w", err)
|
|
}
|
|
|
|
ramSize := ""
|
|
|
|
ramRegex := regexp.MustCompile(`Mem:\s+(\S+)`) // Matches the total memory size
|
|
|
|
ramMatch := ramRegex.FindStringSubmatch(string(output))
|
|
if len(ramMatch) > 1 {
|
|
ramSize = ramMatch[1]
|
|
} else {
|
|
return "", fmt.Errorf("could not parse RAM information from free command")
|
|
}
|
|
|
|
return ramSize, nil
|
|
}
|
|
|
|
// func cleanString(s string) string {
|
|
// s = strings.ToLower(s)
|
|
|
|
// reg := regexp.MustCompile("[^a-z0-9]+") // Matches one or more non-alphanumeric characters
|
|
// return reg.ReplaceAllString(s, "")
|
|
// }
|