├── .gitattributes ├── .github ├── FUNDING.yml ├── dependabot.yml ├── labeler.yml └── workflows │ ├── docs.yml │ ├── labeler.yml │ ├── monitor-upstream-releases.yml │ ├── monitor-upstream-repositories.yml │ ├── stale.yml │ ├── update-autofirma-CAs-by-provider.yml │ ├── update-autofirma-trusted-providers.yml │ ├── update-fixed-output-derivations-lock.yml │ └── update-flake-lock.yml ├── .mergify.yml ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── artwork ├── logo.svg ├── logo_inkscape.svg ├── logo_white.svg ├── logo_white_inkscape.svg └── social_preview.svg ├── docs ├── .gitignore ├── book.toml ├── default.nix └── src │ ├── SUMMARY.md │ ├── home_manager_options.md │ ├── how_to_contribute.md │ ├── installation.md │ ├── installation_home_manager_module.md │ ├── installation_home_manager_standalone.md │ ├── installation_nixos_module.md │ ├── introduction.md │ ├── nixos_options.md │ ├── security.md │ └── troubleshooting.md ├── fixed-output-derivations.lock ├── flake.lock ├── flake.nix ├── nix ├── autofirma │ ├── create-autofirma-cert │ ├── default.nix │ ├── dependencies │ │ ├── clienteafirma-external │ │ │ └── default.nix │ │ └── jmulticard │ │ │ └── default.nix │ ├── hm-module.nix │ ├── module.nix │ ├── patches │ │ └── clienteafirma │ │ │ ├── aarch64_elf.patch │ │ │ ├── certutilpath.patch │ │ │ ├── dark_mode_fix.patch │ │ │ ├── detect_java_version.patch │ │ │ ├── dont_check_java_version.patch │ │ │ ├── etc_config.patch │ │ │ └── pr-367.patch │ └── truststore │ │ ├── default.nix │ │ └── prestadores │ │ ├── CAs-by-provider │ │ ├── A01337260.json │ │ ├── A40573396.json │ │ ├── A62634068.json │ │ ├── A82733262.json │ │ ├── B85626240.json │ │ ├── B87341228.json │ │ ├── G63287510.json │ │ ├── Q2826004J.json │ │ └── S2816015H.json │ │ ├── CAs_fetch_links.json │ │ ├── default.nix │ │ └── providers.json ├── configuradorfnmt │ ├── default.nix │ ├── hm-module.nix │ └── module.nix ├── dnieremote │ ├── default.nix │ ├── hm-module.nix │ └── module.nix ├── tests │ ├── _common │ │ ├── hm-as-nixos-module │ │ │ └── autofirma-user.nix │ │ ├── hm-standalone │ │ │ └── autofirma-user.nix │ │ ├── nixos │ │ │ └── stateVersion.nix │ │ ├── pkgs │ │ │ └── test_certs.nix │ │ └── tests │ │ │ └── autofirma_test_server │ │ │ ├── default.nix │ │ │ └── www │ │ │ └── index.php │ ├── hm-as-nixos-module │ │ ├── autofirma │ │ │ ├── cli │ │ │ │ └── sign-document.nix │ │ │ ├── config │ │ │ │ └── omitAskOnClose.nix │ │ │ └── firefoxIntegration │ │ │ │ ├── connection-method │ │ │ │ ├── auxiliary-servers │ │ │ │ │ ├── default.nix │ │ │ │ │ └── test.js │ │ │ │ ├── build-connection-method-test.nix │ │ │ │ ├── websocket │ │ │ │ │ ├── default.nix │ │ │ │ │ └── test.js │ │ │ │ └── xhr │ │ │ │ │ ├── default.nix │ │ │ │ │ └── test.js │ │ │ │ └── protocol-handler │ │ │ │ └── default.nix │ │ ├── configuradorfnmt │ │ │ └── firefoxIntegration │ │ │ │ └── request-certificate.nix │ │ └── dnieremote │ │ │ └── config │ │ │ ├── jumpintro-no.nix │ │ │ ├── jumpintro-usb.nix │ │ │ ├── jumpintro-wifi.nix │ │ │ └── wifiport.nix │ ├── hm-standalone │ │ ├── autofirma │ │ │ ├── cli │ │ │ │ └── sign-document.nix │ │ │ ├── config │ │ │ │ └── omitAskOnClose.nix │ │ │ └── firefoxIntegration │ │ │ │ ├── connection-method │ │ │ │ ├── auxiliary-servers │ │ │ │ │ ├── default.nix │ │ │ │ │ └── test.js │ │ │ │ ├── build-connection-method-test.nix │ │ │ │ ├── websocket │ │ │ │ │ ├── default.nix │ │ │ │ │ └── test.js │ │ │ │ └── xhr │ │ │ │ │ ├── default.nix │ │ │ │ │ └── test.js │ │ │ │ └── protocol-handler │ │ │ │ └── default.nix │ │ ├── configuradorfnmt │ │ │ └── firefoxIntegration │ │ │ │ └── request-certificate.nix │ │ └── dnieremote │ │ │ └── config │ │ │ ├── jumpintro-no.nix │ │ │ ├── jumpintro-usb.nix │ │ │ ├── jumpintro-wifi.nix │ │ │ └── wifiport.nix │ ├── nixos │ │ ├── autofirma │ │ │ ├── cli │ │ │ │ └── sign-document.nix │ │ │ └── firefoxIntegration │ │ │ │ ├── connection-method │ │ │ │ ├── auxiliary-servers │ │ │ │ │ ├── default.nix │ │ │ │ │ └── test.js │ │ │ │ ├── build-connection-method-test.nix │ │ │ │ ├── websocket │ │ │ │ │ ├── default.nix │ │ │ │ │ └── test.js │ │ │ │ └── xhr │ │ │ │ │ ├── default.nix │ │ │ │ │ └── test.js │ │ │ │ └── protocol-handler │ │ │ │ └── default.nix │ │ ├── configuradorfnmt │ │ │ └── firefoxIntegration │ │ │ │ └── request-certificate.nix │ │ └── dnieremote │ │ │ └── config │ │ │ ├── jumpintro-no.nix │ │ │ ├── jumpintro-usb.nix │ │ │ ├── jumpintro-wifi.nix │ │ │ └── wifiport.nix │ ├── overlay │ │ └── default.nix │ └── unit │ │ └── default.nix └── tools │ ├── download-autofirma-trusted-providers │ ├── default.nix │ └── download-autofirma-trusted-providers.sh │ ├── download-url-linked-CAs │ ├── default.nix │ └── download-url-linked-CAs.py │ ├── pom-tools │ ├── default.nix │ └── lib │ │ ├── add-xml-doclet-to-javadoc-plugin.py │ │ ├── remove-module-on-profile.sh │ │ ├── reset-maven-metadata-local-timestamp.sh │ │ ├── reset-project-build-timestamp.sh │ │ ├── update-dependency-version-by-groupId.sh │ │ ├── update-java-version.sh │ │ ├── update-pkg-version.sh │ │ └── update-plugin-version-by-groupId.sh │ ├── properties-to-json │ ├── default.nix │ └── properties-to-json.py │ └── update-fixed-output-derivations │ ├── default.nix │ └── update-fixed-output-derivations.py └── templates ├── README.md ├── home-manager-nixos └── flake.nix ├── home-manager-standalone └── flake.nix └── nixos-module └── flake.nix /.gitattributes: -------------------------------------------------------------------------------- 1 | flake.nix merge=ours 2 | flake.lock merge=ours 3 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [ nilp0inter ] # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2] 2 | open_collective: nix-community 3 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "daily" 7 | -------------------------------------------------------------------------------- /.github/labeler.yml: -------------------------------------------------------------------------------- 1 | "autofirma": 2 | - changed-files: 3 | - any-glob-to-any-file: 4 | - nix/autofirma/**/* # All files under nix/autofirma 5 | - nix/tests/**/autofirma/**/* # Autofirma-related tests 6 | 7 | "dnieremote": 8 | - changed-files: 9 | - any-glob-to-any-file: 10 | - nix/dnieremote/**/* # All files under nix/dnieremote 11 | - nix/tests/**/dnieremote/**/* # DNIeRemote-related tests 12 | 13 | "configuradorfnmt": 14 | - changed-files: 15 | - any-glob-to-any-file: 16 | - nix/configuradorfnmt/**/* # All files under nix/configuradorfnmt 17 | - nix/tests/**/configuradorfnmt/**/* 18 | 19 | "modules": 20 | - changed-files: 21 | - any-glob-to-any-file: 22 | - nix/**/module.nix # Generic module definitions 23 | - nix/**/hm-module.nix # Home Manager module definitions 24 | 25 | "tools": 26 | - changed-files: 27 | - any-glob-to-any-file: 28 | - nix/tools/**/* # Generic tools (update scripts, etc.) 29 | 30 | "truststore": 31 | - changed-files: 32 | - any-glob-to-any-file: 33 | - nix/autofirma/truststore/**/* 34 | - nix/tests/_common/pkgs/test_certs.nix 35 | - nix/tests/_common/tests/autofirma_test_server/**/* 36 | 37 | "tests": 38 | - changed-files: 39 | - any-glob-to-any-file: 40 | - nix/tests/**/* # Capture any test changes 41 | 42 | "docs": 43 | - changed-files: 44 | - any-glob-to-any-file: 45 | - docs/**/* # Documentation files 46 | - README.md 47 | - nix/tools/properties-to-json/**/* 48 | 49 | -------------------------------------------------------------------------------- /.github/workflows/docs.yml: -------------------------------------------------------------------------------- 1 | name: Docs 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | paths: 8 | - 'README.md' 9 | - 'docs/**' 10 | - 'nix/**/module.nix' 11 | - 'nix/**/hm-module.nix' 12 | - 'nix/tools/properties-to-json/**' 13 | 14 | jobs: 15 | build: 16 | name: Build 17 | 18 | permissions: 19 | contents: read 20 | 21 | runs-on: ubuntu-latest 22 | 23 | steps: 24 | - name: Install Nix 25 | uses: DeterminateSystems/nix-installer-action@90bb610b90bf290cad97484ba341453bd1cbefea # v19 26 | with: 27 | github-token: ${{ secrets.GITHUB_TOKEN }} 28 | extra-conf: | 29 | extra-experimental-features = nix-command flakes 30 | 31 | - name: Set up cache 32 | uses: DeterminateSystems/magic-nix-cache-action@565684385bcd71bad329742eefe8d12f2e765b39 # v13 33 | 34 | - name: Build docs 35 | run: nix -L build github:${{ github.repository }}/${{ github.sha }}#docs 36 | 37 | - name: Prepare docs for upload 38 | run: cp -r --dereference --no-preserve=mode,ownership result/ public/ 39 | 40 | - name: Upload artifact 41 | uses: actions/upload-pages-artifact@7b1f4a764d45c48632c6b24a0339c27f5614fb0b # v4.0.0 42 | with: 43 | path: public/ 44 | 45 | deploy: 46 | name: Deploy 47 | 48 | needs: build 49 | 50 | permissions: 51 | pages: write 52 | id-token: write 53 | 54 | environment: 55 | name: github-pages 56 | url: ${{ steps.deployment.outputs.page_url }} 57 | 58 | runs-on: ubuntu-latest 59 | 60 | steps: 61 | - name: Deploy docs to GitHub Pages 62 | id: deployment 63 | uses: actions/deploy-pages@d6db90164ac5ed86f2b6aed7e0febac5b3c0c03e # v4.0.5 64 | 65 | check-nixos-search: 66 | name: Check readiness for nixos-search 67 | runs-on: ubuntu-latest 68 | 69 | steps: 70 | - name: Install Nix 71 | uses: DeterminateSystems/nix-installer-action@90bb610b90bf290cad97484ba341453bd1cbefea # v19 72 | with: 73 | github-token: ${{ secrets.GITHUB_TOKEN }} 74 | extra-conf: | 75 | extra-experimental-features = nix-command flakes 76 | 77 | - name: Set up cache 78 | uses: DeterminateSystems/magic-nix-cache-action@565684385bcd71bad329742eefe8d12f2e765b39 # v13 79 | 80 | - name: Check flake-info 81 | id: flake-info 82 | shell: bash 83 | run: | 84 | nix run github:NixOS/nixos-search#flake-info -- --json flake github:${{ github.repository }}/${{ github.event.pull_request.head.sha || github.sha }} | jq . 85 | -------------------------------------------------------------------------------- /.github/workflows/labeler.yml: -------------------------------------------------------------------------------- 1 | name: "Pull Request Labeler" 2 | on: 3 | - pull_request_target 4 | 5 | jobs: 6 | labeler: 7 | permissions: 8 | contents: read 9 | pull-requests: write 10 | runs-on: ubuntu-latest 11 | steps: 12 | - uses: actions/labeler@8558fd74291d67161a8a78ce36a881fa63b766a9 #v5.0.0 13 | -------------------------------------------------------------------------------- /.github/workflows/monitor-upstream-releases.yml: -------------------------------------------------------------------------------- 1 | name: Monitor Upstream Releases 2 | on: 3 | schedule: 4 | - cron: "0 5 * * *" # Daily at 06:00 CET / 07:00 CEST 5 | workflow_dispatch: 6 | 7 | permissions: 8 | actions: read 9 | contents: write 10 | issues: write 11 | 12 | jobs: 13 | monitor_autofirma: 14 | name: Monitor AutoFirma Releases 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Monitor AutoFirma Releases 18 | id: monitor 19 | uses: nilp0inter/urlwatch-action@daaec60bb7dd6071ee3c25665683bedb6515070c # v0.1.0 20 | with: 21 | cache-name: 'urlwatch-autofirma' 22 | token: ${{ secrets.GITHUB_TOKEN }} 23 | urls: | 24 | url: "https://firmaelectronica.gob.es/Home/Descargas.html" 25 | ssl_no_verify: true 26 | filter: 27 | - xpath: //a 28 | - grep: "AutoFirma" 29 | - grep: "Linux" 30 | 31 | - name: Create change notification 32 | if: ${{ steps.monitor.outputs.changes != '' }} 33 | uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 34 | env: 35 | DETECTED_CHANGES: ${{ steps.monitor.outputs.report }} 36 | with: 37 | script: | 38 | await github.rest.issues.create({ 39 | owner: context.repo.owner, 40 | repo: context.repo.repo, 41 | title: 'New official release of AutoFirma found! 🎉', 42 | body: process.env.DETECTED_CHANGES, 43 | labels: ['upstream', 'update'] 44 | }); 45 | 46 | monitor_configuradorfnmt: 47 | name: Monitor Configurador FNMT-RCM Releases 48 | runs-on: ubuntu-latest 49 | steps: 50 | - name: Monitor Configurador FNMT-RCM Releases 51 | id: monitor 52 | uses: nilp0inter/urlwatch-action@v0.1.0 53 | with: 54 | cache-name: 'urlwatch-configuradorfnmt' 55 | token: ${{ secrets.GITHUB_TOKEN }} 56 | urls: | 57 | url: "https://www.sede.fnmt.gob.es/descargas/descarga-software/instalacion-software-generacion-de-claves" 58 | ssl_no_verify: true 59 | filter: 60 | - xpath: //a 61 | - grep: "Configurador" 62 | - grep: "FNMT-RCM" 63 | - grep: "Linux" 64 | - xpath: //@href 65 | 66 | - name: Create change notification 67 | if: ${{ steps.monitor.outputs.changes != '' }} 68 | uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 69 | env: 70 | DETECTED_CHANGES: ${{ steps.monitor.outputs.report }} 71 | with: 72 | script: | 73 | await github.rest.issues.create({ 74 | owner: context.repo.owner, 75 | repo: context.repo.repo, 76 | title: 'New official release of Configurador FNMT-RCM found! 🎉', 77 | body: process.env.DETECTED_CHANGES, 78 | labels: ['upstream', 'update'] 79 | }); 80 | 81 | monitor_dnieremote: 82 | name: Monitor DNIeRemote Releases 83 | runs-on: ubuntu-latest 84 | steps: 85 | - name: Monitor DNIeRemote Releases 86 | id: monitor 87 | uses: nilp0inter/urlwatch-action@v0.1.0 88 | with: 89 | cache-name: 'urlwatch-dnieremote' 90 | token: ${{ secrets.GITHUB_TOKEN }} 91 | urls: | 92 | name: "DNIeRemote" 93 | url: "https://www.dnielectronico.es/PortalDNIe/PRF1_Cons02.action?pag=REF_1015&id_menu=67" 94 | ssl_no_verify: true 95 | filter: 96 | - xpath: //a 97 | - grep: "DNIe" 98 | - grep: "Remote" 99 | - grep: "Linux" 100 | - xpath: //@href 101 | 102 | - name: Create change notification 103 | if: ${{ steps.monitor.outputs.changes != '' }} 104 | uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 105 | env: 106 | DETECTED_CHANGES: ${{ steps.monitor.outputs.report }} 107 | with: 108 | script: | 109 | await github.rest.issues.create({ 110 | owner: context.repo.owner, 111 | repo: context.repo.repo, 112 | title: 'New official release of DNIeRemote found! 🎉', 113 | body: process.env.DETECTED_CHANGES, 114 | labels: ['upstream', 'update'] 115 | }); 116 | -------------------------------------------------------------------------------- /.github/workflows/monitor-upstream-repositories.yml: -------------------------------------------------------------------------------- 1 | name: Monitor Upstream Repositories 2 | on: 3 | schedule: 4 | - cron: "0 5 * * *" # Daily at 06:00 CET / 07:00 CEST 5 | workflow_dispatch: 6 | 7 | permissions: 8 | actions: read 9 | contents: write 10 | issues: write 11 | 12 | jobs: 13 | monitor: 14 | name: Monitor ${{ matrix.owner }}/${{ matrix.repo }}/${{ matrix.object }} 15 | runs-on: ubuntu-latest 16 | strategy: 17 | matrix: 18 | object: 19 | - tags 20 | - branches 21 | owner: 22 | - ctt-gob-es 23 | repo: 24 | - clienteafirma 25 | - clienteafirma-external 26 | - jmulticard 27 | steps: 28 | - name: Monitor ${{ matrix.owner }}/${{ matrix.repo }}/${{ matrix.object }} 29 | id: monitor 30 | uses: nilp0inter/urlwatch-action@daaec60bb7dd6071ee3c25665683bedb6515070c # v0.1.0 31 | with: 32 | cache-name: 'urlwatch-cache-${{ matrix.owner }}-${{ matrix.repo }}-${{ matrix.object }}' 33 | token: ${{ secrets.GITHUB_TOKEN }} 34 | urls: | 35 | url: https://api.github.com/repos/${{ matrix.owner }}/${{ matrix.repo }}/${{ matrix.object }} 36 | filter: 37 | - jq: '.[] | .name' 38 | - sort: 39 | 40 | - name: Create change notification 41 | if: ${{ steps.monitor.outputs.changes != '' }} 42 | uses: actions/github-script@ed597411d8f924073f98dfc5c65a23a2325f34cd # v8.0.0 43 | env: 44 | DETECTED_CHANGES: ${{ steps.monitor.outputs.report }} 45 | with: 46 | script: | 47 | await github.rest.issues.create({ 48 | owner: context.repo.owner, 49 | repo: context.repo.repo, 50 | title: '${{ matrix.owner }}/${{ matrix.repo }}: Detected changes in ${{ matrix.object }}', 51 | body: `# Detected changes in ${{ matrix.object }}\n\n${process.env.DETECTED_CHANGES}`, 52 | labels: ['upstream'] 53 | }); 54 | -------------------------------------------------------------------------------- /.github/workflows/stale.yml: -------------------------------------------------------------------------------- 1 | name: Close Inactive Issues 2 | on: 3 | schedule: 4 | - cron: "0 2 * * *" # Daily at 03:00 CET / 04:00 CEST 5 | workflow_dispatch: 6 | 7 | jobs: 8 | close-issues: 9 | runs-on: ubuntu-latest 10 | permissions: 11 | issues: write 12 | pull-requests: write 13 | steps: 14 | - uses: actions/stale@5f858e3efba33a5ca4407a664cc011ad407f2008 # v10.1.0 15 | with: 16 | days-before-issue-stale: 14 17 | days-before-issue-close: 7 18 | stale-issue-label: "stale" 19 | stale-issue-message: "This issue is stale because it has been open for 14 days with no activity." 20 | close-issue-message: "This issue was closed because it has been inactive for 7 days since being marked as stale." 21 | days-before-pr-stale: -1 22 | days-before-pr-close: -1 23 | exempt-issue-labels: "bug,enhancement,progress-tracking" 24 | repo-token: ${{ secrets.GITHUB_TOKEN }} 25 | 26 | -------------------------------------------------------------------------------- /.github/workflows/update-autofirma-CAs-by-provider.yml: -------------------------------------------------------------------------------- 1 | name: Update AutoFirma CAs by Provider 2 | 3 | on: 4 | schedule: 5 | - cron: "0 4 * * 1,3,5" # Monday, Wednesday, Friday at 05:00 CET / 06:00 CEST 6 | push: 7 | branches: 8 | - main 9 | paths: 10 | - 'nix/autofirma/truststore/prestadores/CAs_fetch_links.json' 11 | - 'nix/autofirma/truststore/prestadores/providers.json' 12 | workflow_dispatch: 13 | repository_dispatch: 14 | 15 | jobs: 16 | parse-ca-fetch-links: 17 | name: Parse CA Fetch Links JSON 18 | runs-on: ubuntu-latest 19 | outputs: 20 | fetch_links: ${{ steps.extract-fetch-links.outputs.fetch_links }} 21 | markdown_links: ${{ steps.extract-fetch-links.outputs.markdown_links }} 22 | steps: 23 | - name: Checkout Repository 24 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 25 | 26 | - id: extract-fetch-links 27 | name: Extract Fetch Links and Generate Markdown 28 | shell: bash 29 | run: | 30 | echo "fetch_links=$(jq -c '.' nix/autofirma/truststore/prestadores/CAs_fetch_links.json)" >> $GITHUB_OUTPUT 31 | echo 'markdown_links<> $GITHUB_OUTPUT 32 | jq -r '.[] | "- [" + .cif + ".json](" + .url + ")"' nix/autofirma/truststore/prestadores/CAs_fetch_links.json >> $GITHUB_OUTPUT 33 | echo 'EOF' >> $GITHUB_OUTPUT 34 | 35 | download-ca-files: 36 | name: Download CA Files for Each Provider 37 | needs: parse-ca-fetch-links 38 | runs-on: ubuntu-latest 39 | strategy: 40 | fail-fast: true 41 | matrix: 42 | fetch_link: ${{ fromJson(needs.parse-ca-fetch-links.outputs.fetch_links) }} 43 | steps: 44 | - name: Checkout Repository 45 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 46 | 47 | - name: Install Nix Package Manager 48 | uses: cachix/install-nix-action@fd24c48048070c1be9acd18c9d369a83f0fe94d7 # v31.8.1 49 | 50 | - name: Download CA for ${{ matrix.fetch_link.cif }} 51 | shell: bash # https://github.com/actions/runner-images/issues/4459#issuecomment-1374859960 52 | run: | 53 | echo '${{ toJson(matrix.fetch_link) }}' \ 54 | | nix --accept-flake-config develop --command -- download-url-linked-CAs \ 55 | | tee nix/autofirma/truststore/prestadores/CAs-by-provider/${{ matrix.fetch_link.cif }}.json 56 | 57 | - name: Upload CA Artifact for ${{ matrix.fetch_link.cif }} 58 | uses: actions/upload-artifact@ea165f8d65b6e75b540449e92b4886f43607fa02 # v4.6.2 59 | with: 60 | name: CAs-${{ matrix.fetch_link.cif }} 61 | path: nix/autofirma/truststore/prestadores/CAs-by-provider/${{ matrix.fetch_link.cif }}.json 62 | 63 | create-ca-pull-request: 64 | name: Create Pull Request with Updated CA Files 65 | needs: 66 | - download-ca-files 67 | - parse-ca-fetch-links 68 | runs-on: ubuntu-latest 69 | steps: 70 | - name: Checkout Repository 71 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 72 | 73 | - name: Clear Existing CA Files 74 | run: rm -f nix/autofirma/truststore/prestadores/CAs-by-provider/*.json 75 | 76 | - name: Download CA Artifacts 77 | uses: actions/download-artifact@018cc2cf5baa6db3ef3c5f8a56943fffe632ef53 # v6.0.0 78 | with: 79 | pattern: CAs-* 80 | path: nix/autofirma/truststore/prestadores/CAs-by-provider 81 | merge-multiple: true 82 | 83 | - name: Create Pull Request for Updated CA Files 84 | uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 85 | with: 86 | branch: update/autofirma-CAs-by-provider 87 | base: main 88 | author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> 89 | delete-branch: true 90 | labels: | 91 | security 92 | merge-queue 93 | commit-message: 'update: AutoFirma CAs-by-provider' 94 | title: "Update Trusted Providers CAs for autofirma-nix" 95 | body: | 96 | This PR updates the JSON files for each trusted provider based on the information available on their respective websites. 97 | 98 | **List of Provider URLs:** 99 | 100 | ${{ needs.parse-ca-fetch-links.outputs.markdown_links }} 101 | 102 | #### Review Checklist: 103 | 1. Verify that the updated list aligns with the official sources. 104 | 2. Ensure that no entries have been unintentionally removed, possibly due to temporary page outages. 105 | 106 | Thank you for your review! 107 | 108 | add-paths: | 109 | nix/autofirma/truststore/prestadores/CAs-by-provider 110 | -------------------------------------------------------------------------------- /.github/workflows/update-autofirma-trusted-providers.yml: -------------------------------------------------------------------------------- 1 | name: Update AutoFirma Trusted Providers 2 | 3 | on: 4 | schedule: 5 | - cron: "0 4 * * 2,4,6" # Tuesday, Thursday, Saturday at 05:00 CET / 06:00 CEST 6 | workflow_dispatch: 7 | repository_dispatch: 8 | 9 | jobs: 10 | download_autofirma_trusted_providers: 11 | name: Download AutoFirma Trusted Provider List 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout Repository 15 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 16 | 17 | - name: Install Nix 18 | uses: cachix/install-nix-action@fd24c48048070c1be9acd18c9d369a83f0fe94d7 # v31.8.1 19 | 20 | - name: Download AutoFirma Trusted Providers 21 | run: | 22 | nix develop --accept-flake-config --command download-autofirma-trusted-providers > nix/autofirma/truststore/prestadores/providers.json 23 | 24 | - name: Create Pull Request for the new trusted providers file 25 | uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 26 | with: 27 | branch: update/autofirma-trusted-providers 28 | base: main 29 | author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> 30 | delete-branch: true 31 | labels: | 32 | security 33 | merge-queue 34 | commit-message: 'update: AutoFirma trusted providers' 35 | title: "Update Trusted Providers List for autofirma-nix" 36 | body: | 37 | This PR updates the JSON file of trusted providers based on the latest official information. For reference, the human-readable PDF is available at: [PAe aFirma Anexo PSC](http://administracionelectronica.gob.es/PAe/aFirma-Anexo-PSC). 38 | 39 | #### Review Tasks: 40 | 1. Verify the updated list aligns with the official source. 41 | 2. For new providers, add their CA download page and CIF to `nix/autofirma/truststore/prestadores/CAs_fetch_links.json`. 42 | 3. For removed providers, clean up related files in `nix/autofirma/truststore/prestadores/CAs-by-provider/`. 43 | 44 | Thank you for reviewing! 45 | 46 | add-paths: | 47 | nix/autofirma/truststore/prestadores/providers.json 48 | -------------------------------------------------------------------------------- /.github/workflows/update-fixed-output-derivations-lock.yml: -------------------------------------------------------------------------------- 1 | name: Update Fixed-Output Derivations Lock 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - develop 8 | - 'release-*' 9 | paths: 10 | - flake.lock 11 | workflow_dispatch: 12 | 13 | jobs: 14 | update_fixed_output: 15 | runs-on: ubuntu-latest 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 19 | with: 20 | # Checks out the branch that triggered the workflow 21 | ref: ${{ github.ref }} 22 | 23 | - name: Install Nix 24 | uses: cachix/install-nix-action@fd24c48048070c1be9acd18c9d369a83f0fe94d7 # v31.8.1 25 | 26 | - name: Update fixed-output derivations 27 | run: | 28 | nix develop --accept-flake-config --command update-fixed-output-derivations 29 | 30 | - name: Create Pull Request for the updated fixed-output derivations lock file 31 | uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 32 | with: 33 | # Use the branch name from the push event for both the new branch and the PR base 34 | branch: update/fixed-output-derivations/${{ github.ref_name }} 35 | base: ${{ github.ref_name }} 36 | author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> 37 | delete-branch: true 38 | labels: | 39 | dependencies 40 | merge-queue 41 | commit-message: 'fixed-output-derivations.lock' 42 | title: "Update fixed-output-derivations.lock for `${{ github.ref_name }}`" 43 | body: | 44 | This pull request updates the `fixed-output-derivations.lock` file for the `${{ github.ref_name }}` branch. The updates ensure that the hashes for the fixed-output derivations are current, maintaining the integrity of our build process. These updates encompass all necessary external dependencies required for building the project's components. 45 | 46 | #### Why This Update? 47 | Keeping the `fixed-output-derivations.lock` file updated is crucial for: 48 | - **Reproducible Builds:** Ensures that builds are consistent across different environments by locking dependency versions. 49 | - **Security:** Helps in verifying the integrity of dependencies, mitigating potential security risks from tampered or malicious packages. 50 | 51 | #### Reviewer Instructions: 52 | 1. **Verify Automated Tests:** Please ensure that all automated tests pass successfully. 53 | 2. **Merge Guidelines:** Once verification is complete, squash and merge this pull request to maintain a clean commit history. 54 | 55 | Thank you for reviewing! 56 | 57 | --- 58 | 59 | *This PR was generated automatically by a bot to keep dependencies up-to-date.* 60 | add-paths: fixed-output-derivations.lock 61 | -------------------------------------------------------------------------------- /.github/workflows/update-flake-lock.yml: -------------------------------------------------------------------------------- 1 | name: Update Flake Lock 2 | on: 3 | schedule: 4 | - cron: "0 4 * * *" # Daily at 05:00 CET / 06:00 CEST 5 | workflow_dispatch: 6 | repository_dispatch: 7 | 8 | env: 9 | IS_NIXOS_OLDSTABLE_DEPRECATED: ${{ vars.IS_NIXOS_OLDSTABLE_DEPRECATED }} 10 | NIXOS_OLDSTABLE_BRANCH: ${{ vars.NIXOS_OLDSTABLE_BRANCH }} 11 | NIXOS_STABLE_BRANCH: ${{ vars.NIXOS_STABLE_BRANCH }} 12 | 13 | jobs: 14 | update_main_develop_and_stable: 15 | name: Update Main and Stable Branches 16 | runs-on: ubuntu-latest 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | branch: [ 21 | "main", 22 | "develop", 23 | "release-${{ vars.NIXOS_STABLE_BRANCH }}" 24 | ] 25 | env: 26 | UPDATE_BRANCH: update/flake/${{ matrix.branch }} 27 | steps: 28 | - name: Checkout repository 29 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 30 | with: 31 | ref: ${{ matrix.branch }} 32 | 33 | - name: Install Nix 34 | uses: cachix/install-nix-action@fd24c48048070c1be9acd18c9d369a83f0fe94d7 # v31.8.1 35 | 36 | - name: Update flake.lock 37 | uses: DeterminateSystems/update-flake-lock@c5930b397a673a70ca70be06020e943aeac310a1 # v27 38 | with: 39 | branch: "${{ env.UPDATE_BRANCH }}" 40 | pr-labels: | 41 | dependencies 42 | merge-queue 43 | pr-title: "Update flake.lock for `${{ matrix.branch }}`" 44 | pr-base: ${{ matrix.branch }} 45 | pr-body: | 46 | Automated changes by the [update-flake-lock](https://github.com/DeterminateSystems/update-flake-lock) GitHub Action. 47 | 48 | ``` 49 | {{ env.GIT_COMMIT_MESSAGE }} 50 | ``` 51 | 52 | ### Running GitHub Actions on this PR 53 | 54 | GitHub Actions will not run workflows on pull requests which are opened by a GitHub Action. 55 | 56 | To run GitHub Actions workflows on this PR, run: 57 | 58 | ```sh 59 | git branch -D ${{ env.UPDATE_BRANCH }} 60 | git fetch origin 61 | git checkout ${{ env.UPDATE_BRANCH }} 62 | git commit --amend --no-edit 63 | git push origin ${{ env.UPDATE_BRANCH }} --force 64 | ``` 65 | 66 | update_oldstable: 67 | name: Update Oldstable Branch 68 | if: ${{ vars.IS_NIXOS_OLDSTABLE_DEPRECATED == '0' }} 69 | runs-on: ubuntu-latest 70 | env: 71 | UPDATE_BRANCH: update/flake/release-${{ vars.NIXOS_OLDSTABLE_BRANCH }} 72 | steps: 73 | - name: Checkout repository 74 | uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5.0.0 75 | with: 76 | ref: "release-${{ vars.NIXOS_OLDSTABLE_BRANCH }}" 77 | 78 | - name: Install Nix 79 | uses: cachix/install-nix-action@fd24c48048070c1be9acd18c9d369a83f0fe94d7 # v31.8.1 80 | 81 | - name: Update flake.lock 82 | uses: DeterminateSystems/update-flake-lock@c5930b397a673a70ca70be06020e943aeac310a1 # v27 83 | with: 84 | branch: "${{ env.UPDATE_BRANCH }}" 85 | pr-labels: | 86 | dependencies 87 | merge-queue 88 | pr-title: "Update flake.lock for `release-${{ vars.NIXOS_OLDSTABLE_BRANCH }}`" 89 | pr-base: "release-${{ vars.NIXOS_OLDSTABLE_BRANCH }}" 90 | pr-body: | 91 | Automated changes by the [update-flake-lock](https://github.com/DeterminateSystems/update-flake-lock) GitHub Action. 92 | 93 | ``` 94 | {{ env.GIT_COMMIT_MESSAGE }} 95 | ``` 96 | 97 | ### Running GitHub Actions on this PR 98 | 99 | GitHub Actions will not run workflows on pull requests which are opened by a GitHub Action. 100 | 101 | To run GitHub Actions workflows on this PR, run: 102 | 103 | ```sh 104 | git branch -D ${{ env.UPDATE_BRANCH }} 105 | git fetch origin 106 | git checkout ${{ env.UPDATE_BRANCH }} 107 | git commit --amend --no-edit 108 | git push origin ${{ env.UPDATE_BRANCH }} --force 109 | ``` 110 | -------------------------------------------------------------------------------- /.mergify.yml: -------------------------------------------------------------------------------- 1 | queue_rules: 2 | - name: default 3 | merge_conditions: 4 | - check-success=buildbot/nix-build 5 | merge_method: squash 6 | 7 | pull_request_rules: 8 | - name: auto-merge PRs updating lock files 9 | conditions: 10 | - base~=(main|develop|release-\d+\.\d+) 11 | - label~=merge-queue|dependencies 12 | - files~=\.*\.lock$ 13 | actions: 14 | queue: 15 | - name: delete branches of closed PRs from an automation 16 | conditions: 17 | - base~=(main|develop|release-\d+\.\d+) 18 | - label~=merge-queue 19 | - closed 20 | actions: 21 | delete_head_branch: 22 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to autofirma-nix 2 | 3 | First off, thank you for considering contributing to `autofirma-nix`. It's people like you that make this project great! 4 | 5 | The following is a set of guidelines for contributing to `autofirma-nix`, which is hosted in the [nix-community](https://github.com/nix-community) on GitHub. These are mostly guidelines, not rules. Use your best judgment, and feel free to propose changes to this document in a pull request. 6 | 7 | ## How Can I Contribute? 8 | 9 | ### Reporting Bugs 10 | 11 | If you find a bug, please report it by opening an issue in the [issue tracker](https://github.com/nix-community/autofirma-nix/issues). Please include as much detail as possible, including steps to reproduce the issue, your environment, and any relevant logs. 12 | 13 | ### Suggesting Enhancements 14 | 15 | If you have an idea for an enhancement or a new feature, please open an issue in the [issue tracker](https://github.com/nix-community/autofirma-nix/issues) and describe your idea in detail. We welcome all suggestions and will discuss them to see if they align with the project's goals. 16 | 17 | ### Pull Requests 18 | 19 | #### Getting Started 20 | 21 | 1. Fork the repository. 22 | 2. Clone your fork to your local machine. 23 | 3. Create a new branch for your changes. 24 | 25 | #### Making Changes 26 | 27 | 1. Make your changes in your local branch. 28 | 2. Write clear and concise commit messages. Follow the [Conventional Commits](https://www.conventionalcommits.org/) specification. 29 | 3. Ensure that your code adheres to the project's coding standards. 30 | 4. If you've added code that should be tested, add tests. 31 | 5. Run the test suite to ensure that all tests pass. 32 | 33 | #### Submitting Pull Requests 34 | 35 | 1. Push your changes to your fork. 36 | 2. Open a pull request against the `main` branch in the upstream repository. 37 | 3. In the pull request description, explain the purpose of your changes and link to any relevant issues. 38 | 4. Be prepared to discuss and iterate on your changes. We may ask you to make modifications, and that's okay! 39 | 40 | ### Coding Standards 41 | 42 | - Follow the existing coding style in the repository. 43 | - Write clear and concise code. 44 | - Document your code where necessary. 45 | - Ensure that your code is well-tested. 46 | 47 | ### Testing 48 | 49 | - Add tests for any new functionality you introduce. 50 | - Ensure that all existing tests pass before submitting your pull request. 51 | - Run `nix flake check` to run the test suite. 52 | 53 | ## Additional Resources 54 | 55 | - [Issue Tracker](https://github.com/nix-community/autofirma-nix/issues) 56 | - [Pull Requests](https://github.com/nix-community/autofirma-nix/pulls) 57 | - [Conventional Commits](https://www.conventionalcommits.org/) 58 | - [Nix](https://nixos.org/) 59 | 60 | Thank you for your contributions! 61 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Roberto Abdelkader Martínez Pérez 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | 4 | 5 | 6 | Autofirma-Nix Logo 7 | 8 | 9 |

