fix(web): broadcastchannel not supported on old safari (#4014)

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 <nightah@me.com>
pull/4029/head
James Elliott 2022-09-19 14:49:25 +10:00 committed by GitHub
parent a0b3d32774
commit 1ba6effe6b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 83 additions and 20 deletions

View File

@ -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",

View File

@ -25,6 +25,7 @@ specifiers:
'@typescript-eslint/parser': 5.37.0
'@vitejs/plugin-react': 2.1.0
axios: 0.27.2
broadcast-channel: 4.10.0
classnames: 2.3.2
esbuild: 0.15.8
esbuild-jest: 0.5.0
@ -76,6 +77,7 @@ dependencies:
'@mui/material': 5.10.5_af5ln35zuaotaffazii6n6bke4
'@mui/styles': 5.10.3_w5j4k42lgipnm43s3brx6h3c34
axios: 0.27.2
broadcast-channel: 4.10.0
classnames: 2.3.2
i18next: 21.9.2
i18next-browser-languagedetector: 6.1.5
@ -4182,7 +4184,6 @@ packages:
/balanced-match/1.0.2:
resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==}
dev: true
/base/0.11.2:
resolution: {integrity: sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==}
@ -4197,12 +4198,16 @@ packages:
pascalcase: 0.1.1
dev: true
/big-integer/1.6.51:
resolution: {integrity: sha512-GPEid2Y9QU1Exl1rpO9B2IPJGHPSupF5GnVIP0blYvNOMer2bTvSWs1jGOUg04hTmu67nmLsQ9TBo1puaotBHg==}
engines: {node: '>=0.6'}
dev: false
/brace-expansion/1.1.11:
resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==}
dependencies:
balanced-match: 1.0.2
concat-map: 0.0.1
dev: true
/braces/2.3.2:
resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==}
@ -4229,6 +4234,19 @@ packages:
fill-range: 7.0.1
dev: true
/broadcast-channel/4.10.0:
resolution: {integrity: sha512-hOUh312XyHk6JTVyX9cyXaH1UYs+2gHVtnW16oQAu9FL7ALcXGXc/YoJWqlkV8vUn14URQPMmRi4A9q4UrwVEQ==}
dependencies:
'@babel/runtime': 7.18.9
detect-node: 2.1.0
microseconds: 0.2.0
nano-time: 1.0.0
oblivious-set: 1.0.0
p-queue: 6.6.2
rimraf: 3.0.2
unload: 2.3.1
dev: false
/browser-process-hrtime/1.0.0:
resolution: {integrity: sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==}
dev: true
@ -4437,8 +4455,7 @@ packages:
dev: true
/concat-map/0.0.1:
resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==}
dev: true
resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=}
/confusing-browser-globals/1.0.11:
resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==}
@ -4712,6 +4729,10 @@ packages:
engines: {node: '>=8'}
dev: true
/detect-node/2.1.0:
resolution: {integrity: sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==}
dev: false
/diff-sequences/29.0.0:
resolution: {integrity: sha512-7Qe/zd1wxSDL4D/X/FPjOMB+ZMDt71W94KYaq05I2l0oQqgXgs7s4ftYYmV38gBSrPz2vcygxfs1xn0FT+rKNA==}
engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0}
@ -5508,6 +5529,10 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/eventemitter3/4.0.7:
resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==}
dev: false
/exec-sh/0.3.6:
resolution: {integrity: sha512-nQn+hI3yp+oD0huYhKwvYI32+JFeq+XkNcD1GAo3Y/MjxsfVGmrrzrnzjWiNY6f+pUCP440fThsFh5gZrRAU/w==}
dev: true
@ -5750,7 +5775,6 @@ packages:
/fs.realpath/1.0.0:
resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==}
dev: true
/fsevents/2.3.2:
resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==}
@ -5872,7 +5896,6 @@ packages:
minimatch: 3.1.2
once: 1.4.0
path-is-absolute: 1.0.1
dev: true
/global-dirs/0.1.1:
resolution: {integrity: sha512-NknMLn7F2J7aflwFOlGdNIuCDpN3VGoSoB+aap3KABFWbHVn1TCgFC+np23J8W2BiZbjfEw3BFBycSMv1AFblg==}
@ -6138,11 +6161,9 @@ packages:
dependencies:
once: 1.4.0
wrappy: 1.0.2
dev: true
/inherits/2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
dev: true
/ini/1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
@ -7381,6 +7402,10 @@ packages:
picomatch: 2.3.1
dev: true
/microseconds/0.2.0:
resolution: {integrity: sha512-n7DHHMjR1avBbSpsTBj6fmMGh2AGrifVV4e+WYc3Q9lO+xnSZ3NyhcBND3vzzatt05LFhoKFRxrIyklmLlUtyA==}
dev: false
/mime-db/1.52.0:
resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==}
engines: {node: '>= 0.6'}
@ -7405,7 +7430,6 @@ packages:
resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==}
dependencies:
brace-expansion: 1.1.11
dev: true
/minimist-options/4.1.0:
resolution: {integrity: sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==}
@ -7440,6 +7464,12 @@ packages:
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
dev: true
/nano-time/1.0.0:
resolution: {integrity: sha512-flnngywOoQ0lLQOTRNexn2gGSNuM9bKj9RZAWSzhQ+UJYaAFG9bac4DW9VHjUAzrOaIcajHybCTHe/bkvozQqA==}
dependencies:
big-integer: 1.6.51
dev: false
/nanoid/3.3.4:
resolution: {integrity: sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==}
engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1}
@ -7622,11 +7652,14 @@ packages:
es-abstract: 1.20.1
dev: true
/oblivious-set/1.0.0:
resolution: {integrity: sha512-z+pI07qxo4c2CulUHCDf9lcqDlMSo72N/4rLUpRXf6fu+q8vjt8y0xS+Tlf8NTJDdTXHbdeO1n3MlbctwEoXZw==}
dev: false
/once/1.4.0:
resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==}
dependencies:
wrappy: 1.0.2
dev: true
/onetime/5.1.2:
resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==}
@ -7671,7 +7704,6 @@ packages:
/p-finally/1.0.0:
resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==}
engines: {node: '>=4'}
dev: true
/p-limit/1.3.0:
resolution: {integrity: sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==}
@ -7715,6 +7747,21 @@ packages:
p-limit: 3.1.0
dev: true
/p-queue/6.6.2:
resolution: {integrity: sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ==}
engines: {node: '>=8'}
dependencies:
eventemitter3: 4.0.7
p-timeout: 3.2.0
dev: false
/p-timeout/3.2.0:
resolution: {integrity: sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg==}
engines: {node: '>=8'}
dependencies:
p-finally: 1.0.0
dev: false
/p-try/1.0.0:
resolution: {integrity: sha512-U1etNYuMJoIz3ZXSrrySFjsXQTWOx2/jdi86L+2pRvph/qMKL6sbcCYdH23fqsbm8TH2Gn0OybpT4eSFlCVHww==}
engines: {node: '>=4'}
@ -7764,7 +7811,6 @@ packages:
/path-is-absolute/1.0.1:
resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==}
engines: {node: '>=0.10.0'}
dev: true
/path-key/2.0.1:
resolution: {integrity: sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==}
@ -8250,7 +8296,6 @@ packages:
hasBin: true
dependencies:
glob: 7.2.3
dev: true
/rollup/2.78.0:
resolution: {integrity: sha512-4+YfbQC9QEVvKTanHhIAFVUFSRsezvQF8vFOJwtGfb9Bb+r014S+qryr9PSmw8x6sMnPkmFBGAvIFVQxvJxjtg==}
@ -8997,6 +9042,13 @@ packages:
engines: {node: '>= 10.0.0'}
dev: true
/unload/2.3.1:
resolution: {integrity: sha512-MUZEiDqvAN9AIDRbbBnVYVvfcR6DrjCqeU2YQMmliFZl9uaBUjTkhuDQkBiyAy8ad5bx1TXVbqZ3gg7namsWjA==}
dependencies:
'@babel/runtime': 7.18.9
detect-node: 2.1.0
dev: false
/unset-value/1.0.0:
resolution: {integrity: sha512-PcA2tsuGSF9cnySLHTLSh2qrQiJ70mn+r+Glzxv2TWZblxsxCC52BDlZoPCsz7STd9pN7EZetkWZBAvk4cgZdQ==}
engines: {node: '>=0.10.0'}
@ -9234,7 +9286,6 @@ packages:
/wrappy/1.0.2:
resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==}
dev: true
/write-file-atomic/3.0.3:
resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==}

View File

@ -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";
@ -25,6 +26,7 @@ export interface Props {
onAuthenticationStart: () => void;
onAuthenticationFailure: () => void;
onAuthenticationSuccess: (redirectURL: string | undefined) => void;
onChannelStateChange: () => void;
}
const FirstFactorForm = function (props: Props) {
@ -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);
@ -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]);
@ -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);

View File

@ -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();
@ -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);
@ -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.
@ -195,6 +203,7 @@ const LoginPortal = function (props: Props) {
onAuthenticationStart={() => setFirstFactorDisabled(true)}
onAuthenticationFailure={() => setFirstFactorDisabled(false)}
onAuthenticationSuccess={handleAuthSuccess}
onChannelStateChange={handleChannelStateChange}
/>
</ComponentOrLoading>
}