Let the group join decide when a refused relay join matters
This commit is contained in:
parent
7e98cb2575
commit
17f53946f1
1 changed files with 32 additions and 35 deletions
|
|
@ -316,59 +316,57 @@ const fail = (
|
||||||
codeHinted = false,
|
codeHinted = false,
|
||||||
): Outcome => ({ ok: false, step, message, codeHinted });
|
): Outcome => ({ ok: false, step, message, codeHinted });
|
||||||
|
|
||||||
// Runs the two-level join: relay first (a group join needs relay membership),
|
// Bare relay joins the relay declined, per pubkey. A refusal is only a hint:
|
||||||
// then group. Everything free happens silently; the first refusal is reported
|
// some relays (pyramid) let non-members into open groups, so the group join
|
||||||
// as the step needing user input.
|
// decides whether relay membership was needed. Remembering it spares one
|
||||||
// Relay-level join (NIP-43). `refused` is set when the relay declined for an
|
// doomed signature per room.
|
||||||
// unclear reason: a group refusal right after is then more likely the relay
|
const relayRefusals: Record<string, Outcome> = {};
|
||||||
// gate than the group's.
|
|
||||||
async function ensureRelayAccess(
|
// Relay-level join (NIP-43). Returns the refusal, if any, without acting on it.
|
||||||
pubkey: string,
|
async function tryRelayJoin(pubkey: string, codes: Codes): Promise<Outcome> {
|
||||||
codes: Codes,
|
|
||||||
): Promise<{ outcome: Outcome; refused: boolean }> {
|
|
||||||
await ensureRelayMembershipChecked(pubkey);
|
await ensureRelayMembershipChecked(pubkey);
|
||||||
if (relayMembership[pubkey] !== "guest") {
|
if (relayMembership[pubkey] !== "guest") return { ok: true };
|
||||||
return { outcome: { ok: true }, refused: false };
|
if (!codes.relay && relayRefusals[pubkey]) return relayRefusals[pubkey];
|
||||||
}
|
|
||||||
const tags: string[][] = [["-"]];
|
const tags: string[][] = [["-"]];
|
||||||
if (codes.relay) tags.push(["claim", codes.relay]);
|
if (codes.relay) tags.push(["claim", codes.relay]);
|
||||||
|
let outcome: Outcome = { ok: true };
|
||||||
|
let policy = false;
|
||||||
try {
|
try {
|
||||||
await publishSigned(28934, tags);
|
await publishSigned(28934, tags);
|
||||||
relayMembership[pubkey] = "member";
|
relayMembership[pubkey] = "member";
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const msg = reason(e);
|
const msg = reason(e);
|
||||||
|
policy = prefixed(msg, "restricted:") || prefixed(msg, "blocked:");
|
||||||
if (prefixed(msg, "duplicate:")) {
|
if (prefixed(msg, "duplicate:")) {
|
||||||
relayMembership[pubkey] = "member";
|
relayMembership[pubkey] = "member";
|
||||||
} else if (prefixed(msg, "restricted:")) {
|
|
||||||
// A bare request refused is the expected probe, not a user error
|
|
||||||
return {
|
|
||||||
outcome: fail(
|
|
||||||
"relay-code",
|
|
||||||
codes.relay ? stripPrefix(msg) : null,
|
|
||||||
true,
|
|
||||||
),
|
|
||||||
refused: true,
|
|
||||||
};
|
|
||||||
} else if (prefixed(msg, "blocked:")) {
|
} else if (prefixed(msg, "blocked:")) {
|
||||||
return { outcome: fail("error", stripPrefix(msg)), refused: true };
|
outcome = fail("error", stripPrefix(msg));
|
||||||
} else {
|
} else {
|
||||||
return { outcome: { ok: true }, refused: true };
|
// A bare request refused is the expected probe, not a user error
|
||||||
|
outcome = fail("relay-code", codes.relay ? stripPrefix(msg) : null, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { outcome: { ok: true }, refused: false };
|
if (outcome.ok) delete relayRefusals[pubkey];
|
||||||
|
else if (!codes.relay && policy) relayRefusals[pubkey] = outcome;
|
||||||
|
return outcome;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Runs the two-level join: relay first (a group join may need relay
|
||||||
|
// membership), then group. Everything free happens silently; the first
|
||||||
|
// refusal that actually blocks is reported as the step needing user input.
|
||||||
async function ensureAccess(groupId: string, codes: Codes): Promise<Outcome> {
|
async function ensureAccess(groupId: string, codes: Codes): Promise<Outcome> {
|
||||||
const pubkey = auth.user?.pubkey;
|
const pubkey = auth.user?.pubkey;
|
||||||
if (!pubkey) return fail("error", "Not logged in");
|
if (!pubkey) return fail("error", "Not logged in");
|
||||||
|
|
||||||
const relay = await ensureRelayAccess(pubkey, codes);
|
|
||||||
if (!relay.outcome.ok) return relay.outcome;
|
|
||||||
const relayRefused = relay.refused;
|
|
||||||
|
|
||||||
await ensureMembershipChecked(groupId);
|
await ensureMembershipChecked(groupId);
|
||||||
const k = memberKey(groupId);
|
const k = memberKey(groupId);
|
||||||
if (membership[k] === "member") return { ok: true };
|
if (membership[k] === "member") return { ok: true };
|
||||||
|
|
||||||
|
const relay = await tryRelayJoin(pubkey, codes);
|
||||||
|
// A code the user typed is judged at once; a bare refusal only counts if
|
||||||
|
// the group join fails too
|
||||||
|
if (!relay.ok && codes.relay) return relay;
|
||||||
|
|
||||||
const tags: string[][] = [["h", groupId]];
|
const tags: string[][] = [["h", groupId]];
|
||||||
if (codes.group) tags.push(["code", codes.group]);
|
if (codes.group) tags.push(["code", codes.group]);
|
||||||
try {
|
try {
|
||||||
|
|
@ -376,9 +374,7 @@ async function ensureAccess(groupId: string, codes: Codes): Promise<Outcome> {
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const msg = reason(e);
|
const msg = reason(e);
|
||||||
if (!prefixed(msg, "duplicate:")) {
|
if (!prefixed(msg, "duplicate:")) {
|
||||||
if (prefixed(msg, "restricted:") && relayRefused) {
|
if (prefixed(msg, "restricted:") && !relay.ok) return relay;
|
||||||
return fail("relay-code", stripPrefix(msg), true);
|
|
||||||
}
|
|
||||||
if (prefixed(msg, "restricted:")) {
|
if (prefixed(msg, "restricted:")) {
|
||||||
const hinted = mentionsCode(msg);
|
const hinted = mentionsCode(msg);
|
||||||
return fail(
|
return fail(
|
||||||
|
|
@ -448,6 +444,7 @@ async function runWithAccess(
|
||||||
const pubkey = auth.user?.pubkey;
|
const pubkey = auth.user?.pubkey;
|
||||||
if (retry && pubkey && prefixed(reason(e), "restricted:")) {
|
if (retry && pubkey && prefixed(reason(e), "restricted:")) {
|
||||||
delete membership[memberKey(groupId)];
|
delete membership[memberKey(groupId)];
|
||||||
|
delete relayRefusals[pubkey];
|
||||||
if (relayMembership[pubkey] === "member")
|
if (relayMembership[pubkey] === "member")
|
||||||
relayMembership[pubkey] = "guest";
|
relayMembership[pubkey] = "guest";
|
||||||
return runWithAccess(groupId, action, codes, false);
|
return runWithAccess(groupId, action, codes, false);
|
||||||
|
|
@ -479,7 +476,7 @@ export async function submitJoinCode(code?: string) {
|
||||||
const outcome = groupId
|
const outcome = groupId
|
||||||
? await ensureAccess(groupId, codes)
|
? await ensureAccess(groupId, codes)
|
||||||
: pubkey
|
: pubkey
|
||||||
? (await ensureRelayAccess(pubkey, codes)).outcome
|
? await tryRelayJoin(pubkey, codes)
|
||||||
: fail("error", "Not logged in");
|
: fail("error", "Not logged in");
|
||||||
if (!outcome.ok) {
|
if (!outcome.ok) {
|
||||||
openModal(groupId, outcome, cb);
|
openModal(groupId, outcome, cb);
|
||||||
|
|
@ -503,7 +500,7 @@ export async function joinRelay(cb: () => void | Promise<void>): Promise<void> {
|
||||||
if (!pubkey || busy) return;
|
if (!pubkey || busy) return;
|
||||||
busy = true;
|
busy = true;
|
||||||
try {
|
try {
|
||||||
const { outcome } = await ensureRelayAccess(pubkey, {});
|
const outcome = await tryRelayJoin(pubkey, {});
|
||||||
if (!outcome.ok) {
|
if (!outcome.ok) {
|
||||||
openModal(null, outcome, cb);
|
openModal(null, outcome, cb);
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue