Llamada enmascarada

Esta guía te explica cómo poner en práctica la idea descrita en el Caso de uso de la comunicación de voz privada. Te enseña a crear un proxy de voz con el software de Vonage SDK de servidor de nodosutilizando números virtuales para ocultar los números de teléfono reales de los participantes. El código fuente completo también está disponible en nuestra Proxy de voz mediante el repositorio de GitHub de la Voice API. También puedes dirigirte a Code Hub para probar la API de llamadas enmascaradas.

Visión general

En algunos casos, puede que necesites que dos usuarios se comuniquen sin revelar sus números de teléfono personales. Por ejemplo, en un servicio de viajes compartidos, los usuarios necesitan coordinar las horas de recogida sin revelar sus datos de contacto, lo que también ayuda a evitar acuerdos directos que podrían mermar tus ingresos.

Con las API de Vonage, puedes proporcionar a los participantes números temporales que ocultan sus números de teléfono reales durante la llamada. Una vez finalizada la llamada, los números temporales se revocan, lo que garantiza la privacidad.

Pasos

Esta guía proporciona instrucciones para construir la aplicación, incluyendo:

Requisitos previos

Para seguir este caso de uso, necesitas:

Repositorio de código

Hay un Repositorio GitHub que contiene el código.

Configuración

Tienes que crear un .env que contiene la configuración. Las instrucciones para hacerlo se explican en la sección LÉEME de GitHub. A medida que avanza en esta guía, puede rellenar el archivo de configuración con los valores necesarios para variables como la clave de API, el secreto de API, el ID de aplicación, el modo de depuración y los números aprovisionados.

Crear una aplicación de Voice API

Una aplicación de la Voice API es un concepto de Vonage. No debe confundirse con la aplicación que vas a desarrollar. Se trata, más bien, de un «contenedor» que alberga los parámetros de autenticación y configuración necesarios para trabajar con la Voice API.

Puedes crear una aplicación Voice API con la CLI de Vonage. Debes proporcionar un nombre para la aplicación y las URL de dos puntos finales de webhook: el primero es el punto final al que las API de Vonage harán una solicitud cuando recibas una llamada entrante en tu número virtual, y el segundo es el punto final donde la API puede publicar datos de eventos.

Sustituye el nombre de dominio del siguiente comando de la CLI de Vonage por tu nombre de dominio de ngrok (para obtener más información sobre cómo hacerlo, consulta el Cómo ejecutar ngrok guía) y ejecútalo en el directorio raíz de tu proyecto:

vonage apps:create "Voice Proxy" --voice_answer_url=https://example.com/proxy-call --voice_event_url=https://example.com/event

Este comando crea un archivo llamado voice_proxy.key que contiene información de autenticación y devuelve un ID de aplicación único. Anote este ID porque lo necesitará en los pasos siguientes.

Crear la aplicación web

Esta aplicación utiliza el Express marco para el enrutamiento y la SDK del servidor Vonage Node para trabajar con la Voice API. dotenv para que la aplicación pueda configurarse mediante un archivo .env archivo de texto.

En server.js, el código inicializa las dependencias de la aplicación e inicia el servidor web. Se implementa un controlador de rutas para la página de inicio de la aplicación (/) para que pueda comprobar que el servidor está funcionando ejecutando node server.js y visitando http://localhost:3000 en tu navegador:

"use strict";

const express = require('express');
const bodyParser = require('body-parser');

const app = express();
app.set('port', (process.env.PORT || 3000));
app.use(bodyParser.urlencoded({ extended: false }));

const config = require(__dirname + '/../config');

const VoiceProxy = require('./VoiceProxy');
const voiceProxy = new VoiceProxy(config);

app.listen(app.get('port'), function() {
  console.log('Voice Proxy App listening on port', app.get('port'));
});

