ForSubscribe sanitises appID against path traversal before forming the lock filename.
(appID string)
| 31 | |
| 32 | // ForSubscribe sanitises appID against path traversal before forming the lock filename. |
| 33 | func ForSubscribe(appID string) (*LockFile, error) { |
| 34 | if appID == "" { |
| 35 | return nil, fmt.Errorf("app ID must not be empty") |
| 36 | } |
| 37 | dir := filepath.Join(core.GetConfigDir(), "locks") |
| 38 | if err := vfs.MkdirAll(dir, 0700); err != nil { |
| 39 | return nil, fmt.Errorf("create lock dir: %w", err) |
| 40 | } |
| 41 | safe := safeIDChars.ReplaceAllString(appID, "_") |
| 42 | name := filepath.Base(fmt.Sprintf("subscribe_%s.lock", safe)) |
| 43 | path := filepath.Join(dir, name) |
| 44 | return New(path), nil |
| 45 | } |
| 46 | |
| 47 | // TryLock acquires an exclusive non-blocking lock; auto-released on process exit. |
| 48 | func (l *LockFile) TryLock() error { |