mirror of https://github.com/186526/net186-bot
Init
This commit is contained in:
parent
1c1dabbb33
commit
2a5e1b74c9
|
@ -102,3 +102,5 @@ dist
|
||||||
|
|
||||||
# TernJS port file
|
# TernJS port file
|
||||||
.tern-port
|
.tern-port
|
||||||
|
|
||||||
|
src/config.ts
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,30 @@
|
||||||
|
{
|
||||||
|
"name": "net186-bot",
|
||||||
|
"version": "0.0.1",
|
||||||
|
"description": "A looking glass telegram bot using hyperglass' openapi.",
|
||||||
|
"main": "dist/app.js",
|
||||||
|
"scripts": {
|
||||||
|
"build": "rm -rf dist/* && tsc",
|
||||||
|
"start": "node dist/app.js"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/186526/net186-bot.git"
|
||||||
|
},
|
||||||
|
"author": "real186526 <i@186526.xyz>",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/186526/net186-bot/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/186526/net186-bot#readme",
|
||||||
|
"devDependencies": {
|
||||||
|
"@types/node": "^18.11.18",
|
||||||
|
"tslint": "^6.1.3",
|
||||||
|
"typescript": "^4.9.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"axios": "^1.2.2",
|
||||||
|
"ip-address": "^8.1.0",
|
||||||
|
"telegraf": "^4.11.2"
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,131 @@
|
||||||
|
import axios, { AxiosInstance } from "axios";
|
||||||
|
import { adapter, capabilities, device, info, queryError, querySuccess } from "../types/adapter";
|
||||||
|
import { Address4, Address6 } from 'ip-address';
|
||||||
|
|
||||||
|
interface deviceRaw {
|
||||||
|
name: string;
|
||||||
|
network: {
|
||||||
|
name: string;
|
||||||
|
display_name: string;
|
||||||
|
};
|
||||||
|
vrfs: {
|
||||||
|
name: string;
|
||||||
|
display_name: string;
|
||||||
|
}[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface queryTypeRaw {
|
||||||
|
name: capabilities;
|
||||||
|
display_name: string;
|
||||||
|
enable: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default class Hyperglass implements adapter {
|
||||||
|
private axiosInstance: AxiosInstance;
|
||||||
|
constructor(link: string) {
|
||||||
|
this.axiosInstance = axios.create({
|
||||||
|
baseURL: link,
|
||||||
|
headers: {
|
||||||
|
"Content-Type": "application/json",
|
||||||
|
},
|
||||||
|
transformRequest: [
|
||||||
|
(data: object) => {
|
||||||
|
return JSON.stringify(data);
|
||||||
|
},
|
||||||
|
],
|
||||||
|
transformResponse: [
|
||||||
|
(data: string) => {
|
||||||
|
return JSON.parse(data);
|
||||||
|
},
|
||||||
|
],
|
||||||
|
validateStatus: function (status) {
|
||||||
|
return status < 500;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this.axiosInstance.get("/api/info").then((r) => {
|
||||||
|
if (!(r.data.version as string).includes("hyperglass")) {
|
||||||
|
throw new Error(
|
||||||
|
"Not found hyperglass in /api/info. Please check your Hyperglass URL."
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async info(): Promise<info> {
|
||||||
|
const response = await this.axiosInstance.get("/api/info");
|
||||||
|
return {
|
||||||
|
name: response.data.name,
|
||||||
|
organization: response.data.organization,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
async devicesRaw(): Promise<deviceRaw[]> {
|
||||||
|
const response = await this.axiosInstance.get("/api/devices");
|
||||||
|
return response.data as deviceRaw[];
|
||||||
|
}
|
||||||
|
async listQueiesTypeRaw(): Promise<queryTypeRaw[]> {
|
||||||
|
const response = await this.axiosInstance.get("/api/queries");
|
||||||
|
return response.data as queryTypeRaw[];
|
||||||
|
}
|
||||||
|
|
||||||
|
async capabilities(): Promise<capabilities[]> {
|
||||||
|
return (await this.listQueiesTypeRaw()).reduce(
|
||||||
|
(previous: capabilities[], current) => {
|
||||||
|
if (current.enable) {
|
||||||
|
previous.push(current.name);
|
||||||
|
}
|
||||||
|
return previous;
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
async devices(): Promise<device[]> {
|
||||||
|
const devicesRaw = await this.devicesRaw();
|
||||||
|
const globalCapabilities = await this.capabilities();
|
||||||
|
return devicesRaw.map((k) => {
|
||||||
|
return {
|
||||||
|
name: k.name,
|
||||||
|
group: k.network.display_name,
|
||||||
|
capabilities: globalCapabilities,
|
||||||
|
vrfs: k.vrfs.map((k) => k.name),
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async query(capability: capabilities, device: device, vrf: string, target: Address4 | Address6): Promise<queryError | querySuccess> {
|
||||||
|
|
||||||
|
const response = await this.axiosInstance.post("api/query/", {
|
||||||
|
query_location: device.name.replace(/[^A-Za-z0-9\_\-\s]/g,"").replaceAll(" ","_").toLowerCase(),
|
||||||
|
query_target: target.address,
|
||||||
|
query_vrf: vrf,
|
||||||
|
query_type: capability,
|
||||||
|
});
|
||||||
|
|
||||||
|
if (response.status == 200) {
|
||||||
|
return {
|
||||||
|
level: response.data.level as "success",
|
||||||
|
output: response.data.output as string,
|
||||||
|
timestamp: new Date(response.data.timestamp),
|
||||||
|
} as querySuccess;
|
||||||
|
} else if (response.status == 400) {
|
||||||
|
return {
|
||||||
|
level: response.data.level as "danger",
|
||||||
|
output: "Request Content Error: " + response.data.output as string,
|
||||||
|
} as queryError;
|
||||||
|
} else if (response.status == 422) {
|
||||||
|
return {
|
||||||
|
level: response.data.level as "danger",
|
||||||
|
output: "Request Format Error: " + response.data.output as string,
|
||||||
|
} as queryError;
|
||||||
|
} else if (response.status == 500) {
|
||||||
|
return {
|
||||||
|
level: response.data.level as "danger",
|
||||||
|
output: "Server Error: " + response.data.output as string,
|
||||||
|
} as queryError;
|
||||||
|
} else {
|
||||||
|
return {
|
||||||
|
level: "danger",
|
||||||
|
output: "Unknown Error.",
|
||||||
|
} as queryError;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { Context, Telegraf } from 'telegraf';
|
||||||
|
import { Update } from 'typegram';
|
||||||
|
import handleInfo from './handler/info';
|
||||||
|
import config from "./config";
|
||||||
|
|
||||||
|
const bot: Telegraf<Context<Update>> = new Telegraf(config.token);
|
||||||
|
|
||||||
|
bot.start(handleInfo(config.adapter));
|
||||||
|
|
||||||
|
bot.launch();
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { Context } from "telegraf";
|
||||||
|
import { adapter } from "../types/adapter";
|
||||||
|
|
||||||
|
export default function handleInfo(adapter: adapter) {
|
||||||
|
return async (ctx: Context)=>{
|
||||||
|
const info = await adapter.info();
|
||||||
|
ctx.reply(`${info.name} Bot from ${info.organization}.`)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,44 @@
|
||||||
|
import { Address4, Address6 } from "ip-address";
|
||||||
|
|
||||||
|
enum capabilities {
|
||||||
|
"BGP Route" = "bgp_route",
|
||||||
|
"Ping" = "ping",
|
||||||
|
"Traceroute" = "traceroute",
|
||||||
|
}
|
||||||
|
|
||||||
|
interface info {
|
||||||
|
name: string;
|
||||||
|
organization: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface device {
|
||||||
|
name: string;
|
||||||
|
group: string;
|
||||||
|
capabilities: capabilities[];
|
||||||
|
vrfs: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface queryResponse {
|
||||||
|
level: "success" | "warning" | "error" | "danger";
|
||||||
|
}
|
||||||
|
|
||||||
|
interface queryError extends queryResponse {
|
||||||
|
output?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface querySuccess extends queryResponse {
|
||||||
|
level: "success";
|
||||||
|
output: string;
|
||||||
|
timestamp: Date;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface adapter {
|
||||||
|
info(): Promise<info>;
|
||||||
|
devices(): Promise<device[]>;
|
||||||
|
query(
|
||||||
|
capability: capabilities,
|
||||||
|
device: device,
|
||||||
|
vrf: string,
|
||||||
|
target: Address4 | Address6
|
||||||
|
): Promise<queryError | querySuccess | queryResponse>;
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
interface config {
|
||||||
|
token: string; // Telegram Bot token.
|
||||||
|
adapter: adapter;
|
||||||
|
}
|
|
@ -0,0 +1,19 @@
|
||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"module": "commonjs",
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"target": "es2021",
|
||||||
|
"moduleResolution": "node",
|
||||||
|
"strict": true,
|
||||||
|
"sourceMap": true,
|
||||||
|
"lib": [
|
||||||
|
"es2021"
|
||||||
|
],
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"rootDir": "src",
|
||||||
|
"outDir": "dist"
|
||||||
|
},
|
||||||
|
"typeRoots": [
|
||||||
|
"./src/types"
|
||||||
|
]
|
||||||
|
}
|
Loading…
Reference in New Issue