@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/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, names) {
9762
+ function attestationLabel(method, names2, proof = {}) {
9763
+ const dnssec = proof.dnssec ? ", validated by DNSSEC" : "";
9713
9764
  return {
9714
- declared: `Stated by ${names.site}`,
9715
- oauth: `Signed in with ${names.provider}`,
9716
- gist: `Published a proof on ${names.provider}`,
9717
- backlink: `Linked back to ${names.site}`,
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 === "backlink" ? globe() : void 0);
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.3.0";
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, names, additional = false) {
10533
- const label = attestationLabel(attestation.method, names);
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 names = { site: evidence.siteName, provider };
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.kind === "mailbox" ? void 0 : evidence.external.id,
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, names),
10747
- ...evidence.attestations.external.slice(1).flatMap((a2) => attestationNote(a2, names, true)),
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.kind === "mailbox" ? void 0 : flow.external.id,
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
- base.pathname = base.pathname.replace(/\/$/, "");
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(`${base.href}/site/session`, {
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(`${base.href}${path}`, {
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(`${base.href}${path}`, {
11695
+ const response = await fetch(`${root}${path}`, {
11638
11696
  credentials: "same-origin",
11639
11697
  cache: "no-store",
11640
- ...data ? {
11641
- method: "POST",
11642
- headers: { "Content-Type": "application/json" },
11643
- body: JSON.stringify(data)
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("/methods");
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
- "/sessions",
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(`/flows/${encodeURIComponent(id)}?format=json`, void 0, id)),
11664
- submit: async (id, artifact) => flowView(await ask(`/flows/${encodeURIComponent(id)}/submit`, { artifact }, id)),
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
- `/flows/${encodeURIComponent(id)}/approve`,
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 = `${base.href}/site/enter`;
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 = `${base.href}/verify`;
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(`/connections/${encodeURIComponent(id)}/disconnect`, {});
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(`/connections/${encodeURIComponent(id)}/mark`, { as: as2 });
11904
+ return ask(routePath("mark", id), { as: as2 });
11845
11905
  },
11846
- issueShare: (id) => request(`/connections/${encodeURIComponent(id)}/share`, {}),
11847
- revokeShare: (id) => request(`/connections/${encodeURIComponent(id)}/share-revoke`, {})
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
@@ -7,4 +7,4 @@
7
7
  * output stays what tsc emitted and nothing has to be substituted into it. A version bump
8
8
  * changes this line with package.json.
9
9
  */
10
- export declare const version = "v0.3.0";
10
+ export declare const version = "v0.5.0";
package/dist/version.js CHANGED
@@ -7,4 +7,4 @@
7
7
  * output stays what tsc emitted and nothing has to be substituted into it. A version bump
8
8
  * changes this line with package.json.
9
9
  */
10
- export const version = 'v0.3.0';
10
+ export const version = 'v0.5.0';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bkazemi/verily",
3
- "version": "0.3.0",
3
+ "version": "0.5.0",
4
4
  "description": "Self-hosted account-to-account verification for Node.js",
5
5
  "type": "module",
6
6
  "license": "MIT",