Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added locales to Captcha Submodule and refactored i18n for maintenance purposes. #156

Merged
merged 4 commits into from
Feb 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
# History of changes (since 5/2022)

## Release 1.2.6

### Enhancements
* SABI-68: Spanish ressource bundles added
** THX to deepl I added French, Italian as well

### Technical Maintenance

* SABI-128 Additional TLS on Backend component (required by aquarium-IoT project)

## Release 1.2.5

### Bugfixes
Expand Down
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'?"
Loading
Loading