Skip to content

feat: Implement secure credential management with AES encryption - #8

Merged
MathCunha16 merged 7 commits into
mainfrom
feature/backend/credentials
Jul 17, 2026
Merged

feat: Implement secure credential management with AES encryption#8
MathCunha16 merged 7 commits into
mainfrom
feature/backend/credentials

Conversation

@MathCunha16

@MathCunha16 MathCunha16 commented Jul 14, 2026

Copy link
Copy Markdown
Owner

This pull request introduces a secure master password and vault locking mechanism to the backend, along with support for credential encryption. The changes include new domain models, use cases, exception handling, and implementation classes for master password setup, unlocking, and vault locking. The Bouncy Castle cryptography library replaces the previous dotenv dependency for enhanced security.

Security and Vault Management:

  • Added use cases and implementations for master password setup (SetupMasterPasswordUseCase, SetupMasterPasswordImpl), unlocking (UnlockVaultUseCase, UnlockVaultImpl), and locking the vault (LockVaultUseCase, LockVaultImpl), including secure key derivation and session management. [1] [2] [3] [4] [5] [6]
  • Introduced a check for master password setup status (CheckMasterPasswordSetupUseCase, CheckMasterPasswordSetupImpl). [1] [2]

Credential Management:

  • Added a new use case and implementation for creating credentials with encryption using the master key, ensuring payloads are securely handled and wiped from memory after use (CreateCredentialUseCase, CreateCredentialCommand, CreateCredentialImpl). [1] [2] [3]

Exception Handling:

  • Introduced custom exceptions for various vault and password states, including MasterPasswordAlreadyConfiguredException, MasterPasswordNotConfiguredException, VaultLockedException, InvalidMasterPasswordException, and CryptoException. [1] [2] [3] [4] [5]

Domain Model:

  • Added an AppSetting domain model for storing application settings such as password hash and salt.

Build System and Dependencies:

  • Replaced the dotenv dependency with Bouncy Castle for cryptographic operations in build.gradle.kts. [1] [2]

These changes lay the foundation for securely managing credentials and vault access in the backend.- Add CreateCredentialUseCase, CreateCredentialImpl, and associated domain models.

  • Introduce encrypted credential storage using AES encryption via Bouncy Castle.
  • Add database support for app settings and credentials with Liquibase changelogs.
  • Implement master password setup, lock, and unlock functionalities.
  • Provide persistence adapters for AppSetting and Credential entities.
  • Update Gradle dependencies with Bouncy Castle integration.

Summary by CodeRabbit

  • Novos Recursos
    • Adicionado gerenciamento completo de credenciais por projeto: criar, listar com paginação, consultar, atualizar e excluir.
    • Suporte a tipos de segredo: login, chave de API e texto livre.
    • Endpoints para senha mestra: configurar, desbloquear, bloquear e consultar status do cofre.
    • O cofre bloqueia automaticamente após 15 minutos de inatividade.
  • Segurança
    • Criptografia de credenciais com AES-GCM e derivação de chaves com Argon2.
    • Tratamento de erros e validações com respostas padronizadas.
    • Proteção reforçada para limpeza de dados sensíveis em memória.
  • Documentação
    • Orientações sobre proteção e higiene de dados sensíveis em memória.

- Add `CreateCredentialUseCase`, `CreateCredentialImpl`, and associated domain models.
- Introduce encrypted credential storage using AES encryption via Bouncy Castle.
- Add database support for app settings and credentials with Liquibase changelogs.
- Implement master password setup, lock, and unlock functionalities.
- Provide persistence adapters for `AppSetting` and `Credential` entities.
- Update Gradle dependencies with Bouncy Castle integration.
@MathCunha16 MathCunha16 self-assigned this Jul 14, 2026
@MathCunha16 MathCunha16 added documentation Improvements or additions to documentation enhancement New feature or request labels Jul 14, 2026
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: 16b7814c-fa5f-4664-bbfd-4167843f33f5

📥 Commits

Reviewing files that changed from the base of the PR and between cb624fa and 25fc626.

📒 Files selected for processing (26)
  • backend/src/main/java/com/devaulty/backend/BackendApplication.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/scheduler/VaultAutoLockScheduler.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/CredentialController.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/CredentialWebMapper.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/exception/GlobalExceptionHandler.java
  • backend/src/main/java/com/devaulty/backend/adapter/out/crypto/Argon2KeyDeriverAdapter.java
  • backend/src/main/java/com/devaulty/backend/adapter/out/crypto/BouncyCastleCryptoAdapter.java
  • backend/src/main/java/com/devaulty/backend/adapter/out/crypto/MasterKeySessionHolder.java
  • backend/src/main/java/com/devaulty/backend/application/impl/credential/CreateCredentialImpl.java
  • backend/src/main/java/com/devaulty/backend/application/impl/credential/DeleteCredentialImpl.java
  • backend/src/main/java/com/devaulty/backend/application/impl/credential/GetAllCredentialsByProjectImpl.java
  • backend/src/main/java/com/devaulty/backend/application/impl/credential/GetCredentialByIdImpl.java
  • backend/src/main/java/com/devaulty/backend/application/impl/credential/UpdateCredentialImpl.java
  • backend/src/main/java/com/devaulty/backend/application/impl/security/SetupMasterPasswordImpl.java
  • backend/src/main/java/com/devaulty/backend/application/port/out/security/CryptoPort.java
  • backend/src/main/java/com/devaulty/backend/application/port/out/security/MasterKeySessionPort.java
  • backend/src/test/java/com/devaulty/backend/adapter/in/scheduler/VaultAutoLockSchedulerTest.java
  • backend/src/test/java/com/devaulty/backend/adapter/in/web/credential/CredentialControllerIT.java
  • backend/src/test/java/com/devaulty/backend/adapter/in/web/security/SecurityControllerIT.java
  • backend/src/test/java/com/devaulty/backend/adapter/out/crypto/BouncyCastleCryptoAdapterTest.java
  • backend/src/test/java/com/devaulty/backend/adapter/out/crypto/MasterKeySessionHolderTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/credential/CreateCredentialImplTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/credential/DeleteCredentialImplTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/credential/GetAllCredentialsByProjectImplTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/credential/GetCredentialByIdImplTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/credential/UpdateCredentialImplTest.java
