feat: publish dbussmsforward refactor

This commit is contained in:
2026-05-08 23:54:03 +08:00
commit 9f1ee9ffe6
77 changed files with 15585 additions and 0 deletions
@@ -0,0 +1,32 @@
using DbusSmsForward.Helper;
using DbusSmsForward.Services;
using DbusSmsForward.SettingModel;
using DbusSmsForward.SMSModel;
using System.Text.Json.Nodes;
namespace DbusSmsForward.Notifications;
public sealed class AutmanPushNotificationSender(DbusSmsForwardOptions options) : NotificationSenderBase("autmanpush")
{
private readonly AutmanPushConfig _config = options.Notifications.AutmanPush;
public override bool IsEnabled => _config.Enabled && !string.IsNullOrWhiteSpace(_config.ApiUrl);
public override async Task SendAsync(SmsContentModel sms, string body, string deviceName, CancellationToken cancellationToken)
{
JsonObject payload = new()
{
["title"] = BuildTitle(sms.TelNumber, string.Empty),
["content"] = body,
["deviceName"] = deviceName,
["phoneNumber"] = sms.TelNumber
};
if (!string.IsNullOrWhiteSpace(_config.AccessToken))
{
payload["accessToken"] = _config.AccessToken;
}
await HttpHelper.PostAsync(_config.ApiUrl, payload, _config.SkipTlsValidation, cancellationToken);
}
}
@@ -0,0 +1,27 @@
using DbusSmsForward.Helper;
using DbusSmsForward.ProcessSmsContent;
using DbusSmsForward.Services;
using DbusSmsForward.SettingModel;
using DbusSmsForward.SMSModel;
using System.Web;
namespace DbusSmsForward.Notifications;
public sealed class BarkNotificationSender(DbusSmsForwardOptions options) : NotificationSenderBase("bark")
{
private readonly BarkConfig _config = options.Notifications.Bark;
public override bool IsEnabled => _config.Enabled && !string.IsNullOrWhiteSpace(_config.ServerUrl) && !string.IsNullOrWhiteSpace(_config.BarkKey);
public override async Task SendAsync(SmsContentModel sms, string body, string deviceName, CancellationToken cancellationToken)
{
SmsCodeModel code = NotificationContentBuilder.ExtractCode(options, sms);
string url = $"{_config.ServerUrl.TrimEnd('/')}/{_config.BarkKey}/{HttpUtility.UrlEncode(body)}?group={HttpUtility.UrlEncode(sms.TelNumber)}&title={HttpUtility.UrlEncode(BuildTitle(sms.TelNumber, code.CodeValue))}";
if (!string.IsNullOrWhiteSpace(code.CodeValue))
{
url += $"&autoCopy=1&copy={HttpUtility.UrlEncode(code.CodeValue)}";
}
await HttpHelper.HttpGetAsync(url, _config.SkipTlsValidation, cancellationToken);
}
}
@@ -0,0 +1,47 @@
using DbusSmsForward.Helper;
using DbusSmsForward.Services;
using DbusSmsForward.SettingModel;
using DbusSmsForward.SMSModel;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json.Nodes;
using System.Web;
namespace DbusSmsForward.Notifications;
public sealed class DingTalkNotificationSender(DbusSmsForwardOptions options) : NotificationSenderBase("dingtalk")
{
private readonly DingTalkConfig _config = options.Notifications.DingTalk;
public override bool IsEnabled => _config.Enabled && !string.IsNullOrWhiteSpace(_config.AccessToken);
public override async Task SendAsync(SmsContentModel sms, string body, string deviceName, CancellationToken cancellationToken)
{
string url = $"{_config.Endpoint}?access_token={HttpUtility.UrlEncode(_config.AccessToken)}";
if (!string.IsNullOrWhiteSpace(_config.Secret))
{
long timestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
string sign = AddSign(timestamp, _config.Secret);
url += $"&timestamp={timestamp}&sign={sign}";
}
JsonObject payload = new()
{
["msgtype"] = "text",
["text"] = new JsonObject
{
["content"] = body
}
};
await HttpHelper.PostAsync(url, payload, _config.SkipTlsValidation, cancellationToken);
}
private static string AddSign(long timestamp, string secret)
{
string stringToSign = $"{timestamp}\n{secret}";
using HMACSHA256 hmacsha256 = new(Encoding.UTF8.GetBytes(secret));
byte[] hashmessage = hmacsha256.ComputeHash(Encoding.UTF8.GetBytes(stringToSign));
return HttpUtility.UrlEncode(Convert.ToBase64String(hashmessage), Encoding.UTF8);
}
}
@@ -0,0 +1,31 @@
using DbusSmsForward.ProcessSmsContent;
using DbusSmsForward.Services;
using DbusSmsForward.SettingModel;
using DbusSmsForward.SMSModel;
using MailKit.Net.Smtp;
using MimeKit;
namespace DbusSmsForward.Notifications;
public sealed class EmailNotificationSender(DbusSmsForwardOptions options) : NotificationSenderBase("email")
{
private readonly EmailConfig _config = options.Notifications.Email;
public override bool IsEnabled => _config.Enabled && !string.IsNullOrWhiteSpace(_config.SmtpHost) && !string.IsNullOrWhiteSpace(_config.SendEmail) && !string.IsNullOrWhiteSpace(_config.ReceiveEmail);
public override async Task SendAsync(SmsContentModel sms, string body, string deviceName, CancellationToken cancellationToken)
{
SmsCodeModel code = NotificationContentBuilder.ExtractCode(options, sms);
MimeMessage message = new();
message.From.Add(new MailboxAddress("DbusSmsForward", _config.SendEmail));
message.To.Add(new MailboxAddress(string.Empty, _config.ReceiveEmail));
message.Subject = BuildTitle(sms.TelNumber, code.CodeValue);
message.Body = new TextPart("plain") { Text = body };
using SmtpClient client = new();
await client.ConnectAsync(_config.SmtpHost, _config.SmtpPort, _config.EnableSsl, cancellationToken);
await client.AuthenticateAsync(_config.SendEmail, _config.EmailKey, cancellationToken);
await client.SendAsync(message, cancellationToken);
await client.DisconnectAsync(true, cancellationToken);
}
}
@@ -0,0 +1,10 @@
using DbusSmsForward.SMSModel;
namespace DbusSmsForward.Notifications;
public interface INotificationSender
{
string Name { get; }
bool IsEnabled { get; }
Task SendAsync(SmsContentModel sms, string body, string deviceName, CancellationToken cancellationToken);
}
@@ -0,0 +1,13 @@
using DbusSmsForward.SMSModel;
namespace DbusSmsForward.Notifications;
public abstract class NotificationSenderBase(string name) : INotificationSender
{
public string Name { get; } = name;
public abstract bool IsEnabled { get; }
public abstract Task SendAsync(SmsContentModel sms, string body, string deviceName, CancellationToken cancellationToken);
protected static string BuildTitle(string telNumber, string codeValue)
=> string.IsNullOrWhiteSpace(codeValue) ? $"短信转发 {telNumber}" : $"{codeValue} 短信转发 {telNumber}";
}
@@ -0,0 +1,31 @@
using DbusSmsForward.Helper;
using DbusSmsForward.Notifications;
using DbusSmsForward.ProcessSmsContent;
using DbusSmsForward.Services;
using DbusSmsForward.SettingModel;
using DbusSmsForward.SMSModel;
using System.Net.Http.Json;
using System.Text.Json.Nodes;
namespace DbusSmsForward.Notifications;
public sealed class PushPlusNotificationSender(DbusSmsForwardOptions options) : NotificationSenderBase("pushplus")
{
private readonly PushPlusConfig _config = options.Notifications.PushPlus;
public override bool IsEnabled => _config.Enabled && !string.IsNullOrWhiteSpace(_config.Token);
public override async Task SendAsync(SmsContentModel sms, string body, string deviceName, CancellationToken cancellationToken)
{
SmsCodeModel code = NotificationContentBuilder.ExtractCode(options, sms);
JsonObject payload = new()
{
["token"] = _config.Token,
["title"] = BuildTitle(sms.TelNumber, code.CodeValue),
["content"] = body,
["topic"] = string.Empty
};
await HttpHelper.PostAsync(_config.Endpoint, payload, _config.SkipTlsValidation, cancellationToken);
}
}
@@ -0,0 +1,51 @@
using DbusSmsForward.Services;
using DbusSmsForward.SettingModel;
using DbusSmsForward.SMSModel;
using System.Diagnostics;
namespace DbusSmsForward.Notifications;
public sealed class ShellNotificationSender(DbusSmsForwardOptions options) : NotificationSenderBase("shell")
{
private readonly ShellConfig _config = options.Notifications.Shell;
public override bool IsEnabled => _config.Enabled && !string.IsNullOrWhiteSpace(_config.ShellPath);
public override async Task SendAsync(SmsContentModel sms, string body, string deviceName, CancellationToken cancellationToken)
{
ProcessStartInfo startInfo = new()
{
FileName = _config.ShellPath,
UseShellExecute = false,
CreateNoWindow = true,
RedirectStandardOutput = true,
RedirectStandardError = true
};
foreach (string arg in new[]
{
sms.TelNumber,
sms.SmsDate,
sms.SmsContent,
string.Empty,
string.Empty,
deviceName
})
{
startInfo.ArgumentList.Add(arg ?? string.Empty);
}
using Process process = Process.Start(startInfo) ?? throw new InvalidOperationException("Unable to start shell process.");
using CancellationTokenRegistration registration = cancellationToken.Register(() =>
{
try { if (!process.HasExited) process.Kill(true); } catch { }
});
await process.WaitForExitAsync(cancellationToken);
if (process.ExitCode != 0)
{
string error = await process.StandardError.ReadToEndAsync(cancellationToken);
throw new InvalidOperationException($"Shell sender exited with code {process.ExitCode}: {error}");
}
}
}
@@ -0,0 +1,25 @@
using DbusSmsForward.Helper;
using DbusSmsForward.Services;
using DbusSmsForward.SettingModel;
using DbusSmsForward.SMSModel;
using System.Web;
namespace DbusSmsForward.Notifications;
public sealed class TelegramNotificationSender(DbusSmsForwardOptions options) : NotificationSenderBase("telegram")
{
private readonly TelegramBotConfig _config = options.Notifications.TelegramBot;
public override bool IsEnabled => _config.Enabled && !string.IsNullOrWhiteSpace(_config.BotToken) && !string.IsNullOrWhiteSpace(_config.ChatId);
public override async Task SendAsync(SmsContentModel sms, string body, string deviceName, CancellationToken cancellationToken)
{
string apiBase = _config.EnableCustomApi && !string.IsNullOrWhiteSpace(_config.CustomApi)
? _config.CustomApi.TrimEnd('/')
: "https://api.telegram.org";
string text = body;
string url = $"{apiBase}/bot{_config.BotToken}/sendMessage?chat_id={HttpUtility.UrlEncode(_config.ChatId)}&text={HttpUtility.UrlEncode(text)}";
await HttpHelper.HttpGetAsync(url, _config.SkipTlsValidation, cancellationToken);
}
}
@@ -0,0 +1,37 @@
using DbusSmsForward.Helper;
using DbusSmsForward.Services;
using DbusSmsForward.SettingModel;
using DbusSmsForward.SMSModel;
using System.Text.Json.Nodes;
namespace DbusSmsForward.Notifications;
public sealed class WeComApplicationNotificationSender(DbusSmsForwardOptions options) : NotificationSenderBase("wecom")
{
private readonly WeComApplicationConfig _config = options.Notifications.WeComApplication;
public override bool IsEnabled => _config.Enabled && !string.IsNullOrWhiteSpace(_config.CorpId) && !string.IsNullOrWhiteSpace(_config.AgentId) && !string.IsNullOrWhiteSpace(_config.ApplicationSecret);
public override async Task SendAsync(SmsContentModel sms, string body, string deviceName, CancellationToken cancellationToken)
{
string tokenUrl = $"https://qyapi.weixin.qq.com/cgi-bin/gettoken?corpid={Uri.EscapeDataString(_config.CorpId)}&corpsecret={Uri.EscapeDataString(_config.ApplicationSecret)}";
string tokenResponse = await HttpHelper.HttpGetAsync(tokenUrl, _config.SkipTlsValidation, cancellationToken);
JsonObject tokenJson = JsonNode.Parse(tokenResponse)?.AsObject() ?? throw new InvalidOperationException("Invalid WeCom token response.");
string accessToken = tokenJson["access_token"]?.ToString() ?? throw new InvalidOperationException("WeCom access_token missing.");
JsonObject payload = new()
{
["touser"] = "@all",
["msgtype"] = "text",
["agentid"] = _config.AgentId,
["text"] = new JsonObject
{
["content"] = body
},
["safe"] = 0
};
string sendUrl = $"https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token={Uri.EscapeDataString(accessToken)}";
await HttpHelper.PostAsync(sendUrl, payload, _config.SkipTlsValidation, cancellationToken);
}
}