增加版本数据库兼容

增加多通道消息发送
BARK部分代码
This commit is contained in:
xpnas 2021-04-02 01:14:09 +08:00
parent 1e1cdfa6c2
commit bb7e25729f
19 changed files with 643 additions and 107 deletions

View File

@ -1,7 +1,7 @@
<template>
<div class='app-container'>
<el-dialog :title='title' :visible.sync='dialogVisible' :append-to-body='true'>
<el-form ref="authform" :model="authform" label-width="100px" label-position='right' :rules="authformrules">
<el-form ref="authform" :model="authform" label-width="120px" label-position='right' :rules="authformrules">
<el-form-item label='通道类型'>
<el-select :disabled='isModify' value-key="key" v-model='selectTemplate' placeholder='请选择' @change="selectTemplateChange">
<el-option v-for="item in sendTemplates" :key="item.key" :label="item.name" :value="item">

View File

@ -22,5 +22,23 @@ namespace Inotify.Common
return result.Replace("-", "");
}
public static string UrlEncode(this string str)
{
string urlStr = System.Web.HttpUtility.UrlEncode(str);
return urlStr;
}
public static string Base64Encode(this string source)
{
byte[] bytes = (Encoding.UTF8.GetBytes(source));
return Convert.ToBase64String(bytes);
}
public static string Base64Decode(this string source)
{
var bytes = Convert.FromBase64String(source);
return System.Text.Encoding.Default.GetString(bytes);
}
}
}

View File

@ -0,0 +1,118 @@
using Inotify.Data;
using Inotify.Data.Models;
using Inotify.Sends;
using Inotify.Sends.Products;
using Microsoft.AspNetCore.Mvc;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace Inotify.Controllers
{
public class DeviceInfo
{
public string? Token { get; set; }
public string? Key { get; set; }
public string? DeviceToken { get; set; }
public string? Device_key { get; set; }
public string? Device_token { get; set; }
}
[ApiController]
[Route("/")]
public class BarkControlor : BaseControlor
{
[HttpGet, Route("Ping")]
public JsonResult Ping(string? token)
{
return OK();
}
[HttpGet, Route("Info")]
public JsonResult Info(string? token)
{
return Json(new
{
version = "v2",
build = "2021.03.29",
arch = RuntimeInformation.OSDescription,
commit = "inotfy",
devices = RuntimeInformation.OSDescription
});
}
[HttpGet, Route("Healthz")]
public string Healthz(string? token)
{
return "ok";
}
[HttpPost, Route("Register")]
public JsonResult Register(DeviceInfo deviceInfo)
{
if (!string.IsNullOrEmpty(deviceInfo.Key))
deviceInfo.Device_key = deviceInfo.Key;
if (!string.IsNullOrEmpty(deviceInfo.DeviceToken))
deviceInfo.Device_token = deviceInfo.DeviceToken;
if (string.IsNullOrEmpty(deviceInfo.Device_key))
return Fail(400, "request bind failed : device_key is empty");
if (string.IsNullOrEmpty(deviceInfo.Device_token))
return Fail(400, "request bind failed : device_token not empty");
var userInfo = DBManager.Instance.DBase.Query<SendUserInfo>().FirstOrDefault(e => e.Token == deviceInfo.Token);
if (userInfo == null)
{
return Fail(400, "request bind failed : device not registered");
}
else
{
var barkAuth = new BarkAuth() { DeviceToken = deviceInfo.Device_token };
var barkTemplateAttribute = typeof(BarkSendTemplate).GetCustomAttributes(typeof(SendMethodKeyAttribute), false).OfType<SendMethodKeyAttribute>().First();
var barkSendAuthInfo = DBManager.Instance.DBase.Query<SendAuthInfo>().FirstOrDefault(e => e.UserId == userInfo.Id && e.SendMethodTemplate == barkTemplateAttribute.Key);
if (barkSendAuthInfo == null)
{
barkSendAuthInfo = new SendAuthInfo()
{
Name = barkTemplateAttribute.Name,
SendMethodTemplate = barkTemplateAttribute.Key,
AuthData = JsonConvert.SerializeObject(barkAuth),
UserId = userInfo.Id,
CreateTime = DateTime.Now,
ModifyTime = DateTime.Now
};
var sendAuthId = Convert.ToInt32(DBManager.Instance.DBase.Insert<SendAuthInfo>(barkSendAuthInfo));
userInfo.SendAuthId = sendAuthId;
DBManager.Instance.DBase.Update(userInfo, e => e.SendAuthId);
}
else
{
barkSendAuthInfo.AuthData = JsonConvert.SerializeObject(barkAuth);
barkSendAuthInfo.ModifyTime = DateTime.Now;
DBManager.Instance.DBase.Update(barkSendAuthInfo);
}
return Json(new
{
key = deviceInfo.Device_key,
device_key = deviceInfo.Device_key,
device_token = deviceInfo.Device_token
});
}
}
}
}

