From 5968666b8ef835e5e17be69c390d6d2a1ff85516 Mon Sep 17 00:00:00 2001 From: Saturn-V Date: Wed, 18 Oct 2023 17:49:43 -0700 Subject: [PATCH] [wip] support an external dataset via mounted JSON file --- .gitignore | 1 + docker-compose.yml | 22 + docker/Dockerfile | 5 + docker/datasource/Dockerfile | 10 + docker/datasource/data/data.json | 1 + docker/datasource/package-lock.json | 304 ++++++++++ docker/datasource/package.json | 16 + docker/datasource/src/index.ts | 143 +++++ index.html | 895 ++++++++++++++++------------ 9 files changed, 1016 insertions(+), 381 deletions(-) create mode 100644 .gitignore create mode 100644 docker-compose.yml create mode 100644 docker/datasource/Dockerfile create mode 100644 docker/datasource/data/data.json create mode 100644 docker/datasource/package-lock.json create mode 100644 docker/datasource/package.json create mode 100644 docker/datasource/src/index.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..40b878d --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a6dd72a --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,22 @@ +--- +version: "1.0" +services: + pewpew: + build: + context: . + dockerfile: ./docker/Dockerfile + volumes: + - ./docker/datasource/data:/opt/pewpew/data + ports: + - 8080:8080 + restart: unless-stopped + # depends_on: + # - "pewpew_data" + + # pewpew_data: + # build: + # context: ./docker/datasource + # dockerfile: ./docker/datasource/Dockerfile + # volumes: + # - ./docker/datasource/data:/datasource/data + # restart: unless-stopped diff --git a/docker/Dockerfile b/docker/Dockerfile index 25286ad..7c16640 100644 --- a/docker/Dockerfile +++ b/docker/Dockerfile @@ -1,8 +1,13 @@ FROM node:latest + EXPOSE 8080 + WORKDIR /opt/pewpew COPY . /opt/pewpew RUN npm install http-server -g RUN mkdir -p /opt/pewpew + +VOLUME ./data + CMD ["http-server","-a","0.0.0.0","-p","8080","/opt/pewpew"] diff --git a/docker/datasource/Dockerfile b/docker/datasource/Dockerfile new file mode 100644 index 0000000..71e5f88 --- /dev/null +++ b/docker/datasource/Dockerfile @@ -0,0 +1,10 @@ +FROM node:latest + +EXPOSE 8090 +WORKDIR /datasource +COPY . . +RUN npm install --include-dev + +VOLUME ./data + +CMD ["npm","run","trace"] diff --git a/docker/datasource/data/data.json b/docker/datasource/data/data.json new file mode 100644 index 0000000..70f1e82 --- /dev/null +++ b/docker/datasource/data/data.json @@ -0,0 +1 @@ +{"data":[{"hit":{"origin":{"latitude":37.3083,"longitude":-121.9643},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":37.7506,"longitude":-122.4121},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":37.7506,"longitude":-122.4121},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":37.3083,"longitude":-121.9643},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":37.3083,"longitude":-121.9643},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":37.3083,"longitude":-121.9643},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":37.3083,"longitude":-121.9643},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":37.3083,"longitude":-121.9643},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":30.5875,"longitude":-97.8535},"destination":{"latitude":37.3512,"longitude":-121.8846}}},{"hit":{"origin":{"latitude":37.3083,"longitude":-121.9643},"destination":{"latitude":37.3512,"longitude":-121.8846}}}]} \ No newline at end of file diff --git a/docker/datasource/package-lock.json b/docker/datasource/package-lock.json new file mode 100644 index 0000000..2f1e3ac --- /dev/null +++ b/docker/datasource/package-lock.json @@ -0,0 +1,304 @@ +{ + "name": "pewpew-datasource", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "pewpew-datasource", + "version": "1.0.0", + "license": "ISC", + "devDependencies": { + "@types/node": "^20.8.7", + "node-fetch": "^3.3.2", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.1.tgz", + "integrity": "sha512-dSYZh7HhCDtCKm4QakX0xFpsRDqjjtZf/kjI/v3T3Nwt5r8/qz/M19F9ySyOqU94SXBmeG9ttTul+YnR4LOxFA==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "20.8.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.7.tgz", + "integrity": "sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==", + "dev": true, + "dependencies": { + "undici-types": "~5.25.1" + } + }, + "node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "dev": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dev": true, + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dev": true, + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici-types": { + "version": "5.25.3", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", + "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", + "dev": true + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + } + } +} diff --git a/docker/datasource/package.json b/docker/datasource/package.json new file mode 100644 index 0000000..c86d57f --- /dev/null +++ b/docker/datasource/package.json @@ -0,0 +1,16 @@ +{ + "name": "pewpew-datasource", + "version": "1.0.0", + "description": "An adapter to pewpew to load a datasource", + "main": "./src/index.ts", + "scripts": { + "trace": "ts-node ./src/index.ts" + }, + "author": "", + "license": "ISC", + "devDependencies": { + "@types/node": "^20.8.7", + "ts-node": "^10.9.1", + "typescript": "^5.2.2" + } +} diff --git a/docker/datasource/src/index.ts b/docker/datasource/src/index.ts new file mode 100644 index 0000000..3ce6d66 --- /dev/null +++ b/docker/datasource/src/index.ts @@ -0,0 +1,143 @@ +import fs from 'fs' + +const tenant_id = "3209935f-cc7a-42f8-aec8-87e3589716cb" +const client_id = "a0a2f365-ff6b-4aa2-b6dd-99d06e29266b" +const client_secret = "lCO8Q~-iIn_w9kL4ntIB_PQu7.PL5klPd-AlfbDu" +const AUTHORITY = `https://login.microsoftonline.com/${tenant_id}` +const GRAPH = `https://graph.microsoft.com` +const TOKEN_URL = `${AUTHORITY}/oauth2/v2.0/token` +const SIGN_INS_URL = `${GRAPH}/v1.0/auditLogs/signIns` +const LOOKUP_IP_URL = 'http://ip-api.com/json' +const LOOKUP_IP_LIMIT = 35 + +const PAYLOAD: Record = { + grant_type: "client_credentials", + client_id: client_id, + client_secret: client_secret, + scope: "https://graph.microsoft.com/.default", +} + +try { + main() +} catch (error: any) { + console.error(error); + +} + +async function main() { + const accessToken = await getAccessToken() + const signIns = await getSignIns(accessToken) + + + const datapoints = await traceSignIns(signIns) + console.log(datapoints); + await writeToDisk({data: datapoints}) + +} + +async function getAccessToken(): Promise { + console.log('Fetching ACCESS_TOKEN...'); + + const response = await fetch(TOKEN_URL, { + method: "POST", + body: Object.keys(PAYLOAD).map(key => encodeURIComponent(key) + '=' + encodeURIComponent(PAYLOAD[key])).join('&'), + headers: { + 'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8' + }, + }) + + const body: any = await response.json() + console.log('Fetched ACCESS_TOKEN'); + return body["access_token"] + +} + +interface SignIn { + ip: string, + occurredAt: Date +} +async function getSignIns(accessToken: string): Promise { + console.log('Fetching SIGN_INS...'); + const response = await fetch(`${SIGN_INS_URL}?${encodeURIComponent("$filter")}=${encodeURIComponent("createdDateTime ge 2023-10-17T21:00:00Z")}`, { + headers: { + 'Authorization': `Bearer ${accessToken}` + }, + }) + const body: any = await response.json() + console.log('Fetched SIGN_INS'); + return body.value.map(({ ipAddress, createdDateTime }: { [key: string]: any }) => ({ ip: ipAddress, occurredAt: createdDateTime })) +} + +// hit: { + // origin: Coordinates, + // destination: Coordinates + // } + // strokeColor: string + // reason: string +interface Coordinates { + latitude: number + longitude: number +} + +async function lookupIP(ip: string): Promise { + const response = await fetch(`${LOOKUP_IP_URL}/${encodeURIComponent(ip)}`) + const body: any = await response.json() + return { + latitude: body.lat, + longitude: body.lon, + } +} + +async function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)) +} + +interface Hit { + origin: Coordinates + destination: Coordinates +} + +interface DataPoint { + hit: Hit + strokeColor?: string + reason?: string +} +async function traceSignIns(signIns: SignIn[], smoke: boolean = true): Promise { + console.log('Fetching destination IP info...'); + const destination = await lookupIP("67.180.150.47") + console.log('Fetched destination IP info'); + + let counter = 0 + let iteration = 1 + const origins: DataPoint[] = [] + for (const {ip, occurredAt} of signIns) { + if (counter === 0) { + console.log(`Fetching IP info for ${LOOKUP_IP_LIMIT} IP addresses (batch ${iteration}/${Math.ceil(signIns.length/LOOKUP_IP_LIMIT)})`); + + } + console.log(`Processing ${counter+1}/${LOOKUP_IP_LIMIT}`); + + if (counter >= LOOKUP_IP_LIMIT) { + if (smoke) break + await sleep(62500) + counter = 0 + iteration += 1 + } + const origin = await lookupIP(ip) + const datapoint = { + hit: { + origin, + destination + } + } + origins.push(datapoint) + counter += 1 + } + return origins +} + +async function writeToDisk(data: any) { + return new Promise((resolve) => + fs.writeFile('data/data.json', JSON.stringify(data), 'utf8', resolve) + ) +} \ No newline at end of file diff --git a/index.html b/index.html index 323eb65..255491f 100644 --- a/index.html +++ b/index.html @@ -1,114 +1,156 @@ + - - - - - - - - - - - - - + + + + + + + + + + + + + @@ -124,61 +166,73 @@ -
+
+
+
IPew Attack Map
- Creative Commons License + Creative Commons License
-

