Click2Call

El microservicio Click2Call expone una pequeña API HTTP/JSON que origina llamadas click-to-call sin necesidad de un JWT del portal. Está pensado para ser consumido por una extensión de navegador que detecta números de teléfono en las páginas web y, al hacer clic, solicita al servicio que realice la llamada.

A diferencia de las APIs REST basadas en roles, este servicio no utiliza autenticación JWT: el llamante demuestra la propiedad de un terminal con las propias credenciales SIP del terminal mediante HTTP Digest, de modo que la contraseña nunca viaja por la red.

Si tiene éxito, el servicio lanza, a través de AMI, un Originate que reutiliza el dialplan click2dial ya existente:

  1. Pata 1: suena el propio terminal del usuario.

  2. Pata 2: cuando el usuario contesta, se genera la llamada hacia el destination solicitado.

Nota

Este servicio se distribuye como el paquete ivozprovider-click2call y escucha en su propio puerto (tras un proxy TLS en producción). Es independiente de las APIs REST /api/platform, /api/brand y /api/provider.

Endpoints

El flujo siempre tiene dos pasos: primero solicitar un desafío (challenge) y después realizar la llamada firmando el destino con dicho desafío.

1) POST /challenge

Solicita un nonce de un solo uso para un Address of Record (AoR).

Cuerpo de la petición:

{ "aor": "username@domain" }

Respuesta (200):

{ "nonce": "<server-issued nonce>", "realm": "domain" }
  • aor: el username@domain del terminal.

  • realm (devuelto): la parte de dominio del AoR, a utilizar en el digest.

El nonce está firmado con HMAC, tiene una caducidad configurable (nonce_ttl) y es de un solo uso, por lo que no hay reenvío (replay). En este paso no se accede a la base de datos.

2) POST /call

Realiza la llamada. El destino debe firmarse con un digest calculado a partir de la contraseña del terminal y del nonce obtenido anteriormente.

Cuerpo de la petición:

{
  "aor": "username@domain",
  "nonce": "<nonce from /challenge>",
  "response": "<digest response>",
  "destination": "+34900000000",
  "iden": "optional-call-id",
  "maxDuration": 10800000,
  "dialTimeout": 30,
  "optimize": false
}

Respuesta (200):

{ "iden": "<call iden>" }
  • destination: número de destino (^[+*0-9]+$).

  • iden (opcional): identificador proporcionado por el llamante (^[A-Za-z0-9_-]{1,32}$); si se omite, el servicio genera uno (base62 de 16 caracteres) y lo devuelve en la respuesta.

  • maxDuration (ms, por defecto 10800000), dialTimeout (s, por defecto 30), optimize (booleano, por defecto false).

El iden devuelto identifica la llamada generada: se usa como ChannelId de AMI y se propaga en la pata 2 (la llamada hacia el destino) hacia el proxy como la cabecera SIP X-Info-Click2Dial-iden. El proxy lo almacena como el IDEN de la llamada para esa pata, de modo que puede correlacionarse con la petición /call originaria desde los CDRs y los datos en tiempo real.

Cálculo del digest

El digest se calcula en el lado del cliente, basado en MD5, y solo viaja response (la contraseña nunca sale del cliente):

HA1      = MD5(username : realm : password)
HA2      = MD5(destination)
response = MD5(HA1 : nonce : HA2)

El servidor lo recalcula y lo compara en tiempo constante.

Nota

En el navegador crypto.subtle no proporciona MD5; utiliza una librería como blueimp-md5 / crypto-js. El CORS se resuelve declarando el origen del servicio en los host_permissions de la extensión; el servicio devuelve los orígenes permitidos a partir de su configuración.

Códigos de error

Código

Motivo

400

JSON / AoR / destino / iden no válidos

401

nonce no válido, caducado o reutilizado

403

AoR no elegible (sin terminal+endpoint+usuario+extensión) o digest incorrecto

502

no se pudo resolver el Application Server (Kamailio) ni originar la llamada (AMI)

Por seguridad, no se revela el motivo exacto entre «el AoR no existe» y «contraseña incorrecta»: ambos devuelven 403.

Caso de uso

Un intercambio típico desde la extensión de navegador:

  1. POST /challenge con el aor del terminal con sesión iniciada → obtener nonce y realm.

  2. Calcular response a partir de username, realm, password, nonce y el destination sobre el que se ha hecho clic.

  3. POST /call con aor, nonce, response y destination → suena el terminal del usuario y, al contestar, se marca el destino. Conserva el iden devuelto para correlacionar la llamada más adelante.