mirror of https://github.com/Chocobozzz/PeerTube
				
				
				
			
		
			
				
	
	
		
			79 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
			
		
		
	
	
			79 lines
		
	
	
		
			2.0 KiB
		
	
	
	
		
			TypeScript
		
	
	
import { pathExists, writeFile } from 'fs-extra'
 | 
						|
import maxmind, { CountryResponse, Reader } from 'maxmind'
 | 
						|
import { join } from 'path'
 | 
						|
import { CONFIG } from '@server/initializers/config'
 | 
						|
import { logger, loggerTagsFactory } from './logger'
 | 
						|
import { isBinaryResponse, peertubeGot } from './requests'
 | 
						|
 | 
						|
const lTags = loggerTagsFactory('geo-ip')
 | 
						|
 | 
						|
const mmbdFilename = 'dbip-country-lite-latest.mmdb'
 | 
						|
const mmdbPath = join(CONFIG.STORAGE.BIN_DIR, mmbdFilename)
 | 
						|
 | 
						|
export class GeoIP {
 | 
						|
  private static instance: GeoIP
 | 
						|
 | 
						|
  private reader: Reader<CountryResponse>
 | 
						|
 | 
						|
  private constructor () {
 | 
						|
  }
 | 
						|
 | 
						|
  async safeCountryISOLookup (ip: string): Promise<string> {
 | 
						|
    if (CONFIG.GEO_IP.ENABLED === false) return null
 | 
						|
 | 
						|
    await this.initReaderIfNeeded()
 | 
						|
 | 
						|
    try {
 | 
						|
      const result = this.reader.get(ip)
 | 
						|
      if (!result) return null
 | 
						|
 | 
						|
      return result.country.iso_code
 | 
						|
    } catch (err) {
 | 
						|
      logger.error('Cannot get country from IP.', { err })
 | 
						|
 | 
						|
      return null
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  async updateDatabase () {
 | 
						|
    if (CONFIG.GEO_IP.ENABLED === false) return
 | 
						|
 | 
						|
    const url = CONFIG.GEO_IP.COUNTRY.DATABASE_URL
 | 
						|
 | 
						|
    logger.info('Updating GeoIP database from %s.', url, lTags())
 | 
						|
 | 
						|
    const gotOptions = { context: { bodyKBLimit: 200_000 }, responseType: 'buffer' as 'buffer' }
 | 
						|
 | 
						|
    try {
 | 
						|
      const gotResult = await peertubeGot(url, gotOptions)
 | 
						|
 | 
						|
      if (!isBinaryResponse(gotResult)) {
 | 
						|
        throw new Error('Not a binary response')
 | 
						|
      }
 | 
						|
 | 
						|
      await writeFile(mmdbPath, gotResult.body)
 | 
						|
 | 
						|
      // Reinit reader
 | 
						|
      this.reader = undefined
 | 
						|
 | 
						|
      logger.info('GeoIP database updated %s.', mmdbPath, lTags())
 | 
						|
    } catch (err) {
 | 
						|
      logger.error('Cannot update GeoIP database from %s.', url, { err, ...lTags() })
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  private async initReaderIfNeeded () {
 | 
						|
    if (!this.reader) {
 | 
						|
      if (!await pathExists(mmdbPath)) {
 | 
						|
        await this.updateDatabase()
 | 
						|
      }
 | 
						|
 | 
						|
      this.reader = await maxmind.open(mmdbPath)
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  static get Instance () {
 | 
						|
    return this.instance || (this.instance = new this())
 | 
						|
  }
 | 
						|
}
 |