@bsv/wallet-toolbox 1.1.25 → 1.1.27

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 (209) hide show
  1. package/docs/client.md +78 -2313
  2. package/docs/setup.md +15 -19
  3. package/docs/wallet.md +78 -2313
  4. package/out/src/Setup.d.ts +4 -0
  5. package/out/src/Setup.d.ts.map +1 -1
  6. package/out/src/Setup.js +19 -9
  7. package/out/src/Setup.js.map +1 -1
  8. package/out/src/Wallet.d.ts +1 -6
  9. package/out/src/Wallet.d.ts.map +1 -1
  10. package/out/src/Wallet.js +2 -29
  11. package/out/src/Wallet.js.map +1 -1
  12. package/out/src/index.all.d.ts +0 -9
  13. package/out/src/index.all.d.ts.map +1 -1
  14. package/out/src/index.all.js +0 -9
  15. package/out/src/index.all.js.map +1 -1
  16. package/out/src/index.client.d.ts +0 -9
  17. package/out/src/index.client.d.ts.map +1 -1
  18. package/out/src/index.client.js +0 -9
  19. package/out/src/index.client.js.map +1 -1
  20. package/out/src/storage/WalletStorageManager.d.ts.map +1 -1
  21. package/out/src/storage/WalletStorageManager.js +2 -0
  22. package/out/src/storage/WalletStorageManager.js.map +1 -1
  23. package/out/test/examples/backup.test.d.ts +14 -0
  24. package/out/test/examples/backup.test.d.ts.map +1 -0
  25. package/out/test/examples/backup.test.js +59 -0
  26. package/out/test/examples/backup.test.js.map +1 -0
  27. package/out/test/wallet/action/abortAction.test.d.ts.map +1 -0
  28. package/out/test/{Wallet → wallet}/action/abortAction.test.js.map +1 -1
  29. package/out/test/wallet/action/createAction.test.d.ts.map +1 -0
  30. package/out/test/{Wallet → wallet}/action/createAction.test.js.map +1 -1
  31. package/out/test/{Wallet → wallet}/action/createAction2.test.d.ts.map +1 -1
  32. package/out/test/{Wallet → wallet}/action/createAction2.test.js.map +1 -1
  33. package/out/test/wallet/action/createActionToGenerateBeefs.man.test.d.ts.map +1 -0
  34. package/out/test/{Wallet → wallet}/action/createActionToGenerateBeefs.man.test.js.map +1 -1
  35. package/out/test/wallet/action/internalizeAction.test.d.ts.map +1 -0
  36. package/out/test/{Wallet → wallet}/action/internalizeAction.test.js.map +1 -1
  37. package/out/test/wallet/action/relinquishOutput.test.d.ts.map +1 -0
  38. package/out/test/{Wallet → wallet}/action/relinquishOutput.test.js.map +1 -1
  39. package/out/test/wallet/construct/Wallet.constructor.test.d.ts.map +1 -0
  40. package/out/test/{Wallet → wallet}/construct/Wallet.constructor.test.js.map +1 -1
  41. package/out/test/wallet/list/listActions.test.d.ts.map +1 -0
  42. package/out/test/{Wallet → wallet}/list/listActions.test.js.map +1 -1
  43. package/out/test/wallet/list/listActions2.test.d.ts.map +1 -0
  44. package/out/test/{Wallet → wallet}/list/listActions2.test.js.map +1 -1
  45. package/out/test/wallet/list/listCertificates.test.d.ts.map +1 -0
  46. package/out/test/{Wallet → wallet}/list/listCertificates.test.js.map +1 -1
  47. package/out/test/wallet/list/listOutputs.test.d.ts.map +1 -0
  48. package/out/test/{Wallet → wallet}/list/listOutputs.test.js.map +1 -1
  49. package/out/test/wallet/sync/Wallet.sync.test.d.ts.map +1 -0
  50. package/out/test/{Wallet → wallet}/sync/Wallet.sync.test.js.map +1 -1
  51. package/out/tsconfig.all.tsbuildinfo +1 -1
  52. package/package.json +3 -3
  53. package/src/Setup.ts +22 -9
  54. package/src/Wallet.ts +3 -47
  55. package/src/index.all.ts +0 -9
  56. package/src/index.client.ts +0 -9
  57. package/src/storage/WalletStorageManager.ts +1 -0
  58. package/test/examples/backup.test.ts +66 -0
  59. package/out/src/CWIStyleWalletManager.d.ts +0 -411
  60. package/out/src/CWIStyleWalletManager.d.ts.map +0 -1
  61. package/out/src/CWIStyleWalletManager.js +0 -1131
  62. package/out/src/CWIStyleWalletManager.js.map +0 -1
  63. package/out/src/SetupClient.d.ts +0 -249
  64. package/out/src/SetupClient.d.ts.map +0 -1
  65. package/out/src/SetupClient.js +0 -252
  66. package/out/src/SetupClient.js.map +0 -1
  67. package/out/src/SimpleWalletManager.d.ts +0 -169
  68. package/out/src/SimpleWalletManager.d.ts.map +0 -1
  69. package/out/src/SimpleWalletManager.js +0 -315
  70. package/out/src/SimpleWalletManager.js.map +0 -1
  71. package/out/src/WalletAuthenticationManager.d.ts +0 -33
  72. package/out/src/WalletAuthenticationManager.d.ts.map +0 -1
  73. package/out/src/WalletAuthenticationManager.js +0 -107
  74. package/out/src/WalletAuthenticationManager.js.map +0 -1
  75. package/out/src/WalletPermissionsManager.d.ts +0 -575
  76. package/out/src/WalletPermissionsManager.d.ts.map +0 -1
  77. package/out/src/WalletPermissionsManager.js +0 -1807
  78. package/out/src/WalletPermissionsManager.js.map +0 -1
  79. package/out/src/WalletSettingsManager.d.ts +0 -59
  80. package/out/src/WalletSettingsManager.d.ts.map +0 -1
  81. package/out/src/WalletSettingsManager.js +0 -168
  82. package/out/src/WalletSettingsManager.js.map +0 -1
  83. package/out/src/__tests/CWIStyleWalletManager.test.d.ts +0 -2
  84. package/out/src/__tests/CWIStyleWalletManager.test.d.ts.map +0 -1
  85. package/out/src/__tests/CWIStyleWalletManager.test.js +0 -472
  86. package/out/src/__tests/CWIStyleWalletManager.test.js.map +0 -1
  87. package/out/src/__tests/WalletPermissionsManager.callbacks.test.d.ts +0 -2
  88. package/out/src/__tests/WalletPermissionsManager.callbacks.test.d.ts.map +0 -1
  89. package/out/src/__tests/WalletPermissionsManager.callbacks.test.js +0 -239
  90. package/out/src/__tests/WalletPermissionsManager.callbacks.test.js.map +0 -1
  91. package/out/src/__tests/WalletPermissionsManager.checks.test.d.ts +0 -2
  92. package/out/src/__tests/WalletPermissionsManager.checks.test.d.ts.map +0 -1
  93. package/out/src/__tests/WalletPermissionsManager.checks.test.js +0 -644
  94. package/out/src/__tests/WalletPermissionsManager.checks.test.js.map +0 -1
  95. package/out/src/__tests/WalletPermissionsManager.encryption.test.d.ts +0 -2
  96. package/out/src/__tests/WalletPermissionsManager.encryption.test.d.ts.map +0 -1
  97. package/out/src/__tests/WalletPermissionsManager.encryption.test.js +0 -295
  98. package/out/src/__tests/WalletPermissionsManager.encryption.test.js.map +0 -1
  99. package/out/src/__tests/WalletPermissionsManager.fixtures.d.ts +0 -82
  100. package/out/src/__tests/WalletPermissionsManager.fixtures.d.ts.map +0 -1
  101. package/out/src/__tests/WalletPermissionsManager.fixtures.js +0 -260
  102. package/out/src/__tests/WalletPermissionsManager.fixtures.js.map +0 -1
  103. package/out/src/__tests/WalletPermissionsManager.flows.test.d.ts +0 -2
  104. package/out/src/__tests/WalletPermissionsManager.flows.test.d.ts.map +0 -1
  105. package/out/src/__tests/WalletPermissionsManager.flows.test.js +0 -389
  106. package/out/src/__tests/WalletPermissionsManager.flows.test.js.map +0 -1
  107. package/out/src/__tests/WalletPermissionsManager.initialization.test.d.ts +0 -2
  108. package/out/src/__tests/WalletPermissionsManager.initialization.test.d.ts.map +0 -1
  109. package/out/src/__tests/WalletPermissionsManager.initialization.test.js +0 -227
  110. package/out/src/__tests/WalletPermissionsManager.initialization.test.js.map +0 -1
  111. package/out/src/__tests/WalletPermissionsManager.proxying.test.d.ts +0 -2
  112. package/out/src/__tests/WalletPermissionsManager.proxying.test.d.ts.map +0 -1
  113. package/out/src/__tests/WalletPermissionsManager.proxying.test.js +0 -566
  114. package/out/src/__tests/WalletPermissionsManager.proxying.test.js.map +0 -1
  115. package/out/src/__tests/WalletPermissionsManager.tokens.test.d.ts +0 -2
  116. package/out/src/__tests/WalletPermissionsManager.tokens.test.d.ts.map +0 -1
  117. package/out/src/__tests/WalletPermissionsManager.tokens.test.js +0 -460
  118. package/out/src/__tests/WalletPermissionsManager.tokens.test.js.map +0 -1
  119. package/out/src/utility/identityUtils.d.ts +0 -31
  120. package/out/src/utility/identityUtils.d.ts.map +0 -1
  121. package/out/src/utility/identityUtils.js +0 -114
  122. package/out/src/utility/identityUtils.js.map +0 -1
  123. package/out/src/wab-client/WABClient.d.ts +0 -38
  124. package/out/src/wab-client/WABClient.d.ts.map +0 -1
  125. package/out/src/wab-client/WABClient.js +0 -95
  126. package/out/src/wab-client/WABClient.js.map +0 -1
  127. package/out/src/wab-client/__tests/WABClient.test.d.ts +0 -2
  128. package/out/src/wab-client/__tests/WABClient.test.d.ts.map +0 -1
  129. package/out/src/wab-client/__tests/WABClient.test.js +0 -47
  130. package/out/src/wab-client/__tests/WABClient.test.js.map +0 -1
  131. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.d.ts +0 -34
  132. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.d.ts.map +0 -1
  133. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.js +0 -16
  134. package/out/src/wab-client/auth-method-interactors/AuthMethodInteractor.js.map +0 -1
  135. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.d.ts +0 -7
  136. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.d.ts.map +0 -1
  137. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.js +0 -40
  138. package/out/src/wab-client/auth-method-interactors/PersonaIDInteractor.js.map +0 -1
  139. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.d.ts +0 -28
  140. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.d.ts.map +0 -1
  141. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.js +0 -73
  142. package/out/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.js.map +0 -1
  143. package/out/test/Wallet/action/abortAction.test.d.ts.map +0 -1
  144. package/out/test/Wallet/action/createAction.test.d.ts.map +0 -1
  145. package/out/test/Wallet/action/createActionToGenerateBeefs.man.test.d.ts.map +0 -1
  146. package/out/test/Wallet/action/internalizeAction.test.d.ts.map +0 -1
  147. package/out/test/Wallet/action/relinquishOutput.test.d.ts.map +0 -1
  148. package/out/test/Wallet/construct/Wallet.constructor.test.d.ts.map +0 -1
  149. package/out/test/Wallet/list/listActions.test.d.ts.map +0 -1
  150. package/out/test/Wallet/list/listActions2.test.d.ts.map +0 -1
  151. package/out/test/Wallet/list/listCertificates.test.d.ts.map +0 -1
  152. package/out/test/Wallet/list/listOutputs.test.d.ts.map +0 -1
  153. package/out/test/Wallet/sync/Wallet.sync.test.d.ts.map +0 -1
  154. package/src/CWIStyleWalletManager.ts +0 -1891
  155. package/src/SimpleWalletManager.ts +0 -553
  156. package/src/WalletAuthenticationManager.ts +0 -183
  157. package/src/WalletPermissionsManager.ts +0 -2639
  158. package/src/WalletSettingsManager.ts +0 -241
  159. package/src/__tests/CWIStyleWalletManager.test.ts +0 -709
  160. package/src/__tests/WalletPermissionsManager.callbacks.test.ts +0 -328
  161. package/src/__tests/WalletPermissionsManager.checks.test.ts +0 -857
  162. package/src/__tests/WalletPermissionsManager.encryption.test.ts +0 -407
  163. package/src/__tests/WalletPermissionsManager.fixtures.ts +0 -283
  164. package/src/__tests/WalletPermissionsManager.flows.test.ts +0 -490
  165. package/src/__tests/WalletPermissionsManager.initialization.test.ts +0 -333
  166. package/src/__tests/WalletPermissionsManager.proxying.test.ts +0 -753
  167. package/src/__tests/WalletPermissionsManager.tokens.test.ts +0 -584
  168. package/src/utility/identityUtils.ts +0 -170
  169. package/src/wab-client/WABClient.ts +0 -103
  170. package/src/wab-client/__tests/WABClient.test.ts +0 -58
  171. package/src/wab-client/auth-method-interactors/AuthMethodInteractor.ts +0 -47
  172. package/src/wab-client/auth-method-interactors/PersonaIDInteractor.ts +0 -45
  173. package/src/wab-client/auth-method-interactors/TwilioPhoneInteractor.ts +0 -82
  174. /package/out/test/{Wallet → wallet}/action/abortAction.test.d.ts +0 -0
  175. /package/out/test/{Wallet → wallet}/action/abortAction.test.js +0 -0
  176. /package/out/test/{Wallet → wallet}/action/createAction.test.d.ts +0 -0
  177. /package/out/test/{Wallet → wallet}/action/createAction.test.js +0 -0
  178. /package/out/test/{Wallet → wallet}/action/createAction2.test.d.ts +0 -0
  179. /package/out/test/{Wallet → wallet}/action/createAction2.test.js +0 -0
  180. /package/out/test/{Wallet → wallet}/action/createActionToGenerateBeefs.man.test.d.ts +0 -0
  181. /package/out/test/{Wallet → wallet}/action/createActionToGenerateBeefs.man.test.js +0 -0
  182. /package/out/test/{Wallet → wallet}/action/internalizeAction.test.d.ts +0 -0
  183. /package/out/test/{Wallet → wallet}/action/internalizeAction.test.js +0 -0
  184. /package/out/test/{Wallet → wallet}/action/relinquishOutput.test.d.ts +0 -0
  185. /package/out/test/{Wallet → wallet}/action/relinquishOutput.test.js +0 -0
  186. /package/out/test/{Wallet → wallet}/construct/Wallet.constructor.test.d.ts +0 -0
  187. /package/out/test/{Wallet → wallet}/construct/Wallet.constructor.test.js +0 -0
  188. /package/out/test/{Wallet → wallet}/list/listActions.test.d.ts +0 -0
  189. /package/out/test/{Wallet → wallet}/list/listActions.test.js +0 -0
  190. /package/out/test/{Wallet → wallet}/list/listActions2.test.d.ts +0 -0
  191. /package/out/test/{Wallet → wallet}/list/listActions2.test.js +0 -0
  192. /package/out/test/{Wallet → wallet}/list/listCertificates.test.d.ts +0 -0
  193. /package/out/test/{Wallet → wallet}/list/listCertificates.test.js +0 -0
  194. /package/out/test/{Wallet → wallet}/list/listOutputs.test.d.ts +0 -0
  195. /package/out/test/{Wallet → wallet}/list/listOutputs.test.js +0 -0
  196. /package/out/test/{Wallet → wallet}/sync/Wallet.sync.test.d.ts +0 -0
  197. /package/out/test/{Wallet → wallet}/sync/Wallet.sync.test.js +0 -0
  198. /package/test/{Wallet → wallet}/action/abortAction.test.ts +0 -0
  199. /package/test/{Wallet → wallet}/action/createAction.test.ts +0 -0
  200. /package/test/{Wallet → wallet}/action/createAction2.test.ts +0 -0
  201. /package/test/{Wallet → wallet}/action/createActionToGenerateBeefs.man.test.ts +0 -0
  202. /package/test/{Wallet → wallet}/action/internalizeAction.test.ts +0 -0
  203. /package/test/{Wallet → wallet}/action/relinquishOutput.test.ts +0 -0
  204. /package/test/{Wallet → wallet}/construct/Wallet.constructor.test.ts +0 -0
  205. /package/test/{Wallet → wallet}/list/listActions.test.ts +0 -0
  206. /package/test/{Wallet → wallet}/list/listActions2.test.ts +0 -0
  207. /package/test/{Wallet → wallet}/list/listCertificates.test.ts +0 -0
  208. /package/test/{Wallet → wallet}/list/listOutputs.test.ts +0 -0
  209. /package/test/{Wallet → wallet}/sync/Wallet.sync.test.ts +0 -0
