diff --git a/apps/app/package.json b/apps/app/package.json index c35b8556daa..0f67168c0c5 100644 --- a/apps/app/package.json +++ b/apps/app/package.json @@ -1,6 +1,6 @@ { "name": "@growi/app", - "version": "7.3.6", + "version": "7.3.7-RC.0", "license": "MIT", "private": "true", "scripts": { diff --git a/apps/app/src/client/components/Admin/AdminHome/AdminHome.jsx b/apps/app/src/client/components/Admin/AdminHome/AdminHome.jsx index 5e735a5a930..fc43abd8c32 100644 --- a/apps/app/src/client/components/Admin/AdminHome/AdminHome.jsx +++ b/apps/app/src/client/components/Admin/AdminHome/AdminHome.jsx @@ -17,6 +17,7 @@ import { withUnstatedContainers } from '../../UnstatedUtils'; import { EnvVarsTable } from './EnvVarsTable'; import SystemInfomationTable from './SystemInfomationTable'; + const logger = loggerFactory('growi:admin'); const AdminHome = (props) => { @@ -59,7 +60,7 @@ const AdminHome = (props) => { ) } { - // Alert message will be displayed in case that V5 migration has not been compleated + // Alert message will be displayed in case that V5 migration has not been compleated (migrationStatus != null && !migrationStatus.isV5Compatible) && (
@@ -90,7 +91,7 @@ const AdminHome = (props) => {

{t('admin:admin_top.env_var_priority')}

{/* eslint-disable-next-line react/no-danger */}

- {adminHomeContainer.state.envVars && } +

diff --git a/apps/app/src/client/components/Admin/AdminHome/EnvVarsTable.tsx b/apps/app/src/client/components/Admin/AdminHome/EnvVarsTable.tsx index 9a25953ae46..ccb5d46cbcb 100644 --- a/apps/app/src/client/components/Admin/AdminHome/EnvVarsTable.tsx +++ b/apps/app/src/client/components/Admin/AdminHome/EnvVarsTable.tsx @@ -1,13 +1,20 @@ import React, { type JSX } from 'react'; +import { LoadingSpinner } from '@growi/ui/dist/components'; + type EnvVarsTableProps = { - envVars: Record, + envVars?: Record, } export const EnvVarsTable: React.FC = (props: EnvVarsTableProps) => { + const { envVars } = props; + if (envVars == null) { + return ; + } + const envVarRows: JSX.Element[] = []; - for (const [key, value] of Object.entries(props.envVars)) { + for (const [key, value] of Object.entries(envVars ?? {})) { if (value != null) { envVarRows.push( diff --git a/apps/app/src/client/components/Admin/AdminHome/SystemInfomationTable.tsx b/apps/app/src/client/components/Admin/AdminHome/SystemInfomationTable.tsx index e1ef6a63cfd..c1ce1241987 100644 --- a/apps/app/src/client/components/Admin/AdminHome/SystemInfomationTable.tsx +++ b/apps/app/src/client/components/Admin/AdminHome/SystemInfomationTable.tsx @@ -1,5 +1,7 @@ import React from 'react'; +import { LoadingSpinner } from '@growi/ui/dist/components'; + import AdminHomeContainer from '~/client/services/AdminHomeContainer'; import { withUnstatedContainers } from '../../UnstatedUtils'; @@ -17,7 +19,7 @@ const SystemInformationTable = (props: Props) => { } = adminHomeContainer.state; if (growiVersion == null || nodeVersion == null || npmVersion == null || pnpmVersion == null) { - return <>; + return ; } return ( diff --git a/apps/app/src/client/components/Admin/Security/GitHubSecuritySettingContents.jsx b/apps/app/src/client/components/Admin/Security/GitHubSecuritySettingContents.jsx index 7474880988d..332e64c68f6 100644 --- a/apps/app/src/client/components/Admin/Security/GitHubSecuritySettingContents.jsx +++ b/apps/app/src/client/components/Admin/Security/GitHubSecuritySettingContents.jsx @@ -36,9 +36,11 @@ const GitHubSecurityManagementContents = (props) => { const onClickSubmit = useCallback(async(data) => { try { - await adminGitHubSecurityContainer.changeGitHubClientId(data.githubClientId ?? ''); - await adminGitHubSecurityContainer.changeGitHubClientSecret(data.githubClientSecret ?? ''); - await adminGitHubSecurityContainer.updateGitHubSetting(); + await adminGitHubSecurityContainer.updateGitHubSetting({ + githubClientId: data.githubClientId ?? '', + githubClientSecret: data.githubClientSecret ?? '', + isSameUsernameTreatedAsIdenticalUser: adminGitHubSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser, + }); await adminGeneralSecurityContainer.retrieveSetupStratedies(); toastSuccess(t('security_settings.OAuth.GitHub.updated_github')); } diff --git a/apps/app/src/client/components/Admin/Security/GoogleSecuritySettingContents.jsx b/apps/app/src/client/components/Admin/Security/GoogleSecuritySettingContents.jsx index 8dc8dacb1f4..9af4d5ccfa0 100644 --- a/apps/app/src/client/components/Admin/Security/GoogleSecuritySettingContents.jsx +++ b/apps/app/src/client/components/Admin/Security/GoogleSecuritySettingContents.jsx @@ -34,9 +34,11 @@ const GoogleSecurityManagementContents = (props) => { const onClickSubmit = useCallback(async(data) => { try { - await adminGoogleSecurityContainer.changeGoogleClientId(data.googleClientId ?? ''); - await adminGoogleSecurityContainer.changeGoogleClientSecret(data.googleClientSecret ?? ''); - await adminGoogleSecurityContainer.updateGoogleSetting(); + await adminGoogleSecurityContainer.updateGoogleSetting({ + googleClientId: data.googleClientId ?? '', + googleClientSecret: data.googleClientSecret ?? '', + isSameEmailTreatedAsIdenticalUser: adminGoogleSecurityContainer.state.isSameEmailTreatedAsIdenticalUser, + }); await adminGeneralSecurityContainer.retrieveSetupStratedies(); toastSuccess(t('security_settings.OAuth.Google.updated_google')); } diff --git a/apps/app/src/client/components/Admin/Security/LdapSecuritySettingContents.tsx b/apps/app/src/client/components/Admin/Security/LdapSecuritySettingContents.tsx index b5fd949025a..743e41b0087 100644 --- a/apps/app/src/client/components/Admin/Security/LdapSecuritySettingContents.tsx +++ b/apps/app/src/client/components/Admin/Security/LdapSecuritySettingContents.tsx @@ -56,17 +56,20 @@ const LdapSecuritySettingContents = (props: Props) => { const onSubmit = useCallback(async(data) => { try { - await adminLdapSecurityContainer.changeServerUrl(data.serverUrl); - await adminLdapSecurityContainer.changeBindDN(data.ldapBindDN); - await adminLdapSecurityContainer.changeBindDNPassword(data.ldapBindDNPassword); - await adminLdapSecurityContainer.changeSearchFilter(data.ldapSearchFilter); - await adminLdapSecurityContainer.changeAttrMapUsername(data.ldapAttrMapUsername); - await adminLdapSecurityContainer.changeAttrMapMail(data.ldapAttrMapMail); - await adminLdapSecurityContainer.changeAttrMapName(data.ldapAttrMapName); - await adminLdapSecurityContainer.changeGroupSearchBase(data.ldapGroupSearchBase); - await adminLdapSecurityContainer.changeGroupSearchFilter(data.ldapGroupSearchFilter); - await adminLdapSecurityContainer.changeGroupDnProperty(data.ldapGroupDnProperty); - await adminLdapSecurityContainer.updateLdapSetting(); + await adminLdapSecurityContainer.updateLdapSetting({ + serverUrl: data.serverUrl, + isUserBind: adminLdapSecurityContainer.state.isUserBind, + ldapBindDN: data.ldapBindDN, + ldapBindDNPassword: data.ldapBindDNPassword, + ldapSearchFilter: data.ldapSearchFilter, + ldapAttrMapUsername: data.ldapAttrMapUsername, + isSameUsernameTreatedAsIdenticalUser: adminLdapSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser, + ldapAttrMapMail: data.ldapAttrMapMail, + ldapAttrMapName: data.ldapAttrMapName, + ldapGroupSearchBase: data.ldapGroupSearchBase, + ldapGroupSearchFilter: data.ldapGroupSearchFilter, + ldapGroupDnProperty: data.ldapGroupDnProperty, + }); await adminGeneralSecurityContainer.retrieveSetupStratedies(); toastSuccess(t('security_settings.ldap.updated_ldap')); } diff --git a/apps/app/src/client/components/Admin/Security/LocalSecuritySettingContents.tsx b/apps/app/src/client/components/Admin/Security/LocalSecuritySettingContents.tsx index f42f4dab685..b34c7a10b36 100644 --- a/apps/app/src/client/components/Admin/Security/LocalSecuritySettingContents.tsx +++ b/apps/app/src/client/components/Admin/Security/LocalSecuritySettingContents.tsx @@ -38,8 +38,12 @@ const LocalSecuritySettingContents = (props: Props): JSX.Element => { const onSubmit = useCallback(async(data) => { try { - await adminLocalSecurityContainer.changeRegistrationWhitelist(data.registrationWhitelist); - await adminLocalSecurityContainer.updateLocalSecuritySetting(); + await adminLocalSecurityContainer.updateLocalSecuritySetting({ + registrationMode: adminLocalSecurityContainer.state.registrationMode, + registrationWhitelist: data.registrationWhitelist.split('\n'), + isPasswordResetEnabled: adminLocalSecurityContainer.state.isPasswordResetEnabled, + isEmailAuthenticationEnabled: adminLocalSecurityContainer.state.isEmailAuthenticationEnabled, + }); await adminGeneralSecurityContainer.retrieveSetupStratedies(); toastSuccess(t('security_settings.updated_general_security_setting')); } diff --git a/apps/app/src/client/components/Admin/Security/OidcSecuritySettingContents.tsx b/apps/app/src/client/components/Admin/Security/OidcSecuritySettingContents.tsx index a70fbbcd8b9..fb3af745fc0 100644 --- a/apps/app/src/client/components/Admin/Security/OidcSecuritySettingContents.tsx +++ b/apps/app/src/client/components/Admin/Security/OidcSecuritySettingContents.tsx @@ -68,23 +68,26 @@ const OidcSecurityManagementContents = (props: Props) => { const onSubmit = useCallback(async(data) => { try { - await adminOidcSecurityContainer.changeOidcProviderName(data.oidcProviderName); - await adminOidcSecurityContainer.changeOidcIssuerHost(data.oidcIssuerHost); - await adminOidcSecurityContainer.changeOidcClientId(data.oidcClientId); - await adminOidcSecurityContainer.changeOidcClientSecret(data.oidcClientSecret); - await adminOidcSecurityContainer.changeOidcAuthorizationEndpoint(data.oidcAuthorizationEndpoint); - await adminOidcSecurityContainer.changeOidcTokenEndpoint(data.oidcTokenEndpoint); - await adminOidcSecurityContainer.changeOidcRevocationEndpoint(data.oidcRevocationEndpoint); - await adminOidcSecurityContainer.changeOidcIntrospectionEndpoint(data.oidcIntrospectionEndpoint); - await adminOidcSecurityContainer.changeOidcUserInfoEndpoint(data.oidcUserInfoEndpoint); - await adminOidcSecurityContainer.changeOidcEndSessionEndpoint(data.oidcEndSessionEndpoint); - await adminOidcSecurityContainer.changeOidcRegistrationEndpoint(data.oidcRegistrationEndpoint); - await adminOidcSecurityContainer.changeOidcJWKSUri(data.oidcJWKSUri); - await adminOidcSecurityContainer.changeOidcAttrMapId(data.oidcAttrMapId); - await adminOidcSecurityContainer.changeOidcAttrMapUserName(data.oidcAttrMapUserName); - await adminOidcSecurityContainer.changeOidcAttrMapName(data.oidcAttrMapName); - await adminOidcSecurityContainer.changeOidcAttrMapEmail(data.oidcAttrMapEmail); - await adminOidcSecurityContainer.updateOidcSetting(); + await adminOidcSecurityContainer.updateOidcSetting({ + oidcProviderName: data.oidcProviderName, + oidcIssuerHost: data.oidcIssuerHost, + oidcClientId: data.oidcClientId, + oidcClientSecret: data.oidcClientSecret, + oidcAuthorizationEndpoint: data.oidcAuthorizationEndpoint, + oidcTokenEndpoint: data.oidcTokenEndpoint, + oidcRevocationEndpoint: data.oidcRevocationEndpoint, + oidcIntrospectionEndpoint: data.oidcIntrospectionEndpoint, + oidcUserInfoEndpoint: data.oidcUserInfoEndpoint, + oidcEndSessionEndpoint: data.oidcEndSessionEndpoint, + oidcRegistrationEndpoint: data.oidcRegistrationEndpoint, + oidcJWKSUri: data.oidcJWKSUri, + oidcAttrMapId: data.oidcAttrMapId, + oidcAttrMapUserName: data.oidcAttrMapUserName, + oidcAttrMapName: data.oidcAttrMapName, + oidcAttrMapEmail: data.oidcAttrMapEmail, + isSameUsernameTreatedAsIdenticalUser: adminOidcSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser, + isSameEmailTreatedAsIdenticalUser: adminOidcSecurityContainer.state.isSameEmailTreatedAsIdenticalUser, + }); await adminGeneralSecurityContainer.retrieveSetupStratedies(); toastSuccess(t('security_settings.OAuth.OIDC.updated_oidc')); } diff --git a/apps/app/src/client/components/Admin/Security/SamlSecuritySettingContents.tsx b/apps/app/src/client/components/Admin/Security/SamlSecuritySettingContents.tsx index e11b60e2f3b..8eb3a5f05e3 100644 --- a/apps/app/src/client/components/Admin/Security/SamlSecuritySettingContents.tsx +++ b/apps/app/src/client/components/Admin/Security/SamlSecuritySettingContents.tsx @@ -46,18 +46,20 @@ const SamlSecurityManagementContents = (props: Props) => { }, [adminSamlSecurityContainer.state, reset]); const onSubmit = useCallback(async(data) => { - adminSamlSecurityContainer.changeSamlEntryPoint(data.samlEntryPoint); - adminSamlSecurityContainer.changeSamlIssuer(data.samlIssuer); - adminSamlSecurityContainer.changeSamlCert(data.samlCert); - adminSamlSecurityContainer.changeSamlAttrMapId(data.samlAttrMapId); - adminSamlSecurityContainer.changeSamlAttrMapUserName(data.samlAttrMapUsername); - adminSamlSecurityContainer.changeSamlAttrMapMail(data.samlAttrMapMail); - adminSamlSecurityContainer.changeSamlAttrMapFirstName(data.samlAttrMapFirstName); - adminSamlSecurityContainer.changeSamlAttrMapLastName(data.samlAttrMapLastName); - adminSamlSecurityContainer.changeSamlABLCRule(data.samlABLCRule); - try { - await adminSamlSecurityContainer.updateSamlSetting(); + await adminSamlSecurityContainer.updateSamlSetting({ + samlEntryPoint: data.samlEntryPoint, + samlIssuer: data.samlIssuer, + samlCert: data.samlCert, + samlAttrMapId: data.samlAttrMapId, + samlAttrMapUsername: data.samlAttrMapUsername, + samlAttrMapMail: data.samlAttrMapMail, + samlAttrMapFirstName: data.samlAttrMapFirstName, + samlAttrMapLastName: data.samlAttrMapLastName, + isSameUsernameTreatedAsIdenticalUser: adminSamlSecurityContainer.state.isSameUsernameTreatedAsIdenticalUser, + isSameEmailTreatedAsIdenticalUser: adminSamlSecurityContainer.state.isSameEmailTreatedAsIdenticalUser, + samlABLCRule: data.samlABLCRule, + }); toastSuccess(t('security_settings.SAML.updated_saml')); } catch (err) { diff --git a/apps/app/src/client/components/Admin/Security/SecuritySetting/index.tsx b/apps/app/src/client/components/Admin/Security/SecuritySetting/index.tsx index f12eef8df6f..ac04ce83f5c 100644 --- a/apps/app/src/client/components/Admin/Security/SecuritySetting/index.tsx +++ b/apps/app/src/client/components/Admin/Security/SecuritySetting/index.tsx @@ -36,10 +36,21 @@ const SecuritySettingComponent: React.FC = ({ adminGeneralSecurityContain const onSubmit = useCallback(async(data: FormData) => { try { - // Update sessionMaxAge from form data - await adminGeneralSecurityContainer.setSessionMaxAge(data.sessionMaxAge); - // Save all security settings - await adminGeneralSecurityContainer.updateGeneralSecuritySetting(); + // Save all security settings with form data + await adminGeneralSecurityContainer.updateGeneralSecuritySetting({ + sessionMaxAge: data.sessionMaxAge, + restrictGuestMode: adminGeneralSecurityContainer.state.currentRestrictGuestMode, + pageDeletionAuthority: adminGeneralSecurityContainer.state.currentPageDeletionAuthority, + pageCompleteDeletionAuthority: adminGeneralSecurityContainer.state.currentPageCompleteDeletionAuthority, + pageRecursiveDeletionAuthority: adminGeneralSecurityContainer.state.currentPageRecursiveDeletionAuthority, + pageRecursiveCompleteDeletionAuthority: adminGeneralSecurityContainer.state.currentPageRecursiveCompleteDeletionAuthority, + isAllGroupMembershipRequiredForPageCompleteDeletion: adminGeneralSecurityContainer.state.isAllGroupMembershipRequiredForPageCompleteDeletion, + hideRestrictedByGroup: adminGeneralSecurityContainer.state.currentGroupRestrictionDisplayMode === 'Hidden', + hideRestrictedByOwner: adminGeneralSecurityContainer.state.currentOwnerRestrictionDisplayMode === 'Hidden', + isUsersHomepageDeletionEnabled: adminGeneralSecurityContainer.state.isUsersHomepageDeletionEnabled, + isForceDeleteUserHomepageOnUserDeletion: adminGeneralSecurityContainer.state.isForceDeleteUserHomepageOnUserDeletion, + isRomUserAllowedToComment: adminGeneralSecurityContainer.state.isRomUserAllowedToComment, + }); toastSuccess(t('security_settings.updated_general_security_setting')); } catch (err) { diff --git a/apps/app/src/client/services/AdminGeneralSecurityContainer.js b/apps/app/src/client/services/AdminGeneralSecurityContainer.js index 72cafa823e4..6561d8d1c89 100644 --- a/apps/app/src/client/services/AdminGeneralSecurityContainer.js +++ b/apps/app/src/client/services/AdminGeneralSecurityContainer.js @@ -239,9 +239,22 @@ export default class AdminGeneralSecurityContainer extends Container { * @memberOf AdminGeneralSecuritySContainer * @return {string} Appearance */ - async updateGeneralSecuritySetting() { - - let requestParams = { + async updateGeneralSecuritySetting(formData) { + + let requestParams = formData != null ? { + sessionMaxAge: formData.sessionMaxAge, + restrictGuestMode: formData.restrictGuestMode, + pageDeletionAuthority: formData.pageDeletionAuthority, + pageCompleteDeletionAuthority: formData.pageCompleteDeletionAuthority, + pageRecursiveDeletionAuthority: formData.pageRecursiveDeletionAuthority, + pageRecursiveCompleteDeletionAuthority: formData.pageRecursiveCompleteDeletionAuthority, + isAllGroupMembershipRequiredForPageCompleteDeletion: formData.isAllGroupMembershipRequiredForPageCompleteDeletion, + hideRestrictedByGroup: formData.hideRestrictedByGroup, + hideRestrictedByOwner: formData.hideRestrictedByOwner, + isUsersHomepageDeletionEnabled: formData.isUsersHomepageDeletionEnabled, + isForceDeleteUserHomepageOnUserDeletion: formData.isForceDeleteUserHomepageOnUserDeletion, + isRomUserAllowedToComment: formData.isRomUserAllowedToComment, + } : { sessionMaxAge: this.state.sessionMaxAge, restrictGuestMode: this.state.currentRestrictGuestMode, pageDeletionAuthority: this.state.currentPageDeletionAuthority, diff --git a/apps/app/src/client/services/AdminGitHubSecurityContainer.js b/apps/app/src/client/services/AdminGitHubSecurityContainer.js index 32db1855a6f..256533c04e4 100644 --- a/apps/app/src/client/services/AdminGitHubSecurityContainer.js +++ b/apps/app/src/client/services/AdminGitHubSecurityContainer.js @@ -61,20 +61,6 @@ export default class AdminGitHubSecurityContainer extends Container { return 'AdminGitHubSecurityContainer'; } - /** - * Change githubClientId - */ - changeGitHubClientId(value) { - this.setState({ githubClientId: value }); - } - - /** - * Change githubClientSecret - */ - changeGitHubClientSecret(value) { - this.setState({ githubClientSecret: value }); - } - /** * Switch isSameUsernameTreatedAsIdenticalUser */ @@ -85,10 +71,16 @@ export default class AdminGitHubSecurityContainer extends Container { /** * Update githubSetting */ - async updateGitHubSetting() { - const { githubClientId, githubClientSecret, isSameUsernameTreatedAsIdenticalUser } = this.state; - - let requestParams = { githubClientId, githubClientSecret, isSameUsernameTreatedAsIdenticalUser }; + async updateGitHubSetting(formData) { + let requestParams = formData != null ? { + githubClientId: formData.githubClientId, + githubClientSecret: formData.githubClientSecret, + isSameUsernameTreatedAsIdenticalUser: formData.isSameUsernameTreatedAsIdenticalUser, + } : { + githubClientId: this.state.githubClientId, + githubClientSecret: this.state.githubClientSecret, + isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser, + }; requestParams = await removeNullPropertyFromObject(requestParams); const response = await apiv3Put('/security-setting/github-oauth', requestParams); diff --git a/apps/app/src/client/services/AdminGoogleSecurityContainer.js b/apps/app/src/client/services/AdminGoogleSecurityContainer.js index 797f50af6d3..b5e606998c0 100644 --- a/apps/app/src/client/services/AdminGoogleSecurityContainer.js +++ b/apps/app/src/client/services/AdminGoogleSecurityContainer.js @@ -62,20 +62,6 @@ export default class AdminGoogleSecurityContainer extends Container { return 'AdminGoogleSecurityContainer'; } - /** - * Change googleClientId - */ - changeGoogleClientId(value) { - this.setState({ googleClientId: value }); - } - - /** - * Change googleClientSecret - */ - changeGoogleClientSecret(value) { - this.setState({ googleClientSecret: value }); - } - /** * Switch isSameEmailTreatedAsIdenticalUser */ @@ -87,11 +73,15 @@ export default class AdminGoogleSecurityContainer extends Container { /** * Update googleSetting */ - async updateGoogleSetting() { - const { googleClientId, googleClientSecret, isSameEmailTreatedAsIdenticalUser } = this.state; - - let requestParams = { - googleClientId, googleClientSecret, isSameEmailTreatedAsIdenticalUser, + async updateGoogleSetting(formData) { + let requestParams = formData != null ? { + googleClientId: formData.googleClientId, + googleClientSecret: formData.googleClientSecret, + isSameEmailTreatedAsIdenticalUser: formData.isSameEmailTreatedAsIdenticalUser, + } : { + googleClientId: this.state.googleClientId, + googleClientSecret: this.state.googleClientSecret, + isSameEmailTreatedAsIdenticalUser: this.state.isSameEmailTreatedAsIdenticalUser, }; requestParams = await removeNullPropertyFromObject(requestParams); diff --git a/apps/app/src/client/services/AdminLdapSecurityContainer.js b/apps/app/src/client/services/AdminLdapSecurityContainer.js index 4f049ee133b..cb90568ed0f 100644 --- a/apps/app/src/client/services/AdminLdapSecurityContainer.js +++ b/apps/app/src/client/services/AdminLdapSecurityContainer.js @@ -78,13 +78,6 @@ export default class AdminLdapSecurityContainer extends Container { return 'AdminLdapSecurityContainer'; } - /** - * Change serverUrl - */ - changeServerUrl(serverUrl) { - this.setState({ serverUrl }); - } - /** * Change ldapBindMode * @param {boolean} isUserBind true: User Bind, false: Admin Bind @@ -93,34 +86,6 @@ export default class AdminLdapSecurityContainer extends Container { this.setState({ isUserBind }); } - /** - * Change bindDN - */ - changeBindDN(ldapBindDN) { - this.setState({ ldapBindDN }); - } - - /** - * Change bindDNPassword - */ - changeBindDNPassword(ldapBindDNPassword) { - this.setState({ ldapBindDNPassword }); - } - - /** - * Change ldapSearchFilter - */ - changeSearchFilter(ldapSearchFilter) { - this.setState({ ldapSearchFilter }); - } - - /** - * Change ldapAttrMapUsername - */ - changeAttrMapUsername(ldapAttrMapUsername) { - this.setState({ ldapAttrMapUsername }); - } - /** * Switch is same username treated as identical user */ @@ -128,63 +93,36 @@ export default class AdminLdapSecurityContainer extends Container { this.setState({ isSameUsernameTreatedAsIdenticalUser: !this.state.isSameUsernameTreatedAsIdenticalUser }); } - /** - * Change ldapAttrMapMail - */ - changeAttrMapMail(ldapAttrMapMail) { - this.setState({ ldapAttrMapMail }); - } - - /** - * Change ldapAttrMapName - */ - changeAttrMapName(ldapAttrMapName) { - this.setState({ ldapAttrMapName }); - } - - /** - * Change ldapGroupSearchBase - */ - changeGroupSearchBase(ldapGroupSearchBase) { - this.setState({ ldapGroupSearchBase }); - } - - /** - * Change ldapGroupSearchFilter - */ - changeGroupSearchFilter(ldapGroupSearchFilter) { - this.setState({ ldapGroupSearchFilter }); - } - - /** - * Change ldapGroupDnProperty - */ - changeGroupDnProperty(ldapGroupDnProperty) { - this.setState({ ldapGroupDnProperty }); - } - /** * Update ldap option */ - async updateLdapSetting() { - const { - serverUrl, isUserBind, ldapBindDN, ldapBindDNPassword, ldapSearchFilter, ldapAttrMapUsername, isSameUsernameTreatedAsIdenticalUser, - ldapAttrMapMail, ldapAttrMapName, ldapGroupSearchBase, ldapGroupSearchFilter, ldapGroupDnProperty, - } = this.state; - - let requestParams = { - serverUrl, - isUserBind, - ldapBindDN, - ldapBindDNPassword, - ldapSearchFilter, - ldapAttrMapUsername, - isSameUsernameTreatedAsIdenticalUser, - ldapAttrMapMail, - ldapAttrMapName, - ldapGroupSearchBase, - ldapGroupSearchFilter, - ldapGroupDnProperty, + async updateLdapSetting(formData) { + let requestParams = formData != null ? { + serverUrl: formData.serverUrl, + isUserBind: formData.isUserBind, + ldapBindDN: formData.ldapBindDN, + ldapBindDNPassword: formData.ldapBindDNPassword, + ldapSearchFilter: formData.ldapSearchFilter, + ldapAttrMapUsername: formData.ldapAttrMapUsername, + isSameUsernameTreatedAsIdenticalUser: formData.isSameUsernameTreatedAsIdenticalUser, + ldapAttrMapMail: formData.ldapAttrMapMail, + ldapAttrMapName: formData.ldapAttrMapName, + ldapGroupSearchBase: formData.ldapGroupSearchBase, + ldapGroupSearchFilter: formData.ldapGroupSearchFilter, + ldapGroupDnProperty: formData.ldapGroupDnProperty, + } : { + serverUrl: this.state.serverUrl, + isUserBind: this.state.isUserBind, + ldapBindDN: this.state.ldapBindDN, + ldapBindDNPassword: this.state.ldapBindDNPassword, + ldapSearchFilter: this.state.ldapSearchFilter, + ldapAttrMapUsername: this.state.ldapAttrMapUsername, + isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser, + ldapAttrMapMail: this.state.ldapAttrMapMail, + ldapAttrMapName: this.state.ldapAttrMapName, + ldapGroupSearchBase: this.state.ldapGroupSearchBase, + ldapGroupSearchFilter: this.state.ldapGroupSearchFilter, + ldapGroupDnProperty: this.state.ldapGroupDnProperty, }; requestParams = await removeNullPropertyFromObject(requestParams); diff --git a/apps/app/src/client/services/AdminLocalSecurityContainer.js b/apps/app/src/client/services/AdminLocalSecurityContainer.js index b13089b4adb..a1314d9da7d 100644 --- a/apps/app/src/client/services/AdminLocalSecurityContainer.js +++ b/apps/app/src/client/services/AdminLocalSecurityContainer.js @@ -71,13 +71,6 @@ export default class AdminLocalSecurityContainer extends Container { this.setState({ registrationMode: value }); } - /** - * Change registration whitelist - */ - changeRegistrationWhitelist(value) { - this.setState({ registrationWhitelist: value.split('\n') }); - } - /** * Switch password reset enabled */ @@ -95,14 +88,19 @@ export default class AdminLocalSecurityContainer extends Container { /** * update local security setting */ - async updateLocalSecuritySetting() { - const { registrationWhitelist, isPasswordResetEnabled, isEmailAuthenticationEnabled } = this.state; - const response = await apiv3Put('/security-setting/local-setting', { + async updateLocalSecuritySetting(formData) { + const requestParams = formData != null ? { + registrationMode: formData.registrationMode, + registrationWhitelist: formData.registrationWhitelist, + isPasswordResetEnabled: formData.isPasswordResetEnabled, + isEmailAuthenticationEnabled: formData.isEmailAuthenticationEnabled, + } : { registrationMode: this.state.registrationMode, - registrationWhitelist, - isPasswordResetEnabled, - isEmailAuthenticationEnabled, - }); + registrationWhitelist: this.state.registrationWhitelist, + isPasswordResetEnabled: this.state.isPasswordResetEnabled, + isEmailAuthenticationEnabled: this.state.isEmailAuthenticationEnabled, + }; + const response = await apiv3Put('/security-setting/local-setting', requestParams); const { localSettingParams } = response.data; diff --git a/apps/app/src/client/services/AdminOidcSecurityContainer.js b/apps/app/src/client/services/AdminOidcSecurityContainer.js index 2d0fec1c08b..04f5c8e6f7b 100644 --- a/apps/app/src/client/services/AdminOidcSecurityContainer.js +++ b/apps/app/src/client/services/AdminOidcSecurityContainer.js @@ -89,118 +89,6 @@ export default class AdminOidcSecurityContainer extends Container { return 'AdminOidcSecurityContainer'; } - /** - * Change oidcProviderName - */ - changeOidcProviderName(inputValue) { - this.setState({ oidcProviderName: inputValue }); - } - - /** - * Change oidcIssuerHost - */ - changeOidcIssuerHost(inputValue) { - this.setState({ oidcIssuerHost: inputValue }); - } - - /** - * Change oidcAuthorizationEndpoint - */ - changeOidcAuthorizationEndpoint(inputValue) { - this.setState({ oidcAuthorizationEndpoint: inputValue }); - } - - /** - * Change oidcTokenEndpoint - */ - changeOidcTokenEndpoint(inputValue) { - this.setState({ oidcTokenEndpoint: inputValue }); - } - - /** - * Change oidcRevocationEndpoint - */ - changeOidcRevocationEndpoint(inputValue) { - this.setState({ oidcRevocationEndpoint: inputValue }); - } - - /** - * Change oidcIntrospectionEndpoint - */ - changeOidcIntrospectionEndpoint(inputValue) { - this.setState({ oidcIntrospectionEndpoint: inputValue }); - } - - /** - * Change oidcUserInfoEndpoint - */ - changeOidcUserInfoEndpoint(inputValue) { - this.setState({ oidcUserInfoEndpoint: inputValue }); - } - - /** - * Change oidcEndSessionEndpoint - */ - changeOidcEndSessionEndpoint(inputValue) { - this.setState({ oidcEndSessionEndpoint: inputValue }); - } - - /** - * Change oidcRegistrationEndpoint - */ - changeOidcRegistrationEndpoint(inputValue) { - this.setState({ oidcRegistrationEndpoint: inputValue }); - } - - /** - * Change oidcJWKSUri - */ - changeOidcJWKSUri(inputValue) { - this.setState({ oidcJWKSUri: inputValue }); - } - - /** - * Change oidcClientId - */ - changeOidcClientId(inputValue) { - this.setState({ oidcClientId: inputValue }); - } - - /** - * Change oidcClientSecret - */ - changeOidcClientSecret(inputValue) { - this.setState({ oidcClientSecret: inputValue }); - } - - /** - * Change oidcAttrMapId - */ - changeOidcAttrMapId(inputValue) { - this.setState({ oidcAttrMapId: inputValue }); - } - - /** - * Change oidcAttrMapUserName - */ - changeOidcAttrMapUserName(inputValue) { - this.setState({ oidcAttrMapUserName: inputValue }); - } - - /** - * Change oidcAttrMapName - */ - changeOidcAttrMapName(inputValue) { - this.setState({ oidcAttrMapName: inputValue }); - } - - /** - * Change oidcAttrMapEmail - */ - changeOidcAttrMapEmail(inputValue) { - this.setState({ oidcAttrMapEmail: inputValue }); - } - /** * Switch sameUsernameTreatedAsIdenticalUser */ @@ -218,47 +106,45 @@ export default class AdminOidcSecurityContainer extends Container { /** * Update OpenID Connect */ - async updateOidcSetting() { - const { - oidcProviderName, - oidcIssuerHost, - oidcAuthorizationEndpoint, - oidcTokenEndpoint, - oidcRevocationEndpoint, - oidcIntrospectionEndpoint, - oidcUserInfoEndpoint, - oidcEndSessionEndpoint, - oidcRegistrationEndpoint, - oidcJWKSUri, - oidcClientId, - oidcClientSecret, - oidcAttrMapId, - oidcAttrMapUserName, - oidcAttrMapName, - oidcAttrMapEmail, - isSameUsernameTreatedAsIdenticalUser, - isSameEmailTreatedAsIdenticalUser, - } = this.state; - - let requestParams = { - oidcProviderName, - oidcIssuerHost, - oidcAuthorizationEndpoint, - oidcTokenEndpoint, - oidcRevocationEndpoint, - oidcIntrospectionEndpoint, - oidcUserInfoEndpoint, - oidcEndSessionEndpoint, - oidcRegistrationEndpoint, - oidcJWKSUri, - oidcClientId, - oidcClientSecret, - oidcAttrMapId, - oidcAttrMapUserName, - oidcAttrMapName, - oidcAttrMapEmail, - isSameUsernameTreatedAsIdenticalUser, - isSameEmailTreatedAsIdenticalUser, + async updateOidcSetting(formData) { + let requestParams = formData != null ? { + oidcProviderName: formData.oidcProviderName, + oidcIssuerHost: formData.oidcIssuerHost, + oidcAuthorizationEndpoint: formData.oidcAuthorizationEndpoint, + oidcTokenEndpoint: formData.oidcTokenEndpoint, + oidcRevocationEndpoint: formData.oidcRevocationEndpoint, + oidcIntrospectionEndpoint: formData.oidcIntrospectionEndpoint, + oidcUserInfoEndpoint: formData.oidcUserInfoEndpoint, + oidcEndSessionEndpoint: formData.oidcEndSessionEndpoint, + oidcRegistrationEndpoint: formData.oidcRegistrationEndpoint, + oidcJWKSUri: formData.oidcJWKSUri, + oidcClientId: formData.oidcClientId, + oidcClientSecret: formData.oidcClientSecret, + oidcAttrMapId: formData.oidcAttrMapId, + oidcAttrMapUserName: formData.oidcAttrMapUserName, + oidcAttrMapName: formData.oidcAttrMapName, + oidcAttrMapEmail: formData.oidcAttrMapEmail, + isSameUsernameTreatedAsIdenticalUser: formData.isSameUsernameTreatedAsIdenticalUser, + isSameEmailTreatedAsIdenticalUser: formData.isSameEmailTreatedAsIdenticalUser, + } : { + oidcProviderName: this.state.oidcProviderName, + oidcIssuerHost: this.state.oidcIssuerHost, + oidcAuthorizationEndpoint: this.state.oidcAuthorizationEndpoint, + oidcTokenEndpoint: this.state.oidcTokenEndpoint, + oidcRevocationEndpoint: this.state.oidcRevocationEndpoint, + oidcIntrospectionEndpoint: this.state.oidcIntrospectionEndpoint, + oidcUserInfoEndpoint: this.state.oidcUserInfoEndpoint, + oidcEndSessionEndpoint: this.state.oidcEndSessionEndpoint, + oidcRegistrationEndpoint: this.state.oidcRegistrationEndpoint, + oidcJWKSUri: this.state.oidcJWKSUri, + oidcClientId: this.state.oidcClientId, + oidcClientSecret: this.state.oidcClientSecret, + oidcAttrMapId: this.state.oidcAttrMapId, + oidcAttrMapUserName: this.state.oidcAttrMapUserName, + oidcAttrMapName: this.state.oidcAttrMapName, + oidcAttrMapEmail: this.state.oidcAttrMapEmail, + isSameUsernameTreatedAsIdenticalUser: this.state.isSameUsernameTreatedAsIdenticalUser, + isSameEmailTreatedAsIdenticalUser: this.state.isSameEmailTreatedAsIdenticalUser, }; requestParams = await removeNullPropertyFromObject(requestParams); diff --git a/apps/app/src/client/services/AdminSamlSecurityContainer.js b/apps/app/src/client/services/AdminSamlSecurityContainer.js index cceef3769ab..587d141ca24 100644 --- a/apps/app/src/client/services/AdminSamlSecurityContainer.js +++ b/apps/app/src/client/services/AdminSamlSecurityContainer.js @@ -98,62 +98,6 @@ export default class AdminSamlSecurityContainer extends Container { return 'AdminSamlSecurityContainer'; } - /** - * Change samlEntryPoint - */ - changeSamlEntryPoint(inputValue) { - this.setState({ samlEntryPoint: inputValue }); - } - - /** - * Change samlIssuer - */ - changeSamlIssuer(inputValue) { - this.setState({ samlIssuer: inputValue }); - } - - /** - * Change samlCert - */ - changeSamlCert(inputValue) { - this.setState({ samlCert: inputValue }); - } - - /** - * Change samlAttrMapId - */ - changeSamlAttrMapId(inputValue) { - this.setState({ samlAttrMapId: inputValue }); - } - - /** - * Change samlAttrMapUsername - */ - changeSamlAttrMapUserName(inputValue) { - this.setState({ samlAttrMapUsername: inputValue }); - } - - /** - * Change samlAttrMapMail - */ - changeSamlAttrMapMail(inputValue) { - this.setState({ samlAttrMapMail: inputValue }); - } - - /** - * Change samlAttrMapFirstName - */ - changeSamlAttrMapFirstName(inputValue) { - this.setState({ samlAttrMapFirstName: inputValue }); - } - - /** - * Change samlAttrMapLastName - */ - changeSamlAttrMapLastName(inputValue) { - this.setState({ samlAttrMapLastName: inputValue }); - } - /** * Switch isSameUsernameTreatedAsIdenticalUser */ @@ -168,19 +112,24 @@ export default class AdminSamlSecurityContainer extends Container { this.setState({ isSameEmailTreatedAsIdenticalUser: !this.state.isSameEmailTreatedAsIdenticalUser }); } - /** - * Change samlABLCRule - */ - changeSamlABLCRule(inputValue) { - this.setState({ samlABLCRule: inputValue }); - } - /** * Update saml option */ - async updateSamlSetting() { - - let requestParams = { + async updateSamlSetting(formData) { + + let requestParams = formData != null ? { + entryPoint: formData.samlEntryPoint, + issuer: formData.samlIssuer, + cert: formData.samlCert, + attrMapId: formData.samlAttrMapId, + attrMapUsername: formData.samlAttrMapUsername, + attrMapMail: formData.samlAttrMapMail, + attrMapFirstName: formData.samlAttrMapFirstName, + attrMapLastName: formData.samlAttrMapLastName, + isSameUsernameTreatedAsIdenticalUser: formData.isSameUsernameTreatedAsIdenticalUser, + isSameEmailTreatedAsIdenticalUser: formData.isSameEmailTreatedAsIdenticalUser, + ABLCRule: formData.samlABLCRule, + } : { entryPoint: this.state.samlEntryPoint, issuer: this.state.samlIssuer, cert: this.state.samlCert, diff --git a/apps/pdf-converter/.env b/apps/pdf-converter/.env index 12c220c7936..09d0bad128c 100644 --- a/apps/pdf-converter/.env +++ b/apps/pdf-converter/.env @@ -1 +1,2 @@ PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium +PUPPETEER_CLUSTER_CONFIG={"maxConcurrency":1, "concurrency": 2} diff --git a/apps/pdf-converter/docker/README.md b/apps/pdf-converter/docker/README.md index d5c3feb11c0..96359d7eb8f 100644 --- a/apps/pdf-converter/docker/README.md +++ b/apps/pdf-converter/docker/README.md @@ -5,10 +5,10 @@ GROWI PDF Converter Official docker image [![Node CI for pdf-converter](https://github.com/growilabs/growi/actions/workflows/ci-pdf-converter.yml/badge.svg)](https://github.com/growilabs/growi/actions/workflows/ci-pdf-converter.yml) [![docker-pulls](https://img.shields.io/docker/pulls/growilabs/pdf-converter.svg)](https://hub.docker.com/r/growilabs/pdf-converter/) -Supported tags and respective Dockerfile links +Dockerfile link ------------------------------------------------ -* [`1.0.0`, `latest` (Dockerfile)](https://github.com/growilabs/growi/blob/master/apps/pdf-converter/docker/Dockerfile) +https://github.com/growilabs/growi/blob/master/apps/pdf-converter/docker/Dockerfile What is GROWI PDF Converter used for? diff --git a/apps/pdf-converter/package.json b/apps/pdf-converter/package.json index 57e06468be4..c1c0b133af9 100644 --- a/apps/pdf-converter/package.json +++ b/apps/pdf-converter/package.json @@ -1,6 +1,6 @@ { "name": "@growi/pdf-converter", - "version": "1.1.3-RC.0", + "version": "1.2.1-RC.0", "main": "dist/index.js", "types": "dist/index.d.ts", "license": "MIT", diff --git a/apps/pdf-converter/src/service/pdf-convert.ts b/apps/pdf-converter/src/service/pdf-convert.ts index d9fa1526c77..e94da6f2e3f 100644 --- a/apps/pdf-converter/src/service/pdf-convert.ts +++ b/apps/pdf-converter/src/service/pdf-convert.ts @@ -5,6 +5,7 @@ import { pipeline as pipelinePromise } from 'node:stream/promises'; import { OnInit } from '@tsed/common'; import { Service } from '@tsed/di'; import { Logger } from '@tsed/logger'; +import type { PuppeteerNodeLaunchOptions } from 'puppeteer'; import { Cluster } from 'puppeteer-cluster'; interface PageInfo { @@ -37,8 +38,6 @@ interface JobInfo { class PdfConvertService implements OnInit { private puppeteerCluster: Cluster | undefined; - private maxConcurrency = 1; - private convertRetryLimit = 5; private tmpOutputRootDir = '/tmp/page-bulk-export'; @@ -292,15 +291,8 @@ class PdfConvertService implements OnInit { private async initPuppeteerCluster(): Promise { if (process.env.SKIP_PUPPETEER_INIT === 'true') return; - this.puppeteerCluster = await Cluster.launch({ - concurrency: Cluster.CONCURRENCY_PAGE, - maxConcurrency: this.maxConcurrency, - workerCreationDelay: 10000, - puppeteerOptions: { - // ref) https://github.com/growilabs/growi/pull/10192 - args: ['--no-sandbox'], - }, - }); + const config = this.getPuppeteerClusterConfig(); + this.puppeteerCluster = await Cluster.launch(config); await this.puppeteerCluster.task(async ({ page, data: htmlString }) => { await page.setContent(htmlString, { waitUntil: 'domcontentloaded' }); @@ -326,6 +318,51 @@ class PdfConvertService implements OnInit { }); } + /** + * Get puppeteer cluster configuration from environment variable + * @returns merged cluster configuration + */ + private getPuppeteerClusterConfig(): Record { + // Default cluster configuration + const defaultConfig = { + concurrency: Cluster.CONCURRENCY_CONTEXT, + maxConcurrency: 1, + workerCreationDelay: 10000, + // Puppeteer options (not configurable for security reasons) + // ref) https://github.com/growilabs/growi/pull/10192 + puppeteerOptions: { + args: ['--no-sandbox'], + }, + }; + + // Parse configuration from environment variable + let customConfig: Record = {}; + if (process.env.PUPPETEER_CLUSTER_CONFIG) { + try { + customConfig = JSON.parse(process.env.PUPPETEER_CLUSTER_CONFIG); + } catch (err) { + this.logger.warn( + 'Failed to parse PUPPETEER_CLUSTER_CONFIG, using default values', + err, + ); + } + } + + // Remove puppeteerOptions from custom config if present (not allowed for security) + if (customConfig.puppeteerOptions) { + this.logger.warn( + 'puppeteerOptions configuration is not allowed for security reasons and will be ignored', + ); + delete customConfig.puppeteerOptions; + } + + // Merge configurations (customConfig overrides defaultConfig, except puppeteerOptions) + return { + ...defaultConfig, + ...customConfig, + }; + } + /** * Get parent path from given path * @param path target path diff --git a/apps/slackbot-proxy/package.json b/apps/slackbot-proxy/package.json index 8ecad4b984e..17eb33af3fd 100644 --- a/apps/slackbot-proxy/package.json +++ b/apps/slackbot-proxy/package.json @@ -1,6 +1,6 @@ { "name": "@growi/slackbot-proxy", - "version": "7.3.6-slackbot-proxy.0", + "version": "7.3.7-slackbot-proxy.0", "license": "MIT", "private": "true", "scripts": { diff --git a/package.json b/package.json index 62e1561ead6..dd887c266f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "growi", - "version": "7.3.6", + "version": "7.3.7-RC.0", "description": "Team collaboration software using markdown", "license": "MIT", "private": "true",