Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: Add NTLM Credentials support #2710

Merged
merged 20 commits into from
Aug 3, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions src/app/PersistableValues.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 = {
Expand Down Expand Up @@ -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: '',
}),
};
3 changes: 3 additions & 0 deletions src/app/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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<PersistableValues>;
[APP_ALLOWED_NTLM_CREDENTIALS_DOMAINS_SET]: string;
};
45 changes: 43 additions & 2 deletions src/app/main/app.ts
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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,
Expand Down Expand Up @@ -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) => {
Expand All @@ -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() });
};
31 changes: 31 additions & 0 deletions src/app/reducers/allowedNTLMCredentialsDomains.ts
Original file line number Diff line number Diff line change
@@ -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<typeof APP_SETTINGS_LOADED>
| ActionOf<typeof APP_ALLOWED_NTLM_CREDENTIALS_DOMAINS_SET>;

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;
}
};
4 changes: 4 additions & 0 deletions src/app/selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,8 @@ export const selectPersistableValues = createStructuredSelector<
hasHideOnTrayNotificationShown: ({ hasHideOnTrayNotificationShown }) =>
hasHideOnTrayNotificationShown,
lastSelectedServerUrl: ({ lastSelectedServerUrl }) => lastSelectedServerUrl,
allowedNTLMCredentialsDomains: ({ allowedNTLMCredentialsDomains }) =>
allowedNTLMCredentialsDomains,
isNTLMCredentialsEnabled: ({ isNTLMCredentialsEnabled }) =>
isNTLMCredentialsEnabled,
});
9 changes: 9 additions & 0 deletions src/i18n/en.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -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."
}
}
},
Expand Down
13 changes: 13 additions & 0 deletions src/i18n/pt-BR.i18n.json
Original file line number Diff line number Diff line change
Expand Up @@ -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."
}
}
},
Expand Down
4 changes: 4 additions & 0 deletions src/store/rootReducer.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand All @@ -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';
Expand Down Expand Up @@ -74,6 +76,8 @@ export const rootReducer = combineReducers({
isAddNewServersEnabled,
hasHideOnTrayNotificationShown,
lastSelectedServerUrl,
allowedNTLMCredentialsDomains,
isNTLMCredentialsEnabled,
});

export type RootState = ReturnType<typeof rootReducer>;
3 changes: 3 additions & 0 deletions src/ui/actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
};
2 changes: 2 additions & 0 deletions src/ui/components/SettingsView/GeneralTab.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -23,6 +24,7 @@ export const GeneralTab: FC = () => (
{process.platform === 'win32' && <MinimizeOnClose />}
<SideBar />
{process.platform !== 'darwin' && <MenuBar />}
<NTLMCredentials />
{!process.mas && <ClearPermittedScreenCaptureServers />}
</FieldGroup>
</Box>
Expand Down
85 changes: 85 additions & 0 deletions src/ui/components/SettingsView/features/NTLMCredentials.tsx
Original file line number Diff line number Diff line change
@@ -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> = (props) => {
const isNTLMCredentialsEnabled = useSelector(
({ isNTLMCredentialsEnabled }: RootState) => isNTLMCredentialsEnabled
);
const allowedNTLMCredentialsDomains = useSelector(
({ allowedNTLMCredentialsDomains }: RootState) =>
allowedNTLMCredentialsDomains
);
const { t } = useTranslation();
const dispatch = useDispatch<Dispatch<RootAction>>();

const handleToggleChange = useCallback(
(event: ChangeEvent<HTMLInputElement>) => {
const isChecked = event.currentTarget.checked;
dispatch({
type: SETTINGS_NTLM_CREDENTIALS_CHANGED,
payload: isChecked,
});
},
[dispatch]
);

const handleDomainsChange = useCallback(
(event: React.FocusEvent<HTMLInputElement>) => {
const domains = event.target.value;
dispatch({
type: APP_ALLOWED_NTLM_CREDENTIALS_DOMAINS_SET,
payload: domains,
});
},
[dispatch]
);

return (
<Field className={props.className}>
<Field.Row>
<ToggleSwitch
onChange={handleToggleChange}
checked={isNTLMCredentialsEnabled}
/>
<Field.Label htmlFor='toggle-switch'>
{t('settings.options.ntlmCredentials.title')}
</Field.Label>
</Field.Row>
<Field.Row>
<Field.Hint>
{t('settings.options.ntlmCredentials.description')}
</Field.Hint>
</Field.Row>
<Field.Row>
<Field.Row size={'100%'}>
<InputBox
defaultValue={allowedNTLMCredentialsDomains as string}
onBlur={handleDomainsChange}
type={'text'}
disabled={!isNTLMCredentialsEnabled}
placeholder='*example.com, *foobar.com, *baz'
/>
</Field.Row>
</Field.Row>
<Field.Row>
<Field.Hint>{t('settings.options.ntlmCredentials.domains')}</Field.Hint>
</Field.Row>
</Field>
);
};
28 changes: 28 additions & 0 deletions src/ui/reducers/isNTLMCredentialsEnabled.ts
Original file line number Diff line number Diff line change
@@ -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<typeof APP_SETTINGS_LOADED>
| ActionOf<typeof SETTINGS_NTLM_CREDENTIALS_CHANGED>;

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;
}
};
Loading