3 | {# Used for the login tests. #}
4 | {% if data.user %}
5 | logged in
6 | {% else %}
7 | logged out
8 | {% endif %}
9 |
10 |
--------------------------------------------------------------------------------
/test/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "//": "This package.json file is not actually installed.",
3 | "//": "Apostrophe requires that all npm modules to be loaded by moog",
4 | "//": "exist in package.json at project level, which for a test is here",
5 | "dependencies": {
6 | "apostrophe": "^3.13.0",
7 | "@apostrophecms/login-totp": "git://github.com/apostrophecms/login-totp.git"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | ## UNRELEASED
4 |
5 | ### Changes
6 |
7 | * Bumbs `eslint-config-apostrophe` to `5`, fixes errors, removes unused dependencies.
8 |
9 | ## 1.3.2 (2025-03-19)
10 |
11 | * Fix pasting on MacOS.
12 | * Add stylelint.
13 | * Add data-test attributes.
14 |
15 | ## 1.3.1 (2024-10-31)
16 |
17 | * Adds AI-generated and community-reviewed missing translations
18 |
19 | ## 1.3.0 (2024-07-10)
20 |
21 | ### Adds
22 |
23 | * Add missing UI translation keys.
24 |
25 | ## 1.2.0 (2024-03-12)
26 |
27 | ### Changes
28 |
29 | * Compatible with both Apostrophe 3.x and Apostrophe 4.x (both Vue 2 and Vue 3).
30 |
31 | ## 1.1.0 (2023-08-16)
32 |
33 | ### Adds
34 |
35 | - Add `totp-complete` and `totp-invalid-token` structured logging events.
36 |
37 | ## 1.0.1 (2023-02-17)
38 |
39 | - Remove `apostrophe` as a peer dependency.
40 |
41 | ## 1.0.0 (2023-01-16)
42 |
43 | - Declared stable. No code changes.
44 |
45 | ## 1.0.0-beta (2022-02-04)
46 |
47 | - Builds out the beta release of a TOTP login requirement module.
48 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) 2021 Apostrophe Technologies
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 |
5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6 |
7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8 |
--------------------------------------------------------------------------------
/i18n/aposTotp/en.json:
--------------------------------------------------------------------------------
1 | {
2 | "missingSecret": "You should provide a secret of a length of 10 characters in your @apostrophecms/login module config.",
3 | "badSecretSize": "Your secret should be 10 characters in length.",
4 | "invalidToken": "Invalid code, try again.",
5 | "updateError": "An error occurred while setting up your TOTP account.",
6 | "verify": "Verify",
7 | "loginTitleSetup": "Enable Authenticator Support",
8 | "loginTitle": "Enter the six digit code from your authenticator app.",
9 | "setupText1": "Install Google Authenticator or similar TOTP app, then",
10 | "setupText2": "Scan this QR code",
11 | "setupText3": "Or manually enter this key",
12 | "loginText": "Then enter the verification code from your authenticator app",
13 | "copyKey": "Copy key",
14 | "successMessage": "Success! Completing the login process...",
15 | "notConfigured": "Not configured, refresh the login page to configure TOTP",
16 | "resetTotpLabel": "Reset TOTP",
17 | "resetTotpHelp": "Select this option and save to reset the user's TOTP (Google Authenticator) configuration once, so they can set it up again.",
18 | "totpLabel": "TOTP"
19 | }
20 |
--------------------------------------------------------------------------------
/i18n/aposTotp/sk.json:
--------------------------------------------------------------------------------
1 | {
2 | "missingSecret": "Mali by ste poskytnúť tajomstvo s dĺžkou 10 znakov vo svojej konfigurácii modulu @apostrophecms/login.",
3 | "badSecretSize": "Vaše tajomstvo by malo mať dĺžku 10 znakov.",
4 | "invalidToken": "Neplatný kód, skúste znova.",
5 | "updateError": "Pri nastavovaní vášho TOTP účtu sa vyskytla chyba.",
6 | "verify": "Overiť",
7 | "loginTitleSetup": "Povoliť podporu autentifikátora",
8 | "loginTitle": "Zadajte šesť miestny kód zo svojho autentifikačného aplikácie.",
9 | "setupText1": "Nainštalujte Google Authenticator alebo podobnú aplikáciu TOTP, potom",
10 | "setupText2": "Oscanovať tento QR kód",
11 | "setupText3": "Alebo zadajte tento kľúč ručne",
12 | "loginText": "Potom zadajte overovací kód zo svojho autentifikačného aplikácie",
13 | "copyKey": "Skopírovať kľúč",
14 | "successMessage": "Úspech! Dokončovanie procesu prihlásenia...",
15 | "notConfigured": "Nastavené nie je, obnovte prihlasovaciu stránku na konfiguráciu TOTP",
16 | "resetTotpLabel": "Obnoviť TOTP",
17 | "resetTotpHelp": "Vyberte túto možnosť a uložte ju na obnovenie TOTP (Google Authenticator) konfigurácie používateľa jedenkrát, aby si ju mohli nastaviť znova.",
18 | "totpLabel": "TOTP"
19 | }
20 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "@apostrophecms/login-totp",
3 | "version": "1.3.2",
4 | "description": "Adds totp (time-based one-time password) to Apostrophe login pages",
5 | "main": "index.js",
6 | "scripts": {
7 | "lint": "npm run eslint && npm run stylelint",
8 | "eslint": "eslint --ext .js,.vue .",
9 | "stylelint": "stylelint ui/**/*.{scss,vue}",
10 | "test": "npm run lint && mocha"
11 | },
12 | "repository": {
13 | "type": "git",
14 | "url": "git+https://github.com/apostrophecms/login-totp.git"
15 | },
16 | "keywords": [
17 | "apostrophe",
18 | "login",
19 | "totp"
20 | ],
21 | "author": "Apostrophe Technologies",
22 | "license": "MIT",
23 | "bugs": {
24 | "url": "https://github.com/apostrophecms/login-totp/issues"
25 | },
26 | "homepage": "https://github.com/apostrophecms/login-totp#readme",
27 | "devDependencies": {
28 | "apostrophe": "github:apostrophecms/apostrophe",
29 | "eslint-config-apostrophe": "^5.0.0",
30 | "mocha": "^7.2.0",
31 | "stylelint": "^16.0.0",
32 | "stylelint-config-apostrophe": "^4.1.0"
33 | },
34 | "dependencies": {
35 | "qrcode": "^1.5.0",
36 | "thirty-two": "^1.0.2",
37 | "totp-generator": "0.0.13"
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/i18n/aposTotp/pt-BR.json:
--------------------------------------------------------------------------------
1 | {
2 | "missingSecret": "Você deve fornecer um segredo com comprimento de 10 caracteres na configuração do seu módulo @apostrophecms/login.",
3 | "badSecretSize": "Seu segredo deve ter 10 caracteres de comprimento.",
4 | "invalidToken": "Código inválido, tente novamente.",
5 | "updateError": "Ocorreu um erro ao configurar sua conta TOTP.",
6 | "verify": "Verificar",
7 | "loginTitleSetup": "Habilitar Suporte ao Authenticator",
8 | "loginTitle": "Insira o código de seis dígitos do seu aplicativo autenticador.",
9 | "setupText1": "Instale o Google Authenticator ou um aplicativo TOTP semelhante, então",
10 | "setupText2": "Escaneie este código QR",
11 | "setupText3": "Ou insira esta chave manualmente",
12 | "loginText": "Em seguida, insira o código de verificação do seu aplicativo autenticador",
13 | "copyKey": "Copiar chave",
14 | "successMessage": "Sucesso! Finalizando o processo de login...",
15 | "notConfigured": "Não configurado, atualize a página de login para configurar o TOTP",
16 | "resetTotpLabel": "Redefinir TOTP",
17 | "resetTotpHelp": "Selecione esta opção e salve para redefinir a configuração do TOTP (Google Authenticator) do usuário uma vez, para que ele possa configurá-la novamente.",
18 | "totpLabel": "TOTP"
19 | }
20 |
--------------------------------------------------------------------------------
/i18n/aposTotp/it.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 | "missingSecret": "Devi fornire un segreto di lunghezza 10 caratteri nella configurazione del tuo modulo @apostrophecms/login.",
4 | "badSecretSize": "Il tuo segreto deve avere 10 caratteri di lunghezza.",
5 | "invalidToken": "Codice non valido, riprova.",
6 | "updateError": "Si è verificato un errore durante la configurazione del tuo account TOTP.",
7 | "verify": "Verifica",
8 | "loginTitleSetup": "Abilita il supporto Authenticator",
9 | "loginTitle": "Inserisci il codice a sei cifre dalla tua app di autenticazione.",
10 | "setupText1": "Installa Google Authenticator o un'app TOTP simile, quindi",
11 | "setupText2": "Scansiona questo codice QR",
12 | "setupText3": "Oppure inserisci manualmente questa chiave",
13 | "loginText": "Poi inserisci il codice di verifica dalla tua app di autenticazione",
14 | "copyKey": "Copia chiave",
15 | "successMessage": "Successo! Completando il processo di accesso...",
16 | "notConfigured": "Non configurato, aggiorna la pagina di accesso per configurare TOTP",
17 | "resetTotpLabel": "Reimposta TOTP",
18 | "resetTotpHelp": "Seleziona questa opzione e salva per reimpostare la configurazione TOTP dell'utente (Google Authenticator) una sola volta, in modo che possano configurarlo di nuovo.",
19 | "totpLabel": "TOTP"
20 | }
21 |
--------------------------------------------------------------------------------
/i18n/aposTotp/es.json:
--------------------------------------------------------------------------------
1 | {
2 | "missingSecret": "Deberías proporcionar un secreto de una longitud de 10 caracteres en la configuración de tu módulo @apostrophecms/login.",
3 | "badSecretSize": "Tu secreto debería tener 10 caracteres de longitud.",
4 | "invalidToken": "Código inválido, intenta de nuevo.",
5 | "updateError": "Ocurrió un error mientras configurabas tu cuenta TOTP.",
6 | "verify": "Verificar",
7 | "loginTitleSetup": "Habilitar soporte para autenticador",
8 | "loginTitle": "Introduce el código de seis dígitos de tu aplicación de autenticador.",
9 | "setupText1": "Instala Google Authenticator o una aplicación TOTP similar, luego",
10 | "setupText2": "Escanea este código QR",
11 | "setupText3": "O introduce manualmente esta clave",
12 | "loginText": "Luego introduce el código de verificación de tu aplicación de autenticador",
13 | "copyKey": "Copiar clave",
14 | "successMessage": "¡Éxito! Completar el proceso de inicio de sesión...",
15 | "notConfigured": "No configurado, actualiza la página de inicio de sesión para configurar TOTP",
16 | "resetTotpLabel": "Restablecer TOTP",
17 | "resetTotpHelp": "Selecciona esta opción y guarda para restablecer la configuración de TOTP (Google Authenticator) del usuario una vez, para que puedan configurarlo de nuevo.",
18 | "totpLabel": "TOTP"
19 | }
20 |
--------------------------------------------------------------------------------
/i18n/aposTotp/fr.json:
--------------------------------------------------------------------------------
1 | {
2 | "missingSecret": "Vous devez fournir un secret d'une longueur de 10 caractères dans la configuration de votre module @apostrophecms/login.",
3 | "badSecretSize": "Votre secret doit avoir 10 caractères.",
4 | "invalidToken": "Code invalide, réessayez.",
5 | "updateError": "Une erreur est survenue lors de la configuration de votre compte TOTP.",
6 | "verify": "Vérifier",
7 | "loginTitleSetup": "Activer le support d'Authenticator",
8 | "loginTitle": "Entrez le code à six chiffres de votre application d'authentification.",
9 | "setupText1": "Installez Google Authenticator ou une application TOTP similaire, puis",
10 | "setupText2": "Scannez ce code QR",
11 | "setupText3": "Ou entrez manuellement cette clé",
12 | "loginText": "Puis entrez le code de vérification de votre application d'authentification",
13 | "copyKey": "Copier la clé",
14 | "successMessage": "Succès ! Complétez le processus de connexion...",
15 | "notConfigured": "Non configuré, rafraîchissez la page de connexion pour configurer TOTP",
16 | "resetTotpLabel": "Réinitialiser TOTP",
17 | "resetTotpHelp": "Sélectionnez cette option et enregistrez pour réinitialiser la configuration TOTP (Google Authenticator) de l'utilisateur une fois, afin qu'il puisse la configurer à nouveau.",
18 | "totpLabel": "TOTP"
19 | }
20 |
--------------------------------------------------------------------------------
/i18n/aposTotp/de.json:
--------------------------------------------------------------------------------
1 | {
2 | "missingSecret": "Sie sollten ein Geheimnis mit einer Länge von 10 Zeichen in Ihrer @apostrophecms/login-Modulkonfiguration angeben.",
3 |
4 | "badSecretSize": "Ihr Geheimnis sollte 10 Zeichen lang sein.",
5 | "invalidToken": "Ungültiger Code, versuchen Sie es erneut.",
6 | "updateError": "Beim Einrichten Ihres TOTP-Kontos ist ein Fehler aufgetreten.",
7 | "verify": "Überprüfen",
8 | "loginTitleSetup": "Authenticator-Unterstützung aktivieren",
9 | "loginTitle": "Geben Sie den sechsstelligen Code aus Ihrer Authenticator-App ein.",
10 | "setupText1": "Installieren Sie Google Authenticator oder eine ähnliche TOTP-App, dann",
11 | "setupText2": "Scannen Sie diesen QR-Code",
12 | "setupText3": "Oder geben Sie diesen Schlüssel manuell ein",
13 | "loginText": "Geben Sie dann den Verifizierungscode aus Ihrer Authenticator-App ein",
14 | "copyKey": "Schlüssel kopieren",
15 | "successMessage": "Erfolg! Beenden des Anmeldevorgangs...",
16 | "notConfigured": "Nicht konfiguriert, aktualisieren Sie die Anmeldeseite, um TOTP zu konfigurieren",
17 | "resetTotpLabel": "TOTP zurücksetzen",
18 | "resetTotpHelp": "Wählen Sie diese Option und speichern Sie, um die TOTP (Google Authenticator)-Konfiguration des Benutzers einmal zurückzusetzen, damit sie sie neu einrichten können.",
19 | "totpLabel": "TOTP"
20 | }
21 |
--------------------------------------------------------------------------------
/.github/workflows/main.yml:
--------------------------------------------------------------------------------
1 | # This is a basic workflow to help you get started with Actions
2 |
3 | name: tests
4 |
5 | # Controls when the action will run.
6 | on:
7 | push:
8 | branches: ["main"]
9 | pull_request:
10 | branches: ["*"]
11 |
12 | # Allows you to run this workflow manually from the Actions tab
13 | workflow_dispatch:
14 |
15 | # A workflow run is made up of one or more jobs that can run sequentially or in parallel
16 | jobs:
17 | # This workflow contains a single job called "build"
18 | build:
19 | # The type of runner that the job will run on
20 | runs-on: ubuntu-latest
21 | strategy:
22 | matrix:
23 | # current LTS
24 | node-version: [18, 20]
25 | mongodb-version: [6.0, 7.0, 8.0]
26 |
27 | # Steps represent a sequence of tasks that will be executed as part of the job
28 | steps:
29 | - name: Git checkout
30 | uses: actions/checkout@v2
31 |
32 | - name: Use Node.js ${{ matrix.node-version }}
33 | uses: actions/setup-node@v1
34 | with:
35 | node-version: ${{ matrix.node-version }}
36 |
37 | - name: Start MongoDB
38 | uses: supercharge/mongodb-github-action@1.3.0
39 | with:
40 | mongodb-version: ${{ matrix.mongodb-version }}
41 |
42 | - run: npm install
43 |
44 | - run: npm test
45 | env:
46 | CI: true
47 |
--------------------------------------------------------------------------------
/modules/@apostrophecms/user-totp/index.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | improve: '@apostrophecms/user',
3 | fields: {
4 | add: {
5 | resetTotp: {
6 | label: 'aposTotp:resetTotpLabel',
7 | type: 'boolean',
8 | help: 'aposTotp:resetTotpHelp'
9 | }
10 | },
11 | group: {
12 | totp: {
13 | label: 'aposTotp:totpLabel',
14 | fields: [ 'resetTotp' ]
15 | }
16 | }
17 | },
18 | tasks(self) {
19 | return {
20 | 'reset-totp': {
21 | usage: 'Invoke this task with a username or email address to reset TOTP (Google Authenticator) so they can set it up again.',
22 | async task(argv) {
23 | const username = argv._[1];
24 | const result = await self.safe.updateOne({
25 | $or: [
26 | {
27 | username
28 | },
29 | {
30 | email: username
31 | }
32 | ]
33 | }, {
34 | $unset: {
35 | totp: 1
36 | }
37 | });
38 | if (!result.modifiedCount) {
39 | throw 'User not found.';
40 | }
41 | }
42 | }
43 | };
44 | },
45 | handlers(self) {
46 | return {
47 | beforeSave: {
48 | async resetTotp(req, doc) {
49 | if (doc.resetTotp) {
50 | doc.resetTotp = false;
51 | await self.apos.user.safe.updateOne({
52 | _id: doc._id
53 | }, {
54 | $unset: {
55 | totp: 1
56 | }
57 | });
58 | }
59 | }
60 | }
61 | };
62 | }
63 | };
64 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |