Require authentication to participate in chat (#4762)

* feat(chat): require authentication to participate in chat

* fix: it's pretty much impossible to bypass the auth requirement, addressing review feedback anyway

* feat(chat): render chat text input as disabled if chat auth is required

* Commit updated API documentation

---------

Co-authored-by: Owncast <owncast@owncast.online>
This commit is contained in:
Gabe Kangas
2026-01-28 11:49:07 -08:00
committed by GitHub
co-authored by Owncast
parent 83c8b2b3d5
commit 93b482871f
29 changed files with 5194 additions and 5143 deletions
+18 -1
View File
@@ -2,6 +2,7 @@
import { useRecoilValue } from 'recoil';
import { useEffect } from 'react';
import { ErrorBoundary } from 'react-error-boundary';
import { useTranslation } from 'next-export-i18n';
import { ChatMessage } from '../../../../interfaces/chat-message.model';
import { ChatContainer } from '../../../../components/chat/ChatContainer/ChatContainer';
import {
@@ -12,6 +13,7 @@ import {
appStateAtom,
serverStatusState,
isChatAvailableSelector,
chatAuthenticatedAtom,
} from '../../../../components/stores/ClientConfigStore';
import Header from '../../../../components/ui/Header/Header';
import { ClientConfig } from '../../../../interfaces/client-config.model';
@@ -19,8 +21,10 @@ import { AppStateOptions } from '../../../../components/stores/application-state
import { ServerStatus } from '../../../../interfaces/server-status.model';
import { Theme } from '../../../../components/theme/Theme';
import { ComponentError } from '../../../../components/ui/ComponentError/ComponentError';
import { Localization } from '../../../../types/localization';
export default function ReadWriteChatEmbed() {
const { t } = useTranslation();
const currentUser = useRecoilValue(currentUserAtom);
const messages = useRecoilValue<ChatMessage[]>(visibleChatMessagesSelector);
const clientConfig = useRecoilValue<ClientConfig>(clientConfigStateAtom);
@@ -28,8 +32,19 @@ export default function ReadWriteChatEmbed() {
const appState = useRecoilValue<AppStateOptions>(appStateAtom);
const isChatAvailable = useRecoilValue(isChatAvailableSelector);
const isUserAuthenticated = useRecoilValue<boolean>(chatAuthenticatedAtom);
const { name, chatDisabled } = clientConfig;
const { name, chatDisabled, chatRequireAuthentication } = clientConfig;
// Determine if chat input should be enabled based on authentication requirements.
// Moderators bypass the authentication requirement.
const chatInputEnabled = !!(
isChatAvailable &&
(!chatRequireAuthentication || isUserAuthenticated || currentUser?.isModerator)
);
const chatInputDisabledMessage = chatRequireAuthentication
? t(Localization.Frontend.Chat.authenticateToChat)
: t(Localization.Frontend.chatDisabled);
const { videoAvailable } = appState;
const { streamTitle, online } = clientStatus;
@@ -73,6 +88,8 @@ export default function ReadWriteChatEmbed() {
showInput
height="92vh"
chatAvailable={isChatAvailable}
inputEnabled={chatInputEnabled}
inputDisabledPlaceholder={chatInputDisabledMessage}
/>
</div>
)}