10 | 11 |

autofirma-nix

12 | 13 | [![built with nix](https://builtwithnix.org/badge.svg)](https://builtwithnix.org) 14 | 15 | Nix packages, NixOS modules, and Home Manager modules for the suite of tools required to interact with Spain's public administration digital services: 16 | 17 | - **AutoFirma** - Digital document signing and web authentication 18 | - **DNIeRemote** - Use your smartphone as an NFC reader for your Spanish national ID card 19 | > **⚠️ Android Compatibility Note:** The DNIeSmartConnect Android app may not be available on Google Play for modern Android devices. See the [troubleshooting guide](https://nix-community.github.io/autofirma-nix/troubleshooting.html#dnieremote-android-app-compatibility) for installation alternatives. 20 | - **Configurador FNMT-RCM** - Request and install certificates from the Spanish Royal Mint 21 | 22 | ## Quick Start 23 | 24 | ```bash 25 | # Run DNIeRemote directly 26 | nix run github:nix-community/autofirma-nix#dnieremote 27 | 28 | # Create a new NixOS configuration with AutoFirma 29 | nix flake new --template github:nix-community/autofirma-nix#nixos-module ./my-autofirma-system 30 | 31 | # Create a new Home Manager configuration with AutoFirma 32 | nix flake new --template github:nix-community/autofirma-nix#home-manager-standalone ./my-autofirma-home 33 | ``` 34 | 35 | ## Documentation 36 | 37 | Comprehensive documentation is available at: 38 | https://nix-community.github.io/autofirma-nix/ 39 | 40 | There you'll find: 41 | - Detailed installation instructions for NixOS and Home Manager 42 | - Configuration options reference 43 | - Security considerations 44 | - Troubleshooting guide 45 | 46 | ## License 47 | 48 | This project is licensed under the MIT License - see the LICENSE file for details. 49 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | 3 | ### Created by https://www.gitignore.io 4 | ### MdBook ### 5 | book 6 | 7 | -------------------------------------------------------------------------------- /docs/book.toml: -------------------------------------------------------------------------------- 1 | [book] 2 | authors = ["Roberto Abdelkader Martínez Pérez", "pancho horrillo", "César Gallego Rodríguez"] 3 | language = "en" 4 | multilingual = false 5 | src = "src" 6 | title = "autofirma-nix" 7 | -------------------------------------------------------------------------------- /docs/default.nix: -------------------------------------------------------------------------------- 1 | { pkgs, lib, inputs, ... }: 2 | 3 | let 4 | makeOptionsDoc = configuration: pkgs.nixosOptionsDoc { 5 | inherit (configuration) options; 6 | 7 | # Filter out any options not beginning with `autofirma-nix` 8 | 9 | transformOptions = option: option // { 10 | visible = option.visible && 11 | builtins.length option.loc > 1 && 12 | builtins.elem (builtins.elemAt option.loc 1) [ "autofirma" "dnieremote" "configuradorfnmt" ]; 13 | }; 14 | }; 15 | 16 | nixos = makeOptionsDoc 17 | (lib.nixosSystem { 18 | inherit (pkgs) system; 19 | modules = [ 20 | inputs.home-manager.nixosModules.home-manager 21 | inputs.self.nixosModules.default 22 | ]; 23 | }); 24 | 25 | homeManager = makeOptionsDoc 26 | (inputs.home-manager.lib.homeManagerConfiguration { 27 | inherit pkgs; 28 | modules = [ 29 | inputs.self.homeManagerModules.default 30 | { 31 | home = { 32 | homeDirectory = "/home/book"; 33 | stateVersion = "24.11"; 34 | username = "book"; 35 | }; 36 | } 37 | ]; 38 | }); 39 | 40 | in pkgs.stdenvNoCC.mkDerivation { 41 | name = "autofirma-nix-book"; 42 | src = ./.; 43 | 44 | patchPhase = '' 45 | cp ${../README.md} src/README.md 46 | 47 | # mdBook doesn't support this Markdown extension yet 48 | substituteInPlace **/*.md \ 49 | --replace-quiet '> [!NOTE]' '> **Note**' \ 50 | --replace-quiet '> [!TIP]' '> **Tip**' \ 51 | --replace-quiet '> [!IMPORTANT]' '> **Important**' \ 52 | --replace-quiet '> [!WARNING]' '> **Warning**' \ 53 | --replace-quiet '> [!CAUTION]' '> **Caution**' 54 | 55 | # The "declared by" links point to a file which only exists when the docs 56 | # are built locally. This removes the links. 57 | sed '/*Declared by:*/,/^$/d' <${nixos.optionsCommonMark} >>src/nixos_options.md 58 | sed '/*Declared by:*/,/^$/d' <${homeManager.optionsCommonMark} >>src/home_manager_options.md 59 | ''; 60 | 61 | buildPhase = '' 62 | ${pkgs.mdbook}/bin/mdbook build --dest-dir $out 63 | ''; 64 | } 65 | 66 | -------------------------------------------------------------------------------- /docs/src/SUMMARY.md: -------------------------------------------------------------------------------- 1 | [Introduction](./introduction.md) 2 | 3 | # User guide 4 | 5 | - [Installation](./installation.md) 6 | - [NixOS module](./installation_nixos_module.md) 7 | - [Home Manager with NixOS](./installation_home_manager_module.md) 8 | - [Home Manager standalone](./installation_home_manager_standalone.md) 9 | - [Security](./security.md) 10 | - [Troubleshooting](./troubleshooting.md) 11 | 12 | # Reference 13 | 14 | - [NixOS options](./nixos_options.md) 15 | - [Home Manager options](./home_manager_options.md) 16 | -------------------------------------------------------------------------------- /docs/src/home_manager_options.md: -------------------------------------------------------------------------------- 1 | # Home Manager options 2 | 3 | The following options can only be set in a Home Manager configuration. 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/src/how_to_contribute.md: -------------------------------------------------------------------------------- 1 | # How to Contribute 2 | -------------------------------------------------------------------------------- /docs/src/installation.md: -------------------------------------------------------------------------------- 1 | # Installation 2 | 3 | This project is distributed as a Nix flake that supports three integration paths: 4 | 5 | 1. **NixOS module** - For system-wide installation 6 | 2. **Home Manager module with NixOS** - For per-user installation when Home Manager is used as a NixOS module 7 | 3. **Home Manager standalone** - For per-user installation with standalone Home Manager 8 | 9 | ## Flake Input Setup 10 | 11 | For all installation methods, you'll need to add autofirma-nix to your flake inputs: 12 | 13 | ```nix 14 | { 15 | inputs = { 16 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 17 | 18 | # Only needed for Home Manager options 19 | home-manager = { 20 | url = "github:nix-community/home-manager"; 21 | inputs.nixpkgs.follows = "nixpkgs"; 22 | }; 23 | 24 | autofirma-nix = { 25 | url = "github:nix-community/autofirma-nix"; # For nixpkgs-unstable 26 | # url = "github:nix-community/autofirma-nix/release-25.05"; # For NixOS 25.05 27 | inputs.nixpkgs.follows = "nixpkgs"; 28 | }; 29 | }; 30 | 31 | nixConfig = { 32 | extra-substituters = [ 33 | "https://nix-community.cachix.org" 34 | ]; 35 | extra-trusted-public-keys = [ 36 | "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" 37 | ]; 38 | }; 39 | } 40 | ``` 41 | 42 | The binary cache configuration is strongly recommended to avoid unnecessary local compilation. 43 | -------------------------------------------------------------------------------- /docs/src/installation_home_manager_module.md: -------------------------------------------------------------------------------- 1 | # Home Manager with NixOS 2 | 3 | If you're using Home Manager as a NixOS module and want a per-user AutoFirma setup, this approach provides fine-grained configuration for each user. 4 | 5 | ## Quick Start with Template 6 | 7 | You can quickly get started with a fully configured template: 8 | 9 | ```bash 10 | $ nix flake new --template github:nix-community/autofirma-nix#home-manager-nixos ./my-autofirma-system-with-hm 11 | ``` 12 | 13 | This creates a new directory with a complete flake configuration for Home Manager as a NixOS module with all available options. 14 | 15 | ## Minimal Configuration 16 | 17 | First, make sure Home Manager is imported in your NixOS configuration: 18 | 19 | ```nix 20 | { 21 | imports = [ 22 | # Your other imports 23 | home-manager.nixosModules.home-manager 24 | ]; 25 | } 26 | ``` 27 | 28 | Then, configure AutoFirma for a specific user: 29 | 30 | ```nix 31 | { 32 | home-manager.users.yourUsername = { config, pkgs, ... }: { 33 | imports = [ 34 | autofirma-nix.homeManagerModules.default 35 | ]; 36 | 37 | # Enable AutoFirma with Firefox integration 38 | programs.autofirma = { 39 | enable = true; 40 | firefoxIntegration.profiles = { 41 | default = { 42 | enable = true; 43 | }; 44 | }; 45 | }; 46 | 47 | # DNIeRemote for using smartphone as DNIe reader 48 | programs.dnieremote = { 49 | enable = true; 50 | }; 51 | # Note: The Android app may not be available on Google Play for modern devices. 52 | # See the troubleshooting guide for installation alternatives. 53 | 54 | # FNMT certificate configurator 55 | programs.configuradorfnmt = { 56 | enable = true; 57 | firefoxIntegration.profiles = { 58 | default = { 59 | enable = true; 60 | }; 61 | }; 62 | }; 63 | 64 | # Configure Firefox 65 | programs.firefox = { 66 | enable = true; 67 | policies = { 68 | SecurityDevices = { 69 | "OpenSC PKCS11" = "${pkgs.opensc}/lib/opensc-pkcs11.so"; 70 | "DNIeRemote" = "${config.programs.dnieremote.finalPackage}/lib/libdnieremotepkcs11.so"; 71 | }; 72 | }; 73 | profiles.default = { 74 | id = 0; 75 | }; 76 | }; 77 | }; 78 | } 79 | ``` 80 | 81 | ## What This Does 82 | 83 | With this configuration: 84 | 85 | 1. AutoFirma is only available to the specified user(s) 86 | 2. Firefox integration is limited to specific Firefox profiles 87 | 3. DNIeRemote integration allows using your phone as an NFC card reader for your DNIe (see [troubleshooting](./troubleshooting.md#dnieremote-android-app-compatibility) for Android app installation) 88 | 4. The FNMT certificate configurator helps with requesting and managing digital certificates 89 | 5. Each user can have their own customized setup 90 | 6. Only users who need these tools will have them installed 91 | 92 | ## Rebuild and Apply 93 | 94 | After adding these changes, rebuild your NixOS configuration: 95 | 96 | ```bash 97 | sudo nixos-rebuild switch --flake .#yourHostname 98 | ``` 99 | -------------------------------------------------------------------------------- /docs/src/installation_home_manager_standalone.md: -------------------------------------------------------------------------------- 1 | # Home Manager Standalone 2 | 3 | If you're using Home Manager in standalone mode (not integrated with NixOS configuration), this approach lets you manage AutoFirma through your personal configuration. 4 | 5 | ## Quick Start with Template 6 | 7 | You can quickly get started with a fully configured template: 8 | 9 | ```bash 10 | $ nix flake new --template github:nix-community/autofirma-nix#home-manager-standalone ./my-autofirma-home 11 | ``` 12 | 13 | This creates a new directory with a complete flake configuration for standalone Home Manager with all available options. 14 | 15 | ## Minimal Configuration 16 | 17 | In your `flake.nix` for Home Manager: 18 | 19 | ```nix 20 | { 21 | outputs = { self, nixpkgs, home-manager, autofirma-nix, ... }: { 22 | homeConfigurations."yourUsername" = home-manager.lib.homeManagerConfiguration { 23 | pkgs = nixpkgs.legacyPackages.x86_64-linux; 24 | 25 | modules = [ 26 | autofirma-nix.homeManagerModules.default 27 | 28 | { 29 | # Adds AutoFirma to your personal Home Manager setup 30 | programs.autofirma = { 31 | enable = true; 32 | 33 | # Configures Firefox integration for your specific profile(s) 34 | firefoxIntegration.profiles = { 35 | default = { 36 | enable = true; 37 | }; 38 | }; 39 | }; 40 | 41 | # DNIeRemote for using smartphone as DNIe reader 42 | programs.dnieremote = { 43 | enable = true; 44 | }; 45 | # Note: The Android app may not be available on Google Play for modern devices. 46 | # See the troubleshooting guide for installation alternatives. 47 | 48 | # FNMT certificate configurator 49 | programs.configuradorfnmt = { 50 | enable = true; 51 | firefoxIntegration.profiles = { 52 | default = { 53 | enable = true; 54 | }; 55 | }; 56 | }; 57 | 58 | # Configure Firefox 59 | programs.firefox = { 60 | enable = true; 61 | policies = { 62 | SecurityDevices = { 63 | "OpenSC PKCS11" = "${pkgs.opensc}/lib/opensc-pkcs11.so"; 64 | "DNIeRemote" = "${config.programs.dnieremote.finalPackage}/lib/libdnieremotepkcs11.so"; 65 | }; 66 | }; 67 | profiles.default = { 68 | id = 0; 69 | }; 70 | }; 71 | } 72 | ]; 73 | }; 74 | }; 75 | } 76 | ``` 77 | 78 | ## What This Does 79 | 80 | This configuration: 81 | 82 | 1. Adds AutoFirma to your personal Home Manager setup 83 | 2. Configures Firefox integration for your specific profile(s) 84 | 3. DNIeRemote integration allows using your phone as an NFC card reader for your DNIe (see [troubleshooting](./troubleshooting.md#dnieremote-android-app-compatibility) for Android app installation) 85 | 4. The FNMT certificate configurator helps with requesting and managing digital certificates 86 | 5. Provides a complete environment for working with Spanish digital signatures 87 | 6. Preserves the flexibility of Home Manager's standalone mode 88 | 89 | ## Apply the Configuration 90 | 91 | After adding these changes, apply your Home Manager configuration: 92 | 93 | ```bash 94 | home-manager switch --flake .#yourUsername 95 | ``` 96 | -------------------------------------------------------------------------------- /docs/src/installation_nixos_module.md: -------------------------------------------------------------------------------- 1 | # NixOS Module Installation 2 | 3 | For system-wide installation where all users can access AutoFirma, DNIeRemote, and Configurador FNMT, the NixOS module is the most straightforward approach. 4 | 5 | ## Quick Start with Template 6 | 7 | You can quickly get started with a fully configured template: 8 | 9 | ```bash 10 | $ nix flake new --template github:nix-community/autofirma-nix#nixos-module ./my-autofirma-system 11 | ``` 12 | 13 | This creates a new directory with a complete flake configuration for NixOS with all available options. 14 | 15 | ## Minimal Configuration 16 | 17 | For your NixOS flake configuration: 18 | 19 | ```nix 20 | { 21 | nixosConfigurations.mysystem = nixpkgs.lib.nixosSystem { 22 | system = "x86_64-linux"; 23 | 24 | modules = [ 25 | autofirma-nix.nixosModules.default 26 | 27 | ({ config, pkgs, ... }: { 28 | # The autofirma command becomes available system-wide 29 | programs.autofirma = { 30 | enable = true; 31 | firefoxIntegration.enable = true; 32 | }; 33 | 34 | # DNIeRemote integration for using phone as NFC reader 35 | programs.dnieremote = { 36 | enable = true; 37 | }; 38 | # Note: The Android app may not be available on Google Play for modern devices. 39 | # See the troubleshooting guide for installation alternatives. 40 | 41 | # The FNMT certificate configurator 42 | programs.configuradorfnmt = { 43 | enable = true; 44 | firefoxIntegration.enable = true; 45 | }; 46 | 47 | # Firefox configured to work with AutoFirma 48 | programs.firefox = { 49 | enable = true; 50 | policies.SecurityDevices = { 51 | "OpenSC PKCS#11" = "${pkgs.opensc}/lib/opensc-pkcs11.so"; 52 | "DNIeRemote" = "${config.programs.dnieremote.finalPackage}/lib/libdnieremotepkcs11.so"; 53 | }; 54 | }; 55 | 56 | # Enable PC/SC smart card service 57 | services.pcscd.enable = true; 58 | }) 59 | ]; 60 | }; 61 | } 62 | ``` 63 | 64 | ## What This Does 65 | 66 | When you enable the NixOS module: 67 | 68 | 1. The `autofirma` command becomes available system-wide for signing documents 69 | 2. Firefox (if enabled through `programs.firefox.enable`) is configured to work with AutoFirma 70 | 3. DNIeRemote integration allows using your phone as an NFC card reader for your DNIe (see [troubleshooting](./troubleshooting.md#dnieremote-android-app-compatibility) for Android app installation) 71 | 4. The FNMT certificate configurator helps with requesting and managing digital certificates 72 | 73 | ## Rebuild and Apply 74 | 75 | After adding these changes, rebuild your NixOS configuration: 76 | 77 | ```bash 78 | sudo nixos-rebuild switch --flake .#yourHostname 79 | ``` -------------------------------------------------------------------------------- /docs/src/introduction.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | Welcome to **autofirma-nix**! This project provides a suite of tools to interact with Spain’s public administration, seamlessly integrating into your NixOS and Home Manager setup. It includes: 4 | 5 | - **AutoFirma** for digitally signing documents and authenticating on various Spanish administration websites—because ink and paper are so last century. 6 | - **DNIeRemote** for using an NFC-based national ID via an Android device—no more digging through drawers for that card reader you haven’t seen since 2010. 7 | - **Configurador FNMT-RCM** for securely requesting personal certificates from the Spanish Royal Mint—yes, the mint that makes actual coins. 8 | - Integration with **Mozilla Firefox** (provided on both the NixOS and the Home Manager modules) that allows Firefox to communicate with AutoFirma, as required by some sites—now with automatic setup! 9 | 10 | ## DNIeRemote Android App Compatibility 11 | 12 | ⚠️ **Important Note for DNIeRemote Users:** 13 | 14 | The DNIeSmartConnect Android app may not be available on Google Play for modern Android devices (Android 13 and later). However, the app can still be installed and used on these devices through alternative installation methods. 15 | 16 | For detailed instructions on how to install DNIeSmartConnect on modern Android devices, please see the [troubleshooting section](./troubleshooting.md#dnieremote-android-app-compatibility). 17 | -------------------------------------------------------------------------------- /docs/src/nixos_options.md: -------------------------------------------------------------------------------- 1 | # NixOS options 2 | 3 | The following options can only be set in a NixOS configuration. 4 | 5 | 6 | -------------------------------------------------------------------------------- /docs/src/security.md: -------------------------------------------------------------------------------- 1 | # Security 2 | 3 | AutoFirma chats with remote servers in a couple of different ways to handle document signing and authentication. Here’s the lowdown on these scenarios and how certificates fit into the bigger picture. 4 | 5 | ## Browser-based scenario 6 | 7 | In most cases, your friendly web browser takes care of the heavy lifting for server authentication: it connects to the remote server and confirms the server’s identity with its own certificate store. After that, the browser opens a WebSocket to AutoFirma, relaying commands back and forth. For this communication to work, a SSL certificate is created and added to Firefox; depending on the installation method you chose is located either in `/etc/AutoFirma` or in `$HOME/.afirma/AutoFirma`. 8 | 9 | ## Direct connection scenario 10 | 11 | Sometimes, the browser tells AutoFirma to talk directly to the remote server. In that case, AutoFirma itself must determine which Certificate Authorities (CAs) are valid. This is where certificate management in AutoFirma becomes important. 12 | 13 | ## Managing certificates in autofirma-nix 14 | 15 | AutoFirma trusts a certificate only if it meets two conditions: 16 | 17 | 1. **Official Provider** 18 | It must come from one of the providers published in the Spanish Government’s authorized list. 19 | 20 | 2. **System CA Store** 21 | It must also appear in your system’s *ca-bundle* (or *cacerts*) on NixOS. If your NixOS configuration blocks or adds a certificate, AutoFirma respects that setting. 22 | 23 | If a certificate is missing from the system CA store or explicitly blocked, AutoFirma will ignore it—even if it shows up on the official list. 24 | 25 | ### Relevant NixOS options 26 | 27 | - **`security.pki.certificateFiles`** 28 | Adds extra certificates to the global truststore. If a certificate is on the official list, and you include it here, AutoFirma will trust it. 29 | 30 | - **`security.pki.caCertificateBlacklist`** 31 | Blocks specific certificates. Even if one is on the official list, AutoFirma ignores it if it appears here. 32 | 33 | #### Minimal example 34 | 35 | ```nix 36 | { 37 | security.pki = { 38 | certificateFiles = [ 39 | ./my-certificate.crt 40 | ]; 41 | caCertificateBlacklist = [ 42 | "Izenpe.com" 43 | ]; 44 | }; 45 | programs.autofirma.enable = true; 46 | } 47 | ``` 48 | 49 | In this snippet, if `./my-certificate.crt` is on the official list, AutoFirma will trust it, while any certificate from `Izenpe.com` is blacklisted, no matter what. 50 | 51 | -------------------------------------------------------------------------------- /docs/src/troubleshooting.md: -------------------------------------------------------------------------------- 1 | # Troubleshooting 2 | 3 | Encountering issues? Here are some tips to get you back on track: 4 | 5 | ## Security devices do not seem to update or do not appear 6 | 7 | If you have installed AutoFirma and enabled Firefox integration, but Firefox does not 8 | detect the security devices, you may need to remove the `pkcs11.txt` file from the 9 | Firefox profile folder. For instance, if you enabled the Home Manager module and the 10 | profile is named `myprofile`, the file is located in `~/.mozilla/firefox/myprofile/pkcs11.txt`. 11 | 12 | Removing it and restarting Firefox should solve the issue: 13 | 14 | ```console 15 | $ rm ~/.mozilla/firefox/myprofile/pkcs11.txt 16 | $ firefox 17 | ``` 18 | 19 | ## Missing certificates even though the DNIe PIN was requested 20 | 21 | If OpenSC PKCS#11 prompts you for a password but no certificates are available for 22 | signing, you might see something like the following in the Autofirma logs (when 23 | running it from a terminal): 24 | 25 | ```console 26 | $ autofirma 27 | ... 28 | INFO: El almacen externo 'OpenSC PKCS#11' ha podido inicializarse, se anadiran sus entradas y se detiene la carga del resto de almacenes 29 | ... 30 | INFO: Se ocultara el certificado por no estar vigente: java.security.cert.CertificateExpiredException: NotAfter: Sat Oct 26 15:03:27 GMT 2024 31 | ... 32 | INFO: Se ocultara el certificado por no estar vigente: java.security.cert.CertificateExpiredException: NotAfter: Sat Oct 26 15:03:27 GMT 2024 33 | ... 34 | SEVERE: Se genero un error en el dialogo de seleccion de certificados: java.lang.reflect.InvocationTargetException 35 | .... 36 | SEVERE: El almacen no contiene ningun certificado que se pueda usar para firmar: es.gob.afirma.keystores.AOCertificatesNotFoundException: No se han encontrado certificados validos en el almacen 37 | ``` 38 | 39 | This occurs because your certificates have expired, as indicated by the “NotAfter:” date. 40 | 41 | If the certificates are not expired because you recently renewed them, but you used 42 | AutoFirma before this renewal, it is possible that OpenSC has cached your old certificates. 43 | To fix this, you need to delete the OpenSC cache. [By default, it is located at 44 | $HOME/.cache/opensc](https://github.com/OpenSC/OpenSC/wiki/Environment-variables). 45 | 46 | ```console 47 | $ rm -rf $HOME/.cache/opensc 48 | ``` 49 | 50 | ## DNIeRemote Android App Compatibility 51 | 52 | The DNIeSmartConnect Android app may not be available on Google Play for modern Android devices (Android 13 and later). This is because the app has not been updated to meet current Google Play requirements. However, the app itself still works on modern Android devices and can be installed using alternative methods. 53 | 54 | ### Installation Options 55 | 56 | #### Option A: Install via APK from APKCombo 57 | 58 | 1. **Allow installation from unknown sources** 59 | - Android 9+ (Pie and newer): `Settings` > `Apps & notifications` > `Special app access` > `Install unknown apps` > select the app (Chrome, your file manager, etc.) > Enable "Allow from this source". 60 | 61 | 2. **Download the APK with APKCombo** 62 | - Visit: https://apkcombo.com/playstore-downloader/ 63 | - Package name: `es.gob.fnmt.dniesmartconnect` 64 | - APKCombo fetches the APK securely from Play servers. 65 | 66 | 3. **Install the APK** 67 | - Open the downloaded APK and follow the prompts. 68 | 69 | 4. **Post-install** 70 | - Grant necessary permissions and test the DNIeRemote integration with the PC side. 71 | 72 | #### Option B: Install on a compatible device and transfer the APK 73 | 74 | 1. **On a compatible Android device, install from Google Play** 75 | - Search for "DNIeSmartConnect" on Google Play Store and install the app. 76 | 77 | 2. **Transfer/export the APK to your target device** 78 | - Use a backup/transfer method (e.g., USB, Bluetooth, cloud storage, or an APK extractor/backup tool) to get the APK file from the compatible device to your target device. 79 | 80 | 3. **Install on the target device** 81 | - Ensure unknown sources are allowed for the installer (as described in Option A, Step 1), then install the APK from the transferred location. 82 | 83 | 4. **Post-install** 84 | - Grant permissions and verify that DNIeRemote works with your PC. 85 | 86 | ### Security Verification 87 | 88 | To verify the legitimacy of any downloaded APK, use `apksigner verify --print-certs your-app.apk`. Authenticate that the APK's signing certificate matches the official one from Google Play (CNP-FNMT). This confirms that your download is the genuine, untampered DNIeSmartConnect app. 89 | 90 | ### Additional Resources 91 | 92 | For more detailed instructions and background information, see this blog post: [Como instalar DNIeRemote en Android 13 o posterior](https://www.jasoft.org/Blog/post/como-instalar-dnieremote-en-android-13-o-posterior) 93 | 94 | -------------------------------------------------------------------------------- /fixed-output-derivations.lock: -------------------------------------------------------------------------------- 1 | { 2 | "autofirma.clienteafirma.dependencies.jmulticard": { 3 | "hash": "sha256-qI6gYbGKTQ4Q4tV8NI37TSd3eQTyHHgndUGS943UvNU=" 4 | }, 5 | "autofirma.clienteafirma.dependencies.clienteafirma-external": { 6 | "hash": "sha256-N2lFeRM/eu/tMFTCQRYSHYrbXNgbAv49S7qTaUmb2+Q=" 7 | }, 8 | "autofirma.clienteafirma": { 9 | "hash": "sha256-jaiDhXT346+0zWlD1J9xhwDpjQca9DSpBmNgF+VKaJs=", 10 | "dependencies": [ 11 | "autofirma.clienteafirma.dependencies.jmulticard", 12 | "autofirma.clienteafirma.dependencies.clienteafirma-external" 13 | ] 14 | } 15 | } -------------------------------------------------------------------------------- /nix/autofirma/create-autofirma-cert: -------------------------------------------------------------------------------- 1 | if [[ "$1" == '--verbose' ]]; then 2 | shift 3 | set -o verbose 4 | fi 5 | 6 | _autofirma_dir="$1" 7 | _autofirma_ca="${_autofirma_dir}/AutoFirma_ROOT.cer" 8 | _autofirma_pfx="${_autofirma_dir}/autofirma.pfx" 9 | _cert_days="3650" 10 | _cert_cn="AutoFirma ROOT" 11 | 12 | function _make_ca_config { 13 | cat <<-EOF > "${_temp_dir}/openssl.cnf" 14 | [ ca ] 15 | default_ca=CA_autofirma 16 | [ CA_autofirma ] 17 | dir=${_temp_dir} 18 | new_certs_dir=\$dir 19 | database=\$dir/index.txt 20 | serial=\$dir/serial 21 | crlnumber=\$dir/crlnumber 22 | default_days=${_cert_days} 23 | default_crl_days=30 24 | default_md=sha256 25 | preserve=no 26 | x509_extensions=usr_cert 27 | email_in_dn=no 28 | copy_extensions=copy 29 | [ policy_ca ] 30 | countryName=optional 31 | stateOrProvinceName=optional 32 | localityName=optional 33 | organizationName=optional 34 | organizationalUnitName=optional 35 | commonName=supplied 36 | emailAddress=optional 37 | [ req ] 38 | default_bits=4096 39 | x509_extensions=v3_ca 40 | distinguished_name=req_distinguished_name 41 | [ req_distinguished_name ] 42 | commonName_default=${_cert_cn} 43 | [ usr_cert ] 44 | basicConstraints=CA:FALSE 45 | subjectKeyIdentifier=hash 46 | authorityKeyIdentifier=keyid:always,issuer:always 47 | subjectAltName=IP:127.0.0.1 48 | [ v3_ca ] 49 | basicConstraints=critical,CA:TRUE 50 | subjectKeyIdentifier=hash 51 | authorityKeyIdentifier=keyid:always,issuer:always 52 | keyUsage=cRLSign,digitalSignature,keyCertSign,keyEncipherment,dataEncipherment 53 | extendedKeyUsage=serverAuth,clientAuth,anyExtendedKeyUsage 54 | EOF 55 | touch "${_temp_dir}/index.txt" 56 | echo "01" > "${_temp_dir}/crlnumber" 57 | } 58 | 59 | function do_init { 60 | mkdir -p "${_autofirma_dir}" 61 | _temp_dir="$(mktemp -d)" 62 | _ca="openssl ca -config ${_temp_dir}/openssl.cnf" 63 | _req="openssl req -config ${_temp_dir}/openssl.cnf" 64 | rm -f "${_autofirma_ca}" "${_autofirma_pfx}" 65 | _make_ca_config 66 | openssl rand -base64 48 > "${_temp_dir}/randomkey.txt" 67 | # Make local CA 68 | ${_req} -new -passout file:"${_temp_dir}/randomkey.txt" \ 69 | -keyout "${_temp_dir}/autofirma.key" \ 70 | -subj "/CN=${_cert_cn}" \ 71 | -out "${_temp_dir}/autofirma.csr" 72 | ${_ca} -batch -create_serial -notext -selfsign \ 73 | -extensions v3_ca \ 74 | -policy policy_ca \ 75 | -out "${_autofirma_ca}" \ 76 | -days ${_cert_days} \ 77 | -passin file:"${_temp_dir}/randomkey.txt" \ 78 | -keyfile "${_temp_dir}/autofirma.key" \ 79 | -infiles "${_temp_dir}/autofirma.csr" 80 | # Make user certificate and key 81 | ${_req} -new -passout file:"${_temp_dir}/randomkey.txt" \ 82 | -keyout "${_temp_dir}/user.key" \ 83 | -subj "/CN=127.0.0.1" \ 84 | -out "${_temp_dir}/user.csr" 85 | ${_ca} -batch -notext \ 86 | -extensions usr_cert \ 87 | -policy policy_ca \ 88 | -out "${_temp_dir}/user.cer" \ 89 | -cert "${_autofirma_ca}" \ 90 | -keyfile "${_temp_dir}/autofirma.key" \ 91 | -passin file:"${_temp_dir}/randomkey.txt" \ 92 | -infiles "${_temp_dir}/user.csr" 93 | # Make user pfx from certificate and key 94 | openssl pkcs12 -export -passin file:"${_temp_dir}/randomkey.txt" \ 95 | -inkey "${_temp_dir}/user.key" \ 96 | -certfile "${_autofirma_ca}" \ 97 | -in "${_temp_dir}/user.cer" \ 98 | -name "socketautofirma" \ 99 | -passout pass:654321 \ 100 | -out "${_autofirma_pfx}" 101 | rm -rf "${_temp_dir}" 102 | unset _ca _req _temp_dir 103 | } 104 | 105 | # If any required cert or key is missing rebuild it 106 | if [[ ! -r "${_autofirma_ca}" || ! -r "${_autofirma_pfx}" ]]; then 107 | do_init 108 | else 109 | true # Explicit success exit code 110 | fi 111 | -------------------------------------------------------------------------------- /nix/autofirma/dependencies/clienteafirma-external/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | stdenv, 4 | fetchFromGitHub, 5 | maven, 6 | pom-tools, 7 | rsync, 8 | src, 9 | maven-dependencies-hash ? "", 10 | }: let 11 | name = "clienteafirma-external"; 12 | 13 | clienteafirma-external-src = stdenv.mkDerivation { 14 | name = "${name}-src"; 15 | 16 | inherit src; 17 | 18 | nativeBuildInputs = [pom-tools]; 19 | 20 | dontBuild = true; 21 | 22 | patchPhase = '' 23 | find . -name '*.jar' -delete # just in case 24 | 25 | update-java-version "1.8" 26 | update-pkg-version "${src.rev}-autofirma-nix" 27 | update-dependency-version-by-groupId "es.gob.afirma.lib" "${src.rev}-autofirma-nix" 28 | reset-project-build-timestamp 29 | ''; 30 | 31 | installPhase = '' 32 | mkdir -p $out/ 33 | cp -R . $out/ 34 | ''; 35 | 36 | dontFixup = true; 37 | }; 38 | 39 | clienteafirma-external-dependencies = stdenv.mkDerivation { 40 | name = "${name}-dependencies"; 41 | 42 | src = clienteafirma-external-src; 43 | 44 | nativeBuildInputs = [ 45 | maven 46 | ]; 47 | 48 | buildPhase = '' 49 | runHook preBuild 50 | 51 | mkdir -p $out/.m2/repository 52 | 53 | mvn clean package dependency:go-offline -Dmaven.repo.local=$out/.m2/repository -DskipTests 54 | 55 | runHook postBuild 56 | ''; 57 | 58 | installPhase = '' 59 | runHook preInstall 60 | 61 | rm -rf $out/.m2/respository/es/gob/afirma/lib 62 | 63 | find $out -type f \( \ 64 | -name \*.lastUpdated \ 65 | -o -name resolver-status.properties \ 66 | -o -name _remote.repositories \) \ 67 | -delete 68 | 69 | runHook postInstall 70 | ''; 71 | 72 | dontFixup = true; 73 | outputHashAlgo = "sha256"; 74 | outputHashMode = "recursive"; 75 | outputHash = maven-dependencies-hash; 76 | }; 77 | in 78 | stdenv.mkDerivation { 79 | pname = "${name}-m2-repository"; 80 | version = src.rev; 81 | 82 | groupId = "es.gob.afirma.lib"; 83 | finalVersion = "${src.rev}-autofirma-nix"; 84 | 85 | src = clienteafirma-external-src; 86 | 87 | nativeBuildInputs = [ 88 | maven 89 | rsync 90 | pom-tools 91 | ]; 92 | 93 | buildPhase = '' 94 | cp -r ${clienteafirma-external-dependencies}/.m2 . && chmod -R u+w .m2 95 | 96 | mvn --offline package -Dmaven.repo.local=.m2/repository -DskipTests 97 | ''; 98 | 99 | installPhase = '' 100 | mkdir -p $out/.m2/repository/es/gob/afirma/lib 101 | 102 | rm -rf .m2/repository/es/gob/afirma/lib 103 | 104 | mvn --offline install -Dmaven.repo.local=.m2/repository -DskipTests 105 | 106 | rsync -av .m2/repository/es/gob/afirma/lib $out/.m2/repository/es/gob/afirma/ 107 | 108 | find $out -type f \( \ 109 | -name \*.lastUpdated \ 110 | -o -name resolver-status.properties \ 111 | -o -name _remote.repositories \) \ 112 | -delete 113 | ''; 114 | 115 | fixupPhase = '' 116 | cd $out/.m2/repository 117 | reset-maven-metadata-local-timestamp 118 | ''; 119 | 120 | meta = with lib; { 121 | description = "External libraries used by Cliente @firma"; 122 | homepage = "https://github.com/ctt-gob-es/clienteafirma-external"; 123 | license = with licenses; [gpl2Only eupl11]; 124 | maintainers = with maintainers; [nilp0inter]; 125 | platforms = platforms.linux; 126 | }; 127 | } 128 | -------------------------------------------------------------------------------- /nix/autofirma/dependencies/jmulticard/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | stdenv, 4 | fetchFromGitHub, 5 | maven, 6 | pom-tools, 7 | rsync, 8 | src, 9 | maven-dependencies-hash ? "", 10 | }: let 11 | name = "jmulticard"; 12 | 13 | jmulticard-src = stdenv.mkDerivation { 14 | name = "${name}-src"; 15 | 16 | inherit src; 17 | 18 | nativeBuildInputs = [ 19 | pom-tools 20 | ]; 21 | 22 | dontBuild = true; 23 | 24 | patchPhase = '' 25 | find . -name '*.jar' -delete # just in case 26 | 27 | update-java-version "1.8" 28 | update-pkg-version "${src.rev}-autofirma-nix" 29 | update-dependency-version-by-groupId "es.gob.afirma.jmulticard" "${src.rev}-autofirma-nix" 30 | reset-project-build-timestamp 31 | ''; 32 | 33 | installPhase = '' 34 | mkdir -p $out/ 35 | cp -R . $out/ 36 | ''; 37 | 38 | dontFixup = true; 39 | }; 40 | 41 | jmulticard-dependencies = stdenv.mkDerivation { 42 | name = "${name}-dependencies"; 43 | 44 | src = jmulticard-src; 45 | 46 | nativeBuildInputs = [ 47 | maven 48 | ]; 49 | 50 | buildPhase = '' 51 | runHook preBuild 52 | 53 | mkdir -p $out/.m2/repository 54 | 55 | mvn clean package dependency:go-offline -Dmaven.repo.local=$out/.m2/repository -DskipTests 56 | 57 | runHook postBuild 58 | ''; 59 | 60 | installPhase = '' 61 | runHook preInstall 62 | 63 | rm -rf $out/.m2/respository/es/gob/afirma/jmulticard 64 | 65 | find $out -type f \( \ 66 | -name \*.lastUpdated \ 67 | -o -name resolver-status.properties \ 68 | -o -name _remote.repositories \) \ 69 | -delete 70 | 71 | runHook postInstall 72 | ''; 73 | 74 | dontFixup = true; 75 | outputHashAlgo = "sha256"; 76 | outputHashMode = "recursive"; 77 | outputHash = maven-dependencies-hash; 78 | }; 79 | in 80 | stdenv.mkDerivation { 81 | pname = "${name}-m2-repository"; 82 | version = src.rev; 83 | 84 | groupId = "es.gob.afirma.jmulticard"; 85 | finalVersion = "${src.rev}-autofirma-nix"; 86 | 87 | src = jmulticard-src; 88 | 89 | nativeBuildInputs = [ 90 | rsync 91 | maven 92 | pom-tools 93 | ]; 94 | 95 | buildPhase = '' 96 | cp -r ${jmulticard-dependencies}/.m2 . && chmod -R u+w .m2 97 | 98 | mvn --offline package -Dmaven.repo.local=.m2/repository -DskipTests 99 | ''; 100 | 101 | installPhase = '' 102 | mkdir -p $out/.m2/repository/es/gob/afirma/jmulticard 103 | 104 | rm -rf .m2/repository/es/gob/afirma/jmulticard 105 | 106 | mvn --offline install -Dmaven.repo.local=.m2/repository -DskipTests 107 | 108 | rsync -av .m2/repository/es/gob/afirma/jmulticard $out/.m2/repository/es/gob/afirma/ 109 | 110 | find $out -type f \( \ 111 | -name \*.lastUpdated \ 112 | -o -name resolver-status.properties \ 113 | -o -name _remote.repositories \) \ 114 | -delete 115 | ''; 116 | 117 | fixupPhase = '' 118 | cd $out/.m2/repository 119 | reset-maven-metadata-local-timestamp 120 | ''; 121 | 122 | meta = with lib; { 123 | description = "Capa abstracta de acceso a tarjetas inteligentes 100% java"; 124 | homepage = "https://github.com/ctt-gob-es/jmulticard"; 125 | license = with licenses; [gpl2Only eupl11]; 126 | maintainers = with maintainers; [nilp0inter]; 127 | platforms = platforms.linux; 128 | }; 129 | } 130 | -------------------------------------------------------------------------------- /nix/autofirma/module.nix: -------------------------------------------------------------------------------- 1 | inputs: { 2 | pkgs, 3 | config, 4 | lib, 5 | ... 6 | }: 7 | with lib; let 8 | cfg = config.programs.autofirma; 9 | inherit (pkgs.stdenv.hostPlatform) system; 10 | create-autofirma-cert = pkgs.writeShellApplication { 11 | name = "create-autofirma-cert"; 12 | runtimeInputs = with pkgs; [ openssl ]; 13 | text = builtins.readFile ./create-autofirma-cert; 14 | }; 15 | in { 16 | options.programs.autofirma.truststore = { 17 | package = mkPackageOption inputs.self.packages.${system} "autofirma-truststore" {}; 18 | finalPackage = mkOption { 19 | type = types.package; 20 | readOnly = true; 21 | default = cfg.truststore.package.override { caBundle = config.environment.etc."ssl/certs/ca-certificates.crt".source; }; 22 | defaultText = 23 | literalExpression 24 | "`programs.autofirma.truststore.package` with applied configuration"; 25 | description = '' 26 | The AutoFirma truststore package after applying configuration. 27 | ''; 28 | }; 29 | }; 30 | 31 | options.programs.autofirma = { 32 | enable = mkEnableOption "AutoFirma"; 33 | fixJavaCerts = mkEnableOption "Fix Java certificates"; 34 | package = mkPackageOption inputs.self.packages.${system} "autofirma" {}; 35 | finalPackage = mkOption { 36 | type = types.package; 37 | readOnly = true; 38 | default = cfg.package.override { 39 | autofirma-truststore = cfg.truststore.finalPackage; 40 | firefox = config.programs.firefox.package; 41 | }; 42 | defaultText = 43 | literalExpression 44 | "`programs.autofirma.package` with applied configuration"; 45 | description = '' 46 | The AutoFirma package after applying configuration. 47 | ''; 48 | }; 49 | firefoxIntegration.enable = mkEnableOption "Firefox integration"; 50 | }; 51 | 52 | config.environment.systemPackages = mkIf cfg.enable (lib.warnIf cfg.fixJavaCerts "The option `programs.autofirma.fixJavaCerts` is deprecated." [ 53 | cfg.finalPackage 54 | ]); 55 | 56 | config.programs = mkIf cfg.enable { 57 | firefox = mkIf cfg.firefoxIntegration.enable { 58 | autoConfigFiles = lib.mkAfter [ 59 | "${cfg.finalPackage}/etc/firefox/pref/AutoFirma.js" 60 | ]; 61 | policies.Certificates.ImportEnterpriseRoots = true; 62 | policies.Certificates.Install = [ "/etc/AutoFirma/AutoFirma_ROOT.cer" ]; 63 | }; 64 | }; 65 | 66 | config.systemd.services = mkIf (cfg.enable && cfg.firefoxIntegration.enable) { 67 | create-autofirma-cert = { 68 | enable = true; 69 | description = "Create certificate for AutoFirma and browser communication"; 70 | wants = [ "display-manager.service" ]; 71 | serviceConfig = { 72 | Type = "oneshot"; 73 | ExecStart = "${lib.getExe create-autofirma-cert} /etc/AutoFirma"; 74 | RemainAfterExit = true; 75 | }; 76 | wantedBy = [ "multi-user.target" ]; 77 | }; 78 | }; 79 | 80 | } 81 | -------------------------------------------------------------------------------- /nix/autofirma/patches/clienteafirma/aarch64_elf.patch: -------------------------------------------------------------------------------- 1 | diff --git a/afirma-keystores-mozilla/src/main/java/es/gob/afirma/keystores/mozilla/bintutil/ElfParser.java b/afirma-keystores-mozilla/src/main/java/es/gob/afirma/keystores/mozilla/bintutil/ElfParser.java 2 | index ae1f04d97..897b662d9 100644 3 | --- a/afirma-keystores-mozilla/src/main/java/es/gob/afirma/keystores/mozilla/bintutil/ElfParser.java 4 | +++ b/afirma-keystores-mozilla/src/main/java/es/gob/afirma/keystores/mozilla/bintutil/ElfParser.java 5 | @@ -139,8 +139,10 @@ public final class ElfParser { 6 | return false; 7 | } 8 | return "64".equals(Platform.getJavaArch()) && //$NON-NLS-1$ 9 | - Platform.MACHINE.AMD64.equals(Platform.getMachineType()) && 10 | + (Platform.MACHINE.AMD64.equals(Platform.getMachineType()) && 11 | ElfMachineType.AMD64.equals(a) || 12 | + Platform.MACHINE.ARM64.equals(Platform.getMachineType()) && 13 | + ElfMachineType.ARM64.equals(a)) || 14 | "32".equals(Platform.getJavaArch()) && //$NON-NLS-1$ 15 | (Platform.MACHINE.X86.equals(Platform.getMachineType()) || Platform.MACHINE.AMD64.equals(Platform.getMachineType())) && // 32 puede estar en maquina de 32 o de 64 bits 16 | ElfMachineType.X86.equals(a); 17 | -------------------------------------------------------------------------------- /nix/autofirma/patches/clienteafirma/certutilpath.patch: -------------------------------------------------------------------------------- 1 | diff --git a/afirma-ui-simple-configurator/src/main/java/es/gob/afirma/standalone/configurator/ConfiguratorFirefoxLinux.java b/afirma-ui-simple-configurator/src/main/java/es/gob/afirma/standalone/configurator/ConfiguratorFirefoxLinux.java 2 | index 05aa49a81..194996a48 100644 3 | --- a/afirma-ui-simple-configurator/src/main/java/es/gob/afirma/standalone/configurator/ConfiguratorFirefoxLinux.java 4 | +++ b/afirma-ui-simple-configurator/src/main/java/es/gob/afirma/standalone/configurator/ConfiguratorFirefoxLinux.java 5 | @@ -33,8 +33,8 @@ final class ConfiguratorFirefoxLinux { 6 | private static final Logger LOGGER = Logger.getLogger("es.gob.afirma"); //$NON-NLS-1$ 7 | 8 | private static final String FILE_AUTOFIRMA_CERTIFICATE = "AutoFirma_ROOT.cer"; //$NON-NLS-1$ 9 | - private static final String CERTUTIL_EXE = "certutil"; //$NON-NLS-1$ 10 | - private static final String CERTUTIL_RELATIVE_PATH = "certutil" + File.separator + CERTUTIL_EXE; //$NON-NLS-1$ 11 | + private static final String CERTUTIL_EXE = "@certutilpath"; //$NON-NLS-1$ 12 | + private static final String CERTUTIL_RELATIVE_PATH = "certutil" + File.separator + "certutil"; //$NON-NLS-1$ 13 | 14 | private static final String PROFILES_INI_RELATIVE_PATH = ".mozilla/firefox/profiles.ini";//$NON-NLS-1$ 15 | private static final String PROFILES_INI_RELATIVE_PATH_UBUNTU_22 = "snap/firefox/common/.mozilla/firefox/profiles.ini"; //$NON-NLS-1$ 16 | -------------------------------------------------------------------------------- /nix/autofirma/patches/clienteafirma/dark_mode_fix.patch: -------------------------------------------------------------------------------- 1 | diff --git a/afirma-simple/src/main/java/es/gob/afirma/standalone/ui/SignPanel.java b/afirma-simple/src/main/java/es/gob/afirma/standalone/ui/SignPanel.java 2 | index 0326b64ae..fc5f0bb33 100644 3 | --- a/afirma-simple/src/main/java/es/gob/afirma/standalone/ui/SignPanel.java 4 | +++ b/afirma-simple/src/main/java/es/gob/afirma/standalone/ui/SignPanel.java 5 | @@ -856,7 +856,6 @@ public final class SignPanel extends JPanel implements LoadDataFileListener, Sig 6 | setBackground(LookAndFeelManager.DEFAULT_COLOR); 7 | introPanel.setBackground(LookAndFeelManager.DEFAULT_COLOR); 8 | selectPanel.setBackground(LookAndFeelManager.DEFAULT_COLOR); 9 | - welcomeLabel.setForeground(new Color(3399)); 10 | } 11 | 12 | } 13 | diff --git a/afirma-ui-core-jse-keystores/src/main/java/es/gob/afirma/ui/core/jse/certificateselection/CertificateSelectionPanel.java b/afirma-ui-core-jse-keystores/src/main/java/es/gob/afirma/ui/core/jse/certificateselection/CertificateSelectionPanel.java 14 | index 2fefc5b66..ba7ffe688 100644 15 | --- a/afirma-ui-core-jse-keystores/src/main/java/es/gob/afirma/ui/core/jse/certificateselection/CertificateSelectionPanel.java 16 | +++ b/afirma-ui-core-jse-keystores/src/main/java/es/gob/afirma/ui/core/jse/certificateselection/CertificateSelectionPanel.java 17 | @@ -151,7 +151,6 @@ final class CertificateSelectionPanel extends JPanel implements ListSelectionLis 18 | 19 | if (!CertificateSelectionPanel.highContrast) { 20 | try { 21 | - mainMessage.setForeground(Color.decode("0x0033BC")); //$NON-NLS-1$ 22 | windowColor = UIManager.getColor("window") != null ? //$NON-NLS-1$ 23 | new Color(UIManager.getColor("window").getRGB()) : //$NON-NLS-1$ 24 | Color.WHITE; 25 | -------------------------------------------------------------------------------- /nix/autofirma/patches/clienteafirma/detect_java_version.patch: -------------------------------------------------------------------------------- 1 | diff --git a/afirma-core/src/main/java/es/gob/afirma/core/misc/AOUtil.java b/afirma-core/src/main/java/es/gob/afirma/core/misc/AOUtil.java 2 | index b0d25e2e9..91a57ae18 100644 3 | --- a/afirma-core/src/main/java/es/gob/afirma/core/misc/AOUtil.java 4 | +++ b/afirma-core/src/main/java/es/gob/afirma/core/misc/AOUtil.java 5 | @@ -495,7 +495,7 @@ public final class AOUtil { 6 | return false; 7 | } 8 | try { 9 | - if (Integer.parseInt(ver.substring(0, 1)) > 8) { 10 | + if (isOnlyNumber(ver) && Integer.parseInt(ver) > 8) { 11 | return true; 12 | } 13 | // En el nuevo esquema de versionado de Java se sigue el patron [1-9][0-9]*((\.0)*\.[1-9][0-9]*)*, 14 | -------------------------------------------------------------------------------- /nix/autofirma/patches/clienteafirma/dont_check_java_version.patch: -------------------------------------------------------------------------------- 1 | diff --git a/afirma-simple/src/main/java/es/gob/afirma/standalone/SimpleAfirma.java b/afirma-simple/src/main/java/es/gob/afirma/standalone/SimpleAfirma.java 2 | index 22b2cd997..3e52d8a07 100644 3 | --- a/afirma-simple/src/main/java/es/gob/afirma/standalone/SimpleAfirma.java 4 | +++ b/afirma-simple/src/main/java/es/gob/afirma/standalone/SimpleAfirma.java 5 | @@ -1021,7 +1021,6 @@ public final class SimpleAfirma implements PropertyChangeListener, WindowListene 6 | LOGGER.info("Iniciando entorno grafico"); //$NON-NLS-1$ 7 | saf.initGUI(null); 8 | 9 | - checkJavaVersion(saf.getMainFrame()); 10 | } else { 11 | LOGGER.log(Level.WARNING, "La aplicacion ya se encuentra activa en otra ventana. Se cerrara esta instancia"); //$NON-NLS-1$ 12 | AOUIFactory.showErrorMessage(SimpleAfirmaMessages.getString("SimpleAfirma.3"), //$NON-NLS-1$ 13 | -------------------------------------------------------------------------------- /nix/autofirma/patches/clienteafirma/etc_config.patch: -------------------------------------------------------------------------------- 1 | diff --git a/afirma-simple/src/main/java/es/gob/afirma/standalone/protocol/SecureSocketUtils.java b/afirma-simple/src/main/java/es/gob/afirma/standalone/protocol/SecureSocketUtils.java 2 | index 4485c27aa..6e96cb830 100644 3 | --- a/afirma-simple/src/main/java/es/gob/afirma/standalone/protocol/SecureSocketUtils.java 4 | +++ b/afirma-simple/src/main/java/es/gob/afirma/standalone/protocol/SecureSocketUtils.java 5 | @@ -65,7 +65,8 @@ class SecureSocketUtils { 6 | * @return Almacén de claves o {@code null} si no se encontró. */ 7 | private static File getKeyStoreFile() { 8 | 9 | - File appDir = AutoFirmaUtil.getApplicationDirectory(); 10 | + // Check first in /etc for the KeyStoreFile 11 | + File appDir = new File("/etc/AutoFirma"); 12 | 13 | if (appDir != null && new File(appDir, KEYSTORE_NAME).exists() 14 | && new File(appDir, CA_ROOT_NAME).exists()) { 15 | -------------------------------------------------------------------------------- /nix/autofirma/patches/clienteafirma/pr-367.patch: -------------------------------------------------------------------------------- 1 | diff --git a/afirma-keystores-mozilla/src/main/java/es/gob/afirma/keystores/mozilla/MozillaKeyStoreUtilitiesUnix.java b/afirma-keystores-mozilla/src/main/java/es/gob/afirma/keystores/mozilla/MozillaKeyStoreUtilitiesUnix.java 2 | index 0342d2423..aa80f52b4 100644 3 | --- a/afirma-keystores-mozilla/src/main/java/es/gob/afirma/keystores/mozilla/MozillaKeyStoreUtilitiesUnix.java 4 | +++ b/afirma-keystores-mozilla/src/main/java/es/gob/afirma/keystores/mozilla/MozillaKeyStoreUtilitiesUnix.java 5 | @@ -154,27 +154,32 @@ final class MozillaKeyStoreUtilitiesUnix { 6 | 7 | // Tomamos lo numeros de version de firefox identificados 8 | final List firefoxVersions = new ArrayList<>(); 9 | - for (final String filename : directoryLib.list()) { 10 | - if (filename.startsWith("firefox-")) { //$NON-NLS-1$ 11 | - firefoxVersions.add(filename.replace("firefox-", "")); //$NON-NLS-1$ //$NON-NLS-2$ 12 | + final String[] fileList = directoryLib.list(); 13 | + if (fileList != null) { 14 | + for (final String filename : fileList) { 15 | + if (filename.startsWith("firefox-")) { //$NON-NLS-1$ 16 | + firefoxVersions.add(filename.replace("firefox-", "")); //$NON-NLS-1$ //$NON-NLS-2$ 17 | + } 18 | } 19 | - } 20 | 21 | - // Calculamos el numero de version mayor 22 | - for (final String versionText : firefoxVersions) { 23 | - Version version; 24 | - try { 25 | - version = new Version(versionText); 26 | - } 27 | - catch (final Exception e) { 28 | - LOGGER.warning( 29 | - "Se encontro un numero de version de Firefox no soportado (" + versionText + "): " + e //$NON-NLS-1$ //$NON-NLS-2$ 30 | - ); 31 | - continue; 32 | - } 33 | - if (maxVersion == null || version.compareTo(maxVersion) > 0) { 34 | - maxVersion = version; 35 | + // Calculamos el numero de version mayor 36 | + for (final String versionText : firefoxVersions) { 37 | + Version version; 38 | + try { 39 | + version = new Version(versionText); 40 | + } 41 | + catch (final Exception e) { 42 | + LOGGER.warning( 43 | + "Se encontro un numero de version de Firefox no soportado (" + versionText + "): " + e //$NON-NLS-1$ //$NON-NLS-2$ 44 | + ); 45 | + continue; 46 | + } 47 | + if (maxVersion == null || version.compareTo(maxVersion) > 0) { 48 | + maxVersion = version; 49 | + } 50 | } 51 | + } else { 52 | + LOGGER.warning("No se pudo listar el directorio " + directoryLib.getAbsolutePath()); 53 | } 54 | } 55 | return maxVersion != null ? maxVersion.toString() : null; 56 | -------------------------------------------------------------------------------- /nix/autofirma/truststore/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | openssl, 4 | stdenv, 5 | jre, 6 | writeShellScript, 7 | runCommand, 8 | cacert, 9 | caBundle ? null, 10 | govTrustedCerts ? [], # Trust no one. The trust is out there. 11 | storepass ? "autofirma", 12 | }: let 13 | finalCABundle = if caBundle == null then "${cacert}/etc/ssl/certs/ca-bundle.crt" else caBundle; 14 | add-cert-to-truststore = cert: let 15 | cif = lib.attrsets.attrByPath ["meta" "trusted" "provider" "cif"] "unknown-cif" cert; 16 | url = lib.attrsets.attrByPath ["meta" "trusted" "cert" "url"] "unknown-url" cert; 17 | alias = "${cif}-${url}"; 18 | in 19 | writeShellScript "add-cert-to-truststore" '' 20 | ${openssl}/bin/openssl verify -CAfile ${finalCABundle} ${cert} && exec ${jre}/bin/keytool -importcert -noprompt -alias "${alias}" -keystore "$1" -storepass ${storepass} -file ${cert} || echo "Invalid cert or not present in ca-bundle." 21 | ''; 22 | to-pem-file = cert: 23 | runCommand "${cert.name}.pem" {} '' 24 | echo >> $out 25 | echo "NAME: ${lib.attrsets.attrByPath ["meta" "trusted" "provider" "name"] "unknown-name" cert}" >> $out 26 | echo "CIF: ${lib.attrsets.attrByPath ["meta" "trusted" "provider" "cif"] "unknown-cif" cert}" >> $out 27 | echo "URL: ${lib.attrsets.attrByPath ["meta" "trusted" "cert" "url"] "unknown-url" cert}" >> $out 28 | ${lib.getExe openssl} x509 -in ${cert} -out - >> $out 29 | ''; 30 | in 31 | stdenv.mkDerivation { 32 | name = "autofirma-truststore"; 33 | srcs = builtins.map add-cert-to-truststore govTrustedCerts; 34 | phases = ["buildPhase"]; 35 | buildPhase = '' 36 | for addValidatedCertToTruststore in $srcs; do 37 | $addValidatedCertToTruststore $out 38 | done 39 | ''; 40 | passthru = { 41 | inherit govTrustedCerts; 42 | pemBundle = stdenv.mkDerivation { 43 | name = "autofirma-truststore-bundle.pem"; 44 | srcs = builtins.map to-pem-file govTrustedCerts; 45 | phases = ["installPhase"]; 46 | installPhase = '' 47 | for _src in $srcs; do 48 | ${openssl}/bin/openssl verify -CAfile ${finalCABundle} $_src && cat $_src >> $out || echo "Invalid cert in $_src, skipping." 49 | done 50 | ''; 51 | }; 52 | }; 53 | } 54 | -------------------------------------------------------------------------------- /nix/autofirma/truststore/prestadores/CAs-by-provider/A01337260.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"cif": "A01337260", "hash": "sha256-HlCRd4dDDwPL9ARHoN8k1znCTkYIpDFiL4OZMIsK6Cs=", "url": "https://www.izenpe.eus/contenidos/informacion/cas_izenpe/es_cas/adjuntos/IZENPE_ROOT_NQC.crt"}, 3 | {"cif": "A01337260", "hash": "sha256-jluLrtxNWL4OMBzMtu0XPAjXx3zkNQlzOJ/xr6EdemU=", "url": "https://www.izenpe.eus/contenidos/informacion/cas_izenpe/es_cas/adjuntos/IZENPE_ROOT_QC.crt"}, 4 | {"cif": "A01337260", "hash": "sha256-JTDMjpgyFQK62W+bH7obCZ4tKZ4PRUi7kU82O8DUUx8=", "url": "https://www.izenpe.eus/contenidos/informacion/cas_izenpe/es_cas/adjuntos/RAIZ2007_cert_sha256.crt"}, 5 | {"cif": "A01337260", "hash": "sha256-q8gNDHG8tUBSmvUZw0ywEsZaYcWnvsoYTZBAuvXnnvQ=", "url": "https://www.izenpe.eus/contenidos/informacion/cas_izenpe/es_cas/adjuntos/izenpe_root_ssl_2024.crt"} 6 | ] 7 | -------------------------------------------------------------------------------- /nix/autofirma/truststore/prestadores/CAs-by-provider/A40573396.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"cif": "A40573396", "hash": "sha256-/gpljigppo6MmFE4u3tCYbVfX/Oh7ay0i19ajZJ+opQ=", "url": "https://www.accv.es/fileadmin/Archivos/certificados/ACCVRAIZ1.crt"}, 3 | {"cif": "A40573396", "hash": "sha256-8aoOxmJwW7KXtDf2fqnkZQ7FvF6VZ1eqfwTX2ZRUceM=", "url": "https://www.accv.es/fileadmin/Archivos/certificados/accv_root_ecc_eidas_2023.crt"}, 4 | {"cif": "A40573396", "hash": "sha256-rMrf6ruG3fp/K6Euo4UruQs809w5tYNkwy3ooqvQbLw=", "url": "https://www.accv.es/fileadmin/Archivos/certificados/accv_root_ecc_eidas_tsa_2024.crt"}, 5 | {"cif": "A40573396", "hash": "sha256-ec1VRVKWrftVzfDb6RdphaC1A8VEJ2xakwXy7JtmaTo=", "url": "https://www.accv.es/fileadmin/Archivos/certificados/accv_root_ecc_tls_2024.crt"}, 6 | {"cif": "A40573396", "hash": "sha256-Wnaes9nWqXcL3Bv0EmMr012tab3yTunNddK2WbSg3ck=", "url": "https://www.accv.es/fileadmin/Archivos/certificados/accv_root_rsa_eidas_2023.crt"}, 7 | {"cif": "A40573396", "hash": "sha256-Y8MIDMi/Y8lMdBpw2u9StSdKz+CD64zsKRMeogk4jCU=", "url": "https://www.accv.es/fileadmin/Archivos/certificados/accv_root_rsa_eidas_tsa_2024.crt"}, 8 | {"cif": "A40573396", "hash": "sha256-tAv6iICgL5MCVkPG27053xlKKFTQduFnor2EZ8+eLDQ=", "url": "https://www.accv.es/fileadmin/Archivos/certificados/accv_root_rsa_tls_2024.crt"}, 9 | {"cif": "A40573396", "hash": "sha256-VGBy9f7Rp/dCazxDct3bb51Mos04Y5F66ZkNJRBhKDA=", "url": "https://www.accv.es/fileadmin/Archivos/certificados/rootca.crt"} 10 | ] 11 | -------------------------------------------------------------------------------- /nix/autofirma/truststore/prestadores/CAs-by-provider/A62634068.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"cif": "A62634068", "hash": "sha256-V94Fg+/Ssm4DYdqZ2p30ZI3vfuhEHDtyivqbzeD5smo=", "url": "https://crl.firmaprofesional.com/caroot.crt"}, 3 | {"cif": "A62634068", "hash": "sha256-BASAKL8fKGTUj5rU2DKUNmqCiFZVPzsUMD+QFH9dQO8=", "url": "https://crl.firmaprofesional.com/caroot_sha1.crt"}, 4 | {"cif": "A62634068", "hash": "sha256-5xoeM2uZt3fqjrffyVwrSLfic2Zxt8mSPBSuNCZhan8=", "url": "https://crl.firmaprofesional.com/fprootprivate2020.crt"} 5 | ] 6 | -------------------------------------------------------------------------------- /nix/autofirma/truststore/prestadores/CAs-by-provider/A82733262.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"cif": "A82733262", "hash": "sha256-TIy4l/7V/864eWzf73DB00BE8sUIXoXefOnIZ5iiniw=", "url": "https://psc.sia.es/ac_raiz.crt"}, 3 | {"cif": "A82733262", "hash": "sha256-IIGYh8BGniUXx2RhhBiPxCIbzJ2YtEBfE+imE6/nyuk=", "url": "https://psc.sia.es/ac_raiz_2020.crt"} 4 | ] 5 | -------------------------------------------------------------------------------- /nix/autofirma/truststore/prestadores/CAs-by-provider/B85626240.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"cif": "B85626240", "hash": "sha256-TUAE2LKThbt3gS6KIqnrUCbuNl6EbtfluYO95i9NF/8=", "url": "https://ca.eadtrust.eu/eadtrust-root-ecc256eaddvov2019.crt"}, 3 | {"cif": "B85626240", "hash": "sha256-gqp4VszKI91qTaO5g/FFkw247bKXpBkmgIKjUGKVXoo=", "url": "https://ca.eadtrust.eu/eadtrust-root-ecc256eadevpsd22019.crt"}, 4 | {"cif": "B85626240", "hash": "sha256-boVGLARWGtlIZyP+H1NZYFmG91iSa0UJ992GzyctwU4=", "url": "https://ca.eadtrust.eu/eadtrust-root-ecc256eadq2019.crt"}, 5 | {"cif": "B85626240", "hash": "sha256-itabzRM9aP8RNbTX77q/FfH3hN60J+kI6L3LSoNXjCI=", "url": "https://ca.eadtrust.eu/eadtrust-root-ecc384eaddvov2019.crt"}, 6 | {"cif": "B85626240", "hash": "sha256-xujB+8qgXcxyDre/2DXc50EIiLZD+t3eZFVtzE9pfso=", "url": "https://ca.eadtrust.eu/eadtrust-root-ecc384eadevpsd22019.crt"}, 7 | {"cif": "B85626240", "hash": "sha256-y+lniislM4Jn8aO9w7RshB0WSR84z/QmUjeD1szOjSw=", "url": "https://ca.eadtrust.eu/eadtrust-root-ecc384eadq2019.crt"}, 8 | {"cif": "B85626240", "hash": "sha256-L20TXFaOvafE51bvhw0HmDoyr2PQaeXcPaJrxAL8KQg=", "url": "https://ca.eadtrust.eu/eadtrust-root-rsa2048eadnq2019.crt"}, 9 | {"cif": "B85626240", "hash": "sha256-xUAF325oM2PEQC0AhfjbgeH+oityYZ2rK6HD493D9FU=", "url": "https://ca.eadtrust.eu/eadtrust-root-rsa2048eadq2019.crt"}, 10 | {"cif": "B85626240", "hash": "sha256-MfJNS4PRJtur5L9grbaRL9mnqqMFu8MMh0np/ENDRXs=", "url": "https://ca.eadtrust.eu/eadtrust-root-rsa4096eaddvov2019.crt"}, 11 | {"cif": "B85626240", "hash": "sha256-LzeuJB84ZMLsAjEMyH1NZ0rw7GU9JJsIl+5bcRb3Qdk=", "url": "https://ca.eadtrust.eu/eadtrust-root-rsa4096eadevpsd22019.crt"}, 12 | {"cif": "B85626240", "hash": "sha256-7L40XHWLt/Tx/92mQrd65WEo9Qh4PeAns4PY3tGeZ6s=", "url": "https://ca.eadtrust.eu/eadtrust-root-rsa4096eadq2019.crt"}, 13 | {"cif": "B85626240", "hash": "sha256-OGzsrVWWmWmfE4nfN5/yLTrVr0PfFM/b66chiztinKQ=", "url": "https://ca.eadtrust.eu/eadtrust-root-rsa8192eaddvov2019.crt"}, 14 | {"cif": "B85626240", "hash": "sha256-FilcQsaV5goNVX7orokwuHKL86SUnb9xeEjuZaQDAZA=", "url": "https://ca.eadtrust.eu/eadtrust-root-rsa8192eadevpsd22019.crt"}, 15 | {"cif": "B85626240", "hash": "sha256-eDk34YpXm1Y3fWS46Ow+CLQENQHeChVZofRx7UiIPqw=", "url": "https://ca.eadtrust.eu/eadtrust-root-rsa8192eadq2019.crt"} 16 | ] 17 | -------------------------------------------------------------------------------- /nix/autofirma/truststore/prestadores/CAs-by-provider/B87341228.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"cif": "B87341228", "hash": "sha256-4yaPYQa6i2ZaGpYt3qFFnSpGly8fJEAymzkLiVdJrUU=", "url": "https://anf.es/certificates_download/ANF_Global_Root_CA_2033.cer"}, 3 | {"cif": "B87341228", "hash": "sha256-4K+9LA7pWmjNmjxZCy0/4HwKbQvnlq5SkeQk1HeSF44=", "url": "https://anf.es/certificates_download/ANF_Global_Root_CA_SHA256_2036.cer"}, 4 | {"cif": "B87341228", "hash": "sha256-NpIAZZ8DJ5aq+es5o2glqjAgctn+QytFuJhalCHvPHU=", "url": "https://anf.es/certificates_download/ANF_Server_CA_2010.cer"}, 5 | {"cif": "B87341228", "hash": "sha256-+4/sdZFpuRBrHlEWRMYYxRMENz9sBkMIjYvv/RuZdZk=", "url": "https://www.anf.es/certificates-download/ANFSecureServerRootCA.cer"}, 6 | {"cif": "B87341228", "hash": "sha256-VEGU2dht7UxvLvGApmV6o6AnXX1uO0203XaxcPOk2nA=", "url": "https://www.anf.es/certificates_download/ANF_Secure_Server_Root_CA_SHA25.cer"}, 7 | {"cif": "B87341228", "hash": "sha256-cdlBNsYP9XRujZMjJ6mu1b5qMfQsf1WwWjdPm29NJyc=", "url": "https://www.anf.es/certificates_download/ANF_Server_CA_2015.cer"} 8 | ] 9 | -------------------------------------------------------------------------------- /nix/autofirma/truststore/prestadores/CAs-by-provider/G63287510.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"cif": "G63287510", "hash": "sha256-LP/QaC3INUyGGzvoLEpTonRoSBktLX/FbTPjvnopEAU=", "url": "https://crl.anf.es/certificates-download/ANFACEcuadorRootCA.cer"}, 3 | {"cif": "G63287510", "hash": "sha256-+NhqlreyFcWoeJaXJkEE0pa0W1x5y0FY7pOhUOFNyaQ=", "url": "https://crl.anf.es/certificates-download/ANFACSLRootCA.cer"}, 4 | {"cif": "G63287510", "hash": "sha256-ZyMom5UtgGXqhIO2p8M0TvTfcaRs0bcla9jzDNE2eOk=", "url": "https://crl.anf.es/certificates-download/ANFACUruguayTestRootCA.cer"}, 5 | {"cif": "G63287510", "hash": "sha256-DzYdiyWBI+qbuE3T8sghwChUeWJuEYXhLxoEuFVG5Fk=", "url": "https://crl.anf.es/certificates-download/ANFHighAssuranceEcuadorRootCA.cer"}, 6 | {"cif": "G63287510", "hash": "sha256-+4/sdZFpuRBrHlEWRMYYxRMENz9sBkMIjYvv/RuZdZk=", "url": "https://crl.anf.es/certificates-download/ANFSecureServerRootCA.cer"}, 7 | {"cif": "G63287510", "hash": "sha256-4K+9LA7pWmjNmjxZCy0/4HwKbQvnlq5SkeQk1HeSF44=", "url": "https://crl.anf.es/certificates-download/ANF_Global_Root_CA_SHA256_2036.cer"} 8 | ] 9 | -------------------------------------------------------------------------------- /nix/autofirma/truststore/prestadores/CAs-by-provider/Q2826004J.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"cif": "Q2826004J", "hash": "sha256-lWmUjKEh08eh0HvR3X4dSOp6Wx7j5+lVfAbDuLKMAj4=", "url": "https://www.sede.fnmt.gob.es/documents/10445900/10526749/AC_RAIZ_FNMT_RCM_TSA.cer"}, 3 | {"cif": "Q2826004J", "hash": "sha256-VUFTsT0s+d23U7++Gk4K4I0KpBhwWP5gorhisuS4e8s=", "url": "https://www.sede.fnmt.gob.es/documents/10445900/10526749/AC_Raiz_FNMT-RCM-SS.cer"}, 4 | {"cif": "Q2826004J", "hash": "sha256-vTzoQ4eTGakHoSpOsU+uhUsIOQTm3Ahn9xgFJcoimb4=", "url": "https://www.sede.fnmt.gob.es/documents/10445900/10526749/AC_Raiz_FNMT-RCM_G2.cer"}, 5 | {"cif": "Q2826004J", "hash": "sha256-68VXDCkBjE1nsaoSe68S9wO0YR68F7fatVc4lBebk/o=", "url": "https://www.sede.fnmt.gob.es/documents/10445900/10526749/AC_Raiz_FNMT-RCM_SHA256.cer"} 6 | ] 7 | -------------------------------------------------------------------------------- /nix/autofirma/truststore/prestadores/CAs-by-provider/S2816015H.json: -------------------------------------------------------------------------------- 1 | [ 2 | {"cif": "S2816015H", "curlOptsList": ["--tls13-ciphers", "TLS_AES_256_GCM_SHA384"], "hash": "sha256-wqsaf94krHI0vEdmRNOlS8ugK8pfe9CBFVgXorSX5ts=", "url": "https://www.policia.es/certs/AC_Raiz_DGP-SHA2.cer"}, 3 | {"cif": "S2816015H", "curlOptsList": ["--tls13-ciphers", "TLS_AES_256_GCM_SHA384"], "hash": "sha256-ztLM2UJO25WYdY9PW0fMBv0zvKl/kCYadnPBzx753N8=", "url": "https://www.policia.es/certs/AC_Raiz_DGP2-SHA2.cer"} 4 | ] 5 | -------------------------------------------------------------------------------- /nix/autofirma/truststore/prestadores/CAs_fetch_links.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "url": "https://www.accv.es/servicios/empresas/descarga-de-certificados-jerarquia/", 4 | "cif": "A40573396" 5 | }, 6 | { 7 | "url": "https://www.sede.fnmt.gob.es/descargas/certificados-raiz-de-la-fnmt", 8 | "cif": "Q2826004J" 9 | }, 10 | { 11 | "url": "https://crl.anf.es/", 12 | "cif": "G63287510" 13 | }, 14 | { 15 | "url": "https://www.anf.ac/certificados-ca-raiz/", 16 | "cif": "B87341228" 17 | }, 18 | { 19 | "url": "https://www.policia.es/_es/certificados_digitales.php", 20 | "cif": "S2816015H", 21 | "curlOptsList": [ 22 | "--tls13-ciphers", 23 | "TLS_AES_256_GCM_SHA384" 24 | ] 25 | }, 26 | { 27 | "url": "https://eadtrust.eu/en/documents-in-force/", 28 | "cif": "B85626240" 29 | }, 30 | { 31 | "url": "https://crl.firmaprofesional.com/", 32 | "cif": "A62634068" 33 | }, 34 | { 35 | "url": "https://psc.sia.es/", 36 | "cif": "A82733262" 37 | }, 38 | { 39 | "url": "https://www.izenpe.eus/descarga-de-certificados/webize01-cndoctecnica/es/", 40 | "cif": "A01337260" 41 | } 42 | ] 43 | -------------------------------------------------------------------------------- /nix/autofirma/truststore/prestadores/default.nix: -------------------------------------------------------------------------------- 1 | {fetchurl}: let 2 | trusted-providers = builtins.fromJSON (builtins.readFile ./providers.json); 3 | read-provider-certs = provider: map (cert: {inherit provider cert;}) (builtins.fromJSON (builtins.readFile ./CAs-by-provider/${provider.cif}.json)); 4 | fetch-ca = trusted: 5 | fetchurl { 6 | url = trusted.cert.url; 7 | sha256 = trusted.cert.hash; 8 | curlOptsList = trusted.cert.curlOptsList or []; 9 | meta = {inherit trusted;}; 10 | }; 11 | in 12 | map fetch-ca (builtins.concatMap read-provider-certs trusted-providers) 13 | -------------------------------------------------------------------------------- /nix/autofirma/truststore/prestadores/providers.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "name": "ANF AUTORIDAD DE CERTIFICACIÓN ASOCIACIÓN (ANF AC)", 4 | "cif": "G63287510", 5 | "website": "www.anf.es", 6 | "source": "Registro Nacional de Asociaciones con el nº 171443 de la Sección 1ª" 7 | }, 8 | { 9 | "name": "ANF CERTIFICATION AUTHORITY SL", 10 | "cif": "B87341228", 11 | "website": "https://www.anf.ac/", 12 | "source": "Registro Mercantil de Madrid Tomo 33744, Hoja M-607340, Folio 155" 13 | }, 14 | { 15 | "name": "Dirección General de la Policía", 16 | "cif": "S2816015H", 17 | "website": "www.dnielectronico.es/", 18 | "source": "Órgano de la Administración del Estado. Sus competencias vienen atribuidas por la Constitución Española de 1978 y por Ley Orgánica 2/1986, de 13 de marzo, de Fuerzas y Cuerpos de Seguridad." 19 | }, 20 | { 21 | "name": "EADTrust European Agency of Digital Trust, S.L.", 22 | "cif": "B85626240", 23 | "website": "https://eadtrust.eu", 24 | "source": "Registro Mercantil de Madrid: Tomo 26.403, Folio 63, Hoja M-475828 Insc: 1" 25 | }, 26 | { 27 | "name": "Firmaprofesional, S.A.", 28 | "cif": "A62634068", 29 | "website": "www.firmaprofesional.com", 30 | "source": "Registro Mercantil de Barcelona, Tomo 33996, Folio 152, Hoja B240292, Num. Insc. 2" 31 | }, 32 | { 33 | "name": "Fábrica Nacional de Moneda y Timbre - Real Casa de la Moneda, Entidad Pública Empresarial, Medio Propio (FNMT-RCM)", 34 | "cif": "Q2826004J", 35 | "website": "www.cert.fnmt.es", 36 | "source": "Las competencias de la FNMT-RCM quedan definidas por el Real Decreto 1317/2001 de 30 de noviembre, por el que se desarrolla el artículo 81 de la Ley 66/1999" 37 | }, 38 | { 39 | "name": "Infraestructuras y Servicios de Telecomunicaciones y Certificación S.A.", 40 | "cif": "A40573396", 41 | "website": "www.accv.es", 42 | "source": "Registro Mercantil de Valencia. Sección 8. Hoja 189461." 43 | }, 44 | { 45 | "name": "SISTEMAS INFORMATICOS ABIERTOS, S.A.U.", 46 | "cif": "A82733262", 47 | "website": "https://psc.sia.es", 48 | "source": "Registro Mercantil de Madrid Tomo:15741 Folio:28 sección 8 Hoja: M-265398 N.Inscrip.: 1" 49 | }, 50 | { 51 | "name": "Ziurtapen eta Zerbitzu Enpresa - Empresa de Certificación y Servicios, Izenpe, S.A.", 52 | "cif": "A01337260", 53 | "website": "www.izenpe.eus", 54 | "source": "Registro Mercantil de Álava, Tomo 1055, Libro 0, Folio 62, Sección 8, Hoja VI-8926, Inscripción: 1." 55 | } 56 | ] 57 | -------------------------------------------------------------------------------- /nix/configuradorfnmt/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | stdenv, 4 | fetchurl, 5 | dpkg, 6 | temurin-jre-bin-23, 7 | runtimeShell, 8 | buildFHSEnv, 9 | makeDesktopItem, 10 | }: let 11 | pname = "configuradorfnmt"; 12 | version = "5.0.2"; 13 | meta = with lib; { 14 | description = "Application to request the necessary keys for obtaining a digital certificate from the FNMT."; 15 | homepage = "https://www.sede.fnmt.gob.es/descargas/descarga-software/instalacion-software-generacion-de-claves"; 16 | license = with licenses; []; # TODO 17 | maintainers = with maintainers; [nilp0inter]; 18 | mainProgram = "configuradorfnmt"; 19 | platforms = platforms.linux; 20 | }; 21 | thisPkg = stdenv.mkDerivation { 22 | inherit meta; 23 | name = "configuradorfnmt-pkg"; 24 | version = version; 25 | 26 | src = fetchurl { 27 | url = "https://descargas.cert.fnmt.es/Linux/${pname}_${version}.amd64.deb"; 28 | hash = "sha256-+j/Fj5JwRtPozZLzZkc1RX1J9vRqDymIq/CzwLQjraY="; 29 | }; 30 | 31 | buildInputs = [ 32 | dpkg 33 | ]; 34 | 35 | unpackCmd = "dpkg-deb -x $src ."; 36 | 37 | installPhase = '' 38 | runHook preInstall 39 | mkdir -p $out/lib/configuradorfnmt $out/share 40 | cp -r share/doc $out/share 41 | cp lib/configuradorfnmt/*.* $out/lib/configuradorfnmt 42 | runHook postInstall 43 | ''; 44 | 45 | postInstall = '' 46 | mkdir -p $out/bin 47 | cat > $out/bin/configuradorfnmt < $out/etc/firefox/pref/configuradorfnmt.js < $out/bin/dnieremotewizard <<'EOF' 28 | #!${pkgs.stdenv.shell} 29 | export XAUTHORITY=$HOME/.Xauthority 30 | export HOME=/etc/dnieRemote 31 | EOF 32 | cat >> $out/bin/dnieremotewizard <\n"; 11 | echo "\n"; 12 | echo "\n"; 13 | echo " \n"; 14 | echo " \n"; 15 | echo " Test Page\n"; 16 | echo "\n"; 17 | echo "\n"; 18 | 19 | // Always load autoscript.js. 20 | echo " \n"; 21 | echo " \n"; 22 | 23 | echo "\n"; 24 | echo "\n"; 25 | 26 | exit; 27 | } 28 | 29 | // Handle POST request. 30 | if ($_SERVER['REQUEST_METHOD'] === 'POST') { 31 | // Get the "test_output" parameter from the form data. 32 | $testOutput = isset($_POST['test_output']) ? $_POST['test_output'] : ''; 33 | 34 | // Write the data to the output file. 35 | if (file_put_contents($outputFile, $testOutput . "\n") === false) { 36 | echo "Failed to write to $testFile"; 37 | exit; 38 | } 39 | 40 | // Respond to the client. 41 | echo "Data has been saved successfully."; 42 | exit; 43 | } 44 | 45 | // Handle other request methods. 46 | http_response_code(405); // Method Not Allowed 47 | header("Allow: GET, POST"); 48 | echo "Unsupported request method."; 49 | exit; 50 | -------------------------------------------------------------------------------- /nix/tests/hm-as-nixos-module/autofirma/cli/sign-document.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager, lib }: 2 | let 3 | openssl = lib.getExe pkgs.openssl; 4 | in 5 | 6 | pkgs.nixosTest { 7 | name = "test-hm-as-nixos-module-autofirma-firefoxIntegration-sign-document"; 8 | nodes.machine = { config, pkgs, modulesPath, ... }: { 9 | imports = [ 10 | home-manager.nixosModules.home-manager 11 | (modulesPath + "./../tests/common/x11.nix") 12 | ../../../_common/hm-as-nixos-module/autofirma-user.nix 13 | ]; 14 | 15 | home-manager.users.autofirma-user = { 16 | imports = [ 17 | self.homeManagerModules.autofirma 18 | ]; 19 | programs.autofirma.enable = true; 20 | }; 21 | 22 | system.stateVersion = "${lib.versions.major lib.version}.${lib.versions.minor lib.version}"; 23 | }; 24 | 25 | testScript = '' 26 | def user_cmd(cmd): 27 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 28 | 29 | machine.wait_for_x() 30 | 31 | machine.succeed(user_cmd('echo "NixOS AutoFirma Sign Test" > document.txt')) 32 | machine.succeed(user_cmd('${openssl} req -x509 -newkey rsa:2048 -keyout private.key -out certificate.crt -days 365 -nodes -subj "/C=ES/O=TEST AUTOFIRMA NIX/OU=DNIE/CN=AC DNIE 004" -passout pass:1234')) 33 | machine.succeed(user_cmd('${openssl} pkcs12 -export -out certificate.p12 -inkey private.key -in certificate.crt -name "testcert" -password pass:1234')) 34 | 35 | machine.succeed(user_cmd('autofirma sign -store pkcs12:certificate.p12 -i document.txt -o document.txt.sign -filter alias.contains=testcert -password 1234 -xml')) 36 | ''; 37 | } 38 | -------------------------------------------------------------------------------- /nix/tests/hm-as-nixos-module/autofirma/config/omitAskOnClose.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager }: 2 | pkgs.nixosTest { 3 | name = "test-hm-as-nixos-module-autofirma-config-omitAskOnClose"; 4 | nodes.machine = { config, pkgs, modulesPath, ... }: { 5 | imports = [ 6 | home-manager.nixosModules.home-manager 7 | (modulesPath + "./../tests/common/x11.nix") 8 | ../../../_common/hm-as-nixos-module/autofirma-user.nix 9 | ]; 10 | 11 | home-manager.users.autofirma-user = {config, ... }: { 12 | imports = [ 13 | self.homeManagerModules.autofirma 14 | ]; 15 | 16 | programs.autofirma.enable = true; 17 | programs.autofirma.config.omitAskOnClose = true; 18 | }; 19 | }; 20 | 21 | testScript = '' 22 | def user_cmd(cmd): 23 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 24 | 25 | machine.wait_for_unit("default.target") 26 | machine.wait_for_x() 27 | 28 | machine.execute(user_cmd("autofirma >&2 &")) 29 | 30 | machine.wait_for_window('AutoFirma\s.*', 30) 31 | machine.sleep(5) 32 | machine.send_key("alt-f4") 33 | machine.wait_until_succeeds(user_cmd('[ ! $(pgrep -x java) ]'), 30) 34 | ''; 35 | } 36 | 37 | 38 | -------------------------------------------------------------------------------- /nix/tests/hm-as-nixos-module/autofirma/firefoxIntegration/connection-method/auxiliary-servers/default.nix: -------------------------------------------------------------------------------- 1 | import ../build-connection-method-test.nix { 2 | testName = "test-hm-as-nixos-module-autofirma-firefoxIntegration-connection-method-auxiliary-servers"; 3 | jsTestFile = ./test.js; 4 | } 5 | -------------------------------------------------------------------------------- /nix/tests/hm-as-nixos-module/autofirma/firefoxIntegration/connection-method/auxiliary-servers/test.js: -------------------------------------------------------------------------------- 1 | // JavaScript implementation for TestAutoFirma using provided signing services 2 | 3 | (function() { 4 | function initializeMiniApplet(storageUrl, retrieverUrl) { 5 | console.log(`Initializing MiniApplet with ${storageUrl} and ${retrieverUrl}`); 6 | MiniApplet.setServlets(storageUrl, retrieverUrl); 7 | MiniApplet.setForceWSMode(true); 8 | MiniApplet.cargarAppAfirma(); 9 | } 10 | 11 | function generateSignature(data, onSuccess, onError) { 12 | try { 13 | MiniApplet.sign(data, "SHA256withRSA", "CAdES", "headless=true", onSuccess, onError); 14 | } catch (error) { 15 | onError("Exception", error.message); 16 | } 17 | } 18 | 19 | function sendResultToServer(message) { 20 | const formData = new FormData(); 21 | formData.append("test_output", message); 22 | 23 | fetch("/test.php", { 24 | method: "POST", 25 | body: formData 26 | }).then(response => { 27 | if (response.ok) { 28 | console.log("Result sent successfully."); 29 | } else { 30 | console.error("Failed to send result to server."); 31 | } 32 | }).catch(error => { 33 | console.error("Error sending result to server:", error); 34 | }); 35 | } 36 | 37 | function handleSignatureResult(message) { 38 | console.log(`Signature Successful: ${message}`); 39 | sendResultToServer(`Signature Successful: ${message}`); 40 | } 41 | 42 | function handleError(errorType, errorMessage) { 43 | console.error(`Error (${errorType}): ${errorMessage}`); 44 | sendResultToServer(`Error (${errorType}): ${errorMessage}`); 45 | } 46 | 47 | function startSigningProcess() { 48 | const storageUrl = 'https://autofirma-nix.com/afirma-signature-storage/StorageService'; 49 | const retrieverUrl = 'https://autofirma-nix.com/afirma-signature-retriever/RetrieveService'; 50 | const dataToSign = btoa(document.documentElement.outerHTML); 51 | 52 | initializeMiniApplet(storageUrl, retrieverUrl); 53 | 54 | generateSignature( 55 | dataToSign, 56 | handleSignatureResult, 57 | handleError 58 | ); 59 | } 60 | 61 | // Automatically start the signing process on page load 62 | window.addEventListener('DOMContentLoaded', startSigningProcess); 63 | })(); 64 | 65 | -------------------------------------------------------------------------------- /nix/tests/hm-as-nixos-module/autofirma/firefoxIntegration/connection-method/build-connection-method-test.nix: -------------------------------------------------------------------------------- 1 | { testName, jsTestFile }: 2 | { self, pkgs, system, home-manager }: 3 | let 4 | testCerts = pkgs.callPackage ../../../../_common/pkgs/test_certs.nix {}; 5 | in 6 | pkgs.nixosTest { 7 | name = testName; 8 | nodes.machine = { config, pkgs, modulesPath, ... }: { 9 | imports = [ 10 | home-manager.nixosModules.home-manager 11 | (modulesPath + "./../tests/common/x11.nix") 12 | ../../../../_common/tests/autofirma_test_server 13 | ../../../../_common/hm-as-nixos-module/autofirma-user.nix 14 | ]; 15 | 16 | home-manager.users.autofirma-user = {config, osConfig, ... }: { 17 | imports = [ 18 | self.homeManagerModules.autofirma 19 | ]; 20 | 21 | programs.autofirma.enable = true; 22 | programs.autofirma.truststore.package = self.packages."${system}".autofirma-truststore.override (old: { 23 | caBundle = osConfig.environment.etc."ssl/certs/ca-certificates.crt".source; 24 | govTrustedCerts = old.govTrustedCerts ++ osConfig.security.pki.certificateFiles; 25 | }); 26 | programs.autofirma.firefoxIntegration.profiles.default.enable = true; 27 | 28 | programs.firefox.enable = true; 29 | programs.firefox.profiles.default.id = 0; 30 | # Allow Firefox to open AutoConfig settings without user interaction 31 | programs.firefox.profiles.default.settings."network.protocol-handler.expose.afirma" = true; 32 | }; 33 | 34 | environment.systemPackages = with pkgs; [ 35 | nss.tools 36 | ]; 37 | 38 | autofirma-test-server.jsTestFile = jsTestFile; 39 | }; 40 | 41 | testScript = '' 42 | def user_cmd(cmd): 43 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 44 | 45 | machine.wait_for_unit("default.target") 46 | machine.wait_for_x() 47 | 48 | machine.wait_for_open_port(port=443) 49 | 50 | profile_dir = "default" 51 | machine.execute(user_cmd("firefox >&2 &")) 52 | 53 | machine.wait_for_file(f"/home/autofirma-user/.mozilla/firefox/{profile_dir}/cert9.db") 54 | machine.wait_for_file(f"/home/autofirma-user/.mozilla/firefox/{profile_dir}/key4.db") 55 | machine.sleep(5) 56 | 57 | machine.succeed(user_cmd(f'pk12util -i ${testCerts}/ciudadano_scard_act.p12 -d sql:/home/autofirma-user/.mozilla/firefox/{profile_dir} -W ""')) 58 | machine.sleep(5) 59 | 60 | machine.succeed("rm -f /tmp/test_output.txt") 61 | 62 | # Open firefox and allow it to import AutoConfig settings 63 | machine.execute(user_cmd("firefox --new-tab https://autofirma-nix.com/index.php >&2 &")) 64 | 65 | machine.wait_for_file("/tmp/test_output.txt") 66 | machine.sleep(5) 67 | machine.succeed("grep 'Signature Successful:' /tmp/test_output.txt") 68 | 69 | ''; 70 | } 71 | 72 | -------------------------------------------------------------------------------- /nix/tests/hm-as-nixos-module/autofirma/firefoxIntegration/connection-method/websocket/default.nix: -------------------------------------------------------------------------------- 1 | import ../build-connection-method-test.nix { 2 | testName = "test-hm-as-nixos-module-autofirma-firefoxIntegration-connection-method-websocket"; 3 | jsTestFile = ./test.js; 4 | } 5 | -------------------------------------------------------------------------------- /nix/tests/hm-as-nixos-module/autofirma/firefoxIntegration/connection-method/websocket/test.js: -------------------------------------------------------------------------------- 1 | // JavaScript implementation for TestAutoFirma using provided signing services 2 | 3 | (function() { 4 | function initializeMiniApplet(storageUrl, retrieverUrl) { 5 | console.log(`Initializing MiniApplet with ${storageUrl} and ${retrieverUrl}`); 6 | MiniApplet.cargarAppAfirma(storageUrl); 7 | } 8 | 9 | function generateSignature(data, onSuccess, onError) { 10 | try { 11 | MiniApplet.sign(data, "SHA256withRSA", "CAdES", "headless=true", onSuccess, onError); 12 | } catch (error) { 13 | onError("Exception", error.message); 14 | } 15 | } 16 | 17 | function sendResultToServer(message) { 18 | const formData = new FormData(); 19 | formData.append("test_output", message); 20 | 21 | fetch("/test.php", { 22 | method: "POST", 23 | body: formData 24 | }).then(response => { 25 | if (response.ok) { 26 | console.log("Result sent successfully."); 27 | } else { 28 | console.error("Failed to send result to server."); 29 | } 30 | }).catch(error => { 31 | console.error("Error sending result to server:", error); 32 | }); 33 | } 34 | 35 | function handleSignatureResult(message) { 36 | console.log(`Signature Successful: ${message}`); 37 | sendResultToServer(`Signature Successful: ${message}`); 38 | } 39 | 40 | function handleError(errorType, errorMessage) { 41 | console.error(`Error (${errorType}): ${errorMessage}`); 42 | sendResultToServer(`Error (${errorType}): ${errorMessage}`); 43 | } 44 | 45 | function startSigningProcess() { 46 | const storageUrl = '/afirma-signature-storage'; 47 | const retrieverUrl = '/afirma-signature-retriever'; 48 | const dataToSign = btoa(document.documentElement.outerHTML); 49 | 50 | initializeMiniApplet(storageUrl, retrieverUrl); 51 | 52 | generateSignature( 53 | dataToSign, 54 | handleSignatureResult, 55 | handleError 56 | ); 57 | } 58 | 59 | // Automatically start the signing process on page load 60 | window.addEventListener('DOMContentLoaded', startSigningProcess); 61 | })(); 62 | -------------------------------------------------------------------------------- /nix/tests/hm-as-nixos-module/autofirma/firefoxIntegration/connection-method/xhr/default.nix: -------------------------------------------------------------------------------- 1 | import ../build-connection-method-test.nix { 2 | testName = "test-hm-as-nixos-module-autofirma-firefoxIntegration-connection-method-xhr"; 3 | jsTestFile = ./test.js; 4 | } 5 | -------------------------------------------------------------------------------- /nix/tests/hm-as-nixos-module/autofirma/firefoxIntegration/connection-method/xhr/test.js: -------------------------------------------------------------------------------- 1 | // JavaScript implementation for TestAutoFirma using provided signing services 2 | 3 | (function() { 4 | function initializeMiniApplet(storageUrl, retrieverUrl) { 5 | console.log(`Initializing MiniApplet with ${storageUrl} and ${retrieverUrl}`); 6 | MiniApplet.cargarAppAfirma(storageUrl); 7 | } 8 | 9 | function generateSignature(data, onSuccess, onError) { 10 | try { 11 | MiniApplet.sign(data, "SHA256withRSA", "CAdES", "headless=true", onSuccess, onError); 12 | } catch (error) { 13 | onError("Exception", error.message); 14 | } 15 | } 16 | 17 | function sendResultToServer(message) { 18 | const formData = new FormData(); 19 | formData.append("test_output", message); 20 | 21 | fetch("/test.php", { 22 | method: "POST", 23 | body: formData 24 | }).then(response => { 25 | if (response.ok) { 26 | console.log("Result sent successfully."); 27 | } else { 28 | console.error("Failed to send result to server."); 29 | } 30 | }).catch(error => { 31 | console.error("Error sending result to server:", error); 32 | }); 33 | } 34 | 35 | function handleSignatureResult(message) { 36 | console.log(`Signature Successful: ${message}`); 37 | sendResultToServer(`Signature Successful: ${message}`); 38 | } 39 | 40 | function handleError(errorType, errorMessage) { 41 | console.error(`Error (${errorType}): ${errorMessage}`); 42 | sendResultToServer(`Error (${errorType}): ${errorMessage}`); 43 | } 44 | 45 | function startSigningProcess() { 46 | const storageUrl = '/afirma-signature-storage'; 47 | const retrieverUrl = '/afirma-signature-retriever'; 48 | const dataToSign = btoa(document.documentElement.outerHTML); 49 | 50 | delete window.WebSocket; 51 | 52 | initializeMiniApplet(storageUrl, retrieverUrl); 53 | 54 | generateSignature( 55 | dataToSign, 56 | handleSignatureResult, 57 | handleError 58 | ); 59 | } 60 | 61 | // Automatically start the signing process on page load 62 | window.addEventListener('DOMContentLoaded', startSigningProcess); 63 | })(); 64 | -------------------------------------------------------------------------------- /nix/tests/hm-as-nixos-module/autofirma/firefoxIntegration/protocol-handler/default.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager, lib }: 2 | pkgs.nixosTest { 3 | name = "test-hm-as-nixos-module-autofirma-firefoxIntegration-protocol-handler"; 4 | nodes.machine = { config, pkgs, modulesPath, ... }: { 5 | imports = [ 6 | home-manager.nixosModules.home-manager 7 | (modulesPath + "./../tests/common/x11.nix") 8 | ../../../../_common/hm-as-nixos-module/autofirma-user.nix 9 | ]; 10 | 11 | home-manager.users.autofirma-user = {config, ... }: { 12 | imports = [ 13 | self.homeManagerModules.autofirma 14 | ]; 15 | programs.firefox.enable = true; 16 | programs.firefox.profiles.default.id = 0; 17 | programs.firefox.profiles.default.settings."network.protocol-handler.expose.afirma" = true; 18 | 19 | programs.autofirma.enable = true; 20 | programs.autofirma.firefoxIntegration.profiles.default.enable = true; 21 | 22 | home.packages = [ 23 | (pkgs.writeScriptBin "open-autofirma-via-firefox" '' 24 | cat <<'EOF' > /tmp/autofirma.html 25 | 26 | 27 | 28 | 29 | 30 |

Redirecting to autofirma...

31 | 32 | 33 | EOF 34 | 35 | ${lib.getExe config.programs.firefox.finalPackage} /tmp/autofirma.html 36 | '') 37 | ]; 38 | }; 39 | }; 40 | 41 | testScript = '' 42 | def user_cmd(cmd): 43 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 44 | 45 | machine.wait_for_unit("default.target") 46 | machine.wait_for_x() 47 | 48 | # Open firefox and allow it to import AutoConfig settings 49 | machine.execute(user_cmd("firefox >&2 &")) 50 | machine.wait_for_window("Mozilla Firefox") 51 | machine.sleep(5) 52 | 53 | # Open an afirma:// URL in Firefox 54 | machine.execute(user_cmd("open-autofirma-via-firefox")) 55 | 56 | # Wait for the AutoFirma window to appear 57 | machine.wait_for_window('Seleccione el fichero de datos a firmar', 30) 58 | machine.sleep(5) 59 | machine.screenshot("screen") 60 | ''; 61 | } 62 | -------------------------------------------------------------------------------- /nix/tests/hm-as-nixos-module/configuradorfnmt/firefoxIntegration/request-certificate.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager, lib }: 2 | pkgs.nixosTest { 3 | name = "test-hm-as-nixos-module-configuradorfnmt-firefoxIntegration-request-certificate"; 4 | nodes.machine = { config, pkgs, modulesPath, ... }: { 5 | imports = [ 6 | home-manager.nixosModules.home-manager 7 | (modulesPath + "./../tests/common/x11.nix") 8 | ../../../_common/hm-as-nixos-module/autofirma-user.nix 9 | ]; 10 | 11 | home-manager.users.autofirma-user = {config, ... }: { 12 | imports = [ 13 | self.homeManagerModules.configuradorfnmt 14 | ]; 15 | programs.firefox.enable = true; 16 | programs.firefox.profiles.default.id = 0; 17 | programs.firefox.profiles.default.settings."network.protocol-handler.expose.fnmtcr" = true; 18 | 19 | programs.configuradorfnmt.enable = true; 20 | programs.configuradorfnmt.firefoxIntegration.profiles.default.enable = true; 21 | 22 | home.packages = [ 23 | (pkgs.writeScriptBin "open-configuradorfnmt-via-firefox" '' 24 | cat <<'EOF' > /tmp/configuradorfnmt.html 25 | 26 | 27 | 28 | 29 | 30 |

