feat: Add auth flow (#146)

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_
This commit is contained in:
Wanjohi
2025-01-04 00:02:28 +03:00
committed by GitHub
parent 33895974a7
commit fc5a755408
136 changed files with 3512 additions and 1914 deletions

View File

@@ -0,0 +1,202 @@
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, "")
// }