Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/database/models/document-meta.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ interface IDocumentMeta extends MongooseDocument {
ownerDid: string | null;
ownerIdentityDid: string | null;
portalAddress: string | null;
ddocId: string | null; // on-chain id when documentId is an opaque o- id; owner-only, never emitted
ddocId: string | null; // on-chain id when documentId is an opaque link id; owner-only, never emitted
appType?: "ddoc" | "dsheet";
editLock: string | null; // roomKey-wrapped
title: string | null; // roomKey-encrypted
Expand Down
9 changes: 6 additions & 3 deletions src/services/mongodb-store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,15 @@ const HYDRATION_SLOW_MS = 500;
const HYDRATION_LARGE_BYTES = 2 * 1024 * 1024;
const HYDRATION_LARGE_ROWS = 2_000;

// An opaque link id, by exact shape: addresses, hashes and on-chain ids can also start with 0x.
const LINK_ID_RE = /^0x[1-9A-HJ-NP-Za-km-z]{18}$/;

export const acceptedDdocId = (documentId: string, ddocId: unknown): string | null =>
typeof ddocId === "string" &&
ddocId.length > 0 &&
ddocId.length <= 64 &&
documentId.startsWith("o-") &&
!ddocId.startsWith("o-")
LINK_ID_RE.test(documentId) &&
!LINK_ID_RE.test(ddocId)
? ddocId
: null;

Expand Down Expand Up @@ -528,7 +531,7 @@ export class MongoDBStore {
const rows: any[] = await DocumentMetaModel.find({
isPublished: { $ne: true },
portalAddress: { $ne: null },
$or: [{ _id: { $not: /^o-/ } }, { ddocId: { $ne: null } }],
$or: [{ _id: { $not: LINK_ID_RE } }, { ddocId: { $ne: null } }],
})
.select("portalAddress ddocId")
.sort({ updatedAt: -1 })
Expand Down
29 changes: 27 additions & 2 deletions src/tests/services/mongodb-store.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { describe, it, expect, vi, beforeEach } from "vitest";
import { DocumentUpdateModel } from "../../database/models/document-update";
import { CounterModel } from "../../database/models/counter";
import { MongoDBStore, SessionTerminatedError } from "../../services/mongodb-store";
import { MongoDBStore, SessionTerminatedError, acceptedDdocId } from "../../services/mongodb-store";

vi.mock("../../database/models", () => {
const save = vi.fn().mockResolvedValue(undefined);
Expand Down Expand Up @@ -313,7 +313,7 @@ describe("listDocumentsForOwner", () => {
expect(DocumentMetaModel.find).toHaveBeenCalledWith({
isPublished: { $ne: true },
portalAddress: { $ne: null },
$or: [{ _id: { $not: /^o-/ } }, { ddocId: { $ne: null } }],
$or: [{ _id: { $not: /^0x[1-9A-HJ-NP-Za-km-z]{18}$/ } }, { ddocId: { $ne: null } }],
});
expect(sort).toHaveBeenCalledWith({ updatedAt: -1 });
expect(limit).toHaveBeenCalledWith(500);
Expand Down Expand Up @@ -794,3 +794,28 @@ describe("lockWireFormat: duplicate-key race", () => {
await expect(store.lockWireFormat("doc-1")).resolves.toBe(false);
});
});

describe("acceptedDdocId", () => {
const LINK_ID = "0x" + "Zk".repeat(9);
const DDOC_ID = "7sLHvGNqsvNDhRm8tPKZSu";

it("keeps the on-chain id for a room named by a link id", () => {
expect(acceptedDdocId(LINK_ID, DDOC_ID)).toBe(DDOC_ID);
});

it("keeps an on-chain id that itself starts with 0x", () => {
expect(acceptedDdocId(LINK_ID, "0xabc")).toBe("0xabc");
});

it("refuses a link id as the on-chain id", () => {
expect(acceptedDdocId(LINK_ID, "0x" + "Gh".repeat(9))).toBeNull();
});

it.each([
["a plain room", DDOC_ID],
["a room named by an address", "0x" + "a1".repeat(20)],
["a room with the old o- prefix", "o-" + "Zk".repeat(9)],
])("stores nothing for %s", (_, documentId) => {
expect(acceptedDdocId(documentId, DDOC_ID)).toBeNull();
});
});
Loading