Redirecting to configuradorfnmt...

31 | 32 | 33 | EOF 34 | 35 | ${lib.getExe config.programs.firefox.finalPackage} /tmp/configuradorfnmt.html 36 | '') 37 | ]; 38 | }; 39 | }; 40 | 41 | testScript = '' 42 | def user_cmd(cmd): 43 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 44 | 45 | machine.wait_for_unit("default.target") 46 | machine.wait_for_x() 47 | 48 | # Open firefox and allow it to import AutoConfig settings 49 | machine.execute(user_cmd("firefox >&2 &")) 50 | machine.wait_for_window("Mozilla Firefox") 51 | machine.sleep(5) 52 | 53 | # Open an fnmtcr:// URL in Firefox 54 | machine.execute(user_cmd("open-configuradorfnmt-via-firefox")) 55 | 56 | # Wait for the ConfiguradorFNMT-RCM window to appear 57 | machine.wait_for_window('Uso de tarjeta criptográfica inteligente', 30) 58 | machine.sleep(5) 59 | machine.screenshot("screen") 60 | ''; 61 | } 62 | 63 | -------------------------------------------------------------------------------- /nix/tests/hm-as-nixos-module/dnieremote/config/jumpintro-no.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager }: 2 | pkgs.nixosTest { 3 | name = "test-hm-as-nixos-module-dnieremote-config-jumpintro-no"; 4 | nodes.machine = { config, pkgs, modulesPath, ... }: { 5 | imports = [ 6 | home-manager.nixosModules.home-manager 7 | (modulesPath + "./../tests/common/x11.nix") 8 | ../../../_common/hm-as-nixos-module/autofirma-user.nix 9 | ]; 10 | 11 | home-manager.users.autofirma-user = {config, ... }: { 12 | imports = [ 13 | self.homeManagerModules.dnieremote 14 | ]; 15 | 16 | programs.dnieremote.enable = true; 17 | programs.dnieremote.jumpIntro = "no"; 18 | }; 19 | }; 20 | 21 | testScript = '' 22 | def user_cmd(cmd): 23 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 24 | 25 | machine.wait_for_unit("default.target") 26 | machine.wait_for_x() 27 | 28 | machine.execute(user_cmd("dnieremotewizard >&2 &")) 29 | 30 | # Wait for the wizard to start and present the introduction screen 31 | machine.wait_for_window('Introducción', 30) 32 | machine.sleep(5) 33 | machine.screenshot("screen") 34 | ''; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /nix/tests/hm-as-nixos-module/dnieremote/config/jumpintro-usb.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager}: 2 | pkgs.nixosTest { 3 | name = "test-hm-as-nixos-module-dnieremote-config-jumpintro-usb"; 4 | nodes.machine = { config, pkgs, modulesPath, ... }: { 5 | imports = [ 6 | home-manager.nixosModules.home-manager 7 | (modulesPath + "./../tests/common/x11.nix") 8 | ../../../_common/hm-as-nixos-module/autofirma-user.nix 9 | ]; 10 | 11 | home-manager.users.autofirma-user = {config, ... }: { 12 | imports = [ 13 | self.homeManagerModules.dnieremote 14 | ]; 15 | 16 | programs.dnieremote.enable = true; 17 | programs.dnieremote.jumpIntro = "usb"; 18 | }; 19 | }; 20 | 21 | testScript = '' 22 | def user_cmd(cmd): 23 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 24 | 25 | machine.wait_for_unit("default.target") 26 | machine.wait_for_x() 27 | 28 | machine.execute(user_cmd("dnieremotewizard >&2 &")) 29 | 30 | # Wait for the wizard to start and jump into the usb screen and fail due to no usb device 31 | machine.wait_for_window('Finalización', 30) 32 | machine.sleep(5) 33 | machine.screenshot("screen") 34 | ''; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /nix/tests/hm-as-nixos-module/dnieremote/config/jumpintro-wifi.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager}: 2 | pkgs.nixosTest { 3 | name = "test-hm-as-nixos-module-dnieremote-config-jumpintro-wifi"; 4 | nodes.machine = { config, pkgs, modulesPath, ... }: { 5 | imports = [ 6 | home-manager.nixosModules.home-manager 7 | (modulesPath + "./../tests/common/x11.nix") 8 | ../../../_common/hm-as-nixos-module/autofirma-user.nix 9 | ]; 10 | 11 | home-manager.users.autofirma-user = {config, ... }: { 12 | imports = [ 13 | self.homeManagerModules.dnieremote 14 | ]; 15 | 16 | programs.dnieremote.enable = true; 17 | programs.dnieremote.jumpIntro = "wifi"; 18 | }; 19 | }; 20 | 21 | testScript = '' 22 | def user_cmd(cmd): 23 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 24 | 25 | machine.wait_for_unit("default.target") 26 | machine.wait_for_x() 27 | 28 | machine.execute(user_cmd("dnieremotewizard >&2 &")) 29 | 30 | # Wait for the wizard to start and jump into the wifi screen 31 | machine.wait_for_window('Vinculación dispositivo y DNIe', 30) 32 | machine.sleep(5) 33 | machine.screenshot("screen") 34 | ''; 35 | } 36 | 37 | -------------------------------------------------------------------------------- /nix/tests/hm-as-nixos-module/dnieremote/config/wifiport.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager}: 2 | pkgs.nixosTest { 3 | name = "test-hm-as-nixos-module-dnieremote-config-wifiport"; 4 | nodes.machine = { config, pkgs, modulesPath, ... }: { 5 | imports = [ 6 | home-manager.nixosModules.home-manager 7 | (modulesPath + "./../tests/common/x11.nix") 8 | ../../../_common/hm-as-nixos-module/autofirma-user.nix 9 | ]; 10 | 11 | home-manager.users.autofirma-user = {config, ... }: { 12 | imports = [ 13 | self.homeManagerModules.dnieremote 14 | ]; 15 | 16 | programs.dnieremote.enable = true; 17 | programs.dnieremote.jumpIntro = "wifi"; 18 | programs.dnieremote.wifiPort = 4444; 19 | }; 20 | }; 21 | 22 | testScript = '' 23 | def user_cmd(cmd): 24 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 25 | 26 | machine.wait_for_unit("default.target") 27 | machine.wait_for_x() 28 | 29 | bind_ip = machine.execute("ip -4 route get 1.1.1.1 | grep -oP '(?<=src )\d+(\.\d+){3}'")[1].rstrip('\n') 30 | 31 | machine.succeed("grep 'wifiport=4444;' /home/autofirma-user/dnieRemote.cfg") 32 | 33 | # Wait for the wizard to start and jump into the wifi screen 34 | machine.execute(user_cmd("dnieremotewizard >&2 &")) 35 | 36 | machine.wait_for_open_port(4444, bind_ip, 30) 37 | ''; 38 | } 39 | 40 | -------------------------------------------------------------------------------- /nix/tests/hm-standalone/autofirma/cli/sign-document.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager, lib }: 2 | let 3 | openssl = lib.getExe pkgs.openssl; 4 | stateVersion = "${lib.versions.major lib.version}.${lib.versions.minor lib.version}"; 5 | homeManagerStandaloneConfiguration = home-manager.lib.homeManagerConfiguration { 6 | inherit pkgs; 7 | modules = [ 8 | self.homeManagerModules.autofirma 9 | { 10 | home.username = "autofirma-user"; 11 | home.homeDirectory = "/home/autofirma-user"; 12 | home.stateVersion = "${stateVersion}"; 13 | 14 | programs.autofirma.enable = true; 15 | } 16 | ]; 17 | }; 18 | in 19 | 20 | pkgs.nixosTest { 21 | name = "test-hm-standalone-autofirma-cli-sign-document"; 22 | nodes.machine = { config, pkgs, modulesPath, ... }: { 23 | imports = [ 24 | (modulesPath + "./../tests/common/x11.nix") 25 | ../../../_common/hm-standalone/autofirma-user.nix 26 | ]; 27 | 28 | environment.systemPackages = [ 29 | homeManagerStandaloneConfiguration.activationPackage 30 | ]; 31 | 32 | system.stateVersion = stateVersion; 33 | }; 34 | 35 | testScript = '' 36 | def user_cmd(cmd): 37 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 38 | 39 | machine.wait_for_x() 40 | machine.succeed(user_cmd('home-manager-generation')) 41 | 42 | machine.succeed(user_cmd('echo "NixOS AutoFirma Sign Test" > document.txt')) 43 | machine.succeed(user_cmd('${openssl} req -x509 -newkey rsa:2048 -keyout private.key -out certificate.crt -days 365 -nodes -subj "/C=ES/O=TEST AUTOFIRMA NIX/OU=DNIE/CN=AC DNIE 004" -passout pass:1234')) 44 | machine.succeed(user_cmd('${openssl} pkcs12 -export -out certificate.p12 -inkey private.key -in certificate.crt -name "testcert" -password pass:1234')) 45 | 46 | machine.succeed(user_cmd('autofirma sign -store pkcs12:certificate.p12 -i document.txt -o document.txt.sign -filter alias.contains=testcert -password 1234 -xml')) 47 | ''; 48 | } 49 | -------------------------------------------------------------------------------- /nix/tests/hm-standalone/autofirma/config/omitAskOnClose.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager, lib }: 2 | let 3 | stateVersion = "${lib.versions.major lib.version}.${lib.versions.minor lib.version}"; 4 | homeManagerStandaloneConfiguration = home-manager.lib.homeManagerConfiguration { 5 | inherit pkgs; 6 | modules = [ 7 | self.homeManagerModules.autofirma 8 | 9 | ({ config, ... }: { 10 | home.username = "autofirma-user"; 11 | home.homeDirectory = "/home/autofirma-user"; 12 | home.stateVersion = "${stateVersion}"; 13 | 14 | programs.autofirma.enable = true; 15 | programs.autofirma.config.omitAskOnClose = true; 16 | }) 17 | ]; 18 | }; 19 | in 20 | pkgs.nixosTest { 21 | name = "test-hm-standalone-autofirma-config-omitAskOnClose"; 22 | nodes.machine = { config, pkgs, modulesPath, ... }: { 23 | imports = [ 24 | (modulesPath + "./../tests/common/x11.nix") 25 | ../../../_common/hm-standalone/autofirma-user.nix 26 | ]; 27 | 28 | environment.systemPackages = [ 29 | homeManagerStandaloneConfiguration.activationPackage 30 | ]; 31 | 32 | system.stateVersion = stateVersion; 33 | }; 34 | 35 | testScript = '' 36 | def user_cmd(cmd): 37 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 38 | 39 | machine.wait_for_unit("default.target") 40 | machine.wait_for_x() 41 | machine.succeed(user_cmd('xhost +SI:localuser:root')) 42 | 43 | machine.succeed(user_cmd('home-manager-generation')) 44 | 45 | machine.execute(user_cmd("autofirma >&2 &")) 46 | 47 | machine.wait_for_window('AutoFirma\s.*', 30) 48 | machine.sleep(5) 49 | machine.send_key("alt-f4") 50 | machine.wait_until_succeeds(user_cmd('[ ! $(pgrep -x java) ]'), 30) 51 | ''; 52 | } 53 | 54 | 55 | -------------------------------------------------------------------------------- /nix/tests/hm-standalone/autofirma/firefoxIntegration/connection-method/auxiliary-servers/default.nix: -------------------------------------------------------------------------------- 1 | import ../build-connection-method-test.nix { 2 | testName = "test-hm-standalone-autofirma-firefoxIntegration-connection-method-auxiliary-servers"; 3 | jsTestFile = ./test.js; 4 | } 5 | -------------------------------------------------------------------------------- /nix/tests/hm-standalone/autofirma/firefoxIntegration/connection-method/auxiliary-servers/test.js: -------------------------------------------------------------------------------- 1 | // JavaScript implementation for TestAutoFirma using provided signing services 2 | 3 | (function() { 4 | function initializeMiniApplet(storageUrl, retrieverUrl) { 5 | console.log(`Initializing MiniApplet with ${storageUrl} and ${retrieverUrl}`); 6 | MiniApplet.setServlets(storageUrl, retrieverUrl); 7 | MiniApplet.setForceWSMode(true); 8 | MiniApplet.cargarAppAfirma(); 9 | } 10 | 11 | function generateSignature(data, onSuccess, onError) { 12 | try { 13 | MiniApplet.sign(data, "SHA256withRSA", "CAdES", "headless=true", onSuccess, onError); 14 | } catch (error) { 15 | onError("Exception", error.message); 16 | } 17 | } 18 | 19 | function sendResultToServer(message) { 20 | const formData = new FormData(); 21 | formData.append("test_output", message); 22 | 23 | fetch("/test.php", { 24 | method: "POST", 25 | body: formData 26 | }).then(response => { 27 | if (response.ok) { 28 | console.log("Result sent successfully."); 29 | } else { 30 | console.error("Failed to send result to server."); 31 | } 32 | }).catch(error => { 33 | console.error("Error sending result to server:", error); 34 | }); 35 | } 36 | 37 | function handleSignatureResult(message) { 38 | console.log(`Signature Successful: ${message}`); 39 | sendResultToServer(`Signature Successful: ${message}`); 40 | } 41 | 42 | function handleError(errorType, errorMessage) { 43 | console.error(`Error (${errorType}): ${errorMessage}`); 44 | sendResultToServer(`Error (${errorType}): ${errorMessage}`); 45 | } 46 | 47 | function startSigningProcess() { 48 | const storageUrl = 'https://autofirma-nix.com/afirma-signature-storage/StorageService'; 49 | const retrieverUrl = 'https://autofirma-nix.com/afirma-signature-retriever/RetrieveService'; 50 | const dataToSign = btoa(document.documentElement.outerHTML); 51 | 52 | initializeMiniApplet(storageUrl, retrieverUrl); 53 | 54 | generateSignature( 55 | dataToSign, 56 | handleSignatureResult, 57 | handleError 58 | ); 59 | } 60 | 61 | // Automatically start the signing process on page load 62 | window.addEventListener('DOMContentLoaded', startSigningProcess); 63 | })(); 64 | 65 | -------------------------------------------------------------------------------- /nix/tests/hm-standalone/autofirma/firefoxIntegration/connection-method/build-connection-method-test.nix: -------------------------------------------------------------------------------- 1 | { testName, jsTestFile }: 2 | { self, pkgs, system, home-manager, lib }: 3 | let 4 | testCerts = pkgs.callPackage ../../../../_common/pkgs/test_certs.nix {}; 5 | stateVersion = "${lib.versions.major lib.version}.${lib.versions.minor lib.version}"; 6 | homeManagerStandaloneConfiguration = systemConfig: home-manager.lib.homeManagerConfiguration { 7 | inherit pkgs; 8 | modules = [ 9 | self.homeManagerModules.autofirma 10 | { 11 | home.username = "autofirma-user"; 12 | home.homeDirectory = "/home/autofirma-user"; 13 | home.stateVersion = "${stateVersion}"; 14 | 15 | home.file.cabundle.text = systemConfig.environment.etc."ssl/certs/ca-certificates.crt".source; 16 | 17 | programs.autofirma.enable = true; 18 | programs.autofirma.truststore.package = self.packages."${system}".autofirma-truststore.override { 19 | caBundle = systemConfig.environment.etc."ssl/certs/ca-certificates.crt".source; 20 | govTrustedCerts = systemConfig.security.pki.certificateFiles; 21 | }; 22 | programs.autofirma.firefoxIntegration.profiles.default.enable = true; 23 | 24 | programs.firefox.enable = true; 25 | programs.firefox.profiles.default.id = 0; 26 | # Allow Firefox to open AutoConfig settings without user interaction 27 | programs.firefox.profiles.default.settings."network.protocol-handler.expose.afirma" = true; 28 | } 29 | ]; 30 | }; 31 | in 32 | pkgs.nixosTest { 33 | name = testName; 34 | nodes.machine = { config, pkgs, modulesPath, ... }: { 35 | imports = [ 36 | home-manager.nixosModules.home-manager 37 | (modulesPath + "./../tests/common/x11.nix") 38 | ../../../../_common/tests/autofirma_test_server 39 | ../../../../_common/hm-standalone/autofirma-user.nix 40 | ]; 41 | 42 | environment.systemPackages = with pkgs; [ 43 | (homeManagerStandaloneConfiguration config).activationPackage 44 | nss.tools 45 | ]; 46 | 47 | autofirma-test-server.jsTestFile = jsTestFile; 48 | 49 | system.stateVersion = stateVersion; 50 | }; 51 | 52 | testScript = '' 53 | def user_cmd(cmd): 54 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 55 | 56 | machine.wait_for_unit("default.target") 57 | machine.wait_for_x() 58 | machine.succeed(user_cmd('xhost +SI:localuser:root')) 59 | 60 | machine.succeed(user_cmd('home-manager-generation')) 61 | 62 | machine.wait_for_open_port(port=443) 63 | 64 | profile_dir = "default" 65 | machine.execute(user_cmd("firefox >&2 &")) 66 | 67 | machine.wait_for_file(f"/home/autofirma-user/.mozilla/firefox/{profile_dir}/cert9.db") 68 | machine.wait_for_file(f"/home/autofirma-user/.mozilla/firefox/{profile_dir}/key4.db") 69 | machine.sleep(5) 70 | 71 | machine.succeed(user_cmd(f'pk12util -i ${testCerts}/ciudadano_scard_act.p12 -d sql:/home/autofirma-user/.mozilla/firefox/{profile_dir} -W ""')) 72 | 73 | machine.succeed("rm -f /tmp/test_output.txt") 74 | machine.sleep(5) 75 | 76 | # Open firefox and allow it to import AutoConfig settings 77 | machine.execute(user_cmd("firefox --new-tab https://autofirma-nix.com/index.php >&2 &")) 78 | 79 | machine.wait_for_file("/tmp/test_output.txt") 80 | machine.sleep(5) 81 | machine.succeed("grep 'Signature Successful:' /tmp/test_output.txt") 82 | 83 | ''; 84 | } 85 | 86 | 87 | -------------------------------------------------------------------------------- /nix/tests/hm-standalone/autofirma/firefoxIntegration/connection-method/websocket/default.nix: -------------------------------------------------------------------------------- 1 | import ../build-connection-method-test.nix { 2 | testName = "test-hm-standalone-autofirma-firefoxIntegration-connection-method-websocket"; 3 | jsTestFile = ./test.js; 4 | } 5 | -------------------------------------------------------------------------------- /nix/tests/hm-standalone/autofirma/firefoxIntegration/connection-method/websocket/test.js: -------------------------------------------------------------------------------- 1 | // JavaScript implementation for TestAutoFirma using provided signing services 2 | 3 | (function() { 4 | function initializeMiniApplet(storageUrl, retrieverUrl) { 5 | console.log(`Initializing MiniApplet with ${storageUrl} and ${retrieverUrl}`); 6 | MiniApplet.cargarAppAfirma(storageUrl); 7 | } 8 | 9 | function generateSignature(data, onSuccess, onError) { 10 | try { 11 | MiniApplet.sign(data, "SHA256withRSA", "CAdES", "headless=true", onSuccess, onError); 12 | } catch (error) { 13 | onError("Exception", error.message); 14 | } 15 | } 16 | 17 | function sendResultToServer(message) { 18 | const formData = new FormData(); 19 | formData.append("test_output", message); 20 | 21 | fetch("/test.php", { 22 | method: "POST", 23 | body: formData 24 | }).then(response => { 25 | if (response.ok) { 26 | console.log("Result sent successfully."); 27 | } else { 28 | console.error("Failed to send result to server."); 29 | } 30 | }).catch(error => { 31 | console.error("Error sending result to server:", error); 32 | }); 33 | } 34 | 35 | function handleSignatureResult(message) { 36 | console.log(`Signature Successful: ${message}`); 37 | sendResultToServer(`Signature Successful: ${message}`); 38 | } 39 | 40 | function handleError(errorType, errorMessage) { 41 | console.error(`Error (${errorType}): ${errorMessage}`); 42 | sendResultToServer(`Error (${errorType}): ${errorMessage}`); 43 | } 44 | 45 | function startSigningProcess() { 46 | const storageUrl = '/afirma-signature-storage'; 47 | const retrieverUrl = '/afirma-signature-retriever'; 48 | const dataToSign = btoa(document.documentElement.outerHTML); 49 | 50 | initializeMiniApplet(storageUrl, retrieverUrl); 51 | 52 | generateSignature( 53 | dataToSign, 54 | handleSignatureResult, 55 | handleError 56 | ); 57 | } 58 | 59 | // Automatically start the signing process on page load 60 | window.addEventListener('DOMContentLoaded', startSigningProcess); 61 | })(); 62 | -------------------------------------------------------------------------------- /nix/tests/hm-standalone/autofirma/firefoxIntegration/connection-method/xhr/default.nix: -------------------------------------------------------------------------------- 1 | import ../build-connection-method-test.nix { 2 | testName = "test-hm-standalone-autofirma-firefoxIntegration-connection-method-xhr"; 3 | jsTestFile = ./test.js; 4 | } 5 | -------------------------------------------------------------------------------- /nix/tests/hm-standalone/autofirma/firefoxIntegration/connection-method/xhr/test.js: -------------------------------------------------------------------------------- 1 | // JavaScript implementation for TestAutoFirma using provided signing services 2 | 3 | (function() { 4 | function initializeMiniApplet(storageUrl, retrieverUrl) { 5 | console.log(`Initializing MiniApplet with ${storageUrl} and ${retrieverUrl}`); 6 | MiniApplet.cargarAppAfirma(storageUrl); 7 | } 8 | 9 | function generateSignature(data, onSuccess, onError) { 10 | try { 11 | MiniApplet.sign(data, "SHA256withRSA", "CAdES", "headless=true", onSuccess, onError); 12 | } catch (error) { 13 | onError("Exception", error.message); 14 | } 15 | } 16 | 17 | function sendResultToServer(message) { 18 | const formData = new FormData(); 19 | formData.append("test_output", message); 20 | 21 | fetch("/test.php", { 22 | method: "POST", 23 | body: formData 24 | }).then(response => { 25 | if (response.ok) { 26 | console.log("Result sent successfully."); 27 | } else { 28 | console.error("Failed to send result to server."); 29 | } 30 | }).catch(error => { 31 | console.error("Error sending result to server:", error); 32 | }); 33 | } 34 | 35 | function handleSignatureResult(message) { 36 | console.log(`Signature Successful: ${message}`); 37 | sendResultToServer(`Signature Successful: ${message}`); 38 | } 39 | 40 | function handleError(errorType, errorMessage) { 41 | console.error(`Error (${errorType}): ${errorMessage}`); 42 | sendResultToServer(`Error (${errorType}): ${errorMessage}`); 43 | } 44 | 45 | function startSigningProcess() { 46 | const storageUrl = '/afirma-signature-storage'; 47 | const retrieverUrl = '/afirma-signature-retriever'; 48 | const dataToSign = btoa(document.documentElement.outerHTML); 49 | 50 | delete window.WebSocket; 51 | 52 | initializeMiniApplet(storageUrl, retrieverUrl); 53 | 54 | generateSignature( 55 | dataToSign, 56 | handleSignatureResult, 57 | handleError 58 | ); 59 | } 60 | 61 | // Automatically start the signing process on page load 62 | window.addEventListener('DOMContentLoaded', startSigningProcess); 63 | })(); 64 | -------------------------------------------------------------------------------- /nix/tests/hm-standalone/autofirma/firefoxIntegration/protocol-handler/default.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager, lib }: 2 | let 3 | stateVersion = "${lib.versions.major lib.version}.${lib.versions.minor lib.version}"; 4 | homeManagerStandaloneConfiguration = home-manager.lib.homeManagerConfiguration { 5 | inherit pkgs; 6 | modules = [ 7 | self.homeManagerModules.autofirma 8 | ({ config, ... }: { 9 | home.username = "autofirma-user"; 10 | home.homeDirectory = "/home/autofirma-user"; 11 | home.stateVersion = "${stateVersion}"; 12 | 13 | programs.firefox.enable = true; 14 | programs.firefox.profiles.default.id = 0; 15 | programs.firefox.profiles.default.settings."network.protocol-handler.expose.afirma" = true; 16 | 17 | programs.autofirma.enable = true; 18 | programs.autofirma.firefoxIntegration.profiles.default.enable = true; 19 | 20 | home.packages = [ 21 | (pkgs.writeScriptBin "open-autofirma-via-firefox" '' 22 | cat <<'EOF' > /tmp/autofirma.html 23 | 24 | 25 | 26 | 27 | 28 |

