@intentic/keyring 1.344.0 → 1.345.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (231) hide show
  1. package/README.md +141 -45
  2. package/dist/address.d.ts +0 -1
  3. package/dist/address.d.ts.map +1 -1
  4. package/dist/address.js +1 -1
  5. package/dist/address.js.map +1 -1
  6. package/dist/app.d.ts.map +1 -1
  7. package/dist/app.js +49 -48
  8. package/dist/app.js.map +1 -1
  9. package/dist/askpass/answer.d.ts +12 -0
  10. package/dist/askpass/answer.d.ts.map +1 -0
  11. package/dist/askpass/answer.js +204 -0
  12. package/dist/askpass/answer.js.map +1 -0
  13. package/dist/askpass/askpass.d.ts +6 -0
  14. package/dist/askpass/askpass.d.ts.map +1 -1
  15. package/dist/askpass/askpass.js +28 -0
  16. package/dist/askpass/askpass.js.map +1 -1
  17. package/dist/audit.d.ts +5 -2
  18. package/dist/audit.d.ts.map +1 -1
  19. package/dist/audit.js +15 -2
  20. package/dist/audit.js.map +1 -1
  21. package/dist/consent/consent-posix.d.ts +7 -3
  22. package/dist/consent/consent-posix.d.ts.map +1 -1
  23. package/dist/consent/consent-posix.js +82 -12
  24. package/dist/consent/consent-posix.js.map +1 -1
  25. package/dist/consent/consent-windows.d.ts +3 -1
  26. package/dist/consent/consent-windows.d.ts.map +1 -1
  27. package/dist/consent/consent-windows.js +174 -62
  28. package/dist/consent/consent-windows.js.map +1 -1
  29. package/dist/consent/consent.d.ts +41 -2
  30. package/dist/consent/consent.d.ts.map +1 -1
  31. package/dist/consent/consent.js +7 -5
  32. package/dist/consent/consent.js.map +1 -1
  33. package/dist/core.d.ts +3 -30
  34. package/dist/core.d.ts.map +1 -1
  35. package/dist/core.js +189 -62
  36. package/dist/core.js.map +1 -1
  37. package/dist/git-credential/git-credential.d.ts +18 -0
  38. package/dist/git-credential/git-credential.d.ts.map +1 -0
  39. package/dist/git-credential/git-credential.js +68 -0
  40. package/dist/git-credential/git-credential.js.map +1 -0
  41. package/dist/index.d.ts +5 -2
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +5 -2
  44. package/dist/index.js.map +1 -1
  45. package/dist/native-host/framing.d.ts +10 -0
  46. package/dist/native-host/framing.d.ts.map +1 -0
  47. package/dist/native-host/framing.js +33 -0
  48. package/dist/native-host/framing.js.map +1 -0
  49. package/dist/native-host/native-host.d.ts +11 -0
  50. package/dist/native-host/native-host.d.ts.map +1 -0
  51. package/dist/native-host/native-host.js +130 -0
  52. package/dist/native-host/native-host.js.map +1 -0
  53. package/dist/passwords/access.d.ts +73 -0
  54. package/dist/passwords/access.d.ts.map +1 -0
  55. package/dist/passwords/access.js +3 -0
  56. package/dist/passwords/access.js.map +1 -0
  57. package/dist/passwords/app-ops.d.ts +18 -0
  58. package/dist/passwords/app-ops.d.ts.map +1 -0
  59. package/dist/passwords/app-ops.js +261 -0
  60. package/dist/passwords/app-ops.js.map +1 -0
  61. package/dist/passwords/capture.d.ts +35 -0
  62. package/dist/passwords/capture.d.ts.map +1 -0
  63. package/dist/passwords/capture.js +306 -0
  64. package/dist/passwords/capture.js.map +1 -0
  65. package/dist/passwords/entries.d.ts +20 -0
  66. package/dist/passwords/entries.d.ts.map +1 -0
  67. package/dist/passwords/entries.js +57 -0
  68. package/dist/passwords/entries.js.map +1 -0
  69. package/dist/passwords/fills.d.ts +10 -0
  70. package/dist/passwords/fills.d.ts.map +1 -0
  71. package/dist/passwords/fills.js +87 -0
  72. package/dist/passwords/fills.js.map +1 -0
  73. package/dist/passwords/needs.d.ts +11 -0
  74. package/dist/passwords/needs.d.ts.map +1 -0
  75. package/dist/passwords/needs.js +232 -0
  76. package/dist/passwords/needs.js.map +1 -0
  77. package/dist/passwords/phone.d.ts +19 -0
  78. package/dist/passwords/phone.d.ts.map +1 -0
  79. package/dist/passwords/phone.js +125 -0
  80. package/dist/passwords/phone.js.map +1 -0
  81. package/dist/protocol.d.ts +1169 -0
  82. package/dist/protocol.d.ts.map +1 -1
  83. package/dist/protocol.js +86 -1
  84. package/dist/protocol.js.map +1 -1
  85. package/dist/service/channel.d.ts +10 -3
  86. package/dist/service/channel.d.ts.map +1 -1
  87. package/dist/service/channel.js +31 -13
  88. package/dist/service/channel.js.map +1 -1
  89. package/dist/service/door.d.ts +45 -4
  90. package/dist/service/door.d.ts.map +1 -1
  91. package/dist/service/door.js +31 -2
  92. package/dist/service/door.js.map +1 -1
  93. package/dist/service/helper.d.ts +18 -1
  94. package/dist/service/helper.d.ts.map +1 -1
  95. package/dist/service/helper.js +68 -28
  96. package/dist/service/helper.js.map +1 -1
  97. package/dist/service/linux/install-linux.d.ts +12 -0
  98. package/dist/service/linux/install-linux.d.ts.map +1 -0
  99. package/dist/service/linux/install-linux.js +133 -0
  100. package/dist/service/linux/install-linux.js.map +1 -0
  101. package/dist/service/linux/paths-linux.d.ts +21 -0
  102. package/dist/service/linux/paths-linux.d.ts.map +1 -0
  103. package/dist/service/linux/paths-linux.js +31 -0
  104. package/dist/service/linux/paths-linux.js.map +1 -0
  105. package/dist/service/linux/polkit-linux.d.ts +29 -0
  106. package/dist/service/linux/polkit-linux.d.ts.map +1 -0
  107. package/dist/service/linux/polkit-linux.js +89 -0
  108. package/dist/service/linux/polkit-linux.js.map +1 -0
  109. package/dist/service/linux/service-run-linux.d.ts +4 -0
  110. package/dist/service/linux/service-run-linux.d.ts.map +1 -0
  111. package/dist/service/linux/service-run-linux.js +52 -0
  112. package/dist/service/linux/service-run-linux.js.map +1 -0
  113. package/dist/service/linux/session-linux.d.ts +4 -0
  114. package/dist/service/linux/session-linux.d.ts.map +1 -0
  115. package/dist/service/linux/session-linux.js +13 -0
  116. package/dist/service/linux/session-linux.js.map +1 -0
  117. package/dist/service/linux/unit-linux.d.ts +16 -0
  118. package/dist/service/linux/unit-linux.d.ts.map +1 -0
  119. package/dist/service/linux/unit-linux.js +67 -0
  120. package/dist/service/linux/unit-linux.js.map +1 -0
  121. package/dist/service/platform.d.ts +7 -0
  122. package/dist/service/platform.d.ts.map +1 -0
  123. package/dist/service/platform.js +62 -0
  124. package/dist/service/platform.js.map +1 -0
  125. package/dist/service/recovery.d.ts +3 -0
  126. package/dist/service/recovery.d.ts.map +1 -0
  127. package/dist/service/recovery.js +22 -0
  128. package/dist/service/recovery.js.map +1 -0
  129. package/dist/service/remote.d.ts +4 -1
  130. package/dist/service/remote.d.ts.map +1 -1
  131. package/dist/service/remote.js +41 -6
  132. package/dist/service/remote.js.map +1 -1
  133. package/dist/service/service-key.d.ts +9 -0
  134. package/dist/service/service-key.d.ts.map +1 -0
  135. package/dist/service/service-key.js +55 -0
  136. package/dist/service/service-key.js.map +1 -0
  137. package/dist/service/service-run.d.ts +20 -2
  138. package/dist/service/service-run.d.ts.map +1 -1
  139. package/dist/service/service-run.js +52 -46
  140. package/dist/service/service-run.js.map +1 -1
  141. package/dist/service/user.d.ts +8 -0
  142. package/dist/service/user.d.ts.map +1 -0
  143. package/dist/service/user.js +39 -0
  144. package/dist/service/user.js.map +1 -0
  145. package/dist/service/{acl.d.ts → windows/acl-windows.d.ts} +3 -3
  146. package/dist/service/windows/acl-windows.d.ts.map +1 -0
  147. package/dist/service/{acl.js → windows/acl-windows.js} +3 -3
  148. package/dist/service/windows/acl-windows.js.map +1 -0
  149. package/dist/service/{install.d.ts → windows/install-windows.d.ts} +4 -2
  150. package/dist/service/windows/install-windows.d.ts.map +1 -0
  151. package/dist/service/{install.js → windows/install-windows.js} +13 -12
  152. package/dist/service/windows/install-windows.js.map +1 -0
  153. package/dist/service/windows/leftovers-windows.d.ts +8 -0
  154. package/dist/service/windows/leftovers-windows.d.ts.map +1 -0
  155. package/dist/service/windows/leftovers-windows.js +44 -0
  156. package/dist/service/windows/leftovers-windows.js.map +1 -0
  157. package/dist/service/{paths.d.ts → windows/paths-windows.d.ts} +4 -5
  158. package/dist/service/windows/paths-windows.d.ts.map +1 -0
  159. package/dist/service/{paths.js → windows/paths-windows.js} +5 -5
  160. package/dist/service/windows/paths-windows.js.map +1 -0
  161. package/dist/service/windows/service-run-windows.d.ts +4 -0
  162. package/dist/service/windows/service-run-windows.d.ts.map +1 -0
  163. package/dist/service/windows/service-run-windows.js +46 -0
  164. package/dist/service/windows/service-run-windows.js.map +1 -0
  165. package/dist/service/windows/session-windows.d.ts +4 -0
  166. package/dist/service/windows/session-windows.d.ts.map +1 -0
  167. package/dist/service/windows/session-windows.js +13 -0
  168. package/dist/service/windows/session-windows.js.map +1 -0
  169. package/dist/service/windows/sid-windows.d.ts +3 -0
  170. package/dist/service/windows/sid-windows.d.ts.map +1 -0
  171. package/dist/service/{sid.js → windows/sid-windows.js} +2 -2
  172. package/dist/service/windows/sid-windows.js.map +1 -0
  173. package/dist/service/{task.d.ts → windows/task-windows.d.ts} +4 -3
  174. package/dist/service/windows/task-windows.d.ts.map +1 -0
  175. package/dist/service/{task.js → windows/task-windows.js} +19 -2
  176. package/dist/service/windows/task-windows.js.map +1 -0
  177. package/dist/service/wire.d.ts +32 -0
  178. package/dist/service/wire.d.ts.map +1 -1
  179. package/dist/service/wire.js +15 -0
  180. package/dist/service/wire.js.map +1 -1
  181. package/dist/typing/clipboard.d.ts +13 -0
  182. package/dist/typing/clipboard.d.ts.map +1 -0
  183. package/dist/typing/clipboard.js +56 -0
  184. package/dist/typing/clipboard.js.map +1 -0
  185. package/dist/typing/index.d.ts.map +1 -1
  186. package/dist/typing/index.js +2 -1
  187. package/dist/typing/index.js.map +1 -1
  188. package/dist/typing/typist.d.ts +3 -1
  189. package/dist/typing/typist.d.ts.map +1 -1
  190. package/dist/typing/typist.js +2 -1
  191. package/dist/typing/typist.js.map +1 -1
  192. package/dist/vault.d.ts +785 -0
  193. package/dist/vault.d.ts.map +1 -1
  194. package/dist/vault.js +24 -2
  195. package/dist/vault.js.map +1 -1
  196. package/dist/watch/apps.d.ts +10 -0
  197. package/dist/watch/apps.d.ts.map +1 -0
  198. package/dist/watch/apps.js +95 -0
  199. package/dist/watch/apps.js.map +1 -0
  200. package/dist/watch/chip.d.ts +52 -0
  201. package/dist/watch/chip.d.ts.map +1 -0
  202. package/dist/watch/chip.js +76 -0
  203. package/dist/watch/chip.js.map +1 -0
  204. package/dist/watch/lines-child.d.ts +9 -0
  205. package/dist/watch/lines-child.d.ts.map +1 -0
  206. package/dist/watch/lines-child.js +34 -0
  207. package/dist/watch/lines-child.js.map +1 -0
  208. package/dist/watch/watch-linux.d.ts +6 -0
  209. package/dist/watch/watch-linux.d.ts.map +1 -0
  210. package/dist/watch/watch-linux.js +52 -0
  211. package/dist/watch/watch-linux.js.map +1 -0
  212. package/dist/watch/watch-windows.d.ts +6 -0
  213. package/dist/watch/watch-windows.d.ts.map +1 -0
  214. package/dist/watch/watch-windows.js +110 -0
  215. package/dist/watch/watch-windows.js.map +1 -0
  216. package/package.json +5 -5
  217. package/dist/serve.d.ts +0 -17
  218. package/dist/serve.d.ts.map +0 -1
  219. package/dist/serve.js +0 -65
  220. package/dist/serve.js.map +0 -1
  221. package/dist/service/acl.d.ts.map +0 -1
  222. package/dist/service/acl.js.map +0 -1
  223. package/dist/service/install.d.ts.map +0 -1
  224. package/dist/service/install.js.map +0 -1
  225. package/dist/service/paths.d.ts.map +0 -1
  226. package/dist/service/paths.js.map +0 -1
  227. package/dist/service/sid.d.ts +0 -3
  228. package/dist/service/sid.d.ts.map +0 -1
  229. package/dist/service/sid.js.map +0 -1
  230. package/dist/service/task.d.ts.map +0 -1
  231. package/dist/service/task.js.map +0 -1
