GeoIpLookup.js 2.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. const request = require('request')
  2. const settings = require('@overleaf/settings')
  3. const _ = require('lodash')
  4. const logger = require('@overleaf/logger')
  5. const { URL } = require('url')
  6. const { promisify, promisifyMultiResult } = require('@overleaf/promise-utils')
  7. const DEFAULT_CURRENCY_CODE = 'USD'
  8. const currencyMappings = {
  9. GB: 'GBP',
  10. US: 'USD',
  11. CH: 'CHF',
  12. NZ: 'NZD',
  13. AU: 'AUD',
  14. DK: 'DKK',
  15. NO: 'NOK',
  16. CA: 'CAD',
  17. SE: 'SEK',
  18. SG: 'SGD',
  19. IN: 'INR',
  20. BR: 'BRL',
  21. MX: 'MXN',
  22. CO: 'COP',
  23. CL: 'CLP',
  24. PE: 'PEN',
  25. }
  26. const validCurrencyParams = Object.values(currencyMappings).concat([
  27. 'EUR',
  28. 'INR',
  29. 'BRL',
  30. 'MXN',
  31. 'COP',
  32. 'CLP',
  33. 'PEN',
  34. ])
  35. // Countries which would likely prefer Euro's
  36. const EuroCountries = [
  37. 'AT',
  38. 'BE',
  39. 'BG',
  40. 'HR',
  41. 'CY',
  42. 'CZ',
  43. 'EE',
  44. 'FI',
  45. 'FR',
  46. 'DE',
  47. 'EL',
  48. 'HU',
  49. 'IE',
  50. 'IT',
  51. 'LV',
  52. 'LT',
  53. 'LU',
  54. 'MT',
  55. 'NL',
  56. 'PL',
  57. 'PT',
  58. 'RO',
  59. 'SK',
  60. 'SI',
  61. 'ES',
  62. ]
  63. _.forEach(EuroCountries, country => (currencyMappings[country] = 'EUR'))
  64. function isValidCurrencyParam(currency) {
  65. if (!currency) {
  66. return false
  67. }
  68. return validCurrencyParams.includes(currency)
  69. }
  70. function getDetails(ip, callback) {
  71. if (!ip) {
  72. return callback(new Error('no ip passed'))
  73. }
  74. ip = ip.trim().split(' ')[0]
  75. const opts = {
  76. url: new URL(ip, settings.apis.geoIpLookup.url).href,
  77. timeout: 1000,
  78. json: true,
  79. }
  80. logger.debug({ ip, opts }, 'getting geo ip details')
  81. request.get(opts, function (err, res, ipDetails) {
  82. if (err) {
  83. logger.warn({ err, ip }, 'error getting ip details')
  84. }
  85. callback(err, ipDetails)
  86. })
  87. }
  88. function getCurrencyCode(ip, callback) {
  89. getDetails(ip, function (err, ipDetails) {
  90. if (err || !ipDetails) {
  91. logger.err(
  92. { err, ip },
  93. `problem getting currencyCode for ip, defaulting to ${DEFAULT_CURRENCY_CODE}`
  94. )
  95. return callback(null, DEFAULT_CURRENCY_CODE)
  96. }
  97. const countryCode =
  98. ipDetails && ipDetails.country_code
  99. ? ipDetails.country_code.toUpperCase()
  100. : undefined
  101. const currencyCode = currencyMappings[countryCode] || DEFAULT_CURRENCY_CODE
  102. logger.debug({ ip, currencyCode, ipDetails }, 'got currencyCode for ip')
  103. callback(err, currencyCode, countryCode)
  104. })
  105. }
  106. module.exports = {
  107. getDetails,
  108. getCurrencyCode,
  109. isValidCurrencyParam,
  110. promises: {
  111. getDetails: promisify(getDetails),
  112. getCurrencyCode: promisifyMultiResult(getCurrencyCode, [
  113. 'currencyCode',
  114. 'countryCode',
  115. ]),
  116. },
  117. DEFAULT_CURRENCY_CODE,
  118. }