| 1 | // Package instanceidentity owns the Desktop data-home identity across processes. |
| 2 | package instanceidentity |
| 3 | |
| 4 | import ( |
| 5 | "crypto/sha256" |
| 6 | "encoding/hex" |
| 7 | "errors" |
| 8 | "os" |
| 9 | "path/filepath" |
| 10 | "strings" |
| 11 | |
| 12 | "github.com/google/uuid" |
| 13 | |
| 14 | "reasonix/internal/pathidentity" |
| 15 | ) |
| 16 | |
| 17 | const Prefix = "com.reasonix.desktop" |
| 18 | const UpdateEnvironmentKey = "REASONIX_UPDATE_INSTANCE_ID" |
| 19 | |
| 20 | var trayNamespace = uuid.MustParse("af8b2b6e-cf17-43b9-afb9-b0bf2695d8ac") |
| 21 | |
| 22 | func CanonicalHome(home string) string { |
| 23 | identity, err := ResolveHome(home) |
| 24 | if err != nil { |
| 25 | return "" |
| 26 | } |
| 27 | return identity.Key |
| 28 | } |
| 29 | |
| 30 | func ResolveHome(home string) (pathidentity.Identity, error) { |
| 31 | home = strings.TrimSpace(home) |
| 32 | if home == "" { |
| 33 | return pathidentity.Identity{}, errors.New("Reasonix data home is empty") |
| 34 | } |
| 35 | baseDir := "" |
| 36 | if !filepath.IsAbs(home) { |
| 37 | var err error |
| 38 | baseDir, err = os.Getwd() |
| 39 | if err != nil { |
| 40 | return pathidentity.Identity{}, err |
| 41 | } |
| 42 | } |
| 43 | return pathidentity.Resolve(home, pathidentity.Options{BaseDir: baseDir, FollowLeaf: true}) |
| 44 | } |
| 45 | |
| 46 | func AccessHome(home string) string { |
| 47 | identity, err := ResolveHome(home) |
| 48 | if err != nil { |
| 49 | return "" |
| 50 | } |
| 51 | return identity.AccessPath |
| 52 | } |
| 53 | |
| 54 | func Digest(home string) string { |
| 55 | identity, err := ResolveHome(home) |
| 56 | if err != nil { |
| 57 | return "" |
| 58 | } |
| 59 | sum := sha256.Sum256([]byte(identity.Key)) |
| 60 | return "sha256:" + hex.EncodeToString(sum[:]) |
| 61 | } |
| 62 | |
| 63 | func ForHome(home string) string { |
| 64 | home = CanonicalHome(home) |
| 65 | if home == "" { |
| 66 | return Prefix |
| 67 | } |
| 68 | sum := sha256.Sum256([]byte(home)) |
| 69 | return Prefix + "." + hex.EncodeToString(sum[:8]) |
| 70 | } |
| 71 | |
| 72 | func Valid(id string) bool { |
| 73 | suffix, ok := strings.CutPrefix(id, Prefix+".") |
| 74 | if !ok || len(suffix) != 16 { |
| 75 | return false |
| 76 | } |
| 77 | _, err := hex.DecodeString(suffix) |
| 78 | return err == nil && suffix == strings.ToLower(suffix) |
| 79 | } |
| 80 | |
| 81 | func TrayGUID(id string) string { return "{" + uuid.NewSHA1(trayNamespace, []byte(id)).String() + "}" } |
| 82 | |
| 83 | // UpdateEnvironment freezes relative data homes before the helper changes cwd. |
| 84 | func UpdateEnvironment(base []string, home string) []string { |
| 85 | home = AccessHome(home) |
| 86 | env := make([]string, 0, len(base)+2) |
| 87 | for _, entry := range base { |
| 88 | key, _, _ := strings.Cut(entry, "=") |
| 89 | if !strings.EqualFold(key, "REASONIX_HOME") && !strings.EqualFold(key, UpdateEnvironmentKey) { |
| 90 | env = append(env, entry) |
| 91 | } |
| 92 | } |
| 93 | return append(env, "REASONIX_HOME="+home, UpdateEnvironmentKey+"="+ForHome(home)) |
| 94 | } |
| 95 | |
| 96 | func UpdateID() string { return os.Getenv(UpdateEnvironmentKey) } |
| 97 |