From 2e5e10343469dc2c3fa9857c94703f36e2a6b670 Mon Sep 17 00:00:00 2001 From: booooza Date: Fri, 14 Jun 2024 12:25:19 +0200 Subject: [PATCH 1/4] New notification provider: Threema Gateway --- server/notification-providers/threema.js | 83 ++++++++++++++++++++++++ server/notification.js | 2 + src/components/NotificationDialog.vue | 1 + src/components/notifications/Threema.vue | 78 ++++++++++++++++++++++ src/components/notifications/index.js | 2 + src/lang/en.json | 14 +++- 6 files changed, 179 insertions(+), 1 deletion(-) create mode 100644 server/notification-providers/threema.js create mode 100644 src/components/notifications/Threema.vue diff --git a/server/notification-providers/threema.js b/server/notification-providers/threema.js new file mode 100644 index 000000000..cf60876f2 --- /dev/null +++ b/server/notification-providers/threema.js @@ -0,0 +1,83 @@ +const NotificationProvider = require("./notification-provider"); +const axios = require("axios"); + +class Threema extends NotificationProvider { + name = "threema"; + + /** + * @inheritdoc + */ + async send(notification, msg, monitorJSON = null, heartbeatJSON = null) { + const url = "https://msgapi.threema.ch/send_simple"; + + const config = { + headers: { + "Accept": "*/*", + "Content-Type": "application/x-www-form-urlencoded; charset=utf-8" + } + }; + + const data = { + from: notification.threemaSenderIdentity, + secret: notification.threemaSecret, + text: msg + }; + + switch (notification.threemaRecipientType) { + case "identity": + data.to = notification.threemaRecipient; + break; + case "phone": + data.phone = notification.threemaRecipient; + break; + case "email": + data.email = notification.threemaRecipient; + break; + default: + throw new Error(`Unsupported recipient type: ${notification.threemaRecipientType}`); + } + + try { + await axios.post(url, new URLSearchParams(data), config); + return "Threema notification sent successfully."; + } catch (error) { + this.handleApiError(error); + this.throwGeneralAxiosError(error); + } + } + + /** + * Handle Threema API errors + * @param {any} error The error to handle + * @returns {void} + */ + handleApiError(error) { + if (error.response) { + const status = error.response.status; + switch (status) { + case 400: + error.message = "Invalid recipient identity or account not set up for basic mode (400)."; + break; + case 401: + error.message = "Incorrect API identity or secret (401)."; + break; + case 402: + error.message = "No credits remaining (402)."; + break; + case 404: + error.message = "Recipient not found (404)."; + break; + case 413: + error.message = "Message is too long (413)."; + break; + case 500: + error.message = "Temporary internal server error (500)."; + break; + default: + break; + } + } + } +} + +module.exports = Threema; diff --git a/server/notification.js b/server/notification.js index 8feb5bd9a..28b0db758 100644 --- a/server/notification.js +++ b/server/notification.js @@ -51,6 +51,7 @@ const Stackfield = require("./notification-providers/stackfield"); const Teams = require("./notification-providers/teams"); const TechulusPush = require("./notification-providers/techulus-push"); const Telegram = require("./notification-providers/telegram"); +const Threema = require("./notification-providers/threema"); const Twilio = require("./notification-providers/twilio"); const Splunk = require("./notification-providers/splunk"); const Webhook = require("./notification-providers/webhook"); @@ -133,6 +134,7 @@ class Notification { new Teams(), new TechulusPush(), new Telegram(), + new Threema(), new Twilio(), new Splunk(), new Webhook(), diff --git a/src/components/NotificationDialog.vue b/src/components/NotificationDialog.vue index 1c4636d56..427366619 100644 --- a/src/components/NotificationDialog.vue +++ b/src/components/NotificationDialog.vue @@ -152,6 +152,7 @@ export default { "stackfield": "Stackfield", "teams": "Microsoft Teams", "telegram": "Telegram", + "threema": "Threema", "twilio": "Twilio", "Splunk": "Splunk", "webhook": "Webhook", diff --git a/src/components/notifications/Threema.vue b/src/components/notifications/Threema.vue new file mode 100644 index 000000000..79ec89ed5 --- /dev/null +++ b/src/components/notifications/Threema.vue @@ -0,0 +1,78 @@ + + diff --git a/src/components/notifications/index.js b/src/components/notifications/index.js index 0fcdf0504..5d49b8a4a 100644 --- a/src/components/notifications/index.js +++ b/src/components/notifications/index.js @@ -52,6 +52,7 @@ import STMP from "./SMTP.vue"; import Teams from "./Teams.vue"; import TechulusPush from "./TechulusPush.vue"; import Telegram from "./Telegram.vue"; +import Threema from "./Threema.vue"; import Twilio from "./Twilio.vue"; import Webhook from "./Webhook.vue"; import WeCom from "./WeCom.vue"; @@ -119,6 +120,7 @@ const NotificationFormList = { "stackfield": Stackfield, "teams": Teams, "telegram": Telegram, + "threema": Threema, "twilio": Twilio, "Splunk": Splunk, "webhook": Webhook, diff --git a/src/lang/en.json b/src/lang/en.json index fcf46ff4a..8f7b34ef2 100644 --- a/src/lang/en.json +++ b/src/lang/en.json @@ -942,5 +942,17 @@ "Allow Long SMS": "Allow Long SMS", "cellsyntSplitLongMessages": "Split long messages into up to 6 parts. 153 x 6 = 918 characters.", "max 15 digits": "max 15 digits", - "max 11 alphanumeric characters": "max 11 alphanumeric characters" + "max 11 alphanumeric characters": "max 11 alphanumeric characters", + "wayToGetThreemaGateway": "You can register for Threema Gateway {0}.", + "threemaRecipient": "Recipient", + "threemaRecipientType": "Recipient Type", + "threemaRecipientTypeIdentity": "Threema-ID", + "threemaRecipientTypeIdentityFormat": "8 characters", + "threemaRecipientTypePhone": "Phone Number", + "threemaRecipientTypePhoneFormat": "E.164, without leading +", + "threemaRecipientTypeEmail": "Email Address", + "threemaSenderIdentity": "Sender", + "threemaSenderIdentityFormat": "8 characters, usually starts with '*'", + "threemaApiAuthenticationSecret": "API authentication secret", + "threemaBasicModeInfo": "Note: This integration uses Threema Gateway in basic mode (server-based encryption). Further details can be found {0}." } From 39b0c62c1dd8e39e175858c2293f8730b1f41b84 Mon Sep 17 00:00:00 2001 From: booooza Date: Mon, 17 Jun 2024 08:34:53 +0200 Subject: [PATCH 2/4] Refactor error handling to improve clarity and maintainability --- server/notification-providers/threema.js | 48 +++++++++++------------- 1 file changed, 21 insertions(+), 27 deletions(-) diff --git a/server/notification-providers/threema.js b/server/notification-providers/threema.js index cf60876f2..07a54ab6e 100644 --- a/server/notification-providers/threema.js +++ b/server/notification-providers/threema.js @@ -41,41 +41,35 @@ class Threema extends NotificationProvider { await axios.post(url, new URLSearchParams(data), config); return "Threema notification sent successfully."; } catch (error) { - this.handleApiError(error); - this.throwGeneralAxiosError(error); + const errorMessage = this.handleApiError(error); + this.throwGeneralAxiosError(errorMessage); } } /** * Handle Threema API errors * @param {any} error The error to handle - * @returns {void} + * @returns {string} Additional error context */ handleApiError(error) { - if (error.response) { - const status = error.response.status; - switch (status) { - case 400: - error.message = "Invalid recipient identity or account not set up for basic mode (400)."; - break; - case 401: - error.message = "Incorrect API identity or secret (401)."; - break; - case 402: - error.message = "No credits remaining (402)."; - break; - case 404: - error.message = "Recipient not found (404)."; - break; - case 413: - error.message = "Message is too long (413)."; - break; - case 500: - error.message = "Temporary internal server error (500)."; - break; - default: - break; - } + if (!error.response) { + return error.message; + } + switch (error.response.status) { + case 400: + return "Invalid recipient identity or account not set up for basic mode (400)."; + case 401: + return "Incorrect API identity or secret (401)."; + case 402: + return "No credits remaining (402)."; + case 404: + return "Recipient not found (404)."; + case 413: + return "Message is too long (413)."; + case 500: + return "Temporary internal server error (500)."; + default: + return error.message; } } } From 0960ec62b7732c98cd1bb858674df35bdf99033e Mon Sep 17 00:00:00 2001 From: booooza Date: Mon, 17 Jun 2024 08:46:08 +0200 Subject: [PATCH 3/4] Adjust Threema notification view to conform with project standards --- src/components/notifications/Threema.vue | 35 +++++++++++++++--------- 1 file changed, 22 insertions(+), 13 deletions(-) diff --git a/src/components/notifications/Threema.vue b/src/components/notifications/Threema.vue index 79ec89ed5..9e46459de 100644 --- a/src/components/notifications/Threema.vue +++ b/src/components/notifications/Threema.vue @@ -2,7 +2,7 @@
- + +
+

{{ $t("threemaRecipientTypeIdentityFormat") }}

+
-
- +
+ +
+

{{ $t("threemaRecipientTypePhoneFormat") }}

+
-
+
- + +
+

{{ $t("threemaSenderIdentityFormat") }}

+
- - {{ $t("here") }} - - - {{ $t("here") }} -
+ + {{ $t("here") }} + + + {{ $t("here") }} +