From 3003d930a27ac926dce297bc1e6b73bfd5a7226a Mon Sep 17 00:00:00 2001 From: Wouter Ensink <46427708+w-ensink@users.noreply.github.com> Date: Mon, 16 Dec 2024 10:35:18 +0100 Subject: [PATCH] add redis transactions to token requests --- .../tokens/RedisTokenRequestRepository.java | 59 ++++++++++++++++--- 1 file changed, 50 insertions(+), 9 deletions(-) diff --git a/src/main/java/foundation/privacybydesign/sms/tokens/RedisTokenRequestRepository.java b/src/main/java/foundation/privacybydesign/sms/tokens/RedisTokenRequestRepository.java index a092c2b..fff13eb 100644 --- a/src/main/java/foundation/privacybydesign/sms/tokens/RedisTokenRequestRepository.java +++ b/src/main/java/foundation/privacybydesign/sms/tokens/RedisTokenRequestRepository.java @@ -1,5 +1,6 @@ package foundation.privacybydesign.sms.tokens; +import java.awt.Panel; import java.util.List; import org.slf4j.Logger; @@ -8,6 +9,8 @@ import foundation.privacybydesign.sms.redis.Redis; import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisSentinelPool; +import redis.clients.jedis.Response; +import redis.clients.jedis.Transaction; import redis.clients.jedis.params.ScanParams; import redis.clients.jedis.resps.ScanResult; @@ -16,7 +19,7 @@ * Useful for when the sms issuer needs to be stateless. */ class RedisTokenRequestRepository implements TokenRequestRepository { - private static Logger logger = LoggerFactory.getLogger(RedisTokenRequestRepository.class); + private static Logger LOG = LoggerFactory.getLogger(RedisTokenRequestRepository.class); private static String namespace = "request"; JedisSentinelPool pool; @@ -28,9 +31,24 @@ class RedisTokenRequestRepository implements TokenRequestRepository { public void store(String phone, TokenRequest request) { final String key = Redis.createKey(namespace, phone); try (var jedis = pool.getResource()) { - jedis.hset(key, "token", request.token); - jedis.hset(key, "tries", Integer.toString(request.tries)); - jedis.hset(key, "created", String.valueOf(request.created)); + jedis.watch(key); + + Transaction transaction = jedis.multi(); + transaction.hset(key, "token", request.token); + transaction.hset(key, "tries", Integer.toString(request.tries)); + transaction.hset(key, "created", String.valueOf(request.created)); + + final List result = transaction.exec(); + + if (result == null) { + LOG.error("failed to set token: redis transaction exec() result is null"); + return; + } + for (var r : result) { + if (r instanceof Exception) { + LOG.error("failed to set token: " + ((Exception) r).getMessage()); + } + } } } @@ -71,7 +89,7 @@ private void removeIfExpired(Jedis jedis, String key) { jedis.del(key); } } catch (NumberFormatException e) { - logger.error("Failed to parse " + key + " creation into long: " + e.getMessage()); + LOG.error("Failed to parse " + key + " creation into long: " + e.getMessage()); } } } @@ -81,12 +99,35 @@ public TokenRequest retrieve(String phone) { try (var jedis = pool.getResource()) { final String key = Redis.createKey(namespace, phone); try { - String token = jedis.hget(key, "token"); - int tries = Integer.parseInt(jedis.hget(key, "tries")); - long created = Long.parseLong(jedis.hget(key, "created")); + + jedis.watch(key); + Transaction transaction = jedis.multi(); + + final Response tokenRes = transaction.hget(key, "token"); + final Response triesRes = transaction.hget(key, "tries"); + final Response createdRes = transaction.hget(key, "created"); + + final List execRes = transaction.exec(); + + if (execRes == null) { + LOG.error("error while getting token request from redis: exec result is null"); + return null; + } + + for (var r : execRes) { + if (r instanceof Exception) { + LOG.error("error while getting token request from redis: " + ((Exception) r).getMessage()); + return null; + } + } + + final String token = tokenRes.get(); + final int tries = Integer.parseInt(triesRes.get()); + final long created = Long.parseLong(createdRes.get()); + return new TokenRequest(token, tries, created); } catch (NumberFormatException e) { - logger.error("failed to parse for " + key + ": " + e.getMessage()); + LOG.error("failed to parse for " + key + ": " + e.getMessage()); return null; } }