View File

@ -36,7 +36,7 @@ namespace Inotify.Controllers
}
public class BaseController : ControllerBase
public class BaseControlor : ControllerBase
{
public string UserName
{
@ -64,30 +64,44 @@ namespace Inotify.Controllers
}
}
protected JsonResult OK(object? obj = null)
protected JsonResult OK()
{
return new JsonResult(new
return Json(new
{
code = 200,
data = obj ?? "sucess"
message = "sucess",
timestamp = (DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds
});
}
protected JsonResult OK(object obj )
{
return Json(new
{
code = 200,
message = "sucess",
data = obj ?? "",
timestamp = (DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds
});
}
protected JsonResult Fail()
{
return new JsonResult(new
return Json(new
{
code = 404,
data = "fail"
message = "failed",
timestamp = (DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds
});
}
protected JsonResult Fail(int code)
{
return new JsonResult(new
return Json(new
{
code,
data = "fail"
message = "failed",
timestamp = (DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds
});
}
@ -96,11 +110,14 @@ namespace Inotify.Controllers
return new JsonResult(new
{
code,
message
message,
timestamp = (DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds
});
}
protected JsonResult Json(object obj)
{
return new JsonResult(obj);
}
}
}

View File

@ -26,7 +26,7 @@ namespace Inotify.Controllers
{
[ApiController]
[Route("api/oauth")]
public class OAuthController : BaseController
public class OAuthController : BaseControlor
{
private readonly IGitHubLogin m_gitHubLogin;

View File

@ -9,7 +9,7 @@ namespace Inotify.Controllers
{
[ApiController]
[Route("api")]
public class SendController : BaseController
public class SendController : BaseControlor
{
[HttpGet, Route("send")]
public JsonResult Send(string token, string title, string? data)

View File

@ -1,6 +1,7 @@
using Inotify.Data;
using Inotify.Data.Models;
using Inotify.Sends;
using Inotify.Sends.Products;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
@ -17,7 +18,7 @@ namespace Inotify.Controllers
{
[ApiController]
[Route("api/setting")]
public class SettingControlor : BaseController
public class SettingControlor : BaseControlor
{
[HttpGet, Authorize(Policys.SystemOrUsers)]
public JsonResult Index()
@ -48,7 +49,7 @@ namespace Inotify.Controllers
sendTemplate.Name = sendAuthInfo.Name;
sendTemplate.AuthData = sendAuthInfo.AuthData;
sendTemplate.SendAuthId = sendAuthInfo.Id;
sendTemplate.IsActive = sendAuthInfo.Id == userInfo.SendAuthId;
sendTemplate.IsActive = sendAuthInfo.Active;
sendTemplate.AuthToTemplate(sendAuthInfo.AuthData);
userSendTemplates.Add(sendTemplate);
}
@ -68,9 +69,9 @@ namespace Inotify.Controllers
var authInfo = DBManager.Instance.DBase.Query<SendAuthInfo>().FirstOrDefault(e => e.Id == sendAuthId && e.UserId == userInfo.Id);
if (authInfo != null)
{
userInfo.SendAuthId = state ? sendAuthId : -1;
DBManager.Instance.DBase.Update(userInfo);
return OK(userInfo);
authInfo.Active = state;
DBManager.Instance.DBase.Update(authInfo);
return OK(authInfo);
}
}
return Fail();
@ -97,6 +98,14 @@ namespace Inotify.Controllers
{
var userInfo = DBManager.Instance.GetUser(UserName);
if (userInfo != null && inputTemeplate.Key != null && inputTemeplate.Name != null)
{
var barkKey = typeof(BarkSendTemplate).GetCustomAttributes(typeof(SendMethodKeyAttribute), false).OfType<SendMethodKeyAttribute>().First().Key;
if (barkKey == inputTemeplate.Key
&& DBManager.Instance.DBase.Query<SendAuthInfo>().FirstOrDefault(e => e.UserId == userInfo.Id && e.SendMethodTemplate == barkKey) != null)
{
return Fail(406, "您只能添加一个BARK通道");
}
else
{
var authInfo = inputTemeplate.TemplateToAuth();
var sendAuth = new SendAuthInfo()
@ -110,6 +119,8 @@ namespace Inotify.Controllers
};
DBManager.Instance.DBase.Insert(sendAuth);
return OK(sendAuth);
}
}
return Fail();
}

View File

@ -14,7 +14,7 @@ namespace Inotify.Controllers
{
[ApiController]
[Route("api/settingsys")]
public class SetttingSysControlor : BaseController
public class SetttingSysControlor : BaseControlor
{
[HttpGet, Route("GetGlobal"), Authorize(Policys.Systems)]
public IActionResult GetGlobal()

View File

@ -7,6 +7,7 @@ using Microsoft.IdentityModel;
using Newtonsoft.Json;
using NPoco;
using NPoco.Migrations;
using NPoco.Migrations.CurrentVersion;
using System;
using System.Data;
using System.IO;
@ -18,6 +19,8 @@ namespace Inotify.Data
{
public class DBManager
{
private readonly string MigrationName = "inotify";
private readonly SqliteConnection m_dbConnection;
private readonly Migrator m_migrator;
@ -40,6 +43,8 @@ namespace Inotify.Data
}
}
public readonly string Inotify_Data;
public Database DBase { get; private set; }
private static DBManager? m_Instance;
@ -58,13 +63,18 @@ namespace Inotify.Data
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux))
{
Inotify_Data = Path.Combine(Directory.GetCurrentDirectory(), m_dataPath);
if (!Directory.Exists(Inotify_Data)) Directory.CreateDirectory(Inotify_Data);
m_jwtPath = Path.Combine(Directory.GetCurrentDirectory(), "/" + m_dataPath + "/jwt.json");
m_dbPath = Path.Combine(Directory.GetCurrentDirectory(), "/" + m_dataPath + "/data.db");
}
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
var dataPath = Path.Combine(Directory.GetCurrentDirectory(), m_dataPath);
if (!Directory.Exists(dataPath)) Directory.CreateDirectory(dataPath);
Inotify_Data = Path.Combine(Directory.GetCurrentDirectory(), m_dataPath);
if (!Directory.Exists(Inotify_Data)) Directory.CreateDirectory(Inotify_Data);
m_jwtPath = Path.Combine(Directory.GetCurrentDirectory(), m_dataPath + "/jwt.json");
m_dbPath = Path.Combine(Directory.GetCurrentDirectory(), m_dataPath + "/data.db");
@ -132,42 +142,43 @@ namespace Inotify.Data
return authInfo.AuthData;
}
public void GetAuth(string token, out SendAuthInfo[] sendAuthInfos)
{
sendAuthInfos = null;
var upToekn = token.ToUpper();
var userInfo = DBManager.Instance.DBase.Query<SendUserInfo>().FirstOrDefault(e => e.Token == upToekn && e.Active);
if (userInfo != null)
sendAuthInfos = DBManager.Instance.DBase.Query<SendAuthInfo>().Where(e => e.UserId == userInfo.Id && e.Active).ToArray();
}
public void Run()
{
if (!m_migrator.TableExists<SendInfo>())
m_migrator.CreateTable<SendInfo>(true).Execute();
var codeVersion = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version;
var migrationBuilder = new MigrationBuilder(MigrationName, DBase);
var versionProvider = new DatabaseCurrentVersionProvider(DBase);
if (!m_migrator.TableExists<SystemInfo>())
{
m_migrator.CreateTable<SystemInfo>(true).Execute();
DBase.Insert(new SystemInfo()
migrationBuilder.Append(new Version(codeVersion.ToString()), new LatestMigration());
versionProvider.SetMigrationVersion(MigrationName, new Version(codeVersion.ToString()));
}
else
{
key = "administrators",
Value = "admin"
});
if (versionProvider.GetMigrationVersion(MigrationName).ToString() == "0.0")
{
versionProvider.SetMigrationVersion(MigrationName, new Version(1, 0, 0, 0));
}
if (!m_migrator.TableExists<SendUserInfo>())
{
m_migrator.CreateTable<SendUserInfo>(true).Execute();
SendUserInfo userInfo = new SendUserInfo()
{
Token = "112D77BAD9704FFEAECD716B5678DFBE".ToUpper(),
UserName = "admin",
Email = "admin@qq.com",
CreateTime = DateTime.Now,
Active = true,
Password = "123456".ToMd5()
};
DBase.Insert(userInfo);
var builder = new MigrationBuilder(MigrationName, DBase);
builder.Append(new Version(2, 0, 0, 0), new V2UpdateMigration());
builder.Execute();
}
}
}
if (!m_migrator.TableExists<SendAuthInfo>())
{
m_migrator.CreateTable<SendAuthInfo>(true).Execute();
}
}
}
}

View File

@ -0,0 +1,78 @@
using Inotify.Common;
using Inotify.Data.Models;
using NPoco.Migrations;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Inotify.Data
{
public class EmptyMigration : Migration, IMigration
{
protected override void execute()
{
}
}
public class LatestMigration : Migration, IMigration
{
protected override void execute()
{
if (!Migrator.TableExists<SystemInfo>())
{
Migrator.CreateTable<SystemInfo>(true).Execute();
Migrator.Database.Insert(new SystemInfo()
{
key = "administrators",
Value = "admin"
});
}
if (!Migrator.TableExists<SendInfo>())
Migrator.CreateTable<SendInfo>(true).Execute();
if (!Migrator.TableExists<SendUserInfo>())
{
Migrator.CreateTable<SendUserInfo>(true).Execute();
SendUserInfo userInfo = new SendUserInfo()
{
Token = Guid.NewGuid().ToString("N").ToUpper(),
UserName = "admin",
Email = "admin@qq.com",
CreateTime = DateTime.Now,
Active = true,
Password = "123456".ToMd5()
};
Migrator.Database.Insert(userInfo);
}
if (!Migrator.TableExists<SendAuthInfo>())
{
Migrator.CreateTable<SendAuthInfo>(true).Execute();
}
}
}
public class V2UpdateMigration : Migration, IMigration
{
protected override void execute()
{
//V2版本允许多通道,激活标记放入SendAuthInfo表中增加Active列
//更新原有用户的激活通道
Migrator.AlterTable<SendAuthInfo>().AddColumn(e => e.Active).Execute();
Migrator.Database.UpdateMany<SendAuthInfo>().OnlyFields(e => e.Active).Execute(new SendAuthInfo() { Active = false });
var activeUsers = Migrator.Database.Query<SendUserInfo>().ToList();
activeUsers.ForEach(user =>
{
var sendUserInfo = Migrator.Database.Query<SendAuthInfo>().FirstOrDefault(e => e.Id == user.SendAuthId);
if (sendUserInfo != null)
{
sendUserInfo.Active = true;
Migrator.Database.Update(sendUserInfo, e => e.Active); ;
}
});
}
}
}

View File

@ -26,5 +26,8 @@ namespace Inotify.Data.Models
[NPoco.Column("createTime")]
public DateTime CreateTime { get; set; }
[NPoco.Column("active")]
public bool Active { get; set; }
}
}

View File

@ -6,16 +6,14 @@
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
<StartupObject>Inotify.Program</StartupObject>
<Nullable>enable</Nullable>
<AssemblyVersion>2.0.0.0</AssemblyVersion>
<FileVersion>2.0.0.0</FileVersion>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
<WarningLevel>3</WarningLevel>
</PropertyGroup>
<ItemGroup>
<None Include="..\.editorconfig" Link=".editorconfig" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="FluentEmail.Core" Version="3.0.0" />
<PackageReference Include="FluentEmail.Liquid" Version="3.0.0" />
@ -30,4 +28,12 @@
<PackageReference Include="System.Runtime.Caching" Version="5.0.0" />
<PackageReference Include="Telegram.Bot" Version="15.7.1" />
</ItemGroup>
<ItemGroup>
<None Update="inotify_data\AuthKey_LH4T9V5U4R_5U8LBRXG3A.p8">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None>
</ItemGroup>
<ProjectExtensions><VisualStudio><UserProperties properties_4launchsettings_1json__JsonSchema="" /></VisualStudio></ProjectExtensions>
</Project>

View File

@ -5,7 +5,7 @@ VisualStudioVersion = 16.0.30804.86
MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{80E8FF2E-B685-44E6-82A8-FDCA48EDAD47}"
ProjectSection(SolutionItems) = preProject
..\.editorconfig = ..\.editorconfig
.editorconfig = .editorconfig
EndProjectSection
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Inotify", "Inotify.csproj", "{9AF94AE0-E8C6-414C-A0AC-EDFB301CA05E}"

View File

@ -0,0 +1,248 @@
using Inotify.Common;
using Inotify.Data;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices;
using System.Security.Cryptography;
using System.Security.Policy;
using System.Text;
using System.Threading.Tasks;
namespace Inotify.Sends.Products
{
public class BarkMessage
{
public BarkMessage(string body) : this(string.Empty, body) { }
public BarkMessage(string title, string body)
{
this.Title = title;
this.Body = body;
}
#region
/// <summary>
/// 标题,加粗
/// </summary>
public string Title { get; set; } = string.Empty;
/// <summary>
/// 正文
/// </summary>
public string Body { get; set; } = string.Empty;
/// <summary>
/// 自动保存
/// </summary>
public string IsArchive { get; set; } = "1";
/// <summary>
/// 链接
/// </summary>
public string Url { get; set; } = string.Empty;
/// <summary>
/// 自动复制
/// </summary>
public string AutoMaticallyCopy { get; set; } = "0";
/// <summary>
/// 复制文本
/// </summary>
public string Copy { get; set; } = string.Empty;
#endregion
#region
/// <summary>
/// 设置链接
/// </summary>
/// <param name="url"></param>
/// <returns></returns>
public BarkMessage SetUrl(string url)
{
this.Url = url;
return this;
}
/// <summary>
/// 设置保存,默认保存
/// </summary>
/// <returns></returns>
public BarkMessage SetArchive()
{
IsArchive = "1";
return this;
}
/// <summary>
/// 设置不保存,默认保存
/// </summary>
/// <returns></returns>
public BarkMessage SetNotArchive()
{
IsArchive = "0";
return this;
}
/// <summary>
/// 设置自动复制,默认不自动复制
/// </summary>
/// <returns></returns>
public BarkMessage SetAutoCopy()
{
this.AutoMaticallyCopy = "1";
return this;
}
/// <summary>
/// 设置不自动复制,默认不自动复制
/// </summary>
/// <returns></returns>
public BarkMessage SetNotAutoCopy()
{
this.AutoMaticallyCopy = "1";
return this;
}
/// <summary>
/// 设置自动拷贝的文本,默认拷贝全文
/// </summary>
/// <param name="text"></param>
/// <returns></returns>
public BarkMessage SetCopyText(string text)
{
Copy = text;
return this;
}
#endregion
}
public class BarkAuth
{
[InputTypeAttribte(0, "IsArchive", "自动保存", "1")]
public string IsArchive { get; set; }
[InputTypeAttribte(0, "AutoMaticallyCopy", "自动复制", "0")]
public string AutoMaticallyCopy { get; set; }
[InputTypeAttribte(0, "DeviceToken", "DeviceToken", "DeviceToken",false)]
public string DeviceToken { get; set; }
}
[SendMethodKey("3B6DE04D-A9EF-4C91-A151-60B7425C5AB2", "Bark(未完成)", Order = -1)]
public class BarkSendTemplate : SendTemplate<BarkAuth>
{
private static readonly string Topic = "me.fin.bark";
private static readonly string KeyID = "LH4T9V5U4R";
private static readonly string TeamID = "5U8LBRXG3A";
private static CngKey SecretKey;
public override BarkAuth Auth { get; set; }
public override bool SendMessage(SendMessage message)
{
var barkMessage = new BarkMessage(message.Title, message.Data)
{
IsArchive = Auth.IsArchive,
AutoMaticallyCopy = Auth.AutoMaticallyCopy
};
SendMesssage(barkMessage, Auth.DeviceToken);
return false;
}
private bool SendMesssage(BarkMessage barkMessage, string device_Tokne)
{
if (SecretKey == null)
{
var authPath = Path.Combine(DBManager.Instance.Inotify_Data, "AuthKey_LH4T9V5U4R_5U8LBRXG3A.p8");
var privateKeyContent = File.ReadAllText(authPath).Split('\n')[1];
SecretKey = CngKey.Import(Convert.FromBase64String(privateKeyContent), CngKeyBlobFormat.Pkcs8PrivateBlob);
}
if (barkMessage == null)
return false;
if (device_Tokne == null)
return false;
var expiration = DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
var expirationSeconds = (long)expiration.TotalSeconds;
var alert = new Dictionary<string, object>();
if (!string.IsNullOrEmpty(barkMessage.Body))
alert.Add("body", barkMessage.Body);
if (!string.IsNullOrEmpty(barkMessage.Title))
alert.Add("title", barkMessage.Title);
var aps = new Dictionary<string, object>
{
{ "category", "Bark" },
{ "sound", "1107" },
{ "badge", "0" },
{ "mutable-content", "1" },
{ "alert", alert }
};
var payload = new Dictionary<string, object>
{
{ "aps", aps },
{ "isarchive", barkMessage.IsArchive },
{ "automaticallycopy", barkMessage.AutoMaticallyCopy },
{ "iss", TeamID},
{ "iat", expirationSeconds}
};
if (!string.IsNullOrEmpty(barkMessage.Url))
payload.Add("url", barkMessage.Url);
if (!string.IsNullOrEmpty(barkMessage.Copy))
payload.Add("copy", barkMessage.Copy);
var headers = new
{
alg = "ES256",
kid = KeyID
};
var hearderString = JObject.FromObject(headers).ToString();
var payloadString = JObject.FromObject(payload).ToString();
var accessToken = SignES256(SecretKey, hearderString, payloadString);
var data = Encoding.UTF8.GetBytes(payloadString);
var httpClient = new HttpClient();
var requestMessage = new HttpRequestMessage
{
RequestUri = new Uri(string.Format("https://{0}:{1}/3/device/{2}", "api.development.push.apple.com", 443, device_Tokne))
};
requestMessage.Headers.Add("authorization", string.Format("bearer {0}", accessToken));
requestMessage.Headers.Add("apns-id", Guid.NewGuid().ToString());
requestMessage.Headers.Add("apns-expiration", "0");
requestMessage.Headers.Add("apns-priority", "10");
requestMessage.Headers.Add("apns-topic", Topic);
requestMessage.Method = HttpMethod.Post;
requestMessage.Content = new ByteArrayContent(data);
var task = httpClient.SendAsync(requestMessage);
task.Wait();
var responseMessage = task.Result;
if (responseMessage.StatusCode == System.Net.HttpStatusCode.OK)
{
return true;
}
return true;
}
private string SignES256(CngKey secretKey, string header, string payload)
{
using ECDsaCng dsa = new ECDsaCng(secretKey)
{
HashAlgorithm = CngAlgorithm.Sha256
};
var unsignedJwtData = Convert.ToBase64String(Encoding.UTF8.GetBytes(header)) + "." + Convert.ToBase64String(Encoding.UTF8.GetBytes(payload));
var signature = dsa.SignData(Encoding.UTF8.GetBytes(unsignedJwtData));
return unsignedJwtData + "." + Convert.ToBase64String(signature);
}
}
}

View File

@ -13,9 +13,13 @@ namespace Inotify.Sends.Products
[InputTypeAttribte(0, "URL", "请求地址", "https://api.day.app/token/{title}/{data}")]
public string URL { get; set; }
[InputTypeAttribte(1, "Encoding", "Encoding", "utf-8|ascii|gbk")]
[InputTypeAttribte(1, "Encoding", "Encoding", "utf-8")]
public string Encoding { get; set; }
[InputTypeAttribte(1, "ContentType", "ContentType", "application/json")]
public string ContentType { get; set; }
[InputTypeAttribte(2, "Data", "POST参数", @"{""msgid"":""123456"",""title"":""{title}"",""data"":""{data}""}")]
public string Data { get; set; }
@ -32,6 +36,10 @@ namespace Inotify.Sends.Products
if (Auth.Data == null)
Auth.Data = "";
if (string.IsNullOrEmpty(Auth.ContentType))
Auth.ContentType = "application/json";
if (string.IsNullOrEmpty(Auth.Encoding))
Auth.Encoding = "utf-8";
@ -43,7 +51,7 @@ namespace Inotify.Sends.Products
var data = Auth.Data.Replace("{title}", message.Title).Replace("{data}", message.Data);
var bytes = Encoding.GetEncoding(Auth.Encoding).GetBytes(data);
webRequest.Method = "POST";
webRequest.ContentType = "application/x-www-urlencoded";
webRequest.ContentType = Auth.ContentType;
webRequest.ContentLength = bytes.Length;
var requestStream = webRequest.GetRequestStream();
requestStream.Write(bytes, 0, bytes.Length);

View File

@ -85,7 +85,7 @@ namespace Inotify.Sends.Products
var content = string.IsNullOrEmpty(data) ? title : title + "\n" + data;
var isImage = !String.IsNullOrEmpty(title) && IsUrl(title) && IsImage(title) && String.IsNullOrEmpty(data);
var imageData = isImage ? GetImage(title) : null;
string mediaId = null;
string mediaId = string.Empty;
if (imageData != null)
mediaId = UpLoadIMage(accessToken, imageData);
@ -171,17 +171,21 @@ namespace Inotify.Sends.Products
postStream.Write(endBoundaryBytes, 0, endBoundaryBytes.Length);
postStream.Close();
HttpWebResponse response = request.GetResponse() as HttpWebResponse;
if (request.GetResponse() is HttpWebResponse response)
{
Stream instream = response.GetResponseStream();
StreamReader sr = new StreamReader(instream, Encoding.UTF8);
string content = sr.ReadToEnd();
var result = JObject.Parse(content);
return result.Value<string>("media_id").ToString();
}
}
catch
{
}
return null;
}
}
}
}