Redirecting to autofirma...

29 | 30 | 31 | EOF 32 | 33 | ${lib.getExe config.programs.firefox.finalPackage} /tmp/autofirma.html 34 | '') 35 | ]; 36 | }) 37 | ]; 38 | }; 39 | in 40 | pkgs.nixosTest { 41 | name = "test-hm-standalone-autofirma-firefoxIntegration-protocol-handler"; 42 | nodes.machine = { config, pkgs, modulesPath, ... }: { 43 | imports = [ 44 | (modulesPath + "./../tests/common/x11.nix") 45 | ../../../../_common/hm-standalone/autofirma-user.nix 46 | ]; 47 | 48 | environment.systemPackages = [ 49 | homeManagerStandaloneConfiguration.activationPackage 50 | ]; 51 | 52 | system.stateVersion = stateVersion; 53 | }; 54 | 55 | testScript = '' 56 | def user_cmd(cmd): 57 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 58 | 59 | machine.wait_for_x() 60 | machine.succeed(user_cmd('xhost +SI:localuser:root')) 61 | 62 | machine.succeed(user_cmd('home-manager-generation')) 63 | 64 | # Open firefox and allow it to import AutoConfig settings 65 | machine.execute(user_cmd("firefox >&2 &")) 66 | machine.wait_for_window("Mozilla Firefox") 67 | machine.sleep(5) 68 | 69 | # Open an afirma:// URL in Firefox 70 | machine.execute(user_cmd("open-autofirma-via-firefox")) 71 | 72 | # Wait for the AutoFirma window to appear 73 | machine.wait_for_window('Seleccione el fichero de datos a firmar', 30) 74 | machine.sleep(5) 75 | machine.screenshot("screen") 76 | ''; 77 | } 78 | 79 | -------------------------------------------------------------------------------- /nix/tests/hm-standalone/configuradorfnmt/firefoxIntegration/request-certificate.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager, lib }: 2 | let 3 | stateVersion = "${lib.versions.major lib.version}.${lib.versions.minor lib.version}"; 4 | homeManagerStandaloneConfiguration = home-manager.lib.homeManagerConfiguration { 5 | inherit pkgs; 6 | modules = [ 7 | self.homeManagerModules.configuradorfnmt 8 | ({ config, ... }: { 9 | home.username = "autofirma-user"; 10 | home.homeDirectory = "/home/autofirma-user"; 11 | home.stateVersion = "${stateVersion}"; 12 | 13 | programs.firefox.enable = true; 14 | programs.firefox.profiles.default.id = 0; 15 | programs.firefox.profiles.default.settings."network.protocol-handler.expose.fnmtcr" = true; 16 | 17 | programs.configuradorfnmt.enable = true; 18 | programs.configuradorfnmt.firefoxIntegration.profiles.default.enable = true; 19 | 20 | home.packages = [ 21 | (pkgs.writeScriptBin "open-configuradorfnmt-via-firefox" '' 22 | cat <<'EOF' > /tmp/configuradorfnmt.html 23 | 24 | 25 | 26 | 27 | 28 |

Redirecting to configuradorfnmt...

29 | 30 | 31 | EOF 32 | 33 | ${lib.getExe config.programs.firefox.finalPackage} /tmp/configuradorfnmt.html 34 | '') 35 | ]; 36 | }) 37 | ]; 38 | }; 39 | in 40 | pkgs.nixosTest { 41 | name = "test-hm-standalone-configuradorfnmt-firefoxIntegration-request-certificate"; 42 | nodes.machine = { config, pkgs, modulesPath, ... }: { 43 | imports = [ 44 | (modulesPath + "./../tests/common/x11.nix") 45 | ../../../_common/hm-standalone/autofirma-user.nix 46 | ]; 47 | 48 | environment.systemPackages = [ 49 | homeManagerStandaloneConfiguration.activationPackage 50 | ]; 51 | 52 | system.stateVersion = stateVersion; 53 | }; 54 | 55 | testScript = '' 56 | def user_cmd(cmd): 57 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 58 | 59 | machine.wait_for_unit("default.target") 60 | machine.wait_for_x() 61 | machine.succeed(user_cmd('xhost +SI:localuser:root')) 62 | 63 | machine.succeed(user_cmd('home-manager-generation')) 64 | 65 | # Open firefox and allow it to import AutoConfig settings 66 | machine.execute(user_cmd("firefox >&2 &")) 67 | machine.wait_for_window("Mozilla Firefox") 68 | machine.sleep(5) 69 | 70 | # Open an fnmtcr:// URL in Firefox 71 | machine.execute(user_cmd("open-configuradorfnmt-via-firefox")) 72 | 73 | # Wait for the ConfiguradorFNMT-RCM window to appear 74 | machine.wait_for_window('Uso de tarjeta criptográfica inteligente', 30) 75 | machine.sleep(5) 76 | machine.screenshot("screen") 77 | ''; 78 | } 79 | 80 | 81 | -------------------------------------------------------------------------------- /nix/tests/hm-standalone/dnieremote/config/jumpintro-no.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager, lib }: 2 | let 3 | stateVersion = "${lib.versions.major lib.version}.${lib.versions.minor lib.version}"; 4 | homeManagerStandaloneConfiguration = home-manager.lib.homeManagerConfiguration { 5 | inherit pkgs; 6 | modules = [ 7 | self.homeManagerModules.dnieremote 8 | 9 | ({ config, ... }: { 10 | home.username = "autofirma-user"; 11 | home.homeDirectory = "/home/autofirma-user"; 12 | home.stateVersion = "${stateVersion}"; 13 | 14 | programs.dnieremote.enable = true; 15 | programs.dnieremote.jumpIntro = "no"; 16 | }) 17 | ]; 18 | }; 19 | in 20 | pkgs.nixosTest { 21 | name = "test-hm-standalone-dnieremote-config-jumpintro-no"; 22 | nodes.machine = { config, pkgs, modulesPath, ... }: { 23 | imports = [ 24 | (modulesPath + "./../tests/common/x11.nix") 25 | ../../../_common/hm-standalone/autofirma-user.nix 26 | ]; 27 | 28 | environment.systemPackages = [ 29 | homeManagerStandaloneConfiguration.activationPackage 30 | ]; 31 | 32 | system.stateVersion = stateVersion; 33 | }; 34 | 35 | testScript = '' 36 | def user_cmd(cmd): 37 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 38 | 39 | machine.wait_for_unit("default.target") 40 | machine.wait_for_x() 41 | machine.succeed(user_cmd('xhost +SI:localuser:root')) 42 | 43 | machine.succeed(user_cmd('home-manager-generation')) 44 | 45 | machine.execute(user_cmd("dnieremotewizard >&2 &")) 46 | 47 | # Wait for the wizard to start and present the introduction screen 48 | machine.wait_for_window('Introducción', 30) 49 | machine.sleep(5) 50 | machine.screenshot("screen") 51 | ''; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /nix/tests/hm-standalone/dnieremote/config/jumpintro-usb.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager, lib }: 2 | let 3 | stateVersion = "${lib.versions.major lib.version}.${lib.versions.minor lib.version}"; 4 | homeManagerStandaloneConfiguration = home-manager.lib.homeManagerConfiguration { 5 | inherit pkgs; 6 | modules = [ 7 | self.homeManagerModules.dnieremote 8 | 9 | ({ config, ... }: { 10 | home.username = "autofirma-user"; 11 | home.homeDirectory = "/home/autofirma-user"; 12 | home.stateVersion = "${stateVersion}"; 13 | 14 | programs.dnieremote.enable = true; 15 | programs.dnieremote.jumpIntro = "usb"; 16 | }) 17 | ]; 18 | }; 19 | in 20 | pkgs.nixosTest { 21 | name = "test-hm-standalone-dnieremote-config-jumpintro-usb"; 22 | nodes.machine = { config, pkgs, modulesPath, ... }: { 23 | imports = [ 24 | (modulesPath + "./../tests/common/x11.nix") 25 | ../../../_common/hm-standalone/autofirma-user.nix 26 | ]; 27 | 28 | environment.systemPackages = [ 29 | homeManagerStandaloneConfiguration.activationPackage 30 | ]; 31 | 32 | system.stateVersion = stateVersion; 33 | }; 34 | 35 | testScript = '' 36 | def user_cmd(cmd): 37 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 38 | 39 | machine.wait_for_unit("default.target") 40 | machine.wait_for_x() 41 | machine.succeed(user_cmd('xhost +SI:localuser:root')) 42 | 43 | machine.succeed(user_cmd('home-manager-generation')) 44 | 45 | machine.execute(user_cmd("dnieremotewizard >&2 &")) 46 | 47 | # Wait for the wizard to start and jump into the usb screen and fail due to no usb device 48 | machine.wait_for_window('Finalización', 30) 49 | machine.sleep(5) 50 | machine.screenshot("screen") 51 | ''; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /nix/tests/hm-standalone/dnieremote/config/jumpintro-wifi.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager, lib }: 2 | let 3 | stateVersion = "${lib.versions.major lib.version}.${lib.versions.minor lib.version}"; 4 | homeManagerStandaloneConfiguration = home-manager.lib.homeManagerConfiguration { 5 | inherit pkgs; 6 | modules = [ 7 | self.homeManagerModules.dnieremote 8 | 9 | ({ config, ... }: { 10 | home.username = "autofirma-user"; 11 | home.homeDirectory = "/home/autofirma-user"; 12 | home.stateVersion = "${stateVersion}"; 13 | 14 | programs.dnieremote.enable = true; 15 | programs.dnieremote.jumpIntro = "wifi"; 16 | }) 17 | ]; 18 | }; 19 | in 20 | pkgs.nixosTest { 21 | name = "test-hm-standalone-dnieremote-config-jumpintro-wifi"; 22 | nodes.machine = { config, pkgs, modulesPath, ... }: { 23 | imports = [ 24 | (modulesPath + "./../tests/common/x11.nix") 25 | ../../../_common/hm-standalone/autofirma-user.nix 26 | ]; 27 | 28 | environment.systemPackages = [ 29 | homeManagerStandaloneConfiguration.activationPackage 30 | ]; 31 | 32 | system.stateVersion = stateVersion; 33 | }; 34 | 35 | testScript = '' 36 | def user_cmd(cmd): 37 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 38 | 39 | machine.wait_for_unit("default.target") 40 | machine.wait_for_x() 41 | machine.succeed(user_cmd('xhost +SI:localuser:root')) 42 | 43 | machine.succeed(user_cmd('home-manager-generation')) 44 | 45 | machine.execute(user_cmd("dnieremotewizard >&2 &")) 46 | 47 | # Wait for the wizard to start and jump into the wifi screen 48 | machine.wait_for_window('Vinculación dispositivo y DNIe', 30) 49 | machine.sleep(5) 50 | machine.screenshot("screen") 51 | ''; 52 | } 53 | 54 | -------------------------------------------------------------------------------- /nix/tests/hm-standalone/dnieremote/config/wifiport.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, home-manager, lib }: 2 | let 3 | stateVersion = "${lib.versions.major lib.version}.${lib.versions.minor lib.version}"; 4 | homeManagerStandaloneConfiguration = home-manager.lib.homeManagerConfiguration { 5 | inherit pkgs; 6 | modules = [ 7 | self.homeManagerModules.dnieremote 8 | 9 | ({ config, ... }: { 10 | home.username = "autofirma-user"; 11 | home.homeDirectory = "/home/autofirma-user"; 12 | home.stateVersion = "${stateVersion}"; 13 | 14 | programs.dnieremote.enable = true; 15 | programs.dnieremote.jumpIntro = "wifi"; 16 | programs.dnieremote.wifiPort = 4444; 17 | }) 18 | ]; 19 | }; 20 | in 21 | pkgs.nixosTest { 22 | name = "test-hm-standalone-dnieremote-config-wifiport"; 23 | nodes.machine = { config, pkgs, modulesPath, ... }: { 24 | imports = [ 25 | (modulesPath + "./../tests/common/x11.nix") 26 | ../../../_common/hm-standalone/autofirma-user.nix 27 | ]; 28 | 29 | environment.systemPackages = [ 30 | homeManagerStandaloneConfiguration.activationPackage 31 | ]; 32 | 33 | system.stateVersion = stateVersion; 34 | }; 35 | 36 | testScript = '' 37 | def user_cmd(cmd): 38 | return f"su -l autofirma-user --shell /bin/sh -c $'export XDG_RUNTIME_DIR=/run/user/$UID ; {cmd}'" 39 | 40 | machine.wait_for_unit("default.target") 41 | machine.wait_for_x() 42 | machine.succeed(user_cmd('xhost +SI:localuser:root')) 43 | 44 | machine.succeed(user_cmd('home-manager-generation')) 45 | 46 | bind_ip = machine.execute("ip -4 route get 1.1.1.1 | grep -oP '(?<=src )\d+(\.\d+){3}'")[1].rstrip('\n') 47 | 48 | machine.succeed("grep 'wifiport=4444;' /home/autofirma-user/dnieRemote.cfg") 49 | 50 | # Wait for the wizard to start and jump into the wifi screen 51 | machine.execute(user_cmd("dnieremotewizard >&2 &")) 52 | 53 | machine.wait_for_open_port(4444, bind_ip, 30) 54 | ''; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /nix/tests/nixos/autofirma/cli/sign-document.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, lib }: 2 | let 3 | openssl = lib.getExe pkgs.openssl; 4 | in 5 | 6 | pkgs.nixosTest { 7 | name = "test-nixos-autofirma-cli-sign-document"; 8 | nodes.machine = { config, pkgs, modulesPath, ... }: { 9 | imports = [ 10 | self.nixosModules.autofirma 11 | (modulesPath + "./../tests/common/x11.nix") 12 | ../../../_common/nixos/stateVersion.nix 13 | ]; 14 | 15 | programs.autofirma.enable = true; 16 | }; 17 | 18 | testScript = '' 19 | machine.succeed('echo "NixOS AutoFirma Sign Test" > document.txt') 20 | machine.succeed('${openssl} req -x509 -newkey rsa:2048 -keyout private.key -out certificate.crt -days 365 -nodes -subj "/C=ES/O=TEST AUTOFIRMA NIX/OU=DNIE/CN=AC DNIE 004" -passout pass:1234') 21 | machine.succeed('${openssl} pkcs12 -export -out certificate.p12 -inkey private.key -in certificate.crt -name "testcert" -password pass:1234') 22 | 23 | machine.wait_for_x() 24 | 25 | machine.succeed('autofirma sign -store pkcs12:certificate.p12 -i document.txt -o document.txt.sign -filter alias.contains=testcert -password 1234 -xml') 26 | ''; 27 | } 28 | -------------------------------------------------------------------------------- /nix/tests/nixos/autofirma/firefoxIntegration/connection-method/auxiliary-servers/default.nix: -------------------------------------------------------------------------------- 1 | import ../build-connection-method-test.nix { 2 | testName = "nixos-autofirma-firefoxIntegration-connection-method-auxiliary-servers"; 3 | jsTestFile = ./test.js; 4 | } 5 | -------------------------------------------------------------------------------- /nix/tests/nixos/autofirma/firefoxIntegration/connection-method/auxiliary-servers/test.js: -------------------------------------------------------------------------------- 1 | // JavaScript implementation for TestAutoFirma using provided signing services 2 | 3 | (function() { 4 | function initializeMiniApplet(storageUrl, retrieverUrl) { 5 | console.log(`Initializing MiniApplet with ${storageUrl} and ${retrieverUrl}`); 6 | MiniApplet.setServlets(storageUrl, retrieverUrl); 7 | MiniApplet.setForceWSMode(true); 8 | MiniApplet.cargarAppAfirma(); 9 | } 10 | 11 | function generateSignature(data, onSuccess, onError) { 12 | try { 13 | MiniApplet.sign(data, "SHA256withRSA", "CAdES", "headless=true", onSuccess, onError); 14 | } catch (error) { 15 | onError("Exception", error.message); 16 | } 17 | } 18 | 19 | function sendResultToServer(message) { 20 | const formData = new FormData(); 21 | formData.append("test_output", message); 22 | 23 | fetch("/test.php", { 24 | method: "POST", 25 | body: formData 26 | }).then(response => { 27 | if (response.ok) { 28 | console.log("Result sent successfully."); 29 | } else { 30 | console.error("Failed to send result to server."); 31 | } 32 | }).catch(error => { 33 | console.error("Error sending result to server:", error); 34 | }); 35 | } 36 | 37 | function handleSignatureResult(message) { 38 | console.log(`Signature Successful: ${message}`); 39 | sendResultToServer(`Signature Successful: ${message}`); 40 | } 41 | 42 | function handleError(errorType, errorMessage) { 43 | console.error(`Error (${errorType}): ${errorMessage}`); 44 | sendResultToServer(`Error (${errorType}): ${errorMessage}`); 45 | } 46 | 47 | function startSigningProcess() { 48 | const storageUrl = 'https://autofirma-nix.com/afirma-signature-storage/StorageService'; 49 | const retrieverUrl = 'https://autofirma-nix.com/afirma-signature-retriever/RetrieveService'; 50 | const dataToSign = btoa(document.documentElement.outerHTML); 51 | 52 | initializeMiniApplet(storageUrl, retrieverUrl); 53 | 54 | generateSignature( 55 | dataToSign, 56 | handleSignatureResult, 57 | handleError 58 | ); 59 | } 60 | 61 | // Automatically start the signing process on page load 62 | window.addEventListener('DOMContentLoaded', startSigningProcess); 63 | })(); 64 | 65 | -------------------------------------------------------------------------------- /nix/tests/nixos/autofirma/firefoxIntegration/connection-method/build-connection-method-test.nix: -------------------------------------------------------------------------------- 1 | { testName, jsTestFile }: 2 | { self, pkgs, lib, system }: 3 | let 4 | testCerts = pkgs.callPackage ../../../../_common/pkgs/test_certs.nix {}; 5 | in 6 | pkgs.nixosTest { 7 | name = testName; 8 | nodes.machine = { config, pkgs, modulesPath, ... }: { 9 | imports = [ 10 | self.nixosModules.autofirma 11 | (modulesPath + "./../tests/common/x11.nix") 12 | ../../../../_common/tests/autofirma_test_server 13 | ../../../../_common/nixos/stateVersion.nix 14 | ]; 15 | 16 | programs.autofirma.enable = true; 17 | programs.autofirma.truststore.package = self.packages."${system}".autofirma-truststore.override (old: { 18 | caBundle = config.environment.etc."ssl/certs/ca-certificates.crt".source; 19 | govTrustedCerts = old.govTrustedCerts ++ config.security.pki.certificateFiles; 20 | }); 21 | 22 | programs.autofirma.firefoxIntegration.enable = true; 23 | 24 | programs.firefox.enable = true; 25 | 26 | # Allow Firefox to open AutoConfig settings without user interaction 27 | programs.firefox.autoConfig = '' 28 | pref("network.protocol-handler.expose.afirma", true); 29 | ''; 30 | 31 | autofirma-test-server.jsTestFile = jsTestFile; 32 | 33 | environment.systemPackages = [ 34 | pkgs.nss.tools 35 | ]; 36 | 37 | }; 38 | 39 | testScript = '' 40 | machine.wait_for_unit("default.target") 41 | machine.wait_for_x() 42 | 43 | machine.wait_for_open_port(port=443) 44 | 45 | machine.succeed("firefox --headless --CreateProfile default") 46 | profile_dir = machine.succeed("grep -oP 'Path=\\K.*' ~/.mozilla/firefox/profiles.ini").rstrip("\n") 47 | machine.execute("firefox >&2 &") 48 | 49 | machine.wait_for_file(f"~/.mozilla/firefox/{profile_dir}/cert9.db") 50 | machine.wait_for_file(f"~/.mozilla/firefox/{profile_dir}/key4.db") 51 | machine.sleep(5) 52 | 53 | machine.succeed(f'pk12util -i ${testCerts}/ciudadano_scard_act.p12 -d sql:/root/.mozilla/firefox/{profile_dir} -W ""') 54 | machine.sleep(5) 55 | 56 | # Open firefox and allow it to import AutoConfig settings 57 | machine.execute("firefox --new-tab https://autofirma-nix.com/index.php >&2 &") 58 | 59 | machine.wait_for_file("/tmp/test_output.txt") 60 | machine.sleep(5) 61 | machine.succeed("grep 'Signature Successful:' /tmp/test_output.txt") 62 | 63 | ''; 64 | } 65 | -------------------------------------------------------------------------------- /nix/tests/nixos/autofirma/firefoxIntegration/connection-method/websocket/default.nix: -------------------------------------------------------------------------------- 1 | import ../build-connection-method-test.nix { 2 | testName = "nixos-autofirma-firefoxIntegration-connection-method-websocket"; 3 | jsTestFile = ./test.js; 4 | } 5 | -------------------------------------------------------------------------------- /nix/tests/nixos/autofirma/firefoxIntegration/connection-method/websocket/test.js: -------------------------------------------------------------------------------- 1 | // JavaScript implementation for TestAutoFirma using provided signing services 2 | 3 | (function() { 4 | function initializeMiniApplet(storageUrl, retrieverUrl) { 5 | console.log(`Initializing MiniApplet with ${storageUrl} and ${retrieverUrl}`); 6 | MiniApplet.cargarAppAfirma(storageUrl); 7 | } 8 | 9 | function generateSignature(data, onSuccess, onError) { 10 | try { 11 | MiniApplet.sign(data, "SHA256withRSA", "CAdES", "headless=true", onSuccess, onError); 12 | } catch (error) { 13 | onError("Exception", error.message); 14 | } 15 | } 16 | 17 | function sendResultToServer(message) { 18 | const formData = new FormData(); 19 | formData.append("test_output", message); 20 | 21 | fetch("/test.php", { 22 | method: "POST", 23 | body: formData 24 | }).then(response => { 25 | if (response.ok) { 26 | console.log("Result sent successfully."); 27 | } else { 28 | console.error("Failed to send result to server."); 29 | } 30 | }).catch(error => { 31 | console.error("Error sending result to server:", error); 32 | }); 33 | } 34 | 35 | function handleSignatureResult(message) { 36 | console.log(`Signature Successful: ${message}`); 37 | sendResultToServer(`Signature Successful: ${message}`); 38 | } 39 | 40 | function handleError(errorType, errorMessage) { 41 | console.error(`Error (${errorType}): ${errorMessage}`); 42 | sendResultToServer(`Error (${errorType}): ${errorMessage}`); 43 | } 44 | 45 | function startSigningProcess() { 46 | const storageUrl = '/afirma-signature-storage'; 47 | const retrieverUrl = '/afirma-signature-retriever'; 48 | const dataToSign = btoa(document.documentElement.outerHTML); 49 | 50 | initializeMiniApplet(storageUrl, retrieverUrl); 51 | 52 | generateSignature( 53 | dataToSign, 54 | handleSignatureResult, 55 | handleError 56 | ); 57 | } 58 | 59 | // Automatically start the signing process on page load 60 | window.addEventListener('DOMContentLoaded', startSigningProcess); 61 | })(); 62 | -------------------------------------------------------------------------------- /nix/tests/nixos/autofirma/firefoxIntegration/connection-method/xhr/default.nix: -------------------------------------------------------------------------------- 1 | import ../build-connection-method-test.nix { 2 | testName = "nixos-autofirma-firefoxIntegration-connection-method-xhr"; 3 | jsTestFile = ./test.js; 4 | } 5 | -------------------------------------------------------------------------------- /nix/tests/nixos/autofirma/firefoxIntegration/connection-method/xhr/test.js: -------------------------------------------------------------------------------- 1 | // JavaScript implementation for TestAutoFirma using provided signing services 2 | 3 | (function() { 4 | function initializeMiniApplet(storageUrl, retrieverUrl) { 5 | console.log(`Initializing MiniApplet with ${storageUrl} and ${retrieverUrl}`); 6 | MiniApplet.cargarAppAfirma(storageUrl); 7 | } 8 | 9 | function generateSignature(data, onSuccess, onError) { 10 | try { 11 | MiniApplet.sign(data, "SHA256withRSA", "CAdES", "headless=true", onSuccess, onError); 12 | } catch (error) { 13 | onError("Exception", error.message); 14 | } 15 | } 16 | 17 | function sendResultToServer(message) { 18 | const formData = new FormData(); 19 | formData.append("test_output", message); 20 | 21 | fetch("/test.php", { 22 | method: "POST", 23 | body: formData 24 | }).then(response => { 25 | if (response.ok) { 26 | console.log("Result sent successfully."); 27 | } else { 28 | console.error("Failed to send result to server."); 29 | } 30 | }).catch(error => { 31 | console.error("Error sending result to server:", error); 32 | }); 33 | } 34 | 35 | function handleSignatureResult(message) { 36 | console.log(`Signature Successful: ${message}`); 37 | sendResultToServer(`Signature Successful: ${message}`); 38 | } 39 | 40 | function handleError(errorType, errorMessage) { 41 | console.error(`Error (${errorType}): ${errorMessage}`); 42 | sendResultToServer(`Error (${errorType}): ${errorMessage}`); 43 | } 44 | 45 | function startSigningProcess() { 46 | const storageUrl = '/afirma-signature-storage'; 47 | const retrieverUrl = '/afirma-signature-retriever'; 48 | const dataToSign = btoa(document.documentElement.outerHTML); 49 | 50 | delete window.WebSocket; 51 | 52 | initializeMiniApplet(storageUrl, retrieverUrl); 53 | 54 | generateSignature( 55 | dataToSign, 56 | handleSignatureResult, 57 | handleError 58 | ); 59 | } 60 | 61 | // Automatically start the signing process on page load 62 | window.addEventListener('DOMContentLoaded', startSigningProcess); 63 | })(); 64 | -------------------------------------------------------------------------------- /nix/tests/nixos/autofirma/firefoxIntegration/protocol-handler/default.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, lib }: 2 | pkgs.nixosTest { 3 | name = "test-nixos-autofirma-firefoxIntegration-sign-document"; 4 | nodes.machine = { config, pkgs, modulesPath, ... }: { 5 | imports = [ 6 | self.nixosModules.autofirma 7 | (modulesPath + "./../tests/common/x11.nix") 8 | ../../../../_common/nixos/stateVersion.nix 9 | ]; 10 | 11 | programs.autofirma.enable = true; 12 | programs.autofirma.firefoxIntegration.enable = true; 13 | 14 | programs.firefox.enable = true; 15 | 16 | # Allow Firefox to open AutoConfig settings without user interaction 17 | programs.firefox.autoConfig = '' 18 | pref("network.protocol-handler.expose.afirma", true); 19 | ''; 20 | 21 | environment.systemPackages = [ 22 | (pkgs.writeScriptBin "open-autofirma-via-firefox" '' 23 | cat <<'EOF' > /tmp/autofirma.html 24 | 25 | 26 | 27 | 28 | 29 |

Redirecting to autofirma...

30 | 31 | 32 | EOF 33 | 34 | ${lib.getExe config.programs.firefox.package} /tmp/autofirma.html 35 | '') 36 | ]; 37 | }; 38 | 39 | testScript = '' 40 | machine.wait_for_unit("default.target") 41 | machine.wait_for_x() 42 | 43 | # Open firefox and allow it to import AutoConfig settings 44 | machine.execute("firefox >&2 &") 45 | machine.wait_for_window("Mozilla Firefox") 46 | machine.sleep(5) 47 | 48 | # Open an afirma:// URL in Firefox 49 | machine.execute("open-autofirma-via-firefox") 50 | 51 | # Wait for the AutoFirma window to appear 52 | machine.wait_for_window('Seleccione el fichero de datos a firmar', 30) 53 | machine.screenshot("screen") 54 | ''; 55 | } 56 | -------------------------------------------------------------------------------- /nix/tests/nixos/configuradorfnmt/firefoxIntegration/request-certificate.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, lib }: 2 | pkgs.nixosTest { 3 | name = "test-nixos-configuradorfnmt-firefoxIntegration-request-certificate"; 4 | nodes.machine = { config, pkgs, modulesPath, ... }: { 5 | imports = [ 6 | self.nixosModules.configuradorfnmt 7 | (modulesPath + "./../tests/common/x11.nix") 8 | ../../../_common/nixos/stateVersion.nix 9 | ]; 10 | 11 | programs.configuradorfnmt.enable = true; 12 | programs.configuradorfnmt.firefoxIntegration.enable = true; 13 | 14 | programs.firefox.enable = true; 15 | 16 | # Allow Firefox to open AutoConfig settings without user interaction 17 | programs.firefox.autoConfig = '' 18 | pref("network.protocol-handler.expose.fnmtcr", true); 19 | ''; 20 | 21 | environment.systemPackages = [ 22 | (pkgs.writeScriptBin "open-configuradorfnmt-via-firefox" '' 23 | cat <<'EOF' > /tmp/configuradorfnmt.html 24 | 25 | 26 | 27 | 28 | 29 |

