增加版本数据库兼容
增加多通道消息发送 BARK部分代码
This commit is contained in:
parent
1e1cdfa6c2
commit
bb7e25729f
@ -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">
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
118
Inotify/Controllers/BarkControlor.cs
Normal file
118
Inotify/Controllers/BarkControlor.cs
Normal 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
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@ namespace Inotify.Controllers
|
||||
{
|
||||
[ApiController]
|
||||
[Route("api/oauth")]
|
||||
public class OAuthController : BaseController
|
||||
public class OAuthController : BaseControlor
|
||||
{
|
||||
private readonly IGitHubLogin m_gitHubLogin;
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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()
|
||||
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
78
Inotify/Data/DBMigrations.cs
Normal file
78
Inotify/Data/DBMigrations.cs
Normal 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); ;
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@ -26,5 +26,8 @@ namespace Inotify.Data.Models
|
||||
|
||||
[NPoco.Column("createTime")]
|
||||
public DateTime CreateTime { get; set; }
|
||||
|
||||
[NPoco.Column("active")]
|
||||
public bool Active { get; set; }
|
||||
}
|
||||
}
|
||||
|
@ -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>
|
||||
|
@ -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}"
|
||||
|
248
Inotify/Sends/Products/BarkSendTemplate.cs
Normal file
248
Inotify/Sends/Products/BarkSendTemplate.cs
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
@ -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>();
|
||||
|
@ -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();
|
||||
|
Loading…
Reference in New Issue
Block a user