mirror of
https://github.com/hcengineering/platform.git
synced 2024-12-28 14:03:55 +03:00
Disable owner space security (#2705)
Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
parent
7b14204aab
commit
f0bcbd1c82
@ -13,10 +13,10 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import { AccountRole } from '@hcengineering/core'
|
||||
import { Builder } from '@hcengineering/model'
|
||||
import core from './component'
|
||||
import {
|
||||
TFullTextSearchContext,
|
||||
TArrOf,
|
||||
TAttachedDoc,
|
||||
TAttribute,
|
||||
@ -30,6 +30,8 @@ import {
|
||||
TEnum,
|
||||
TEnumOf,
|
||||
TFulltextData,
|
||||
TFullTextSearchContext,
|
||||
TIndexStageState,
|
||||
TInterface,
|
||||
TMixin,
|
||||
TObj,
|
||||
@ -46,8 +48,7 @@ import {
|
||||
TTypeRelatedDocument,
|
||||
TTypeString,
|
||||
TTypeTimestamp,
|
||||
TVersion,
|
||||
TIndexStageState
|
||||
TVersion
|
||||
} from './core'
|
||||
import { TAccount, TSpace } from './security'
|
||||
import { TUserStatus } from './transient'
|
||||
@ -105,4 +106,14 @@ export function createModel (builder: Builder): void {
|
||||
TConfiguration,
|
||||
TConfigurationElement
|
||||
)
|
||||
|
||||
builder.createDoc(
|
||||
core.class.Account,
|
||||
core.space.Model,
|
||||
{
|
||||
email: 'anticrm@hc.engineering',
|
||||
role: AccountRole.Owner
|
||||
},
|
||||
core.account.System
|
||||
)
|
||||
}
|
||||
|
@ -13,28 +13,9 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import core, { AccountRole, Client, TxOperations } from '@hcengineering/core'
|
||||
import { MigrateOperation, MigrationClient, MigrationUpgradeClient } from '@hcengineering/model'
|
||||
|
||||
export const coreOperation: MigrateOperation = {
|
||||
async migrate (client: MigrationClient): Promise<void> {},
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {
|
||||
await createSystemAccount(client)
|
||||
}
|
||||
}
|
||||
|
||||
async function createSystemAccount (client: Client): Promise<void> {
|
||||
const current = await client.findOne(core.class.Account, { _id: core.account.System })
|
||||
if (current === undefined) {
|
||||
const txop = new TxOperations(client, core.account.System)
|
||||
await txop.createDoc(
|
||||
core.class.Account,
|
||||
core.space.Model,
|
||||
{
|
||||
email: 'anticrm@hc.engineering',
|
||||
role: AccountRole.Owner
|
||||
},
|
||||
core.account.System
|
||||
)
|
||||
}
|
||||
async upgrade (client: MigrationUpgradeClient): Promise<void> {}
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ export class PrivateMiddleware extends BaseMiddleware implements Middleware {
|
||||
const txCUD = tx as TxCUD<Doc>
|
||||
const domain = this.storage.hierarchy.getDomain(txCUD.objectClass)
|
||||
if (this.targetDomains.includes(domain)) {
|
||||
const account = await getUser(this.storage, ctx)
|
||||
const account = (await getUser(this.storage, ctx))._id
|
||||
if (account !== tx.modifiedBy && account !== core.account.System) {
|
||||
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
|
||||
}
|
||||
@ -74,7 +74,7 @@ export class PrivateMiddleware extends BaseMiddleware implements Middleware {
|
||||
const domain = this.storage.hierarchy.getDomain(_class)
|
||||
if (this.targetDomains.includes(domain)) {
|
||||
const account = await getUser(this.storage, ctx)
|
||||
if (account !== core.account.System) {
|
||||
if (account._id !== core.account.System) {
|
||||
newQuery = {
|
||||
...query,
|
||||
modifiedBy: account
|
||||
@ -95,7 +95,7 @@ export class PrivateMiddleware extends BaseMiddleware implements Middleware {
|
||||
async isAvailable (ctx: SessionContext, doc: Doc): Promise<boolean> {
|
||||
const domain = this.storage.hierarchy.getDomain(doc._class)
|
||||
if (!this.targetDomains.includes(domain)) return true
|
||||
const account = await getUser(this.storage, ctx)
|
||||
const account = (await getUser(this.storage, ctx))._id
|
||||
return doc.modifiedBy === account || account === core.account.System
|
||||
}
|
||||
|
||||
|
@ -39,7 +39,7 @@ import core, {
|
||||
import platform, { PlatformError, Severity, Status } from '@hcengineering/platform'
|
||||
import { Middleware, SessionContext, TxMiddlewareResult } from '@hcengineering/server-core'
|
||||
import { BaseMiddleware } from './base'
|
||||
import { getUser, mergeTargets } from './utils'
|
||||
import { getUser, isOwner, mergeTargets } from './utils'
|
||||
|
||||
/**
|
||||
* @public
|
||||
@ -241,8 +241,8 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
||||
const space = this.privateSpaces[tx.objectSpace]
|
||||
if (space !== undefined) {
|
||||
const account = await getUser(this.storage, ctx)
|
||||
if (account !== core.account.System) {
|
||||
const allowed = this.allowedSpaces[account]
|
||||
if (!isOwner(account)) {
|
||||
const allowed = this.allowedSpaces[account._id]
|
||||
if (allowed === undefined || !allowed.includes(isSpace ? (cudTx.objectId as Ref<Space>) : tx.objectSpace)) {
|
||||
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
|
||||
}
|
||||
@ -255,22 +255,21 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
||||
return [res[0], res[1], mergeTargets(targets, res[2])]
|
||||
}
|
||||
|
||||
private async getAllAllowedSpaces (ctx: SessionContext): Promise<Ref<Space>[]> {
|
||||
private async getAllAllowedSpaces (account: Account): Promise<Ref<Space>[]> {
|
||||
let userSpaces: Ref<Space>[] = []
|
||||
try {
|
||||
const account = await getUser(this.storage, ctx)
|
||||
userSpaces = this.allowedSpaces[account] ?? []
|
||||
return [...userSpaces, account as string as Ref<Space>, ...this.publicSpaces, ...this.systemSpaces]
|
||||
userSpaces = this.allowedSpaces[account._id] ?? []
|
||||
return [...userSpaces, account._id as string as Ref<Space>, ...this.publicSpaces, ...this.systemSpaces]
|
||||
} catch {
|
||||
return [...this.publicSpaces, ...this.systemSpaces]
|
||||
}
|
||||
}
|
||||
|
||||
private async mergeQuery<T extends Doc>(
|
||||
ctx: SessionContext,
|
||||
account: Account,
|
||||
query: ObjQueryType<T['space']>
|
||||
): Promise<ObjQueryType<T['space']>> {
|
||||
const spaces = await this.getAllAllowedSpaces(ctx)
|
||||
const spaces = await this.getAllAllowedSpaces(account)
|
||||
if (typeof query === 'string') {
|
||||
if (!spaces.includes(query)) {
|
||||
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
|
||||
@ -290,17 +289,22 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
||||
options?: FindOptions<T>
|
||||
): Promise<FindResult<T>> {
|
||||
const newQuery = query
|
||||
if (query.space !== undefined) {
|
||||
newQuery.space = await this.mergeQuery(ctx, query.space)
|
||||
} else {
|
||||
const spaces = await this.getAllAllowedSpaces(ctx)
|
||||
newQuery.space = { $in: spaces }
|
||||
const account = await getUser(this.storage, ctx)
|
||||
if (!isOwner(account)) {
|
||||
if (query.space !== undefined) {
|
||||
newQuery.space = await this.mergeQuery(account, query.space)
|
||||
} else {
|
||||
const spaces = await this.getAllAllowedSpaces(account)
|
||||
newQuery.space = { $in: spaces }
|
||||
}
|
||||
}
|
||||
const findResult = await this.provideFindAll(ctx, _class, newQuery, options)
|
||||
if (options?.lookup !== undefined) {
|
||||
for (const object of findResult) {
|
||||
if (object.$lookup !== undefined) {
|
||||
await this.filterLookup(ctx, object.$lookup)
|
||||
if (!isOwner(account)) {
|
||||
if (options?.lookup !== undefined) {
|
||||
for (const object of findResult) {
|
||||
if (object.$lookup !== undefined) {
|
||||
await this.filterLookup(ctx, object.$lookup)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -310,8 +314,8 @@ export class SpaceSecurityMiddleware extends BaseMiddleware implements Middlewar
|
||||
async isUnavailable (ctx: SessionContext, space: Ref<Space>): Promise<boolean> {
|
||||
if (this.privateSpaces[space] === undefined) return false
|
||||
const account = await getUser(this.storage, ctx)
|
||||
if (account === core.account.System) return false
|
||||
return !this.allowedSpaces[account]?.includes(space)
|
||||
if (isOwner(account)) return false
|
||||
return !this.allowedSpaces[account._id]?.includes(space)
|
||||
}
|
||||
|
||||
async filterLookup<T extends Doc>(ctx: SessionContext, lookup: LookupData<T>): Promise<void> {
|
||||
|
@ -13,7 +13,7 @@
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
import core, { Account, Ref, ServerStorage } from '@hcengineering/core'
|
||||
import core, { Account, AccountRole, ServerStorage } from '@hcengineering/core'
|
||||
import platform, { PlatformError, Severity, Status } from '@hcengineering/platform'
|
||||
import { SessionContext } from '@hcengineering/server-core'
|
||||
|
||||
@ -29,13 +29,28 @@ export function mergeTargets (current: string[] | undefined, prev: string[] | un
|
||||
return res
|
||||
}
|
||||
|
||||
export async function getUser (storage: ServerStorage, ctx: SessionContext): Promise<Ref<Account>> {
|
||||
export async function getUser (storage: ServerStorage, ctx: SessionContext): Promise<Account> {
|
||||
if (ctx.userEmail === undefined) {
|
||||
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
|
||||
}
|
||||
const account = (await storage.modelDb.findAll(core.class.Account, { email: ctx.userEmail }))[0]
|
||||
if (account === undefined) {
|
||||
if (ctx.userEmail === 'anticrm@hc.engineering') {
|
||||
return {
|
||||
_id: core.account.System,
|
||||
_class: core.class.Account,
|
||||
role: AccountRole.Owner,
|
||||
email: 'anticrm@hc.engineering',
|
||||
space: core.space.Model,
|
||||
modifiedBy: core.account.System,
|
||||
modifiedOn: 0
|
||||
}
|
||||
}
|
||||
throw new PlatformError(new Status(Severity.ERROR, platform.status.Forbidden, {}))
|
||||
}
|
||||
return account._id
|
||||
return account
|
||||
}
|
||||
|
||||
export function isOwner (account: Account): boolean {
|
||||
return account.role === AccountRole.Owner || account._id === core.account.System
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user