View File

@ -15,11 +15,9 @@ using System.Threading;
namespace Inotify.Sends
{
public class SendTaskManager
{
private static SendTaskManager m_Instance;
public static SendTaskManager Instance
{
get
@ -154,7 +152,11 @@ namespace Inotify.Sends
try
{
var message = m_sendMessages.Take();
var authData = DBManager.Instance.GetAuth(message.Token, out string temeplateId);
DBManager.Instance.GetAuth(message.Token, out SendAuthInfo[] sendAuthInfos);
foreach (var authInfo in sendAuthInfos)
{
var authData = authInfo.AuthData;
var temeplateId = authInfo.SendMethodTemplate;
if (temeplateId != null && authData != null)
{
if (m_sendMethodTemplateTypes.ContainsKey(temeplateId))
@ -181,16 +183,18 @@ namespace Inotify.Sends
OnSendSucessed?.Invoke(this, message);
continue;
}
}
}
}
}
}
else
{
OnSendFailed?.Invoke(this, message);
}
}
}
}
}
}
}
}
catch (ThreadInterruptedException)
{
break;

View File

@ -47,6 +47,8 @@ namespace Inotify.Sends
public InputType? Type { get; set; }
public int? Order { get; set; }
public string? Value { get; set; }
public bool Visuable { get; set; }
}
public class InputTemeplate
@ -109,7 +111,8 @@ namespace Inotify.Sends
{
public InputTypeValue InputTypeData { get; set; }
private InputTypeAttribte(int order, string name, string description, string defaultValue, InputType type)
private InputTypeAttribte(int order, string name, string description, string defaultValue, InputType type,bool visuable=true)
{
InputTypeData = new InputTypeValue
{
@ -117,18 +120,19 @@ namespace Inotify.Sends
Description = description,
Default = defaultValue,
Order = order,
Type = type
Type = type,
Visuable=visuable
};
}
public InputTypeAttribte(int order, string name, string description, string defaultValue)
: this(order, name, description, defaultValue, InputType.TEXT)
public InputTypeAttribte(int order, string name, string description, string defaultValue, bool visuable = true)
: this(order, name, description, defaultValue, InputType.TEXT, visuable)
{
}
public InputTypeAttribte(int order, string name, string description, bool defaultValue)
: this(order, name, description, "", InputType.CHECK)
public InputTypeAttribte(int order, string name, string description, bool defaultValue, bool visuable = true)
: this(order, name, description, "", InputType.CHECK, visuable)
{
InputTypeData.Default = defaultValue ? "是" : "否";
}
@ -152,6 +156,7 @@ namespace Inotify.Sends
.SelectMany(e => e.GetCustomAttributes(typeof(InputTypeAttribte), false))
.Cast<InputTypeAttribte>()
.Select(e => e.InputTypeData)
.Where(e=>e.Visuable)
.ToList();
var sendMethodKeyAttribute = this.GetType().GetCustomAttribute<SendMethodKeyAttribute>();

View File

@ -108,6 +108,11 @@ namespace Inotify
var options = new RewriteOptions();
options.AddRewrite(@"api/(.*).send/(.*)/(.*)", "api/send?token=$1&title=$2&data=$3", true);
options.AddRewrite(@"api/(.*).send/(.*)", "api/send?token=$1&title=$2", true);
options.AddRewrite(@"\?act=(.*)/{.*}/(.*)/(.*)", "api/send?token=$1&title=$3&data=$4", true);
options.AddRewrite(@"\?act=(.*)/{.*}/(.*)", "api/send?token=$1&title=$3", true);
//https://im.xpnas.com/?act=123456/ZtCLMPWQWtjJQpKmQS6hoV/
app.UseRewriter(options);
app.UseRouting();