@hollware/server 0.3.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.
@@ -1,4 +1,4 @@
1
- import { a as findInvitation, c as invitationById, d as saveChallenge, f as takeChallenge, i as createUser, l as passkeysOf, m as userHandle, o as findPasskey, p as touchPasskey, r as createSession, t as addPasskey, u as redeemInvitation } from "./store-Sq0pwUQv.mjs";
1
+ import { a as findInvitation, c as invitationById, d as redeemInvitation, f as saveChallenge, h as userHandle, i as createUser, m as touchPasskey, o as findPasskey, p as takeChallenge, r as createSession, t as addPasskey, u as passkeysOf } from "./store-CsuER6J7.mjs";
2
2
  import { HollwareError, newId } from "@hollware/core";
3
3
  import { generateAuthenticationOptions, generateRegistrationOptions, verifyAuthenticationResponse, verifyRegistrationResponse } from "@simplewebauthn/server";
4
4
  import { isoBase64URL } from "@simplewebauthn/server/helpers";
@@ -17,10 +17,10 @@ function refused(message, fix) {
17
17
  }
18
18
  /** The options of `navigator.credentials.create` for the person of an invitation. */
19
19
  async function registrationOptions(ceremony, invitationSecret) {
20
- const invitation = await findInvitation(ceremony.db, ceremony.site, invitationSecret, ceremony.now);
20
+ const invitation = await findInvitation(ceremony.db, invitationSecret, ceremony.now);
21
21
  if (invitation === null) throw refused("This link is not valid: it was used already, or it expired.", "Ask the owner of this Hollware for a new invitation.");
22
22
  const userId = invitation.userId ?? newId("usr");
23
- const existing = invitation.userId === null ? [] : await passkeysOf(ceremony.db, ceremony.site, invitation.userId);
23
+ const existing = invitation.userId === null ? [] : await passkeysOf(ceremony.db, invitation.userId);
24
24
  const rp = relyingParty(ceremony);
25
25
  const options = await generateRegistrationOptions({
26
26
  rpName: "Hollware",
@@ -36,7 +36,6 @@ async function registrationOptions(ceremony, invitationSecret) {
36
36
  });
37
37
  return {
38
38
  challengeId: await saveChallenge(ceremony.db, {
39
- site: ceremony.site,
40
39
  challenge: options.challenge,
41
40
  purpose: "register",
42
41
  invitationId: invitation.id,
@@ -52,7 +51,6 @@ async function registrationOptions(ceremony, invitationSecret) {
52
51
  */
53
52
  async function verifyRegistration(ceremony, input) {
54
53
  const challenge = await takeChallenge(ceremony.db, {
55
- site: ceremony.site,
56
54
  id: input.challengeId,
57
55
  purpose: "register",
58
56
  now: ceremony.now
@@ -66,18 +64,17 @@ async function verifyRegistration(ceremony, input) {
66
64
  expectedRPID: rp.id
67
65
  });
68
66
  if (!verified.verified) throw refused("The passkey could not be verified.", "Try again.");
69
- const invitation = await invitationById(ceremony.db, ceremony.site, challenge.invitationId);
70
- if (invitation === null || !await redeemInvitation(ceremony.db, ceremony.site, invitation.id, ceremony.now)) throw refused("This link is not valid: it was used already, or it expired.", "Ask the owner of this Hollware for a new invitation.");
67
+ const invitation = await invitationById(ceremony.db, challenge.invitationId);
68
+ if (invitation === null || !await redeemInvitation(ceremony.db, invitation.id, ceremony.now)) throw refused("This link is not valid: it was used already, or it expired.", "Ask the owner of this Hollware for a new invitation.");
71
69
  if (invitation.userId === null) await createUser(ceremony.db, {
72
70
  id: challenge.userId,
73
71
  name: input.name.trim() === "" ? "Unnamed" : input.name.trim(),
74
72
  role: invitation.role,
75
- site: ceremony.site,
73
+ site: invitation.site,
76
74
  now: ceremony.now
77
75
  });
78
76
  const { credential } = verified.registrationInfo;
79
77
  await addPasskey(ceremony.db, {
80
- site: ceremony.site,
81
78
  userId: challenge.userId,
82
79
  credentialId: credential.id,
83
80
  publicKey: isoBase64URL.fromBuffer(credential.publicKey),
@@ -87,7 +84,6 @@ async function verifyRegistration(ceremony, input) {
87
84
  now: ceremony.now
88
85
  });
89
86
  const session = await createSession(ceremony.db, {
90
- site: ceremony.site,
91
87
  userId: challenge.userId,
92
88
  now: ceremony.now,
93
89
  hours: SESSION_HOURS
@@ -97,7 +93,7 @@ async function verifyRegistration(ceremony, input) {
97
93
  session: session.secret
98
94
  };
99
95
  }
100
- /** The options of `navigator.credentials.get`: any passkey of this site, chosen by the person. */
96
+ /** The options of `navigator.credentials.get`: any passkey of this deployment, chosen by the person. */
101
97
  async function authenticationOptions(ceremony) {
102
98
  const rp = relyingParty(ceremony);
103
99
  const options = await generateAuthenticationOptions({
@@ -106,7 +102,6 @@ async function authenticationOptions(ceremony) {
106
102
  });
107
103
  return {
108
104
  challengeId: await saveChallenge(ceremony.db, {
109
- site: ceremony.site,
110
105
  challenge: options.challenge,
111
106
  purpose: "authenticate",
112
107
  invitationId: null,
@@ -116,16 +111,15 @@ async function authenticationOptions(ceremony) {
116
111
  options
117
112
  };
118
113
  }
119
- /** Verifies a sign-in with a passkey of this site, and opens the person's session. */
114
+ /** Verifies a sign-in with a passkey of this deployment, and opens the person's session. */
120
115
  async function verifyAuthentication(ceremony, input) {
121
116
  const challenge = await takeChallenge(ceremony.db, {
122
- site: ceremony.site,
123
117
  id: input.challengeId,
124
118
  purpose: "authenticate",
125
119
  now: ceremony.now
126
120
  });
127
121
  if (challenge === null) throw refused("The sign-in expired.", "Sign in again.");
128
- const passkey = await findPasskey(ceremony.db, ceremony.site, input.response.id);
122
+ const passkey = await findPasskey(ceremony.db, input.response.id);
129
123
  if (passkey === null) throw refused("This passkey is not one of this Hollware.", "Use a passkey you registered here.");
130
124
  const rp = relyingParty(ceremony);
131
125
  const verified = await verifyAuthenticationResponse({
@@ -143,7 +137,6 @@ async function verifyAuthentication(ceremony, input) {
143
137
  if (!verified.verified) throw refused("The passkey could not be verified.", "Try again.");
144
138
  await touchPasskey(ceremony.db, passkey.id, verified.authenticationInfo.newCounter, ceremony.now);
145
139
  const session = await createSession(ceremony.db, {
146
- site: ceremony.site,
147
140
  userId: passkey.userId,
148
141
  now: ceremony.now,
149
142
  hours: SESSION_HOURS
package/dist/index.d.mts CHANGED
@@ -333,6 +333,17 @@ type Principal = {
333
333
  readonly site: string;
334
334
  /** The scopes of the grant intersected with those of the user's role, as of now. */
335
335
  readonly scopes: readonly Scope[];
336
+ } | {
337
+ /**
338
+ * A read token (`hw_read_`): it reads the published content of its site over the read API,
339
+ * and the gateway turns it away from every other route.
340
+ */
341
+ readonly kind: 'read';
342
+ readonly userId: string;
343
+ readonly tokenId: string;
344
+ readonly site: string;
345
+ /** `content:read` while its user's role has it, else nothing. */
346
+ readonly scopes: readonly Scope[];
336
347
  } | {
337
348
  /** A Worker of the same account, over the RPC binding: it reads published content. */
338
349
  readonly kind: 'binding';