Skip to content

Commit

Permalink
Patches for compliance (#1819)
Browse files Browse the repository at this point in the history
Co-authored-by: Gasper Grom <gasper.grom@gmail.com>
Co-authored-by: Joana Maia <joana@crowd.dev>
  • Loading branch information
3 people committed Nov 15, 2023
1 parent 26a140e commit 08bf721
Show file tree
Hide file tree
Showing 17 changed files with 113 additions and 10 deletions.
1 change: 1 addition & 0 deletions backend/src/api/tenant/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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`,
Expand Down
5 changes: 4 additions & 1 deletion backend/src/api/tenant/tenantFind.ts
Original file line number Diff line number Diff line change
@@ -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 {
Expand Down
23 changes: 23 additions & 0 deletions backend/src/api/tenant/tenantFindName.ts
Original file line number Diff line number Diff line change
@@ -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()
}
}
10 changes: 10 additions & 0 deletions backend/src/database/repositories/userRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
Expand Down
2 changes: 2 additions & 0 deletions backend/src/i18n/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.`,
Expand Down
4 changes: 2 additions & 2 deletions backend/src/security/permissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ class Permissions {
},
userRead: {
id: 'userRead',
allowedRoles: [roles.admin, roles.readonly],
allowedRoles: [roles.admin],
allowedPlans: [
plans.essential,
plans.growth,
Expand All @@ -110,7 +110,7 @@ class Permissions {
},
userAutocomplete: {
id: 'userAutocomplete',
allowedRoles: [roles.admin, roles.readonly],
allowedRoles: [roles.admin],
allowedPlans: [
plans.essential,
plans.growth,
Expand Down
6 changes: 6 additions & 0 deletions backend/src/services/auth/authService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down
2 changes: 1 addition & 1 deletion frontend/src/i18n/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}',
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/modules/auth/pages/signin-page.vue
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,11 @@
class="h-4 flex items-center ri-error-warning-line text-base text-red-500"
/>
<span
v-if="error === 'Password is invalid'"
class="pl-1 text-2xs text-red-500 leading-4.5"
>Passwords must have at least one letter, one number, one symbol, and be at least 8 characters long.</span>
<span
v-else
class="pl-1 text-2xs text-red-500 leading-4.5"
>{{ error }}</span>
</div>
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/modules/auth/pages/#-page.vue
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,11 @@
class="h-4 flex items-center ri-error-warning-line text-base text-red-500"
/>
<span
v-if="error === 'Password is invalid'"
class="pl-1 text-2xs text-red-500 leading-4.5"
>Passwords must have at least one letter, one number, one symbol, and be at least 8 characters long.</span>
<span
v-else
class="pl-1 text-2xs text-red-500 leading-4.5"
>{{ error }}</span>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
:disable-active-class="true"
link-class="!p-3 !h-10 !mb-0 !mt-1 !text-xs"
/>
<div class="px-1">
<div v-if="hasPermissionsForSettings" class="px-1">
<div class="p-3 h-10 text-xs text-black mt-1 rounded hover:bg-gray-50 cursor-pointer" @click.stop="emit('edit', tenant)">
Edit workspace
</div>
Expand All @@ -25,8 +25,14 @@
</section>

<!-- Add workspace -->
<section class="px-2 pb-3 border-b border-gray-100">
<section
class="border-b border-gray-100"
:class="{
'px-2 pb-3': hasPermissionsForSettings,
}"
>
<div
v-if="hasPermissionsForSettings"
class="px-3 h-10 text-sm font-normal rounded hover:bg-gray-50 cursor-pointer flex items-center text-brand-500"
@click="emit('add')"
>
Expand Down Expand Up @@ -102,6 +108,7 @@ import { computed } from 'vue';
import { useUserStore } from '@/modules/user/store/pinia';
import { storeToRefs } from 'pinia';
import { FeatureFlag } from '@/utils/featureFlag';
import { SettingsPermissions } from '@/modules/settings/settings-permissions';
const emit = defineEmits<{(e:'add'): any, (e: 'edit', value: TenantModel): any}>();
Expand All @@ -113,6 +120,17 @@ const userStore = useUserStore();
const { isDeveloperModeActive } = storeToRefs(userStore);
const { updateDeveloperMode } = userStore;
const hasPermissionsForSettings = computed(
() => {
const settingsPermissions = new SettingsPermissions(
currentTenant.value,
currentUser.value,
);
return settingsPermissions.edit || settingsPermissions.lockedForCurrentPlan;
},
);
const tenants = computed<TenantModel[]>(() => {
const currentTenantId = currentTenant.value.id;
const restTenants = rows.value.filter((ten: TenantModel) => ten.id !== currentTenantId)
Expand Down
10 changes: 9 additions & 1 deletion frontend/src/modules/layout/config/links/api-keys.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { MenuLink } from '@/modules/layout/types/MenuLink';
import { SettingsPermissions } from '@/modules/settings/settings-permissions';

const apiKeys: MenuLink = {
id: 'api-keys',
Expand All @@ -7,7 +8,14 @@ const apiKeys: MenuLink = {
routeOptions: {
query: { activeTab: 'api-keys' },
},
display: () => true,
display: ({ user, tenant }) => {
const settingsPermissions = new SettingsPermissions(
tenant,
user,
);

return settingsPermissions.edit || settingsPermissions.lockedForCurrentPlan;
},
disable: () => false,
};

Expand Down
10 changes: 9 additions & 1 deletion frontend/src/modules/layout/config/links/plans-billing.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { MenuLink } from '@/modules/layout/types/MenuLink';
import { SettingsPermissions } from '@/modules/settings/settings-permissions';

const plansBilling: MenuLink = {
id: 'plans-billing',
Expand All @@ -7,7 +8,14 @@ const plansBilling: MenuLink = {
routeOptions: {
query: { activeTab: 'plans' },
},
display: () => true,
display: ({ user, tenant }) => {
const settingsPermissions = new SettingsPermissions(
tenant,
user,
);

return settingsPermissions.edit || settingsPermissions.lockedForCurrentPlan;
},
disable: () => false,
};

Expand Down
10 changes: 9 additions & 1 deletion frontend/src/modules/layout/config/links/users-permissions.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { MenuLink } from '@/modules/layout/types/MenuLink';
import { SettingsPermissions } from '@/modules/settings/settings-permissions';

const usersPermissions: MenuLink = {
id: 'users-permissions',
Expand All @@ -7,7 +8,14 @@ const usersPermissions: MenuLink = {
routeOptions: {
query: { activeTab: 'users' },
},
display: () => true,
display: ({ user, tenant }) => {
const settingsPermissions = new SettingsPermissions(
tenant,
user,
);

return settingsPermissions.edit || settingsPermissions.lockedForCurrentPlan;
},
disable: () => false,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -267,7 +267,7 @@ export default {
id: this.id,
tenantId: this.tenantId,
});
this.currentTenant = await TenantService.find(
this.currentTenant = await TenantService.findName(
this.tenantId,
);
} else {
Expand Down
5 changes: 5 additions & 0 deletions frontend/src/modules/tenant/tenant-service.js
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,11 @@ export class TenantService {
return response.data;
}

static async findName(id) {
const response = await authAxios.get(`/tenant/${id}/name`);
return response.data;
}

static async findByUrl(url) {
const response = await authAxios.get('/tenant/url', {
params: { url },
Expand Down
1 change: 1 addition & 0 deletions frontend/src/modules/user/user-model.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const fields = {
}),
password: new StringField('password', label('password'), {
required: true,
matches: /^(?=.*[A-Za-z])(?=.*\d)(?=.*[@$!%*#?&])[A-Za-z\d@$!%*#?&]{8,}$/,
}),
passwordConfirmation: new StringField(
'passwordConfirmation',
Expand Down

0 comments on commit 08bf721

Please # to comment.