- extensions table (tenant-scoped, RLS): number, sip_password_enc
(AES-256-GCM via packages/shared/src/crypto.ts), caller_id, context,
sofia_profile, codecs, max_registrations
- apps/api/src/extensions: CRUD (POST/GET/GET:id/DELETE), protected by a
new generic PermissionGuard (@RequirePermission decorator), tenant
resolved only from the JWT (never trusted from the client)
- SIP password is returned in plaintext only once, in the create response;
toPublicExtension() explicitly destructures the encrypted field out
(not a spread) so it can't leak by accident
- b2bcall-fs-config now resolves real directory data: Tenant.telephonyDomain
-> Extension.number, decrypts the password, builds proper directory XML
including a dial-string param (missing it caused originate to fail with
MANDATORY_IE_MISSING instead of the expected USER_NOT_REGISTERED)
- pinned FreeSWITCH's 357737{domain} to a stable value (b2bcall.local) via a
vars.xml patch in the Dockerfile -- it previously used the container's
dynamic IP, which could never match a stored telephony_domain
- added HTTP Basic auth between FreeSWITCH and fs-config
(gateway-credentials, timingSafeEqual comparison) now that the service
returns real secret data, closing the gap flagged as pending in the XML
Curl phase instead of leaving it open
- found and fixed: PermissionGuard's constructor-injected Reflector came
back undefined at runtime under tsx/esbuild (unreliable cross-file
decorator metadata emission) -- fixed with an explicit @Inject(Reflector);
worth watching for in future guards/services run via tsx
- verified end-to-end: create extension -> originate user/<ext> reports
USER_NOT_REGISTERED (found, not registered) -> delete -> back to
SUBSCRIBER_ABSENT (not found); password never reappears in any GET;
unauthenticated fs-config requests get 401
- docs/EXTENSIONS.md
25 lines
871 B
Docker
25 lines
871 B
Docker
# syntax=docker/dockerfile:1.7
|
|
FROM node:22-slim
|
|
|
|
RUN corepack enable && corepack prepare pnpm@11.24.0 --activate
|
|
|
|
WORKDIR /repo
|
|
|
|
COPY pnpm-workspace.yaml package.json pnpm-lock.yaml tsconfig.base.json ./
|
|
COPY packages/types packages/types
|
|
COPY packages/shared packages/shared
|
|
COPY packages/telephony packages/telephony
|
|
COPY packages/database packages/database
|
|
COPY apps/freeswitch-config apps/freeswitch-config
|
|
|
|
RUN pnpm install --frozen-lockfile --filter @b2bcall/freeswitch-config...
|
|
|
|
# `prisma generate` só precisa do schema, não de uma conexão real — o valor
|
|
# aqui é só um placeholder pra satisfazer o carregamento do prisma.config.ts.
|
|
ENV DATABASE_URL="postgresql://placeholder:placeholder@localhost:5432/placeholder"
|
|
RUN pnpm --filter @b2bcall/database exec prisma generate
|
|
|
|
WORKDIR /repo/apps/freeswitch-config
|
|
|
|
CMD ["pnpm", "exec", "tsx", "src/main.ts"]
|