Typescript v5 + eslint 8.57 WIP
This commit also improves some type handling in the project.
This commit is contained in:
parent
64a9c7be21
commit
7b3d93b290
@ -1,14 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"env": {},
|
||||
"extends": [],
|
||||
"globals": {},
|
||||
"plugins": [],
|
||||
"ignorePatterns": [
|
||||
"node_modules/", "dist/", "webpack.config.js",
|
||||
"build/",
|
||||
"vendor/",
|
||||
"support/documentation",
|
||||
"build-*js"],
|
||||
"rules": {}
|
||||
}
|
@ -2,7 +2,7 @@
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
'use strict';
|
||||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
extends: [
|
||||
|
@ -10,6 +10,9 @@
|
||||
### Minor changes and fixes
|
||||
|
||||
* Various translation updates.
|
||||
* Using Typescript 5.5.4, and Eslint 8.57.0 (with new ruleset).
|
||||
* Fix race condition in bot/ctl.
|
||||
* Various type improvements.
|
||||
|
||||
## 11.0.1
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
"es6": true
|
||||
},
|
||||
"extends": [
|
||||
"standard-with-typescript",
|
||||
"eslint-config-love",
|
||||
"plugin:lit/recommended"
|
||||
],
|
||||
"globals": {},
|
||||
|
@ -5,7 +5,7 @@
|
||||
"es6": true
|
||||
},
|
||||
"extends": [
|
||||
"standard-with-typescript"
|
||||
"eslint-config-love"
|
||||
],
|
||||
"globals": {},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
|
94
eslint.config.mjs
Normal file
94
eslint.config.mjs
Normal file
@ -0,0 +1,94 @@
|
||||
// SPDX-FileCopyrightText: 2024 John Livingston <https://www.john-livingston.fr/>
|
||||
//
|
||||
// SPDX-License-Identifier: AGPL-3.0-only
|
||||
|
||||
import love from 'eslint-config-love'
|
||||
import eslint from '@eslint/js'
|
||||
import tseslint from 'typescript-eslint'
|
||||
import typescriptParser from '@typescript-eslint/parser'
|
||||
import stylistic from '@stylistic/eslint-plugin'
|
||||
import globals from 'globals'
|
||||
|
||||
export default tseslint.config(
|
||||
{
|
||||
ignores: [
|
||||
"node_modules/", "dist/", "webpack.config.js",
|
||||
"build/",
|
||||
"vendor/",
|
||||
"support/documentation", "support",
|
||||
"build-*js",
|
||||
|
||||
"shared", "client", "conversejs"
|
||||
]
|
||||
},
|
||||
eslint.configs.recommended,
|
||||
...tseslint.configs.recommended,
|
||||
{
|
||||
...love,
|
||||
files: ['**/*.ts']
|
||||
},
|
||||
{
|
||||
plugins: {
|
||||
'@stylistic': stylistic
|
||||
},
|
||||
rules: {
|
||||
"@stylistic/semi": ["error", "never"]
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['**/*.ts'],
|
||||
rules: {
|
||||
"@typescript-eslint/no-empty-function": ["error", {"allow": ["arrowFunctions"]}],
|
||||
"@typescript-eslint/no-unused-vars": [2, {"argsIgnorePattern": "^_", "caughtErrorsIgnorePattern": "^_"}],
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"@typescript-eslint/no-misused-promises": "error",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"@typescript-eslint/strict-boolean-expressions": "off",
|
||||
"@typescript-eslint/return-await": [2, "in-try-catch"], // FIXME: correct?
|
||||
"@typescript-eslint/no-invalid-void-type": "off",
|
||||
"@typescript-eslint/triple-slash-reference": "off",
|
||||
"@typescript-eslint/no-explicit-any": "off", // FIXME: should be "error", and we should use 'unknown' in the code.
|
||||
"init-declarations": "off",
|
||||
"@typescript-eslint/init-declarations": "off",
|
||||
"@typescript-eslint/consistent-type-imports": "off",
|
||||
"@typescript-eslint/consistent-type-exports": "off",
|
||||
"@typescript-eslint/no-require-imports": "off",
|
||||
"@typescript-eslint/unbound-method": "off",
|
||||
"@typescript-eslint/prefer-promise-reject-errors": "off",
|
||||
"max-params": "off",
|
||||
"@typescript-eslint/max-params": ["error", { "max": 8 }], // FIXME: this rules should use the default max value.
|
||||
"@typescript-eslint/explicit-function-return-type": "error",
|
||||
"@typescript-eslint/no-confusing-void-expression": "off",
|
||||
"@typescript-eslint/class-methods-use-this": "off",
|
||||
"@typescript-eslint/non-nullable-type-assertion-style": "off",
|
||||
"max-len": [
|
||||
"error",
|
||||
{
|
||||
"code": 120,
|
||||
"comments": 120
|
||||
}
|
||||
],
|
||||
"no-unused-vars": "off"
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['.stylelintrc.js'],
|
||||
languageOptions: {
|
||||
globals: globals.node
|
||||
}
|
||||
},
|
||||
{
|
||||
files: ['server/**/*.js', 'server/**/*.ts'], // only ts?
|
||||
languageOptions: {
|
||||
ecmaVersion: 6,
|
||||
globals: {
|
||||
...globals.node
|
||||
},
|
||||
parser: typescriptParser,
|
||||
parserOptions: {
|
||||
ecmaVersion: 2018,
|
||||
project: './server/tsconfig.json'
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
5207
package-lock.json
generated
5207
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
20
package.json
20
package.json
@ -38,32 +38,29 @@
|
||||
"xmppjs-chat-bot": "^0.4.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.10.0",
|
||||
"@lit-labs/motion": "^1.0.7",
|
||||
"@lit/context": "^1.1.1",
|
||||
"@lit/task": "^1.0.0",
|
||||
"@peertube/feed": "^5.1.0",
|
||||
"@peertube/peertube-types": "^5.2.0",
|
||||
"@stylistic/eslint-plugin": "^2.7.2",
|
||||
"@tsconfig/node12": "^1.0.9",
|
||||
"@types/async": "^3.2.9",
|
||||
"@types/escape-html": "^1.0.4",
|
||||
"@types/eslint__js": "^8.42.3",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/got": "^9.6.12",
|
||||
"@types/http-proxy": "^1.17.9",
|
||||
"@types/node": "^16.11.6",
|
||||
"@types/winston": "^2.4.4",
|
||||
"@types/xmpp__jid": "^1.3.5",
|
||||
"@typescript-eslint/eslint-plugin": "^4.29.0",
|
||||
"@typescript-eslint/parser": "^4.29.0",
|
||||
"@typescript-eslint/parser": "^8.4.0",
|
||||
"commander": "^11.0.0",
|
||||
"esbuild": "^0.16.1",
|
||||
"eslint": "^7.32.0",
|
||||
"eslint-config-standard": "^16.0.3",
|
||||
"eslint-config-standard-with-typescript": "^20.0.0",
|
||||
"eslint-plugin-import": "^2.25.2",
|
||||
"eslint-plugin-lit": "^1.13.0",
|
||||
"eslint-plugin-node": "^11.1.0",
|
||||
"eslint-plugin-promise": "^5.1.1",
|
||||
"eslint-plugin-standard": "^5.0.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-love": "^64.0.0",
|
||||
"globals": "^15.9.0",
|
||||
"lit": "^2.4.0",
|
||||
"lit-analyzer": "^1.2.1",
|
||||
"npm-run-all": "^4.1.5",
|
||||
@ -73,7 +70,8 @@
|
||||
"stylelint-config-recommended-scss": "^5.0.1",
|
||||
"stylelint-config-standard-scss": "^2.0.1",
|
||||
"svgo": "^2.8.0",
|
||||
"typescript": "^4.3.5",
|
||||
"typescript": "^5.5.4",
|
||||
"typescript-eslint": "^8.4.0",
|
||||
"yaml": "^2.2.1"
|
||||
},
|
||||
"engine": {
|
||||
|
@ -1,40 +0,0 @@
|
||||
{
|
||||
"root": true,
|
||||
"env": {
|
||||
"browser": false,
|
||||
"es6": true
|
||||
},
|
||||
"extends": [
|
||||
"standard-with-typescript"
|
||||
],
|
||||
"globals": {},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"project": [
|
||||
"./server/tsconfig.json"
|
||||
]
|
||||
},
|
||||
"plugins": [
|
||||
"@typescript-eslint"
|
||||
],
|
||||
"ignorePatterns": [],
|
||||
"rules": {
|
||||
"@typescript-eslint/no-unused-vars": [2, {"argsIgnorePattern": "^_"}],
|
||||
"@typescript-eslint/no-floating-promises": "error",
|
||||
"@typescript-eslint/no-misused-promises": "error",
|
||||
"@typescript-eslint/no-var-requires": "off",
|
||||
"@typescript-eslint/strict-boolean-expressions": "off",
|
||||
"@typescript-eslint/return-await": [2, "in-try-catch"], // FIXME: correct?
|
||||
"@typescript-eslint/no-invalid-void-type": "off",
|
||||
"@typescript-eslint/triple-slash-reference": "off",
|
||||
"max-len": [
|
||||
"error",
|
||||
{
|
||||
"code": 120,
|
||||
"comments": 120
|
||||
}
|
||||
],
|
||||
"no-unused-vars": "off"
|
||||
}
|
||||
}
|
@ -88,7 +88,7 @@ class BotsCtl {
|
||||
moderationBotProcess.stderr?.on('data', (data) => {
|
||||
// change error level for non-relevant errors:
|
||||
data = data.toString()
|
||||
if (/Warning.*NODE_TLS_REJECT_UNAUTHORIZED.*'0'.*TLS/.test(data)) {
|
||||
if (/Warning.*NODE_TLS_REJECT_UNAUTHORIZED.*'0'.*TLS/.test(data as string)) {
|
||||
this.logger.debug(`ModerationBot stderr: ${data as string}`)
|
||||
return
|
||||
}
|
||||
@ -123,9 +123,11 @@ class BotsCtl {
|
||||
}
|
||||
const p = new Promise<void>((resolve, reject) => {
|
||||
try {
|
||||
if (!this.moderationBotProcess) { resolve() }
|
||||
const moderationBotProcess: ReturnType<typeof child_process.spawn> =
|
||||
this.moderationBotProcess as ReturnType<typeof child_process.spawn>
|
||||
if (!this.moderationBotProcess) {
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
const moderationBotProcess: ReturnType<typeof child_process.spawn> = this.moderationBotProcess
|
||||
|
||||
let resolved = false
|
||||
// Trying to kill, and force kill if it takes more than X seconds
|
||||
|
@ -189,7 +189,7 @@ class BotConfiguration {
|
||||
})).toString()
|
||||
|
||||
config = JSON.parse(content)
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
this.logger.info('Error reading the moderation bot global configuration file, assuming it does not exists.')
|
||||
config = undefined
|
||||
}
|
||||
@ -275,7 +275,7 @@ class BotConfiguration {
|
||||
content = (await fs.promises.readFile(filePath, {
|
||||
encoding: 'utf-8'
|
||||
})).toString()
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
this.logger.debug('Failed to read room conf file, assuming it does not exists')
|
||||
this.roomConfCache.set(roomJID, null)
|
||||
return null
|
||||
@ -284,7 +284,7 @@ class BotConfiguration {
|
||||
let json: RoomConf
|
||||
try {
|
||||
json = JSON.parse(content) as RoomConf
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
this.logger.error(`Error parsing JSON file ${filePath}, assuming empty`)
|
||||
this.roomConfCache.set(roomJID, null)
|
||||
return null
|
||||
|
@ -59,7 +59,7 @@ async function initChannelConfiguration (options: RegisterServerOptions): Promis
|
||||
|
||||
logger.info(`Channel ${channelId} deleted, removing 'custom emojis' related stuff.`)
|
||||
try {
|
||||
Emojis.singletonSafe()?.deleteChannelDefinition(channelId)
|
||||
await Emojis.singletonSafe()?.deleteChannelDefinition(channelId)
|
||||
} catch (err) {
|
||||
logger.error(err)
|
||||
}
|
||||
@ -87,7 +87,7 @@ async function initChannelConfiguration (options: RegisterServerOptions): Promis
|
||||
])
|
||||
|
||||
await fillVideoCustomFields(options, video)
|
||||
const hasChat = await videoHasWebchat({
|
||||
const hasChat = videoHasWebchat({
|
||||
'chat-per-live-video': !!settings['chat-per-live-video'],
|
||||
'chat-all-lives': !!settings['chat-all-lives'],
|
||||
'chat-all-non-lives': !!settings['chat-all-non-lives'],
|
||||
|
@ -17,31 +17,36 @@ import { channelTermsMaxLength } from '../../../../shared/lib/constants'
|
||||
async function sanitizeChannelConfigurationOptions (
|
||||
_options: RegisterServerOptions,
|
||||
_channelId: number | string,
|
||||
data: any
|
||||
data: unknown
|
||||
): Promise<ChannelConfigurationOptions> {
|
||||
if (typeof data !== 'object') {
|
||||
if (!_assertObjectType(data)) {
|
||||
throw new Error('Invalid data type')
|
||||
}
|
||||
|
||||
const botData = data.bot
|
||||
if (typeof botData !== 'object') {
|
||||
const botData = data.bot ?? {}
|
||||
if (!_assertObjectType(botData)) {
|
||||
throw new Error('Invalid data.bot data type')
|
||||
}
|
||||
|
||||
// slowMode not present in livechat <= 8.2.0:
|
||||
const slowModeData = data.slowMode ?? {}
|
||||
slowModeData.duration ??= slowModeData.defaultDuration ?? 0 // v8.3.0 to 8.3.2: was in defaultDuration
|
||||
|
||||
if (typeof slowModeData !== 'object') {
|
||||
if (!_assertObjectType(slowModeData)) {
|
||||
throw new Error('Invalid data.slowMode data type')
|
||||
}
|
||||
slowModeData.duration ??= slowModeData.defaultDuration ?? 0 // v8.3.0 to 8.3.2: was in defaultDuration
|
||||
|
||||
const moderationData = data.moderation ?? {} // comes with livechat 10.3.0
|
||||
if (!_assertObjectType(moderationData)) {
|
||||
throw new Error('Invalid data.moderation data type')
|
||||
}
|
||||
moderationData.delay ??= 0
|
||||
moderationData.anonymize ??= false // comes with livechat 11.0.0
|
||||
|
||||
// mute not present in livechat <= 10.2.0
|
||||
const mute = data.mute ?? {}
|
||||
if (!_assertObjectType(mute)) {
|
||||
throw new Error('Invalid data.mute data type')
|
||||
}
|
||||
mute.anonymous ??= false
|
||||
|
||||
// forbidSpecialChars comes with livechat 11.1.0
|
||||
@ -51,13 +56,12 @@ async function sanitizeChannelConfigurationOptions (
|
||||
tolerance: 0,
|
||||
applyToModerators: false
|
||||
}
|
||||
|
||||
if (typeof mute !== 'object') {
|
||||
throw new Error('Invalid data.mute data type')
|
||||
if (!_assertObjectType(botData.forbidSpecialChars)) {
|
||||
throw new Error('Invalid data.forbidSpecialChars data type')
|
||||
}
|
||||
|
||||
// terms not present in livechat <= 10.2.0
|
||||
let terms = data.terms
|
||||
let terms = data.terms ?? undefined
|
||||
if (terms !== undefined && (typeof terms !== 'string')) {
|
||||
throw new Error('Invalid data.terms data type')
|
||||
}
|
||||
@ -94,7 +98,11 @@ async function sanitizeChannelConfigurationOptions (
|
||||
return result
|
||||
}
|
||||
|
||||
function _readBoolean (data: any, f: string): boolean {
|
||||
function _assertObjectType (data: unknown): data is Record<string, unknown> {
|
||||
return !!data && (typeof data === 'object') && Object.keys(data).every(k => typeof k === 'string')
|
||||
}
|
||||
|
||||
function _readBoolean (data: Record<string, unknown>, f: string): boolean {
|
||||
if (!(f in data)) {
|
||||
return false
|
||||
}
|
||||
@ -104,11 +112,11 @@ function _readBoolean (data: any, f: string): boolean {
|
||||
return data[f]
|
||||
}
|
||||
|
||||
function _readInteger (data: any, f: string, min: number, max: number): number {
|
||||
function _readInteger (data: Record<string, unknown>, f: string, min: number, max: number): number {
|
||||
if (!(f in data)) {
|
||||
throw new Error('Missing integer value for field ' + f)
|
||||
}
|
||||
const v = parseInt(data[f])
|
||||
const v = typeof data[f] === 'number' ? Math.trunc(data[f]) : parseInt(data[f] as string)
|
||||
if (isNaN(v)) {
|
||||
throw new Error('Invalid value type for field ' + f)
|
||||
}
|
||||
@ -121,7 +129,7 @@ function _readInteger (data: any, f: string, min: number, max: number): number {
|
||||
return v
|
||||
}
|
||||
|
||||
function _readSimpleInput (data: any, f: string, strict?: boolean, noSpace?: boolean): string {
|
||||
function _readSimpleInput (data: Record<string, unknown>, f: string, strict?: boolean, noSpace?: boolean): string {
|
||||
if (!(f in data)) {
|
||||
return ''
|
||||
}
|
||||
@ -130,7 +138,7 @@ function _readSimpleInput (data: any, f: string, strict?: boolean, noSpace?: boo
|
||||
}
|
||||
// Removing control characters.
|
||||
// eslint-disable-next-line no-control-regex
|
||||
let s = (data[f] as string).replace(/[\u0000-\u001F\u007F-\u009F]/g, '')
|
||||
let s = data[f].replace(/[\u0000-\u001F\u007F-\u009F]/g, '')
|
||||
if (strict) {
|
||||
// Replacing all invalid characters, no need to throw an error..
|
||||
s = s.replace(/[^\p{L}\p{N}\p{Z}_-]$/gu, '')
|
||||
@ -141,7 +149,7 @@ function _readSimpleInput (data: any, f: string, strict?: boolean, noSpace?: boo
|
||||
return s
|
||||
}
|
||||
|
||||
function _readStringArray (data: any, f: string): string[] {
|
||||
function _readStringArray (data: Record<string, unknown>, f: string): string[] {
|
||||
if (!(f in data)) {
|
||||
return []
|
||||
}
|
||||
@ -162,7 +170,7 @@ function _readStringArray (data: any, f: string): string[] {
|
||||
return result
|
||||
}
|
||||
|
||||
function _readMultiLineString (data: any, f: string): string {
|
||||
function _readMultiLineString (data: Record<string, unknown>, f: string): string {
|
||||
if (!(f in data)) {
|
||||
return ''
|
||||
}
|
||||
@ -171,11 +179,11 @@ function _readMultiLineString (data: any, f: string): string {
|
||||
}
|
||||
// Removing control characters (must authorize \u001A: line feed)
|
||||
// eslint-disable-next-line no-control-regex
|
||||
const s = (data[f] as string).replace(/[\u0000-\u0009\u001B-\u001F\u007F-\u009F]/g, '')
|
||||
const s = data[f].replace(/[\u0000-\u0009\u001B-\u001F\u007F-\u009F]/g, '')
|
||||
return s
|
||||
}
|
||||
|
||||
async function _readRegExpArray (data: any, f: string): Promise<string[]> {
|
||||
async function _readRegExpArray (data: Record<string, unknown>, f: string): Promise<string[]> {
|
||||
// Note: this function can instanciate a lot of RegExp.
|
||||
// To avoid freezing the server, we make it async, and will validate each regexp in a separate tick.
|
||||
if (!(f in data)) {
|
||||
@ -195,11 +203,11 @@ async function _readRegExpArray (data: any, f: string): Promise<string[]> {
|
||||
}
|
||||
// value must be a valid regexp
|
||||
try {
|
||||
async function _validate (): Promise<void> {
|
||||
async function _validate (v: string): Promise<void> {
|
||||
// eslint-disable-next-line no-new
|
||||
new RegExp(v)
|
||||
}
|
||||
await _validate()
|
||||
await _validate(v)
|
||||
} catch (_err) {
|
||||
throw new Error('Invalid value in field ' + f)
|
||||
}
|
||||
@ -208,12 +216,17 @@ async function _readRegExpArray (data: any, f: string): Promise<string[]> {
|
||||
return result
|
||||
}
|
||||
|
||||
async function _readForbiddenWords (botData: any): Promise<ChannelConfigurationOptions['bot']['forbiddenWords']> {
|
||||
async function _readForbiddenWords (
|
||||
botData: Record<string, unknown>
|
||||
): Promise<ChannelConfigurationOptions['bot']['forbiddenWords']> {
|
||||
if (!Array.isArray(botData.forbiddenWords)) {
|
||||
throw new Error('Invalid forbiddenWords data')
|
||||
}
|
||||
const result: ChannelConfigurationOptions['bot']['forbiddenWords'] = []
|
||||
for (const fw of botData.forbiddenWords) {
|
||||
if (!_assertObjectType(fw)) {
|
||||
throw new Error('Invalid entry in botData.forbiddenWords')
|
||||
}
|
||||
const regexp = !!fw.regexp
|
||||
let entries
|
||||
if (regexp) {
|
||||
@ -239,9 +252,9 @@ async function _readForbiddenWords (botData: any): Promise<ChannelConfigurationO
|
||||
}
|
||||
|
||||
async function _readForbidSpecialChars (
|
||||
botData: any
|
||||
botData: Record<string, unknown>
|
||||
): Promise<ChannelConfigurationOptions['bot']['forbidSpecialChars']> {
|
||||
if (typeof botData.forbidSpecialChars !== 'object') {
|
||||
if (!_assertObjectType(botData.forbidSpecialChars)) {
|
||||
throw new Error('Invalid forbidSpecialChars data')
|
||||
}
|
||||
const result: ChannelConfigurationOptions['bot']['forbidSpecialChars'] = {
|
||||
@ -253,12 +266,15 @@ async function _readForbidSpecialChars (
|
||||
return result
|
||||
}
|
||||
|
||||
function _readQuotes (botData: any): ChannelConfigurationOptions['bot']['quotes'] {
|
||||
function _readQuotes (botData: Record<string, unknown>): ChannelConfigurationOptions['bot']['quotes'] {
|
||||
if (!Array.isArray(botData.quotes)) {
|
||||
throw new Error('Invalid quotes data')
|
||||
}
|
||||
const result: ChannelConfigurationOptions['bot']['quotes'] = []
|
||||
for (const qs of botData.quotes) {
|
||||
if (!_assertObjectType(qs)) {
|
||||
throw new Error('Invalid entry in botData.quotes')
|
||||
}
|
||||
const messages = _readStringArray(qs, 'messages')
|
||||
const delay = _readInteger(qs, 'delay', 1, 6000)
|
||||
|
||||
@ -270,12 +286,15 @@ function _readQuotes (botData: any): ChannelConfigurationOptions['bot']['quotes'
|
||||
return result
|
||||
}
|
||||
|
||||
function _readCommands (botData: any): ChannelConfigurationOptions['bot']['commands'] {
|
||||
function _readCommands (botData: Record<string, unknown>): ChannelConfigurationOptions['bot']['commands'] {
|
||||
if (!Array.isArray(botData.commands)) {
|
||||
throw new Error('Invalid commands data')
|
||||
}
|
||||
const result: ChannelConfigurationOptions['bot']['commands'] = []
|
||||
for (const cs of botData.commands) {
|
||||
if (!_assertObjectType(cs)) {
|
||||
throw new Error('Invalid entry in botData.commands')
|
||||
}
|
||||
const message = _readSimpleInput(cs, 'message')
|
||||
const command = _readSimpleInput(cs, 'command', false, true)
|
||||
|
||||
|
@ -140,7 +140,7 @@ function channelConfigurationOptionsToBotRoomConf (
|
||||
for (const handler of previousRoomConf.handlers) {
|
||||
if (!handlersIds.has(handler.id)) {
|
||||
// cloning to avoid issues...
|
||||
const disabledHandler = JSON.parse(JSON.stringify(handler))
|
||||
const disabledHandler = JSON.parse(JSON.stringify(handler)) as typeof handler
|
||||
disabledHandler.enabled = false
|
||||
handlers.push(disabledHandler)
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ async function getConverseJSParams (
|
||||
externalAuthOIDC ??= []
|
||||
externalAuthOIDC.push({
|
||||
type: oidc.type,
|
||||
buttonLabel: buttonLabel,
|
||||
buttonLabel,
|
||||
url: authUrl
|
||||
})
|
||||
}
|
||||
@ -127,7 +127,7 @@ async function getConverseJSParams (
|
||||
localWebsocketServiceUrl: localWsUri,
|
||||
remoteBoshServiceUrl: remoteConnectionInfos?.anonymous?.boshUri ?? null,
|
||||
remoteWebsocketServiceUrl: remoteConnectionInfos?.anonymous?.wsUri ?? null,
|
||||
authenticationUrl: authenticationUrl,
|
||||
authenticationUrl,
|
||||
autoViewerMode,
|
||||
theme: converseJSTheme,
|
||||
forceReadonly,
|
||||
@ -150,7 +150,7 @@ function _interfaceParams (
|
||||
transparent: InitConverseJSParams['transparent']
|
||||
converseJSTheme: InitConverseJSParams['theme']
|
||||
} {
|
||||
let autoViewerMode: boolean = false
|
||||
let autoViewerMode = false
|
||||
const forceReadonly: boolean | 'noscroll' = params.readonly ?? false
|
||||
if (!forceReadonly) {
|
||||
autoViewerMode = true // auto join the chat in viewer mode, if not logged in
|
||||
|
@ -45,7 +45,7 @@ async function initCustomFields (options: RegisterServerOptions): Promise<void>
|
||||
|
||||
const body: any = params.body
|
||||
const video: Video | undefined = params.video
|
||||
if (!video || !video.id) {
|
||||
if (!video?.id) {
|
||||
return
|
||||
}
|
||||
if (!body.pluginData) return
|
||||
@ -115,7 +115,7 @@ async function fillVideoRemoteLiveChat (
|
||||
const infos = await getVideoLiveChatInfos(options, video)
|
||||
if (!infos) { return }
|
||||
|
||||
let ok: boolean = false
|
||||
let ok = false
|
||||
// We must check if there is a compatible connection protocol...
|
||||
if (anonymousConnectionInfos(infos)) {
|
||||
// Connection ok using a remote anonymous account. That's enought.
|
||||
|
@ -61,7 +61,7 @@ interface ChannelInfos {
|
||||
async function getChannelInfosById (
|
||||
options: RegisterServerOptions,
|
||||
channelId: number,
|
||||
restrictToLocalChannels: boolean = false
|
||||
restrictToLocalChannels = false
|
||||
): Promise<ChannelInfos | null> {
|
||||
if (!channelId) {
|
||||
throw new Error('Missing channelId')
|
||||
|
@ -87,7 +87,7 @@ function _getProsodyDebuggerOptions (options: RegisterServerOptions, json: any):
|
||||
if (!json.debug_prosody.debugger_path) { return undefined }
|
||||
if (typeof json.debug_prosody.debugger_path !== 'string') { return undefined }
|
||||
|
||||
const mobdebugPath = json.debug_prosody.debugger_path
|
||||
const mobdebugPath = json.debug_prosody.debugger_path as string
|
||||
|
||||
if (!fs.statSync(mobdebugPath).isDirectory()) {
|
||||
options.peertubeHelpers.logger.error('There should be a debugger, but cant find it. Path should be: ', mobdebugPath)
|
||||
|
@ -235,7 +235,7 @@ export async function diagProsody (test: string, options: RegisterServerOptions)
|
||||
title: 'Prosody error log (last 50 lines)',
|
||||
message: logLines.join('\n')
|
||||
})
|
||||
} catch (error) {
|
||||
} catch (_err) {
|
||||
// Error should be because file does not exists. This is not an error case, just ignoring.
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ export interface TestResult {
|
||||
|
||||
export function newResult (test: string): TestResult {
|
||||
return {
|
||||
test: test,
|
||||
test,
|
||||
ok: false,
|
||||
messages: [],
|
||||
debug: [],
|
||||
|
@ -26,7 +26,7 @@ export async function diagVideo (test: string, { settingsManager }: RegisterServ
|
||||
result.messages.push('Displaying «open in new window» button')
|
||||
}
|
||||
|
||||
let atLeastOne: boolean = false
|
||||
let atLeastOne = false
|
||||
if (videoSettings['chat-per-live-video']) {
|
||||
result.messages.push('Chat can be enabled on live videos.')
|
||||
atLeastOne = true
|
||||
|
@ -114,7 +114,7 @@ export class Emojis {
|
||||
// File does not exist, this is normal.
|
||||
return undefined
|
||||
}
|
||||
throw err
|
||||
throw err as Error
|
||||
}
|
||||
return JSON.parse(content.toString())
|
||||
}
|
||||
@ -316,7 +316,7 @@ export class Emojis {
|
||||
}
|
||||
|
||||
const result: ChannelEmojis = {
|
||||
customEmojis: customEmojis
|
||||
customEmojis
|
||||
}
|
||||
return [result, buffersInfos]
|
||||
}
|
||||
@ -387,7 +387,7 @@ export class Emojis {
|
||||
})
|
||||
} catch (err: any) {
|
||||
if (!(('code' in err) && err.code === 'ENOENT')) {
|
||||
this.logger.error(err)
|
||||
this.logger.error(err as string)
|
||||
}
|
||||
} finally {
|
||||
this.channelCache.delete(channelId)
|
||||
@ -475,15 +475,17 @@ async function _getConverseEmojiCodes (options: RegisterServerOptions): Promise<
|
||||
const converseEmojiDefPath = path.join(__dirname, '..', '..', '..', 'converse-emoji.json')
|
||||
options.peertubeHelpers.logger.debug('Loading Converse Emojis from file ' + converseEmojiDefPath)
|
||||
|
||||
const converseEmojis: {[key: string]: any} = JSON.parse(
|
||||
await (await fs.promises.readFile(converseEmojiDefPath)).toString()
|
||||
const converseEmojis: Record<string, any> = JSON.parse(
|
||||
(await fs.promises.readFile(converseEmojiDefPath)).toString()
|
||||
)
|
||||
|
||||
const r = []
|
||||
for (const [key, block] of Object.entries(converseEmojis)) {
|
||||
if (key === 'custom') { continue } // These are not used.
|
||||
r.push(
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
...Object.values(block)
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
.map((d: any) => d.cp ? _emojiCpToRegexp(d.cp) : d.sn)
|
||||
.filter((sn: string) => sn && sn !== '')
|
||||
)
|
||||
|
@ -238,7 +238,7 @@ class ExternalAuthOIDC {
|
||||
this.logger.debug('OIDC Discovery url is valid: ' + uri.toString())
|
||||
|
||||
this.providerHostName = uri.hostname
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
errors.push('Invalid discovery url')
|
||||
}
|
||||
}
|
||||
@ -349,11 +349,17 @@ class ExternalAuthOIDC {
|
||||
if (!encryptedCodeVerifier) {
|
||||
throw new Error('Received callback but code verifier not found in request cookies.')
|
||||
}
|
||||
if (typeof encryptedCodeVerifier !== 'string') {
|
||||
throw new Error('Invalid code-verifier type.')
|
||||
}
|
||||
|
||||
const encryptedState = req.cookies[this.cookieNamePrefix + 'state']
|
||||
if (!encryptedState) {
|
||||
throw new Error('Received callback but state not found in request cookies.')
|
||||
}
|
||||
if (typeof encryptedState !== 'string') {
|
||||
throw new Error('Invalid state data type')
|
||||
}
|
||||
|
||||
const codeVerifier = await this.decrypt(encryptedCodeVerifier)
|
||||
const state = await this.decrypt(encryptedState)
|
||||
@ -451,7 +457,7 @@ class ExternalAuthOIDC {
|
||||
const decipher = createDecipheriv(algorithm, this.secretKey, iv)
|
||||
|
||||
// FIXME: dismiss the "as any" below (dont understand why Typescript is not happy without)
|
||||
return decipher.update(encrypted as any, outputEncoding, inputEncoding) + decipher.final(inputEncoding)
|
||||
return decipher.update(encrypted.toString(), outputEncoding, inputEncoding) + decipher.final(inputEncoding)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -491,8 +497,11 @@ class ExternalAuthOIDC {
|
||||
if (typeof o.nickname !== 'string' || o.nickname === '') {
|
||||
throw new Error('No nickname')
|
||||
}
|
||||
if (typeof o.expire !== 'string' || o.expire === '') {
|
||||
throw new Error('Invalid expire data type')
|
||||
}
|
||||
|
||||
const expire = new Date(Date.parse(o.expire))
|
||||
const expire = new Date(Date.parse(o.expire as string))
|
||||
if (!(expire instanceof Date) || isNaN(expire.getTime())) {
|
||||
throw new Error('Invalid expire date')
|
||||
}
|
||||
@ -548,7 +557,7 @@ class ExternalAuthOIDC {
|
||||
if (!(field in userInfos)) { continue }
|
||||
if (typeof userInfos[field] !== 'string') { continue }
|
||||
if (userInfos[field] === '') { continue }
|
||||
return userInfos[field] as string
|
||||
return userInfos[field]
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
@ -571,7 +580,7 @@ class ExternalAuthOIDC {
|
||||
responseType: 'buffer'
|
||||
}).buffer()
|
||||
|
||||
const mimeType = await getMimeTypeFromArrayBuffer(buf)
|
||||
const mimeType = getMimeTypeFromArrayBuffer(buf as ArrayBuffer)
|
||||
if (!mimeType) {
|
||||
throw new Error('Failed to get the avatar file type')
|
||||
}
|
||||
@ -603,7 +612,7 @@ class ExternalAuthOIDC {
|
||||
const filePath = path.resolve(this.avatarsDir, file)
|
||||
const buf = await fs.promises.readFile(filePath)
|
||||
|
||||
const mimeType = await getMimeTypeFromArrayBuffer(buf)
|
||||
const mimeType = getMimeTypeFromArrayBuffer(buf)
|
||||
if (!mimeType) {
|
||||
throw new Error('Failed to get the default avatar file type')
|
||||
}
|
||||
@ -778,7 +787,7 @@ class ExternalAuthOIDC {
|
||||
const m = token.match(/^(\w+)-/)
|
||||
if (!m) { return null }
|
||||
return ExternalAuthOIDC.singleton(m[1])
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,7 @@ export async function initFederation (options: RegisterServerOptions): Promise<v
|
||||
|
||||
registerHook({
|
||||
target: 'filter:activity-pub.activity.context.build.result',
|
||||
handler: async (jsonld: any) => {
|
||||
handler: async (jsonld: any[]) => {
|
||||
return videoContextBuildJSONLD(options, jsonld)
|
||||
}
|
||||
})
|
||||
|
@ -56,7 +56,7 @@ async function videoBuildJSONLD (
|
||||
}
|
||||
|
||||
await fillVideoCustomFields(options, video)
|
||||
const hasChat = await videoHasWebchat({
|
||||
const hasChat = videoHasWebchat({
|
||||
'chat-per-live-video': !!settings['chat-per-live-video'],
|
||||
'chat-all-lives': !!settings['chat-all-lives'],
|
||||
'chat-all-non-lives': !!settings['chat-all-non-lives'],
|
||||
|
@ -169,7 +169,7 @@ function sanitizePeertubeLiveChatServerInfos (
|
||||
*/
|
||||
function sanitizeCustomEmojisUrl (
|
||||
options: RegisterServerOptions,
|
||||
customEmojisUrl: any,
|
||||
customEmojisUrl: unknown,
|
||||
referenceUrl?: string
|
||||
): string | undefined {
|
||||
let checkHost: undefined | string
|
||||
@ -206,8 +206,8 @@ interface URLConstraints {
|
||||
domain?: string
|
||||
}
|
||||
|
||||
function _validUrl (s: string, constraints: URLConstraints): boolean {
|
||||
if ((typeof s) !== 'string') { return false }
|
||||
function _validUrl (s: unknown, constraints: URLConstraints): s is string {
|
||||
if (typeof s !== 'string') { return false }
|
||||
if (s === '') { return false }
|
||||
let url: URL
|
||||
try {
|
||||
@ -265,13 +265,13 @@ function _validateHost (s: any, mustBeSubDomainOf?: string): false | string {
|
||||
}
|
||||
}
|
||||
|
||||
function _readReferenceUrl (s: any): undefined | string {
|
||||
function _readReferenceUrl (s: unknown): undefined | string {
|
||||
try {
|
||||
if (typeof s !== 'string') { return undefined }
|
||||
if (!s.startsWith('https://') && !s.startsWith('http://')) {
|
||||
s = 'http://' + s
|
||||
}
|
||||
const url = new URL(s)
|
||||
const url = new URL(s as string)
|
||||
const host = url.hostname
|
||||
// Just to avoid some basic spoofing, we must check that host is not simply something like "com".
|
||||
// We will check if there is at least one dot. This test is not perfect, but can limit spoofing cases.
|
||||
@ -283,16 +283,16 @@ function _readReferenceUrl (s: any): undefined | string {
|
||||
}
|
||||
|
||||
function _sanitizePeertubeLiveChatInfosV0 (
|
||||
options: RegisterServerOptions, chatInfos: any, referenceUrl?: string
|
||||
options: RegisterServerOptions, chatInfos: unknown, referenceUrl?: string
|
||||
): LiveChatJSONLDAttributeV1 {
|
||||
const logger = options.peertubeHelpers.logger
|
||||
logger.debug('We are have to migrate data from the old JSONLD format')
|
||||
|
||||
if (chatInfos === false) { return false }
|
||||
if (typeof chatInfos !== 'object') { return false }
|
||||
if (!_assertObjectType(chatInfos)) { return false}
|
||||
|
||||
if (chatInfos.type !== 'xmpp') { return false }
|
||||
if ((typeof chatInfos.jid) !== 'string') { return false }
|
||||
if (typeof chatInfos.jid !== 'string') { return false }
|
||||
|
||||
// no link? invalid! dropping all.
|
||||
if (!Array.isArray(chatInfos.links)) { return false }
|
||||
@ -327,10 +327,10 @@ function _sanitizePeertubeLiveChatInfosV0 (
|
||||
}
|
||||
|
||||
for (const link of chatInfos.links) {
|
||||
if ((typeof link) !== 'object') { continue }
|
||||
if (!_assertObjectType(link) || (typeof link.type !== 'string')) { continue }
|
||||
if (['xmpp-bosh-anonymous', 'xmpp-websocket-anonymous'].includes(link.type)) {
|
||||
if ((typeof link.jid) !== 'string') { continue }
|
||||
if ((typeof link.url) !== 'string') { continue }
|
||||
if (typeof link.jid !== 'string') { continue }
|
||||
if (typeof link.url !== 'string') { continue }
|
||||
|
||||
if (
|
||||
!_validUrl(link.url, {
|
||||
@ -372,6 +372,10 @@ function sanitizeXMPPHostFromInstanceUrl (_options: RegisterServerOptions, s: an
|
||||
}
|
||||
}
|
||||
|
||||
function _assertObjectType (data: unknown): data is Record<string, unknown> {
|
||||
return !!data && (typeof data === 'object') && Object.keys(data).every(k => typeof k === 'string')
|
||||
}
|
||||
|
||||
export {
|
||||
sanitizePeertubeLiveChatInfos,
|
||||
sanitizePeertubeLiveChatServerInfos,
|
||||
|
@ -75,7 +75,7 @@ export async function listModFirewallFiles (
|
||||
})
|
||||
|
||||
return files.map(f => path.join(dir, f.name)).sort()
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
// should be that the directory does not exists
|
||||
return []
|
||||
}
|
||||
@ -148,7 +148,7 @@ export async function sanitizeModFirewallConfig (
|
||||
throw new Error('Invalid data in data.files (content)')
|
||||
}
|
||||
|
||||
if (entry.name.length > maxFirewallNameLength || !firewallNameRegexp.test(entry.name)) {
|
||||
if (entry.name.length > maxFirewallNameLength || !firewallNameRegexp.test(entry.name as string)) {
|
||||
throw new Error('Invalid name in data.files')
|
||||
}
|
||||
if (entry.content.length > maxFirewallFileSize) {
|
||||
|
@ -6,22 +6,57 @@ import { eachSeries } from 'async'
|
||||
import type { NextFunction, Request, RequestHandler, Response } from 'express'
|
||||
|
||||
// Syntactic sugar to avoid try/catch in express controllers
|
||||
// Thanks: https://medium.com/@Abazhenov/using-async-await-in-express-with-node-8-b8af872c0016
|
||||
|
||||
export type RequestPromiseHandler = ((req: Request, res: Response, next: NextFunction) => Promise<any>)
|
||||
|
||||
function asyncMiddleware (fun: RequestPromiseHandler | RequestPromiseHandler[]): RequestHandler {
|
||||
// type asyncMiddleWareFunction = (req: Request, res: Response, next: NextFunction) => Promise<void>
|
||||
// function asyncMiddleware (fun: RequestPromiseHandler | RequestPromiseHandler[]): asyncMiddleWareFunction {
|
||||
// return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
|
||||
// if (!Array.isArray(fun)) {
|
||||
// // eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
|
||||
// Promise.resolve((fun as RequestHandler)(req, res, next))
|
||||
// .catch(err => { next(err) })
|
||||
// return
|
||||
// }
|
||||
|
||||
// try {
|
||||
// for (const f of fun) {
|
||||
// await new Promise<void>((resolve, reject) => {
|
||||
// // eslint-disable-next-line @typescript-eslint/no-floating-promises
|
||||
// asyncMiddleware(f)(req, res, err => {
|
||||
// if (err) {
|
||||
// reject(err)
|
||||
// return
|
||||
// }
|
||||
// resolve()
|
||||
// })
|
||||
// })
|
||||
// }
|
||||
|
||||
// next()
|
||||
// } catch (err) {
|
||||
// next(err)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
function asyncMiddleware (fun: RequestPromiseHandler | RequestPromiseHandler[]) {
|
||||
return (req: Request, res: Response, next: NextFunction) => {
|
||||
if (Array.isArray(fun)) {
|
||||
eachSeries(fun as RequestHandler[], (f, cb) => {
|
||||
Promise.resolve(f(req, res, (err: any) => cb(err)))
|
||||
.catch(err => next(err))
|
||||
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
|
||||
Promise.resolve(f(req, res, (err: any) => {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unsafe-argument
|
||||
cb(err)
|
||||
}))
|
||||
.catch(err => { next(err) })
|
||||
}, next)
|
||||
return
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-confusing-void-expression
|
||||
Promise.resolve((fun as RequestHandler)(req, res, next))
|
||||
.catch(err => next(err))
|
||||
.catch(err => { next(err) })
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -65,8 +65,8 @@ export class LivechatProsodyAuth {
|
||||
private readonly _prosodyDomain: string
|
||||
private _userTokensEnabled: boolean
|
||||
private readonly _tokensPath: string
|
||||
private readonly _passwords: Map<string, Password> = new Map()
|
||||
private readonly _tokensInfoByJID: Map<string, LivechatTokenInfos | undefined> = new Map()
|
||||
private readonly _passwords = new Map<string, Password>()
|
||||
private readonly _tokensInfoByJID = new Map<string, LivechatTokenInfos | undefined>()
|
||||
private readonly _secretKey: string
|
||||
protected readonly _logger: {
|
||||
debug: (s: string) => void
|
||||
@ -122,8 +122,8 @@ export class LivechatProsodyAuth {
|
||||
const nickname: string | undefined = await getUserNickname(this._options, user)
|
||||
return {
|
||||
jid: normalizedUsername + '@' + this._prosodyDomain,
|
||||
password: password,
|
||||
nickname: nickname,
|
||||
password,
|
||||
nickname,
|
||||
type: 'peertube'
|
||||
}
|
||||
}
|
||||
@ -136,7 +136,7 @@ export class LivechatProsodyAuth {
|
||||
if (this._userTokensEnabled) {
|
||||
try {
|
||||
const tokensInfo = await this._getTokensInfoForJID(normalizedUsername + '@' + this._prosodyDomain)
|
||||
if (!tokensInfo || !tokensInfo.tokens.length) {
|
||||
if (!tokensInfo?.tokens.length) {
|
||||
return false
|
||||
}
|
||||
// Checking that the user is valid:
|
||||
@ -159,7 +159,7 @@ export class LivechatProsodyAuth {
|
||||
if (this._userTokensEnabled) {
|
||||
try {
|
||||
const tokensInfo = await this._getTokensInfoForJID(normalizedUsername + '@' + this._prosodyDomain)
|
||||
if (!tokensInfo || !tokensInfo.tokens.length) {
|
||||
if (!tokensInfo?.tokens.length) {
|
||||
return false
|
||||
}
|
||||
// Checking that the user is valid:
|
||||
@ -247,7 +247,7 @@ export class LivechatProsodyAuth {
|
||||
}
|
||||
const nickname: string | undefined = await getUserNickname(this._options, user)
|
||||
const jid = normalizedUsername + '@' + this._prosodyDomain
|
||||
const token = await this._createToken(user.id, jid, label)
|
||||
const token = await this._createToken(user.id as number, jid, label)
|
||||
|
||||
token.nickname = nickname
|
||||
return token
|
||||
@ -279,7 +279,7 @@ export class LivechatProsodyAuth {
|
||||
return false
|
||||
}
|
||||
|
||||
await this._saveTokens(user.id, jid, tokensInfo.tokens.filter(t => t.id !== id))
|
||||
await this._saveTokens(user.id as number, jid, tokensInfo.tokens.filter(t => t.id !== id))
|
||||
return true
|
||||
}
|
||||
|
||||
@ -293,8 +293,8 @@ export class LivechatProsodyAuth {
|
||||
|
||||
const password = generatePassword(20)
|
||||
this._passwords.set(normalizedUsername, {
|
||||
password: password,
|
||||
validity: validity
|
||||
password,
|
||||
validity
|
||||
})
|
||||
return password
|
||||
}
|
||||
@ -330,7 +330,7 @@ export class LivechatProsodyAuth {
|
||||
const user = await this._options.peertubeHelpers.user.loadById(userId)
|
||||
if (!user || user.blocked) { return false }
|
||||
return true
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -381,7 +381,7 @@ export class LivechatProsodyAuth {
|
||||
this._tokensInfoByJID.set(jid, undefined)
|
||||
return undefined
|
||||
}
|
||||
throw err
|
||||
throw err as Error
|
||||
}
|
||||
}
|
||||
|
||||
@ -456,7 +456,7 @@ export class LivechatProsodyAuth {
|
||||
const decipher = createDecipheriv(algorithm, this._secretKey, iv)
|
||||
|
||||
// FIXME: dismiss the "as any" below (dont understand why Typescript is not happy without)
|
||||
return decipher.update(encrypted as any, outputEncoding, inputEncoding) + decipher.final(inputEncoding)
|
||||
return decipher.update(encrypted.toString(), outputEncoding, inputEncoding) + decipher.final(inputEncoding)
|
||||
}
|
||||
|
||||
public static singleton (): LivechatProsodyAuth {
|
||||
|
@ -39,7 +39,7 @@ function startProsodyCertificatesRenewCheck (options: RegisterServerOptions, con
|
||||
}, checkInterval)
|
||||
|
||||
renew = {
|
||||
timer: timer
|
||||
timer
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,7 @@ async function getProsodyFilePaths (options: RegisterServerOptions): Promise<Pro
|
||||
}
|
||||
|
||||
return {
|
||||
dir: dir,
|
||||
dir,
|
||||
pid: path.resolve(dir, 'prosody.pid'),
|
||||
error: path.resolve(dir, 'prosody.err'),
|
||||
log: path.resolve(dir, 'prosody.log'),
|
||||
@ -217,7 +217,7 @@ async function getProsodyConfig (options: RegisterServerOptionsV5): Promise<Pros
|
||||
? settings['chat-terms']
|
||||
: undefined
|
||||
|
||||
let useExternal: boolean = false
|
||||
let useExternal = false
|
||||
try {
|
||||
const oidcs = ExternalAuthOIDC.allSingletons()
|
||||
for (const oidc of oidcs) {
|
||||
@ -377,7 +377,7 @@ async function getProsodyConfig (options: RegisterServerOptionsV5): Promise<Pros
|
||||
config.useBotsVirtualHost(paths.botAvatars, paths.botAvatarsFiles)
|
||||
bots.moderation = await BotConfiguration.singleton().getModerationBotGlobalConf()
|
||||
if (bots.moderation?.connection?.password && typeof bots.moderation.connection.password === 'string') {
|
||||
valuesToHideInDiagnostic.set('BotPassword', bots.moderation.connection.password)
|
||||
valuesToHideInDiagnostic.set('BotPassword', bots.moderation.connection.password as string)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -7,7 +7,7 @@ import { getProsodyDomain } from './domain'
|
||||
import { getUserNameByChannelId } from '../../database/channel'
|
||||
import { BotConfiguration } from '../../configuration/bot'
|
||||
|
||||
interface Affiliations { [jid: string]: 'outcast' | 'none' | 'member' | 'admin' | 'owner' }
|
||||
type Affiliations = Record<string, 'outcast' | 'none' | 'member' | 'admin' | 'owner'>
|
||||
|
||||
async function _getCommonAffiliations (options: RegisterServerOptions, _prosodyDomain: string): Promise<Affiliations> {
|
||||
const r: Affiliations = {}
|
||||
|
@ -97,7 +97,7 @@ abstract class ProsodyConfigBlock {
|
||||
if (!this.entries.has(name)) {
|
||||
this.entries.set(name, [])
|
||||
}
|
||||
let entry = this.entries.get(name) as ConfigEntryValue
|
||||
let entry = this.entries.get(name) ?? []
|
||||
if (!Array.isArray(entry)) {
|
||||
entry = [entry]
|
||||
}
|
||||
@ -112,7 +112,7 @@ abstract class ProsodyConfigBlock {
|
||||
if (!this.entries.has(name)) {
|
||||
return
|
||||
}
|
||||
let entry = this.entries.get(name) as ConfigEntryValue
|
||||
let entry = this.entries.get(name) ?? []
|
||||
if (!Array.isArray(entry)) {
|
||||
entry = [entry]
|
||||
}
|
||||
|
@ -139,9 +139,9 @@ async function prosodyCtl (
|
||||
reject(new Error('Missing prosodyctl command executable'))
|
||||
return
|
||||
}
|
||||
let d: string = ''
|
||||
let e: string = ''
|
||||
let m: string = ''
|
||||
let d = ''
|
||||
let e = ''
|
||||
let m = ''
|
||||
const cmdArgs = [
|
||||
...filePaths.execCtlArgs,
|
||||
'--config',
|
||||
@ -196,7 +196,7 @@ async function prosodyCtl (
|
||||
// (else it can cause trouble by cleaning AppImage extract too soon)
|
||||
spawned.on('close', (code) => {
|
||||
resolve({
|
||||
code: code,
|
||||
code,
|
||||
stdout: d,
|
||||
sterr: e,
|
||||
message: m
|
||||
@ -399,8 +399,8 @@ async function ensureProsodyRunning (
|
||||
})
|
||||
}
|
||||
logger.info('Waiting for the prosody process to launch')
|
||||
let count: number = 0
|
||||
let processStarted: boolean = false
|
||||
let count = 0
|
||||
let processStarted = false
|
||||
while (!processStarted && count < 5) {
|
||||
count++
|
||||
await sleep(500)
|
||||
@ -418,8 +418,8 @@ async function ensureProsodyRunning (
|
||||
return
|
||||
}
|
||||
logger.info('Prosody is running')
|
||||
await startProsodyLogRotate(options, filePaths)
|
||||
await startProsodyCertificatesRenewCheck(options, config)
|
||||
startProsodyLogRotate(options, filePaths)
|
||||
startProsodyCertificatesRenewCheck(options, config)
|
||||
}
|
||||
|
||||
async function ensureProsodyNotRunning (options: RegisterServerOptions): Promise<void> {
|
||||
|
@ -10,7 +10,7 @@ import { reloadProsody } from './ctl'
|
||||
type Rotate = (file: string, options: {
|
||||
count?: number
|
||||
compress?: boolean
|
||||
}, cb: Function) => void
|
||||
}, cb: (err: any) => void) => void
|
||||
const rotate: Rotate = require('log-rotate')
|
||||
|
||||
interface ProsodyLogRotate {
|
||||
@ -27,9 +27,10 @@ async function _rotate (options: RegisterServerOptions, path: string): Promise<v
|
||||
rotate(path, { count: 14, compress: false }, (err: any) => {
|
||||
if (err) {
|
||||
options.peertubeHelpers.logger.error('Failed to rotate file ' + path, err)
|
||||
return resolve()
|
||||
resolve()
|
||||
return
|
||||
}
|
||||
return resolve()
|
||||
resolve()
|
||||
})
|
||||
})
|
||||
return p
|
||||
@ -79,7 +80,7 @@ function startProsodyLogRotate (options: RegisterServerOptions, paths: ProsodyFi
|
||||
}, checkInterval)
|
||||
|
||||
logRotate = {
|
||||
timer: timer,
|
||||
timer,
|
||||
lastRotation: Date.now()
|
||||
}
|
||||
}
|
||||
|
@ -36,11 +36,11 @@ class RoomChannel {
|
||||
|
||||
protected room2Channel: Map<string, number> = new Map<string, number>()
|
||||
protected channel2Rooms: Map<number, Map<string, true>> = new Map<number, Map<string, true>>()
|
||||
protected needSync: boolean = false
|
||||
protected needSync = false
|
||||
protected roomConfToUpdate: Map<string, true> = new Map<string, true>()
|
||||
|
||||
protected syncTimeout: ReturnType<typeof setTimeout> | undefined
|
||||
protected isWriting: boolean = false
|
||||
protected isWriting = false
|
||||
|
||||
constructor (params: {
|
||||
options: RegisterServerOptions
|
||||
@ -113,7 +113,7 @@ class RoomChannel {
|
||||
let content: string
|
||||
try {
|
||||
content = (await fs.promises.readFile(this.dataFilePath)).toString()
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
this.logger.info('Failed reading room-channel data file (' + this.dataFilePath + '), assuming it does not exists')
|
||||
return false
|
||||
}
|
||||
@ -122,7 +122,7 @@ class RoomChannel {
|
||||
let data: any
|
||||
try {
|
||||
data = JSON.parse(content)
|
||||
} catch (err) {
|
||||
} catch (_err) {
|
||||
this.logger.error('Unable to parse the content of the room-channel data file, will start with an empty database.')
|
||||
return false
|
||||
}
|
||||
@ -233,7 +233,7 @@ class RoomChannel {
|
||||
}
|
||||
|
||||
await fillVideoCustomFields(this.options, video)
|
||||
const hasChat = await videoHasWebchat({
|
||||
const hasChat = videoHasWebchat({
|
||||
'chat-per-live-video': !!settings['chat-per-live-video'],
|
||||
'chat-all-lives': !!settings['chat-all-lives'],
|
||||
'chat-all-non-lives': !!settings['chat-all-non-lives'],
|
||||
@ -405,7 +405,7 @@ class RoomChannel {
|
||||
this.syncTimeout = undefined
|
||||
this.logger.info('Running scheduled sync')
|
||||
this.sync().then(() => {}, (err) => {
|
||||
this.logger.error(err)
|
||||
this.logger.error(err as string)
|
||||
// We will not re-schedule the sync, to avoid flooding error log if there is an issue with the server
|
||||
})
|
||||
}, 100)
|
||||
|
@ -86,7 +86,7 @@ async function initRoomApiRouter (options: RegisterServerOptions, router: Router
|
||||
// Now, we have two different room type: per video or per channel.
|
||||
if (settings['prosody-room-type'] === 'channel') {
|
||||
const matches = jid.match(/^channel\.(\d+)$/)
|
||||
if (!matches || !matches[1]) {
|
||||
if (!matches?.[1]) {
|
||||
logger.warn(`Invalid channel room jid '${jid}'.`)
|
||||
res.sendStatus(403)
|
||||
return
|
||||
@ -117,7 +117,7 @@ async function initRoomApiRouter (options: RegisterServerOptions, router: Router
|
||||
},
|
||||
await _getChannelSpecificOptions(options, channelId)
|
||||
),
|
||||
affiliations: affiliations
|
||||
affiliations
|
||||
}
|
||||
|
||||
RoomChannel.singleton().link(channelId, jid)
|
||||
@ -172,7 +172,7 @@ async function initRoomApiRouter (options: RegisterServerOptions, router: Router
|
||||
},
|
||||
await _getChannelSpecificOptions(options, video.channelId)
|
||||
),
|
||||
affiliations: affiliations
|
||||
affiliations
|
||||
}
|
||||
|
||||
RoomChannel.singleton().link(video.channelId, jid)
|
||||
|
@ -147,7 +147,7 @@ async function initWebchatRouter (options: RegisterServerOptionsV5): Promise<Rou
|
||||
const additionnalMessage: string = escapeHTML(err.livechatError?.message as string ?? '')
|
||||
const message: string = escapeHTML(loc('chatroom_not_accessible'))
|
||||
|
||||
res.status(code)
|
||||
res.status(typeof code === 'number' ? code : 500)
|
||||
res.send(`<!DOCTYPE html PUBLIC "-//IETF//DTD HTML 2.0//EN"><html>
|
||||
<head><title>${message}</title></head>
|
||||
<body>
|
||||
@ -272,7 +272,7 @@ async function initWebchatRouter (options: RegisterServerOptionsV5): Promise<Rou
|
||||
res.status(200)
|
||||
const r: ProsodyListRoomsResult = {
|
||||
ok: true,
|
||||
rooms: rooms
|
||||
rooms
|
||||
}
|
||||
res.json(r)
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ async function initRSS (options: RegisterServerOptions): Promise<void> {
|
||||
}
|
||||
|
||||
await fillVideoCustomFields(options, video)
|
||||
const hasChat = await videoHasWebchat({
|
||||
const hasChat = videoHasWebchat({
|
||||
'chat-per-live-video': !!settings['chat-per-live-video'],
|
||||
'chat-all-lives': !!settings['chat-all-lives'],
|
||||
'chat-all-non-lives': !!settings['chat-all-non-lives'],
|
||||
|
@ -105,7 +105,7 @@ async function register (options: RegisterServerOptions): Promise<any> {
|
||||
}
|
||||
)
|
||||
}
|
||||
)
|
||||
).catch(() => {})
|
||||
}, () => {})
|
||||
} catch (error) {
|
||||
options.peertubeHelpers.logger.error('Error when launching Prosody: ' + (error as string))
|
||||
|
@ -5,7 +5,7 @@
|
||||
"es6": true
|
||||
},
|
||||
"extends": [
|
||||
"standard-with-typescript"
|
||||
"eslint-config-love"
|
||||
],
|
||||
"globals": {},
|
||||
"parser": "@typescript-eslint/parser",
|
||||
|
Loading…
Reference in New Issue
Block a user