refactor(web): remove query-string package (#4696)

This change drops the redundant query-string package and utilises native react hooks from react-router-dom.
pull/4697/head
Amir Zarrinkafsh 2023-01-04 21:29:39 +11:00 committed by GitHub
parent 2912d3ffb2
commit 03da825ab0
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 46 additions and 79 deletions

View File

@ -35,7 +35,6 @@
"i18next-browser-languagedetector": "7.0.1",
"i18next-http-backend": "2.1.1",
"qrcode.react": "3.1.0",
"query-string": "7.1.3",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-i18next": "12.1.1",

View File

@ -50,7 +50,6 @@ specifiers:
jest-watch-typeahead: 2.2.1
prettier: 2.8.1
qrcode.react: 3.1.0
query-string: 7.1.3
react: 18.2.0
react-dom: 18.2.0
react-i18next: 12.1.1
@ -84,7 +83,6 @@ dependencies:
i18next-browser-languagedetector: 7.0.1
i18next-http-backend: 2.1.1
qrcode.react: 3.1.0_react@18.2.0
query-string: 7.1.3
react: 18.2.0
react-dom: 18.2.0_react@18.2.0
react-i18next: 12.1.1_25zoxyjt3sfdpelgxivbzvmrha
@ -4849,6 +4847,7 @@ packages:
/decode-uri-component/0.2.2:
resolution: {integrity: sha512-FqUYQ+8o158GyGTrMFJms9qh3CqTKvAqgqsTnkLI8sKu0028orqBhxNMFkFen0zGyg6epACD32pjVk58ngIErQ==}
engines: {node: '>=0.10'}
dev: true
/dedent/0.7.0:
resolution: {integrity: sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==}
@ -5676,11 +5675,6 @@ packages:
to-regex-range: 5.0.1
dev: true
/filter-obj/1.1.0:
resolution: {integrity: sha512-8rXg1ZnX7xzy2NGDVkBVaAy+lSlPNwad13BtgSlLuxfIslyt5Vg64U7tFcCt4WS1R0hvtnQybT/IyCkGZ3DpXQ==}
engines: {node: '>=0.10.0'}
dev: false
/find-root/1.1.0:
resolution: {integrity: sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==}
dev: false
@ -7991,16 +7985,6 @@ packages:
react: 18.2.0
dev: false
/query-string/7.1.3:
resolution: {integrity: sha512-hh2WYhq4fi8+b+/2Kg9CEge4fDPvHS534aOOvOZeQ3+Vf2mCFsaFBYj0i+iXcAq6I9Vzp5fjMFBlONvayDC1qg==}
engines: {node: '>=6'}
dependencies:
decode-uri-component: 0.2.2
filter-obj: 1.1.0
split-on-first: 1.1.0
strict-uri-encode: 2.0.0
dev: false
/queue-microtask/1.2.3:
resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==}
dev: true
@ -8593,11 +8577,6 @@ packages:
resolution: {integrity: sha512-Ctl2BrFiM0X3MANYgj3CkygxhRmr9mi6xhejbdO960nF6EDJApTYpn0BQnDKlnNBULKiCN1n3w9EBkHK8ZWg+g==}
dev: true
/split-on-first/1.1.0:
resolution: {integrity: sha512-43ZssAJaMusuKWL8sKUBQXHWOpq8d6CfN/u1p4gUzfJkM05C8rxTmYrkIPTXapZpORA6LkkzcUulJ8FqA7Uudw==}
engines: {node: '>=6'}
dev: false
/split-string/3.1.0:
resolution: {integrity: sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==}
engines: {node: '>=0.10.0'}
@ -8630,11 +8609,6 @@ packages:
object-copy: 0.1.0
dev: true
/strict-uri-encode/2.0.0:
resolution: {integrity: sha512-QwiXZgpRcKkhTj2Scnn++4PKtWsH0kpzZ62L2R6c/LUVYv7hVnZqcg2+sMuT6R7Jusu1vviK/MFsu6kNJfWlEQ==}
engines: {node: '>=4'}
dev: false
/string-length/4.0.2:
resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==}
engines: {node: '>=10'}