Ten en cuenta que el código crea una instancia de un objeto de la clase VoiceProxy para enrutar los mensajes enviados a su número virtual al número real del destinatario. El proceso de proxy se describe en la sección Delegar la llamada capítulo de esta guía. Por ahora, ten en cuenta que esta clase inicializa el SDK de Vonage Server utilizando la clave y el secreto de la API que configurarás en el siguiente paso. Esta configuración permite que tu aplicación realice y reciba llamadas de voz:

const VoiceProxy = function(config) {
  this.config = config;
  
  this.nexmo = new Nexmo({
      apiKey: this.config.VONAGE_API_KEY,
      apiSecret: this.config.VONAGE_API_SECRET
    },{
      debug: this.config.VONAGE_DEBUG
    });
  
  // Virtual Numbers to be assigned to UserA and UserB
  this.provisionedNumbers = [].concat(this.config.PROVISIONED_NUMBERS);
  
  // In progress conversations
  this.conversations = [];
};

Suministro de números virtuales

Los números virtuales se utilizan para ocultar los números de teléfono reales a los usuarios de sus aplicaciones.

El siguiente diagrama de flujo muestra el proceso de asignación y configuración de un número virtual:

Para contratar un número virtual, debes buscar entre los números disponibles que cumplan tus criterios. Por ejemplo, un número de teléfono de un país concreto con servicio de voz:

const Nexmo = require('nexmo');

/**
 * Create a new VoiceProxy
 */
const VoiceProxy = function(config) {
  this.config = config;

  this.nexmo = new Nexmo({
    apiKey: this.config.NEXMO_API_KEY,
    apiSecret: this.config.NEXMO_API_SECRET
  },{
    debug: this.config.NEXMO_DEBUG
  });

  // Virtual Numbers to be assigned to UserA and UserB
  this.provisionedNumbers = [].concat(this.config.PROVISIONED_NUMBERS);

  // In progress conversations
  this.conversations = [];
};

/**
 * Provision two virtual numbers. Would provision more in a real app.
 */
VoiceProxy.prototype.provisionVirtualNumbers = function() {
  // Buy a UK number with VOICE capabilities.
  // For this example we'll also get SMS so we can send them a text notification
  this.nexmo.number.search('GB', {features: 'VOICE,SMS'}, function(err, res) {
    if(err) {
      console.error(err);
    }
    else {
      const numbers = res.numbers;

      // For demo purposes:
      // - Assume that at least two numbers will be available
      // - Rent just two virtual numbers: one for each conversation participant
      this.rentNumber(numbers[0]);
      this.rentNumber(numbers[1]);
    }
  }.bind(this));
};

A continuación, alquile los números que desee y asócielos a su solicitud.

NOTA: Algunos tipos de Numbers pueden requerir que proporcione más información, como una dirección postal. Si no puede obtener un número mediante programación, puede visitar la página Panel de control para desarrolladores para solicitar dichos Numbers. Tenga en cuenta que algunos Numbers pueden requerir que se solicite información y que el proceso no estará totalmente automatizado.

Cuando se produzca un evento relacionado con cualquier número asociado con una aplicación, Vonage enviará una solicitud a tu punto final de webhook con información sobre el evento. Después de la configuración, asegúrate de almacenar el número de teléfono para su uso posterior:

/**
 * Rent the given numbers
 */
VoiceProxy.prototype.rentNumber = function(number) {
  this.nexmo.number.buy(number.country, number.msisdn, function(err, res) {
    if(err) {
      console.error(err);
    }
    else {
      this.configureNumber(number);
    }
  }.bind(this));
};

/**
 * Configure the number to be associated with the Voice Proxy application.
 */
VoiceProxy.prototype.configureNumber = function(number) {
  const options = {
    voiceCallbackType: 'app',
    voiceCallbackValue: this.config.NEXMO_APP_ID,
  };
  this.nexmo.number.update(number.country, number.msisdn, options, function(err, res) {
    if(err) {
      console.error(err);
    }
    else {
      this.provisionedNumbers.push(number);
    }
  }.bind(this));
};

Para aprovisionar números virtuales, visite http://localhost:3000/numbers/provision en tu navegador.

