diff --git a/.github/sync.yml b/.github/sync.yml
new file mode 100644
index 00000000..9793455b
--- /dev/null
+++ b/.github/sync.yml
@@ -0,0 +1,8 @@
+Tiqr/eduid-app-android:
+ - source: localizations.yaml
+ dest: localizations.yaml
+
+Tiqr/eduid-app-ios:
+ - source: localizations.yaml
+ dest: EduID/localizations.yaml
+
diff --git a/.github/workflows/localicious.yaml b/.github/workflows/localicious.yaml
new file mode 100644
index 00000000..c4d8fd58
--- /dev/null
+++ b/.github/workflows/localicious.yaml
@@ -0,0 +1,59 @@
+name: Update translations
+on:
+ workflow_dispatch:
+ push:
+ paths:
+ - 'localizations.yaml'
+jobs:
+ localicious:
+ runs-on: ubuntu-24.04
+ permissions:
+ contents: write
+ steps:
+ - uses: actions/checkout@v3
+ - name: lint yaml files
+ uses: ibiqlik/action-yamllint@v3
+ with:
+ file_or_dir: ./localizations.yaml
+ - uses: actions/setup-node@v4
+ with:
+ cache-dependency-path: myconext-gui/
+ node-version: 16
+ cache: 'npm'
+ - name: Install localicious/
+ run: |
+ npm install -g @picnicsupermarket/localicious
+ - name: Create Localizable.strings files
+ run: |
+ cd ${{ github.workspace }}
+ localicious render ./localizations.yaml ./account-gui/src/locale/ --languages en,nl --outputTypes js -c SHARED
+ rm -fr ./account-gui/src/locale/js/Localizable.ts
+ localicious render ./localizations.yaml ./myconext-gui/src/locale/ --languages en,nl --outputTypes js -c SHARED
+ rm -fr ./myconext-gui/src/locale/js/Localizable.ts
+ - name: Commit updated files
+ uses: stefanzweifel/git-auto-commit-action@v4
+ with:
+ commit_message: Automated update of strings.xml after updating localizations.yaml
+ file_pattern: '**/strings.json'
+ sync-eduid-apps:
+ needs: localicious
+ runs-on: ubuntu-24.04
+ if: ${{ !contains(github.event.head_commit.message, '#AUTO#') }}
+ steps:
+ - name: Checkout Repository
+ uses: actions/checkout@master
+ - name: Get token for the Tiqr github org
+ uses: actions/create-github-app-token@v1
+ id: app-token-tiqr-org
+ with:
+ app-id: ${{ secrets.SYNC_APP_ID }}
+ private-key: ${{ secrets.SYNC_PRIVATE_KEY }}
+ owner: Tiqr
+ - name: Create PR for new translation in eduid-app repos
+ uses: BetaHuhn/repo-file-sync-action@v1
+ with:
+ GH_INSTALLATION_TOKEN: ${{ steps.app-token-tiqr-org.outputs.token }}
+ COMMIT_PREFIX: "#AUTO#"
+ CONFIG_PATH: .github/sync.yml
+
+
\ No newline at end of file
diff --git a/.yamllint.yaml b/.yamllint.yaml
new file mode 100644
index 00000000..0db1ba9d
--- /dev/null
+++ b/.yamllint.yaml
@@ -0,0 +1,34 @@
+---
+
+yaml-files:
+ - '*.yaml'
+ - '*.yml'
+ - '.yamllint'
+
+rules:
+ anchors: enable
+ braces: enable
+ brackets: enable
+ colons: enable
+ commas: enable
+ comments:
+ level: warning
+ comments-indentation:
+ level: warning
+ document-end: disable
+ document-start:
+ level: warning
+ empty-lines: enable
+ empty-values: disable
+ float-values: disable
+ hyphens: enable
+ indentation: enable
+ key-duplicates: enable
+ key-ordering: disable
+ line-length: disable
+ new-line-at-end-of-file: enable
+ new-lines: enable
+ octal-values: disable
+ quoted-strings: disable
+ trailing-spaces: enable
+ truthy: disable
diff --git a/README.md b/README.md
index 87560a3a..e0f0d26f 100644
--- a/README.md
+++ b/README.md
@@ -5,31 +5,52 @@
An IdP for OpenConext. A user can create and manage his own identity. Authentication uses a magic-link by default, and FIDO2 or a password can be added later.
-## [Getting started](#getting-started)
-
-### [System Requirements](#system-requirements)
-
-- Java 11
+## Content
+
+- [Getting started](#getting-started)
+ - [System Requirements](#system-requirements)
+- [Building and running](#building-and-running)
+ - [The myconext-server](#The-myconext-server)
+ - [The account-gui](#the-account-gui)
+ - [The myconext-gui](#The-myconext-gui)
+ - [Build](#build)
+ - [Mail](#mail)
+ - [Crypto](#crypto)
+ - [Miscellaneous](#miscellaneous)
+ - [Migration](#migration)
+ - [Attribute Manipulation](#attribute-manipulation)
+ - [Attribute Aggregation](#attribute-aggregation)
+ - [OpenAPI Documentation](#OpenAPI-Documentation)
+ - [IDIN & e-Herkenning](#IDIN-&-e-Herkenning)
+ - [Running the IdP and testing localhost](#Running-the-IdP-and-testing-localhost)
+
+
+## Getting started
+
+### System Requirements
+
+- Java 21
- Maven 3
- MongoDB 3.4.x
- Yarn 1.x
- NodeJS
-- Ansible
+- (Ansible)
-## [Building and running](#building-and-running)
+## Building and running
-### [The myconext-server](#myconext-server)
+### The myconext-server
This project uses Spring Boot and Maven. To run locally, type:
-`cd myconext-server`
-
-`mvn spring-boot:run -Dspring-boot.run.profiles=dev`
+```
+cd myconext-server
+mvn spring-boot:run -Dspring-boot.run.profiles=dev
+```
When developing, it's convenient to just execute the applications main-method, which is in [Application](myconext-server/src/main/java/myconext/MyConextServerApplication.java).
Don't forget to set the active profile to dev.
-### [The account-gui](#myconext-gui)
+### The account-gui
The myconext client is build with Svelte and to get initially started:
@@ -41,7 +62,7 @@ yarn dev
Browse to the [application homepage](http://localhost:3001/).
-### [The myconext-gui](#myconext-gui)
+### The myconext-gui
The IdP is also build with Svelte and to get initially started:
@@ -53,13 +74,13 @@ yarn start
There is no home page, you'll need to visit an SP and choose eduID to login.
-### [Build](#build)
+### Build
To deploy production bundles
```bash
mvn deploy
```
-### [Mail](#mail)
+### Mail
The default mail configuration sends mails to port 1025. Install https://mailpit.axllent.org/ and capture all emails send.
You can see all mails delivered at http://0.0.0.0:8025/ when mailpit is installed.
@@ -67,7 +88,7 @@ You can see all mails delivered at http://0.0.0.0:8025/ when mailpit is installe
brew install mailpit
```
-### [Crypto](#crypto)
+### Crypto
The myconext application uses a private RSA key and corresponding certificate to sign the SAML requests. We don't want
to provide defaults, so in the integration tests the key / certificate pair is generated on the fly. if you want to
@@ -87,23 +108,34 @@ If you need to register the public key in EB then issue this command and copy &
```
cat myconext.crt |ghead -n -1 |tail -n +2 | tr -d '\n'; echo
```
-### [Miscellaneous](#miscellaneous)
+### Translations
+
+The github actions will generate new translations of the source is changed.
+
+```
+yarn localicious render ./localizations.yaml ./account-gui/src/locale/ --languages en,nl --outputTypes js -c SHARED
+rm -fr ./account-gui/src/locale/js/Localizable.ts
+yarn localicious render ./localizations.yaml ./myconext-gui/src/locale/ --languages en,nl --outputTypes js -c SHARED
+rm -fr ./myconext-gui/src/locale/js/Localizable.ts
+```
+
+### Miscellaneous
To get an overview of the git source file's:
```
cloc --read-lang-def=cloc_definitions.txt --vcs=git
```
-### [Migration](#migration)
+### Migration
It's possible to migrate from an existing IdP to this IdP. A new identity will be created, and the eppn wil be copied.
-### [Attribute Manipulation](#attribute-manipulation)
+### Attribute Manipulation
```
curl -u oidcng:secret "http://login.test2.eduid.nl/myconext/api/attribute-manipulation?sp_entity_id=https://test.okke&uid=0eaa7fb2-4f94-476f-b3f6-c8dfc4115a87&sp_institution_guid=null"
```
-### [Attribute Aggregation](#attribute-aggregation)
+### Attribute Aggregation
```
curl -u aa:secret "https://login.test2.eduid.nl/myconext/api/attribute-aggregation?sp_entity_id=https://mijn.test2.eduid.nl/shibboleth&eduperson_principal_name=j.doe@example.com"
```
diff --git a/account-gui/package.json b/account-gui/package.json
index 29a19601..59d37e49 100644
--- a/account-gui/package.json
+++ b/account-gui/package.json
@@ -38,7 +38,9 @@
"test:watch": "npm run test -- --watch"
},
"dependencies": {
+ "save-dev": "^0.0.1-security",
"@github/webauthn-json": "^2.1.1",
+ "@picnicsupermarket/localicious": "^1.0.1",
"dompurify": "^3.2.2",
"i18n-js": "^3.3.0",
"js-cookie": "^3.0.5",
diff --git a/account-gui/src/App.svelte b/account-gui/src/App.svelte
index 01d8f63b..f9f7f6c2 100644
--- a/account-gui/src/App.svelte
+++ b/account-gui/src/App.svelte
@@ -15,7 +15,7 @@
import Footer from "./components/Footer.svelte";
import {onMount} from "svelte";
import {allowedEmailDomains, configuration, institutionalEmailDomains} from "./api";
- import I18n from "i18n-js";
+ import I18n from "./locale/I18n";
import {conf} from "./stores/conf";
import {domains} from "./stores/domains";
import Loader from "./components/Loader.svelte";
@@ -55,21 +55,20 @@
onMount(() => configuration()
.then(json => {
$conf = json;
- if (typeof window !== "undefined") {
- const urlSearchParams = new URLSearchParams(window.location.search);
- if (urlSearchParams.has("lang")) {
- I18n.locale = urlSearchParams.get("lang").toLowerCase();
- } else if (Cookies.get("lang", {domain: $conf.domain})) {
- I18n.locale = Cookies.get("lang", {domain: $conf.domain}).toLowerCase();
- } else {
- I18n.locale = navigator.language.toLowerCase().substring(0, 2);
- }
+ const urlSearchParams = new URLSearchParams(window.location.search);
+ let locale = "en";
+ if (urlSearchParams.has("lang")) {
+ locale = urlSearchParams.get("lang").toLowerCase();
+ } else if (Cookies.get("lang", {domain: $conf.domain})) {
+ locale = Cookies.get("lang", {domain: $conf.domain}).toLowerCase();
} else {
- I18n.locale = "en";
+ locale = navigator.language.toLowerCase().substring(0, 2);
}
- if (["nl", "en"].indexOf(I18n.locale) < 0) {
- I18n.locale = "en";
+ if (["nl", "en"].indexOf(locale) < 0) {
+ locale = "en";
}
+ I18n.changeLocale(locale);
+
$user.knownUser = Cookies.get(cookieNames.USERNAME);
$user.email = $user.knownUser || "";
$user.preferredLogin = Cookies.get(cookieNames.LOGIN_PREFERENCE);
@@ -219,43 +218,43 @@