@posthog/maxmind-plugin
Advanced tools
+6
-1
| { | ||
| "name": "@posthog/maxmind-plugin", | ||
| "version": "0.1.3", | ||
| "version": "0.1.4", | ||
| "description": "Ingest GeoIP data via MaxMind databases", | ||
@@ -13,2 +13,7 @@ "main": "dist/index.js", | ||
| }, | ||
| "files": [ | ||
| "dist", | ||
| "README.md", | ||
| "LICENSE" | ||
| ], | ||
| "repository": { | ||
@@ -15,0 +20,0 @@ "type": "git", |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
| Maxmind test files from https://github.com/maxmind/MaxMind-DB/tree/master/test-data |
| import { createPageview, getMeta, resetMeta, clone } from '@posthog/plugin-scaffold/test/utils.js' | ||
| import { setupPlugin, processEvent } from '../src' | ||
| import * as fs from 'fs' | ||
| import * as path from 'path' | ||
| import { PluginAttachment, PluginMeta } from 'posthog-plugins' | ||
| import Reader, { Response } from 'mmdb-lib' | ||
| interface Meta extends PluginMeta { | ||
| config: { | ||
| localhostIP: string | ||
| } | ||
| attachments: { | ||
| maxmindMmdb?: PluginAttachment | ||
| } | ||
| global: { | ||
| ipLookup?: Reader<Response> | ||
| } | ||
| } | ||
| function resetMetaWithDatabase(file: string): Meta { | ||
| return resetMeta({ | ||
| config: { | ||
| localhostIp: '127.0.0.1', | ||
| }, | ||
| attachments: { | ||
| maxmindMmdb: file | ||
| ? { | ||
| content_type: '*/*', | ||
| file_name: file, | ||
| contents: fs.readFileSync(path.join(__dirname, './assets/', file)), | ||
| } | ||
| : null, | ||
| }, | ||
| }) | ||
| } | ||
| test('setupPlugin and processEvent with no DB', async () => { | ||
| const meta = resetMetaWithDatabase(null) | ||
| await setupPlugin(meta) | ||
| expect(meta.global.ipLookup).not.toBeDefined() | ||
| const pageviewEvent = createPageview() | ||
| const processedPageviewEvent = await processEvent(clone(pageviewEvent), getMeta()) | ||
| expect(processedPageviewEvent).toEqual(pageviewEvent) | ||
| }) | ||
| test('GeoLite2-City', async () => { | ||
| const meta = resetMetaWithDatabase('GeoLite2-City-Test.mmdb') | ||
| await setupPlugin(meta) | ||
| expect(meta.global.ipLookup).toBeDefined() | ||
| const event = await processEvent({ ...createPageview(), ip: '89.160.20.129' }, meta) | ||
| expect(event.properties).toEqual(expect.objectContaining({ | ||
| $city_name: 'Linköping', | ||
| $country_name: 'Sweden', | ||
| $country_code: 'SE', | ||
| $continent_name: 'Europe', | ||
| $continent_code: 'EU', | ||
| $latitude: 58.4167, | ||
| $longitude: 15.6167, | ||
| $time_zone: 'Europe/Stockholm', | ||
| $subdivision_1_code: 'E', | ||
| $subdivision_1_name: 'Östergötland County', | ||
| })) | ||
| }) | ||
| test('GeoIP2-City', async () => { | ||
| const meta = resetMetaWithDatabase('GeoIP2-City-Test.mmdb') | ||
| await setupPlugin(meta) | ||
| expect(meta.global.ipLookup).toBeDefined() | ||
| const event = await processEvent({ ...createPageview(), ip: '89.160.20.129' }, meta) | ||
| expect(event.properties).toEqual(expect.objectContaining({ | ||
| $city_name: 'Linköping', | ||
| $country_name: 'Sweden', | ||
| $country_code: 'SE', | ||
| $continent_name: 'Europe', | ||
| $continent_code: 'EU', | ||
| $latitude: 58.4167, | ||
| $longitude: 15.6167, | ||
| $time_zone: 'Europe/Stockholm', | ||
| $subdivision_1_code: 'E', | ||
| $subdivision_1_name: 'Östergötland County', | ||
| })) | ||
| }) | ||
| test('GeoLite2-Country', async () => { | ||
| const meta = resetMetaWithDatabase('GeoLite2-Country-Test.mmdb') | ||
| await setupPlugin(meta) | ||
| expect(meta.global.ipLookup).toBeDefined() | ||
| const event = await processEvent({ ...createPageview(), ip: '89.160.20.129' }, meta) | ||
| expect(event.properties).toEqual(expect.objectContaining({ | ||
| $country_name: 'Sweden', | ||
| $country_code: 'SE', | ||
| $continent_name: 'Europe', | ||
| $continent_code: 'EU', | ||
| })) | ||
| }) | ||
| test('GeoIP2-Country', async () => { | ||
| const meta = resetMetaWithDatabase('GeoIP2-Country-Test.mmdb') | ||
| await setupPlugin(meta) | ||
| expect(meta.global.ipLookup).toBeDefined() | ||
| const event = await processEvent({ ...createPageview(), ip: '89.160.20.129' }, meta) | ||
| expect(event.properties).toEqual(expect.objectContaining({ | ||
| $country_name: 'Sweden', | ||
| $country_code: 'SE', | ||
| $continent_name: 'Europe', | ||
| $continent_code: 'EU', | ||
| })) | ||
| }) |
| { | ||
| "trailingComma": "es5", | ||
| "tabWidth": 4, | ||
| "semi": false, | ||
| "singleQuote": true, | ||
| "printWidth": 120 | ||
| } |
| module.exports = { | ||
| preset: 'ts-jest', | ||
| testEnvironment: 'node', | ||
| modulePathIgnorePatterns: ['<rootDir>/dist/'], | ||
| } |
Sorry, the diff of this file is not supported yet
-26
| { | ||
| "name": "MaxMind GeoIP", | ||
| "url": "https://www.npmjs.com/package/@posthog/maxmind-plugin", | ||
| "description": "Ingest GeoIP data via MaxMind databases", | ||
| "main": "dist/index.js", | ||
| "config": [ | ||
| { | ||
| "markdown": "Sign up for a [MaxMind.com](https://www.maxmind.com) account, download and extract the database and then upload the extracted `.mmdb` file below.\n\nYou can either download the large city databases (GeoIP2 City or GeoLite2 City) or the smaller country databases (e.g. GeoLite2 Country).\n\nSome PostHog installations might have problems loading the huge (70+MB) city databases, so unless you really need the additional data, we recommend installing the smaller (3MB) country database instead." | ||
| }, | ||
| { | ||
| "key": "maxmindMmdb", | ||
| "name": "GeoIP .mddb database", | ||
| "type": "attachment", | ||
| "hint": "The \"GeoIP2 City\", \"GeoLite2 City\", \"GeoIP2 Country\", \"GeoLite2 Country\" .mmdb database file", | ||
| "required": true | ||
| }, | ||
| { | ||
| "key": "localhostIP", | ||
| "name": "IP to use instead of 127.0.0.1", | ||
| "type": "string", | ||
| "hint": "Useful if testing locally", | ||
| "default": "", | ||
| "required": false | ||
| } | ||
| ] | ||
| } |
| import commonjs from 'rollup-plugin-commonjs' | ||
| import resolve from 'rollup-plugin-node-resolve' | ||
| import pkg from './package.json' | ||
| import typescript from 'rollup-plugin-typescript2' | ||
| import builtins from 'rollup-plugin-node-builtins' | ||
| const extensions = ['.js', '.jsx', '.ts', '.tsx'] | ||
| const external = Object.keys(pkg.dependencies || {}).concat(Object.keys(pkg.peerDependencies || {})) | ||
| export default [ | ||
| { | ||
| input: './src/index.ts', | ||
| output: { | ||
| file: pkg.main, | ||
| format: 'cjs', | ||
| }, | ||
| external, | ||
| plugins: [ | ||
| builtins(), | ||
| // Allows node_modules resolution | ||
| resolve({ | ||
| extensions, | ||
| preferBuiltins: false, | ||
| mainFields: ['jsnext', 'module', 'main'], | ||
| }), | ||
| // Allow bundling cjs modules. Rollup doesn't understand cjs | ||
| commonjs({ | ||
| include: 'node_modules/**', | ||
| }), | ||
| // Compile TypeScript/JavaScript files | ||
| typescript({ | ||
| include: ['*.ts', '**/*.ts'], | ||
| }), | ||
| ], | ||
| }, | ||
| ] |
-58
| import Reader, { CityResponse, Response } from 'mmdb-lib' | ||
| import { PluginMeta, PluginEvent, PluginAttachment } from '@posthog/plugin-scaffold' | ||
| interface Meta extends PluginMeta { | ||
| config: { | ||
| localhostIP: string | ||
| } | ||
| attachments: { | ||
| maxmindMmdb?: PluginAttachment | ||
| } | ||
| global: { | ||
| ipLookup?: Reader<Response> | ||
| } | ||
| } | ||
| export async function setupPlugin({ attachments, global }: Meta) { | ||
| if (attachments.maxmindMmdb) { | ||
| global.ipLookup = new Reader(attachments.maxmindMmdb.contents) | ||
| } | ||
| } | ||
| export function processEvent(event: PluginEvent, { global, config }: Meta) { | ||
| if (event.ip === '127.0.0.1' && config.localhostIP) { | ||
| event.ip = config.localhostIP | ||
| } | ||
| if (event.ip && event.properties && global.ipLookup) { | ||
| const response = global.ipLookup.get(event.ip) as CityResponse | ||
| if (response) { | ||
| if (response.city) { | ||
| event.properties['$city_name'] = response.city.names?.en | ||
| } | ||
| if (response.country) { | ||
| event.properties['$country_name'] = response.country.names?.en | ||
| event.properties['$country_code'] = response.country.iso_code | ||
| } | ||
| if (response.continent) { | ||
| event.properties['$continent_name'] = response.continent.names?.en | ||
| event.properties['$continent_code'] = response.continent.code | ||
| } | ||
| if (response.postal) { | ||
| event.properties['$postal_code'] = response.postal.code | ||
| } | ||
| if (response.location) { | ||
| event.properties['$latitude'] = response.location?.latitude | ||
| event.properties['$longitude'] = response.location?.longitude | ||
| event.properties['$time_zone'] = response.location?.time_zone | ||
| } | ||
| if (response.subdivisions) { | ||
| response.subdivisions.forEach((subDivision, index) => { | ||
| event.properties[`$subdivision_${index + 1}_code`] = subDivision.iso_code | ||
| event.properties[`$subdivision_${index + 1}_name`] = subDivision.names?.en | ||
| }) | ||
| } | ||
| } | ||
| } | ||
| return event | ||
| } |
| { | ||
| "compilerOptions": { | ||
| "module": "ES2015", | ||
| "declaration": true, | ||
| "removeComments": true, | ||
| "emitDecoratorMetadata": true, | ||
| "experimentalDecorators": true, | ||
| "target": "ES2015", | ||
| "sourceMap": true, | ||
| "outDir": "./dist", | ||
| "baseUrl": "./src", | ||
| "incremental": true, | ||
| "resolveJsonModule": true, | ||
| "moduleResolution": "node", | ||
| "esModuleInterop": true | ||
| }, | ||
| "exclude": ["node_modules", "dist"] | ||
| } |
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
Filesystem access
Supply chain riskAccesses the file system, and could potentially read sensitive data.
Found 1 instance in 1 package
URL strings
Supply chain riskPackage contains fragments of external URLs or IP addresses, which the package may be accessing at runtime.
Found 1 instance in 1 package
1
-50%105003
-48.25%6
-68.42%3013
-7.32%