Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions common/config/rush/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions foundations/server/packages/middleware/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
},
"dependencies": {
"@hcengineering/core": "workspace:^0.7.24",
"@hcengineering/contact": "workspace:^0.7.0",
"@hcengineering/platform": "workspace:^0.7.19",
"@hcengineering/server-core": "workspace:^0.7.18",
"@hcengineering/query": "workspace:^0.7.17",
Expand Down
32 changes: 20 additions & 12 deletions foundations/server/packages/middleware/src/guestPermissions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
type TxMiddlewareResult
} from '@hcengineering/server-core'
import core, {
type Account,
AccountRole,
type Doc,
hasAccountRole,
Expand All @@ -19,6 +20,7 @@ import core, {
type TxUpdateDoc
} from '@hcengineering/core'
import platform, { PlatformError, Severity, Status } from '@hcengineering/platform'
import contact, { type Person } from '@hcengineering/contact'

export class GuestPermissionsMiddleware extends BaseMiddleware implements Middleware {
static async create (
Expand All @@ -40,44 +42,44 @@ export class GuestPermissionsMiddleware extends BaseMiddleware implements Middle
}

for (const tx of txes) {
this.processTx(ctx, tx)
await this.processTx(ctx, tx)
}

return await this.provideTx(ctx, txes)
}

private processTx (ctx: MeasureContext<SessionData>, tx: Tx): void {
private async processTx (ctx: MeasureContext<SessionData>, tx: Tx): Promise<void> {
const h = this.context.hierarchy
if (tx._class === core.class.TxApplyIf) {
const applyTx = tx as TxApplyIf
for (const t of applyTx.txes) {
this.processTx(ctx, t)
await this.processTx(ctx, t)
}
return
}
if (TxProcessor.isExtendsCUD(tx._class)) {
const socialIds = ctx.contextData.account.socialIds
const { account } = ctx.contextData
const cudTx = tx as TxCUD<Doc>
const isSpace = h.isDerived(cudTx.objectClass, core.class.Space)
if (isSpace) {
if (this.isForbiddenSpaceTx(cudTx as TxCUD<Space>, socialIds)) {
if (await this.isForbiddenSpaceTx(ctx, cudTx as TxCUD<Space>, account)) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
}
} else if (cudTx.space !== core.space.DerivedTx && this.isForbiddenTx(cudTx, socialIds)) {
} else if (cudTx.space !== core.space.DerivedTx && (await this.isForbiddenTx(ctx, cudTx, account))) {
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
}
}
}

private isForbiddenTx (tx: TxCUD<Doc>, socialIds: PersonId[]): boolean {
private async isForbiddenTx (ctx: MeasureContext, tx: TxCUD<Doc>, account: Account): Promise<boolean> {
if (tx._class === core.class.TxMixin) return false
return !this.hasMixinAccessLevel(tx, socialIds)
return !(await this.hasMixinAccessLevel(ctx, tx, account))
}

private isForbiddenSpaceTx (tx: TxCUD<Space>, socialIds: PersonId[]): boolean {
private async isForbiddenSpaceTx (ctx: MeasureContext, tx: TxCUD<Space>, account: Account): Promise<boolean> {
if (tx._class === core.class.TxRemoveDoc) return true
if (tx._class === core.class.TxCreateDoc) {
return !this.hasMixinAccessLevel(tx, socialIds)
return !(await this.hasMixinAccessLevel(ctx, tx, account))
}
if (tx._class === core.class.TxUpdateDoc) {
const updateTx = tx as TxUpdateDoc<Space>
Expand All @@ -93,7 +95,7 @@ export class GuestPermissionsMiddleware extends BaseMiddleware implements Middle
return false
}

private hasMixinAccessLevel (tx: TxCUD<Doc>, socialIds: PersonId[]): boolean {
private async hasMixinAccessLevel (ctx: MeasureContext, tx: TxCUD<Doc>, account: Account): Promise<boolean> {
const h = this.context.hierarchy
const accessLevelMixin = h.classHierarchyMixin(tx.objectClass, core.mixin.TxAccessLevel)
if (accessLevelMixin === undefined) return false
Expand All @@ -104,9 +106,15 @@ export class GuestPermissionsMiddleware extends BaseMiddleware implements Middle
return accessLevelMixin.removeAccessLevel === AccountRole.Guest
}
if (tx._class === core.class.TxUpdateDoc) {
if (accessLevelMixin.isIdentity === true && socialIds.includes(tx.objectId as unknown as PersonId)) {
if (accessLevelMixin.isIdentity === true && account.socialIds.includes(tx.objectId as unknown as PersonId)) {
return true
}
if (accessLevelMixin.isIdentity === true && h.isDerived(tx.objectClass, contact.class.Person)) {
const person = (await this.findAll(ctx, tx.objectClass, { _id: tx.objectId }, { limit: 1 }))[0] as
| Person
| undefined
return person?.personUuid === account.uuid
}
return accessLevelMixin.updateAccessLevel === AccountRole.Guest
}
return false
Expand Down
3 changes: 2 additions & 1 deletion models/contact/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,8 @@ export function createModel (builder: Builder): void {
})

builder.mixin(contact.class.Person, core.class.Class, core.mixin.TxAccessLevel, {
createAccessLevel: AccountRole.Guest
createAccessLevel: AccountRole.Guest,
isIdentity: true
})

builder.mixin(contact.class.SocialIdentity, core.class.Class, core.mixin.TxAccessLevel, {
Expand Down
Loading