Redirecting to configuradorfnmt...

30 | 31 | 32 | EOF 33 | 34 | ${lib.getExe config.programs.firefox.package} /tmp/configuradorfnmt.html 35 | '') 36 | ]; 37 | }; 38 | 39 | testScript = '' 40 | machine.wait_for_unit("default.target") 41 | machine.wait_for_x() 42 | 43 | # Open firefox and allow it to import AutoConfig settings 44 | machine.execute("firefox >&2 &") 45 | machine.wait_for_window("Mozilla Firefox") 46 | machine.sleep(5) 47 | 48 | # Open an fnmtcr:// URL in Firefox 49 | machine.execute("open-configuradorfnmt-via-firefox") 50 | 51 | # Configurador FNMT-RCM should open automatically 52 | machine.wait_for_window('Uso de tarjeta criptográfica inteligente', 30) 53 | machine.screenshot("screen") 54 | ''; 55 | } 56 | -------------------------------------------------------------------------------- /nix/tests/nixos/dnieremote/config/jumpintro-no.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs }: 2 | pkgs.nixosTest { 3 | name = "test-nixos-module-dnieremote-config-jumpintro-no"; 4 | nodes.machine = { config, pkgs, modulesPath, ... }: { 5 | imports = [ 6 | self.nixosModules.dnieremote 7 | (modulesPath + "./../tests/common/x11.nix") 8 | ../../../_common/nixos/stateVersion.nix 9 | ]; 10 | 11 | programs.dnieremote.enable = true; 12 | programs.dnieremote.jumpIntro = "no"; 13 | }; 14 | 15 | testScript = '' 16 | machine.wait_for_unit("default.target") 17 | machine.wait_for_x() 18 | 19 | machine.execute("dnieremotewizard >&2 &") 20 | 21 | # Wait for the wizard to start and present the introduction screen 22 | machine.wait_for_window('Introducción', 30) 23 | machine.sleep(5) 24 | machine.screenshot("screen") 25 | ''; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /nix/tests/nixos/dnieremote/config/jumpintro-usb.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs }: 2 | pkgs.nixosTest { 3 | name = "test-nixos-module-dnieremote-config-jumpintro-usb"; 4 | nodes.machine = { config, pkgs, modulesPath, ... }: { 5 | imports = [ 6 | self.nixosModules.dnieremote 7 | (modulesPath + "./../tests/common/x11.nix") 8 | ../../../_common/nixos/stateVersion.nix 9 | ]; 10 | 11 | programs.dnieremote.enable = true; 12 | programs.dnieremote.jumpIntro = "usb"; 13 | }; 14 | 15 | testScript = '' 16 | machine.wait_for_unit("default.target") 17 | machine.wait_for_x() 18 | 19 | machine.execute("dnieremotewizard >&2 &") 20 | 21 | # Wait for the wizard to start and jump into the usb screen and fail due to no usb device 22 | machine.wait_for_window('Finalización', 30) 23 | machine.sleep(5) 24 | machine.screenshot("screen") 25 | ''; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /nix/tests/nixos/dnieremote/config/jumpintro-wifi.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs }: 2 | pkgs.nixosTest { 3 | name = "test-nixos-module-dnieremote-config-jumpintro-wifi"; 4 | nodes.machine = { config, pkgs, modulesPath, ... }: { 5 | imports = [ 6 | self.nixosModules.dnieremote 7 | (modulesPath + "./../tests/common/x11.nix") 8 | ../../../_common/nixos/stateVersion.nix 9 | ]; 10 | 11 | programs.dnieremote.enable = true; 12 | programs.dnieremote.jumpIntro = "wifi"; 13 | }; 14 | 15 | testScript = '' 16 | machine.wait_for_unit("default.target") 17 | machine.wait_for_x() 18 | 19 | machine.execute("dnieremotewizard >&2 &") 20 | 21 | # Wait for the wizard to start and jump into the wifi screen 22 | machine.wait_for_window('Vinculación dispositivo y DNIe', 30) 23 | machine.sleep(5) 24 | machine.screenshot("screen") 25 | ''; 26 | } 27 | 28 | -------------------------------------------------------------------------------- /nix/tests/nixos/dnieremote/config/wifiport.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs }: 2 | pkgs.nixosTest { 3 | name = "test-nixos-module-dnieremote-config-wifiport"; 4 | nodes.machine = { config, pkgs, modulesPath, ... }: { 5 | imports = [ 6 | self.nixosModules.dnieremote 7 | (modulesPath + "./../tests/common/x11.nix") 8 | ../../../_common/nixos/stateVersion.nix 9 | ]; 10 | 11 | programs.dnieremote.enable = true; 12 | programs.dnieremote.jumpIntro = "wifi"; 13 | programs.dnieremote.wifiPort = 4444; 14 | programs.dnieremote.openFirewall = true; 15 | 16 | networking.firewall.enable = true; 17 | }; 18 | 19 | testScript = '' 20 | machine.wait_for_unit("default.target") 21 | machine.wait_for_x() 22 | 23 | bind_ip = machine.execute("ip -4 route get 1.1.1.1 | grep -oP '(?<=src )\d+(\.\d+){3}'")[1].rstrip('\n') 24 | 25 | machine.succeed("grep 'wifiport=4444;' /etc/dnieRemote/dnieRemote.cfg") 26 | 27 | # Wait for the wizard to start and jump into the wifi screen 28 | machine.execute("dnieremotewizard >&2 &") 29 | 30 | machine.wait_for_open_port(4444, bind_ip, 30) 31 | ''; 32 | } 33 | 34 | -------------------------------------------------------------------------------- /nix/tests/overlay/default.nix: -------------------------------------------------------------------------------- 1 | { self, pkgs, lib }: 2 | let 3 | openssl = lib.getExe pkgs.openssl; 4 | in 5 | 6 | pkgs.nixosTest { 7 | name = "test-overlay"; 8 | nodes.machine = { config, pkgs, modulesPath, ... }: let 9 | pkgs' = pkgs.extend self.overlays.default; 10 | in { 11 | imports = [ 12 | (modulesPath + "./../tests/common/x11.nix") 13 | ../_common/nixos/stateVersion.nix 14 | ]; 15 | 16 | environment.systemPackages = with pkgs'; [ 17 | autofirma 18 | ]; 19 | 20 | }; 21 | 22 | testScript = '' 23 | machine.succeed('echo "NixOS AutoFirma Sign Test" > document.txt') 24 | machine.succeed('${openssl} req -x509 -newkey rsa:2048 -keyout private.key -out certificate.crt -days 365 -nodes -subj "/C=ES/O=TEST AUTOFIRMA NIX/OU=DNIE/CN=AC DNIE 004" -passout pass:1234') 25 | machine.succeed('${openssl} pkcs12 -export -out certificate.p12 -inkey private.key -in certificate.crt -name "testcert" -password pass:1234') 26 | 27 | machine.wait_for_x() 28 | 29 | machine.succeed('autofirma sign -store pkcs12:certificate.p12 -i document.txt -o document.txt.sign -filter alias.contains=testcert -password 1234 -xml') 30 | ''; 31 | } 32 | 33 | -------------------------------------------------------------------------------- /nix/tests/unit/default.nix: -------------------------------------------------------------------------------- 1 | { self }: 2 | with builtins; 3 | let 4 | ascendingOrder = sort lessThan; 5 | truststorePath = "${self}/nix/autofirma/truststore"; 6 | providers = fromJSON (readFile "${truststorePath}/prestadores/providers.json"); 7 | allCAFiles = attrNames (readDir "${truststorePath}/prestadores/CAs-by-provider"); 8 | CAFetchLinks = fromJSON (readFile "${truststorePath}/prestadores/CAs_fetch_links.json"); 9 | in 10 | { 11 | testProviderListIsNotEmpty = { 12 | expr = length providers > 0; 13 | expected = true; 14 | }; 15 | testCAFilesAndTrustedProvidersMatch = let 16 | trimJsonExt = s: substring 0 ((stringLength s) - (stringLength ".json")) s; 17 | in { 18 | expr = ascendingOrder (map trimJsonExt allCAFiles); 19 | expected = ascendingOrder (map (p: p.cif) providers); 20 | }; 21 | testAllCAFilesHaveFetchLinkEntry = { 22 | expr = ascendingOrder (map (p: p.cif) CAFetchLinks); 23 | expected = ascendingOrder (map (p: p.cif) providers); 24 | }; 25 | testAllFetchLinksHaveURLField = { 26 | expr = all (link: hasAttr "url" link) CAFetchLinks; 27 | expected = true; 28 | }; 29 | } 30 | -------------------------------------------------------------------------------- /nix/tools/download-autofirma-trusted-providers/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | writeShellApplication, 3 | xmlstarlet, 4 | jq, 5 | }: 6 | writeShellApplication { 7 | name = "download-autofirma-trusted-providers"; 8 | runtimeInputs = [xmlstarlet jq]; 9 | text = builtins.readFile ./download-autofirma-trusted-providers.sh; 10 | bashOptions = [ 11 | "errexit" 12 | "nounset" 13 | "pipefail" 14 | "xtrace" 15 | ]; 16 | } 17 | -------------------------------------------------------------------------------- /nix/tools/download-autofirma-trusted-providers/download-autofirma-trusted-providers.sh: -------------------------------------------------------------------------------- 1 | PRESTADORES_XML_URL="https://sedeaplicaciones.minetur.gob.es/PrestadoresDatosAbiertos/Prestadores.xml" 2 | 3 | xmlstarlet \ 4 | sel \ 5 | -t \ 6 | -m '/PRESTADORES/PRESTADOR[PrestadorCualificado[text() = "true"] and SERVICIOS/SERVICIO[Clasificacion[text() = "Certificados cualificados de Sede electrónica de la Administración Pública"]]]' \ 7 | -o '{"name": "' -v 'normalize-space(NombreSocial)' \ 8 | -o '", "cif": "' -v 'normalize-space(Cif)' \ 9 | -o '", "website": "' -v 'normalize-space(DominioInternet)' \ 10 | -o '", "source": "' -v 'normalize-space(FuenteConstitucion)' \ 11 | -o '"}' \ 12 | -n <(curl -s --output - "$PRESTADORES_XML_URL") | sort | uniq | jq -s . 13 | 14 | -------------------------------------------------------------------------------- /nix/tools/download-url-linked-CAs/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | python3Packages, 3 | openssl, 4 | chromedriver, 5 | chromium, 6 | curl, 7 | nix, 8 | makeWrapper 9 | }: 10 | python3Packages.buildPythonApplication { 11 | name = "download-url-linked-CAs"; 12 | nativeBuildInputs = [ 13 | makeWrapper 14 | ]; 15 | propagatedBuildInputs = [ 16 | python3Packages.beautifulsoup4 17 | python3Packages.selenium 18 | curl 19 | openssl 20 | nix 21 | chromedriver 22 | chromium 23 | ]; 24 | dontUnpack = true; 25 | format = "other"; 26 | installPhase = '' 27 | install -Dm755 ${./download-url-linked-CAs.py} $out/bin/download-url-linked-CAs 28 | # makewrapper that addes the path to cromedriver to the var CHROMEDRIVER_PATH 29 | wrapProgram $out/bin/download-url-linked-CAs \ 30 | --set "CHROMEDRIVER_PATH" "${chromedriver}/bin/chromedriver" 31 | ''; 32 | } 33 | -------------------------------------------------------------------------------- /nix/tools/pom-tools/default.nix: -------------------------------------------------------------------------------- 1 | { 2 | lib, 3 | writeShellApplication, 4 | writers, 5 | xmlstarlet, 6 | symlinkJoin, 7 | }: let 8 | shellScripts = lib.mapAttrsToList (name: path: 9 | writeShellApplication { 10 | name = name; 11 | runtimeInputs = [ xmlstarlet ]; 12 | text = builtins.readFile path; 13 | }) { 14 | update-java-version = ./lib/update-java-version.sh; 15 | update-pkg-version = ./lib/update-pkg-version.sh; 16 | update-dependency-version-by-groupId = ./lib/update-dependency-version-by-groupId.sh; 17 | remove-module-on-profile = ./lib/remove-module-on-profile.sh; 18 | reset-project-build-timestamp = ./lib/reset-project-build-timestamp.sh; 19 | reset-maven-metadata-local-timestamp = ./lib/reset-maven-metadata-local-timestamp.sh; 20 | update-plugin-version-by-groupId = ./lib/update-plugin-version-by-groupId.sh; 21 | }; 22 | pythonScripts = lib.mapAttrsToList (name: path: 23 | writers.writePython3Bin name { libraries = [ ]; flakeIgnore = [ "E501" ]; } (builtins.readFile path) 24 | ) { 25 | add-xml-doclet-to-javadoc-plugin = ./lib/add-xml-doclet-to-javadoc-plugin.py; 26 | }; 27 | in 28 | symlinkJoin { 29 | name = "pom-tools"; 30 | paths = shellScripts ++ pythonScripts; 31 | } 32 | -------------------------------------------------------------------------------- /nix/tools/pom-tools/lib/add-xml-doclet-to-javadoc-plugin.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import xml.etree.ElementTree as ET 3 | from xml.dom import minidom 4 | 5 | if len(sys.argv) != 3: 6 | sys.stderr.write("Usage: {} \n".format(sys.argv[0])) 7 | sys.exit(1) 8 | 9 | javadoc_version = sys.argv[1] 10 | xml_doclet_version = sys.argv[2] 11 | 12 | # Maven POM uses this namespace 13 | NS = {'mvn': 'http://maven.apache.org/POM/4.0.0'} 14 | ET.register_namespace('', NS['mvn']) 15 | 16 | tree = ET.parse('pom.xml') 17 | root = tree.getroot() 18 | 19 | # Find the element that's a direct child of 20 | build = root.find('mvn:build', NS) 21 | if build is None: 22 | build = ET.SubElement(root, '{http://maven.apache.org/POM/4.0.0}build') 23 | 24 | # Find the element under 25 | plugins = build.find('mvn:plugins', NS) 26 | if plugins is None: 27 | plugins = ET.SubElement(build, '{http://maven.apache.org/POM/4.0.0}plugins') 28 | 29 | # Optionally, check if a maven-javadoc-plugin is already present and remove it 30 | for plugin in plugins.findall('mvn:plugin', NS): 31 | aid = plugin.find('mvn:artifactId', NS) 32 | if aid is not None and aid.text == 'maven-javadoc-plugin': 33 | plugins.remove(plugin) 34 | 35 | # Create the new plugin element 36 | plugin = ET.Element('{http://maven.apache.org/POM/4.0.0}plugin') 37 | 38 | groupId = ET.SubElement(plugin, '{http://maven.apache.org/POM/4.0.0}groupId') 39 | groupId.text = "org.apache.maven.plugins" 40 | 41 | artifactId = ET.SubElement(plugin, '{http://maven.apache.org/POM/4.0.0}artifactId') 42 | artifactId.text = "maven-javadoc-plugin" 43 | 44 | version = ET.SubElement(plugin, '{http://maven.apache.org/POM/4.0.0}version') 45 | version.text = javadoc_version 46 | 47 | executions = ET.SubElement(plugin, '{http://maven.apache.org/POM/4.0.0}executions') 48 | execution = ET.SubElement(executions, '{http://maven.apache.org/POM/4.0.0}execution') 49 | 50 | exec_id = ET.SubElement(execution, '{http://maven.apache.org/POM/4.0.0}id') 51 | exec_id.text = "xml-doclet" 52 | 53 | phase = ET.SubElement(execution, '{http://maven.apache.org/POM/4.0.0}phase') 54 | phase.text = "prepare-package" 55 | 56 | goals = ET.SubElement(execution, '{http://maven.apache.org/POM/4.0.0}goals') 57 | goal = ET.SubElement(goals, '{http://maven.apache.org/POM/4.0.0}goal') 58 | goal.text = "javadoc" 59 | 60 | configuration = ET.SubElement(execution, '{http://maven.apache.org/POM/4.0.0}configuration') 61 | 62 | useStd = ET.SubElement(configuration, '{http://maven.apache.org/POM/4.0.0}useStandardDocletOptions') 63 | useStd.text = "false" 64 | 65 | doclet = ET.SubElement(configuration, '{http://maven.apache.org/POM/4.0.0}doclet') 66 | doclet.text = "com.manticore.tools.xmldoclet.XmlDoclet" 67 | 68 | additionalOptions = ET.SubElement(configuration, '{http://maven.apache.org/POM/4.0.0}additionalOptions') 69 | additionalOptions.text = "-d ${project.build.directory}" 70 | 71 | docletArtifact = ET.SubElement(configuration, '{http://maven.apache.org/POM/4.0.0}docletArtifact') 72 | da_groupId = ET.SubElement(docletArtifact, '{http://maven.apache.org/POM/4.0.0}groupId') 73 | da_groupId.text = "com.manticore-projects.tools" 74 | da_artifactId = ET.SubElement(docletArtifact, '{http://maven.apache.org/POM/4.0.0}artifactId') 75 | da_artifactId.text = "xml-doclet" 76 | da_version = ET.SubElement(docletArtifact, '{http://maven.apache.org/POM/4.0.0}version') 77 | da_version.text = xml_doclet_version 78 | da_classifier = ET.SubElement(docletArtifact, '{http://maven.apache.org/POM/4.0.0}classifier') 79 | da_classifier.text = "all" 80 | 81 | # Append the new plugin to the element 82 | plugins.append(plugin) 83 | 84 | # Pretty-print and write back to pom.xml 85 | rough_string = ET.tostring(root, 'utf-8') 86 | # Use minidom to pretty-print 87 | reparsed = minidom.parseString(rough_string) 88 | pretty_xml = reparsed.toprettyxml(indent=" ") 89 | 90 | # Remove blank lines 91 | pretty_xml_no_blanks = "\n".join([line for line in pretty_xml.split("\n") if line.strip()]) 92 | 93 | with open('pom.xml', 'w', encoding='utf-8') as f: 94 | f.write(pretty_xml_no_blanks) 95 | -------------------------------------------------------------------------------- /nix/tools/pom-tools/lib/remove-module-on-profile.sh: -------------------------------------------------------------------------------- 1 | xmlstarlet \ 2 | edit \ 3 | --inplace \ 4 | -N mvn=http://maven.apache.org/POM/4.0.0 \ 5 | --delete '/mvn:project/mvn:profiles/mvn:profile[mvn:id="'"$1"'"]/mvn:modules/mvn:module[text()="'"$2"'"]' \ 6 | pom.xml ./**/pom.xml 7 | -------------------------------------------------------------------------------- /nix/tools/pom-tools/lib/reset-maven-metadata-local-timestamp.sh: -------------------------------------------------------------------------------- 1 | shopt -s globstar 2 | 3 | xmlstarlet \ 4 | edit \ 5 | --inplace \ 6 | --update '/metadata/versioning/lastUpdated' \ 7 | --value "19800101000002" \ 8 | ./**/maven-metadata-local.xml 9 | 10 | -------------------------------------------------------------------------------- /nix/tools/pom-tools/lib/reset-project-build-timestamp.sh: -------------------------------------------------------------------------------- 1 | shopt -s globstar 2 | 3 | xmlstarlet \ 4 | edit \ 5 | --inplace \ 6 | -N mvn=http://maven.apache.org/POM/4.0.0 \ 7 | --subnode '/mvn:project/mvn:properties' \ 8 | --type elem \ 9 | -n "project.build.outputTimestamp" \ 10 | --value "1980-01-01T00:00:02Z" \ 11 | pom.xml ./**/pom.xml 12 | -------------------------------------------------------------------------------- /nix/tools/pom-tools/lib/update-dependency-version-by-groupId.sh: -------------------------------------------------------------------------------- 1 | shopt -s globstar 2 | 3 | xmlstarlet \ 4 | edit \ 5 | --inplace \ 6 | -N mvn=http://maven.apache.org/POM/4.0.0 \ 7 | --update '/mvn:project//mvn:dependencies/mvn:dependency/mvn:version[../mvn:groupId[text()='\'"$1"\'']]' \ 8 | --value "$2" \ 9 | pom.xml ./**/pom.xml 10 | -------------------------------------------------------------------------------- /nix/tools/pom-tools/lib/update-java-version.sh: -------------------------------------------------------------------------------- 1 | shopt -s globstar 2 | 3 | xmlstarlet edit \ 4 | --inplace \ 5 | -N mvn=http://maven.apache.org/POM/4.0.0 \ 6 | --update "//mvn:plugin/mvn:configuration/*[self::mvn:source or self::mvn:target]" \ 7 | --value "$1" \ 8 | pom.xml ./**/pom.xml 9 | -------------------------------------------------------------------------------- /nix/tools/pom-tools/lib/update-pkg-version.sh: -------------------------------------------------------------------------------- 1 | shopt -s globstar 2 | 3 | xmlstarlet \ 4 | edit \ 5 | --inplace \ 6 | -N mvn=http://maven.apache.org/POM/4.0.0 \ 7 | --update '/mvn:project/mvn:version' \ 8 | --value "$1" \ 9 | pom.xml ./**/pom.xml 10 | 11 | xmlstarlet \ 12 | edit \ 13 | --inplace \ 14 | -N mvn=http://maven.apache.org/POM/4.0.0 \ 15 | --update '/mvn:project/mvn:parent/mvn:version' \ 16 | --value "$1" \ 17 | pom.xml ./**/pom.xml 18 | -------------------------------------------------------------------------------- /nix/tools/pom-tools/lib/update-plugin-version-by-groupId.sh: -------------------------------------------------------------------------------- 1 | shopt -s globstar 2 | 3 | if [[ $# -ne 3 ]]; then 4 | echo "Usage: $0 " 5 | exit 1 6 | fi 7 | 8 | GROUP_ID="$1" 9 | ARTIFACT_ID="$2" 10 | NEW_VERSION="$3" 11 | 12 | xmlstarlet ed --inplace -N mvn=http://maven.apache.org/POM/4.0.0 \ 13 | --update "/mvn:project//mvn:build//mvn:plugin[mvn:groupId='$GROUP_ID' and mvn:artifactId='$ARTIFACT_ID']/mvn:version" \ 14 | --value "$NEW_VERSION" \ 15 | pom.xml ./**/pom.xml 16 | -------------------------------------------------------------------------------- /nix/tools/properties-to-json/default.nix: -------------------------------------------------------------------------------- 1 | { stdenv, python3, pandoc, makeWrapper, lib }: 2 | 3 | stdenv.mkDerivation { 4 | name = "properties-to-json"; 5 | dontUnpack = true; # No archive to unpack (using a single script file) 6 | 7 | # Dependencies 8 | nativeBuildInputs = [ makeWrapper ]; # needed for makeWrapper utility 9 | buildInputs = [ python3 pandoc ]; # python3 interpreter and pandoc at runtime 10 | 11 | installPhase = '' 12 | # Install the Python script to $out/bin and make it executable 13 | install -Dm755 ${./properties-to-json.py} $out/bin/properties-to-json 14 | 15 | # Patch the shebang to use the exact python3 path from Nix store 16 | patchShebangs $out/bin 17 | 18 | # Wrap the script to include pandoc in PATH at runtime 19 | wrapProgram $out/bin/properties-to-json \ 20 | --prefix PATH : ${pandoc}/bin 21 | ''; 22 | } 23 | -------------------------------------------------------------------------------- /nix/tools/properties-to-json/properties-to-json.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python3 2 | import sys 3 | import json 4 | import xml.etree.ElementTree as ET 5 | import html 6 | import subprocess 7 | 8 | 9 | def html_to_markdown(html_content): 10 | """ 11 | Convert HTML content to strict markdown using pandoc. 12 | Uses stdin/stdout instead of temporary files. 13 | """ 14 | if not html_content.strip(): 15 | return "" 16 | 17 | try: 18 | process = subprocess.Popen( 19 | ["pandoc", "--from=html", "--to=markdown_strict"], 20 | stdin=subprocess.PIPE, 21 | stdout=subprocess.PIPE, 22 | stderr=subprocess.PIPE, 23 | text=True 24 | ) 25 | stdout, stderr = process.communicate(input=html_content) 26 | 27 | if process.returncode != 0: 28 | print(f"Error converting HTML to markdown: {stderr}", 29 | file=sys.stderr) 30 | return html_content 31 | 32 | return stdout.strip() 33 | except Exception as e: 34 | print(f"Failed to convert HTML to markdown: {e}", file=sys.stderr) 35 | return html_content 36 | 37 | 38 | def load_properties(properties_file): 39 | """ 40 | Load properties from a Java properties file, 41 | skipping comments and duplicate lines. 42 | Trims whitespace from keys and values. 43 | """ 44 | props = {} 45 | seen_lines = set() 46 | 47 | with open(properties_file, "r", encoding="utf-8") as f: 48 | for line in f: 49 | line = line.strip() 50 | # Skip lines that start with '#' or don't contain '=' 51 | if not line or line.startswith('#') or '=' not in line: 52 | continue 53 | # Only process unique lines 54 | if line in seen_lines: 55 | continue 56 | seen_lines.add(line) 57 | 58 | # Split at the first '=' 59 | key, value = line.split('=', 1) 60 | key = key.strip() 61 | value = value.strip() if value is not None else "" 62 | props[key] = value 63 | 64 | return props 65 | 66 | 67 | def load_xml_descriptions(xml_file): 68 | """ 69 | Parse the XML file and return a mapping of preference 70 | constants to descriptions. 71 | """ 72 | tree = ET.parse(xml_file) 73 | root = tree.getroot() 74 | 75 | pref_info = {} 76 | for field in root.findall(".//field"): 77 | constant_elem = field.find("constant") 78 | comment_elem = field.find("comment") 79 | 80 | if constant_elem is None or constant_elem.text is None: 81 | continue 82 | 83 | # Remove surrounding quotes from constant text and trim whitespace 84 | constant_text = constant_elem.text.strip().strip('"') 85 | 86 | # Extract and unescape comment text 87 | comment_text = "" 88 | if comment_elem is not None: 89 | # Combine text and tail if present (to capture inner tags' text) 90 | comment_text = ''.join(comment_elem.itertext()).strip() 91 | comment_text = html.unescape(comment_text) 92 | # Convert HTML to markdown 93 | comment_text = html_to_markdown(comment_text) 94 | 95 | pref_info[constant_text] = comment_text 96 | 97 | return pref_info 98 | 99 | 100 | def main(properties_file, xml_file): 101 | # 1. Load properties 102 | master_prefs = load_properties(properties_file) 103 | 104 | # 2. Load XML descriptions 105 | pref_info = load_xml_descriptions(xml_file) 106 | 107 | # 3. Merge preferences with descriptions 108 | merged_prefs = {} 109 | for key, default_value in master_prefs.items(): 110 | description = pref_info.get(key, "") 111 | merged_prefs[key] = { 112 | "default": default_value, 113 | "description": description 114 | } 115 | 116 | # 4. Output merged JSON 117 | print(json.dumps(merged_prefs, indent=2, ensure_ascii=False)) 118 | 119 | 120 | if __name__ == "__main__": 121 | if len(sys.argv) != 3: 122 | print( 123 | (f"Usage: {sys.argv[0]} " 124 | "preferences.properties " 125 | "preferences-javadoc.xml"), 126 | file=sys.stderr) 127 | sys.exit(1) 128 | 129 | main(sys.argv[1], sys.argv[2]) 130 | -------------------------------------------------------------------------------- /nix/tools/update-fixed-output-derivations/default.nix: -------------------------------------------------------------------------------- 1 | { writers, python3Packages }: 2 | writers.writePython3Bin "update-fixed-output-derivations" { 3 | libraries = [ python3Packages.toposort ]; 4 | flakeIgnore = [ "E501" ]; 5 | } (builtins.readFile ./update-fixed-output-derivations.py) 6 | -------------------------------------------------------------------------------- /templates/README.md: -------------------------------------------------------------------------------- 1 | # AutoFirma-Nix Templates 2 | 3 | This directory contains flake templates for the three supported installation methods of autofirma-nix. 4 | 5 | ## Available Templates 6 | 7 | 1. **nixos-module** - System-wide installation for NixOS 8 | 2. **home-manager-nixos** - Per-user installation with Home Manager as a NixOS module 9 | 3. **home-manager-standalone** - Per-user installation with standalone Home Manager 10 | 11 | Each template can be used by running: 12 | 13 | ```bash 14 | nix flake new --template github:nix-community/autofirma-nix#template-name ./destination-directory 15 | ``` 16 | 17 | For example: 18 | 19 | ```bash 20 | nix flake new --template github:nix-community/autofirma-nix#nixos-module ./my-autofirma-system 21 | ``` -------------------------------------------------------------------------------- /templates/home-manager-standalone/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "Home Manager Standalone for AutoFirma (user-specific installation without NixOS)"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 | 7 | home-manager = { 8 | url = "github:nix-community/home-manager"; 9 | inputs.nixpkgs.follows = "nixpkgs"; 10 | }; 11 | 12 | autofirma-nix = { 13 | url = "github:nix-community/autofirma-nix"; 14 | # For stable release: url = "github:nix-community/autofirma-nix/release-24.11"; 15 | inputs.nixpkgs.follows = "nixpkgs"; 16 | }; 17 | }; 18 | 19 | nixConfig = { 20 | extra-substituters = [ 21 | "https://nix-community.cachix.org" 22 | ]; 23 | extra-trusted-public-keys = [ 24 | "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" 25 | ]; 26 | }; 27 | 28 | outputs = { self, nixpkgs, home-manager, autofirma-nix, ... }: 29 | let 30 | system = "x86_64-linux"; 31 | pkgs = nixpkgs.legacyPackages.${system}; 32 | in { 33 | homeConfigurations."myuser" = home-manager.lib.homeManagerConfiguration { 34 | inherit pkgs; 35 | 36 | modules = [ 37 | autofirma-nix.homeManagerModules.default 38 | 39 | ({pkgs, config, ... }: { 40 | home = { 41 | username = "myuser"; 42 | homeDirectory = "/home/myuser"; 43 | stateVersion = "23.11"; 44 | }; 45 | 46 | # =============================== 47 | # === AutoFirma Configuration === 48 | # =============================== 49 | programs.autofirma = { 50 | # Enable AutoFirma 51 | enable = true; 52 | 53 | # Firefox integration with specific profile(s) 54 | firefoxIntegration.profiles = { 55 | default = { 56 | enable = true; 57 | }; 58 | }; 59 | 60 | # Custom package (uncomment if needed) 61 | # package = pkgs.autofirma; 62 | 63 | # Custom truststore package (uncomment if needed) 64 | # truststore.package = pkgs.autofirma-truststore; 65 | 66 | # AutoFirma config options 67 | config = { 68 | # Avoid confirmation dialog when closing 69 | omitAskOnClose = true; 70 | 71 | # Enable JMultiCard functionality 72 | enabledJmulticard = true; 73 | 74 | # Allow invalid signatures 75 | allowInvalidSignatures = false; 76 | 77 | # Use implicit mode for CAdES signatures 78 | cadesImplicitMode = true; 79 | 80 | # More config options available - see home_manager_options.html 81 | }; 82 | }; 83 | 84 | # =============================== 85 | # === DNIeRemote Configuration === 86 | # =============================== 87 | programs.dnieremote = { 88 | # Enable DNIeRemote for using smartphone as DNIe reader 89 | enable = true; 90 | 91 | # Skip intro screen and go directly to USB or WiFi setup 92 | # Possible values: "no" (default), "usb", "wifi" 93 | jumpIntro = "no"; 94 | 95 | # Port for WiFi connection to smartphone 96 | wifiPort = 9501; 97 | 98 | # Port for USB connection to smartphone 99 | usbPort = 9501; 100 | 101 | # Custom package (uncomment if needed) 102 | # package = pkgs.dnieremote; 103 | }; 104 | 105 | # ======================================= 106 | # === FNMT Configurator Configuration === 107 | # ======================================= 108 | programs.configuradorfnmt = { 109 | # Enable FNMT certificate configuration tool 110 | enable = true; 111 | 112 | # Firefox integration with specific profile(s) 113 | firefoxIntegration.profiles = { 114 | default = { 115 | enable = true; 116 | }; 117 | }; 118 | 119 | # Custom package (uncomment if needed) 120 | # package = pkgs.configuradorfnmt; 121 | }; 122 | 123 | # ============================= 124 | # === Firefox Configuration === 125 | # ============================= 126 | programs.firefox = { 127 | enable = true; 128 | 129 | # Set up security devices for DNIe access 130 | policies = { 131 | SecurityDevices = { 132 | # For physical smart card readers (like DNIe) 133 | "OpenSC PKCS11" = "${pkgs.opensc}/lib/opensc-pkcs11.so"; 134 | 135 | # For smartphone NFC using DNIeRemote 136 | "DNIeRemote" = "${config.programs.dnieremote.finalPackage}/lib/libdnieremotepkcs11.so"; 137 | }; 138 | }; 139 | 140 | # Define Firefox profiles 141 | profiles.default = { 142 | id = 0; # Makes this the default profile 143 | }; 144 | }; 145 | 146 | }) 147 | ]; 148 | }; 149 | }; 150 | } 151 | -------------------------------------------------------------------------------- /templates/nixos-module/flake.nix: -------------------------------------------------------------------------------- 1 | { 2 | description = "NixOS system with AutoFirma (system-wide installation)"; 3 | 4 | inputs = { 5 | nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; 6 | 7 | autofirma-nix = { 8 | url = "github:nix-community/autofirma-nix"; 9 | # For stable release: url = "github:nix-community/autofirma-nix/release-24.11"; 10 | inputs.nixpkgs.follows = "nixpkgs"; 11 | }; 12 | }; 13 | 14 | nixConfig = { 15 | extra-substituters = [ 16 | "https://nix-community.cachix.org" 17 | ]; 18 | extra-trusted-public-keys = [ 19 | "nix-community.cachix.org-1:mB9FSh9qf2dCimDSUo8Zy7bkq5CX+/rkCWyvRCYg3Fs=" 20 | ]; 21 | }; 22 | 23 | outputs = { self, nixpkgs, autofirma-nix, ... }: { 24 | nixosConfigurations.mysystem = nixpkgs.lib.nixosSystem { 25 | system = "x86_64-linux"; 26 | 27 | modules = [ 28 | autofirma-nix.nixosModules.default 29 | 30 | ({ config, pkgs, ... }: { 31 | # Basic system configuration 32 | networking.hostName = "mysystem"; 33 | time.timeZone = "Europe/Madrid"; 34 | system.stateVersion = "23.11"; 35 | 36 | users.users.myuser = { 37 | isNormalUser = true; 38 | extraGroups = [ "wheel" "networkmanager" ]; 39 | }; 40 | 41 | # =============================== 42 | # === AutoFirma Configuration === 43 | # =============================== 44 | programs.autofirma = { 45 | # Enable AutoFirma 46 | enable = true; 47 | 48 | # Enable Firefox integration 49 | firefoxIntegration.enable = true; 50 | 51 | # Fix Java certificates (deprecated) 52 | # fixJavaCerts = false; 53 | 54 | # Custom package (uncomment if needed) 55 | # package = pkgs.autofirma; 56 | 57 | # Custom truststore package (uncomment if needed) 58 | # truststore.package = pkgs.autofirma-truststore; 59 | }; 60 | 61 | # ======================================= 62 | # === DNIeRemote Configuration === 63 | # ======================================= 64 | programs.dnieremote = { 65 | # Enable DNIeRemote for using smartphone as DNIe reader 66 | enable = true; 67 | 68 | # Skip intro screen and go directly to USB or WiFi setup 69 | # Possible values: "no" (default), "usb", "wifi" 70 | jumpIntro = "no"; 71 | 72 | # Port for WiFi connection to smartphone 73 | wifiPort = 9501; 74 | 75 | # Port for USB connection to smartphone 76 | usbPort = 9501; 77 | 78 | # Whether to open the firewall for the WiFi port 79 | openFirewall = false; 80 | 81 | # Custom package (uncomment if needed) 82 | # package = pkgs.dnieremote; 83 | }; 84 | 85 | # ======================================= 86 | # === FNMT Configurator Configuration === 87 | # ======================================= 88 | programs.configuradorfnmt = { 89 | # Enable FNMT certificate configuration tool 90 | enable = true; 91 | 92 | # Enable Firefox integration 93 | firefoxIntegration.enable = true; 94 | 95 | # Custom package (uncomment if needed) 96 | # package = pkgs.configuradorfnmt; 97 | }; 98 | 99 | # ============================= 100 | # === Firefox Configuration === 101 | # ============================= 102 | programs.firefox = { 103 | enable = true; 104 | 105 | # Set up security devices for DNIe access 106 | policies = { 107 | SecurityDevices = { 108 | # For physical smart card readers (like DNIe) 109 | "OpenSC PKCS#11" = "${pkgs.opensc}/lib/opensc-pkcs11.so"; 110 | 111 | # For smartphone NFC using DNIeRemote 112 | "DNIeRemote" = "${config.programs.dnieremote.finalPackage}/lib/libdnieremotepkcs11.so"; 113 | }; 114 | }; 115 | }; 116 | 117 | # Enable PC/SC smart card service 118 | services.pcscd.enable = true; 119 | }) 120 | ]; 121 | }; 122 | }; 123 | } 124 | --------------------------------------------------------------------------------