addXauthEntry adds an Xauthority entry to the Xauthority file. The Xauthority file is located at ~/.Xauthority.
(ctx context.Context, fs afero.Fs, host string, display string, authProtocol string, authCookie string)
| 375 | // addXauthEntry adds an Xauthority entry to the Xauthority file. |
| 376 | // The Xauthority file is located at ~/.Xauthority. |
| 377 | func addXauthEntry(ctx context.Context, fs afero.Fs, host string, display string, authProtocol string, authCookie string) error { |
| 378 | // Get the Xauthority file path |
| 379 | homeDir, err := os.UserHomeDir() |
| 380 | if err != nil { |
| 381 | return xerrors.Errorf("failed to get user home directory: %w", err) |
| 382 | } |
| 383 | |
| 384 | xauthPath := filepath.Join(homeDir, ".Xauthority") |
| 385 | |
| 386 | lock := flock.New(xauthPath) |
| 387 | defer lock.Close() |
| 388 | ok, err := lock.TryLockContext(ctx, 100*time.Millisecond) |
| 389 | if !ok { |
| 390 | return xerrors.Errorf("failed to lock Xauthority file: %w", err) |
| 391 | } |
| 392 | if err != nil { |
| 393 | return xerrors.Errorf("failed to lock Xauthority file: %w", err) |
| 394 | } |
| 395 | |
| 396 | // Open or create the Xauthority file |
| 397 | file, err := fs.OpenFile(xauthPath, os.O_RDWR|os.O_CREATE, 0o600) |
| 398 | if err != nil { |
| 399 | return xerrors.Errorf("failed to open Xauthority file: %w", err) |
| 400 | } |
| 401 | defer file.Close() |
| 402 | |
| 403 | // Convert the authCookie from hex string to byte slice |
| 404 | authCookieBytes, err := hex.DecodeString(authCookie) |
| 405 | if err != nil { |
| 406 | return xerrors.Errorf("failed to decode auth cookie: %w", err) |
| 407 | } |
| 408 | |
| 409 | // Read the Xauthority file and look for an existing entry for the host, |
| 410 | // display, and auth protocol. If an entry is found, overwrite the auth |
| 411 | // cookie (if it fits). Otherwise, mark the entry for deletion. |
| 412 | type deleteEntry struct { |
| 413 | start, end int |
| 414 | } |
| 415 | var deleteEntries []deleteEntry |
| 416 | pos := 0 |
| 417 | updated := false |
| 418 | for { |
| 419 | entry, err := readXauthEntry(file) |
| 420 | if err != nil { |
| 421 | if errors.Is(err, io.EOF) { |
| 422 | break |
| 423 | } |
| 424 | return xerrors.Errorf("failed to read Xauthority entry: %w", err) |
| 425 | } |
| 426 | |
| 427 | nextPos := pos + entry.Len() |
| 428 | cookieStartPos := nextPos - len(entry.authCookie) |
| 429 | |
| 430 | if entry.family == 0x0100 && entry.address == host && entry.display == display && entry.authProtocol == authProtocol { |
| 431 | if !updated && len(entry.authCookie) == len(authCookieBytes) { |
| 432 | // Overwrite the auth cookie |
| 433 | _, err := file.WriteAt(authCookieBytes, int64(cookieStartPos)) |
| 434 | if err != nil { |