Fix security ()

This commit is contained in:
Denis Bykhov 2024-12-10 08:04:40 +05:00 committed by GitHub
parent 56896badd9
commit 1ff7141bc1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 35 additions and 14 deletions
server

View File

@ -62,6 +62,9 @@ export interface ServerFindOptions<T extends Doc> extends FindOptions<T> {
domain: Domain
}
// using for join query security
allowedSpaces?: Ref<Space>[]
// Optional measure context, for server side operations
ctx?: MeasureContext
}

View File

@ -22,7 +22,7 @@ import {
type MeasureContext,
Ref
} from '@hcengineering/core'
import { BaseMiddleware, Middleware, type PipelineContext } from '@hcengineering/server-core'
import { BaseMiddleware, Middleware, ServerFindOptions, type PipelineContext } from '@hcengineering/server-core'
import { deepEqual } from 'fast-equals'
interface Query {
@ -45,7 +45,7 @@ export class QueryJoiner {
ctx: MeasureContext,
_class: Ref<Class<T>>,
query: DocumentQuery<T>,
options?: FindOptions<T>
options?: ServerFindOptions<T>
): Promise<FindResult<T>> {
// Will find a query or add + 1 to callbacks
const q = this.findQuery(_class, query, options) ?? this.createQuery(_class, query, options)
@ -131,7 +131,7 @@ export class QueryJoinMiddleware extends BaseMiddleware implements Middleware {
ctx: MeasureContext,
_class: Ref<Class<T>>,
query: DocumentQuery<T>,
options?: FindOptions<T>
options?: ServerFindOptions<T>
): Promise<FindResult<T>> {
// Will find a query or add + 1 to callbacks
return this.joiner.findAll(ctx, _class, query, options)

View File

@ -21,7 +21,6 @@ import core, {
Doc,
DocumentQuery,
Domain,
FindOptions,
FindResult,
LookupData,
MeasureContext,
@ -47,7 +46,13 @@ import core, {
type SessionData
} from '@hcengineering/core'
import platform, { PlatformError, Severity, Status } from '@hcengineering/platform'
import { BaseMiddleware, Middleware, TxMiddlewareResult, type PipelineContext } from '@hcengineering/server-core'
import {
BaseMiddleware,
Middleware,
ServerFindOptions,
TxMiddlewareResult,
type PipelineContext
} from '@hcengineering/server-core'
import { isOwner, isSystem } from './utils'
type SpaceWithMembers = Pick<Space, '_id' | 'members' | 'private' | '_class'>
@ -416,6 +421,14 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
}
}
ctx.contextData.broadcast.targets.spaceSec = (tx) => {
const space = this.spacesMap.get(tx.objectSpace)
if (space === undefined) return undefined
if (this.systemSpaces.has(space._id) || this.mainSpaces.includes(space._id)) return undefined
return space.members.length === 0 ? undefined : this.getTargets(space?.members)
}
await this.next?.handleBroadcast(ctx)
}
@ -497,7 +510,7 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
ctx: MeasureContext<SessionData>,
_class: Ref<Class<T>>,
query: DocumentQuery<T>,
options?: FindOptions<T>
options?: ServerFindOptions<T>
): Promise<FindResult<T>> {
await this.init(ctx)
@ -509,12 +522,7 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
let clientFilterSpaces: Set<Ref<Space>> | undefined
if (
!this.skipFindCheck &&
!isSystem(account, ctx) &&
account.role !== AccountRole.DocGuest &&
domain !== DOMAIN_MODEL
) {
if (!isSystem(account, ctx) && account.role !== AccountRole.DocGuest && domain !== DOMAIN_MODEL) {
if (!isOwner(account, ctx) || !isSpace) {
if (query[field] !== undefined) {
const res = await this.mergeQuery(ctx, account, query[field], domain, isSpace)
@ -536,6 +544,11 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
delete (newQuery as any)[field]
} else if (spaces.result.length === 1) {
;(newQuery as any)[field] = spaces.result[0]
if (options !== undefined) {
options.allowedSpaces = spaces.result
} else {
options = { allowedSpaces: spaces.result }
}
} else {
// Check if spaces > 85% of all domain spaces, in this case return all and filter on client.
if (spaces.result.length / spaces.domainSpaces.size > 0.85 && options?.limit === undefined) {
@ -543,17 +556,22 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
delete newQuery.space
} else {
;(newQuery as any)[field] = { $in: spaces.result }
if (options !== undefined) {
options.allowedSpaces = spaces.result
} else {
options = { allowedSpaces: spaces.result }
}
}
}
}
}
}
let findResult = await this.provideFindAll(ctx, _class, newQuery, options)
let findResult = await this.provideFindAll(ctx, _class, !this.skipFindCheck ? newQuery : query, options)
if (clientFilterSpaces !== undefined) {
const cfs = clientFilterSpaces
findResult = toFindResult(
findResult.filter((it) => cfs.has(it.space)),
findResult.filter((it) => cfs.has((it as any)[field])),
findResult.total,
findResult.lookupMap
)