jam411 3 лет назад
Родитель
Сommit
a0cde0c75b

+ 1 - 1
packages/app/_obsolete/src/client/nologin.jsx

@@ -10,7 +10,7 @@ import AppContainer from '~/client/services/AppContainer';
 import CompleteUserRegistrationForm from '~/components/CompleteUserRegistrationForm';
 import CompleteUserRegistrationForm from '~/components/CompleteUserRegistrationForm';
 import { swrGlobalConfiguration } from '~/utils/swr-utils';
 import { swrGlobalConfiguration } from '~/utils/swr-utils';
 
 
-import LoginForm from '../components/Login/LoginForm';
+import LoginForm from '../components/LoginForm';
 import PasswordResetExecutionForm from '../components/PasswordResetExecutionForm';
 import PasswordResetExecutionForm from '../components/PasswordResetExecutionForm';
 import PasswordResetRequestForm from '../components/PasswordResetRequestForm';
 import PasswordResetRequestForm from '../components/PasswordResetRequestForm';
 
 

+ 1 - 1
packages/app/config/rate-limiter.ts

@@ -33,7 +33,7 @@ export const defaultConfig: IApiRateLimitEndpointMap = {
     maxRequests: MAX_REQUESTS_TIER_1,
     maxRequests: MAX_REQUESTS_TIER_1,
     usersPerIpProspection: 100,
     usersPerIpProspection: 100,
   },
   },
-  '/login/activateInvited': {
+  '/invited/activateInvited': {
     method: 'POST',
     method: 'POST',
     maxRequests: MAX_REQUESTS_TIER_2,
     maxRequests: MAX_REQUESTS_TIER_2,
   },
   },

+ 0 - 0
packages/app/src/components/Login/Invited.module.scss → packages/app/src/components/Invited.module.scss


+ 2 - 2
packages/app/src/components/Login/InvitedForm.tsx → packages/app/src/components/InvitedForm.tsx

@@ -2,7 +2,7 @@ import React from 'react';
 
 
 import { useTranslation } from 'next-i18next';
 import { useTranslation } from 'next-i18next';
 
 
