Force authentication to see public content
This commit is contained in:
parent
1d9cdb4645
commit
7571af38cb
8 changed files with 101 additions and 17 deletions
|
@ -22,6 +22,7 @@ import WaitlistPage from 'soapbox/features/verification/waitlist_page';
|
|||
import { createGlobals } from 'soapbox/globals';
|
||||
import { useAppSelector, useAppDispatch, useOwnAccount, useFeatures, useSoapboxConfig, useSettings, useSystemTheme } from 'soapbox/hooks';
|
||||
import MESSAGES from 'soapbox/locales/messages';
|
||||
import { useCachedLocationHandler } from 'soapbox/utils/redirect';
|
||||
import { generateThemeCss } from 'soapbox/utils/theme';
|
||||
|
||||
import { checkOnboardingStatus } from '../actions/onboarding';
|
||||
|
@ -64,6 +65,7 @@ const loadInitial = () => {
|
|||
};
|
||||
|
||||
const SoapboxMount = () => {
|
||||
useCachedLocationHandler();
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const me = useAppSelector(state => state.me);
|
||||
|
|
|
@ -1,13 +1,14 @@
|
|||
import React from 'react';
|
||||
import { Link, Redirect, Route, Switch } from 'react-router-dom';
|
||||
import { defineMessages, useIntl } from 'react-intl';
|
||||
import { Link, Redirect, Route, Switch, useHistory } from 'react-router-dom';
|
||||
|
||||
import LandingGradient from 'soapbox/components/landing-gradient';
|
||||
import SiteLogo from 'soapbox/components/site-logo';
|
||||
import BundleContainer from 'soapbox/features/ui/containers/bundle_container';
|
||||
import { NotificationsContainer } from 'soapbox/features/ui/util/async-components';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
import { useAppSelector, useFeatures, useSoapboxConfig } from 'soapbox/hooks';
|
||||
|
||||
import { Card, CardBody } from '../../components/ui';
|
||||
import { Button, Card, CardBody } from '../../components/ui';
|
||||
import LoginPage from '../auth_login/components/login_page';
|
||||
import PasswordReset from '../auth_login/components/password_reset';
|
||||
import PasswordResetConfirm from '../auth_login/components/password_reset_confirm';
|
||||
|
@ -17,22 +18,52 @@ import RegisterInvite from '../register_invite';
|
|||
import Verification from '../verification';
|
||||
import EmailPassthru from '../verification/email_passthru';
|
||||
|
||||
const messages = defineMessages({
|
||||
register: { id: 'auth_layout.register', defaultMessage: 'Create an account' },
|
||||
});
|
||||
|
||||
const AuthLayout = () => {
|
||||
const intl = useIntl();
|
||||
const history = useHistory();
|
||||
|
||||
const siteTitle = useAppSelector(state => state.instance.title);
|
||||
const soapboxConfig = useSoapboxConfig();
|
||||
const pepeEnabled = soapboxConfig.getIn(['extensions', 'pepe', 'enabled']) === true;
|
||||
|
||||
const features = useFeatures();
|
||||
const instance = useAppSelector((state) => state.instance);
|
||||
const isOpen = features.accountCreation && instance.registrations;
|
||||
const pepeOpen = useAppSelector(state => state.verification.getIn(['instance', 'registrations'], false) === true);
|
||||
const isLoginPage = history.location.pathname === '/login';
|
||||
const shouldShowRegisterLink = (isLoginPage && (isOpen || (pepeEnabled && pepeOpen)));
|
||||
|
||||
return (
|
||||
<div className='h-full'>
|
||||
<LandingGradient />
|
||||
|
||||
<main className='relative min-h-full sm:flex sm:items-center sm:justify-center py-12'>
|
||||
<div className='w-full sm:max-w-lg md:max-w-2xl space-y-8'>
|
||||
<header className='flex justify-center relative'>
|
||||
<Link to='/' className='cursor-pointer'>
|
||||
<SiteLogo alt={siteTitle} className='h-7' />
|
||||
</Link>
|
||||
<main className='relative min-h-full sm:flex sm:justify-center'>
|
||||
<div className='w-full sm:max-w-lg md:max-w-2xl lg:max-w-6xl'>
|
||||
<header className='flex justify-between relative py-12 px-2'>
|
||||
<div className='relative z-0 flex-1 px-2 lg:flex lg:items-center lg:justify-center lg:absolute lg:inset-0'>
|
||||
<Link to='/' className='cursor-pointer'>
|
||||
<SiteLogo alt={siteTitle} className='h-7' />
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
{shouldShowRegisterLink && (
|
||||
<div className='relative z-10 ml-auto flex items-center'>
|
||||
<Button
|
||||
theme='link'
|
||||
icon={require('@tabler/icons/icons/user.svg')}
|
||||
to='/signup'
|
||||
>
|
||||
{intl.formatMessage(messages.register)}
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</header>
|
||||
|
||||
<div className='flex flex-col justify-center items-center'>
|
||||
<div className='flex flex-col h-full justify-center items-center'>
|
||||
<div className='pb-10 sm:mx-auto w-full sm:max-w-lg md:max-w-2xl'>
|
||||
<Card variant='rounded' size='xl'>
|
||||
<CardBody>
|
||||
|
|
|
@ -7,6 +7,7 @@ import { Redirect } from 'react-router-dom';
|
|||
import { logIn, verifyCredentials, switchAccount } from 'soapbox/actions/auth';
|
||||
import { fetchInstance } from 'soapbox/actions/instance';
|
||||
import { closeModal } from 'soapbox/actions/modals';
|
||||
import { getRedirectUrl } from 'soapbox/utils/redirect';
|
||||
import { isStandalone } from 'soapbox/utils/state';
|
||||
|
||||
import LoginForm from './login_form';
|
||||
|
@ -78,7 +79,10 @@ class LoginPage extends ImmutablePureComponent {
|
|||
|
||||
if (standalone) return <Redirect to='/login/external' />;
|
||||
|
||||
if (shouldRedirect) return <Redirect to='/' />;
|
||||
if (shouldRedirect) {
|
||||
const redirectUri = getRedirectUrl();
|
||||
return <Redirect to={redirectUri} />;
|
||||
}
|
||||
|
||||
if (mfa_auth_needed) return <OtpAuthForm mfa_token={mfa_token} />;
|
||||
|
||||
|
|
|
@ -37,6 +37,7 @@ import RemoteInstancePage from 'soapbox/pages/remote_instance_page';
|
|||
import StatusPage from 'soapbox/pages/status_page';
|
||||
import { getAccessToken } from 'soapbox/utils/auth';
|
||||
import { getVapidKey } from 'soapbox/utils/auth';
|
||||
import { cacheCurrentUrl } from 'soapbox/utils/redirect';
|
||||
import { isStandalone } from 'soapbox/utils/state';
|
||||
// import GroupSidebarPanel from '../groups/sidebar_panel';
|
||||
|
||||
|
@ -278,7 +279,7 @@ const SwitchingColumnsArea: React.FC = ({ children }) => {
|
|||
<WrappedRoute path='/@:username/following' publicRoute={!authenticatedProfile} component={Following} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/media' publicRoute={!authenticatedProfile} component={AccountGallery} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/tagged/:tag' exact component={AccountTimeline} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/favorites' component={FavouritedStatuses} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/favorites' component={FavouritedStatuses} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/pins' component={PinnedStatuses} page={ProfilePage} content={children} />
|
||||
<WrappedRoute path='/@:username/posts/:statusId' publicRoute exact page={StatusPage} component={Status} content={children} />
|
||||
<Redirect from='/@:username/:statusId' to='/@:username/posts/:statusId' />
|
||||
|
@ -330,6 +331,7 @@ const UI: React.FC = ({ children }) => {
|
|||
const intl = useIntl();
|
||||
const history = useHistory();
|
||||
const dispatch = useDispatch();
|
||||
const { guestExperience } = useSoapboxConfig();
|
||||
|
||||
const [draggingOver, setDraggingOver] = useState<boolean>(false);
|
||||
const [mobile, setMobile] = useState<boolean>(isMobile(window.innerWidth));
|
||||
|
@ -479,7 +481,7 @@ const UI: React.FC = ({ children }) => {
|
|||
document.addEventListener('drop', handleDrop, false);
|
||||
document.addEventListener('dragleave', handleDragLeave, false);
|
||||
|
||||
if ('serviceWorker' in navigator) {
|
||||
if ('serviceWorker' in navigator) {
|
||||
navigator.serviceWorker.addEventListener('message', handleServiceWorkerPostMessage);
|
||||
}
|
||||
|
||||
|
@ -608,6 +610,11 @@ const UI: React.FC = ({ children }) => {
|
|||
// Wait for login to succeed or fail
|
||||
if (me === null) return null;
|
||||
|
||||
if (!me && !guestExperience) {
|
||||
cacheCurrentUrl(history.location);
|
||||
return <Redirect to='/login' />;
|
||||
}
|
||||
|
||||
type HotkeyHandlers = { [key: string]: (keyEvent?: KeyboardEvent) => void };
|
||||
|
||||
const handlers: HotkeyHandlers = {
|
||||
|
|
|
@ -86,13 +86,14 @@ const WrappedRoute: React.FC<IWrappedRoute> = ({
|
|||
</>
|
||||
);
|
||||
|
||||
const renderLoading = () => renderWithLayout(<ColumnLoading />);
|
||||
const renderLoading = () => renderWithLayout(<ColumnLoading />);
|
||||
const renderForbidden = () => renderWithLayout(<ColumnForbidden />);
|
||||
const renderError = (props: any) => renderWithLayout(<BundleColumnError {...props} />);
|
||||
const renderError = (props: any) => renderWithLayout(<BundleColumnError {...props} />);
|
||||
|
||||
const loginRedirect = () => {
|
||||
const actualUrl = encodeURIComponent(`${history.location.pathname}${history.location.search}`);
|
||||
return <Redirect to={`/login?redirect_uri=${actualUrl}`} />;
|
||||
localStorage.setItem('soapbox:redirect_uri', actualUrl);
|
||||
return <Redirect to='/login' />;
|
||||
};
|
||||
|
||||
const authorized = [
|
||||
|
|
|
@ -11,6 +11,7 @@ import snackbar from 'soapbox/actions/snackbar';
|
|||
import { createAccount } from 'soapbox/actions/verification';
|
||||
import { removeStoredVerification } from 'soapbox/actions/verification';
|
||||
import { useAppSelector } from 'soapbox/hooks';
|
||||
import { getRedirectUrl } from 'soapbox/utils/redirect';
|
||||
|
||||
import { Button, Form, FormGroup, Input } from '../../components/ui';
|
||||
|
||||
|
@ -81,7 +82,8 @@ const Registration = () => {
|
|||
}, []);
|
||||
|
||||
if (shouldRedirect) {
|
||||
return <Redirect to='/' />;
|
||||
const redirectUri = getRedirectUrl();
|
||||
return <Redirect to={redirectUri} />;
|
||||
}
|
||||
|
||||
return (
|
||||
|
|
|
@ -115,6 +115,7 @@ export const SoapboxConfigRecord = ImmutableRecord({
|
|||
singleUserMode: false,
|
||||
singleUserModeProfile: '',
|
||||
linkFooterMessage: '',
|
||||
guestExperience: true,
|
||||
links: ImmutableMap<string, string>(),
|
||||
}, 'SoapboxConfig');
|
||||
|
||||
|
|
36
app/soapbox/utils/redirect.ts
Normal file
36
app/soapbox/utils/redirect.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
import { Location } from 'history';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const LOCAL_STORAGE_REDIRECT_KEY = 'soapbox:redirect-uri';
|
||||
|
||||
const cacheCurrentUrl = (location: Location<unknown>) => {
|
||||
const actualUrl = encodeURIComponent(`${location.pathname}${location.search}`);
|
||||
localStorage.setItem(LOCAL_STORAGE_REDIRECT_KEY, actualUrl);
|
||||
return actualUrl;
|
||||
};
|
||||
|
||||
const getRedirectUrl = () => {
|
||||
let redirectUri = localStorage.getItem(LOCAL_STORAGE_REDIRECT_KEY);
|
||||
if (redirectUri) {
|
||||
redirectUri = decodeURIComponent(redirectUri);
|
||||
}
|
||||
|
||||
localStorage.removeItem(LOCAL_STORAGE_REDIRECT_KEY);
|
||||
return redirectUri || '/';
|
||||
};
|
||||
|
||||
const useCachedLocationHandler = () => {
|
||||
const removeCachedRedirectUri = () => localStorage.removeItem(LOCAL_STORAGE_REDIRECT_KEY);
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('beforeunload', removeCachedRedirectUri);
|
||||
|
||||
return () => {
|
||||
window.removeEventListener('beforeunload', removeCachedRedirectUri);
|
||||
};
|
||||
}, []);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export { cacheCurrentUrl, getRedirectUrl, useCachedLocationHandler };
|
Loading…
Reference in a new issue