Commit 91223aea by Tuomas Riihimäki

Add some checks to stuff broken by domain migration from thread-store to username

1 parent 1acfee20
...@@ -168,7 +168,7 @@ public class CardTemplateBean implements CardTemplateBeanLocal { ...@@ -168,7 +168,7 @@ public class CardTemplateBean implements CardTemplateBeanLocal {
public PrintedCard checkPrintedCard(EventUser user) { public PrintedCard checkPrintedCard(EventUser user) {
logger.info("Checking printed card"); logger.info("Checking printed card");
user = eventUserFacade.find(user.getId()); user = eventUserFacade.reload(user);
LanEvent currEvent = eventBean.getCurrentEvent(); LanEvent currEvent = eventBean.getCurrentEvent();
List<PrintedCard> myCards = printedcardfacade.getCards(user); List<PrintedCard> myCards = printedcardfacade.getCards(user);
......
...@@ -32,6 +32,12 @@ public class UserLoginUtils { ...@@ -32,6 +32,12 @@ public class UserLoginUtils {
} }
public static String getUsernameFromJaasString(String username) { public static String getUsernameFromJaasString(String username) {
return username.split("@[^@]+$")[0]; String[] splitted = username.split("@[^@]+$");
String ret = null;
if (splitted.length > 0) {
ret = splitted[0];
}
return ret;
} }
} }
...@@ -246,7 +246,7 @@ public class HostnameFilter implements Filter { ...@@ -246,7 +246,7 @@ public class HostnameFilter implements Filter {
restAuthStr = httpRequest.getHeader("Authorization"); restAuthStr = httpRequest.getHeader("Authorization");
// } // }
if (restAuthStr == null) { if (restAuthStr == null && httpRequest.getParameter("appkey") != null) {
StringBuilder hashBuilder = new StringBuilder(); StringBuilder hashBuilder = new StringBuilder();
hashBuilder.append(JaasBeanLocal.REST_PREFIX); hashBuilder.append(JaasBeanLocal.REST_PREFIX);
...@@ -257,9 +257,15 @@ public class HostnameFilter implements Filter { ...@@ -257,9 +257,15 @@ public class HostnameFilter implements Filter {
hashBuilder.append(httpRequest.getPathInfo()); hashBuilder.append(httpRequest.getPathInfo());
restAuthStr = hashBuilder.toString(); restAuthStr = hashBuilder.toString();
} }
boolean ret = true; boolean ret = true;
try { try {
httpRequest.login('@' + parseHostname(httpRequest), restAuthStr); if (restAuthStr == null) {
throw new ServletException("No auth data");
}
final String username = "@" + parseHostname(httpRequest);
logger.info("Logging in with username {} and password {}", username, restAuthStr);
httpRequest.login(username, restAuthStr);
} catch (ServletException loginEx) { } catch (ServletException loginEx) {
ret = false; ret = false;
logger.info("Rest api authentication failed for path " + httpRequest.getPathInfo() + " " logger.info("Rest api authentication failed for path " + httpRequest.getPathInfo() + " "
...@@ -296,10 +302,11 @@ public class HostnameFilter implements Filter { ...@@ -296,10 +302,11 @@ public class HostnameFilter implements Filter {
logbean.sendMessage(MoyaEventType.USER_PERMISSION_VIOLATION, logbean.sendMessage(MoyaEventType.USER_PERMISSION_VIOLATION,
"Hostname mismatch privilege escalation! User '", httpRequest.getUserPrincipal(), "' tried to change hostname from '", "Hostname mismatch privilege escalation! User '", httpRequest.getUserPrincipal(), "' tried to change hostname from '",
userDomain, "' to '", hostname, ","); userDomain, "' to '", hostname, ",");
throw new RuntimeException("Hostname mismatch!"); throw new RuntimeException("Hostname mismatch! Expected: " + hostname + " but logged in as " + userDomain);
} }
} }
BortalLocalContextHolder.setInDevelopmentMode(developmentMode); BortalLocalContextHolder.setInDevelopmentMode(developmentMode);
return hostname; return hostname;
......
/* /*
* Copyright Codecrew Ry * Copyright Codecrew Ry
* *
* All rights reserved. * All rights reserved.
* *
* This license applies to any software containing a notice placed by the * This license applies to any software containing a notice placed by the
* copyright holder. Such software is herein referred to as the Software. * copyright holder. Such software is herein referred to as the Software.
* This license covers modification, distribution and use of the Software. * This license covers modification, distribution and use of the Software.
* *
* Any distribution and use in source and binary forms, with or without * Any distribution and use in source and binary forms, with or without
* modification is not permitted without explicit written permission from the * modification is not permitted without explicit written permission from the
* copyright owner. * copyright owner.
* *
* A non-exclusive royalty-free right is granted to the copyright owner of the * A non-exclusive royalty-free right is granted to the copyright owner of the
* Software to use, modify and distribute all modifications to the Software in * Software to use, modify and distribute all modifications to the Software in
* future versions of the Software. * future versions of the Software.
* *
*/ */
package fi.codecrew.moya.rest; package fi.codecrew.moya.rest;
...@@ -43,6 +43,7 @@ import javax.ws.rs.core.Response; ...@@ -43,6 +43,7 @@ import javax.ws.rs.core.Response;
import javax.ws.rs.core.Response.ResponseBuilder; import javax.ws.rs.core.Response.ResponseBuilder;
import javax.ws.rs.core.Response.Status; import javax.ws.rs.core.Response.Status;
import fi.codecrew.moya.model.*;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
...@@ -59,12 +60,6 @@ import fi.codecrew.moya.beans.TicketBeanLocal; ...@@ -59,12 +60,6 @@ import fi.codecrew.moya.beans.TicketBeanLocal;
import fi.codecrew.moya.beans.UserBeanLocal; import fi.codecrew.moya.beans.UserBeanLocal;
import fi.codecrew.moya.entitysearch.UserSearchQuery; import fi.codecrew.moya.entitysearch.UserSearchQuery;
import fi.codecrew.moya.enums.apps.UserPermission; import fi.codecrew.moya.enums.apps.UserPermission;
import fi.codecrew.moya.model.EventUser;
import fi.codecrew.moya.model.GroupMembership;
import fi.codecrew.moya.model.Place;
import fi.codecrew.moya.model.ReaderEvent;
import fi.codecrew.moya.model.User;
import fi.codecrew.moya.model.UserImage;
import fi.codecrew.moya.rest.pojo.userinfo.v1.EventUserRestPojo; import fi.codecrew.moya.rest.pojo.userinfo.v1.EventUserRestPojo;
import fi.codecrew.moya.rest.pojo.userinfo.v1.PrintedCardRestPojo; import fi.codecrew.moya.rest.pojo.userinfo.v1.PrintedCardRestPojo;
import fi.codecrew.moya.rest.pojo.userinfo.v1.SimpleEventuserRoot; import fi.codecrew.moya.rest.pojo.userinfo.v1.SimpleEventuserRoot;
...@@ -75,8 +70,8 @@ import fi.codecrew.moya.utilities.SearchResult; ...@@ -75,8 +70,8 @@ import fi.codecrew.moya.utilities.SearchResult;
@RequestScoped @RequestScoped
@Path("/user") @Path("/user")
@Consumes({ MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML }) @Consumes({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
@Produces({ MediaType.APPLICATION_JSON + "; charset=UTF-8" }) @Produces({MediaType.APPLICATION_JSON + "; charset=UTF-8"})
@Api(value = "/user", description = "Administer users") @Api(value = "/user", description = "Administer users")
public class UserRestView { public class UserRestView {
...@@ -108,10 +103,10 @@ public class UserRestView { ...@@ -108,10 +103,10 @@ public class UserRestView {
@POST @POST
@Path("/giveplace/{placeId}") @Path("/giveplace/{placeId}")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@ApiOperation(value = "Set place status to give/ungive", response = UserReservationPlacePojo.class) @ApiOperation(value = "Set place status to give/ungive", response = UserReservationPlacePojo.class)
public Response setPlacesGivenStatus( public Response setPlacesGivenStatus(
@PathParam("placeId") Integer id, @PathParam("placeId") Integer id,
@FormParam("action") String status) { @FormParam("action") String status) {
Place place = placebean.find(id); Place place = placebean.find(id);
if (place == null) { if (place == null) {
...@@ -129,17 +124,17 @@ public class UserRestView { ...@@ -129,17 +124,17 @@ public class UserRestView {
ResponseBuilder resp = Response.ok(); ResponseBuilder resp = Response.ok();
switch (status) { switch (status) {
case "give": case "give":
gm = placegroupbean.markGroupMembershipEntered(gm); gm = placegroupbean.markGroupMembershipEntered(gm);
break; break;
case "ungive": case "ungive":
gm = placegroupbean.markGroupMembershipNotEntered(gm); gm = placegroupbean.markGroupMembershipNotEntered(gm);
break; break;
default: default:
resp = Response.status(Status.BAD_REQUEST); resp = Response.status(Status.BAD_REQUEST);
resp.status(Status.BAD_REQUEST); resp.status(Status.BAD_REQUEST);
resp.entity("Unknown status" + status + " possible values: 'give' and 'ungive'"); resp.entity("Unknown status" + status + " possible values: 'give' and 'ungive'");
return resp.build(); return resp.build();
} }
...@@ -150,38 +145,38 @@ public class UserRestView { ...@@ -150,38 +145,38 @@ public class UserRestView {
@GET @GET
@Path("/reservationswithcode/{code}") @Path("/reservationswithcode/{code}")
@ApiOperation(value = "Get places with code", response = UserReservationRoot.class) @ApiOperation(value = "Get places with code", response = UserReservationRoot.class)
public Response getPlacesWithCode(@PathParam("code") String code) { public Response getPlacesWithCode(@PathParam("code") String code) {
try { try {
EventUser curruser = permbean.getCurrentUser(); EventUser curruser = permbean.getCurrentUser();
ReaderEvent revent = readerbean.checkCode("restapi: " + curruser.getLogin(), code); ReaderEvent revent = readerbean.checkCode("restapi: " + curruser.getLogin(), code);
if (revent != null && revent.getUser() != null) { if (revent != null && revent.getUser() != null) {
EventUser eu = revent.getUser(); EventUser eu = revent.getUser();
List<GroupMembership> gms = ticketbean.findMembershipPrintlistForUser(eu); List<GroupMembership> gms = ticketbean.findMembershipPrintlistForUser(eu);
UserReservationRoot ret = new UserReservationRoot(); UserReservationRoot ret = new UserReservationRoot();
ret.setUser(PojoUtils.initEventUserRestPojo(eu)); ret.setUser(PojoUtils.initEventUserRestPojo(eu));
for (GroupMembership g : gms) { for (GroupMembership g : gms) {
ret.getReservations().add(PojoUtils.initUserReservationPlace(g)); ret.getReservations().add(PojoUtils.initUserReservationPlace(g));
} }
return Response.ok(ret).build(); return Response.ok(ret).build();
} }
return Response.status(Status.NOT_FOUND).build(); return Response.status(Status.NOT_FOUND).build();
} catch (Exception e) { } catch (Exception e) {
logger.error("Getting places failed", e); logger.error("Getting places failed", e);
return Response.serverError().build(); return Response.serverError().build();
} }
} }
@GET @GET
@Path("/{userid}/reservations") @Path("/{userid}/reservations")
@ApiOperation(value = "Get user's reservations", response = UserReservationRoot.class) @ApiOperation(value = "Get user's reservations", response = UserReservationRoot.class)
public Response usersPlaces(@PathParam("userid") Integer userid) { public Response usersPlaces(@PathParam("userid") Integer userid) {
EventUser eu = userbean.findByUserId(userid, false); EventUser eu = userbean.findByUserId(userid, false);
if (eu != null) { if (eu != null) {
...@@ -200,12 +195,12 @@ public class UserRestView { ...@@ -200,12 +195,12 @@ public class UserRestView {
@POST @POST
@Path("/auth") @Path("/auth")
@Produces({ MediaType.APPLICATION_JSON }) @Produces({MediaType.APPLICATION_JSON})
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@ApiOperation(value = "Authenticate", response = EventUserRestPojo.class) @ApiOperation(value = "Authenticate", response = EventUserRestPojo.class)
public Response auth( public Response auth(
@FormParam("username") String username, @FormParam("username") String username,
@FormParam("password") String password) { @FormParam("password") String password) {
logger.info("Tried to login with rest {} , {}", username, password); logger.info("Tried to login with rest {} , {}", username, password);
boolean success = true; boolean success = true;
try { try {
...@@ -243,30 +238,35 @@ public class UserRestView { ...@@ -243,30 +238,35 @@ public class UserRestView {
@Path("/eventusers") @Path("/eventusers")
@ApiOperation(value = "Get EventUsers", response = SimpleEventuserRoot.class) @ApiOperation(value = "Get EventUsers", response = SimpleEventuserRoot.class)
public SimpleEventuserRoot getEventUsers( public SimpleEventuserRoot getEventUsers(
@DefaultValue("0") @QueryParam("pagesize") Integer pagesize, @DefaultValue("0") @QueryParam("pagesize") Integer pagesize,
@DefaultValue("0") @QueryParam("page") Integer page, @DefaultValue("0") @QueryParam("page") Integer page,
@QueryParam("search") String search @QueryParam("search") String search
) { ) {
try { try {
UserSearchQuery q = new UserSearchQuery(page, pagesize, null, search, QuerySortOrder.UNSORTED); UserSearchQuery q = new UserSearchQuery(page, pagesize, null, search, QuerySortOrder.UNSORTED);
SearchResult<EventUser> users = userbean.getThisEventsUsers(q); SearchResult<EventUser> users = userbean.getThisEventsUsers(q);
return PojoUtils.parseEventusers(users.getResults()); return PojoUtils.parseEventusers(users.getResults());
} catch (Exception e) { } catch (Exception e) {
logger.error("Getting EventUsers failed", e); logger.error("Getting EventUsers failed", e);
throw e; throw e;
} }
} }
@GET @GET
@Path("/card/{eventuserId}") @Path("/card/{eventuserId}")
@ApiOperation(value = "Get PrintedCard for EventUser", response = PrintedCardRestPojo.class) @ApiOperation(value = "Get PrintedCard for EventUser", response = PrintedCardRestPojo.class)
public PrintedCardRestPojo getUsersCard( public PrintedCardRestPojo getUsersCard(
@ApiParam("EventUser entity ID") @PathParam("eventuserId") Integer eventuserid) { @ApiParam("EventUser entity ID") @PathParam("eventuserId") Integer eventuserid) {
EventUser user = userbean.findByEventUserId(eventuserid); EventUser user = userbean.findByEventUserId(eventuserid);
return PojoUtils.initPrintedCardRestPojo(cardbean.checkPrintedCard(user)); logger.warn("users card for user: {}", user);
PrintedCard card = cardbean.checkPrintedCard(user);
if (card == null) {
return null;
}
return PojoUtils.initPrintedCardRestPojo(card);
} }
...@@ -274,7 +274,7 @@ public class UserRestView { ...@@ -274,7 +274,7 @@ public class UserRestView {
@Path("/eventuser/{cardauthcode}") @Path("/eventuser/{cardauthcode}")
@ApiOperation(value = "Get EventUser by cardAuthCode", response = EventUserRestPojo.class) @ApiOperation(value = "Get EventUser by cardAuthCode", response = EventUserRestPojo.class)
public EventUserRestPojo getEventUser( public EventUserRestPojo getEventUser(
@ApiParam("Card authentication code") @PathParam("cardauthcode") String code) { @ApiParam("Card authentication code") @PathParam("cardauthcode") String code) {
EventUser user = userbean.getUserByAuthcode(code); EventUser user = userbean.getUserByAuthcode(code);
if (user != null) if (user != null)
...@@ -283,123 +283,124 @@ public class UserRestView { ...@@ -283,123 +283,124 @@ public class UserRestView {
return new EventUserRestPojo(); return new EventUserRestPojo();
} }
@GET @GET
@Path("/") @Path("/")
@Produces({ MediaType.APPLICATION_JSON }) @Produces({MediaType.APPLICATION_JSON})
@ApiOperation(value = "Find event user", response = EventUserRestPojo.class) @ApiOperation(value = "Find event user", response = EventUserRestPojo.class)
public Response getEventUser(@QueryParam("email") @ApiParam("Email address") String email, public Response getEventUser(@QueryParam("email") @ApiParam("Email address") String email,
@QueryParam("login") @ApiParam("Username") String userName) { @QueryParam("login") @ApiParam("Username") String userName) {
try { try {
if (permbean.hasPermission(UserPermission.VIEW_ALL) == false) { if (permbean.hasPermission(UserPermission.VIEW_ALL) == false) {
return Response.status(Status.FORBIDDEN).build(); return Response.status(Status.FORBIDDEN).build();
} }
EventUser eventUser; EventUser eventUser;
User user = null; User user = null;
// If username not given, try to find username by email // If username not given, try to find username by email
if (userName == null || userName.isEmpty()) { if (userName == null || userName.isEmpty()) {
user = userbean.findUserByEmailUsername(email); user = userbean.findUserByEmailUsername(email);
} }
if(user != null) { if (user != null) {
eventUser = userbean.getEventUser(user, true); eventUser = userbean.getEventUser(user, true);
} else { } else {
// Get the user // Get the user
eventUser = userbean.findEventuserByLogin(userName); eventUser = userbean.findEventuserByLogin(userName);
} }
if (eventUser == null) { if (eventUser == null) {
return Response.status(Status.NOT_FOUND).build(); return Response.status(Status.NOT_FOUND).build();
} }
// Return the EventUser // Return the EventUser
return Response.ok(PojoUtils.initEventUserRestPojo(eventUser)).build(); return Response.ok(PojoUtils.initEventUserRestPojo(eventUser)).build();
} catch (Exception e) { } catch (Exception e) {
logger.error("Finding event user failed", e); logger.error("Finding event user failed", e);
return Response.serverError().build(); return Response.serverError().build();
} }
} }
@POST @POST
@Path("/{userid}/check-password") @Path("/{userid}/check-password")
@Produces({ MediaType.APPLICATION_JSON }) @Produces({MediaType.APPLICATION_JSON})
@ApiOperation(value = "Check user password", response = EventUserRestPojo.class) @ApiOperation(value = "Check user password", response = EventUserRestPojo.class)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response checkPassword(@PathParam("userid") @ApiParam("User ID") Integer userId, public Response checkPassword(@PathParam("userid") @ApiParam("User ID") Integer userId,
@FormParam("password") @ApiParam("Password") String password) { @FormParam("password") @ApiParam("Password") String password) {
try { try {
if (permbean.hasPermission(UserPermission.VIEW_ALL) == false) { if (permbean.hasPermission(UserPermission.VIEW_ALL) == false) {
return Response.status(Status.FORBIDDEN).build(); return Response.status(Status.FORBIDDEN).build();
} }
EventUser user = userbean.findByUserId(userId, true); EventUser user = userbean.findByUserId(userId, true);
if (user == null) { if (user == null) {
return Response.status(Status.NOT_FOUND).build(); return Response.status(Status.NOT_FOUND).build();
} }
//boolean passwordOk = user.checkPassword(password); //boolean passwordOk = user.checkPassword(password);
boolean passwordOk = userbean.checkPassword(user, password); boolean passwordOk = userbean.checkPassword(user, password);
if (passwordOk) { if (passwordOk) {
return Response.ok(PojoUtils.initEventUserRestPojo(user), MediaType.APPLICATION_JSON_TYPE).build(); return Response.ok(PojoUtils.initEventUserRestPojo(user), MediaType.APPLICATION_JSON_TYPE).build();
} }
return Response.status(Status.UNAUTHORIZED).entity(PojoUtils.initErrorPojo("Wrong password")).build(); return Response.status(Status.UNAUTHORIZED).entity(PojoUtils.initErrorPojo("Wrong password")).build();
} catch (Exception e) { } catch (Exception e) {
logger.error("Checking user authentication failed", e); logger.error("Checking user authentication failed", e);
return Response.serverError().entity(PojoUtils.initErrorPojo("Checking password failed")).build(); return Response.serverError().entity(PojoUtils.initErrorPojo("Checking password failed")).build();
} }
} }
@POST @POST
@Path("/{userid}/reset-password") @Path("/{userid}/reset-password")
@Produces({ MediaType.APPLICATION_JSON }) @Produces({MediaType.APPLICATION_JSON})
@ApiOperation(value = "Reset user password", response = EventUserRestPojo.class) @ApiOperation(value = "Reset user password", response = EventUserRestPojo.class)
@Consumes(MediaType.APPLICATION_FORM_URLENCODED) @Consumes(MediaType.APPLICATION_FORM_URLENCODED)
public Response resetPassword(@PathParam("userid") @ApiParam("User ID") Integer userId, public Response resetPassword(@PathParam("userid") @ApiParam("User ID") Integer userId,
@FormParam("password") @ApiParam("New password") String password) { @FormParam("password") @ApiParam("New password") String password) {
try { try {
if (permbean.hasPermission(UserPermission.MODIFY) == false || permbean.hasPermission(UserPermission.VIEW_ALL)) { if (permbean.hasPermission(UserPermission.MODIFY) == false || permbean.hasPermission(UserPermission.VIEW_ALL)) {
return Response.status(Status.FORBIDDEN).build(); return Response.status(Status.FORBIDDEN).build();
} }
EventUser eventUser = userbean.findByUserId(userId, true); EventUser eventUser = userbean.findByUserId(userId, true);
User user = eventUser.getUser(); User user = eventUser.getUser();
userbean.resetPassword(user, password); userbean.resetPassword(user, password);
return Response.ok(PojoUtils.initEventUserRestPojo(eventUser)).build(); return Response.ok(PojoUtils.initEventUserRestPojo(eventUser)).build();
} catch (Exception e) { } catch (Exception e) {
logger.error("Checking user authentication failed", e); logger.error("Checking user authentication failed", e);
return Response.serverError().entity(PojoUtils.initErrorPojo("Resetting user password failed")).build(); return Response.serverError().entity(PojoUtils.initErrorPojo("Resetting user password failed")).build();
} }
} }
/** /**
* Post forma parameter "image" with the image data in it. * Post forma parameter "image" with the image data in it.
* @param request *
* @param userId * @param request
* @return * @param userId
* @throws IOException * @return
*/ * @throws IOException
@PUT */
@Path("/{userid}/image") @PUT
@ApiOperation(value = "Upload image", response = EventUserRestPojo.class) @Path("/{userid}/image")
@Consumes(MediaType.MULTIPART_FORM_DATA) @ApiOperation(value = "Upload image", response = EventUserRestPojo.class)
public Response updateUserImage(@Context HttpServletRequest request, @Consumes(MediaType.MULTIPART_FORM_DATA)
@PathParam("userid") @ApiParam("User ID") Integer userId) throws IOException { public Response updateUserImage(@Context HttpServletRequest request,
try { @PathParam("userid") @ApiParam("User ID") Integer userId) throws IOException {
if (permbean.hasPermission(UserPermission.MODIFY) == false || permbean.hasPermission(UserPermission.VIEW_ALL)) { try {
return Response.status(Status.FORBIDDEN).build(); if (permbean.hasPermission(UserPermission.MODIFY) == false || permbean.hasPermission(UserPermission.VIEW_ALL)) {
} return Response.status(Status.FORBIDDEN).build();
Part imagePart = request.getPart("image"); }
EventUser eventUser = userbean.findByUserId(userId, true); Part imagePart = request.getPart("image");
UserImage userImage = userbean.uploadImage(eventUser, imagePart.getContentType(), EventUser eventUser = userbean.findByUserId(userId, true);
imagePart.getInputStream(), imagePart.getSubmittedFileName(), null); UserImage userImage = userbean.uploadImage(eventUser, imagePart.getContentType(),
return Response.ok(PojoUtils.initEventUserRestPojo(eventUser)).build(); imagePart.getInputStream(), imagePart.getSubmittedFileName(), null);
} catch (ServletException e) { return Response.ok(PojoUtils.initEventUserRestPojo(eventUser)).build();
logger.error("Updating user image failed", e); } catch (ServletException e) {
return Response.serverError().entity(PojoUtils.initErrorPojo("Updating user image failed")).build(); logger.error("Updating user image failed", e);
} return Response.serverError().entity(PojoUtils.initErrorPojo("Updating user image failed")).build();
} }
}
} }
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!