@backstage-community/plugin-rbac-backend
Version:
185 lines (181 loc) • 6.05 kB
JavaScript
;
var errors = require('@backstage/errors');
const CONDITIONAL_TABLE = "role-condition-policies";
class DataBaseConditionalStorage {
constructor(knex) {
this.knex = knex;
}
async filterConditions(roleEntityRef, pluginId, resourceType, actions, permissionNames, trx) {
const db = trx ?? this.knex;
const daoRaws = await db.table(CONDITIONAL_TABLE).where((builder) => {
if (pluginId) {
builder.where("pluginId", pluginId);
}
if (resourceType) {
builder.where("resourceType", resourceType);
}
if (roleEntityRef) {
if (Array.isArray(roleEntityRef)) {
builder.whereIn("roleEntityRef", roleEntityRef);
} else {
builder.where("roleEntityRef", roleEntityRef);
}
}
});
let conditions = [];
if (daoRaws) {
conditions = daoRaws.map((dao) => this.daoToConditionalDecision(dao));
}
if (permissionNames && permissionNames.length > 0) {
conditions = conditions.filter((condition) => {
return permissionNames.every(
(permissionName) => condition.permissionMapping.map((permInfo) => permInfo.name).includes(permissionName)
);
});
}
if (actions && actions.length > 0) {
conditions = conditions.filter((condition) => {
return actions.every(
(action) => condition.permissionMapping.map((permInfo) => permInfo.action).includes(action)
);
});
}
return conditions;
}
async createCondition(conditionalDecision, idsToExclude) {
await this.checkConflictedConditions(
conditionalDecision.roleEntityRef,
conditionalDecision.resourceType,
conditionalDecision.pluginId,
conditionalDecision.permissionMapping.map((permInfo) => permInfo.action),
void 0,
void 0,
idsToExclude
);
const conditionRaw = this.toDAO(conditionalDecision);
const result = await this.knex.table(CONDITIONAL_TABLE).insert(conditionRaw).returning("id");
if (result && result?.length > 0) {
return result[0].id;
}
throw new Error(`Failed to create the condition.`);
}
async checkConflictedConditions(roleEntityRef, resourceType, pluginId, queryConditionActions, idToExclude, trx, idsToExclude) {
const db = trx ?? this.knex;
let conditionsForTheSameResource = await this.filterConditions(
roleEntityRef,
pluginId,
resourceType,
void 0,
void 0,
db
);
conditionsForTheSameResource = conditionsForTheSameResource.filter(
(c) => c.id !== idToExclude && (idsToExclude === void 0 || c.id === void 0 || !idsToExclude.has(c.id))
);
if (conditionsForTheSameResource) {
const conflictedCondition = conditionsForTheSameResource.find(
(condition) => {
const conditionActions = condition.permissionMapping.map(
(permInfo) => permInfo.action
);
return queryConditionActions.some(
(action) => conditionActions.includes(action)
);
}
);
if (conflictedCondition) {
const conflictedActions = queryConditionActions.filter(
(action) => conflictedCondition.permissionMapping.some((p) => p.action === action)
);
throw new errors.ConflictError(
`Found condition with conflicted permission action '${JSON.stringify(
conflictedActions
)}'. Role could have multiple conditions for the same resource type '${conflictedCondition.resourceType}', but with different permission action sets.`
);
}
}
}
async getCondition(id, trx) {
const db = trx ?? this.knex;
const daoRaw = await db.table(CONDITIONAL_TABLE).where("id", id).first();
if (daoRaw) {
return this.daoToConditionalDecision(daoRaw);
}
return void 0;
}
async deleteCondition(id) {
const condition = await this.getCondition(id);
if (!condition) {
throw new errors.NotFoundError(`Condition with id ${id} was not found`);
}
await this.knex?.table(CONDITIONAL_TABLE).delete().whereIn("id", [id]);
}
async updateCondition(id, conditionalDecision, trx, idsToExclude) {
const db = trx ?? this.knex;
const condition = await this.getCondition(id, db);
if (!condition) {
throw new errors.NotFoundError(`Condition with id ${id} was not found`);
}
await this.checkConflictedConditions(
conditionalDecision.roleEntityRef,
conditionalDecision.resourceType,
conditionalDecision.pluginId,
conditionalDecision.permissionMapping.map((perm) => perm.action),
id,
db,
idsToExclude
);
const conditionRaw = this.toDAO(conditionalDecision);
conditionRaw.id = id;
const result = await db.table(CONDITIONAL_TABLE).where("id", conditionRaw.id).update(conditionRaw).returning("id");
if (!result || result.length === 0) {
throw new Error(`Failed to update the condition with id: ${id}.`);
}
}
toDAO(conditionalDecision) {
const {
result,
pluginId,
resourceType,
conditions,
roleEntityRef,
permissionMapping
} = conditionalDecision;
const conditionsJson = JSON.stringify(conditions);
return {
result,
pluginId,
resourceType,
conditionsJson,
roleEntityRef,
permissions: JSON.stringify(permissionMapping)
};
}
daoToConditionalDecision(dao) {
if (!dao.id) {
throw new errors.InputError(`Missed id in the dao object: ${dao}`);
}
const {
id,
result,
pluginId,
resourceType,
conditionsJson,
roleEntityRef,
permissions
} = dao;
const conditions = JSON.parse(conditionsJson);
return {
id,
result,
pluginId,
resourceType,
conditions,
roleEntityRef,
permissionMapping: JSON.parse(permissions)
};
}
}
exports.CONDITIONAL_TABLE = CONDITIONAL_TABLE;
exports.DataBaseConditionalStorage = DataBaseConditionalStorage;
//# sourceMappingURL=conditional-storage.cjs.js.map