Ya dispone de los números virtuales necesarios para enmascarar la comunicación entre sus usuarios.

NOTA: En una aplicación de producción, elegirá entre un conjunto de números virtuales. Sin embargo, es importante mantener esta funcionalidad para alquilar números adicionales sobre la marcha.

Crear una convocatoria

El flujo de trabajo para crear una convocatoria es el que se presenta en el diagrama:

La siguiente llamada:

/**
 * Create a new tracked conversation so there is a real/virtual mapping of numbers.
 */
VoiceProxy.prototype.createConversation = function(userANumber, userBNumber, cb) {
  this.checkNumbers(userANumber, userBNumber)
    .then(this.saveConversation.bind(this))
    .then(this.sendSMS.bind(this))
    .then(function(conversation) {
      cb(null, conversation);
    })
    .catch(function(err) {
      cb(err);
    });
};

Validar los números de teléfono

Cuando los usuarios de tu aplicación introduzcan sus números de teléfono, utiliza Number Insight para asegurarte de que sean válidos. También puedes ver en qué país están registrados los números de teléfono:

/**
 * Ensure the given numbers are valid and which country they are associated with.
 */
VoiceProxy.prototype.checkNumbers = function(userANumber, userBNumber) {
  const niGetPromise = (number) => new Promise ((resolve) => {
    this.nexmo.numberInsight.get(number, (error, result) => {
      if(error) {
        console.error('error',error);
      }
      else {
        return resolve(result);
      }
    })
  });

  const userAGet = niGetPromise({level: 'basic', number: userANumber});
  const userBGet = niGetPromise({level: 'basic', number: userBNumber});

  return Promise.all([userAGet, userBGet]);
};

Asignar números de teléfono a números reales

Una vez que esté seguro de que los números de teléfono son válidos, asigne cada número real a un campo número virtual y guarda la llamada:

/**
 * Store the conversation information.
 */
VoiceProxy.prototype.saveConversation = function(results) {
  let userAResult = results[0];
  let userANumber = {
    msisdn: userAResult.international_format_number,
    country: userAResult.country_code
  };

  let userBResult = results[1];
  let userBNumber = {
    msisdn: userBResult.international_format_number,
    country: userBResult.country_code
  };

  // Create conversation object - for demo purposes:
  // - Use first indexed LVN for user A
  // - Use second indexed LVN for user B
  let conversation = {
    userA: {
      realNumber: userANumber,
      virtualNumber: this.provisionedNumbers[0]
    },
    userB: {
      realNumber: userBNumber,
      virtualNumber: this.provisionedNumbers[1]
    }
  };

  this.conversations.push(conversation);

  return conversation;
};

Enviar un SMS de confirmación

En un sistema de comunicación privada, cuando un usuario se pone en contacto con otro, el interlocutor llama a un número virtual desde su teléfono.

Envía un SMS para informar a cada participante en la conversación del número virtual al que debe llamar:

/**
 * Send an SMS to each conversation participant so they know each other's
 * virtual number and can call either other via the proxy.
 */
VoiceProxy.prototype.sendSMS = function(conversation) {
  // Send UserA conversation information
  // From the UserB virtual number
  // To the UserA real number
  this.nexmo.message.sendSms(conversation.userB.virtualNumber.msisdn,
                             conversation.userA.realNumber.msisdn,
                             'Call this number to talk to UserB');

  // Send UserB conversation information
  // From the UserA virtual number
  // To the UserB real number
  this.nexmo.message.sendSms(conversation.userA.virtualNumber.msisdn,
                             conversation.userB.realNumber.msisdn,
                             'Call this number to talk to UserB');

  return conversation;
};

Los usuarios no pueden enviarse SMS entre sí. Para habilitar esta funcionalidad, debe configurar Comunicación SMS privada.

En esta guía, cada usuario ha recibido el número virtual mediante un SMS. En otros sistemas, este número podría facilitarse mediante correo electrónico, notificaciones dentro de la aplicación o un número predefinido.

