feat(desktop-client): derive stable client_id from machine identity
Generate the desktop client_id deterministically from OS machine identifiers (IOPlatformUUID / MachineGuid / /etc/machine-id) scoped per tenant+workspace+user, with a persisted UUID fallback when the OS lookup fails. The renderer now requests the id over a new IPC bridge instead of keeping a localStorage UUID, so reinstalls and storage clears no longer fork into duplicate clients. Server enforces the id as required and rejects empty/malformed UUIDs. Also harden bootstrap reveal flow and single-instance exit so a second launch focuses the existing window. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -36,7 +36,7 @@ func (s *DesktopClientService) WithTaskService(taskSvc *DesktopTaskService) *Des
|
||||
}
|
||||
|
||||
type RegisterDesktopClientRequest struct {
|
||||
ClientID string `json:"client_id"`
|
||||
ClientID string `json:"client_id" binding:"required"`
|
||||
DeviceName string `json:"device_name" binding:"required"`
|
||||
OS string `json:"os" binding:"required"`
|
||||
CPUArch string `json:"cpu_arch"`
|
||||
@@ -107,7 +107,11 @@ func (s *DesktopClientService) Register(ctx context.Context, actor auth.Actor, r
|
||||
return nil, response.ErrInternal(50071, "desktop_client_token_failed", "failed to generate desktop client token")
|
||||
}
|
||||
|
||||
clientID := resolveRegisterClientID(req.ClientID)
|
||||
clientID, err := parseRegisterClientID(req.ClientID)
|
||||
if err != nil {
|
||||
return nil, response.ErrBadRequest(40033, "invalid_desktop_client_id", "desktop client_id must be a non-empty uuid generated by the desktop client")
|
||||
}
|
||||
|
||||
client, err := s.repo.Register(ctx, repository.RegisterDesktopClientParams{
|
||||
ID: clientID,
|
||||
TenantID: actor.TenantID,
|
||||
@@ -298,10 +302,10 @@ func parseDesktopAccountIDs(values []string) []uuid.UUID {
|
||||
return accountIDs
|
||||
}
|
||||
|
||||
func resolveRegisterClientID(value string) uuid.UUID {
|
||||
func parseRegisterClientID(value string) (uuid.UUID, error) {
|
||||
parsed, err := uuid.Parse(strings.TrimSpace(value))
|
||||
if err == nil && parsed != uuid.Nil {
|
||||
return parsed
|
||||
if err != nil || parsed == uuid.Nil {
|
||||
return uuid.Nil, fmt.Errorf("invalid desktop client id")
|
||||
}
|
||||
return uuid.New()
|
||||
return parsed, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user