fix: validate credential ownership in attribute sync update (#28873)
This commit is contained in:
+2
-1
@@ -63,6 +63,7 @@ export interface ISyncFormData {
|
||||
id: string;
|
||||
name: string;
|
||||
credentialId?: number;
|
||||
integration?: AttributeSyncIntegrations;
|
||||
enabled: boolean;
|
||||
organizationId: number;
|
||||
ruleId: string;
|
||||
@@ -138,7 +139,7 @@ export interface IIntegrationAttributeSyncUpdateParams {
|
||||
integrationAttributeSync: Omit<
|
||||
IntegrationAttributeSync,
|
||||
"attributeSyncRule" | "syncFieldMappings" | "integration"
|
||||
>;
|
||||
> & { integration?: AttributeSyncIntegrations };
|
||||
attributeSyncRule: AttributeSyncRule;
|
||||
fieldMappingsToCreate: Omit<AttributeSyncFieldMapping, "id">[];
|
||||
fieldMappingsToUpdate: AttributeSyncFieldMapping[];
|
||||
|
||||
+7
@@ -217,4 +217,11 @@ export class IntegrationAttributeSyncService {
|
||||
async getAllByCredentialId(credentialId: number) {
|
||||
return this.deps.integrationAttributeSyncRepository.getAllByCredentialId(credentialId);
|
||||
}
|
||||
|
||||
async validateCredentialBelongsToOrg(credentialId: number, organizationId: number) {
|
||||
return this.deps.credentialRepository.findByIdAndTeamId({
|
||||
id: credentialId,
|
||||
teamId: organizationId,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,8 @@
|
||||
import { getIntegrationAttributeSyncService } from "@calcom/ee/integration-attribute-sync/di/IntegrationAttributeSyncService.container";
|
||||
import {
|
||||
AttributeSyncIntegrations,
|
||||
type ISyncFormData,
|
||||
} from "@calcom/ee/integration-attribute-sync/repositories/IIntegrationAttributeSyncRepository";
|
||||
import {
|
||||
DuplicateAttributeWithinSyncError,
|
||||
DuplicateAttributeAcrossSyncsError,
|
||||
@@ -37,8 +41,29 @@ const updateAttributeSyncHandler = async ({ ctx, input }: UpdateAttributeSyncOpt
|
||||
throw new TRPCError({ code: "UNAUTHORIZED" });
|
||||
}
|
||||
|
||||
// Never trust user-supplied organizationId — override with authenticated user's org
|
||||
const safeInput: ISyncFormData = { ...input, organizationId: org.id };
|
||||
|
||||
// Validate credential belongs to the user's organization and derive integration type
|
||||
if (input.credentialId !== undefined) {
|
||||
const credential = await integrationAttributeSyncService.validateCredentialBelongsToOrg(
|
||||
input.credentialId,
|
||||
org.id
|
||||
);
|
||||
if (!credential) {
|
||||
throw new TRPCError({ code: "NOT_FOUND", message: "Credential not found" });
|
||||
}
|
||||
|
||||
const integrationValue = credential.app?.slug || credential.type;
|
||||
if (!Object.values(AttributeSyncIntegrations).includes(integrationValue as AttributeSyncIntegrations)) {
|
||||
throw new TRPCError({ code: "BAD_REQUEST", message: `Unsupported integration type: ${integrationValue}` });
|
||||
}
|
||||
|
||||
safeInput.integration = integrationValue as AttributeSyncIntegrations;
|
||||
}
|
||||
|
||||
try {
|
||||
await integrationAttributeSyncService.updateIncludeRulesAndMappings(input);
|
||||
await integrationAttributeSyncService.updateIncludeRulesAndMappings(safeInput);
|
||||
} catch (error) {
|
||||
if (error instanceof DuplicateAttributeWithinSyncError) {
|
||||
throw new TRPCError({
|
||||
|
||||
Reference in New Issue
Block a user