View File

@ -1 +1,7 @@
export const Identifier = "id";
export const Identifier: string = "id";
export const IdentityToken: string = "token";
export const RedirectionURL: string = "rd";
export const RequestMethod: string = "rm";

View File

@ -0,0 +1,7 @@
import { useSearchParams } from "react-router-dom";
export function useQueryParam(queryParam: string) {
const [searchParams] = useSearchParams();
const value = searchParams.get(queryParam);
return value !== "" ? (value as string) : undefined;
}

View File

@ -1,10 +0,0 @@
import queryString from "query-string";
import { useLocation } from "react-router-dom";
export function useRedirectionURL() {
const location = useLocation();
const queryParams = queryString.parse(location.search);
return queryParams && "rd" in queryParams ? (queryParams["rd"] as string) : undefined;
}

View File

@ -1,8 +0,0 @@
import queryString from "query-string";
import { useLocation } from "react-router-dom";
export function useRequestMethod() {
const location = useLocation();
const queryParams = queryString.parse(location.search);
return queryParams && "rm" in queryParams ? (queryParams["rm"] as string) : undefined;
}

View File

@ -1,6 +0,0 @@
import queryString from "query-string";
export function extractIdentityToken(locationSearch: string) {
const queryParams = queryString.parse(locationSearch);
return queryParams && "token" in queryParams ? (queryParams["token"] as string) : null;
}

View File

