Signed file follow up (#12347)
This commit is contained in:
@ -1,12 +1,9 @@
|
||||
import { buildSignedPath } from 'twenty-shared/utils';
|
||||
|
||||
import { QueryResultGetterHandlerInterface } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/interfaces/query-result-getter-handler.interface';
|
||||
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
||||
import { NoteWorkspaceEntity } from 'src/modules/note/standard-objects/note.workspace-entity';
|
||||
import { TaskWorkspaceEntity } from 'src/modules/task/standard-objects/task.workspace-entity';
|
||||
import { extractFilenameFromPath } from 'src/engine/core-modules/file/utils/extract-file-id-from-path.utils';
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
type RichTextBlock = Record<string, any>;
|
||||
@ -57,19 +54,16 @@ export class ActivityQueryResultGetterHandler
|
||||
|
||||
imageUrl.searchParams.delete('token');
|
||||
|
||||
const signedPayload = this.fileService.encodeFileToken({
|
||||
filename: extractFilenameFromPath(imageProps.url),
|
||||
workspaceId: workspaceId,
|
||||
const signedPath = this.fileService.signFileUrl({
|
||||
url: imageProps.url.toString(),
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
return {
|
||||
...block,
|
||||
props: {
|
||||
...imageProps,
|
||||
url: buildSignedPath({
|
||||
path: imageUrl.toString(),
|
||||
token: signedPayload,
|
||||
}),
|
||||
url: signedPath,
|
||||
},
|
||||
};
|
||||
}),
|
||||
|
||||
@ -1,10 +1,7 @@
|
||||
import { buildSignedPath } from 'twenty-shared/utils';
|
||||
|
||||
import { QueryResultGetterHandlerInterface } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/interfaces/query-result-getter-handler.interface';
|
||||
|
||||
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
||||
import { AttachmentWorkspaceEntity } from 'src/modules/attachment/standard-objects/attachment.workspace-entity';
|
||||
import { extractFilenameFromPath } from 'src/engine/core-modules/file/utils/extract-file-id-from-path.utils';
|
||||
|
||||
export class AttachmentQueryResultGetterHandler
|
||||
implements QueryResultGetterHandlerInterface
|
||||
@ -19,14 +16,9 @@ export class AttachmentQueryResultGetterHandler
|
||||
return attachment;
|
||||
}
|
||||
|
||||
const signedPayload = this.fileService.encodeFileToken({
|
||||
filename: extractFilenameFromPath(attachment.fullPath),
|
||||
workspaceId: workspaceId,
|
||||
});
|
||||
|
||||
const signedPath = buildSignedPath({
|
||||
path: attachment.fullPath,
|
||||
token: signedPayload,
|
||||
const signedPath = this.fileService.signFileUrl({
|
||||
url: attachment.fullPath,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const fullPath = `${process.env.SERVER_URL}/files/${signedPath}`;
|
||||
|
||||
@ -1,10 +1,7 @@
|
||||
import { buildSignedPath } from 'twenty-shared/utils';
|
||||
|
||||
import { QueryResultGetterHandlerInterface } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/interfaces/query-result-getter-handler.interface';
|
||||
|
||||
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
||||
import { PersonWorkspaceEntity } from 'src/modules/person/standard-objects/person.workspace-entity';
|
||||
import { extractFilenameFromPath } from 'src/engine/core-modules/file/utils/extract-file-id-from-path.utils';
|
||||
|
||||
export class PersonQueryResultGetterHandler
|
||||
implements QueryResultGetterHandlerInterface
|
||||
@ -19,17 +16,14 @@ export class PersonQueryResultGetterHandler
|
||||
return person;
|
||||
}
|
||||
|
||||
const signedPayload = this.fileService.encodeFileToken({
|
||||
filename: extractFilenameFromPath(person.avatarUrl),
|
||||
const signedPath = this.fileService.signFileUrl({
|
||||
url: person.avatarUrl,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
return {
|
||||
...person,
|
||||
avatarUrl: buildSignedPath({
|
||||
path: person.avatarUrl,
|
||||
token: signedPayload,
|
||||
}),
|
||||
avatarUrl: signedPath,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,10 +1,7 @@
|
||||
import { buildSignedPath } from 'twenty-shared/utils';
|
||||
|
||||
import { QueryResultGetterHandlerInterface } from 'src/engine/api/graphql/workspace-query-runner/factories/query-result-getters/interfaces/query-result-getter-handler.interface';
|
||||
|
||||
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
||||
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
|
||||
import { extractFilenameFromPath } from 'src/engine/core-modules/file/utils/extract-file-id-from-path.utils';
|
||||
|
||||
export class WorkspaceMemberQueryResultGetterHandler
|
||||
implements QueryResultGetterHandlerInterface
|
||||
@ -19,17 +16,14 @@ export class WorkspaceMemberQueryResultGetterHandler
|
||||
return workspaceMember;
|
||||
}
|
||||
|
||||
const signedPayload = this.fileService.encodeFileToken({
|
||||
filename: extractFilenameFromPath(workspaceMember.avatarUrl),
|
||||
const signedPath = this.fileService.signFileUrl({
|
||||
url: workspaceMember.avatarUrl,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
return {
|
||||
...workspaceMember,
|
||||
avatarUrl: buildSignedPath({
|
||||
path: workspaceMember.avatarUrl,
|
||||
token: signedPayload,
|
||||
}),
|
||||
avatarUrl: signedPath,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,10 +4,13 @@ import { basename, dirname, extname } from 'path';
|
||||
import { Stream } from 'stream';
|
||||
|
||||
import { v4 as uuidV4 } from 'uuid';
|
||||
import { buildSignedPath } from 'twenty-shared/utils';
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
|
||||
import { FileStorageService } from 'src/engine/core-modules/file-storage/file-storage.service';
|
||||
import { JwtWrapperService } from 'src/engine/core-modules/jwt/services/jwt-wrapper.service';
|
||||
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
|
||||
import { extractFilenameFromPath } from 'src/engine/core-modules/file/utils/extract-file-id-from-path.utils';
|
||||
|
||||
export type FilePayloadToEncode = {
|
||||
workspaceId: string;
|
||||
@ -35,6 +38,20 @@ export class FileService {
|
||||
});
|
||||
}
|
||||
|
||||
signFileUrl({ url, workspaceId }: { url: string; workspaceId: string }) {
|
||||
if (!isNonEmptyString(url)) {
|
||||
return url;
|
||||
}
|
||||
|
||||
return buildSignedPath({
|
||||
path: url,
|
||||
token: this.encodeFileToken({
|
||||
filename: extractFilenameFromPath(url),
|
||||
workspaceId,
|
||||
}),
|
||||
});
|
||||
}
|
||||
|
||||
encodeFileToken(payloadToEncode: FilePayloadToEncode) {
|
||||
const fileTokenExpiresIn = this.twentyConfigService.get(
|
||||
'FILE_TOKEN_EXPIRES_IN',
|
||||
|
||||
@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { isNonEmptyString } from '@sniptt/guards';
|
||||
import { FieldMetadataType } from 'twenty-shared/types';
|
||||
import { buildSignedPath, getLogoUrlFromDomainName } from 'twenty-shared/utils';
|
||||
import { getLogoUrlFromDomainName } from 'twenty-shared/utils';
|
||||
import { Brackets, ObjectLiteral } from 'typeorm';
|
||||
import chunk from 'lodash.chunk';
|
||||
|
||||
@ -43,7 +43,6 @@ import { formatSearchTerms } from 'src/engine/core-modules/search/utils/format-s
|
||||
import { SearchArgs } from 'src/engine/core-modules/search/dtos/search-args';
|
||||
import { SearchResultConnectionDTO } from 'src/engine/core-modules/search/dtos/search-result-connection.dto';
|
||||
import { SearchResultEdgeDTO } from 'src/engine/core-modules/search/dtos/search-result-edge.dto';
|
||||
import { extractFilenameFromPath } from 'src/engine/core-modules/file/utils/extract-file-id-from-path.utils';
|
||||
import { SearchRecordDTO } from 'src/engine/core-modules/search/dtos/search-record.dto';
|
||||
|
||||
type LastRanks = { tsRankCD: number; tsRank: number };
|
||||
@ -366,15 +365,10 @@ export class SearchService {
|
||||
}
|
||||
|
||||
private getImageUrlWithToken(avatarUrl: string, workspaceId: string): string {
|
||||
const signedPayload = this.fileService.encodeFileToken({
|
||||
filename: extractFilenameFromPath(avatarUrl),
|
||||
return this.fileService.signFileUrl({
|
||||
url: avatarUrl,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
return buildSignedPath({
|
||||
path: avatarUrl,
|
||||
token: signedPayload,
|
||||
});
|
||||
}
|
||||
|
||||
getImageIdentifierValue(
|
||||
|
||||
@ -1,11 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { buildSignedPath } from 'twenty-shared/utils';
|
||||
|
||||
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
||||
import { DeletedWorkspaceMember } from 'src/engine/core-modules/user/dtos/deleted-workspace-member.dto';
|
||||
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
|
||||
import { extractFilenameFromPath } from 'src/engine/core-modules/file/utils/extract-file-id-from-path.utils';
|
||||
|
||||
@Injectable()
|
||||
export class DeletedWorkspaceMemberTranspiler {
|
||||
@ -18,15 +15,10 @@ export class DeletedWorkspaceMemberTranspiler {
|
||||
workspaceMember: Pick<WorkspaceMemberWorkspaceEntity, 'avatarUrl' | 'id'>;
|
||||
workspaceId: string;
|
||||
}): string {
|
||||
const signedPayload = this.fileService.encodeFileToken({
|
||||
filename: extractFilenameFromPath(workspaceMember.avatarUrl),
|
||||
return this.fileService.signFileUrl({
|
||||
url: workspaceMember.avatarUrl,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
return buildSignedPath({
|
||||
path: workspaceMember.avatarUrl,
|
||||
token: signedPayload,
|
||||
});
|
||||
}
|
||||
|
||||
toDeletedWorkspaceMemberDto(
|
||||
@ -40,15 +32,16 @@ export class DeletedWorkspaceMemberTranspiler {
|
||||
userEmail,
|
||||
} = workspaceMember;
|
||||
|
||||
const avatarUrl = userWorkspaceId
|
||||
? this.generateSignedAvatarUrl({
|
||||
workspaceId: userWorkspaceId,
|
||||
workspaceMember: {
|
||||
avatarUrl: avatarUrlFromEntity,
|
||||
id,
|
||||
},
|
||||
})
|
||||
: null;
|
||||
const avatarUrl =
|
||||
userWorkspaceId && avatarUrlFromEntity
|
||||
? this.generateSignedAvatarUrl({
|
||||
workspaceId: userWorkspaceId,
|
||||
workspaceMember: {
|
||||
avatarUrl: avatarUrlFromEntity,
|
||||
id,
|
||||
},
|
||||
})
|
||||
: null;
|
||||
|
||||
return {
|
||||
id,
|
||||
|
||||
@ -14,7 +14,6 @@ import crypto from 'crypto';
|
||||
import { GraphQLJSONObject } from 'graphql-type-json';
|
||||
import { FileUpload, GraphQLUpload } from 'graphql-upload';
|
||||
import { PermissionsOnAllObjectRecords } from 'twenty-shared/constants';
|
||||
import { buildSignedPath } from 'twenty-shared/utils';
|
||||
import { WorkspaceActivationStatus } from 'twenty-shared/workspace';
|
||||
import { In, Repository } from 'typeorm';
|
||||
|
||||
@ -31,7 +30,6 @@ import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/service
|
||||
import { SignedFileDTO } from 'src/engine/core-modules/file/file-upload/dtos/signed-file.dto';
|
||||
import { FileUploadService } from 'src/engine/core-modules/file/file-upload/services/file-upload.service';
|
||||
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
||||
import { extractFilenameFromPath } from 'src/engine/core-modules/file/utils/extract-file-id-from-path.utils';
|
||||
import { OnboardingStatus } from 'src/engine/core-modules/onboarding/enums/onboarding-status.enum';
|
||||
import {
|
||||
OnboardingService,
|
||||
@ -220,15 +218,10 @@ export class UserResolver {
|
||||
);
|
||||
|
||||
if (workspaceMember && workspaceMember.avatarUrl) {
|
||||
const avatarUrlToken = this.fileService.encodeFileToken({
|
||||
filename: extractFilenameFromPath(workspaceMember.avatarUrl),
|
||||
workspaceMember.avatarUrl = this.fileService.signFileUrl({
|
||||
url: workspaceMember.avatarUrl,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
|
||||
workspaceMember.avatarUrl = buildSignedPath({
|
||||
path: workspaceMember.avatarUrl,
|
||||
token: avatarUrlToken,
|
||||
});
|
||||
}
|
||||
|
||||
// TODO Refactor to be transpiled to WorkspaceMember instead
|
||||
@ -272,15 +265,10 @@ export class UserResolver {
|
||||
|
||||
for (const workspaceMemberEntity of workspaceMemberEntities) {
|
||||
if (workspaceMemberEntity.avatarUrl) {
|
||||
const avatarUrlToken = this.fileService.encodeFileToken({
|
||||
filename: extractFilenameFromPath(workspaceMemberEntity.avatarUrl),
|
||||
workspaceMemberEntity.avatarUrl = this.fileService.signFileUrl({
|
||||
url: workspaceMemberEntity.avatarUrl,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
|
||||
workspaceMemberEntity.avatarUrl = buildSignedPath({
|
||||
path: workspaceMemberEntity.avatarUrl,
|
||||
token: avatarUrlToken,
|
||||
});
|
||||
}
|
||||
|
||||
// TODO Refactor to be transpiled to WorkspaceMember instead
|
||||
|
||||
@ -1,8 +1,6 @@
|
||||
import { UseFilters, UseGuards } from '@nestjs/common';
|
||||
import { Args, Mutation, Query, Resolver } from '@nestjs/graphql';
|
||||
|
||||
import { buildSignedPath } from 'twenty-shared/utils';
|
||||
|
||||
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
||||
import { User } from 'src/engine/core-modules/user/user.entity';
|
||||
import { SendInvitationsOutput } from 'src/engine/core-modules/workspace-invitation/dtos/send-invitations.output';
|
||||
@ -16,7 +14,6 @@ import { UserAuthGuard } from 'src/engine/guards/user-auth.guard';
|
||||
import { WorkspaceAuthGuard } from 'src/engine/guards/workspace-auth.guard';
|
||||
import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants';
|
||||
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
|
||||
import { extractFilenameFromPath } from 'src/engine/core-modules/file/utils/extract-file-id-from-path.utils';
|
||||
|
||||
import { SendInvitationsInput } from './dtos/send-invitations.input';
|
||||
|
||||
@ -72,15 +69,10 @@ export class WorkspaceInvitationResolver {
|
||||
let workspaceLogoWithToken = '';
|
||||
|
||||
if (workspace.logo) {
|
||||
const signedPayload = this.fileService.encodeFileToken({
|
||||
filename: extractFilenameFromPath(workspace.logo),
|
||||
workspaceLogoWithToken = this.fileService.signFileUrl({
|
||||
url: workspace.logo,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
|
||||
workspaceLogoWithToken = buildSignedPath({
|
||||
path: workspace.logo,
|
||||
token: signedPayload,
|
||||
});
|
||||
}
|
||||
|
||||
return await this.workspaceInvitationService.sendInvitations(
|
||||
|
||||
@ -12,7 +12,7 @@ import { InjectRepository } from '@nestjs/typeorm';
|
||||
import assert from 'assert';
|
||||
|
||||
import { FileUpload, GraphQLUpload } from 'graphql-upload';
|
||||
import { buildSignedPath, isDefined } from 'twenty-shared/utils';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
import { FileFolder } from 'src/engine/core-modules/file/interfaces/file-folder.interface';
|
||||
@ -52,7 +52,6 @@ import { RoleDTO } from 'src/engine/metadata-modules/role/dtos/role.dto';
|
||||
import { RoleService } from 'src/engine/metadata-modules/role/role.service';
|
||||
import { GraphqlValidationExceptionFilter } from 'src/filters/graphql-validation-exception.filter';
|
||||
import { streamToBuffer } from 'src/utils/stream-to-buffer';
|
||||
import { extractFilenameFromPath } from 'src/engine/core-modules/file/utils/extract-file-id-from-path.utils';
|
||||
import { SignedFileDTO } from 'src/engine/core-modules/file/file-upload/dtos/signed-file.dto';
|
||||
|
||||
import { Workspace } from './workspace.entity';
|
||||
@ -229,15 +228,10 @@ export class WorkspaceResolver {
|
||||
async logo(@Parent() workspace: Workspace): Promise<string> {
|
||||
if (workspace.logo) {
|
||||
try {
|
||||
const signedPayload = this.fileService.encodeFileToken({
|
||||
filename: extractFilenameFromPath(workspace.logo),
|
||||
return this.fileService.signFileUrl({
|
||||
url: workspace.logo,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
|
||||
return buildSignedPath({
|
||||
path: workspace.logo,
|
||||
token: signedPayload,
|
||||
});
|
||||
} catch (e) {
|
||||
return workspace.logo;
|
||||
}
|
||||
@ -304,15 +298,10 @@ export class WorkspaceResolver {
|
||||
|
||||
if (workspace.logo) {
|
||||
try {
|
||||
const signedPayload = this.fileService.encodeFileToken({
|
||||
filename: extractFilenameFromPath(workspace.logo),
|
||||
workspaceLogoWithToken = this.fileService.signFileUrl({
|
||||
url: workspace.logo,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
|
||||
workspaceLogoWithToken = buildSignedPath({
|
||||
path: workspace.logo,
|
||||
token: signedPayload,
|
||||
});
|
||||
} catch (e) {
|
||||
workspaceLogoWithToken = workspace.logo;
|
||||
}
|
||||
|
||||
@ -8,12 +8,9 @@ import {
|
||||
Resolver,
|
||||
} from '@nestjs/graphql';
|
||||
|
||||
import { buildSignedPath } from 'twenty-shared/utils';
|
||||
|
||||
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
|
||||
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
|
||||
import { FileService } from 'src/engine/core-modules/file/services/file.service';
|
||||
import { extractFilenameFromPath } from 'src/engine/core-modules/file/utils/extract-file-id-from-path.utils';
|
||||
import { UserWorkspaceService } from 'src/engine/core-modules/user-workspace/user-workspace.service';
|
||||
import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto';
|
||||
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
|
||||
@ -194,15 +191,10 @@ export class RoleResolver {
|
||||
await Promise.all(
|
||||
workspaceMembers.map(async (workspaceMember) => {
|
||||
if (workspaceMember && workspaceMember.avatarUrl) {
|
||||
const avatarUrlToken = this.fileService.encodeFileToken({
|
||||
filename: extractFilenameFromPath(workspaceMember.avatarUrl),
|
||||
workspaceMember.avatarUrl = this.fileService.signFileUrl({
|
||||
url: workspaceMember.avatarUrl,
|
||||
workspaceId: workspace.id,
|
||||
});
|
||||
|
||||
workspaceMember.avatarUrl = buildSignedPath({
|
||||
path: workspaceMember.avatarUrl,
|
||||
token: avatarUrlToken,
|
||||
});
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user