feat: Implement company code validation in flow management

- Enhanced the FlowController to include user company code validation for flow definitions, ensuring that users can only access and modify flows belonging to their company.
- Updated the FlowDefinitionService to accept company code as a parameter for create, update, and delete operations, enforcing ownership checks.
- Introduced sanitization methods in FlowConditionParser to prevent SQL injection for column and table names.
- Modified the FlowDataMoveService to validate table names and column names during data movement operations, enhancing security.
- Updated the frontend components to support batch data movement with proper validation and error handling.
This commit is contained in:
kjs
2026-03-03 10:38:38 +09:00
parent e2d88f01e3
commit fd5c61b12a
9 changed files with 207 additions and 56 deletions

View File

@@ -19,7 +19,8 @@ export class FlowDefinitionService {
userId: string,
userCompanyCode?: string
): Promise<FlowDefinition> {
const companyCode = request.companyCode || userCompanyCode || "*";
// 클라이언트 입력(request.companyCode) 무시 - 인증된 사용자의 회사 코드만 사용
const companyCode = userCompanyCode || "*";
console.log("🔥 flowDefinitionService.create called with:", {
name: request.name,
@@ -118,10 +119,21 @@ export class FlowDefinitionService {
/**
* 플로우 정의 단일 조회
* companyCode가 전달되면 해당 회사 소유 플로우만 반환
*/
async findById(id: number): Promise<FlowDefinition | null> {
const query = "SELECT * FROM flow_definition WHERE id = $1";
const result = await db.query(query, [id]);
async findById(id: number, companyCode?: string): Promise<FlowDefinition | null> {
let query: string;
let params: any[];
if (companyCode && companyCode !== "*") {
query = "SELECT * FROM flow_definition WHERE id = $1 AND company_code = $2";
params = [id, companyCode];
} else {
query = "SELECT * FROM flow_definition WHERE id = $1";
params = [id];
}
const result = await db.query(query, params);
if (result.length === 0) {
return null;
@@ -132,10 +144,12 @@ export class FlowDefinitionService {
/**
* 플로우 정의 수정
* companyCode가 전달되면 해당 회사 소유 플로우만 수정 가능
*/
async update(
id: number,
request: UpdateFlowDefinitionRequest
request: UpdateFlowDefinitionRequest,
companyCode?: string
): Promise<FlowDefinition | null> {
const fields: string[] = [];
const params: any[] = [];
@@ -160,18 +174,27 @@ export class FlowDefinitionService {
}
if (fields.length === 0) {
return this.findById(id);
return this.findById(id, companyCode);
}
fields.push(`updated_at = NOW()`);
let whereClause = `WHERE id = $${paramIndex}`;
params.push(id);
paramIndex++;
if (companyCode && companyCode !== "*") {
whereClause += ` AND company_code = $${paramIndex}`;
params.push(companyCode);
paramIndex++;
}
const query = `
UPDATE flow_definition
SET ${fields.join(", ")}
WHERE id = $${paramIndex}
${whereClause}
RETURNING *
`;
params.push(id);
const result = await db.query(query, params);
@@ -184,10 +207,21 @@ export class FlowDefinitionService {
/**
* 플로우 정의 삭제
* companyCode가 전달되면 해당 회사 소유 플로우만 삭제 가능
*/
async delete(id: number): Promise<boolean> {
const query = "DELETE FROM flow_definition WHERE id = $1 RETURNING id";
const result = await db.query(query, [id]);
async delete(id: number, companyCode?: string): Promise<boolean> {
let query: string;
let params: any[];
if (companyCode && companyCode !== "*") {
query = "DELETE FROM flow_definition WHERE id = $1 AND company_code = $2 RETURNING id";
params = [id, companyCode];
} else {
query = "DELETE FROM flow_definition WHERE id = $1 RETURNING id";
params = [id];
}
const result = await db.query(query, params);
return result.length > 0;
}