🚧 Files skipped from review as they are similar to previous changes (12)
  • backend/src/main/java/com/devaulty/backend/application/port/out/security/MasterKeySessionPort.java
  • backend/src/main/java/com/devaulty/backend/adapter/out/crypto/Argon2KeyDeriverAdapter.java
  • backend/src/main/java/com/devaulty/backend/application/impl/credential/GetAllCredentialsByProjectImpl.java
  • backend/src/main/java/com/devaulty/backend/application/impl/credential/DeleteCredentialImpl.java
  • backend/src/test/java/com/devaulty/backend/application/impl/credential/GetCredentialByIdImplTest.java
  • backend/src/main/java/com/devaulty/backend/application/impl/credential/UpdateCredentialImpl.java
  • backend/src/test/java/com/devaulty/backend/application/impl/credential/UpdateCredentialImplTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/credential/CreateCredentialImplTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/credential/DeleteCredentialImplTest.java
  • backend/src/test/java/com/devaulty/backend/adapter/in/web/security/SecurityControllerIT.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/CredentialController.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/CredentialWebMapper.java

📝 Walkthrough

Walkthrough

A alteração adiciona gerenciamento de credenciais criptografadas, persistência JPA, APIs REST, validações, Argon2, AES-GCM com Bouncy Castle, controle de sessão da chave mestra, expiração automática, migrações Liquibase e testes unitários e de integração.

Changes

Credenciais e segurança do cofre

