Change handleGetCarCatalog auth concept
MODIFY
src/authorization/AuthorizationsDefinition.ts
src/authorization/AuthorizationsDefinition.ts
@@ -33,7 +33,16 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
]
},
{ resource: Entity.CAR_CATALOGS, action: Action.SYNCHRONIZE, attributes: ['*'] },
- { resource: Entity.CAR_CATALOG, action: Action.READ, attributes: ['*'] },
+ {
+ resource: Entity.CAR_CATALOG, action: Action.READ, attributes: [
+ 'id', 'vehicleModel', 'vehicleMake', 'vehicleModelVersion', 'batteryCapacityFull', 'fastchargeChargeSpeed',
+ 'performanceTopspeed', 'performanceAcceleration', 'rangeWLTP', 'rangeReal', 'efficiencyReal', 'drivetrainPropulsion',
+ 'drivetrainTorque', 'batteryCapacityUseable', 'chargePlug', 'fastChargePlug', 'fastChargePowerMax', 'chargePlugLocation',
+ 'drivetrainPowerHP', 'chargeStandardChargeSpeed', 'chargeStandardChargeTime', 'miscSeats', 'miscBody', 'miscIsofix', 'miscTurningCircle',
+ 'miscSegment', 'miscIsofixSeats', 'chargeStandardPower', 'chargeStandardPhase', 'chargeAlternativePower', 'hash',
+ 'chargeAlternativePhase', 'chargeOptionPower', 'chargeOptionPhase', 'image', 'chargeOptionPhaseAmp', 'chargeAlternativePhaseAmp'
+ ]
+ },
]
},
admin: {
@@ -142,8 +151,17 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
'fastChargePowerMax', 'drivetrainPowerHP'
]
},
- { resource: Entity.CAR_CATALOG, action: Action.READ, attributes: ['*'] },
- { resource: Entity.CAR, action: [Action.CREATE, Action.UPDATE, Action.DELETE], attributes: ['*'] },
+
+ {
+ resource: Entity.CAR_CATALOG, action: Action.READ, attributes: [
+ 'id', 'vehicleModel', 'vehicleMake', 'vehicleModelVersion', 'batteryCapacityFull', 'fastchargeChargeSpeed',
+ 'performanceTopspeed', 'performanceAcceleration', 'rangeWLTP', 'rangeReal', 'efficiencyReal', 'drivetrainPropulsion',
+ 'drivetrainTorque', 'batteryCapacityUseable', 'chargePlug', 'fastChargePlug', 'fastChargePowerMax', 'chargePlugLocation',
+ 'drivetrainPowerHP', 'chargeStandardChargeSpeed', 'chargeStandardChargeTime', 'miscSeats', 'miscBody', 'miscIsofix', 'miscTurningCircle',
+ 'miscSegment', 'miscIsofixSeats', 'chargeStandardPower', 'chargeStandardPhase', 'chargeAlternativePower', 'hash',
+ 'chargeAlternativePhase', 'chargeOptionPower', 'chargeOptionPhase', 'image', 'chargeOptionPhaseAmp', 'chargeAlternativePhaseAmp'
+ ]
+ }, { resource: Entity.CAR, action: [Action.CREATE, Action.UPDATE, Action.DELETE], attributes: ['*'] },
{
resource: Entity.CAR, action: Action.READ, attributes: [
'id', 'type', 'vin', 'licensePlate', 'converter', 'default', 'owner', 'createdOn', 'lastChangedOn',
@@ -202,8 +220,17 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
'fastChargePowerMax', 'drivetrainPowerHP'
]
},
- { resource: Entity.CAR_CATALOG, action: Action.READ, attributes: ['*'] },
- { resource: Entity.CAR, action: [Action.CREATE, Action.UPDATE, Action.DELETE], attributes: ['*'] },
+
+ {
+ resource: Entity.CAR_CATALOG, action: Action.READ, attributes: [
+ 'id', 'vehicleModel', 'vehicleMake', 'vehicleModelVersion', 'batteryCapacityFull', 'fastchargeChargeSpeed',
+ 'performanceTopspeed', 'performanceAcceleration', 'rangeWLTP', 'rangeReal', 'efficiencyReal', 'drivetrainPropulsion',
+ 'drivetrainTorque', 'batteryCapacityUseable', 'chargePlug', 'fastChargePlug', 'fastChargePowerMax', 'chargePlugLocation',
+ 'drivetrainPowerHP', 'chargeStandardChargeSpeed', 'chargeStandardChargeTime', 'miscSeats', 'miscBody', 'miscIsofix', 'miscTurningCircle',
+ 'miscSegment', 'miscIsofixSeats', 'chargeStandardPower', 'chargeStandardPhase', 'chargeAlternativePower', 'hash',
+ 'chargeAlternativePhase', 'chargeOptionPower', 'chargeOptionPhase', 'image', 'chargeOptionPhaseAmp', 'chargeAlternativePhaseAmp'
+ ]
+ }, { resource: Entity.CAR, action: [Action.CREATE, Action.UPDATE, Action.DELETE], attributes: ['*'] },
{
resource: Entity.CAR, action: Action.READ, attributes: [
'id', 'type', 'vin', 'licensePlate', 'converter', 'default', 'owner', 'createdOn', 'lastChangedOn',
@@ -367,8 +394,16 @@ const AUTHORIZATION_DEFINITION: AuthorizationDefinition = {
'fastChargePowerMax', 'drivetrainPowerHP'
]
},
- { resource: Entity.CAR_CATALOG, action: Action.READ, attributes: ['*'] },
{
+ resource: Entity.CAR_CATALOG, action: Action.READ, attributes: [
+ 'id', 'vehicleModel', 'vehicleMake', 'vehicleModelVersion', 'batteryCapacityFull', 'fastchargeChargeSpeed',
+ 'performanceTopspeed', 'performanceAcceleration', 'rangeWLTP', 'rangeReal', 'efficiencyReal', 'drivetrainPropulsion',
+ 'drivetrainTorque', 'batteryCapacityUseable', 'chargePlug', 'fastChargePlug', 'fastChargePowerMax', 'chargePlugLocation',
+ 'drivetrainPowerHP', 'chargeStandardChargeSpeed', 'chargeStandardChargeTime', 'miscSeats', 'miscBody', 'miscIsofix', 'miscTurningCircle',
+ 'miscSegment', 'miscIsofixSeats', 'chargeStandardPower', 'chargeStandardPhase', 'chargeAlternativePower', 'hash',
+ 'chargeAlternativePhase', 'chargeOptionPower', 'chargeOptionPhase', 'image', 'chargeOptionPhaseAmp', 'chargeAlternativePhaseAmp'
+ ]
+ }, {
resource: Entity.CAR, action: Action.READ, attributes: [
'id', 'type', 'vin', 'licensePlate', 'converter', 'default', 'owner', 'createdOn', 'lastChangedOn',
'carCatalogID', 'carCatalog.vehicleMake', 'carCatalog.vehicleModel', 'carCatalog.vehicleModelVersion', 'carCatalog.image',

MODIFY
src/server/rest/v1/service/AuthorizationService.ts
src/server/rest/v1/service/AuthorizationService.ts
@@ -735,6 +735,19 @@ export default class AuthorizationService {
return authorizationFilters;
}
+ public static async checkAndGetCarCatalogAuthorizationFilters(tenant: Tenant, userToken: UserToken, filteredRequest: Record<string, any>,
+ action: Action): Promise<AuthorizationFilter> {
+ const authorizationFilters: AuthorizationFilter = {
+ filters: {},
+ dataSources: new Map(),
+ projectFields: [ ],
+ authorized: false
+ };
+ // Check static & dynamic authorization
+ await this.canPerformAuthorizationAction(tenant, userToken, Entity.CAR_CATALOG, action, authorizationFilters, filteredRequest);
+ return authorizationFilters;
+ }
+
public static async getSiteAdminSiteIDs(tenantID: string, userToken: UserToken): Promise<string[]> {
// Get the Sites where the user is Site Admin
const userSites = await UserStorage.getUserSites(tenantID,

MODIFY
src/server/rest/v1/service/CarService.ts
src/server/rest/v1/service/CarService.ts
@@ -59,34 +59,14 @@ export default class CarService {
}
public static async handleGetCarCatalog(action: ServerAction, req: Request, res: Response, next: NextFunction): Promise<void> {
- if (!Authorizations.isSuperAdmin(req.user)) {
// Check if component is active
UtilsService.assertComponentIsActiveFromToken(req.user, TenantComponents.CAR,
Action.READ, Entity.CAR_CATALOG, MODULE_NAME, 'handleGetCarCatalog');
- }
- // Check auth
- if (!await Authorizations.canReadCarCatalog(req.user)) {
- throw new AppAuthError({
- errorCode: HTTPAuthError.FORBIDDEN,
- user: req.user,
- action: Action.LIST, entity: Entity.CAR_CATALOG,
- module: MODULE_NAME, method: 'handleGetCarCatalog'
- });
- }
// Filter
const filteredRequest = CarSecurity.filterCarCatalogRequest(req.query);
- UtilsService.assertIdIsProvided(action, filteredRequest.ID, MODULE_NAME, 'handleGetCarCatalog', req.user);
- // Get the car
- const carCatalog = await CarStorage.getCarCatalog(filteredRequest.ID,
- { withImage: true },
- [
- 'id', 'vehicleModel', 'vehicleMake', 'vehicleModelVersion', 'batteryCapacityFull', 'fastchargeChargeSpeed',
- 'performanceTopspeed', 'performanceAcceleration', 'rangeWLTP', 'rangeReal', 'efficiencyReal', 'drivetrainPropulsion',
- 'drivetrainTorque', 'batteryCapacityUseable', 'chargePlug', 'fastChargePlug', 'fastChargePowerMax', 'chargePlugLocation',
- 'drivetrainPowerHP', 'chargeStandardChargeSpeed', 'chargeStandardChargeTime', 'miscSeats', 'miscBody', 'miscIsofix', 'miscTurningCircle',
- 'miscSegment', 'miscIsofixSeats', 'chargeStandardPower', 'chargeStandardPhase', 'chargeAlternativePower', 'hash',
- 'chargeAlternativePhase', 'chargeOptionPower', 'chargeOptionPhase', 'image', 'chargeOptionPhaseAmp', 'chargeAlternativePhaseAmp'
- ]);
+ // Check and get Car cATALOG
+ const carCatalog = await UtilsService.checkAndGetCarCatalogAuthorization(req.tenant, req.user, filteredRequest.ID, Action.READ, action,
+ { withImage: true }, true);
// Return
res.json(carCatalog);
next();

MODIFY
src/server/rest/v1/service/UtilsService.ts
src/server/rest/v1/service/UtilsService.ts
import { Action, Entity } from '../../../../types/Authorization';
-import { Car, CarType } from '../../../../types/Car';
+import { Car, CarCatalog, CarType } from '../../../../types/Car';
import ChargingStation, { ChargePoint, Voltage } from '../../../../types/ChargingStation';
import { HTTPAuthError, HTTPError } from '../../../../types/HTTPError';
import { NextFunction, Request, Response } from 'express';
@@ -538,6 +538,37 @@ export default class UtilsService {
return car;
}
+ public static async checkAndGetCarCatalogAuthorization(tenant: Tenant, userToken: UserToken, carCatalogID: number, authAction: Action,
+ action: ServerAction, additionalFilters: Record<string, any>, applyProjectFields = false): Promise<CarCatalog> {
+ // Check mandatory fields
+ UtilsService.assertIdIsProvided(action, carCatalogID, MODULE_NAME, 'checkAndGetCarCatalogAuthorization', userToken);
+ // Get dynamic auth
+ const authorizationFilter = await AuthorizationService.checkAndGetCarCatalogAuthorizationFilters(
+ tenant, userToken, { ID: carCatalogID }, Action.READ);
+ if (!authorizationFilter.authorized) {
+ throw new AppAuthError({
+ errorCode: HTTPAuthError.FORBIDDEN,
+ user: userToken,
+ action: Action.READ, entity: Entity.CAR_CATALOG,
+ module: MODULE_NAME, method: 'checkAndGetCarCatalogAuthorization',
+ value: carCatalogID.toString()
+ });
+ }
+ // Get the car
+ const carCatalog = await CarStorage.getCarCatalog(carCatalogID, {
+ ...additionalFilters,
+ ...authorizationFilter.filters
+ },
+ applyProjectFields ? authorizationFilter.projectFields : null
+ );
+ // Check it exists
+ UtilsService.assertObjectExists(action, carCatalog, `Car Catalog ID '${carCatalogID}' does not exist`,
+ MODULE_NAME, 'checkAndGetCarCatalogAuthorization', userToken);
+ // todo: check if extra auth is needed?
+ // Return
+ return carCatalog;
+ }
+
public static sendEmptyDataResult(res: Response, next: NextFunction): void {
res.json(Constants.DB_EMPTY_DATA_RESULT);
next();

Change handleGetCarCatalog auth concept