diff --git a/src/app/PersistableValues.ts b/src/app/PersistableValues.ts index 82416b8776..7bd923fbef 100644 --- a/src/app/PersistableValues.ts +++ b/src/app/PersistableValues.ts @@ -60,13 +60,15 @@ type PersistableValues_3_8_12 = PersistableValues_3_8_9 & { hasHideOnTrayNotificationShown: boolean; }; -type PersistableValues_3_9_5 = PersistableValues_3_8_12 & { +type PersistableValues_3_9_6 = PersistableValues_3_8_12 & { lastSelectedServerUrl: string; + allowedNTLMCredentialsDomains: string | null; + isNTLMCredentialsEnabled: boolean; }; export type PersistableValues = Pick< - PersistableValues_3_9_5, - keyof PersistableValues_3_9_5 + PersistableValues_3_9_6, + keyof PersistableValues_3_9_6 >; export const migrations = { @@ -113,4 +115,10 @@ export const migrations = { ...before, hasHideOnTrayNotificationShown: false, }), + '>=3.9.6': (before: PersistableValues_3_8_12): PersistableValues_3_9_6 => ({ + ...before, + isNTLMCredentialsEnabled: false, + allowedNTLMCredentialsDomains: null, + lastSelectedServerUrl: '', + }), }; diff --git a/src/app/actions.ts b/src/app/actions.ts index 6a5019f81b..3b8024af59 100644 --- a/src/app/actions.ts +++ b/src/app/actions.ts @@ -4,10 +4,13 @@ export const APP_ERROR_THROWN = 'app/error-thrown'; export const APP_PATH_SET = 'app/path-set'; export const APP_VERSION_SET = 'app/version-set'; export const APP_SETTINGS_LOADED = 'app/settings-loaded'; +export const APP_ALLOWED_NTLM_CREDENTIALS_DOMAINS_SET = + 'app/allowed-ntlm-credentials-domains-set'; export type AppActionTypeToPayloadMap = { [APP_ERROR_THROWN]: Error; [APP_PATH_SET]: string; [APP_VERSION_SET]: string; [APP_SETTINGS_LOADED]: Partial; + [APP_ALLOWED_NTLM_CREDENTIALS_DOMAINS_SET]: string; }; diff --git a/src/app/main/app.ts b/src/app/main/app.ts index 8b97145e8d..98f819cb37 100644 --- a/src/app/main/app.ts +++ b/src/app/main/app.ts @@ -1,4 +1,4 @@ -import { app } from 'electron'; +import { app, session } from 'electron'; import rimraf from 'rimraf'; // eslint-disable-next-line @typescript-eslint/ban-ts-comment @@ -14,11 +14,16 @@ import { dispatch, listen } from '../../store'; import { readSetting } from '../../store/readSetting'; import { SETTINGS_CLEAR_PERMITTED_SCREEN_CAPTURE_PERMISSIONS, + SETTINGS_NTLM_CREDENTIALS_CHANGED, SETTINGS_SET_HARDWARE_ACCELERATION_OPT_IN_CHANGED, } from '../../ui/actions'; import { askForClearScreenCapturePermission } from '../../ui/main/dialogs'; import { getRootWindow } from '../../ui/main/rootWindow'; -import { APP_PATH_SET, APP_VERSION_SET } from '../actions'; +import { + APP_ALLOWED_NTLM_CREDENTIALS_DOMAINS_SET, + APP_PATH_SET, + APP_VERSION_SET, +} from '../actions'; export const packageJsonInformation = { productName: packageJson.productName, @@ -94,6 +99,29 @@ export const setupApp = (): void => { relaunchApp(); }); + listen(APP_ALLOWED_NTLM_CREDENTIALS_DOMAINS_SET, (action) => { + if (action.payload.length > 0) { + session.defaultSession.allowNTLMCredentialsForDomains(action.payload); + } + }); + + listen(SETTINGS_NTLM_CREDENTIALS_CHANGED, (action) => { + if (action.payload === true) { + const allowedNTLMCredentialsDomains = readSetting( + 'allowedNTLMCredentialsDomains' + ); + if (allowedNTLMCredentialsDomains) { + console.log('Setting NTLM credentials', allowedNTLMCredentialsDomains); + session.defaultSession.allowNTLMCredentialsForDomains( + allowedNTLMCredentialsDomains + ); + } + } else { + console.log('Clearing NTLM credentials'); + session.defaultSession.allowNTLMCredentialsForDomains(''); + } + }); + listen( SETTINGS_CLEAR_PERMITTED_SCREEN_CAPTURE_PERMISSIONS, async (_action) => { @@ -108,6 +136,19 @@ export const setupApp = (): void => { } ); + const allowedNTLMCredentialsDomains = readSetting( + 'allowedNTLMCredentialsDomains' + ); + + const isNTLMCredentialsEnabled = readSetting('isNTLMCredentialsEnabled'); + + if (isNTLMCredentialsEnabled && allowedNTLMCredentialsDomains.length > 0) { + console.log('Setting NTLM credentials', allowedNTLMCredentialsDomains); + session.defaultSession.allowNTLMCredentialsForDomains( + allowedNTLMCredentialsDomains + ); + } + dispatch({ type: APP_PATH_SET, payload: app.getAppPath() }); dispatch({ type: APP_VERSION_SET, payload: app.getVersion() }); }; diff --git a/src/app/reducers/allowedNTLMCredentialsDomains.ts b/src/app/reducers/allowedNTLMCredentialsDomains.ts new file mode 100644 index 0000000000..b1b4ba370d --- /dev/null +++ b/src/app/reducers/allowedNTLMCredentialsDomains.ts @@ -0,0 +1,31 @@ +import type { Reducer } from 'redux'; + +import type { ActionOf } from '../../store/actions'; +import { + APP_ALLOWED_NTLM_CREDENTIALS_DOMAINS_SET, + APP_SETTINGS_LOADED, +} from '../actions'; + +type allowedNTLMCredentialsDomainsAction = + | ActionOf + | ActionOf; + +export const allowedNTLMCredentialsDomains: Reducer< + string | null, + allowedNTLMCredentialsDomainsAction +> = (state = null, action) => { + switch (action.type) { + case APP_SETTINGS_LOADED: { + const { allowedNTLMCredentialsDomains = state } = action.payload; + return allowedNTLMCredentialsDomains; + } + + case APP_ALLOWED_NTLM_CREDENTIALS_DOMAINS_SET: { + if (action.payload === null) return null; + return action.payload; + } + + default: + return state; + } +}; diff --git a/src/app/selectors.ts b/src/app/selectors.ts index 90d9e4f5ab..8307e08265 100644 --- a/src/app/selectors.ts +++ b/src/app/selectors.ts @@ -41,4 +41,8 @@ export const selectPersistableValues = createStructuredSelector< hasHideOnTrayNotificationShown: ({ hasHideOnTrayNotificationShown }) => hasHideOnTrayNotificationShown, lastSelectedServerUrl: ({ lastSelectedServerUrl }) => lastSelectedServerUrl, + allowedNTLMCredentialsDomains: ({ allowedNTLMCredentialsDomains }) => + allowedNTLMCredentialsDomains, + isNTLMCredentialsEnabled: ({ isNTLMCredentialsEnabled }) => + isNTLMCredentialsEnabled, }); diff --git a/src/i18n/en.i18n.json b/src/i18n/en.i18n.json index 7b395bd6ce..8756cb346c 100644 --- a/src/i18n/en.i18n.json +++ b/src/i18n/en.i18n.json @@ -223,6 +223,15 @@ "clearPermittedScreenCaptureServers": { "title": "Clear Screen Capture Permissions", "description": "Clear the screen capture permissions that was selected to not ask again on video calls." + }, + "allowScreenCaptureOnVideoCalls": { + "title": "Allow Screen Capture on Video Calls", + "description": "Allow screen capture on video calls. This will ask for permission on each video call." + }, + "ntlmCredentials": { + "title": "NTLM Credentials", + "description": "Allow NTLM Credentials to be used when connecting to a server.", + "domains": "Domains that will use the credentials. Separated by comma. Use * to match all domains." } } }, diff --git a/src/i18n/pt-BR.i18n.json b/src/i18n/pt-BR.i18n.json index 216102e657..5763879d86 100644 --- a/src/i18n/pt-BR.i18n.json +++ b/src/i18n/pt-BR.i18n.json @@ -205,6 +205,19 @@ "trayIcon": { "title": "Ícone da bandeja", "description": "Mostra um ícone na bandeja do sistema para acessar rapidamente a aplicação. Se o ícone da bandeja estiver ativado, a aplicação será minimizada para a barra de tarefas ao ser fechada. Por outro lado se o ícone da bandeja estiver desativado, a aplicação será finalizada ao ser fechada." + }, + "clearPermittedScreenCaptureServers": { + "title": "Limpar Permissões de Captura de Tela", + "description": "Limpar as permissões de captura de tela que foram selecionadas para não perguntar novamente em chamadas de vídeo." + }, + "allowScreenCaptureOnVideoCalls": { + "title": "Permitir Captura de Tela em Chamadas de Vídeo", + "description": "Permitir captura de tela em chamadas de vídeo. Isso solicitará permissão em cada chamada de vídeo." + }, + "ntlmCredentials": { + "title": "Credenciais NTLM", + "description": "Permitir o uso de credenciais NTLM ao conectar-se a um servidor.", + "domains": "Domínios que usarão as credenciais. Separados por vírgula. Use * para permitir todos os domínios." } } }, diff --git a/src/store/rootReducer.ts b/src/store/rootReducer.ts index ee02f5fcbb..580df55ca0 100644 --- a/src/store/rootReducer.ts +++ b/src/store/rootReducer.ts @@ -1,5 +1,6 @@ import { combineReducers } from 'redux'; +import { allowedNTLMCredentialsDomains } from '../app/reducers/allowedNTLMCredentialsDomains'; import { appPath } from '../app/reducers/appPath'; import { appVersion } from '../app/reducers/appVersion'; import { downloads } from '../downloads/reducers/downloads'; @@ -20,6 +21,7 @@ import { isInternalVideoChatWindowEnabled } from '../ui/reducers/isInternalVideo import { isMenuBarEnabled } from '../ui/reducers/isMenuBarEnabled'; import { isMessageBoxFocused } from '../ui/reducers/isMessageBoxFocused'; import { isMinimizeOnCloseEnabled } from '../ui/reducers/isMinimizeOnCloseEnabled'; +import { isNTLMCredentialsEnabled } from '../ui/reducers/isNTLMCredentialsEnabled'; import { isReportEnabled } from '../ui/reducers/isReportEnabled'; import { isShowWindowOnUnreadChangedEnabled } from '../ui/reducers/isShowWindowOnUnreadChangedEnabled'; import { isSideBarEnabled } from '../ui/reducers/isSideBarEnabled'; @@ -74,6 +76,8 @@ export const rootReducer = combineReducers({ isAddNewServersEnabled, hasHideOnTrayNotificationShown, lastSelectedServerUrl, + allowedNTLMCredentialsDomains, + isNTLMCredentialsEnabled, }); export type RootState = ReturnType; diff --git a/src/ui/actions.ts b/src/ui/actions.ts index d5d348656a..bd21020990 100644 --- a/src/ui/actions.ts +++ b/src/ui/actions.ts @@ -83,6 +83,8 @@ export const SETTINGS_SET_IS_MENU_BAR_ENABLED_CHANGED = 'settings/set-is-menu-bar-enabled-changed'; export const SETTINGS_CLEAR_PERMITTED_SCREEN_CAPTURE_PERMISSIONS = 'settings/clear-permitted-screen-capture-permissions'; +export const SETTINGS_NTLM_CREDENTIALS_CHANGED = + 'settings/ntlm-credentials-changed'; export const SET_HAS_TRAY_MINIMIZE_NOTIFICATION_SHOWN = 'notifications/set-has-tray-minimize-notification-shown'; export const VIDEO_CALL_WINDOW_OPEN_URL = 'video-call-window/open-url'; @@ -163,6 +165,7 @@ export type UiActionTypeToPayloadMap = { [SETTINGS_SET_IS_MENU_BAR_ENABLED_CHANGED]: boolean; [SETTINGS_CLEAR_PERMITTED_SCREEN_CAPTURE_PERMISSIONS]: void; [SET_HAS_TRAY_MINIMIZE_NOTIFICATION_SHOWN]: boolean; + [SETTINGS_NTLM_CREDENTIALS_CHANGED]: boolean; [VIDEO_CALL_WINDOW_OPEN_URL]: { url: string }; [DOWNLOADS_BACK_BUTTON_CLICKED]: string; }; diff --git a/src/ui/components/SettingsView/GeneralTab.tsx b/src/ui/components/SettingsView/GeneralTab.tsx index 3dea2b637a..95e20936bb 100644 --- a/src/ui/components/SettingsView/GeneralTab.tsx +++ b/src/ui/components/SettingsView/GeneralTab.tsx @@ -8,6 +8,7 @@ import { HardwareAcceleration } from './features/HardwareAcceleration'; import { InternalVideoChatWindow } from './features/InternalVideoChatWindow'; import { MenuBar } from './features/MenuBar'; import { MinimizeOnClose } from './features/MinimizeOnClose'; +import { NTLMCredentials } from './features/NTLMCredentials'; import { ReportErrors } from './features/ReportErrors'; import { SideBar } from './features/SideBar'; import { TrayIcon } from './features/TrayIcon'; @@ -23,6 +24,7 @@ export const GeneralTab: FC = () => ( {process.platform === 'win32' && } {process.platform !== 'darwin' && } + {!process.mas && } diff --git a/src/ui/components/SettingsView/features/NTLMCredentials.tsx b/src/ui/components/SettingsView/features/NTLMCredentials.tsx new file mode 100644 index 0000000000..16354866a5 --- /dev/null +++ b/src/ui/components/SettingsView/features/NTLMCredentials.tsx @@ -0,0 +1,85 @@ +import { Field, InputBox, ToggleSwitch } from '@rocket.chat/fuselage'; +import React, { + useCallback, + type ChangeEvent, + type Dispatch, + type FC, +} from 'react'; +import { useTranslation } from 'react-i18next'; +import { useDispatch, useSelector } from 'react-redux'; + +import { APP_ALLOWED_NTLM_CREDENTIALS_DOMAINS_SET } from '../../../../app/actions'; +import type { RootAction } from '../../../../store/actions'; +import type { RootState } from '../../../../store/rootReducer'; +import { SETTINGS_NTLM_CREDENTIALS_CHANGED } from '../../../actions'; + +type Props = { + className?: string; +}; + +export const NTLMCredentials: FC = (props) => { + const isNTLMCredentialsEnabled = useSelector( + ({ isNTLMCredentialsEnabled }: RootState) => isNTLMCredentialsEnabled + ); + const allowedNTLMCredentialsDomains = useSelector( + ({ allowedNTLMCredentialsDomains }: RootState) => + allowedNTLMCredentialsDomains + ); + const { t } = useTranslation(); + const dispatch = useDispatch>(); + + const handleToggleChange = useCallback( + (event: ChangeEvent) => { + const isChecked = event.currentTarget.checked; + dispatch({ + type: SETTINGS_NTLM_CREDENTIALS_CHANGED, + payload: isChecked, + }); + }, + [dispatch] + ); + + const handleDomainsChange = useCallback( + (event: React.FocusEvent) => { + const domains = event.target.value; + dispatch({ + type: APP_ALLOWED_NTLM_CREDENTIALS_DOMAINS_SET, + payload: domains, + }); + }, + [dispatch] + ); + + return ( + + + + + {t('settings.options.ntlmCredentials.title')} + + + + + {t('settings.options.ntlmCredentials.description')} + + + + + + + + + {t('settings.options.ntlmCredentials.domains')} + + + ); +}; diff --git a/src/ui/reducers/isNTLMCredentialsEnabled.ts b/src/ui/reducers/isNTLMCredentialsEnabled.ts new file mode 100644 index 0000000000..996d737aff --- /dev/null +++ b/src/ui/reducers/isNTLMCredentialsEnabled.ts @@ -0,0 +1,28 @@ +import type { Reducer } from 'redux'; + +import { APP_SETTINGS_LOADED } from '../../app/actions'; +import type { ActionOf } from '../../store/actions'; +import { SETTINGS_NTLM_CREDENTIALS_CHANGED } from '../actions'; + +type isNTLMCredentialsEnabledAction = + | ActionOf + | ActionOf; + +export const isNTLMCredentialsEnabled: Reducer< + boolean, + isNTLMCredentialsEnabledAction +> = (state = false, action) => { + switch (action.type) { + case APP_SETTINGS_LOADED: { + const { isNTLMCredentialsEnabled = state } = action.payload; + return isNTLMCredentialsEnabled; + } + + case SETTINGS_NTLM_CREDENTIALS_CHANGED: { + return action.payload; + } + + default: + return state; + } +};