Skip to content

Commit

Permalink
Added locales to Captcha Submodule and refactored i18n for maintenanc…
Browse files Browse the repository at this point in the history
…e purposes. (#156)
  • Loading branch information
StefanSchubert authored Feb 25, 2024
1 parent 2264116 commit 405fba2
Show file tree
Hide file tree
Showing 11 changed files with 193 additions and 89 deletions.
2 changes: 2 additions & 0 deletions DEVELOPERS_MANUAL.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ With a look at [Building-Block View](https://github.com/StefanSchubert/sabi/wiki
<nvd.api.key>YOUR_API_KEY</nvd.api.key>
</properties>

* If you work with IntelliJ: Install the "Jakarta Server Faces (JSF)" Plugin

#### Prepare your local docker environment

Do some maven builds in the following order:
Expand Down
10 changes: 5 additions & 5 deletions captcha/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,14 @@
<!-- Taking care to have all spring dependencies right. -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>3.2.1</version>
<version>3.2.2</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<modelVersion>4.0.0</modelVersion>

<groupId>de.bluewhale</groupId>
<artifactId>captcha-light</artifactId>
<version>1.2.4</version>
<version>1.2.5</version>
<packaging>jar</packaging>
<description>A REST-full microservice service for CAPTCHA running as spring boot application</description>

Expand Down Expand Up @@ -46,9 +46,9 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<springdoc.openapiv2.version>2.3.0</springdoc.openapiv2.version>
<micrometer.prometheus.version>1.12.1</micrometer.prometheus.version>
<owasp.plugin.version>9.0.7</owasp.plugin.version>
<maven-surefire-plugin.version>3.2.3</maven-surefire-plugin.version>
<micrometer.prometheus.version>1.12.3</micrometer.prometheus.version>
<owasp.plugin.version>9.0.9</owasp.plugin.version>
<maven-surefire-plugin.version>3.2.5</maven-surefire-plugin.version>
<versions.maven.plugin.version>2.16.2</versions.maven.plugin.version>
</properties>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public class CaptchaController {
@ResponseStatus(HttpStatus.OK)
public ResponseEntity<ChallengeTo> getNewCaptchaChallenge(
@PathVariable(value = "language", required = true)
@Parameter(name = "language", description = "ISO-639-1 language code - used for i18n in communication.") String language) {
@Parameter(name = "language", description = "ISO-639-1 language code - used for i18n in communication. English will be used as fallback, if language is not available.") String language) {

ResponseEntity<ChallengeTo> response;

Expand Down
135 changes: 55 additions & 80 deletions captcha/src/main/java/de/bluewhale/captcha/service/QAGenerator.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,174 +38,131 @@ public class QAGenerator {

// -------------------------- STATIC METHODS --------------------------

// FIXME: 30.09.18 These data shuld be json config, which is loaded as runtime.

static {
// This pattern challenge1 could be dynamically generated on the fly
// as this is nonsense as the source is open...but for the start it's fine
ChallengeData challenge1 = new ChallengeData();
challenge1.questionMap.put(Locale.GERMAN, "Welches passt nicht zum Muster?");
challenge1.questionMap.put(Locale.ENGLISH, "Which one does not fit to the pattern?");
// The questions from the ressource bundle will be combined with the possible answers in this step.
// The criteria for new questions is, that the possible answers are as language agnostic as possible.

ChallengeData challenge1 = new ChallengeData(1);
challenge1.answerMap.put("A1-B2-C2D", FALSE);
challenge1.answerMap.put("K8-V4-W7H", FALSE);
challenge1.answerMap.put("J6-N8-9T9", TRUE);
challenge1.answerMap.put("V1-J3-Q2P", FALSE);

ChallengeData challenge2 = new ChallengeData();
challenge2.questionMap.put(Locale.GERMAN, "Was passt nicht?");
challenge2.questionMap.put(Locale.ENGLISH, "Which option does not fit?");
ChallengeData challenge2 = new ChallengeData(2);
challenge2.answerMap.put("Saturn", FALSE);
challenge2.answerMap.put("Jupiter", FALSE);
challenge2.answerMap.put("Moon", TRUE);
challenge2.answerMap.put("Venus", FALSE);

ChallengeData challenge3 = new ChallengeData();
challenge3.questionMap.put(Locale.GERMAN, "Welcher Wert muss gering gehalten werden?");
challenge3.questionMap.put(Locale.ENGLISH, "Which value is to be minimized?");
ChallengeData challenge3 = new ChallengeData(3);
challenge3.answerMap.put("PO4", TRUE);
challenge3.answerMap.put("Ca", FALSE);
challenge3.answerMap.put("Mg", FALSE);
challenge3.answerMap.put("NO3", FALSE);

ChallengeData challenge4 = new ChallengeData();
challenge4.questionMap.put(Locale.GERMAN, "Was gibt es davon sprachlich?");
challenge4.questionMap.put(Locale.ENGLISH, "Which one exists likely as spoken words?");
ChallengeData challenge4 = new ChallengeData(4);
challenge4.answerMap.put("+-0", TRUE);
challenge4.answerMap.put("#-#", FALSE);
challenge4.answerMap.put("+##", FALSE);
challenge4.answerMap.put("##0", FALSE);

ChallengeData challenge5 = new ChallengeData();
challenge5.questionMap.put(Locale.GERMAN, "Wen würdest du aufmuntern?");
challenge5.questionMap.put(Locale.ENGLISH, "Who needs a little support?");
ChallengeData challenge5 = new ChallengeData(5);
challenge5.answerMap.put(":-)", FALSE);
challenge5.answerMap.put(";-)", FALSE);
challenge5.answerMap.put(":-(", TRUE);
challenge5.answerMap.put(":-x", FALSE);

ChallengeData challenge6 = new ChallengeData();
challenge6.questionMap.put(Locale.GERMAN, "Platform 9 3/4 was passt dazu am besten?");
challenge6.questionMap.put(Locale.ENGLISH, "Platform 9 3/4 which association fits best?");
ChallengeData challenge6 = new ChallengeData(6);
challenge6.answerMap.put("@@@@@", FALSE);
challenge6.answerMap.put("#####", FALSE);
challenge6.answerMap.put("+++++", FALSE);
challenge6.answerMap.put("=====", TRUE);

ChallengeData challenge7 = new ChallengeData();
challenge7.questionMap.put(Locale.GERMAN, "Was würdest du vermehren?");
challenge7.questionMap.put(Locale.ENGLISH, "Which one would you increase?");
ChallengeData challenge7 = new ChallengeData(7);
challenge7.answerMap.put("@@@", FALSE);
challenge7.answerMap.put("§§§", FALSE);
challenge7.answerMap.put("%%%", FALSE);
challenge7.answerMap.put("$$$", TRUE);

ChallengeData challenge8 = new ChallengeData();
challenge8.questionMap.put(Locale.GERMAN, "Was nimmt mehr Fläche ein?");
challenge8.questionMap.put(Locale.ENGLISH, "Which one occupies the bigger space?");
ChallengeData challenge8 = new ChallengeData(8);
challenge8.answerMap.put("C", FALSE);
challenge8.answerMap.put("W", TRUE);
challenge8.answerMap.put("I", FALSE);
challenge8.answerMap.put("L", FALSE);

ChallengeData challenge9 = new ChallengeData();
challenge9.questionMap.put(Locale.GERMAN, "Wenn jeder Strich ein Bleistift wäre und du diese nun in eine Linie setzt, was gibt die längere Strecke?");
challenge9.questionMap.put(Locale.ENGLISH, "If each line is a pencil and you set them in a line, which one would result in the max line?");
ChallengeData challenge9 = new ChallengeData(9);
challenge9.answerMap.put("=====", FALSE);
challenge9.answerMap.put("#####", TRUE);
challenge9.answerMap.put("NNNNN", FALSE);
challenge9.answerMap.put("XXXXX", FALSE);

ChallengeData challenge10 = new ChallengeData();
challenge10.questionMap.put(Locale.GERMAN, "Was wird immer besser erreichbar?");
challenge10.questionMap.put(Locale.ENGLISH, "Which one gets more and more reachable?");
ChallengeData challenge10 = new ChallengeData(10);
challenge10.answerMap.put("Jupiter", FALSE);
challenge10.answerMap.put("Mars", TRUE);
challenge10.answerMap.put("Venus", FALSE);
challenge10.answerMap.put("Saturn", FALSE);

ChallengeData challenge11 = new ChallengeData();
challenge11.questionMap.put(Locale.GERMAN, "Welche Box passt 27 mal in eine 15x15x15 Box?");
challenge11.questionMap.put(Locale.ENGLISH, "Which box fits 27 times in a 15x15x15 box?");
ChallengeData challenge11 = new ChallengeData(11);
challenge11.answerMap.put("10x10x10 Box", FALSE);
challenge11.answerMap.put("5x5x5 Box", TRUE);
challenge11.answerMap.put("4x8x12 Box", FALSE);
challenge11.answerMap.put("20x20x20 Box", FALSE);

ChallengeData challenge12 = new ChallengeData();
challenge12.questionMap.put(Locale.GERMAN, "Welcher Ball rollt am ehesten durch ein Mäuseloch?");
challenge12.questionMap.put(Locale.ENGLISH, "Which ball is likely to be rolling through a mouse hole?");
ChallengeData challenge12 = new ChallengeData(12);
challenge12.answerMap.put("5cm Ball", TRUE);
challenge12.answerMap.put("10cm Ball", FALSE);
challenge12.answerMap.put("15cm Ball", FALSE);
challenge12.answerMap.put("20cm Ball", FALSE);

ChallengeData challenge13 = new ChallengeData();
challenge13.questionMap.put(Locale.GERMAN, "Hinter dir kollidieren zwei schnelle Objekte, wo wirst du es am geringsten bemerken?");
challenge13.questionMap.put(Locale.ENGLISH, "Two fast objects are colliding behind you, where will you hardly recognize it?");
ChallengeData challenge13 = new ChallengeData(13);
challenge13.answerMap.put("500km NN", TRUE);
challenge13.answerMap.put("10km NN", FALSE);
challenge13.answerMap.put("-50m NN (sea)", FALSE);
challenge13.answerMap.put("5m NN", FALSE);

ChallengeData challenge14 = new ChallengeData();
challenge14.questionMap.put(Locale.GERMAN, "Welches davon kippen manche in ihr Riff-Aquarium?");
challenge14.questionMap.put(Locale.ENGLISH, "Which one of these will be added by some of us to the reef-tank?");
ChallengeData challenge14 = new ChallengeData(14);
challenge14.answerMap.put("Blue Curaçao", FALSE);
challenge14.answerMap.put("Vodka", TRUE);
challenge14.answerMap.put("Campari", FALSE);
challenge14.answerMap.put("Ginger Ale", FALSE);

ChallengeData challenge15 = new ChallengeData();
challenge15.questionMap.put(Locale.GERMAN, "Wer fällt aus der Reihe?");
challenge15.questionMap.put(Locale.ENGLISH, "Who does not fit here?");
ChallengeData challenge15 = new ChallengeData(15);
challenge15.answerMap.put("Wall-E", FALSE);
challenge15.answerMap.put("E.T.", TRUE);
challenge15.answerMap.put("R2D2", FALSE);
challenge15.answerMap.put("No.5", FALSE);

ChallengeData challenge16 = new ChallengeData();
challenge16.questionMap.put(Locale.GERMAN, "Welche Eigenschaften von Seegraswiesen können uns zukünftig helfen?");
challenge16.questionMap.put(Locale.ENGLISH, "What are the best capabilities of Seaweed-Cultures for our furture?");
ChallengeData challenge16 = new ChallengeData(16);
challenge16.answerMap.put("\\|/\\|/", FALSE);
challenge16.answerMap.put("Superfood", FALSE);
challenge16.answerMap.put("C02-Storage", TRUE);
challenge16.answerMap.put("=~=~=~~", FALSE);

ChallengeData challenge17 = new ChallengeData();
challenge17.questionMap.put(Locale.GERMAN, "Welche Zahl ist nur durch eins und sich selbst teilbar, so dass das Ergebnis wieder eine Ganze Zahl ergibt?");
challenge17.questionMap.put(Locale.ENGLISH, "If the result must be a whole number, which one of those can be divided only by 1 and itself?");
ChallengeData challenge17 = new ChallengeData(17);
challenge17.answerMap.put("9", FALSE);
challenge17.answerMap.put("4", FALSE);
challenge17.answerMap.put("22", FALSE);
challenge17.answerMap.put("5", TRUE);

ChallengeData challenge18 = new ChallengeData();
challenge18.questionMap.put(Locale.GERMAN, "Was geschieht mit Korallen bei einer durchschnittlichen Wassertemperatur vom 30°C");
challenge18.questionMap.put(Locale.ENGLISH, "What happens to corals if the average water temperature is around 86°F?");
ChallengeData challenge18 = new ChallengeData(18);
challenge18.answerMap.put("☠️", TRUE);
challenge18.answerMap.put("🦐", FALSE);
challenge18.answerMap.put("🐡", FALSE);
challenge18.answerMap.put("🧜🏽‍", FALSE);

ChallengeData challenge19 = new ChallengeData();
challenge19.questionMap.put(Locale.GERMAN, "Was geschieht wahrscheinlich mit den nützlichen Bakterien in deinem Riff, wenn der KH-Wert sinkt?");
challenge19.questionMap.put(Locale.ENGLISH, "What is likely to happen to the useful bacteria in your reef if the carbonate level decreases?");
ChallengeData challenge19 = new ChallengeData(19);
challenge19.answerMap.put("🦐", FALSE);
challenge19.answerMap.put("🐡", FALSE);
challenge19.answerMap.put("🧜🏽‍", FALSE);
challenge19.answerMap.put("☠️", TRUE);

ChallengeData challenge20 = new ChallengeData();
challenge20.questionMap.put(Locale.GERMAN, "Wer von den gezeigten hat die Chance älter als die anderen zu werden?");
challenge20.questionMap.put(Locale.ENGLISH, "Who among those shown has the chance to become older than the others?");
ChallengeData challenge20 = new ChallengeData(20);
challenge20.answerMap.put("🐬", FALSE);
challenge20.answerMap.put("🐒", FALSE);
challenge20.answerMap.put("🐢", TRUE);
challenge20.answerMap.put("🦉", FALSE);

ChallengeData challenge21 = new ChallengeData();
challenge21.questionMap.put(Locale.GERMAN, "Emotie Rätsel: Welche Kombination repräsentiert den Song Titel 'Walking this way'?");
challenge21.questionMap.put(Locale.ENGLISH, "Emotie quiz: Which combination represents the song 'Walking this way'?");
ChallengeData challenge21 = new ChallengeData(21);
challenge21.answerMap.put("🪢👀", FALSE);
challenge21.answerMap.put("🚶‍➡️", TRUE);
challenge21.answerMap.put("🏄‍💨", FALSE);
Expand Down Expand Up @@ -245,24 +202,42 @@ public class QAGenerator {
*/
public ChallengeTo provideChallengeFor(final String pLanguage) {

int questionIndex = random.nextInt(dataSet.size());

Object[] challenges = dataSet.toArray();
ChallengeData challengeData = (ChallengeData) challenges[questionIndex];

ChallengeTo challengeTo = new ChallengeTo();

Map<Locale, String> questionMap = challengeData.questionMap;
Locale locale;

try {
locale = new Locale(pLanguage);

// check for supported locales and set "en" as fallback
switch (pLanguage) {
case "de":
case "en":
case "fr":
case "es":
case "it":
locale = new Locale(pLanguage);
break;
default: locale = Locale.ENGLISH;
}

locale.getISO3Language(); // semantic check

} catch (MissingResourceException pE) {
locale = Locale.ENGLISH;
}

ResourceBundle bundle = ResourceBundle.getBundle("i18n/ChallengeSamples", locale);

int questionIndex = random.nextInt(dataSet.size());

Object[] challenges = dataSet.toArray();
ChallengeData challengeData = (ChallengeData) challenges[questionIndex];

ChallengeTo challengeTo = new ChallengeTo();

challengeTo.setLanguage(locale.getLanguage());
challengeTo.setQuestion(questionMap.get(locale));

String localedQuestion = bundle.getString(challengeData.questionKey);

challengeTo.setQuestion(localedQuestion);

// As for the answer map, we generate answer tokens and for the right one
// we register it with the ValidationCache.
Expand Down Expand Up @@ -293,11 +268,11 @@ private String createToken(int pTOKEN_SIZE) {
// -------------------------- INNER CLASSES --------------------------

private static class ChallengeData {
protected Map<Locale, String> questionMap;
protected String questionKey;
protected Map<String, Boolean> answerMap; // the one marked with true is the right answer.

public ChallengeData() {
this.questionMap = new HashMap<Locale, String>();
public ChallengeData(int challengeNumber) {
this.questionKey = "challenge."+challengeNumber+".question";
this.answerMap = new HashMap<String, Boolean>();
}
}
Expand Down
21 changes: 21 additions & 0 deletions captcha/src/main/resources/i18n/ChallengeSamples.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
challenge.1.question="Which one does not match the pattern?"
challenge.2.question="What does not fit?"
challenge.3.question="Which value must be kept low?"
challenge.4.question="What is there linguistically?"
challenge.5.question="Who would you cheer up?"
challenge.6.question="Platform 9 3/4 what fits best?"
challenge.7.question="What would you increase?"
challenge.8.question="What takes up more space?"
challenge.9.question="If each line were a pencil and you now put them in a line, what gives the longer distance?"
challenge.10.question="What is becoming more accessible?"
challenge.11.question="Which box fits 27 times into a 15x15x15 box?"
challenge.12.question="Which ball is most likely to roll through a mouse hole?"
challenge.13.question="Two fast objects collide behind you, where will you notice it the least?"
challenge.14.question="Which of these do some people tip into their reef aquarium?"
challenge.15.question="Who falls out of line?"
challenge.16.question="Which characteristics of seagrass meadows can help us in the future?"
challenge.17.question="Which number can only be divided by one and itself, so that the result is a whole number again?"
challenge.18.question="What happens to corals at an average water temperature of 30\u00B0C"
challenge.19.question="What is likely to happen to the beneficial bacteria in your reef when the KH value drops?"
challenge.20.question="Which of those shown has the chance to grow older than the others?"
challenge.21.question="Emotie riddle: Which combination represents the song title 'Walking this way'?"
21 changes: 21 additions & 0 deletions captcha/src/main/resources/i18n/ChallengeSamples_de.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
challenge.1.question="Welches passt nicht zum Muster?"
challenge.2.question="Was passt nicht?"
challenge.3.question="Welcher Wert muss gering gehalten werden?"
challenge.4.question="Was gibt es davon sprachlich?"
challenge.5.question="Wen w\u00FCrdest du aufmuntern?"
challenge.6.question="Platform 9 3/4 was passt dazu am besten?"
challenge.7.question="Was w\u00FCrdest du vermehren?"
challenge.8.question="Was nimmt mehr Fl\u00E4che ein?"
challenge.9.question="Wenn jeder Strich ein Bleistift w\u00E4re und du diese nun in eine Linie setzt, was gibt die l\u00E4ngere Strecke?"
challenge.10.question="Was wird immer besser erreichbar?"
challenge.11.question="Welche Box passt 27 mal in eine 15x15x15 Box?"
challenge.12.question="Welcher Ball rollt am ehesten durch ein M\u00E4useloch?"
challenge.13.question="Hinter dir kollidieren zwei schnelle Objekte, wo wirst du es am geringsten bemerken?"
challenge.14.question="Welches davon kippen manche in ihr Riff-Aquarium?"
challenge.15.question="Wer f\u00E4llt aus der Reihe?"
challenge.16.question="Welche Eigenschaften von Seegraswiesen k\u00F6nnen uns zuk\u00FCnftig helfen?"
challenge.17.question="Welche Zahl ist nur durch eins und sich selbst teilbar, so dass das Ergebnis wieder eine Ganze Zahl ergibt?"
challenge.18.question="Was geschieht mit Korallen bei einer durchschnittlichen Wassertemperatur vom 30\u00B0C"
challenge.19.question="Was geschieht wahrscheinlich mit den n\u00FCtzlichen Bakterien in deinem Riff, wenn der KH-Wert sinkt?"
challenge.20.question="Wer von den gezeigten hat die Chance \u00E4lter als die anderen zu werden?"
challenge.21.question="Emotie R\u00E4tsel: Welche Kombination repr\u00E4sentiert den Song Titel 'Walking this way'?"
Loading

0 comments on commit 405fba2

Please sign in to comment.