mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-09 15:07:10 +02:00
feat: case insensitive names
This commit is contained in:
@@ -237,16 +237,86 @@ describe("resolveFilterAliases", () => {
|
||||
expect(result.authors?.length).toBe(5000);
|
||||
});
|
||||
|
||||
it("should handle mixed case aliases (should not match)", () => {
|
||||
// Aliases are case-sensitive and should be lowercase
|
||||
it("should handle mixed case aliases (case-insensitive)", () => {
|
||||
// Aliases are case-insensitive for user convenience
|
||||
const accountPubkey = "a".repeat(64);
|
||||
const contacts = ["b".repeat(64), "c".repeat(64)];
|
||||
const filter: NostrFilter = { authors: ["$Me", "$CONTACTS"] };
|
||||
const result = resolveFilterAliases(filter, "a".repeat(64), [
|
||||
"b".repeat(64),
|
||||
]);
|
||||
const result = resolveFilterAliases(filter, accountPubkey, contacts);
|
||||
|
||||
// These should NOT be resolved (case mismatch)
|
||||
expect(result.authors).toContain("$Me");
|
||||
expect(result.authors).toContain("$CONTACTS");
|
||||
// These should be resolved despite case differences
|
||||
expect(result.authors).toContain(accountPubkey);
|
||||
expect(result.authors).toContain(contacts[0]);
|
||||
expect(result.authors).toContain(contacts[1]);
|
||||
expect(result.authors).not.toContain("$Me");
|
||||
expect(result.authors).not.toContain("$CONTACTS");
|
||||
});
|
||||
});
|
||||
|
||||
describe("case-insensitive alias resolution", () => {
|
||||
it("should resolve $ME (uppercase) in authors", () => {
|
||||
const filter: NostrFilter = { authors: ["$ME"] };
|
||||
const accountPubkey = "a".repeat(64);
|
||||
const result = resolveFilterAliases(filter, accountPubkey, []);
|
||||
|
||||
expect(result.authors).toEqual([accountPubkey]);
|
||||
expect(result.authors).not.toContain("$ME");
|
||||
});
|
||||
|
||||
it("should resolve $Me (mixed case) in #p tags", () => {
|
||||
const filter: NostrFilter = { "#p": ["$Me"] };
|
||||
const accountPubkey = "a".repeat(64);
|
||||
const result = resolveFilterAliases(filter, accountPubkey, []);
|
||||
|
||||
expect(result["#p"]).toEqual([accountPubkey]);
|
||||
expect(result["#p"]).not.toContain("$Me");
|
||||
});
|
||||
|
||||
it("should resolve $CONTACTS (uppercase) in authors", () => {
|
||||
const filter: NostrFilter = { authors: ["$CONTACTS"] };
|
||||
const contacts = ["a".repeat(64), "b".repeat(64)];
|
||||
const result = resolveFilterAliases(filter, undefined, contacts);
|
||||
|
||||
expect(result.authors).toEqual(contacts);
|
||||
expect(result.authors).not.toContain("$CONTACTS");
|
||||
});
|
||||
|
||||
it("should resolve $Contacts (mixed case) in #P tags", () => {
|
||||
const filter: NostrFilter = { "#P": ["$Contacts"] };
|
||||
const contacts = ["a".repeat(64), "b".repeat(64)];
|
||||
const result = resolveFilterAliases(filter, undefined, contacts);
|
||||
|
||||
expect(result["#P"]).toEqual(contacts);
|
||||
expect(result["#P"]).not.toContain("$Contacts");
|
||||
});
|
||||
|
||||
it("should handle multiple case variations in same filter", () => {
|
||||
const filter: NostrFilter = {
|
||||
authors: ["$me", "$ME", "$Me"],
|
||||
"#p": ["$contacts", "$CONTACTS", "$Contacts"],
|
||||
};
|
||||
const accountPubkey = "a".repeat(64);
|
||||
const contacts = ["b".repeat(64), "c".repeat(64)];
|
||||
const result = resolveFilterAliases(filter, accountPubkey, contacts);
|
||||
|
||||
// Should deduplicate all variants of $me to single pubkey
|
||||
expect(result.authors).toEqual([accountPubkey]);
|
||||
// Should deduplicate all variants of $contacts
|
||||
expect(result["#p"]).toEqual(contacts);
|
||||
});
|
||||
|
||||
it("should handle sloppy typing with whitespace-like patterns", () => {
|
||||
const filter: NostrFilter = {
|
||||
authors: ["$ME", "$me", "$Me"],
|
||||
"#P": ["$CONTACTS", "$contacts", "$Contacts"],
|
||||
};
|
||||
const accountPubkey = "a".repeat(64);
|
||||
const contacts = ["b".repeat(64), "c".repeat(64)];
|
||||
const result = resolveFilterAliases(filter, accountPubkey, contacts);
|
||||
|
||||
expect(result.authors?.length).toBe(1);
|
||||
expect(result.authors).toContain(accountPubkey);
|
||||
expect(result["#P"]).toEqual(contacts);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ export function getDisplayName(
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve $me and $contacts aliases in a Nostr filter
|
||||
* Resolve $me and $contacts aliases in a Nostr filter (case-insensitive)
|
||||
* @param filter - Filter that may contain $me or $contacts aliases
|
||||
* @param accountPubkey - Current user's pubkey (for $me resolution)
|
||||
* @param contacts - Array of contact pubkeys (for $contacts resolution)
|
||||
@@ -44,11 +44,12 @@ export function resolveFilterAliases(
|
||||
const resolvedAuthors: string[] = [];
|
||||
|
||||
for (const author of resolved.authors) {
|
||||
if (author === "$me") {
|
||||
const normalized = author.toLowerCase();
|
||||
if (normalized === "$me") {
|
||||
if (accountPubkey) {
|
||||
resolvedAuthors.push(accountPubkey);
|
||||
}
|
||||
} else if (author === "$contacts") {
|
||||
} else if (normalized === "$contacts") {
|
||||
resolvedAuthors.push(...contacts);
|
||||
} else {
|
||||
resolvedAuthors.push(author);
|
||||
@@ -64,11 +65,12 @@ export function resolveFilterAliases(
|
||||
const resolvedPTags: string[] = [];
|
||||
|
||||
for (const pTag of resolved["#p"]) {
|
||||
if (pTag === "$me") {
|
||||
const normalized = pTag.toLowerCase();
|
||||
if (normalized === "$me") {
|
||||
if (accountPubkey) {
|
||||
resolvedPTags.push(accountPubkey);
|
||||
}
|
||||
} else if (pTag === "$contacts") {
|
||||
} else if (normalized === "$contacts") {
|
||||
resolvedPTags.push(...contacts);
|
||||
} else {
|
||||
resolvedPTags.push(pTag);
|
||||
@@ -84,11 +86,12 @@ export function resolveFilterAliases(
|
||||
const resolvedPTagsUppercase: string[] = [];
|
||||
|
||||
for (const pTag of resolved["#P"]) {
|
||||
if (pTag === "$me") {
|
||||
const normalized = pTag.toLowerCase();
|
||||
if (normalized === "$me") {
|
||||
if (accountPubkey) {
|
||||
resolvedPTagsUppercase.push(accountPubkey);
|
||||
}
|
||||
} else if (pTag === "$contacts") {
|
||||
} else if (normalized === "$contacts") {
|
||||
resolvedPTagsUppercase.push(...contacts);
|
||||
} else {
|
||||
resolvedPTagsUppercase.push(pTag);
|
||||
|
||||
@@ -725,6 +725,41 @@ describe("parseReqCommand", () => {
|
||||
});
|
||||
});
|
||||
|
||||
describe("case-insensitive aliases", () => {
|
||||
it("should normalize $ME to $me in authors", () => {
|
||||
const result = parseReqCommand(["-a", "$ME"]);
|
||||
expect(result.filter.authors).toContain("$me");
|
||||
expect(result.needsAccount).toBe(true);
|
||||
});
|
||||
|
||||
it("should normalize $CONTACTS to $contacts in authors", () => {
|
||||
const result = parseReqCommand(["-a", "$CONTACTS"]);
|
||||
expect(result.filter.authors).toContain("$contacts");
|
||||
expect(result.needsAccount).toBe(true);
|
||||
});
|
||||
|
||||
it("should normalize mixed case $Me to $me in #p tags", () => {
|
||||
const result = parseReqCommand(["-p", "$Me"]);
|
||||
expect(result.filter["#p"]).toContain("$me");
|
||||
expect(result.needsAccount).toBe(true);
|
||||
});
|
||||
|
||||
it("should normalize $CONTACTS to $contacts in #P tags", () => {
|
||||
const result = parseReqCommand(["-P", "$CONTACTS"]);
|
||||
expect(result.filter["#P"]).toContain("$contacts");
|
||||
expect(result.needsAccount).toBe(true);
|
||||
});
|
||||
|
||||
it("should handle mixed case aliases with other values", () => {
|
||||
const hex = "a".repeat(64);
|
||||
const result = parseReqCommand(["-a", `$ME,${hex},$Contacts`]);
|
||||
expect(result.filter.authors).toContain("$me");
|
||||
expect(result.filter.authors).toContain("$contacts");
|
||||
expect(result.filter.authors).toContain(hex);
|
||||
expect(result.needsAccount).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe("$me alias in #p tags (-p)", () => {
|
||||
it("should detect $me in #p tags", () => {
|
||||
const result = parseReqCommand(["-p", "$me"]);
|
||||
|
||||
@@ -127,9 +127,10 @@ export function parseReqCommand(args: string[]): ParsedReqCommand {
|
||||
const values = nextArg.split(",").map((a) => a.trim());
|
||||
for (const authorStr of values) {
|
||||
if (!authorStr) continue;
|
||||
// Check for $me and $contacts aliases
|
||||
if (authorStr === "$me" || authorStr === "$contacts") {
|
||||
authors.add(authorStr);
|
||||
// Check for $me and $contacts aliases (case-insensitive)
|
||||
const normalized = authorStr.toLowerCase();
|
||||
if (normalized === "$me" || normalized === "$contacts") {
|
||||
authors.add(normalized);
|
||||
addedAny = true;
|
||||
} else if (isNip05(authorStr)) {
|
||||
// Check if it's a NIP-05 identifier
|
||||
@@ -188,9 +189,10 @@ export function parseReqCommand(args: string[]): ParsedReqCommand {
|
||||
const values = nextArg.split(",").map((p) => p.trim());
|
||||
for (const pubkeyStr of values) {
|
||||
if (!pubkeyStr) continue;
|
||||
// Check for $me and $contacts aliases
|
||||
if (pubkeyStr === "$me" || pubkeyStr === "$contacts") {
|
||||
pTags.add(pubkeyStr);
|
||||
// Check for $me and $contacts aliases (case-insensitive)
|
||||
const normalized = pubkeyStr.toLowerCase();
|
||||
if (normalized === "$me" || normalized === "$contacts") {
|
||||
pTags.add(normalized);
|
||||
addedAny = true;
|
||||
} else if (isNip05(pubkeyStr)) {
|
||||
// Check if it's a NIP-05 identifier
|
||||
@@ -223,9 +225,10 @@ export function parseReqCommand(args: string[]): ParsedReqCommand {
|
||||
const values = nextArg.split(",").map((p) => p.trim());
|
||||
for (const pubkeyStr of values) {
|
||||
if (!pubkeyStr) continue;
|
||||
// Check for $me and $contacts aliases
|
||||
if (pubkeyStr === "$me" || pubkeyStr === "$contacts") {
|
||||
pTagsUppercase.add(pubkeyStr);
|
||||
// Check for $me and $contacts aliases (case-insensitive)
|
||||
const normalized = pubkeyStr.toLowerCase();
|
||||
if (normalized === "$me" || normalized === "$contacts") {
|
||||
pTagsUppercase.add(normalized);
|
||||
addedAny = true;
|
||||
} else if (isNip05(pubkeyStr)) {
|
||||
// Check if it's a NIP-05 identifier
|
||||
|
||||
Reference in New Issue
Block a user