Source: subscribers/matomo.js

/**
 * Event subscribe for matomo statistics.
 * @module subscribers/matomo
 * @license MIT
 * @author Kai KRETSCHMANN <kai@kretschmann.consulting>
 */

const eventEmitter = require('../utils/eventer').em;

const log4js = require('log4js');
const logger = log4js.getLogger();
logger.level = process.env.LOGLEVEL || /* istanbul ignore next */ 'debug';

const MatomoTracker = require('matomo-tracker');
let matomo = null;
logger.debug(`MATOMO url ${process.env.MATOMO_URL} !`);
if ((process.env.MATOMO_URL !== undefined) && (process.env.MATOMO_URL !== null) && (process.env.MATOMO_URL !== '')) {
  matomo = new MatomoTracker(process.env.MATOMO_ID, process.env.MATOMO_URL);
  logger.info('MATOMO connected');
} else {
  logger.warn('No matomo url defined');
}
const baseUrl = 'https://api.binarytransparency.net/';

/**
 * Get remote IP number by connection or header data.
 * @function getRemoteAddr
 * @private
 * @param {object} req The web request object
 * @returns {string} IP number
 */
function getRemoteAddr (req) {
  if (req.headers['x-forwarded-for']) {
    const aIPs = req.headers['x-forwarded-for'].split(',');
    const firstIP = aIPs[0];
    logger.debug(firstIP);
    return firstIP;
  }
  if (req.headers['x-real-ip']) return req.headers['x-real-ip'];

  if (req.ip) return req.ip;
  if (req._remoteAddress) return req._remoteAddress;
  const sock = req.socket;
  if (sock.socket) return sock.socket.remoteAddress;
  return sock.remoteAddress;
}

/**
 * Subscribe to apihit event.
 * @function apihit
 * @public
 * @param {object} req The web request object
 */
eventEmitter.on('apihit', function getApiHit (req) {
  logger.debug('In subscriber');

  if (matomo == null) return;

  const url = req.url;
  const urlparts = url.split('/');
  const urlMethod = urlparts[0] + '/' + urlparts[1] + '/' + urlparts[2];
  const reqMethod = req.method;
  const reqUseragent = req.headers['user-agent'];
  const reqLanguage = req.headers['accept-language'];

  logger.debug(`log ${urlMethod}`);
  matomo.track({
    url: baseUrl + urlMethod,
    action_name: 'API call',
    token_auth: process.env.MATOMO_TOKEN_AUTH,
    cip: getRemoteAddr(req),
    ca: 1,
    ua: reqUseragent,
    lang: reqLanguage,
    cvar: JSON.stringify({
      1: ['API version', urlparts[1]],
      2: ['HTTP method', reqMethod]
    })
  });
});

/**
 * Subscribe to grpchit event.
 * @function grpchit
 * @public
 * @param {object} call The grpc request object
 */
eventEmitter.on('grpchit', function getApiHit (call) {
  logger.debug('In subscriber');

  if (matomo == null) return;

  const url = call.call.handler.path;
  const urlparts = url.split('/');
  const urlMethod = urlparts[0] + '/' + urlparts[1] + '/' + urlparts[2];
  const peerIP = call.getPeer().split(':')[0];
  const reqUseragent = call.metadata.get('user-agent')[0];
  logger.debug(`IP of peer: ${peerIP}`);
  logger.debug(`log ${urlMethod}`);
  logger.debug(`ua ${reqUseragent}`);

  matomo.track({
    url: baseUrl + urlMethod,
    action_name: 'gRPC call',
    token_auth: process.env.MATOMO_TOKEN_AUTH,
    cip: peerIP,
    ca: 1,
    ua: reqUseragent
  });
});

/**
 * Subscribe to posthit event.
 * @function posthit
 * @public
 * @param {string} urlpath The path request string
 */
eventEmitter.on('posthit', function getPostHit (urlpath) {
  logger.debug('In subscriber');

  if (matomo == null) return;

  matomo.track({
    url: baseUrl + urlpath,
    action_name: 'POST call',
    token_auth: process.env.MATOMO_TOKEN_AUTH
  });
});

module.exports = {}