diff options
4 files changed, 32 insertions, 8 deletions
diff --git a/src/main/java/org/traccar/api/BaseObjectResource.java b/src/main/java/org/traccar/api/BaseObjectResource.java index 2a801221b..3c97dd1f8 100644 --- a/src/main/java/org/traccar/api/BaseObjectResource.java +++ b/src/main/java/org/traccar/api/BaseObjectResource.java @@ -68,7 +68,7 @@ public abstract class BaseObjectResource<T extends BaseModel> extends BaseResour @POST public Response add(T entity) throws Exception { - permissionsService.checkEdit(getUserId(), entity, true); + permissionsService.checkEdit(getUserId(), entity, true, false); entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id")))); LogAction.create(getUserId(), entity); @@ -86,13 +86,16 @@ public abstract class BaseObjectResource<T extends BaseModel> extends BaseResour @Path("{id}") @PUT public Response update(T entity) throws Exception { - permissionsService.checkEdit(getUserId(), entity, false); permissionsService.checkPermission(baseClass, getUserId(), entity.getId()); + boolean skipReadonly = false; if (entity instanceof User) { + User after = (User) entity; User before = storage.getObject(User.class, new Request( new Columns.All(), new Condition.Equals("id", entity.getId()))); permissionsService.checkUserUpdate(getUserId(), before, (User) entity); + skipReadonly = permissionsService.getUser(getUserId()) + .compare(after, "notificationTokens", "termsAccepted"); } else if (entity instanceof Group) { Group group = (Group) entity; if (group.getId() == group.getGroupId()) { @@ -100,6 +103,8 @@ public abstract class BaseObjectResource<T extends BaseModel> extends BaseResour } } + permissionsService.checkEdit(getUserId(), entity, false, skipReadonly); + storage.updateObject(entity, new Request( new Columns.Exclude("id"), new Condition.Equals("id", entity.getId()))); @@ -120,8 +125,8 @@ public abstract class BaseObjectResource<T extends BaseModel> extends BaseResour @Path("{id}") @DELETE public Response remove(@PathParam("id") long id) throws Exception { - permissionsService.checkEdit(getUserId(), baseClass, false); permissionsService.checkPermission(baseClass, getUserId(), id); + permissionsService.checkEdit(getUserId(), baseClass, false, false); storage.removeObject(baseClass, new Request(new Condition.Equals("id", id))); cacheManager.invalidateObject(true, baseClass, id, ObjectOperation.DELETE); diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index 971c29c60..61d96669e 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -137,8 +137,8 @@ public class DeviceResource extends BaseObjectResource<Device> { @Path("{id}/accumulators") @PUT public Response updateAccumulators(DeviceAccumulators entity) throws Exception { - permissionsService.checkEdit(getUserId(), Device.class, false); permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId()); + permissionsService.checkEdit(getUserId(), Device.class, false, false); Position position = storage.getObject(Position.class, new Request( new Columns.All(), new Condition.LatestPositions(entity.getDeviceId()))); diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java index d60bbafb8..d4a6fba1a 100644 --- a/src/main/java/org/traccar/api/security/PermissionsService.java +++ b/src/main/java/org/traccar/api/security/PermissionsService.java @@ -98,10 +98,12 @@ public class PermissionsService { } } - public void checkEdit(long userId, Class<?> clazz, boolean addition) throws StorageException, SecurityException { + public void checkEdit( + long userId, Class<?> clazz, boolean addition, boolean skipReadonly) + throws StorageException, SecurityException { if (!getUser(userId).getAdministrator()) { boolean denied = false; - if (getServer().getReadonly() || getUser(userId).getReadonly()) { + if (!skipReadonly && (getServer().getReadonly() || getUser(userId).getReadonly())) { denied = true; } else if (clazz.equals(Device.class)) { denied = getServer().getDeviceReadonly() || getUser(userId).getDeviceReadonly() @@ -121,9 +123,11 @@ public class PermissionsService { } } - public void checkEdit(long userId, BaseModel object, boolean addition) throws StorageException, SecurityException { + public void checkEdit( + long userId, BaseModel object, boolean addition, boolean skipReadonly) + throws StorageException, SecurityException { if (!getUser(userId).getAdministrator()) { - checkEdit(userId, object.getClass(), addition); + checkEdit(userId, object.getClass(), addition, skipReadonly); if (object instanceof GroupedModel) { GroupedModel after = ((GroupedModel) object); if (after.getGroupId() > 0) { diff --git a/src/main/java/org/traccar/model/User.java b/src/main/java/org/traccar/model/User.java index 9b8ee3e53..7cf8c25a6 100644 --- a/src/main/java/org/traccar/model/User.java +++ b/src/main/java/org/traccar/model/User.java @@ -17,11 +17,13 @@ package org.traccar.model; import com.fasterxml.jackson.annotation.JsonIgnore; +import org.apache.commons.lang3.builder.EqualsBuilder; import org.traccar.storage.QueryIgnore; import org.traccar.helper.Hashing; import org.traccar.storage.StorageName; import java.util.Date; +import java.util.HashMap; @StorageName("tc_users") public class User extends ExtendedModel implements UserRestrictions, Disableable { @@ -305,4 +307,17 @@ public class User extends ExtendedModel implements UserRestrictions, Disableable return Hashing.validatePassword(password, hashedPassword, salt); } + public boolean compare(User other, String... exclusions) { + if (!EqualsBuilder.reflectionEquals(this, other, "attributes", "hashedPassword", "salt")) { + return false; + } + var thisAttributes = new HashMap<>(getAttributes()); + var otherAttributes = new HashMap<>(other.getAttributes()); + for (String exclusion : exclusions) { + thisAttributes.remove(exclusion); + otherAttributes.remove(exclusion); + } + return thisAttributes.equals(otherAttributes); + } + } |