Authentication token generation (#98):
* setting to disable the feature (aka "panic button")
This commit is contained in:
parent
a9b6474b8f
commit
257fdbd2c2
@ -18,6 +18,7 @@ export type LiveChatSettings = SettingEntries & {
|
|||||||
'prosody-room-allow-s2s': boolean
|
'prosody-room-allow-s2s': boolean
|
||||||
'converse-theme': ConverseJSTheme
|
'converse-theme': ConverseJSTheme
|
||||||
'prosody-room-type': string
|
'prosody-room-type': string
|
||||||
|
'livechat-token-disabled': boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export class PtContext {
|
export class PtContext {
|
||||||
|
@ -111,7 +111,12 @@ export class ShareChatElement extends LivechatElement {
|
|||||||
// Note: for dockEnabled, we check:
|
// Note: for dockEnabled, we check:
|
||||||
// * that the user is logged in
|
// * that the user is logged in
|
||||||
// * that the video is local (for remote video, tests case are too complicated, and it's not the main use case, so…)
|
// * that the video is local (for remote video, tests case are too complicated, and it's not the main use case, so…)
|
||||||
this.dockEnabled = !isAnonymousUser(this.ptContext.ptOptions) && this._video.isLocal
|
// * settings is not disabled
|
||||||
|
this.dockEnabled = (
|
||||||
|
!isAnonymousUser(this.ptContext.ptOptions) &&
|
||||||
|
this._video.isLocal &&
|
||||||
|
!settings['livechat-token-disabled']
|
||||||
|
)
|
||||||
this.autocolorsAvailable = isAutoColorsAvailable(settings['converse-theme'])
|
this.autocolorsAvailable = isAutoColorsAvailable(settings['converse-theme'])
|
||||||
|
|
||||||
this._restorePreviousState()
|
this._restorePreviousState()
|
||||||
|
@ -536,3 +536,11 @@ token_action_create: Create a new token
|
|||||||
token_action_revoke: Revoke the token
|
token_action_revoke: Revoke the token
|
||||||
token_default_label: Token generated from the web interface
|
token_default_label: Token generated from the web interface
|
||||||
token_action_revoke_confirm: Are you sure you want to revoke this token?
|
token_action_revoke_confirm: Are you sure you want to revoke this token?
|
||||||
|
auth_description: |
|
||||||
|
<h3>Authentication</h3>
|
||||||
|
livechat_token_disabled_label: 'Disable livechat tokens'
|
||||||
|
livechat_token_disabled_description: |
|
||||||
|
Users can generate long term tokens to connect to the chat.
|
||||||
|
These tokens can for example be used to include the chat in OBS web docks.
|
||||||
|
Check <a href="https://johnxlivingston.github.io/peertube-plugin-livechat/documentation/user/obs" target="_blank">the documentation</a> for more information.
|
||||||
|
You can disable this feature by checking this setting.
|
||||||
|
@ -63,6 +63,7 @@ let singleton: LivechatProsodyAuth | undefined
|
|||||||
export class LivechatProsodyAuth {
|
export class LivechatProsodyAuth {
|
||||||
private readonly _options: RegisterServerOptions
|
private readonly _options: RegisterServerOptions
|
||||||
private readonly _prosodyDomain: string
|
private readonly _prosodyDomain: string
|
||||||
|
private _userTokensEnabled: boolean
|
||||||
private readonly _tokensPath: string
|
private readonly _tokensPath: string
|
||||||
private readonly _passwords: Map<string, Password> = new Map()
|
private readonly _passwords: Map<string, Password> = new Map()
|
||||||
private readonly _tokensInfoByJID: Map<string, LivechatTokenInfos | undefined> = new Map()
|
private readonly _tokensInfoByJID: Map<string, LivechatTokenInfos | undefined> = new Map()
|
||||||
@ -80,9 +81,10 @@ export class LivechatProsodyAuth {
|
|||||||
outputEncoding: 'hex' as Encoding
|
outputEncoding: 'hex' as Encoding
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor (options: RegisterServerOptions, prosodyDomain: string, secretKey: string) {
|
constructor (options: RegisterServerOptions, prosodyDomain: string, userTokensEnabled: boolean, secretKey: string) {
|
||||||
this._options = options
|
this._options = options
|
||||||
this._prosodyDomain = prosodyDomain
|
this._prosodyDomain = prosodyDomain
|
||||||
|
this._userTokensEnabled = userTokensEnabled
|
||||||
this._secretKey = secretKey
|
this._secretKey = secretKey
|
||||||
this._tokensPath = path.join(
|
this._tokensPath = path.join(
|
||||||
options.peertubeHelpers.plugin.getDataDirectoryPath(),
|
options.peertubeHelpers.plugin.getDataDirectoryPath(),
|
||||||
@ -131,6 +133,7 @@ export class LivechatProsodyAuth {
|
|||||||
if (entry) {
|
if (entry) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if (this._userTokensEnabled) {
|
||||||
try {
|
try {
|
||||||
const tokensInfo = await this._getTokensInfoForJID(normalizedUsername + '@' + this._prosodyDomain)
|
const tokensInfo = await this._getTokensInfoForJID(normalizedUsername + '@' + this._prosodyDomain)
|
||||||
if (!tokensInfo || !tokensInfo.tokens.length) {
|
if (!tokensInfo || !tokensInfo.tokens.length) {
|
||||||
@ -144,6 +147,7 @@ export class LivechatProsodyAuth {
|
|||||||
this._logger.error(err as string)
|
this._logger.error(err as string)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -152,6 +156,7 @@ export class LivechatProsodyAuth {
|
|||||||
if (entry && entry.password === password) {
|
if (entry && entry.password === password) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
if (this._userTokensEnabled) {
|
||||||
try {
|
try {
|
||||||
const tokensInfo = await this._getTokensInfoForJID(normalizedUsername + '@' + this._prosodyDomain)
|
const tokensInfo = await this._getTokensInfoForJID(normalizedUsername + '@' + this._prosodyDomain)
|
||||||
if (!tokensInfo || !tokensInfo.tokens.length) {
|
if (!tokensInfo || !tokensInfo.tokens.length) {
|
||||||
@ -170,6 +175,7 @@ export class LivechatProsodyAuth {
|
|||||||
this._logger.error(err as string)
|
this._logger.error(err as string)
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -179,6 +185,9 @@ export class LivechatProsodyAuth {
|
|||||||
* @param user the user
|
* @param user the user
|
||||||
*/
|
*/
|
||||||
public async getUserTokens (user: MUserDefault): Promise<LivechatToken[] | undefined> {
|
public async getUserTokens (user: MUserDefault): Promise<LivechatToken[] | undefined> {
|
||||||
|
if (!this._userTokensEnabled) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
if (!user || !user.id) {
|
if (!user || !user.id) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
@ -210,7 +219,22 @@ export class LivechatProsodyAuth {
|
|||||||
return tokens
|
return tokens
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable or disable user tokens. Must be called when the settings change.
|
||||||
|
* @param enabled
|
||||||
|
*/
|
||||||
|
public setUserTokensEnabled (enabled: boolean): void {
|
||||||
|
this._userTokensEnabled = !!enabled
|
||||||
|
if (!this.userRegistered) {
|
||||||
|
// Empty the cache:
|
||||||
|
this._tokensInfoByJID.clear()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public async createUserToken (user: MUserDefault, label: string): Promise<LivechatToken | undefined> {
|
public async createUserToken (user: MUserDefault, label: string): Promise<LivechatToken | undefined> {
|
||||||
|
if (!this._userTokensEnabled) {
|
||||||
|
return undefined
|
||||||
|
}
|
||||||
if (!user || !user.id) {
|
if (!user || !user.id) {
|
||||||
return undefined
|
return undefined
|
||||||
}
|
}
|
||||||
@ -230,6 +254,9 @@ export class LivechatProsodyAuth {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async revokeUserToken (user: MUserDefault, id: number): Promise<boolean> {
|
public async revokeUserToken (user: MUserDefault, id: number): Promise<boolean> {
|
||||||
|
if (!this._userTokensEnabled) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
if (!user || !user.id) {
|
if (!user || !user.id) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@ -448,12 +475,13 @@ export class LivechatProsodyAuth {
|
|||||||
await options.storageManager.storeData('livechat-prosody-auth-secretkey', secretKey)
|
await options.storageManager.storeData('livechat-prosody-auth-secretkey', secretKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
singleton = new LivechatProsodyAuth(options, prosodyDomain, secretKey)
|
const userTokenDisabled = await options.settingsManager.getSetting('livechat-token-disabled')
|
||||||
|
|
||||||
|
singleton = new LivechatProsodyAuth(options, prosodyDomain, !userTokenDisabled, secretKey)
|
||||||
return singleton
|
return singleton
|
||||||
}
|
}
|
||||||
|
|
||||||
public static async destroySingleton (): Promise<void> {
|
public static async destroySingleton (): Promise<void> {
|
||||||
// TODO: sync to disk
|
|
||||||
singleton = undefined
|
singleton = undefined
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,7 @@ import { RoomChannel } from './room-channel'
|
|||||||
import { BotsCtl } from './bots/ctl'
|
import { BotsCtl } from './bots/ctl'
|
||||||
import { ExternalAuthOIDC, ExternalAuthOIDCType } from './external-auth/oidc'
|
import { ExternalAuthOIDC, ExternalAuthOIDCType } from './external-auth/oidc'
|
||||||
import { Emojis } from './emojis'
|
import { Emojis } from './emojis'
|
||||||
|
import { LivechatProsodyAuth } from './prosody/auth'
|
||||||
import { loc } from './loc'
|
import { loc } from './loc'
|
||||||
const escapeHTML = require('escape-html')
|
const escapeHTML = require('escape-html')
|
||||||
|
|
||||||
@ -21,6 +22,7 @@ async function initSettings (options: RegisterServerOptions): Promise<void> {
|
|||||||
initImportantNotesSettings(options)
|
initImportantNotesSettings(options)
|
||||||
initChatSettings(options)
|
initChatSettings(options)
|
||||||
initFederationSettings(options)
|
initFederationSettings(options)
|
||||||
|
initAuth(options)
|
||||||
initExternalAuth(options)
|
initExternalAuth(options)
|
||||||
initAdvancedChannelCustomizationSettings(options)
|
initAdvancedChannelCustomizationSettings(options)
|
||||||
initChatBehaviourSettings(options)
|
initChatBehaviourSettings(options)
|
||||||
@ -73,6 +75,8 @@ async function initSettings (options: RegisterServerOptions): Promise<void> {
|
|||||||
await Emojis.destroySingleton()
|
await Emojis.destroySingleton()
|
||||||
await Emojis.initSingleton(options)
|
await Emojis.initSingleton(options)
|
||||||
|
|
||||||
|
LivechatProsodyAuth.singleton().setUserTokensEnabled(!settings['livechat-token-disabled'])
|
||||||
|
|
||||||
peertubeHelpers.logger.info('Saving settings, ensuring prosody is running')
|
peertubeHelpers.logger.info('Saving settings, ensuring prosody is running')
|
||||||
await ensureProsodyRunning(options)
|
await ensureProsodyRunning(options)
|
||||||
|
|
||||||
@ -181,6 +185,35 @@ function initFederationSettings ({ registerSetting }: RegisterServerOptions): vo
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize settings related to authentication.
|
||||||
|
* @param options peertube server options
|
||||||
|
*/
|
||||||
|
function initAuth (options: RegisterServerOptions): void {
|
||||||
|
const registerSetting = options.registerSetting
|
||||||
|
|
||||||
|
registerSetting({
|
||||||
|
type: 'html',
|
||||||
|
private: true,
|
||||||
|
descriptionHTML: loc('auth_description')
|
||||||
|
})
|
||||||
|
|
||||||
|
registerSetting({
|
||||||
|
type: 'html',
|
||||||
|
private: true,
|
||||||
|
descriptionHTML: loc('experimental_warning')
|
||||||
|
})
|
||||||
|
|
||||||
|
registerSetting({
|
||||||
|
name: 'livechat-token-disabled',
|
||||||
|
label: loc('livechat_token_disabled_label'),
|
||||||
|
descriptionHTML: loc('livechat_token_disabled_description'),
|
||||||
|
type: 'input-checkbox',
|
||||||
|
default: false,
|
||||||
|
private: false
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers settings related to the "External Authentication" section.
|
* Registers settings related to the "External Authentication" section.
|
||||||
* @param param0 server options
|
* @param param0 server options
|
||||||
|
@ -52,7 +52,7 @@ async function register (options: RegisterServerOptions): Promise<any> {
|
|||||||
await initSettings(options)
|
await initSettings(options)
|
||||||
|
|
||||||
await Emojis.initSingleton(options) // after settings, before routes
|
await Emojis.initSingleton(options) // after settings, before routes
|
||||||
await LivechatProsodyAuth.initSingleton(options)
|
await LivechatProsodyAuth.initSingleton(options) // after settings, before routes
|
||||||
|
|
||||||
await initCustomFields(options)
|
await initCustomFields(options)
|
||||||
await initRouters(options)
|
await initRouters(options)
|
||||||
|
@ -24,6 +24,12 @@ Following settings concern the federation with other Peertube instances, and oth
|
|||||||
|
|
||||||
{{% livechat_label federation_dont_publish_remotely_description %}}
|
{{% livechat_label federation_dont_publish_remotely_description %}}
|
||||||
|
|
||||||
|
## Authentication
|
||||||
|
|
||||||
|
### {{% livechat_label livechat_token_disabled_label %}}
|
||||||
|
|
||||||
|
In case you have any trouble with the long term authentication tokens, you can disable the feature here.
|
||||||
|
|
||||||
## External Authentication
|
## External Authentication
|
||||||
|
|
||||||
See the detailed documentation page:
|
See the detailed documentation page:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user