From f910e56a45a4adc08287b6674d011bd25ea52b27 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 12 Dec 2021 10:54:18 -0800 Subject: Token to override current session --- .../org/traccar/api/resource/SessionResource.java | 33 +++++++++++++--------- 1 file changed, 20 insertions(+), 13 deletions(-) (limited to 'src/main/java/org/traccar/api/resource/SessionResource.java') diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index e3c5d457f..60ce5490a 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2021 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -57,8 +57,19 @@ public class SessionResource extends BaseResource { @PermitAll @GET public User get(@QueryParam("token") String token) throws SQLException, UnsupportedEncodingException { + + if (token != null) { + User user = Context.getUsersManager().getUserByToken(token); + if (user != null) { + Context.getPermissionsManager().checkUserEnabled(user.getId()); + request.getSession().setAttribute(USER_ID_KEY, user.getId()); + return user; + } + } + Long userId = (Long) request.getSession().getAttribute(USER_ID_KEY); if (userId == null) { + Cookie[] cookies = request.getCookies(); String email = null, password = null; if (cookies != null) { @@ -77,24 +88,20 @@ public class SessionResource extends BaseResource { if (email != null && password != null) { User user = Context.getPermissionsManager().login(email, password); if (user != null) { - userId = user.getId(); - request.getSession().setAttribute(USER_ID_KEY, userId); - } - } else if (token != null) { - User user = Context.getUsersManager().getUserByToken(token); - if (user != null) { - userId = user.getId(); - request.getSession().setAttribute(USER_ID_KEY, userId); + Context.getPermissionsManager().checkUserEnabled(user.getId()); + request.getSession().setAttribute(USER_ID_KEY, user.getId()); + return user; } } - } - if (userId != null) { + } else { + Context.getPermissionsManager().checkUserEnabled(userId); return Context.getPermissionsManager().getUser(userId); - } else { - throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); + } + + throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); } @PermitAll -- cgit v1.2.3 From 1c73bae2e23242673e0a07cdbc2493700f134ceb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 13 Feb 2022 23:34:25 -0800 Subject: New storage implementation --- setup/default.xml | 30 --- src/main/java/org/traccar/MainEventHandler.java | 4 +- .../java/org/traccar/api/BaseObjectResource.java | 7 +- .../org/traccar/api/SecurityRequestFilter.java | 4 +- .../traccar/api/resource/AttributeResource.java | 9 +- .../org/traccar/api/resource/DeviceResource.java | 3 +- .../org/traccar/api/resource/EventResource.java | 6 +- .../org/traccar/api/resource/PasswordResource.java | 6 +- .../traccar/api/resource/PermissionsResource.java | 10 +- .../org/traccar/api/resource/PositionResource.java | 4 +- .../org/traccar/api/resource/ReportResource.java | 28 +-- .../org/traccar/api/resource/ServerResource.java | 6 +- .../org/traccar/api/resource/SessionResource.java | 6 +- .../traccar/api/resource/StatisticsResource.java | 4 +- .../org/traccar/api/resource/UserResource.java | 3 +- .../org/traccar/database/BaseObjectManager.java | 10 +- .../org/traccar/database/ConnectionManager.java | 6 +- .../java/org/traccar/database/DataManager.java | 265 ++++++++------------- .../java/org/traccar/database/DeviceManager.java | 28 +-- .../traccar/database/ExtendedObjectManager.java | 6 +- .../java/org/traccar/database/GroupsManager.java | 4 +- .../org/traccar/database/NotificationManager.java | 4 +- .../org/traccar/database/PermissionsManager.java | 10 +- .../org/traccar/database/SimpleObjectManager.java | 6 +- .../org/traccar/database/StatisticsManager.java | 4 +- .../java/org/traccar/database/UsersManager.java | 9 + .../java/org/traccar/handler/FilterHandler.java | 4 +- src/main/java/org/traccar/model/Attribute.java | 3 + src/main/java/org/traccar/model/Calendar.java | 2 + src/main/java/org/traccar/model/Command.java | 8 + src/main/java/org/traccar/model/Device.java | 7 +- src/main/java/org/traccar/model/Driver.java | 4 + src/main/java/org/traccar/model/Event.java | 3 + src/main/java/org/traccar/model/Geofence.java | 2 + src/main/java/org/traccar/model/Group.java | 3 + src/main/java/org/traccar/model/Maintenance.java | 3 + src/main/java/org/traccar/model/Notification.java | 4 +- src/main/java/org/traccar/model/Order.java | 3 + src/main/java/org/traccar/model/Position.java | 15 +- src/main/java/org/traccar/model/Server.java | 2 + src/main/java/org/traccar/model/Statistics.java | 3 + src/main/java/org/traccar/model/User.java | 2 + src/main/java/org/traccar/reports/Events.java | 6 +- src/main/java/org/traccar/reports/Route.java | 6 +- src/main/java/org/traccar/reports/Stops.java | 8 +- src/main/java/org/traccar/reports/Summary.java | 8 +- src/main/java/org/traccar/reports/Trips.java | 8 +- .../java/org/traccar/storage/DatabaseStorage.java | 71 ++++-- .../java/org/traccar/storage/QueryBuilder.java | 6 +- src/main/java/org/traccar/storage/Storage.java | 15 +- .../java/org/traccar/storage/query/Columns.java | 22 +- .../java/org/traccar/storage/query/Condition.java | 42 +++- src/main/java/org/traccar/storage/query/Limit.java | 15 ++ .../java/org/traccar/storage/query/Request.java | 22 ++ .../java/org/traccar/database/DataManagerTest.java | 81 ------- 55 files changed, 420 insertions(+), 440 deletions(-) create mode 100644 src/main/java/org/traccar/storage/query/Limit.java delete mode 100644 src/test/java/org/traccar/database/DataManagerTest.java (limited to 'src/main/java/org/traccar/api/resource/SessionResource.java') diff --git a/setup/default.xml b/setup/default.xml index 0d8133627..a1ba5ca33 100644 --- a/setup/default.xml +++ b/setup/default.xml @@ -41,37 +41,7 @@ true true - true ./schema/changelog-master.xml - - - SELECT * FROM tc_users - WHERE email = :email OR login = :email - - - - SELECT * FROM tc_positions WHERE deviceId = :deviceId AND fixTime BETWEEN :from AND :to ORDER BY fixTime - - - - SELECT * FROM tc_positions WHERE deviceId = :deviceId AND fixTime <= :time ORDER BY fixTime DESC LIMIT 1 - - - - SELECT tc_positions.* FROM tc_positions INNER JOIN tc_devices ON tc_positions.id = tc_devices.positionid; - - - - UPDATE tc_devices SET positionId = :id WHERE id = :deviceId - - - - SELECT * FROM tc_events WHERE deviceId = :deviceId AND eventTime BETWEEN :from AND :to ORDER BY eventTime - - - - SELECT * FROM tc_statistics WHERE captureTime BETWEEN :from AND :to ORDER BY captureTime - 5001 5002 diff --git a/src/main/java/org/traccar/MainEventHandler.java b/src/main/java/org/traccar/MainEventHandler.java index 4889f6a2e..a3f6f4105 100644 --- a/src/main/java/org/traccar/MainEventHandler.java +++ b/src/main/java/org/traccar/MainEventHandler.java @@ -27,8 +27,8 @@ import org.traccar.config.Keys; import org.traccar.database.StatisticsManager; import org.traccar.helper.DateUtil; import org.traccar.model.Position; +import org.traccar.storage.StorageException; -import java.sql.SQLException; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashSet; @@ -57,7 +57,7 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter { Position position = (Position) msg; try { Context.getDeviceManager().updateLatestPosition(position); - } catch (SQLException error) { + } catch (StorageException error) { LOGGER.warn("Failed to update device", error); } diff --git a/src/main/java/org/traccar/api/BaseObjectResource.java b/src/main/java/org/traccar/api/BaseObjectResource.java index 71f3939cb..22756f62a 100644 --- a/src/main/java/org/traccar/api/BaseObjectResource.java +++ b/src/main/java/org/traccar/api/BaseObjectResource.java @@ -41,6 +41,7 @@ import org.traccar.model.Group; import org.traccar.model.GroupedModel; import org.traccar.model.ScheduledModel; import org.traccar.model.User; +import org.traccar.storage.StorageException; public abstract class BaseObjectResource extends BaseResource { @@ -87,7 +88,7 @@ public abstract class BaseObjectResource extends BaseResour } @POST - public Response add(T entity) throws SQLException { + public Response add(T entity) throws StorageException { Context.getPermissionsManager().checkReadonly(getUserId()); if (baseClass.equals(Device.class)) { Context.getPermissionsManager().checkDeviceReadonly(getUserId()); @@ -120,7 +121,7 @@ public abstract class BaseObjectResource extends BaseResour @Path("{id}") @PUT - public Response update(T entity) throws SQLException { + public Response update(T entity) throws StorageException { Context.getPermissionsManager().checkReadonly(getUserId()); if (baseClass.equals(Device.class)) { Context.getPermissionsManager().checkDeviceReadonly(getUserId()); @@ -150,7 +151,7 @@ public abstract class BaseObjectResource extends BaseResour @Path("{id}") @DELETE - public Response remove(@PathParam("id") long id) throws SQLException { + public Response remove(@PathParam("id") long id) throws StorageException { Context.getPermissionsManager().checkReadonly(getUserId()); if (baseClass.equals(Device.class)) { Context.getPermissionsManager().checkDeviceReadonly(getUserId()); diff --git a/src/main/java/org/traccar/api/SecurityRequestFilter.java b/src/main/java/org/traccar/api/SecurityRequestFilter.java index 33b6b37df..6b190be9f 100644 --- a/src/main/java/org/traccar/api/SecurityRequestFilter.java +++ b/src/main/java/org/traccar/api/SecurityRequestFilter.java @@ -23,6 +23,7 @@ import org.traccar.api.resource.SessionResource; import org.traccar.database.StatisticsManager; import org.traccar.helper.DataConverter; import org.traccar.model.User; +import org.traccar.storage.StorageException; import javax.annotation.security.PermitAll; import javax.servlet.http.HttpServletRequest; @@ -34,7 +35,6 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; -import java.sql.SQLException; public class SecurityRequestFilter implements ContainerRequestFilter { @@ -82,7 +82,7 @@ public class SecurityRequestFilter implements ContainerRequestFilter { Main.getInjector().getInstance(StatisticsManager.class).registerRequest(user.getId()); securityContext = new UserSecurityContext(new UserPrincipal(user.getId())); } - } catch (SQLException e) { + } catch (StorageException e) { throw new WebApplicationException(e); } diff --git a/src/main/java/org/traccar/api/resource/AttributeResource.java b/src/main/java/org/traccar/api/resource/AttributeResource.java index de69d871c..d2dc28903 100644 --- a/src/main/java/org/traccar/api/resource/AttributeResource.java +++ b/src/main/java/org/traccar/api/resource/AttributeResource.java @@ -16,8 +16,6 @@ */ package org.traccar.api.resource; -import java.sql.SQLException; - import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.POST; @@ -34,6 +32,7 @@ import org.traccar.api.ExtendedObjectResource; import org.traccar.model.Attribute; import org.traccar.model.Position; import org.traccar.handler.ComputedAttributesHandler; +import org.traccar.storage.StorageException; @Path("attributes/computed") @Produces(MediaType.APPLICATION_JSON) @@ -75,21 +74,21 @@ public class AttributeResource extends ExtendedObjectResource { } @POST - public Response add(Attribute entity) throws SQLException { + public Response add(Attribute entity) throws StorageException { Context.getPermissionsManager().checkAdmin(getUserId()); return super.add(entity); } @Path("{id}") @PUT - public Response update(Attribute entity) throws SQLException { + public Response update(Attribute entity) throws StorageException { Context.getPermissionsManager().checkAdmin(getUserId()); return super.update(entity); } @Path("{id}") @DELETE - public Response remove(@PathParam("id") long id) throws SQLException { + public Response remove(@PathParam("id") long id) throws StorageException { Context.getPermissionsManager().checkAdmin(getUserId()); return super.remove(id); } diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index 7006cdb84..9436b59f6 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -21,6 +21,7 @@ import org.traccar.database.DeviceManager; import org.traccar.helper.LogAction; import org.traccar.model.Device; import org.traccar.model.DeviceAccumulators; +import org.traccar.storage.StorageException; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -87,7 +88,7 @@ public class DeviceResource extends BaseObjectResource { @Path("{id}/accumulators") @PUT - public Response updateAccumulators(DeviceAccumulators entity) throws SQLException { + public Response updateAccumulators(DeviceAccumulators entity) throws StorageException { if (!Context.getPermissionsManager().getUserAdmin(getUserId())) { Context.getPermissionsManager().checkManager(getUserId()); Context.getPermissionsManager().checkPermission(Device.class, getUserId(), entity.getDeviceId()); diff --git a/src/main/java/org/traccar/api/resource/EventResource.java b/src/main/java/org/traccar/api/resource/EventResource.java index 34e4a94ce..354d96e4f 100644 --- a/src/main/java/org/traccar/api/resource/EventResource.java +++ b/src/main/java/org/traccar/api/resource/EventResource.java @@ -15,8 +15,6 @@ */ package org.traccar.api.resource; -import java.sql.SQLException; - import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -31,16 +29,16 @@ import org.traccar.api.BaseResource; import org.traccar.model.Event; import org.traccar.model.Geofence; import org.traccar.model.Maintenance; +import org.traccar.storage.StorageException; @Path("events") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) - public class EventResource extends BaseResource { @Path("{id}") @GET - public Event get(@PathParam("id") long id) throws SQLException { + public Event get(@PathParam("id") long id) throws StorageException { Event event = Context.getDataManager().getObject(Event.class, id); if (event == null) { throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); diff --git a/src/main/java/org/traccar/api/resource/PasswordResource.java b/src/main/java/org/traccar/api/resource/PasswordResource.java index 1868a6191..0642ff3cc 100644 --- a/src/main/java/org/traccar/api/resource/PasswordResource.java +++ b/src/main/java/org/traccar/api/resource/PasswordResource.java @@ -21,6 +21,7 @@ import org.traccar.api.BaseResource; import org.traccar.model.User; import org.traccar.notification.NotificationMessage; import org.traccar.notification.TextTemplateFormatter; +import org.traccar.storage.StorageException; import javax.annotation.security.PermitAll; import javax.mail.MessagingException; @@ -31,7 +32,6 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import java.sql.SQLException; import java.util.UUID; @Path("password") @@ -44,7 +44,7 @@ public class PasswordResource extends BaseResource { @Path("reset") @PermitAll @POST - public Response reset(@FormParam("email") String email) throws SQLException, MessagingException { + public Response reset(@FormParam("email") String email) throws StorageException, MessagingException { for (long userId : Context.getUsersManager().getAllItems()) { User user = Context.getUsersManager().getById(userId); if (email.equals(user.getEmail())) { @@ -66,7 +66,7 @@ public class PasswordResource extends BaseResource { @PermitAll @POST public Response update( - @FormParam("token") String token, @FormParam("password") String password) throws SQLException { + @FormParam("token") String token, @FormParam("password") String password) throws StorageException { for (long userId : Context.getUsersManager().getAllItems()) { User user = Context.getUsersManager().getById(userId); if (token.equals(user.getString(PASSWORD_RESET_TOKEN))) { diff --git a/src/main/java/org/traccar/api/resource/PermissionsResource.java b/src/main/java/org/traccar/api/resource/PermissionsResource.java index 54d3964b6..7def38919 100644 --- a/src/main/java/org/traccar/api/resource/PermissionsResource.java +++ b/src/main/java/org/traccar/api/resource/PermissionsResource.java @@ -16,7 +16,6 @@ */ package org.traccar.api.resource; -import java.sql.SQLException; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -37,6 +36,7 @@ import org.traccar.helper.LogAction; import org.traccar.model.Device; import org.traccar.model.Permission; import org.traccar.model.User; +import org.traccar.storage.StorageException; @Path("permissions") @Produces(MediaType.APPLICATION_JSON) @@ -71,7 +71,7 @@ public class PermissionsResource extends BaseResource { @Path("bulk") @POST - public Response add(List> entities) throws SQLException, ClassNotFoundException { + public Response add(List> entities) throws StorageException, ClassNotFoundException { Context.getPermissionsManager().checkReadonly(getUserId()); checkPermissionTypes(entities); for (LinkedHashMap entity: entities) { @@ -89,13 +89,13 @@ public class PermissionsResource extends BaseResource { } @POST - public Response add(LinkedHashMap entity) throws SQLException, ClassNotFoundException { + public Response add(LinkedHashMap entity) throws StorageException, ClassNotFoundException { return add(Collections.singletonList(entity)); } @DELETE @Path("bulk") - public Response remove(List> entities) throws SQLException, ClassNotFoundException { + public Response remove(List> entities) throws StorageException, ClassNotFoundException { Context.getPermissionsManager().checkReadonly(getUserId()); checkPermissionTypes(entities); for (LinkedHashMap entity: entities) { @@ -113,7 +113,7 @@ public class PermissionsResource extends BaseResource { } @DELETE - public Response remove(LinkedHashMap entity) throws SQLException, ClassNotFoundException { + public Response remove(LinkedHashMap entity) throws StorageException, ClassNotFoundException { return remove(Collections.singletonList(entity)); } diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java index 53157197b..511032402 100644 --- a/src/main/java/org/traccar/api/resource/PositionResource.java +++ b/src/main/java/org/traccar/api/resource/PositionResource.java @@ -18,6 +18,7 @@ package org.traccar.api.resource; import org.traccar.Context; import org.traccar.api.BaseResource; import org.traccar.model.Position; +import org.traccar.storage.StorageException; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -25,7 +26,6 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -41,7 +41,7 @@ public class PositionResource extends BaseResource { public Collection getJson( @QueryParam("deviceId") long deviceId, @QueryParam("id") List positionIds, @QueryParam("from") Date from, @QueryParam("to") Date to) - throws SQLException { + throws StorageException { if (!positionIds.isEmpty()) { ArrayList positions = new ArrayList<>(); for (Long positionId : positionIds) { diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java index 23ffaf54c..03df0d03a 100644 --- a/src/main/java/org/traccar/api/resource/ReportResource.java +++ b/src/main/java/org/traccar/api/resource/ReportResource.java @@ -18,7 +18,6 @@ package org.traccar.api.resource; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.sql.SQLException; import java.util.Collection; import java.util.Date; import java.util.List; @@ -51,6 +50,7 @@ import org.traccar.reports.model.SummaryReport; import org.traccar.reports.model.TripReport; import org.traccar.reports.Route; import org.traccar.reports.Stops; +import org.traccar.storage.StorageException; @Path("reports") @Produces(MediaType.APPLICATION_JSON) @@ -63,11 +63,11 @@ public class ReportResource extends BaseResource { private static final String CONTENT_DISPOSITION_VALUE_XLSX = "attachment; filename=report.xlsx"; private interface ReportExecutor { - void execute(ByteArrayOutputStream stream) throws SQLException, IOException; + void execute(ByteArrayOutputStream stream) throws StorageException, IOException; } private Response executeReport( - long userId, boolean mail, ReportExecutor executor) throws SQLException, IOException { + long userId, boolean mail, ReportExecutor executor) throws StorageException, IOException { final ByteArrayOutputStream stream = new ByteArrayOutputStream(); if (mail) { new Thread(() -> { @@ -82,7 +82,7 @@ public class ReportResource extends BaseResource { Context.getMailManager().sendMessage( userId, "Report", "The report is in the attachment.", attachment); - } catch (SQLException | IOException | MessagingException e) { + } catch (StorageException | IOException | MessagingException e) { LOGGER.warn("Report failed", e); } }).start(); @@ -98,7 +98,7 @@ public class ReportResource extends BaseResource { @GET public Collection getRoute( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("from") Date from, @QueryParam("to") Date to) throws SQLException { + @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { Context.getPermissionsManager().checkDisableReports(getUserId()); LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds); return Route.getObjects(getUserId(), deviceIds, groupIds, from, to); @@ -110,7 +110,7 @@ public class ReportResource extends BaseResource { public Response getRouteExcel( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail) - throws SQLException, IOException { + throws StorageException, IOException { Context.getPermissionsManager().checkDisableReports(getUserId()); return executeReport(getUserId(), mail, stream -> { LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds); @@ -123,7 +123,7 @@ public class ReportResource extends BaseResource { public Collection getEvents( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("type") final List types, - @QueryParam("from") Date from, @QueryParam("to") Date to) throws SQLException { + @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { Context.getPermissionsManager().checkDisableReports(getUserId()); LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds); return Events.getObjects(getUserId(), deviceIds, groupIds, types, from, to); @@ -136,7 +136,7 @@ public class ReportResource extends BaseResource { @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("type") final List types, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail) - throws SQLException, IOException { + throws StorageException, IOException { Context.getPermissionsManager().checkDisableReports(getUserId()); return executeReport(getUserId(), mail, stream -> { LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds); @@ -149,7 +149,7 @@ public class ReportResource extends BaseResource { public Collection getSummary( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("daily") boolean daily) - throws SQLException { + throws StorageException { Context.getPermissionsManager().checkDisableReports(getUserId()); LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds); return Summary.getObjects(getUserId(), deviceIds, groupIds, from, to, daily); @@ -162,7 +162,7 @@ public class ReportResource extends BaseResource { @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("daily") boolean daily, @QueryParam("mail") boolean mail) - throws SQLException, IOException { + throws StorageException, IOException { Context.getPermissionsManager().checkDisableReports(getUserId()); return executeReport(getUserId(), mail, stream -> { LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds); @@ -175,7 +175,7 @@ public class ReportResource extends BaseResource { @Produces(MediaType.APPLICATION_JSON) public Collection getTrips( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("from") Date from, @QueryParam("to") Date to) throws SQLException { + @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { Context.getPermissionsManager().checkDisableReports(getUserId()); LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds); return Trips.getObjects(getUserId(), deviceIds, groupIds, from, to); @@ -187,7 +187,7 @@ public class ReportResource extends BaseResource { public Response getTripsExcel( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail) - throws SQLException, IOException { + throws StorageException, IOException { Context.getPermissionsManager().checkDisableReports(getUserId()); return executeReport(getUserId(), mail, stream -> { LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds); @@ -200,7 +200,7 @@ public class ReportResource extends BaseResource { @Produces(MediaType.APPLICATION_JSON) public Collection getStops( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("from") Date from, @QueryParam("to") Date to) throws SQLException { + @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { Context.getPermissionsManager().checkDisableReports(getUserId()); LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds); return Stops.getObjects(getUserId(), deviceIds, groupIds, from, to); @@ -212,7 +212,7 @@ public class ReportResource extends BaseResource { public Response getStopsExcel( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail) - throws SQLException, IOException { + throws StorageException, IOException { Context.getPermissionsManager().checkDisableReports(getUserId()); return executeReport(getUserId(), mail, stream -> { LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds); diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index 91488afff..8096c66fa 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -19,6 +19,7 @@ import org.traccar.Context; import org.traccar.api.BaseResource; import org.traccar.helper.LogAction; import org.traccar.model.Server; +import org.traccar.storage.StorageException; import javax.annotation.security.PermitAll; import javax.ws.rs.Consumes; @@ -29,7 +30,6 @@ import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import java.sql.SQLException; @Path("server") @Produces(MediaType.APPLICATION_JSON) @@ -38,7 +38,7 @@ public class ServerResource extends BaseResource { @PermitAll @GET - public Server get(@QueryParam("force") boolean force) throws SQLException { + public Server get(@QueryParam("force") boolean force) throws StorageException { if (force) { return Context.getDataManager().getServer(); } else { @@ -47,7 +47,7 @@ public class ServerResource extends BaseResource { } @PUT - public Response update(Server entity) throws SQLException { + public Response update(Server entity) throws StorageException { Context.getPermissionsManager().checkAdmin(getUserId()); Context.getPermissionsManager().updateServer(entity); LogAction.edit(getUserId(), entity); diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 60ce5490a..8422e0b49 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -21,6 +21,7 @@ import org.traccar.helper.DataConverter; import org.traccar.helper.ServletHelper; import org.traccar.helper.LogAction; import org.traccar.model.User; +import org.traccar.storage.StorageException; import javax.annotation.security.PermitAll; import javax.servlet.http.Cookie; @@ -40,7 +41,6 @@ import javax.ws.rs.core.Response; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; -import java.sql.SQLException; @Path("session") @Produces(MediaType.APPLICATION_JSON) @@ -56,7 +56,7 @@ public class SessionResource extends BaseResource { @PermitAll @GET - public User get(@QueryParam("token") String token) throws SQLException, UnsupportedEncodingException { + public User get(@QueryParam("token") String token) throws StorageException, UnsupportedEncodingException { if (token != null) { User user = Context.getUsersManager().getUserByToken(token); @@ -107,7 +107,7 @@ public class SessionResource extends BaseResource { @PermitAll @POST public User add( - @FormParam("email") String email, @FormParam("password") String password) throws SQLException { + @FormParam("email") String email, @FormParam("password") String password) throws StorageException { User user = Context.getPermissionsManager().login(email, password); if (user != null) { request.getSession().setAttribute(USER_ID_KEY, user.getId()); diff --git a/src/main/java/org/traccar/api/resource/StatisticsResource.java b/src/main/java/org/traccar/api/resource/StatisticsResource.java index 58073e7d1..5c0734877 100644 --- a/src/main/java/org/traccar/api/resource/StatisticsResource.java +++ b/src/main/java/org/traccar/api/resource/StatisticsResource.java @@ -18,6 +18,7 @@ package org.traccar.api.resource; import org.traccar.Context; import org.traccar.api.BaseResource; import org.traccar.model.Statistics; +import org.traccar.storage.StorageException; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -25,7 +26,6 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; -import java.sql.SQLException; import java.util.Collection; import java.util.Date; @@ -36,7 +36,7 @@ public class StatisticsResource extends BaseResource { @GET public Collection get( - @QueryParam("from") Date from, @QueryParam("to") Date to) throws SQLException { + @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { Context.getPermissionsManager().checkAdmin(getUserId()); return Context.getDataManager().getStatistics(from, to); } diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java index d54cc2382..83bb8fd0b 100644 --- a/src/main/java/org/traccar/api/resource/UserResource.java +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -22,6 +22,7 @@ import org.traccar.database.UsersManager; import org.traccar.helper.LogAction; import org.traccar.model.ManagedUser; import org.traccar.model.User; +import org.traccar.storage.StorageException; import javax.annotation.security.PermitAll; import javax.ws.rs.Consumes; @@ -67,7 +68,7 @@ public class UserResource extends BaseObjectResource { @Override @PermitAll @POST - public Response add(User entity) throws SQLException { + public Response add(User entity) throws StorageException { if (!Context.getPermissionsManager().getUserAdmin(getUserId())) { Context.getPermissionsManager().checkUserUpdate(getUserId(), new User(), entity); if (Context.getPermissionsManager().getUserManager(getUserId())) { diff --git a/src/main/java/org/traccar/database/BaseObjectManager.java b/src/main/java/org/traccar/database/BaseObjectManager.java index be6310033..dd8b3bae4 100644 --- a/src/main/java/org/traccar/database/BaseObjectManager.java +++ b/src/main/java/org/traccar/database/BaseObjectManager.java @@ -16,7 +16,6 @@ */ package org.traccar.database; -import java.sql.SQLException; import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; @@ -29,6 +28,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.model.BaseModel; +import org.traccar.storage.StorageException; public class BaseObjectManager { @@ -102,7 +102,7 @@ public class BaseObjectManager { removeCachedItem(cachedItemId); } } - } catch (SQLException error) { + } catch (StorageException error) { LOGGER.warn("Error refreshing items", error); } finally { writeUnlock(); @@ -119,7 +119,7 @@ public class BaseObjectManager { } } - public void addItem(T item) throws SQLException { + public void addItem(T item) throws StorageException { dataManager.addObject(item); addNewItem(item); } @@ -133,7 +133,7 @@ public class BaseObjectManager { } } - public void updateItem(T item) throws SQLException { + public void updateItem(T item) throws StorageException { dataManager.updateObject(item); updateCachedItem(item); } @@ -147,7 +147,7 @@ public class BaseObjectManager { } } - public void removeItem(long itemId) throws SQLException { + public void removeItem(long itemId) throws StorageException { BaseModel item = getById(itemId); if (item != null) { dataManager.removeObject(baseClass, itemId); diff --git a/src/main/java/org/traccar/database/ConnectionManager.java b/src/main/java/org/traccar/database/ConnectionManager.java index e12d44612..359061f00 100644 --- a/src/main/java/org/traccar/database/ConnectionManager.java +++ b/src/main/java/org/traccar/database/ConnectionManager.java @@ -30,9 +30,9 @@ import org.traccar.model.Device; import org.traccar.model.DeviceState; import org.traccar.model.Event; import org.traccar.model.Position; +import org.traccar.storage.StorageException; import java.net.SocketAddress; -import java.sql.SQLException; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -127,8 +127,8 @@ public class ConnectionManager { try { Context.getDeviceManager().updateDeviceStatus(device); - } catch (SQLException error) { - LOGGER.warn("Update device status error", error); + } catch (StorageException e) { + LOGGER.warn("Update device status error", e); } updateDevice(device); diff --git a/src/main/java/org/traccar/database/DataManager.java b/src/main/java/org/traccar/database/DataManager.java index 199167419..303b8e033 100644 --- a/src/main/java/org/traccar/database/DataManager.java +++ b/src/main/java/org/traccar/database/DataManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,15 +41,20 @@ import org.traccar.model.Group; import org.traccar.model.Maintenance; import org.traccar.model.ManagedUser; import org.traccar.model.Notification; -import org.traccar.model.Order; import org.traccar.model.Permission; import org.traccar.model.Position; import org.traccar.model.Server; import org.traccar.model.Statistics; import org.traccar.model.User; +import org.traccar.storage.DatabaseStorage; import org.traccar.storage.QueryBuilder; -import org.traccar.storage.QueryExtended; -import org.traccar.storage.QueryIgnore; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Limit; +import org.traccar.storage.query.Order; +import org.traccar.storage.query.Request; import javax.sql.DataSource; import java.beans.Introspector; @@ -57,11 +62,10 @@ import java.io.File; import java.lang.reflect.Method; import java.net.URL; import java.sql.SQLException; -import java.util.Arrays; import java.util.Collection; import java.util.Date; -import java.util.HashSet; -import java.util.Set; +import java.util.LinkedList; +import java.util.List; public class DataManager { @@ -81,6 +85,8 @@ public class DataManager { return dataSource; } + private final Storage storage; + private boolean generateQueries; private final boolean forceLdap; @@ -92,6 +98,8 @@ public class DataManager { initDatabase(); initDatabaseSchema(); + + storage = new DatabaseStorage(dataSource); } private void initDatabase() throws Exception { @@ -134,58 +142,6 @@ public class DataManager { dataSource = new HikariDataSource(hikariConfig); } - public static String constructObjectQuery(String action, Class clazz, boolean extended) { - switch (action) { - case ACTION_INSERT: - case ACTION_UPDATE: - StringBuilder result = new StringBuilder(); - StringBuilder fields = new StringBuilder(); - StringBuilder values = new StringBuilder(); - - Set methods = new HashSet<>(Arrays.asList(clazz.getMethods())); - methods.removeAll(Arrays.asList(Object.class.getMethods())); - methods.removeAll(Arrays.asList(BaseModel.class.getMethods())); - for (Method method : methods) { - boolean skip; - if (extended) { - skip = !method.isAnnotationPresent(QueryExtended.class); - } else { - skip = method.isAnnotationPresent(QueryIgnore.class) - || method.isAnnotationPresent(QueryExtended.class) && !action.equals(ACTION_INSERT); - } - if (!skip && method.getName().startsWith("get") && method.getParameterTypes().length == 0) { - String name = Introspector.decapitalize(method.getName().substring(3)); - if (action.equals(ACTION_INSERT)) { - fields.append(name).append(", "); - values.append(":").append(name).append(", "); - } else { - fields.append(name).append(" = :").append(name).append(", "); - } - } - } - fields.setLength(fields.length() - 2); - if (action.equals(ACTION_INSERT)) { - values.setLength(values.length() - 2); - result.append("INSERT INTO ").append(getObjectsTableName(clazz)).append(" ("); - result.append(fields).append(") "); - result.append("VALUES (").append(values).append(")"); - } else { - result.append("UPDATE ").append(getObjectsTableName(clazz)).append(" SET "); - result.append(fields); - result.append(" WHERE id = :id"); - } - return result.toString(); - case ACTION_SELECT_ALL: - return "SELECT * FROM " + getObjectsTableName(clazz); - case ACTION_SELECT: - return "SELECT * FROM " + getObjectsTableName(clazz) + " WHERE id = :id"; - case ACTION_DELETE: - return "DELETE FROM " + getObjectsTableName(clazz) + " WHERE id = :id"; - default: - throw new IllegalArgumentException("Unknown action"); - } - } - public static String constructPermissionQuery(String action, Class owner, Class property) { switch (action) { case ACTION_SELECT_ALL: @@ -204,39 +160,6 @@ public class DataManager { } } - private String getQuery(String key) { - String query = config.getString(key); - if (query == null) { - LOGGER.info("Query not provided: " + key); - } - return query; - } - - public String getQuery(String action, Class clazz) { - return getQuery(action, clazz, false); - } - - public String getQuery(String action, Class clazz, boolean extended) { - String queryName; - if (action.equals(ACTION_SELECT_ALL)) { - queryName = "database.select" + clazz.getSimpleName() + "s"; - } else { - queryName = "database." + action.toLowerCase() + clazz.getSimpleName(); - if (extended) { - queryName += "Extended"; - } - } - String query = config.getString(queryName); - if (query == null) { - if (generateQueries) { - query = constructObjectQuery(action, clazz, extended); - } else { - LOGGER.info("Query not provided: " + queryName); - } - } - return query; - } - public String getQuery(String action, Class owner, Class property) { String queryName; switch (action) { @@ -302,10 +225,12 @@ public class DataManager { } } - public User login(String email, String password) throws SQLException { - User user = QueryBuilder.create(dataSource, getQuery("database.loginUser")) - .setString("email", email.trim()) - .executeQuerySingle(User.class); + public User login(String email, String password) throws StorageException { + User user = storage.getObject(User.class, new Request( + new Columns.Include("id", "login", "hashedPassword", "salt"), + new Condition.Or( + new Condition.Equals("email", "email", email.trim()), + new Condition.Equals("login", "email")))); LdapProvider ldapProvider = Context.getLdapProvider(); if (user != null) { if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password) @@ -322,57 +247,75 @@ public class DataManager { return null; } - public void updateDeviceStatus(Device device) throws SQLException { - QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, Device.class, true)) - .setObject(device) - .executeUpdate(); + public void updateUserPassword(User user) throws StorageException { + storage.updateObject(user, new Request( + new Columns.Include("hashedPassword", "salt"), + new Condition.Equals("id", "id"))); } - public Collection getPositions(long deviceId, Date from, Date to) throws SQLException { - return QueryBuilder.create(dataSource, getQuery("database.selectPositions")) - .setLong("deviceId", deviceId) - .setDate("from", from) - .setDate("to", to) - .executeQuery(Position.class); + public void updateDeviceStatus(Device device) throws StorageException { + storage.updateObject(device, new Request( + new Columns.Include("lastUpdate"), + new Condition.Equals("id", "id"))); } - public Position getPrecedingPosition(long deviceId, Date date) throws SQLException { - return QueryBuilder.create(dataSource, getQuery("database.selectPrecedingPosition")) - .setLong("deviceId", deviceId) - .setDate("time", date) - .executeQuerySingle(Position.class); + public Collection getPositions(long deviceId, Date from, Date to) throws StorageException { + return storage.getObjects(Position.class, new Request( + new Columns.All(), + new Condition.And( + new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Between("fixTime", "from", from, "to", to)), + new Order("fixTime"))); } - public void updateLatestPosition(Position position) throws SQLException { - QueryBuilder.create(dataSource, getQuery("database.updateLatestPosition")) - .setDate("now", new Date()) - .setObject(position) - .executeUpdate(); + public Position getPrecedingPosition(long deviceId, Date date) throws StorageException { + return storage.getObject(Position.class, new Request( + new Columns.All(), + new Condition.And( + new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Compare("fixTime", "<=", "time", date)), + new Order(true, "fixTime"), + new Limit(1))); } - public Collection getLatestPositions() throws SQLException { - return QueryBuilder.create(dataSource, getQuery("database.selectLatestPositions")) - .executeQuery(Position.class); + public void updateLatestPosition(Position position) throws StorageException { + Device device = new Device(); + device.setId(position.getDeviceId()); + device.setPositionId(position.getId()); + storage.updateObject(device, new Request( + new Columns.Include("positionId"), + new Condition.Equals("id", "id"))); + } + + public Collection getLatestPositions() throws StorageException { + List positions = new LinkedList<>(); + List devices = storage.getObjects(Device.class, new Request(new Columns.Include("positionId"))); + for (Device device : devices) { + positions.addAll(storage.getObjects(Position.class, new Request( + new Columns.All(), + new Condition.Equals("id", "id", device.getPositionId())))); + } + return positions; } - public Server getServer() throws SQLException { - return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, Server.class)) - .executeQuerySingle(Server.class); + public Server getServer() throws StorageException { + return storage.getObject(Server.class, new Request(new Columns.All())); } - public Collection getEvents(long deviceId, Date from, Date to) throws SQLException { - return QueryBuilder.create(dataSource, getQuery("database.selectEvents")) - .setLong("deviceId", deviceId) - .setDate("from", from) - .setDate("to", to) - .executeQuery(Event.class); + public Collection getEvents(long deviceId, Date from, Date to) throws StorageException { + return storage.getObjects(Event.class, new Request( + new Columns.All(), + new Condition.And( + new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Between("eventTime", "from", from, "to", to)), + new Order("eventTime"))); } - public Collection getStatistics(Date from, Date to) throws SQLException { - return QueryBuilder.create(dataSource, getQuery("database.selectStatistics")) - .setDate("from", from) - .setDate("to", to) - .executeQuery(Statistics.class); + public Collection getStatistics(Date from, Date to) throws StorageException { + return storage.getObjects(Statistics.class, new Request( + new Columns.All(), + new Condition.Between("captureTime", "from", from, "to", to), + new Order("captureTime"))); } public static Class getClassByName(String name) throws ClassNotFoundException { @@ -400,7 +343,7 @@ public class DataManager { case "notification": return Notification.class; case "order": - return Order.class; + return org.traccar.model.Order.class; default: throw new ClassNotFoundException(); } @@ -412,51 +355,49 @@ public class DataManager { } public Collection getPermissions(Class owner, Class property) - throws SQLException, ClassNotFoundException { - return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, owner, property)) - .executePermissionsQuery(); + throws StorageException, ClassNotFoundException { + try { + return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, owner, property)) + .executePermissionsQuery(); + } catch (SQLException e) { + throw new StorageException(e); + } } public void linkObject(Class owner, long ownerId, Class property, long propertyId, boolean link) - throws SQLException { + throws StorageException { + try { QueryBuilder.create(dataSource, getQuery(link ? ACTION_INSERT : ACTION_DELETE, owner, property)) .setLong(makeNameId(owner), ownerId) .setLong(makeNameId(property), propertyId) .executeUpdate(); + } catch (SQLException e) { + throw new StorageException(e); + } } - public T getObject(Class clazz, long entityId) throws SQLException { - return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT, clazz)) - .setLong("id", entityId) - .executeQuerySingle(clazz); + public T getObject(Class clazz, long entityId) throws StorageException { + return storage.getObject(clazz, new Request( + new Columns.All(), + new Condition.Equals("id", "id", entityId))); } - public Collection getObjects(Class clazz) throws SQLException { - return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, clazz)) - .executeQuery(clazz); + public Collection getObjects(Class clazz) throws StorageException { + return storage.getObjects(clazz, new Request(new Columns.All())); } - public void addObject(BaseModel entity) throws SQLException { - entity.setId(QueryBuilder.create(dataSource, getQuery(ACTION_INSERT, entity.getClass()), true) - .setObject(entity) - .executeUpdate()); + public void addObject(BaseModel entity) throws StorageException { + entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id")))); } - public void updateObject(BaseModel entity) throws SQLException { - QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, entity.getClass())) - .setObject(entity) - .executeUpdate(); - if (entity instanceof User && ((User) entity).getHashedPassword() != null) { - QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, User.class, true)) - .setObject(entity) - .executeUpdate(); - } + public void updateObject(BaseModel entity) throws StorageException { + storage.updateObject(entity, new Request( + new Columns.Exclude("id"), + new Condition.Equals("id", "id"))); } - public void removeObject(Class clazz, long entityId) throws SQLException { - QueryBuilder.create(dataSource, getQuery(ACTION_DELETE, clazz)) - .setLong("id", entityId) - .executeUpdate(); + public void removeObject(Class clazz, long entityId) throws StorageException { + storage.removeObject(clazz, new Request(new Condition.Equals("id", "id", entityId))); } } diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java index c8a99274c..40591e869 100644 --- a/src/main/java/org/traccar/database/DeviceManager.java +++ b/src/main/java/org/traccar/database/DeviceManager.java @@ -37,6 +37,7 @@ import org.traccar.model.DeviceAccumulators; import org.traccar.model.Group; import org.traccar.model.Position; import org.traccar.model.Server; +import org.traccar.storage.StorageException; public class DeviceManager extends BaseObjectManager implements IdentityManager, ManagableObjects { @@ -94,13 +95,13 @@ public class DeviceManager extends BaseObjectManager implements Identity } return device.getId(); - } catch (SQLException e) { + } catch (StorageException e) { LOGGER.warn("Automatic device registration error", e); return 0; } } - public void updateDeviceCache(boolean force) throws SQLException { + public void updateDeviceCache(boolean force) { long lastUpdate = devicesLastUpdate.get(); if ((force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay) && devicesLastUpdate.compareAndSet(lastUpdate, System.currentTimeMillis())) { @@ -144,24 +145,11 @@ public class DeviceManager extends BaseObjectManager implements Identity return defaultPassword; } - public Device getDeviceByPhone(String phone) { - try { - readLock(); - return devicesByPhone.get(phone); - } finally { - readUnlock(); - } - } - @Override public Set getAllItems() { Set result = super.getAllItems(); if (result.isEmpty()) { - try { - updateDeviceCache(true); - } catch (SQLException e) { - LOGGER.warn("Update device cache error", e); - } + updateDeviceCache(true); result = super.getAllItems(); } return result; @@ -309,7 +297,7 @@ public class DeviceManager extends BaseObjectManager implements Identity positions.remove(deviceId); } - public void updateDeviceStatus(Device device) throws SQLException { + public void updateDeviceStatus(Device device) throws StorageException { getDataManager().updateDeviceStatus(device); Device cachedDevice = getById(device.getId()); if (cachedDevice != null) { @@ -323,7 +311,7 @@ public class DeviceManager extends BaseObjectManager implements Identity for (Position position : getDataManager().getLatestPositions()) { positions.put(position.getDeviceId(), position); } - } catch (SQLException error) { + } catch (StorageException error) { LOGGER.warn("Load latest positions error", error); } } @@ -334,7 +322,7 @@ public class DeviceManager extends BaseObjectManager implements Identity return lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) >= 0; } - public void updateLatestPosition(Position position) throws SQLException { + public void updateLatestPosition(Position position) throws StorageException { if (isLatestPosition(position)) { @@ -451,7 +439,7 @@ public class DeviceManager extends BaseObjectManager implements Identity return result; } - public void resetDeviceAccumulators(DeviceAccumulators deviceAccumulators) throws SQLException { + public void resetDeviceAccumulators(DeviceAccumulators deviceAccumulators) throws StorageException { Position last = positions.get(deviceAccumulators.getDeviceId()); if (last != null) { if (deviceAccumulators.getTotalDistance() != null) { diff --git a/src/main/java/org/traccar/database/ExtendedObjectManager.java b/src/main/java/org/traccar/database/ExtendedObjectManager.java index 93e5820fb..006ed47b2 100644 --- a/src/main/java/org/traccar/database/ExtendedObjectManager.java +++ b/src/main/java/org/traccar/database/ExtendedObjectManager.java @@ -16,7 +16,6 @@ */ package org.traccar.database; -import java.sql.SQLException; import java.util.Collection; import java.util.HashSet; import java.util.Map; @@ -30,6 +29,7 @@ import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.model.Permission; import org.traccar.model.BaseModel; +import org.traccar.storage.StorageException; public abstract class ExtendedObjectManager extends SimpleObjectManager { @@ -87,7 +87,7 @@ public abstract class ExtendedObjectManager extends SimpleO } @Override - public void removeItem(long itemId) throws SQLException { + public void removeItem(long itemId) throws StorageException { super.removeItem(itemId); refreshExtendedPermissions(); } @@ -133,7 +133,7 @@ public abstract class ExtendedObjectManager extends SimpleO } } - } catch (SQLException | ClassNotFoundException error) { + } catch (StorageException | ClassNotFoundException error) { LOGGER.warn("Refresh permissions error", error); } finally { writeUnlock(); diff --git a/src/main/java/org/traccar/database/GroupsManager.java b/src/main/java/org/traccar/database/GroupsManager.java index c35f35f93..dafddc0cc 100644 --- a/src/main/java/org/traccar/database/GroupsManager.java +++ b/src/main/java/org/traccar/database/GroupsManager.java @@ -16,12 +16,12 @@ */ package org.traccar.database; -import java.sql.SQLException; import java.util.HashSet; import java.util.Set; import org.traccar.Context; import org.traccar.model.Group; +import org.traccar.storage.StorageException; public class GroupsManager extends BaseObjectManager implements ManagableObjects { @@ -57,7 +57,7 @@ public class GroupsManager extends BaseObjectManager implements Managable } @Override - public void updateItem(Group group) throws SQLException { + public void updateItem(Group group) throws StorageException { checkGroupCycles(group); super.updateItem(group); } diff --git a/src/main/java/org/traccar/database/NotificationManager.java b/src/main/java/org/traccar/database/NotificationManager.java index 9f9a83cd2..f358b1d4d 100644 --- a/src/main/java/org/traccar/database/NotificationManager.java +++ b/src/main/java/org/traccar/database/NotificationManager.java @@ -18,7 +18,6 @@ package org.traccar.database; import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.sql.SQLException; import java.util.Arrays; import java.util.Date; import java.util.HashSet; @@ -36,6 +35,7 @@ import org.traccar.model.Event; import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.Typed; +import org.traccar.storage.StorageException; public class NotificationManager extends ExtendedObjectManager { @@ -66,7 +66,7 @@ public class NotificationManager extends ExtendedObjectManager { public void updateEvent(Event event, Position position) { try { getDataManager().addObject(event); - } catch (SQLException error) { + } catch (StorageException error) { LOGGER.warn("Event save error", error); } diff --git a/src/main/java/org/traccar/database/PermissionsManager.java b/src/main/java/org/traccar/database/PermissionsManager.java index ab841a521..2bb808033 100644 --- a/src/main/java/org/traccar/database/PermissionsManager.java +++ b/src/main/java/org/traccar/database/PermissionsManager.java @@ -33,8 +33,8 @@ import org.traccar.model.Order; import org.traccar.model.Permission; import org.traccar.model.Server; import org.traccar.model.User; +import org.traccar.storage.StorageException; -import java.sql.SQLException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -156,7 +156,7 @@ public class PermissionsManager { public void refreshServer() { try { server = dataManager.getServer(); - } catch (SQLException error) { + } catch (StorageException error) { LOGGER.warn("Refresh server config error", error); } } @@ -193,7 +193,7 @@ public class PermissionsManager { } } - } catch (SQLException | ClassNotFoundException error) { + } catch (StorageException | ClassNotFoundException error) { LOGGER.warn("Refresh device permissions error", error); } @@ -499,12 +499,12 @@ public class PermissionsManager { return server; } - public void updateServer(Server server) throws SQLException { + public void updateServer(Server server) throws StorageException { dataManager.updateObject(server); this.server = server; } - public User login(String email, String password) throws SQLException { + public User login(String email, String password) throws StorageException { User user = dataManager.login(email, password); if (user != null) { checkUserEnabled(user.getId()); diff --git a/src/main/java/org/traccar/database/SimpleObjectManager.java b/src/main/java/org/traccar/database/SimpleObjectManager.java index eb8284d4e..78701720f 100644 --- a/src/main/java/org/traccar/database/SimpleObjectManager.java +++ b/src/main/java/org/traccar/database/SimpleObjectManager.java @@ -16,7 +16,6 @@ */ package org.traccar.database; -import java.sql.SQLException; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -28,6 +27,7 @@ import org.traccar.Context; import org.traccar.model.BaseModel; import org.traccar.model.Permission; import org.traccar.model.User; +import org.traccar.storage.StorageException; public abstract class SimpleObjectManager extends BaseObjectManager implements ManagableObjects { @@ -83,7 +83,7 @@ public abstract class SimpleObjectManager extends BaseObjec Set items = userItems.computeIfAbsent(permission.getOwnerId(), key -> new HashSet<>()); items.add(permission.getPropertyId()); } - } catch (SQLException | ClassNotFoundException error) { + } catch (StorageException | ClassNotFoundException error) { LOGGER.warn("Error getting permissions", error); } finally { writeUnlock(); @@ -92,7 +92,7 @@ public abstract class SimpleObjectManager extends BaseObjec } @Override - public void removeItem(long itemId) throws SQLException { + public void removeItem(long itemId) throws StorageException { super.removeItem(itemId); refreshUserItems(); } diff --git a/src/main/java/org/traccar/database/StatisticsManager.java b/src/main/java/org/traccar/database/StatisticsManager.java index 4ad6d9d5c..3579ce7a5 100644 --- a/src/main/java/org/traccar/database/StatisticsManager.java +++ b/src/main/java/org/traccar/database/StatisticsManager.java @@ -23,12 +23,12 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.DateUtil; import org.traccar.model.Statistics; +import org.traccar.storage.StorageException; import javax.inject.Inject; import javax.ws.rs.client.Client; import javax.ws.rs.client.Entity; import javax.ws.rs.core.Form; -import java.sql.SQLException; import java.util.Calendar; import java.util.Date; import java.util.HashMap; @@ -106,7 +106,7 @@ public class StatisticsManager { try { dataManager.addObject(statistics); - } catch (SQLException e) { + } catch (StorageException e) { LOGGER.warn("Error saving statistics", e); } diff --git a/src/main/java/org/traccar/database/UsersManager.java b/src/main/java/org/traccar/database/UsersManager.java index b741a85b6..31759dc8b 100644 --- a/src/main/java/org/traccar/database/UsersManager.java +++ b/src/main/java/org/traccar/database/UsersManager.java @@ -21,6 +21,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.traccar.model.User; +import org.traccar.storage.StorageException; public class UsersManager extends SimpleObjectManager { @@ -58,6 +59,14 @@ public class UsersManager extends SimpleObjectManager { } } + @Override + public void updateItem(User user) throws StorageException { + if (user.getHashedPassword() != null) { + getDataManager().updateUserPassword(user); + } + super.updateItem(user); + } + @Override protected void removeCachedItem(long userId) { User cachedUser = getById(userId); diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index 2b850c755..e576a26b8 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -24,8 +24,8 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; +import org.traccar.storage.StorageException; -import java.sql.SQLException; import java.util.Date; @ChannelHandler.Sharable @@ -174,7 +174,7 @@ public class FilterHandler extends BaseDataHandler { try { Date newFixTime = position.getFixTime(); preceding = Context.getDataManager().getPrecedingPosition(deviceId, newFixTime); - } catch (SQLException e) { + } catch (StorageException e) { LOGGER.warn("Error retrieving preceding position; fallbacking to last received position.", e); preceding = getLastReceivedPosition(deviceId); } diff --git a/src/main/java/org/traccar/model/Attribute.java b/src/main/java/org/traccar/model/Attribute.java index 45d40b3ec..65f2e3881 100644 --- a/src/main/java/org/traccar/model/Attribute.java +++ b/src/main/java/org/traccar/model/Attribute.java @@ -16,6 +16,9 @@ */ package org.traccar.model; +import org.traccar.storage.StorageName; + +@StorageName("tc_attributes") public class Attribute extends BaseModel { private String description; diff --git a/src/main/java/org/traccar/model/Calendar.java b/src/main/java/org/traccar/model/Calendar.java index af6364626..102c0be52 100644 --- a/src/main/java/org/traccar/model/Calendar.java +++ b/src/main/java/org/traccar/model/Calendar.java @@ -25,6 +25,7 @@ import net.fortuna.ical4j.model.DateTime; import net.fortuna.ical4j.model.Period; import net.fortuna.ical4j.model.component.CalendarComponent; import org.traccar.storage.QueryIgnore; +import org.traccar.storage.StorageName; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -32,6 +33,7 @@ import java.time.Duration; import java.util.Collection; import java.util.Date; +@StorageName("tc_calendars") public class Calendar extends ExtendedModel { private String name; diff --git a/src/main/java/org/traccar/model/Command.java b/src/main/java/org/traccar/model/Command.java index 71bc232e9..03961c7b2 100644 --- a/src/main/java/org/traccar/model/Command.java +++ b/src/main/java/org/traccar/model/Command.java @@ -18,7 +18,9 @@ package org.traccar.model; import org.traccar.storage.QueryIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.traccar.storage.StorageName; +@StorageName("tc_commands") @JsonIgnoreProperties(ignoreUnknown = true) public class Command extends Message implements Cloneable { @@ -104,6 +106,12 @@ public class Command extends Message implements Cloneable { return super.getDeviceId(); } + @QueryIgnore + @Override + public void setDeviceId(long deviceId) { + super.setDeviceId(deviceId); + } + private String description; public String getDescription() { diff --git a/src/main/java/org/traccar/model/Device.java b/src/main/java/org/traccar/model/Device.java index 46de8003d..836a6709c 100644 --- a/src/main/java/org/traccar/model/Device.java +++ b/src/main/java/org/traccar/model/Device.java @@ -20,7 +20,9 @@ import java.util.List; import org.traccar.storage.QueryExtended; import org.traccar.storage.QueryIgnore; +import org.traccar.storage.StorageName; +@StorageName("tc_devices") public class Device extends GroupedModel { private String name; @@ -54,13 +56,13 @@ public class Device extends GroupedModel { return status != null ? status : STATUS_OFFLINE; } + @QueryIgnore public void setStatus(String status) { this.status = status; } private Date lastUpdate; - @QueryExtended public Date getLastUpdate() { if (lastUpdate != null) { return new Date(lastUpdate.getTime()); @@ -69,6 +71,7 @@ public class Device extends GroupedModel { } } + @QueryExtended public void setLastUpdate(Date lastUpdate) { if (lastUpdate != null) { this.lastUpdate = new Date(lastUpdate.getTime()); @@ -84,6 +87,7 @@ public class Device extends GroupedModel { return positionId; } + @QueryIgnore public void setPositionId(long positionId) { this.positionId = positionId; } @@ -95,6 +99,7 @@ public class Device extends GroupedModel { return geofenceIds; } + @QueryIgnore public void setGeofenceIds(List geofenceIds) { this.geofenceIds = geofenceIds; } diff --git a/src/main/java/org/traccar/model/Driver.java b/src/main/java/org/traccar/model/Driver.java index 05f52fd4d..b9e023088 100644 --- a/src/main/java/org/traccar/model/Driver.java +++ b/src/main/java/org/traccar/model/Driver.java @@ -16,6 +16,9 @@ */ package org.traccar.model; +import org.traccar.storage.StorageName; + +@StorageName("tc_drivers") public class Driver extends ExtendedModel { private String name; @@ -37,4 +40,5 @@ public class Driver extends ExtendedModel { public void setUniqueId(String uniqueId) { this.uniqueId = uniqueId; } + } diff --git a/src/main/java/org/traccar/model/Event.java b/src/main/java/org/traccar/model/Event.java index a7a134ecf..6e3953fda 100644 --- a/src/main/java/org/traccar/model/Event.java +++ b/src/main/java/org/traccar/model/Event.java @@ -15,8 +15,11 @@ */ package org.traccar.model; +import org.traccar.storage.StorageName; + import java.util.Date; +@StorageName("tc_events") public class Event extends Message { public Event(String type, Position position) { diff --git a/src/main/java/org/traccar/model/Geofence.java b/src/main/java/org/traccar/model/Geofence.java index a451da9f5..5b857580d 100644 --- a/src/main/java/org/traccar/model/Geofence.java +++ b/src/main/java/org/traccar/model/Geofence.java @@ -26,7 +26,9 @@ import org.traccar.geofence.GeofencePolygon; import org.traccar.geofence.GeofencePolyline; import com.fasterxml.jackson.annotation.JsonIgnore; +import org.traccar.storage.StorageName; +@StorageName("tc_geofences") public class Geofence extends ScheduledModel { public static final String TYPE_GEOFENCE_CILCLE = "geofenceCircle"; diff --git a/src/main/java/org/traccar/model/Group.java b/src/main/java/org/traccar/model/Group.java index 91ea2319d..ff69f61fa 100644 --- a/src/main/java/org/traccar/model/Group.java +++ b/src/main/java/org/traccar/model/Group.java @@ -15,6 +15,9 @@ */ package org.traccar.model; +import org.traccar.storage.StorageName; + +@StorageName("tc_groups") public class Group extends GroupedModel { private String name; diff --git a/src/main/java/org/traccar/model/Maintenance.java b/src/main/java/org/traccar/model/Maintenance.java index 73f67ea96..cad100a3a 100644 --- a/src/main/java/org/traccar/model/Maintenance.java +++ b/src/main/java/org/traccar/model/Maintenance.java @@ -16,6 +16,9 @@ */ package org.traccar.model; +import org.traccar.storage.StorageName; + +@StorageName("tc_maintenances") public class Maintenance extends ExtendedModel { private String name; diff --git a/src/main/java/org/traccar/model/Notification.java b/src/main/java/org/traccar/model/Notification.java index 01ca2711c..95e446132 100644 --- a/src/main/java/org/traccar/model/Notification.java +++ b/src/main/java/org/traccar/model/Notification.java @@ -21,7 +21,9 @@ import java.util.Set; import org.traccar.storage.QueryIgnore; import com.fasterxml.jackson.annotation.JsonIgnore; +import org.traccar.storage.StorageName; +@StorageName("tc_notifications") public class Notification extends ScheduledModel { private boolean always; @@ -44,7 +46,6 @@ public class Notification extends ScheduledModel { this.type = type; } - private String notificators; public String getNotificators() { @@ -55,7 +56,6 @@ public class Notification extends ScheduledModel { this.notificators = transports; } - @JsonIgnore @QueryIgnore public Set getNotificatorsTypes() { diff --git a/src/main/java/org/traccar/model/Order.java b/src/main/java/org/traccar/model/Order.java index fe6d926b8..7d09b0a47 100644 --- a/src/main/java/org/traccar/model/Order.java +++ b/src/main/java/org/traccar/model/Order.java @@ -15,6 +15,9 @@ */ package org.traccar.model; +import org.traccar.storage.StorageName; + +@StorageName("tc_orders") public class Order extends ExtendedModel { private String uniqueId; diff --git a/src/main/java/org/traccar/model/Position.java b/src/main/java/org/traccar/model/Position.java index bbea58901..348370e2c 100644 --- a/src/main/java/org/traccar/model/Position.java +++ b/src/main/java/org/traccar/model/Position.java @@ -17,8 +17,11 @@ package org.traccar.model; import java.util.Date; +import com.fasterxml.jackson.annotation.JsonIgnore; import org.traccar.storage.QueryIgnore; +import org.traccar.storage.StorageName; +@StorageName("tc_positions") public class Position extends Message { public static final String KEY_ORIGINAL = "raw"; @@ -190,6 +193,7 @@ public class Position extends Message { this.fixTime = fixTime; } + @QueryIgnore public void setTime(Date time) { setDeviceTime(time); setFixTime(time); @@ -202,6 +206,7 @@ public class Position extends Message { return outdated; } + @QueryIgnore public void setOutdated(boolean outdated) { this.outdated = outdated; } @@ -296,10 +301,18 @@ public class Position extends Message { this.network = network; } - @Override + @JsonIgnore @QueryIgnore + @Override public String getType() { return super.getType(); } + @JsonIgnore + @QueryIgnore + @Override + public void setType(String type) { + super.setType(type); + } + } diff --git a/src/main/java/org/traccar/model/Server.java b/src/main/java/org/traccar/model/Server.java index fdb071a18..b48e84939 100644 --- a/src/main/java/org/traccar/model/Server.java +++ b/src/main/java/org/traccar/model/Server.java @@ -18,7 +18,9 @@ package org.traccar.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.traccar.Context; import org.traccar.storage.QueryIgnore; +import org.traccar.storage.StorageName; +@StorageName("tc_servers") @JsonIgnoreProperties(ignoreUnknown = true) public class Server extends ExtendedModel { diff --git a/src/main/java/org/traccar/model/Statistics.java b/src/main/java/org/traccar/model/Statistics.java index a9a117aef..0dc1b98e8 100644 --- a/src/main/java/org/traccar/model/Statistics.java +++ b/src/main/java/org/traccar/model/Statistics.java @@ -15,9 +15,12 @@ */ package org.traccar.model; +import org.traccar.storage.StorageName; + import java.util.Date; import java.util.Map; +@StorageName("tc_statistics") public class Statistics extends ExtendedModel { private Date captureTime; diff --git a/src/main/java/org/traccar/model/User.java b/src/main/java/org/traccar/model/User.java index 447cf691c..94828ab95 100644 --- a/src/main/java/org/traccar/model/User.java +++ b/src/main/java/org/traccar/model/User.java @@ -20,9 +20,11 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import org.traccar.storage.QueryExtended; import org.traccar.storage.QueryIgnore; import org.traccar.helper.Hashing; +import org.traccar.storage.StorageName; import java.util.Date; +@StorageName("tc_users") public class User extends ExtendedModel { private String name; diff --git a/src/main/java/org/traccar/reports/Events.java b/src/main/java/org/traccar/reports/Events.java index 66d9e708d..e4b905702 100644 --- a/src/main/java/org/traccar/reports/Events.java +++ b/src/main/java/org/traccar/reports/Events.java @@ -20,7 +20,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -35,6 +34,7 @@ import org.traccar.model.Geofence; import org.traccar.model.Group; import org.traccar.model.Maintenance; import org.traccar.reports.model.DeviceReport; +import org.traccar.storage.StorageException; public final class Events { @@ -42,7 +42,7 @@ public final class Events { } public static Collection getObjects(long userId, Collection deviceIds, Collection groupIds, - Collection types, Date from, Date to) throws SQLException { + Collection types, Date from, Date to) throws StorageException { ReportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { @@ -66,7 +66,7 @@ public final class Events { public static void getExcel(OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, - Collection types, Date from, Date to) throws SQLException, IOException { + Collection types, Date from, Date to) throws StorageException, IOException { ReportUtils.checkPeriodLimit(from, to); ArrayList devicesEvents = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); diff --git a/src/main/java/org/traccar/reports/Route.java b/src/main/java/org/traccar/reports/Route.java index 6adb00aae..4a5edd295 100644 --- a/src/main/java/org/traccar/reports/Route.java +++ b/src/main/java/org/traccar/reports/Route.java @@ -20,7 +20,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -31,6 +30,7 @@ import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.model.Position; import org.traccar.reports.model.DeviceReport; +import org.traccar.storage.StorageException; public final class Route { @@ -38,7 +38,7 @@ public final class Route { } public static Collection getObjects(long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException { + Date from, Date to) throws StorageException { ReportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { @@ -50,7 +50,7 @@ public final class Route { public static void getExcel(OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException, IOException { + Date from, Date to) throws StorageException, IOException { ReportUtils.checkPeriodLimit(from, to); ArrayList devicesRoutes = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); diff --git a/src/main/java/org/traccar/reports/Stops.java b/src/main/java/org/traccar/reports/Stops.java index 2036b0641..36a4a7549 100644 --- a/src/main/java/org/traccar/reports/Stops.java +++ b/src/main/java/org/traccar/reports/Stops.java @@ -21,7 +21,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -35,13 +34,14 @@ import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.reports.model.DeviceReport; import org.traccar.reports.model.StopReport; +import org.traccar.storage.StorageException; public final class Stops { private Stops() { } - private static Collection detectStops(long deviceId, Date from, Date to) throws SQLException { + private static Collection detectStops(long deviceId, Date from, Date to) throws StorageException { boolean ignoreOdometer = Context.getDeviceManager() .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true); @@ -55,7 +55,7 @@ public final class Stops { public static Collection getObjects( long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException { + Date from, Date to) throws StorageException { ReportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { @@ -67,7 +67,7 @@ public final class Stops { public static void getExcel( OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException, IOException { + Date from, Date to) throws StorageException, IOException { ReportUtils.checkPeriodLimit(from, to); ArrayList devicesStops = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); diff --git a/src/main/java/org/traccar/reports/Summary.java b/src/main/java/org/traccar/reports/Summary.java index d576ac1e6..4924af062 100644 --- a/src/main/java/org/traccar/reports/Summary.java +++ b/src/main/java/org/traccar/reports/Summary.java @@ -20,7 +20,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; @@ -31,6 +30,7 @@ import org.traccar.Context; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; import org.traccar.reports.model.SummaryReport; +import org.traccar.storage.StorageException; public final class Summary { @@ -97,7 +97,7 @@ public final class Summary { } private static Collection calculateSummaryResults( - long userId, long deviceId, Date from, Date to, boolean daily) throws SQLException { + long userId, long deviceId, Date from, Date to, boolean daily) throws StorageException { ArrayList positions = new ArrayList<>(Context.getDataManager().getPositions(deviceId, from, to)); @@ -122,7 +122,7 @@ public final class Summary { } public static Collection getObjects(long userId, Collection deviceIds, - Collection groupIds, Date from, Date to, boolean daily) throws SQLException { + Collection groupIds, Date from, Date to, boolean daily) throws StorageException { ReportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { @@ -134,7 +134,7 @@ public final class Summary { public static void getExcel(OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, - Date from, Date to, boolean daily) throws SQLException, IOException { + Date from, Date to, boolean daily) throws StorageException, IOException { ReportUtils.checkPeriodLimit(from, to); Collection summaries = getObjects(userId, deviceIds, groupIds, from, to, daily); String templatePath = Context.getConfig().getString("report.templatesPath", diff --git a/src/main/java/org/traccar/reports/Trips.java b/src/main/java/org/traccar/reports/Trips.java index 7c0cd6921..1461b869e 100644 --- a/src/main/java/org/traccar/reports/Trips.java +++ b/src/main/java/org/traccar/reports/Trips.java @@ -20,7 +20,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -34,13 +33,14 @@ import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.reports.model.DeviceReport; import org.traccar.reports.model.TripReport; +import org.traccar.storage.StorageException; public final class Trips { private Trips() { } - private static Collection detectTrips(long deviceId, Date from, Date to) throws SQLException { + private static Collection detectTrips(long deviceId, Date from, Date to) throws StorageException { boolean ignoreOdometer = Context.getDeviceManager() .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true); @@ -53,7 +53,7 @@ public final class Trips { } public static Collection getObjects(long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException { + Date from, Date to) throws StorageException { ReportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { @@ -65,7 +65,7 @@ public final class Trips { public static void getExcel(OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException, IOException { + Date from, Date to) throws StorageException, IOException { ReportUtils.checkPeriodLimit(from, to); ArrayList devicesTrips = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); diff --git a/src/main/java/org/traccar/storage/DatabaseStorage.java b/src/main/java/org/traccar/storage/DatabaseStorage.java index 0bcab7d20..2c893ebbc 100644 --- a/src/main/java/org/traccar/storage/DatabaseStorage.java +++ b/src/main/java/org/traccar/storage/DatabaseStorage.java @@ -2,6 +2,7 @@ package org.traccar.storage; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Limit; import org.traccar.storage.query.Order; import org.traccar.storage.query.Request; @@ -24,7 +25,7 @@ public class DatabaseStorage extends Storage { @Override public List getObjects(Class clazz, Request request) throws StorageException { StringBuilder query = new StringBuilder("SELECT "); - query.append(formatColumns(request.getColumns(), clazz, c -> c)); + query.append(formatColumns(request.getColumns(), clazz, "get", c -> c)); query.append(" FROM ").append(getTableName(clazz)); query.append(formatCondition(request.getCondition())); query.append(formatOrder(request.getOrder())); @@ -44,9 +45,9 @@ public class DatabaseStorage extends Storage { StringBuilder query = new StringBuilder("INSERT INTO "); query.append(getTableName(entity.getClass())); query.append("("); - query.append(formatColumns(request.getColumns(), entity.getClass(), c -> c)); + query.append(formatColumns(request.getColumns(), entity.getClass(), "set", c -> c)); query.append(") VALUES ("); - query.append(formatColumns(request.getColumns(), entity.getClass(), c -> ':' + c)); + query.append(formatColumns(request.getColumns(), entity.getClass(), "set", c -> ':' + c)); query.append(")"); try { QueryBuilder builder = QueryBuilder.create(dataSource, query.toString(), true); @@ -62,7 +63,7 @@ public class DatabaseStorage extends Storage { StringBuilder query = new StringBuilder("UPDATE "); query.append(getTableName(entity.getClass())); query.append(" SET "); - query.append(formatColumns(request.getColumns(), entity.getClass(), c -> c + " = :" + c)); + query.append(formatColumns(request.getColumns(), entity.getClass(), "set", c -> c + " = :" + c)); query.append(formatCondition(request.getCondition())); try { QueryBuilder builder = QueryBuilder.create(dataSource, query.toString()); @@ -101,31 +102,46 @@ public class DatabaseStorage extends Storage { } private Map getConditionVariables(Condition genericCondition) { - Map result = new HashMap<>(); - if (genericCondition instanceof Condition.Equals) { - Condition.Equals condition = (Condition.Equals) genericCondition; - result.put(condition.getVariable(), condition.getValue()); + Map results = new HashMap<>(); + if (genericCondition instanceof Condition.Compare) { + Condition.Compare condition = (Condition.Compare) genericCondition; + if (condition.getValue() != null) { + results.put(condition.getVariable(), condition.getValue()); + } } else if (genericCondition instanceof Condition.Between) { Condition.Between condition = (Condition.Between) genericCondition; - result.put(condition.getFromVariable(), condition.getFromValue()); - result.put(condition.getToVariable(), condition.getToValue()); + results.put(condition.getFromVariable(), condition.getFromValue()); + results.put(condition.getToVariable(), condition.getToValue()); + } else if (genericCondition instanceof Condition.Binary) { + Condition.Binary condition = (Condition.Binary) genericCondition; + results.putAll(getConditionVariables(condition.getFirst())); + results.putAll(getConditionVariables(condition.getSecond())); } - return result; + return results; } - private String formatColumns(Columns columns, Class clazz, Function mapper) { - return columns.getColumns(clazz).stream().map(mapper).collect(Collectors.joining(", ")); + private String formatColumns( + Columns columns, Class clazz, String type, Function mapper) { + return columns.getColumns(clazz, type).stream().map(mapper).collect(Collectors.joining(", ")); } private String formatCondition(Condition genericCondition) { + return formatCondition(genericCondition, true); + } + + private String formatCondition(Condition genericCondition, boolean appendWhere) { StringBuilder result = new StringBuilder(); if (genericCondition != null) { - result.append(" WHERE "); - if (genericCondition instanceof Condition.Equals) { + if (appendWhere) { + result.append(" WHERE "); + } + if (genericCondition instanceof Condition.Compare) { - Condition.Equals condition = (Condition.Equals) genericCondition; + Condition.Compare condition = (Condition.Compare) genericCondition; result.append(condition.getColumn()); - result.append(" == :"); + result.append(" "); + result.append(condition.getOperator()); + result.append(" :"); result.append(condition.getVariable()); } else if (genericCondition instanceof Condition.Between) { @@ -137,12 +153,14 @@ public class DatabaseStorage extends Storage { result.append(" AND :"); result.append(condition.getToVariable()); - } else if (genericCondition instanceof Condition.And) { + } else if (genericCondition instanceof Condition.Binary) { - Condition.And condition = (Condition.And) genericCondition; - result.append(formatCondition(condition.getFirst())); - result.append(" AND "); - result.append(formatCondition(condition.getSecond())); + Condition.Binary condition = (Condition.Binary) genericCondition; + result.append(formatCondition(condition.getFirst(), false)); + result.append(" "); + result.append(condition.getOperator()); + result.append(" "); + result.append(formatCondition(condition.getSecond(), false)); } } @@ -161,4 +179,13 @@ public class DatabaseStorage extends Storage { return result.toString(); } + private String formatLimit(Limit limit) { + StringBuilder result = new StringBuilder(); + if (limit != null) { + result.append(" LIMIT "); + result.append(limit.getValue()); + } + return result.toString(); + } + } diff --git a/src/main/java/org/traccar/storage/QueryBuilder.java b/src/main/java/org/traccar/storage/QueryBuilder.java index 838472c8b..edaacb74d 100644 --- a/src/main/java/org/traccar/storage/QueryBuilder.java +++ b/src/main/java/org/traccar/storage/QueryBuilder.java @@ -276,8 +276,7 @@ public final class QueryBuilder { Method[] methods = object.getClass().getMethods(); for (Method method : methods) { - if (method.getName().startsWith("get") && method.getParameterTypes().length == 0 - && !method.isAnnotationPresent(QueryIgnore.class)) { + if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) { String name = method.getName().substring(3); try { if (method.getReturnType().equals(boolean.class)) { @@ -412,8 +411,7 @@ public final class QueryBuilder { Method[] methods = clazz.getMethods(); for (final Method method : methods) { - if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 - && !method.isAnnotationPresent(QueryIgnore.class)) { + if (method.getName().startsWith("set") && method.getParameterTypes().length == 1) { final String name = method.getName().substring(3); diff --git a/src/main/java/org/traccar/storage/Storage.java b/src/main/java/org/traccar/storage/Storage.java index b95ce9505..3726fbf50 100644 --- a/src/main/java/org/traccar/storage/Storage.java +++ b/src/main/java/org/traccar/storage/Storage.java @@ -6,20 +6,17 @@ import java.util.List; public abstract class Storage { - abstract List getObjects(Class clazz, Request request) throws StorageException; + public abstract List getObjects(Class clazz, Request request) throws StorageException; - abstract long addObject(T entity, Request request) throws StorageException; + public abstract long addObject(T entity, Request request) throws StorageException; - abstract void updateObject(T entity, Request request) throws StorageException; + public abstract void updateObject(T entity, Request request) throws StorageException; - abstract void removeObject(Class clazz, Request request) throws StorageException; + public abstract void removeObject(Class clazz, Request request) throws StorageException; - T getObject(Class clazz, Request request) throws StorageException { + public T getObject(Class clazz, Request request) throws StorageException { var objects = getObjects(clazz, request); - if (objects.isEmpty()) { - throw new StorageException("No objects found"); - } - return objects.get(0); + return objects.isEmpty() ? null : objects.get(0); } } diff --git a/src/main/java/org/traccar/storage/query/Columns.java b/src/main/java/org/traccar/storage/query/Columns.java index 1a13665ee..196d2281c 100644 --- a/src/main/java/org/traccar/storage/query/Columns.java +++ b/src/main/java/org/traccar/storage/query/Columns.java @@ -1,5 +1,6 @@ package org.traccar.storage.query; +import org.traccar.storage.QueryExtended; import org.traccar.storage.QueryIgnore; import java.lang.reflect.Method; @@ -11,14 +12,17 @@ import java.util.stream.Collectors; public abstract class Columns { - public abstract List getColumns(Class clazz); + public abstract List getColumns(Class clazz, String type); - protected List getAllColumns(Class clazz) { + protected List getAllColumns(Class clazz, String type) { List columns = new LinkedList<>(); Method[] methods = clazz.getMethods(); for (Method method : methods) { - if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 - && !method.isAnnotationPresent(QueryIgnore.class)) { + int parameterCount = type.equals("set") ? 1 : 0; + if (method.getName().startsWith(type) && method.getParameterTypes().length == parameterCount + && !method.isAnnotationPresent(QueryIgnore.class) + && !method.isAnnotationPresent(QueryExtended.class) + && !method.getName().equals("getClass")) { columns.add(method.getName().substring(3).toLowerCase()); } } @@ -27,8 +31,8 @@ public abstract class Columns { public static class All extends Columns { @Override - public List getColumns(Class clazz) { - return getAllColumns(clazz); + public List getColumns(Class clazz, String type) { + return getAllColumns(clazz, type); } } @@ -40,7 +44,7 @@ public abstract class Columns { } @Override - public List getColumns(Class clazz) { + public List getColumns(Class clazz, String type) { return columns; } } @@ -53,8 +57,8 @@ public abstract class Columns { } @Override - public List getColumns(Class clazz) { - return getAllColumns(clazz).stream() + public List getColumns(Class clazz, String type) { + return getAllColumns(clazz, type).stream() .filter(column -> !columns.contains(column)) .collect(Collectors.toList()); } diff --git a/src/main/java/org/traccar/storage/query/Condition.java b/src/main/java/org/traccar/storage/query/Condition.java index 50d520bc7..82c8e8479 100644 --- a/src/main/java/org/traccar/storage/query/Condition.java +++ b/src/main/java/org/traccar/storage/query/Condition.java @@ -2,13 +2,25 @@ package org.traccar.storage.query; public interface Condition { - class Equals implements Condition { + class Equals extends Compare { + public Equals(String column, String variable) { + this(column, variable, null); + } + + public Equals(String column, String variable, Object value) { + super(column, "=", variable, value); + } + } + + class Compare implements Condition { private final String column; + private final String operator; private final String variable; private final Object value; - public Equals(String column, String variable, Object value) { + public Compare(String column, String operator, String variable, Object value) { this.column = column; + this.operator = operator; this.variable = variable; this.value = value; } @@ -17,6 +29,10 @@ public interface Condition { return column; } + public String getOperator() { + return operator; + } + public String getVariable() { return variable; } @@ -62,13 +78,27 @@ public interface Condition { } } - class And implements Condition { + class Or extends Binary { + public Or(Condition first, Condition second) { + super(first, second, "OR"); + } + } + + class And extends Binary { + public And(Condition first, Condition second) { + super(first, second, "AND"); + } + } + + class Binary implements Condition { private final Condition first; private final Condition second; + private final String operator; - public And(Condition first, Condition second) { + public Binary(Condition first, Condition second, String operator) { this.first = first; this.second = second; + this.operator = operator; } public Condition getFirst() { @@ -78,6 +108,10 @@ public interface Condition { public Condition getSecond() { return second; } + + public String getOperator() { + return operator; + } } } diff --git a/src/main/java/org/traccar/storage/query/Limit.java b/src/main/java/org/traccar/storage/query/Limit.java new file mode 100644 index 000000000..4a20f0ce2 --- /dev/null +++ b/src/main/java/org/traccar/storage/query/Limit.java @@ -0,0 +1,15 @@ +package org.traccar.storage.query; + +public class Limit { + + private final int value; + + public Limit(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + +} diff --git a/src/main/java/org/traccar/storage/query/Request.java b/src/main/java/org/traccar/storage/query/Request.java index 8536cafd0..a98dd48f7 100644 --- a/src/main/java/org/traccar/storage/query/Request.java +++ b/src/main/java/org/traccar/storage/query/Request.java @@ -5,11 +5,29 @@ public class Request { private final Columns columns; private final Condition condition; private final Order order; + private final Limit limit; + + public Request(Columns columns) { + this(columns, null, null); + } + + public Request(Condition condition) { + this(null, condition, null); + } + + public Request(Columns columns, Condition condition) { + this(columns, condition, null); + } public Request(Columns columns, Condition condition, Order order) { + this(columns, condition, order, null); + } + + public Request(Columns columns, Condition condition, Order order, Limit limit) { this.columns = columns; this.condition = condition; this.order = order; + this.limit = limit; } public Columns getColumns() { @@ -24,4 +42,8 @@ public class Request { return order; } + public Limit getLimit() { + return limit; + } + } diff --git a/src/test/java/org/traccar/database/DataManagerTest.java b/src/test/java/org/traccar/database/DataManagerTest.java deleted file mode 100644 index 23043e96e..000000000 --- a/src/test/java/org/traccar/database/DataManagerTest.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.traccar.database; - -import org.junit.Test; -import org.traccar.model.Attribute; -import org.traccar.model.Device; -import org.traccar.model.Driver; -import org.traccar.model.Geofence; -import org.traccar.model.Group; -import org.traccar.model.ManagedUser; -import org.traccar.model.Position; -import org.traccar.model.User; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class DataManagerTest { - - @Test - public void constructObjectQuery() { - assertEquals("SELECT * FROM tc_users", - DataManager.constructObjectQuery(DataManager.ACTION_SELECT_ALL, User.class, false)); - assertEquals("DELETE FROM tc_groups WHERE id = :id", - DataManager.constructObjectQuery(DataManager.ACTION_DELETE, Group.class, false)); - assertEquals("SELECT * FROM tc_positions WHERE id = :id", - DataManager.constructObjectQuery(DataManager.ACTION_SELECT, Position.class, false)); - - String insertDevice = DataManager.constructObjectQuery(DataManager.ACTION_INSERT, Device.class, false); - assertFalse(insertDevice.contains("class")); - assertFalse(insertDevice.contains("id")); - assertFalse(insertDevice.contains("status")); - assertFalse(insertDevice.contains("geofenceIds")); - - String updateDeviceStatus = DataManager.constructObjectQuery("update", Device.class, true); - assertTrue(updateDeviceStatus.contains("lastUpdate")); - - String updateUser = DataManager.constructObjectQuery(DataManager.ACTION_UPDATE, User.class, false); - assertFalse(updateUser.contains("class")); - assertFalse(updateUser.contains("password")); - assertFalse(updateUser.contains("salt")); - - String updateUserPassword = DataManager.constructObjectQuery(DataManager.ACTION_UPDATE, User.class, true); - assertFalse(updateUserPassword.contains("name")); - assertTrue(updateUserPassword.contains("hashedPassword")); - assertTrue(updateUserPassword.contains("salt")); - - String insertPosition = DataManager.constructObjectQuery(DataManager.ACTION_INSERT, Position.class, false); - assertFalse(insertPosition.contains("type")); - assertFalse(insertPosition.contains("outdated")); - - } - - @Test - public void constructPermissionsQuery() { - assertEquals("SELECT userId, deviceId FROM tc_user_device", - DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, User.class, Device.class)); - - assertEquals("SELECT userId, managedUserId FROM tc_user_user", - DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, User.class, ManagedUser.class)); - - assertEquals("SELECT deviceId, driverId FROM tc_device_driver", - DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, Device.class, Driver.class)); - - assertEquals("SELECT groupId, geofenceId FROM tc_group_geofence", - DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, Group.class, Geofence.class)); - - assertEquals("INSERT INTO tc_user_device (userId, deviceId) VALUES (:userId, :deviceId)", - DataManager.constructPermissionQuery(DataManager.ACTION_INSERT, User.class, Device.class)); - - assertEquals("DELETE FROM tc_user_user WHERE userId = :userId AND managedUserId = :managedUserId", - DataManager.constructPermissionQuery(DataManager.ACTION_DELETE, User.class, ManagedUser.class)); - - assertEquals("INSERT INTO tc_device_geofence (deviceId, geofenceId) VALUES (:deviceId, :geofenceId)", - DataManager.constructPermissionQuery(DataManager.ACTION_INSERT, Device.class, Geofence.class)); - - assertEquals("DELETE FROM tc_group_attribute WHERE groupId = :groupId AND attributeId = :attributeId", - DataManager.constructPermissionQuery(DataManager.ACTION_DELETE, Group.class, Attribute.class)); - - } - -} -- cgit v1.2.3 From fed6597faa141ba3ee8b11bff2c987ac981fd91b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 24 May 2022 08:59:27 -0700 Subject: Include address in login logs --- .../java/org/traccar/api/resource/SessionResource.java | 5 ++--- src/main/java/org/traccar/helper/LogAction.java | 17 ++++++++++------- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'src/main/java/org/traccar/api/resource/SessionResource.java') diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 8422e0b49..136aab0eb 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -110,8 +110,7 @@ public class SessionResource extends BaseResource { @FormParam("email") String email, @FormParam("password") String password) throws StorageException { User user = Context.getPermissionsManager().login(email, password); if (user != null) { - request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); return user; } else { LogAction.failedLogin(ServletHelper.retrieveRemoteAddress(request)); @@ -121,7 +120,7 @@ public class SessionResource extends BaseResource { @DELETE public Response remove() { - LogAction.logout(getUserId()); + LogAction.logout(getUserId(), ServletHelper.retrieveRemoteAddress(request)); request.getSession().removeAttribute(USER_ID_KEY); return Response.noContent().build(); } diff --git a/src/main/java/org/traccar/helper/LogAction.java b/src/main/java/org/traccar/helper/LogAction.java index d16b25483..b255b9206 100644 --- a/src/main/java/org/traccar/helper/LogAction.java +++ b/src/main/java/org/traccar/helper/LogAction.java @@ -47,7 +47,7 @@ public final class LogAction { private static final String PATTERN_OBJECT = "user: %d, action: %s, object: %s, id: %d"; private static final String PATTERN_LINK = "user: %d, action: %s, owner: %s, id: %d, property: %s, id: %d"; - private static final String PATTERN_LOGIN = "user: %d, action: %s"; + private static final String PATTERN_LOGIN = "user: %d, action: %s, from: %s"; private static final String PATTERN_LOGIN_FAILED = "login failed from: %s"; private static final String PATTERN_DEVICE_ACCUMULATORS = "user: %d, action: %s, deviceId: %d"; private static final String PATTERN_REPORT = "user: %d, report: %s, from: %s, to: %s, devices: %s, groups: %s"; @@ -72,12 +72,12 @@ public final class LogAction { logLinkAction(ACTION_UNLINK, userId, owner, ownerId, property, propertyId); } - public static void login(long userId) { - logLoginAction(ACTION_LOGIN, userId); + public static void login(long userId, String remoteAddress) { + logLoginAction(ACTION_LOGIN, userId, remoteAddress); } - public static void logout(long userId) { - logLoginAction(ACTION_LOGOUT, userId); + public static void logout(long userId, String remoteAddress) { + logLoginAction(ACTION_LOGOUT, userId, remoteAddress); } public static void failedLogin(String remoteAddress) { @@ -105,8 +105,11 @@ public final class LogAction { Introspector.decapitalize(property.getSimpleName()), propertyId)); } - private static void logLoginAction(String action, long userId) { - LOGGER.info(String.format(PATTERN_LOGIN, userId, action)); + private static void logLoginAction(String action, long userId, String remoteAddress) { + if (remoteAddress == null || remoteAddress.isEmpty()) { + remoteAddress = "unknown"; + } + LOGGER.info(String.format(PATTERN_LOGIN, userId, action, remoteAddress)); } public static void logReport( -- cgit v1.2.3 From 0ba89aa35180f965e8c8ca85560d7ee7a1849b3c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 24 May 2022 09:02:56 -0700 Subject: Fix login issue --- src/main/java/org/traccar/api/resource/SessionResource.java | 1 + 1 file changed, 1 insertion(+) (limited to 'src/main/java/org/traccar/api/resource/SessionResource.java') diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 136aab0eb..1ccba1270 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -110,6 +110,7 @@ public class SessionResource extends BaseResource { @FormParam("email") String email, @FormParam("password") String password) throws StorageException { User user = Context.getPermissionsManager().login(email, password); if (user != null) { + request.getSession().setAttribute(USER_ID_KEY, user.getId()); LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); return user; } else { -- cgit v1.2.3 From 63ecf80c11ec9bce19df18fc24ad863a9c2cb212 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 15 Jun 2022 09:55:50 -0700 Subject: Remove users manager --- schema/changelog-5.1.xml | 12 +++ src/main/java/org/traccar/Context.java | 13 +-- src/main/java/org/traccar/MainModule.java | 9 +- .../java/org/traccar/api/BaseObjectResource.java | 17 ++-- .../org/traccar/api/resource/DeviceResource.java | 16 ++-- .../org/traccar/api/resource/PasswordResource.java | 43 +++++----- .../org/traccar/api/resource/SessionResource.java | 6 +- .../org/traccar/api/resource/UserResource.java | 77 ++++++++++------- .../traccar/api/security/PermissionsService.java | 33 +++++++- .../java/org/traccar/database/DataManager.java | 3 +- .../java/org/traccar/database/DeviceManager.java | 16 ---- .../org/traccar/database/PermissionsManager.java | 98 ++++----------------- .../org/traccar/database/SimpleObjectManager.java | 70 --------------- .../java/org/traccar/database/UsersManager.java | 99 ---------------------- 14 files changed, 153 insertions(+), 359 deletions(-) delete mode 100644 src/main/java/org/traccar/database/UsersManager.java (limited to 'src/main/java/org/traccar/api/resource/SessionResource.java') diff --git a/schema/changelog-5.1.xml b/schema/changelog-5.1.xml index e68325625..e972813f6 100644 --- a/schema/changelog-5.1.xml +++ b/schema/changelog-5.1.xml @@ -16,6 +16,18 @@ + + + + + + + + + + + + diff --git a/src/main/java/org/traccar/Context.java b/src/main/java/org/traccar/Context.java index 51c420390..5eaa1e15c 100644 --- a/src/main/java/org/traccar/Context.java +++ b/src/main/java/org/traccar/Context.java @@ -23,12 +23,10 @@ import org.traccar.database.DeviceManager; import org.traccar.database.GroupsManager; import org.traccar.database.IdentityManager; import org.traccar.database.PermissionsManager; -import org.traccar.database.UsersManager; import org.traccar.helper.Log; import org.traccar.model.BaseModel; import org.traccar.model.Device; import org.traccar.model.Group; -import org.traccar.model.User; import org.traccar.session.ConnectionManager; public final class Context { @@ -54,12 +52,6 @@ public final class Context { return dataManager; } - private static UsersManager usersManager; - - public static UsersManager getUsersManager() { - return usersManager; - } - private static GroupsManager groupsManager; public static GroupsManager getGroupsManager() { @@ -94,7 +86,6 @@ public final class Context { } if (dataManager != null) { - usersManager = new UsersManager(dataManager); groupsManager = new GroupsManager(dataManager); deviceManager = new DeviceManager( config, dataManager, Main.getInjector().getInstance(ConnectionManager.class)); @@ -102,7 +93,7 @@ public final class Context { identityManager = deviceManager; - permissionsManager = new PermissionsManager(dataManager, usersManager); + permissionsManager = new PermissionsManager(dataManager, dataManager.getStorage()); } @@ -111,8 +102,6 @@ public final class Context { return (BaseObjectManager) deviceManager; } else if (clazz.equals(Group.class)) { return (BaseObjectManager) groupsManager; - } else if (clazz.equals(User.class)) { - return (BaseObjectManager) usersManager; } return null; } diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index dd496e5a4..dd7e375d3 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -31,7 +31,6 @@ import org.traccar.broadcast.BroadcastService; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.database.LdapProvider; -import org.traccar.database.UsersManager; import org.traccar.helper.SanitizerModule; import org.traccar.notification.EventForwarder; import org.traccar.database.DataManager; @@ -118,11 +117,6 @@ public class MainModule extends AbstractModule { return Context.getDataManager(); } - @Provides - public static UsersManager provideUsersManager() { - return Context.getUsersManager(); - } - @Provides public static IdentityManager provideIdentityManager() { return Context.getIdentityManager(); @@ -292,8 +286,7 @@ public class MainModule extends AbstractModule { } @Provides - public static EventForwarder provideEventForwarder( - Config config, Client client, CacheManager cacheManager, UsersManager usersManager) { + public static EventForwarder provideEventForwarder(Config config, Client client, CacheManager cacheManager) { if (config.hasKey(Keys.EVENT_FORWARD_URL)) { return new EventForwarder(config, client, cacheManager); } diff --git a/src/main/java/org/traccar/api/BaseObjectResource.java b/src/main/java/org/traccar/api/BaseObjectResource.java index aa777f3f6..f8545a5d7 100644 --- a/src/main/java/org/traccar/api/BaseObjectResource.java +++ b/src/main/java/org/traccar/api/BaseObjectResource.java @@ -19,7 +19,6 @@ package org.traccar.api; import org.traccar.Context; import org.traccar.database.BaseObjectManager; import org.traccar.database.ExtendedObjectManager; -import org.traccar.database.SimpleObjectManager; import org.traccar.helper.LogAction; import org.traccar.model.BaseModel; import org.traccar.model.Device; @@ -82,9 +81,7 @@ public abstract class BaseObjectResource extends BaseResour cacheManager.invalidate(User.class, getUserId(), baseClass, entity.getId()); LogAction.link(getUserId(), User.class, getUserId(), baseClass, entity.getId()); - if (manager instanceof SimpleObjectManager) { - ((SimpleObjectManager) manager).refreshUserItems(); - } else if (baseClass.equals(Group.class) || baseClass.equals(Device.class)) { + if (baseClass.equals(Group.class) || baseClass.equals(Device.class)) { Context.getPermissionsManager().refreshDeviceAndGroupPermissions(); } return Response.ok(entity).build(); @@ -95,6 +92,11 @@ public abstract class BaseObjectResource extends BaseResour public Response update(T entity) throws StorageException { permissionsService.checkEdit(getUserId(), entity, false); permissionsService.checkPermission(baseClass, getUserId(), entity.getId()); + if (entity instanceof User) { + User before = storage.getObject(User.class, new Request( + new Columns.All(), new Condition.Equals("id", "id", entity.getId()))); + permissionsService.checkUserUpdate(getUserId(), before, (User) entity); + } BaseObjectManager manager = Context.getManager(baseClass); if (manager != null) { @@ -123,11 +125,8 @@ public abstract class BaseObjectResource extends BaseResour BaseObjectManager manager = Context.getManager(baseClass); if (manager != null) { manager.removeItem(id); - if (manager instanceof SimpleObjectManager) { - ((SimpleObjectManager) manager).refreshUserItems(); - if (manager instanceof ExtendedObjectManager) { - ((ExtendedObjectManager) manager).refreshExtendedPermissions(); - } + if (manager instanceof ExtendedObjectManager) { + ((ExtendedObjectManager) manager).refreshExtendedPermissions(); } } else { storage.removeObject(baseClass, new Request(new Condition.Equals("id", "id", id))); diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index 309308e75..cd5ebf0c5 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -49,7 +49,7 @@ public class DeviceResource extends BaseObjectResource { public Collection get( @QueryParam("all") boolean all, @QueryParam("userId") long userId, @QueryParam("uniqueId") List uniqueIds, - @QueryParam("id") List deviceIds) { + @QueryParam("id") List deviceIds) throws StorageException { DeviceManager deviceManager = Context.getDeviceManager(); Set result; if (all) { @@ -57,13 +57,13 @@ public class DeviceResource extends BaseObjectResource { result = deviceManager.getAllItems(); } else { Context.getPermissionsManager().checkManager(getUserId()); - result = deviceManager.getManagedItems(getUserId()); + result = deviceManager.getUserItems(getUserId()); } } else if (uniqueIds.isEmpty() && deviceIds.isEmpty()) { if (userId == 0) { userId = getUserId(); } - Context.getPermissionsManager().checkUser(getUserId(), userId); + permissionsService.checkUser(getUserId(), userId); if (Context.getPermissionsManager().getUserAdmin(getUserId())) { result = deviceManager.getAllUserItems(userId); } else { @@ -73,11 +73,11 @@ public class DeviceResource extends BaseObjectResource { result = new HashSet<>(); for (String uniqueId : uniqueIds) { Device device = deviceManager.getByUniqueId(uniqueId); - Context.getPermissionsManager().checkDevice(getUserId(), device.getId()); + permissionsService.checkPermission(Device.class, getUserId(), device.getId()); result.add(device.getId()); } for (Long deviceId : deviceIds) { - Context.getPermissionsManager().checkDevice(getUserId(), deviceId); + permissionsService.checkPermission(Device.class, getUserId(), deviceId); result.add(deviceId); } } @@ -87,9 +87,9 @@ public class DeviceResource extends BaseObjectResource { @Path("{id}/accumulators") @PUT public Response updateAccumulators(DeviceAccumulators entity) throws StorageException { - if (!Context.getPermissionsManager().getUserAdmin(getUserId())) { - Context.getPermissionsManager().checkManager(getUserId()); - Context.getPermissionsManager().checkPermission(Device.class, getUserId(), entity.getDeviceId()); + if (permissionsService.notAdmin(getUserId())) { + permissionsService.checkManager(getUserId()); + permissionsService.checkPermission(Device.class, getUserId(), entity.getDeviceId()); } Context.getDeviceManager().resetDeviceAccumulators(entity); LogAction.resetDeviceAccumulators(getUserId(), entity.getDeviceId()); diff --git a/src/main/java/org/traccar/api/resource/PasswordResource.java b/src/main/java/org/traccar/api/resource/PasswordResource.java index c7244f41c..643471797 100644 --- a/src/main/java/org/traccar/api/resource/PasswordResource.java +++ b/src/main/java/org/traccar/api/resource/PasswordResource.java @@ -15,12 +15,14 @@ */ package org.traccar.api.resource; -import org.traccar.Context; import org.traccar.api.BaseResource; import org.traccar.database.MailManager; import org.traccar.model.User; import org.traccar.notification.TextTemplateFormatter; import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; import javax.annotation.security.PermitAll; import javax.inject.Inject; @@ -51,18 +53,17 @@ public class PasswordResource extends BaseResource { @PermitAll @POST public Response reset(@FormParam("email") String email) throws StorageException, MessagingException { - for (long userId : Context.getUsersManager().getAllItems()) { - User user = Context.getUsersManager().getById(userId); - if (email.equals(user.getEmail())) { - String token = UUID.randomUUID().toString().replaceAll("-", ""); - user.set(PASSWORD_RESET_TOKEN, token); - Context.getUsersManager().updateItem(user); - var velocityContext = textTemplateFormatter.prepareContext(permissionsService.getServer(), user); - velocityContext.put("token", token); - var fullMessage = textTemplateFormatter.formatMessage(velocityContext, "passwordReset", "full"); - mailManager.sendMessage(user, fullMessage.getSubject(), fullMessage.getBody()); - break; - } + User user = storage.getObject(User.class, new Request( + new Columns.All(), new Condition.Equals("email", "email", email))); + if (user != null) { + String token = UUID.randomUUID().toString().replaceAll("-", ""); + user.set(PASSWORD_RESET_TOKEN, token); + storage.updateObject(user, new Request(new Columns.Exclude("id"), new Condition.Equals("id", "id"))); + + var velocityContext = textTemplateFormatter.prepareContext(permissionsService.getServer(), user); + velocityContext.put("token", token); + var fullMessage = textTemplateFormatter.formatMessage(velocityContext, "passwordReset", "full"); + mailManager.sendMessage(user, fullMessage.getSubject(), fullMessage.getBody()); } return Response.ok().build(); } @@ -72,14 +73,14 @@ public class PasswordResource extends BaseResource { @POST public Response update( @FormParam("token") String token, @FormParam("password") String password) throws StorageException { - for (long userId : Context.getUsersManager().getAllItems()) { - User user = Context.getUsersManager().getById(userId); - if (token.equals(user.getString(PASSWORD_RESET_TOKEN))) { - user.getAttributes().remove(PASSWORD_RESET_TOKEN); - user.setPassword(password); - Context.getUsersManager().updateItem(user); - return Response.ok().build(); - } + User user = storage.getObjects(User.class, new Request(new Columns.All())).stream() + .filter(it -> token.equals(it.getString(PASSWORD_RESET_TOKEN))) + .findFirst().orElse(null); + if (user != null) { + user.getAttributes().remove(PASSWORD_RESET_TOKEN); + user.setPassword(password); + storage.updateObject(user, new Request(new Columns.Exclude("id"), new Condition.Equals("id", "id"))); + return Response.ok().build(); } return Response.status(Response.Status.NOT_FOUND).build(); } diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 1ccba1270..a0bf0cba5 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -22,6 +22,9 @@ import org.traccar.helper.ServletHelper; import org.traccar.helper.LogAction; import org.traccar.model.User; import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; import javax.annotation.security.PermitAll; import javax.servlet.http.Cookie; @@ -59,7 +62,8 @@ public class SessionResource extends BaseResource { public User get(@QueryParam("token") String token) throws StorageException, UnsupportedEncodingException { if (token != null) { - User user = Context.getUsersManager().getUserByToken(token); + User user = storage.getObject(User.class, new Request( + new Columns.All(), new Condition.Equals("token", "token", token))); if (user != null) { Context.getPermissionsManager().checkUserEnabled(user.getId()); request.getSession().setAttribute(USER_ID_KEY, user.getId()); diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java index 84f41ca1a..20fce9e32 100644 --- a/src/main/java/org/traccar/api/resource/UserResource.java +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,17 +15,20 @@ */ package org.traccar.api.resource; -import org.traccar.Context; import org.traccar.api.BaseObjectResource; +import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.database.UsersManager; import org.traccar.helper.LogAction; import org.traccar.model.ManagedUser; import org.traccar.model.Permission; import org.traccar.model.User; import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; import javax.annotation.security.PermitAll; +import javax.inject.Inject; import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.POST; @@ -34,63 +37,77 @@ import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import java.sql.SQLException; import java.util.Collection; import java.util.Date; -import java.util.Set; @Path("users") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) public class UserResource extends BaseObjectResource { + @Inject + private Config config; + public UserResource() { super(User.class); } @GET - public Collection get(@QueryParam("userId") long userId) throws SQLException { - UsersManager usersManager = Context.getUsersManager(); - Set result; - if (Context.getPermissionsManager().getUserAdmin(getUserId())) { - if (userId != 0) { - result = usersManager.getUserItems(userId); - } else { - result = usersManager.getAllItems(); - } - } else if (Context.getPermissionsManager().getUserManager(getUserId())) { - result = usersManager.getManagedItems(getUserId()); + public Collection get(@QueryParam("userId") long userId) throws StorageException { + permissionsService.checkUser(getUserId(), userId); + if (userId > 0) { + return storage.getObjects(baseClass, new Request( + new Columns.All(), + new Condition.Permission(User.class, userId, ManagedUser.class).excludeGroups())); + } else if (permissionsService.notAdmin(getUserId())) { + return storage.getObjects(baseClass, new Request( + new Columns.All(), + new Condition.Permission(User.class, getUserId(), ManagedUser.class).excludeGroups())); } else { - throw new SecurityException("Admin or manager access required"); + return storage.getObjects(baseClass, new Request(new Columns.All())); } - return usersManager.getItems(result); } @Override @PermitAll @POST public Response add(User entity) throws StorageException { - if (!Context.getPermissionsManager().getUserAdmin(getUserId())) { - Context.getPermissionsManager().checkUserUpdate(getUserId(), new User(), entity); - if (Context.getPermissionsManager().getUserManager(getUserId())) { - Context.getPermissionsManager().checkUserLimit(getUserId()); + User currentUser = permissionsService.getUser(getUserId()); + if (permissionsService.notAdmin(getUserId())) { + permissionsService.checkUserUpdate(getUserId(), new User(), entity); + if (currentUser != null && currentUser.getUserLimit() != 0) { + int userLimit = currentUser.getUserLimit(); + if (userLimit > 0) { + int userCount = storage.getObjects(baseClass, new Request( + new Columns.All(), + new Condition.Permission(User.class, getUserId(), ManagedUser.class).excludeGroups())) + .size(); + if (userCount >= userLimit) { + throw new SecurityException("Manager user limit reached"); + } + } } else { - Context.getPermissionsManager().checkRegistration(getUserId()); - entity.setDeviceLimit(Context.getConfig().getInteger(Keys.USERS_DEFAULT_DEVICE_LIMIT)); - int expirationDays = Context.getConfig().getInteger(Keys.USERS_DEFAULT_EXPIRATION_DAYS); + if (!permissionsService.getServer().getRegistration()) { + throw new SecurityException("Registration disabled"); + } + entity.setDeviceLimit(config.getInteger(Keys.USERS_DEFAULT_DEVICE_LIMIT)); + int expirationDays = config.getInteger(Keys.USERS_DEFAULT_EXPIRATION_DAYS); if (expirationDays > 0) { - entity.setExpirationTime( - new Date(System.currentTimeMillis() + (long) expirationDays * 24 * 3600 * 1000)); + entity.setExpirationTime(new Date(System.currentTimeMillis() + expirationDays * 86400000L)); } } } - Context.getUsersManager().addItem(entity); + + entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id")))); + storage.updateObject(entity, new Request( + new Columns.Include("hashedPassword", "salt"), new Condition.Equals("id", "id"))); + LogAction.create(getUserId(), entity); - if (Context.getPermissionsManager().getUserManager(getUserId())) { + + if (currentUser != null && currentUser.getUserLimit() != 0) { storage.addPermission(new Permission(User.class, getUserId(), ManagedUser.class, entity.getId())); LogAction.link(getUserId(), User.class, getUserId(), ManagedUser.class, entity.getId()); } - Context.getUsersManager().refreshUserItems(); return Response.ok(entity).build(); } diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java index c70414b2a..f39ded2b7 100644 --- a/src/main/java/org/traccar/api/security/PermissionsService.java +++ b/src/main/java/org/traccar/api/security/PermissionsService.java @@ -57,7 +57,7 @@ public class PermissionsService { } public User getUser(long userId) throws StorageException { - if (user == null) { + if (user == null && userId > 0) { user = storage.getObject( User.class, new Request(new Columns.All(), new Condition.Equals("id", "id", userId))); } @@ -74,6 +74,12 @@ public class PermissionsService { } } + public void checkManager(long userId) throws StorageException, SecurityException { + if (!getUser(userId).getAdministrator() && getUser(userId).getUserLimit() == 0) { + throw new SecurityException("Manager access required"); + } + } + public interface CheckRestrictionCallback { boolean denied(UserRestrictions userRestrictions); } @@ -137,6 +143,31 @@ public class PermissionsService { } } + public void checkUserUpdate(long userId, User before, User after) throws StorageException, SecurityException { + if (before.getAdministrator() != after.getAdministrator() + || before.getDeviceLimit() != after.getDeviceLimit() + || before.getUserLimit() != after.getUserLimit()) { + checkAdmin(userId); + } + User user = getUser(userId); + if (user != null && user.getExpirationTime() != null + && (after.getExpirationTime() == null + || user.getExpirationTime().compareTo(after.getExpirationTime()) < 0)) { + checkAdmin(userId); + } + if (before.getReadonly() != after.getReadonly() + || before.getDeviceReadonly() != after.getDeviceReadonly() + || before.getDisabled() != after.getDisabled() + || before.getLimitCommands() != after.getLimitCommands() + || before.getDisableReports() != after.getDisableReports()) { + if (userId == after.getId()) { + checkAdmin(userId); + } else { + checkUser(userId, after.getId()); + } + } + } + public void checkPermission( Class clazz, long userId, long objectId) throws StorageException, SecurityException { if (!getUser(userId).getAdministrator() && !(clazz.equals(User.class) && userId == objectId)) { diff --git a/src/main/java/org/traccar/database/DataManager.java b/src/main/java/org/traccar/database/DataManager.java index fd45a0321..6921634dd 100644 --- a/src/main/java/org/traccar/database/DataManager.java +++ b/src/main/java/org/traccar/database/DataManager.java @@ -25,7 +25,6 @@ import liquibase.database.DatabaseFactory; import liquibase.exception.LiquibaseException; import liquibase.resource.FileSystemResourceAccessor; import liquibase.resource.ResourceAccessor; -import org.traccar.Context; import org.traccar.Main; import org.traccar.config.Config; import org.traccar.config.Keys; @@ -155,7 +154,7 @@ public class DataManager { } else { if (ldapProvider != null && ldapProvider.login(email, password)) { user = ldapProvider.getUser(email); - Context.getUsersManager().addItem(user); + user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); return user; } } diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java index e1d6ad1dd..9ba486988 100644 --- a/src/main/java/org/traccar/database/DeviceManager.java +++ b/src/main/java/org/traccar/database/DeviceManager.java @@ -177,22 +177,6 @@ public class DeviceManager extends BaseObjectManager implements Identity } } - public Set getAllManagedItems(long userId) { - Set result = new HashSet<>(getAllUserItems(userId)); - for (long managedUserId : Context.getUsersManager().getUserItems(userId)) { - result.addAll(getAllUserItems(managedUserId)); - } - return result; - } - - public Set getManagedItems(long userId) { - Set result = new HashSet<>(getUserItems(userId)); - for (long managedUserId : Context.getUsersManager().getUserItems(userId)) { - result.addAll(getUserItems(managedUserId)); - } - return result; - } - private void addByUniqueId(Device device) { try { writeLock(); diff --git a/src/main/java/org/traccar/database/PermissionsManager.java b/src/main/java/org/traccar/database/PermissionsManager.java index f34810439..833480eea 100644 --- a/src/main/java/org/traccar/database/PermissionsManager.java +++ b/src/main/java/org/traccar/database/PermissionsManager.java @@ -18,14 +18,17 @@ package org.traccar.database; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.Context; -import org.traccar.model.BaseModel; +import org.traccar.api.security.PermissionsService; import org.traccar.model.Device; import org.traccar.model.Group; -import org.traccar.model.ManagedUser; import org.traccar.model.Permission; import org.traccar.model.Server; import org.traccar.model.User; +import org.traccar.storage.Storage; import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; import java.util.HashMap; import java.util.HashSet; @@ -39,7 +42,7 @@ public class PermissionsManager { private static final Logger LOGGER = LoggerFactory.getLogger(PermissionsManager.class); private final DataManager dataManager; - private final UsersManager usersManager; + private final Storage storage; private volatile Server server; @@ -50,9 +53,9 @@ public class PermissionsManager { private final Map> deviceUsers = new HashMap<>(); private final Map> groupDevices = new HashMap<>(); - public PermissionsManager(DataManager dataManager, UsersManager usersManager) { + public PermissionsManager(DataManager dataManager, Storage storage) { this.dataManager = dataManager; - this.usersManager = usersManager; + this.storage = storage; refreshServer(); refreshDeviceAndGroupPermissions(); } @@ -74,11 +77,11 @@ public class PermissionsManager { } public User getUser(long userId) { - readLock(); try { - return usersManager.getById(userId); - } finally { - readUnlock(); + return storage.getObject(User.class, new Request( + new Columns.All(), new Condition.Equals("id", "id", userId))); + } catch (StorageException e) { + throw new RuntimeException(e); } } @@ -222,20 +225,6 @@ public class PermissionsManager { } } - public void checkManager(long userId, long managedUserId) throws SecurityException { - checkManager(userId); - if (!usersManager.getUserItems(userId).contains(managedUserId)) { - throw new SecurityException("User access denied"); - } - } - - public void checkUserLimit(long userId) throws SecurityException { - int userLimit = getUser(userId).getUserLimit(); - if (userLimit != -1 && usersManager.getUserItems(userId).size() >= userLimit) { - throw new SecurityException("Manager user limit reached"); - } - } - public boolean getUserReadonly(long userId) { User user = getUser(userId); return user != null && user.getReadonly(); @@ -260,64 +249,11 @@ public class PermissionsManager { } } - public void checkUserUpdate(long userId, User before, User after) throws SecurityException { - if (before.getAdministrator() != after.getAdministrator() - || before.getDeviceLimit() != after.getDeviceLimit() - || before.getUserLimit() != after.getUserLimit()) { - checkAdmin(userId); - } - User user = getUser(userId); - if (user != null && user.getExpirationTime() != null - && (after.getExpirationTime() == null - || user.getExpirationTime().compareTo(after.getExpirationTime()) < 0)) { - checkAdmin(userId); - } - if (before.getReadonly() != after.getReadonly() - || before.getDeviceReadonly() != after.getDeviceReadonly() - || before.getDisabled() != after.getDisabled() - || before.getLimitCommands() != after.getLimitCommands() - || before.getDisableReports() != after.getDisableReports()) { - if (userId == after.getId()) { - checkAdmin(userId); - } - if (!getUserAdmin(userId)) { - checkManager(userId); - } - } - } - - public void checkUser(long userId, long managedUserId) throws SecurityException { - if (userId != managedUserId && !getUserAdmin(userId)) { - checkManager(userId, managedUserId); - } - } - public void checkDevice(long userId, long deviceId) throws SecurityException { - if (!Context.getDeviceManager().getUserItems(userId).contains(deviceId) && !getUserAdmin(userId)) { - checkManager(userId); - for (long managedUserId : usersManager.getUserItems(userId)) { - if (Context.getDeviceManager().getUserItems(managedUserId).contains(deviceId)) { - return; - } - } - throw new SecurityException("Device access denied"); - } - } - - public void checkRegistration(long userId) { - if (!server.getRegistration() && !getUserAdmin(userId)) { - throw new SecurityException("Registration disabled"); - } - } - - public void checkPermission(Class object, long userId, long objectId) - throws SecurityException { - SimpleObjectManager manager = null; - - if (object.equals(Device.class)) { - checkDevice(userId, objectId); - } else { - throw new IllegalArgumentException("Unknown object type"); + try { + new PermissionsService(storage).checkPermission(Device.class, userId, deviceId); + } catch (StorageException e) { + throw new RuntimeException(e); } } @@ -326,8 +262,6 @@ public class PermissionsManager { if (permission.getPropertyClass().equals(Device.class) || permission.getPropertyClass().equals(Group.class)) { refreshDeviceAndGroupPermissions(); - } else if (permission.getPropertyClass().equals(ManagedUser.class)) { - usersManager.refreshUserItems(); } } } diff --git a/src/main/java/org/traccar/database/SimpleObjectManager.java b/src/main/java/org/traccar/database/SimpleObjectManager.java index 74bbc054f..8bb22b8a8 100644 --- a/src/main/java/org/traccar/database/SimpleObjectManager.java +++ b/src/main/java/org/traccar/database/SimpleObjectManager.java @@ -16,82 +16,12 @@ */ package org.traccar.database; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; import org.traccar.model.BaseModel; -import org.traccar.model.Permission; -import org.traccar.model.User; -import org.traccar.storage.StorageException; public abstract class SimpleObjectManager extends BaseObjectManager { - private static final Logger LOGGER = LoggerFactory.getLogger(SimpleObjectManager.class); - - private Map> userItems; - protected SimpleObjectManager(DataManager dataManager, Class baseClass) { super(dataManager, baseClass); } - public final Set getUserItems(long userId) { - try { - readLock(); - Set result = userItems.get(userId); - if (result != null) { - return new HashSet<>(result); - } else { - return new HashSet<>(); - } - } finally { - readUnlock(); - } - } - - public Set getManagedItems(long userId) { - Set result = getUserItems(userId); - for (long managedUserId : Context.getUsersManager().getUserItems(userId)) { - result.addAll(getUserItems(managedUserId)); - } - return result; - } - - public final boolean checkItemPermission(long userId, long itemId) { - return getUserItems(userId).contains(itemId); - } - - @Override - public void refreshItems() { - super.refreshItems(); - refreshUserItems(); - } - - public final void refreshUserItems() { - if (getDataManager() != null) { - try { - writeLock(); - userItems = new ConcurrentHashMap<>(); - for (Permission permission : getDataManager().getPermissions(User.class, getBaseClass())) { - Set items = userItems.computeIfAbsent(permission.getOwnerId(), key -> new HashSet<>()); - items.add(permission.getPropertyId()); - } - } catch (StorageException | ClassNotFoundException error) { - LOGGER.warn("Error getting permissions", error); - } finally { - writeUnlock(); - } - } - } - - @Override - public void removeItem(long itemId) throws StorageException { - super.removeItem(itemId); - refreshUserItems(); - } - } diff --git a/src/main/java/org/traccar/database/UsersManager.java b/src/main/java/org/traccar/database/UsersManager.java deleted file mode 100644 index a54226cfe..000000000 --- a/src/main/java/org/traccar/database/UsersManager.java +++ /dev/null @@ -1,99 +0,0 @@ -/* - * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org) - * Copyright 2017 Andrey Kunitsyn (andrey@traccar.org) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.traccar.database; - -import java.util.Map; -import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; - -import org.traccar.model.User; -import org.traccar.storage.StorageException; - -public class UsersManager extends SimpleObjectManager { - - private Map usersTokens; - - public UsersManager(DataManager dataManager) { - super(dataManager, User.class); - if (usersTokens == null) { - usersTokens = new ConcurrentHashMap<>(); - } - } - - private void putToken(User user) { - if (usersTokens == null) { - usersTokens = new ConcurrentHashMap<>(); - } - if (user.getToken() != null) { - usersTokens.put(user.getToken(), user); - } - } - - @Override - protected void addNewItem(User user) { - super.addNewItem(user); - putToken(user); - } - - @Override - protected void updateCachedItem(User user) { - User cachedUser = getById(user.getId()); - super.updateCachedItem(user); - putToken(user); - if (cachedUser.getToken() != null && !cachedUser.getToken().equals(user.getToken())) { - usersTokens.remove(cachedUser.getToken()); - } - } - - @Override - public void addItem(User user) throws StorageException { - super.addItem(user); - getDataManager().updateUserPassword(user); - } - - @Override - public void updateItem(User user) throws StorageException { - if (user.getHashedPassword() != null) { - getDataManager().updateUserPassword(user); - } - super.updateItem(user); - } - - @Override - protected void removeCachedItem(long userId) { - User cachedUser = getById(userId); - if (cachedUser != null) { - String userToken = cachedUser.getToken(); - super.removeCachedItem(userId); - if (userToken != null) { - usersTokens.remove(userToken); - } - } - } - - @Override - public Set getManagedItems(long userId) { - Set result = getUserItems(userId); - result.add(userId); - return result; - } - - public User getUserByToken(String token) { - return usersTokens.get(token); - } - -} -- cgit v1.2.3 From 51cdee534cd9990d1de173814fe95c55dead4934 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 16 Jun 2022 08:24:48 -0700 Subject: Refactor login --- src/main/java/org/traccar/api/MediaFilter.java | 1 - .../org/traccar/api/resource/SessionResource.java | 23 +++--- .../traccar/api/security/PermissionsService.java | 13 ---- .../api/security/SecurityRequestFilter.java | 7 +- .../java/org/traccar/database/DataManager.java | 31 +------- .../java/org/traccar/database/LoginService.java | 89 ++++++++++++++++++++++ .../org/traccar/database/PermissionsManager.java | 22 ------ 7 files changed, 104 insertions(+), 82 deletions(-) create mode 100644 src/main/java/org/traccar/database/LoginService.java (limited to 'src/main/java/org/traccar/api/resource/SessionResource.java') diff --git a/src/main/java/org/traccar/api/MediaFilter.java b/src/main/java/org/traccar/api/MediaFilter.java index c6ac811d7..e0609871a 100644 --- a/src/main/java/org/traccar/api/MediaFilter.java +++ b/src/main/java/org/traccar/api/MediaFilter.java @@ -61,7 +61,6 @@ public class MediaFilter implements Filter { if (session != null) { userId = (Long) session.getAttribute(SessionResource.USER_ID_KEY); if (userId != null) { - permissionsService.checkUserEnabled(userId); statisticsManager.registerRequest(userId); } } diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index a0bf0cba5..70561f997 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -15,18 +15,16 @@ */ package org.traccar.api.resource; -import org.traccar.Context; import org.traccar.api.BaseResource; +import org.traccar.database.LoginService; import org.traccar.helper.DataConverter; import org.traccar.helper.ServletHelper; import org.traccar.helper.LogAction; import org.traccar.model.User; import org.traccar.storage.StorageException; -import org.traccar.storage.query.Columns; -import org.traccar.storage.query.Condition; -import org.traccar.storage.query.Request; import javax.annotation.security.PermitAll; +import javax.inject.Inject; import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.ws.rs.Consumes; @@ -54,6 +52,9 @@ public class SessionResource extends BaseResource { public static final String USER_COOKIE_KEY = "user"; public static final String PASS_COOKIE_KEY = "password"; + @Inject + private LoginService loginService; + @javax.ws.rs.core.Context private HttpServletRequest request; @@ -62,11 +63,10 @@ public class SessionResource extends BaseResource { public User get(@QueryParam("token") String token) throws StorageException, UnsupportedEncodingException { if (token != null) { - User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("token", "token", token))); + User user = loginService.login(token); if (user != null) { - Context.getPermissionsManager().checkUserEnabled(user.getId()); request.getSession().setAttribute(USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); return user; } } @@ -90,18 +90,17 @@ public class SessionResource extends BaseResource { } } if (email != null && password != null) { - User user = Context.getPermissionsManager().login(email, password); + User user = loginService.login(email, password); if (user != null) { - Context.getPermissionsManager().checkUserEnabled(user.getId()); request.getSession().setAttribute(USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); return user; } } } else { - Context.getPermissionsManager().checkUserEnabled(userId); - return Context.getPermissionsManager().getUser(userId); + return permissionsService.getUser(userId); } @@ -112,7 +111,7 @@ public class SessionResource extends BaseResource { @POST public User add( @FormParam("email") String email, @FormParam("password") String password) throws StorageException { - User user = Context.getPermissionsManager().login(email, password); + User user = loginService.login(email, password); if (user != null) { request.getSession().setAttribute(USER_ID_KEY, user.getId()); LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java index 8732a0d04..f39ded2b7 100644 --- a/src/main/java/org/traccar/api/security/PermissionsService.java +++ b/src/main/java/org/traccar/api/security/PermissionsService.java @@ -92,19 +92,6 @@ public class PermissionsService { } } - public void checkUserEnabled(long userId) throws StorageException, SecurityException { - User user = getUser(userId); - if (user == null) { - throw new SecurityException("Unknown account"); - } - if (user.getDisabled()) { - throw new SecurityException("Account is disabled"); - } - if (user.getExpirationTime() != null && System.currentTimeMillis() > user.getExpirationTime().getTime()) { - throw new SecurityException("Account has expired"); - } - } - public void checkEdit(long userId, Class clazz, boolean addition) throws StorageException, SecurityException { if (!getUser(userId).getAdministrator()) { boolean denied = false; diff --git a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java index 9f20acb40..ad45dc112 100644 --- a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java +++ b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,9 +17,9 @@ package org.traccar.api.security; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.traccar.Context; import org.traccar.Main; import org.traccar.api.resource.SessionResource; +import org.traccar.database.LoginService; import org.traccar.database.StatisticsManager; import org.traccar.helper.DataConverter; import org.traccar.model.User; @@ -77,7 +77,7 @@ public class SecurityRequestFilter implements ContainerRequestFilter { try { String[] auth = decodeBasicAuth(authHeader); - User user = Context.getPermissionsManager().login(auth[0], auth[1]); + User user = Main.getInjector().getInstance(LoginService.class).login(auth[0], auth[1]); if (user != null) { Main.getInjector().getInstance(StatisticsManager.class).registerRequest(user.getId()); securityContext = new UserSecurityContext(new UserPrincipal(user.getId())); @@ -90,7 +90,6 @@ public class SecurityRequestFilter implements ContainerRequestFilter { Long userId = (Long) request.getSession().getAttribute(SessionResource.USER_ID_KEY); if (userId != null) { - Context.getPermissionsManager().checkUserEnabled(userId); Main.getInjector().getInstance(StatisticsManager.class).registerRequest(userId); securityContext = new UserSecurityContext(new UserPrincipal(userId)); } diff --git a/src/main/java/org/traccar/database/DataManager.java b/src/main/java/org/traccar/database/DataManager.java index 3cad2dd63..aa600e375 100644 --- a/src/main/java/org/traccar/database/DataManager.java +++ b/src/main/java/org/traccar/database/DataManager.java @@ -15,15 +15,11 @@ */ package org.traccar.database; -import org.traccar.Main; -import org.traccar.config.Config; -import org.traccar.config.Keys; import org.traccar.model.BaseModel; import org.traccar.model.Device; import org.traccar.model.Permission; import org.traccar.model.Position; import org.traccar.model.Server; -import org.traccar.model.User; import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; @@ -40,34 +36,9 @@ public class DataManager { private final Storage storage; - private final boolean forceLdap; - @Inject - public DataManager(Config config, Storage storage) throws Exception { + public DataManager(Storage storage) throws Exception { this.storage = storage; - forceLdap = config.getBoolean(Keys.LDAP_FORCE); - } - - public User login(String email, String password) throws StorageException { - User user = storage.getObject(User.class, new Request( - new Columns.Include("id", "login", "hashedPassword", "salt"), - new Condition.Or( - new Condition.Equals("email", "email", email.trim()), - new Condition.Equals("login", "email")))); - LdapProvider ldapProvider = Main.getInjector().getInstance(LdapProvider.class); - if (user != null) { - if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password) - || !forceLdap && user.isPasswordValid(password)) { - return user; - } - } else { - if (ldapProvider != null && ldapProvider.login(email, password)) { - user = ldapProvider.getUser(email); - user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); - return user; - } - } - return null; } public void updateDeviceStatus(Device device) throws StorageException { diff --git a/src/main/java/org/traccar/database/LoginService.java b/src/main/java/org/traccar/database/LoginService.java new file mode 100644 index 000000000..a30e443b5 --- /dev/null +++ b/src/main/java/org/traccar/database/LoginService.java @@ -0,0 +1,89 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.database; + +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.User; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +public class LoginService { + + private final Storage storage; + private final LdapProvider ldapProvider; + + private final boolean forceLdap; + + @Inject + public LoginService(Config config, Storage storage, @Nullable LdapProvider ldapProvider) { + this.storage = storage; + this.ldapProvider = ldapProvider; + forceLdap = config.getBoolean(Keys.LDAP_FORCE); + } + + public User login(String token) throws StorageException { + User user = storage.getObject(User.class, new Request( + new Columns.All(), new Condition.Equals("token", "token", token))); + if (user != null) { + checkUserEnabled(user); + } + return user; + } + + public User login(String email, String password) throws StorageException { + User user = storage.getObject(User.class, new Request( + new Columns.Include("id", "login", "hashedPassword", "salt"), + new Condition.Or( + new Condition.Equals("email", "email", email.trim()), + new Condition.Equals("login", "email")))); + if (user != null) { + if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password) + || !forceLdap && user.isPasswordValid(password)) { + checkUserEnabled(user); + return user; + } + } else { + if (ldapProvider != null && ldapProvider.login(email, password)) { + user = ldapProvider.getUser(email); + user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); + checkUserEnabled(user); + return user; + } + } + return null; + } + + + private void checkUserEnabled(User user) throws SecurityException { + if (user == null) { + throw new SecurityException("Unknown account"); + } + if (user.getDisabled()) { + throw new SecurityException("Account is disabled"); + } + if (user.getExpirationTime() != null && System.currentTimeMillis() > user.getExpirationTime().getTime()) { + throw new SecurityException("Account has expired"); + } + } + +} diff --git a/src/main/java/org/traccar/database/PermissionsManager.java b/src/main/java/org/traccar/database/PermissionsManager.java index f6fbd9489..4ac27c717 100644 --- a/src/main/java/org/traccar/database/PermissionsManager.java +++ b/src/main/java/org/traccar/database/PermissionsManager.java @@ -190,19 +190,6 @@ public class PermissionsManager { } } - public void checkUserEnabled(long userId) throws SecurityException { - User user = getUser(userId); - if (user == null) { - throw new SecurityException("Unknown account"); - } - if (user.getDisabled()) { - throw new SecurityException("Account is disabled"); - } - if (user.getExpirationTime() != null && System.currentTimeMillis() > user.getExpirationTime().getTime()) { - throw new SecurityException("Account has expired"); - } - } - public void refreshPermissions(Permission permission) { if (permission.getOwnerClass().equals(User.class)) { if (permission.getPropertyClass().equals(Device.class) @@ -212,13 +199,4 @@ public class PermissionsManager { } } - public User login(String email, String password) throws StorageException { - User user = dataManager.login(email, password); - if (user != null) { - checkUserEnabled(user.getId()); - return getUser(user.getId()); - } - return null; - } - } -- cgit v1.2.3 From f5a9207393463879cfe85e94259ee70d6d5b9980 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 22 Jun 2022 07:02:42 -0700 Subject: Support service admin account --- .../org/traccar/api/resource/SessionResource.java | 2 +- .../org/traccar/api/security/LoginService.java | 94 ++++++++++++++++++++++ .../traccar/api/security/PermissionsService.java | 8 +- .../api/security/SecurityRequestFilter.java | 1 - .../traccar/api/security/ServiceAccountUser.java | 30 +++++++ src/main/java/org/traccar/config/Keys.java | 8 ++ .../java/org/traccar/database/LoginService.java | 88 -------------------- 7 files changed, 139 insertions(+), 92 deletions(-) create mode 100644 src/main/java/org/traccar/api/security/LoginService.java create mode 100644 src/main/java/org/traccar/api/security/ServiceAccountUser.java delete mode 100644 src/main/java/org/traccar/database/LoginService.java (limited to 'src/main/java/org/traccar/api/resource/SessionResource.java') diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 70561f997..91052fc6b 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -16,7 +16,7 @@ package org.traccar.api.resource; import org.traccar.api.BaseResource; -import org.traccar.database.LoginService; +import org.traccar.api.security.LoginService; import org.traccar.helper.DataConverter; import org.traccar.helper.ServletHelper; import org.traccar.helper.LogAction; diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java new file mode 100644 index 000000000..9938cf6dc --- /dev/null +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -0,0 +1,94 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.api.security; + +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.database.LdapProvider; +import org.traccar.model.User; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; + +import javax.annotation.Nullable; +import javax.inject.Inject; + +public class LoginService { + + private final Storage storage; + private final LdapProvider ldapProvider; + + private final String serviceAccountToken; + private final boolean forceLdap; + + @Inject + public LoginService(Config config, Storage storage, @Nullable LdapProvider ldapProvider) { + this.storage = storage; + this.ldapProvider = ldapProvider; + serviceAccountToken = config.getString(Keys.WEB_SERVICE_ACCOUNT_TOKEN); + forceLdap = config.getBoolean(Keys.LDAP_FORCE); + } + + public User login(String token) throws StorageException { + if (serviceAccountToken != null && serviceAccountToken.equals(token)) { + return new ServiceAccountUser(); + } + User user = storage.getObject(User.class, new Request( + new Columns.All(), new Condition.Equals("token", "token", token))); + if (user != null) { + checkUserEnabled(user); + } + return user; + } + + public User login(String email, String password) throws StorageException { + User user = storage.getObject(User.class, new Request( + new Columns.All(), + new Condition.Or( + new Condition.Equals("email", "email", email.trim()), + new Condition.Equals("login", "email")))); + if (user != null) { + if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password) + || !forceLdap && user.isPasswordValid(password)) { + checkUserEnabled(user); + return user; + } + } else { + if (ldapProvider != null && ldapProvider.login(email, password)) { + user = ldapProvider.getUser(email); + user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); + checkUserEnabled(user); + return user; + } + } + return null; + } + + private void checkUserEnabled(User user) throws SecurityException { + if (user == null) { + throw new SecurityException("Unknown account"); + } + if (user.getDisabled()) { + throw new SecurityException("Account is disabled"); + } + if (user.getExpirationTime() != null && System.currentTimeMillis() > user.getExpirationTime().getTime()) { + throw new SecurityException("Account has expired"); + } + } + +} diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java index ea7a9d572..e5bc52f22 100644 --- a/src/main/java/org/traccar/api/security/PermissionsService.java +++ b/src/main/java/org/traccar/api/security/PermissionsService.java @@ -58,8 +58,12 @@ public class PermissionsService { public User getUser(long userId) throws StorageException { if (user == null && userId > 0) { - user = storage.getObject( - User.class, new Request(new Columns.All(), new Condition.Equals("id", "id", userId))); + if (userId == ServiceAccountUser.ID) { + user = new ServiceAccountUser(); + } else { + user = storage.getObject( + User.class, new Request(new Columns.All(), new Condition.Equals("id", "id", userId))); + } } return user; } diff --git a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java index 3413175c8..eaf5b28c4 100644 --- a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java +++ b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java @@ -18,7 +18,6 @@ package org.traccar.api.security; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.api.resource.SessionResource; -import org.traccar.database.LoginService; import org.traccar.database.StatisticsManager; import org.traccar.helper.DataConverter; import org.traccar.model.User; diff --git a/src/main/java/org/traccar/api/security/ServiceAccountUser.java b/src/main/java/org/traccar/api/security/ServiceAccountUser.java new file mode 100644 index 000000000..644142434 --- /dev/null +++ b/src/main/java/org/traccar/api/security/ServiceAccountUser.java @@ -0,0 +1,30 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.api.security; + +import org.traccar.model.User; + +public class ServiceAccountUser extends User { + + public static final long ID = 9000000000000000000L; + + public ServiceAccountUser() { + setId(ID); + setName("Service Account"); + setEmail("none"); + setAdministrator(true); + } +} diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index a03e47022..3f52fbd96 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -673,6 +673,14 @@ public final class Keys { "web.debug", List.of(KeyType.CONFIG)); + /** + * A token to login as a virtual admin account. Can be used to restore access in case of issues with regular admin + * login. For example, if password is lost and can't be restored. + */ + public static final ConfigKey WEB_SERVICE_ACCOUNT_TOKEN = new StringConfigKey( + "web.serviceAccountToken", + List.of(KeyType.CONFIG)); + /** * Cross-origin resource sharing origin header value. */ diff --git a/src/main/java/org/traccar/database/LoginService.java b/src/main/java/org/traccar/database/LoginService.java deleted file mode 100644 index 2c541e2aa..000000000 --- a/src/main/java/org/traccar/database/LoginService.java +++ /dev/null @@ -1,88 +0,0 @@ -/* - * Copyright 2022 Anton Tananaev (anton@traccar.org) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.traccar.database; - -import org.traccar.config.Config; -import org.traccar.config.Keys; -import org.traccar.model.User; -import org.traccar.storage.Storage; -import org.traccar.storage.StorageException; -import org.traccar.storage.query.Columns; -import org.traccar.storage.query.Condition; -import org.traccar.storage.query.Request; - -import javax.annotation.Nullable; -import javax.inject.Inject; - -public class LoginService { - - private final Storage storage; - private final LdapProvider ldapProvider; - - private final boolean forceLdap; - - @Inject - public LoginService(Config config, Storage storage, @Nullable LdapProvider ldapProvider) { - this.storage = storage; - this.ldapProvider = ldapProvider; - forceLdap = config.getBoolean(Keys.LDAP_FORCE); - } - - public User login(String token) throws StorageException { - User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("token", "token", token))); - if (user != null) { - checkUserEnabled(user); - } - return user; - } - - public User login(String email, String password) throws StorageException { - User user = storage.getObject(User.class, new Request( - new Columns.All(), - new Condition.Or( - new Condition.Equals("email", "email", email.trim()), - new Condition.Equals("login", "email")))); - if (user != null) { - if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password) - || !forceLdap && user.isPasswordValid(password)) { - checkUserEnabled(user); - return user; - } - } else { - if (ldapProvider != null && ldapProvider.login(email, password)) { - user = ldapProvider.getUser(email); - user.setId(storage.addObject(user, new Request(new Columns.Exclude("id")))); - checkUserEnabled(user); - return user; - } - } - return null; - } - - private void checkUserEnabled(User user) throws SecurityException { - if (user == null) { - throw new SecurityException("Unknown account"); - } - if (user.getDisabled()) { - throw new SecurityException("Account is disabled"); - } - if (user.getExpirationTime() != null && System.currentTimeMillis() > user.getExpirationTime().getTime()) { - throw new SecurityException("Account has expired"); - } - } - -} -- cgit v1.2.3 From 1271b2e7a772c8458b567d7f424d5a38365b5d75 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 22 Jun 2022 08:35:59 -0700 Subject: Login as another user --- .../java/org/traccar/api/resource/SessionResource.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) (limited to 'src/main/java/org/traccar/api/resource/SessionResource.java') diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 91052fc6b..8eabdc63c 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -22,6 +22,9 @@ import org.traccar.helper.ServletHelper; import org.traccar.helper.LogAction; import org.traccar.model.User; import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; import javax.annotation.security.PermitAll; import javax.inject.Inject; @@ -33,6 +36,7 @@ import javax.ws.rs.FormParam; import javax.ws.rs.GET; import javax.ws.rs.POST; import javax.ws.rs.Path; +import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; @@ -107,6 +111,17 @@ public class SessionResource extends BaseResource { throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); } + @Path("{id}") + @GET + public User get(@PathParam("id") long userId) throws StorageException { + permissionsService.checkAdmin(getUserId()); + User user = storage.getObject(User.class, new Request( + new Columns.All(), new Condition.Equals("id", "id", userId))); + request.getSession().setAttribute(USER_ID_KEY, user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); + return user; + } + @PermitAll @POST public User add( -- cgit v1.2.3 From ab6970135850655313e257cf44fb68c67e9f1e80 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 2 Aug 2022 19:16:11 -0700 Subject: New API token system --- schema/changelog-5.3.xml | 2 + .../org/traccar/api/resource/SessionResource.java | 30 ++++++++-- .../org/traccar/api/security/LoginService.java | 13 ++++- .../api/security/SecurityRequestFilter.java | 4 +- .../org/traccar/api/signature/CryptoManager.java | 25 +++++---- .../org/traccar/api/signature/TokenManager.java | 64 ++++++++++++++++++++++ src/main/java/org/traccar/model/User.java | 17 ------ 7 files changed, 117 insertions(+), 38 deletions(-) create mode 100644 src/main/java/org/traccar/api/signature/TokenManager.java (limited to 'src/main/java/org/traccar/api/resource/SessionResource.java') diff --git a/schema/changelog-5.3.xml b/schema/changelog-5.3.xml index a689bc236..3b103a6fa 100644 --- a/schema/changelog-5.3.xml +++ b/schema/changelog-5.3.xml @@ -32,6 +32,8 @@ + + diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 8eabdc63c..f70b67cde 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.traccar.api.resource; import org.traccar.api.BaseResource; import org.traccar.api.security.LoginService; +import org.traccar.api.signature.TokenManager; import org.traccar.helper.DataConverter; import org.traccar.helper.ServletHelper; import org.traccar.helper.LogAction; @@ -40,12 +41,16 @@ import javax.ws.rs.PathParam; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.WebApplicationException; +import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import java.io.UnsupportedEncodingException; +import java.io.IOException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.util.Date; +import java.util.concurrent.TimeUnit; @Path("session") @Produces(MediaType.APPLICATION_JSON) @@ -59,12 +64,15 @@ public class SessionResource extends BaseResource { @Inject private LoginService loginService; - @javax.ws.rs.core.Context + @Inject + private TokenManager tokenManager; + + @Context private HttpServletRequest request; @PermitAll @GET - public User get(@QueryParam("token") String token) throws StorageException, UnsupportedEncodingException { + public User get(@QueryParam("token") String token) throws StorageException, IOException, GeneralSecurityException { if (token != null) { User user = loginService.login(token); @@ -84,11 +92,11 @@ public class SessionResource extends BaseResource { for (Cookie cookie : cookies) { if (cookie.getName().equals(USER_COOKIE_KEY)) { byte[] emailBytes = DataConverter.parseBase64( - URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII.name())); + URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII)); email = new String(emailBytes, StandardCharsets.UTF_8); } else if (cookie.getName().equals(PASS_COOKIE_KEY)) { byte[] passwordBytes = DataConverter.parseBase64( - URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII.name())); + URLDecoder.decode(cookie.getValue(), StandardCharsets.US_ASCII)); password = new String(passwordBytes, StandardCharsets.UTF_8); } } @@ -144,4 +152,14 @@ public class SessionResource extends BaseResource { return Response.noContent().build(); } + @Path("token") + @POST + public String requestToken( + @FormParam("expiration") Date expiration) throws StorageException, GeneralSecurityException, IOException { + if (expiration == null) { + expiration = new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(7)); + } + return tokenManager.generateToken(getUserId(), expiration); + } + } diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java index 104a6fac3..1e82a4cf2 100644 --- a/src/main/java/org/traccar/api/security/LoginService.java +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -15,6 +15,7 @@ */ package org.traccar.api.security; +import org.traccar.api.signature.TokenManager; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.database.LdapProvider; @@ -27,29 +28,35 @@ import org.traccar.storage.query.Request; import javax.annotation.Nullable; import javax.inject.Inject; +import java.io.IOException; +import java.security.GeneralSecurityException; public class LoginService { private final Storage storage; + private final TokenManager tokenManager; private final LdapProvider ldapProvider; private final String serviceAccountToken; private final boolean forceLdap; @Inject - public LoginService(Config config, Storage storage, @Nullable LdapProvider ldapProvider) { + public LoginService( + Config config, Storage storage, TokenManager tokenManager, @Nullable LdapProvider ldapProvider) { this.storage = storage; + this.tokenManager = tokenManager; this.ldapProvider = ldapProvider; serviceAccountToken = config.getString(Keys.WEB_SERVICE_ACCOUNT_TOKEN); forceLdap = config.getBoolean(Keys.LDAP_FORCE); } - public User login(String token) throws StorageException { + public User login(String token) throws StorageException, GeneralSecurityException, IOException { if (serviceAccountToken != null && serviceAccountToken.equals(token)) { return new ServiceAccountUser(); } + long userId = tokenManager.verifyToken(token); User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("token", "token", token))); + new Columns.All(), new Condition.Equals("id", "id", userId))); if (user != null) { checkUserEnabled(user); } diff --git a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java index ada7bf997..94b6bbf05 100644 --- a/src/main/java/org/traccar/api/security/SecurityRequestFilter.java +++ b/src/main/java/org/traccar/api/security/SecurityRequestFilter.java @@ -33,8 +33,10 @@ import javax.ws.rs.container.ResourceInfo; import javax.ws.rs.core.Context; import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; +import java.io.IOException; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; public class SecurityRequestFilter implements ContainerRequestFilter { @@ -94,7 +96,7 @@ public class SecurityRequestFilter implements ContainerRequestFilter { statisticsManager.registerRequest(user.getId()); securityContext = new UserSecurityContext(new UserPrincipal(user.getId())); } - } catch (StorageException e) { + } catch (StorageException | GeneralSecurityException | IOException e) { throw new WebApplicationException(e); } diff --git a/src/main/java/org/traccar/api/signature/CryptoManager.java b/src/main/java/org/traccar/api/signature/CryptoManager.java index ea59dcd70..8a3e7704c 100644 --- a/src/main/java/org/traccar/api/signature/CryptoManager.java +++ b/src/main/java/org/traccar/api/signature/CryptoManager.java @@ -15,7 +15,6 @@ */ package org.traccar.api.signature; -import org.traccar.helper.DataConverter; import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; @@ -46,28 +45,32 @@ public class CryptoManager { this.storage = storage; } - public String sign(String data) throws GeneralSecurityException, StorageException { + public byte[] sign(byte[] data) throws GeneralSecurityException, StorageException { if (privateKey == null) { initializeKeys(); } Signature signature = Signature.getInstance("SHA256withECDSA"); signature.initSign(privateKey); - signature.update(data.getBytes()); - return data + '.' + DataConverter.printBase64(signature.sign()); + signature.update(data); + byte[] block = signature.sign(); + byte[] combined = new byte[1 + block.length + data.length]; + combined[0] = (byte) block.length; + System.arraycopy(block, 0, combined, 1, block.length); + System.arraycopy(data, 0, combined, 1 + block.length, data.length); + return combined; } - public String verify(String data) throws GeneralSecurityException, StorageException { + public byte[] verify(byte[] data) throws GeneralSecurityException, StorageException { if (publicKey == null) { initializeKeys(); } Signature signature = Signature.getInstance("SHA256withECDSA"); signature.initVerify(publicKey); - - int delimiter = data.lastIndexOf('.'); - String originalData = data.substring(0, delimiter); - - signature.update(originalData.getBytes()); - if (!signature.verify(DataConverter.parseBase64(data.substring(delimiter + 1)))) { + int length = data[0]; + byte[] originalData = new byte[data.length - 1 - length]; + System.arraycopy(data, 1 + length, originalData, 0, originalData.length); + signature.update(originalData); + if (!signature.verify(data, 1, length)) { throw new SecurityException("Invalid signature"); } return originalData; diff --git a/src/main/java/org/traccar/api/signature/TokenManager.java b/src/main/java/org/traccar/api/signature/TokenManager.java new file mode 100644 index 000000000..3f39d5380 --- /dev/null +++ b/src/main/java/org/traccar/api/signature/TokenManager.java @@ -0,0 +1,64 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.api.signature; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.ObjectMapper; +import org.apache.commons.codec.binary.Base64; +import org.traccar.storage.StorageException; + +import javax.inject.Inject; +import java.io.IOException; +import java.security.GeneralSecurityException; +import java.util.Date; + +public class TokenManager { + + private final ObjectMapper objectMapper; + private final CryptoManager cryptoManager; + + public static class Data { + @JsonProperty("u") + private long userId; + @JsonProperty("e") + private Date expiration; + } + + @Inject + public TokenManager(ObjectMapper objectMapper, CryptoManager cryptoManager) { + this.objectMapper = objectMapper; + this.cryptoManager = cryptoManager; + } + + public String generateToken( + long userId, Date expiration) throws IOException, GeneralSecurityException, StorageException { + Data data = new Data(); + data.userId = userId; + data.expiration = expiration; + byte[] encoded = objectMapper.writeValueAsBytes(data); + return Base64.encodeBase64URLSafeString(cryptoManager.sign(encoded)); + } + + public long verifyToken(String token) throws IOException, GeneralSecurityException, StorageException { + byte[] encoded = cryptoManager.verify(Base64.decodeBase64(token)); + Data data = objectMapper.readValue(encoded, Data.class); + if (data.expiration.before(new Date())) { + throw new SecurityException("Token has expired"); + } + return data.userId; + } + +} diff --git a/src/main/java/org/traccar/model/User.java b/src/main/java/org/traccar/model/User.java index 3db20c753..53594fe07 100644 --- a/src/main/java/org/traccar/model/User.java +++ b/src/main/java/org/traccar/model/User.java @@ -208,23 +208,6 @@ public class User extends ExtendedModel implements UserRestrictions, Disableable this.deviceReadonly = deviceReadonly; } - private String token; - - public String getToken() { - return token; - } - - public void setToken(String token) { - if (token != null && !token.isEmpty()) { - if (!token.matches("^[a-zA-Z0-9-]{16,}$")) { - throw new IllegalArgumentException("Illegal token"); - } - this.token = token; - } else { - this.token = null; - } - } - private boolean limitCommands; @Override -- cgit v1.2.3 From 62e4876406de1951705e76f85c1e099c36d48a87 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 2 Aug 2022 20:40:29 -0700 Subject: New tokens for password reset --- .../org/traccar/api/resource/PasswordResource.java | 33 +++++++++++----------- .../org/traccar/api/resource/SessionResource.java | 3 -- .../org/traccar/api/signature/TokenManager.java | 9 +++++- 3 files changed, 25 insertions(+), 20 deletions(-) (limited to 'src/main/java/org/traccar/api/resource/SessionResource.java') diff --git a/src/main/java/org/traccar/api/resource/PasswordResource.java b/src/main/java/org/traccar/api/resource/PasswordResource.java index 91c2d8ecf..1fb08b02a 100644 --- a/src/main/java/org/traccar/api/resource/PasswordResource.java +++ b/src/main/java/org/traccar/api/resource/PasswordResource.java @@ -16,6 +16,7 @@ package org.traccar.api.resource; import org.traccar.api.BaseResource; +import org.traccar.api.signature.TokenManager; import org.traccar.mail.MailManager; import org.traccar.model.User; import org.traccar.notification.TextTemplateFormatter; @@ -34,35 +35,34 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import java.util.UUID; +import java.io.IOException; +import java.security.GeneralSecurityException; @Path("password") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_FORM_URLENCODED) public class PasswordResource extends BaseResource { - private static final String PASSWORD_RESET_TOKEN = "passwordToken"; - @Inject private MailManager mailManager; + @Inject + private TokenManager tokenManager; + @Inject private TextTemplateFormatter textTemplateFormatter; @Path("reset") @PermitAll @POST - public Response reset(@FormParam("email") String email) throws StorageException, MessagingException { + public Response reset(@FormParam("email") String email) + throws StorageException, MessagingException, GeneralSecurityException, IOException { + User user = storage.getObject(User.class, new Request( new Columns.All(), new Condition.Equals("email", "email", email))); if (user != null) { - String token = UUID.randomUUID().toString().replaceAll("-", ""); - user.set(PASSWORD_RESET_TOKEN, token); - storage.updateObject(user, new Request( - new Columns.Include("attributes"), new Condition.Equals("id", "id"))); - var velocityContext = textTemplateFormatter.prepareContext(permissionsService.getServer(), user); - velocityContext.put("token", token); + velocityContext.put("token", tokenManager.generateToken(user.getId(), null)); var fullMessage = textTemplateFormatter.formatMessage(velocityContext, "passwordReset", "full"); mailManager.sendMessage(user, fullMessage.getSubject(), fullMessage.getBody()); } @@ -73,15 +73,16 @@ public class PasswordResource extends BaseResource { @PermitAll @POST public Response update( - @FormParam("token") String token, @FormParam("password") String password) throws StorageException { - User user = storage.getObjects(User.class, new Request(new Columns.All())).stream() - .filter(it -> token.equals(it.getString(PASSWORD_RESET_TOKEN))) - .findFirst().orElse(null); + @FormParam("token") String token, @FormParam("password") String password) + throws StorageException, GeneralSecurityException, IOException { + + long userId = tokenManager.verifyToken(token); + User user = storage.getObject(User.class, new Request( + new Columns.All(), new Condition.Equals("id", "id", userId))); if (user != null) { - user.getAttributes().remove(PASSWORD_RESET_TOKEN); user.setPassword(password); storage.updateObject(user, new Request( - new Columns.Include("attributes", "hashedPassword", "salt"), new Condition.Equals("id", "id"))); + new Columns.Include("hashedPassword", "salt"), new Condition.Equals("id", "id"))); return Response.ok().build(); } return Response.status(Response.Status.NOT_FOUND).build(); diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index f70b67cde..61c3a5885 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -156,9 +156,6 @@ public class SessionResource extends BaseResource { @POST public String requestToken( @FormParam("expiration") Date expiration) throws StorageException, GeneralSecurityException, IOException { - if (expiration == null) { - expiration = new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(7)); - } return tokenManager.generateToken(getUserId(), expiration); } diff --git a/src/main/java/org/traccar/api/signature/TokenManager.java b/src/main/java/org/traccar/api/signature/TokenManager.java index 3f39d5380..a51234a95 100644 --- a/src/main/java/org/traccar/api/signature/TokenManager.java +++ b/src/main/java/org/traccar/api/signature/TokenManager.java @@ -24,9 +24,12 @@ import javax.inject.Inject; import java.io.IOException; import java.security.GeneralSecurityException; import java.util.Date; +import java.util.concurrent.TimeUnit; public class TokenManager { + private static final int DEFAULT_EXPIRATION_DAYS = 7; + private final ObjectMapper objectMapper; private final CryptoManager cryptoManager; @@ -47,7 +50,11 @@ public class TokenManager { long userId, Date expiration) throws IOException, GeneralSecurityException, StorageException { Data data = new Data(); data.userId = userId; - data.expiration = expiration; + if (expiration != null) { + data.expiration = expiration; + } else { + data.expiration = new Date(System.currentTimeMillis() + TimeUnit.DAYS.toMillis(DEFAULT_EXPIRATION_DAYS)); + } byte[] encoded = objectMapper.writeValueAsBytes(data); return Base64.encodeBase64URLSafeString(cryptoManager.sign(encoded)); } -- cgit v1.2.3 From bd55a835340547aabc3f401bb97e181a3e70df8f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 2 Aug 2022 20:44:34 -0700 Subject: Remove unused import --- src/main/java/org/traccar/api/resource/SessionResource.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src/main/java/org/traccar/api/resource/SessionResource.java') diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 61c3a5885..05f492d73 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -19,8 +19,8 @@ import org.traccar.api.BaseResource; import org.traccar.api.security.LoginService; import org.traccar.api.signature.TokenManager; import org.traccar.helper.DataConverter; -import org.traccar.helper.ServletHelper; import org.traccar.helper.LogAction; +import org.traccar.helper.ServletHelper; import org.traccar.model.User; import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; @@ -44,13 +44,11 @@ import javax.ws.rs.WebApplicationException; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; - import java.io.IOException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.util.Date; -import java.util.concurrent.TimeUnit; @Path("session") @Produces(MediaType.APPLICATION_JSON) -- cgit v1.2.3 From 4c8e98ed409df6e12128591eb1d8d0cf0856deb7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 13 Oct 2022 10:31:54 -0700 Subject: Refactor database code (fix #4961) --- src/main/java/org/traccar/MainEventHandler.java | 2 +- .../java/org/traccar/api/BaseObjectResource.java | 11 +++-- src/main/java/org/traccar/api/MediaFilter.java | 2 +- .../org/traccar/api/resource/CommandResource.java | 2 +- .../org/traccar/api/resource/DeviceResource.java | 8 ++-- .../org/traccar/api/resource/EventResource.java | 2 +- .../org/traccar/api/resource/PasswordResource.java | 7 +-- .../org/traccar/api/resource/PositionResource.java | 2 +- .../org/traccar/api/resource/ServerResource.java | 2 +- .../org/traccar/api/resource/SessionResource.java | 2 +- .../org/traccar/api/resource/UserResource.java | 3 +- .../org/traccar/api/security/LoginService.java | 7 +-- .../traccar/api/security/PermissionsService.java | 4 +- .../java/org/traccar/database/CommandsManager.java | 8 ++-- .../org/traccar/database/DeviceLookupService.java | 2 +- .../java/org/traccar/handler/FilterHandler.java | 2 +- .../handler/events/GeofenceEventHandler.java | 3 +- .../traccar/handler/events/MotionEventHandler.java | 2 +- .../handler/events/OverspeedEventHandler.java | 2 +- .../org/traccar/helper/model/PositionUtil.java | 2 +- src/main/java/org/traccar/model/Device.java | 7 ++- .../org/traccar/reports/EventsReportProvider.java | 4 +- .../org/traccar/reports/GpxExportProvider.java | 2 +- .../org/traccar/reports/KmlExportProvider.java | 2 +- .../org/traccar/reports/RouteReportProvider.java | 2 +- .../org/traccar/reports/StopsReportProvider.java | 2 +- .../org/traccar/reports/TripsReportProvider.java | 2 +- .../org/traccar/reports/common/ReportUtils.java | 4 +- .../org/traccar/session/ConnectionManager.java | 4 +- .../org/traccar/session/cache/CacheManager.java | 12 ++--- .../java/org/traccar/storage/DatabaseStorage.java | 25 +++++----- .../java/org/traccar/storage/QueryBuilder.java | 54 +++++++++++----------- .../java/org/traccar/storage/query/Columns.java | 3 +- .../java/org/traccar/storage/query/Condition.java | 8 +--- 34 files changed, 102 insertions(+), 104 deletions(-) (limited to 'src/main/java/org/traccar/api/resource/SessionResource.java') diff --git a/src/main/java/org/traccar/MainEventHandler.java b/src/main/java/org/traccar/MainEventHandler.java index 17bcad0dd..877f03ae7 100644 --- a/src/main/java/org/traccar/MainEventHandler.java +++ b/src/main/java/org/traccar/MainEventHandler.java @@ -90,7 +90,7 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter { updatedDevice.setPositionId(position.getId()); storage.updateObject(updatedDevice, new Request( new Columns.Include("positionId"), - new Condition.Equals("id", "id"))); + new Condition.Equals("id", updatedDevice.getId()))); cacheManager.updatePosition(position); connectionManager.updatePosition(true, position); diff --git a/src/main/java/org/traccar/api/BaseObjectResource.java b/src/main/java/org/traccar/api/BaseObjectResource.java index 0ec2bfeaa..904781e54 100644 --- a/src/main/java/org/traccar/api/BaseObjectResource.java +++ b/src/main/java/org/traccar/api/BaseObjectResource.java @@ -56,7 +56,7 @@ public abstract class BaseObjectResource extends BaseResour public Response getSingle(@PathParam("id") long id) throws StorageException { permissionsService.checkPermission(baseClass, getUserId(), id); T entity = storage.getObject(baseClass, new Request( - new Columns.All(), new Condition.Equals("id", "id", id))); + new Columns.All(), new Condition.Equals("id", id))); if (entity != null) { return Response.ok(entity).build(); } else { @@ -86,7 +86,7 @@ public abstract class BaseObjectResource extends BaseResour if (entity instanceof User) { User before = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", entity.getId()))); + new Columns.All(), new Condition.Equals("id", entity.getId()))); permissionsService.checkUserUpdate(getUserId(), before, (User) entity); } else if (entity instanceof Group) { Group group = (Group) entity; @@ -97,12 +97,13 @@ public abstract class BaseObjectResource extends BaseResour storage.updateObject(entity, new Request( new Columns.Exclude("id"), - new Condition.Equals("id", "id"))); + new Condition.Equals("id", entity.getId()))); if (entity instanceof User) { User user = (User) entity; if (user.getHashedPassword() != null) { storage.updateObject(entity, new Request( - new Columns.Include("hashedPassword", "salt"), new Condition.Equals("id", "id"))); + new Columns.Include("hashedPassword", "salt"), + new Condition.Equals("id", entity.getId()))); } } cacheManager.updateOrInvalidate(true, entity); @@ -117,7 +118,7 @@ public abstract class BaseObjectResource extends BaseResour permissionsService.checkEdit(getUserId(), baseClass, false); permissionsService.checkPermission(baseClass, getUserId(), id); - storage.removeObject(baseClass, new Request(new Condition.Equals("id", "id", id))); + storage.removeObject(baseClass, new Request(new Condition.Equals("id", id))); cacheManager.invalidate(baseClass, id); LogAction.remove(getUserId(), baseClass, id); diff --git a/src/main/java/org/traccar/api/MediaFilter.java b/src/main/java/org/traccar/api/MediaFilter.java index 6d95c66a8..ab75bdc5d 100644 --- a/src/main/java/org/traccar/api/MediaFilter.java +++ b/src/main/java/org/traccar/api/MediaFilter.java @@ -84,7 +84,7 @@ public class MediaFilter implements Filter { String[] parts = path != null ? path.split("/") : null; if (parts != null && parts.length >= 2) { Device device = storage.getObject(Device.class, new Request( - new Columns.All(), new Condition.Equals("uniqueId", "uniqueId", parts[1]))); + new Columns.All(), new Condition.Equals("uniqueId", parts[1]))); if (device != null) { permissionsServiceProvider.get().checkPermission(Device.class, userId, device.getId()); chain.doFilter(request, response); diff --git a/src/main/java/org/traccar/api/resource/CommandResource.java b/src/main/java/org/traccar/api/resource/CommandResource.java index 92804e725..80b9fd18f 100644 --- a/src/main/java/org/traccar/api/resource/CommandResource.java +++ b/src/main/java/org/traccar/api/resource/CommandResource.java @@ -110,7 +110,7 @@ public class CommandResource extends ExtendedObjectResource { permissionsService.checkPermission(Command.class, getUserId(), entity.getId()); long deviceId = entity.getDeviceId(); entity = storage.getObject(baseClass, new Request( - new Columns.All(), new Condition.Equals("id", "id", entity.getId()))); + new Columns.All(), new Condition.Equals("id", entity.getId()))); entity.setDeviceId(deviceId); } else { permissionsService.checkRestriction(getUserId(), UserRestrictions::getLimitCommands); diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index 1d9bc20ec..c0b0cea0d 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -84,14 +84,14 @@ public class DeviceResource extends BaseObjectResource { result.addAll(storage.getObjects(Device.class, new Request( new Columns.All(), new Condition.And( - new Condition.Equals("uniqueId", "uniqueId", uniqueId), + new Condition.Equals("uniqueId", uniqueId), new Condition.Permission(User.class, getUserId(), Device.class))))); } for (Long deviceId : deviceIds) { result.addAll(storage.getObjects(Device.class, new Request( new Columns.All(), new Condition.And( - new Condition.Equals("id", "id", deviceId), + new Condition.Equals("id", deviceId), new Condition.Permission(User.class, getUserId(), Device.class))))); } return result; @@ -142,7 +142,7 @@ public class DeviceResource extends BaseObjectResource { device.setPositionId(position.getId()); storage.updateObject(device, new Request( new Columns.Include("positionId"), - new Condition.Equals("id", "id"))); + new Condition.Equals("id", device.getId()))); try { cacheManager.addDevice(position.getDeviceId()); @@ -169,7 +169,7 @@ public class DeviceResource extends BaseObjectResource { Device device = storage.getObject(Device.class, new Request( new Columns.All(), new Condition.And( - new Condition.Equals("id", "id", deviceId), + new Condition.Equals("id", deviceId), new Condition.Permission(User.class, getUserId(), Device.class)))); if (device != null) { String name = "device"; diff --git a/src/main/java/org/traccar/api/resource/EventResource.java b/src/main/java/org/traccar/api/resource/EventResource.java index 3870e9af9..afdaf52b5 100644 --- a/src/main/java/org/traccar/api/resource/EventResource.java +++ b/src/main/java/org/traccar/api/resource/EventResource.java @@ -41,7 +41,7 @@ public class EventResource extends BaseResource { @GET public Event get(@PathParam("id") long id) throws StorageException { Event event = storage.getObject(Event.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", id))); + new Columns.All(), new Condition.Equals("id", id))); if (event == null) { throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); } diff --git a/src/main/java/org/traccar/api/resource/PasswordResource.java b/src/main/java/org/traccar/api/resource/PasswordResource.java index 625ff4cb1..ebf4e3b91 100644 --- a/src/main/java/org/traccar/api/resource/PasswordResource.java +++ b/src/main/java/org/traccar/api/resource/PasswordResource.java @@ -59,7 +59,7 @@ public class PasswordResource extends BaseResource { throws StorageException, MessagingException, GeneralSecurityException, IOException { User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("email", "email", email))); + new Columns.All(), new Condition.Equals("email", email))); if (user != null) { var velocityContext = textTemplateFormatter.prepareContext(permissionsService.getServer(), user); velocityContext.put("token", tokenManager.generateToken(user.getId())); @@ -78,11 +78,12 @@ public class PasswordResource extends BaseResource { long userId = tokenManager.verifyToken(token); User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", userId))); + new Columns.All(), new Condition.Equals("id", userId))); if (user != null) { user.setPassword(password); storage.updateObject(user, new Request( - new Columns.Include("hashedPassword", "salt"), new Condition.Equals("id", "id"))); + new Columns.Include("hashedPassword", "salt"), + new Condition.Equals("id", userId))); return Response.ok().build(); } return Response.status(Response.Status.NOT_FOUND).build(); diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java index 7d7921085..042dd1e23 100644 --- a/src/main/java/org/traccar/api/resource/PositionResource.java +++ b/src/main/java/org/traccar/api/resource/PositionResource.java @@ -67,7 +67,7 @@ public class PositionResource extends BaseResource { var positions = new ArrayList(); for (long positionId : positionIds) { Position position = storage.getObject(Position.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", positionId))); + new Columns.All(), new Condition.Equals("id", positionId))); permissionsService.checkPermission(Device.class, getUserId(), position.getDeviceId()); positions.add(position); } diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index e35cd7d95..e7f0b93ca 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -76,7 +76,7 @@ public class ServerResource extends BaseResource { permissionsService.checkAdmin(getUserId()); storage.updateObject(entity, new Request( new Columns.Exclude("id"), - new Condition.Equals("id", "id"))); + new Condition.Equals("id", entity.getId()))); cacheManager.updateOrInvalidate(true, entity); LogAction.edit(getUserId(), entity); return Response.ok(entity).build(); diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 05f492d73..1e984fbd0 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -122,7 +122,7 @@ public class SessionResource extends BaseResource { public User get(@PathParam("id") long userId) throws StorageException { permissionsService.checkAdmin(getUserId()); User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", userId))); + new Columns.All(), new Condition.Equals("id", userId))); request.getSession().setAttribute(USER_ID_KEY, user.getId()); LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); return user; diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java index dd71de4c6..91875ef51 100644 --- a/src/main/java/org/traccar/api/resource/UserResource.java +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -100,7 +100,8 @@ public class UserResource extends BaseObjectResource { entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id")))); storage.updateObject(entity, new Request( - new Columns.Include("hashedPassword", "salt"), new Condition.Equals("id", "id"))); + new Columns.Include("hashedPassword", "salt"), + new Condition.Equals("id", entity.getId()))); LogAction.create(getUserId(), entity); diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java index 32487f06b..88bafcfb5 100644 --- a/src/main/java/org/traccar/api/security/LoginService.java +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -58,7 +58,7 @@ public class LoginService { } long userId = tokenManager.verifyToken(token); User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", userId))); + new Columns.All(), new Condition.Equals("id", userId))); if (user != null) { checkUserEnabled(user); } @@ -66,11 +66,12 @@ public class LoginService { } public User login(String email, String password) throws StorageException { + email = email.trim(); User user = storage.getObject(User.class, new Request( new Columns.All(), new Condition.Or( - new Condition.Equals("email", "email", email.trim()), - new Condition.Equals("login", "email")))); + new Condition.Equals("email", email), + new Condition.Equals("login", email)))); if (user != null) { if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password) || !forceLdap && user.isPasswordValid(password)) { diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java index ddfaaab94..0d4877fdb 100644 --- a/src/main/java/org/traccar/api/security/PermissionsService.java +++ b/src/main/java/org/traccar/api/security/PermissionsService.java @@ -62,7 +62,7 @@ public class PermissionsService { user = new ServiceAccountUser(); } else { user = storage.getObject( - User.class, new Request(new Columns.All(), new Condition.Equals("id", "id", userId))); + User.class, new Request(new Columns.All(), new Condition.Equals("id", userId))); } } return user; @@ -187,7 +187,7 @@ public class PermissionsService { var object = storage.getObject(clazz, new Request( new Columns.Include("id"), new Condition.And( - new Condition.Equals("id", "id", objectId), + new Condition.Equals("id", objectId), new Condition.Permission( User.class, userId, clazz.equals(User.class) ? ManagedUser.class : clazz)))); if (object == null) { diff --git a/src/main/java/org/traccar/database/CommandsManager.java b/src/main/java/org/traccar/database/CommandsManager.java index 53040ad53..764ea637b 100644 --- a/src/main/java/org/traccar/database/CommandsManager.java +++ b/src/main/java/org/traccar/database/CommandsManager.java @@ -69,9 +69,9 @@ public class CommandsManager implements BroadcastInterface { throw new RuntimeException("SMS not configured"); } Device device = storage.getObject(Device.class, new Request( - new Columns.Include("positionId", "phone"), new Condition.Equals("id", "id", deviceId))); + new Columns.Include("positionId", "phone"), new Condition.Equals("id", deviceId))); Position position = storage.getObject(Position.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", device.getPositionId()))); + new Columns.All(), new Condition.Equals("id", device.getPositionId()))); if (position != null) { BaseProtocol protocol = serverManager.getProtocol(position.getProtocol()); protocol.sendTextCommand(device.getPhone(), command); @@ -101,12 +101,12 @@ public class CommandsManager implements BroadcastInterface { try { var commands = storage.getObjects(QueuedCommand.class, new Request( new Columns.All(), - new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Equals("deviceId", deviceId), new Order(false, "id"), new Limit(count))); for (var command : commands) { storage.removeObject(QueuedCommand.class, new Request( - new Condition.Equals("id", "id", command.getId()))); + new Condition.Equals("id", command.getId()))); } return commands.stream().map(QueuedCommand::toCommand).collect(Collectors.toList()); } catch (StorageException e) { diff --git a/src/main/java/org/traccar/database/DeviceLookupService.java b/src/main/java/org/traccar/database/DeviceLookupService.java index 9cf0899ee..28910c24a 100644 --- a/src/main/java/org/traccar/database/DeviceLookupService.java +++ b/src/main/java/org/traccar/database/DeviceLookupService.java @@ -108,7 +108,7 @@ public class DeviceLookupService { for (String uniqueId : uniqueIds) { if (!isThrottled(uniqueId)) { device = storage.getObject(Device.class, new Request( - new Columns.All(), new Condition.Equals("uniqueId", "uniqueId", uniqueId))); + new Columns.All(), new Condition.Equals("uniqueId", uniqueId))); if (device != null) { lookupSucceeded(uniqueId); break; diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index f09cb16a3..3722f2a22 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -88,7 +88,7 @@ public class FilterHandler extends BaseDataHandler { return storage.getObject(Position.class, new Request( new Columns.All(), new Condition.And( - new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Equals("deviceId", deviceId), new Condition.Compare("fixTime", "<=", "time", date)), new Order(true, "fixTime"), new Limit(1))); diff --git a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java index b1be7e8ad..9414f4b31 100644 --- a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java +++ b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java @@ -82,7 +82,8 @@ public class GeofenceEventHandler extends BaseEventHandler { try { storage.updateObject(device, new Request( - new Columns.Include("geofenceIds"), new Condition.Equals("id", "id"))); + new Columns.Include("geofenceIds"), + new Condition.Equals("id", device.getId()))); } catch (StorageException e) { throw new RuntimeException("Update device geofences error", e); } diff --git a/src/main/java/org/traccar/handler/events/MotionEventHandler.java b/src/main/java/org/traccar/handler/events/MotionEventHandler.java index 3511cf682..1b9763c41 100644 --- a/src/main/java/org/traccar/handler/events/MotionEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MotionEventHandler.java @@ -76,7 +76,7 @@ public class MotionEventHandler extends BaseEventHandler { try { storage.updateObject(device, new Request( new Columns.Include("motionState", "motionTime", "motionDistance"), - new Condition.Equals("id", "id"))); + new Condition.Equals("id", device.getId()))); } catch (StorageException e) { LOGGER.warn("Update device motion error", e); } diff --git a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java index 3928fcc88..4d6aa8857 100644 --- a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java +++ b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java @@ -113,7 +113,7 @@ public class OverspeedEventHandler extends BaseEventHandler { try { storage.updateObject(device, new Request( new Columns.Include("overspeedState", "overspeedTime", "overspeedGeofenceId"), - new Condition.Equals("id", "id"))); + new Condition.Equals("id", device.getId()))); } catch (StorageException e) { LOGGER.warn("Update device overspeed error", e); } diff --git a/src/main/java/org/traccar/helper/model/PositionUtil.java b/src/main/java/org/traccar/helper/model/PositionUtil.java index 31f828947..6c380b81a 100644 --- a/src/main/java/org/traccar/helper/model/PositionUtil.java +++ b/src/main/java/org/traccar/helper/model/PositionUtil.java @@ -59,7 +59,7 @@ public final class PositionUtil { return storage.getObjects(Position.class, new Request( new Columns.All(), new Condition.And( - new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Equals("deviceId", deviceId), new Condition.Between("fixTime", "from", from, "to", to)), new Order("fixTime"))); } diff --git a/src/main/java/org/traccar/model/Device.java b/src/main/java/org/traccar/model/Device.java index 147b0fd20..7728172cb 100644 --- a/src/main/java/org/traccar/model/Device.java +++ b/src/main/java/org/traccar/model/Device.java @@ -52,22 +52,22 @@ public class Device extends GroupedModel implements Disableable { private String status; + @QueryIgnore public String getStatus() { return status != null ? status : STATUS_OFFLINE; } - @QueryIgnore public void setStatus(String status) { this.status = status != null ? status.trim() : null; } private Date lastUpdate; + @QueryIgnore public Date getLastUpdate() { return this.lastUpdate; } - @QueryIgnore public void setLastUpdate(Date lastUpdate) { this.lastUpdate = lastUpdate; } @@ -79,18 +79,17 @@ public class Device extends GroupedModel implements Disableable { return positionId; } - @QueryIgnore public void setPositionId(long positionId) { this.positionId = positionId; } private List geofenceIds; + @QueryIgnore public List getGeofenceIds() { return geofenceIds; } - @QueryIgnore public void setGeofenceIds(List geofenceIds) { if (geofenceIds != null) { this.geofenceIds = geofenceIds.stream().map(Number::longValue).collect(Collectors.toList()); diff --git a/src/main/java/org/traccar/reports/EventsReportProvider.java b/src/main/java/org/traccar/reports/EventsReportProvider.java index 878c0265d..d0d4fe8bf 100644 --- a/src/main/java/org/traccar/reports/EventsReportProvider.java +++ b/src/main/java/org/traccar/reports/EventsReportProvider.java @@ -64,7 +64,7 @@ public class EventsReportProvider { return storage.getObjects(Event.class, new Request( new Columns.All(), new Condition.And( - new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Equals("deviceId", deviceId), new Condition.Between("eventTime", "from", from, "to", to)), new Order("eventTime"))); } @@ -134,7 +134,7 @@ public class EventsReportProvider { sheetNames.add(WorkbookUtil.createSafeSheetName(deviceEvents.getDeviceName())); if (device.getGroupId() > 0) { Group group = storage.getObject(Group.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", device.getGroupId()))); + new Columns.All(), new Condition.Equals("id", device.getGroupId()))); if (group != null) { deviceEvents.setGroupName(group.getName()); } diff --git a/src/main/java/org/traccar/reports/GpxExportProvider.java b/src/main/java/org/traccar/reports/GpxExportProvider.java index f1a0f292d..ccbd97fc3 100644 --- a/src/main/java/org/traccar/reports/GpxExportProvider.java +++ b/src/main/java/org/traccar/reports/GpxExportProvider.java @@ -42,7 +42,7 @@ public class GpxExportProvider { OutputStream outputStream, long deviceId, Date from, Date to) throws StorageException { var device = storage.getObject(Device.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", deviceId))); + new Columns.All(), new Condition.Equals("id", deviceId))); var positions = PositionUtil.getPositions(storage, deviceId, from, to); try (PrintWriter writer = new PrintWriter(outputStream)) { diff --git a/src/main/java/org/traccar/reports/KmlExportProvider.java b/src/main/java/org/traccar/reports/KmlExportProvider.java index e8b5c4278..24fcfb8ab 100644 --- a/src/main/java/org/traccar/reports/KmlExportProvider.java +++ b/src/main/java/org/traccar/reports/KmlExportProvider.java @@ -43,7 +43,7 @@ public class KmlExportProvider { OutputStream outputStream, long deviceId, Date from, Date to) throws StorageException { var device = storage.getObject(Device.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", deviceId))); + new Columns.All(), new Condition.Equals("id", deviceId))); var positions = PositionUtil.getPositions(storage, deviceId, from, to); var dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); diff --git a/src/main/java/org/traccar/reports/RouteReportProvider.java b/src/main/java/org/traccar/reports/RouteReportProvider.java index 0f618822e..3ee651619 100644 --- a/src/main/java/org/traccar/reports/RouteReportProvider.java +++ b/src/main/java/org/traccar/reports/RouteReportProvider.java @@ -80,7 +80,7 @@ public class RouteReportProvider { sheetNames.add(WorkbookUtil.createSafeSheetName(deviceRoutes.getDeviceName())); if (device.getGroupId() > 0) { Group group = storage.getObject(Group.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", device.getGroupId()))); + new Columns.All(), new Condition.Equals("id", device.getGroupId()))); if (group != null) { deviceRoutes.setGroupName(group.getName()); } diff --git a/src/main/java/org/traccar/reports/StopsReportProvider.java b/src/main/java/org/traccar/reports/StopsReportProvider.java index ba61ef6a1..ec3fd2215 100644 --- a/src/main/java/org/traccar/reports/StopsReportProvider.java +++ b/src/main/java/org/traccar/reports/StopsReportProvider.java @@ -87,7 +87,7 @@ public class StopsReportProvider { sheetNames.add(WorkbookUtil.createSafeSheetName(deviceStops.getDeviceName())); if (device.getGroupId() > 0) { Group group = storage.getObject(Group.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", device.getGroupId()))); + new Columns.All(), new Condition.Equals("id", device.getGroupId()))); if (group != null) { deviceStops.setGroupName(group.getName()); } diff --git a/src/main/java/org/traccar/reports/TripsReportProvider.java b/src/main/java/org/traccar/reports/TripsReportProvider.java index 2d9bcdfbf..265811354 100644 --- a/src/main/java/org/traccar/reports/TripsReportProvider.java +++ b/src/main/java/org/traccar/reports/TripsReportProvider.java @@ -87,7 +87,7 @@ public class TripsReportProvider { sheetNames.add(WorkbookUtil.createSafeSheetName(deviceTrips.getDeviceName())); if (device.getGroupId() > 0) { Group group = storage.getObject(Group.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", device.getGroupId()))); + new Columns.All(), new Condition.Equals("id", device.getGroupId()))); if (group != null) { deviceTrips.setGroupName(group.getName()); } diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index 1de774dab..120dadcf5 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -95,7 +95,7 @@ public class ReportUtils { return storage.getObject(clazz, new Request( new Columns.All(), new Condition.And( - new Condition.Equals("id", "id", objectId), + new Condition.Equals("id", objectId), new Condition.Permission(User.class, userId, clazz)))); } @@ -166,7 +166,7 @@ public class ReportUtils { if (driverUniqueId != null) { Driver driver = storage.getObject(Driver.class, new Request( new Columns.All(), - new Condition.Equals("uniqueId", "uniqueId", driverUniqueId))); + new Condition.Equals("uniqueId", driverUniqueId))); if (driver != null) { return driver.getName(); } diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java index 9e50c9ead..37a42d827 100644 --- a/src/main/java/org/traccar/session/ConnectionManager.java +++ b/src/main/java/org/traccar/session/ConnectionManager.java @@ -215,7 +215,7 @@ public class ConnectionManager implements BroadcastInterface { if (device == null) { try { device = storage.getObject(Device.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", deviceId))); + new Columns.All(), new Condition.Equals("id", deviceId))); } catch (StorageException e) { LOGGER.warn("Failed to get device", e); } @@ -265,7 +265,7 @@ public class ConnectionManager implements BroadcastInterface { try { storage.updateObject(device, new Request( new Columns.Include("status", "lastUpdate"), - new Condition.Equals("id", "id"))); + new Condition.Equals("id", deviceId))); } catch (StorageException e) { LOGGER.warn("Update device status error", e); } diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index ed67ed70e..8f2e7ba93 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -201,7 +201,7 @@ public class CacheManager implements BroadcastInterface { public void invalidateObject(boolean local, Class clazz, long id) { try { var object = storage.getObject(clazz, new Request( - new Columns.All(), new Condition.Equals("id", "id", id))); + new Columns.All(), new Condition.Equals("id", id))); if (object != null) { updateOrInvalidate(local, object); } else { @@ -286,7 +286,7 @@ public class CacheManager implements BroadcastInterface { Map, Set> links = new HashMap<>(); Device device = storage.getObject(Device.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", deviceId))); + new Columns.All(), new Condition.Equals("id", deviceId))); if (device != null) { addObject(deviceId, device); @@ -294,7 +294,7 @@ public class CacheManager implements BroadcastInterface { long groupId = device.getGroupId(); while (groupDepth < GROUP_DEPTH_LIMIT && groupId > 0) { Group group = storage.getObject(Group.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", groupId))); + new Columns.All(), new Condition.Equals("id", groupId))); links.computeIfAbsent(Group.class, k -> new LinkedHashSet<>()).add(group.getId()); addObject(deviceId, group); groupId = group.getGroupId(); @@ -311,7 +311,7 @@ public class CacheManager implements BroadcastInterface { var scheduled = (ScheduledModel) object; if (scheduled.getCalendarId() > 0) { var calendar = storage.getObject(Calendar.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", scheduled.getCalendarId()))); + new Columns.All(), new Condition.Equals("id", scheduled.getCalendarId()))); links.computeIfAbsent(Notification.class, k -> new LinkedHashSet<>()) .add(calendar.getId()); addObject(deviceId, calendar); @@ -336,7 +336,7 @@ public class CacheManager implements BroadcastInterface { addObject(deviceId, notification); if (notification.getCalendarId() > 0) { var calendar = storage.getObject(Calendar.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", notification.getCalendarId()))); + new Columns.All(), new Condition.Equals("id", notification.getCalendarId()))); links.computeIfAbsent(Notification.class, k -> new LinkedHashSet<>()) .add(calendar.getId()); addObject(deviceId, calendar); @@ -348,7 +348,7 @@ public class CacheManager implements BroadcastInterface { if (device.getPositionId() > 0) { devicePositions.put(deviceId, storage.getObject(Position.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", device.getPositionId())))); + new Columns.All(), new Condition.Equals("id", device.getPositionId())))); } } } diff --git a/src/main/java/org/traccar/storage/DatabaseStorage.java b/src/main/java/org/traccar/storage/DatabaseStorage.java index 8ca464147..884c8fca8 100644 --- a/src/main/java/org/traccar/storage/DatabaseStorage.java +++ b/src/main/java/org/traccar/storage/DatabaseStorage.java @@ -57,7 +57,7 @@ public class DatabaseStorage extends Storage { if (request.getColumns() instanceof Columns.All) { query.append('*'); } else { - query.append(formatColumns(request.getColumns(), clazz, "get", c -> c)); + query.append(formatColumns(request.getColumns().getColumns(clazz, "set"), c -> c)); } query.append(" FROM ").append(getStorageName(clazz)); query.append(formatCondition(request.getCondition())); @@ -76,16 +76,17 @@ public class DatabaseStorage extends Storage { @Override public long addObject(T entity, Request request) throws StorageException { + List columns = request.getColumns().getColumns(entity.getClass(), "get"); StringBuilder query = new StringBuilder("INSERT INTO "); query.append(getStorageName(entity.getClass())); query.append("("); - query.append(formatColumns(request.getColumns(), entity.getClass(), "set", c -> c)); + query.append(formatColumns(columns, c -> c)); query.append(") VALUES ("); - query.append(formatColumns(request.getColumns(), entity.getClass(), "set", c -> ':' + c)); + query.append(formatColumns(columns, c -> ':' + c)); query.append(")"); try { QueryBuilder builder = QueryBuilder.create(config, dataSource, objectMapper, query.toString(), true); - builder.setObject(entity); + builder.setObject(entity, columns); return builder.executeUpdate(); } catch (SQLException e) { throw new StorageException(e); @@ -94,14 +95,15 @@ public class DatabaseStorage extends Storage { @Override public void updateObject(T entity, Request request) throws StorageException { + List columns = request.getColumns().getColumns(entity.getClass(), "get"); StringBuilder query = new StringBuilder("UPDATE "); query.append(getStorageName(entity.getClass())); query.append(" SET "); - query.append(formatColumns(request.getColumns(), entity.getClass(), "set", c -> c + " = :" + c)); + query.append(formatColumns(columns, c -> c + " = :" + c)); query.append(formatCondition(request.getCondition())); try { QueryBuilder builder = QueryBuilder.create(config, dataSource, objectMapper, query.toString()); - builder.setObject(entity); + builder.setObject(entity, columns); for (Map.Entry variable : getConditionVariables(request.getCondition()).entrySet()) { builder.setValue(variable.getKey(), variable.getValue()); } @@ -135,12 +137,10 @@ public class DatabaseStorage extends Storage { query.append(Permission.getStorageName(ownerClass, propertyClass)); var conditions = new LinkedList(); if (ownerId > 0) { - conditions.add(new Condition.Equals( - Permission.getKey(ownerClass), Permission.getKey(ownerClass), ownerId)); + conditions.add(new Condition.Equals(Permission.getKey(ownerClass), ownerId)); } if (propertyId > 0) { - conditions.add(new Condition.Equals( - Permission.getKey(propertyClass), Permission.getKey(propertyClass), propertyId)); + conditions.add(new Condition.Equals(Permission.getKey(propertyClass), propertyId)); } Condition combinedCondition = Condition.merge(conditions); query.append(formatCondition(combinedCondition)); @@ -230,9 +230,8 @@ public class DatabaseStorage extends Storage { return results; } - private String formatColumns( - Columns columns, Class clazz, String type, Function mapper) { - return columns.getColumns(clazz, type).stream().map(mapper).collect(Collectors.joining(", ")); + private String formatColumns(List columns, Function mapper) { + return columns.stream().map(mapper).collect(Collectors.joining(", ")); } private String formatCondition(Condition genericCondition) throws StorageException { diff --git a/src/main/java/org/traccar/storage/QueryBuilder.java b/src/main/java/org/traccar/storage/QueryBuilder.java index a58ebe2b4..fa71a8e8f 100644 --- a/src/main/java/org/traccar/storage/QueryBuilder.java +++ b/src/main/java/org/traccar/storage/QueryBuilder.java @@ -37,10 +37,12 @@ import java.sql.Timestamp; import java.sql.Types; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; @SuppressWarnings("UnusedReturnValue") public final class QueryBuilder { @@ -283,36 +285,32 @@ public final class QueryBuilder { return this; } - public QueryBuilder setObject(Object object) throws SQLException { - - Method[] methods = object.getClass().getMethods(); - - for (Method method : methods) { - if (method.getName().startsWith("get") && method.getParameterTypes().length == 0 - && !method.getName().equals("getClass")) { - String name = method.getName().substring(3); - try { - if (method.getReturnType().equals(boolean.class)) { - setBoolean(name, (Boolean) method.invoke(object)); - } else if (method.getReturnType().equals(int.class)) { - setInteger(name, (Integer) method.invoke(object)); - } else if (method.getReturnType().equals(long.class)) { - setLong(name, (Long) method.invoke(object), name.endsWith("Id")); - } else if (method.getReturnType().equals(double.class)) { - setDouble(name, (Double) method.invoke(object)); - } else if (method.getReturnType().equals(String.class)) { - setString(name, (String) method.invoke(object)); - } else if (method.getReturnType().equals(Date.class)) { - setDate(name, (Date) method.invoke(object)); - } else if (method.getReturnType().equals(byte[].class)) { - setBlob(name, (byte[]) method.invoke(object)); - } else { - setString(name, objectMapper.writeValueAsString(method.invoke(object))); - } - } catch (IllegalAccessException | InvocationTargetException | JsonProcessingException error) { - LOGGER.warn("Get property error", error); + public QueryBuilder setObject(Object object, List columns) throws SQLException { + + try { + for (String column : columns) { + Method method = object.getClass().getMethod( + "get" + Character.toUpperCase(column.charAt(0)) + column.substring(1)); + if (method.getReturnType().equals(boolean.class)) { + setBoolean(column, (Boolean) method.invoke(object)); + } else if (method.getReturnType().equals(int.class)) { + setInteger(column, (Integer) method.invoke(object)); + } else if (method.getReturnType().equals(long.class)) { + setLong(column, (Long) method.invoke(object), column.endsWith("Id")); + } else if (method.getReturnType().equals(double.class)) { + setDouble(column, (Double) method.invoke(object)); + } else if (method.getReturnType().equals(String.class)) { + setString(column, (String) method.invoke(object)); + } else if (method.getReturnType().equals(Date.class)) { + setDate(column, (Date) method.invoke(object)); + } else if (method.getReturnType().equals(byte[].class)) { + setBlob(column, (byte[]) method.invoke(object)); + } else { + setString(column, objectMapper.writeValueAsString(method.invoke(object))); } } + } catch (ReflectiveOperationException | JsonProcessingException e) { + LOGGER.warn("Set object error", e); } return this; diff --git a/src/main/java/org/traccar/storage/query/Columns.java b/src/main/java/org/traccar/storage/query/Columns.java index 545995b3c..a00400b36 100644 --- a/src/main/java/org/traccar/storage/query/Columns.java +++ b/src/main/java/org/traccar/storage/query/Columns.java @@ -17,6 +17,7 @@ package org.traccar.storage.query; import org.traccar.storage.QueryIgnore; +import java.beans.Introspector; import java.lang.reflect.Method; import java.util.Arrays; import java.util.LinkedList; @@ -36,7 +37,7 @@ public abstract class Columns { if (method.getName().startsWith(type) && method.getParameterTypes().length == parameterCount && !method.isAnnotationPresent(QueryIgnore.class) && !method.getName().equals("getClass")) { - columns.add(method.getName().substring(3).toLowerCase()); + columns.add(Introspector.decapitalize(method.getName().substring(3))); } } return columns; diff --git a/src/main/java/org/traccar/storage/query/Condition.java b/src/main/java/org/traccar/storage/query/Condition.java index 136b0402b..08b199052 100644 --- a/src/main/java/org/traccar/storage/query/Condition.java +++ b/src/main/java/org/traccar/storage/query/Condition.java @@ -34,12 +34,8 @@ public interface Condition { } class Equals extends Compare { - public Equals(String column, String variable) { - this(column, variable, null); - } - - public Equals(String column, String variable, Object value) { - super(column, "=", variable, value); + public Equals(String column, Object value) { + super(column, "=", column, value); } } -- cgit v1.2.3 From 1417098fa45a3060f17e0cca6d8226b12e7f174e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 15 Jan 2023 17:37:20 -0800 Subject: Remove default admin --- schema/changelog-4.0-clean.xml | 8 -------- src/main/java/org/traccar/api/resource/ServerResource.java | 8 ++++++++ src/main/java/org/traccar/api/resource/SessionResource.java | 5 ++++- src/main/java/org/traccar/api/resource/UserResource.java | 5 +++++ src/main/java/org/traccar/helper/model/UserUtil.java | 11 +++++++++++ src/main/java/org/traccar/model/Server.java | 12 ++++++++++++ src/main/java/org/traccar/storage/query/Request.java | 6 +++--- 7 files changed, 43 insertions(+), 12 deletions(-) (limited to 'src/main/java/org/traccar/api/resource/SessionResource.java') diff --git a/schema/changelog-4.0-clean.xml b/schema/changelog-4.0-clean.xml index f3f814eba..b4d8ac0ba 100644 --- a/schema/changelog-4.0-clean.xml +++ b/schema/changelog-4.0-clean.xml @@ -620,14 +620,6 @@ - - - - - - - - diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index e7f0b93ca..4b7ee9189 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -16,6 +16,7 @@ package org.traccar.api.resource; import org.traccar.api.BaseResource; +import org.traccar.helper.model.UserUtil; import org.traccar.mail.MailManager; import org.traccar.geocoder.Geocoder; import org.traccar.helper.Log; @@ -65,6 +66,13 @@ public class ServerResource extends BaseResource { server.setEmailEnabled(mailManager.getEmailEnabled()); server.setGeocoderEnabled(geocoder != null); User user = permissionsService.getUser(getUserId()); + if (user != null) { + if (user.getAdministrator()) { + server.setStorageSpace(Log.getStorageSpace()); + } + } else { + server.setNewServer(UserUtil.isEmpty(storage)); + } if (user != null && user.getAdministrator()) { server.setStorageSpace(Log.getStorageSpace()); } diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 1e984fbd0..7025d5fa7 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -110,7 +110,10 @@ public class SessionResource extends BaseResource { } else { - return permissionsService.getUser(userId); + User user = permissionsService.getUser(userId); + if (user != null) { + return user; + } } diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java index 91875ef51..e41ebbe61 100644 --- a/src/main/java/org/traccar/api/resource/UserResource.java +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -19,6 +19,7 @@ import org.traccar.api.BaseObjectResource; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.LogAction; +import org.traccar.helper.model.UserUtil; import org.traccar.model.ManagedUser; import org.traccar.model.Permission; import org.traccar.model.User; @@ -98,6 +99,10 @@ public class UserResource extends BaseObjectResource { } } + if (UserUtil.isEmpty(storage)) { + entity.setAdministrator(true); + } + entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id")))); storage.updateObject(entity, new Request( new Columns.Include("hashedPassword", "salt"), diff --git a/src/main/java/org/traccar/helper/model/UserUtil.java b/src/main/java/org/traccar/helper/model/UserUtil.java index 9919e1d95..9f93afeae 100644 --- a/src/main/java/org/traccar/helper/model/UserUtil.java +++ b/src/main/java/org/traccar/helper/model/UserUtil.java @@ -17,6 +17,11 @@ package org.traccar.helper.model; import org.traccar.model.Server; import org.traccar.model.User; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Order; +import org.traccar.storage.query.Request; import java.util.TimeZone; @@ -25,6 +30,12 @@ public final class UserUtil { private UserUtil() { } + public static boolean isEmpty(Storage storage) throws StorageException { + return storage.getObjects(User.class, new Request( + new Columns.Include("id"), + new Order("id", false, 1))).isEmpty(); + } + public static String getDistanceUnit(Server server, User user) { return lookupStringAttribute(server, user, "distanceUnit", "km"); } diff --git a/src/main/java/org/traccar/model/Server.java b/src/main/java/org/traccar/model/Server.java index 9e248e7bb..73645721b 100644 --- a/src/main/java/org/traccar/model/Server.java +++ b/src/main/java/org/traccar/model/Server.java @@ -249,4 +249,16 @@ public class Server extends ExtendedModel implements UserRestrictions { this.storageSpace = storageSpace; } + private boolean newServer; + + @QueryIgnore + public boolean getNewServer() { + return newServer; + } + + @QueryIgnore + public void setNewServer(boolean newServer) { + this.newServer = newServer; + } + } diff --git a/src/main/java/org/traccar/storage/query/Request.java b/src/main/java/org/traccar/storage/query/Request.java index 6e9cecc63..b9c2c963c 100644 --- a/src/main/java/org/traccar/storage/query/Request.java +++ b/src/main/java/org/traccar/storage/query/Request.java @@ -33,11 +33,11 @@ public class Request { this(columns, condition, null); } - public Request(Columns columns, Condition condition, Order order) { - this(columns, condition, order, null); + public Request(Columns columns, Order order) { + this(columns, null, order); } - public Request(Columns columns, Condition condition, Order order, Limit limit) { + public Request(Columns columns, Condition condition, Order order) { this.columns = columns; this.condition = condition; this.order = order; -- cgit v1.2.3