@bkazemi/verily 0.3.0 → 0.5.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 +51 -8
- package/dist/browser/connect-dialog.js +2 -2
- package/dist/browser/evidence-dialog.js +4 -4
- package/dist/browser/index.js +29 -23
- package/dist/browser/provider-mark.js +5 -3
- package/dist/core/index.d.ts +77 -7
- package/dist/core/index.js +18 -3
- package/dist/core/routes.d.ts +57 -0
- package/dist/core/routes.js +52 -0
- package/dist/server/domain.d.ts +117 -0
- package/dist/server/domain.js +374 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +102 -38
- package/dist/server/link.js +1 -16
- package/dist/server/pgp.d.ts +2 -0
- package/dist/server/pgp.js +1 -1
- package/dist/server/public-fetch.d.ts +10 -0
- package/dist/server/public-fetch.js +15 -0
- package/dist/server/service.d.ts +72 -1
- package/dist/server/service.js +233 -22
- package/dist/site/index.js +2 -2
- package/dist/verily.js +97 -37
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
package/dist/verily.js
CHANGED
|
@@ -9575,6 +9575,9 @@ var Verily = (() => {
|
|
|
9575
9575
|
__export(browser_exports, {
|
|
9576
9576
|
Refused: () => Refused,
|
|
9577
9577
|
attestationLabel: () => attestationLabel,
|
|
9578
|
+
dialogPath: () => dialogPath,
|
|
9579
|
+
dialogRoute: () => dialogRoute,
|
|
9580
|
+
externalId: () => externalId,
|
|
9578
9581
|
externalLink: () => externalLink,
|
|
9579
9582
|
externalName: () => externalName,
|
|
9580
9583
|
fresh: () => fresh,
|
|
@@ -9588,6 +9591,9 @@ var Verily = (() => {
|
|
|
9588
9591
|
presentConnections: () => presentConnections,
|
|
9589
9592
|
proofTitle: () => proofTitle,
|
|
9590
9593
|
providerMethod: () => providerMethod,
|
|
9594
|
+
routeOf: () => routeOf,
|
|
9595
|
+
routePath: () => routePath,
|
|
9596
|
+
routes: () => routes,
|
|
9591
9597
|
signedBy: () => signedBy,
|
|
9592
9598
|
status: () => status,
|
|
9593
9599
|
statusLabel: () => statusLabel,
|
|
@@ -9660,6 +9666,50 @@ var Verily = (() => {
|
|
|
9660
9666
|
return void 0;
|
|
9661
9667
|
}
|
|
9662
9668
|
|
|
9669
|
+
// src/core/routes.ts
|
|
9670
|
+
var routes = {
|
|
9671
|
+
methods: { method: "GET", path: "/methods" },
|
|
9672
|
+
start: { method: "POST", path: "/sessions" },
|
|
9673
|
+
flow: { method: "GET", path: "/flows/:id", format: "json" },
|
|
9674
|
+
submit: { method: "POST", path: "/flows/:id/submit" },
|
|
9675
|
+
approve: { method: "POST", path: "/flows/:id/approve" },
|
|
9676
|
+
disconnect: { method: "POST", path: "/connections/:id/disconnect", manages: true },
|
|
9677
|
+
mark: { method: "POST", path: "/connections/:id/mark", manages: true },
|
|
9678
|
+
share: { method: "POST", path: "/connections/:id/share", manages: true, dialog: false },
|
|
9679
|
+
shareRevoke: {
|
|
9680
|
+
method: "POST",
|
|
9681
|
+
path: "/connections/:id/share-revoke",
|
|
9682
|
+
manages: true,
|
|
9683
|
+
dialog: false
|
|
9684
|
+
}
|
|
9685
|
+
};
|
|
9686
|
+
var names = Object.keys(routes);
|
|
9687
|
+
function matches(route, path) {
|
|
9688
|
+
const want = route.path.split("/");
|
|
9689
|
+
const got = path.split("/");
|
|
9690
|
+
return want.length === got.length && want.every((part, at2) => part === ":id" ? got[at2] !== "" : part === got[at2]);
|
|
9691
|
+
}
|
|
9692
|
+
function routePath(name, id) {
|
|
9693
|
+
const route = routes[name];
|
|
9694
|
+
const path = route.path.replace(":id", encodeURIComponent(id ?? ""));
|
|
9695
|
+
return route.format ? `${path}?format=${route.format}` : path;
|
|
9696
|
+
}
|
|
9697
|
+
function routeOf(method, path) {
|
|
9698
|
+
return names.find((name) => routes[name].method === method && matches(routes[name], path));
|
|
9699
|
+
}
|
|
9700
|
+
function dialogRoute(method, path, query) {
|
|
9701
|
+
const name = routeOf(method, path);
|
|
9702
|
+
const route = name && routes[name];
|
|
9703
|
+
if (!route || route.dialog === false) return void 0;
|
|
9704
|
+
return !route.format || query.get("format") === route.format ? name : void 0;
|
|
9705
|
+
}
|
|
9706
|
+
function dialogPath(path) {
|
|
9707
|
+
return names.some((name) => {
|
|
9708
|
+
const route = routes[name];
|
|
9709
|
+
return route.dialog !== false && matches(route, path);
|
|
9710
|
+
});
|
|
9711
|
+
}
|
|
9712
|
+
|
|
9663
9713
|
// src/core/index.ts
|
|
9664
9714
|
var Refused = class extends Error {
|
|
9665
9715
|
};
|
|
@@ -9709,16 +9759,23 @@ var Verily = (() => {
|
|
|
9709
9759
|
function externalName(external) {
|
|
9710
9760
|
return external.kind === void 0 || external.kind === "account" ? `@${external.handle.replace(/^@/, "")}` : external.handle;
|
|
9711
9761
|
}
|
|
9712
|
-
function attestationLabel(method,
|
|
9762
|
+
function attestationLabel(method, names2, proof = {}) {
|
|
9763
|
+
const dnssec = proof.dnssec ? ", validated by DNSSEC" : "";
|
|
9713
9764
|
return {
|
|
9714
|
-
|
|
9715
|
-
|
|
9716
|
-
|
|
9717
|
-
|
|
9765
|
+
// A site's word carries a proof only where its own DNS was read naming this verifier.
|
|
9766
|
+
declared: proof.artifactUrl ? `Stated by ${names2.site}, whose DNS names this verifier${dnssec}` : `Stated by ${names2.site}`,
|
|
9767
|
+
oauth: `Signed in with ${names2.provider}`,
|
|
9768
|
+
gist: `Published a proof on ${names2.provider}`,
|
|
9769
|
+
backlink: `Linked back to ${names2.site}`,
|
|
9770
|
+
dns: `Published a proof in its DNS${dnssec}`,
|
|
9771
|
+
wellknown: "Published a proof in a file it serves",
|
|
9718
9772
|
signature: "Proved with a signature",
|
|
9719
9773
|
code: "Entered a code sent to this address"
|
|
9720
9774
|
}[method];
|
|
9721
9775
|
}
|
|
9776
|
+
function externalId(external) {
|
|
9777
|
+
return external.kind === "mailbox" || external.kind === "domain" ? void 0 : external.id;
|
|
9778
|
+
}
|
|
9722
9779
|
function externalLink(external) {
|
|
9723
9780
|
return external.kind === "mailbox" ? void 0 : external.profileUrl;
|
|
9724
9781
|
}
|
|
@@ -9882,7 +9939,7 @@ var Verily = (() => {
|
|
|
9882
9939
|
openpgp: key,
|
|
9883
9940
|
email: envelope
|
|
9884
9941
|
};
|
|
9885
|
-
return marks2[provider]?.() ?? (method
|
|
9942
|
+
return marks2[provider]?.() ?? (["backlink", "dns", "wellknown"].includes(method ?? "") ? globe() : void 0);
|
|
9886
9943
|
}
|
|
9887
9944
|
|
|
9888
9945
|
// src/browser/badge.ts
|
|
@@ -10428,7 +10485,7 @@ ${claims(evidence)}`;
|
|
|
10428
10485
|
}
|
|
10429
10486
|
|
|
10430
10487
|
// src/version.ts
|
|
10431
|
-
var version = "v0.
|
|
10488
|
+
var version = "v0.5.0";
|
|
10432
10489
|
|
|
10433
10490
|
// src/browser/evidence-dialog.ts
|
|
10434
10491
|
function stampLink() {
|
|
@@ -10529,8 +10586,8 @@ ${claims(evidence)}`;
|
|
|
10529
10586
|
}
|
|
10530
10587
|
return svg;
|
|
10531
10588
|
}
|
|
10532
|
-
function attestationNote(attestation,
|
|
10533
|
-
const label = attestationLabel(attestation.method,
|
|
10589
|
+
function attestationNote(attestation, names2, additional = false) {
|
|
10590
|
+
const label = attestationLabel(attestation.method, names2, attestation);
|
|
10534
10591
|
if (!label) return [];
|
|
10535
10592
|
const note = node("div", additional ? "+ " : "", `muted ${additional ? "additional" : "method"}`);
|
|
10536
10593
|
if (!attestation.artifactUrl) {
|
|
@@ -10730,21 +10787,21 @@ ${claims(evidence)}`;
|
|
|
10730
10787
|
for (const [label, time] of dateRows) {
|
|
10731
10788
|
dates.append(node("dt", label), node("dd", moment(time)));
|
|
10732
10789
|
}
|
|
10733
|
-
const
|
|
10790
|
+
const names2 = { site: evidence.siteName, provider };
|
|
10734
10791
|
const logo2 = providerMark(evidence.provider, evidence.attestations.external[0].method);
|
|
10735
10792
|
const card = accountCard(
|
|
10736
10793
|
// The mark and the name, or just the name. A mark that falls back to writing the name
|
|
10737
10794
|
// would print it twice here, since this heading writes it either way.
|
|
10738
10795
|
logo2 ? [logo2, document.createTextNode(provider)] : [document.createTextNode(provider)],
|
|
10739
10796
|
externalName(evidence.external),
|
|
10740
|
-
// A mailbox's address is its name already, so there is no second identifier.
|
|
10741
|
-
evidence.external
|
|
10797
|
+
// A mailbox's address or a domain is its name already, so there is no second identifier.
|
|
10798
|
+
externalId(evidence.external),
|
|
10742
10799
|
externalLink(evidence.external),
|
|
10743
10800
|
// Status first, then how it was shown, then when. The proof explains the state
|
|
10744
10801
|
// above it, so it cannot sit before that state has been given.
|
|
10745
10802
|
summary,
|
|
10746
|
-
...attestationNote(main,
|
|
10747
|
-
...evidence.attestations.external.slice(1).flatMap((a2) => attestationNote(a2,
|
|
10803
|
+
...attestationNote(main, names2),
|
|
10804
|
+
...evidence.attestations.external.slice(1).flatMap((a2) => attestationNote(a2, names2, true)),
|
|
10748
10805
|
...evidence.status === "revoked" || retired ? [] : evidence.mark === "preferred" ? [node("div", "Preferred", "listing preferred")] : evidence.mark === "unused" ? [node("div", "No longer used", "listing")] : [],
|
|
10749
10806
|
dates,
|
|
10750
10807
|
...manage && removable(evidence).length ? [manageRow(evidence, manage)] : []
|
|
@@ -11353,7 +11410,7 @@ ${claims(evidence)}`;
|
|
|
11353
11410
|
const external = accountCard(
|
|
11354
11411
|
logo2 ? [logo2, document.createTextNode(flow.provider.name)] : [document.createTextNode(flow.provider.name)],
|
|
11355
11412
|
externalName(flow.external),
|
|
11356
|
-
flow.external
|
|
11413
|
+
externalId(flow.external),
|
|
11357
11414
|
externalLink(flow.external)
|
|
11358
11415
|
);
|
|
11359
11416
|
const parts = [subjectCard(flow.local), linkMark(), external];
|
|
@@ -11588,7 +11645,7 @@ ${claims(evidence)}`;
|
|
|
11588
11645
|
function init({ backendUrl, handoffUrl }) {
|
|
11589
11646
|
const base = new URL(backendUrl, location.href);
|
|
11590
11647
|
if (!["https:", "http:"].includes(base.protocol)) throw new Error("Invalid backend URL");
|
|
11591
|
-
|
|
11648
|
+
const root = base.href.replace(/\/$/, "");
|
|
11592
11649
|
const remote = base.origin !== location.origin;
|
|
11593
11650
|
const bindings = /* @__PURE__ */ new Map();
|
|
11594
11651
|
let session;
|
|
@@ -11601,7 +11658,7 @@ ${claims(evidence)}`;
|
|
|
11601
11658
|
const vouched = handed.ok ? await handed.json() : void 0;
|
|
11602
11659
|
if (!record(vouched) || typeof vouched.token !== "string")
|
|
11603
11660
|
throw new Error("Verily request unavailable");
|
|
11604
|
-
const traded = await fetch(`${
|
|
11661
|
+
const traded = await fetch(`${root}/site/session`, {
|
|
11605
11662
|
method: "POST",
|
|
11606
11663
|
credentials: "omit",
|
|
11607
11664
|
cache: "no-store",
|
|
@@ -11616,11 +11673,12 @@ ${claims(evidence)}`;
|
|
|
11616
11673
|
async function ask(path, data, flow) {
|
|
11617
11674
|
if (!remote) return request(path, data);
|
|
11618
11675
|
const binding = flow && bindings.get(flow);
|
|
11619
|
-
const response = await fetch(`${
|
|
11676
|
+
const response = await fetch(`${root}${path}`, {
|
|
11620
11677
|
credentials: "omit",
|
|
11621
11678
|
cache: "no-store",
|
|
11622
11679
|
method: data ? "POST" : "GET",
|
|
11623
11680
|
headers: {
|
|
11681
|
+
Accept: "application/json",
|
|
11624
11682
|
Authorization: `Bearer ${await (session ??= openSession())}`,
|
|
11625
11683
|
...binding ? { "X-Verily-Flow": binding } : {},
|
|
11626
11684
|
...data ? { "Content-Type": "application/json" } : {}
|
|
@@ -11634,21 +11692,23 @@ ${claims(evidence)}`;
|
|
|
11634
11692
|
return answer;
|
|
11635
11693
|
}
|
|
11636
11694
|
async function request(path, data) {
|
|
11637
|
-
const response = await fetch(`${
|
|
11695
|
+
const response = await fetch(`${root}${path}`, {
|
|
11638
11696
|
credentials: "same-origin",
|
|
11639
11697
|
cache: "no-store",
|
|
11640
|
-
|
|
11641
|
-
|
|
11642
|
-
|
|
11643
|
-
|
|
11644
|
-
|
|
11698
|
+
// Says what is wanted back, whatever is sent. A header any page may send to another
|
|
11699
|
+
// origin without asking first, so a badge on a static site reads as it did.
|
|
11700
|
+
headers: {
|
|
11701
|
+
Accept: "application/json",
|
|
11702
|
+
...data ? { "Content-Type": "application/json" } : {}
|
|
11703
|
+
},
|
|
11704
|
+
...data ? { method: "POST", body: JSON.stringify(data) } : {}
|
|
11645
11705
|
});
|
|
11646
11706
|
if (!response.ok) throw new Error("Verily request unavailable");
|
|
11647
11707
|
return response.json();
|
|
11648
11708
|
}
|
|
11649
11709
|
const flows = {
|
|
11650
11710
|
async methods() {
|
|
11651
|
-
const data = await ask("
|
|
11711
|
+
const data = await ask(routePath("methods"));
|
|
11652
11712
|
if (!record(data) || !record(data.local) || !Array.isArray(data.methods))
|
|
11653
11713
|
throw new Error("Invalid methods response");
|
|
11654
11714
|
if (typeof data.local.profileUrl === "string") safeUrl(data.local.profileUrl);
|
|
@@ -11656,15 +11716,15 @@ ${claims(evidence)}`;
|
|
|
11656
11716
|
},
|
|
11657
11717
|
start: async (provider, method, renew) => flowView(
|
|
11658
11718
|
await ask(
|
|
11659
|
-
"
|
|
11719
|
+
routePath("start"),
|
|
11660
11720
|
renew ? { kind: "renew", connectionId: renew, provider, method } : { kind: "connect", provider, method }
|
|
11661
11721
|
)
|
|
11662
11722
|
),
|
|
11663
|
-
read: async (id) => flowView(await ask(
|
|
11664
|
-
submit: async (id, artifact) => flowView(await ask(
|
|
11723
|
+
read: async (id) => flowView(await ask(routePath("flow", id), void 0, id)),
|
|
11724
|
+
submit: async (id, artifact) => flowView(await ask(routePath("submit", id), { artifact }, id)),
|
|
11665
11725
|
async approve(id, visibility, cancel) {
|
|
11666
11726
|
const data = await ask(
|
|
11667
|
-
|
|
11727
|
+
routePath("approve", id),
|
|
11668
11728
|
{ action: cancel ? "cancel" : "approve", visibility },
|
|
11669
11729
|
id
|
|
11670
11730
|
);
|
|
@@ -11694,7 +11754,7 @@ ${claims(evidence)}`;
|
|
|
11694
11754
|
);
|
|
11695
11755
|
};
|
|
11696
11756
|
window.addEventListener("message", receive);
|
|
11697
|
-
popup.location.href = `${
|
|
11757
|
+
popup.location.href = `${root}/site/enter`;
|
|
11698
11758
|
}
|
|
11699
11759
|
} : {}
|
|
11700
11760
|
};
|
|
@@ -11718,7 +11778,7 @@ ${claims(evidence)}`;
|
|
|
11718
11778
|
pill.setAttribute("aria-haspopup", "dialog");
|
|
11719
11779
|
pill.onclick = async () => {
|
|
11720
11780
|
if (typeof HTMLDialogElement === "undefined" && !remote) {
|
|
11721
|
-
location.href = `${
|
|
11781
|
+
location.href = `${root}/verify`;
|
|
11722
11782
|
return;
|
|
11723
11783
|
}
|
|
11724
11784
|
const result = await client.openConnect(element);
|
|
@@ -11833,7 +11893,7 @@ ${claims(evidence)}`;
|
|
|
11833
11893
|
},
|
|
11834
11894
|
disconnect(id) {
|
|
11835
11895
|
if (remote) session = void 0;
|
|
11836
|
-
return ask(
|
|
11896
|
+
return ask(routePath("disconnect", id), {});
|
|
11837
11897
|
},
|
|
11838
11898
|
/**
|
|
11839
11899
|
* Says how the holder would have an account listed, or retires it. Names one record
|
|
@@ -11841,10 +11901,10 @@ ${claims(evidence)}`;
|
|
|
11841
11901
|
*/
|
|
11842
11902
|
mark(id, as2) {
|
|
11843
11903
|
if (remote) session = void 0;
|
|
11844
|
-
return ask(
|
|
11904
|
+
return ask(routePath("mark", id), { as: as2 });
|
|
11845
11905
|
},
|
|
11846
|
-
issueShare: (id) => request(
|
|
11847
|
-
revokeShare: (id) => request(
|
|
11906
|
+
issueShare: (id) => request(routePath("share", id), {}),
|
|
11907
|
+
revokeShare: (id) => request(routePath("shareRevoke", id), {})
|
|
11848
11908
|
};
|
|
11849
11909
|
return client;
|
|
11850
11910
|
}
|
|
@@ -11893,7 +11953,7 @@ ${claims(evidence)}`;
|
|
|
11893
11953
|
}
|
|
11894
11954
|
function validAttestation(attestation) {
|
|
11895
11955
|
if (!record(attestation)) return false;
|
|
11896
|
-
return ["backend", "provider"].includes(String(attestation.by)) && typeof attestation.method === "string" && typeof attestation.confirmedAt === "number" && Number.isFinite(attestation.confirmedAt) && (attestation.expect === void 0 || typeof attestation.expect === "string") && // Rendered as a link later, so only http(s) may ever reach an href.
|
|
11956
|
+
return ["backend", "provider"].includes(String(attestation.by)) && typeof attestation.method === "string" && typeof attestation.confirmedAt === "number" && Number.isFinite(attestation.confirmedAt) && (attestation.expect === void 0 || typeof attestation.expect === "string") && (attestation.dnssec === void 0 || typeof attestation.dnssec === "boolean") && // Rendered as a link later, so only http(s) may ever reach an href.
|
|
11897
11957
|
(attestation.artifactUrl === void 0 || httpUrl2(attestation.artifactUrl));
|
|
11898
11958
|
}
|
|
11899
11959
|
function httpUrl2(value) {
|
|
@@ -11914,7 +11974,7 @@ ${claims(evidence)}`;
|
|
|
11914
11974
|
(k2) => typeof value.external[k2] === "string"
|
|
11915
11975
|
) && (value.local.profileUrl === void 0 || typeof value.local.profileUrl === "string") && // A signed record lives beside the record it was made from and nowhere else, since the
|
|
11916
11976
|
// keys it is checked against are read from where the record lives.
|
|
11917
|
-
(value.signedUrl === void 0 || value.signedUrl === `${value.evidenceUrl}?format=signed`) && validAttestations(value.attestations) && (value.local.kind === void 0 || typeof value.local.kind === "string") && (value.external.kind === void 0 || ["account", "key", "page", "mailbox"].includes(String(value.external.kind))) && (value.revokedAt === void 0 || typeof value.revokedAt === "number" && Number.isFinite(value.revokedAt)) && ["verified", "unconfirmed", "expired", "retired", "revoked"].includes(String(value.status)) && // A retired record stands on its dates, so one that does not say when is not one.
|
|
11977
|
+
(value.signedUrl === void 0 || value.signedUrl === `${value.evidenceUrl}?format=signed`) && validAttestations(value.attestations) && (value.local.kind === void 0 || typeof value.local.kind === "string") && (value.external.kind === void 0 || ["account", "key", "page", "mailbox", "domain"].includes(String(value.external.kind))) && (value.revokedAt === void 0 || typeof value.revokedAt === "number" && Number.isFinite(value.revokedAt)) && ["verified", "unconfirmed", "expired", "retired", "revoked"].includes(String(value.status)) && // A retired record stands on its dates, so one that does not say when is not one.
|
|
11918
11978
|
(value.status === "retired" ? typeof value.retiredAt === "number" && Number.isFinite(value.retiredAt) : value.retiredAt === void 0) && (value.mark === void 0 || ["preferred", "unused"].includes(String(value.mark))) && ["public", "unlisted"].includes(String(value.visibility)) && (value.connectedAt === void 0 || typeof value.connectedAt === "number" && Number.isFinite(value.connectedAt)) && ["authenticatedAt", "approvedAt", "expiresAt"].every(
|
|
11919
11979
|
(k2) => typeof value[k2] === "number" && Number.isFinite(value[k2])
|
|
11920
11980
|
);
|
package/dist/version.d.ts
CHANGED
package/dist/version.js
CHANGED