Skip to content

Commit

Permalink
fix: block new users immediately when enforcement=ON (#19816)
Browse files Browse the repository at this point in the history
* fix: block new users immediately when enforcement=ON

* fix formatting

* add tests
  • Loading branch information
mshabarov authored Aug 23, 2024
1 parent 7ee907e commit 52c3794
Show file tree
Hide file tree
Showing 4 changed files with 85 additions and 13 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ public static Optional<Cookie> getTrackingCookie(VaadinRequest request) {
* contains invalid data.
* @see FlowDauIntegration#generateNewCookie(VaadinRequest)
*/
static Optional<DauCookie> parserCookie(Cookie cookie) {
static Optional<DauCookie> parseCookie(Cookie cookie) {
String cookieValue = cookie.getValue();
String[] tokens = cookieValue.split("\\$");
if (tokens.length != 2) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,30 +45,38 @@ public void requestStart(VaadinRequest request, VaadinResponse response) {

// user is counted even if request handling throws an exception
Optional<DAUUtils.DauCookie> maybePresentCookie = DAUUtils
.getTrackingCookie(request).flatMap(DAUUtils::parserCookie);
.getTrackingCookie(request).flatMap(DAUUtils::parseCookie);
if (maybePresentCookie.isPresent()) {
DAUUtils.DauCookie dauCookie = maybePresentCookie.get();
if (dauCookie.isActive()) {

VaadinSession vaadinSession = VaadinSession.getCurrent();
String userIdentity = Optional.ofNullable(userIdentitySupplier)
.flatMap(supplier -> supplier
.apply(new UserIdentityContext(request,
vaadinSession)))
.orElse(null);
FlowDauIntegration.trackUser(request, dauCookie.trackingHash(),
userIdentity);
// ignore user's activity threshold if enforcement
if (dauCookie.isActive() || FlowDauIntegration.shouldEnforce()) {
trackUser(request, dauCookie.trackingHash());
}

} else if (response != null) {
// response can be null, for example for PUSH websocket requests

// DAU cookie is created if not present and re-created if invalid
Cookie cookie = FlowDauIntegration.generateNewCookie(request);
response.addCookie(cookie);

// Enforce new users immediately, even if they are not yet active
// and tracked
if (FlowDauIntegration.shouldEnforce()) {
trackUser(request, DAUUtils.parseCookie(cookie).orElseThrow()
.trackingHash());
}
}
}

private void trackUser(VaadinRequest request, String trackingHash) {
VaadinSession vaadinSession = VaadinSession.getCurrent();
String userIdentity = Optional.ofNullable(userIdentitySupplier)
.flatMap(supplier -> supplier
.apply(new UserIdentityContext(request, vaadinSession)))
.orElse(null);
FlowDauIntegration.trackUser(request, trackingHash, userIdentity);
}

@Override
public void handleException(VaadinRequest request, VaadinResponse response,
VaadinSession vaadinSession, Exception t) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,17 @@ static void trackUser(VaadinRequest request, String trackingHash,
}
}

/**
* Tells whether new user, i.e. who just opens the browser, not yet tracked,
* not yet counted, should be blocked immediately.
*
* @return {@literal true} if the current request/user should be blocked,
* {@literal false} otherwise.
*/
static boolean shouldEnforce() {
return DauIntegration.shouldEnforce();
}

/**
* Potentially applies enforcement to the current request if DAU limit is
* exceeded.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -362,6 +362,59 @@ public void requestStart_invalidCookie_doNotTrack() {
}
}

@Test
public void requestStart_dauCookiePresent_notActiveUser_enforcement_tracksUser() {
VaadinRequest request = Mockito.mock(VaadinRequest.class);
VaadinResponse response = Mockito.mock(VaadinResponse.class);
Mockito.when(request
.getParameter(ApplicationConstants.REQUEST_TYPE_PARAMETER))
.thenReturn(HandlerHelper.RequestType.INIT.getIdentifier());

String trackingHash = "trackingHash";
Instant creationTime = Instant.now()
.minusSeconds(DAU_MIN_ACTIVITY_IN_SECONDS / 2);
Cookie cookie = new Cookie(DAUUtils.DAU_COOKIE_NAME,
trackingHash + "$" + creationTime.toEpochMilli());

Mockito.when(request.getCookies()).thenReturn(new Cookie[] { cookie });

VaadinSession.setCurrent(new MockVaadinSession(vaadinService));

try (MockedStatic<DauIntegration> dauIntegration = Mockito
.mockStatic(DauIntegration.class)) {
dauIntegration.when(DauIntegration::shouldEnforce).thenReturn(true);
interceptor.requestStart(request, response);
dauIntegration
.verify(() -> DauIntegration.trackUser(trackingHash, null));
} finally {
VaadinSession.setCurrent(null);
}
}

@Test
public void requestStart_noDauCookie_notActiveUser_enforcement_tracksUser() {
VaadinRequest request = Mockito.mock(VaadinRequest.class);
VaadinResponse response = Mockito.mock(VaadinResponse.class);
Mockito.when(request
.getParameter(ApplicationConstants.REQUEST_TYPE_PARAMETER))
.thenReturn(HandlerHelper.RequestType.INIT.getIdentifier());

String trackingHash = "trackingHash";
VaadinSession.setCurrent(new MockVaadinSession(vaadinService));

try (MockedStatic<DauIntegration> dauIntegration = Mockito
.mockStatic(DauIntegration.class)) {
dauIntegration.when(DauIntegration::shouldEnforce).thenReturn(true);
dauIntegration.when(DauIntegration::newTrackingHash)
.thenReturn(trackingHash);
interceptor.requestStart(request, response);
dauIntegration
.verify(() -> DauIntegration.trackUser(trackingHash, null));
} finally {
VaadinSession.setCurrent(null);
}
}

private static Cookie createCookie(String trackingHash, boolean active) {
Instant creationTime = Instant.now();
if (active) {
Expand Down

0 comments on commit 52c3794

Please sign in to comment.