yao/engine/machine.go
Max 1c79908649 Enhance OAuth Device Flow implementation
- Add support for the OAuth Device Authorization Flow (RFC 8628) in the OpenAPI service, allowing devices with limited input capabilities to obtain authorization.
- Implement `DeviceAuthorization()` and `AuthorizeDevice()` methods to handle device and user code generation, storage, and authorization.
- Update the OAuth endpoints to include `/device/authorize` for user code authorization and fix the discovery endpoint path for device authorization.
- Introduce MongoDB service in CI workflows for testing and enhance the unit test workflow with Redis setup.
- Update Go module dependencies to include necessary packages for the new features.

This commit significantly advances the OAuth capabilities of the application, enabling a more flexible authorization process for devices.
2026-03-04 15:19:48 +08:00

88 lines
1.9 KiB
Go

package engine
import (
"crypto/sha256"
"fmt"
"net"
"os"
"runtime"
"strings"
"sync"
"github.com/yaoapp/gou/process"
)
// MachineInfo contains deterministic machine identification.
type MachineInfo struct {
ID string `json:"id"` // "yao-cli-{hash32}" deterministic client ID
Hostname string `json:"hostname"` // OS hostname
Platform string `json:"platform"` // runtime.GOOS: "darwin", "linux", "windows"
}
var (
cachedMachineInfo *MachineInfo
machineOnce sync.Once
machineErr error
)
func init() {
process.Register("utils.app.MachineID", processMachineID)
}
// GetMachineID returns a deterministic machine fingerprint.
// The result is cached after the first call.
func GetMachineID() (*MachineInfo, error) {
machineOnce.Do(func() {
cachedMachineInfo, machineErr = computeMachineID()
})
return cachedMachineInfo, machineErr
}
func computeMachineID() (*MachineInfo, error) {
hostname, _ := os.Hostname()
raw, err := platformMachineID()
if err != nil || strings.TrimSpace(raw) == "" {
raw = fallbackMachineID(hostname)
}
hash := sha256.Sum256([]byte(raw))
id := fmt.Sprintf("yao-cli-%x", hash[:16]) // 32 hex chars
return &MachineInfo{
ID: id,
Hostname: hostname,
Platform: runtime.GOOS,
}, nil
}
func fallbackMachineID(hostname string) string {
mac := firstHardwareAddr()
return hostname + ":" + mac
}
func firstHardwareAddr() string {
ifaces, err := net.Interfaces()
if err != nil {
return "unknown"
}
for _, iface := range ifaces {
if iface.Flags&net.FlagLoopback != 0 || len(iface.HardwareAddr) == 0 {
continue
}
return iface.HardwareAddr.String()
}
return "unknown"
}
func processMachineID(p *process.Process) interface{} {
info, err := GetMachineID()
if err != nil {
return map[string]interface{}{"error": err.Error()}
}
return map[string]interface{}{
"id": info.ID,
"hostname": info.Hostname,
"platform": info.Platform,
}
}