From 2f4873119c264f1df2fc5b4b1786ec5a870a0c88 Mon Sep 17 00:00:00 2001 From: alyssa Date: Wed, 16 Oct 2024 09:07:37 +0900 Subject: [PATCH] server-checks chatops --- package.json | 3 +- src/config.ts | 1 + src/evt/messageCreate.ts | 150 +++++++++++++++++++++++++++++++++++++++ yarn.lock | 20 ++++-- 4 files changed, 169 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 04092e1..3017347 100644 --- a/package.json +++ b/package.json @@ -2,11 +2,12 @@ "dependencies": { "@beenotung/level-ts": "^1.15.0", "@types/ioredis": "^4.28.10", + "@types/node": "^22.7.5", "axios": "^0.24.0", "detritus-client-rest": "^0.10.5", "detritus-client-socket": "^0.8.3", "ioredis": "^5.0.2", "ts-node": "^10.7.0", - "typescript": "^4.4.3" + "typescript": "^5.6.3" } } diff --git a/src/config.ts b/src/config.ts index 76e47dd..584cc0f 100644 --- a/src/config.ts +++ b/src/config.ts @@ -3,6 +3,7 @@ export default { chat_role_id: "823595534567866428", restrict_role_id: "895972446992228382", admin_role_id: "686489711719612502", + infra_role_id: "1291763746657669211", // 2 weeks newAccountDuration: 60 // seconds diff --git a/src/evt/messageCreate.ts b/src/evt/messageCreate.ts index 4f2670f..7d01172 100644 --- a/src/evt/messageCreate.ts +++ b/src/evt/messageCreate.ts @@ -20,6 +20,8 @@ export default async (evt: any, ctx: Context) => { const content: string = evt.content.toLowerCase(); + if (evt.author.id != "883545422860283964") return; + if (content == "?ping") return await ctx.rest.createMessage(evt.channel_id, "meow!"); @@ -116,4 +118,152 @@ export default async (evt: any, ctx: Context) => { await ctx.rest.createMessage(evt.channel_id, res); } + + if (content?.startsWith("+s") && evt.member.roles.includes(config.infra_role_id)) { + if (content == "+s h" || content == "+s help") { + await ctx.rest.createMessage(evt.channel_id, "server-checks chatops\n\n`+s`: list silences\n`+s +`: create silence\n`+s -`: delete silence" + + "\n`+s override`: override @infra pings to your account (for testing and such)\n`+s clearoverride`: clear ping override"); + } else if (content.length == 2) { + let res = await fetch( + `https://api.cloudflare.com/client/v4/accounts/${process.env.cf_account}/storage/kv/namespaces/4fd4893d94354dac96da55a68c5df4fc/values/silences`, + { headers: { authorization: `Bearer ${process.env.cf_token}` } }) + .then((x: any) => x.json()); + console.log(res); + let silences = res.map((x: any) => `- \`${x.check ?? (x.checkPrefix+"*")}@${x.node}\``).join("\n"); + if (silences == "") silences = "no silences set"; + await ctx.rest.createMessage(evt.channel_id, silences); + } else if (content[3] == "+") { + // add silence + let newsilence: any = content.slice(4).split("@"); + if (newsilence.length != 2) { + await ctx.rest.createMessage(evt.channel_id, "format: `check@host`, optionally accepting a wildcard for hostname (`somecheck@*`) and/or at end of check name (someprefix*@somehost)") + return + } + // parse text + newsilence = [newsilence].map(x => ({ check: x[0], checkPrefix: null, node: x[1] })) + .map(x => { + if (x.check.endsWith("*")) { + x.checkPrefix = x.check.slice(0, -1); + x.check = null; + } + return x; + })[0]; + console.log(newsilence); + + let curSilences = await fetch( + `https://api.cloudflare.com/client/v4/accounts/${process.env.cf_account}/storage/kv/namespaces/4fd4893d94354dac96da55a68c5df4fc/values/silences`, + { headers: { authorization: `Bearer ${process.env.cf_token}` } }) + .then((x: any) => x.json()); + + if (!!curSilences.find((x: any) => x.check == newsilence.check && x.checkPrefix == newsilence.checkPrefix && x.node == newsilence.node)) { + await ctx.rest.createMessage(evt.channel_id, "check already exists"); + return; + } + + curSilences.push(newsilence); + + let res = await fetch( + `https://api.cloudflare.com/client/v4/accounts/${process.env.cf_account}/storage/kv/namespaces/4fd4893d94354dac96da55a68c5df4fc/values/silences`, + { + method: "PUT", + headers: { authorization: `Bearer ${process.env.cf_token}` }, + body: JSON.stringify(curSilences), + }) + .then((x: any) => x.json()); + if (res.success) { + await ctx.rest.createMessage(evt.channel_id, "ok"); + } else { + await ctx.rest.createMessage(evt.channel_id, `not ok: ${JSON.stringify(res)}`); + } + } else if (content[3] == "-") { + // remove silence + let newsilence: any = content.slice(4).split("@"); + if (newsilence.length != 2) { + await ctx.rest.createMessage(evt.channel_id, "format: `check@host`, optionally accepting a wildcard for hostname (`somecheck@*`) and/or at end of check name (someprefix*@somehost)") + return + } + // parse text + newsilence = [newsilence].map(x => ({ check: x[0], checkPrefix: null, node: x[1] })) + .map(x => { + if (x.check.endsWith("*")) { + x.checkPrefix = x.check.slice(0, -1); + x.check = null; + } + return x; + })[0]; + console.log(newsilence); + + let curSilences = await fetch( + `https://api.cloudflare.com/client/v4/accounts/${process.env.cf_account}/storage/kv/namespaces/4fd4893d94354dac96da55a68c5df4fc/values/silences`, + { headers: { authorization: `Bearer ${process.env.cf_token}` } }) + .then((x: any) => x.json()); + console.log("del: get", curSilences); + + let idx = curSilences.find((x: any) => x.check == newsilence.check && x.checkPrefix == newsilence.checkPrefix && x.node == newsilence.node); + + if (idx == null) { + await ctx.rest.createMessage(evt.channel_id, "check doesn't exist"); + return; + } + + curSilences.splice(idx, 1); + console.log("del: send", curSilences); + + let res = await fetch( + `https://api.cloudflare.com/client/v4/accounts/${process.env.cf_account}/storage/kv/namespaces/4fd4893d94354dac96da55a68c5df4fc/values/silences`, + { + method: "PUT", + headers: { authorization: `Bearer ${process.env.cf_token}` }, + body: JSON.stringify(curSilences), + }) + .then((x: any) => x.json()); + if (res.success) { + await ctx.rest.createMessage(evt.channel_id, "ok"); + } else { + await ctx.rest.createMessage(evt.channel_id, `not ok: ${JSON.stringify(res)}`); + } + } else if (content == "+s clear") { + let res = await fetch( + `https://api.cloudflare.com/client/v4/accounts/${process.env.cf_account}/storage/kv/namespaces/4fd4893d94354dac96da55a68c5df4fc/values/silences`, + { + method: "PUT", + headers: { authorization: `Bearer ${process.env.cf_token}` }, + body: JSON.stringify([]), + }) + .then((x: any) => x.json()); + if (res.success) { + await ctx.rest.createMessage(evt.channel_id, "ok"); + } else { + await ctx.rest.createMessage(evt.channel_id, `not ok: ${JSON.stringify(res)}`); + } + } else if (content == "+s override") { + let res = await fetch( + `https://api.cloudflare.com/client/v4/accounts/${process.env.cf_account}/storage/kv/namespaces/4fd4893d94354dac96da55a68c5df4fc/values/notif`, + { + method: "PUT", + headers: { authorization: `Bearer ${process.env.cf_token}` }, + body: `<@${evt.author.id}>`, + }) + .then((x: any) => x.json()); + if (res.success) { + await ctx.rest.createMessage(evt.channel_id, "ok"); + } else { + await ctx.rest.createMessage(evt.channel_id, `not ok: ${JSON.stringify(res)}`); + } + } else if (content == "+s clearoverride") { + let res = await fetch( + `https://api.cloudflare.com/client/v4/accounts/${process.env.cf_account}/storage/kv/namespaces/4fd4893d94354dac96da55a68c5df4fc/values/notif`, + { + method: "PUT", + headers: { authorization: `Bearer ${process.env.cf_token}` }, + body: "", + }) + .then((x: any) => x.json()); + if (res.success) { + await ctx.rest.createMessage(evt.channel_id, "ok"); + } else { + await ctx.rest.createMessage(evt.channel_id, `not ok: ${JSON.stringify(res)}`); + } + } + } } diff --git a/yarn.lock b/yarn.lock index c80b2f5..51815b0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -64,6 +64,13 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.17.21.tgz#6359d8cf73481e312a43886fa50afc70ce5592c6" integrity sha512-zv8ukKci1mrILYiQOwGSV4FpkZhyxQtuFWGya2GujWg+zVAeRQ4qbaMmWp9vb9889CFA8JECH7lkwCL6Ygg8kA== +"@types/node@^22.7.5": + version "22.7.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-22.7.5.tgz#cfde981727a7ab3611a481510b473ae54442b92b" + integrity sha512-jML7s2NAzMWc//QSJ1a3prpk78cOPchGvXJsC3C6R6PSMoooztvRVQEz89gmBTBY1SPMaqo5teB4uNHPdetShQ== + dependencies: + undici-types "~6.19.2" + abstract-leveldown@^6.2.1: version "6.3.0" resolved "https://registry.yarnpkg.com/abstract-leveldown/-/abstract-leveldown-6.3.0.tgz#d25221d1e6612f820c35963ba4bd739928f6026a" @@ -642,10 +649,15 @@ typedarray-to-buffer@~3.1.5: dependencies: is-typedarray "^1.0.0" -typescript@^4.4.3: - version "4.4.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324" - integrity sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA== +typescript@^5.6.3: + version "5.6.3" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.6.3.tgz#5f3449e31c9d94febb17de03cc081dd56d81db5b" + integrity sha512-hjcS1mhfuyi4WW8IWtjP7brDrG2cuDZukyrYrSauoXGNgx0S7zceP07adYkJycEr56BOUTNPzbInooiN3fn1qw== + +undici-types@~6.19.2: + version "6.19.8" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.19.8.tgz#35111c9d1437ab83a7cdc0abae2f26d88eda0a02" + integrity sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw== util-deprecate@^1.0.1, util-deprecate@~1.0.1: version "1.0.2"