From d988a10f973ffd2b7c515bd207f00b8a718cf41d Mon Sep 17 00:00:00 2001 From: Denis Bykhov Date: Fri, 31 Oct 2025 01:24:55 +0500 Subject: [PATCH] Improve pg security perfomance Signed-off-by: Denis Bykhov --- packages/postgres/CHANGELOG.json | 12 ++++++++++++ packages/postgres/CHANGELOG.md | 9 ++++++++- packages/postgres/package.json | 2 +- packages/postgres/src/storage.ts | 29 ++++++++++++++--------------- 4 files changed, 35 insertions(+), 17 deletions(-) diff --git a/packages/postgres/CHANGELOG.json b/packages/postgres/CHANGELOG.json index 745b279d08..b4f324d96e 100644 --- a/packages/postgres/CHANGELOG.json +++ b/packages/postgres/CHANGELOG.json @@ -1,6 +1,18 @@ { "name": "@hcengineering/postgres", "entries": [ + { + "version": "0.7.17", + "tag": "@hcengineering/postgres_v0.7.17", + "date": "Thu, 30 Oct 2025 20:24:36 GMT", + "comments": { + "patch": [ + { + "comment": "Improve security pg perfomance" + } + ] + } + }, { "version": "0.7.16", "tag": "@hcengineering/postgres_v0.7.16", diff --git a/packages/postgres/CHANGELOG.md b/packages/postgres/CHANGELOG.md index 4689f0f126..476de891a6 100644 --- a/packages/postgres/CHANGELOG.md +++ b/packages/postgres/CHANGELOG.md @@ -1,6 +1,13 @@ # Change Log - @hcengineering/postgres -This log was last generated on Wed, 29 Oct 2025 18:01:56 GMT and should not be manually modified. +This log was last generated on Thu, 30 Oct 2025 20:24:36 GMT and should not be manually modified. + +## 0.7.17 +Thu, 30 Oct 2025 20:24:36 GMT + +### Patches + +- Improve security pg perfomance ## 0.7.16 Wed, 29 Oct 2025 18:01:56 GMT diff --git a/packages/postgres/package.json b/packages/postgres/package.json index 0d330ddb62..beb443fa8d 100644 --- a/packages/postgres/package.json +++ b/packages/postgres/package.json @@ -1,6 +1,6 @@ { "name": "@hcengineering/postgres", - "version": "0.7.16", + "version": "0.7.17", "main": "lib/index.js", "svelte": "src/index.ts", "types": "types/index.d.ts", diff --git a/packages/postgres/src/storage.ts b/packages/postgres/src/storage.ts index 539aa61405..8d572576de 100644 --- a/packages/postgres/src/storage.ts +++ b/packages/postgres/src/storage.ts @@ -470,16 +470,16 @@ abstract class PostgresAdapterBase implements DbAdapter { const select = `SELECT ${this.getProjection(vars, domain, projection, joins, options?.associations)} FROM ${domain}` - const showArchived = shouldShowArchived(query, options) - const secJoin = this.addSecurity(_class, vars, query, showArchived, domain, ctx.contextData) - if (secJoin !== undefined) { - sqlChunks.push(secJoin) - } if (joins.length > 0) { sqlChunks.push(this.buildJoinString(vars, joins)) } sqlChunks.push(`WHERE ${this.buildQuery(vars, _class, domain, query, joins, options)}`) + const showArchived = shouldShowArchived(query, options) + const secJoin = this.addSecurity(_class, vars, query, showArchived, domain, ctx.contextData) + if (secJoin !== undefined) { + sqlChunks.push(secJoin) + } if (options?.sort !== undefined) { sqlChunks.push(this.buildOrder(_class, domain, options.sort, joins)) } @@ -491,18 +491,17 @@ abstract class PostgresAdapterBase implements DbAdapter { let total = options?.total === true ? 0 : -1 if (options?.total === true) { const pvars = new ValuesVariables() - const showArchived = shouldShowArchived(query, options) - const secJoin = this.addSecurity(_class, pvars, query, showArchived, domain, ctx.contextData) const totalChunks: string[] = [] - if (secJoin !== undefined) { - totalChunks.push(secJoin) - } const joins = this.buildJoin(_class, options?.lookup) if (joins.length > 0) { totalChunks.push(this.buildJoinString(pvars, joins)) } totalChunks.push(`WHERE ${this.buildQuery(pvars, _class, domain, query, joins, options)}`) - + const showArchived = shouldShowArchived(query, options) + const secJoin = this.addSecurity(_class, pvars, query, showArchived, domain, ctx.contextData) + if (secJoin !== undefined) { + totalChunks.push(secJoin) + } const totalReq = `SELECT COUNT(${domain}._id) as count FROM ${domain}` const totalSql = [totalReq, ...totalChunks].join(' ') const totalResult = await connection.execute(totalSql, pvars.getValues()) @@ -632,14 +631,14 @@ abstract class PostgresAdapterBase implements DbAdapter { const privateCheck = domain === DOMAIN_SPACE ? ' OR sec.private = false' : '' const archivedCheck = showArchived ? '' : ' AND sec.archived = false' const q = `(sec._id = '${core.space.Space}' OR sec."_class" = '${core.class.SystemSpace}' OR sec.members @> '{"${acc.uuid}"}'${privateCheck})${archivedCheck}` - const res = `INNER JOIN ${translateDomain(DOMAIN_SPACE)} AS sec ON sec._id = ${domain}.${key} AND sec."workspaceId" = ${vars.add(this.workspaceId, '::uuid')}` + const res = `EXISTS (SELECT 1 FROM ${translateDomain(DOMAIN_SPACE)} sec WHERE sec._id = ${domain}.${key} AND sec."workspaceId" = ${vars.add(this.workspaceId, '::uuid')} AND ${q})` const collabSec = getClassCollaborators(this.modelDb, this.hierarchy, _class) if (collabSec?.provideSecurity === true && [AccountRole.Guest, AccountRole.ReadOnlyGuest].includes(acc.role)) { - const collab = ` INNER JOIN ${translateDomain(DOMAIN_COLLABORATOR)} AS collab_sec ON collab_sec.collaborator = '${acc.uuid}' AND collab_sec."attachedTo" = ${domain}._id AND collab_sec."workspaceId" = ${vars.add(this.workspaceId, '::uuid')} OR ${q}` - return res + collab + const collab = `OR EXISTS (SELECT 1 FROM ${translateDomain(DOMAIN_COLLABORATOR)} collab_sec WHERE collab_sec."workspaceId" = ${vars.add(this.workspaceId, '::uuid')} AND collab_sec."attachedTo" = ${domain}._id AND collab_sec.collaborator = '${acc.uuid}')` + return `AND (${res} + ${collab})` } - return `${res} AND ${q}` + return `AND (${res})` } } }