@volter/world-core 2.0.16 → 2.0.17

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.
@@ -131,6 +131,33 @@ export function transitSealer(options) {
131
131
  const named = `${mount}/${options.key}`;
132
132
  const addr = options.addr.replace(/\/+$/, '');
133
133
  const fingerprintKey = options.fingerprintKey ?? `${options.key}-fingerprint`;
134
+ // a periodic token lives while it is renewed within its period: after a call it answered, at most once a day, the
135
+ // sealer renews its own. A vault that refuses (a token that is not renewable, a root or dev token) is asked again the
136
+ // next day; one that did not answer, after the next call. The token's own period is the bound.
137
+ let renewedAt = 0;
138
+ const renew = async () => {
139
+ if (Date.now() - renewedAt < 86_400_000)
140
+ return;
141
+ renewedAt = Date.now();
142
+ let status;
143
+ try {
144
+ status = (await (options.fetch ?? fetch)(`${addr}/v1/auth/token/renew-self`, {
145
+ method: 'POST',
146
+ headers: { 'x-vault-token': await options.token(), 'content-type': 'application/json', ...(options.namespace ? { 'x-vault-namespace': options.namespace } : {}) },
147
+ body: '{}',
148
+ signal: AbortSignal.timeout(options.timeoutMs ?? 10_000),
149
+ })).status;
150
+ }
151
+ catch (error) {
152
+ renewedAt = 0;
153
+ console.warn(`[credential] the vault at ${addr} did not answer renewing this host's token (${error.message})`);
154
+ return;
155
+ }
156
+ if (status >= 500)
157
+ renewedAt = 0;
158
+ if (status >= 300)
159
+ console.warn(`[credential] the vault at ${addr} did not renew this host's token (${status})`);
160
+ };
134
161
  const call = async (op, body, key = options.key) => {
135
162
  const which = `${mount}/${key}`;
136
163
  let response;
@@ -150,6 +177,7 @@ export function transitSealer(options) {
150
177
  const answer = (await response.json());
151
178
  if (!answer.data)
152
179
  throw new Error(`the vault answered transit ${op} with ${which} without data`);
180
+ void renew();
153
181
  return answer.data;
154
182
  };
155
183
  const fingerprintOf = async (plaintext) => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@volter/world-core",
3
- "version": "2.0.16",
3
+ "version": "2.0.17",
4
4
  "description": "The kernel of Volter World: one log per twin, branches as pointers, checkpoints, the fold that keeps a twin current, the head that performs a write against the vendor, references, and the git plane. A twin package builds on it; the runtime serves it.",
5
5
  "keywords": [
6
6
  "twin",
package/src/credential.ts CHANGED
@@ -207,6 +207,29 @@ export function transitSealer(options: TransitSealerOptions): Sealer {
207
207
  const named = `${mount}/${options.key}`;
208
208
  const addr = options.addr.replace(/\/+$/, '');
209
209
  const fingerprintKey = options.fingerprintKey ?? `${options.key}-fingerprint`;
210
+ // a periodic token lives while it is renewed within its period: after a call it answered, at most once a day, the
211
+ // sealer renews its own. A vault that refuses (a token that is not renewable, a root or dev token) is asked again the
212
+ // next day; one that did not answer, after the next call. The token's own period is the bound.
213
+ let renewedAt = 0;
214
+ const renew = async (): Promise<void> => {
215
+ if (Date.now() - renewedAt < 86_400_000) return;
216
+ renewedAt = Date.now();
217
+ let status: number;
218
+ try {
219
+ status = (await (options.fetch ?? fetch)(`${addr}/v1/auth/token/renew-self`, {
220
+ method: 'POST',
221
+ headers: { 'x-vault-token': await options.token(), 'content-type': 'application/json', ...(options.namespace ? { 'x-vault-namespace': options.namespace } : {}) },
222
+ body: '{}',
223
+ signal: AbortSignal.timeout(options.timeoutMs ?? 10_000),
224
+ })).status;
225
+ } catch (error) {
226
+ renewedAt = 0;
227
+ console.warn(`[credential] the vault at ${addr} did not answer renewing this host's token (${(error as Error).message})`);
228
+ return;
229
+ }
230
+ if (status >= 500) renewedAt = 0;
231
+ if (status >= 300) console.warn(`[credential] the vault at ${addr} did not renew this host's token (${status})`);
232
+ };
210
233
  const call = async (op: 'encrypt' | 'decrypt' | 'hmac', body: Record<string, string | number>, key = options.key): Promise<Record<string, string>> => {
211
234
  const which = `${mount}/${key}`;
212
235
  let response: Response;
@@ -223,6 +246,7 @@ export function transitSealer(options: TransitSealerOptions): Sealer {
223
246
  if (!response.ok) throw new Error(`the vault refused transit ${op} with ${which} (${response.status})`);
224
247
  const answer = (await response.json()) as { data?: Record<string, string> };
225
248
  if (!answer.data) throw new Error(`the vault answered transit ${op} with ${which} without data`);
249
+ void renew();
226
250
  return answer.data;
227
251
  };
228
252
  const fingerprintOf = async (plaintext: Uint8Array): Promise<string> => {