-import { useCsrfToken, useCurrentUser } from '../../stores/context';
+import { useCsrfToken, useCurrentUser } from '../stores/context';
 
 
 export type InvitedFormProps = {
 export type InvitedFormProps = {
   invitedFormUsername: string,
   invitedFormUsername: string,
@@ -26,7 +26,7 @@ export const InvitedForm = (props: InvitedFormProps): JSX.Element => {
         <strong>{ t('invited.discription_heading') }</strong><br></br>
         <strong>{ t('invited.discription_heading') }</strong><br></br>
         <small>{ t('invited.discription') }</small>
         <small>{ t('invited.discription') }</small>
       </p>
       </p>
-      <form role="form" action="/login/activateInvited" method="post" id="invited-form">
+      <form role="form" action="/invited/activateInvited" method="post" id="invited-form">
         {/* Email Form */}
         {/* Email Form */}
         <div className="input-group">
         <div className="input-group">
           <div className="input-group-prepend">
           <div className="input-group-prepend">

+ 0 - 0
packages/app/src/components/Login/LoginForm.jsx → packages/app/src/components/LoginForm.jsx


+ 10 - 42
packages/app/src/pages/login/[[...path]].page.tsx → packages/app/src/pages/invited.page.tsx

@@ -4,19 +4,18 @@ import { IUserHasId, IUser } from '@growi/core';
 import { NextPage, GetServerSideProps, GetServerSidePropsContext } from 'next';
 import { NextPage, GetServerSideProps, GetServerSidePropsContext } from 'next';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import { serverSideTranslations } from 'next-i18next/serverSideTranslations';
 import dynamic from 'next/dynamic';
 import dynamic from 'next/dynamic';
-import { useRouter } from 'next/router';
 
 
+import { InvitedFormProps } from '~/components/InvitedForm';
 import { NoLoginLayout } from '~/components/Layout/NoLoginLayout';
 import { NoLoginLayout } from '~/components/Layout/NoLoginLayout';
-import { InvitedFormProps } from '~/components/Login/InvitedForm';
 import { CrowiRequest } from '~/interfaces/crowi-request';
 import { CrowiRequest } from '~/interfaces/crowi-request';
 
 
-import { useCsrfToken, useCurrentPathname, useCurrentUser } from '../../stores/context';
+import { useCsrfToken, useCurrentPathname, useCurrentUser } from '../stores/context';
+
 import {
 import {
   CommonProps, getServerSideCommonProps, useCustomTitle, getNextI18NextConfig,
   CommonProps, getServerSideCommonProps, useCustomTitle, getNextI18NextConfig,
-} from '../utils/commons';
+} from './utils/commons';
 
 
-const LoginForm = dynamic(() => import('~/components/Login/LoginForm'), { ssr: false });
-const InvitedForm = dynamic<InvitedFormProps>(() => import('~/components/Login/InvitedForm').then(mod => mod.InvitedForm), { ssr: false });
+const InvitedForm = dynamic<InvitedFormProps>(() => import('~/components/InvitedForm').then(mod => mod.InvitedForm), { ssr: false });
 
 
 type Props = CommonProps & {
 type Props = CommonProps & {
   isMailerSetup: boolean,
   isMailerSetup: boolean,
@@ -27,48 +26,17 @@ type Props = CommonProps & {
   invitedFormName: string,
   invitedFormName: string,
 }
 }
 
 
-const LoginPage: NextPage<Props> = (props: Props) => {
-
-  const router = useRouter();
-  const { path } = router.query;
-  const pagePathKeys: string[] = Array.isArray(path) ? path : ['login'];
+const InvitedPage: NextPage<Props> = (props: Props) => {
 
 
   useCsrfToken(props.csrfToken);
   useCsrfToken(props.csrfToken);
   useCurrentPathname(props.currentPathname);
   useCurrentPathname(props.currentPathname);
   useCurrentUser(props.currentUser);
   useCurrentUser(props.currentUser);
 
 
-  const loginPagesMap = {
-    login: {
-      component: <LoginForm
-        isLocalStrategySetup={true}
-        isLdapStrategySetup={true}
-        objOfIsExternalAuthEnableds={props.enabledStrategies}
-        isRegistrationEnabled={true}
-        isPasswordResetEnabled={true}
-        registrationWhiteList={props.registrationWhiteList}
-      />,
-      classNames: ['login-page'],
-    },
-    invited: {
-      component: <InvitedForm
-        invitedFormUsername={props.invitedFormUsername}
-        invitedFormName={props.invitedFormName}
-      />,
-      classNames: ['invited-page'],
-    },
-  };
-
-  const getTargetPageToRender = (pagesMap, keys): {component: JSX.Element, classNames: string[]} => {
-    return keys.reduce((pagesMap, key) => {
-      return pagesMap[key];
-    }, pagesMap);
-  };
-
-  const targetPage = getTargetPageToRender(loginPagesMap, pagePathKeys);
+  const classNames: string[] = ['invited-page'];
 
 
   return (
   return (
-    <NoLoginLayout title={useCustomTitle(props, 'GROWI')} className={targetPage.classNames.join(' ')}>
-      { targetPage.component }
+    <NoLoginLayout title={useCustomTitle(props, 'GROWI')} className={classNames.join(' ')}>
+      <InvitedForm invitedFormUsername={props.invitedFormUsername} invitedFormName={props.invitedFormName} />
     </NoLoginLayout>
     </NoLoginLayout>
   );
   );
 
 
@@ -142,4 +110,4 @@ export const getServerSideProps: GetServerSideProps = async(context: GetServerSi
   return { props };
   return { props };
 };
 };
 
 
-export default LoginPage;
+export default InvitedPage;

+ 101 - 0
packages/app/src/pages/login.page.tsx

@@ -0,0 +1,101 @@
+import React from 'react';
+
+
+import {
+  NextPage, GetServerSideProps, GetServerSidePropsContext,
+} from 'next';
+import dynamic from 'next/dynamic';
+
+import { NoLoginLayout } from '~/components/Layout/NoLoginLayout';
+import { CrowiRequest } from '~/interfaces/crowi-request';
+
+import {
+  useCsrfToken,
+  useCurrentPathname,
+} from '../stores/context';
+
+
+import {
+  CommonProps, getServerSideCommonProps, useCustomTitle,
+} from './utils/commons';
+
+const LoginForm = dynamic(() => import('~/components/LoginForm'), { ssr: false });
+
+type Props = CommonProps & {
+
+  pageWithMetaStr: string,
+  isMailerSetup: boolean,
+  enabledStrategies: unknown,
+  registrationWhiteList: string[],
+};
+
+const LoginPage: NextPage<Props> = (props: Props) => {
+
+  // commons
+  useCsrfToken(props.csrfToken);
+
+  // page
+  useCurrentPathname(props.currentPathname);
+
+  const classNames: string[] = ['login-page'];
+
+  return (
+    <NoLoginLayout title={useCustomTitle(props, 'GROWI')} className={classNames.join(' ')}>
+      <LoginForm objOfIsExternalAuthEnableds={props.enabledStrategies} isLocalStrategySetup={true} isLdapStrategySetup={true}
+        isRegistrationEnabled={true} registrationWhiteList={props.registrationWhiteList} isPasswordResetEnabled={true} />
+    </NoLoginLayout>
+  );
+};
+
+function injectEnabledStrategies(context: GetServerSidePropsContext, props: Props): void {
+  const req: CrowiRequest = context.req as CrowiRequest;
+  const { crowi } = req;
+  const {
+    configManager,
+  } = crowi;
+
+  const enabledStrategies = {
+    google: configManager.getConfig('crowi', 'security:passport-google:isEnabled'),
+    github: configManager.getConfig('crowi', 'security:passport-github:isEnabled'),
+    facebook: false,
+    twitter: configManager.getConfig('crowi', 'security:passport-twitter:isEnabled'),
+    smal: configManager.getConfig('crowi', 'security:passport-saml:isEnabled'),
+    oidc: configManager.getConfig('crowi', 'security:passport-oidc:isEnabled'),
+    basic: configManager.getConfig('crowi', 'security:passport-basic:isEnabled'),
+  };
+
+  props.enabledStrategies = enabledStrategies;
+}
+
+async function injectServerConfigurations(context: GetServerSidePropsContext, props: Props): Promise<void> {
+  const req: CrowiRequest = context.req as CrowiRequest;
+  const { crowi } = req;
+  const {
+    mailService,
+    configManager,
+  } = crowi;
+
+  props.isMailerSetup = mailService.isMailerSetup;
+  props.registrationWhiteList = configManager.getConfig('crowi', 'security:registrationWhiteList');
+}
+
+export const getServerSideProps: GetServerSideProps = async(context: GetServerSidePropsContext) => {
+  const result = await getServerSideCommonProps(context);
+
+  // check for presence
+  // see: https://github.com/vercel/next.js/issues/19271#issuecomment-730006862
+  if (!('props' in result)) {
+    throw new Error('invalid getSSP result');
+  }
+
+  const props: Props = result.props as Props;
+
+  injectServerConfigurations(context, props);
+  injectEnabledStrategies(context, props);
+
+  return {
+    props,
+  };
+};
+
+export default LoginPage;

+ 1 - 1
packages/app/src/server/middlewares/login-required.js

@@ -27,7 +27,7 @@ module.exports = (crowi, isGuestAllowed = false, fallback = null) => {
         return res.redirect('/login/error/suspended');
         return res.redirect('/login/error/suspended');
       }
       }
       if (req.user.status === User.STATUS_INVITED) {
       if (req.user.status === User.STATUS_INVITED) {
-        return res.redirect('/login/invited');
+        return res.redirect('/invited');
       }
       }
     }
     }
 
 

+ 2 - 2
packages/app/src/server/routes/index.js

@@ -80,8 +80,8 @@ module.exports = function(crowi, app) {
 
 
   app.get('/login/error/:reason'      , applicationInstalled, login.error);
   app.get('/login/error/:reason'      , applicationInstalled, login.error);
   app.get('/login'                    , applicationInstalled, login.preLogin, next.delegateToNext);
   app.get('/login'                    , applicationInstalled, login.preLogin, next.delegateToNext);
-  app.get('/login/invited'            , applicationInstalled, next.delegateToNext);
-  app.post('/login/activateInvited'   , applicationInstalled, loginFormValidator.inviteRules(), loginFormValidator.inviteValidation, csrfProtection, login.invited);
+  app.get('/invited'            , applicationInstalled, next.delegateToNext);
+  app.post('/invited/activateInvited'   , applicationInstalled, loginFormValidator.inviteRules(), loginFormValidator.inviteValidation, csrfProtection, login.invited);
   app.post('/login'                   , applicationInstalled, loginFormValidator.loginRules(), loginFormValidator.loginValidation, csrfProtection,  addActivity, loginPassport.loginWithLocal, loginPassport.loginWithLdap, loginPassport.loginFailure);
   app.post('/login'                   , applicationInstalled, loginFormValidator.loginRules(), loginFormValidator.loginValidation, csrfProtection,  addActivity, loginPassport.loginWithLocal, loginPassport.loginWithLdap, loginPassport.loginFailure);
 
 
   app.post('/register'                , applicationInstalled, registerFormValidator.registerRules(), registerFormValidator.registerValidation, csrfProtection, addActivity, login.register);
   app.post('/register'                , applicationInstalled, registerFormValidator.registerRules(), registerFormValidator.registerValidation, csrfProtection, addActivity, login.register);

+ 1 - 1
packages/app/src/server/views/invited.html

@@ -71,7 +71,7 @@
         <small>招待を受け取ったメールアドレスでアカウントを作成します</small>
         <small>招待を受け取ったメールアドレスでアカウントを作成します</small>
       </p>
       </p>
 
 
-      <form role="form" action="/login/activateInvited" method="post" id="invited-form">
+      <form role="form" action="/invited/activateInvited" method="post" id="invited-form">
 
 
         <div class="input-group">
         <div class="input-group">
           <div class="input-group-prepend">
           <div class="input-group-prepend">

+ 3 - 3
packages/app/test/integration/middlewares/login-required.test.js

@@ -47,7 +47,7 @@ describe('loginRequired', () => {
         userStatus  | expectedPath
         userStatus  | expectedPath
         ${1}        | ${'/login/error/registered'}
         ${1}        | ${'/login/error/registered'}
         ${3}        | ${'/login/error/suspended'}
         ${3}        | ${'/login/error/suspended'}
-        ${5}        | ${'/login/invited'}
+        ${5}        | ${'/invited'}
       `('redirect to \'$expectedPath\' when user.status is \'$userStatus\'', ({ userStatus, expectedPath }) => {
       `('redirect to \'$expectedPath\' when user.status is \'$userStatus\'', ({ userStatus, expectedPath }) => {
 
 
         req.user = {
         req.user = {
@@ -122,7 +122,7 @@ describe('loginRequired', () => {
         userStatus  | expectedPath
         userStatus  | expectedPath
         ${1}        | ${'/login/error/registered'}
         ${1}        | ${'/login/error/registered'}
         ${3}        | ${'/login/error/suspended'}
         ${3}        | ${'/login/error/suspended'}
-        ${5}        | ${'/login/invited'}
+        ${5}        | ${'/invited'}
       `('redirect to \'$expectedPath\' when user.status is \'$userStatus\'', ({ userStatus, expectedPath }) => {
       `('redirect to \'$expectedPath\' when user.status is \'$userStatus\'', ({ userStatus, expectedPath }) => {
 
 
         req.user = {
         req.user = {
@@ -248,7 +248,7 @@ describe('loginRequired', () => {
       userStatus  | expectedPath
       userStatus  | expectedPath
       ${1}        | ${'/login/error/registered'}
       ${1}        | ${'/login/error/registered'}
       ${3}        | ${'/login/error/suspended'}
       ${3}        | ${'/login/error/suspended'}
-      ${5}        | ${'/login/invited'}
+      ${5}        | ${'/invited'}
     `('redirect to \'$expectedPath\' when user.status is \'$userStatus\'', ({ userStatus, expectedPath }) => {
     `('redirect to \'$expectedPath\' when user.status is \'$userStatus\'', ({ userStatus, expectedPath }) => {
       req.user = {
       req.user = {
         _id: 'user id',
         _id: 'user id',