Layer / File(s) Summary
Contratos e modelos de domínio
backend/src/main/java/com/devaulty/backend/application/port/**, backend/src/main/java/com/devaulty/backend/domain/**, backend/src/main/java/com/devaulty/backend/application/exception/**
Define contratos de credenciais, segurança, criptografia, modelos de domínio, tipos de segredo, DTO criptográfico e exceções.
Criptografia e sessão da chave mestra
backend/build.gradle.kts, backend/src/main/java/com/devaulty/backend/adapter/out/crypto/**, backend/src/main/java/com/devaulty/backend/application/impl/security/**, backend/src/main/java/com/devaulty/backend/adapter/in/scheduler/**
Adiciona Argon2, AES-GCM com AAD e Bouncy Castle, armazenamento da chave em memória, expiração por inatividade e operações de setup, unlock, lock e status.
Persistência e migrações
backend/src/main/java/com/devaulty/backend/adapter/out/persistence/**, backend/src/main/resources/db/changelog/**
Adiciona entidades, mappers, repositórios e adaptadores para credenciais e configurações, além das tabelas e includes Liquibase correspondentes.
Casos de uso de credenciais
backend/src/main/java/com/devaulty/backend/application/impl/credential/**, backend/src/main/java/com/devaulty/backend/infrastructure/configuration/CredentialBeanConfig.java
Implementa criação, consulta, listagem paginada, atualização e exclusão de credenciais com validações de projeto, sessão e configuração da senha mestra.
APIs web e validação
backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/**, backend/src/main/java/com/devaulty/backend/adapter/in/web/security/**, backend/src/main/java/com/devaulty/backend/adapter/in/web/exception/**
Adiciona contratos OpenAPI, controllers, DTOs, mapeamento de payloads sensíveis e handlers para exceções de segurança, criptografia e validação.
Testes e higiene de memória
backend/src/test/java/com/devaulty/backend/**, docs/security/memory-hygiene.md
Valida os fluxos de segurança, criptografia, credenciais, APIs, paginação, atualização, exclusão, expiração e limpeza de arrays sensíveis.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Cliente
  participant CredentialController
  participant CredentialWebMapper
  participant CredentialUseCase
  participant CryptoPort
  participant CredentialPersistenceAdapter
  Cliente->>CredentialController: envia requisição de credencial
  CredentialController->>CredentialWebMapper: converte request em command
  CredentialController->>CredentialUseCase: executa operação
  CredentialUseCase->>CryptoPort: cifra ou decifra payload com AAD
  CredentialUseCase->>CredentialPersistenceAdapter: salva ou consulta dados
  CredentialPersistenceAdapter-->>CredentialUseCase: retorna credencial
  CredentialUseCase-->>CredentialController: retorna dados descriptografados
  CredentialController-->>Cliente: responde via HTTP
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 2.48% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed O título resume bem a principal mudança: gerenciamento seguro de credenciais com criptografia AES.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch

Comment @coderabbitai help to get the list of available commands.

…d API integration:

- Add `DecryptedCredential` to include decrypted payload functionality.
- Introduce web-layer DTOs (`CreateCredentialRequest`, `CredentialSummaryResponse`, `CredentialViewResponse`) and `CredentialController`.
- Implement memory hygiene rules for sensitive data handling.
- Update `CreateCredentialUseCase` to return `DecryptedCredential` and document ownership transfer responsibilities.
- Add `MasterPasswordRequest` for security-related APIs.
- Replace `ENV_FILE` with `RAW_TEXT` in `CredentialSecretType`.
- Add new custom exception `JsonProcessingException`.
…security measures

- Implement `DeleteCredentialUseCase` and `DeleteCredentialImpl` for deleting credentials by ID.
- Add `GetCredentialByIdUseCase` and `GetCredentialByIdImpl` to retrieve and decrypt credential details.
- Introduce `UpdateCredentialUseCase` and `UpdateCredentialImpl` to update credentials securely.
- Create `GetAllCredentialsByProjectUseCase` for paginated retrieval of credential summaries.
- Extend `CredentialController` to handle all new CRUD operations.
- Update mappers and persistence layer to support new use cases.
- Ensure secure handling of sensitive data with memory hygiene practices.
- Refactor all controllers (`SecurityController`, `CredentialController`) to implement corresponding APIs (`SecurityApi`, `CredentialApi`) and ensure consistency.
- Add detailed OpenAPI documentation using annotations for all endpoints.
- Introduce comprehensive exception handling in `GlobalExceptionHandler` for secure and informative error responses.
- Implement new custom exceptions to handle domain-specific errors (e.g., master password, vault lock, etc.).
…status monitoring

- Add `GetSessionStatusUseCase` and `GetSessionStatusImpl` for retrieving cryptographic session status.
- Extend `SecurityController` and `SecurityApi` with a new `/vault/status` endpoint.
- Create `SessionStatus` record to represent session state and remaining timeout duration.
- Implement `VaultAutoLockScheduler` to automatically lock vault after 15 minutes of inactivity.
- Enhance `MasterKeySessionPort` and `MasterKeySessionHolder` with timeout and activity tracking.
…ndling

- Introduced unit tests for use cases such as updating, deleting credentials, and session management.
- Added integration tests for `CredentialController` endpoints with decrypted payload verification.
- Included detailed tests for cryptographic adapters (e.g., `BouncyCastleCryptoAdapter`, `Argon2KeyDeriverAdapter`).
- Enhanced `MasterKeySessionHolder` and `VaultAutoLockScheduler` test coverage with edge cases for session management and timeouts.
- Improved exception handling test coverage for security-related operations.
@MathCunha16
MathCunha16 marked this pull request as ready for review July 17, 2026 09:44

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 18

🧹 Nitpick comments (6)
backend/src/main/java/com/devaulty/backend/adapter/in/web/security/SecurityController.java (1)

31-34: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Mantenha a limpeza da senha somente no consumidor terminal.

Os casos de uso recebem a propriedade do array e já o zeram em finally. Remova os Arrays.fill do controller para preservar uma única responsabilidade de ownership.

Correção proposta
 setupMasterPasswordUseCase.execute(request.masterPassword());
-Arrays.fill(request.masterPassword(),'\0');
 return ResponseEntity.noContent().build();

 boolean result = unlockVaultUseCase.execute(request.masterPassword());
-Arrays.fill(request.masterPassword(),'\0');
 return ResponseEntity.ok(result);

Also applies to: 51-54

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/src/main/java/com/devaulty/backend/adapter/in/web/security/SecurityController.java`
around lines 31 - 34, Remova as chamadas `Arrays.fill` dos métodos
`setupMasterPassword` e do trecho adicional indicado no `SecurityController`.
Mantenha a limpeza dos arrays exclusivamente nos casos de uso, que já possuem a
propriedade e realizam o zeramento em `finally`.
backend/src/main/java/com/devaulty/backend/domain/model/Credential.java (1)

25-35: 🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

Evite aliasing dos arrays criptográficos.

Os setters armazenam as referências recebidas e os getters expõem os arrays internos. Como CreateCredentialImpl.java:57-124 passa diretamente os arrays de CryptoResultDto para Credential, uma mutação ou limpeza posterior pode corromper o ciphertext, IV ou auth tag. Use cópias defensivas nas fronteiras ou documente e imponha claramente a posse desses buffers.

Also applies to: 69-91

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@backend/src/main/java/com/devaulty/backend/domain/model/Credential.java`
around lines 25 - 35, Elimine o aliasing dos buffers criptográficos em
Credential: faça cópias defensivas de payloadEncrypted, encryptionIv e
encryptionAuthTag ao recebê-los e ao retorná-los nos getters, preservando null
quando aplicável. Atualize os setters correspondentes para copiar os arrays
recebidos, garantindo que CreateCredentialImpl não compartilhe referências
mutáveis com o estado interno.
backend/src/main/java/com/devaulty/backend/application/port/in/credential/GetAllCredentialsByProjectUseCase.java (1)

3-8: 📐 Maintainability & Code Quality | 🔵 Trivial | 🏗️ Heavy lift

Evite expor Page do Spring Data no port de aplicação.

Esse contrato acopla a camada de aplicação ao framework e força consumidores, como o adaptador de persistência, a compartilharem tipos de infraestrutura. Prefira um resultado de paginação próprio caso a arquitetura hexagonal seja um requisito deste projeto.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/src/main/java/com/devaulty/backend/application/port/in/credential/GetAllCredentialsByProjectUseCase.java`
around lines 3 - 8, Remova o acoplamento de GetAllCredentialsByProjectUseCase ao
Spring Data, substituindo Page por um tipo próprio de paginação pertencente à
aplicação. Atualize execute e os adaptadores/consumidores relacionados para usar
esse resultado, preservando os metadados e itens paginados necessários.
backend/src/test/java/com/devaulty/backend/application/impl/security/SetupMasterPasswordImplTest.java (1)

51-54: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Valide quais configurações foram persistidas.

times(2) também passa se o código salvar duas vezes o hash ou o salt. Capture os dois AppSetting e confirme as chaves master_password_hash e master_password_salt, além de valores não vazios.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/src/test/java/com/devaulty/backend/application/impl/security/SetupMasterPasswordImplTest.java`
around lines 51 - 54, Atualize o teste do fluxo de configuração da senha mestra
para capturar os dois argumentos salvos pelo appSettingRepositoryPort.save, em
vez de verificar apenas times(2). Valide que as configurações persistidas
possuem as chaves MASTER_PASSWORD_HASH_KEY e MASTER_PASSWORD_SALT_KEY, cada uma
com valor não vazio, mantendo as demais verificações existentes.
backend/src/test/java/com/devaulty/backend/application/impl/security/UnlockVaultImplTest.java (1)

75-76: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Verifique a limpeza de todo o password.

As asserções atuais validam somente password[0]; uma limpeza parcial ainda passaria. Compare o array completo com um char[] zerado.

-        assertEquals('\0', password[0]);
+        assertArrayEquals(new char[password.length], password);

Aplique a mesma alteração aos três cenários.

Also applies to: 103-104, 124-125

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/src/test/java/com/devaulty/backend/application/impl/security/UnlockVaultImplTest.java`
around lines 75 - 76, Atualize as asserções de limpeza nos três cenários de
UnlockVaultImplTest para comparar o array password completo com um char[] do
mesmo tamanho preenchido com '\0', em vez de validar apenas password[0].
Preserve as demais verificações dos testes.
backend/src/test/java/com/devaulty/backend/adapter/out/crypto/BouncyCastleCryptoAdapterTest.java (1)

27-54: 🔒 Security & Privacy | 🔵 Trivial | ⚡ Quick win

Adicione uma regressão contra reutilização de IV.

Criptografe o mesmo payload duas vezes e confirme que os IVs são diferentes. O teste atual aceitaria um IV fixo de 12 bytes, o que comprometeria a segurança do AES-GCM.

Teste sugerido
+    `@Test`
+    void shouldGenerateUniqueIvForEachEncryption() {
+        byte[] data = "same payload".getBytes(StandardCharsets.UTF_8);
+
+        CryptoResultDto first = cryptoAdapter.encrypt(data, secretKey);
+        CryptoResultDto second = cryptoAdapter.encrypt(data, secretKey);
+
+        assertFalse(java.util.Arrays.equals(first.iv(), second.iv()));
+    }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In
`@backend/src/test/java/com/devaulty/backend/adapter/out/crypto/BouncyCastleCryptoAdapterTest.java`
around lines 27 - 54, Atualize o teste shouldEncryptAndDecryptSuccessfully para
criptografar o mesmo originalData duas vezes e validar que os IVs retornados por
encryptResult são diferentes, mantendo as asserções existentes de tamanho e
decriptação. Use assertNotEquals ou equivalente para garantir que o AES-GCM não
reutiliza um IV fixo.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In
`@backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/CredentialController.java`:
- Around line 53-59: Validate the page and size parameters in
CredentialController.getAllByProject before invoking
getAllCredentialsByProjectUseCase.execute: reject page values below 0 and
enforce size within 1..100, returning the appropriate client validation response
for invalid inputs.
- Around line 45-48: Atualize o fluxo do método do CredentialController para
consumir e limpar decryptedCredential.decryptedPayload() antes de chamar
uriLocationBuilderHelper.buildLocationUri, ou assegure essa limpeza em um bloco
finally. Preserve a criação da resposta com mapper.toViewResponse e garanta que
o payload seja sempre zerado mesmo quando a construção da URI lançar uma
exceção.

In
`@backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/CredentialWebMapper.java`:
- Around line 109-122: Em CredentialWebMapper.java, nos trechos das linhas
109-122 e 93-103, elimine a materialização de segredos em String: serialize a
estrutura diretamente em buffers mutáveis, preferencialmente byte[], e não
desserialize o payload como Map<String, String>. Em
CredentialViewResponse.java, linhas 9-18, substitua a representação atual por
uma estrutura mutável que possa ser limpa imediatamente após a serialização
HTTP, preservando a limpeza dos buffers de segredo.

In
`@backend/src/main/java/com/devaulty/backend/adapter/in/web/exception/GlobalExceptionHandler.java`:
- Around line 35-38: Restrinja o handler handleIllegalArgumentException em
GlobalExceptionHandler para tratar apenas a exceção específica da aplicação
usada para entradas inválidas, em vez de capturar todo IllegalArgumentException.
Remova ou ajuste o handler genérico para que demais IllegalArgumentException
sigam o tratamento padrão de HTTP 500.

In
`@backend/src/main/java/com/devaulty/backend/adapter/in/web/security/dto/MasterPasswordRequest.java`:
- Around line 6-9: Ensure rejected requests have their secret character arrays
cleared during MethodArgumentNotValidException handling or an equivalent
validation-error path before they remain referenced by BindingResult. Apply this
to masterPassword in
backend/src/main/java/com/devaulty/backend/adapter/in/web/security/dto/MasterPasswordRequest.java
lines 6-9, all secret arrays in
backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/dto/CreateCredentialRequest.java
lines 9-36, and all secret arrays in
backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/dto/UpdateCredentialRequest.java
lines 8-44; preserve normal controller and mapper behavior for valid requests.

In
`@backend/src/main/java/com/devaulty/backend/adapter/out/crypto/Argon2KeyDeriverAdapter.java`:
- Around line 42-50: Atualize o método de derivação em Argon2KeyDeriverAdapter
para usar apenas os bytes válidos do ByteBuffer retornado por
StandardCharsets.UTF_8.encode, copiando buffer.remaining() antes de chamar
gen.generateBytes. No bloco finally existente, limpe também keyBytes além de
passwordBytes, preservando a SecretKeySpec retornada.

In
`@backend/src/main/java/com/devaulty/backend/adapter/out/crypto/MasterKeySessionHolder.java`:
- Around line 18-24: Atualize setKey() para zerar o conteúdo anterior de
rawKeyBytes antes de substituí-lo, preservando o comportamento quando a nova
chave não possui bytes codificados. Revise clear() e a documentação/mensagem
associada para remover a promessa de destruição segura, deixando explícito que a
limpeza é apenas best-effort; não tente zerar cópias internas mantidas por
masterKey.

In
`@backend/src/main/java/com/devaulty/backend/application/impl/credential/CreateCredentialImpl.java`:
- Around line 60-61: Atualize o fluxo de criação de credencial que usa
`payloadBytes` para limpar também o `ByteBuffer` intermediário criado pela
codificação de `command.payload()`. Antes de qualquer saída, sobrescreva o
conteúdo do `buffer` e, quando aplicável, de `buffer.array()`, além das limpezas
já existentes; não use apenas `clear()`, pois ele não zera os dados.

In
`@backend/src/main/java/com/devaulty/backend/application/impl/credential/GetCredentialByIdImpl.java`:
- Around line 54-58: Reordene as validações em GetCredentialByIdImpl e
UpdateCredentialImpl para executar
checkMasterPasswordSetupUseCase.isSetupRequired() antes de
masterKeySessionPort.getKey() e da validação de chave; mantenha as exceções e
demais verificações existentes inalteradas nos arquivos
backend/src/main/java/com/devaulty/backend/application/impl/credential/GetCredentialByIdImpl.java
(linhas 54-58) e
backend/src/main/java/com/devaulty/backend/application/impl/credential/UpdateCredentialImpl.java
(linhas 66-71).

In
`@backend/src/main/java/com/devaulty/backend/application/impl/security/SetupMasterPasswordImpl.java`:
- Around line 51-57: Altere o fluxo de SetupMasterPasswordImpl para publicar a
chave somente após o commit da transação: mantenha a derivação em deriveKey, mas
adie sessionHolder.setKey(secretKey) usando um callback afterCommit ou mecanismo
transacional equivalente. Preserve a persistência dos valores por
appSettingRepositoryPort.save e garanta que falhas no save ou no commit não
atualizem a sessão.

In
`@backend/src/main/java/com/devaulty/backend/application/port/in/credential/CreateCredentialCommand.java`:
- Around line 7-15: Valide secretType e payload no fluxo de CredentialWebMapper
antes de construir CreateCredentialCommand, rejeitando combinações ausentes ou
inconsistentes e evitando payload nulo. Propague essa falha como erro de
validação do cliente (4xx) no endpoint, em vez de permitir que
CreateCredentialImpl alcance CharBuffer.wrap(command.payload()) e gere
NullPointerException.

In
`@backend/src/main/java/com/devaulty/backend/application/port/out/security/CryptoPort.java`:
- Around line 9-11: Update the CryptoPort encrypt/decrypt contract to accept
stable AAD representing the credential context, such as canonically serialized
projectId and credentialId. Ensure credentialId is generated before encryption
when necessary, and propagate the same AAD to both AES-GCM operations via
Cipher.updateAAD(...) so encryption and decryption authenticate the binding.

In
`@backend/src/main/java/com/devaulty/backend/application/port/out/security/MasterKeySessionPort.java`:
- Around line 7-12: A expiração da sessão deve ser decidida atomicamente antes
de disponibilizar ou renovar a chave. Em MasterKeySessionPort, adicione uma
operação atômica para validar o timeout e obter a chave ou limpar a sessão;
implemente esse contrato em MasterKeySessionHolder, garantindo que getKey/touch
não renovem sessões expiradas; e altere VaultAutoLockScheduler para delegar a
decisão de expiração a essa operação, evitando que o scheduler remova uma sessão
recém-renovada. Sites envolvidos:
backend/src/main/java/com/devaulty/backend/application/port/out/security/MasterKeySessionPort.java
linhas 7-12;
backend/src/main/java/com/devaulty/backend/adapter/out/crypto/MasterKeySessionHolder.java
linhas 39-43;
backend/src/main/java/com/devaulty/backend/adapter/in/scheduler/VaultAutoLockScheduler.java
linhas 27-33.

In
`@backend/src/main/resources/db/changelog/changesets/002-create-projects-table.yaml`:
- Line 3: Restore the historical changeset identities: use id
001-create-projects-table through 005-create-notes-table in
backend/src/main/resources/db/changelog/changesets/002-create-projects-table.yaml:3,
003-create-snippets-table.yaml:3, 004-create-links-table.yaml:3,
005-create-problems-table.yaml:3, and 006-create-notes-table.yaml:3
respectively. In
backend/src/main/resources/db/changelog/db.changelog-master.yaml:3-21, preserve
the historical includes and append app-settings and credentials as new
changesets with unique identifiers after them.

In
`@backend/src/test/java/com/devaulty/backend/adapter/in/web/credential/CredentialControllerIT.java`:
- Around line 384-417: Strengthen the integration tests to verify persistence
and at-rest protection: in CredentialControllerIT.java:384-417, reload the
entity after update and assert the ciphertext, IV, and auth tag changed and
decrypt to the new payload; in CredentialControllerIT.java:76-104, reload the
entity and assert the stored payload excludes plaintext secrets and decrypts
successfully; in CredentialControllerIT.java:345-382, reload the entity and
verify its metadata while preserving the original ciphertext; in
SecurityControllerIT.java:33-49, assert the persisted hash and salt are
non-empty and the stored value differs from the original password.

In
`@backend/src/test/java/com/devaulty/backend/adapter/in/web/security/SecurityControllerIT.java`:
- Around line 72-85: Update the setup state in
setupMasterPassword_shouldReturnConflict_whenAlreadyConfigured and the
additionally referenced test to save both master_password_hash and
master_password_salt in AppSettingEntity, representing a complete configured
master-password state.

In
`@backend/src/test/java/com/devaulty/backend/application/impl/credential/GetAllCredentialsByProjectImplTest.java`:
- Around line 87-121: Inverta a ordem das validações no fluxo de execução de
getAllCredentialsUseCase.execute para verificar
checkMasterPasswordSetupUseCase.isSetupRequired() antes de classificar o cofre
como bloqueado por masterKeySessionPort.getKey() nulo. Atualize os testes
shouldThrowVaultLockedExceptionWhenKeyIsNull e
shouldThrowMasterPasswordNotConfiguredExceptionWhenSetupIsRequired para refletir
essa precedência, incluindo mocks e verificações de chamadas.

In
`@backend/src/test/java/com/devaulty/backend/application/impl/credential/UpdateCredentialImplTest.java`:
- Around line 108-109: Atualize o teste UpdateCredentialImplTest para verificar
que todos os caracteres de command.payload() foram zerados, em vez de validar
apenas o primeiro elemento; percorra o payload completo e preserve a expectativa
de que cada posição contenha '\0'.

---

Nitpick comments:
In
`@backend/src/main/java/com/devaulty/backend/adapter/in/web/security/SecurityController.java`:
- Around line 31-34: Remova as chamadas `Arrays.fill` dos métodos
`setupMasterPassword` e do trecho adicional indicado no `SecurityController`.
Mantenha a limpeza dos arrays exclusivamente nos casos de uso, que já possuem a
propriedade e realizam o zeramento em `finally`.

In
`@backend/src/main/java/com/devaulty/backend/application/port/in/credential/GetAllCredentialsByProjectUseCase.java`:
- Around line 3-8: Remova o acoplamento de GetAllCredentialsByProjectUseCase ao
Spring Data, substituindo Page por um tipo próprio de paginação pertencente à
aplicação. Atualize execute e os adaptadores/consumidores relacionados para usar
esse resultado, preservando os metadados e itens paginados necessários.

In `@backend/src/main/java/com/devaulty/backend/domain/model/Credential.java`:
- Around line 25-35: Elimine o aliasing dos buffers criptográficos em
Credential: faça cópias defensivas de payloadEncrypted, encryptionIv e
encryptionAuthTag ao recebê-los e ao retorná-los nos getters, preservando null
quando aplicável. Atualize os setters correspondentes para copiar os arrays
recebidos, garantindo que CreateCredentialImpl não compartilhe referências
mutáveis com o estado interno.

In
`@backend/src/test/java/com/devaulty/backend/adapter/out/crypto/BouncyCastleCryptoAdapterTest.java`:
- Around line 27-54: Atualize o teste shouldEncryptAndDecryptSuccessfully para
criptografar o mesmo originalData duas vezes e validar que os IVs retornados por
encryptResult são diferentes, mantendo as asserções existentes de tamanho e
decriptação. Use assertNotEquals ou equivalente para garantir que o AES-GCM não
reutiliza um IV fixo.

In
`@backend/src/test/java/com/devaulty/backend/application/impl/security/SetupMasterPasswordImplTest.java`:
- Around line 51-54: Atualize o teste do fluxo de configuração da senha mestra
para capturar os dois argumentos salvos pelo appSettingRepositoryPort.save, em
vez de verificar apenas times(2). Valide que as configurações persistidas
possuem as chaves MASTER_PASSWORD_HASH_KEY e MASTER_PASSWORD_SALT_KEY, cada uma
com valor não vazio, mantendo as demais verificações existentes.

In
`@backend/src/test/java/com/devaulty/backend/application/impl/security/UnlockVaultImplTest.java`:
- Around line 75-76: Atualize as asserções de limpeza nos três cenários de
UnlockVaultImplTest para comparar o array password completo com um char[] do
mesmo tamanho preenchido com '\0', em vez de validar apenas password[0].
Preserve as demais verificações dos testes.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI (base), Organization UI (inherited)

Review profile: CHILL

Plan: Pro

Run ID: a66a325c-339d-466c-bee0-7b8eb40459f8

📥 Commits

Reviewing files that changed from the base of the PR and between 319f377 and cb624fa.

📒 Files selected for processing (91)
  • backend/build.gradle.kts
  • backend/src/main/java/com/devaulty/backend/adapter/in/scheduler/VaultAutoLockScheduler.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/CredentialApi.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/CredentialController.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/CredentialWebMapper.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/dto/CreateCredentialRequest.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/dto/CredentialSummaryResponse.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/dto/CredentialViewResponse.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/credential/dto/UpdateCredentialRequest.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/exception/GlobalExceptionHandler.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/security/SecurityApi.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/security/SecurityController.java
  • backend/src/main/java/com/devaulty/backend/adapter/in/web/security/dto/MasterPasswordRequest.java
  • backend/src/main/java/com/devaulty/backend/adapter/out/crypto/Argon2KeyDeriverAdapter.java
  • backend/src/main/java/com/devaulty/backend/adapter/out/crypto/BouncyCastleCryptoAdapter.java
  • backend/src/main/java/com/devaulty/backend/adapter/out/crypto/MasterKeySessionHolder.java
  • backend/src/main/java/com/devaulty/backend/adapter/out/persistence/credential/CredentialEntity.java
  • backend/src/main/java/com/devaulty/backend/adapter/out/persistence/credential/CredentialMapper.java
  • backend/src/main/java/com/devaulty/backend/adapter/out/persistence/credential/CredentialPersistenceAdapter.java
  • backend/src/main/java/com/devaulty/backend/adapter/out/persistence/credential/SpringDataCredentialRepository.java
  • backend/src/main/java/com/devaulty/backend/adapter/out/persistence/setting/AppSettingEntity.java
  • backend/src/main/java/com/devaulty/backend/adapter/out/persistence/setting/AppSettingMapper.java
  • backend/src/main/java/com/devaulty/backend/adapter/out/persistence/setting/AppSettingPersistenceAdapter.java
  • backend/src/main/java/com/devaulty/backend/adapter/out/persistence/setting/SpringDataAppSettingRepository.java
  • backend/src/main/java/com/devaulty/backend/application/exception/CryptoException.java
  • backend/src/main/java/com/devaulty/backend/application/exception/InvalidMasterPasswordException.java
  • backend/src/main/java/com/devaulty/backend/application/exception/JsonProcessingException.java
  • backend/src/main/java/com/devaulty/backend/application/exception/MasterPasswordAlreadyConfiguredException.java
  • backend/src/main/java/com/devaulty/backend/application/exception/MasterPasswordNotConfiguredException.java
  • backend/src/main/java/com/devaulty/backend/application/exception/VaultLockedException.java
  • backend/src/main/java/com/devaulty/backend/application/impl/credential/CreateCredentialImpl.java
  • backend/src/main/java/com/devaulty/backend/application/impl/credential/DeleteCredentialImpl.java
  • backend/src/main/java/com/devaulty/backend/application/impl/credential/GetAllCredentialsByProjectImpl.java
  • backend/src/main/java/com/devaulty/backend/application/impl/credential/GetCredentialByIdImpl.java
  • backend/src/main/java/com/devaulty/backend/application/impl/credential/UpdateCredentialImpl.java
  • backend/src/main/java/com/devaulty/backend/application/impl/security/CheckMasterPasswordSetupImpl.java
  • backend/src/main/java/com/devaulty/backend/application/impl/security/GetSessionStatusImpl.java
  • backend/src/main/java/com/devaulty/backend/application/impl/security/LockVaultImpl.java
  • backend/src/main/java/com/devaulty/backend/application/impl/security/SetupMasterPasswordImpl.java
  • backend/src/main/java/com/devaulty/backend/application/impl/security/UnlockVaultImpl.java
  • backend/src/main/java/com/devaulty/backend/application/port/in/credential/CreateCredentialCommand.java
  • backend/src/main/java/com/devaulty/backend/application/port/in/credential/CreateCredentialUseCase.java
  • backend/src/main/java/com/devaulty/backend/application/port/in/credential/CredentialSummary.java
  • backend/src/main/java/com/devaulty/backend/application/port/in/credential/DecryptedCredential.java
  • backend/src/main/java/com/devaulty/backend/application/port/in/credential/DeleteCredentialUseCase.java
  • backend/src/main/java/com/devaulty/backend/application/port/in/credential/GetAllCredentialsByProjectUseCase.java
  • backend/src/main/java/com/devaulty/backend/application/port/in/credential/GetCredentialByIdUseCase.java
  • backend/src/main/java/com/devaulty/backend/application/port/in/credential/UpdateCredentialCommand.java
  • backend/src/main/java/com/devaulty/backend/application/port/in/credential/UpdateCredentialUseCase.java
  • backend/src/main/java/com/devaulty/backend/application/port/in/security/CheckMasterPasswordSetupUseCase.java
  • backend/src/main/java/com/devaulty/backend/application/port/in/security/GetSessionStatusUseCase.java
  • backend/src/main/java/com/devaulty/backend/application/port/in/security/LockVaultUseCase.java
  • backend/src/main/java/com/devaulty/backend/application/port/in/security/SessionStatus.java
  • backend/src/main/java/com/devaulty/backend/application/port/in/security/SetupMasterPasswordUseCase.java
  • backend/src/main/java/com/devaulty/backend/application/port/in/security/UnlockVaultUseCase.java
  • backend/src/main/java/com/devaulty/backend/application/port/out/persistence/AppSettingRepositoryPort.java
  • backend/src/main/java/com/devaulty/backend/application/port/out/persistence/CredentialRepositoryPort.java
  • backend/src/main/java/com/devaulty/backend/application/port/out/security/CryptoPort.java
  • backend/src/main/java/com/devaulty/backend/application/port/out/security/KeyDerivationPort.java
  • backend/src/main/java/com/devaulty/backend/application/port/out/security/MasterKeySessionPort.java
  • backend/src/main/java/com/devaulty/backend/application/port/out/security/dto/CryptoResultDto.java
  • backend/src/main/java/com/devaulty/backend/domain/model/AppSetting.java
  • backend/src/main/java/com/devaulty/backend/domain/model/Credential.java
  • backend/src/main/java/com/devaulty/backend/domain/model/enums/CredentialSecretType.java
  • backend/src/main/java/com/devaulty/backend/infrastructure/configuration/CredentialBeanConfig.java
  • backend/src/main/java/com/devaulty/backend/infrastructure/configuration/SecurityBeanConfig.java
  • backend/src/main/resources/db/changelog/changesets/001-create-app-settings-table.yaml
  • backend/src/main/resources/db/changelog/changesets/002-create-projects-table.yaml
  • backend/src/main/resources/db/changelog/changesets/003-create-snippets-table.yaml
  • backend/src/main/resources/db/changelog/changesets/004-create-links-table.yaml
  • backend/src/main/resources/db/changelog/changesets/005-create-problems-table.yaml
  • backend/src/main/resources/db/changelog/changesets/006-create-notes-table.yaml
  • backend/src/main/resources/db/changelog/changesets/007-create-credentials-table.yaml
  • backend/src/main/resources/db/changelog/db.changelog-master.yaml
  • backend/src/test/java/com/devaulty/backend/adapter/in/scheduler/VaultAutoLockSchedulerTest.java
  • backend/src/test/java/com/devaulty/backend/adapter/in/web/credential/CredentialControllerIT.java
  • backend/src/test/java/com/devaulty/backend/adapter/in/web/security/SecurityControllerIT.java
  • backend/src/test/java/com/devaulty/backend/adapter/out/crypto/Argon2KeyDeriverAdapterTest.java
  • backend/src/test/java/com/devaulty/backend/adapter/out/crypto/BouncyCastleCryptoAdapterTest.java
  • backend/src/test/java/com/devaulty/backend/adapter/out/crypto/MasterKeySessionHolderTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/credential/CreateCredentialImplTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/credential/DeleteCredentialImplTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/credential/GetAllCredentialsByProjectImplTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/credential/GetCredentialByIdImplTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/credential/UpdateCredentialImplTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/security/CheckMasterPasswordSetupImplTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/security/GetSessionStatusImplTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/security/LockVaultImplTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/security/SetupMasterPasswordImplTest.java
  • backend/src/test/java/com/devaulty/backend/application/impl/security/UnlockVaultImplTest.java
  • docs/security/memory-hygiene.md

…ssion management

- Introduce AAD (Additional Authenticated Data) for cryptographic operations to enhance security.
- Add secure memory clearance for sensitive data (`ByteBuffer`, arrays) in key workflows to improve hygiene.
- Implement `computeAad()` methods in credential use cases to include AAD in encryption and decryption.
- Refactor `MasterKeySessionHolder` with inactivity timeout checks and ensure secure session clearance on expiry.
- Update `VaultAutoLockScheduler` to use new session expiration logic.
- Add stricter validation for `CreateCredentialRequest` and `UpdateCredentialRequest` with improved error messaging.
- Refactor cryptographic tests to cover AAD scenarios and edge cases.
@MathCunha16
MathCunha16 merged commit 1d8f7af into main Jul 17, 2026
1 check passed
@MathCunha16
MathCunha16 deleted the feature/backend/credentials branch July 17, 2026 12:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

documentation Improvements or additions to documentation enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant