Skip to content

Commit

Permalink
fix(web): broadcastchannel not supported on old safari (authelia#4014)
Browse files Browse the repository at this point in the history
This utilizes a wrapper around the BroadcastChannel API to handle browsers which don't properly support the API such as Safari prior to 10.4 and iOS prior to 10.4. Where possible it uses the native API.

Co-authored-by: Amir Zarrinkafsh <[email protected]>
  • Loading branch information
james-d-elliott and nightah authored Sep 19, 2022
1 parent a0b3d32 commit 1ba6eff
Show file tree
Hide file tree
Showing 4 changed files with 83 additions and 20 deletions.
1 change: 1 addition & 0 deletions web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"@mui/material": "5.10.5",
"@mui/styles": "5.10.3",
"axios": "0.27.2",
"broadcast-channel": "4.10.0",
"classnames": "2.3.2",
"i18next": "21.9.2",
"i18next-browser-languagedetector": "6.1.5",
Expand Down
79 changes: 65 additions & 14 deletions web/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 7 additions & 5 deletions web/src/views/LoginPortal/FirstFactor/FirstFactorForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import React, { MutableRefObject, useEffect, useMemo, useRef, useState } from "r

import { Button, Checkbox, FormControlLabel, Grid, Link, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { BroadcastChannel } from "broadcast-channel";
import classnames from "classnames";
import { useTranslation } from "react-i18next";
import { useNavigate } from "react-router-dom";
Expand All @@ -25,6 +26,7 @@ export interface Props {
onAuthenticationStart: () => void;
onAuthenticationFailure: () => void;
onAuthenticationSuccess: (redirectURL: string | undefined) => void;
onChannelStateChange: () => void;
}

const FirstFactorForm = function (props: Props) {
Expand All @@ -34,7 +36,7 @@ const FirstFactorForm = function (props: Props) {
const requestMethod = useRequestMethod();
const workflow = useWorkflow();

const loginChannel = useMemo(() => new BroadcastChannel("login"), []);
const loginChannel = useMemo(() => new BroadcastChannel<boolean>("login"), []);
const [rememberMe, setRememberMe] = useState(false);
const [username, setUsername] = useState("");
const [usernameError, setUsernameError] = useState(false);
Expand All @@ -52,9 +54,9 @@ const FirstFactorForm = function (props: Props) {
}, [usernameRef]);

useEffect(() => {
loginChannel.addEventListener("message", (ev) => {
if (ev.data) {
props.onAuthenticationSuccess(redirectionURL);
loginChannel.addEventListener("message", (authenticated) => {
if (authenticated) {
props.onChannelStateChange();
}
});
}, [loginChannel, redirectionURL, props]);
Expand All @@ -80,7 +82,7 @@ const FirstFactorForm = function (props: Props) {
props.onAuthenticationStart();
try {
const res = await postFirstFactor(username, password, rememberMe, redirectionURL, requestMethod, workflow);
loginChannel.postMessage(true);
await loginChannel.postMessage(true);
props.onAuthenticationSuccess(res ? res.redirect : undefined);
} catch (err) {
console.error(err);
Expand Down
11 changes: 10 additions & 1 deletion web/src/views/LoginPortal/LoginPortal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ const LoginPortal = function (props: Props) {
const workflow = useWorkflow();
const { createErrorNotification } = useNotifications();
const [firstFactorDisabled, setFirstFactorDisabled] = useState(true);
const [broadcastRedirect, setBroadcastRedirect] = useState(false);
const redirector = useRedirector();

const [state, fetchState, , fetchStateError] = useAutheliaState();
Expand Down Expand Up @@ -115,7 +116,8 @@ const LoginPortal = function (props: Props) {
((configuration &&
configuration.available_methods.size === 0 &&
state.authentication_level >= AuthenticationLevel.OneFactor) ||
state.authentication_level === AuthenticationLevel.TwoFactor)
state.authentication_level === AuthenticationLevel.TwoFactor ||
broadcastRedirect)
) {
try {
const res = await checkSafeRedirection(redirectionURL);
Expand Down Expand Up @@ -164,8 +166,14 @@ const LoginPortal = function (props: Props) {
configuration,
createErrorNotification,
redirector,
broadcastRedirect,
]);

const handleChannelStateChange = async () => {
setBroadcastRedirect(true);
fetchState();
};

const handleAuthSuccess = async (redirectionURL: string | undefined) => {
if (redirectionURL) {
// Do an external redirection pushed by the server.
Expand Down Expand Up @@ -195,6 +203,7 @@ const LoginPortal = function (props: Props) {
onAuthenticationStart={() => setFirstFactorDisabled(true)}
onAuthenticationFailure={() => setFirstFactorDisabled(false)}
onAuthenticationSuccess={handleAuthSuccess}
onChannelStateChange={handleChannelStateChange}
/>
</ComponentOrLoading>
}
Expand Down

0 comments on commit 1ba6eff

Please sign in to comment.