Skip to content

Commit f5795bb

Browse files
committed
Merge branch 'instruct-user-to-enable-full-disk-access-for-the-app-des-966'
2 parents 71d3cfa + 4650984 commit f5795bb

File tree

9 files changed

+298
-211
lines changed

9 files changed

+298
-211
lines changed

Diff for: gui/locales/messages.pot

+17-1
Original file line numberDiff line numberDiff line change
@@ -1087,7 +1087,11 @@ msgid "Disconnected and unsecure"
10871087
msgstr ""
10881088

10891089
msgctxt "notifications"
1090-
msgid "Failed to enable split tunneling. Please try again or disable it."
1090+
msgid "Failed to enable split tunneling."
1091+
msgstr ""
1092+
1093+
msgctxt "notifications"
1094+
msgid "Failed to enable split tunneling. Please try reconnecting or disable split tunneling."
10911095
msgstr ""
10921096

10931097
msgctxt "notifications"
@@ -1682,6 +1686,14 @@ msgctxt "tray-icon-tooltip"
16821686
msgid "Connecting. %(location)s"
16831687
msgstr ""
16841688

1689+
msgctxt "troubleshoot"
1690+
msgid "Enable “Full Disk Access” for “Mullvad VPN” in the macOS system settings."
1691+
msgstr ""
1692+
1693+
msgctxt "troubleshoot"
1694+
msgid "Failed to enable split tunneling. This is because the app is missing system permissions. What you can do:"
1695+
msgstr ""
1696+
16851697
msgctxt "troubleshoot"
16861698
msgid "If these steps do not work please send a problem report."
16871699
msgstr ""
@@ -1690,6 +1702,10 @@ msgctxt "troubleshoot"
16901702
msgid "Make sure you have NF tables support."
16911703
msgstr ""
16921704

1705+
msgctxt "troubleshoot"
1706+
msgid "Open system settings"
1707+
msgstr ""
1708+
16931709
msgctxt "troubleshoot"
16941710
msgid "This error can happen when something other than Mullvad is actively updating the DNS."
16951711
msgstr ""

Diff for: gui/src/main/daemon-rpc.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -1047,10 +1047,9 @@ function convertFromTunnelStateError(state: grpcTypes.ErrorState.AsObject): Erro
10471047
cause: ErrorStateCause.splitTunnelError,
10481048
};
10491049
case grpcTypes.ErrorState.Cause.NEED_FULL_DISK_PERMISSIONS:
1050-
// TODO: handle correctly
10511050
return {
10521051
...baseError,
1053-
cause: ErrorStateCause.splitTunnelError,
1052+
cause: ErrorStateCause.needFullDiskPermissions,
10541053
};
10551054
case grpcTypes.ErrorState.Cause.VPN_PERMISSION_DENIED:
10561055
// VPN_PERMISSION_DENIED is only ever created on Android

Diff for: gui/src/main/user-interface.ts

+10-2
Original file line numberDiff line numberDiff line change
@@ -74,12 +74,20 @@ export default class UserInterface implements WindowControllerDelegate {
7474
});
7575

7676
IpcMainEventChannel.app.handleShowLaunchDaemonSettings(async () => {
77+
try {
78+
await execAsync('open x-apple.systempreferences:com.apple.LoginItems-Settings.extension');
79+
} catch (error) {
80+
log.error(`Failed to open launch daemon settings: ${error}`);
81+
}
82+
});
83+
84+
IpcMainEventChannel.app.handleShowFullDiskAccessSettings(async () => {
7785
try {
7886
await execAsync(
79-
'open -W x-apple.systempreferences:com.apple.LoginItems-Settings.extension',
87+
'open "x-apple.systempreferences:com.apple.preference.security?Privacy_AllFiles"',
8088
);
8189
} catch (error) {
82-
log.error(`Failed to open launch daemon settings: ${error}`);
90+
log.error(`Failed to open Full Disk Access settings: ${error}`);
8391
}
8492
});
8593
}

Diff for: gui/src/renderer/app.tsx

+4
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,10 @@ export default class AppRenderer {
529529
await IpcRendererEventChannel.app.showLaunchDaemonSettings();
530530
}
531531

