From 239f667fe09bf4a9519e1692eaf66f414a0317f8 Mon Sep 17 00:00:00 2001 From: Lea Date: Thu, 17 Aug 2023 16:41:17 +0200 Subject: [PATCH] feat: add ntfy.sh notifications --- notifications.mjs | 56 +++++++++++++++++++++++++++++++++++++++++ package.json | 1 + pnpm-lock.yaml | 63 +++++++++++++++++++++++++++++++++++++++++++++++ server.js | 2 ++ 4 files changed, 122 insertions(+) create mode 100644 notifications.mjs diff --git a/notifications.mjs b/notifications.mjs new file mode 100644 index 0000000..da8618f --- /dev/null +++ b/notifications.mjs @@ -0,0 +1,56 @@ +import { createClient } from 'redis'; +import { NtfyClient, MessagePriority } from 'ntfy'; + +/** + * NTFY_SERVER + * NTFY_TOPIC + * NTFY_USERNAME + * NTFY_PASSWORD + */ + +if (!process.env.NTFY_TOPIC) { + console.log('$NTFY_TOPIC not set'); +} else { + console.log('Listening for new reports'); + + const ntfy = new NtfyClient(process.env.NTFY_SERVER); + const redis = createClient({ + url: process.env.REDIS, + }); + + redis.SUBSCRIBE('global', async (message) => { + try { + const event = JSON.parse(message); + if (event.type != "ReportCreate") return; + console.log('New report:', event.content); + + await ntfy.publish({ + title: `Report created (${event.content.type}, ${event.content.report_reason})`, + message: event.additional_context || "No reason provided", + iconURL: 'https://futacockinside.me/files/attention.png', + actions: [ + { + label: 'View report', + type: 'view', + url: `https://admin.revolt.chat/panel/reports/${event._id}`, + clear: true, + } + ], + priority: event.content.report_reason.includes('Illegal') + ? MessagePriority.HIGH + : MessagePriority.DEFAULT, + topic: process.env.NTFY_TOPIC, + authorization: process.env.NTFY_USERNAME && process.env.NTFY_PASSWORD + ? { + username: process.env.NTFY_USERNAME, + password: process.env.NTFY_PASSWORD, + } + : undefined, + }); + } catch(e) { + console.log(e); + } + }); + + redis.connect(); +} diff --git a/package.json b/package.json index b9f41b4..a3c750c 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "mongodb": "^5.7.0", "next": "13.4.12", "next-auth": "^4.22.3", + "ntfy": "^1.3.1", "postcss": "8.4.27", "react": "18.2.0", "react-dom": "18.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fd92def..3d783a2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -86,6 +86,9 @@ dependencies: next-auth: specifier: ^4.22.3 version: 4.22.3(next@13.4.12)(react-dom@18.2.0)(react@18.2.0) + ntfy: + specifier: ^1.3.1 + version: 1.3.1 postcss: specifier: 8.4.27 version: 8.4.27 @@ -1700,6 +1703,10 @@ packages: resolution: {integrity: sha512-eBvWn1lvIApYMhzQMsu9ciLfkBY499mFZlNqG+/9WR7PVlroQw0vG30cOQQbaKz3sCEc44TAOu2ykzqXSNnwag==} dev: false + /asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + dev: false + /autoprefixer@10.4.14(postcss@8.4.27): resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==} engines: {node: ^10 || ^12 || >=14} @@ -1733,6 +1740,16 @@ packages: transitivePeerDependencies: - debug + /axios@1.3.6: + resolution: {integrity: sha512-PEcdkk7JcdPiMDkvM4K6ZBRYq9keuVJsToxm2zQIM70Qqo2WHTdJZMXcG9X+RmRp2VPNUQC8W1RAGbgt6b1yMg==} + dependencies: + follow-redirects: 1.15.2 + form-data: 4.0.0 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + dev: false + /axobject-query@3.2.1: resolution: {integrity: sha512-jsyHu61e6N4Vbz/v18DHwWYKK0bSWLqn47eeDSKPB7m8tqMHF9YJ+mhIk2lVteyZrY8tnSj/jHOv4YiTCuCJgg==} dependencies: @@ -1921,6 +1938,13 @@ packages: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} dev: false + /combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + dependencies: + delayed-stream: 1.0.0 + dev: false + /comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} dev: false @@ -2035,6 +2059,11 @@ packages: object-keys: 1.1.1 dev: false + /delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dev: false + /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -2578,6 +2607,15 @@ packages: is-callable: 1.2.7 dev: false + /form-data@4.0.0: + resolution: {integrity: sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==} + engines: {node: '>= 6'} + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + mime-types: 2.1.35 + dev: false + /fraction.js@4.2.0: resolution: {integrity: sha512-MhLuK+2gUcnZe8ZHlaaINnQLl0xRIGRfcGk2yl8xoQAfHrSsL3rYu6FCmBdkdbhc9EPlwyGHewaRsvwRMJtAlA==} dev: false @@ -3612,6 +3650,18 @@ packages: braces: 3.0.2 picomatch: 2.3.1 + /mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + dev: false + + /mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + dependencies: + mime-db: 1.52.0 + dev: false + /mime@3.0.0: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} engines: {node: '>=10.0.0'} @@ -3804,6 +3854,15 @@ packages: path-key: 4.0.0 dev: false + /ntfy@1.3.1: + resolution: {integrity: sha512-XzEfKoEPamoLOHGcO5FC2nFFrDi3/Dkm/R5loxbEiow+m2bkjmoPkDw4shugmF+bNQ5Mh2NIYmcqAO1yTsvC9w==} + engines: {node: '>= 14.16'} + dependencies: + axios: 1.3.6 + transitivePeerDependencies: + - debug + dev: false + /oauth@0.9.15: resolution: {integrity: sha512-a5ERWK1kh38ExDEfoO6qUHJb32rd7aYmPHuyCu3Fta/cnICvYmgd2uhuKXvPD+PXB+gCEYYEaQdIRAjCOwAKNA==} dev: false @@ -4145,6 +4204,10 @@ packages: resolution: {integrity: sha512-kma4U7AFCTwpqq5twzC1YVIDXSqg6qQK6JN0smOw8fgRy1OkMi0CYSzFmsy6dnqSenamAtj0CyXMUJ1Mf6oROg==} dev: false + /proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + dev: false + /punycode@2.3.0: resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==} engines: {node: '>=6'} diff --git a/server.js b/server.js index c9ddd8b..fda8457 100644 --- a/server.js +++ b/server.js @@ -38,3 +38,5 @@ app.prepare().then(() => { console.log(`> Ready on http://${hostname}:${port}`); }); }); + +import('./notifications.mjs');