About IPew

- Attack maps are the <blink> tag of information security. They are pure eye candy, meant to scare the general public and WOW unsuspecting executives visiting Security Operations Centers. Yet, security vendors keep cranking them out. We didn't want organizations without "real" data or l33t animation skills to to feel left out, so we built this map for anyone to use [CC BY-SA]. Plus, they're all missing sound effects! And, most (all, really) use mind-numbingly dumb map projections, begging the question: "Does Greenland make my map look big?".
-
- The default map uses a statistical model (infrequently updated) for source "attack" node country of origin & frequency while destinations are fully randomized. The default sound is a Star Wars "blaster" (guess which one!). Sounds can be customized and an organization name can be specified, plus there are a few other interesting options.
-
- Check out the github repository for more information and instructions on how to customize the map options for maximum effect.
-
- Brought to you by @alexcpsec, @hrbrmstr & Data-Driven Security +

About IPew

+ Attack maps are the <blink> tag of information security. They are + pure eye candy, meant to scare the general public and WOW unsuspecting executives visiting Security + Operations Centers. Yet, security vendors keep cranking them out. We didn't want organizations without "real" data + or l33t animation skills to to feel left out, so we built this map for anyone to use [CC BY-SA]. Plus, they're all + missing sound effects! And, most (all, really) use mind-numbingly dumb map projections, begging the question: + "Does Greenland make my map look big?".
+
+ The default map uses a statistical model (infrequently updated) for source "attack" node country of origin & + frequency while destinations are fully randomized. The default sound is a Star Wars "blaster" (guess which one!). + Sounds can be customized and an organization name can be specified, plus there are a few other interesting + options.
+
+ Check out the github repository for more information + and instructions on how to customize the map options for maximum effect.
+
+ Brought to you by @alexcpsec, @hrbrmstr & Data-Driven + Security
- × + × + - + + \ No newline at end of file