@ -8,20 +8,20 @@ import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames";
import { QRCodeSVG } from "qrcode.react";
import { useTranslation } from "react-i18next";
import { useLocation, useNavigate } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import AppStoreBadges from "@components/AppStoreBadges";
import { GoogleAuthenticator } from "@constants/constants";
import { IndexRoute } from "@constants/Routes";
import { IdentityToken } from "@constants/SearchParams";
import { useNotifications } from "@hooks/NotificationsContext";
import { useQueryParam } from "@hooks/QueryParam";
import LoginLayout from "@layouts/LoginLayout";
import { completeTOTPRegistrationProcess } from "@services/RegisterDevice";
import { extractIdentityToken } from "@utils/IdentityToken";
const RegisterOneTimePassword = function () {
const styles = useStyles();
const navigate = useNavigate();
const location = useLocation();
// The secret retrieved from the API is all is ok.
const [secretURL, setSecretURL] = useState("empty");
const [secretBase32, setSecretBase32] = useState(undefined as string | undefined);
@ -32,7 +32,7 @@ const RegisterOneTimePassword = function () {
// Get the token from the query param to give it back to the API when requesting
// the secret for OTP.
const processToken = extractIdentityToken(location.search);
const processToken = useQueryParam(IdentityToken);
const handleDoneClick = () => {
navigate(IndexRoute);

View File

@ -2,24 +2,24 @@ import React, { useCallback, useEffect, useState } from "react";
import { Button, Theme, Typography } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import { useLocation, useNavigate } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import FingerTouchIcon from "@components/FingerTouchIcon";
import { IdentityToken } from "@constants/SearchParams";
import { useNotifications } from "@hooks/NotificationsContext";
import { useQueryParam } from "@hooks/QueryParam";
import LoginLayout from "@layouts/LoginLayout";
import { AttestationResult } from "@models/Webauthn";
import { FirstFactorPath } from "@services/Api";
import { performAttestationCeremony } from "@services/Webauthn";
import { extractIdentityToken } from "@utils/IdentityToken";
const RegisterWebauthn = function () {
const styles = useStyles();
const navigate = useNavigate();
const location = useLocation();
const { createErrorNotification } = useNotifications();
const [, setRegistrationInProgress] = useState(false);
const processToken = extractIdentityToken(location.search);
const processToken = useQueryParam(IdentityToken);
const handleBackClick = () => {
navigate(FirstFactorPath);

View File

@ -9,9 +9,9 @@ import { useNavigate } from "react-router-dom";
import FixedTextField from "@components/FixedTextField";
import { ResetPasswordStep1Route } from "@constants/Routes";
import { RedirectionURL, RequestMethod } from "@constants/SearchParams";
import { useNotifications } from "@hooks/NotificationsContext";
import { useRedirectionURL } from "@hooks/RedirectionURL";
import { useRequestMethod } from "@hooks/RequestMethod";
import { useQueryParam } from "@hooks/QueryParam";
import { useWorkflow } from "@hooks/Workflow";
import LoginLayout from "@layouts/LoginLayout";
import { postFirstFactor } from "@services/FirstFactor";
@ -32,8 +32,8 @@ export interface Props {
const FirstFactorForm = function (props: Props) {
const styles = useStyles();
const navigate = useNavigate();
const redirectionURL = useRedirectionURL();
const requestMethod = useRequestMethod();
const redirectionURL = useQueryParam(RedirectionURL);
const requestMethod = useQueryParam(RequestMethod);
const [workflow] = useWorkflow();
const loginChannel = useMemo(() => new BroadcastChannel<boolean>("login"), []);

View File

@ -10,9 +10,10 @@ import {
SecondFactorTOTPSubRoute,
SecondFactorWebauthnSubRoute,
} from "@constants/Routes";
import { RedirectionURL } from "@constants/SearchParams";
import { useConfiguration } from "@hooks/Configuration";
import { useNotifications } from "@hooks/NotificationsContext";
import { useRedirectionURL } from "@hooks/RedirectionURL";
import { useQueryParam } from "@hooks/QueryParam";
import { useRedirector } from "@hooks/Redirector";
import { useAutheliaState } from "@hooks/State";
import { useUserInfoPOST } from "@hooks/UserInfo";
@ -38,7 +39,7 @@ const RedirectionErrorMessage =
const LoginPortal = function (props: Props) {
const navigate = useNavigate();
const location = useLocation();
const redirectionURL = useRedirectionURL();
const redirectionURL = useQueryParam(RedirectionURL);
const { createErrorNotification } = useNotifications();
const [firstFactorDisabled, setFirstFactorDisabled] = useState(true);
const [broadcastRedirect, setBroadcastRedirect] = useState(false);

View File

@ -2,7 +2,8 @@ import React, { useCallback, useEffect, useRef, useState } from "react";
import { useTranslation } from "react-i18next";
import { useRedirectionURL } from "@hooks/RedirectionURL";
import { RedirectionURL } from "@constants/SearchParams";
import { useQueryParam } from "@hooks/QueryParam";
import { useUserInfoTOTPConfiguration } from "@hooks/UserInfoTOTPConfiguration";
import { useWorkflow } from "@hooks/Workflow";
import { completeTOTPSignIn } from "@services/OneTimePassword";
@ -33,7 +34,7 @@ const OneTimePasswordMethod = function (props: Props) {
const [state, setState] = useState(
props.authenticationLevel === AuthenticationLevel.TwoFactor ? State.Success : State.Idle,
);
const redirectionURL = useRedirectionURL();
const redirectionURL = useQueryParam(RedirectionURL);
const [workflow, workflowID] = useWorkflow();
const { t: translate } = useTranslation();

View File

@ -6,8 +6,9 @@ import makeStyles from "@mui/styles/makeStyles";
import FailureIcon from "@components/FailureIcon";
import PushNotificationIcon from "@components/PushNotificationIcon";
import SuccessIcon from "@components/SuccessIcon";
import { RedirectionURL } from "@constants/SearchParams";
import { useIsMountedRef } from "@hooks/Mounted";
import { useRedirectionURL } from "@hooks/RedirectionURL";
import { useQueryParam } from "@hooks/QueryParam";
import { useWorkflow } from "@hooks/Workflow";
import {
DuoDevicePostRequest,
@ -44,7 +45,7 @@ export interface Props {
const PushNotificationMethod = function (props: Props) {
const styles = useStyles();
const [state, setState] = useState(State.SignInInProgress);
const redirectionURL = useRedirectionURL();
const redirectionURL = useQueryParam(RedirectionURL);
const [workflow, workflowID] = useWorkflow();
const mounted = useIsMountedRef();
const [enroll_url, setEnrollUrl] = useState("");

View File

@ -6,8 +6,9 @@ import makeStyles from "@mui/styles/makeStyles";
import FailureIcon from "@components/FailureIcon";
import FingerTouchIcon from "@components/FingerTouchIcon";
import LinearProgressBar from "@components/LinearProgressBar";
import { RedirectionURL } from "@constants/SearchParams";
import { useIsMountedRef } from "@hooks/Mounted";
import { useRedirectionURL } from "@hooks/RedirectionURL";
import { useQueryParam } from "@hooks/QueryParam";
import { useTimer } from "@hooks/Timer";
import { useWorkflow } from "@hooks/Workflow";
import { AssertionResult } from "@models/Webauthn";
@ -40,7 +41,7 @@ const WebauthnMethod = function (props: Props) {
const signInTimeout = 30;
const [state, setState] = useState(State.WaitTouch);
const styles = useStyles();
const redirectionURL = useRedirectionURL();
const redirectionURL = useQueryParam(RedirectionURL);
const [workflow, workflowID] = useWorkflow();
const mounted = useIsMountedRef();
const [timerPercent, triggerTimer] = useTimer(signInTimeout * 1000 - 500);

View File

@ -6,9 +6,10 @@ import { useTranslation } from "react-i18next";
import { Navigate } from "react-router-dom";
import { IndexRoute } from "@constants/Routes";
import { RedirectionURL } from "@constants/SearchParams";
import { useIsMountedRef } from "@hooks/Mounted";
import { useNotifications } from "@hooks/NotificationsContext";
import { useRedirectionURL } from "@hooks/RedirectionURL";
import { useQueryParam } from "@hooks/QueryParam";
import { useRedirector } from "@hooks/Redirector";
import LoginLayout from "@layouts/LoginLayout";
import { signOut } from "@services/SignOut";
@ -19,7 +20,7 @@ const SignOut = function (props: Props) {
const mounted = useIsMountedRef();
const styles = useStyles();
const { createErrorNotification } = useNotifications();
const redirectionURL = useRedirectionURL();
const redirectionURL = useQueryParam(RedirectionURL);
const redirector = useRedirector();
const [timedOut, setTimedOut] = useState(false);
const [safeRedirect, setSafeRedirect] = useState(false);

View File

@ -5,21 +5,21 @@ import { Button, Grid, IconButton, InputAdornment, Theme } from "@mui/material";
import makeStyles from "@mui/styles/makeStyles";
import classnames from "classnames";
import { useTranslation } from "react-i18next";
import { useLocation, useNavigate } from "react-router-dom";
import { useNavigate } from "react-router-dom";
import FixedTextField from "@components/FixedTextField";
import PasswordMeter from "@components/PasswordMeter";
import { IndexRoute } from "@constants/Routes";
import { IdentityToken } from "@constants/SearchParams";
import { useNotifications } from "@hooks/NotificationsContext";
import { useQueryParam } from "@hooks/QueryParam";
import LoginLayout from "@layouts/LoginLayout";
import { PasswordPolicyConfiguration, PasswordPolicyMode } from "@models/PasswordPolicy";
import { getPasswordPolicyConfiguration } from "@services/PasswordPolicyConfiguration";
import { completeResetPasswordProcess, resetPassword } from "@services/ResetPassword";
import { extractIdentityToken } from "@utils/IdentityToken";
const ResetPasswordStep2 = function () {
const styles = useStyles();
const location = useLocation();
const [formDisabled, setFormDisabled] = useState(true);
const [password1, setPassword1] = useState("");
const [password2, setPassword2] = useState("");
@ -43,7 +43,7 @@ const ResetPasswordStep2 = function () {
// Get the token from the query param to give it back to the API when requesting
// the secret for OTP.
const processToken = extractIdentityToken(location.search);
const processToken = useQueryParam(IdentityToken);
const completeProcess = useCallback(async () => {
if (!processToken) {