package/README.md CHANGED
@@ -1,16 +1,17 @@
1
1
  # keyring
2
2
 
3
- `intentic-keyring`, the password vault on a user's own computer: a process of its own beside
3
+ `intentic-keyring`, the password vault behind Passwords on a user's own computer: a protected service of its own beside
4
4
  [intentic-machine](../machine) that types a secret into a window, answers an ssh or sudo prompt, or hands a value to a
5
5
  sandbox for one use, without the sandbox's agent ever holding the value.
6
6
 
7
7
  ```mermaid
8
8
  flowchart LR
9
9
  sb["Sandbox daemon<br/>signs grants"] -->|"keyring* procedures<br/>over the device link"| m["intentic-machine<br/>relays, reads nothing"]
10
- m -->|"local pipe"| k(["intentic-keyring<br/>vault · consent · typing"])
11
- k -->|"checks window, types"| app["FortiClient, RDP,<br/>any native app"]
10
+ m -->|"local pipe"| h["session helper<br/>prompts · typing · chip"]
11
+ h -->|"the door"| k(["protected service<br/>vault · consent"])
12
+ h -->|"checks window, types"| app["FortiClient, RDP,<br/>any native app"]
12
13
  k -->|"adb"| phone["Android app"]
13
- ssh["ssh · sudo · git"] --> ap["intentic-askpass"] -->|"local pipe"| k
14
+ ssh["ssh · sudo · git"] --> ap["intentic-askpass"] -->|"local pipe"| h
14
15
  k -->|"sealed to the sandbox"| m
15
16
  k <-->|"sealed to each other,<br/>through a sandbox"| k2(["keyring on another<br/>of the owner's computers"])
16
17
  ```