532+
public showFullDiskAccessSettings = async () => {
533+
await IpcRendererEventChannel.app.showFullDiskAccessSettings();
534+
};
535+
532536
public async sendProblemReport(
533537
email: string,
534538
message: string,

Diff for: gui/src/renderer/components/NotificationArea.tsx

+31-9
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ interface IProps {
4343
}
4444

4545
export default function NotificationArea(props: IProps) {
46+
const { showFullDiskAccessSettings } = useAppContext();
47+
4648
const account = useSelector((state: IReduxState) => state.account);
4749
const locale = useSelector((state: IReduxState) => state.userInterface.locale);
4850
const tunnelState = useSelector((state: IReduxState) => state.connection.status);
@@ -65,7 +67,7 @@ export default function NotificationArea(props: IProps) {
6567
blockWhenDisconnected,
6668
hasExcludedApps,
6769
}),
68-
new ErrorNotificationProvider({ tunnelState, hasExcludedApps }),
70+
new ErrorNotificationProvider({ tunnelState, hasExcludedApps, showFullDiskAccessSettings }),
6971
new InconsistentVersionNotificationProvider({ consistent: version.consistent }),
7072
new UnsupportedVersionNotificationProvider(version),
7173
];
@@ -168,20 +170,40 @@ function NotificationActionWrapper(props: INotificationActionWrapperProps) {
168170
}
169171
}
170172

173+
const problemReportButton = troubleshootInfo?.buttons ? (
174+
<AppButton.BlueButton key="problem-report" onClick={goToProblemReport}>
175+
{messages.pgettext('in-app-notifications', 'Send problem report')}
176+
</AppButton.BlueButton>
177+
) : (
178+
<AppButton.GreenButton key="problem-report" onClick={goToProblemReport}>
179+
{messages.pgettext('in-app-notifications', 'Send problem report')}
180+
</AppButton.GreenButton>
181+
);
182+
183+
let buttons = [
184+
problemReportButton,
185+
<AppButton.BlueButton key="back" onClick={closeTroubleshootInfo}>
186+
{messages.gettext('Back')}
187+
</AppButton.BlueButton>,
188+
];
189+
190+
if (troubleshootInfo?.buttons) {
191+
const actionButtons = troubleshootInfo.buttons.map((button) => (
192+
<AppButton.GreenButton key={button.label} onClick={button.action}>
193+
{button.label}
194+
</AppButton.GreenButton>
195+
));
196+
197+
buttons = actionButtons.concat(buttons);
198+
}
199+
171200
return (
172201
<>
173202
<NotificationActions>{actionComponent}</NotificationActions>
174203
<ModalAlert
175204
isOpen={troubleshootInfo !== undefined}
176205
type={ModalAlertType.info}
177-
buttons={[
178-
<AppButton.GreenButton key="problem-report" onClick={goToProblemReport}>
179-
{messages.pgettext('in-app-notifications', 'Send problem report')}
180-
</AppButton.GreenButton>,
181-
<AppButton.BlueButton key="back" onClick={closeTroubleshootInfo}>
182-
{messages.gettext('Back')}
183-
</AppButton.BlueButton>,
184-
]}
206+
buttons={buttons}
185207
close={closeTroubleshootInfo}>
186208
<ModalMessage>{troubleshootInfo?.details}</ModalMessage>
187209
<ModalMessage>

Diff for: gui/src/shared/daemon-rpc-types.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ export enum ErrorStateCause {
4848
tunnelParameterError,
4949
isOffline,
5050
splitTunnelError,
51+
needFullDiskPermissions,
5152
}
5253

5354
export enum AuthFailedError {
@@ -71,7 +72,8 @@ export type ErrorState =
7172
| ErrorStateCause.setDnsError
7273
| ErrorStateCause.startTunnelError
7374
| ErrorStateCause.isOffline
74-
| ErrorStateCause.splitTunnelError;
75+
| ErrorStateCause.splitTunnelError
76+
| ErrorStateCause.needFullDiskPermissions;
7577
blockingError?: FirewallPolicyError;
7678
}
7779
| {

Diff for: gui/src/shared/ipc-schema.ts

+1
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ export const ipcSchema = {
162162
openUrl: invoke<string, void>(),
163163
showOpenDialog: invoke<Electron.OpenDialogOptions, Electron.OpenDialogReturnValue>(),
164164
showLaunchDaemonSettings: invoke<void, void>(),
165+
showFullDiskAccessSettings: invoke<void, void>(),
165166
getPathBaseName: invoke<string, string>(),
166167
},
167168
tunnel: {

0 commit comments

Comments
 (0)