@bkazemi/verily 0.2.0 → 0.4.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.
- package/README.md +30 -17
- package/dist/browser/badge.js +16 -5
- package/dist/browser/connect-dialog.d.ts +13 -2
- package/dist/browser/connect-dialog.js +19 -9
- package/dist/browser/evidence-dialog.d.ts +19 -1
- package/dist/browser/evidence-dialog.js +165 -18
- package/dist/browser/index.d.ts +10 -1
- package/dist/browser/index.js +58 -14
- package/dist/browser/logo.d.ts +2 -0
- package/dist/browser/logo.js +2 -0
- package/dist/browser/mark.d.ts +2 -0
- package/dist/browser/mark.js +6 -0
- package/dist/browser/provider-mark.js +5 -3
- package/dist/browser/signed.d.ts +4 -0
- package/dist/browser/signed.js +23 -6
- package/dist/core/index.d.ts +39 -6
- package/dist/core/index.js +23 -0
- package/dist/core/signed.d.ts +20 -5
- package/dist/core/signed.js +5 -2
- package/dist/server/domain.d.ts +51 -0
- package/dist/server/domain.js +285 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +106 -42
- package/dist/server/link.js +1 -16
- package/dist/server/public-fetch.d.ts +10 -0
- package/dist/server/public-fetch.js +15 -0
- package/dist/server/service.d.ts +42 -3
- package/dist/server/service.js +156 -10
- package/dist/site/index.d.ts +2 -1
- package/dist/verily.js +213 -36
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/server/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { attestationLabel, externalLink, externalName, isArtifactProvider, isCodeProvider, isRedirectProvider, localSide, proofTitle, providerMethod, statusLabel, signedBy, } from '../core/index.js';
|
|
1
|
+
import { attestationLabel, externalId, externalLink, externalName, isArtifactProvider, isCodeProvider, isRedirectProvider, lastProved, localSide, proofTitle, providerMethod, statusLabel, signedBy, } from '../core/index.js';
|
|
2
2
|
import { artifactAttempts, codeAttempts, VerilyService, Unavailable, } from './service.js';
|
|
3
3
|
import { copyScript, waitScript } from './copy.js';
|
|
4
4
|
import { escape } from './escape.js';
|
|
@@ -10,6 +10,7 @@ export { discordProvider } from './discord.js';
|
|
|
10
10
|
export { youtubeProvider } from './youtube.js';
|
|
11
11
|
export { githubGistProvider } from './github-gist.js';
|
|
12
12
|
export { linkProvider, githubLinkProvider } from './link.js';
|
|
13
|
+
export { dnsProvider, wellKnownProvider, } from './domain.js';
|
|
13
14
|
export { pgpProvider } from './pgp.js';
|
|
14
15
|
export { generateSigningKey, signer } from './signing.js';
|
|
15
16
|
export { emailProvider, } from './email.js';
|
|
@@ -98,6 +99,8 @@ function methodAction(provider) {
|
|
|
98
99
|
oauth: `Sign in with ${provider.name}`,
|
|
99
100
|
gist: `Publish a proof on ${provider.name}`,
|
|
100
101
|
backlink: `Link back from ${provider.name}`,
|
|
102
|
+
dns: 'Add a DNS record',
|
|
103
|
+
wellknown: 'Serve a file',
|
|
101
104
|
signature: `Sign with ${provider.name}`,
|
|
102
105
|
code: `Confirm by ${provider.name.toLowerCase()}`,
|
|
103
106
|
};
|
|
@@ -118,9 +121,13 @@ function artifactField(provider) {
|
|
|
118
121
|
* standing: it goes on the record with this one, and they did not ask for it by name.
|
|
119
122
|
*/
|
|
120
123
|
function standingNote(flow, site) {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
:
|
|
124
|
+
const found = {
|
|
125
|
+
backlink: `This account already links back to ${site}.`,
|
|
126
|
+
dns: `This domain already names ${site} in a DNS record.`,
|
|
127
|
+
wellknown: `This domain already names ${site} in a file it serves.`,
|
|
128
|
+
};
|
|
129
|
+
const note = flow.standing?.map((a) => found[a.method]).find((said) => said !== undefined);
|
|
130
|
+
return note ? `${note} Confirming records that too.` : undefined;
|
|
124
131
|
}
|
|
125
132
|
/**
|
|
126
133
|
* Said above a proof that was handed back and refused, while the flow still waits for it:
|
|
@@ -134,9 +141,13 @@ function refusedNote(flow) {
|
|
|
134
141
|
}
|
|
135
142
|
/** Said beside every artifact method: what the holder publishes is public by design. */
|
|
136
143
|
function artifactNote(provider) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
: 'This
|
|
144
|
+
const notes = {
|
|
145
|
+
backlink: 'This link is public, as is the page you point at. Anyone reading either one can follow it here.',
|
|
146
|
+
dns: 'This record is public, as is the page it names. Anyone reading either one can follow it here.',
|
|
147
|
+
wellknown: 'This file is public, as is the page it names. Anyone reading either one can follow it here.',
|
|
148
|
+
};
|
|
149
|
+
return (notes[provider.method] ??
|
|
150
|
+
'This line is public, as is whatever published it. Publish nothing else alongside it.');
|
|
140
151
|
}
|
|
141
152
|
/**
|
|
142
153
|
* Where a mailed code stands, for whichever renderer asks the holder for the next thing:
|
|
@@ -161,6 +172,21 @@ const codeNote = "We'll email this address to confirm it's yours. The address is
|
|
|
161
172
|
function providerNames(providers) {
|
|
162
173
|
return [...new Set(providers.map((p) => p.name))].join(' or ');
|
|
163
174
|
}
|
|
175
|
+
/**
|
|
176
|
+
* What the holder would be linking, for the sentence that asks them to: an account with a
|
|
177
|
+
* sign-in provider, a key, an address, a domain. Each is named once, however many ways it
|
|
178
|
+
* can be shown.
|
|
179
|
+
*/
|
|
180
|
+
function heldNames(providers) {
|
|
181
|
+
const held = (p) => ({
|
|
182
|
+
signature: `${p.name} key`,
|
|
183
|
+
code: `${p.name.toLowerCase()} address`,
|
|
184
|
+
dns: 'domain',
|
|
185
|
+
wellknown: 'domain',
|
|
186
|
+
})[providerMethod(p)] ?? `${p.name} account`;
|
|
187
|
+
const names = [...new Set(providers.map(held))];
|
|
188
|
+
return names.length > 1 ? `${names.slice(0, -1).join(', ')} or ${names.at(-1)}` : names[0];
|
|
189
|
+
}
|
|
164
190
|
/** Seconds are the finest thing a record measured in days can mean; milliseconds are noise. */
|
|
165
191
|
const moment = (time) => new Date(time).toISOString().replace(/\.\d{3}Z$/, 'Z');
|
|
166
192
|
/**
|
|
@@ -243,22 +269,34 @@ function evidencePage(e, base, report, keyId) {
|
|
|
243
269
|
// identifier stays: that one is the provider's word, not the site's own wording.
|
|
244
270
|
card(local.heading, local.value, e.local.profileUrl, undefined, attestationNote(e.attestations.local, names)) +
|
|
245
271
|
card(names.provider, externalName(e.external), externalLink(e.external),
|
|
246
|
-
// A mailbox's address is its name already, so there is no second identifier.
|
|
247
|
-
e.external
|
|
248
|
-
times(
|
|
249
|
-
[
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
'
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
272
|
+
// A mailbox's address or a domain is its name already, so there is no second identifier.
|
|
273
|
+
externalId(e.external), externalNotes(e.attestations, names)) +
|
|
274
|
+
times(e.status === 'retired'
|
|
275
|
+
? [
|
|
276
|
+
['Approved', e.approvedAt],
|
|
277
|
+
// Two rows, always, so a reader sees any gap between them: an account retired
|
|
278
|
+
// weeks after it was last proved went unproved for those weeks.
|
|
279
|
+
['Last verified', lastProved(e)],
|
|
280
|
+
['Retired', e.retiredAt],
|
|
281
|
+
['Sharing link expires', e.linkExpiresAt],
|
|
282
|
+
]
|
|
283
|
+
: [
|
|
284
|
+
['Approved', e.approvedAt],
|
|
285
|
+
['Authenticated', e.authenticatedAt],
|
|
286
|
+
[
|
|
287
|
+
current ? 'Valid until' : 'Expired on',
|
|
288
|
+
e.status === 'revoked' ? undefined : e.expiresAt,
|
|
289
|
+
],
|
|
290
|
+
['Revoked on', e.revokedAt],
|
|
291
|
+
// Only a method that publishes an artifact drifts; a sign-in does not go stale.
|
|
292
|
+
[
|
|
293
|
+
'Last checked',
|
|
294
|
+
e.attestations.external[0].artifactUrl
|
|
295
|
+
? e.attestations.external[0].confirmedAt
|
|
296
|
+
: undefined,
|
|
297
|
+
],
|
|
298
|
+
['Sharing link expires', e.linkExpiresAt],
|
|
299
|
+
]) +
|
|
262
300
|
`${e.linkExpiresAt ? '<p class="fine">Anyone with this link can view and forward it.</p>' : ''}
|
|
263
301
|
${e.signedUrl ? `<p class="signed" id="signed"><strong>Signed by ${escape(e.verifierName)}</strong>${keyId ? ` with OpenPGP key <a href="${escape(base)}/keys.asc">${escape(keyId)}</a>` : ''}. <a href="${escape(safeUrl(e.signedUrl))}">Download the signed record</a>, which <a href="${escape(base)}/check">can be checked</a> without this page.</p>` : ''}
|
|
264
302
|
<p class="fine">This connection does not establish legal identity, trustworthiness, content authorship, or permanent ownership.</p>
|
|
@@ -275,14 +313,23 @@ const checkForm = '<form method="post"><label>Signed record <textarea name="reco
|
|
|
275
313
|
function checkedPage(d, keyId, base) {
|
|
276
314
|
const names = { site: d.siteName, provider: d.providerName };
|
|
277
315
|
const local = localSide(d.local, d.siteName);
|
|
278
|
-
|
|
316
|
+
// A retired record did not stand when it was signed, and its heading says so first.
|
|
317
|
+
const retired = d.version === 2;
|
|
318
|
+
return page(base, retired ? 'Retired connection' : 'Signed record', `<p>${escape(d.verifierName)} signed this record. It shows what stood when it was signed, not what stands now.</p>` +
|
|
279
319
|
card(local.heading, local.value, d.local.profileUrl, undefined, attestationNote(d.attestations.local, names)) +
|
|
280
|
-
card(names.provider, externalName(d.external), externalLink(d.external), d.external
|
|
281
|
-
times(
|
|
282
|
-
[
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
320
|
+
card(names.provider, externalName(d.external), externalLink(d.external), externalId(d.external), externalNotes(d.attestations, names)) +
|
|
321
|
+
times(retired
|
|
322
|
+
? [
|
|
323
|
+
['Signed', d.issuedAt],
|
|
324
|
+
['Approved', d.approvedAt],
|
|
325
|
+
['Last verified', lastProved(d)],
|
|
326
|
+
['Retired', d.retiredAt],
|
|
327
|
+
]
|
|
328
|
+
: [
|
|
329
|
+
['Signed', d.issuedAt],
|
|
330
|
+
['Approved', d.approvedAt],
|
|
331
|
+
['Valid until', d.expiresAt],
|
|
332
|
+
]) +
|
|
286
333
|
`<p class="fine">Signing key <a href="${escape(base)}/keys.asc">${escape(keyId)}</a>.</p>
|
|
287
334
|
<p class="fine"><a href="${escape(safeUrl(d.evidenceUrl))}">See whether this connection still stands</a></p>`);
|
|
288
335
|
}
|
|
@@ -374,13 +421,24 @@ export function createVerily(options) {
|
|
|
374
421
|
/**
|
|
375
422
|
* The methods a page offers. A flow on an existing record stays in its namespace, so
|
|
376
423
|
* where the holder is signed in that record narrows the list; removing a link from the
|
|
377
|
-
* external side refuses a standing proof, which anybody can hand back.
|
|
424
|
+
* external side refuses a standing proof, which anybody can hand back. A retired record
|
|
425
|
+
* is renewed by the method it was first shown by, so that one is offered alone.
|
|
378
426
|
*/
|
|
379
427
|
async function offer(kind, id, user, requested) {
|
|
380
428
|
let namespace = requested ?? undefined;
|
|
381
|
-
|
|
382
|
-
|
|
429
|
+
let only;
|
|
430
|
+
if (user && id) {
|
|
431
|
+
const held = await service.read(id, user);
|
|
432
|
+
namespace = held.provider;
|
|
433
|
+
if (held.status === 'retired') {
|
|
434
|
+
// Who can read a retired record is frozen with the rest of it.
|
|
435
|
+
if (kind === 'visibility')
|
|
436
|
+
throw new Unavailable();
|
|
437
|
+
only = held.attestations.external[0].method;
|
|
438
|
+
}
|
|
439
|
+
}
|
|
383
440
|
const offered = (user ? permitted(user) : service.providers).filter((p) => (namespace === undefined || p.id === namespace) &&
|
|
441
|
+
(only === undefined || providerMethod(p) === only) &&
|
|
384
442
|
!(['revoke', 'share-revoke'].includes(kind) && isArtifactProvider(p) && p.expect));
|
|
385
443
|
if (!offered.length)
|
|
386
444
|
throw new Unavailable();
|
|
@@ -428,8 +486,8 @@ export function createVerily(options) {
|
|
|
428
486
|
profileUrl: user.profileUrl,
|
|
429
487
|
});
|
|
430
488
|
/**
|
|
431
|
-
* A connect flow as the in-page dialog draws it: the same steps the flow pages
|
|
432
|
-
* through, as data, so the holder never has to leave the page they started on.
|
|
489
|
+
* A connect or renew flow as the in-page dialog draws it: the same steps the flow pages
|
|
490
|
+
* walk through, as data, so the holder never has to leave the page they started on.
|
|
433
491
|
*/
|
|
434
492
|
async function flowView(flow, authorizationUrl) {
|
|
435
493
|
const provider = service.providerOf(flow);
|
|
@@ -472,10 +530,10 @@ export function createVerily(options) {
|
|
|
472
530
|
view.connectionId = flow.resultId;
|
|
473
531
|
return view;
|
|
474
532
|
}
|
|
475
|
-
/** A flow the dialog may read: one this holder started, to connect an account. */
|
|
533
|
+
/** A flow the dialog may read: one this holder started, to connect an account or renew one. */
|
|
476
534
|
async function ownFlow(request, id) {
|
|
477
535
|
const flow = await service.flow(id, binding(request));
|
|
478
|
-
if (flow.kind
|
|
536
|
+
if (!['connect', 'renew'].includes(flow.kind) || (await local(request)).id !== flow.local?.id)
|
|
479
537
|
throw new Unavailable();
|
|
480
538
|
return flow;
|
|
481
539
|
}
|
|
@@ -560,7 +618,7 @@ export function createVerily(options) {
|
|
|
560
618
|
${user
|
|
561
619
|
? card(subject(user).heading, subject(user).value, user.profileUrl)
|
|
562
620
|
: '<p>Authenticate with the matching external account to review and remove this link.</p>'}
|
|
563
|
-
<p>Confirm the connection between this ${escape(subjectNoun(user?.kind) ?? 'site')} and your ${escape(
|
|
621
|
+
<p>Confirm the connection between this ${escape(subjectNoun(user?.kind) ?? 'site')} and your ${escape(heldNames(offered))}.</p>
|
|
564
622
|
${kind === 'renew' && offered.length > 1 ? '<p class="fine">Renewing another way adds that method beneath the one this connection was first shown by.</p>' : ''}
|
|
565
623
|
${forms}`));
|
|
566
624
|
}
|
|
@@ -653,7 +711,7 @@ export function createVerily(options) {
|
|
|
653
711
|
? 'Add to connection'
|
|
654
712
|
: 'Confirm connection', `
|
|
655
713
|
${card(subject(flow.local).heading, subject(flow.local).value, flow.local.profileUrl)}
|
|
656
|
-
${card(provider.name, externalName(flow.external), externalLink(flow.external), flow.external
|
|
714
|
+
${card(provider.name, externalName(flow.external), externalLink(flow.external), externalId(flow.external))}
|
|
657
715
|
${joined ? `<p>This account is already linked here. Confirming adds this method to that connection, beneath the one it was first shown by, and it stays ${escape(joined.visibility)}.</p>` : ''}
|
|
658
716
|
${found ? `<p>${escape(found)}</p>` : ''}
|
|
659
717
|
<p class="fine">${escape(service.siteOf(flow.local))} receives the result. Verified via ${escape(options.verifierName)}.</p>
|
|
@@ -775,7 +833,7 @@ export function createVerily(options) {
|
|
|
775
833
|
}), await context(request, kind),
|
|
776
834
|
// Posted from this origin, which the check on every POST has already held it to.
|
|
777
835
|
true);
|
|
778
|
-
if (asJson &&
|
|
836
|
+
if (asJson && ['connect', 'renew'].includes(kind))
|
|
779
837
|
return json(await flowView(await service.flow(flow.flowId, flow.binding), flow.authorizationUrl), flowCookie(flow.binding));
|
|
780
838
|
return redirect(entry(flow), flowCookie(flow.binding));
|
|
781
839
|
}
|
|
@@ -815,15 +873,21 @@ export function createVerily(options) {
|
|
|
815
873
|
return json(id ? { outcome: 'complete', connectionId: id } : { outcome: 'cancelled' });
|
|
816
874
|
return await ended(await service.flow(flow.id, binding(request)));
|
|
817
875
|
}
|
|
818
|
-
const management = path.match(/^\/connections\/([^/]+)\/(disconnect|share|share-revoke|visibility)$/);
|
|
876
|
+
const management = path.match(/^\/connections\/([^/]+)\/(disconnect|mark|share|share-revoke|visibility)$/);
|
|
819
877
|
if (management) {
|
|
820
878
|
const user = await local(request), id = management[1];
|
|
821
879
|
if (management[2] === 'disconnect') {
|
|
822
880
|
await service.revoke(id, user);
|
|
823
881
|
return json({ ok: true });
|
|
824
882
|
}
|
|
883
|
+
// Acts on the account the record names: every record of it this holder has.
|
|
884
|
+
if (management[2] === 'mark') {
|
|
885
|
+
await service.mark(id, user, data.as);
|
|
886
|
+
return json({ ok: true });
|
|
887
|
+
}
|
|
825
888
|
if (management[2] === 'visibility') {
|
|
826
|
-
await service.read(id, user)
|
|
889
|
+
if ((await service.read(id, user)).status === 'retired')
|
|
890
|
+
throw new Unavailable();
|
|
827
891
|
return json({ url: `${service.baseUrl}/visibility/${id}` });
|
|
828
892
|
}
|
|
829
893
|
return json((await service.share(id, user, management[2] === 'share-revoke')) ?? { ok: true });
|
package/dist/server/link.js
CHANGED
|
@@ -4,7 +4,7 @@ import { MIMEType } from 'node:util';
|
|
|
4
4
|
import { html, parse } from 'parse5';
|
|
5
5
|
import { Refused, } from '../core/index.js';
|
|
6
6
|
import { discard, readBounded } from './body.js';
|
|
7
|
-
import {
|
|
7
|
+
import { transport } from './public-fetch.js';
|
|
8
8
|
/**
|
|
9
9
|
* Domain suffixes that must never be fetched. The holder names the address, so it names
|
|
10
10
|
* the host, and these are the names that can resolve to something inside the network
|
|
@@ -134,21 +134,6 @@ async function backlinked(response, page, subject, maxBytes) {
|
|
|
134
134
|
// Not finding it in part of a page is not the same as it not being there.
|
|
135
135
|
throw new Refused(truncated ? 'Page is too large to read' : 'Page has no rel="me" link to this subject');
|
|
136
136
|
}
|
|
137
|
-
/**
|
|
138
|
-
* How pages are fetched. A deployment that named its hosts has vouched for where they
|
|
139
|
-
* resolve, so the platform's own fetch will do. One that reads any host has vouched for
|
|
140
|
-
* nothing, and the holder picks the name: every address it resolves to is checked, on the
|
|
141
|
-
* connection that uses it, which only Node lets this do.
|
|
142
|
-
*/
|
|
143
|
-
function transport(options) {
|
|
144
|
-
if (options.fetch)
|
|
145
|
-
return options.fetch;
|
|
146
|
-
if (options.hosts)
|
|
147
|
-
return (url, init) => fetch(url, init);
|
|
148
|
-
if (!pinnable())
|
|
149
|
-
throw new Error('Reading any host needs Node, which lets it check where a name resolves; name the hosts to read instead');
|
|
150
|
-
return publicFetch();
|
|
151
|
-
}
|
|
152
137
|
/**
|
|
153
138
|
* The address the holder handed back, once it is one this may fetch. They choose it, so
|
|
154
139
|
* an unguarded fetch here is an open proxy: HTTPS only, a public-looking name rather than
|
|
@@ -19,5 +19,15 @@ export type Fetch = (url: string, init: RequestInit) => Promise<Response>;
|
|
|
19
19
|
* `allowed` decides which addresses may be connected to, and is only for tests.
|
|
20
20
|
*/
|
|
21
21
|
export declare function publicFetch(resolve?: Resolve, allowed?: (address: string) => boolean): Fetch;
|
|
22
|
+
/**
|
|
23
|
+
* How an address the holder named is fetched. A deployment that named its hosts has
|
|
24
|
+
* vouched for where they resolve, so the platform's own fetch will do. One that reads any
|
|
25
|
+
* host has vouched for nothing, and the holder picks the name: every address it resolves
|
|
26
|
+
* to is checked, on the connection that uses it, which only Node lets this do.
|
|
27
|
+
*/
|
|
28
|
+
export declare function transport(options: {
|
|
29
|
+
fetch?: typeof fetch;
|
|
30
|
+
hosts?: string[];
|
|
31
|
+
}): Fetch;
|
|
22
32
|
/** Whether this runtime is Node, the only one that lets `publicFetch()` pin its lookup. */
|
|
23
33
|
export declare function pinnable(): boolean;
|
|
@@ -37,6 +37,21 @@ export function publicFetch(resolve = system, allowed) {
|
|
|
37
37
|
}
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
+
/**
|
|
41
|
+
* How an address the holder named is fetched. A deployment that named its hosts has
|
|
42
|
+
* vouched for where they resolve, so the platform's own fetch will do. One that reads any
|
|
43
|
+
* host has vouched for nothing, and the holder picks the name: every address it resolves
|
|
44
|
+
* to is checked, on the connection that uses it, which only Node lets this do.
|
|
45
|
+
*/
|
|
46
|
+
export function transport(options) {
|
|
47
|
+
if (options.fetch)
|
|
48
|
+
return options.fetch;
|
|
49
|
+
if (options.hosts)
|
|
50
|
+
return (url, init) => fetch(url, init);
|
|
51
|
+
if (!pinnable())
|
|
52
|
+
throw new Error('Reading any host needs Node, which lets it check where a name resolves; name the hosts to read instead');
|
|
53
|
+
return publicFetch();
|
|
54
|
+
}
|
|
40
55
|
/** A lookup that answers only with addresses that are all permitted, or not at all. */
|
|
41
56
|
function pinned(resolve, permitted) {
|
|
42
57
|
return (hostname, options, callback) => {
|
package/dist/server/service.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Attestations, type Connection, type Evidence, type ExternalAccount, type Flow, type LocalAccount, type Provider, type SignedDocument, type SignedEvidence, type Storage, type VerifierKey, type Visibility } from '../core/index.js';
|
|
1
|
+
import { type Attestations, type Connection, type Evidence, type ExternalAccount, type Flow, type LocalAccount, type Mark, type Provider, type SignedDocument, type SignedEvidence, type Storage, type VerifierKey, type Visibility } from '../core/index.js';
|
|
2
2
|
export declare const secret: () => string;
|
|
3
3
|
export declare const hash: (value: string) => string;
|
|
4
4
|
export declare class Unavailable extends Error {
|
|
@@ -64,6 +64,10 @@ export declare class VerilyService {
|
|
|
64
64
|
* A public record that stands, signed as of now. Signed when asked for, not when
|
|
65
65
|
* approved, so a signed record says the record stood on the day it was taken and none can be
|
|
66
66
|
* made once it is removed.
|
|
67
|
+
*
|
|
68
|
+
* A retired record is signed too, as what it is: the durable form of the claim that the
|
|
69
|
+
* account was the holder's when it was last proved. It did not stand when it was signed,
|
|
70
|
+
* so it is a version of its own that says so, which a reader of the first refuses.
|
|
67
71
|
*/
|
|
68
72
|
signed(id: string): Promise<SignedEvidence>;
|
|
69
73
|
/** What a signed record says, if this instance signed it. */
|
|
@@ -129,6 +133,10 @@ export declare class VerilyService {
|
|
|
129
133
|
* Removing a link from the external side takes a method whose proof is fresh. A standing
|
|
130
134
|
* proof, such as a link back, is there for anyone to point at: handing one back shows
|
|
131
135
|
* the link exists, not that whoever handed it back holds the account.
|
|
136
|
+
*
|
|
137
|
+
* A retired record is renewed by the method it was first shown by and no other. Another
|
|
138
|
+
* would be listed beneath a main proof nobody has read since, and the record would come
|
|
139
|
+
* back unconfirmed.
|
|
132
140
|
*/
|
|
133
141
|
private chosen;
|
|
134
142
|
/**
|
|
@@ -243,7 +251,8 @@ export declare class VerilyService {
|
|
|
243
251
|
* The live record a connect flow reproves by another method, if there is one: the same
|
|
244
252
|
* subject linked to the same account on the same provider, first shown some other way.
|
|
245
253
|
* The same method again is a second record, as it always was; renewing is how that
|
|
246
|
-
* one is extended.
|
|
254
|
+
* one is extended. A retired record is never joined: it is frozen, so proving its account
|
|
255
|
+
* another way makes a new record and leaves that one as history behind it.
|
|
247
256
|
*/
|
|
248
257
|
private joins;
|
|
249
258
|
/**
|
|
@@ -289,6 +298,28 @@ export declare class VerilyService {
|
|
|
289
298
|
mine(local: LocalAccount): Promise<Evidence[]>;
|
|
290
299
|
private owned;
|
|
291
300
|
revoke(id: string, local: LocalAccount): Promise<void>;
|
|
301
|
+
/**
|
|
302
|
+
* The holder's records of one account that are not revoked. A mark belongs to an account,
|
|
303
|
+
* and an account can stand on several records: shown a second way on a record of its own,
|
|
304
|
+
* or removed once and connected again. They are told apart as a badge tells them, by
|
|
305
|
+
* provider and the id the provider gave.
|
|
306
|
+
*/
|
|
307
|
+
private account;
|
|
308
|
+
/**
|
|
309
|
+
* The mark an account's records carry, for a record about to stand beside them: every
|
|
310
|
+
* one neither revoked nor retired, lapsed ones included, since those hold a mark that
|
|
311
|
+
* must survive their own renewal.
|
|
312
|
+
*/
|
|
313
|
+
private accountMark;
|
|
314
|
+
/**
|
|
315
|
+
* Marks an account as the holder would have it listed, or retires it. Names one record
|
|
316
|
+
* and acts on the account, or a mark on one record could vanish behind a sibling, and
|
|
317
|
+
* retiring one could leave the account reading as verified through another.
|
|
318
|
+
*
|
|
319
|
+
* No fresh proof is asked for. A mark never widens who can read a record or makes one
|
|
320
|
+
* read as verified, and a holder retiring an account often can no longer prove it.
|
|
321
|
+
*/
|
|
322
|
+
mark(id: string, local: LocalAccount, as: 'preferred' | 'current' | 'unused' | 'retired'): Promise<void>;
|
|
292
323
|
share(id: string, local: LocalAccount, revoke?: boolean): Promise<{
|
|
293
324
|
url: string;
|
|
294
325
|
expiresAt: number;
|
|
@@ -312,6 +343,8 @@ export declare class VerilyService {
|
|
|
312
343
|
visibilityApprovedAt: number;
|
|
313
344
|
expiresAt: number;
|
|
314
345
|
revokedAt?: number;
|
|
346
|
+
mark?: Mark;
|
|
347
|
+
retiredAt?: number;
|
|
315
348
|
signedUrl?: string;
|
|
316
349
|
}>;
|
|
317
350
|
/**
|
|
@@ -334,6 +367,8 @@ export declare class VerilyService {
|
|
|
334
367
|
* `budget` bounds the reads per run, since providers rate-limit and the alarm this runs
|
|
335
368
|
* on is shared. Oldest first, so nothing starves however many connections are waiting.
|
|
336
369
|
*
|
|
370
|
+
* A retired record is never asked about: its proof is no longer expected to be there.
|
|
371
|
+
*
|
|
337
372
|
* Returns how many were confirmed. A connection revoked here is not one of them.
|
|
338
373
|
*/
|
|
339
374
|
recheck(budget?: number): Promise<number>;
|
|
@@ -347,7 +382,11 @@ export declare class VerilyService {
|
|
|
347
382
|
private reread;
|
|
348
383
|
/** A provider that never answers must not hold up the maintenance run behind it. */
|
|
349
384
|
private deadline;
|
|
350
|
-
/**
|
|
385
|
+
/**
|
|
386
|
+
* Run periodically. Pending secrets expire immediately; historical evidence defaults to 90
|
|
387
|
+
* days. A retired record is history its holder asked to keep, so it stays for as long as
|
|
388
|
+
* it is not revoked, and once revoked goes like any other.
|
|
389
|
+
*/
|
|
351
390
|
prune(retentionMs?: number): Promise<void>;
|
|
352
391
|
private invalidateShare;
|
|
353
392
|
private audit;
|