Auth completo (Argon2id + JWT/refresh rotativo), permissões, Companies e OpenAPI
- Auth (apps/api/src/auth/): Argon2id com parâmetros versionados
(ADR-0005), access token JWT de 15min, refresh token opaco de 256 bits
com rotação e detecção de replay (reuso de token já rotacionado revoga
toda a cadeia de sessões do usuário). Endpoints /api/v1/auth/
{login,refresh,logout,me}.
- Permissões resource+action+scope (ADR-0004) via PermissionGuard,
resolvidas do banco a cada request (nunca cacheadas no JWT) — mudança
de papel tem efeito imediato. super_admin com bypass hardcoded,
espelhando a trava já existente no banco.
- Companies (migration + CRUD): leitura aberta a qualquer autenticado,
escrita restrita a companies:manage; validação de CNPJ via
packages/domain-shared (dígito verificador).
- SeedService: cria o primeiro super_admin a partir de
EDEN_SUPERADMIN_EMAIL/PASSWORD só quando `users` está vazia.
- OpenAPI/Swagger em /api/docs; ValidationPipe global com
whitelist+forbidNonWhitelisted (proteção contra mass-assignment).
- packages/database: repositórios (roles/users/sessions/audit/companies)
reutilizáveis por api e worker.
Validado manualmente contra a stack real (não só typecheck): login com
senha errada → 401 genérico; refresh rotaciona e invalida o token
anterior; reuso do token antigo → replay detectado, cadeia revogada;
logout idempotente; audit log com a sequência completa de eventos;
CNPJ inválido rejeitado; mass-assignment rejeitado.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -10,7 +10,11 @@
|
||||
"typecheck": "tsc -p tsconfig.json --noEmit",
|
||||
"lint": "echo 'no linter configured yet'"
|
||||
},
|
||||
"dependencies": {
|
||||
"zod": "^3.24.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/node": "^22.10.5",
|
||||
"typescript": "^5.7.3"
|
||||
}
|
||||
}
|
||||
|
||||
50
packages/config/src/env-schema.ts
Normal file
50
packages/config/src/env-schema.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { z } from "zod";
|
||||
|
||||
/**
|
||||
* Fail fast on boot if a required secret/config value is missing — same
|
||||
* philosophy as the legacy's JWT_SECRET/SEED_ADMIN_* checks (eden.md §5.6).
|
||||
* Never fall back to an insecure default for a secret.
|
||||
*/
|
||||
export const envSchema = z.object({
|
||||
DATABASE_URL: z.string().min(1, "DATABASE_URL é obrigatório"),
|
||||
EDEN_API_PORT: z.coerce.number().int().positive().default(8080),
|
||||
|
||||
JWT_SIGNING_SECRET: z.string().min(32, "JWT_SIGNING_SECRET precisa ter ao menos 32 caracteres"),
|
||||
SIGNATURE_OTP_SECRET: z.string().min(32).optional(),
|
||||
EDEN_FIELD_ENCRYPTION_KEY: z
|
||||
.string()
|
||||
.min(32, "EDEN_FIELD_ENCRYPTION_KEY precisa ter ao menos 32 caracteres")
|
||||
.optional(),
|
||||
|
||||
EDEN_SUPERADMIN_EMAIL: z.string().email().optional(),
|
||||
EDEN_SUPERADMIN_PASSWORD: z.string().min(8).optional(),
|
||||
|
||||
SMTP_HOST: z.string().optional(),
|
||||
SMTP_PORT: z.coerce.number().int().positive().default(465),
|
||||
SMTP_USER: z.string().optional(),
|
||||
SMTP_PASS: z.string().optional(),
|
||||
SMTP_FROM: z.string().optional(),
|
||||
|
||||
S3_ENDPOINT: z.string().optional(),
|
||||
S3_REGION: z.string().default("us-east-1"),
|
||||
S3_FORCE_PATH_STYLE: z
|
||||
.string()
|
||||
.default("true")
|
||||
.transform((v) => v === "true"),
|
||||
S3_ACCESS_KEY_ID: z.string().optional(),
|
||||
S3_SECRET_ACCESS_KEY: z.string().optional(),
|
||||
S3_BUCKET: z.string().optional(),
|
||||
|
||||
PUBLIC_BASE_URL: z.string().optional(),
|
||||
});
|
||||
|
||||
export type EdenEnv = z.infer<typeof envSchema>;
|
||||
|
||||
export function loadEnv(source: NodeJS.ProcessEnv = process.env): EdenEnv {
|
||||
const result = envSchema.safeParse(source);
|
||||
if (!result.success) {
|
||||
const issues = result.error.issues.map((i) => ` - ${i.path.join(".")}: ${i.message}`).join("\n");
|
||||
throw new Error(`Configuração de ambiente inválida:\n${issues}`);
|
||||
}
|
||||
return result.data;
|
||||
}
|
||||
@@ -1,6 +1 @@
|
||||
/**
|
||||
* Shared env-var schema/validation (fail fast on boot if a required var is
|
||||
* missing — same philosophy as the legacy's JWT_SECRET/SEED_ADMIN_* checks,
|
||||
* eden.md §5.6). Placeholder until apps/api's config module needs it.
|
||||
*/
|
||||
export const CONFIG_PACKAGE_VERSION = "0.1.0";
|
||||
export { envSchema, loadEnv, type EdenEnv } from "./env-schema.js";
|
||||
|
||||
Reference in New Issue
Block a user