mx-puppet-bridge
Advanced tools
Comparing version 0.0.20 to 0.0.21
@@ -12,2 +12,3 @@ /// <reference types="node" /> | ||
topic?: string | null; | ||
groupId?: string | null; | ||
isDirect?: boolean | null; | ||
@@ -14,0 +15,0 @@ } |
@@ -79,2 +79,4 @@ "use strict"; | ||
let created = false; | ||
let removeGroup; | ||
let addGroup; | ||
if (!chan) { | ||
@@ -128,3 +130,5 @@ if (!doCreate) { | ||
log.verbose("Uploading initial room avatar..."); | ||
const { doUpdate: doUpdateAvatar, mxcUrl, hash } = yield util_1.Util.MaybeUploadFile(client, data); | ||
const { doUpdate: doUpdateAvatar, mxcUrl, hash } = yield util_1.Util.MaybeUploadFile((buffer, mimetype, filename) => __awaiter(this, void 0, void 0, function* () { | ||
return yield this.bridge.uploadContent(client, buffer, mimetype, filename); | ||
}), data); | ||
updateAvatar = doUpdateAvatar; | ||
@@ -161,2 +165,6 @@ if (updateAvatar) { | ||
} | ||
if (data.groupId) { | ||
chan.groupId = data.groupId; | ||
addGroup = chan.groupId; | ||
} | ||
created = true; | ||
@@ -179,3 +187,5 @@ } | ||
log.verbose("Updating avatar"); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = yield util_1.Util.MaybeUploadFile(client, data, chan.avatarHash); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = yield util_1.Util.MaybeUploadFile((buffer, mimetype, filename) => __awaiter(this, void 0, void 0, function* () { | ||
return yield this.bridge.uploadContent(client, buffer, mimetype, filename); | ||
}), data, chan.avatarHash); | ||
if (updateAvatar) { | ||
@@ -195,2 +205,8 @@ doUpdate = true; | ||
} | ||
if (data.groupId !== undefined && data.groupId !== chan.groupId) { | ||
doUpdate = true; | ||
removeGroup = chan.groupId; | ||
addGroup = data.groupId; | ||
chan.groupId = data.groupId; | ||
} | ||
} | ||
@@ -202,2 +218,20 @@ if (doUpdate) { | ||
this.mxidLock.release(lockKey); | ||
// update associated group only after releasing the lock | ||
if (this.bridge.groupSyncEnabled) { | ||
if (removeGroup) { | ||
yield this.bridge.groupSync.removeRoomFromGroup({ | ||
groupId: removeGroup, | ||
puppetId: chan.puppetId, | ||
}, chan.roomId); | ||
} | ||
if (addGroup) { | ||
yield this.bridge.groupSync.addRoomToGroup({ | ||
groupId: addGroup, | ||
puppetId: chan.puppetId, | ||
}, chan.roomId); | ||
} | ||
} | ||
else { | ||
log.verbose("Group sync is disabled"); | ||
} | ||
log.verbose("Returning mxid"); | ||
@@ -204,0 +238,0 @@ return { mxid, created }; |
@@ -27,2 +27,3 @@ export declare class MxBridgeConfig { | ||
avatarUrl?: string; | ||
enableGroupSync: boolean; | ||
} | ||
@@ -29,0 +30,0 @@ export declare class MxBridgeConfigLogging { |
@@ -29,2 +29,3 @@ "use strict"; | ||
this.loginSharedSecretMap = {}; | ||
this.enableGroupSync = true; | ||
} | ||
@@ -31,0 +32,0 @@ } |
@@ -11,2 +11,3 @@ import { IDatabaseConnector } from "./connector"; | ||
topic?: string | null; | ||
groupId?: string | null; | ||
} | ||
@@ -13,0 +14,0 @@ export declare class DbChanStore { |
@@ -82,3 +82,4 @@ "use strict"; | ||
avatar_hash, | ||
topic | ||
topic, | ||
group_id | ||
) VALUES ( | ||
@@ -92,3 +93,4 @@ $mxid, | ||
$avatar_hash, | ||
$topic | ||
$topic, | ||
$group_id | ||
)`; | ||
@@ -104,3 +106,4 @@ } | ||
avatar_hash = $avatar_hash, | ||
topic = $topic | ||
topic = $topic, | ||
group_id = $group_id | ||
WHERE mxid = $mxid`; | ||
@@ -117,2 +120,3 @@ } | ||
topic: data.topic || null, | ||
group_id: data.groupId || null, | ||
}); | ||
@@ -180,2 +184,3 @@ this.remoteCache.set(`${data.puppetId};${data.roomId}`, data); | ||
data.topic = row.topic; | ||
data.groupId = row.group_id; | ||
this.remoteCache.set(`${data.puppetId};${data.roomId}`, data); | ||
@@ -182,0 +187,0 @@ this.mxidCache.set(data.mxid, data); |
@@ -7,4 +7,5 @@ export * from "./puppetbridge"; | ||
export { IRemoteUser } from "./usersyncroniser"; | ||
export { IRemoteGroup } from "./groupsyncroniser"; | ||
export { Store } from "./store"; | ||
export { IDbSchema } from "./db/schema/dbschema"; | ||
export { ICommand, SendMessageFn } from "./botprovisioner"; |
/// <reference types="node" /> | ||
import { Appservice, Intent } from "matrix-bot-sdk"; | ||
import { Appservice, Intent, MatrixClient } from "matrix-bot-sdk"; | ||
import { EventEmitter } from "events"; | ||
import { ChannelSyncroniser, IRemoteChan } from "./channelsyncroniser"; | ||
import { UserSyncroniser, IRemoteUser } from "./usersyncroniser"; | ||
import { GroupSyncroniser, IRemoteGroup } from "./groupsyncroniser"; | ||
import { MxBridgeConfig } from "./config"; | ||
import { DbUserStore } from "./db/userstore"; | ||
import { DbChanStore } from "./db/chanstore"; | ||
import { DbGroupStore } from "./db/groupstore"; | ||
import { DbPuppetStore, IMxidInfo } from "./db/puppetstore"; | ||
@@ -77,2 +79,3 @@ import { DbEventStore } from "./db/eventstore"; | ||
export declare type CreateUserHook = (user: IRemoteUser) => Promise<IRemoteUser | null>; | ||
export declare type CreateGroupHook = (group: IRemoteGroup) => Promise<IRemoteGroup | null>; | ||
export declare type GetDescHook = (puppetId: number, data: any) => Promise<string>; | ||
@@ -87,2 +90,3 @@ export declare type BotHeaderMsgHook = () => string; | ||
createUser?: CreateUserHook; | ||
createGroup?: CreateGroupHook; | ||
getDesc?: GetDescHook; | ||
@@ -101,2 +105,3 @@ botHeaderMsg?: BotHeaderMsgHook; | ||
userSync: UserSyncroniser; | ||
groupSync: GroupSyncroniser; | ||
hooks: IPuppetBridgeHooks; | ||
@@ -121,8 +126,11 @@ config: MxBridgeConfig; | ||
get chanStore(): DbChanStore; | ||
get groupStore(): DbGroupStore; | ||
get puppetStore(): DbPuppetStore; | ||
get eventStore(): DbEventStore; | ||
get Config(): MxBridgeConfig; | ||
get groupSyncEnabled(): boolean; | ||
start(): Promise<void>; | ||
setCreateChanHook(hook: CreateChanHook): void; | ||
setCreateUserHook(hook: CreateUserHook): void; | ||
setCreateGroupHook(hook: CreateGroupHook): void; | ||
setGetDescHook(hook: GetDescHook): void; | ||
@@ -138,2 +146,3 @@ setBotHeaderMsgHook(hook: BotHeaderMsgHook): void; | ||
updateChannel(chan: IRemoteChan): Promise<void>; | ||
updateGroup(group: IRemoteGroup): Promise<void>; | ||
bridgeChannel(chan: IRemoteChan): Promise<void>; | ||
@@ -163,2 +172,3 @@ unbridgeChannelByMxid(mxid: string): Promise<void>; | ||
getRoomMemberInfo(roomId: string, userId: string): Promise<IMemberInfo>; | ||
uploadContent(client: MatrixClient, thing: string | Buffer, mimetype?: string, filename?: string): Promise<string>; | ||
private getRoomDisplaynameCache; | ||
@@ -165,0 +175,0 @@ private updateCachedRoomMemberInfo; |
@@ -20,2 +20,3 @@ "use strict"; | ||
const usersyncroniser_1 = require("./usersyncroniser"); | ||
const groupsyncroniser_1 = require("./groupsyncroniser"); | ||
const config_1 = require("./config"); | ||
@@ -65,2 +66,3 @@ const util_1 = require("./util"); | ||
this.userSync = new usersyncroniser_1.UserSyncroniser(this); | ||
this.groupSync = new groupsyncroniser_1.GroupSyncroniser(this); | ||
this.provisioner = new provisioner_1.Provisioner(this); | ||
@@ -149,2 +151,5 @@ this.presenceHandler = new presencehandler_1.PresenceHandler(this); | ||
} | ||
get groupStore() { | ||
return this.store.groupStore; | ||
} | ||
get puppetStore() { | ||
@@ -159,2 +164,5 @@ return this.store.puppetStore; | ||
} | ||
get groupSyncEnabled() { | ||
return this.hooks.createGroup && this.config.bridge.enableGroupSync ? true : false; | ||
} | ||
start() { | ||
@@ -236,2 +244,5 @@ return __awaiter(this, void 0, void 0, function* () { | ||
} | ||
setCreateGroupHook(hook) { | ||
this.hooks.createGroup = hook; | ||
} | ||
setGetDescHook(hook) { | ||
@@ -277,2 +288,8 @@ this.hooks.getDesc = hook; | ||
} | ||
updateGroup(group) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
log.verbose("Got request to update a group"); | ||
yield this.groupSync.getMxid(group, false); | ||
}); | ||
} | ||
bridgeChannel(chan) { | ||
@@ -621,2 +638,41 @@ return __awaiter(this, void 0, void 0, function* () { | ||
} | ||
uploadContent(client, thing, mimetype, filename) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let buffer; | ||
if (typeof thing === "string") { | ||
const maybeMxcUrl = yield this.store.getFileMxc(thing); | ||
if (maybeMxcUrl) { | ||
return maybeMxcUrl; | ||
} | ||
if (!filename) { | ||
const matches = thing.match(/\/([^\.\/]+\.[a-zA-Z0-9]+)(?:$|\?)/); | ||
if (matches) { | ||
filename = matches[1]; | ||
} | ||
} | ||
buffer = yield util_1.Util.DownloadFile(thing); | ||
} | ||
else { | ||
buffer = thing; | ||
} | ||
{ | ||
const maybeMxcUrl = yield this.store.getFileMxc(buffer); | ||
if (maybeMxcUrl) { | ||
return maybeMxcUrl; | ||
} | ||
} | ||
if (!filename) { | ||
filename = "file"; | ||
} | ||
if (!mimetype) { | ||
mimetype = util_1.Util.GetMimeType(buffer); | ||
} | ||
const mxcUrl = yield client.uploadContent(buffer, mimetype, filename); | ||
if (typeof thing === "string") { | ||
yield this.store.setFileMxc(thing, mxcUrl, filename); | ||
} | ||
yield this.store.setFileMxc(buffer, mxcUrl, filename); | ||
return mxcUrl; | ||
}); | ||
} | ||
getRoomDisplaynameCache(roomId) { | ||
@@ -666,3 +722,3 @@ if (!(roomId in this.memberInfoCache)) { | ||
} | ||
const fileMxc = yield client.uploadContent(buffer, mimetype, name); | ||
const fileMxc = yield this.uploadContent(client, buffer, mimetype, name); | ||
const info = { | ||
@@ -902,3 +958,4 @@ mimetype, | ||
} | ||
const puppetMxid = yield this.provisioner.getMxid(room.puppetId); | ||
const puppetData = yield this.provisioner.get(room.puppetId); | ||
const puppetMxid = puppetData ? puppetData.puppetMxid : ""; | ||
if (event.sender !== puppetMxid) { | ||
@@ -910,2 +967,6 @@ if (!this.config.relay.enabled || !this.provisioner.canRelay(event.sender)) { | ||
} | ||
const delayedKey = `${puppetMxid}_${roomId}`; | ||
this.delayedFunction.set(delayedKey, () => __awaiter(this, void 0, void 0, function* () { | ||
yield this.chanSync.maybeLeaveGhost(roomId, puppetMxid); | ||
}), GHOST_PUPPET_LEAVE_TIMEOUT, false); | ||
log.info(`New message by ${event.sender} of type ${event.type} to process!`); | ||
@@ -912,0 +973,0 @@ if (event.content.source === "remote") { |
@@ -0,1 +1,2 @@ | ||
/// <reference types="node" /> | ||
import { IDbSchema } from "./db/schema/dbschema"; | ||
@@ -5,6 +6,7 @@ import { MxBridgeConfigDatabase } from "./config"; | ||
import { DbChanStore } from "./db/chanstore"; | ||
import { DbGroupStore } from "./db/groupstore"; | ||
import { DbPuppetStore } from "./db/puppetstore"; | ||
import { DbEventStore } from "./db/eventstore"; | ||
import { IDatabaseConnector } from "./db/connector"; | ||
export declare const CURRENT_SCHEMA = 6; | ||
export declare const CURRENT_SCHEMA = 8; | ||
declare type GetSchemaClass = (version: number) => IDbSchema; | ||
@@ -16,2 +18,3 @@ export declare class Store { | ||
private pUserStore; | ||
private pGroupStore; | ||
private pPuppetStore; | ||
@@ -22,2 +25,3 @@ private pEventStore; | ||
get userStore(): DbUserStore; | ||
get groupStore(): DbGroupStore; | ||
get puppetStore(): DbPuppetStore; | ||
@@ -27,2 +31,4 @@ get eventStore(): DbEventStore; | ||
close(): Promise<void>; | ||
getFileMxc(thing: string | Buffer): Promise<string | null>; | ||
setFileMxc(thing: string | Buffer, mxcUrl: string, filename?: string): Promise<void>; | ||
createTable(statement: string, tablename: string): Promise<void>; | ||
@@ -29,0 +35,0 @@ private getSchemaVersion; |
@@ -17,6 +17,8 @@ "use strict"; | ||
const chanstore_1 = require("./db/chanstore"); | ||
const groupstore_1 = require("./db/groupstore"); | ||
const puppetstore_1 = require("./db/puppetstore"); | ||
const eventstore_1 = require("./db/eventstore"); | ||
const util_1 = require("./util"); | ||
const log = new log_1.Log("Store"); | ||
exports.CURRENT_SCHEMA = 6; | ||
exports.CURRENT_SCHEMA = 8; | ||
class Store { | ||
@@ -32,2 +34,5 @@ constructor(config) { | ||
} | ||
get groupStore() { | ||
return this.pGroupStore; | ||
} | ||
get puppetStore() { | ||
@@ -83,2 +88,36 @@ return this.pPuppetStore; | ||
} | ||
getFileMxc(thing) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let key = ""; | ||
if (typeof thing === "string") { | ||
key = thing; | ||
} | ||
else { | ||
key = util_1.Util.HashBuffer(thing); | ||
} | ||
const ret = yield this.db.Get("SELECT mxc_url FROM file_mxc_map WHERE thing = $key", { key }); | ||
if (!ret) { | ||
return null; | ||
} | ||
return ret.mxc_url; | ||
}); | ||
} | ||
setFileMxc(thing, mxcUrl, filename) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
let key = ""; | ||
if (typeof thing === "string") { | ||
key = thing; | ||
} | ||
else { | ||
key = util_1.Util.HashBuffer(thing); | ||
} | ||
if ((yield this.getFileMxc(key))) { | ||
return; // nothing to do | ||
} | ||
if (!filename) { | ||
filename = ""; | ||
} | ||
yield this.db.Run("INSERT INTO file_mxc_map (thing, mxc_url, filename) VALUES ($key, $mxcUrl, $filename)", { key, mxcUrl, filename }); | ||
}); | ||
} | ||
createTable(statement, tablename) { | ||
@@ -137,2 +176,3 @@ return __awaiter(this, void 0, void 0, function* () { | ||
this.pUserStore = new userstore_1.DbUserStore(this.db); | ||
this.pGroupStore = new groupstore_1.DbGroupStore(this.db); | ||
this.pPuppetStore = new puppetstore_1.DbPuppetStore(this.db); | ||
@@ -139,0 +179,0 @@ this.pEventStore = new eventstore_1.DbEventStore(this.db); |
@@ -5,5 +5,5 @@ declare type DelayedFunctionFn = () => void | Promise<void>; | ||
constructor(); | ||
set(key: string, fn: DelayedFunctionFn, timeout: number): void; | ||
set(key: string, fn: DelayedFunctionFn, timeout: number, clearOldTimer?: boolean): void; | ||
release(key: string): void; | ||
} | ||
export {}; |
@@ -7,5 +7,10 @@ "use strict"; | ||
} | ||
set(key, fn, timeout) { | ||
// clear the old timeout | ||
this.release(key); | ||
set(key, fn, timeout, clearOldTimer = true) { | ||
if (clearOldTimer) { | ||
// clear the old timeout | ||
this.release(key); | ||
} | ||
else if (this.map.has(key)) { | ||
return; | ||
} | ||
// set the new timeout | ||
@@ -12,0 +17,0 @@ const i = setTimeout(() => { |
@@ -127,3 +127,5 @@ "use strict"; | ||
log.verbose("Updating avatar"); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = yield util_1.Util.MaybeUploadFile(client, data, user.avatarHash); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = yield util_1.Util.MaybeUploadFile((buffer, mimetype, filename) => __awaiter(this, void 0, void 0, function* () { | ||
return yield this.bridge.uploadContent(client, buffer, mimetype, filename); | ||
}), data, user.avatarHash); | ||
log.silly(`Should update avatar? ${updateAvatar}`); | ||
@@ -130,0 +132,0 @@ if (updateAvatar) { |
/// <reference types="node" /> | ||
import { MatrixClient } from "matrix-bot-sdk"; | ||
export interface IMakeUploadFileData { | ||
@@ -14,3 +13,4 @@ avatarUrl?: string | null; | ||
static AsyncForEach(arr: any, callback: any): Promise<void>; | ||
static MaybeUploadFile(client: MatrixClient, data: IMakeUploadFileData, oldHash?: string | null): Promise<{ | ||
static HashBuffer(b: Buffer): string; | ||
static MaybeUploadFile(uploadFn: (b: Buffer, m?: string, f?: string) => Promise<string>, data: IMakeUploadFileData, oldHash?: string | null): Promise<{ | ||
doUpdate: boolean; | ||
@@ -17,0 +17,0 @@ mxcUrl: string | undefined; |
@@ -105,3 +105,8 @@ "use strict"; | ||
} | ||
static MaybeUploadFile(client, data, oldHash) { | ||
static HashBuffer(b) { | ||
return hasha(b, { | ||
algorithm: "sha512", | ||
}); | ||
} | ||
static MaybeUploadFile(uploadFn, data, oldHash) { | ||
return __awaiter(this, void 0, void 0, function* () { | ||
@@ -124,5 +129,3 @@ let buffer = data.avatarBuffer; | ||
} | ||
const hash = hasha(buffer, { | ||
algorithm: "sha512", | ||
}); | ||
const hash = Util.HashBuffer(buffer); | ||
if (hash === oldHash) { | ||
@@ -143,3 +146,3 @@ // image didn't change, short-circuit out of here | ||
} | ||
const avatarMxc = yield client.uploadContent(buffer, Util.GetMimeType(buffer), filename); | ||
const avatarMxc = yield uploadFn(buffer, Util.GetMimeType(buffer), filename); | ||
return { | ||
@@ -146,0 +149,0 @@ doUpdate: true, |
{ | ||
"name": "mx-puppet-bridge", | ||
"version": "0.0.20", | ||
"version": "0.0.21", | ||
"description": "Matrix Puppeting Bridge library", | ||
@@ -27,3 +27,3 @@ "repository": { | ||
"markdown-it": "^9.1.0", | ||
"matrix-bot-sdk": "^0.4.0", | ||
"matrix-bot-sdk": "git+https://github.com/Sorunome/matrix-js-bot-sdk.git#98625ea857141ebed07f0c967a61985aa2bb28d3", | ||
"pg-promise": "^8.7.2", | ||
@@ -30,0 +30,0 @@ "request": "^2.88.0", |
@@ -22,2 +22,3 @@ import { PuppetBridge } from "./puppetbridge"; | ||
topic?: string | null; | ||
groupId?: string | null; | ||
isDirect?: boolean | null; | ||
@@ -91,2 +92,4 @@ } | ||
let created = false; | ||
let removeGroup: string | undefined | null; | ||
let addGroup: string | undefined | null; | ||
if (!chan) { | ||
@@ -140,3 +143,6 @@ if (!doCreate) { | ||
log.verbose("Uploading initial room avatar..."); | ||
const { doUpdate: doUpdateAvatar, mxcUrl, hash } = await Util.MaybeUploadFile(client!, data); | ||
const { doUpdate: doUpdateAvatar, mxcUrl, hash } = await Util.MaybeUploadFile( | ||
async (buffer: Buffer, mimetype?: string, filename?: string) => { | ||
return await this.bridge.uploadContent(client!, buffer, mimetype, filename); | ||
}, data); | ||
updateAvatar = doUpdateAvatar; | ||
@@ -173,2 +179,6 @@ if (updateAvatar) { | ||
} | ||
if (data.groupId) { | ||
chan.groupId = data.groupId; | ||
addGroup = chan.groupId; | ||
} | ||
created = true; | ||
@@ -196,3 +206,6 @@ } else { | ||
log.verbose("Updating avatar"); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = await Util.MaybeUploadFile(client!, data, chan.avatarHash); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = await Util.MaybeUploadFile( | ||
async (buffer: Buffer, mimetype?: string, filename?: string) => { | ||
return await this.bridge.uploadContent(client!, buffer, mimetype, filename); | ||
}, data, chan.avatarHash); | ||
if (updateAvatar) { | ||
@@ -222,2 +235,8 @@ doUpdate = true; | ||
} | ||
if (data.groupId !== undefined && data.groupId !== chan.groupId) { | ||
doUpdate = true; | ||
removeGroup = chan.groupId; | ||
addGroup = data.groupId; | ||
chan.groupId = data.groupId; | ||
} | ||
} | ||
@@ -232,2 +251,20 @@ | ||
// update associated group only after releasing the lock | ||
if (this.bridge.groupSyncEnabled) { | ||
if (removeGroup) { | ||
await this.bridge.groupSync.removeRoomFromGroup({ | ||
groupId: removeGroup, | ||
puppetId: chan.puppetId, | ||
}, chan.roomId); | ||
} | ||
if (addGroup) { | ||
await this.bridge.groupSync.addRoomToGroup({ | ||
groupId: addGroup, | ||
puppetId: chan.puppetId, | ||
}, chan.roomId); | ||
} | ||
} else { | ||
log.verbose("Group sync is disabled"); | ||
} | ||
log.verbose("Returning mxid"); | ||
@@ -234,0 +271,0 @@ return { mxid, created }; |
@@ -29,2 +29,3 @@ export class MxBridgeConfig { | ||
public avatarUrl?: string; | ||
public enableGroupSync: boolean = true; | ||
} | ||
@@ -31,0 +32,0 @@ |
@@ -19,2 +19,3 @@ import { IDatabaseConnector, ISqlRow } from "./connector"; | ||
topic?: string | null; | ||
groupId?: string | null; | ||
} | ||
@@ -95,3 +96,4 @@ | ||
avatar_hash, | ||
topic | ||
topic, | ||
group_id | ||
) VALUES ( | ||
@@ -105,3 +107,4 @@ $mxid, | ||
$avatar_hash, | ||
$topic | ||
$topic, | ||
$group_id | ||
)`; | ||
@@ -116,3 +119,4 @@ } else { | ||
avatar_hash = $avatar_hash, | ||
topic = $topic | ||
topic = $topic, | ||
group_id = $group_id | ||
WHERE mxid = $mxid`; | ||
@@ -129,2 +133,3 @@ } | ||
topic: data.topic || null, | ||
group_id: data.groupId || null, | ||
}); | ||
@@ -197,2 +202,3 @@ this.remoteCache.set(`${data.puppetId};${data.roomId}`, data); | ||
data.topic = row.topic as string | null; | ||
data.groupId = row.group_id as string | null; | ||
@@ -199,0 +205,0 @@ this.remoteCache.set(`${data.puppetId};${data.roomId}`, data); |
@@ -7,4 +7,5 @@ export * from "./puppetbridge"; | ||
export { IRemoteUser } from "./usersyncroniser"; | ||
export { IRemoteGroup } from "./groupsyncroniser"; | ||
export { Store } from "./store"; | ||
export { IDbSchema } from "./db/schema/dbschema"; | ||
export { ICommand, SendMessageFn } from "./botprovisioner"; |
@@ -16,2 +16,3 @@ import * as fs from "fs"; | ||
import { UserSyncroniser, IRemoteUser } from "./usersyncroniser"; | ||
import { GroupSyncroniser, IRemoteGroup } from "./groupsyncroniser"; | ||
import { MxBridgeConfig } from "./config"; | ||
@@ -22,2 +23,3 @@ import { Util } from "./util"; | ||
import { DbChanStore } from "./db/chanstore"; | ||
import { DbGroupStore } from "./db/groupstore"; | ||
import { DbPuppetStore, IMxidInfo } from "./db/puppetstore"; | ||
@@ -126,2 +128,3 @@ import { DbEventStore } from "./db/eventstore"; | ||
export type CreateUserHook = (user: IRemoteUser) => Promise<IRemoteUser | null>; | ||
export type CreateGroupHook = (group: IRemoteGroup) => Promise<IRemoteGroup | null>; | ||
export type GetDescHook = (puppetId: number, data: any) => Promise<string>; | ||
@@ -137,2 +140,3 @@ export type BotHeaderMsgHook = () => string; | ||
createUser?: CreateUserHook; | ||
createGroup?: CreateGroupHook; | ||
getDesc?: GetDescHook; | ||
@@ -149,2 +153,3 @@ botHeaderMsg?: BotHeaderMsgHook; | ||
public userSync: UserSyncroniser; | ||
public groupSync: GroupSyncroniser; | ||
public hooks: IPuppetBridgeHooks; | ||
@@ -191,2 +196,3 @@ public config: MxBridgeConfig; | ||
this.userSync = new UserSyncroniser(this); | ||
this.groupSync = new GroupSyncroniser(this); | ||
this.provisioner = new Provisioner(this); | ||
@@ -284,2 +290,6 @@ this.presenceHandler = new PresenceHandler(this); | ||
get groupStore(): DbGroupStore { | ||
return this.store.groupStore; | ||
} | ||
get puppetStore(): DbPuppetStore { | ||
@@ -297,2 +307,6 @@ return this.store.puppetStore; | ||
get groupSyncEnabled(): boolean { | ||
return this.hooks.createGroup && this.config.bridge.enableGroupSync ? true : false; | ||
} | ||
public async start() { | ||
@@ -371,2 +385,6 @@ log.info("Starting application service...."); | ||
public setCreateGroupHook(hook: CreateGroupHook) { | ||
this.hooks.createGroup = hook; | ||
} | ||
public setGetDescHook(hook: GetDescHook) { | ||
@@ -414,2 +432,7 @@ this.hooks.getDesc = hook; | ||
public async updateGroup(group: IRemoteGroup) { | ||
log.verbose("Got request to update a group"); | ||
await this.groupSync.getMxid(group, false); | ||
} | ||
public async bridgeChannel(chan: IRemoteChan) { | ||
@@ -732,2 +755,44 @@ if (!this.hooks.createChan) { | ||
public async uploadContent( | ||
client: MatrixClient, | ||
thing: string | Buffer, | ||
mimetype?: string, | ||
filename?: string, | ||
): Promise<string> { | ||
let buffer: Buffer; | ||
if (typeof thing === "string") { | ||
const maybeMxcUrl = await this.store.getFileMxc(thing); | ||
if (maybeMxcUrl) { | ||
return maybeMxcUrl; | ||
} | ||
if (!filename) { | ||
const matches = thing.match(/\/([^\.\/]+\.[a-zA-Z0-9]+)(?:$|\?)/); | ||
if (matches) { | ||
filename = matches[1]; | ||
} | ||
} | ||
buffer = await Util.DownloadFile(thing); | ||
} else { | ||
buffer = thing; | ||
} | ||
{ | ||
const maybeMxcUrl = await this.store.getFileMxc(buffer); | ||
if (maybeMxcUrl) { | ||
return maybeMxcUrl; | ||
} | ||
} | ||
if (!filename) { | ||
filename = "file"; | ||
} | ||
if (!mimetype) { | ||
mimetype = Util.GetMimeType(buffer); | ||
} | ||
const mxcUrl = await client.uploadContent(buffer, mimetype, filename); | ||
if (typeof thing === "string") { | ||
await this.store.setFileMxc(thing, mxcUrl, filename); | ||
} | ||
await this.store.setFileMxc(buffer, mxcUrl, filename); | ||
return mxcUrl; | ||
} | ||
private getRoomDisplaynameCache(roomId: string): { [userId: string]: IMemberInfo } { | ||
@@ -776,3 +841,4 @@ if (!(roomId in this.memberInfoCache)) { | ||
} | ||
const fileMxc = await client.uploadContent( | ||
const fileMxc = await this.uploadContent( | ||
client, | ||
buffer, | ||
@@ -1011,3 +1077,6 @@ mimetype, | ||
} | ||
const puppetMxid = await this.provisioner.getMxid(room.puppetId); | ||
const puppetData = await this.provisioner.get(room.puppetId); | ||
const puppetMxid = puppetData ? puppetData.puppetMxid : ""; | ||
if (event.sender !== puppetMxid) { | ||
@@ -1019,2 +1088,8 @@ if (!this.config.relay.enabled || !this.provisioner.canRelay(event.sender)) { | ||
} | ||
const delayedKey = `${puppetMxid}_${roomId}`; | ||
this.delayedFunction.set(delayedKey, async () => { | ||
await this.chanSync.maybeLeaveGhost(roomId, puppetMxid); | ||
}, GHOST_PUPPET_LEAVE_TIMEOUT, false); | ||
log.info(`New message by ${event.sender} of type ${event.type} to process!`); | ||
@@ -1021,0 +1096,0 @@ if (event.content.source === "remote") { |
@@ -8,8 +8,10 @@ import { IDbSchema } from "./db/schema/dbschema"; | ||
import { DbChanStore } from "./db/chanstore"; | ||
import { DbGroupStore } from "./db/groupstore"; | ||
import { DbPuppetStore } from "./db/puppetstore"; | ||
import { DbEventStore } from "./db/eventstore"; | ||
import { IDatabaseConnector } from "./db/connector"; | ||
import { Util } from "./util"; | ||
const log = new Log("Store"); | ||
export const CURRENT_SCHEMA = 6; | ||
export const CURRENT_SCHEMA = 8; | ||
@@ -22,2 +24,3 @@ type GetSchemaClass = (version: number) => IDbSchema; | ||
private pUserStore: DbUserStore; | ||
private pGroupStore: DbGroupStore; | ||
private pPuppetStore: DbPuppetStore; | ||
@@ -36,2 +39,6 @@ private pEventStore: DbEventStore; | ||
get groupStore() { | ||
return this.pGroupStore; | ||
} | ||
get puppetStore() { | ||
@@ -88,2 +95,33 @@ return this.pPuppetStore; | ||
public async getFileMxc(thing: string | Buffer): Promise<string | null> { | ||
let key = ""; | ||
if (typeof thing === "string") { | ||
key = thing; | ||
} else { | ||
key = Util.HashBuffer(thing); | ||
} | ||
const ret = await this.db.Get("SELECT mxc_url FROM file_mxc_map WHERE thing = $key", { key }); | ||
if (!ret) { | ||
return null; | ||
} | ||
return ret.mxc_url as string; | ||
} | ||
public async setFileMxc(thing: string | Buffer, mxcUrl: string, filename?: string) { | ||
let key = ""; | ||
if (typeof thing === "string") { | ||
key = thing; | ||
} else { | ||
key = Util.HashBuffer(thing); | ||
} | ||
if ((await this.getFileMxc(key))) { | ||
return; // nothing to do | ||
} | ||
if (!filename) { | ||
filename = ""; | ||
} | ||
await this.db.Run("INSERT INTO file_mxc_map (thing, mxc_url, filename) VALUES ($key, $mxcUrl, $filename)", | ||
{ key, mxcUrl, filename }); | ||
} | ||
public async createTable(statement: string, tablename: string) { | ||
@@ -137,2 +175,3 @@ try { | ||
this.pUserStore = new DbUserStore(this.db); | ||
this.pGroupStore = new DbGroupStore(this.db); | ||
this.pPuppetStore = new DbPuppetStore(this.db); | ||
@@ -139,0 +178,0 @@ this.pEventStore = new DbEventStore(this.db); |
@@ -10,5 +10,9 @@ type DelayedFunctionFn = () => void | Promise<void>; | ||
public set(key: string, fn: DelayedFunctionFn, timeout: number) { | ||
// clear the old timeout | ||
this.release(key); | ||
public set(key: string, fn: DelayedFunctionFn, timeout: number, clearOldTimer: boolean = true) { | ||
if (clearOldTimer) { | ||
// clear the old timeout | ||
this.release(key); | ||
} else if (this.map.has(key)) { | ||
return; | ||
} | ||
@@ -15,0 +19,0 @@ // set the new timeout |
@@ -129,3 +129,6 @@ import { PuppetBridge } from "./puppetbridge"; | ||
log.verbose("Updating avatar"); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = await Util.MaybeUploadFile(client, data, user.avatarHash); | ||
const { doUpdate: updateAvatar, mxcUrl, hash } = await Util.MaybeUploadFile( | ||
async (buffer: Buffer, mimetype?: string, filename?: string) => { | ||
return await this.bridge.uploadContent(client, buffer, mimetype, filename); | ||
}, data, user.avatarHash); | ||
log.silly(`Should update avatar? ${updateAvatar}`); | ||
@@ -132,0 +135,0 @@ if (updateAvatar) { |
@@ -98,4 +98,10 @@ import * as http from "http"; | ||
public static HashBuffer(b: Buffer): string { | ||
return hasha(b, { | ||
algorithm: "sha512", | ||
}); | ||
} | ||
public static async MaybeUploadFile( | ||
client: MatrixClient, | ||
uploadFn: (b: Buffer, m?: string, f?: string) => Promise<string>, | ||
data: IMakeUploadFileData, | ||
@@ -120,5 +126,3 @@ oldHash?: string | null, | ||
} | ||
const hash = hasha(buffer!, { | ||
algorithm: "sha512", | ||
}); | ||
const hash = Util.HashBuffer(buffer!); | ||
if (hash === oldHash) { | ||
@@ -140,7 +144,3 @@ // image didn't change, short-circuit out of here | ||
} | ||
const avatarMxc = await client!.uploadContent( | ||
buffer, | ||
Util.GetMimeType(buffer), | ||
filename, | ||
); | ||
const avatarMxc = await uploadFn(buffer, Util.GetMimeType(buffer), filename); | ||
return { | ||
@@ -147,0 +147,0 @@ doUpdate: true, |
Git dependency
Supply chain riskContains a dependency which resolves to a remote git URL. Dependencies fetched from git URLs are not immutable can be used to inject untrusted code or reduce the likelihood of a reproducible install.
Found 1 instance in 1 package
398525
109
10538
1
- Removed@types/body-parser@1.19.5(transitive)
- Removed@types/connect@3.4.38(transitive)
- Removed@types/express@4.17.21(transitive)
- Removed@types/express-serve-static-core@4.19.1(transitive)
- Removed@types/http-errors@2.0.4(transitive)
- Removed@types/mime@1.3.5(transitive)
- Removed@types/node@20.12.12(transitive)
- Removed@types/qs@6.9.15(transitive)
- Removed@types/range-parser@1.2.7(transitive)
- Removed@types/send@0.17.4(transitive)
- Removed@types/serve-static@1.15.7(transitive)
- Removedaccepts@1.3.8(transitive)
- Removedansi-styles@4.3.0(transitive)
- Removedarray-flatten@1.1.1(transitive)
- Removedbasic-auth@2.0.1(transitive)
- Removedbody-parser@1.20.2(transitive)
- Removedbytes@3.1.2(transitive)
- Removedcall-bind@1.0.7(transitive)
- Removedchalk@3.0.0(transitive)
- Removedcolor-convert@2.0.1(transitive)
- Removedcolor-name@1.1.4(transitive)
- Removedcontent-disposition@0.5.4(transitive)
- Removedcontent-type@1.0.5(transitive)
- Removedcookie@0.6.0(transitive)
- Removedcookie-signature@1.0.6(transitive)
- Removeddebug@2.6.9(transitive)
- Removeddefine-data-property@1.1.4(transitive)
- Removeddepd@2.0.0(transitive)
- Removeddestroy@1.2.0(transitive)
- Removeddom-serializer@1.4.1(transitive)
- Removeddomelementtype@2.3.0(transitive)
- Removeddomhandler@3.3.04.3.1(transitive)
- Removeddomutils@2.8.0(transitive)
- Removedee-first@1.1.1(transitive)
- Removedencodeurl@1.0.2(transitive)
- Removedentities@2.2.0(transitive)
- Removedes-define-property@1.0.0(transitive)
- Removedes-errors@1.3.0(transitive)
- Removedescape-html@1.0.3(transitive)
- Removedetag@1.8.1(transitive)
- Removedexpress@4.19.2(transitive)
- Removedfinalhandler@1.2.0(transitive)
- Removedforwarded@0.2.0(transitive)
- Removedfresh@0.5.2(transitive)
- Removedget-intrinsic@1.2.4(transitive)
- Removedglob-to-regexp@0.4.1(transitive)
- Removedgopd@1.0.1(transitive)
- Removedgraceful-fs@4.2.11(transitive)
- Removedhas-flag@4.0.0(transitive)
- Removedhas-property-descriptors@1.0.2(transitive)
- Removedhas-proto@1.0.3(transitive)
- Removedhas-symbols@1.0.3(transitive)
- Removedhash.js@1.1.7(transitive)
- Removedhtmlencode@0.0.4(transitive)
- Removedhtmlparser2@4.1.0(transitive)
- Removedhttp-errors@2.0.0(transitive)
- Removediconv-lite@0.4.24(transitive)
- Removedipaddr.js@1.9.1(transitive)
- Removedis-promise@2.2.2(transitive)
- Removedlowdb@1.0.0(transitive)
- Removedlru-cache@5.1.1(transitive)
- Removedmatrix-bot-sdk@0.4.1(transitive)
- Removedmedia-typer@0.3.0(transitive)
- Removedmerge-descriptors@1.0.1(transitive)
- Removedmethods@1.1.2(transitive)
- Removedmime@1.6.0(transitive)
- Removedminimalistic-assert@1.0.1(transitive)
- Removedmorgan@1.10.0(transitive)
- Removedms@2.0.0(transitive)
- Removednegotiator@0.6.3(transitive)
- Removedobject-inspect@1.13.1(transitive)
- Removedon-finished@2.3.02.4.1(transitive)
- Removedon-headers@1.0.2(transitive)
- Removedparse-srcset@1.0.2(transitive)
- Removedparseurl@1.3.3(transitive)
- Removedpath-to-regexp@0.1.7(transitive)
- Removedpicocolors@0.2.1(transitive)
- Removedpify@3.0.0(transitive)
- Removedpostcss@7.0.39(transitive)
- Removedproxy-addr@2.0.7(transitive)
- Removedqs@6.11.0(transitive)
- Removedrange-parser@1.2.1(transitive)
- Removedraw-body@2.5.2(transitive)
- Removedsafe-buffer@5.1.2(transitive)
- Removedsanitize-html@1.27.5(transitive)
- Removedsend@0.18.0(transitive)
- Removedserve-static@1.15.0(transitive)
- Removedset-function-length@1.2.2(transitive)
- Removedsetprototypeof@1.2.0(transitive)
- Removedside-channel@1.0.6(transitive)
- Removedsource-map@0.6.1(transitive)
- Removedstatuses@2.0.1(transitive)
- Removedsteno@0.4.4(transitive)
- Removedsupports-color@7.2.0(transitive)
- Removedtoidentifier@1.0.1(transitive)
- Removedtype-is@1.6.18(transitive)
- Removedundici-types@5.26.5(transitive)
- Removedunpipe@1.0.0(transitive)
- Removedutils-merge@1.0.1(transitive)
- Removedvary@1.1.2(transitive)