first commit
This commit is contained in:
329
node_modules/matrix-bot-sdk/lib/appservice/Appservice.d.ts
generated
vendored
Normal file
329
node_modules/matrix-bot-sdk/lib/appservice/Appservice.d.ts
generated
vendored
Normal file
@@ -0,0 +1,329 @@
|
||||
/// <reference types="node" />
|
||||
import { EventEmitter } from "events";
|
||||
import { Intent } from "./Intent";
|
||||
import { IAppserviceCryptoStorageProvider, IAppserviceStorageProvider, IJoinRoomStrategy, IPreprocessor, MatrixClient, Metrics } from "..";
|
||||
import { MatrixBridge } from "./MatrixBridge";
|
||||
/**
|
||||
* Represents an application service's registration file. This is expected to be
|
||||
* loaded from another source, such as a YAML file.
|
||||
* @category Application services
|
||||
*/
|
||||
export interface IAppserviceRegistration {
|
||||
/**
|
||||
* Optional ID for the appplication service. Used by homeservers to track which application
|
||||
* service registers what.
|
||||
*/
|
||||
id?: string;
|
||||
/**
|
||||
* Optional URL at which the application service can be contacted.
|
||||
*/
|
||||
url?: string;
|
||||
/**
|
||||
* The token the application service uses to communicate with the homeserver.
|
||||
*/
|
||||
as_token: string;
|
||||
/**
|
||||
* The token the homeserver uses to communicate with the application service.
|
||||
*/
|
||||
hs_token: string;
|
||||
/**
|
||||
* The application service's own localpart (eg: "_irc_bot" in the user ID "@_irc_bot:domain.com")
|
||||
*/
|
||||
sender_localpart: string;
|
||||
/**
|
||||
* The various namespaces the application service can support.
|
||||
*/
|
||||
namespaces: {
|
||||
/**
|
||||
* The user namespaces the application service is requesting.
|
||||
*/
|
||||
users: {
|
||||
/**
|
||||
* Whether or not the application service holds an exclusive lock on the namespace. This
|
||||
* means that no other user on the homeserver may register users that match this namespace.
|
||||
*/
|
||||
exclusive: boolean;
|
||||
/**
|
||||
* The regular expression that the homeserver uses to determine if a user is in this namespace.
|
||||
*/
|
||||
regex: string;
|
||||
}[];
|
||||
/**
|
||||
* The room namespaces the application service is requesting. This is not for alises.
|
||||
*/
|
||||
rooms: {
|
||||
/**
|
||||
* Whether or not the application service holds an exclusive lock on the namespace.
|
||||
*/
|
||||
exclusive: boolean;
|
||||
/**
|
||||
* The regular expression that the homeserver uses to determine if a user is in this namespace.
|
||||
*/
|
||||
regex: string;
|
||||
}[];
|
||||
/**
|
||||
* The room alias namespaces the application service is requesting.
|
||||
*/
|
||||
aliases: {
|
||||
/**
|
||||
* Whether or not the application service holds an exclusive lock on the namespace. This means
|
||||
* that no other user on the homeserver may register aliases that match this namespace.
|
||||
*/
|
||||
exclusive: boolean;
|
||||
/**
|
||||
* The regular expression that the homeserver uses to determine if an alias is in this namespace.
|
||||
*/
|
||||
regex: string;
|
||||
}[];
|
||||
};
|
||||
/**
|
||||
* The protocols the application service supports. Optional.
|
||||
*/
|
||||
protocols?: string[];
|
||||
/**
|
||||
* If the application service is rate limited by the homeserver. Optional.
|
||||
*/
|
||||
rate_limited?: boolean;
|
||||
/**
|
||||
* **Experimental**
|
||||
*
|
||||
* Should the application service receive ephemeral events from the homeserver. Optional.
|
||||
* @see https://github.com/matrix-org/matrix-doc/pull/2409
|
||||
*/
|
||||
"de.sorunome.msc2409.push_ephemeral"?: boolean;
|
||||
}
|
||||
/**
|
||||
* General options for the application service
|
||||
* @category Application services
|
||||
*/
|
||||
export interface IAppserviceOptions {
|
||||
/**
|
||||
* The port to listen for requests from the homeserver on.
|
||||
*/
|
||||
port: number;
|
||||
/**
|
||||
* The bind address to listen for requests on.
|
||||
*/
|
||||
bindAddress: string;
|
||||
/**
|
||||
* The name of the homeserver, as presented over federation (eg: "matrix.org")
|
||||
*/
|
||||
homeserverName: string;
|
||||
/**
|
||||
* The URL to the homeserver's client server API (eg: "https://matrix.org")
|
||||
*/
|
||||
homeserverUrl: string;
|
||||
/**
|
||||
* The storage provider to use for this application service.
|
||||
*/
|
||||
storage?: IAppserviceStorageProvider;
|
||||
/**
|
||||
* The storage provider to use for setting up encryption. Encryption will be
|
||||
* disabled for all intents and the appservice if not configured.
|
||||
*/
|
||||
cryptoStorage?: IAppserviceCryptoStorageProvider;
|
||||
/**
|
||||
* The registration for this application service.
|
||||
*/
|
||||
registration: IAppserviceRegistration;
|
||||
/**
|
||||
* The join strategy to use for all intents, if any.
|
||||
*/
|
||||
joinStrategy?: IJoinRoomStrategy;
|
||||
/**
|
||||
* Options for how Intents are handled.
|
||||
*/
|
||||
intentOptions?: {
|
||||
/**
|
||||
* The maximum number of intents to keep cached. Defaults to 10 thousand.
|
||||
*/
|
||||
maxCached?: number;
|
||||
/**
|
||||
* The maximum age in milliseconds to keep an Intent around for, provided
|
||||
* the maximum number of intents has been reached. Defaults to 60 minutes.
|
||||
*/
|
||||
maxAgeMs?: number;
|
||||
/**
|
||||
* If false (default), crypto will not be automatically set up for all intent
|
||||
* instances - it will need to be manually enabled with
|
||||
* `await intent.enableEncryption()`.
|
||||
*
|
||||
* If true, crypto will be automatically set up.
|
||||
*
|
||||
* Note that the appservice bot account is considered an intent.
|
||||
*/
|
||||
encryption?: boolean;
|
||||
};
|
||||
}
|
||||
/**
|
||||
* Represents an application service. This provides helper utilities such as tracking
|
||||
* of user intents (clients that are aware of their membership in rooms).
|
||||
* @category Application services
|
||||
*/
|
||||
export declare class Appservice extends EventEmitter {
|
||||
private options;
|
||||
/**
|
||||
* The metrics instance for this appservice. This will raise all metrics
|
||||
* from this appservice instance as well as any intents/MatrixClients created
|
||||
* by the appservice.
|
||||
*/
|
||||
readonly metrics: Metrics;
|
||||
private readonly userPrefix;
|
||||
private readonly aliasPrefix;
|
||||
private readonly registration;
|
||||
private readonly storage;
|
||||
private readonly cryptoStorage;
|
||||
private readonly bridgeInstance;
|
||||
private app;
|
||||
private appServer;
|
||||
private intentsCache;
|
||||
private eventProcessors;
|
||||
private pendingTransactions;
|
||||
/**
|
||||
* Creates a new application service.
|
||||
* @param {IAppserviceOptions} options The options for the application service.
|
||||
*/
|
||||
constructor(options: IAppserviceOptions);
|
||||
/**
|
||||
* Gets the express app instance which is serving requests. Not recommended for
|
||||
* general usage, but may be used to append routes to the web server.
|
||||
*/
|
||||
get expressAppInstance(): import("express-serve-static-core").Express;
|
||||
/**
|
||||
* Gets the bridge-specific APIs for this application service.
|
||||
*/
|
||||
get bridge(): MatrixBridge;
|
||||
/**
|
||||
* Get the application service's "bot" user ID (the sender_localpart).
|
||||
*/
|
||||
get botUserId(): string;
|
||||
/**
|
||||
* Get the application service's "bot" Intent (the sender_localpart).
|
||||
* @returns {Intent} The intent for the application service itself.
|
||||
*/
|
||||
get botIntent(): Intent;
|
||||
/**
|
||||
* Get the application service's "bot" MatrixClient (the sender_localpart).
|
||||
* Normally the botIntent should be used to ensure that the bot user is safely
|
||||
* handled.
|
||||
* @returns {MatrixClient} The client for the application service itself.
|
||||
*/
|
||||
get botClient(): MatrixClient;
|
||||
/**
|
||||
* Starts the application service, opening the bind address to begin processing requests.
|
||||
* @returns {Promise<void>} resolves when started
|
||||
*/
|
||||
begin(): Promise<void>;
|
||||
/**
|
||||
* Stops the application service, freeing the web server.
|
||||
*/
|
||||
stop(): void;
|
||||
/**
|
||||
* Gets an intent for a given localpart. The user ID will be formed with the domain name given
|
||||
* in the constructor.
|
||||
* @param localpart The localpart to get an Intent for.
|
||||
* @returns {Intent} An Intent for the user.
|
||||
*/
|
||||
getIntent(localpart: string): Intent;
|
||||
/**
|
||||
* Gets a full user ID for a given localpart. The user ID will be formed with the domain name given
|
||||
* in the constructor.
|
||||
* @param localpart The localpart to get a user ID for.
|
||||
* @returns {string} The user's ID.
|
||||
*/
|
||||
getUserId(localpart: string): string;
|
||||
/**
|
||||
* Gets an Intent for a given user suffix. The prefix is automatically detected from the registration
|
||||
* options.
|
||||
* @param suffix The user's suffix
|
||||
* @returns {Intent} An Intent for the user.
|
||||
*/
|
||||
getIntentForSuffix(suffix: string): Intent;
|
||||
/**
|
||||
* Gets a full user ID for a given suffix. The prefix is automatically detected from the registration
|
||||
* options.
|
||||
* @param suffix The user's suffix
|
||||
* @returns {string} The user's ID.
|
||||
*/
|
||||
getUserIdForSuffix(suffix: string): string;
|
||||
/**
|
||||
* Gets an Intent for a given user ID.
|
||||
* @param {string} userId The user ID to get an Intent for.
|
||||
* @returns {Intent} An Intent for the user.
|
||||
*/
|
||||
getIntentForUserId(userId: string): Intent;
|
||||
/**
|
||||
* Gets the suffix for the provided user ID. If the user ID is not a namespaced
|
||||
* user, this will return a falsey value.
|
||||
* @param {string} userId The user ID to parse
|
||||
* @returns {string} The suffix from the user ID.
|
||||
*/
|
||||
getSuffixForUserId(userId: string): string;
|
||||
/**
|
||||
* Determines if a given user ID is namespaced by this application service.
|
||||
* @param {string} userId The user ID to check
|
||||
* @returns {boolean} true if the user is namespaced, false otherwise
|
||||
*/
|
||||
isNamespacedUser(userId: string): boolean;
|
||||
/**
|
||||
* Gets a full alias for a given localpart. The alias will be formed with the domain name given
|
||||
* in the constructor.
|
||||
* @param localpart The localpart to get an alias for.
|
||||
* @returns {string} The alias.
|
||||
*/
|
||||
getAlias(localpart: string): string;
|
||||
/**
|
||||
* Gets a full alias for a given suffix. The prefix is automatically detected from the registration
|
||||
* options.
|
||||
* @param suffix The alias's suffix
|
||||
* @returns {string} The alias.
|
||||
*/
|
||||
getAliasForSuffix(suffix: string): string;
|
||||
/**
|
||||
* Gets the localpart of an alias for a given suffix. The prefix is automatically detected from the registration
|
||||
* options. Useful for the createRoom endpoint.
|
||||
* @param suffix The alias's suffix
|
||||
* @returns {string} The alias localpart.
|
||||
*/
|
||||
getAliasLocalpartForSuffix(suffix: string): string;
|
||||
/**
|
||||
* Gets the suffix for the provided alias. If the alias is not a namespaced
|
||||
* alias, this will return a falsey value.
|
||||
* @param {string} alias The alias to parse
|
||||
* @returns {string} The suffix from the alias.
|
||||
*/
|
||||
getSuffixForAlias(alias: string): string;
|
||||
/**
|
||||
* Determines if a given alias is namespaced by this application service.
|
||||
* @param {string} alias The alias to check
|
||||
* @returns {boolean} true if the alias is namespaced, false otherwise
|
||||
*/
|
||||
isNamespacedAlias(alias: string): boolean;
|
||||
/**
|
||||
* Adds a preprocessor to the event pipeline. When this appservice encounters an event, it
|
||||
* will try to run it through the preprocessors it can in the order they were added.
|
||||
* @param {IPreprocessor} preprocessor the preprocessor to add
|
||||
*/
|
||||
addPreprocessor(preprocessor: IPreprocessor): void;
|
||||
/**
|
||||
* Sets the visibility of a room in the appservice's room directory.
|
||||
* @param {string} networkId The network ID to group the room under.
|
||||
* @param {string} roomId The room ID to manipulate the visibility of.
|
||||
* @param {"public" | "private"} visibility The visibility to set for the room.
|
||||
* @return {Promise<any>} resolves when the visibility has been updated.
|
||||
*/
|
||||
setRoomDirectoryVisibility(networkId: string, roomId: string, visibility: "public" | "private"): Promise<any>;
|
||||
private processEphemeralEvent;
|
||||
private processEvent;
|
||||
private processMembershipEvent;
|
||||
private isAuthed;
|
||||
private onTransaction;
|
||||
private onUser;
|
||||
private onRoomAlias;
|
||||
private onKeysClaim;
|
||||
private onKeysQuery;
|
||||
private onThirdpartyProtocol;
|
||||
private handleThirdpartyObject;
|
||||
private onThirdpartyUser;
|
||||
private onThirdpartyLocation;
|
||||
}
|
803
node_modules/matrix-bot-sdk/lib/appservice/Appservice.js
generated
vendored
Normal file
803
node_modules/matrix-bot-sdk/lib/appservice/Appservice.js
generated
vendored
Normal file
@@ -0,0 +1,803 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Appservice = void 0;
|
||||
const express = require("express");
|
||||
const events_1 = require("events");
|
||||
const morgan = require("morgan");
|
||||
const LRU = require("lru-cache");
|
||||
const querystring_1 = require("querystring");
|
||||
const Intent_1 = require("./Intent");
|
||||
const __1 = require("..");
|
||||
const MatrixBridge_1 = require("./MatrixBridge");
|
||||
const EDU_ANNOTATION_KEY = "io.t2bot.sdk.bot.type";
|
||||
var EduAnnotation;
|
||||
(function (EduAnnotation) {
|
||||
EduAnnotation["ToDevice"] = "to_device";
|
||||
EduAnnotation["Ephemeral"] = "ephemeral";
|
||||
})(EduAnnotation || (EduAnnotation = {}));
|
||||
/**
|
||||
* Represents an application service. This provides helper utilities such as tracking
|
||||
* of user intents (clients that are aware of their membership in rooms).
|
||||
* @category Application services
|
||||
*/
|
||||
class Appservice extends events_1.EventEmitter {
|
||||
/**
|
||||
* Creates a new application service.
|
||||
* @param {IAppserviceOptions} options The options for the application service.
|
||||
*/
|
||||
constructor(options) {
|
||||
super();
|
||||
this.options = options;
|
||||
/**
|
||||
* The metrics instance for this appservice. This will raise all metrics
|
||||
* from this appservice instance as well as any intents/MatrixClients created
|
||||
* by the appservice.
|
||||
*/
|
||||
this.metrics = new __1.Metrics();
|
||||
this.bridgeInstance = new MatrixBridge_1.MatrixBridge(this);
|
||||
this.app = express();
|
||||
this.eventProcessors = {};
|
||||
this.pendingTransactions = {};
|
||||
options.joinStrategy = new __1.AppserviceJoinRoomStrategy(options.joinStrategy, this);
|
||||
if (!options.intentOptions)
|
||||
options.intentOptions = {};
|
||||
if (!options.intentOptions.maxAgeMs)
|
||||
options.intentOptions.maxAgeMs = 60 * 60 * 1000;
|
||||
if (!options.intentOptions.maxCached)
|
||||
options.intentOptions.maxCached = 10000;
|
||||
this.intentsCache = new LRU.LRUCache({
|
||||
max: options.intentOptions.maxCached,
|
||||
ttl: options.intentOptions.maxAgeMs,
|
||||
});
|
||||
this.registration = options.registration;
|
||||
// If protocol is not defined, define an empty array.
|
||||
if (!this.registration.protocols) {
|
||||
this.registration.protocols = [];
|
||||
}
|
||||
this.storage = options.storage || new __1.MemoryStorageProvider();
|
||||
options.storage = this.storage;
|
||||
this.cryptoStorage = options.cryptoStorage;
|
||||
this.app.use(express.json({ limit: Number.MAX_SAFE_INTEGER })); // disable limits, use a reverse proxy
|
||||
morgan.token('url-safe', (req) => `${req.path}?${(0, querystring_1.stringify)((0, __1.redactObjectForLogging)(req.query ?? {}))}`);
|
||||
this.app.use(morgan(
|
||||
// Same as "combined", but with sensitive values removed from requests.
|
||||
':remote-addr - :remote-user [:date[clf]] ":method :url-safe HTTP/:http-version" :status :res[content-length] ":referrer" ":user-agent"', { stream: { write: __1.LogService.info.bind(__1.LogService, 'Appservice') } }));
|
||||
// ETag headers break the tests sometimes, and we don't actually need them anyways for
|
||||
// appservices - none of this should be cached.
|
||||
this.app.set('etag', false);
|
||||
this.app.get("/users/:userId", this.onUser.bind(this));
|
||||
this.app.get("/rooms/:roomAlias", this.onRoomAlias.bind(this));
|
||||
this.app.put("/transactions/:txnId", this.onTransaction.bind(this));
|
||||
this.app.get("/_matrix/app/v1/users/:userId", this.onUser.bind(this));
|
||||
this.app.get("/_matrix/app/v1/rooms/:roomAlias", this.onRoomAlias.bind(this));
|
||||
this.app.put("/_matrix/app/v1/transactions/:txnId", this.onTransaction.bind(this));
|
||||
this.app.get("/_matrix/app/v1/thirdparty/protocol/:protocol", this.onThirdpartyProtocol.bind(this));
|
||||
this.app.get("/_matrix/app/v1/thirdparty/user/:protocol", this.onThirdpartyUser.bind(this));
|
||||
this.app.get("/_matrix/app/v1/thirdparty/user", this.onThirdpartyUser.bind(this));
|
||||
this.app.get("/_matrix/app/v1/thirdparty/location/:protocol", this.onThirdpartyLocation.bind(this));
|
||||
this.app.get("/_matrix/app/v1/thirdparty/location", this.onThirdpartyLocation.bind(this));
|
||||
this.app.post("/_matrix/app/unstable/org.matrix.msc3983/keys/claim", this.onKeysClaim.bind(this));
|
||||
this.app.post("/_matrix/app/unstable/org.matrix.msc3984/keys/query", this.onKeysQuery.bind(this));
|
||||
// Workaround for https://github.com/matrix-org/synapse/issues/3780
|
||||
this.app.post("/_matrix/app/v1/unstable/org.matrix.msc3983/keys/claim", this.onKeysClaim.bind(this));
|
||||
this.app.post("/unstable/org.matrix.msc3983/keys/claim", this.onKeysClaim.bind(this));
|
||||
this.app.post("/_matrix/app/v1/unstable/org.matrix.msc3984/keys/query", this.onKeysQuery.bind(this));
|
||||
this.app.post("/unstable/org.matrix.msc3984/keys/query", this.onKeysQuery.bind(this));
|
||||
// We register the 404 handler in the `begin()` function to allow consumers to add their own endpoints.
|
||||
if (!this.registration.namespaces || !this.registration.namespaces.users || this.registration.namespaces.users.length === 0) {
|
||||
throw new Error("No user namespaces in registration");
|
||||
}
|
||||
if (this.registration.namespaces.users.length !== 1) {
|
||||
throw new Error("Too many user namespaces registered: expecting exactly one");
|
||||
}
|
||||
const userPrefix = (this.registration.namespaces.users[0].regex || "").split(":")[0];
|
||||
if (!userPrefix.endsWith(".*") && !userPrefix.endsWith(".+")) {
|
||||
this.userPrefix = null;
|
||||
}
|
||||
else {
|
||||
this.userPrefix = userPrefix.substring(0, userPrefix.length - 2); // trim off the .* part
|
||||
}
|
||||
if (!this.registration.namespaces?.aliases || this.registration.namespaces.aliases.length !== 1) {
|
||||
this.aliasPrefix = null;
|
||||
}
|
||||
else {
|
||||
this.aliasPrefix = (this.registration.namespaces.aliases[0].regex || "").split(":")[0];
|
||||
if (!this.aliasPrefix.endsWith(".*") && !this.aliasPrefix.endsWith(".+")) {
|
||||
this.aliasPrefix = null;
|
||||
}
|
||||
else {
|
||||
this.aliasPrefix = this.aliasPrefix.substring(0, this.aliasPrefix.length - 2); // trim off the .* part
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Gets the express app instance which is serving requests. Not recommended for
|
||||
* general usage, but may be used to append routes to the web server.
|
||||
*/
|
||||
get expressAppInstance() {
|
||||
return this.app;
|
||||
}
|
||||
/**
|
||||
* Gets the bridge-specific APIs for this application service.
|
||||
*/
|
||||
get bridge() {
|
||||
return this.bridgeInstance;
|
||||
}
|
||||
/**
|
||||
* Get the application service's "bot" user ID (the sender_localpart).
|
||||
*/
|
||||
get botUserId() {
|
||||
return this.getUserId(this.registration.sender_localpart);
|
||||
}
|
||||
/**
|
||||
* Get the application service's "bot" Intent (the sender_localpart).
|
||||
* @returns {Intent} The intent for the application service itself.
|
||||
*/
|
||||
get botIntent() {
|
||||
return this.getIntentForUserId(this.botUserId);
|
||||
}
|
||||
/**
|
||||
* Get the application service's "bot" MatrixClient (the sender_localpart).
|
||||
* Normally the botIntent should be used to ensure that the bot user is safely
|
||||
* handled.
|
||||
* @returns {MatrixClient} The client for the application service itself.
|
||||
*/
|
||||
get botClient() {
|
||||
return this.botIntent.underlyingClient;
|
||||
}
|
||||
/**
|
||||
* Starts the application service, opening the bind address to begin processing requests.
|
||||
* @returns {Promise<void>} resolves when started
|
||||
*/
|
||||
begin() {
|
||||
return new Promise((resolve, reject) => {
|
||||
// Per constructor, all other endpoints should 404.
|
||||
// Technically, according to https://spec.matrix.org/v1.6/application-service-api/#unknown-routes we should
|
||||
// be returning 405 for *known* endpoints with the wrong method.
|
||||
this.app.all("*", (req, res) => {
|
||||
res.status(404).json({ errcode: "M_UNRECOGNIZED", error: "Endpoint not implemented" });
|
||||
});
|
||||
this.appServer = this.app.listen(this.options.port, this.options.bindAddress, () => resolve());
|
||||
}).then(async () => {
|
||||
if (this.options.intentOptions?.encryption) {
|
||||
await this.botIntent.enableEncryption();
|
||||
}
|
||||
else {
|
||||
await this.botIntent.ensureRegistered();
|
||||
}
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Stops the application service, freeing the web server.
|
||||
*/
|
||||
stop() {
|
||||
if (!this.appServer)
|
||||
return;
|
||||
this.appServer.close();
|
||||
}
|
||||
/**
|
||||
* Gets an intent for a given localpart. The user ID will be formed with the domain name given
|
||||
* in the constructor.
|
||||
* @param localpart The localpart to get an Intent for.
|
||||
* @returns {Intent} An Intent for the user.
|
||||
*/
|
||||
getIntent(localpart) {
|
||||
return this.getIntentForUserId(this.getUserId(localpart));
|
||||
}
|
||||
/**
|
||||
* Gets a full user ID for a given localpart. The user ID will be formed with the domain name given
|
||||
* in the constructor.
|
||||
* @param localpart The localpart to get a user ID for.
|
||||
* @returns {string} The user's ID.
|
||||
*/
|
||||
getUserId(localpart) {
|
||||
return `@${localpart}:${this.options.homeserverName}`;
|
||||
}
|
||||
/**
|
||||
* Gets an Intent for a given user suffix. The prefix is automatically detected from the registration
|
||||
* options.
|
||||
* @param suffix The user's suffix
|
||||
* @returns {Intent} An Intent for the user.
|
||||
*/
|
||||
getIntentForSuffix(suffix) {
|
||||
return this.getIntentForUserId(this.getUserIdForSuffix(suffix));
|
||||
}
|
||||
/**
|
||||
* Gets a full user ID for a given suffix. The prefix is automatically detected from the registration
|
||||
* options.
|
||||
* @param suffix The user's suffix
|
||||
* @returns {string} The user's ID.
|
||||
*/
|
||||
getUserIdForSuffix(suffix) {
|
||||
if (!this.userPrefix) {
|
||||
throw new Error(`Cannot use getUserIdForSuffix, provided namespace did not include a valid suffix`);
|
||||
}
|
||||
return `${this.userPrefix}${suffix}:${this.options.homeserverName}`;
|
||||
}
|
||||
/**
|
||||
* Gets an Intent for a given user ID.
|
||||
* @param {string} userId The user ID to get an Intent for.
|
||||
* @returns {Intent} An Intent for the user.
|
||||
*/
|
||||
getIntentForUserId(userId) {
|
||||
let intent = this.intentsCache.get(userId);
|
||||
if (!intent) {
|
||||
intent = new Intent_1.Intent(this.options, userId, this);
|
||||
this.intentsCache.set(userId, intent);
|
||||
if (this.options.intentOptions.encryption) {
|
||||
intent.enableEncryption().catch(e => {
|
||||
__1.LogService.error("Appservice", `Failed to set up crypto on intent ${userId}`, e);
|
||||
throw e; // re-throw to cause unhandled exception
|
||||
});
|
||||
}
|
||||
}
|
||||
return intent;
|
||||
}
|
||||
/**
|
||||
* Gets the suffix for the provided user ID. If the user ID is not a namespaced
|
||||
* user, this will return a falsey value.
|
||||
* @param {string} userId The user ID to parse
|
||||
* @returns {string} The suffix from the user ID.
|
||||
*/
|
||||
getSuffixForUserId(userId) {
|
||||
if (!this.userPrefix) {
|
||||
throw new Error(`Cannot use getUserIdForSuffix, provided namespace did not include a valid suffix`);
|
||||
}
|
||||
if (!userId || !userId.startsWith(this.userPrefix) || !userId.endsWith(`:${this.options.homeserverName}`)) {
|
||||
// Invalid ID
|
||||
return null;
|
||||
}
|
||||
return userId
|
||||
.split('')
|
||||
.slice(this.userPrefix.length)
|
||||
.reverse()
|
||||
.slice(this.options.homeserverName.length + 1)
|
||||
.reverse()
|
||||
.join('');
|
||||
}
|
||||
/**
|
||||
* Determines if a given user ID is namespaced by this application service.
|
||||
* @param {string} userId The user ID to check
|
||||
* @returns {boolean} true if the user is namespaced, false otherwise
|
||||
*/
|
||||
isNamespacedUser(userId) {
|
||||
return userId === this.botUserId ||
|
||||
!!this.registration.namespaces?.users.find(({ regex }) => new RegExp(regex).test(userId));
|
||||
}
|
||||
/**
|
||||
* Gets a full alias for a given localpart. The alias will be formed with the domain name given
|
||||
* in the constructor.
|
||||
* @param localpart The localpart to get an alias for.
|
||||
* @returns {string} The alias.
|
||||
*/
|
||||
getAlias(localpart) {
|
||||
return `#${localpart}:${this.options.homeserverName}`;
|
||||
}
|
||||
/**
|
||||
* Gets a full alias for a given suffix. The prefix is automatically detected from the registration
|
||||
* options.
|
||||
* @param suffix The alias's suffix
|
||||
* @returns {string} The alias.
|
||||
*/
|
||||
getAliasForSuffix(suffix) {
|
||||
if (!this.aliasPrefix) {
|
||||
throw new Error("Invalid configured alias prefix");
|
||||
}
|
||||
return `${this.aliasPrefix}${suffix}:${this.options.homeserverName}`;
|
||||
}
|
||||
/**
|
||||
* Gets the localpart of an alias for a given suffix. The prefix is automatically detected from the registration
|
||||
* options. Useful for the createRoom endpoint.
|
||||
* @param suffix The alias's suffix
|
||||
* @returns {string} The alias localpart.
|
||||
*/
|
||||
getAliasLocalpartForSuffix(suffix) {
|
||||
if (!this.aliasPrefix) {
|
||||
throw new Error("Invalid configured alias prefix");
|
||||
}
|
||||
return `${this.aliasPrefix.substr(1)}${suffix}`;
|
||||
}
|
||||
/**
|
||||
* Gets the suffix for the provided alias. If the alias is not a namespaced
|
||||
* alias, this will return a falsey value.
|
||||
* @param {string} alias The alias to parse
|
||||
* @returns {string} The suffix from the alias.
|
||||
*/
|
||||
getSuffixForAlias(alias) {
|
||||
if (!this.aliasPrefix) {
|
||||
throw new Error("Invalid configured alias prefix");
|
||||
}
|
||||
if (!alias || !this.isNamespacedAlias(alias)) {
|
||||
// Invalid ID
|
||||
return null;
|
||||
}
|
||||
return alias
|
||||
.split('')
|
||||
.slice(this.aliasPrefix.length)
|
||||
.reverse()
|
||||
.slice(this.options.homeserverName.length + 1)
|
||||
.reverse()
|
||||
.join('');
|
||||
}
|
||||
/**
|
||||
* Determines if a given alias is namespaced by this application service.
|
||||
* @param {string} alias The alias to check
|
||||
* @returns {boolean} true if the alias is namespaced, false otherwise
|
||||
*/
|
||||
isNamespacedAlias(alias) {
|
||||
if (!this.aliasPrefix) {
|
||||
throw new Error("Invalid configured alias prefix");
|
||||
}
|
||||
return alias.startsWith(this.aliasPrefix) && alias.endsWith(":" + this.options.homeserverName);
|
||||
}
|
||||
/**
|
||||
* Adds a preprocessor to the event pipeline. When this appservice encounters an event, it
|
||||
* will try to run it through the preprocessors it can in the order they were added.
|
||||
* @param {IPreprocessor} preprocessor the preprocessor to add
|
||||
*/
|
||||
addPreprocessor(preprocessor) {
|
||||
if (!preprocessor)
|
||||
throw new Error("Preprocessor cannot be null");
|
||||
const eventTypes = preprocessor.getSupportedEventTypes();
|
||||
if (!eventTypes)
|
||||
return; // Nothing to do
|
||||
for (const eventType of eventTypes) {
|
||||
if (!this.eventProcessors[eventType])
|
||||
this.eventProcessors[eventType] = [];
|
||||
this.eventProcessors[eventType].push(preprocessor);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Sets the visibility of a room in the appservice's room directory.
|
||||
* @param {string} networkId The network ID to group the room under.
|
||||
* @param {string} roomId The room ID to manipulate the visibility of.
|
||||
* @param {"public" | "private"} visibility The visibility to set for the room.
|
||||
* @return {Promise<any>} resolves when the visibility has been updated.
|
||||
*/
|
||||
setRoomDirectoryVisibility(networkId, roomId, visibility) {
|
||||
roomId = encodeURIComponent(roomId);
|
||||
networkId = encodeURIComponent(networkId);
|
||||
return this.botClient.doRequest("PUT", `/_matrix/client/v3/directory/list/appservice/${networkId}/${roomId}`, null, {
|
||||
visibility,
|
||||
});
|
||||
}
|
||||
async processEphemeralEvent(event) {
|
||||
if (!event)
|
||||
return event;
|
||||
if (!this.eventProcessors[event["type"]])
|
||||
return event;
|
||||
for (const processor of this.eventProcessors[event["type"]]) {
|
||||
await processor.processEvent(event, this.botIntent.underlyingClient, __1.EventKind.EphemeralEvent);
|
||||
}
|
||||
return event;
|
||||
}
|
||||
async processEvent(event) {
|
||||
if (!event)
|
||||
return event;
|
||||
if (!this.eventProcessors[event["type"]])
|
||||
return event;
|
||||
for (const processor of this.eventProcessors[event["type"]]) {
|
||||
await processor.processEvent(event, this.botIntent.underlyingClient, __1.EventKind.RoomEvent);
|
||||
}
|
||||
return event;
|
||||
}
|
||||
async processMembershipEvent(event) {
|
||||
if (!event["content"])
|
||||
return;
|
||||
const domain = new __1.UserID(event['state_key']).domain;
|
||||
const botDomain = new __1.UserID(this.botUserId).domain;
|
||||
if (domain !== botDomain)
|
||||
return; // can't be impersonated, so don't try
|
||||
// Update the target intent's joined rooms (fixes transition errors with the cache, like join->kick->join)
|
||||
const intent = this.getIntentForUserId(event['state_key']);
|
||||
await intent.refreshJoinedRooms();
|
||||
const targetMembership = event["content"]["membership"];
|
||||
if (targetMembership === "join") {
|
||||
this.emit("room.join", event["room_id"], event);
|
||||
await intent.underlyingClient.crypto?.onRoomJoin(event["room_id"]);
|
||||
}
|
||||
else if (targetMembership === "ban" || targetMembership === "leave") {
|
||||
this.emit("room.leave", event["room_id"], event);
|
||||
}
|
||||
else if (targetMembership === "invite") {
|
||||
this.emit("room.invite", event["room_id"], event);
|
||||
}
|
||||
}
|
||||
isAuthed(req) {
|
||||
let providedToken = req.query ? req.query["access_token"] : null;
|
||||
if (req.headers && req.headers["authorization"]) {
|
||||
const authHeader = req.headers["authorization"];
|
||||
if (!authHeader.startsWith("Bearer "))
|
||||
providedToken = null;
|
||||
else
|
||||
providedToken = authHeader.substring("Bearer ".length);
|
||||
}
|
||||
return providedToken === this.registration.hs_token;
|
||||
}
|
||||
async onTransaction(req, res) {
|
||||
if (!this.isAuthed(req)) {
|
||||
res.status(401).json({ errcode: "AUTH_FAILED", error: "Authentication failed" });
|
||||
return;
|
||||
}
|
||||
if (typeof (req.body) !== "object") {
|
||||
res.status(400).json({ errcode: "BAD_REQUEST", error: "Expected JSON" });
|
||||
return;
|
||||
}
|
||||
if (!req.body["events"] || !Array.isArray(req.body["events"])) {
|
||||
res.status(400).json({ errcode: "BAD_REQUEST", error: "Invalid JSON: expected events" });
|
||||
return;
|
||||
}
|
||||
const txnId = req.params["txnId"];
|
||||
if (await Promise.resolve(this.storage.isTransactionCompleted(txnId))) {
|
||||
res.status(200).json({});
|
||||
return;
|
||||
}
|
||||
if (this.pendingTransactions[txnId]) {
|
||||
try {
|
||||
await this.pendingTransactions[txnId];
|
||||
res.status(200).json({});
|
||||
}
|
||||
catch (e) {
|
||||
__1.LogService.error("Appservice", e);
|
||||
res.status(500).json({});
|
||||
}
|
||||
return;
|
||||
}
|
||||
__1.LogService.info("Appservice", "Processing transaction " + txnId);
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
this.pendingTransactions[txnId] = new Promise(async (resolve) => {
|
||||
// Process all the crypto stuff first to ensure that future transactions (if not this one)
|
||||
// will decrypt successfully. We start with EDUs because we need structures to put counts
|
||||
// and such into in a later stage, and EDUs are independent of crypto.
|
||||
const byUserId = {};
|
||||
const orderedEdus = [];
|
||||
if (Array.isArray(req.body["de.sorunome.msc2409.to_device"])) {
|
||||
orderedEdus.push(...req.body["de.sorunome.msc2409.to_device"].map(e => ({
|
||||
...e,
|
||||
unsigned: {
|
||||
...e['unsigned'],
|
||||
[EDU_ANNOTATION_KEY]: EduAnnotation.ToDevice,
|
||||
},
|
||||
})));
|
||||
}
|
||||
if (Array.isArray(req.body["de.sorunome.msc2409.ephemeral"])) {
|
||||
orderedEdus.push(...req.body["de.sorunome.msc2409.ephemeral"].map(e => ({
|
||||
...e,
|
||||
unsigned: {
|
||||
...e['unsigned'],
|
||||
[EDU_ANNOTATION_KEY]: EduAnnotation.Ephemeral,
|
||||
},
|
||||
})));
|
||||
}
|
||||
for (let event of orderedEdus) {
|
||||
if (event['edu_type'])
|
||||
event['type'] = event['edu_type']; // handle property change during MSC2409's course
|
||||
__1.LogService.info("Appservice", `Processing ${event['unsigned'][EDU_ANNOTATION_KEY]} event of type ${event["type"]}`);
|
||||
event = await this.processEphemeralEvent(event);
|
||||
// These events aren't tied to rooms, so just emit them generically
|
||||
this.emit("ephemeral.event", event);
|
||||
if (this.cryptoStorage && (event["type"] === "m.room.encrypted" || event.unsigned?.[EDU_ANNOTATION_KEY] === EduAnnotation.ToDevice)) {
|
||||
const toUser = event["to_user_id"];
|
||||
const intent = this.getIntentForUserId(toUser);
|
||||
await intent.enableEncryption();
|
||||
if (!byUserId[toUser])
|
||||
byUserId[toUser] = { counts: null, toDevice: null, unusedFallbacks: null };
|
||||
if (!byUserId[toUser].toDevice)
|
||||
byUserId[toUser].toDevice = [];
|
||||
byUserId[toUser].toDevice.push(event);
|
||||
}
|
||||
}
|
||||
const deviceLists = req.body["org.matrix.msc3202.device_lists"] ?? {
|
||||
changed: [],
|
||||
removed: [],
|
||||
};
|
||||
if (!deviceLists.changed)
|
||||
deviceLists.changed = [];
|
||||
if (!deviceLists.removed)
|
||||
deviceLists.removed = [];
|
||||
if (deviceLists.changed.length || deviceLists.removed.length) {
|
||||
this.emit("device_lists", deviceLists);
|
||||
}
|
||||
let otks = req.body["org.matrix.msc3202.device_one_time_keys_count"];
|
||||
const otks2 = req.body["org.matrix.msc3202.device_one_time_key_counts"];
|
||||
if (otks2 && !otks) {
|
||||
__1.LogService.warn("Appservice", "Your homeserver is using an outdated field (device_one_time_key_counts) to talk to this appservice. " +
|
||||
"If you're using Synapse, please upgrade to 1.73.0 or higher.");
|
||||
otks = otks2;
|
||||
}
|
||||
if (otks) {
|
||||
this.emit("otk.counts", otks);
|
||||
}
|
||||
if (otks && this.cryptoStorage) {
|
||||
for (const userId of Object.keys(otks)) {
|
||||
const intent = this.getIntentForUserId(userId);
|
||||
await intent.enableEncryption();
|
||||
const otksForUser = otks[userId][intent.underlyingClient.crypto.clientDeviceId];
|
||||
if (otksForUser) {
|
||||
if (!byUserId[userId]) {
|
||||
byUserId[userId] = {
|
||||
counts: null,
|
||||
toDevice: null,
|
||||
unusedFallbacks: null,
|
||||
};
|
||||
}
|
||||
byUserId[userId].counts = otksForUser;
|
||||
}
|
||||
}
|
||||
}
|
||||
const fallbacks = req.body["org.matrix.msc3202.device_unused_fallback_key_types"];
|
||||
if (fallbacks) {
|
||||
this.emit("otk.unused_fallback_keys", fallbacks);
|
||||
}
|
||||
if (fallbacks && this.cryptoStorage) {
|
||||
for (const userId of Object.keys(fallbacks)) {
|
||||
const intent = this.getIntentForUserId(userId);
|
||||
await intent.enableEncryption();
|
||||
const fallbacksForUser = fallbacks[userId][intent.underlyingClient.crypto.clientDeviceId];
|
||||
if (Array.isArray(fallbacksForUser) && !fallbacksForUser.includes(__1.OTKAlgorithm.Signed)) {
|
||||
if (!byUserId[userId]) {
|
||||
byUserId[userId] = {
|
||||
counts: null,
|
||||
toDevice: null,
|
||||
unusedFallbacks: null,
|
||||
};
|
||||
}
|
||||
byUserId[userId].unusedFallbacks = fallbacksForUser;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (this.cryptoStorage) {
|
||||
for (const userId of Object.keys(byUserId)) {
|
||||
const intent = this.getIntentForUserId(userId);
|
||||
await intent.enableEncryption();
|
||||
const info = byUserId[userId];
|
||||
const userStorage = this.storage.storageForUser(userId);
|
||||
if (!info.toDevice)
|
||||
info.toDevice = [];
|
||||
if (!info.unusedFallbacks)
|
||||
info.unusedFallbacks = JSON.parse(await userStorage.readValue("last_unused_fallbacks") || "[]");
|
||||
if (!info.counts)
|
||||
info.counts = JSON.parse(await userStorage.readValue("last_counts") || "{}");
|
||||
__1.LogService.info("Appservice", `Updating crypto state for ${userId}`);
|
||||
await intent.underlyingClient.crypto.updateSyncData(info.toDevice, info.counts, info.unusedFallbacks, deviceLists.changed, deviceLists.removed);
|
||||
}
|
||||
}
|
||||
for (let event of req.body["events"]) {
|
||||
__1.LogService.info("Appservice", `Processing event of type ${event["type"]}`);
|
||||
event = await this.processEvent(event);
|
||||
if (event['type'] === 'm.room.encrypted') {
|
||||
this.emit("room.encrypted_event", event["room_id"], event);
|
||||
if (this.cryptoStorage) {
|
||||
try {
|
||||
const encrypted = new __1.EncryptedRoomEvent(event);
|
||||
const roomId = event['room_id'];
|
||||
try {
|
||||
event = (await this.botClient.crypto.decryptRoomEvent(encrypted, roomId)).raw;
|
||||
event = await this.processEvent(event);
|
||||
this.emit("room.decrypted_event", roomId, event);
|
||||
// For logging purposes: show that the event was decrypted
|
||||
__1.LogService.info("Appservice", `Processing decrypted event of type ${event["type"]}`);
|
||||
}
|
||||
catch (e1) {
|
||||
__1.LogService.warn("Appservice", `Bot client was not able to decrypt ${roomId} ${event['event_id']} - trying other intents`);
|
||||
let tryUserId;
|
||||
try {
|
||||
// TODO: This could be more efficient
|
||||
const userIdsInRoom = await this.botClient.getJoinedRoomMembers(roomId);
|
||||
tryUserId = userIdsInRoom.find(u => this.isNamespacedUser(u));
|
||||
}
|
||||
catch (e) {
|
||||
__1.LogService.error("Appservice", "Failed to get members of room - cannot decrypt message");
|
||||
}
|
||||
if (tryUserId) {
|
||||
const intent = this.getIntentForUserId(tryUserId);
|
||||
event = (await intent.underlyingClient.crypto.decryptRoomEvent(encrypted, roomId)).raw;
|
||||
event = await this.processEvent(event);
|
||||
this.emit("room.decrypted_event", roomId, event);
|
||||
// For logging purposes: show that the event was decrypted
|
||||
__1.LogService.info("Appservice", `Processing decrypted event of type ${event["type"]}`);
|
||||
}
|
||||
else {
|
||||
// noinspection ExceptionCaughtLocallyJS
|
||||
throw e1;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (e) {
|
||||
__1.LogService.error("Appservice", `Decryption error on ${event['room_id']} ${event['event_id']}`, e);
|
||||
this.emit("room.failed_decryption", event['room_id'], event, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
this.emit("room.event", event["room_id"], event);
|
||||
if (event['type'] === 'm.room.message') {
|
||||
this.emit("room.message", event["room_id"], event);
|
||||
}
|
||||
if (event['type'] === 'm.room.member' && this.isNamespacedUser(event['state_key'])) {
|
||||
await this.processMembershipEvent(event);
|
||||
}
|
||||
if (event['type'] === 'm.room.tombstone' && event['state_key'] === '') {
|
||||
this.emit("room.archived", event['room_id'], event);
|
||||
}
|
||||
if (event['type'] === 'm.room.create' && event['state_key'] === '' && event['content'] && event['content']['predecessor']) {
|
||||
this.emit("room.upgraded", event['room_id'], event);
|
||||
}
|
||||
}
|
||||
resolve();
|
||||
});
|
||||
try {
|
||||
await this.pendingTransactions[txnId];
|
||||
await Promise.resolve(this.storage.setTransactionCompleted(txnId));
|
||||
res.status(200).json({});
|
||||
}
|
||||
catch (e) {
|
||||
__1.LogService.error("Appservice", e);
|
||||
res.status(500).json({});
|
||||
}
|
||||
}
|
||||
async onUser(req, res) {
|
||||
if (!this.isAuthed(req)) {
|
||||
res.status(401).json({ errcode: "AUTH_FAILED", error: "Authentication failed" });
|
||||
return;
|
||||
}
|
||||
const userId = req.params["userId"];
|
||||
this.emit("query.user", userId, async (result) => {
|
||||
if (result.then)
|
||||
result = await result;
|
||||
if (result === false) {
|
||||
res.status(404).json({ errcode: "USER_DOES_NOT_EXIST", error: "User not created" });
|
||||
}
|
||||
else {
|
||||
const intent = this.getIntentForUserId(userId);
|
||||
await intent.ensureRegistered();
|
||||
if (result.display_name)
|
||||
await intent.underlyingClient.setDisplayName(result.display_name);
|
||||
if (result.avatar_mxc)
|
||||
await intent.underlyingClient.setAvatarUrl(result.avatar_mxc);
|
||||
res.status(200).json(result); // return result for debugging + testing
|
||||
}
|
||||
});
|
||||
}
|
||||
async onRoomAlias(req, res) {
|
||||
if (!this.isAuthed(req)) {
|
||||
res.status(401).json({ errcode: "AUTH_FAILED", error: "Authentication failed" });
|
||||
return;
|
||||
}
|
||||
const roomAlias = req.params["roomAlias"];
|
||||
this.emit("query.room", roomAlias, async (result) => {
|
||||
if (result.then)
|
||||
result = await result;
|
||||
if (result === false) {
|
||||
res.status(404).json({ errcode: "ROOM_DOES_NOT_EXIST", error: "Room not created" });
|
||||
}
|
||||
else {
|
||||
const intent = this.botIntent;
|
||||
await intent.ensureRegistered();
|
||||
result["room_alias_name"] = roomAlias.substring(1).split(':')[0];
|
||||
result["__roomId"] = await intent.underlyingClient.createRoom(result);
|
||||
res.status(200).json(result); // return result for debugging + testing
|
||||
}
|
||||
});
|
||||
}
|
||||
async onKeysClaim(req, res) {
|
||||
if (!this.isAuthed(req)) {
|
||||
res.status(401).json({ errcode: "AUTH_FAILED", error: "Authentication failed" });
|
||||
return;
|
||||
}
|
||||
if (typeof (req.body) !== "object") {
|
||||
res.status(400).json({ errcode: "BAD_REQUEST", error: "Expected JSON" });
|
||||
return;
|
||||
}
|
||||
let responded = false;
|
||||
this.emit("query.key_claim", req.body, (result) => {
|
||||
responded = true;
|
||||
const handleResult = (result2) => {
|
||||
if (!result2) {
|
||||
res.status(404).json({ errcode: "M_UNRECOGNIZED", error: "Endpoint not implemented" });
|
||||
return;
|
||||
}
|
||||
res.status(200).json(result2);
|
||||
};
|
||||
Promise.resolve(result).then(r => handleResult(r)).catch(e => {
|
||||
__1.LogService.error("Appservice", "Error handling key claim API", e);
|
||||
res.status(500).json({ errcode: "M_UNKNOWN", error: "Error handling key claim API" });
|
||||
});
|
||||
});
|
||||
if (!responded) {
|
||||
res.status(404).json({ errcode: "M_UNRECOGNIZED", error: "Endpoint not implemented" });
|
||||
}
|
||||
}
|
||||
async onKeysQuery(req, res) {
|
||||
if (!this.isAuthed(req)) {
|
||||
res.status(401).json({ errcode: "AUTH_FAILED", error: "Authentication failed" });
|
||||
return;
|
||||
}
|
||||
if (typeof (req.body) !== "object") {
|
||||
res.status(400).json({ errcode: "BAD_REQUEST", error: "Expected JSON" });
|
||||
return;
|
||||
}
|
||||
let responded = false;
|
||||
this.emit("query.key", req.body, (result) => {
|
||||
responded = true;
|
||||
const handleResult = (result2) => {
|
||||
if (!result2) {
|
||||
res.status(404).json({ errcode: "M_UNRECOGNIZED", error: "Endpoint not implemented" });
|
||||
return;
|
||||
}
|
||||
// Implementation note: we could probably query the device keys from our storage if we wanted to.
|
||||
res.status(200).json(result2);
|
||||
};
|
||||
Promise.resolve(result).then(r => handleResult(r)).catch(e => {
|
||||
__1.LogService.error("Appservice", "Error handling key query API", e);
|
||||
res.status(500).json({ errcode: "M_UNKNOWN", error: "Error handling key query API" });
|
||||
});
|
||||
});
|
||||
if (!responded) {
|
||||
res.status(404).json({ errcode: "M_UNRECOGNIZED", error: "Endpoint not implemented" });
|
||||
}
|
||||
}
|
||||
onThirdpartyProtocol(req, res) {
|
||||
if (!this.isAuthed(req)) {
|
||||
res.status(401).json({ errcode: "AUTH_FAILED", error: "Authentication failed" });
|
||||
return;
|
||||
}
|
||||
const protocol = req.params["protocol"];
|
||||
if (!this.registration.protocols.includes(protocol)) {
|
||||
res.status(404).json({
|
||||
errcode: "PROTOCOL_NOT_HANDLED",
|
||||
error: "Protocol is not handled by this appservice",
|
||||
});
|
||||
return;
|
||||
}
|
||||
this.emit("thirdparty.protocol", protocol, (protocolResponse) => {
|
||||
res.status(200).json(protocolResponse);
|
||||
});
|
||||
}
|
||||
handleThirdpartyObject(req, res, objType, matrixId) {
|
||||
if (!this.isAuthed(req)) {
|
||||
res.status(401).json({ errcode: "AUTH_FAILED", error: "Authentication failed" });
|
||||
return;
|
||||
}
|
||||
const protocol = req.params["protocol"];
|
||||
const responseFunc = (items) => {
|
||||
if (items && items.length > 0) {
|
||||
res.status(200).json(items);
|
||||
return;
|
||||
}
|
||||
res.status(404).json({
|
||||
errcode: "NO_MAPPING_FOUND",
|
||||
error: "No mappings found",
|
||||
});
|
||||
};
|
||||
// Lookup remote objects(s)
|
||||
if (protocol) { // If protocol is given, we are looking up a objects based on fields
|
||||
if (!this.registration.protocols.includes(protocol)) {
|
||||
res.status(404).json({
|
||||
errcode: "PROTOCOL_NOT_HANDLED",
|
||||
error: "Protocol is not handled by this appservice",
|
||||
});
|
||||
return;
|
||||
}
|
||||
// Remove the access_token
|
||||
delete req.query.access_token;
|
||||
this.emit(`thirdparty.${objType}.remote`, protocol, req.query, responseFunc);
|
||||
return;
|
||||
}
|
||||
else if (matrixId) { // If a user ID is given, we are looking up a remote objects based on a id
|
||||
this.emit(`thirdparty.${objType}.matrix`, matrixId, responseFunc);
|
||||
return;
|
||||
}
|
||||
res.status(400).json({
|
||||
errcode: "INVALID_PARAMETERS",
|
||||
error: "Invalid parameters given",
|
||||
});
|
||||
}
|
||||
onThirdpartyUser(req, res) {
|
||||
return this.handleThirdpartyObject(req, res, "user", req.query["userid"]);
|
||||
}
|
||||
onThirdpartyLocation(req, res) {
|
||||
return this.handleThirdpartyObject(req, res, "location", req.query["alias"]);
|
||||
}
|
||||
}
|
||||
exports.Appservice = Appservice;
|
||||
//# sourceMappingURL=Appservice.js.map
|
1
node_modules/matrix-bot-sdk/lib/appservice/Appservice.js.map
generated
vendored
Normal file
1
node_modules/matrix-bot-sdk/lib/appservice/Appservice.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
113
node_modules/matrix-bot-sdk/lib/appservice/Intent.d.ts
generated
vendored
Normal file
113
node_modules/matrix-bot-sdk/lib/appservice/Intent.d.ts
generated
vendored
Normal file
@@ -0,0 +1,113 @@
|
||||
import { MatrixClient, Metrics } from "..";
|
||||
import { Appservice, IAppserviceOptions } from "./Appservice";
|
||||
import { UnstableAppserviceApis } from "./UnstableAppserviceApis";
|
||||
/**
|
||||
* An Intent is an intelligent client that tracks things like the user's membership
|
||||
* in rooms to ensure the action being performed is possible. This is very similar
|
||||
* to how Intents work in the matrix-js-sdk in that the Intent will ensure that the
|
||||
* user is joined to the room before posting a message, for example.
|
||||
* @category Application services
|
||||
*/
|
||||
export declare class Intent {
|
||||
private options;
|
||||
private impersonateUserId;
|
||||
private appservice;
|
||||
/**
|
||||
* The metrics instance for this intent. Note that this will not raise metrics
|
||||
* for the underlying client - those will be available through this instance's
|
||||
* parent (the appservice).
|
||||
*/
|
||||
readonly metrics: Metrics;
|
||||
private readonly storage;
|
||||
private readonly cryptoStorage;
|
||||
private client;
|
||||
private unstableApisInstance;
|
||||
private knownJoinedRooms;
|
||||
private cryptoSetupPromise;
|
||||
/**
|
||||
* Creates a new intent. Intended to be created by application services.
|
||||
* @param {IAppserviceOptions} options The options for the application service.
|
||||
* @param {string} impersonateUserId The user ID to impersonate.
|
||||
* @param {Appservice} appservice The application service itself.
|
||||
*/
|
||||
constructor(options: IAppserviceOptions, impersonateUserId: string, appservice: Appservice);
|
||||
private makeClient;
|
||||
/**
|
||||
* Gets the user ID this intent is for.
|
||||
*/
|
||||
get userId(): string;
|
||||
/**
|
||||
* Gets the underlying MatrixClient that powers this Intent.
|
||||
*/
|
||||
get underlyingClient(): MatrixClient;
|
||||
/**
|
||||
* Gets the unstable API access class. This is generally not recommended to be
|
||||
* used by appservices.
|
||||
* @return {UnstableAppserviceApis} The unstable API access class.
|
||||
*/
|
||||
get unstableApis(): UnstableAppserviceApis;
|
||||
/**
|
||||
* Sets up crypto on the client if it hasn't already been set up.
|
||||
* @returns {Promise<void>} Resolves when complete.
|
||||
*/
|
||||
enableEncryption(): Promise<void>;
|
||||
/**
|
||||
* Gets the joined rooms for the intent. Note that by working around
|
||||
* the intent to join rooms may yield inaccurate results.
|
||||
* @returns {Promise<string[]>} Resolves to an array of room IDs where
|
||||
* the intent is joined.
|
||||
*/
|
||||
getJoinedRooms(): Promise<string[]>;
|
||||
/**
|
||||
* Leaves the given room.
|
||||
* @param {string} roomId The room ID to leave
|
||||
* @param {string=} reason Optional reason to be included as the reason for leaving the room.
|
||||
* @returns {Promise<any>} Resolves when the room has been left.
|
||||
*/
|
||||
leaveRoom(roomId: string, reason?: string): Promise<any>;
|
||||
/**
|
||||
* Joins the given room
|
||||
* @param {string} roomIdOrAlias the room ID or alias to join
|
||||
* @returns {Promise<string>} resolves to the joined room ID
|
||||
*/
|
||||
joinRoom(roomIdOrAlias: string): Promise<string>;
|
||||
/**
|
||||
* Sends a text message to a room.
|
||||
* @param {string} roomId The room ID to send text to.
|
||||
* @param {string} body The message body to send.
|
||||
* @param {"m.text" | "m.emote" | "m.notice"} msgtype The message type to send.
|
||||
* @returns {Promise<string>} Resolves to the event ID of the sent message.
|
||||
*/
|
||||
sendText(roomId: string, body: string, msgtype?: "m.text" | "m.emote" | "m.notice"): Promise<string>;
|
||||
/**
|
||||
* Sends an event to a room.
|
||||
* @param {string} roomId The room ID to send the event to.
|
||||
* @param {any} content The content of the event.
|
||||
* @returns {Promise<string>} Resolves to the event ID of the sent event.
|
||||
*/
|
||||
sendEvent(roomId: string, content: any): Promise<string>;
|
||||
/**
|
||||
* Ensures the user is registered and joined to the given room.
|
||||
* @param {string} roomId The room ID to join
|
||||
* @returns {Promise<any>} Resolves when complete
|
||||
*/
|
||||
ensureRegisteredAndJoined(roomId: string): Promise<void>;
|
||||
/**
|
||||
* Ensures the user is joined to the given room
|
||||
* @param {string} roomId The room ID to join
|
||||
* @returns {Promise<any>} Resolves when complete
|
||||
*/
|
||||
ensureJoined(roomId: string): Promise<string>;
|
||||
/**
|
||||
* Refreshes which rooms the user is joined to, potentially saving time on
|
||||
* calls like ensureJoined()
|
||||
* @returns {Promise<string[]>} Resolves to the joined room IDs for the user.
|
||||
*/
|
||||
refreshJoinedRooms(): Promise<string[]>;
|
||||
/**
|
||||
* Ensures the user is registered
|
||||
* @param deviceId An optional device ID to register with.
|
||||
* @returns {Promise<any>} Resolves when complete
|
||||
*/
|
||||
ensureRegistered(deviceId?: string): Promise<any>;
|
||||
}
|
363
node_modules/matrix-bot-sdk/lib/appservice/Intent.js
generated
vendored
Normal file
363
node_modules/matrix-bot-sdk/lib/appservice/Intent.js
generated
vendored
Normal file
@@ -0,0 +1,363 @@
|
||||
"use strict";
|
||||
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
||||
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
||||
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
||||
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
||||
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
||||
};
|
||||
var __metadata = (this && this.__metadata) || function (k, v) {
|
||||
if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.Intent = void 0;
|
||||
const __1 = require("..");
|
||||
// noinspection TypeScriptPreferShortImport
|
||||
const decorators_1 = require("../metrics/decorators");
|
||||
const UnstableAppserviceApis_1 = require("./UnstableAppserviceApis");
|
||||
const MatrixError_1 = require("../models/MatrixError");
|
||||
/**
|
||||
* An Intent is an intelligent client that tracks things like the user's membership
|
||||
* in rooms to ensure the action being performed is possible. This is very similar
|
||||
* to how Intents work in the matrix-js-sdk in that the Intent will ensure that the
|
||||
* user is joined to the room before posting a message, for example.
|
||||
* @category Application services
|
||||
*/
|
||||
class Intent {
|
||||
/**
|
||||
* Creates a new intent. Intended to be created by application services.
|
||||
* @param {IAppserviceOptions} options The options for the application service.
|
||||
* @param {string} impersonateUserId The user ID to impersonate.
|
||||
* @param {Appservice} appservice The application service itself.
|
||||
*/
|
||||
constructor(options, impersonateUserId, appservice) {
|
||||
this.options = options;
|
||||
this.impersonateUserId = impersonateUserId;
|
||||
this.appservice = appservice;
|
||||
this.knownJoinedRooms = [];
|
||||
this.metrics = new __1.Metrics(appservice.metrics);
|
||||
this.storage = options.storage;
|
||||
this.cryptoStorage = options.cryptoStorage;
|
||||
this.makeClient(false);
|
||||
}
|
||||
makeClient(withCrypto, accessToken) {
|
||||
let cryptoStore;
|
||||
const storage = this.storage?.storageForUser?.(this.userId);
|
||||
if (withCrypto) {
|
||||
cryptoStore = this.cryptoStorage?.storageForUser(this.userId);
|
||||
if (!cryptoStore) {
|
||||
throw new Error("Tried to set up client with crypto when not available");
|
||||
}
|
||||
if (!storage) {
|
||||
throw new Error("Tried to set up client with crypto, but no persistent storage");
|
||||
}
|
||||
}
|
||||
this.client = new __1.MatrixClient(this.options.homeserverUrl, accessToken ?? this.options.registration.as_token, storage, cryptoStore);
|
||||
this.client.metrics = new __1.Metrics(this.appservice.metrics); // Metrics only go up by one parent
|
||||
this.unstableApisInstance = new UnstableAppserviceApis_1.UnstableAppserviceApis(this.client);
|
||||
if (this.impersonateUserId !== this.appservice.botUserId) {
|
||||
this.client.impersonateUserId(this.impersonateUserId);
|
||||
}
|
||||
if (this.options.joinStrategy) {
|
||||
this.client.setJoinStrategy(this.options.joinStrategy);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Gets the user ID this intent is for.
|
||||
*/
|
||||
get userId() {
|
||||
return this.impersonateUserId;
|
||||
}
|
||||
/**
|
||||
* Gets the underlying MatrixClient that powers this Intent.
|
||||
*/
|
||||
get underlyingClient() {
|
||||
return this.client;
|
||||
}
|
||||
/**
|
||||
* Gets the unstable API access class. This is generally not recommended to be
|
||||
* used by appservices.
|
||||
* @return {UnstableAppserviceApis} The unstable API access class.
|
||||
*/
|
||||
get unstableApis() {
|
||||
return this.unstableApisInstance;
|
||||
}
|
||||
/**
|
||||
* Sets up crypto on the client if it hasn't already been set up.
|
||||
* @returns {Promise<void>} Resolves when complete.
|
||||
*/
|
||||
async enableEncryption() {
|
||||
if (!this.cryptoSetupPromise) {
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
this.cryptoSetupPromise = new Promise(async (resolve, reject) => {
|
||||
try {
|
||||
// Prepare a client first
|
||||
await this.ensureRegistered();
|
||||
const storage = this.storage?.storageForUser?.(this.userId);
|
||||
this.client.impersonateUserId(this.userId); // make sure the devices call works
|
||||
const cryptoStore = this.cryptoStorage?.storageForUser(this.userId);
|
||||
if (!cryptoStore) {
|
||||
// noinspection ExceptionCaughtLocallyJS
|
||||
throw new Error("Failed to create crypto store");
|
||||
}
|
||||
// Try to impersonate a device ID
|
||||
const ownDevices = await this.client.getOwnDevices();
|
||||
let deviceId = await cryptoStore.getDeviceId();
|
||||
if (!deviceId || !ownDevices.some(d => d.device_id === deviceId)) {
|
||||
const deviceKeys = await this.client.getUserDevices([this.userId]);
|
||||
const userDeviceKeys = deviceKeys.device_keys[this.userId];
|
||||
if (userDeviceKeys) {
|
||||
// We really should be validating signatures here, but we're actively looking
|
||||
// for devices without keys to impersonate, so it should be fine. In theory,
|
||||
// those devices won't even be present but we're cautious.
|
||||
const devicesWithKeys = Array.from(Object.entries(userDeviceKeys))
|
||||
.filter(d => d[0] === d[1].device_id && !!d[1].keys?.[`${__1.DeviceKeyAlgorithm.Curve25519}:${d[1].device_id}`])
|
||||
.map(t => t[0]); // grab device ID from tuple
|
||||
deviceId = ownDevices.find(d => !devicesWithKeys.includes(d.device_id))?.device_id;
|
||||
}
|
||||
}
|
||||
let prepared = false;
|
||||
if (deviceId) {
|
||||
this.makeClient(true);
|
||||
this.client.impersonateUserId(this.userId, deviceId);
|
||||
// verify that the server supports impersonating the device
|
||||
const respDeviceId = (await this.client.getWhoAmI()).device_id;
|
||||
prepared = (respDeviceId === deviceId);
|
||||
}
|
||||
if (!prepared) {
|
||||
// XXX: We work around servers that don't support device_id impersonation
|
||||
const accessToken = await Promise.resolve(storage?.readValue("accessToken"));
|
||||
if (!accessToken) {
|
||||
const loginBody = {
|
||||
type: "m.login.application_service",
|
||||
identifier: {
|
||||
type: "m.id.user",
|
||||
user: this.userId,
|
||||
},
|
||||
};
|
||||
const res = await this.client.doRequest("POST", "/_matrix/client/v3/login", {}, loginBody);
|
||||
this.makeClient(true, res['access_token']);
|
||||
storage.storeValue("accessToken", this.client.accessToken);
|
||||
prepared = true;
|
||||
}
|
||||
else {
|
||||
this.makeClient(true, accessToken);
|
||||
prepared = true;
|
||||
}
|
||||
}
|
||||
if (!prepared) { // noinspection ExceptionCaughtLocallyJS
|
||||
throw new Error("Unable to establish a device ID");
|
||||
}
|
||||
// Now set up crypto
|
||||
await this.client.crypto.prepare(await this.refreshJoinedRooms());
|
||||
this.appservice.on("room.event", (roomId, event) => {
|
||||
if (!this.knownJoinedRooms.includes(roomId))
|
||||
return;
|
||||
this.client.crypto.onRoomEvent(roomId, event);
|
||||
});
|
||||
resolve();
|
||||
}
|
||||
catch (e) {
|
||||
reject(e);
|
||||
}
|
||||
});
|
||||
}
|
||||
return this.cryptoSetupPromise;
|
||||
}
|
||||
/**
|
||||
* Gets the joined rooms for the intent. Note that by working around
|
||||
* the intent to join rooms may yield inaccurate results.
|
||||
* @returns {Promise<string[]>} Resolves to an array of room IDs where
|
||||
* the intent is joined.
|
||||
*/
|
||||
async getJoinedRooms() {
|
||||
await this.ensureRegistered();
|
||||
if (this.knownJoinedRooms.length === 0)
|
||||
await this.refreshJoinedRooms();
|
||||
return this.knownJoinedRooms.map(r => r); // clone
|
||||
}
|
||||
/**
|
||||
* Leaves the given room.
|
||||
* @param {string} roomId The room ID to leave
|
||||
* @param {string=} reason Optional reason to be included as the reason for leaving the room.
|
||||
* @returns {Promise<any>} Resolves when the room has been left.
|
||||
*/
|
||||
async leaveRoom(roomId, reason) {
|
||||
await this.ensureRegistered();
|
||||
return this.client.leaveRoom(roomId, reason).then(async () => {
|
||||
// Recalculate joined rooms now that we've left a room
|
||||
await this.refreshJoinedRooms();
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Joins the given room
|
||||
* @param {string} roomIdOrAlias the room ID or alias to join
|
||||
* @returns {Promise<string>} resolves to the joined room ID
|
||||
*/
|
||||
async joinRoom(roomIdOrAlias) {
|
||||
await this.ensureRegistered();
|
||||
return this.client.joinRoom(roomIdOrAlias).then(async (roomId) => {
|
||||
// Recalculate joined rooms now that we've joined a room
|
||||
await this.refreshJoinedRooms();
|
||||
return roomId;
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Sends a text message to a room.
|
||||
* @param {string} roomId The room ID to send text to.
|
||||
* @param {string} body The message body to send.
|
||||
* @param {"m.text" | "m.emote" | "m.notice"} msgtype The message type to send.
|
||||
* @returns {Promise<string>} Resolves to the event ID of the sent message.
|
||||
*/
|
||||
async sendText(roomId, body, msgtype = "m.text") {
|
||||
return this.sendEvent(roomId, { body: body, msgtype: msgtype });
|
||||
}
|
||||
/**
|
||||
* Sends an event to a room.
|
||||
* @param {string} roomId The room ID to send the event to.
|
||||
* @param {any} content The content of the event.
|
||||
* @returns {Promise<string>} Resolves to the event ID of the sent event.
|
||||
*/
|
||||
async sendEvent(roomId, content) {
|
||||
await this.ensureRegisteredAndJoined(roomId);
|
||||
return this.client.sendMessage(roomId, content);
|
||||
}
|
||||
/**
|
||||
* Ensures the user is registered and joined to the given room.
|
||||
* @param {string} roomId The room ID to join
|
||||
* @returns {Promise<any>} Resolves when complete
|
||||
*/
|
||||
async ensureRegisteredAndJoined(roomId) {
|
||||
await this.ensureRegistered();
|
||||
await this.ensureJoined(roomId);
|
||||
}
|
||||
/**
|
||||
* Ensures the user is joined to the given room
|
||||
* @param {string} roomId The room ID to join
|
||||
* @returns {Promise<any>} Resolves when complete
|
||||
*/
|
||||
async ensureJoined(roomId) {
|
||||
if (this.knownJoinedRooms.indexOf(roomId) !== -1) {
|
||||
return;
|
||||
}
|
||||
await this.refreshJoinedRooms();
|
||||
if (this.knownJoinedRooms.indexOf(roomId) !== -1) {
|
||||
return;
|
||||
}
|
||||
const returnedRoomId = await this.client.joinRoom(roomId);
|
||||
if (!this.knownJoinedRooms.includes(returnedRoomId)) {
|
||||
this.knownJoinedRooms.push(returnedRoomId);
|
||||
}
|
||||
return returnedRoomId;
|
||||
}
|
||||
/**
|
||||
* Refreshes which rooms the user is joined to, potentially saving time on
|
||||
* calls like ensureJoined()
|
||||
* @returns {Promise<string[]>} Resolves to the joined room IDs for the user.
|
||||
*/
|
||||
async refreshJoinedRooms() {
|
||||
this.knownJoinedRooms = await this.client.getJoinedRooms();
|
||||
return this.knownJoinedRooms.map(r => r); // clone
|
||||
}
|
||||
/**
|
||||
* Ensures the user is registered
|
||||
* @param deviceId An optional device ID to register with.
|
||||
* @returns {Promise<any>} Resolves when complete
|
||||
*/
|
||||
async ensureRegistered(deviceId) {
|
||||
if (!(await Promise.resolve(this.storage.isUserRegistered(this.userId)))) {
|
||||
try {
|
||||
const result = await this.client.doRequest("POST", "/_matrix/client/v3/register", null, {
|
||||
type: "m.login.application_service",
|
||||
username: this.userId.substring(1).split(":")[0],
|
||||
device_id: deviceId,
|
||||
});
|
||||
// HACK: Workaround for unit tests
|
||||
if (result['errcode']) {
|
||||
// noinspection ExceptionCaughtLocallyJS
|
||||
throw { body: result }; // eslint-disable-line no-throw-literal
|
||||
}
|
||||
this.client.impersonateUserId(this.userId, result["device_id"]);
|
||||
}
|
||||
catch (err) {
|
||||
if (err instanceof MatrixError_1.MatrixError && err.errcode === "M_USER_IN_USE") {
|
||||
await Promise.resolve(this.storage.addRegisteredUser(this.userId));
|
||||
if (this.userId === this.appservice.botUserId) {
|
||||
return null;
|
||||
}
|
||||
else {
|
||||
__1.LogService.error("Appservice", "Error registering user: User ID is in use");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
else {
|
||||
__1.LogService.error("Appservice", "Encountered error registering user: ");
|
||||
__1.LogService.error("Appservice", (0, __1.extractRequestError)(err));
|
||||
}
|
||||
throw err;
|
||||
}
|
||||
await Promise.resolve(this.storage.addRegisteredUser(this.userId));
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.Intent = Intent;
|
||||
__decorate([
|
||||
(0, decorators_1.timedIntentFunctionCall)(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", Promise)
|
||||
], Intent.prototype, "enableEncryption", null);
|
||||
__decorate([
|
||||
(0, decorators_1.timedIntentFunctionCall)(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", Promise)
|
||||
], Intent.prototype, "getJoinedRooms", null);
|
||||
__decorate([
|
||||
(0, decorators_1.timedIntentFunctionCall)(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], Intent.prototype, "leaveRoom", null);
|
||||
__decorate([
|
||||
(0, decorators_1.timedIntentFunctionCall)(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], Intent.prototype, "joinRoom", null);
|
||||
__decorate([
|
||||
(0, decorators_1.timedIntentFunctionCall)(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, String, String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], Intent.prototype, "sendText", null);
|
||||
__decorate([
|
||||
(0, decorators_1.timedIntentFunctionCall)(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String, Object]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], Intent.prototype, "sendEvent", null);
|
||||
__decorate([
|
||||
(0, decorators_1.timedIntentFunctionCall)(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], Intent.prototype, "ensureRegisteredAndJoined", null);
|
||||
__decorate([
|
||||
(0, decorators_1.timedIntentFunctionCall)(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], Intent.prototype, "ensureJoined", null);
|
||||
__decorate([
|
||||
(0, decorators_1.timedIntentFunctionCall)(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", []),
|
||||
__metadata("design:returntype", Promise)
|
||||
], Intent.prototype, "refreshJoinedRooms", null);
|
||||
__decorate([
|
||||
(0, decorators_1.timedIntentFunctionCall)(),
|
||||
__metadata("design:type", Function),
|
||||
__metadata("design:paramtypes", [String]),
|
||||
__metadata("design:returntype", Promise)
|
||||
], Intent.prototype, "ensureRegistered", null);
|
||||
//# sourceMappingURL=Intent.js.map
|
1
node_modules/matrix-bot-sdk/lib/appservice/Intent.js.map
generated
vendored
Normal file
1
node_modules/matrix-bot-sdk/lib/appservice/Intent.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
85
node_modules/matrix-bot-sdk/lib/appservice/MatrixBridge.d.ts
generated
vendored
Normal file
85
node_modules/matrix-bot-sdk/lib/appservice/MatrixBridge.d.ts
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
import { Appservice } from "./Appservice";
|
||||
import { Intent } from "./Intent";
|
||||
export declare const REMOTE_USER_INFO_ACCOUNT_DATA_EVENT_TYPE = "io.t2bot.sdk.bot.remote_user_info";
|
||||
export declare const REMOTE_ROOM_INFO_ACCOUNT_DATA_EVENT_TYPE = "io.t2bot.sdk.bot.remote_room_info";
|
||||
export declare const REMOTE_USER_MAP_ACCOUNT_DATA_EVENT_TYPE_PREFIX = "io.t2bot.sdk.bot.remote_user_map";
|
||||
export declare const REMOTE_ROOM_MAP_ACCOUNT_DATA_EVENT_TYPE_PREFIX = "io.t2bot.sdk.bot.remote_room_map";
|
||||
/**
|
||||
* @see MatrixBridge
|
||||
* @category Application services
|
||||
*/
|
||||
export interface IRemoteRoomInfo {
|
||||
/**
|
||||
* A unique identifier for the remote user.
|
||||
*/
|
||||
id: string;
|
||||
}
|
||||
/**
|
||||
* @see MatrixBridge
|
||||
* @category Application services
|
||||
*/
|
||||
export interface IRemoteUserInfo {
|
||||
/**
|
||||
* A unique identifier for the remote room (or room equivalent).
|
||||
*/
|
||||
id: string;
|
||||
}
|
||||
/**
|
||||
* Utility class for common operations performed by bridges (represented
|
||||
* as appservices).
|
||||
*
|
||||
* The storage utilities are not intended for bridges which allow 1:many
|
||||
* relationships with the remote network.
|
||||
*
|
||||
* Bridges are generally expected to create their own classes which extend
|
||||
* the IRemoteRoomInfo and IRemoteUserInfo interfaces and serialize to JSON
|
||||
* cleanly. The serialized version of these classes is persisted in various
|
||||
* account data locations for future lookups.
|
||||
* @category Application services
|
||||
*/
|
||||
export declare class MatrixBridge {
|
||||
private appservice;
|
||||
constructor(appservice: Appservice);
|
||||
/**
|
||||
* Gets information about a remote user.
|
||||
* @param {Intent} userIntent The Matrix user intent to get information on.
|
||||
* @returns {Promise<IRemoteUserInfo>} Resolves to the remote user information.
|
||||
*/
|
||||
getRemoteUserInfo<T extends IRemoteUserInfo>(userIntent: Intent): Promise<T>;
|
||||
/**
|
||||
* Sets information about a remote user. Calling this function will map the
|
||||
* provided remote user ID to the intent's owner.
|
||||
* @param {Intent} userIntent The Matrix user intent to store information on.
|
||||
* @param {IRemoteUserInfo} remoteInfo The remote user information to store
|
||||
* @returns {Promise<any>} Resolves when the information has been updated.
|
||||
*/
|
||||
setRemoteUserInfo<T extends IRemoteUserInfo>(userIntent: Intent, remoteInfo: T): Promise<any>;
|
||||
/**
|
||||
* Gets information about a remote room.
|
||||
* @param {string} matrixRoomId The Matrix room ID to get information on.
|
||||
* @returns {Promise<IRemoteRoomInfo>} Resolves to the remote room information.
|
||||
*/
|
||||
getRemoteRoomInfo<T extends IRemoteRoomInfo>(matrixRoomId: string): Promise<T>;
|
||||
/**
|
||||
* Sets information about a remote room. Calling this function will map the
|
||||
* provided remote room ID to the matrix room ID.
|
||||
* @param {string} matrixRoomId The Matrix room ID to store information on.
|
||||
* @param {IRemoteRoomInfo} remoteInfo The remote room information to store
|
||||
* @returns {Promise<any>} Resolves when the information has been updated.
|
||||
*/
|
||||
setRemoteRoomInfo<T extends IRemoteRoomInfo>(matrixRoomId: string, remoteInfo: T): Promise<any>;
|
||||
/**
|
||||
* Gets the Matrix room ID for the provided remote room ID.
|
||||
* @param {string} remoteRoomId The remote room ID to look up.
|
||||
* @returns {Promise<string>} Resolves to the Matrix room ID.
|
||||
*/
|
||||
getMatrixRoomIdForRemote(remoteRoomId: string): Promise<string>;
|
||||
/**
|
||||
* Gets a Matrix user intent for the provided remote user ID.
|
||||
* @param {string} remoteUserId The remote user ID to look up.
|
||||
* @returns {Promise<Intent>} Resolves to the Matrix user intent.
|
||||
*/
|
||||
getIntentForRemote(remoteUserId: string): Promise<Intent>;
|
||||
private updateRemoteUserMapping;
|
||||
private updateRemoteRoomMapping;
|
||||
}
|
111
node_modules/matrix-bot-sdk/lib/appservice/MatrixBridge.js
generated
vendored
Normal file
111
node_modules/matrix-bot-sdk/lib/appservice/MatrixBridge.js
generated
vendored
Normal file
@@ -0,0 +1,111 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.MatrixBridge = exports.REMOTE_ROOM_MAP_ACCOUNT_DATA_EVENT_TYPE_PREFIX = exports.REMOTE_USER_MAP_ACCOUNT_DATA_EVENT_TYPE_PREFIX = exports.REMOTE_ROOM_INFO_ACCOUNT_DATA_EVENT_TYPE = exports.REMOTE_USER_INFO_ACCOUNT_DATA_EVENT_TYPE = void 0;
|
||||
exports.REMOTE_USER_INFO_ACCOUNT_DATA_EVENT_TYPE = "io.t2bot.sdk.bot.remote_user_info";
|
||||
exports.REMOTE_ROOM_INFO_ACCOUNT_DATA_EVENT_TYPE = "io.t2bot.sdk.bot.remote_room_info";
|
||||
exports.REMOTE_USER_MAP_ACCOUNT_DATA_EVENT_TYPE_PREFIX = "io.t2bot.sdk.bot.remote_user_map";
|
||||
exports.REMOTE_ROOM_MAP_ACCOUNT_DATA_EVENT_TYPE_PREFIX = "io.t2bot.sdk.bot.remote_room_map";
|
||||
/**
|
||||
* Utility class for common operations performed by bridges (represented
|
||||
* as appservices).
|
||||
*
|
||||
* The storage utilities are not intended for bridges which allow 1:many
|
||||
* relationships with the remote network.
|
||||
*
|
||||
* Bridges are generally expected to create their own classes which extend
|
||||
* the IRemoteRoomInfo and IRemoteUserInfo interfaces and serialize to JSON
|
||||
* cleanly. The serialized version of these classes is persisted in various
|
||||
* account data locations for future lookups.
|
||||
* @category Application services
|
||||
*/
|
||||
class MatrixBridge {
|
||||
constructor(appservice) {
|
||||
this.appservice = appservice;
|
||||
}
|
||||
/**
|
||||
* Gets information about a remote user.
|
||||
* @param {Intent} userIntent The Matrix user intent to get information on.
|
||||
* @returns {Promise<IRemoteUserInfo>} Resolves to the remote user information.
|
||||
*/
|
||||
async getRemoteUserInfo(userIntent) {
|
||||
await userIntent.ensureRegistered();
|
||||
return userIntent.underlyingClient.getAccountData(exports.REMOTE_USER_INFO_ACCOUNT_DATA_EVENT_TYPE);
|
||||
}
|
||||
/**
|
||||
* Sets information about a remote user. Calling this function will map the
|
||||
* provided remote user ID to the intent's owner.
|
||||
* @param {Intent} userIntent The Matrix user intent to store information on.
|
||||
* @param {IRemoteUserInfo} remoteInfo The remote user information to store
|
||||
* @returns {Promise<any>} Resolves when the information has been updated.
|
||||
*/
|
||||
async setRemoteUserInfo(userIntent, remoteInfo) {
|
||||
await userIntent.ensureRegistered();
|
||||
await userIntent.underlyingClient.setAccountData(exports.REMOTE_USER_INFO_ACCOUNT_DATA_EVENT_TYPE, remoteInfo);
|
||||
await this.updateRemoteUserMapping(userIntent.userId, remoteInfo.id);
|
||||
}
|
||||
/**
|
||||
* Gets information about a remote room.
|
||||
* @param {string} matrixRoomId The Matrix room ID to get information on.
|
||||
* @returns {Promise<IRemoteRoomInfo>} Resolves to the remote room information.
|
||||
*/
|
||||
async getRemoteRoomInfo(matrixRoomId) {
|
||||
const bridgeBot = this.appservice.botIntent;
|
||||
await bridgeBot.ensureRegistered();
|
||||
// We do not need to ensure the user is joined to the room because we can associate
|
||||
// room account data with any arbitrary room.
|
||||
return bridgeBot.underlyingClient.getRoomAccountData(exports.REMOTE_ROOM_INFO_ACCOUNT_DATA_EVENT_TYPE, matrixRoomId);
|
||||
}
|
||||
/**
|
||||
* Sets information about a remote room. Calling this function will map the
|
||||
* provided remote room ID to the matrix room ID.
|
||||
* @param {string} matrixRoomId The Matrix room ID to store information on.
|
||||
* @param {IRemoteRoomInfo} remoteInfo The remote room information to store
|
||||
* @returns {Promise<any>} Resolves when the information has been updated.
|
||||
*/
|
||||
async setRemoteRoomInfo(matrixRoomId, remoteInfo) {
|
||||
const bridgeBot = this.appservice.botIntent;
|
||||
await bridgeBot.ensureRegistered();
|
||||
// We do not need to ensure the user is joined to the room because we can associate
|
||||
// room account data with any arbitrary room.
|
||||
await bridgeBot.underlyingClient.setRoomAccountData(exports.REMOTE_ROOM_INFO_ACCOUNT_DATA_EVENT_TYPE, matrixRoomId, remoteInfo);
|
||||
await this.updateRemoteRoomMapping(matrixRoomId, remoteInfo.id);
|
||||
}
|
||||
/**
|
||||
* Gets the Matrix room ID for the provided remote room ID.
|
||||
* @param {string} remoteRoomId The remote room ID to look up.
|
||||
* @returns {Promise<string>} Resolves to the Matrix room ID.
|
||||
*/
|
||||
async getMatrixRoomIdForRemote(remoteRoomId) {
|
||||
const eventType = `${exports.REMOTE_ROOM_MAP_ACCOUNT_DATA_EVENT_TYPE_PREFIX}.${remoteRoomId}`;
|
||||
const bridgeBot = this.appservice.botIntent;
|
||||
await bridgeBot.ensureRegistered();
|
||||
const result = await bridgeBot.underlyingClient.getAccountData(eventType);
|
||||
return result['id'];
|
||||
}
|
||||
/**
|
||||
* Gets a Matrix user intent for the provided remote user ID.
|
||||
* @param {string} remoteUserId The remote user ID to look up.
|
||||
* @returns {Promise<Intent>} Resolves to the Matrix user intent.
|
||||
*/
|
||||
async getIntentForRemote(remoteUserId) {
|
||||
const eventType = `${exports.REMOTE_USER_MAP_ACCOUNT_DATA_EVENT_TYPE_PREFIX}.${remoteUserId}`;
|
||||
const bridgeBot = this.appservice.botIntent;
|
||||
await bridgeBot.ensureRegistered();
|
||||
const result = await bridgeBot.underlyingClient.getAccountData(eventType);
|
||||
return this.appservice.getIntentForUserId(result['id']);
|
||||
}
|
||||
async updateRemoteUserMapping(matrixUserId, remoteUserId) {
|
||||
const eventType = `${exports.REMOTE_USER_MAP_ACCOUNT_DATA_EVENT_TYPE_PREFIX}.${remoteUserId}`;
|
||||
const bridgeBot = this.appservice.botIntent;
|
||||
await bridgeBot.ensureRegistered();
|
||||
await bridgeBot.underlyingClient.setAccountData(eventType, { id: matrixUserId });
|
||||
}
|
||||
async updateRemoteRoomMapping(matrixRoomId, remoteRoomId) {
|
||||
const eventType = `${exports.REMOTE_ROOM_MAP_ACCOUNT_DATA_EVENT_TYPE_PREFIX}.${remoteRoomId}`;
|
||||
const bridgeBot = this.appservice.botIntent;
|
||||
await bridgeBot.ensureRegistered();
|
||||
await bridgeBot.underlyingClient.setAccountData(eventType, { id: matrixRoomId });
|
||||
}
|
||||
}
|
||||
exports.MatrixBridge = MatrixBridge;
|
||||
//# sourceMappingURL=MatrixBridge.js.map
|
1
node_modules/matrix-bot-sdk/lib/appservice/MatrixBridge.js.map
generated
vendored
Normal file
1
node_modules/matrix-bot-sdk/lib/appservice/MatrixBridge.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"MatrixBridge.js","sourceRoot":"","sources":["../../src/appservice/MatrixBridge.ts"],"names":[],"mappings":";;;AAGa,QAAA,wCAAwC,GAAG,mCAAmC,CAAC;AAC/E,QAAA,wCAAwC,GAAG,mCAAmC,CAAC;AAC/E,QAAA,8CAA8C,GAAG,kCAAkC,CAAC;AACpF,QAAA,8CAA8C,GAAG,kCAAkC,CAAC;AAwBjG;;;;;;;;;;;;GAYG;AACH,MAAa,YAAY;IACrB,YAAoB,UAAsB;QAAtB,eAAU,GAAV,UAAU,CAAY;IAC1C,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,iBAAiB,CAA4B,UAAkB;QACxE,MAAM,UAAU,CAAC,gBAAgB,EAAE,CAAC;QACpC,OAAmB,UAAU,CAAC,gBAAgB,CAAC,cAAc,CAAC,gDAAwC,CAAC,CAAC;IAC5G,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,iBAAiB,CAA4B,UAAkB,EAAE,UAAa;QACvF,MAAM,UAAU,CAAC,gBAAgB,EAAE,CAAC;QACpC,MAAM,UAAU,CAAC,gBAAgB,CAAC,cAAc,CAAC,gDAAwC,EAAE,UAAU,CAAC,CAAC;QACvG,MAAM,IAAI,CAAC,uBAAuB,CAAC,UAAU,CAAC,MAAM,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC;IACzE,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,iBAAiB,CAA4B,YAAoB;QAC1E,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAC5C,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;QACnC,mFAAmF;QACnF,6CAA6C;QAC7C,OAAmB,SAAS,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,gDAAwC,EAAE,YAAY,CAAC,CAAC;IAC7H,CAAC;IAED;;;;;;OAMG;IACI,KAAK,CAAC,iBAAiB,CAA4B,YAAoB,EAAE,UAAa;QACzF,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAC5C,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;QACnC,mFAAmF;QACnF,6CAA6C;QAC7C,MAAM,SAAS,CAAC,gBAAgB,CAAC,kBAAkB,CAAC,gDAAwC,EAAE,YAAY,EAAE,UAAU,CAAC,CAAC;QACxH,MAAM,IAAI,CAAC,uBAAuB,CAAC,YAAY,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC;IACpE,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,wBAAwB,CAAC,YAAoB;QACtD,MAAM,SAAS,GAAG,GAAG,sDAA8C,IAAI,YAAY,EAAE,CAAC;QACtF,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAC5C,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,gBAAgB,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QAC1E,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,kBAAkB,CAAC,YAAoB;QAChD,MAAM,SAAS,GAAG,GAAG,sDAA8C,IAAI,YAAY,EAAE,CAAC;QACtF,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAC5C,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;QACnC,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,gBAAgB,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC;QAC1E,OAAO,IAAI,CAAC,UAAU,CAAC,kBAAkB,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC;IAC5D,CAAC;IAEO,KAAK,CAAC,uBAAuB,CAAC,YAAoB,EAAE,YAAoB;QAC5E,MAAM,SAAS,GAAG,GAAG,sDAA8C,IAAI,YAAY,EAAE,CAAC;QACtF,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAC5C,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;QACnC,MAAM,SAAS,CAAC,gBAAgB,CAAC,cAAc,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;IACrF,CAAC;IAEO,KAAK,CAAC,uBAAuB,CAAC,YAAoB,EAAE,YAAoB;QAC5E,MAAM,SAAS,GAAG,GAAG,sDAA8C,IAAI,YAAY,EAAE,CAAC;QACtF,MAAM,SAAS,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAC5C,MAAM,SAAS,CAAC,gBAAgB,EAAE,CAAC;QACnC,MAAM,SAAS,CAAC,gBAAgB,CAAC,cAAc,CAAC,SAAS,EAAE,EAAE,EAAE,EAAE,YAAY,EAAE,CAAC,CAAC;IACrF,CAAC;CACJ;AA/FD,oCA+FC"}
|
41
node_modules/matrix-bot-sdk/lib/appservice/UnstableAppserviceApis.d.ts
generated
vendored
Normal file
41
node_modules/matrix-bot-sdk/lib/appservice/UnstableAppserviceApis.d.ts
generated
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
import { MatrixClient } from "../MatrixClient";
|
||||
import { MSC2716BatchSendResponse } from "../models/MSC2176";
|
||||
/**
|
||||
* Unstable APIs that shouldn't be used in most circumstances for appservices.
|
||||
* @category Unstable APIs
|
||||
*/
|
||||
export declare class UnstableAppserviceApis {
|
||||
private client;
|
||||
private requestId;
|
||||
constructor(client: MatrixClient);
|
||||
/**
|
||||
* Send several historical events into a room.
|
||||
* @see https://github.com/matrix-org/matrix-doc/pull/2716
|
||||
* @param {string} roomId The roomID to send to.
|
||||
* @param {string} prevEventId The event ID where this batch will be inserted
|
||||
* @param {string} chunkId The chunk ID returned from a previous call. Set falsy to start at the beginning.
|
||||
* @param {any[]} events A set of event contents for events to be inserted into the room.
|
||||
* @param {any[]} stateEventsAtStart A set of state events to be inserted into the room. Defaults to empty.
|
||||
* @returns A set of eventIds and the next chunk ID
|
||||
*/
|
||||
sendHistoricalEventBatch(roomId: string, prevEventId: string, events: any[], stateEventsAtStart?: any[], chunkId?: string): Promise<MSC2716BatchSendResponse>;
|
||||
/**
|
||||
* Sends an event to the given room with a given timestamp.
|
||||
* @param {string} roomId the room ID to send the event to
|
||||
* @param {string} eventType the type of event to send
|
||||
* @param {string} content the event body to send
|
||||
* @param {number} ts The origin_server_ts of the new event
|
||||
* @returns {Promise<string>} resolves to the event ID that represents the event
|
||||
*/
|
||||
sendEventWithTimestamp(roomId: string, eventType: string, content: any, ts: number): Promise<any>;
|
||||
/**
|
||||
* Sends a state event to the given room with a given timestamp.
|
||||
* @param {string} roomId the room ID to send the event to
|
||||
* @param {string} type the event type to send
|
||||
* @param {string} stateKey the state key to send, should not be null
|
||||
* @param {string} content the event body to send
|
||||
* @param {number} ts The origin_server_ts of the new event
|
||||
* @returns {Promise<string>} resolves to the event ID that represents the message
|
||||
*/
|
||||
sendStateEventWithTimestamp(roomId: string, type: string, stateKey: string, content: any, ts: number): Promise<string>;
|
||||
}
|
62
node_modules/matrix-bot-sdk/lib/appservice/UnstableAppserviceApis.js
generated
vendored
Normal file
62
node_modules/matrix-bot-sdk/lib/appservice/UnstableAppserviceApis.js
generated
vendored
Normal file
@@ -0,0 +1,62 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
exports.UnstableAppserviceApis = void 0;
|
||||
/**
|
||||
* Unstable APIs that shouldn't be used in most circumstances for appservices.
|
||||
* @category Unstable APIs
|
||||
*/
|
||||
class UnstableAppserviceApis {
|
||||
constructor(client) {
|
||||
this.client = client;
|
||||
this.requestId = 0;
|
||||
}
|
||||
/**
|
||||
* Send several historical events into a room.
|
||||
* @see https://github.com/matrix-org/matrix-doc/pull/2716
|
||||
* @param {string} roomId The roomID to send to.
|
||||
* @param {string} prevEventId The event ID where this batch will be inserted
|
||||
* @param {string} chunkId The chunk ID returned from a previous call. Set falsy to start at the beginning.
|
||||
* @param {any[]} events A set of event contents for events to be inserted into the room.
|
||||
* @param {any[]} stateEventsAtStart A set of state events to be inserted into the room. Defaults to empty.
|
||||
* @returns A set of eventIds and the next chunk ID
|
||||
*/
|
||||
async sendHistoricalEventBatch(roomId, prevEventId, events, stateEventsAtStart = [], chunkId) {
|
||||
return this.client.doRequest("POST", `/_matrix/client/unstable/org.matrix.msc2716/rooms/${encodeURIComponent(roomId)}/batch_send`, {
|
||||
prev_event: prevEventId,
|
||||
chunk_id: chunkId,
|
||||
}, {
|
||||
events,
|
||||
state_events_at_start: stateEventsAtStart,
|
||||
});
|
||||
}
|
||||
/**
|
||||
* Sends an event to the given room with a given timestamp.
|
||||
* @param {string} roomId the room ID to send the event to
|
||||
* @param {string} eventType the type of event to send
|
||||
* @param {string} content the event body to send
|
||||
* @param {number} ts The origin_server_ts of the new event
|
||||
* @returns {Promise<string>} resolves to the event ID that represents the event
|
||||
*/
|
||||
async sendEventWithTimestamp(roomId, eventType, content, ts) {
|
||||
const txnId = `${(new Date().getTime())}__inc_appts${++this.requestId}`;
|
||||
const path = `/_matrix/client/v3/rooms/${encodeURIComponent(roomId)}/send/${encodeURIComponent(eventType)}/${encodeURIComponent(txnId)}`;
|
||||
const response = await this.client.doRequest("PUT", path, { ts }, content);
|
||||
return response.event_id;
|
||||
}
|
||||
/**
|
||||
* Sends a state event to the given room with a given timestamp.
|
||||
* @param {string} roomId the room ID to send the event to
|
||||
* @param {string} type the event type to send
|
||||
* @param {string} stateKey the state key to send, should not be null
|
||||
* @param {string} content the event body to send
|
||||
* @param {number} ts The origin_server_ts of the new event
|
||||
* @returns {Promise<string>} resolves to the event ID that represents the message
|
||||
*/
|
||||
async sendStateEventWithTimestamp(roomId, type, stateKey, content, ts) {
|
||||
const path = `/_matrix/client/v3/rooms/${encodeURIComponent(roomId)}/state/${encodeURIComponent(type)}/${encodeURIComponent(stateKey)}`;
|
||||
const response = await this.client.doRequest("PUT", path, { ts }, content);
|
||||
return response.event_id;
|
||||
}
|
||||
}
|
||||
exports.UnstableAppserviceApis = UnstableAppserviceApis;
|
||||
//# sourceMappingURL=UnstableAppserviceApis.js.map
|
1
node_modules/matrix-bot-sdk/lib/appservice/UnstableAppserviceApis.js.map
generated
vendored
Normal file
1
node_modules/matrix-bot-sdk/lib/appservice/UnstableAppserviceApis.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"UnstableAppserviceApis.js","sourceRoot":"","sources":["../../src/appservice/UnstableAppserviceApis.ts"],"names":[],"mappings":";;;AAGA;;;GAGG;AACH,MAAa,sBAAsB;IAG/B,YAAoB,MAAoB;QAApB,WAAM,GAAN,MAAM,CAAc;QAFhC,cAAS,GAAG,CAAC,CAAC;IAGtB,CAAC;IAED;;;;;;;;;OASG;IACI,KAAK,CAAC,wBAAwB,CAAC,MAAc,EAAE,WAAmB,EAAE,MAAa,EAAE,qBAA4B,EAAE,EAAE,OAAgB;QACtI,OAAO,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,EAAE,qDAAqD,kBAAkB,CAAC,MAAM,CAAC,aAAa,EAAE;YAC/H,UAAU,EAAE,WAAW;YACvB,QAAQ,EAAE,OAAO;SACpB,EAAE;YACC,MAAM;YACN,qBAAqB,EAAE,kBAAkB;SAC5C,CAAC,CAAC;IACP,CAAC;IAED;;;;;;;OAOG;IACI,KAAK,CAAC,sBAAsB,CAAC,MAAc,EAAE,SAAiB,EAAE,OAAY,EAAE,EAAU;QAC3F,MAAM,KAAK,GAAG,GAAG,CAAC,IAAI,IAAI,EAAE,CAAC,OAAO,EAAE,CAAC,cAAc,EAAE,IAAI,CAAC,SAAS,EAAE,CAAC;QACxE,MAAM,IAAI,GAAG,4BAA4B,kBAAkB,CAAC,MAAM,CAAC,SAAS,kBAAkB,CAAC,SAAS,CAAC,IAAI,kBAAkB,CAAC,KAAK,CAAC,EAAE,CAAC;QACzI,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;QAC3E,OAAO,QAAQ,CAAC,QAAQ,CAAC;IAC7B,CAAC;IAED;;;;;;;;OAQG;IACI,KAAK,CAAC,2BAA2B,CAAC,MAAc,EAAE,IAAY,EAAE,QAAgB,EAAE,OAAY,EAAE,EAAU;QAC7G,MAAM,IAAI,GAAG,4BAA4B,kBAAkB,CAAC,MAAM,CAAC,UAAU,kBAAkB,CAAC,IAAI,CAAC,IAAI,kBAAkB,CAAC,QAAQ,CAAC,EAAE,CAAC;QACxI,MAAM,QAAQ,GAAG,MAAM,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,EAAE,EAAE,EAAE,EAAE,OAAO,CAAC,CAAC;QAC3E,OAAO,QAAQ,CAAC,QAAQ,CAAC;IAC7B,CAAC;CACJ;AAvDD,wDAuDC"}
|
77
node_modules/matrix-bot-sdk/lib/appservice/http_responses.d.ts
generated
vendored
Normal file
77
node_modules/matrix-bot-sdk/lib/appservice/http_responses.d.ts
generated
vendored
Normal file
@@ -0,0 +1,77 @@
|
||||
/**
|
||||
* This is the response format documented in
|
||||
* https://matrix.org/docs/spec/application_service/r0.1.2#get-matrix-app-v1-thirdparty-protocol-protocol
|
||||
* @category Application services
|
||||
*/
|
||||
export interface IApplicationServiceProtocol {
|
||||
user_fields: string[];
|
||||
location_fields: string[];
|
||||
icon: string;
|
||||
field_types: {
|
||||
[field: string]: IFieldType;
|
||||
};
|
||||
instances: {
|
||||
[name: string]: IProtocolInstance;
|
||||
};
|
||||
}
|
||||
interface IFieldType {
|
||||
regexp: string;
|
||||
placeholder: string;
|
||||
}
|
||||
interface IProtocolInstance {
|
||||
desc: string;
|
||||
icon: string;
|
||||
fields: {
|
||||
[field: string]: string;
|
||||
};
|
||||
network_id: string;
|
||||
}
|
||||
/**
|
||||
* This is the response format for an MSC3983 `/keys/claim` request.
|
||||
* See https://github.com/matrix-org/matrix-spec-proposals/pull/3983
|
||||
* @deprecated This can be removed at any time without notice as it is unstable functionality.
|
||||
* @category Application services
|
||||
*/
|
||||
export interface MSC3983KeyClaimResponse {
|
||||
[userId: string]: {
|
||||
[deviceId: string]: {
|
||||
[keyId: string]: {
|
||||
key: string;
|
||||
signatures: {
|
||||
[userId: string]: {
|
||||
[keyId: string]: string;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
/**
|
||||
* This is the response format for an MSC3984 `/keys/query` request.
|
||||
* See https://github.com/matrix-org/matrix-spec-proposals/pull/3984
|
||||
* @deprecated This can be removed at any time without notice as it is unstable functionality.
|
||||
* @category Application services
|
||||
*/
|
||||
export interface MSC3984KeyQueryResponse {
|
||||
device_keys: {
|
||||
[userId: string]: {
|
||||
[deviceId: string]: {
|
||||
algorithms: string[];
|
||||
device_id: string;
|
||||
user_id: string;
|
||||
keys: {
|
||||
[keyId: string]: string;
|
||||
};
|
||||
signatures: {
|
||||
[userId: string]: {
|
||||
[keyId: string]: string;
|
||||
};
|
||||
};
|
||||
unsigned?: {
|
||||
[key: string]: any;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
export {};
|
3
node_modules/matrix-bot-sdk/lib/appservice/http_responses.js
generated
vendored
Normal file
3
node_modules/matrix-bot-sdk/lib/appservice/http_responses.js
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
//# sourceMappingURL=http_responses.js.map
|
1
node_modules/matrix-bot-sdk/lib/appservice/http_responses.js.map
generated
vendored
Normal file
1
node_modules/matrix-bot-sdk/lib/appservice/http_responses.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"http_responses.js","sourceRoot":"","sources":["../../src/appservice/http_responses.ts"],"names":[],"mappings":""}
|
Reference in New Issue
Block a user