From d0b388db5b1268bee76a79c175d4cd22ff2c7f51 Mon Sep 17 00:00:00 2001 From: MHSanaei Date: Sat, 23 May 2026 16:09:52 +0200 Subject: [PATCH] fix(clients): handle delayed-start expiry in bulk adjust Negative ExpiryTime encodes a delay duration (magnitude = ms until the trial begins on first use). Adding positive addDays was simply arithmetically added, so e.g. a -7d delay + 30d turned into +23d since epoch (1970), making the client instantly expired. Branch on sign now: positive ExpiryTime extends additively, negative extends by subtracting so the value stays negative (more delay). Cross-sign reductions are skipped with an explicit reason instead of silently corrupting the field. --- web/service/client.go | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/web/service/client.go b/web/service/client.go index dbfb3aaf..d9d726e4 100644 --- a/web/service/client.go +++ b/web/service/client.go @@ -846,11 +846,25 @@ func (s *ClientService) BulkAdjust(inboundSvc *InboundService, emails []string, applied := false if addDays != 0 { - if rec.ExpiryTime == 0 { + switch { + case rec.ExpiryTime == 0: result.Skipped = append(result.Skipped, BulkAdjustReport{Email: email, Reason: "unlimited expiry"}) - } else { - client.ExpiryTime = rec.ExpiryTime + addExpiryMs - applied = true + case rec.ExpiryTime > 0: + next := rec.ExpiryTime + addExpiryMs + if next <= 0 { + result.Skipped = append(result.Skipped, BulkAdjustReport{Email: email, Reason: "reduction exceeds remaining time"}) + } else { + client.ExpiryTime = next + applied = true + } + default: + next := rec.ExpiryTime - addExpiryMs + if next >= 0 { + result.Skipped = append(result.Skipped, BulkAdjustReport{Email: email, Reason: "reduction exceeds delay window"}) + } else { + client.ExpiryTime = next + applied = true + } } } if addBytes != 0 {