diff --git a/app/src/main/java/io/xeres/app/xrs/service/identity/IdentityServiceStorage.java b/app/src/main/java/io/xeres/app/xrs/service/identity/IdentityServiceStorage.java new file mode 100644 index 00000000..7fe3b284 --- /dev/null +++ b/app/src/main/java/io/xeres/app/xrs/service/identity/IdentityServiceStorage.java @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2024 by David Gerber - https://zapek.com + * + * This file is part of Xeres. + * + * Xeres is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Xeres is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Xeres. If not, see . + */ + +package io.xeres.app.xrs.service.identity; + +import java.util.regex.Pattern; + +public class IdentityServiceStorage +{ + private static final Pattern SERVICE_STRING = Pattern.compile("^v2 \\{P:(.{1,1024}?)}\\{T:(.{1,1024}?)}\\{R:(.{1,1024}?)}$"); + + private Pgp pgp; + private Recognition recognition; + private Reputation reputation; + + private boolean success; + + public IdentityServiceStorage(long pgpIdentifier) + { + } + + public IdentityServiceStorage(String storage) + { + success = in(storage); + } + + private boolean in(String storage) + { + var matcher = SERVICE_STRING.matcher(storage); + + if (!matcher.matches()) + { + return false; + } + + pgp = new Pgp(matcher.group(1)); + if (!pgp.isSuccessful()) + { + return false; + } + + recognition = new Recognition(matcher.group(2)); + if (!recognition.isSuccessful()) + { + return false; + } + + reputation = new Reputation(matcher.group(3)); + if (!reputation.isSuccessful()) + { + return false; + } + return true; + } + + public String out() + { + + return "v2 " + "{P:" + + pgp.out() + + "}" + + "{T:" + + recognition.out() + + "}" + + "{R:" + + reputation.out() + + "}"; + } + + public boolean isSuccess() + { + return success; + } + +} diff --git a/app/src/main/java/io/xeres/app/xrs/service/identity/Pgp.java b/app/src/main/java/io/xeres/app/xrs/service/identity/Pgp.java new file mode 100644 index 00000000..761c3e6e --- /dev/null +++ b/app/src/main/java/io/xeres/app/xrs/service/identity/Pgp.java @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2024 by David Gerber - https://zapek.com + * + * This file is part of Xeres. + * + * Xeres is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Xeres is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Xeres. If not, see . + */ + +package io.xeres.app.xrs.service.identity; + +import io.xeres.common.id.Id; + +import java.time.Instant; +import java.util.regex.Pattern; + +class Pgp +{ + private static final Pattern VALIDATED = Pattern.compile("^K:1 I:(\\p{XDigit}{16})$"); + private static final Pattern UNVALIDATED_WITH_TIMESTAMP_ATTEMPTS_AND_ID = Pattern.compile("^K:0 T:(\\d{1,10}) C:(\\d{1,10}) I:(\\p{XDigit}{16})$"); + private static final Pattern UNVALIDATED_WITH_TIMESTAMP_AND_ATTEMPTS = Pattern.compile("^K:0 T:(\\d{1,10}) C:(\\d{1,10})$"); + private static final Pattern UNVALIDATED_WITH_TIMESTAMP = Pattern.compile("^K:0 T:(\\d{1,10})$"); + + private boolean validated; + private Instant lastCheck; + private int checkAttempt; + private long pgpIdentifier; + + private boolean success; + + public Pgp(long pgpIdentifier) + { + this.pgpIdentifier = pgpIdentifier; + validated = true; + } + + public Pgp(String input) + { + success = in(input); + } + + private boolean in(String input) + { + var matcher = VALIDATED.matcher(input); + if (matcher.matches()) + { + validated = true; + pgpIdentifier = Long.parseUnsignedLong(matcher.group(1), 16); + return true; + } + matcher = UNVALIDATED_WITH_TIMESTAMP_ATTEMPTS_AND_ID.matcher(input); + if (matcher.matches()) + { + lastCheck = Instant.ofEpochSecond(Long.parseLong(matcher.group(1))); + checkAttempt = Integer.parseUnsignedInt(matcher.group(2)); + pgpIdentifier = Long.parseUnsignedLong(matcher.group(3), 16); + return true; + } + matcher = UNVALIDATED_WITH_TIMESTAMP_AND_ATTEMPTS.matcher(input); + if (matcher.matches()) + { + lastCheck = Instant.ofEpochSecond(Long.parseLong(matcher.group(1))); + checkAttempt = Integer.parseUnsignedInt(matcher.group(2)); + return true; + } + matcher = UNVALIDATED_WITH_TIMESTAMP.matcher(input); + if (matcher.matches()) + { + lastCheck = Instant.ofEpochSecond(Long.parseLong(matcher.group(1))); + return true; + } + return false; + } + + public String out() + { + if (validated) + { + return "K:1 I:" + Id.toString(pgpIdentifier); + } + else + { + var sb = new StringBuilder("K:0"); + sb.append(" T:"); + sb.append(lastCheck.getEpochSecond()); + sb.append(" C:"); + sb.append(checkAttempt); + if (pgpIdentifier != 0) + { + sb.append(" I:"); + sb.append(Id.toString(pgpIdentifier)); + } + return sb.toString(); + } + } + + public boolean isSuccessful() + { + return success; + } +} diff --git a/app/src/main/java/io/xeres/app/xrs/service/identity/Recognition.java b/app/src/main/java/io/xeres/app/xrs/service/identity/Recognition.java new file mode 100644 index 00000000..6e708ea8 --- /dev/null +++ b/app/src/main/java/io/xeres/app/xrs/service/identity/Recognition.java @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2024 by David Gerber - https://zapek.com + * + * This file is part of Xeres. + * + * Xeres is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Xeres is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Xeres. If not, see . + */ + +package io.xeres.app.xrs.service.identity; + +import java.time.Instant; +import java.util.regex.Pattern; + +class Recognition +{ + private static final Pattern RECOGNITION_PATTERN = Pattern.compile("^F:(\\d{1,10}) P:(\\d{1,10}) T:(\\d{1,10})$"); + + private int flags; + private Instant publish; + private Instant lastCheck; + + private boolean success; + + public Recognition(int flags, Instant publish, Instant lastCheck) + { + this.flags = flags; + this.publish = publish; + this.lastCheck = lastCheck; + } + + public Recognition(String input) + { + success = in(input); + } + + private boolean in(String input) + { + var matcher = RECOGNITION_PATTERN.matcher(input); + if (matcher.matches()) + { + flags = Integer.parseUnsignedInt(matcher.group(1)); + publish = Instant.ofEpochSecond(Long.parseLong(matcher.group(2))); + lastCheck = Instant.ofEpochSecond(Long.parseLong(matcher.group(3))); + return true; + } + return false; + } + + public String out() + { + return "F:" + + flags + + " P:" + + publish.getEpochSecond() + + " T:" + + lastCheck.getEpochSecond(); + } + + public boolean isSuccessful() + { + return success; + } +} diff --git a/app/src/main/java/io/xeres/app/xrs/service/identity/Reputation.java b/app/src/main/java/io/xeres/app/xrs/service/identity/Reputation.java new file mode 100644 index 00000000..2634298d --- /dev/null +++ b/app/src/main/java/io/xeres/app/xrs/service/identity/Reputation.java @@ -0,0 +1,71 @@ +/* + * Copyright (c) 2024 by David Gerber - https://zapek.com + * + * This file is part of Xeres. + * + * Xeres is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Xeres is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Xeres. If not, see . + */ + +package io.xeres.app.xrs.service.identity; + +import java.util.regex.Pattern; + +class Reputation +{ + private static final Pattern REPUTATION_PATTERN = Pattern.compile("^(-?\\d{1,10}) (-?\\d{1,10}) (-?\\d{1,10}) (-?\\d{1,10})$"); + + private int overallScore; + private int idScore; + private int ownOpinion; + private int peerOpinion; + + private boolean success; + + public Reputation(int overallScore, int idScore, int ownOpinion, int peerOpinion) + { + this.overallScore = overallScore; + this.idScore = idScore; + this.ownOpinion = ownOpinion; + this.peerOpinion = peerOpinion; + } + + public Reputation(String input) + { + success = in(input); + } + + private boolean in(String input) + { + var matcher = REPUTATION_PATTERN.matcher(input); + if (matcher.matches()) + { + overallScore = Integer.parseInt(matcher.group(1)); + idScore = Integer.parseInt(matcher.group(2)); + ownOpinion = Integer.parseInt(matcher.group(3)); + peerOpinion = Integer.parseInt(matcher.group(4)); + return true; + } + return false; + } + + public String out() + { + return String.format("%d %d %d %d", overallScore, idScore, ownOpinion, peerOpinion); + } + + public boolean isSuccessful() + { + return success; + } +} \ No newline at end of file diff --git a/app/src/test/java/io/xeres/app/xrs/service/identity/IdentityServiceStorageTest.java b/app/src/test/java/io/xeres/app/xrs/service/identity/IdentityServiceStorageTest.java new file mode 100644 index 00000000..55a97479 --- /dev/null +++ b/app/src/test/java/io/xeres/app/xrs/service/identity/IdentityServiceStorageTest.java @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2024 by David Gerber - https://zapek.com + * + * This file is part of Xeres. + * + * Xeres is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Xeres is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with Xeres. If not, see . + */ + +package io.xeres.app.xrs.service.identity; + +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertFalse; +import static org.junit.jupiter.api.Assertions.assertTrue; + +class IdentityServiceStorageTest +{ + @Test + void ParseIdentityString_Success() + { + var input = "v2 {P:K:1 I:133E525084DE5D4D}{T:F:4096 P:1614029822 T:1614029841}{R:50 50 0 0}"; + + var identityServiceStorage = new IdentityServiceStorage(input); + assertTrue(identityServiceStorage.isSuccess()); + } + + @Test + void ParseIdentityString_Negative_Rating_Success() + { + var input = "v2 {P:K:1 I:133E525084DE5D4D}{T:F:4096 P:1614029822 T:1614029841}{R:50 -50 0 0}"; + + var identityServiceStorage = new IdentityServiceStorage(input); + assertTrue(identityServiceStorage.isSuccess()); + } + + @Test + void ParseIdentityString_WrongVersion_Failure() + { + var input = "v1 {P:K:1 I:133E525084DE5D4D}{T:F:4096 P:1614029822 T:1614029841}{R:50 50 0 0}"; + + var identityServiceStorage = new IdentityServiceStorage(input); + assertFalse(identityServiceStorage.isSuccess()); + } + + @Test + void ParseIdentityString_NegativePublish_Failure() + { + var input = "v2 {P:K:1 I:133E525084DE5D4D}{T:F:4096 P:-1 T:1614029841}{R:50 50 0 0}"; + + var identityServiceStorage = new IdentityServiceStorage(input); + assertFalse(identityServiceStorage.isSuccess()); + } +} \ No newline at end of file