added SMTP monitor

This commit is contained in:
Brad Koehn 2025-01-01 14:48:23 -06:00
parent be2faf64ce
commit 16edd5932e
No known key found for this signature in database
7 changed files with 81 additions and 5 deletions

View file

@ -0,0 +1,12 @@
exports.up = function (knex) {
return knex.schema
.alterTable("monitor", function (table) {
table.string("smtp_security").defaultTo(null);
});
};
exports.down = function (knex) {
return knex.schema.alterTable("monitor", function (table) {
table.dropColumn("smtp_security");
});
};

4
package-lock.json generated
View file

@ -1,12 +1,12 @@
{ {
"name": "uptime-kuma", "name": "uptime-kuma",
"version": "2.0.0-beta.0", "version": "2.0.0-beta.1",
"lockfileVersion": 3, "lockfileVersion": 3,
"requires": true, "requires": true,
"packages": { "packages": {
"": { "": {
"name": "uptime-kuma", "name": "uptime-kuma",
"version": "2.0.0-beta.0", "version": "2.0.0-beta.1",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"@grpc/grpc-js": "~1.8.22", "@grpc/grpc-js": "~1.8.22",

View file

@ -153,6 +153,7 @@ class Monitor extends BeanModel {
snmpOid: this.snmpOid, snmpOid: this.snmpOid,
jsonPathOperator: this.jsonPathOperator, jsonPathOperator: this.jsonPathOperator,
snmpVersion: this.snmpVersion, snmpVersion: this.snmpVersion,
smtpSecurity: this.smtpSecurity,
rabbitmqNodes: JSON.parse(this.rabbitmqNodes), rabbitmqNodes: JSON.parse(this.rabbitmqNodes),
conditions: JSON.parse(this.conditions), conditions: JSON.parse(this.conditions),
}; };

View file

@ -0,0 +1,47 @@
const { MonitorType } = require("./monitor-type");
const { UP, log, evaluateJsonQuery } = require("../../src/util");
const nodemailer = require("nodemailer");
class SMTPMonitorType extends MonitorType {
name = "smtp";
isSMTPS(smtpSecurity) {
return smtpSecurity === 'secure';
}
isIgnoreTLS(smtpSecurity) {
return smtpSecurity === 'nostarttls';
}
isRequireTLS(smtpSecurity) {
return smtpSecurity === 'starttls';
}
/**
* @inheritdoc
*/
async check(monitor, heartbeat, _server) {
let options = {
port: monitor.port || 25,
host: monitor.hostname,
secure: this.isSMTPS(monitor.smtpSecurity), // use SMTPS (not STARTTLS)
ignoreTLS: this.isIgnoreTLS(monitor.smtpSecurity), // don't use STARTTLS even if it's available
requireTLS: this.isRequireTLS(monitor.smtpSecurity), // use STARTTLS or fail
}
let transporter = nodemailer.createTransport(options);
try {
await transporter.verify();
heartbeat.status = UP;
heartbeat.msg = `SMTP connection verifies successfully`;
} catch (e) {
throw new Error(`SMTP connection doesn't verify: ${e}`);
} finally {
transporter.close();
}
}
}
module.exports = {
SMTPMonitorType,
};

View file

@ -866,8 +866,10 @@ let needSetup = false;
monitor.kafkaProducerAllowAutoTopicCreation; monitor.kafkaProducerAllowAutoTopicCreation;
bean.gamedigGivenPortOnly = monitor.gamedigGivenPortOnly; bean.gamedigGivenPortOnly = monitor.gamedigGivenPortOnly;
bean.remote_browser = monitor.remote_browser; bean.remote_browser = monitor.remote_browser;
bean.smtpSecurity = monitor.smtpSecurity;
bean.snmpVersion = monitor.snmpVersion; bean.snmpVersion = monitor.snmpVersion;
bean.snmpOid = monitor.snmpOid; bean.snmpOid = monitor.snmpOid;
bean.smtpSecurity = monitor.smtpSecurity;
bean.jsonPathOperator = monitor.jsonPathOperator; bean.jsonPathOperator = monitor.jsonPathOperator;
bean.timeout = monitor.timeout; bean.timeout = monitor.timeout;
bean.rabbitmqNodes = JSON.stringify(monitor.rabbitmqNodes); bean.rabbitmqNodes = JSON.stringify(monitor.rabbitmqNodes);

View file

@ -113,6 +113,7 @@ class UptimeKumaServer {
UptimeKumaServer.monitorTypeList["tailscale-ping"] = new TailscalePing(); UptimeKumaServer.monitorTypeList["tailscale-ping"] = new TailscalePing();
UptimeKumaServer.monitorTypeList["dns"] = new DnsMonitorType(); UptimeKumaServer.monitorTypeList["dns"] = new DnsMonitorType();
UptimeKumaServer.monitorTypeList["mqtt"] = new MqttMonitorType(); UptimeKumaServer.monitorTypeList["mqtt"] = new MqttMonitorType();
UptimeKumaServer.monitorTypeList["smtp"] = new SMTPMonitorType();
UptimeKumaServer.monitorTypeList["snmp"] = new SNMPMonitorType(); UptimeKumaServer.monitorTypeList["snmp"] = new SNMPMonitorType();
UptimeKumaServer.monitorTypeList["mongodb"] = new MongodbMonitorType(); UptimeKumaServer.monitorTypeList["mongodb"] = new MongodbMonitorType();
UptimeKumaServer.monitorTypeList["rabbitmq"] = new RabbitMqMonitorType(); UptimeKumaServer.monitorTypeList["rabbitmq"] = new RabbitMqMonitorType();
@ -551,6 +552,7 @@ const { RealBrowserMonitorType } = require("./monitor-types/real-browser-monitor
const { TailscalePing } = require("./monitor-types/tailscale-ping"); const { TailscalePing } = require("./monitor-types/tailscale-ping");
const { DnsMonitorType } = require("./monitor-types/dns"); const { DnsMonitorType } = require("./monitor-types/dns");
const { MqttMonitorType } = require("./monitor-types/mqtt"); const { MqttMonitorType } = require("./monitor-types/mqtt");
const { SMTPMonitorType } = require("./monitor-types/smtp");
const { SNMPMonitorType } = require("./monitor-types/snmp"); const { SNMPMonitorType } = require("./monitor-types/snmp");
const { MongodbMonitorType } = require("./monitor-types/mongodb"); const { MongodbMonitorType } = require("./monitor-types/mongodb");
const { RabbitMqMonitorType } = require("./monitor-types/rabbitmq"); const { RabbitMqMonitorType } = require("./monitor-types/rabbitmq");

View file

@ -24,6 +24,9 @@
<option value="ping"> <option value="ping">
Ping Ping
</option> </option>
<option value="smtp">
SMTP
</option>
<option value="snmp"> <option value="snmp">
SNMP SNMP
</option> </option>
@ -281,8 +284,8 @@
</template> </template>
<!-- Hostname --> <!-- Hostname -->
<!-- TCP Port / Ping / DNS / Steam / MQTT / Radius / Tailscale Ping / SNMP only --> <!-- TCP Port / Ping / DNS / Steam / MQTT / Radius / Tailscale Ping / SNMP / SMTP only -->
<div v-if="monitor.type === 'port' || monitor.type === 'ping' || monitor.type === 'dns' || monitor.type === 'steam' || monitor.type === 'gamedig' || monitor.type === 'mqtt' || monitor.type === 'radius' || monitor.type === 'tailscale-ping' || monitor.type === 'snmp'" class="my-3"> <div v-if="monitor.type === 'port' || monitor.type === 'ping' || monitor.type === 'dns' || monitor.type === 'steam' || monitor.type === 'gamedig' || monitor.type === 'mqtt' || monitor.type === 'radius' || monitor.type === 'tailscale-ping' || monitor.type === 'smtp' || monitor.type === 'snmp'" class="my-3">
<label for="hostname" class="form-label">{{ $t("Hostname") }}</label> <label for="hostname" class="form-label">{{ $t("Hostname") }}</label>
<input <input
id="hostname" id="hostname"
@ -297,7 +300,7 @@
<!-- Port --> <!-- Port -->
<!-- For TCP Port / Steam / MQTT / Radius Type / SNMP --> <!-- For TCP Port / Steam / MQTT / Radius Type / SNMP -->
<div v-if="monitor.type === 'port' || monitor.type === 'steam' || monitor.type === 'gamedig' || monitor.type === 'mqtt' || monitor.type === 'radius' || monitor.type === 'snmp'" class="my-3"> <div v-if="monitor.type === 'port' || monitor.type === 'steam' || monitor.type === 'gamedig' || monitor.type === 'mqtt' || monitor.type === 'radius' || monitor.type === 'smtp' || monitor.type === 'snmp'" class="my-3">
<label for="port" class="form-label">{{ $t("Port") }}</label> <label for="port" class="form-label">{{ $t("Port") }}</label>
<input id="port" v-model="monitor.port" type="number" class="form-control" required min="0" max="65535" step="1"> <input id="port" v-model="monitor.port" type="number" class="form-control" required min="0" max="65535" step="1">
</div> </div>
@ -329,6 +332,15 @@
</select> </select>
</div> </div>
<div v-if="monitor.type === 'smtp'" class="my-3">
<label for="smtp_security" class="form-label">{{ $t("SMTP Security") }}</label>
<select id="smtp_security" v-model="monitor.smtpSecurity" class="form-select">
<option value="secure">SMTPS</option>
<option value="nostarttls">Ignore STARTTLS</option>
<option value="starttls">Use STARTTLS</option>
</select>
</div>
<!-- Json Query --> <!-- Json Query -->
<!-- For Json Query / SNMP --> <!-- For Json Query / SNMP -->
<div v-if="monitor.type === 'json-query' || monitor.type === 'snmp'" class="my-3"> <div v-if="monitor.type === 'json-query' || monitor.type === 'snmp'" class="my-3">