Merge pull request #420 from databasus/develop

FEATURE (email): Add skipping TLS for email notifier
This commit is contained in:
Rostislav Dugin
2026-03-08 22:53:45 +03:00
committed by GitHub
6 changed files with 90 additions and 11 deletions

View File

@@ -23,13 +23,14 @@ const (
)
type EmailNotifier struct {
NotifierID uuid.UUID `json:"notifierId" gorm:"primaryKey;type:uuid;column:notifier_id"`
TargetEmail string `json:"targetEmail" gorm:"not null;type:varchar(255);column:target_email"`
SMTPHost string `json:"smtpHost" gorm:"not null;type:varchar(255);column:smtp_host"`
SMTPPort int `json:"smtpPort" gorm:"not null;column:smtp_port"`
SMTPUser string `json:"smtpUser" gorm:"type:varchar(255);column:smtp_user"`
SMTPPassword string `json:"smtpPassword" gorm:"type:varchar(255);column:smtp_password"`
From string `json:"from" gorm:"type:varchar(255);column:from_email"`
NotifierID uuid.UUID `json:"notifierId" gorm:"primaryKey;type:uuid;column:notifier_id"`
TargetEmail string `json:"targetEmail" gorm:"not null;type:varchar(255);column:target_email"`
SMTPHost string `json:"smtpHost" gorm:"not null;type:varchar(255);column:smtp_host"`
SMTPPort int `json:"smtpPort" gorm:"not null;column:smtp_port"`
SMTPUser string `json:"smtpUser" gorm:"type:varchar(255);column:smtp_user"`
SMTPPassword string `json:"smtpPassword" gorm:"type:varchar(255);column:smtp_password"`
From string `json:"from" gorm:"type:varchar(255);column:from_email"`
IsInsecureSkipVerify bool `json:"isInsecureSkipVerify" gorm:"default:false;column:is_insecure_skip_verify"`
}
func (e *EmailNotifier) TableName() string {
@@ -99,6 +100,7 @@ func (e *EmailNotifier) Update(incoming *EmailNotifier) {
e.SMTPPort = incoming.SMTPPort
e.SMTPUser = incoming.SMTPUser
e.From = incoming.From
e.IsInsecureSkipVerify = incoming.IsInsecureSkipVerify
if incoming.SMTPPassword != "" {
e.SMTPPassword = incoming.SMTPPassword
@@ -198,7 +200,10 @@ func (e *EmailNotifier) sendStartTLS(
func (e *EmailNotifier) createImplicitTLSClient() (*smtp.Client, func(), error) {
addr := net.JoinHostPort(e.SMTPHost, fmt.Sprintf("%d", e.SMTPPort))
tlsConfig := &tls.Config{ServerName: e.SMTPHost}
tlsConfig := &tls.Config{
ServerName: e.SMTPHost,
InsecureSkipVerify: e.IsInsecureSkipVerify,
}
dialer := &net.Dialer{Timeout: DefaultTimeout}
conn, err := tls.DialWithDialer(dialer, "tcp", addr, tlsConfig)
@@ -237,7 +242,10 @@ func (e *EmailNotifier) createStartTLSClient() (*smtp.Client, func(), error) {
}
if ok, _ := client.Extension("STARTTLS"); ok {
if err := client.StartTLS(&tls.Config{ServerName: e.SMTPHost}); err != nil {
if err := client.StartTLS(&tls.Config{
ServerName: e.SMTPHost,
InsecureSkipVerify: e.IsInsecureSkipVerify,
}); err != nil {
_ = client.Quit()
_ = conn.Close()
return nil, nil, fmt.Errorf("STARTTLS failed: %w", err)

View File

@@ -0,0 +1,11 @@
-- +goose Up
-- +goose StatementBegin
ALTER TABLE email_notifiers
ADD COLUMN is_insecure_skip_verify BOOLEAN NOT NULL DEFAULT FALSE;
-- +goose StatementEnd
-- +goose Down
-- +goose StatementBegin
ALTER TABLE email_notifiers
DROP COLUMN is_insecure_skip_verify;
-- +goose StatementEnd

View File

@@ -5,4 +5,5 @@ export interface EmailNotifier {
smtpUser: string;
smtpPassword: string;
from: string;
isInsecureSkipVerify: boolean;
}

View File

@@ -112,6 +112,7 @@ export function EditNotifierComponent({
smtpUser: '',
smtpPassword: '',
from: '',
isInsecureSkipVerify: false,
};
}

View File

@@ -1,5 +1,6 @@
import { InfoCircleOutlined } from '@ant-design/icons';
import { Input, Tooltip } from 'antd';
import { DownOutlined, InfoCircleOutlined, UpOutlined } from '@ant-design/icons';
import { Checkbox, Input, Tooltip } from 'antd';
import { useState } from 'react';
import type { Notifier } from '../../../../../entity/notifiers';
@@ -10,6 +11,9 @@ interface Props {
}
export function EditEmailNotifierComponent({ notifier, setNotifier, setUnsaved }: Props) {
const hasAdvancedValues = !!notifier?.emailNotifier?.isInsecureSkipVerify;
const [showAdvanced, setShowAdvanced] = useState(hasAdvancedValues);
return (
<>
<div className="mb-1 flex w-full flex-col items-start sm:flex-row sm:items-center">
@@ -163,6 +167,53 @@ export function EditEmailNotifierComponent({ notifier, setNotifier, setUnsaved }
</Tooltip>
</div>
</div>
<div className="mt-4 mb-3 flex items-center">
<div
className="flex cursor-pointer items-center text-sm text-blue-600 hover:text-blue-800"
onClick={() => setShowAdvanced(!showAdvanced)}
>
<span className="mr-2">Advanced settings</span>
{showAdvanced ? (
<UpOutlined style={{ fontSize: '12px' }} />
) : (
<DownOutlined style={{ fontSize: '12px' }} />
)}
</div>
</div>
{showAdvanced && (
<div className="mb-1 flex w-full flex-col items-start sm:flex-row sm:items-center">
<div className="mb-1 min-w-[150px] sm:mb-0">Skip TLS verify</div>
<div className="flex items-center">
<Checkbox
checked={notifier?.emailNotifier?.isInsecureSkipVerify || false}
onChange={(e) => {
if (!notifier?.emailNotifier) return;
setNotifier({
...notifier,
emailNotifier: {
...notifier.emailNotifier,
isInsecureSkipVerify: e.target.checked,
},
});
setUnsaved();
}}
>
Skip TLS
</Checkbox>
<Tooltip
className="cursor-pointer"
title="Skip TLS certificate verification. Enable this if your SMTP server uses a self-signed certificate. Warning: this reduces security."
>
<InfoCircleOutlined className="ml-2" style={{ color: 'gray' }} />
</Tooltip>
</div>
</div>
)}
</>
);
}

View File

@@ -36,6 +36,13 @@ export function ShowEmailNotifierComponent({ notifier }: Props) {
<div className="min-w-[110px]">From</div>
{notifier?.emailNotifier?.from || '(auto)'}
</div>
{notifier?.emailNotifier?.isInsecureSkipVerify && (
<div className="mb-1 flex items-center">
<div className="min-w-[110px]">Skip TLS</div>
Enabled
</div>
)}
</>
);
}