@@ -21,7 +22,10 @@ intentic-machine is the agent's hands on the computer: it runs the agent's `run_
21
22
  key kept in its memory would be one bug in its scope checks away from the agent, and it updates itself on a timer at a
22
23
  sandbox maintainer's word. The keyring does only what a vault does, updates only when a person says so
23
24
  (`intentic-machine keyring upgrade` asks the running keyring, which asks the person), and trusts no caller on its pipe
24
- for who it is. Every caller is a process of the same user, so the pipe is not the boundary; three things are:
25
+ for who it is. The vault itself is held by a service running as a system account of its own, so no process of the user,
26
+ the agent's own commands included, can read the vault file or the memory that holds its key (see "The protected
27
+ service" below). Every caller on the pipe is a process of the same user, so the pipe is not the boundary; three things
28
+ are:
25
29
 
26
30
  - **A grant the sandbox signed.** A release or a typing for a sandbox carries a grant (`@intentic/sandbox-contract`
27
31
  `schemas/keyring.ts`), Ed25519-signed by that sandbox's own key, which the keyring fetched over TLS from the
@@ -29,8 +33,9 @@ for who it is. Every caller is a process of the same user, so the pipe is not th
29
33
  names one secret, one target and one nonce, and lives two minutes. The agent's own commands on this computer can
30
34
  reach the pipe but cannot sign one.
31
35
  - **A person at this computer.** Anything that changes the vault, takes a value in, hands one to a local program
32
- (askpass), or answers an `each-use` share asks: Windows Hello where the computer has it, the keyring's passphrase
33
- otherwise. Every prompt says what is asked for, by whom, and where it goes.
36
+ (askpass), or answers an `each-use` share asks: a Windows Hello signature checked by the service against the key it
37
+ pinned at setup on Windows, a polkit check the service runs itself on Linux, and the recovery key where neither can
38
+ answer. Every prompt says what is asked for, by whom, and where it goes.
34
39
  - **The window it lands in.** Typing checks the focused window's program against the entry's list and, for a password,
35
40
  that the focused field is a password field. A value is never typed into a field that would echo it back to a
36
41
  screenshot unless the entry says `anyField`.
@@ -44,34 +49,39 @@ Each entry is shared with each sandbox on its own terms:
44
49
  | Mode | The sandbox gets a value when… | Works with the computer off |
45
50
  | --- | --- | --- |
46
51
  | `each-use` | the person at this computer says yes, each time | no |
47
- | `while-here` | the keyring is unlocked: one Hello tap or passphrase opens it for up to the minutes chosen | no |
52
+ | `while-here` | the keyring is unlocked: one Hello tap or polkit yes opens it for up to the minutes chosen | no |
48
53
  | `copy` | always: a copy, sealed to that sandbox, kept there as an ordinary secret and refreshed when the entry changes | yes |
49
54
 
50
55
  `copy` is the explicit downgrade: the value then lives in the sandbox and its guards are the sandbox's.
51
56
 
52
57
  ## Files
53
58
 
54
- Under `~/.intentic/keyring` (0700, its files 0600):
59
+ In the service's own folder (`%ProgramData%\Intentic\Keyring\<SID>` on Windows, `/var/lib/intentic-keyring/<uid>` on
60
+ Linux), readable by the service's account and an administrator only:
55
61
 
56
62
  - `vault.json`: the entries, sealed under the vault key (AES-256-GCM), and the vault key wrapped once per way of
57
- unlocking: by a key derived from the passphrase (scrypt), and on Windows by a key derived from a Windows Hello
58
- signature over a fixed challenge (KeyCredentialManager signs with an RSA key in the TPM; PKCS#1 v1.5 signatures are
59
- deterministic, so the same challenge gives the same key, and only a Hello gesture produces one). The inbox and sync
60
- private keys live inside the sealed part.
63
+ unlocking: by a key scrypt derives from the recovery key; on Windows by a key derived from a Windows Hello signature
64
+ over a fixed challenge (KeyCredentialManager signs with an RSA key in the TPM; PKCS#1 v1.5 signatures are
65
+ deterministic, so the same challenge gives the same key, and only a Hello gesture produces one); on Linux by the
66
+ service's own key (`service-key.json`). The inbox and sync private keys live inside the sealed part.
61
67
  - `keys.json`: what the keyring needs while locked: its `seal` key pair (for values sent to it to type) and each
62
68
  sandbox's pinned keys.
63
69
  - `audit.jsonl`: one line per decision (who asked, for what, the answer), never a value.
64
- - `keyring.log`, `keyring.pid`.
70
+ - `keyring.log`.
71
+
72
+ `~/.intentic/keyring` (0700) keeps the session helper's pid file and the user's pipe. A vault left there by the per-user
73
+ keyring from before is moved into the service's folder by `service install`, and put back there by `service uninstall`.
65
74
 
66
75
  ## The pipe
67
76
 
68
- A named pipe on Windows (`\\.\pipe\intentic-keyring-<user hash>`), a unix socket in the keyring's directory elsewhere.
69
- One JSON line in, one out (`src/protocol.ts`). A value sent in from this computer (`intentic-machine keyring add`, the
77
+ A named pipe on Windows (`\\.\pipe\intentic-keyring-<user hash>`), a unix socket in `~/.intentic/keyring` elsewhere,
78
+ answered by the session helper, which carries each request through the service's door. One JSON line in, one out
79
+ (`src/protocol.ts`). A value sent in from this computer (`intentic-machine keyring add`, the
70
80
  desktop app) is sealed to the vault's inbox key first, so a process squatting the pipe holds only ciphertext.
71
81
 
72
82
  ## Typing
73
83
 
74
- On Windows the keyring inspects the foreground window (its process's executable, and through UI Automation whether the
84
+ Typing is the session helper's, the service's hands in the person's session. On Windows it inspects the foreground window (its process's executable, and through UI Automation whether the
75
85
  focused element is a password field) and types with `SendInput` Unicode events, never `SendKeys`: the value goes to a
76
86
  PowerShell helper on its standard input, never on a command line another process could read. It checks the
77
87
  foreground window again after typing and says so if it changed. On Linux it types with `xdotool type --file -` or
@@ -102,36 +112,122 @@ computer, each prompt showing both sync-key fingerprints to compare. After that
102
112
  sync key and left in a sandbox both are linked to, which carries ciphertext only; the other takes it in at its next
103
113
  unlock. The newer revision of an entry wins.
104
114
 
105
- ## Hardened mode (Windows)
106
-
107
- `intentic-machine keyring harden` (one UAC prompt) moves the vault out of the user's reach:
108
-
109
- - The vault, its keys and its audit move to `%ProgramData%\Intentic\Keyring\<user SID>`, whose access list names only
110
- `LOCAL SERVICE`, SYSTEM and an elevated administrator. No process of the user, the agent's `run_command` included,
111
- can read the file or the memory of the process that holds it.
112
- - That process is the keyring itself, run by a startup task (`\Intentic\Keyring-<SID>`) as `LOCAL SERVICE` from its
113
- own copy in `%ProgramData%\Intentic\Keyring\bin`, which only an administrator can replace. A task and not a Windows
114
- service because a compiled script cannot answer the service manager's start handshake (`src/service/task.ts`).
115
- - A pipe the service created would refuse the user's writes, so it listens on loopback and writes its port and a random
116
- token to a door file only that user can read (`src/service/door.ts`). The token keeps other users out; it does not keep
117
- out the user's own programs, which is why every value still needs a sandbox's grant or a person's yes.
118
- - The session helper, `intentic-keyring session`, starts at sign-in in place of `serve`. It answers the user's usual pipe
119
- by carrying each request through the door, so intentic-machine and intentic-askpass work unchanged, and it is the
120
- service's hands: it shows the prompts and does the typing. It proves itself once per sign-in with a Windows Hello
121
- signature over the service's challenge (or the passphrase), and every yes it relays afterwards is a Hello signature
122
- over a fresh challenge, checked by the service against the Hello key pinned at setup (`src/service/hello-verify.ts`),
123
- so a helper the agent started cannot say yes for the person.
124
-
125
- What it does not cover: a value being typed passes through the helper, a process of the user, for that moment. Every
126
- other value, the vault key and the vault itself stay with the service.
115
+ ## The protected service
116
+
117
+ There is one mode (2026-10-19; before it the vault was held by `intentic-keyring serve`, a process of the user, and
118
+ the service below was an optional "hardened mode" on Windows). `intentic-machine keyring setup` asks for an
119
+ administrator's yes once (UAC on Windows, `pkexec` on Linux) to run `intentic-keyring service install`, then starts the
120
+ session helper and sets the vault up. Setup refuses on macOS ("Passwords needs the Intentic desktop app's protected
121
+ service, which is not on macOS yet."), and on a Linux without systemd, polkit or setfacl, saying which.
122
+
123
+ Two processes share the work (`src/service/`):
124
+
125
+ - **The service** holds the vault and its key and decides every request (`service run --user <id>`). It cannot reach
126
+ the person's desktop, so it never shows a prompt or types itself.
127
+ - **The session helper**, `intentic-keyring session`, starts at sign-in from the login entry intentic-machine registers.
128
+ It answers the user's usual pipe by carrying each request through the service's door (`src/service/door.ts`), so
129
+ intentic-machine and intentic-askpass work as they did, and it is the service's hands: it shows the prompts and the
130
+ type-once box and does the typing. It proves a person is at the session once per sign-in before the service sends it
131
+ anything; before setup there is no vault and nothing to prove with, so it is let in to enrol Windows Hello, and only
132
+ while no vault exists.
133
+ - **The door** is a loopback port on Windows (a pipe the service created would refuse the user's writes) and a unix
134
+ socket on Linux, beside a random token in a door file only that user can read. The token keeps other users out; it
135
+ does not keep out the user's own programs, which is why every value still needs a sandbox's grant or a person's yes.
136
+
137
+ ### Windows
138
+
139
+ - The vault, its keys and its audit live in `%ProgramData%\Intentic\Keyring\<user SID>`, whose access list names only
140
+ `LOCAL SERVICE`, SYSTEM and an elevated administrator.
141
+ - The service is the keyring run by a startup task (`\Intentic\Keyring-<SID>`) as `LOCAL SERVICE` from its own copy in
142
+ `%ProgramData%\Intentic\Keyring\bin`, which only an administrator can replace. A task and not a Windows service
143
+ because a compiled script cannot answer the service manager's start handshake (`src/service/windows/task-windows.ts`).
144
+ - The helper proves itself with a Windows Hello signature over the service's challenge, and every yes it relays is a
145
+ Hello signature over a fresh challenge, checked by the service against the Hello key pinned at setup
146
+ (`src/service/hello-verify.ts`), so a helper the agent started cannot say yes for the person. Unlocking is a Hello
147
+ tap; the recovery key opens the vault when Hello is reset.
148
+ - The marker `%ProgramData%\Intentic\Keyring\<SID>.hardened` says the service is installed for that user. The name is
149
+ from hardened mode, kept so a PC set up before still reads as set up.
150
+
151
+ ### Linux
152
+
153
+ - `service install`, run as root by pkexec for the user pkexec names (`PKEXEC_UID`), makes the `intentic-keyring` system
154
+ user, copies the program to `/usr/lib/intentic-keyring/intentic-keyring` (root's), writes the templated unit
155
+ `/etc/systemd/system/intentic-keyring@.service` and the polkit action
156
+ `/usr/share/polkit-1/actions/dev.intentic.keyring.policy`, moves a per-user vault from before, writes the marker
157
+ `/var/lib/intentic-keyring/<uid>.installed`, and enables `intentic-keyring@<uid>.service` (`src/service/linux/install-linux.ts`,
158
+ `unit-linux.ts`).
159
+ - systemd runs the instance as `intentic-keyring` with the vault in `/var/lib/intentic-keyring/<uid>` (StateDirectory,
160
+ 0700) and the door in `/run/intentic-keyring/<uid>` (RuntimeDirectory, 0700), which the service opens to that one uid
161
+ with setfacl: the folder may be entered, the socket written, the token read (`src/service/linux/service-run-linux.ts`).
162
+ - Node cannot read a unix socket's peer credentials, so the helper names its pid; the service checks that the pid is a
163
+ live process of that uid (`/proc`) and runs `pkcheck --action-id dev.intentic.keyring.consent --process
164
+ <pid>,<start time>,<uid> --allow-user-interaction` itself. polkit's agent in that session asks for the person's own
165
+ password (`auth_self`, never kept), and the answer comes back to the service, not through the helper
166
+ (`src/service/linux/polkit-linux.ts`). The action's `org.freedesktop.policykit.owner` annotation is what lets the service's
167
+ user ask about another user's process. Every later yes is the same check, its dialog naming what is asked.
168
+ - A daily unlock is that yes: the vault key is wrapped once more under a random key in `service-key.json`, which only the
169
+ service's user reads (`src/service/service-key.ts`). A vault moved in from before has no such wrap yet: its first
170
+ unlock asks its recovery key (or old passphrase) once and adds it. Where polkit cannot ask (no agent in the session,
171
+ pkcheck missing, a polkit too old for the owner annotation), the recovery key is asked through the helper instead.
172
+ - The helper starts from the login entry intentic-machine registers (a systemd user unit or an XDG autostart entry) and
173
+ shows its dialogs with zenity or kdialog.
174
+
175
+ ### Undone
176
+
177
+ `intentic-keyring service uninstall`, run as an administrator by `intentic-machine keyring uninstall` and by the agent's
178
+ `uninstall --purge`: the task or unit is removed and the vault, its keys and its audit go back to `~/.intentic/keyring`.
179
+ Then what the service left goes too (`src/service/windows/leftovers-windows.ts`, `install-linux.ts`): the user's emptied
180
+ folder and, once no other user's marker is left, the service's program, its folders, the Task Scheduler `\Intentic\`
181
+ folder (Windows), and the unit, the polkit action and the system user (Linux). Its JSON answer names them in `swept`,
182
+ and whatever could not go, with why, in `left`.
183
+
184
+ ## The recovery key
185
+
186
+ Setup makes the recovery key, not the person: six groups of five Crockford base32 characters
187
+ (`XXXXX-XXXXX-XXXXX-XXXXX-XXXXX-XXXXX`, 150 bits, `src/service/recovery.ts`), shown once by `keyring setup` and never
188
+ stored. The vault wraps the vault key under it exactly as it wrapped a passphrase (scrypt), and the setup op still names
189
+ the field `passphrase`. Asked for in the passphrase box ("Type your recovery key"), it is read without regard to case,
190
+ spaces or dashes, with I, L and O read as 1, 1 and 0; anything else is tried as typed, so a passphrase from before
191
+ still opens a vault it made.
192
+
193
+ ## The type-once box
194
+
195
+ When nothing in the vault answers a prompt (ssh asking for a password nobody saved, a program's password field, an
196
+ agent's need with no match), the service has the helper show its own box asking for the value once, with a "Remember
197
+ it" choice (consent.ts `ValuePrompt`). The answer goes to the service alone. On Linux it is zenity's `--forms` (a hidden
198
+ field and a Yes/No choice), or two kdialog dialogs; the Windows box is `consent-windows.ts`'s.
199
+
200
+ ## The app chip
201
+
202
+ While the person lets Passwords remember what they type in programs (the vault's `remember.apps`, read through the
203
+ `state` op every minute), the session helper watches which field has the keyboard's focus (`src/watch/`). On Windows a
204
+ long-running PowerShell holds a UI Automation focus-changed handler, reporting whether the focused element is a password
205
+ field, its program's executable and where it is; a small topmost window that never takes focus then shows under the
206
+ field, "Fill with Intentic" when `candidates` has an entry for that program and "Save with Intentic" when not, and goes
207
+ when focus moves or after eight seconds. A click sends `fill-window`. On Linux the watcher is AT-SPI through python3-gi,
208
+ and the chip is a desktop notification with one action, since a Wayland compositor does not let a program place a
209
+ window; without python3's AT-SPI bindings the chip stays off. Nothing reads a field's value or hooks the keyboard.
127
210
 
128
211
  ## Limits
129
212
 
130
- - Without hardened mode, a process of the same user can read the vault key from the keyring's memory while it is
131
- unlocked, and could trick a person into a Hello tap meant for the keyring; `while-here` is for a computer you are at.
132
- - Windows Hello's own prompt says only "Making sure it's you": the topmost notice beside it is what names the request.
133
- A program that raises a Hello prompt of its own gets the same dialog without the notice.
134
- - A Windows Hello prompt raised by a process with no window can open behind other windows; the keyring shows a
135
- topmost notice naming what is asked while it waits.
213
+ - A value being typed passes through the session helper, a process of the user, for that moment, and so does what the
214
+ person types into the type-once box. Every other value, the vault key and the vault itself stay with the service.
215
+ - The helper is proven by a person's yes at sign-in, not by what program it is: a program of the user that gets the
216
+ person to approve it is a helper too. The service checks every later yes itself (a Hello signature, a polkit check),
217
+ so such a helper can show prompts and receive what it is asked to type, but cannot say yes for the person.
218
+ - Before setup, a helper is let in without proof, because there is no vault yet; a program of the user that set the
219
+ vault up first would hold its recovery key. `keyring setup` sets it up right after installing the service.
220
+ - Windows Hello's own prompt for unlocking says only "Making sure it's you", without naming the request, and one
221
+ raised by a process with no window can open behind other windows.
222
+ - On X11 every program of the same user can read keystrokes, those typed into the type-once box and those the helper
223
+ types included; Wayland does not allow that.
136
224
  - Typing cannot be taken back: if focus moves between the check and the last character, the keyring stops and says
137
225
  where the rest went.
226
+ - Password managers read at each use (`op`, `bw`, `keepassxc-cli`) run inside the service: on Linux its unit hides home
227
+ folders (ProtectHome), so a manager that keeps its session there cannot be read from.
228
+
229
+ Not exercised by this package's tests: UAC, Task Scheduler and Windows Hello; systemd, pkexec, polkit's dialog, its
230
+ `$(title)`/`$(message)` substitution and the owner annotation; setfacl; UI Automation's focus events and the chip
231
+ window; AT-SPI and notify-send's action. What is tested is what is pure (paths, the unit and policy text, argv, the
232
+ door's messages, pkcheck's answers, the chip's decisions) and the door, helper and type-once box over real sockets with
233
+ fake hands.
package/dist/address.d.ts CHANGED
@@ -8,7 +8,6 @@ export interface KeyringPaths {
8
8
  readonly pid: string;
9
9
  readonly address: string;
10
10
  }
11
- export declare const userTag: () => string;
12
11
  export declare const keyringAddress: (dir: string, platform?: NodeJS.Platform) => string;
13
12
  export declare const keyringPaths: (dir?: string, platform?: NodeJS.Platform) => KeyringPaths;
14
13
  //# sourceMappingURL=address.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,YAAY,YAAY,CAAC;AAEtC,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC5B;AAGD,eAAO,MAAM,OAAO,QAAO,MAAmG,CAAC;AAE/H,eAAO,MAAM,cAAc,QAAS,MAAM,aAAY,MAAM,CAAC,QAAQ,KAAsB,MACQ,CAAC;AAEpG,eAAO,MAAM,YAAY,SAAS,MAAM,aAA0C,MAAM,CAAC,QAAQ,KAAsB,YAQrH,CAAC"}
1
+ {"version":3,"file":"address.d.ts","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"AASA,eAAO,MAAM,YAAY,YAAY,CAAC;AAEtC,MAAM,WAAW,YAAY;IACzB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IAEvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IAErB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;CAC5B;AAKD,eAAO,MAAM,cAAc,QAAS,MAAM,aAAY,MAAM,CAAC,QAAQ,KAAsB,MACQ,CAAC;AAEpG,eAAO,MAAM,YAAY,SAAS,MAAM,aAA0C,MAAM,CAAC,QAAQ,KAAsB,YAQrH,CAAC"}
package/dist/address.js CHANGED
@@ -3,7 +3,7 @@ import { userInfo } from "node:os";
3
3
  import { join } from "node:path";
4
4
  import { agentHome } from "@intentic/local-agent";
5
5
  export const KEYRING_HOME = "keyring";
6
- export const userTag = () => createHash("sha256").update(userInfo().username.toLowerCase()).digest("hex").slice(0, 12);
6
+ const userTag = () => createHash("sha256").update(userInfo().username.toLowerCase()).digest("hex").slice(0, 12);
7
7
  export const keyringAddress = (dir, platform = process.platform) => platform === "win32" ? `\\\\.\\pipe\\intentic-keyring-${userTag()}` : join(dir, "keyring.sock");
8
8
  export const keyringPaths = (dir = agentHome(KEYRING_HOME).dir, platform = process.platform) => ({
9
9
  dir,
@@ -1 +1 @@
1
- {"version":3,"file":"address.js","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAMlD,MAAM,CAAC,MAAM,YAAY,GAAG,SAAS,CAAC;AAiBtC,MAAM,CAAC,MAAM,OAAO,GAAG,GAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAE/H,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAW,EAAE,QAAQ,GAAoB,OAAO,CAAC,QAAQ,EAAU,EAAE,CAChG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,iCAAiC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;AAEpG,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAG,GAAW,SAAS,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,QAAQ,GAAoB,OAAO,CAAC,QAAQ,EAAgB,EAAE,CAAC,CAAC;IACpI,GAAG;IACH,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC;IAC9B,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC;IAC5B,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC;IAC/B,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC;IAC7B,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC;IAC7B,OAAO,EAAE,cAAc,CAAC,GAAG,EAAE,QAAQ,CAAC;CACzC,CAAC,CAAC"}
1
+ {"version":3,"file":"address.js","sourceRoot":"","sources":["../src/address.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAMlD,MAAM,CAAC,MAAM,YAAY,GAAG,SAAS,CAAC;AAiBtC,MAAM,OAAO,GAAG,GAAW,EAAE,CAAC,UAAU,CAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,QAAQ,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;AAExH,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,GAAW,EAAE,QAAQ,GAAoB,OAAO,CAAC,QAAQ,EAAU,EAAE,CAChG,QAAQ,KAAK,OAAO,CAAC,CAAC,CAAC,iCAAiC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;AAEpG,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,GAAG,GAAW,SAAS,CAAC,YAAY,CAAC,CAAC,GAAG,EAAE,QAAQ,GAAoB,OAAO,CAAC,QAAQ,EAAgB,EAAE,CAAC,CAAC;IACpI,GAAG;IACH,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC;IAC9B,IAAI,EAAE,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC;IAC5B,KAAK,EAAE,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC;IAC/B,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC;IAC7B,GAAG,EAAE,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC;IAC7B,OAAO,EAAE,cAAc,CAAC,GAAG,EAAE,QAAQ,CAAC;CACzC,CAAC,CAAC"}
package/dist/app.d.ts.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AA2GpD,eAAO,MAAM,GAAG,qDAKd,CAAC"}
1
+ {"version":3,"file":"app.d.ts","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAmHpD,eAAO,MAAM,GAAG,qDAKd,CAAC"}
package/dist/app.js CHANGED
@@ -1,29 +1,17 @@
1
+ import { errorMessage } from "@intentic/base/errors";
1
2
  import { agentException } from "@intentic/local-agent";
2
- import { buildApplication, buildCommand, buildRouteMap, text_en } from "@stricli/core";
3
+ import { buildApplication, buildChoiceParser, buildCommand, buildRouteMap, text_en } from "@stricli/core";
3
4
  import { askpass } from "./askpass/askpass-run.js";
4
- import { serve } from "./serve.js";
5
- import { runSession } from "./service/helper.js";
6
- import { installService, uninstallService } from "./service/install.js";
7
- import { SID_RE } from "./service/paths.js";
8
- import { runService } from "./service/service-run.js";
9
- import { realRunner } from "./run.js";
5
+ import { runGitCredential } from "./git-credential/git-credential.js";
6
+ import { runNativeHost } from "./native-host/native-host.js";
7
+ import { installHere, runServiceHere, runSessionHere, uninstallHere, userIdFits } from "./service/platform.js";
10
8
  import { KEYRING_VERSION } from "./version.js";
11
9
  const serveCommand = buildCommand({
12
- docs: { brief: "Run the keyring (started at sign-in; there is one per user)" },
10
+ docs: { brief: "Retired: Passwords runs as a protected service now (intentic-machine keyring setup)" },
13
11
  parameters: {},
14
- async func() {
15
- const served = await serve();
16
- if (!served.ok) {
17
- this.process.stderr.write(`${served.reason}\n`);
18
- process.exitCode = 1;
19
- return;
20
- }
21
- const stop = () => {
22
- void served.stop().then(() => process.exit(0));
23
- };
24
- process.once("SIGINT", stop);
25
- process.once("SIGTERM", stop);
26
- await new Promise(() => undefined);
12
+ func() {
13
+ this.process.stderr.write("Passwords runs as a protected service now, not as `serve`: `intentic-machine keyring setup` moves this computer to it.\n");
14
+ process.exitCode = 1;
27
15
  },
28
16
  });
29
17
  const versionCommand = buildCommand({
@@ -40,58 +28,71 @@ const askpassCommand = buildCommand({
40
28
  process.exitCode = await askpass(prompt.join(" "), this.process.stdout, this.process.stderr);
41
29
  },
42
30
  });
43
- const windowsOnly = () => {
44
- if (process.platform !== "win32") {
45
- process.stderr.write("Hardened mode is Windows-only.\n");
31
+ const readAll = async () => {
32
+ const chunks = [];
33
+ for await (const chunk of process.stdin) {
34
+ chunks.push(Buffer.from(chunk));
35
+ }
36
+ return Buffer.concat(chunks).toString("utf8");
37
+ };
38
+ const gitCredentialCommand = buildCommand({
39
+ docs: { brief: "git's credential helper: get, store or erase an https sign-in (git runs this)" },
40
+ parameters: { flags: {}, positional: { kind: "tuple", parameters: [{ brief: "get, store or erase", parse: buildChoiceParser(["get", "store", "erase"]), placeholder: "get|store|erase" }] } },
41
+ async func(_flags, action) {
42
+ const input = await readAll();
43
+ process.exitCode = await runGitCredential(action, { input, write: (text) => this.process.stdout.write(text), warn: (text) => this.process.stderr.write(text) });
44
+ },
45
+ });
46
+ const nativeHostCommand = buildCommand({
47
+ docs: { brief: "The browser extension's native-messaging host (the browser runs this)" },
48
+ parameters: { flags: {}, positional: { kind: "array", parameter: { brief: "What the browser passes", parse: String } } },
49
+ async func(_flags, ..._passed) {
50
+ process.exitCode = await runNativeHost({ input: process.stdin, write: (frame) => process.stdout.write(frame) });
51
+ },
52
+ });
53
+ const answered = async (stdout, work) => {
54
+ try {
55
+ stdout.write(`${JSON.stringify({ ok: true, ...(await work()) })}\n`);
56
+ }
57
+ catch (error) {
58
+ process.stderr.write(`${errorMessage(error)}\n`);
46
59
  process.exitCode = 1;
47
- return false;
48
60
  }
49
- return true;
50
61
  };
51
62
  const installCommand = buildCommand({
52
- docs: { brief: "Move the vault under the hardened service (run elevated; intentic-machine keyring harden does this)" },
63
+ docs: { brief: "Install Passwords' protected service for you, moving a vault from before into it (run as an administrator; intentic-machine keyring setup does this)" },
53
64
  parameters: {},
54
65
  async func() {
55
- if (windowsOnly()) {
56
- const done = await installService(realRunner);
57
- this.process.stdout.write(`${JSON.stringify({ ok: true, ...done })}\n`);
58
- }
66
+ await answered(this.process.stdout, async () => await installHere());
59
67
  },
60
68
  });
61
69
  const uninstallCommand = buildCommand({
62
- docs: { brief: "Put the vault back in your own folder and remove the hardened service (run elevated)" },
70
+ docs: { brief: "Put the vault back in your own folder and remove Passwords' protected service (run as an administrator)" },
63
71
  parameters: {},
64
72
  async func() {
65
- if (windowsOnly()) {
66
- const done = await uninstallService(realRunner);
67
- this.process.stdout.write(`${JSON.stringify({ ok: true, ...done })}\n`);
68
- }
73
+ await answered(this.process.stdout, async () => await uninstallHere());
69
74
  },
70
75
  });
71
76
  const runCommand = buildCommand({
72
- docs: { brief: "Run the hardened service (what its startup task starts)" },
73
- parameters: { flags: { user: { kind: "parsed", parse: String, brief: "The user's security identifier" } } },
77
+ docs: { brief: "Run Passwords' protected service (what the system starts)" },
78
+ parameters: { flags: { user: { kind: "parsed", parse: String, brief: "The user it is for: a security identifier (Windows) or a uid (Linux)" } } },
74
79
  async func(flags) {
75
- if (!SID_RE.test(flags.user)) {
76
- this.process.stderr.write("--user takes a security identifier (S-1-5-…).\n");
80
+ if (!userIdFits(flags.user)) {
81
+ this.process.stderr.write("--user takes a security identifier (S-1-5-…) on Windows, a numeric uid on Linux.\n");
77
82
  process.exitCode = 1;
78
83
  return;
79
84
  }
80
- if (windowsOnly()) {
81
- await runService(flags.user);
82
- }
85
+ await runServiceHere(flags.user);
83
86
  },
84
87
  });
85
88
  const sessionCommand = buildCommand({
86
- docs: { brief: "Run the session helper of a hardened keyring (started at sign-in)" },
89
+ docs: { brief: "Run Passwords' session helper (started at sign-in)" },
87
90
  parameters: {},
88
91
  async func() {
89
- if (windowsOnly()) {
90
- await runSession();
91
- }
92
+ await runSessionHere();
92
93
  },
93
94
  });
94
- export const app = buildApplication(buildRouteMap({ routes: { serve: serveCommand, version: versionCommand, askpass: askpassCommand, service: buildRouteMap({ routes: { install: installCommand, uninstall: uninstallCommand, run: runCommand }, docs: { brief: "Hardened mode (Windows)" } }), session: sessionCommand }, docs: { brief: "The Intentic keyring" } }), {
95
+ export const app = buildApplication(buildRouteMap({ routes: { serve: serveCommand, version: versionCommand, askpass: askpassCommand, "git-credential": gitCredentialCommand, "native-host": nativeHostCommand, service: buildRouteMap({ routes: { install: installCommand, uninstall: uninstallCommand, run: runCommand }, docs: { brief: "Passwords' protected service" } }), session: sessionCommand }, docs: { brief: "The Intentic keyring" } }), {
95
96
  name: "intentic-keyring",
96
97
  versionInfo: { currentVersion: KEYRING_VERSION },
97
98
  scanner: { caseStyle: "allow-kebab-for-camel" },
package/dist/app.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"app.js","sourceRoot":"","sources":["../src/app.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { type Answer, type VaultAccess } from "../passwords/access.js";
2
+ import type { Captures } from "../passwords/capture.js";
3
+ export declare class Askpass {
4
+ #private;
5
+ private readonly vault;
6
+ private readonly captures;
7
+ constructor(vault: VaultAccess, captures: Captures);
8
+ forget(): void;
9
+ askpass(prompt: string, parent: string | undefined): Answer<"askpass">;
10
+ gitCredential(action: "get" | "erase", url: string, username: string | undefined): Answer<"git-credential">;
11
+ }
12
+ //# sourceMappingURL=answer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"answer.d.ts","sourceRoot":"","sources":["../../src/askpass/answer.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,MAAM,EAAsB,KAAK,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC3F,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAiDxD,qBAAa,OAAO;;IAQZ,OAAO,CAAC,QAAQ,CAAC,KAAK;IACtB,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAF7B,YACqB,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,QAAQ,EACnC;IAEJ,MAAM,IAAI,IAAI,CAGb;IA0BK,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,SAAS,CAAC,CAyB3E;IA2EK,aAAa,CAAC,MAAM,EAAE,KAAK,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,MAAM,CAAC,gBAAgB,CAAC,CAYhH;CAuDJ"}