diff --git a/server/notification-providers/threema.js b/server/notification-providers/threema.js new file mode 100644 index 00000000..07a54ab6 --- /dev/null +++ b/server/notification-providers/threema.js @@ -0,0 +1,77 @@ +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) { + const errorMessage = this.handleApiError(error); + this.throwGeneralAxiosError(errorMessage); + } + } + + /** + * Handle Threema API errors + * @param {any} error The error to handle + * @returns {string} Additional error context + */ + handleApiError(error) { + 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; + } + } +} + +module.exports = Threema; diff --git a/server/notification.js b/server/notification.js index 8feb5bd9..28b0db75 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 1c4636d5..42736661 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 00000000..9e46459d --- /dev/null +++ b/src/components/notifications/Threema.vue @@ -0,0 +1,87 @@ + + diff --git a/src/components/notifications/index.js b/src/components/notifications/index.js index 0fcdf050..5d49b8a4 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 fcf46ff4..f3b6adde 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": "Gateway-ID", + "threemaSenderIdentityFormat": "8 characters, usually starts with *", + "threemaApiAuthenticationSecret": "Gateway-ID Secret", + "threemaBasicModeInfo": "Note: This integration uses Threema Gateway in basic mode (server-based encryption). Further details can be found {0}." }