diff --git a/backend/src/api/tenant/index.ts b/backend/src/api/tenant/index.ts index 0ea84da5d2..97096f37d9 100644 --- a/backend/src/api/tenant/index.ts +++ b/backend/src/api/tenant/index.ts @@ -15,6 +15,7 @@ export default (app) => { app.get(`/tenant`, safeWrap(require('./tenantList').default)) app.get(`/tenant/url`, safeWrap(require('./tenantFind').default)) app.get(`/tenant/:id`, safeWrap(require('./tenantFind').default)) + app.get(`/tenant/:id/name`, safeWrap(require('./tenantFindName').default)) app.get(`/tenant/:tenantId/membersToMerge`, safeWrap(require('./tenantMembersToMerge').default)) app.get( `/tenant/:tenantId/organizationsToMerge`, diff --git a/backend/src/api/tenant/tenantFind.ts b/backend/src/api/tenant/tenantFind.ts index 6f27d6c1b2..6670237626 100644 --- a/backend/src/api/tenant/tenantFind.ts +++ b/backend/src/api/tenant/tenantFind.ts @@ -1,10 +1,13 @@ import identifyTenant from '../../segment/identifyTenant' import TenantService from '../../services/tenantService' import Error404 from '../../errors/Error404' +import PermissionChecker from '../../services/user/permissionChecker' +import Permissions from '../../security/permissions' export default async (req, res) => { + req.currentTenant = { id: req.params.id } + new PermissionChecker(req).validateHas(Permissions.values.memberRead) let payload - if (req.params.id) { payload = await new TenantService(req).findById(req.params.id) } else { diff --git a/backend/src/api/tenant/tenantFindName.ts b/backend/src/api/tenant/tenantFindName.ts new file mode 100644 index 0000000000..ae25895943 --- /dev/null +++ b/backend/src/api/tenant/tenantFindName.ts @@ -0,0 +1,23 @@ +import identifyTenant from '../../segment/identifyTenant' +import TenantService from '../../services/tenantService' +import Error404 from '../../errors/Error404' + +export default async (req, res) => { + // This endpoint is unauthenticated on purpose, but public reprots. + const payload = await new TenantService(req).findById(req.params.id) + + if (payload) { + if (req.currentUser) { + identifyTenant({ ...req, currentTenant: payload }) + } + + const payloadOut = { + name: payload.name, + id: payload.id, + } + + await req.responseHandler.success(req, res, payloadOut) + } else { + throw new Error404() + } +} diff --git a/backend/src/database/repositories/userRepository.ts b/backend/src/database/repositories/userRepository.ts index 7f1f7a63c1..afcd43ce8e 100644 --- a/backend/src/database/repositories/userRepository.ts +++ b/backend/src/database/repositories/userRepository.ts @@ -547,12 +547,22 @@ export default class UserRepository { status: 'active', }, }) + record = { ...record, ...record.json, } delete record.json + // Remove sensitive fields + delete record.password + delete record.emailVerificationToken + delete record.emailVerificationTokenExpiresAt + delete record.providerId + delete record.passwordResetToken + delete record.passwordResetTokenExpiresAt + delete record.jwtTokenInvalidBefore + if (!record) { throw new Error404() } diff --git a/backend/src/i18n/en.ts b/backend/src/i18n/en.ts index 413123012c..86874dbe80 100644 --- a/backend/src/i18n/en.ts +++ b/backend/src/i18n/en.ts @@ -45,6 +45,8 @@ const en = { invalidToken: 'Invalid or expired password reset link', error: `Invalid email`, }, + passwordInvalid: + 'Passwords must have at least one letter, one number, one symbol, and be at least 8 characters long.', emailAddressVerificationEmail: { invalidToken: 'Invalid or expired email verification link.', error: `Email not recognized.`, diff --git a/backend/src/security/permissions.ts b/backend/src/security/permissions.ts index f701f4ab02..7e0ceced70 100644 --- a/backend/src/security/permissions.ts +++ b/backend/src/security/permissions.ts @@ -99,7 +99,7 @@ class Permissions { }, userRead: { id: 'userRead', - allowedRoles: [roles.admin, roles.readonly], + allowedRoles: [roles.admin], allowedPlans: [ plans.essential, plans.growth, @@ -110,7 +110,7 @@ class Permissions { }, userAutocomplete: { id: 'userAutocomplete', - allowedRoles: [roles.admin, roles.readonly], + allowedRoles: [roles.admin], allowedPlans: [ plans.essential, plans.growth, diff --git a/backend/src/services/auth/authService.ts b/backend/src/services/auth/authService.ts index e72f19acac..e18fb9695c 100644 --- a/backend/src/services/auth/authService.ts +++ b/backend/src/services/auth/authService.ts @@ -38,6 +38,12 @@ class AuthService { const existingUser = await UserRepository.findByEmail(email, options) + const passwordRegex = /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/ + + if (!passwordRegex.test(password)) { + throw new Error400(options.language, 'auth.passwordInvalid') + } + // Generates a hashed password to hide the original one. const hashedPassword = await bcrypt.hash(password, BCRYPT_SALT_ROUNDS) diff --git a/frontend/src/i18n/en.js b/frontend/src/i18n/en.js index 36f3a2c648..cca01dcbe2 100644 --- a/frontend/src/i18n/en.js +++ b/frontend/src/i18n/en.js @@ -813,7 +813,7 @@ const en = { /* eslint-disable */ validation: { mixed: { - default: 'path} is invalid', + default: '{path} is invalid', required: 'This field is required', oneOf: '{path} must be one of the following values: ${values}', diff --git a/frontend/src/modules/auth/pages/signin-page.vue b/frontend/src/modules/auth/pages/signin-page.vue index bb4bfac6c9..e480dd0c82 100644 --- a/frontend/src/modules/auth/pages/signin-page.vue +++ b/frontend/src/modules/auth/pages/signin-page.vue @@ -72,6 +72,11 @@ class="h-4 flex items-center ri-error-warning-line text-base text-red-500" /> Passwords must have at least one letter, one number, one symbol, and be at least 8 characters long. + {{ error }} diff --git a/frontend/src/modules/auth/pages/signup-page.vue b/frontend/src/modules/auth/pages/signup-page.vue index eca7056e09..2a1170097a 100644 --- a/frontend/src/modules/auth/pages/signup-page.vue +++ b/frontend/src/modules/auth/pages/signup-page.vue @@ -129,6 +129,11 @@ class="h-4 flex items-center ri-error-warning-line text-base text-red-500" /> Passwords must have at least one letter, one number, one symbol, and be at least 8 characters long. + {{ error }} diff --git a/frontend/src/modules/layout/components/menu/workspace/menu-workspace-popover.vue b/frontend/src/modules/layout/components/menu/workspace/menu-workspace-popover.vue index 337090fb83..e8c7331c9b 100644 --- a/frontend/src/modules/layout/components/menu/workspace/menu-workspace-popover.vue +++ b/frontend/src/modules/layout/components/menu/workspace/menu-workspace-popover.vue @@ -15,7 +15,7 @@ :disable-active-class="true" link-class="!p-3 !h-10 !mb-0 !mt-1 !text-xs" /> -