mirror of
https://github.com/Athou/commafeed.git
synced 2026-11-04 19:34:47 +00:00
prevent users from referencing categories owned by other users
This commit is contained in:
@@ -39,6 +39,7 @@ import jakarta.validation.Valid;
|
|||||||
import jakarta.ws.rs.Consumes;
|
import jakarta.ws.rs.Consumes;
|
||||||
import jakarta.ws.rs.DefaultValue;
|
import jakarta.ws.rs.DefaultValue;
|
||||||
import jakarta.ws.rs.GET;
|
import jakarta.ws.rs.GET;
|
||||||
|
import jakarta.ws.rs.NotFoundException;
|
||||||
import jakarta.ws.rs.POST;
|
import jakarta.ws.rs.POST;
|
||||||
import jakarta.ws.rs.Path;
|
import jakarta.ws.rs.Path;
|
||||||
import jakarta.ws.rs.Produces;
|
import jakarta.ws.rs.Produces;
|
||||||
@@ -333,8 +334,10 @@ public class CategoryREST {
|
|||||||
cat.setPosition(0);
|
cat.setPosition(0);
|
||||||
String parentId = req.getParentId();
|
String parentId = req.getParentId();
|
||||||
if (parentId != null && !ALL.equals(parentId)) {
|
if (parentId != null && !ALL.equals(parentId)) {
|
||||||
FeedCategory parent = new FeedCategory();
|
FeedCategory parent = feedCategoryDAO.findById(user, Long.valueOf(parentId));
|
||||||
parent.setId(Long.valueOf(parentId));
|
if (parent == null) {
|
||||||
|
throw new NotFoundException("parent category not found");
|
||||||
|
}
|
||||||
cat.setParent(parent);
|
cat.setParent(parent);
|
||||||
}
|
}
|
||||||
feedCategoryDAO.persist(cat);
|
feedCategoryDAO.persist(cat);
|
||||||
|
|||||||
@@ -407,13 +407,17 @@ public class FeedREST {
|
|||||||
Preconditions.checkNotNull(req.getUrl());
|
Preconditions.checkNotNull(req.getUrl());
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
User user = authenticationContext.getCurrentUser();
|
||||||
|
|
||||||
FeedCategory category = null;
|
FeedCategory category = null;
|
||||||
if (req.getCategoryId() != null && !CategoryREST.ALL.equals(req.getCategoryId())) {
|
if (req.getCategoryId() != null && !CategoryREST.ALL.equals(req.getCategoryId())) {
|
||||||
category = feedCategoryDAO.findById(Long.valueOf(req.getCategoryId()));
|
category = feedCategoryDAO.findById(user, Long.valueOf(req.getCategoryId()));
|
||||||
|
if (category == null) {
|
||||||
|
return Response.status(Status.NOT_FOUND).build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
FeedInfo info = fetchFeedInternal(prependHttp(req.getUrl()));
|
FeedInfo info = fetchFeedInternal(prependHttp(req.getUrl()));
|
||||||
User user = authenticationContext.getCurrentUser();
|
|
||||||
long subscriptionId = feedSubscriptionService.subscribe(user, info.getUrl(), req.getTitle(), category, 0);
|
long subscriptionId = feedSubscriptionService.subscribe(user, info.getUrl(), req.getTitle(), category, 0);
|
||||||
return Response.ok(subscriptionId).build();
|
return Response.ok(subscriptionId).build();
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.commafeed.frontend.model.Entries;
|
|||||||
import com.commafeed.frontend.model.Subscription;
|
import com.commafeed.frontend.model.Subscription;
|
||||||
import com.commafeed.frontend.model.request.AddCategoryRequest;
|
import com.commafeed.frontend.model.request.AddCategoryRequest;
|
||||||
import com.commafeed.frontend.model.request.InitialSetupRequest;
|
import com.commafeed.frontend.model.request.InitialSetupRequest;
|
||||||
|
import com.commafeed.frontend.model.request.RegistrationRequest;
|
||||||
import com.commafeed.frontend.model.request.SubscribeRequest;
|
import com.commafeed.frontend.model.request.SubscribeRequest;
|
||||||
|
|
||||||
import io.restassured.RestAssured;
|
import io.restassured.RestAssured;
|
||||||
@@ -102,6 +103,26 @@ public abstract class BaseIT {
|
|||||||
.statusCode(200);
|
.statusCode(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected void registerUser(String userName, String password) {
|
||||||
|
RegistrationRequest req = new RegistrationRequest();
|
||||||
|
req.setName(userName);
|
||||||
|
req.setPassword(password);
|
||||||
|
req.setEmail(userName + "@commafeed.com");
|
||||||
|
|
||||||
|
RestAssured.given()
|
||||||
|
.auth()
|
||||||
|
.none()
|
||||||
|
.body(req)
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.post("rest/user/register")
|
||||||
|
.then()
|
||||||
|
.statusCode(HttpStatus.SC_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void authenticateAs(String userName, String password) {
|
||||||
|
RestAssured.authentication = RestAssured.preemptive().basic(userName, password);
|
||||||
|
}
|
||||||
|
|
||||||
protected List<HttpCookie> login() {
|
protected List<HttpCookie> login() {
|
||||||
return login(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
|
return login(TestConstants.ADMIN_USERNAME, TestConstants.ADMIN_PASSWORD);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import com.commafeed.frontend.model.Category;
|
|||||||
import com.commafeed.frontend.model.Entries;
|
import com.commafeed.frontend.model.Entries;
|
||||||
import com.commafeed.frontend.model.Entry;
|
import com.commafeed.frontend.model.Entry;
|
||||||
import com.commafeed.frontend.model.UnreadCount;
|
import com.commafeed.frontend.model.UnreadCount;
|
||||||
|
import com.commafeed.frontend.model.request.AddCategoryRequest;
|
||||||
import com.commafeed.frontend.model.request.CategoryModificationRequest;
|
import com.commafeed.frontend.model.request.CategoryModificationRequest;
|
||||||
import com.commafeed.frontend.model.request.CollapseRequest;
|
import com.commafeed.frontend.model.request.CollapseRequest;
|
||||||
import com.commafeed.frontend.model.request.IDRequest;
|
import com.commafeed.frontend.model.request.IDRequest;
|
||||||
@@ -87,6 +88,38 @@ class CategoryIT extends BaseIT {
|
|||||||
Assertions.assertEquals("test-category-1", root.getChildren().get(1).getName());
|
Assertions.assertEquals("test-category-1", root.getChildren().get(1).getName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void addCategoryWithParent() {
|
||||||
|
String parentId = createCategory("parent");
|
||||||
|
|
||||||
|
AddCategoryRequest request = new AddCategoryRequest();
|
||||||
|
request.setName("child");
|
||||||
|
request.setParentId(parentId);
|
||||||
|
RestAssured.given()
|
||||||
|
.body(request)
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.post("rest/category/add")
|
||||||
|
.then()
|
||||||
|
.statusCode(HttpStatus.SC_OK);
|
||||||
|
|
||||||
|
Category parent = getRootCategory().getChildren().getFirst();
|
||||||
|
Assertions.assertEquals("parent", parent.getName());
|
||||||
|
Assertions.assertEquals("child", parent.getChildren().getFirst().getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void addCategoryWithUnknownParent() {
|
||||||
|
AddCategoryRequest request = new AddCategoryRequest();
|
||||||
|
request.setName("child");
|
||||||
|
request.setParentId("999999");
|
||||||
|
RestAssured.given()
|
||||||
|
.body(request)
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.post("rest/category/add")
|
||||||
|
.then()
|
||||||
|
.statusCode(HttpStatus.SC_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void collapseCategory() {
|
void collapseCategory() {
|
||||||
String categoryId = createCategory("test-category");
|
String categoryId = createCategory("test-category");
|
||||||
@@ -145,6 +178,60 @@ class CategoryIT extends BaseIT {
|
|||||||
Assertions.assertEquals(2, counts[0].getUnreadCount());
|
Assertions.assertEquals(2, counts[0].getUnreadCount());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class ParentOwnedByAnotherUser {
|
||||||
|
private static final String VICTIM = "victim";
|
||||||
|
private static final String ATTACKER = "attacker";
|
||||||
|
private static final String PASSWORD = "MyPassword123!";
|
||||||
|
|
||||||
|
private String victimCategoryId;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void attemptToAddChildToVictimCategory() {
|
||||||
|
registerUser(VICTIM, PASSWORD);
|
||||||
|
registerUser(ATTACKER, PASSWORD);
|
||||||
|
|
||||||
|
authenticateAs(VICTIM, PASSWORD);
|
||||||
|
victimCategoryId = createCategory("victim-category");
|
||||||
|
|
||||||
|
authenticateAs(ATTACKER, PASSWORD);
|
||||||
|
AddCategoryRequest request = new AddCategoryRequest();
|
||||||
|
request.setName("attacker-category");
|
||||||
|
request.setParentId(victimCategoryId);
|
||||||
|
RestAssured.given()
|
||||||
|
.body(request)
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.post("rest/category/add")
|
||||||
|
.then()
|
||||||
|
.statusCode(HttpStatus.SC_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void victimCanDeleteCategory() {
|
||||||
|
authenticateAs(VICTIM, PASSWORD);
|
||||||
|
|
||||||
|
IDRequest request = new IDRequest();
|
||||||
|
request.setId(Long.valueOf(victimCategoryId));
|
||||||
|
RestAssured.given()
|
||||||
|
.body(request)
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.post("rest/category/delete")
|
||||||
|
.then()
|
||||||
|
.statusCode(HttpStatus.SC_OK);
|
||||||
|
Assertions.assertEquals(0, getRootCategory().getChildren().size());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void victimCanDeleteAccount() {
|
||||||
|
authenticateAs(VICTIM, PASSWORD);
|
||||||
|
RestAssured.given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.post("rest/user/profile/deleteAccount")
|
||||||
|
.then()
|
||||||
|
.statusCode(HttpStatus.SC_OK);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
class MarkEntriesAsRead {
|
class MarkEntriesAsRead {
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import com.commafeed.frontend.model.request.FeedInfoRequest;
|
|||||||
import com.commafeed.frontend.model.request.FeedModificationRequest;
|
import com.commafeed.frontend.model.request.FeedModificationRequest;
|
||||||
import com.commafeed.frontend.model.request.IDRequest;
|
import com.commafeed.frontend.model.request.IDRequest;
|
||||||
import com.commafeed.frontend.model.request.MarkRequest;
|
import com.commafeed.frontend.model.request.MarkRequest;
|
||||||
|
import com.commafeed.frontend.model.request.SubscribeRequest;
|
||||||
import com.commafeed.frontend.resource.CategoryREST;
|
import com.commafeed.frontend.resource.CategoryREST;
|
||||||
import com.commafeed.integration.BaseIT;
|
import com.commafeed.integration.BaseIT;
|
||||||
import com.rometools.rome.feed.synd.SyndFeed;
|
import com.rometools.rome.feed.synd.SyndFeed;
|
||||||
@@ -56,6 +57,65 @@ class FeedIT extends BaseIT {
|
|||||||
RestAssured.reset();
|
RestAssured.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Nested
|
||||||
|
class CategoryOwnedByAnotherUser {
|
||||||
|
private static final String VICTIM = "victim";
|
||||||
|
private static final String ATTACKER = "attacker";
|
||||||
|
private static final String PASSWORD = "MyPassword123!";
|
||||||
|
|
||||||
|
private String victimCategoryId;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void attemptToSubscribeInVictimCategory() {
|
||||||
|
registerUser(VICTIM, PASSWORD);
|
||||||
|
registerUser(ATTACKER, PASSWORD);
|
||||||
|
|
||||||
|
authenticateAs(VICTIM, PASSWORD);
|
||||||
|
victimCategoryId = createCategory("victim-category");
|
||||||
|
|
||||||
|
authenticateAs(ATTACKER, PASSWORD);
|
||||||
|
SubscribeRequest request = new SubscribeRequest();
|
||||||
|
request.setUrl(getFeedUrl());
|
||||||
|
request.setTitle("my title for this feed");
|
||||||
|
request.setCategoryId(victimCategoryId);
|
||||||
|
RestAssured.given()
|
||||||
|
.body(request)
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.post("rest/feed/subscribe")
|
||||||
|
.then()
|
||||||
|
.statusCode(HttpStatus.SC_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void victimCanDeleteCategory() {
|
||||||
|
authenticateAs(VICTIM, PASSWORD);
|
||||||
|
|
||||||
|
IDRequest request = new IDRequest();
|
||||||
|
request.setId(Long.valueOf(victimCategoryId));
|
||||||
|
RestAssured.given()
|
||||||
|
.body(request)
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.post("rest/category/delete")
|
||||||
|
.then()
|
||||||
|
.statusCode(HttpStatus.SC_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void victimCanDeleteAccount() {
|
||||||
|
authenticateAs(VICTIM, PASSWORD);
|
||||||
|
RestAssured.given()
|
||||||
|
.contentType(ContentType.JSON)
|
||||||
|
.post("rest/user/profile/deleteAccount")
|
||||||
|
.then()
|
||||||
|
.statusCode(HttpStatus.SC_OK);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void subscriptionIsNotCreated() {
|
||||||
|
Assertions.assertEquals(0, getCategoryEntries(CategoryREST.ALL).getEntries().size());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
class Fetch {
|
class Fetch {
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
Reference in New Issue
Block a user