Skip to content

Commit

Permalink
Merge pull request #594 from cardano-foundation/fix/oobi-not-found
Browse files Browse the repository at this point in the history
Fix/oobi not found
  • Loading branch information
rcmorano authored Oct 2, 2024
2 parents abe7971 + 315257b commit 8f5fac2
Show file tree
Hide file tree
Showing 9 changed files with 240 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,12 @@ def __init__(self, hby):
def on_get(self, req, resp):
# This should be a path param but is causing issues, query will do.
oobi = req.params.get('url')

if oobi is None or oobi == "":
raise falcon.HTTPBadRequest(description=f"required field url missing from request")

result = self.hby.db.roobi.get(keys=(oobi,))

if result:
resp.status = falcon.HTTP_200
resp.text = result.cid
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.POST;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.NOT_FOUND;

@Component
@Slf4j
Expand Down Expand Up @@ -114,12 +115,14 @@ public Either<Problem, String> getOOBI(String oobi, Integer maxAttempts) {
while (attempt < attempts) {
try {
val response = restTemplate.exchange(url, GET, entity, String.class);

if (response.getStatusCode().is2xxSuccessful()) {
log.info("OOBI successfully retrieved after {} attempts", attempt+1);
return Either.right(response.getBody());
}
} catch (HttpClientErrorException e) {
if (e.getStatusCode() != BAD_REQUEST) {
if (e.getStatusCode() == NOT_FOUND) {
log.info("OOBI not found, continuing attempts... "+attempt);
} else {
return Either.left(Problem.builder()
.withTitle("OOBI_FETCH_ERROR")
.withDetail("Unable to fetch OOBI, reason: " + e.getMessage())
Expand All @@ -146,7 +149,91 @@ public Either<Problem, String> getOOBI(String oobi, Integer maxAttempts) {
return Either.left(Problem.builder()
.withTitle("OOBI_NOT_FOUND")
.withDetail("The OOBI was not found after " + attempts + " attempts.")
.withStatus(new HttpStatusAdapter(BAD_REQUEST))
.withStatus(new HttpStatusAdapter(NOT_FOUND))
.build());
}

public Either<Problem, Boolean> updateAndVerifyKeyState(String aid, Integer maxAttempts) {
val updateUrl = String.format("%s/keystate", keriVerifierBaseUrl);
val verifyUrl = String.format("%s/keystate/%s", keriVerifierBaseUrl, aid);

val headers = new HttpHeaders();
headers.add("Content-Type", "application/json");

val requestBody = new HashMap<String, String>();
requestBody.put("pre", aid);

val entity = new HttpEntity<Map<String, String>>(requestBody, headers);

// Attempt to update the key state
try {
val response = restTemplate.exchange(updateUrl, POST, entity, String.class);
if (response.getStatusCode().is2xxSuccessful()) {
log.info("Key state updated successfully for aid: {}", aid);
return verifyKeyState(verifyUrl, maxAttempts);
} else {
return Either.left(Problem.builder()
.withTitle("KEY_STATE_UPDATE_FAILED")
.withDetail("Failed to update key state.")
.withStatus(new HttpStatusAdapter(response.getStatusCode()))
.build());
}
} catch (HttpClientErrorException e) {
log.error("Unable to update key state, reason: {}", e.getMessage());
return Either.left(Problem.builder()
.withTitle("KEY_STATE_UPDATE_ERROR")
.withDetail("Unable to update key state, reason: " + e.getMessage())
.withStatus(new HttpStatusAdapter(e.getStatusCode()))
.build());
}
}

private Either<Problem, Boolean> verifyKeyState(String url, Integer maxAttempts) {
val headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
val entity = new HttpEntity<Void>(headers);

int attempts = (maxAttempts == null) ? 1 : maxAttempts;
int attempt = 0;

while (attempt < attempts) {
try {
val response = restTemplate.exchange(url, GET, entity, String.class);
if (response.getStatusCode().is2xxSuccessful()) {
log.info("Key state verified successfully after {} attempts", attempt + 1);
return Either.right(true);
}
} catch (HttpClientErrorException e) {
if (e.getStatusCode() == NOT_FOUND) {
log.info("Key state not found, continuing attempts... " + (attempt + 1));
} else {
return Either.left(Problem.builder()
.withTitle("KEY_STATE_VERIFICATION_ERROR")
.withDetail("Unable to verify key state, reason: " + e.getMessage())
.withStatus(new HttpStatusAdapter(e.getStatusCode()))
.build());
}
}

attempt++;
if (attempt < attempts) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return Either.left(Problem.builder()
.withTitle("INTERRUPTED_ERROR")
.withDetail("Thread was interrupted while waiting to retry.")
.withStatus(new HttpStatusAdapter(NOT_FOUND))
.build());
}
}
}

return Either.left(Problem.builder()
.withTitle("KEY_STATE_VERIFICATION_FAILED")
.withDetail("The key state verification failed after " + attempts + " attempts.")
.withStatus(new HttpStatusAdapter(NOT_FOUND))
.build());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -428,9 +428,17 @@ private Either<Problem, IsVerifiedResponse> handleKeriVerification(DiscordCheckV

// Step 1: Check if OOBI is already registered
Either<Problem, String> oobiCheckResult = keriVerificationClient.getOOBI(oobi, 1);

if (oobiCheckResult.isRight()) {
log.info("OOBI already registered: {}", oobiCheckResult);
log.info("OOBI already registered: {}", oobiCheckResult.get());

// TODO: Review this implementation once the KERI watchers are operational.
// This solution is temporary and might need adjustments to integrate with the new KERI components
// Step 1.1:Update key state
Either<Problem, Boolean> keyStateUpdateResult = keriVerificationClient.updateAndVerifyKeyState(walletId, 60);
if (keyStateUpdateResult.isLeft()) {
return Either.left(keyStateUpdateResult.getLeft());
}

Either<Problem, Boolean> verificationResult = keriVerificationClient.verifySignature(walletId, signature, payload);

if (verificationResult.isLeft()) {
Expand Down Expand Up @@ -465,13 +473,18 @@ private Either<Problem, IsVerifiedResponse> handleKeriVerification(DiscordCheckV

log.info("OOBI registered successfully: {}", oobiM);

// Step 3: Attempt to verify OOBI registration up to 10 times
// Step 3: Attempt to verify OOBI registration up to 60 times
val oobiFetchResultE = keriVerificationClient.getOOBI(oobi, 60);
if (oobiFetchResultE.isLeft()) {
return Either.left(oobiFetchResultE.getLeft());
}

// Step 4: Verify signature after OOBI registration
// Step 4: Update key state
Either<Problem, Boolean> keyStateUpdateResult = keriVerificationClient.updateAndVerifyKeyState(walletId, 60);
if (keyStateUpdateResult.isLeft()) {
return Either.left(keyStateUpdateResult.getLeft());
}
// Step 5: Verify signature after OOBI registration
val verificationResultE = keriVerificationClient.verifySignature(walletId, signature, payload);
if (verificationResultE.isLeft()) {
return Either.left(verificationResultE.getLeft());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ max.pending.verification.attempts=${MAX_PENDING_VERIFICATION_ATTEMPTS:5}
spring.h2.console.enabled=${H2_CONSOLE_ENABLED:true}

phone.number.salt=${SALT:67274569c9671a4ae3f753b9647ca719}
discord.bot.eventId.binding=${DISCORD_BOT_EVENT_ID_BINDING:CF_SUMMIT_2024_10BCC}
discord.bot.eventId.binding=${DISCORD_BOT_EVENT_ID_BINDING:CF_SUMMIT_2024_15BCC}

discord.bot.username=${DISCORD_BOT_USERNAME:discord_bot}
discord.bot.password=${DISCORD_BOT_PASSWORD:test}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import static org.springframework.http.HttpMethod.GET;
import static org.springframework.http.HttpMethod.POST;
import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.NOT_FOUND;

@RequiredArgsConstructor
@Component
Expand Down Expand Up @@ -47,7 +48,6 @@ public Either<Problem, Boolean> verifySignature(String aid,

try {
val response = restTemplate.exchange(url, POST, entity, String.class);

if (response.getStatusCode().is2xxSuccessful()) {
return Either.right(true);
}
Expand Down Expand Up @@ -78,6 +78,7 @@ public Either<Problem, Boolean> registerOOBI(String oobi) {
requestBody.put("oobi", oobi);

val entity = new HttpEntity<Map<String, String>>(requestBody, headers);

try {
val response = restTemplate.exchange(url, POST, entity, String.class);

Expand Down Expand Up @@ -113,12 +114,14 @@ public Either<Problem, String> getOOBI(String oobi, Integer maxAttempts) {
while (attempt < attempts) {
try {
val response = restTemplate.exchange(url, GET, entity, String.class);

if (response.getStatusCode().is2xxSuccessful()) {
log.info("OOBI successfully retrieved after {} attempts", attempt+1);
return Either.right(response.getBody());
}
} catch (HttpClientErrorException e) {
if (e.getStatusCode() != BAD_REQUEST) {
if (e.getStatusCode() == NOT_FOUND) {
log.info("OOBI not found, continuing attempts...");
} else {
return Either.left(Problem.builder()
.withTitle("OOBI_FETCH_ERROR")
.withDetail("Unable to fetch OOBI, reason: " + e.getMessage())
Expand All @@ -145,8 +148,91 @@ public Either<Problem, String> getOOBI(String oobi, Integer maxAttempts) {
return Either.left(Problem.builder()
.withTitle("OOBI_NOT_FOUND")
.withDetail("The OOBI was not found after " + attempts + " attempts.")
.withStatus(new HttpStatusAdapter(BAD_REQUEST))
.withStatus(new HttpStatusAdapter(NOT_FOUND))
.build());
}

public Either<Problem, Boolean> updateAndVerifyKeyState(String aid, Integer maxAttempts) {
val updateUrl = String.format("%s/keystate", keriVerifierBaseUrl);
val verifyUrl = String.format("%s/keystate/%s", keriVerifierBaseUrl, aid);

val headers = new HttpHeaders();
headers.add("Content-Type", "application/json");

val requestBody = new HashMap<String, String>();
requestBody.put("pre", aid);

val entity = new HttpEntity<Map<String, String>>(requestBody, headers);

// Attempt to update the key state
try {
val response = restTemplate.exchange(updateUrl, POST, entity, String.class);
if (response.getStatusCode().is2xxSuccessful()) {
log.info("Key state updated successfully for aid: {}", aid);
return verifyKeyState(verifyUrl, maxAttempts);
} else {
return Either.left(Problem.builder()
.withTitle("KEY_STATE_UPDATE_FAILED")
.withDetail("Failed to update key state.")
.withStatus(new HttpStatusAdapter(response.getStatusCode()))
.build());
}
} catch (HttpClientErrorException e) {
log.error("Unable to update key state, reason: {}", e.getMessage());
return Either.left(Problem.builder()
.withTitle("KEY_STATE_UPDATE_ERROR")
.withDetail("Unable to update key state, reason: " + e.getMessage())
.withStatus(new HttpStatusAdapter(e.getStatusCode()))
.build());
}
}

private Either<Problem, Boolean> verifyKeyState(String url, Integer maxAttempts) {
val headers = new HttpHeaders();
headers.add("Content-Type", "application/json");
val entity = new HttpEntity<Void>(headers);

int attempts = (maxAttempts == null) ? 1 : maxAttempts;
int attempt = 0;

while (attempt < attempts) {
try {
val response = restTemplate.exchange(url, GET, entity, String.class);
if (response.getStatusCode().is2xxSuccessful()) {
log.info("Key state verified successfully after {} attempts", attempt + 1);
return Either.right(true);
}
} catch (HttpClientErrorException e) {
if (e.getStatusCode() == NOT_FOUND) {
log.info("Key state not found, continuing attempts... " + (attempt + 1));
} else {
return Either.left(Problem.builder()
.withTitle("KEY_STATE_VERIFICATION_ERROR")
.withDetail("Unable to verify key state, reason: " + e.getMessage())
.withStatus(new HttpStatusAdapter(e.getStatusCode()))
.build());
}
}

attempt++;
if (attempt < attempts) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
return Either.left(Problem.builder()
.withTitle("INTERRUPTED_ERROR")
.withDetail("Thread was interrupted while waiting to retry.")
.withStatus(new HttpStatusAdapter(NOT_FOUND))
.build());
}
}
}

return Either.left(Problem.builder()
.withTitle("KEY_STATE_VERIFICATION_FAILED")
.withDetail("The key state verification failed after " + attempts + " attempts.")
.withStatus(new HttpStatusAdapter(NOT_FOUND))
.build());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public class KeriWeb3Filter extends OncePerRequestFilter {
protected void doFilterInternal(HttpServletRequest req,
HttpServletResponse res,
FilterChain chain) throws ServletException, IOException {

val logonSystemM = loginSystemDetector.detect(req);
if (logonSystemM.isEmpty()) {
chain.doFilter(req, res);
Expand Down Expand Up @@ -125,53 +126,40 @@ protected void doFilterInternal(HttpServletRequest req,

// Step 1: Check if OOBI is already registered
Either<Problem, String> oobiCheckResult = keriVerificationClient.getOOBI(headerOobi, 1);
if (oobiCheckResult.isLeft()) {
sendBackProblem(objectMapper, res, oobiCheckResult.getLeft());
return;
}

// Log if OOBI is registered or not
log.info("OOBI status: {}", oobiCheckResult.get());
if (oobiCheckResult.isLeft()) {
log.info("OOBI not registered yet: {}", headerOobi);
// Step 2: Register OOBI if not already registered
val oobiRegistrationResultE = keriVerificationClient.registerOOBI(headerOobi);

if (oobiCheckResult.isRight()) {
log.info("OOBI already registered: {}", oobiCheckResult);
Either<Problem, Boolean> verificationResult = keriVerificationClient.verifySignature(headerAid, headerSignature, headerSignedJson);
if (oobiRegistrationResultE.isLeft()) {
sendBackProblem(objectMapper, res, oobiRegistrationResultE.getLeft());
return;
}

if (verificationResult.isEmpty()) {
val problem = Problem.builder()
.withTitle("KERI_SIGNATURE_VERIFICATION_FAILED")
.withDetail("Unable to verify KERI header signature, reason: " + verificationResult.swap().get().getDetail())
.withStatus(BAD_REQUEST)
.build();
log.info("OOBI registered successfully: {}", headerOobi);

sendBackProblem(objectMapper, res, problem);
// Step 3: Attempt to verify OOBI registration up to 60 times
val oobiFetchResultE = keriVerificationClient.getOOBI(headerOobi, 60);
if (oobiFetchResultE.isLeft()) {
sendBackProblem(objectMapper, res, oobiFetchResultE.getLeft());
return;
}
}

log.info("OOBI not registered yet: {}", headerOobi);
// Step 2: Register OOBI if not already registered
val oobiRegistrationResultE = keriVerificationClient.registerOOBI(headerOobi);

if (oobiRegistrationResultE.isLeft()) {
sendBackProblem(objectMapper, res, oobiRegistrationResultE.getLeft());
// Step 1.1:Update key state
Either<Problem, Boolean> keyStateUpdateResult = keriVerificationClient.updateAndVerifyKeyState(headerAid, 60);
if (keyStateUpdateResult.isLeft()) {
sendBackProblem(objectMapper, res, keyStateUpdateResult.getLeft());
return;
}

log.info("OOBI registered successfully: {}", headerOobi);

// Step 3: Attempt to verify OOBI registration up to 60 times
val oobiFetchResultE = keriVerificationClient.getOOBI(headerOobi, 60);
if (oobiFetchResultE.isLeft()) {
sendBackProblem(objectMapper, res, oobiFetchResultE.getLeft());
return;
}
Either<Problem, Boolean> verificationResult = keriVerificationClient.verifySignature(headerAid, headerSignature, headerSignedJson);

val keriVerificationResultE = keriVerificationClient.verifySignature(headerAid, headerSignature, headerSignedJson);
if (keriVerificationResultE.isEmpty()) {
if (verificationResult.isEmpty()) {
val problem = Problem.builder()
.withTitle("KERI_SIGNATURE_VERIFICATION_FAILED")
.withDetail("Unable to verify KERI header signature, reason: " + keriVerificationResultE.swap().get().getDetail())
.withDetail("Unable to verify KERI header signature, reason: " + verificationResult.swap().get().getDetail())
.withStatus(BAD_REQUEST)
.build();

Expand Down
Loading

0 comments on commit 8f5fac2

Please sign in to comment.