mirror of
https://github.com/moltbot/moltbot.git
synced 2026-04-27 00:17:29 +00:00
Merged via squash.
Prepared head SHA: b0495dc6ca
Co-authored-by: MoerAI <26067127+MoerAI@users.noreply.github.com>
Co-authored-by: gumadeiras <5599352+gumadeiras@users.noreply.github.com>
Reviewed-by: @gumadeiras
This commit is contained in:
@@ -49,6 +49,7 @@ describe("matrix account path propagation", () => {
|
||||
homeserver: "https://matrix.example.org",
|
||||
userId: "@poe:example.org",
|
||||
accessToken: "poe-token",
|
||||
deviceId: "POEDEVICE",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -66,7 +67,7 @@ describe("matrix account path propagation", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("forwards accountId to matrix probes", async () => {
|
||||
it("forwards accountId and deviceId to matrix probes", async () => {
|
||||
await matrixPlugin.status!.probeAccount?.({
|
||||
cfg: {} as never,
|
||||
timeoutMs: 500,
|
||||
@@ -83,6 +84,7 @@ describe("matrix account path propagation", () => {
|
||||
homeserver: "https://matrix.example.org",
|
||||
accessToken: "poe-token",
|
||||
userId: "@poe:example.org",
|
||||
deviceId: "POEDEVICE",
|
||||
timeoutMs: 500,
|
||||
accountId: "poe",
|
||||
});
|
||||
|
||||
@@ -498,6 +498,7 @@ export const matrixPlugin: ChannelPlugin<ResolvedMatrixAccount, MatrixProbe> =
|
||||
homeserver: auth.homeserver,
|
||||
accessToken: auth.accessToken,
|
||||
userId: auth.userId,
|
||||
deviceId: auth.deviceId,
|
||||
timeoutMs,
|
||||
accountId: account.accountId,
|
||||
allowPrivateNetwork: auth.allowPrivateNetwork,
|
||||
|
||||
115
extensions/matrix/src/matrix/client/create-client.test.ts
Normal file
115
extensions/matrix/src/matrix/client/create-client.test.ts
Normal file
@@ -0,0 +1,115 @@
|
||||
import { beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const ensureMatrixSdkLoggingConfiguredMock = vi.hoisted(() => vi.fn());
|
||||
const resolveValidatedMatrixHomeserverUrlMock = vi.hoisted(() => vi.fn());
|
||||
const maybeMigrateLegacyStorageMock = vi.hoisted(() => vi.fn(async () => undefined));
|
||||
const resolveMatrixStoragePathsMock = vi.hoisted(() => vi.fn());
|
||||
const writeStorageMetaMock = vi.hoisted(() => vi.fn());
|
||||
const MatrixClientMock = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("./logging.js", () => ({
|
||||
ensureMatrixSdkLoggingConfigured: ensureMatrixSdkLoggingConfiguredMock,
|
||||
}));
|
||||
|
||||
vi.mock("./config.js", () => ({
|
||||
resolveValidatedMatrixHomeserverUrl: resolveValidatedMatrixHomeserverUrlMock,
|
||||
}));
|
||||
|
||||
vi.mock("./storage.js", () => ({
|
||||
maybeMigrateLegacyStorage: maybeMigrateLegacyStorageMock,
|
||||
resolveMatrixStoragePaths: resolveMatrixStoragePathsMock,
|
||||
writeStorageMeta: writeStorageMetaMock,
|
||||
}));
|
||||
|
||||
vi.mock("../sdk.js", () => ({
|
||||
MatrixClient: MatrixClientMock,
|
||||
}));
|
||||
|
||||
let createMatrixClient: typeof import("./create-client.js").createMatrixClient;
|
||||
|
||||
describe("createMatrixClient", () => {
|
||||
const storagePaths = {
|
||||
rootDir: "/tmp/openclaw-matrix-create-client-test",
|
||||
storagePath: "/tmp/openclaw-matrix-create-client-test/storage.json",
|
||||
recoveryKeyPath: "/tmp/openclaw-matrix-create-client-test/recovery.key",
|
||||
idbSnapshotPath: "/tmp/openclaw-matrix-create-client-test/idb.snapshot",
|
||||
metaPath: "/tmp/openclaw-matrix-create-client-test/storage-meta.json",
|
||||
accountKey: "default",
|
||||
tokenHash: "token-hash",
|
||||
};
|
||||
|
||||
beforeAll(async () => {
|
||||
({ createMatrixClient } = await import("./create-client.js"));
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks();
|
||||
ensureMatrixSdkLoggingConfiguredMock.mockReturnValue(undefined);
|
||||
resolveValidatedMatrixHomeserverUrlMock.mockResolvedValue("https://matrix.example.org");
|
||||
resolveMatrixStoragePathsMock.mockReturnValue(storagePaths);
|
||||
MatrixClientMock.mockImplementation(function MockMatrixClient() {
|
||||
return {
|
||||
stop: vi.fn(),
|
||||
};
|
||||
});
|
||||
});
|
||||
|
||||
it("persists storage metadata by default", async () => {
|
||||
await createMatrixClient({
|
||||
homeserver: "https://matrix.example.org",
|
||||
userId: "@bot:example.org",
|
||||
accessToken: "tok",
|
||||
});
|
||||
|
||||
expect(writeStorageMetaMock).toHaveBeenCalledWith({
|
||||
storagePaths,
|
||||
homeserver: "https://matrix.example.org",
|
||||
userId: "@bot:example.org",
|
||||
accountId: undefined,
|
||||
deviceId: undefined,
|
||||
});
|
||||
expect(resolveMatrixStoragePathsMock).toHaveBeenCalledTimes(1);
|
||||
expect(MatrixClientMock).toHaveBeenCalledWith("https://matrix.example.org", "tok", {
|
||||
userId: "@bot:example.org",
|
||||
password: undefined,
|
||||
deviceId: undefined,
|
||||
encryption: undefined,
|
||||
localTimeoutMs: undefined,
|
||||
initialSyncLimit: undefined,
|
||||
storagePath: storagePaths.storagePath,
|
||||
recoveryKeyPath: storagePaths.recoveryKeyPath,
|
||||
idbSnapshotPath: storagePaths.idbSnapshotPath,
|
||||
cryptoDatabasePrefix: "openclaw-matrix-default-token-hash",
|
||||
autoBootstrapCrypto: undefined,
|
||||
ssrfPolicy: undefined,
|
||||
dispatcherPolicy: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("skips persistent storage wiring when persistence is disabled", async () => {
|
||||
await createMatrixClient({
|
||||
homeserver: "https://matrix.example.org",
|
||||
userId: "@bot:example.org",
|
||||
accessToken: "tok",
|
||||
persistStorage: false,
|
||||
});
|
||||
|
||||
expect(resolveMatrixStoragePathsMock).not.toHaveBeenCalled();
|
||||
expect(writeStorageMetaMock).not.toHaveBeenCalled();
|
||||
expect(MatrixClientMock).toHaveBeenCalledWith("https://matrix.example.org", "tok", {
|
||||
userId: "@bot:example.org",
|
||||
password: undefined,
|
||||
deviceId: undefined,
|
||||
encryption: undefined,
|
||||
localTimeoutMs: undefined,
|
||||
initialSyncLimit: undefined,
|
||||
storagePath: undefined,
|
||||
recoveryKeyPath: undefined,
|
||||
idbSnapshotPath: undefined,
|
||||
cryptoDatabasePrefix: undefined,
|
||||
autoBootstrapCrypto: undefined,
|
||||
ssrfPolicy: undefined,
|
||||
dispatcherPolicy: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -33,6 +33,7 @@ export async function createMatrixClient(params: {
|
||||
accessToken: string;
|
||||
password?: string;
|
||||
deviceId?: string;
|
||||
persistStorage?: boolean;
|
||||
encryption?: boolean;
|
||||
localTimeoutMs?: number;
|
||||
initialSyncLimit?: number;
|
||||
@@ -45,36 +46,41 @@ export async function createMatrixClient(params: {
|
||||
const { MatrixClient, ensureMatrixSdkLoggingConfigured } =
|
||||
await loadMatrixCreateClientRuntimeDeps();
|
||||
ensureMatrixSdkLoggingConfigured();
|
||||
const env = process.env;
|
||||
const homeserver = await resolveValidatedMatrixHomeserverUrl(params.homeserver, {
|
||||
dangerouslyAllowPrivateNetwork: params.allowPrivateNetwork,
|
||||
});
|
||||
const userId = params.userId?.trim() || "unknown";
|
||||
const matrixClientUserId = params.userId?.trim() || undefined;
|
||||
const persistStorage = params.persistStorage !== false;
|
||||
const storagePaths = persistStorage
|
||||
? resolveMatrixStoragePaths({
|
||||
homeserver,
|
||||
userId,
|
||||
accessToken: params.accessToken,
|
||||
accountId: params.accountId,
|
||||
deviceId: params.deviceId,
|
||||
env: process.env,
|
||||
})
|
||||
: null;
|
||||
|
||||
const storagePaths = resolveMatrixStoragePaths({
|
||||
homeserver,
|
||||
userId,
|
||||
accessToken: params.accessToken,
|
||||
accountId: params.accountId,
|
||||
deviceId: params.deviceId,
|
||||
env,
|
||||
});
|
||||
await maybeMigrateLegacyStorage({
|
||||
storagePaths,
|
||||
env,
|
||||
});
|
||||
fs.mkdirSync(storagePaths.rootDir, { recursive: true });
|
||||
if (storagePaths) {
|
||||
await maybeMigrateLegacyStorage({
|
||||
storagePaths,
|
||||
env: process.env,
|
||||
});
|
||||
fs.mkdirSync(storagePaths.rootDir, { recursive: true });
|
||||
writeStorageMeta({
|
||||
storagePaths,
|
||||
homeserver,
|
||||
userId,
|
||||
accountId: params.accountId,
|
||||
deviceId: params.deviceId,
|
||||
});
|
||||
}
|
||||
|
||||
writeStorageMeta({
|
||||
storagePaths,
|
||||
homeserver,
|
||||
userId,
|
||||
accountId: params.accountId,
|
||||
deviceId: params.deviceId,
|
||||
});
|
||||
|
||||
const cryptoDatabasePrefix = `openclaw-matrix-${storagePaths.accountKey}-${storagePaths.tokenHash}`;
|
||||
const cryptoDatabasePrefix = storagePaths
|
||||
? `openclaw-matrix-${storagePaths.accountKey}-${storagePaths.tokenHash}`
|
||||
: undefined;
|
||||
|
||||
return new MatrixClient(homeserver, params.accessToken, {
|
||||
userId: matrixClientUserId,
|
||||
@@ -83,9 +89,9 @@ export async function createMatrixClient(params: {
|
||||
encryption: params.encryption,
|
||||
localTimeoutMs: params.localTimeoutMs,
|
||||
initialSyncLimit: params.initialSyncLimit,
|
||||
storagePath: storagePaths.storagePath,
|
||||
recoveryKeyPath: storagePaths.recoveryKeyPath,
|
||||
idbSnapshotPath: storagePaths.idbSnapshotPath,
|
||||
storagePath: storagePaths?.storagePath,
|
||||
recoveryKeyPath: storagePaths?.recoveryKeyPath,
|
||||
idbSnapshotPath: storagePaths?.idbSnapshotPath,
|
||||
cryptoDatabasePrefix,
|
||||
autoBootstrapCrypto: params.autoBootstrapCrypto,
|
||||
ssrfPolicy: params.ssrfPolicy,
|
||||
|
||||
@@ -34,6 +34,7 @@ describe("probeMatrix", () => {
|
||||
homeserver: "https://matrix.example.org",
|
||||
userId: undefined,
|
||||
accessToken: "tok",
|
||||
persistStorage: false,
|
||||
localTimeoutMs: 1234,
|
||||
});
|
||||
});
|
||||
@@ -50,6 +51,7 @@ describe("probeMatrix", () => {
|
||||
homeserver: "https://matrix.example.org",
|
||||
userId: "@bot:example.org",
|
||||
accessToken: "tok",
|
||||
persistStorage: false,
|
||||
localTimeoutMs: 500,
|
||||
});
|
||||
});
|
||||
@@ -67,6 +69,7 @@ describe("probeMatrix", () => {
|
||||
homeserver: "https://matrix.example.org",
|
||||
userId: "@bot:example.org",
|
||||
accessToken: "tok",
|
||||
persistStorage: false,
|
||||
localTimeoutMs: 500,
|
||||
accountId: "ops",
|
||||
});
|
||||
@@ -87,6 +90,7 @@ describe("probeMatrix", () => {
|
||||
homeserver: "https://matrix.example.org",
|
||||
userId: undefined,
|
||||
accessToken: "tok",
|
||||
persistStorage: false,
|
||||
localTimeoutMs: 500,
|
||||
dispatcherPolicy: {
|
||||
mode: "explicit-proxy",
|
||||
@@ -95,6 +99,44 @@ describe("probeMatrix", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("passes deviceId through to client creation (#61317)", async () => {
|
||||
await probeMatrix({
|
||||
homeserver: "https://matrix.example.org",
|
||||
accessToken: "tok",
|
||||
userId: "@bot:example.org",
|
||||
deviceId: "ABCDEF",
|
||||
timeoutMs: 500,
|
||||
accountId: "ops",
|
||||
});
|
||||
|
||||
expect(createMatrixClientMock).toHaveBeenCalledWith({
|
||||
homeserver: "https://matrix.example.org",
|
||||
userId: "@bot:example.org",
|
||||
accessToken: "tok",
|
||||
deviceId: "ABCDEF",
|
||||
persistStorage: false,
|
||||
localTimeoutMs: 500,
|
||||
accountId: "ops",
|
||||
});
|
||||
});
|
||||
|
||||
it("omits deviceId when not provided", async () => {
|
||||
await probeMatrix({
|
||||
homeserver: "https://matrix.example.org",
|
||||
accessToken: "tok",
|
||||
timeoutMs: 500,
|
||||
});
|
||||
|
||||
expect(createMatrixClientMock).toHaveBeenCalledWith({
|
||||
homeserver: "https://matrix.example.org",
|
||||
userId: undefined,
|
||||
accessToken: "tok",
|
||||
deviceId: undefined,
|
||||
persistStorage: false,
|
||||
localTimeoutMs: 500,
|
||||
});
|
||||
});
|
||||
|
||||
it("returns client validation errors for insecure public http homeservers", async () => {
|
||||
createMatrixClientMock.mockRejectedValue(
|
||||
new Error("Matrix homeserver must use https:// unless it targets a private or loopback host"),
|
||||
|
||||
@@ -24,6 +24,7 @@ export async function probeMatrix(params: {
|
||||
homeserver: string;
|
||||
accessToken: string;
|
||||
userId?: string;
|
||||
deviceId?: string;
|
||||
timeoutMs: number;
|
||||
accountId?: string | null;
|
||||
allowPrivateNetwork?: boolean;
|
||||
@@ -65,6 +66,8 @@ export async function probeMatrix(params: {
|
||||
homeserver: params.homeserver,
|
||||
userId: inputUserId,
|
||||
accessToken: params.accessToken,
|
||||
deviceId: params.deviceId,
|
||||
persistStorage: false,
|
||||
localTimeoutMs: params.timeoutMs,
|
||||
accountId: params.accountId,
|
||||
allowPrivateNetwork: params.allowPrivateNetwork,
|
||||
|
||||
Reference in New Issue
Block a user