"use strict";
// SPDX-License-Identifier: AGPL-3.0-or-later
// Copyright (C) 2024-2026 Gracker (Chris)
// This file is part of SmartPerfetto. See LICENSE for details.
Object.defineProperty(exports, "__esModule", { value: true });
exports.hasRbacPermission = hasRbacPermission;
exports.sharesWorkspaceWithContext = sharesWorkspaceWithContext;
exports.canReadTraceResource = canReadTraceResource;
exports.canDownloadTraceResource = canDownloadTraceResource;
exports.canDeleteTraceResource = canDeleteTraceResource;
exports.canReadReportResource = canReadReportResource;
exports.canDeleteReportResource = canDeleteReportResource;
exports.canReadAnalysisResultResource = canReadAnalysisResultResource;
exports.canCreateAnalysisResultResource = canCreateAnalysisResultResource;
exports.canShareAnalysisResultResource = canShareAnalysisResultResource;
exports.canDeleteAnalysisResultResource = canDeleteAnalysisResultResource;
exports.sendForbidden = sendForbidden;
const resourceOwnership_1 = require("./resourceOwnership");
const ROLE_PERMISSIONS = {
    viewer: ['trace:read', 'report:read', 'analysis_result:read', 'comparison:read'],
    analyst: [
        'trace:read',
        'trace:write',
        'trace:download',
        'trace:delete_own',
        'agent:run',
        'report:read',
        'analysis_result:read',
        'analysis_result:create',
        'analysis_result:share',
        'comparison:create',
        'comparison:read',
        'codebase:read',
    ],
    workspace_admin: [
        'trace:read',
        'trace:write',
        'trace:download',
        'trace:delete_own',
        'trace:delete_any',
        'agent:run',
        'report:read',
        'report:delete',
        'analysis_result:read',
        'analysis_result:create',
        'analysis_result:share',
        'analysis_result:delete',
        'comparison:create',
        'comparison:read',
        'codebase:read',
        'codebase:manage',
        'provider:manage_workspace',
        'audit:read',
        'runtime:manage',
    ],
    org_admin: [
        'trace:read',
        'trace:write',
        'trace:download',
        'trace:delete_own',
        'trace:delete_any',
        'agent:run',
        'report:read',
        'report:delete',
        'analysis_result:read',
        'analysis_result:create',
        'analysis_result:share',
        'analysis_result:delete',
        'comparison:create',
        'comparison:read',
        'codebase:read',
        'codebase:manage',
        'codebase:admin',
        'provider:manage_workspace',
        'provider:manage_org',
        'audit:read',
        'runtime:manage',
    ],
};
const SCOPE_IMPLICATIONS = {
    'trace:delete_own': ['trace:write', 'trace:delete'],
    'trace:delete_any': ['trace:delete:any'],
    'report:delete': ['report:write'],
    'analysis_result:share': ['analysis_result:write'],
    'analysis_result:delete': ['analysis_result:write', 'analysis_result:delete_any'],
};
function hasRbacPermission(context, permission) {
    if (context.scopes.includes('*'))
        return true;
    if (context.scopes.includes(permission))
        return true;
    if (SCOPE_IMPLICATIONS[permission]?.some(scope => context.scopes.includes(scope)))
        return true;
    return context.roles.some(role => ROLE_PERMISSIONS[role]?.includes(permission));
}
function sharesWorkspaceWithContext(resource, context) {
    const owner = (0, resourceOwnership_1.normalizeResourceOwner)(resource);
    return owner.tenantId === context.tenantId && owner.workspaceId === context.workspaceId;
}
function canReadTraceResource(resource, context) {
    return sharesWorkspaceWithContext(resource, context) && hasRbacPermission(context, 'trace:read');
}
function canDownloadTraceResource(resource, context) {
    return sharesWorkspaceWithContext(resource, context)
        && (hasRbacPermission(context, 'trace:download') || hasRbacPermission(context, 'trace:read'));
}
function canDeleteTraceResource(resource, context) {
    if (!sharesWorkspaceWithContext(resource, context))
        return false;
    if (hasRbacPermission(context, 'trace:delete_any'))
        return true;
    return (0, resourceOwnership_1.isOwnedByContext)(resource, context) && hasRbacPermission(context, 'trace:delete_own');
}
function canReadReportResource(resource, context) {
    return sharesWorkspaceWithContext(resource, context) && hasRbacPermission(context, 'report:read');
}
function canDeleteReportResource(resource, context) {
    if (!sharesWorkspaceWithContext(resource, context))
        return false;
    if (hasRbacPermission(context, 'report:delete'))
        return true;
    return (0, resourceOwnership_1.isOwnedByContext)(resource, context) && hasRbacPermission(context, 'report:delete');
}
function canReadAnalysisResultResource(resource, context) {
    if (!sharesWorkspaceWithContext(resource, context))
        return false;
    if (!hasRbacPermission(context, 'analysis_result:read'))
        return false;
    if (resource?.visibility === 'workspace')
        return true;
    return (0, resourceOwnership_1.isOwnedByContext)(resource, context);
}
function canCreateAnalysisResultResource(context) {
    return hasRbacPermission(context, 'analysis_result:create');
}
function canShareAnalysisResultResource(resource, context) {
    if (!sharesWorkspaceWithContext(resource, context))
        return false;
    if (!hasRbacPermission(context, 'analysis_result:share'))
        return false;
    if ((0, resourceOwnership_1.isOwnedByContext)(resource, context))
        return true;
    return hasRbacPermission(context, 'analysis_result:delete');
}
function canDeleteAnalysisResultResource(resource, context) {
    if (!sharesWorkspaceWithContext(resource, context))
        return false;
    if (hasRbacPermission(context, 'analysis_result:delete'))
        return true;
    return false;
}
function sendForbidden(res, details = 'Forbidden') {
    return res.status(403).json({
        success: false,
        error: 'Forbidden',
        details,
    });
}
//# sourceMappingURL=rbac.js.map