@@ -1,1891 +0,0 @@
1
- import {
2
- Hash,
3
- Utils,
4
- Random,
5
- SymmetricKey,
6
- AbortActionArgs,
7
- AbortActionResult,
8
- AcquireCertificateArgs,
9
- AcquireCertificateResult,
10
- AuthenticatedResult,
11
- CreateActionArgs,
12
- CreateActionResult,
13
- CreateHmacArgs,
14
- CreateHmacResult,
15
- CreateSignatureArgs,
16
- CreateSignatureResult,
17
- DiscoverByAttributesArgs,
18
- DiscoverByIdentityKeyArgs,
19
- DiscoverCertificatesResult,
20
- GetHeaderArgs,
21
- GetHeaderResult,
22
- GetHeightResult,
23
- GetNetworkResult,
24
- GetPublicKeyArgs,
25
- GetPublicKeyResult,
26
- GetVersionResult,
27
- InternalizeActionArgs,
28
- InternalizeActionResult,
29
- ListActionsArgs,
30
- ListActionsResult,
31
- ListCertificatesArgs,
32
- ListCertificatesResult,
33
- ListOutputsArgs,
34
- ListOutputsResult,
35
- OriginatorDomainNameStringUnder250Bytes,
36
- ProveCertificateArgs,
37
- ProveCertificateResult,
38
- RelinquishCertificateArgs,
39
- RelinquishCertificateResult,
40
- RelinquishOutputArgs,
41
- RelinquishOutputResult,
42
- RevealCounterpartyKeyLinkageArgs,
43
- RevealCounterpartyKeyLinkageResult,
44
- RevealSpecificKeyLinkageArgs,
45
- RevealSpecificKeyLinkageResult,
46
- SignActionArgs,
47
- SignActionResult,
48
- VerifyHmacArgs,
49
- VerifyHmacResult,
50
- VerifySignatureArgs,
51
- VerifySignatureResult,
52
- WalletDecryptArgs,
53
- WalletDecryptResult,
54
- WalletEncryptArgs,
55
- WalletEncryptResult,
56
- WalletInterface,
57
- OutpointString,
58
- PrivateKey,
59
- LookupResolver,
60
- Broadcaster,
61
- LookupAnswer,
62
- Transaction,
63
- PushDrop,
64
- SHIPBroadcaster as SHIPCast,
65
- CreateActionInput,
66
- SHIPBroadcaster
67
- } from '@bsv/sdk'
68
- import { PrivilegedKeyManager } from './sdk/PrivilegedKeyManager'
69
-
70
- /**
71
- * Number of rounds used in PBKDF2 for deriving password keys.
72
- */
73
- export const PBKDF2_NUM_ROUNDS = 7777
74
-
75
- /**
76
- * Describes the structure of a User Management Protocol (UMP) token.
77
- */
78
- export interface UMPToken {
79
- /**
80
- * Primary key encrypted by the XOR of the password and presentation keys.
81
- */
82
- passwordPresentationPrimary: number[]
83
-
84
- /**
85
- * Primary key encrypted by the XOR of the password and recovery keys.
86
- */
87
- passwordRecoveryPrimary: number[]
88
-
89
- /**
90
- * Primary key encrypted by the XOR of the presentation and recovery keys.
91
- */
92
- presentationRecoveryPrimary: number[]
93
-
94
- /**
95
- * Privileged key encrypted by the XOR of the password and primary keys.
96
- */
97
- passwordPrimaryPrivileged: number[]
98
-
99
- /**
100
- * Privileged key encrypted by the XOR of the presentation and recovery keys.
101
- */
102
- presentationRecoveryPrivileged: number[]
103
-
104
- /**
105
- * Hash of the presentation key.
106
- */
107
- presentationHash: number[]
108
-
109
- /**
110
- * PBKDF2 salt used in conjunction with the password to derive the password key.
111
- */
112
- passwordSalt: number[]
113
-
114
- /**
115
- * Hash of the recovery key.
116
- */
117
- recoveryHash: number[]
118
-
119
- /**
120
- * A copy of the presentation key encrypted with the privileged key.
121
- */
122
- presentationKeyEncrypted: number[]
123
-
124
- /**
125
- * A copy of the recovery key encrypted with the privileged key.
126
- */
127
- recoveryKeyEncrypted: number[]
128
-
129
- /**
130
- * A copy of the password key encrypted with the privileged key.
131
- */
132
- passwordKeyEncrypted: number[]
133
-
134
- /**
135
- * Describes the token's location on-chain, if it's already been published.
136
- */
137
- currentOutpoint?: OutpointString
138
- }
139
-
140
- /**
141
- * Describes a system capable of finding and updating UMP tokens on the blockchain.
142
- */
143
- export interface UMPTokenInteractor {
144
- /**
145
- * Locates the latest valid copy of a UMP token (including its outpoint)
146
- * based on the presentation key hash.
147
- *
148
- * @param hash The hash of the presentation key.
149
- * @returns The UMP token if found; otherwise, undefined.
150
- */
151
- findByPresentationKeyHash: (hash: number[]) => Promise<UMPToken | undefined>
152
-
153
- /**
154
- * Locates the latest valid copy of a UMP token (including its outpoint)
155
- * based on the recovery key hash.
156
- *
157
- * @param hash The hash of the recovery key.
158
- * @returns The UMP token if found; otherwise, undefined.
159
- */
160
- findByRecoveryKeyHash: (hash: number[]) => Promise<UMPToken | undefined>
161
-
162
- /**
163
- * Creates (and optionally consumes the previous version of) a UMP token on-chain.
164
- *
165
- * @param wallet The wallet that might be used to create a new token.
166
- * @param adminOriginator The domain name of the administrative originator.
167
- * @param token The new UMP token to create.
168
- * @param oldTokenToConsume If provided, the old token that must be consumed in the same transaction.
169
- * @returns The newly created outpoint.
170
- */
171
- buildAndSend: (
172
- wallet: WalletInterface,
173
- adminOriginator: OriginatorDomainNameStringUnder250Bytes,
174
- token: UMPToken,
175
- oldTokenToConsume?: UMPToken
176
- ) => Promise<OutpointString>
177
- }
178
-
179
- /**
180
- * @class OverlayUMPTokenInteractor
181
- *
182
- * A concrete implementation of the UMPTokenInteractor interface that interacts
183
- * with Overlay Services and the UMP (User Management Protocol) topic. This class
184
- * is responsible for:
185
- *
186
- * 1) Locating UMP tokens via overlay lookups (ls_users).
187
- * 2) Creating and publishing new or updated UMP token outputs on-chain under
188
- * the "tm_users" topic.
189
- * 3) Consuming (spending) an old token if provided.
190
- */
191
- export class OverlayUMPTokenInteractor implements UMPTokenInteractor {
192
- /**
193
- * A `LookupResolver` instance used to query overlay networks.
194
- */
195
- private resolver: LookupResolver
196
-
197
- /**
198
- * A SHIP broadcaster that can be used to publish updated UMP tokens
199
- * under the `tm_users` topic to overlay service peers.
200
- */
201
- private broadcaster: SHIPBroadcaster
202
-
203
- /**
204
- * Construct a new OverlayUMPTokenInteractor.
205
- *
206
- * @param resolver A LookupResolver instance for performing overlay queries (ls_users).
207
- * @param broadcaster A SHIPBroadcaster instance for sharing new or updated tokens across the `tm_users` overlay.
208
- */
209
- constructor(
210
- resolver: LookupResolver = new LookupResolver(),
211
- broadcaster: SHIPBroadcaster = new SHIPBroadcaster(['tm_users'])
212
- ) {
213
- this.resolver = resolver
214
- this.broadcaster = broadcaster
215
- }
216
-
217
- /**
218
- * Finds a UMP token on-chain by the given presentation key hash, if it exists.
219
- * Uses the ls_users overlay service to perform the lookup.
220
- *
221
- * @param hash The 32-byte SHA-256 hash of the presentation key.
222
- * @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined.
223
- */
224
- public async findByPresentationKeyHash(
225
- hash: number[]
226
- ): Promise<UMPToken | undefined> {
227
- // Query ls_users for the given presentationHash
228
- const question = {
229
- service: 'ls_users',
230
- query: { presentationHash: Utils.toHex(hash) }
231
- }
232
- const answer = await this.resolver.query(question)
233
- return this.parseLookupAnswer(answer)
234
- }
235
-
236
- /**
237
- * Finds a UMP token on-chain by the given recovery key hash, if it exists.
238
- * Uses the ls_users overlay service to perform the lookup.
239
- *
240
- * @param hash The 32-byte SHA-256 hash of the recovery key.
241
- * @returns A UMPToken object (including currentOutpoint) if found, otherwise undefined.
242
- */
243
- public async findByRecoveryKeyHash(
244
- hash: number[]
245
- ): Promise<UMPToken | undefined> {
246
- const question = {
247
- service: 'ls_users',
248
- query: { recoveryHash: Utils.toHex(hash) }
249
- }
250
- const answer = await this.resolver.query(question)
251
- return this.parseLookupAnswer(answer)
252
- }
253
-
254
- /**
255
- * Creates or updates (replaces) a UMP token on-chain. If `oldTokenToConsume` is provided,
256
- * it is spent in the same transaction that creates the new token output. The new token is
257
- * then broadcast and published under the `tm_users` topic using a SHIP broadcast, ensuring
258
- * overlay participants see the updated token.
259
- *
260
- * @param wallet The wallet used to build and sign the transaction.
261
- * @param adminOriginator The domain/FQDN of the administrative originator (wallet operator).
262
- * @param token The new UMPToken to create on-chain.
263
- * @param oldTokenToConsume Optionally, an existing token to consume/spend in the same transaction.
264
- * @returns The outpoint of the newly created UMP token (e.g. "abcd1234...ef.0").
265
- */
266
- public async buildAndSend(
267
- wallet: WalletInterface,
268
- adminOriginator: OriginatorDomainNameStringUnder250Bytes,
269
- token: UMPToken,
270
- oldTokenToConsume?: UMPToken
271
- ): Promise<OutpointString> {
272
- // 1) Construct the data fields for the new UMP token in the same
273
- // 11-field order used by the UMP protocol's PushDrop definition.
274
- const fields: number[][] = new Array(11)
275
-
276
- // See: UMP field ordering
277
- // 0 => passwordSalt
278
- // 1 => passwordPresentationPrimary
279
- // 2 => passwordRecoveryPrimary
280
- // 3 => presentationRecoveryPrimary
281
- // 4 => passwordPrimaryPrivileged
282
- // 5 => presentationRecoveryPrivileged
283
- // 6 => presentationHash
284
- // 7 => recoveryHash
285
- // 8 => presentationKeyEncrypted
286
- // 9 => passwordKeyEncrypted
287
- // 10 => recoveryKeyEncrypted
288
-
289
- fields[0] = token.passwordSalt
290
- fields[1] = token.passwordPresentationPrimary
291
- fields[2] = token.passwordRecoveryPrimary
292
- fields[3] = token.presentationRecoveryPrimary
293
- fields[4] = token.passwordPrimaryPrivileged
294
- fields[5] = token.presentationRecoveryPrivileged
295
- fields[6] = token.presentationHash
296
- fields[7] = token.recoveryHash
297
- fields[8] = token.presentationKeyEncrypted
298
- fields[9] = token.passwordKeyEncrypted
299
- fields[10] = token.recoveryKeyEncrypted
300
-
301
- // 2) Create a PushDrop script referencing these fields, locked with the admin key (for easy revocation).
302
- const script = await new PushDrop(wallet).lock(
303
- fields,
304
- [2, 'admin user-management token'], // protocolID
305
- '1', // keyID
306
- 'self', // counterparty
307
- /*forSelf=*/ true,
308
- /*includeSignature=*/ true
309
- )
310
-
311
- // 3) Prepare the createAction call. If oldTokenToConsume is provided, we gather the outpoint.
312
- const inputs: CreateActionInput[] = []
313
- let inputToken: { beef: number[]; outputIndex: number } | undefined
314
- if (oldTokenToConsume?.currentOutpoint) {
315
- inputs.push({
316
- outpoint: oldTokenToConsume.currentOutpoint,
317
- unlockingScriptLength: 73, // typical signature length
318
- inputDescription: 'Consume old UMP token'
319
- })
320
- inputToken = await this.findByOutpoint(oldTokenToConsume.currentOutpoint)
321
- }
322
-
323
- const outputs = [
324
- {
325
- lockingScript: script.toHex(),
326
- satoshis: 1,
327
- outputDescription: 'New UMP token output'
328
- }
329
- ]
330
-
331
- // 4) Build the partial transaction via createAction.
332
- const createResult = await wallet.createAction(
333
- {
334
- description: oldTokenToConsume
335
- ? 'Renew UMP token (consume old, create new)'
336
- : 'Create new UMP token',
337
- inputs,
338
- outputs,
339
- inputBEEF: inputToken?.beef
340
- },
341
- adminOriginator
342
- )
343
-
344
- // If the transaction is fully processed by the wallet (some wallets might do signAndProcess automatically),
345
- // we retrieve the final TXID from the result.
346
- if (!createResult.signableTransaction) {
347
- const finalTxid =
348
- createResult.txid ||
349
- (createResult.tx
350
- ? Transaction.fromAtomicBEEF(createResult.tx).id('hex')
351
- : undefined)
352
- if (!finalTxid) {
353
- throw new Error('No signableTransaction and no final TX found.')
354
- }
355
- // Now broadcast to `tm_users` using SHIP
356
- const broadcastTx = Transaction.fromAtomicBEEF(createResult.tx!)
357
- await this.broadcaster.broadcast(broadcastTx)
358
- return `${finalTxid}.0`
359
- }
360
-
361
- // 5) If oldTokenToConsume is present, we must sign the input referencing it.
362
- // (If there's no old token, there's nothing to sign for the input.)
363
- let finalTxid = ''
364
- const reference = createResult.signableTransaction.reference
365
- const partialTx = Transaction.fromBEEF(createResult.signableTransaction.tx)
366
-
367
- if (oldTokenToConsume?.currentOutpoint) {
368
- // Unlock the old token with a matching PushDrop unlocker
369
- const unlocker = new PushDrop(wallet).unlock(
370
- [2, 'admin user-management token'],
371
- '1',
372
- 'self'
373
- )
374
- const unlockingScript = await unlocker.sign(partialTx, 0)
375
-
376
- // Provide it to the wallet
377
- const signResult = await wallet.signAction(
378
- {
379
- reference,
380
- spends: {
381
- 0: {
382
- unlockingScript: unlockingScript.toHex()
383
- }
384
- }
385
- },
386
- adminOriginator
387
- )
388
- finalTxid =
389
- signResult.txid ||
390
- (signResult.tx
391
- ? Transaction.fromAtomicBEEF(signResult.tx).id('hex')
392
- : '')
393
- if (!finalTxid) {
394
- throw new Error('Could not finalize transaction for renewed UMP token.')
395
- }
396
- // 6) Broadcast to `tm_users`
397
- const finalAtomicTx = signResult.tx
398
- const broadcastTx = Transaction.fromAtomicBEEF(finalAtomicTx!)
399
- await this.broadcaster.broadcast(broadcastTx)
400
- return `${finalTxid}.0`
401
- } else {
402
- // Fallbaack
403
- const signResult = await wallet.signAction(
404
- { reference, spends: {} },
405
- adminOriginator
406
- )
407
- finalTxid =
408
- signResult.txid ||
409
- (signResult.tx
410
- ? Transaction.fromAtomicBEEF(signResult.tx).id('hex')
411
- : '')
412
- if (!finalTxid) {
413
- throw new Error('Failed to finalize new UMP token transaction.')
414
- }
415
- const finalAtomicTx = signResult.tx
416
- const broadcastTx = Transaction.fromAtomicBEEF(finalAtomicTx!)
417
- await this.broadcaster.broadcast(broadcastTx)
418
- return `${finalTxid}.0`
419
- }
420
- }
421
-
422
- /**
423
- * Attempts to parse a LookupAnswer from the UMP lookup service. If successful,
424
- * extracts the token fields from the resulting transaction and constructs
425
- * a UMPToken object.
426
- *
427
- * @param answer The LookupAnswer returned by a query to ls_users.
428
- * @returns The parsed UMPToken or `undefined` if none found/decodable.
429
- */
430
- private parseLookupAnswer(answer: LookupAnswer): UMPToken | undefined {
431
- if (answer.type !== 'output-list') {
432
- return undefined
433
- }
434
- if (!answer.outputs || answer.outputs.length === 0) {
435
- return undefined
436
- }
437
-
438
- // We expect only one relevant UMP token in most queries, so let's parse the first.
439
- // If multiple are returned, we can parse the first.
440
- const { beef, outputIndex } = answer.outputs[0]
441
- try {
442
- const tx = Transaction.fromBEEF(beef)
443
- const outpoint = `${tx.id('hex')}.${outputIndex}`
444
-
445
- const decoded = PushDrop.decode(tx.outputs[outputIndex].lockingScript)
446
-
447
- // Expecting 11 fields for UMP
448
- if (!decoded.fields || decoded.fields.length < 11) return undefined
449
-
450
- // Build the UMP token from these fields, preserving outpoint
451
- const t: UMPToken = {
452
- passwordSalt: decoded.fields[0],
453
- passwordPresentationPrimary: decoded.fields[1],
454
- passwordRecoveryPrimary: decoded.fields[2],
455
- presentationRecoveryPrimary: decoded.fields[3],
456
- passwordPrimaryPrivileged: decoded.fields[4],
457
- presentationRecoveryPrivileged: decoded.fields[5],
458
- presentationHash: decoded.fields[6],
459
- recoveryHash: decoded.fields[7],
460
- presentationKeyEncrypted: decoded.fields[8],
461
- passwordKeyEncrypted: decoded.fields[9],
462
- recoveryKeyEncrypted: decoded.fields[10],
463
- currentOutpoint: outpoint
464
- }
465
- return t
466
- } catch (e) {
467
- // If we fail to parse or decode, return undefined
468
- return undefined
469
- }
470
- }
471
-
472
- /**
473
- * Finds by outpoint for unlocking / spending previous tokens.
474
- * @param outpoint The outpoint we are searching by
475
- * @returns The result so that we can use it to unlock the transaction
476
- */
477
- private async findByOutpoint(
478
- outpoint: string
479
- ): Promise<{ beef: number[]; outputIndex: number } | undefined> {
480
- const results = await this.resolver.query({
481
- service: 'ls_ump',
482
- query: {
483
- outpoint
484
- }
485
- })
486
- if (results.type !== 'output-list') {
487
- return undefined
488
- }
489
- if (!results.outputs.length) {
490
- return undefined
491
- }
492
- return results.outputs[0]
493
- }
494
- }
495
-
496
- /**
497
- * Manages a "CWI-style" wallet that uses a UMP token and a
498
- * multi-key authentication scheme (password, presentation key, and recovery key).
499
- */
500
- export class CWIStyleWalletManager implements WalletInterface {
501
- /**
502
- * Whether the user is currently authenticated.
503
- */
504
- authenticated: boolean
505
-
506
- /**
507
- * The domain name of the administrative originator (wallet operator / vendor, or your own).
508
- */
509
- private adminOriginator: string
510
-
511
- /**
512
- * The system that locates and publishes UMP tokens on-chain.
513
- */
514
- private UMPTokenInteractor: UMPTokenInteractor
515
-
516
- /**
517
- * A function called to persist the newly generated recovery key.
518
- * It should generally trigger a UI prompt where the user is asked to write it down.
519
- */
520
- private recoveryKeySaver: (key: number[]) => Promise<true>
521
-
522
- /**
523
- * Asks the user to enter their password, for a given reason.
524
- * The test function can be used to see if the password is correct before resolving.
525
- * Only resolve with the correct password or reject with an error.
526
- * Resolving with an incorrect password will throw an error.
527
- */
528
- private passwordRetriever: (
529
- reason: string,
530
- test: (passwordCandidate: string) => boolean
531
- ) => Promise<string>
532
-
533
- /**
534
- * An optional function that funds a new Wallet after the new-user flow, before the system proceeds.
535
- * Allows integration with faucets, and provides the presentation key for use in claiming faucet funds
536
- * that may be bound to it.
537
- */
538
- private newWalletFunder?: (
539
- presentationKey: number[],
540
- wallet: WalletInterface,
541
- adminOriginator: OriginatorDomainNameStringUnder250Bytes
542
- ) => Promise<void>
543
-
544
- /**
545
- * Builds the underlying wallet once the user has been authenticated.
546
- */
547
- private walletBuilder: (
548
- primaryKey: number[],
549
- privilegedKeyManager: PrivilegedKeyManager
550
- ) => Promise<WalletInterface>
551
-
552
- /**
553
- * The current mode of authentication:
554
- * - 'presentation-key-and-password'
555
- * - 'presentation-key-and-recovery-key'
556
- * - 'recovery-key-and-password'
557
- */
558
- authenticationMode:
559
- | 'presentation-key-and-password'
560
- | 'presentation-key-and-recovery-key'
561
- | 'recovery-key-and-password' = 'presentation-key-and-password'
562
-
563
- /**
564
- * Indicates whether this is a new user or an existing user flow:
565
- * - 'new-user'
566
- * - 'existing-user'
567
- */
568
- authenticationFlow: 'new-user' | 'existing-user' = 'new-user'
569
-
570
- /**
571
- * The current UMP token in use (representing the user's keys on-chain).
572
- */
573
- private currentUMPToken?: UMPToken
574
-
575
- /**
576
- * The presentation key, temporarily retained after being provided until authenticated.
577
- */
578
- private presentationKey?: number[]
579
-
580
- /**
581
- * The recovery key, temporarily retained after being provided until authenticated.
582
- */
583
- private recoveryKey?: number[]
584
-
585
- /**
586
- * The user's primary key, which is used to operate the underlying wallet.
587
- * It is also stored within state snapshots.
588
- */
589
- private primaryKey?: number[]
590
-
591
- /**
592
- * The underlying wallet that handles the
593
- * actual signing, encryption, and other wallet operations.
594
- */
595
- private underlying?: WalletInterface
596
-
597
- /**
598
- * Privileged key manager associated with the underlying wallet, used for
599
- * short-term administrative tasks (e.g. re-wrapping or rotating keys).
600
- */
601
- private underlyingPrivilegedKeyManager?: PrivilegedKeyManager
602
-
603
- /**
604
- * Constructs a new CWIStyleWalletManager.
605
- *
606
- * @param adminOriginator The domain name of the administrative originator.
607
- * @param walletBuilder A function that can build an underlying wallet instance
608
- * from a primary key and a privileged key manager
609
- * @param interactor An instance of UMPTokenInteractor capable of managing UMP tokens.
610
- * @param recoveryKeySaver A function that can persist or display a newly generated recovery key.
611
- * @param passwordRetriever A function to request the user's password, given a reason and a test function.
612
- * @param newWalletFunder An optional function called with the presentation key and a new Wallet post-construction to fund it before use.
613
- * @param stateSnapshot If provided, a previously saved snapshot of the wallet's state.
614
- */
615
- constructor(
616
- adminOriginator: OriginatorDomainNameStringUnder250Bytes,
617
- walletBuilder: (
618
- primaryKey: number[],
619
- privilegedKeyManager: PrivilegedKeyManager
620
- ) => Promise<WalletInterface>,
621
- interactor: UMPTokenInteractor = new OverlayUMPTokenInteractor(),
622
- recoveryKeySaver: (key: number[]) => Promise<true>,
623
- passwordRetriever: (
624
- reason: string,
625
- test: (passwordCandidate: string) => boolean
626
- ) => Promise<string>,
627
- newWalletFunder?: (
628
- presentationKey: number[],
629
- wallet: WalletInterface,
630
- adminOriginator: OriginatorDomainNameStringUnder250Bytes
631
- ) => Promise<void>,
632
- stateSnapshot?: number[]
633
- ) {
634
- this.adminOriginator = adminOriginator
635
- this.walletBuilder = walletBuilder
636
- this.UMPTokenInteractor = interactor
637
- this.recoveryKeySaver = recoveryKeySaver
638
- this.passwordRetriever = passwordRetriever
639
- this.authenticated = false
640
- this.newWalletFunder = newWalletFunder
641
-
642
- // If a saved snapshot is provided, attempt to load it.
643
- if (stateSnapshot) {
644
- this.loadSnapshot(stateSnapshot)
645
- }
646
- }
647
-
648
- /**
649
- * Provides the presentation key in an authentication mode that requires it.
650
- * If a UMP token is found based on the key's hash, this is an existing-user flow.
651
- * Otherwise, it is treated as a new-user flow.
652
- *
653
- * @param key The user's presentation key (32 bytes).
654
- * @throws {Error} if user is already authenticated, or if the current mode does not require a presentation key.
655
- */
656
- async providePresentationKey(key: number[]): Promise<void> {
657
- if (this.authenticated) {
658
- throw new Error('User is already authenticated')
659
- }
660
- if (this.authenticationMode === 'recovery-key-and-password') {
661
- throw new Error('Presentation key is not needed in this mode')
662
- }
663
-
664
- const hash = Hash.sha256(key)
665
- const token = await this.UMPTokenInteractor.findByPresentationKeyHash(hash)
666
-
667
- if (!token) {
668
- // No token found -> New user
669
- this.authenticationFlow = 'new-user'
670
- this.presentationKey = key
671
- } else {
672
- // Found token -> existing user
673
- this.authenticationFlow = 'existing-user'
674
- this.presentationKey = key
675
- this.currentUMPToken = token
676
- }
677
- }
678
-
679
- /**
680
- * Provides the password in an authentication mode that requires it.
681
- *
682
- * - **Existing user**:
683
- * Decrypts the primary key using the provided password (and either the presentation key or recovery key, depending on the mode).
684
- * Then builds the underlying wallet, marking the user as authenticated.
685
- *
686
- * - **New user**:
687
- * Generates a new UMP token with fresh keys (primary, privileged, recovery). Publishes it on-chain and builds the wallet.
688
- *
689
- * @param password The user's password as a string.
690
- * @throws {Error} If the user is already authenticated, if the mode does not use a password, or if required keys are missing.
691
- */
692
- async providePassword(password: string): Promise<void> {
693
- if (this.authenticated) {
694
- throw new Error('User is already authenticated')
695
- }
696
- if (this.authenticationMode === 'presentation-key-and-recovery-key') {
697
- throw new Error('Password is not needed in this mode')
698
- }
699
-
700
- // If we detect an existing user flow:
701
- if (this.authenticationFlow === 'existing-user') {
702
- if (!this.currentUMPToken) {
703
- throw new Error(
704
- 'Provide either a presentation key or a recovery key first, depending on the authentication mode.'
705
- )
706
- }
707
- const derivedPasswordKey = Hash.pbkdf2(
708
- Utils.toArray(password, 'utf8'),
709
- this.currentUMPToken.passwordSalt,
710
- PBKDF2_NUM_ROUNDS,
711
- 32,
712
- 'sha512'
713
- )
714
-
715
- if (this.authenticationMode === 'presentation-key-and-password') {
716
- if (!this.presentationKey) {
717
- throw new Error('No presentation key found!')
718
- }
719
-
720
- // Decrypt the primary key with XOR(presentationKey, derivedPasswordKey).
721
- const xorKey = this.XOR(this.presentationKey, derivedPasswordKey)
722
- const decryptedPrimary = new SymmetricKey(xorKey).decrypt(
723
- this.currentUMPToken.passwordPresentationPrimary
724
- ) as number[]
725
-
726
- await this.buildUnderlying(decryptedPrimary)
727
- } else {
728
- // 'recovery-key-and-password' mode
729
- if (!this.recoveryKey) {
730
- throw new Error('No recovery key found!')
731
- }
732
-
733
- // Decrypt the primary key with XOR(recoveryKey, derivedPasswordKey).
734
- const primaryDecryptionKey = this.XOR(
735
- this.recoveryKey,
736
- derivedPasswordKey
737
- )
738
- const decryptedPrimary = new SymmetricKey(primaryDecryptionKey).decrypt(
739
- this.currentUMPToken.passwordRecoveryPrimary
740
- ) as number[]
741
-
742
- // Decrypt the privileged key for immediate use.
743
- const privilegedDecryptionKey = this.XOR(
744
- decryptedPrimary,
745
- derivedPasswordKey
746
- )
747
- const decryptedPrivileged = new SymmetricKey(
748
- privilegedDecryptionKey
749
- ).decrypt(this.currentUMPToken.passwordPrimaryPrivileged) as number[]
750
-
751
- await this.buildUnderlying(decryptedPrimary, decryptedPrivileged)
752
- }
753
-
754
- return
755
- }
756
-
757
- // Otherwise, handle new user flow (only valid in 'presentation-key-and-password').
758
- if (this.authenticationMode !== 'presentation-key-and-password') {
759
- throw new Error(
760
- 'New-user flow requires presentation key and password, not recovery key mode.'
761
- )
762
- }
763
-
764
- if (!this.presentationKey) {
765
- throw new Error('No presentation key provided for new-user flow.')
766
- }
767
-
768
- // Generate new random keys/salt and create a new UMP token.
769
- const recoveryKey = Random(32)
770
- await this.recoveryKeySaver(recoveryKey)
771
-
772
- const passwordSalt = Random(32)
773
- const passwordKey = Hash.pbkdf2(
774
- Utils.toArray(password, 'utf8'),
775
- passwordSalt,
776
- PBKDF2_NUM_ROUNDS,
777
- 32,
778
- 'sha512'
779
- )
780
-
781
- const primaryKey = Random(32)
782
- const privilegedKey = Random(32)
783
-
784
- // Build XOR-based symmetrical keys:
785
- const presentationPassword = new SymmetricKey(
786
- this.XOR(this.presentationKey, passwordKey)
787
- )
788
- const presentationRecovery = new SymmetricKey(
789
- this.XOR(this.presentationKey, recoveryKey)
790
- )
791
- const recoveryPassword = new SymmetricKey(
792
- this.XOR(recoveryKey, passwordKey)
793
- )
794
- const primaryPassword = new SymmetricKey(this.XOR(primaryKey, passwordKey))
795
-
796
- // Temporarily create a privileged key manager for encrypting the keys in the token.
797
- const tempPrivilegedKeyManager = new PrivilegedKeyManager(
798
- async () => new PrivateKey(privilegedKey)
799
- )
800
-
801
- // Build the new UMP token:
802
- const newToken: UMPToken = {
803
- passwordSalt,
804
- passwordPresentationPrimary: presentationPassword.encrypt(
805
- primaryKey
806
- ) as number[],
807
- passwordRecoveryPrimary: recoveryPassword.encrypt(primaryKey) as number[],
808
- presentationRecoveryPrimary: presentationRecovery.encrypt(
809
- primaryKey
810
- ) as number[],
811
- passwordPrimaryPrivileged: primaryPassword.encrypt(
812
- privilegedKey
813
- ) as number[],
814
- presentationRecoveryPrivileged: presentationRecovery.encrypt(
815
- privilegedKey
816
- ) as number[],
817
- presentationHash: Hash.sha256(this.presentationKey),
818
- recoveryHash: Hash.sha256(recoveryKey),
819
- presentationKeyEncrypted: (
820
- await tempPrivilegedKeyManager.encrypt({
821
- plaintext: this.presentationKey,
822
- protocolID: [2, 'admin key wrapping'],
823
- keyID: '1'
824
- })
825
- ).ciphertext,
826
- passwordKeyEncrypted: (
827
- await tempPrivilegedKeyManager.encrypt({
828
- plaintext: passwordKey,
829
- protocolID: [2, 'admin key wrapping'],
830
- keyID: '1'
831
- })
832
- ).ciphertext,
833
- recoveryKeyEncrypted: (
834
- await tempPrivilegedKeyManager.encrypt({
835
- plaintext: recoveryKey,
836
- protocolID: [2, 'admin key wrapping'],
837
- keyID: '1'
838
- })
839
- ).ciphertext
840
- }
841
-
842
- // Now, we can create our new wallet!
843
- this.currentUMPToken = newToken
844
- await this.buildUnderlying(primaryKey)
845
-
846
- // Before we do anything, the new wallet is most likely empty right now.
847
- // We want to provide a chance for someone to fund it, if they want.
848
- if (this.newWalletFunder) {
849
- try {
850
- await this.newWalletFunder(
851
- this.presentationKey,
852
- this.underlying!,
853
- this.adminOriginator
854
- )
855
- } catch (e) {
856
- // swallow error
857
- }
858
- }
859
-
860
- // Publish the new UMP token on-chain and store the resulting outpoint.
861
- this.currentUMPToken.currentOutpoint =
862
- await this.UMPTokenInteractor.buildAndSend(
863
- this.underlying!,
864
- this.adminOriginator,
865
- newToken
866
- )
867
- }
868
-
869
- /**
870
- * Provides the recovery key in an authentication flow that requires it.
871
- *
872
- * @param recoveryKey The user's recovery key (32 bytes).
873
- * @throws {Error} if user is already authenticated, if the mode does not use a recovery key,
874
- * or if a required presentation key is missing in "presentation-key-and-recovery-key" mode.
875
- */
876
- async provideRecoveryKey(recoveryKey: number[]): Promise<void> {
877
- if (this.authenticated) {
878
- throw new Error('Already authenticated')
879
- }
880
-
881
- // Cannot use recovery key in a new-user flow
882
- if (this.authenticationFlow === 'new-user') {
883
- throw new Error('Do not submit recovery key in new-user flow')
884
- }
885
-
886
- if (this.authenticationMode === 'presentation-key-and-password') {
887
- throw new Error('No recovery key required in this mode')
888
- } else if (this.authenticationMode === 'recovery-key-and-password') {
889
- // We will need to wait until the user provides the password as well.
890
- const hash = Hash.sha256(recoveryKey)
891
- const token = await this.UMPTokenInteractor.findByRecoveryKeyHash(hash)
892
- if (!token) {
893
- throw new Error('No user found with this key')
894
- }
895
- this.recoveryKey = recoveryKey
896
- this.currentUMPToken = token
897
- } else {
898
- // 'presentation-key-and-recovery-key'
899
- if (!this.presentationKey) {
900
- throw new Error('Provide the presentation key first')
901
- }
902
- if (!this.currentUMPToken) {
903
- throw new Error('Current UMP token not found')
904
- }
905
-
906
- // Decrypt the primary key:
907
- const xorKey = this.XOR(this.presentationKey, recoveryKey)
908
- const primaryKey = new SymmetricKey(xorKey).decrypt(
909
- this.currentUMPToken.presentationRecoveryPrimary
910
- ) as number[]
911
-
912
- // Decrypt the privileged key (for account recovery).
913
- const privilegedKey = new SymmetricKey(xorKey).decrypt(
914
- this.currentUMPToken.presentationRecoveryPrivileged
915
- ) as number[]
916
-
917
- await this.buildUnderlying(primaryKey, privilegedKey)
918
- }
919
- }
920
-
921
- /**
922
- * Saves the current wallet state (including the current UMP token and primary key)
923
- * into an encrypted snapshot. This snapshot can be stored locally and later passed
924
- * to `loadSnapshot` to restore the wallet state without re-authenticating manually.
925
- *
926
- * @remarks
927
- * Storing the snapshot provides a fully authenticated state.
928
- * This **must** be securely stored (e.g. system keychain or encrypted file).
929
- * If attackers gain access to this snapshot, they can fully control the wallet.
930
- *
931
- * @returns An array of bytes representing the encrypted snapshot.
932
- * @throws {Error} if no primary key or token is currently set.
933
- */
934
- saveSnapshot(): number[] {
935
- if (!this.primaryKey || !this.currentUMPToken) {
936
- throw new Error('No primary key or current UMP token set')
937
- }
938
-
939
- // Generate a random snapshot encryption key:
940
- const snapshotKey = Random(32)
941
-
942
- // Serialize the relevant data to a preimage buffer:
943
- const snapshotPreimageWriter = new Utils.Writer()
944
-
945
- // Write the primary key (32 bytes):
946
- snapshotPreimageWriter.write(this.primaryKey)
947
-
948
- // Write the serialized UMP token:
949
- const serializedToken = this.serializeUMPToken(this.currentUMPToken)
950
- snapshotPreimageWriter.write(serializedToken)
951
-
952
- // Encrypt the combined data with the snapshotKey:
953
- const snapshotPreimage = snapshotPreimageWriter.toArray()
954
- const snapshotPayload = new SymmetricKey(snapshotKey).encrypt(
955
- snapshotPreimage
956
- ) as number[]
957
-
958
- // Build the final snapshot structure: [snapshotKey (32 bytes) + encryptedPayload]
959
- const snapshotWriter = new Utils.Writer()
960
- snapshotWriter.write(snapshotKey)
961
- snapshotWriter.write(snapshotPayload)
962
-
963
- return snapshotWriter.toArray()
964
- }
965
-
966
- /**
967
- * Loads a previously saved state snapshot (e.g. from `saveSnapshot`).
968
- * Upon success, the wallet becomes authenticated without needing to re-enter keys.
969
- *
970
- * @param snapshot An array of bytes that was previously produced by `saveSnapshot`.
971
- * @throws {Error} If the snapshot format is invalid or decryption fails.
972
- */
973
- async loadSnapshot(snapshot: number[]): Promise<void> {
974
- try {
975
- const reader = new Utils.Reader(snapshot)
976
-
977
- // First 32 bytes is the snapshotKey:
978
- const snapshotKey = reader.read(32)
979
-
980
- // The rest is the encrypted payload:
981
- const encryptedPayload = reader.read()
982
-
983
- // Decrypt the payload:
984
- const decryptedPayload = new SymmetricKey(snapshotKey).decrypt(
985
- encryptedPayload
986
- ) as number[]
987
-
988
- const payloadReader = new Utils.Reader(decryptedPayload)
989
-
990
- // Read the primary key (32 bytes):
991
- const primaryKey = payloadReader.read(32)
992
-
993
- // Read the remainder as the serialized UMP token:
994
- const tokenBytes = payloadReader.read()
995
- const token = this.deserializeUMPToken(tokenBytes)
996
-
997
- // Assign and build:
998
- this.currentUMPToken = token
999
- await this.buildUnderlying(primaryKey)
1000
- } catch (error) {
1001
- throw new Error(`Failed to load snapshot: ${(error as Error).message}`)
1002
- }
1003
- }
1004
-
1005
- /**
1006
- * Destroys the underlying wallet, returning to a default state
1007
- */
1008
- destroy(): void {
1009
- this.underlying = undefined
1010
- this.underlyingPrivilegedKeyManager = undefined
1011
- this.authenticated = false
1012
- this.primaryKey = undefined
1013
- this.currentUMPToken = undefined
1014
- this.presentationKey = undefined
1015
- this.recoveryKey = undefined
1016
- this.authenticationMode = 'presentation-key-and-password'
1017
- this.authenticationFlow = 'new-user'
1018
- }
1019
-
1020
- /**
1021
- * Changes the user's password, re-wrapping the primary and privileged keys with the new password factor.
1022
- *
1023
- * @param newPassword The user's new password as a string.
1024
- * @throws {Error} If the user is not authenticated, or if underlying token references are missing.
1025
- */
1026
- async changePassword(newPassword: string): Promise<void> {
1027
- if (!this.authenticated) {
1028
- throw new Error('Not authenticated.')
1029
- }
1030
- if (!this.currentUMPToken) {
1031
- throw new Error('No UMP token to update.')
1032
- }
1033
-
1034
- const passwordSalt = Random(32)
1035
- const passwordKey = Hash.pbkdf2(
1036
- Utils.toArray(newPassword, 'utf8'),
1037
- passwordSalt,
1038
- PBKDF2_NUM_ROUNDS,
1039
- 32,
1040
- 'sha512'
1041
- )
1042
-
1043
- // Decrypt existing factors via the privileged key manager:
1044
- const recoveryKey = (
1045
- await this.underlyingPrivilegedKeyManager!.decrypt({
1046
- ciphertext: this.currentUMPToken.recoveryKeyEncrypted,
1047
- protocolID: [2, 'admin key wrapping'],
1048
- keyID: '1'
1049
- })
1050
- ).plaintext
1051
- const presentationKey = (
1052
- await this.underlyingPrivilegedKeyManager!.decrypt({
1053
- ciphertext: this.currentUMPToken.presentationKeyEncrypted,
1054
- protocolID: [2, 'admin key wrapping'],
1055
- keyID: '1'
1056
- })
1057
- ).plaintext
1058
- const privilegedKey = new SymmetricKey(
1059
- this.XOR(presentationKey, recoveryKey)
1060
- ).decrypt(this.currentUMPToken.presentationRecoveryPrivileged) as number[]
1061
-
1062
- await this.updateAuthFactors(
1063
- passwordSalt,
1064
- passwordKey,
1065
- presentationKey,
1066
- recoveryKey,
1067
- this.primaryKey!,
1068
- privilegedKey
1069
- )
1070
- }
1071
-
1072
- /**
1073
- * Changes the user's recovery key, prompting the user to save the new key.
1074
- *
1075
- * @throws {Error} If the user is not authenticated, or if underlying token references are missing.
1076
- */
1077
- async changeRecoveryKey(): Promise<void> {
1078
- if (!this.authenticated) {
1079
- throw new Error('Not authenticated.')
1080
- }
1081
- if (!this.currentUMPToken) {
1082
- throw new Error('No UMP token to update.')
1083
- }
1084
-
1085
- const recoveryKey = Random(32)
1086
- await this.recoveryKeySaver(recoveryKey)
1087
-
1088
- // Decrypt existing password/presentation keys via the privileged key manager:
1089
- const passwordKey = (
1090
- await this.underlyingPrivilegedKeyManager!.decrypt({
1091
- ciphertext: this.currentUMPToken.passwordKeyEncrypted,
1092
- protocolID: [2, 'admin key wrapping'],
1093
- keyID: '1'
1094
- })
1095
- ).plaintext
1096
- const presentationKey = (
1097
- await this.underlyingPrivilegedKeyManager!.decrypt({
1098
- ciphertext: this.currentUMPToken.presentationKeyEncrypted,
1099
- protocolID: [2, 'admin key wrapping'],
1100
- keyID: '1'
1101
- })
1102
- ).plaintext
1103
- const privilegedKey = new SymmetricKey(
1104
- this.XOR(passwordKey, this.primaryKey!)
1105
- ).decrypt(this.currentUMPToken.passwordPrimaryPrivileged) as number[]
1106
-
1107
- await this.updateAuthFactors(
1108
- this.currentUMPToken.passwordSalt,
1109
- passwordKey,
1110
- presentationKey,
1111
- recoveryKey,
1112
- this.primaryKey!,
1113
- privilegedKey
1114
- )
1115
- }
1116
-
1117
- /**
1118
- * Changes the user's presentation key.
1119
- *
1120
- * @param presentationKey The new presentation key (32 bytes).
1121
- * @throws {Error} If the user is not authenticated, or if underlying token references are missing.
1122
- */
1123
- async changePresentationKey(presentationKey: number[]): Promise<void> {
1124
- if (!this.authenticated) {
1125
- throw new Error('Not authenticated.')
1126
- }
1127
- if (!this.currentUMPToken) {
1128
- throw new Error('No UMP token to update.')
1129
- }
1130
-
1131
- // Decrypt existing password/recovery keys via the privileged key manager:
1132
- const recoveryKey = (
1133
- await this.underlyingPrivilegedKeyManager!.decrypt({
1134
- ciphertext: this.currentUMPToken.recoveryKeyEncrypted,
1135
- protocolID: [2, 'admin key wrapping'],
1136
- keyID: '1'
1137
- })
1138
- ).plaintext
1139
- const passwordKey = (
1140
- await this.underlyingPrivilegedKeyManager!.decrypt({
1141
- ciphertext: this.currentUMPToken.passwordKeyEncrypted,
1142
- protocolID: [2, 'admin key wrapping'],
1143
- keyID: '1'
1144
- })
1145
- ).plaintext
1146
- const privilegedKey = new SymmetricKey(
1147
- this.XOR(passwordKey, this.primaryKey!)
1148
- ).decrypt(this.currentUMPToken.passwordPrimaryPrivileged) as number[]
1149
-
1150
- await this.updateAuthFactors(
1151
- this.currentUMPToken.passwordSalt,
1152
- passwordKey,
1153
- presentationKey,
1154
- recoveryKey,
1155
- this.primaryKey!,
1156
- privilegedKey
1157
- )
1158
- }
1159
-
1160
- /**
1161
- * Internal helper to recompute a UMP token with updated authentication factors and consume the old token on-chain.
1162
- *
1163
- * @param passwordSalt The PBKDF2 salt for the new password factor.
1164
- * @param passwordKey The PBKDF2-derived password key (32 bytes).
1165
- * @param presentationKey The new or existing presentation key (32 bytes).
1166
- * @param recoveryKey The new or existing recovery key (32 bytes).
1167
- * @param primaryKey The user's primary key for re-wrapping.
1168
- * @param privilegedKey The user's privileged key for re-wrapping.
1169
- * @throws {Error} If the user is not authenticated or if keys are unavailable.
1170
- */
1171
- private async updateAuthFactors(
1172
- passwordSalt: number[],
1173
- passwordKey: number[],
1174
- presentationKey: number[],
1175
- recoveryKey: number[],
1176
- primaryKey: number[],
1177
- privilegedKey: number[]
1178
- ): Promise<void> {
1179
- if (!this.authenticated || !this.primaryKey || !this.currentUMPToken) {
1180
- throw new Error('Wallet is not properly authenticated or missing data.')
1181
- }
1182
-
1183
- // Derive symmetrical encryption keys via XOR:
1184
- const presentationPassword = new SymmetricKey(
1185
- this.XOR(presentationKey, passwordKey)
1186
- )
1187
- const presentationRecovery = new SymmetricKey(
1188
- this.XOR(presentationKey, recoveryKey)
1189
- )
1190
- const recoveryPassword = new SymmetricKey(
1191
- this.XOR(recoveryKey, passwordKey)
1192
- )
1193
- const primaryPassword = new SymmetricKey(
1194
- this.XOR(this.primaryKey, passwordKey)
1195
- )
1196
-
1197
- // Build a temporary privileged key manager just to encrypt the new fields:
1198
- const tempPrivilegedKeyManager = new PrivilegedKeyManager(
1199
- async () => new PrivateKey(privilegedKey)
1200
- )
1201
-
1202
- // Construct the new UMP token:
1203
- const newToken: UMPToken = {
1204
- passwordSalt,
1205
- passwordPresentationPrimary: presentationPassword.encrypt(
1206
- this.primaryKey
1207
- ) as number[],
1208
- passwordRecoveryPrimary: recoveryPassword.encrypt(
1209
- this.primaryKey
1210
- ) as number[],
1211
- presentationRecoveryPrimary: presentationRecovery.encrypt(
1212
- this.primaryKey
1213
- ) as number[],
1214
- passwordPrimaryPrivileged: primaryPassword.encrypt(
1215
- privilegedKey
1216
- ) as number[],
1217
- presentationRecoveryPrivileged: presentationRecovery.encrypt(
1218
- privilegedKey
1219
- ) as number[],
1220
- presentationHash: Hash.sha256(presentationKey),
1221
- recoveryHash: Hash.sha256(recoveryKey),
1222
- presentationKeyEncrypted: (
1223
- await tempPrivilegedKeyManager.encrypt({
1224
- plaintext: presentationKey,
1225
- protocolID: [2, 'admin key wrapping'],
1226
- keyID: '1'
1227
- })
1228
- ).ciphertext,
1229
- passwordKeyEncrypted: (
1230
- await tempPrivilegedKeyManager.encrypt({
1231
- plaintext: passwordKey,
1232
- protocolID: [2, 'admin key wrapping'],
1233
- keyID: '1'
1234
- })
1235
- ).ciphertext,
1236
- recoveryKeyEncrypted: (
1237
- await tempPrivilegedKeyManager.encrypt({
1238
- plaintext: recoveryKey,
1239
- protocolID: [2, 'admin key wrapping'],
1240
- keyID: '1'
1241
- })
1242
- ).ciphertext
1243
- }
1244
-
1245
- // Publish the new token on-chain and consume the old one:
1246
- newToken.currentOutpoint = await this.UMPTokenInteractor.buildAndSend(
1247
- this.underlying!,
1248
- this.adminOriginator,
1249
- newToken,
1250
- this.currentUMPToken
1251
- )
1252
- this.currentUMPToken = newToken
1253
- }
1254
-
1255
- /**
1256
- * A helper function to XOR two equal-length byte arrays.
1257
- *
1258
- * @param n1 The first byte array.
1259
- * @param n2 The second byte array.
1260
- * @returns A new byte array which is the element-wise XOR of the two inputs.
1261
- * @throws {Error} if the two arrays are not the same length.
1262
- */
1263
- private XOR(n1: number[], n2: number[]): number[] {
1264
- if (n1.length !== n2.length) {
1265
- throw new Error('lengths mismatch')
1266
- }
1267
- const r = new Array<number>(n1.length)
1268
- for (let i = 0; i < n1.length; i++) {
1269
- r[i] = n1[i] ^ n2[i]
1270
- }
1271
- return r
1272
- }
1273
-
1274
- /**
1275
- * A helper function to serialize a UMP token to a binary format (version=1).
1276
- * The serialization layout is:
1277
- * - [1 byte version (value=1)]
1278
- * - For each array field in the UMP token, [varint length + bytes]
1279
- * - Then [varint length + outpoint string in UTF-8]
1280
- *
1281
- * @param token The UMP token to serialize.
1282
- * @returns A byte array representing the serialized token.
1283
- * @throws {Error} if the token has no currentOutpoint (required for serialization).
1284
- */
1285
- private serializeUMPToken(token: UMPToken): number[] {
1286
- if (!token.currentOutpoint) {
1287
- throw new Error('Token must have outpoint for serialization')
1288
- }
1289
-
1290
- const writer = new Utils.Writer()
1291
- // Write version byte
1292
- writer.writeUInt8(1)
1293
-
1294
- // Helper to write array with length prefix
1295
- const writeArray = (arr: number[]) => {
1296
- writer.writeVarIntNum(arr.length)
1297
- writer.write(arr)
1298
- }
1299
-
1300
- // Write each array-based field in the order they appear on UMPToken
1301
- writeArray(token.passwordPresentationPrimary)
1302
- writeArray(token.passwordRecoveryPrimary)
1303
- writeArray(token.presentationRecoveryPrimary)
1304
- writeArray(token.passwordPrimaryPrivileged)
1305
- writeArray(token.presentationRecoveryPrivileged)
1306
- writeArray(token.presentationHash)
1307
- writeArray(token.passwordSalt)
1308
- writeArray(token.recoveryHash)
1309
- writeArray(token.presentationKeyEncrypted)
1310
- writeArray(token.recoveryKeyEncrypted)
1311
- writeArray(token.passwordKeyEncrypted)
1312
-
1313
- // Finally, write the outpoint string:
1314
- const outpointBytes = Utils.toArray(token.currentOutpoint, 'utf8')
1315
- writer.writeVarIntNum(outpointBytes.length)
1316
- writer.write(outpointBytes)
1317
-
1318
- return writer.toArray()
1319
- }
1320
-
1321
- /**
1322
- * A helper function to deserialize a UMP token from the format described in `serializeUMPToken`.
1323
- *
1324
- * @param bin The serialized byte array.
1325
- * @returns The reconstructed UMP token.
1326
- * @throws {Error} if the version byte is unexpected or if parsing fails.
1327
- */
1328
- private deserializeUMPToken(bin: number[]): UMPToken {
1329
- const reader = new Utils.Reader(bin)
1330
-
1331
- // Check version:
1332
- const version = reader.readUInt8()
1333
- if (version !== 1) {
1334
- throw new Error(`Unsupported UMP token version: ${version}`)
1335
- }
1336
-
1337
- // Helper to read an array with length prefix
1338
- const readArray = (): number[] => {
1339
- const length = reader.readVarIntNum()
1340
- return reader.read(length)
1341
- }
1342
-
1343
- // Read in the correct order:
1344
- const passwordPresentationPrimary = readArray()
1345
- const passwordRecoveryPrimary = readArray()
1346
- const presentationRecoveryPrimary = readArray()
1347
- const passwordPrimaryPrivileged = readArray()
1348
- const presentationRecoveryPrivileged = readArray()
1349
- const presentationHash = readArray()
1350
- const passwordSalt = readArray()
1351
- const recoveryHash = readArray()
1352
- const presentationKeyEncrypted = readArray()
1353
- const recoveryKeyEncrypted = readArray()
1354
- const passwordKeyEncrypted = readArray()
1355
-
1356
- // Read outpoint string:
1357
- const outpointLen = reader.readVarIntNum()
1358
- const outpointBytes = reader.read(outpointLen)
1359
- const currentOutpoint = Utils.toUTF8(outpointBytes)
1360
-
1361
- const token: UMPToken = {
1362
- passwordPresentationPrimary,
1363
- passwordRecoveryPrimary,
1364
- presentationRecoveryPrimary,
1365
- passwordPrimaryPrivileged,
1366
- presentationRecoveryPrivileged,
1367
- presentationHash,
1368
- passwordSalt,
1369
- recoveryHash,
1370
- presentationKeyEncrypted,
1371
- recoveryKeyEncrypted,
1372
- passwordKeyEncrypted,
1373
- currentOutpoint
1374
- }
1375
-
1376
- return token
1377
- }
1378
-
1379
- /**
1380
- * Builds the underlying wallet once the user is authenticated.
1381
- *
1382
- * @param primaryKey The user's primary key (32 bytes).
1383
- * @param privilegedKey Optionally, a privileged key (for short-term usage in account recovery).
1384
- */
1385
- private async buildUnderlying(
1386
- primaryKey: number[],
1387
- privilegedKey?: number[]
1388
- ): Promise<void> {
1389
- if (!this.currentUMPToken) {
1390
- throw new Error(
1391
- 'A UMP token must exist before building underlying wallet!'
1392
- )
1393
- }
1394
-
1395
- this.primaryKey = primaryKey
1396
-
1397
- // Create a privileged manager that either uses the ephemeral privilegedKey if provided,
1398
- // or derives it later from the user's password on demand.
1399
- const privilegedManager = new PrivilegedKeyManager(
1400
- async (reason: string) => {
1401
- if (privilegedKey) {
1402
- // For account recovery: a one-off opportunity to recover.
1403
- const tempKey = new PrivateKey(privilegedKey)
1404
- privilegedKey = undefined
1405
- return tempKey
1406
- }
1407
- // Otherwise, ask user for their password to decrypt the privileged key.
1408
- const password = await this.passwordRetriever(
1409
- reason,
1410
- (passwordCandidate: string) => {
1411
- try {
1412
- const derivedPasswordKey = Hash.pbkdf2(
1413
- Utils.toArray(passwordCandidate, 'utf8'),
1414
- this.currentUMPToken!.passwordSalt,
1415
- PBKDF2_NUM_ROUNDS,
1416
- 32,
1417
- 'sha512'
1418
- )
1419
- // Decrypt the privileged key with XOR(primaryKey, derivedPasswordKey).
1420
- const privilegedDecryptor = this.XOR(
1421
- this.primaryKey!,
1422
- derivedPasswordKey
1423
- )
1424
- const decryptedPrivileged = new SymmetricKey(
1425
- privilegedDecryptor
1426
- ).decrypt(
1427
- this.currentUMPToken!.passwordPrimaryPrivileged
1428
- ) as number[]
1429
- if (decryptedPrivileged) {
1430
- return true
1431
- }
1432
- return false
1433
- } catch (e) {
1434
- return false
1435
- }
1436
- }
1437
- )
1438
- const derivedPasswordKey = Hash.pbkdf2(
1439
- Utils.toArray(password, 'utf8'),
1440
- this.currentUMPToken!.passwordSalt,
1441
- PBKDF2_NUM_ROUNDS,
1442
- 32,
1443
- 'sha512'
1444
- )
1445
- // Decrypt the privileged key with XOR(primaryKey, derivedPasswordKey).
1446
- const privilegedDecryptor = this.XOR(
1447
- this.primaryKey!,
1448
- derivedPasswordKey
1449
- )
1450
- const decryptedPrivileged = new SymmetricKey(
1451
- privilegedDecryptor
1452
- ).decrypt(this.currentUMPToken!.passwordPrimaryPrivileged) as number[]
1453
- return new PrivateKey(decryptedPrivileged)
1454
- }
1455
- )
1456
-
1457
- this.underlyingPrivilegedKeyManager = privilegedManager
1458
-
1459
- // Build the underlying wallet with the primary key and privileged manager.
1460
- this.underlying = await this.walletBuilder(primaryKey, privilegedManager)
1461
-
1462
- this.authenticated = true
1463
- }
1464
-
1465
- /*
1466
- * ---------------------------------------------------------------------------------------
1467
- * Below are the standard WalletInterface methods that simply proxy through to this.underlying,
1468
- * ensuring that the user is authenticated and that the admin originator is not misused.
1469
- * ---------------------------------------------------------------------------------------
1470
- */
1471
-
1472
- async getPublicKey(
1473
- args: GetPublicKeyArgs,
1474
- originator?: OriginatorDomainNameStringUnder250Bytes
1475
- ): Promise<GetPublicKeyResult> {
1476
- if (!this.authenticated) {
1477
- throw new Error('User is not authenticated.')
1478
- }
1479
- if (originator === this.adminOriginator) {
1480
- throw new Error(
1481
- 'External applications are not allowed to use the admin originator.'
1482
- )
1483
- }
1484
- return this.underlying!.getPublicKey(args, originator)
1485
- }
1486
-
1487
- async revealCounterpartyKeyLinkage(
1488
- args: RevealCounterpartyKeyLinkageArgs,
1489
- originator?: OriginatorDomainNameStringUnder250Bytes
1490
- ): Promise<RevealCounterpartyKeyLinkageResult> {
1491
- if (!this.authenticated) {
1492
- throw new Error('User is not authenticated.')
1493
- }
1494
- if (originator === this.adminOriginator) {
1495
- throw new Error(
1496
- 'External applications are not allowed to use the admin originator.'
1497
- )
1498
- }
1499
- return this.underlying!.revealCounterpartyKeyLinkage(args, originator)
1500
- }
1501
-
1502
- async revealSpecificKeyLinkage(
1503
- args: RevealSpecificKeyLinkageArgs,
1504
- originator?: OriginatorDomainNameStringUnder250Bytes
1505
- ): Promise<RevealSpecificKeyLinkageResult> {
1506
- if (!this.authenticated) {
1507
- throw new Error('User is not authenticated.')
1508
- }
1509
- if (originator === this.adminOriginator) {
1510
- throw new Error(
1511
- 'External applications are not allowed to use the admin originator.'
1512
- )
1513
- }
1514
- return this.underlying!.revealSpecificKeyLinkage(args, originator)
1515
- }
1516
-
1517
- async encrypt(
1518
- args: WalletEncryptArgs,
1519
- originator?: OriginatorDomainNameStringUnder250Bytes
1520
- ): Promise<WalletEncryptResult> {
1521
- if (!this.authenticated) {
1522
- throw new Error('User is not authenticated.')
1523
- }
1524
- if (originator === this.adminOriginator) {
1525
- throw new Error(
1526
- 'External applications are not allowed to use the admin originator.'
1527
- )
1528
- }
1529
- return this.underlying!.encrypt(args, originator)
1530
- }
1531
-
1532
- async decrypt(
1533
- args: WalletDecryptArgs,
1534
- originator?: OriginatorDomainNameStringUnder250Bytes
1535
- ): Promise<WalletDecryptResult> {
1536
- if (!this.authenticated) {
1537
- throw new Error('User is not authenticated.')
1538
- }
1539
- if (originator === this.adminOriginator) {
1540
- throw new Error(
1541
- 'External applications are not allowed to use the admin originator.'
1542
- )
1543
- }
1544
- return this.underlying!.decrypt(args, originator)
1545
- }
1546
-
1547
- async createHmac(
1548
- args: CreateHmacArgs,
1549
- originator?: OriginatorDomainNameStringUnder250Bytes
1550
- ): Promise<CreateHmacResult> {
1551
- if (!this.authenticated) {
1552
- throw new Error('User is not authenticated.')
1553
- }
1554
- if (originator === this.adminOriginator) {
1555
- throw new Error(
1556
- 'External applications are not allowed to use the admin originator.'
1557
- )
1558
- }
1559
- return this.underlying!.createHmac(args, originator)
1560
- }
1561
-
1562
- async verifyHmac(
1563
- args: VerifyHmacArgs,
1564
- originator?: OriginatorDomainNameStringUnder250Bytes
1565
- ): Promise<VerifyHmacResult> {
1566
- if (!this.authenticated) {
1567
- throw new Error('User is not authenticated.')
1568
- }
1569
- if (originator === this.adminOriginator) {
1570
- throw new Error(
1571
- 'External applications are not allowed to use the admin originator.'
1572
- )
1573
- }
1574
- return this.underlying!.verifyHmac(args, originator)
1575
- }
1576
-
1577
- async createSignature(
1578
- args: CreateSignatureArgs,
1579
- originator?: OriginatorDomainNameStringUnder250Bytes
1580
- ): Promise<CreateSignatureResult> {
1581
- if (!this.authenticated) {
1582
- throw new Error('User is not authenticated.')
1583
- }
1584
- if (originator === this.adminOriginator) {
1585
- throw new Error(
1586
- 'External applications are not allowed to use the admin originator.'
1587
- )
1588
- }
1589
- return this.underlying!.createSignature(args, originator)
1590
- }
1591
-
1592
- async verifySignature(
1593
- args: VerifySignatureArgs,
1594
- originator?: OriginatorDomainNameStringUnder250Bytes
1595
- ): Promise<VerifySignatureResult> {
1596
- if (!this.authenticated) {
1597
- throw new Error('User is not authenticated.')
1598
- }
1599
- if (originator === this.adminOriginator) {
1600
- throw new Error(
1601
- 'External applications are not allowed to use the admin originator.'
1602
- )
1603
- }
1604
- return this.underlying!.verifySignature(args, originator)
1605
- }
1606
-
1607
- async createAction(
1608
- args: CreateActionArgs,
1609
- originator?: OriginatorDomainNameStringUnder250Bytes
1610
- ): Promise<CreateActionResult> {
1611
- if (!this.authenticated) {
1612
- throw new Error('User is not authenticated.')
1613
- }
1614
- if (originator === this.adminOriginator) {
1615
- throw new Error(
1616
- 'External applications are not allowed to use the admin originator.'
1617
- )
1618
- }
1619
- return this.underlying!.createAction(args, originator)
1620
- }
1621
-
1622
- async signAction(
1623
- args: SignActionArgs,
1624
- originator?: OriginatorDomainNameStringUnder250Bytes
1625
- ): Promise<SignActionResult> {
1626
- if (!this.authenticated) {
1627
- throw new Error('User is not authenticated.')
1628
- }
1629
- if (originator === this.adminOriginator) {
1630
- throw new Error(
1631
- 'External applications are not allowed to use the admin originator.'
1632
- )
1633
- }
1634
- return this.underlying!.signAction(args, originator)
1635
- }
1636
-
1637
- async abortAction(
1638
- args: AbortActionArgs,
1639
- originator?: OriginatorDomainNameStringUnder250Bytes
1640
- ): Promise<AbortActionResult> {
1641
- if (!this.authenticated) {
1642
- throw new Error('User is not authenticated.')
1643
- }
1644
- if (originator === this.adminOriginator) {
1645
- throw new Error(
1646
- 'External applications are not allowed to use the admin originator.'
1647
- )
1648
- }
1649
- return this.underlying!.abortAction(args, originator)
1650
- }
1651
-
1652
- async listActions(
1653
- args: ListActionsArgs,
1654
- originator?: OriginatorDomainNameStringUnder250Bytes
1655
- ): Promise<ListActionsResult> {
1656
- if (!this.authenticated) {
1657
- throw new Error('User is not authenticated.')
1658
- }
1659
- if (originator === this.adminOriginator) {
1660
- throw new Error(
1661
- 'External applications are not allowed to use the admin originator.'
1662
- )
1663
- }
1664
- return this.underlying!.listActions(args, originator)
1665
- }
1666
-
1667
- async internalizeAction(
1668
- args: InternalizeActionArgs,
1669
- originator?: OriginatorDomainNameStringUnder250Bytes
1670
- ): Promise<InternalizeActionResult> {
1671
- if (!this.authenticated) {
1672
- throw new Error('User is not authenticated.')
1673
- }
1674
- if (originator === this.adminOriginator) {
1675
- throw new Error(
1676
- 'External applications are not allowed to use the admin originator.'
1677
- )
1678
- }
1679
- return this.underlying!.internalizeAction(args, originator)
1680
- }
1681
-
1682
- async listOutputs(
1683
- args: ListOutputsArgs,
1684
- originator?: OriginatorDomainNameStringUnder250Bytes
1685
- ): Promise<ListOutputsResult> {
1686
- if (!this.authenticated) {
1687
- throw new Error('User is not authenticated.')
1688
- }
1689
- if (originator === this.adminOriginator) {
1690
- throw new Error(
1691
- 'External applications are not allowed to use the admin originator.'
1692
- )
1693
- }
1694
- return this.underlying!.listOutputs(args, originator)
1695
- }
1696
-
1697
- async relinquishOutput(
1698
- args: RelinquishOutputArgs,
1699
- originator?: OriginatorDomainNameStringUnder250Bytes
1700
- ): Promise<RelinquishOutputResult> {
1701
- if (!this.authenticated) {
1702
- throw new Error('User is not authenticated.')
1703
- }
1704
- if (originator === this.adminOriginator) {
1705
- throw new Error(
1706
- 'External applications are not allowed to use the admin originator.'
1707
- )
1708
- }
1709
- return this.underlying!.relinquishOutput(args, originator)
1710
- }
1711
-
1712
- async acquireCertificate(
1713
- args: AcquireCertificateArgs,
1714
- originator?: OriginatorDomainNameStringUnder250Bytes
1715
- ): Promise<AcquireCertificateResult> {
1716
- if (!this.authenticated) {
1717
- throw new Error('User is not authenticated.')
1718
- }
1719
- if (originator === this.adminOriginator) {
1720
- throw new Error(
1721
- 'External applications are not allowed to use the admin originator.'
1722
- )
1723
- }
1724
- return this.underlying!.acquireCertificate(args, originator)
1725
- }
1726
-
1727
- async listCertificates(
1728
- args: ListCertificatesArgs,
1729
- originator?: OriginatorDomainNameStringUnder250Bytes
1730
- ): Promise<ListCertificatesResult> {
1731
- if (!this.authenticated) {
1732
- throw new Error('User is not authenticated.')
1733
- }
1734
- if (originator === this.adminOriginator) {
1735
- throw new Error(
1736
- 'External applications are not allowed to use the admin originator.'
1737
- )
1738
- }
1739
- return this.underlying!.listCertificates(args, originator)
1740
- }
1741
-
1742
- async proveCertificate(
1743
- args: ProveCertificateArgs,
1744
- originator?: OriginatorDomainNameStringUnder250Bytes
1745
- ): Promise<ProveCertificateResult> {
1746
- if (!this.authenticated) {
1747
- throw new Error('User is not authenticated.')
1748
- }
1749
- if (originator === this.adminOriginator) {
1750
- throw new Error(
1751
- 'External applications are not allowed to use the admin originator.'
1752
- )
1753
- }
1754
- return this.underlying!.proveCertificate(args, originator)
1755
- }
1756
-
1757
- async relinquishCertificate(
1758
- args: RelinquishCertificateArgs,
1759
- originator?: OriginatorDomainNameStringUnder250Bytes
1760
- ): Promise<RelinquishCertificateResult> {
1761
- if (!this.authenticated) {
1762
- throw new Error('User is not authenticated.')
1763
- }
1764
- if (originator === this.adminOriginator) {
1765
- throw new Error(
1766
- 'External applications are not allowed to use the admin originator.'
1767
- )
1768
- }
1769
- return this.underlying!.relinquishCertificate(args, originator)
1770
- }
1771
-
1772
- async discoverByIdentityKey(
1773
- args: DiscoverByIdentityKeyArgs,
1774
- originator?: OriginatorDomainNameStringUnder250Bytes
1775
- ): Promise<DiscoverCertificatesResult> {
1776
- if (!this.authenticated) {
1777
- throw new Error('User is not authenticated.')
1778
- }
1779
- if (originator === this.adminOriginator) {
1780
- throw new Error(
1781
- 'External applications are not allowed to use the admin originator.'
1782
- )
1783
- }
1784
- return this.underlying!.discoverByIdentityKey(args, originator)
1785
- }
1786
-
1787
- async discoverByAttributes(
1788
- args: DiscoverByAttributesArgs,
1789
- originator?: OriginatorDomainNameStringUnder250Bytes
1790
- ): Promise<DiscoverCertificatesResult> {
1791
- if (!this.authenticated) {
1792
- throw new Error('User is not authenticated.')
1793
- }
1794
- if (originator === this.adminOriginator) {
1795
- throw new Error(
1796
- 'External applications are not allowed to use the admin originator.'
1797
- )
1798
- }
1799
- return this.underlying!.discoverByAttributes(args, originator)
1800
- }
1801
-
1802
- async isAuthenticated(
1803
- _: {},
1804
- originator?: OriginatorDomainNameStringUnder250Bytes
1805
- ): Promise<AuthenticatedResult> {
1806
- if (!this.authenticated) {
1807
- throw new Error('User is not authenticated.')
1808
- }
1809
- if (originator === this.adminOriginator) {
1810
- throw new Error(
1811
- 'External applications are not allowed to use the admin originator.'
1812
- )
1813
- }
1814
- return { authenticated: true }
1815
- }
1816
-
1817
- async waitForAuthentication(
1818
- _: {},
1819
- originator?: OriginatorDomainNameStringUnder250Bytes
1820
- ): Promise<AuthenticatedResult> {
1821
- if (originator === this.adminOriginator) {
1822
- throw new Error(
1823
- 'External applications are not allowed to use the admin originator.'
1824
- )
1825
- }
1826
- while (!this.authenticated) {
1827
- await new Promise(resolve => setTimeout(resolve, 100))
1828
- }
1829
- return { authenticated: true }
1830
- }
1831
-
1832
- async getHeight(
1833
- _: {},
1834
- originator?: OriginatorDomainNameStringUnder250Bytes
1835
- ): Promise<GetHeightResult> {
1836
- if (!this.authenticated) {
1837
- throw new Error('User is not authenticated.')
1838
- }
1839
- if (originator === this.adminOriginator) {
1840
- throw new Error(
1841
- 'External applications are not allowed to use the admin originator.'
1842
- )
1843
- }
1844
- return this.underlying!.getHeight({}, originator)
1845
- }
1846
-
1847
- async getHeaderForHeight(
1848
- args: GetHeaderArgs,
1849
- originator?: OriginatorDomainNameStringUnder250Bytes
1850
- ): Promise<GetHeaderResult> {
1851
- if (!this.authenticated) {
1852
- throw new Error('User is not authenticated.')
1853
- }
1854
- if (originator === this.adminOriginator) {
1855
- throw new Error(
1856
- 'External applications are not allowed to use the admin originator.'
1857
- )
1858
- }
1859
- return this.underlying!.getHeaderForHeight(args, originator)
1860
- }
1861
-
1862
- async getNetwork(
1863
- _: {},
1864
- originator?: OriginatorDomainNameStringUnder250Bytes
1865
- ): Promise<GetNetworkResult> {
1866
- if (!this.authenticated) {
1867
- throw new Error('User is not authenticated.')
1868
- }
1869
- if (originator === this.adminOriginator) {
1870
- throw new Error(
1871
- 'External applications are not allowed to use the admin originator.'
1872
- )
1873
- }
1874
- return this.underlying!.getNetwork({}, originator)
1875
- }
1876
-
1877
- async getVersion(
1878
- _: {},
1879
- originator?: OriginatorDomainNameStringUnder250Bytes
1880
- ): Promise<GetVersionResult> {
1881
- if (!this.authenticated) {
1882
- throw new Error('User is not authenticated.')
1883
- }
1884
- if (originator === this.adminOriginator) {
1885
- throw new Error(
1886
- 'External applications are not allowed to use the admin originator.'
1887
- )
1888
- }
1889
- return this.underlying!.getVersion({}, originator)
1890
- }
1891
- }