Gestión de llamadas entrantes

Cuando Vonage recibe una llamada entrante a tu número virtual, realiza una solicitud al punto final de webhook que configuraste cuando creó una aplicación Voice API:

Extracto to y from del webhook entrante y transmitirlos a la lógica de negocio del proxy de voz:

app.get('/proxy-call', function(req, res) {
  const from = req.query.from;
  const to = req.query.to;

  const ncco = voiceProxy.getProxyNCCO(from, to);
  res.json(ncco);
});

Reverse Map Números de teléfono reales a los números virtuales

Ahora que ya conoces el número de teléfono desde el que se realiza la llamada y el número virtual del destinatario, asigna el número virtual de entrada al número de teléfono real de salida:

La dirección de la llamada puede identificarse como:

  • El from El número es un número real de UserA y el to El número es el número de Vonage de UserB
  • El from es un número real UserB y el número to El número es el número de Vonage del usuario A
const fromUserAToUserB = function(from, to, conversation) {
  return (from === conversation.userA.realNumber.msisdn &&
          to === conversation.userB.virtualNumber.msisdn);
};
const fromUserBToUserA = function(from, to, conversation) {
  return (from === conversation.userB.realNumber.msisdn &&
          to === conversation.userA.virtualNumber.msisdn);
};

/**
 * Work out real number to virtual number mapping between users.
 */
VoiceProxy.prototype.getProxyRoute = function(from, to) {
  let proxyRoute = null;
  let conversation;
  for(let i = 0, l = this.conversations.length; i < l; ++i) {
    conversation = this.conversations[i];

    // Use to and from to determine the conversation
    const fromUserA = fromUserAToUserB(from, to, conversation);
    const fromUserB = fromUserBToUserA(from, to, conversation);

    if(fromUserA || fromUserB) {
      proxyRoute = {
        conversation: conversation,
        to: fromUserA? conversation.userB : conversation.userA,
        from: fromUserA? conversation.userA : conversation.userB
      };
      break;
    }
  }

  return proxyRoute;
};

Una vez realizada la búsqueda del número, sólo queda proxy la llamada.

Delegar la llamada

Proxy de la llamada al número de teléfono al que está asociado el número virtual. La dirección from es siempre el número virtual, y el número to es un número de teléfono real.

Para ello, crea un NCCO (Objeto de control de llamadas de Nexmo). Esta OCN utiliza un talk para leer un texto. Cuando la talk ha finalizado, un connect desvía la llamada a un número real.

/**
 * Build the NCCO response to instruct Nexmo how to handle the inbound call.
 */
VoiceProxy.prototype.getProxyNCCO = function(from, to) {
  // Determine how the call should be routed
  const proxyRoute = this.getProxyRoute(from, to);

  if(proxyRoute === null) {
    const errorText = 'No conversation found' +
                    ' from: ' + from +
                    ' to: ' + to;
    throw new Error(errorText);
  }

  // Build the NCCO
  let ncco = [];

  const textAction = {
    action: 'talk',
    text: 'Please wait whilst we connect your call'
  };
  ncco.push(textAction);

  const connectAction = {
    action: 'connect',
    from: proxyRoute.from.virtualNumber.msisdn,
    endpoint: [{
      type: 'phone',
      number: proxyRoute.to.realNumber.msisdn
    }]
  };
  ncco.push(connectAction);

  return ncco;
};

El servidor web devuelve la NCCO a Vonage.

app.get('/proxy-call', function(req, res) {
  const from = req.query.from;
  const to = req.query.to;

  const ncco = voiceProxy.getProxyNCCO(from, to);
  res.json(ncco);
});

Conclusión

Has aprendido a crear un proxy de voz para la comunicación privada. Has asignado y configurado números de teléfono, has analizado los datos de los números, has asignado números reales a números virtuales para garantizar el anonimato, has gestionado una llamada entrante y has redirigido la llamada a otro usuario.

Más información