Skip to content

Commit

Permalink
Merge branch 'feature/SPRIND-83_test' into feature/SPRIND-83
Browse files Browse the repository at this point in the history
  • Loading branch information
sanderPostma committed Nov 15, 2024
2 parents bd3be57 + 08fad96 commit 3c6b784
Show file tree
Hide file tree
Showing 4 changed files with 127 additions and 33 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,29 +16,35 @@ export default (testContext: { getAgent: () => ConfiguredAgent; setup: () => Pro
afterAll(testContext.tearDown)

it('should lookup the location of an IPv4 address', async () => {
await expect(agent.lookupLocation({
ipOrHostname: '77.247.248.1'
})).resolves.toEqual({
await expect(
agent.lookupLocation({
ipOrHostname: '77.247.248.1',
}),
).resolves.toEqual({
continent: 'EU',
country: 'AL'
country: 'AL',
})
})

it('should lookup the location of an IPv6 address', async () => {
await expect(agent.lookupLocation({
ipOrHostname: '2001:4860:7:27f::f5'
})).resolves.toEqual({
await expect(
agent.lookupLocation({
ipOrHostname: '2001:4860:7:27f::f5',
}),
).resolves.toEqual({
continent: 'NA',
country: 'US'
country: 'US',
})
})

it('should lookup the location of a hostname', async () => {
await expect(agent.lookupLocation({
ipOrHostname: 'sphereon.com'
})).resolves.toEqual({
await expect(
agent.lookupLocation({
ipOrHostname: 'sphereon.com',
}),
).resolves.toEqual({
continent: 'EU',
country: 'DE'
country: 'DE',
})
})
})
Expand Down
1 change: 1 addition & 0 deletions packages/anomaly-detection/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"dependencies": {
"cross-fetch": "^3.1.8",
"debug": "^4.3.5",
"dns-query": "^0.11.2",
"mmdb-lib": "^2.1.1",
"typeorm": "^0.3.20"
},
Expand Down
56 changes: 36 additions & 20 deletions packages/anomaly-detection/src/agent/AnomalyDetection.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,41 @@
import {IAgentPlugin} from "@veramo/core";
import {IAnomalyDetection, LookupLocationArgs, LookupLocationResult, schema} from "../index";
import * as dns from 'dns'
import * as mmdb from 'mmdb-lib'
import {CountryResponse} from 'mmdb-lib'
import { IAgentPlugin } from '@veramo/core'
import { IAnomalyDetection, LookupLocationArgs, LookupLocationResult, schema } from '../index'
import { CountryResponse, Reader } from 'mmdb-lib'

export const anomalyDetectionMethods: Array<string> = [
'lookupLocation'
]
type DnsLookupFn = (hostname: string) => Promise<string>

export const anomalyDetectionMethods: Array<string> = ['lookupLocation']

/**
* {@inheritDoc IAnomalyDetection}
*/
export class AnomalyDetection implements IAgentPlugin {
readonly schema = schema.IAnomalyDetection
private readonly db: Buffer
private readonly dnsLookup?: DnsLookupFn
readonly methods: IAnomalyDetection = {
lookupLocation: this.lookupLocation.bind(this)
lookupLocation: this.lookupLocation.bind(this),
}

constructor(args: { geoIpDB: Buffer }) {
const { geoIpDB } = { ...args }
constructor(args: { geoIpDB: Buffer; dnsLookupCallback?: DnsLookupFn }) {
const { geoIpDB, dnsLookupCallback } = { ...args }
if (geoIpDB === undefined || geoIpDB === null) {
throw new Error('The geoIpDB argument is required')
}
this.db = geoIpDB
this.dnsLookup = dnsLookupCallback
}

private async lookupLocation(args: LookupLocationArgs): Promise<LookupLocationResult> {
const { ipOrHostname } = { ...args }
const reader = new mmdb.Reader<CountryResponse>(this.db)
const ipv4Reg = "(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])"
const ipv6Reg = "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))"
const reader = new Reader<CountryResponse>(this.db)
const ipv4Reg = '(([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])\\.){3}([0-9]|[1-9][0-9]|1[0-9][0-9]|2[0-4][0-9]|25[0-5])'
const ipv6Reg =
'(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))'
let result: CountryResponse | null

if (!new RegExp(ipv4Reg).test(ipOrHostname) && !new RegExp(ipv6Reg).test(ipOrHostname)) {
const ip = await this.dnsLookupPromise({ hostname: ipOrHostname })
const ip = await this.resolveDns(ipOrHostname)
result = reader.get(ip)
} else {
result = reader.get(ipOrHostname)
Expand All @@ -43,20 +44,35 @@ export class AnomalyDetection implements IAgentPlugin {
if (result !== undefined && result !== null) {
return Promise.resolve({
continent: result?.continent?.code,
country: result?.country?.iso_code
country: result?.country?.iso_code,
})
}
return null
}

private async dnsLookupPromise(args: { hostname: string }): Promise<string> {
const { hostname } = { ...args }
private async resolveDns(hostname: string): Promise<string> {
if (this.dnsLookup) {
return this.dnsLookup(hostname)
}

// Fallback to Node.js dns
let dns
try {
dns = eval('require("dns")')
} catch (e) {
console.error(e)
throw new Error(
`DNS resolution not available on this platform, use the dnsLookupCallback in the AnomalyDetection constructor to implement DNS resolution for your platform.\r\n${e.message}`,
)
}

return new Promise((resolve, reject) => {
dns.lookup(hostname, (error, ip) => {
dns.lookup(hostname, (error: NodeJS.ErrnoException | null, address: string, family: number) => {
if (error) {
reject(error)
return
}
resolve(ip)
resolve(address)
})
})
}
Expand Down
73 changes: 72 additions & 1 deletion pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 3c6b784

Please sign in to comment.