dm: prompt for login when messaging while logged out

The "Message" button opened the profile modal's messages tab even with no user
logged in, leaving an unusable composer (DMs need a signing identity). Gate
openDirectMessageComposer behind isUserLoggedIn(): surface a login message and
open the login modal (falling back to authService.requestLogin) instead of
opening the messages pane.

Regression: tests/app/dm-composer-login-gate.test.mjs.

Co-Authored-By: Claude Opus 4.8 <[email protected]>
This commit is contained in:
thePR0M3TH3ANandClaude Opus 4.8 committed 2026-06-23 21:22:03 -04:00
1 parent ab68ba51d0
commit fd546fa1e5
2 files changed
+119

No files matched your search

+31
View File
@@ -2974,6 +2974,37 @@ class Application {
return false;
}
// Direct messages require a signing identity. If nobody is logged in, prompt
// for login instead of silently opening an unusable messages tab.
if (!this.isUserLoggedIn()) {
this.showError(
"Please log in with your Nostr account to send a direct message.",
);
try {
if (
this.loginModalController &&
typeof this.loginModalController.openModal === "function" &&
this.loginModalController.openModal({})
) {
return false;
}
} catch (error) {
devLogger.warn(
"[Application] Failed to open login modal for direct message:",
error,
);
}
Promise.resolve(
this.authService?.requestLogin?.({ allowAccountSelection: true }),
).catch((error) => {
devLogger.warn(
"[Application] Direct message login request failed:",
error,
);
});
return false;
}
this.setDmRecipientPubkey(normalized);
if (this.profileController) {
+88
View File
@@ -0,0 +1,88 @@
// Regression: the "Message" button opened the profile modal's messages tab even
// when nobody was logged in — but DMs need a signing identity, so the tab was
// unusable. openDirectMessageComposer must prompt for login instead.
//
// Scenario (SCN-dm-composer-login-gate):
// Given no user is logged in,
// When openDirectMessageComposer is called for a valid recipient,
// Then it surfaces a login prompt (login modal), does NOT open the messages
// pane, and returns false.
// And when a user IS logged in, it proceeds to open the composer.
import test from "node:test";
import assert from "node:assert/strict";
import { Application } from "../../js/app.js";
const RECIPIENT = "d".repeat(64);
function createTestApp({ loggedIn }) {
const calls = {
showError: [],
openModal: 0,
requestLogin: 0,
setRecipient: 0,
showMessagesPane: 0,
};
const app = {
calls,
normalizeHexPubkey: (value) =>
typeof value === "string" && value.trim() ? value.trim() : null,
showError: (msg) => calls.showError.push(msg),
isUserLoggedIn: () => loggedIn,
loginModalController: {
openModal: () => {
calls.openModal += 1;
return true;
},
},
authService: {
requestLogin: () => {
calls.requestLogin += 1;
return Promise.resolve(true);
},
},
setDmRecipientPubkey: () => {
calls.setRecipient += 1;
},
profileController: {
setDirectMessageRecipient: () => {},
show: () => {
calls.showMessagesPane += 1;
},
focusMessageComposer: () => {},
},
openDirectMessageComposer: Application.prototype.openDirectMessageComposer,
};
return app;
}
test("prompts for login and does not open messages when logged out", () => {
const app = createTestApp({ loggedIn: false });
const result = app.openDirectMessageComposer({ recipientPubkey: RECIPIENT });
assert.equal(result, false, "returns false when not logged in");
assert.equal(app.calls.openModal, 1, "opens the login modal");
assert.equal(
app.calls.showMessagesPane,
0,
"must NOT open the messages pane when logged out",
);
assert.equal(app.calls.setRecipient, 0, "must not set a DM recipient");
assert.ok(
app.calls.showError.some((m) => /log in/i.test(m)),
"surfaces a login message",
);
});
test("opens the composer when logged in", () => {
const app = createTestApp({ loggedIn: true });
const result = app.openDirectMessageComposer({ recipientPubkey: RECIPIENT });
assert.equal(result, true, "returns true when logged in");
assert.equal(app.calls.openModal, 0, "does not prompt for login");
assert.equal(app.calls.setRecipient, 1, "sets the DM recipient");
assert.equal(app.calls.showMessagesPane, 1, "opens the messages pane");
});