77 lines
2.7 KiB
TypeScript
77 lines
2.7 KiB
TypeScript
import type { AppserviceConfig } from './types.js';
|
|
|
|
export interface RegistrationOptions {
|
|
/** Unique appservice id in Synapse. Default: "mosaic-as". */
|
|
id?: string;
|
|
/** URL where Synapse reaches the appservice, e.g. http://mosaic-as:8008 */
|
|
url: string;
|
|
/** Alias namespace regex prefix. Default: "#mosaic-". */
|
|
aliasPrefix?: string;
|
|
}
|
|
|
|
const escapeRegex = (value: string): string => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
|
|
/**
|
|
* Build the Synapse appservice registration document (mosaic-as.yaml).
|
|
* Deployment (infrastructure repo) serializes this to YAML and mounts it via
|
|
* app_service_config_files.
|
|
*/
|
|
export function buildRegistration(cfg: AppserviceConfig, options: RegistrationOptions) {
|
|
const prefix = cfg.userPrefix ?? 'agent-';
|
|
return {
|
|
id: options.id ?? 'mosaic-as',
|
|
url: options.url,
|
|
as_token: cfg.asToken,
|
|
hs_token: cfg.hsToken,
|
|
sender_localpart: cfg.senderLocalpart ?? 'mosaic-as',
|
|
rate_limited: false,
|
|
namespaces: {
|
|
users: [
|
|
{
|
|
regex: `@${escapeRegex(prefix)}.*:${escapeRegex(cfg.domain)}`,
|
|
exclusive: true,
|
|
},
|
|
],
|
|
aliases: [
|
|
{
|
|
regex: `${escapeRegex(options.aliasPrefix ?? '#mosaic-')}.*:${escapeRegex(cfg.domain)}`,
|
|
exclusive: false,
|
|
},
|
|
],
|
|
rooms: [],
|
|
},
|
|
};
|
|
}
|
|
|
|
const assertYamlSafe = (field: string, value: string): string => {
|
|
// Tokens/urls/ids are single-line opaque strings; control characters would
|
|
// let a crafted value terminate the scalar and inject YAML keys.
|
|
if (/[\r\n\x00-\x08\x0b-\x1f]/.test(value)) {
|
|
throw new Error(`registration field ${field} contains control characters`);
|
|
}
|
|
return value.replace(/'/g, "''");
|
|
};
|
|
|
|
/** Minimal YAML serialization for the flat registration document. */
|
|
export function registrationToYaml(registration: ReturnType<typeof buildRegistration>): string {
|
|
const ns = registration.namespaces;
|
|
const nsBlock = (entries: Array<{ regex: string; exclusive: boolean }>): string =>
|
|
entries.length === 0
|
|
? ' []'
|
|
: '\n' +
|
|
entries.map((e) => ` - regex: '${e.regex}'\n exclusive: ${e.exclusive}`).join('\n');
|
|
return [
|
|
`id: '${assertYamlSafe('id', registration.id)}'`,
|
|
`url: '${assertYamlSafe('url', registration.url)}'`,
|
|
`as_token: '${assertYamlSafe('as_token', registration.as_token)}'`,
|
|
`hs_token: '${assertYamlSafe('hs_token', registration.hs_token)}'`,
|
|
`sender_localpart: '${assertYamlSafe('sender_localpart', registration.sender_localpart)}'`,
|
|
`rate_limited: ${registration.rate_limited}`,
|
|
'namespaces:',
|
|
` users:${nsBlock(ns.users)}`,
|
|
` aliases:${nsBlock(ns.aliases)}`,
|
|
` rooms:${nsBlock(ns.rooms)}`,
|
|
'',
|
|
].join('\n');
|
|
}
|