import type { ProsodyFilePaths } from './paths' ; import type { ExternalComponent } from './components' ; type ConfigEntryValue = boolean | number | string | ConfigEntryValue [ ] ; type ConfigEntries = Map < string , ConfigEntryValue > ; interface ConfigLogExpirationNever { value : 'never' ; type : 'never' ; } interface ConfigLogExpirationSeconds { value : string ; seconds : number ; type : 'seconds' ; } interface ConfigLogExpirationPeriod { value : string ; type : 'period' ; } interface ConfigLogExpirationError { value : string ; error : string ; type : 'period' ; } type ConfigLogExpiration = ConfigLogExpirationNever | ConfigLogExpirationPeriod | ConfigLogExpirationSeconds | ConfigLogExpirationError ; function writeValue ( value ) { if ( typeof value === 'boolean' ) { return value . toString ( ) + ';\n' ; } if ( typeof value === 'string' ) { return '"' + value . replace ( /"/g , '\\"' ) + '"' + ';\n' ; } if ( typeof value === 'number' ) { return value . toString ( ) + ';\n' ; } if ( Array . isArray ( value ) ) { let s = '{\n' ; for ( let i = 0 ; i < value . length ; i ++ ) { s += '  ' + writeValue ( value [ i ] ) ; } s += '};\n' ; return s ; } throw new Error ( `Don't know how to handle this value: ${ value as string }` ) ; } abstract class ProsodyConfigBlock { entries : ConfigEntries ; prefix : string ; constructor ( prefix ) { this . prefix = prefix ; this . entries = new Map ( ) ; } set ( name , value ) { this . entries . set ( name , value ) ; } add ( name , value ) { if ( ! this . entries . has ( name ) ) { this . entries . set ( name , [ ] ) ; } let entry = this . entries . get ( name ) as ConfigEntryValue ; if ( ! Array . isArray ( entry ) ) { entry = [ entry ] ; } entry . push ( value ) ; this . entries . set ( name , entry ) ; } write ( ) { let content = '' ; this . entries . forEach ( ( value , key ) => { content += this . prefix + key + ' = ' + writeValue ( value ) ; } ) ; return content ; } } class ProsodyConfigGlobal extends ProsodyConfigBlock { constructor ( ) { super ( '' ) ; } } class ProsodyConfigVirtualHost extends ProsodyConfigBlock { name : string ; constructor ( name ) { super ( '  ' ) ; this . name = name ; } write ( ) { return `VirtualHost "${ this . name }"\n` + super . write ( ) ; } } class ProsodyConfigComponent extends ProsodyConfigBlock { name : string ; type ? : string ; constructor ( name , type ? ) { super ( '  ' ) ; this . type = type ; this . name = name ; } write ( ) { if ( this . type !== undefined ) { return `Component "${ this . name }" "${ this . type }"\n` + super . write ( ) ; } return `Component "${ this . name }"\n` + super . write ( ) ; } } type ProsodyLogLevel = 'debug' | 'info' | 'warn' | 'error' ; class ProsodyConfigContent { paths : ProsodyFilePaths ; global : ProsodyConfigGlobal ; authenticated ? : ProsodyConfigVirtualHost ; anon : ProsodyConfigVirtualHost ; muc : ProsodyConfigComponent ; externalComponents : ProsodyConfigComponent [ ] = [ ] ; log : string ; prosodyDomain : string ; constructor ( paths , prosodyDomain ) { this . paths = paths ; this . global = new ProsodyConfigGlobal ( ) ; this . log = '' ; this . prosodyDomain = prosodyDomain ; this . anon = new ProsodyConfigVirtualHost ( 'anon.' + prosodyDomain ) ; this . muc = new ProsodyConfigComponent ( 'room.' + prosodyDomain , 'muc' ) ; this . global . set ( 'daemonize' , false ) ; this . global . set ( 'allow_registration' , false ) ; this . global . set ( 'admins' , [ ] ) ; this . global . set ( 'pidfile' , this . paths . pid ) ; this . global . set ( 'plugin_paths' , [ this . paths . modules ] ) ; this . global . set ( 'data_path' , this . paths . data ) ; this . global . set ( 'default_storage' , 'internal' ) ; this . global . set ( 'storage' , 'internal' ) ; this . global . set ( 'modules_enabled' , [ 'roster' , 'saslauth' , 'carbons' , 'version' , 'uptime' , 'ping' , 'bosh' , 'posix' ] ) ; this . global . set ( 'modules_disabled' , [ 's2s' ] ) ; this . global . set ( 'cross_domain_bosh' , false ) ; this . global . set ( 'consider_bosh_secure' , false ) ; this . global . set ( 'cross_domain_websocket' , false ) ; this . global . set ( 'consider_websocket_secure' , false ) ; this . anon . set ( 'authentication' , 'anonymous' ) ; this . anon . set ( 'modules_enabled' , [ 'ping' ] ) ; this . muc . set ( 'muc_room_locking' , false ) ; this . muc . set ( 'muc_tombstones' , false ) ; this . muc . set ( 'muc_room_default_language' , 'en' ) ; this . muc . set ( 'muc_room_default_public' , false ) ; this . muc . set ( 'muc_room_default_persistent' , false ) ; this . muc . set ( 'muc_room_default_members_only' , false ) ; this . muc . set ( 'muc_room_default_moderated' , false ) ; this . muc . set ( 'muc_room_default_public_jids' , false ) ; this . muc . set ( 'muc_room_default_change_subject' , false ) ; this . muc . set ( 'muc_room_default_history_length' , 20 ) ; } useHttpAuthentication ( url ) { this . authenticated = new ProsodyConfigVirtualHost ( this . prosodyDomain ) ; this . authenticated . set ( 'authentication' , 'http' ) ; this . authenticated . set ( 'modules_enabled' , [ 'ping' , 'auth_http' ] ) ; this . authenticated . set ( 'http_auth_url' , url ) ; } usePeertubeBosh ( prosodyDomain , port ) { this . global . set ( 'c2s_require_encryption' , false ) ; this . global . set ( 'interfaces' , [ '127.0.0.1' , '::1' ] ) ; this . global . set ( 'c2s_ports' , [ ] ) ; this . global . set ( 'c2s_interfaces' , [ '127.0.0.1' , '::1' ] ) ; this . global . set ( 's2s_ports' , [ ] ) ; this . global . set ( 's2s_interfaces' , [ '127.0.0.1' , '::1' ] ) ; this . global . set ( 'http_ports' , [ port ] ) ; this . global . set ( 'http_interfaces' , [ '127.0.0.1' , '::1' ] ) ; this . global . set ( 'https_ports' , [ ] ) ; this . global . set ( 'https_interfaces' , [ '127.0.0.1' , '::1' ] ) ; this . global . set ( 'consider_bosh_secure' , true ) ; this . anon . set ( 'trusted_proxies' , [ '127.0.0.1' , '::1' ] ) ; this . anon . set ( 'allow_anonymous_s2s' , false ) ; this . anon . add ( 'modules_enabled' , 'http' ) ; this . anon . add ( 'modules_enabled' , 'bosh' ) ; this . anon . set ( 'http_host' , prosodyDomain ) ; this . anon . set ( 'http_external_url' , 'http://' + prosodyDomain ) ; this . muc . set ( 'restrict_room_creation' , 'local' ) ; this . muc . set ( 'http_host' , prosodyDomain ) ; this . muc . set ( 'http_external_url' , 'http://' + prosodyDomain ) ; if ( this . authenticated ) { this . authenticated . set ( 'trusted_proxies' , [ '127.0.0.1' , '::1' ] ) ; this . authenticated . set ( 'allow_anonymous_s2s' , false ) ; this . authenticated . add ( 'modules_enabled' , 'http' ) ; this . authenticated . add ( 'modules_enabled' , 'bosh' ) ; this . authenticated . set ( 'http_host' , prosodyDomain ) ; this . authenticated . set ( 'http_external_url' , 'http://' + prosodyDomain ) ; } } useC2S ( c2sPort ) { this . global . set ( 'c2s_ports' , [ c2sPort ] ) ; } useExternalComponents ( componentsPort , components ) { this . global . set ( 'component_ports' , [ componentsPort ] ) ; this . global . set ( 'component_interfaces' , [ '127.0.0.1' , '::1' ] ) ; for ( const component of components ) { const c = new ProsodyConfigComponent ( component . name ) ; c . set ( 'component_secret' , component . secret ) ; this . externalComponents . push ( c ) ; } } useMucHttpDefault ( url ) { this . muc . add ( 'modules_enabled' , 'muc_http_defaults' ) ; this . muc . add ( 'muc_create_api_url' , url ) ; this . muc . set ( 'restrict_room_creation' , false ) ; } param logByDefault param logExpiration useMam ( logByDefault , logExpiration ) { this . muc . add ( 'modules_enabled' , 'muc_mam' ) ; this . muc . set ( 'muc_log_by_default' , ! ! logByDefault ) ; this . muc . set ( 'muc_log_presences' , true ) ; this . muc . set ( 'log_all_rooms' , false ) ; this . muc . set ( 'muc_log_expires_after' , logExpiration . value ) ; const defaultCleanupInterval = 4 * 60 * 60 ; if ( logExpiration . type === 'seconds' && logExpiration . seconds && logExpiration . seconds < defaultCleanupInterval ) { this . muc . set ( 'muc_log_cleanup_interval' , logExpiration . seconds ) ; } else { this . muc . set ( 'muc_log_cleanup_interval' , defaultCleanupInterval ) ; } this . muc . add ( 'modules_enabled' , 'muc_moderation' ) ; } /**
     * Rooms will be persistent by default (they will not be deleted if no participant).
     */ useDefaultPersistent ( ) { this . muc . set ( 'muc_room_default_persistent' , true ) ; } useListRoomsApi ( apikey ) { this . muc . add ( 'modules_enabled' , 'http_peertubelivechat_list_rooms' ) ; this . muc . set ( 'peertubelivechat_list_rooms_apikey' , apikey ) ; } useTestModule ( prosodyApikey , apiurl ) { this . muc . add ( 'modules_enabled' , 'http_peertubelivechat_test' ) ; this . muc . set ( 'peertubelivechat_test_apikey' , prosodyApikey ) ; this . muc . set ( 'peertubelivechat_test_peertube_api_url' , apiurl ) ; } usePeertubeVCards ( peertubeUrl ) { if ( this . authenticated ) { this . authenticated . add ( 'modules_enabled' , 'vcard_peertubelivechat' ) ; this . authenticated . set ( 'peertubelivechat_vcard_peertube_url' , peertubeUrl ) ; } } useAnonymousRandomVCards ( avatarPath ) { if ( this . anon ) { this . anon . add ( 'modules_enabled' , 'random_vcard_peertubelivechat' ) ; this . anon . set ( 'peertubelivechat_random_vcard_avatars_path' , avatarPath ) ; } } setLog ( level , syslog ? ) { let log = '' ; log += 'log = {\n' ; if ( level !== 'error' ) { log += '  ' + level + ' = ' + writeValue ( this . paths . log ) ; } log += '  error = ' + writeValue ( this . paths . error ) ; if ( syslog ) { log += '  { to = "syslog"; levels = ' + writeValue ( syslog ) + ' };\n' ; } log += '\n};\n' ; this . log = log ; } public write ( ) { let content = '' ; content += this . global . write ( ) ; content += this . log + '\n' ; content += '\n\n' ; if ( this . authenticated ) { content += this . authenticated . write ( ) ; content += '\n\n' ; } content += this . anon . write ( ) ; content += '\n\n' ; content += this . muc . write ( ) ; content += '\n\n' ; for ( const externalComponent of this . externalComponents ) { content += '\n\n' ; content += externalComponent . write ( ) ; content += '\n\n' ; } return content ; } } export { ProsodyLogLevel , ProsodyConfigContent , ConfigLogExpiration } ;