Fix workspace logo, cookie security, and improve workspace impersonation (#14838)

3 small fixes:
- Fix workspace logo
- Improve cookie security
- Improve workspace impersonation
This commit is contained in:
Félix Malfait
2025-10-02 18:36:52 +02:00
committed by GitHub
parent 388e49a8cf
commit d4914aa130
18 changed files with 128 additions and 14 deletions
@@ -7,6 +7,7 @@ import { AdminPanelService } from 'src/engine/core-modules/admin-panel/admin-pan
import { AuditService } from 'src/engine/core-modules/audit/services/audit.service';
import { LoginTokenService } from 'src/engine/core-modules/auth/token/services/login-token.service';
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
import { FileService } from 'src/engine/core-modules/file/services/file.service';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { User } from 'src/engine/core-modules/user/user.entity';
@@ -82,6 +83,10 @@ describe('AdminPanelService', () => {
}),
},
},
{
provide: FileService,
useValue: {},
},
],
}).compile();
@@ -9,6 +9,7 @@ import { AuditModule } from 'src/engine/core-modules/audit/audit.module';
import { AuthModule } from 'src/engine/core-modules/auth/auth.module';
import { DomainManagerModule } from 'src/engine/core-modules/domain-manager/domain-manager.module';
import { FeatureFlagModule } from 'src/engine/core-modules/feature-flag/feature-flag.module';
import { FileModule } from 'src/engine/core-modules/file/file.module';
import { HealthModule } from 'src/engine/core-modules/health/health.module';
import { ImpersonationModule } from 'src/engine/core-modules/impersonation/impersonation.module';
import { RedisClientModule } from 'src/engine/core-modules/redis-client/redis-client.module';
@@ -21,6 +22,7 @@ import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permi
TypeOrmModule.forFeature([User]),
AuthModule,
DomainManagerModule,
FileModule,
HealthModule,
RedisClientModule,
TerminusModule,
@@ -20,6 +20,7 @@ import { LoginTokenService } from 'src/engine/core-modules/auth/token/services/l
import { DomainManagerService } from 'src/engine/core-modules/domain-manager/services/domain-manager.service';
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
import { type FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { FileService } from 'src/engine/core-modules/file/services/file.service';
import { type ConfigVariables } from 'src/engine/core-modules/twenty-config/config-variables';
import { CONFIG_VARIABLES_GROUP_METADATA } from 'src/engine/core-modules/twenty-config/constants/config-variables-group-metadata';
import { type ConfigVariablesGroup } from 'src/engine/core-modules/twenty-config/enums/config-variables-group.enum';
@@ -34,15 +35,21 @@ export class AdminPanelService {
private readonly twentyConfigService: TwentyConfigService,
private readonly domainManagerService: DomainManagerService,
private readonly auditService: AuditService,
private readonly fileService: FileService,
@InjectRepository(User)
private readonly userRepository: Repository<User>,
) {}
async userLookup(userIdentifier: string): Promise<UserLookup> {
const isEmail = userIdentifier.includes('@');
const normalizedIdentifier = isEmail
? userIdentifier.toLowerCase()
: userIdentifier;
const targetUser = await this.userRepository.findOne({
where: isEmail ? { email: userIdentifier } : { id: userIdentifier },
where: isEmail
? { email: normalizedIdentifier }
: { id: normalizedIdentifier },
relations: {
userWorkspaces: {
workspace: {
@@ -57,7 +64,9 @@ export class AdminPanelService {
userValidator.assertIsDefinedOrThrow(
targetUser,
new AuthException('User not found', AuthExceptionCode.INVALID_INPUT),
new AuthException('User not found', AuthExceptionCode.INVALID_INPUT, {
userFriendlyMessage: 'User not found. Please check the email or ID.',
}),
);
const allFeatureFlagKeys = Object.values(FeatureFlagKey);
@@ -73,8 +82,18 @@ export class AdminPanelService {
id: userWorkspace.workspace.id,
name: userWorkspace.workspace.displayName ?? '',
totalUsers: userWorkspace.workspace.workspaceUsers.length,
logo: userWorkspace.workspace.logo,
logo: userWorkspace.workspace.logo
? this.fileService.signFileUrl({
url: userWorkspace.workspace.logo,
workspaceId: userWorkspace.workspace.id,
})
: userWorkspace.workspace.logo,
allowImpersonation: userWorkspace.workspace.allowImpersonation,
workspaceUrls: this.domainManagerService.getWorkspaceUrls({
subdomain: userWorkspace.workspace.subdomain,
customDomain: userWorkspace.workspace.customDomain,
isCustomDomainEnabled: userWorkspace.workspace.isCustomDomainEnabled,
}),
users: userWorkspace.workspace.workspaceUsers.map((workspaceUser) => ({
id: workspaceUser.user.id,
email: workspaceUser.user.email,
@@ -2,6 +2,7 @@ import { Field, ObjectType } from '@nestjs/graphql';
import { UUIDScalarType } from 'src/engine/api/graphql/workspace-schema-builder/graphql-types/scalars';
import { FeatureFlag } from 'src/engine/core-modules/feature-flag/feature-flag.entity';
import { WorkspaceUrls } from 'src/engine/core-modules/workspace/dtos/workspace-urls.dto';
@ObjectType()
class UserInfo {
@@ -35,6 +36,9 @@ class WorkspaceInfo {
@Field(() => Number)
totalUsers: number;
@Field(() => WorkspaceUrls)
workspaceUrls: WorkspaceUrls;
@Field(() => [UserInfo])
users: UserInfo[];