- 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.
88 lines
1.9 KiB
Go
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,
|
|
}
|
|
}
|