| 1 |
Conta criada automaticamente na primeira requisição autenticada (JIT — sem POST /accounts) |
Identity/AccountProvisioningMiddleware.cs |
Sem middleware ativo, GET /accounts/me retorna 404 na primeira visita |
| 2 |
Idempotência no provisionamento: se UID já existe, retorna sem erro |
Application/Accounts/Commands/EnsureAccountProvisioned/EnsureAccountProvisionedHandler.cs:18 |
Sem a guarda, race condition cria duplicata e estoura constraint de PK |
| 3 |
Race condition de PK no provisionamento absorvida silenciosamente (log Debug) |
EnsureAccountProvisionedHandler.cs:35 |
Sem esse catch, múltiplas requisições simultâneas do mesmo usuário retornam 409 inesperado |
| 4 |
Colisão de e-mail com UID diferente → ConflictException → 409 |
EnsureAccountProvisionedHandler.cs:21-24 |
Sem a verificação, dois Firebase UIDs poderiam compartilhar o mesmo e-mail |
| 5 |
Nickname: 3–20 chars, somente [A-Za-z0-9 _] |
Domain/Accounts/Account.cs:74 (NicknameRegex) |
Nickname inválido lança DomainException → 422 ao provisionar |
| 6 |
Nickname derivado do displayName do Firebase; se inválido, usa local-part do e-mail sanitizado |
Application/Accounts/Commands/EnsureAccountProvisioned/EnsureAccountProvisionedHandler.cs:43-67 |
Usuários sem displayName recebem apelido gerado; não falha o provisionamento |
| 7 |
E-mail normalizado para lowercase e validado por regex antes de persistir |
Domain/BuildingBlocks/Email.cs:33-36 |
E-mail inválido lança DomainException → 422 |
| 8 |
Nonce de vínculo de carteira expira em 5 minutos |
Application/Accounts/Commands/RequestWalletLinkNonce/RequestWalletLinkNonceHandler.cs:15 |
Após expiração, LinkWallet retorna 410; usuário deve solicitar novo nonce |
| 9 |
Nonce não recriado se ainda válido — mesmo challenge retornado ao cliente |
RequestWalletLinkNonceHandler.cs:32 |
Impede rotação desnecessária; garante que assinatura feita pouco antes ainda seja aceita |
| 10 |
Solicitação de nonce com carteira já vinculada → 409 |
RequestWalletLinkNonceHandler.cs:24-27 |
Sem essa guarda, usuário com carteira poderia iniciar novo fluxo de vínculo |
| 11 |
Assinatura SIWE verificada por ECDSA EcRecover — endereço recuperado deve ser igual ao informado |
Application/Accounts/Commands/LinkWallet/LinkWalletHandler.cs:25-28 |
Assinatura de outro endereço seria aceita (impersonação) |
| 12 |
address validado por regex EVM (^0x[0-9a-fA-F]{40}$) antes mesmo do EcRecover |
Application/Accounts/Commands/LinkWallet/LinkWalletValidator.cs:9-13 |
Sem pré-validação, strings inválidas chegam ao Nethereum e lançam exceção não mapeada |
| 13 |
signature validado: ^0x[0-9a-fA-F]{130}$ (65 bytes hex) |
Application/Accounts/Commands/LinkWallet/LinkWalletValidator.cs:15-19 |
Signature mal formada → 422 com campo indicado |
| 14 |
Nonce consumido (removido) no commit bem-sucedido do vínculo — anti-replay |
LinkWalletHandler.cs:32 |
Sem remoção, a mesma assinatura poderia ser reutilizada |
| 15 |
Carteira já vinculada a outra conta → ConflictException mapeada para WalletAlreadyLinkedException → 409 |
LinkWalletHandler.cs:38-41 |
Sem tratamento de ConflictException do DB, o erro vaza como 500 |
| 16 |
Endereço EVM na conta salvo na forma retornada pelo EcRecover (não o endereço fornecido pelo cliente) |
LinkWalletHandler.cs:30 (account.LinkWallet(recovered)) |
Usar o endereço do cliente permitiria vincular endereço diferente do que foi realmente assinado |
| 17 |
account.LinkWallet valida regex EVM no domínio antes de persistir |
Domain/Accounts/Account.cs:46-50 |
Inconsistência entre validation da Application e do Domain — Domain é a última barreira |
| 18 |
Listings entregues ao cliente somente com status == "Active" (filtro server-side, não via Gridify) |
Infrastructure.Persistence/Repositories/Views/ListingQueryService.cs:18-21 |
Sem o filtro, listings cancelados/comprados aparecem na API |
| 19 |
Pares de staking entregues somente com status == "Staked" e staker == address |
Infrastructure.Persistence/Repositories/Views/StakingQueryService.cs:21 |
Sem o filtro, pares unstaked aparecem na listagem do usuário |
| 20 |
NFTs burned excluídos da listagem por carteira |
Infrastructure.Persistence/Repositories/Views/NftQueryService.cs (filtro !n.Burned) |
NFTs queimados apareceriam na coleção do usuário |
| 21 |
DefaultOrderBy injetado pelo handler quando orderBy ausente — garantia de paginação determinística |
GetListingsHandler.cs:9 ("listedAtBlock desc"); GetAccountStakingHandler.cs:9 ("stakedAt desc") |
Sem ordem padrão, Postgres pode retornar páginas em ordens diferentes — itens duplicados ou pulados |
| 22 |
Campos BigInteger (tokenId, price, supply, etc.) serializados como string para preservar precisão full (78 dígitos) |
Application/*/Dtos/*.cs (todos os DTOs com string para valores on-chain) |
long/decimal truncaria valores acima de 2^63 / 10^28 — corrupção silenciosa de dados on-chain |
| 23 |
Paginação: page 1–200, pageSize 1–100, filter ≤ 500 chars, orderBy ≤ 200 chars |
Application/_Querying/GridifyHardLimits.cs + PagedRequestValidator.cs |
Sem limites, query injection via Gridify ou queries sem índice podem degradar o DB |
| 24 |
GridifyGlobalConfiguration.IgnoreNotMappedFields = false — campo não mapeado → exceção |
Application/_Extensions/DIExtension.cs:41 |
Com true, clientes receberiam resultados sem filtro ao digitar campo errado |
| 25 |
Resumo de transparência em cache de 30 s (IMemoryCache) |
Application/Transparency/Queries/GetSummary/GetSummaryHandler.cs:9 |
Sem cache, cada GET /transparency/summary faz 5 queries ao DB (incluindo SUM full-scan) |
| 26 |
SaveChangesMappingExceptionsAsync converte PostgresException 23505 em ConflictException |
Infrastructure.Persistence/DbContextSaveChangesExtensions.cs:22-25 |
Sem mapeamento, DbUpdateException chega como 500 em vez de 409 |
| 27 |
AuditingInterceptor injeta CreatedAt / UpdatedAt automaticamente via IAuditable |
Infrastructure.Persistence/AuditingInterceptor.cs |
Sem o interceptor, campos de auditoria ficam nulos |
| 28 |
JSON: camelCase, enum como string snake_case upper (ACTIVE/DISABLED), nulls omitidos |
Api/Web/JsonDefaults.cs |
Serialização inconsistente quebraria clientes que dependem do formato |
| 29 |
Firebase JWT validado com issuer securetoken.google.com/<projectId> e audience <projectId> |
Api/Identity/FirebaseJwtExtensions.cs:28-33 |
Tokens de outro projeto seriam aceitos (vazamento cross-tenant) |
| 30 |
Claim user_id preferida sobre sub para ID do usuário |
Api/Identity/IdentityClaims.cs:5-6 |
Firebase emite ambos; sub é o fallback para compatibilidade |
| 31 |
Subscribe no SignalR valida endereço EVM; inválido → HubException (não propaga stack trace) |
Api/Hubs/EventsHub.cs:13 |
Sem validação, grupo por string arbitrária — possível vetor de enumeração de grupos |
| 32 |
forgeFulfilled enviado apenas para o grupo do comprador (hub.Clients.Group(ev.Buyer)) |
Api/Realtime/MarketplaceEventsListener.cs:130 |
Enviar para All vazaria dados de forge de outros usuários |
| 33 |
EnableRetryOnFailure(3, 5s) configurado no Npgsql — resiliência no EF Core |
Infrastructure.Persistence/_Extensions/DIExtension.cs:34-35 |
Sem retry, falhas transitórias de rede derrubam requisições diretamente |