添加BARK支持
This commit is contained in:
parent
d4b1f9faf2
commit
939f64549c
@ -24,6 +24,7 @@
|
||||
"normalize.css": "7.0.0",
|
||||
"nprogress": "0.2.0",
|
||||
"path-to-regexp": "2.4.0",
|
||||
"qrcodejs": "^1.0.0",
|
||||
"vue": "2.6.10",
|
||||
"vue-router": "3.0.6",
|
||||
"vuex": "3.1.0"
|
||||
|
@ -12,7 +12,7 @@
|
||||
<el-input v-model="selectTemplate.name"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item v-for="(item) in selectTemplate.values" :label="item.description" :key="item.name" required>
|
||||
<el-input v-model="item.value" :placeholder="item.default"></el-input>
|
||||
<el-input v-model="item.value" :placeholder="item.default" :readonly="item.readonly"></el-input>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
@ -71,6 +71,7 @@ import {
|
||||
getSendTemplates,
|
||||
addAuthInfo,
|
||||
deepClone,
|
||||
getSendKey
|
||||
|
||||
} from '@/api/setting'
|
||||
|
||||
@ -102,7 +103,7 @@ export default {
|
||||
isModify: false,
|
||||
authform: {},
|
||||
title: "设置",
|
||||
|
||||
sendKey: ""
|
||||
}
|
||||
},
|
||||
created() {
|
||||
@ -117,14 +118,23 @@ export default {
|
||||
})
|
||||
getSendTemplates().then((response) => {
|
||||
if (response.code == 200) {
|
||||
|
||||
this.sendTemplates = response.data;
|
||||
}
|
||||
})
|
||||
getSendKey().then(response => {
|
||||
if (response.code == 200) {
|
||||
this.sendKey = response.data;
|
||||
}
|
||||
})
|
||||
},
|
||||
selectTemplateChange(selectTemplate) {
|
||||
|
||||
this.selectTemplate = deepClone(selectTemplate);
|
||||
this.selectTemplate = deepClone(selectTemplate)
|
||||
if (this.selectTemplate.warning) {
|
||||
this.$message({
|
||||
message: this.selectTemplate.warning,
|
||||
type: 'warning'
|
||||
})
|
||||
}
|
||||
},
|
||||
submitForm(formName) {
|
||||
this.$refs[formName].validate((valid) => {
|
||||
@ -181,8 +191,23 @@ export default {
|
||||
this.title = '修改设置'
|
||||
this.isModify = true;
|
||||
this.selectTemplate = deepClone(row);
|
||||
this.dialogVisible = true;
|
||||
if (this.selectTemplate.type == "Bark") {
|
||||
let wPath = window.document.location.href;
|
||||
let pathName = this.$route.path;
|
||||
let pos = wPath.indexOf(pathName);
|
||||
let localhostPath = wPath.substring(0, pos);
|
||||
localhostPath = localhostPath.replace("#", "");
|
||||
|
||||
var devieItem = this.selectTemplate.values.find(item => {
|
||||
return item.name == "DeviceKey"
|
||||
})
|
||||
var sendUrlItem = this.selectTemplate.values.find(item => {
|
||||
return item.name == "SendUrl"
|
||||
});
|
||||
sendUrlItem.value = localhostPath + "?act=" + this.sendKey + "/" + devieItem.value + "/{title}/{data}"
|
||||
}
|
||||
|
||||
this.dialogVisible = true;
|
||||
},
|
||||
deleteAuth(index, row) {
|
||||
deleteAuthInfo(row.sendAuthId).then((response) => {
|
||||
@ -213,12 +238,13 @@ export default {
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="scss">
|
||||
|
||||
<style lang="scss">
|
||||
@media screen and (min-width:800px) {
|
||||
.el-dialog__wrapper .el-dialog {
|
||||
width: 800px !important;
|
||||
}
|
||||
|
||||
.el-dialog__wrapper .el-dialog .el-dialog__body {
|
||||
overflow: auto
|
||||
}
|
||||
@ -228,9 +254,9 @@ export default {
|
||||
.el-dialog__wrapper .el-dialog {
|
||||
width: 99% !important;
|
||||
}
|
||||
|
||||
.el-dialog__wrapper .el-dialog .el-dialog__body {
|
||||
overflow: auto
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
@ -33,6 +33,16 @@
|
||||
<el-button type="primary" @click="onReSendKey('resetform')">重置SendKey</el-button>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
|
||||
<el-divider content-position="left">BARK授权</el-divider>
|
||||
<el-form ref="resetform" :model="keyForm" label-width="20%">
|
||||
<el-form-item label="绑定地址">
|
||||
<el-input v-model="keyForm.barkUrl" :readonly="true"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<div id="qrcode"> </div>
|
||||
</el-form-item>
|
||||
</el-form>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
@ -95,10 +105,15 @@ export default {
|
||||
let pos = wPath.indexOf(pathName);
|
||||
let localhostPath = wPath.substring(0, pos);
|
||||
localhostPath = localhostPath.replace("#", "");
|
||||
this.keyForm.sendUrlTitle = localhostPath + 'api/'+ this.keyForm.sendKey+'.send' + "/{title}"
|
||||
this.keyForm.sendUrl = localhostPath + 'api/'+ this.keyForm.sendKey+'.send' + "/{title}/{data}"
|
||||
// this.keyForm.sendUrl = localhostPath + 'api/send?token=' + this.keyForm.sendKey + "&title={title}&data={data}"
|
||||
this.keyForm.sendUrlTitle = localhostPath + this.keyForm.sendKey + '.send' + "/{title}"
|
||||
this.keyForm.sendUrl = localhostPath + this.keyForm.sendKey + '.send' + "/{title}/{data}"
|
||||
this.keyForm.barkUrl = wPath.substring(0, pos - 2) + '?act=' + this.keyForm.sendKey
|
||||
this.listLoading = false;
|
||||
new QRCode(document.getElementById("qrcode"), {
|
||||
text: this.keyForm.barkUrl,
|
||||
width: 150,
|
||||
height: 150,
|
||||
});
|
||||
});
|
||||
},
|
||||
onMessage(fromname) {
|
||||
|
@ -36,6 +36,17 @@
|
||||
<el-switch active-color='#13ce66' v-model='settingForm.githubEnable' inactive-color='#ff4949'></el-switch>
|
||||
</template>
|
||||
</el-form-item>
|
||||
|
||||
<el-divider content-position="left">BARK授权</el-divider>
|
||||
<el-form-item label="KeyID">
|
||||
<el-input v-model="settingForm.barkKeyId" placeholder="KeyID">></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="TempID">
|
||||
<el-input v-model="settingForm.barkTeamId" placeholder="TempID"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item label="P8Key">
|
||||
<el-input type="textarea" v-model="settingForm.barkPrivateKey" placeholder="P8Key"></el-input>
|
||||
</el-form-item>
|
||||
<el-form-item>
|
||||
<el-button type="primary" @click="submitForm('settingForm')">确认修改</el-button>
|
||||
</el-form-item>
|
||||
|
@ -7,7 +7,7 @@ function resolve(dir) {
|
||||
}
|
||||
|
||||
const name = defaultSettings.title || 'Inotify'
|
||||
const port = process.env.port || process.env.npm_config_port || 9528
|
||||
const port = process.env.port || process.env.npm_config_port || 9000
|
||||
|
||||
const axiosV = require('axios/package.json').version
|
||||
const echartsV = require('echarts/package.json').version
|
||||
@ -43,7 +43,8 @@ const cdn = {
|
||||
`https://cdn.bootcdn.net/ajax/libs/vue-router/${routerV}/vue-router.min.js`,
|
||||
`https://cdn.bootcdn.net/ajax/libs/element-ui/${elementV}/locale/zh-CN.js`,
|
||||
`https://cdn.bootcdn.net/ajax/libs/js-cookie/${cookieV}/js.cookie.min.js`,
|
||||
`https://cdn.bootcdn.net/ajax/libs/nprogress/${nprogressV}/nprogress.min.js`
|
||||
`https://cdn.bootcdn.net/ajax/libs/nprogress/${nprogressV}/nprogress.min.js`,
|
||||
`https://cdn.bootcdn.net/ajax/libs/qrcodejs/1.0.0/qrcode.js`
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -17,3 +17,9 @@ dotnet_diagnostic.CS8602.severity = none
|
||||
|
||||
# CS8600: 将 null 文本或可能的 null 值转换为不可为 null 类型。
|
||||
dotnet_diagnostic.CS8600.severity = none
|
||||
|
||||
# IDE0037: 使用推断的成员名称
|
||||
dotnet_diagnostic.IDE0037.severity = none
|
||||
|
||||
# IDE0008: 使用显式类型
|
||||
dotnet_diagnostic.IDE0008.severity = none
|
||||
|
@ -9,6 +9,8 @@ namespace Inotify.Common
|
||||
{
|
||||
public static class Extensions
|
||||
{
|
||||
static int rep = 0;
|
||||
|
||||
/// <summary>
|
||||
/// MD5加密字符串(32位大写)
|
||||
/// </summary>
|
||||
@ -30,6 +32,7 @@ namespace Inotify.Common
|
||||
|
||||
public static string Base64Encode(this string source)
|
||||
{
|
||||
if (string.IsNullOrEmpty(source)) return "";
|
||||
byte[] bytes = (Encoding.UTF8.GetBytes(source));
|
||||
return Convert.ToBase64String(bytes);
|
||||
|
||||
@ -37,8 +40,32 @@ namespace Inotify.Common
|
||||
|
||||
public static string Base64Decode(this string source)
|
||||
{
|
||||
if (string.IsNullOrEmpty(source)) return "";
|
||||
var bytes = Convert.FromBase64String(source);
|
||||
return System.Text.Encoding.Default.GetString(bytes);
|
||||
}
|
||||
|
||||
public static string GenerateCheckCode(this int codeCount)
|
||||
{
|
||||
string str = string.Empty;
|
||||
long num2 = DateTime.Now.Ticks + rep;
|
||||
rep++;
|
||||
Random random = new Random(((int)(((ulong)num2) & 0xffffffffL)) | ((int)(num2 >> rep)));
|
||||
for (int i = 0; i < codeCount; i++)
|
||||
{
|
||||
char ch;
|
||||
int num = random.Next();
|
||||
if ((num % 2) == 0)
|
||||
{
|
||||
ch = (char)(0x30 + ((ushort)(num % 10)));
|
||||
}
|
||||
else
|
||||
{
|
||||
ch = (char)(0x41 + ((ushort)(num % 0x1a)));
|
||||
}
|
||||
str += ch.ToString();
|
||||
}
|
||||
return str;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
using Inotify.Data;
|
||||
using Inotify.Common;
|
||||
using Inotify.Data;
|
||||
using Inotify.Data.Models;
|
||||
using Inotify.Sends;
|
||||
using Inotify.Sends.Products;
|
||||
@ -13,106 +14,115 @@ 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)
|
||||
public JsonResult Ping()
|
||||
{
|
||||
return OK();
|
||||
return Me("pong");
|
||||
}
|
||||
|
||||
[HttpGet, Route("Info")]
|
||||
public JsonResult Info(string? token)
|
||||
public JsonResult Info()
|
||||
{
|
||||
var dateTime = System.IO.File.GetLastWriteTime(this.GetType().Assembly.Location);
|
||||
var devices = DBManager.Instance.DBase.Query<SendAuthInfo>().Count();
|
||||
return Json(new
|
||||
{
|
||||
version = "v2",
|
||||
build = "2021.03.29",
|
||||
version = "v2.0.1",
|
||||
build = dateTime.ToString("yyyy-MM-dd HH:mm:ss"),
|
||||
arch = RuntimeInformation.OSDescription,
|
||||
commit = "inotfy",
|
||||
devices = RuntimeInformation.OSDescription
|
||||
commit = System.Reflection.Assembly.GetExecutingAssembly().GetName().Version.ToString(),
|
||||
devices
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
[HttpGet, Route("Healthz")]
|
||||
|
||||
public string Healthz(string? token)
|
||||
public string Healthz()
|
||||
{
|
||||
return "ok";
|
||||
}
|
||||
|
||||
[HttpGet, Route("Register")]
|
||||
public JsonResult Register(string? act, string? key, string? devicetoken, string? device_key) => !string.IsNullOrEmpty(device_key) ?
|
||||
Register(device_key) : Register(act, key, devicetoken);
|
||||
|
||||
[HttpPost, Route("Register")]
|
||||
public JsonResult Register(DeviceInfo deviceInfo)
|
||||
public JsonResult Register(string? act, string? device_key, string? device_token)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(deviceInfo.Key))
|
||||
deviceInfo.Device_key = deviceInfo.Key;
|
||||
if (string.IsNullOrEmpty(act))
|
||||
return Fail(400, "request bind failed : act is empty");
|
||||
|
||||
if (!string.IsNullOrEmpty(deviceInfo.DeviceToken))
|
||||
deviceInfo.Device_token = deviceInfo.DeviceToken;
|
||||
if (string.IsNullOrEmpty(device_token))
|
||||
return Fail(400, "request bind failed : device_token is empty");
|
||||
|
||||
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);
|
||||
var userInfo = DBManager.Instance.DBase.Query<SendUserInfo>().FirstOrDefault(e => e.Token == act);
|
||||
if (userInfo == null)
|
||||
{
|
||||
return Fail(400, "request bind failed : device not registered");
|
||||
return Fail(400, "request bind failed : act is not registered");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
var barkAuth = new BarkAuth() { DeviceToken = deviceInfo.Device_token };
|
||||
BarkAuth barkAuth = null;
|
||||
SendAuthInfo barkSendAuthInfo = null;
|
||||
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
|
||||
if (!string.IsNullOrEmpty(device_key))
|
||||
{
|
||||
barkSendAuthInfo = DBManager.Instance.DBase.Query<SendAuthInfo>().FirstOrDefault(e => e.Key == device_key);
|
||||
if (barkSendAuthInfo != null)
|
||||
{
|
||||
barkAuth = JsonConvert.DeserializeObject<BarkAuth>(barkSendAuthInfo.AuthData);
|
||||
barkAuth.DeviceToken = device_token;
|
||||
barkSendAuthInfo.AuthData = JsonConvert.SerializeObject(barkAuth);
|
||||
barkSendAuthInfo.ModifyTime = DateTime.Now;
|
||||
DBManager.Instance.DBase.Update(barkSendAuthInfo);
|
||||
}
|
||||
}
|
||||
|
||||
if (barkSendAuthInfo == null)
|
||||
{
|
||||
device_key = 16.GenerateCheckCode();
|
||||
barkAuth = new BarkAuth() { DeviceKey = device_key, DeviceToken = device_token, IsArchive = "1", AutoMaticallyCopy = "1", Sound = "1107" };
|
||||
barkSendAuthInfo = new SendAuthInfo()
|
||||
{
|
||||
Name = barkTemplateAttribute.Name,
|
||||
SendMethodTemplate = barkTemplateAttribute.Key,
|
||||
Key = device_key,
|
||||
AuthData = JsonConvert.SerializeObject(barkAuth),
|
||||
UserId = userInfo.Id,
|
||||
CreateTime = DateTime.Now,
|
||||
ModifyTime = DateTime.Now,
|
||||
Active = true,
|
||||
};
|
||||
DBManager.Instance.DBase.Insert(barkSendAuthInfo);
|
||||
}
|
||||
|
||||
return Json(new
|
||||
{
|
||||
key = deviceInfo.Device_key,
|
||||
device_key = deviceInfo.Device_key,
|
||||
device_token = deviceInfo.Device_token
|
||||
key = device_key,
|
||||
device_key = device_key,
|
||||
device_token = device_token
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
[HttpGet, Route("RegisterCheck")]
|
||||
public JsonResult Register(string device_key)
|
||||
{
|
||||
if (string.IsNullOrEmpty(device_key))
|
||||
{
|
||||
return Fail(400, "device key is empty");
|
||||
}
|
||||
if (!DBManager.Instance.DBase.Query<SendAuthInfo>().Any(e => e.Key == device_key))
|
||||
{
|
||||
return Fail(400, "device not registered");
|
||||
}
|
||||
|
||||
return OK();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -70,7 +70,7 @@ namespace Inotify.Controllers
|
||||
{
|
||||
code = 200,
|
||||
message = "sucess",
|
||||
timestamp = (DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds
|
||||
timestamp = (int)(DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds
|
||||
});
|
||||
}
|
||||
|
||||
@ -81,7 +81,17 @@ namespace Inotify.Controllers
|
||||
code = 200,
|
||||
message = "sucess",
|
||||
data = obj ?? "",
|
||||
timestamp = (DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds
|
||||
timestamp = (int)(DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds
|
||||
});
|
||||
}
|
||||
|
||||
protected JsonResult Me(string message)
|
||||
{
|
||||
return Json(new
|
||||
{
|
||||
code = 200,
|
||||
message = message,
|
||||
timestamp = (int)(DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds
|
||||
});
|
||||
}
|
||||
|
||||
@ -91,7 +101,7 @@ namespace Inotify.Controllers
|
||||
{
|
||||
code = 404,
|
||||
message = "failed",
|
||||
timestamp = (DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds
|
||||
timestamp = (int)(DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds
|
||||
});
|
||||
}
|
||||
|
||||
@ -99,9 +109,9 @@ namespace Inotify.Controllers
|
||||
{
|
||||
return Json(new
|
||||
{
|
||||
code,
|
||||
code= code,
|
||||
message = "failed",
|
||||
timestamp = (DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds
|
||||
timestamp = (int)(DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds
|
||||
});
|
||||
}
|
||||
|
||||
@ -109,9 +119,9 @@ namespace Inotify.Controllers
|
||||
{
|
||||
return new JsonResult(new
|
||||
{
|
||||
code,
|
||||
message,
|
||||
timestamp = (DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalMilliseconds
|
||||
code=code,
|
||||
message=message,
|
||||
timestamp = (int)(DateTime.Now.ToUniversalTime() - new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc)).TotalSeconds
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -12,20 +12,39 @@ namespace Inotify.Controllers
|
||||
public class SendController : BaseControlor
|
||||
{
|
||||
[HttpGet, Route("send")]
|
||||
public JsonResult Send(string token, string title, string? data)
|
||||
public JsonResult Send(string token, string title, string? data, string? key)
|
||||
{
|
||||
if (DBManager.Instance.IsSendKey(token))
|
||||
if (DBManager.Instance.IsToken(token, out bool hasActive))
|
||||
{
|
||||
if (!hasActive) return Fail(400, "you have no tunnel is acitve");
|
||||
|
||||
if (!string.IsNullOrEmpty(key))
|
||||
{
|
||||
if (DBManager.Instance.IsSendKey(key, out bool isActive))
|
||||
{
|
||||
if (!isActive)
|
||||
{
|
||||
return Fail(400, $"device:{key} tunnel is not acitve");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
return Fail(400, $"device:{key} is not registered");
|
||||
}
|
||||
}
|
||||
|
||||
var message = new SendMessage()
|
||||
{
|
||||
Token = token,
|
||||
Title = title,
|
||||
Data = data,
|
||||
Key = key,
|
||||
};
|
||||
if (SendTaskManager.Instance.SendMessage(message))
|
||||
return OK();
|
||||
|
||||
if (SendTaskManager.Instance.SendMessage(message)) return OK();
|
||||
}
|
||||
return Fail();
|
||||
|
||||
return Fail(400, $"token:{token} is not registered");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -39,6 +39,7 @@ namespace Inotify.Controllers
|
||||
var userInfo = DBManager.Instance.GetUser(UserName);
|
||||
if (userInfo != null)
|
||||
{
|
||||
var barkTemplateAttribute = typeof(BarkSendTemplate).GetCustomAttributes(typeof(SendMethodKeyAttribute), false).OfType<SendMethodKeyAttribute>().First();
|
||||
var sendAuthInfos = DBManager.Instance.DBase.Query<SendAuthInfo>().Where(e => e.UserId == userInfo.Id).ToArray();
|
||||
var userSendTemplates = new List<InputTemeplate>();
|
||||
foreach (var sendAuthInfo in sendAuthInfos)
|
||||
@ -53,6 +54,10 @@ namespace Inotify.Controllers
|
||||
sendTemplate.AuthToTemplate(sendAuthInfo.AuthData);
|
||||
userSendTemplates.Add(sendTemplate);
|
||||
}
|
||||
if (barkTemplateAttribute.Key == sendTemplate.Key)
|
||||
{
|
||||
sendTemplate.Values.FirstOrDefault(e => e.Name == nameof(BarkSendTemplate.Auth.SendUrl)).Value = "";
|
||||
}
|
||||
}
|
||||
|
||||
return OK(userSendTemplates);
|
||||
@ -100,10 +105,9 @@ namespace Inotify.Controllers
|
||||
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)
|
||||
if (barkKey == inputTemeplate.Key)
|
||||
{
|
||||
return Fail(406, "您只能添加一个BARK通道");
|
||||
return Fail(406, "BARK通道勿手动添加,请使用APP添加BARK地址绑定");
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -131,6 +135,7 @@ namespace Inotify.Controllers
|
||||
var userInfo = DBManager.Instance.GetUser(UserName);
|
||||
if (userInfo != null)
|
||||
{
|
||||
var barkTemplateAttribute = typeof(BarkSendTemplate).GetCustomAttributes(typeof(SendMethodKeyAttribute), false).OfType<SendMethodKeyAttribute>().First();
|
||||
var oldSendInfo = DBManager.Instance.DBase.Query<SendAuthInfo>().FirstOrDefault(e => e.Id == inputTemeplate.SendAuthId);
|
||||
if (oldSendInfo != null && inputTemeplate.Name != null)
|
||||
{
|
||||
|
@ -30,6 +30,9 @@ namespace Inotify.Controllers
|
||||
githubClientID = SendCacheStore.GetSystemValue("githubClientID"),
|
||||
githubClientSecret = SendCacheStore.GetSystemValue("githubClientSecret"),
|
||||
githubEnable = githubEnable != "" && bool.Parse(githubEnable),
|
||||
barkKeyId= SendCacheStore.GetSystemValue("barkKeyId"),
|
||||
barkTeamId = SendCacheStore.GetSystemValue("barkTeamId"),
|
||||
barkPrivateKey = SendCacheStore.GetSystemValue("barkPrivateKey"),
|
||||
});
|
||||
}
|
||||
|
||||
@ -41,7 +44,10 @@ namespace Inotify.Controllers
|
||||
string? proxyenable,
|
||||
string? githubClientID,
|
||||
string? githubClientSecret,
|
||||
string? githubEnable)
|
||||
string? githubEnable,
|
||||
string? barkKeyId,
|
||||
string? barkTeamId,
|
||||
string? barkPrivateKey)
|
||||
{
|
||||
SendCacheStore.SetSystemValue("sendthread", sendthread);
|
||||
SendCacheStore.SetSystemValue("administrators", administrators);
|
||||
@ -50,6 +56,9 @@ namespace Inotify.Controllers
|
||||
SendCacheStore.SetSystemValue("githubClientID", githubClientID);
|
||||
SendCacheStore.SetSystemValue("githubClientSecret", githubClientSecret);
|
||||
SendCacheStore.SetSystemValue("githubEnable", githubEnable);
|
||||
SendCacheStore.SetSystemValue("barkKeyId", barkKeyId);
|
||||
SendCacheStore.SetSystemValue("barkTeamId", barkTeamId);
|
||||
SendCacheStore.SetSystemValue("barkPrivateKey", barkPrivateKey);
|
||||
|
||||
SendTaskManager.Instance.Stop();
|
||||
SendTaskManager.Instance.Run();
|
||||
|
@ -105,16 +105,38 @@ namespace Inotify.Data
|
||||
|
||||
|
||||
m_dbConnection = new SqliteConnection(string.Format("Data Source={0}", m_dbPath));
|
||||
|
||||
if (m_dbConnection.State == ConnectionState.Closed)
|
||||
m_dbConnection.Open();
|
||||
|
||||
DBase = new NPoco.Database(m_dbConnection, DatabaseType.SQLite);
|
||||
DBase = new Database(m_dbConnection, DatabaseType.SQLite);
|
||||
DBase.KeepConnectionAlive = true;
|
||||
m_migrator = new Migrator(DBase);
|
||||
}
|
||||
|
||||
public bool IsSendKey(string token)
|
||||
public bool IsToken(string token,out bool hasActive)
|
||||
{
|
||||
return DBase.Query<SendUserInfo>().Any(e => e.Token == token);
|
||||
hasActive = false;
|
||||
var userInfo= DBase.Query<SendUserInfo>().FirstOrDefault(e => e.Token == token);
|
||||
if (userInfo != null)
|
||||
{
|
||||
hasActive= DBase.Query<SendAuthInfo>().Any(e => e.UserId== userInfo.Id && e.Active);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsSendKey(string key, out bool isActive)
|
||||
{
|
||||
isActive = false;
|
||||
var sendAuthInfo = DBase.Query<SendAuthInfo>().FirstOrDefault(e => e.Key == key);
|
||||
if (sendAuthInfo != null)
|
||||
{
|
||||
isActive = sendAuthInfo.Active;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsUser(string userName)
|
||||
@ -124,10 +146,10 @@ namespace Inotify.Data
|
||||
|
||||
public SendUserInfo GetUser(string userName)
|
||||
{
|
||||
return DBase.Query<SendUserInfo>().First(e => e.UserName == userName);
|
||||
return DBase.Query<SendUserInfo>().FirstOrDefault(e => e.UserName == userName);
|
||||
}
|
||||
|
||||
public string GetAuth(string token, out string guid)
|
||||
public string GetSendAuthInfo(string token, out string guid)
|
||||
{
|
||||
guid = string.Empty;
|
||||
var upToekn = token.ToUpper();
|
||||
@ -142,17 +164,24 @@ namespace Inotify.Data
|
||||
return authInfo.AuthData;
|
||||
}
|
||||
|
||||
public void GetAuth(string token, out SendAuthInfo[] sendAuthInfos)
|
||||
public void GetSendAuthInfos(string token, string key, 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)
|
||||
|
||||
{
|
||||
if (string.IsNullOrEmpty(key))
|
||||
{
|
||||
sendAuthInfos = DBManager.Instance.DBase.Query<SendAuthInfo>().Where(e => e.UserId == userInfo.Id && e.Active).ToArray();
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
sendAuthInfos = DBManager.Instance.DBase.Query<SendAuthInfo>().Where(e => e.UserId == userInfo.Id && e.Active &&e.Key==key).ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Run()
|
||||
{
|
||||
@ -175,10 +204,9 @@ namespace Inotify.Data
|
||||
|
||||
var builder = new MigrationBuilder(MigrationName, DBase);
|
||||
builder.Append(new Version(2, 0, 0, 0), new V2UpdateMigration());
|
||||
builder.Append(new Version(2, 0, 0, 1), new V2001UpdateMigration());
|
||||
builder.Execute();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
@ -59,8 +59,7 @@ namespace Inotify.Data
|
||||
{
|
||||
protected override void execute()
|
||||
{
|
||||
//V2版本允许多通道,激活标记放入SendAuthInfo表中,增加Active列
|
||||
//更新原有用户的激活通道
|
||||
//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();
|
||||
@ -75,4 +74,38 @@ namespace Inotify.Data
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public class V2001UpdateMigration : Migration, IMigration
|
||||
{
|
||||
protected override void execute()
|
||||
{
|
||||
//V2001版本增加SendInfo的key字段
|
||||
Migrator.AlterTable<SendAuthInfo>().AddColumn(e => e.Key).Execute();
|
||||
|
||||
//对AuthInfo的AuthDate字段进行加密
|
||||
var sendAuthInfos = Migrator.Database.Query<SendAuthInfo>().ToList();
|
||||
sendAuthInfos.ForEach(sendAuthInfo =>
|
||||
{
|
||||
sendAuthInfo.AuthData = sendAuthInfo.AuthDataSave;
|
||||
Migrator.Database.Update(sendAuthInfo);
|
||||
});
|
||||
|
||||
//添加bark密钥相关内容
|
||||
Migrator.Database.Insert(new SystemInfo()
|
||||
{
|
||||
key = "barkKeyId",
|
||||
Value = "TEg0VDlWNVU0Ug==".Base64Decode(),
|
||||
});
|
||||
Migrator.Database.Insert(new SystemInfo()
|
||||
{
|
||||
key = "barkTeamId",
|
||||
Value = "NVU4TEJSWEczQQ==".Base64Decode(),
|
||||
});
|
||||
Migrator.Database.Insert(new SystemInfo()
|
||||
{
|
||||
key = "barkPrivateKey",
|
||||
Value = "LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JR1RBZ0VBTUJNR0J5cUdTTTQ5QWdFR0NDcUdTTTQ5QXdFSEJIa3dkd0lCQVFRZzR2dEMzZzVMNUhnS0dKMitUMWVBMHRPaXZSRXZFQVkyZytqdVJYSmtZTDJnQ2dZSUtvWkl6ajBEQVFlaFJBTkNBQVNtT3MzSmtTeW9HRVdac1VHeEZzLzRwdzFySWxTVjJJQzE5TTh1M0c1a3EzNnVwT3d5RldqOUdpM0VqYzlkM3NDNytTSFJxWHJFQUpvdzgvN3RScFYrCi0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0=".Base64Decode()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
using System;
|
||||
|
||||
using Inotify.Common;
|
||||
namespace Inotify.Data.Models
|
||||
{
|
||||
[NPoco.TableName("sendAuthInfo")]
|
||||
@ -19,7 +19,20 @@ namespace Inotify.Data.Models
|
||||
public string SendMethodTemplate { get; set; }
|
||||
|
||||
[NPoco.Column("authData")]
|
||||
public string AuthData { get; set; }
|
||||
public string AuthDataSave { get; set; }
|
||||
|
||||
[NPoco.Ignore]
|
||||
public string AuthData
|
||||
{
|
||||
get
|
||||
{
|
||||
return AuthDataSave.Base64Decode();
|
||||
}
|
||||
set
|
||||
{
|
||||
AuthDataSave = value.Base64Encode();
|
||||
}
|
||||
}
|
||||
|
||||
[NPoco.Column("modifyTime")]
|
||||
public DateTime ModifyTime { get; set; }
|
||||
@ -29,5 +42,9 @@ namespace Inotify.Data.Models
|
||||
|
||||
[NPoco.Column("active")]
|
||||
public bool Active { get; set; }
|
||||
|
||||
[NPoco.Column("key")]
|
||||
public string Key { get; set; }
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -6,8 +6,8 @@
|
||||
<DockerDefaultTargetOS>Linux</DockerDefaultTargetOS>
|
||||
<StartupObject>Inotify.Program</StartupObject>
|
||||
<Nullable>enable</Nullable>
|
||||
<AssemblyVersion>2.0.0.0</AssemblyVersion>
|
||||
<FileVersion>2.0.0.0</FileVersion>
|
||||
<AssemblyVersion>2.0.0.1</AssemblyVersion>
|
||||
<FileVersion>2.0.0.1</FileVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
@ -31,7 +31,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<None Update="inotify_data\AuthKey_LH4T9V5U4R_5U8LBRXG3A.p8">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
<CopyToOutputDirectory>Always</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
|
||||
|
@ -1,9 +1,11 @@
|
||||
using Inotify.Common;
|
||||
using Inotify.Data;
|
||||
using Microsoft.IdentityModel.Tokens;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IdentityModel.Tokens.Jwt;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
@ -16,166 +18,78 @@ 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(1, "Sound", "声音", "1107")]
|
||||
public string Sound { get; set; }
|
||||
|
||||
[InputTypeAttribte(0, "IsArchive", "自动保存", "1")]
|
||||
[InputTypeAttribte(2, "IsArchive", "自动保存", "1或0")]
|
||||
public string IsArchive { get; set; }
|
||||
|
||||
[InputTypeAttribte(0, "AutoMaticallyCopy", "自动复制", "0")]
|
||||
[InputTypeAttribte(3, "AutoMaticallyCopy", "自动复制", "1或0")]
|
||||
public string AutoMaticallyCopy { get; set; }
|
||||
|
||||
[InputTypeAttribte(0, "DeviceToken", "DeviceToken", "DeviceToken",false)]
|
||||
[InputTypeAttribte(4, "DeviceKey", "DeviceKey", "DeviceKey", true, true)]
|
||||
public string DeviceKey { get; set; }
|
||||
|
||||
[InputTypeAttribte(5, "DeviceToken", "DeviceToken", "DeviceToken", true, true)]
|
||||
public string DeviceToken { get; set; }
|
||||
|
||||
[InputTypeAttribte(6, "SendUrl", "SendUrl", "SendUrl", true, true)]
|
||||
public string SendUrl { get; set; }
|
||||
|
||||
|
||||
}
|
||||
|
||||
[SendMethodKey("3B6DE04D-A9EF-4C91-A151-60B7425C5AB2", "Bark(未完成)", Order = -1)]
|
||||
[SendMethodKey("3B6DE04D-A9EF-4C91-A151-60B7425C5AB2", "Bark", Order = 6, Waring = "BARK通道勿手动添加,请使用APP添加BARK地址绑定")]
|
||||
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 string KeyID;
|
||||
|
||||
private static string TeamID;
|
||||
|
||||
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);
|
||||
KeyID = SendCacheStore.GetSystemValue("barkKeyId");
|
||||
TeamID = SendCacheStore.GetSystemValue("barkTeamId");
|
||||
var privateKey = SendCacheStore.GetSystemValue("barkPrivateKey");
|
||||
var privateKeyContent = privateKey.Split('\n')[1];
|
||||
var decodeKey = Convert.FromBase64String(privateKeyContent);
|
||||
SecretKey = CngKey.Import(decodeKey, CngKeyBlobFormat.Pkcs8PrivateBlob);
|
||||
}
|
||||
|
||||
if (barkMessage == null)
|
||||
if (Auth.DeviceToken == null)
|
||||
return false;
|
||||
|
||||
if (device_Tokne == null)
|
||||
return false;
|
||||
var payload = CreatePayload(message);
|
||||
var accessToken = CreateAccessToken(payload);
|
||||
var result = CreatePush(payload, accessToken, Auth.DeviceToken);
|
||||
|
||||
return result;
|
||||
|
||||
}
|
||||
|
||||
private string CreatePayload(SendMessage message)
|
||||
{
|
||||
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);
|
||||
if (!string.IsNullOrEmpty(message.Data))
|
||||
alert.Add("body", message.Data);
|
||||
if (!string.IsNullOrEmpty(message.Title))
|
||||
alert.Add("title", message.Title);
|
||||
|
||||
var aps = new Dictionary<string, object>
|
||||
{
|
||||
{ "category", "Bark" },
|
||||
{ "sound", "1107" },
|
||||
{ "sound", Auth.Sound },
|
||||
{ "badge", "0" },
|
||||
{ "mutable-content", "1" },
|
||||
{ "alert", alert }
|
||||
@ -184,65 +98,88 @@ namespace Inotify.Sends.Products
|
||||
var payload = new Dictionary<string, object>
|
||||
{
|
||||
{ "aps", aps },
|
||||
{ "isarchive", barkMessage.IsArchive },
|
||||
{ "automaticallycopy", barkMessage.AutoMaticallyCopy },
|
||||
{ "isarchive", Auth.IsArchive },
|
||||
{ "automaticallycopy", Auth.AutoMaticallyCopy },
|
||||
{ "iss", TeamID},
|
||||
{ "iat", expirationSeconds}
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(barkMessage.Url))
|
||||
payload.Add("url", barkMessage.Url);
|
||||
if (!string.IsNullOrEmpty(message.Title))
|
||||
payload.Add("copy", message.Title);
|
||||
|
||||
if (!string.IsNullOrEmpty(barkMessage.Copy))
|
||||
payload.Add("copy", barkMessage.Copy);
|
||||
var payloadString = JObject.FromObject(payload).ToString();
|
||||
|
||||
var headers = new
|
||||
|
||||
return payloadString;
|
||||
}
|
||||
|
||||
private string CreateAccessToken(string payload)
|
||||
{
|
||||
using ECDsaCng dsa = new ECDsaCng(SecretKey)
|
||||
{
|
||||
HashAlgorithm = CngAlgorithm.Sha256
|
||||
};
|
||||
var headers = JObject.FromObject(new
|
||||
{
|
||||
alg = "ES256",
|
||||
kid = KeyID
|
||||
}).ToString();
|
||||
|
||||
var unsignedJwtData = Convert.ToBase64String(Encoding.UTF8.GetBytes(headers)) + "." + Convert.ToBase64String(Encoding.UTF8.GetBytes(payload));
|
||||
var signature = dsa.SignData(Encoding.UTF8.GetBytes(unsignedJwtData));
|
||||
return unsignedJwtData + "." + Convert.ToBase64String(signature);
|
||||
}
|
||||
|
||||
private bool CreatePush(string payload, string accessToken, string device_Tokne)
|
||||
{
|
||||
try
|
||||
{
|
||||
var data = Encoding.UTF8.GetBytes(payload);
|
||||
var request = new HttpRequestMessage
|
||||
{
|
||||
Version = new Version(2, 0),
|
||||
RequestUri = new Uri($"https://api.development.push.apple.com:443/3/device/{device_Tokne}")
|
||||
};
|
||||
|
||||
var hearderString = JObject.FromObject(headers).ToString();
|
||||
var payloadString = JObject.FromObject(payload).ToString();
|
||||
var accessToken = SignES256(SecretKey, hearderString, payloadString);
|
||||
var data = Encoding.UTF8.GetBytes(payloadString);
|
||||
|
||||
request.Headers.Add("authorization", string.Format("bearer {0}", accessToken));
|
||||
request.Headers.Add("apns-id", Guid.NewGuid().ToString());
|
||||
request.Headers.Add("apns-expiration", "0");
|
||||
request.Headers.Add("apns-priority", "10");
|
||||
request.Headers.Add("apns-topic", "me.fin.bark");
|
||||
request.Method = HttpMethod.Post;
|
||||
request.Content = new ByteArrayContent(data);
|
||||
|
||||
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);
|
||||
httpClient.DefaultRequestHeaders.Connection.Add("Keep-Alive");
|
||||
|
||||
var task = httpClient.SendAsync(requestMessage);
|
||||
var task = httpClient.SendAsync(request);
|
||||
task.Wait();
|
||||
var responseMessage = task.Result;
|
||||
if (responseMessage.StatusCode == System.Net.HttpStatusCode.OK)
|
||||
{
|
||||
|
||||
var _response_uuid = "";
|
||||
if (responseMessage.Headers.TryGetValues("apns-id", out IEnumerable<string> values))
|
||||
{
|
||||
_response_uuid = values.First();
|
||||
Console.WriteLine($"success: '{_response_uuid}'");
|
||||
return true;
|
||||
}
|
||||
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
var respoinseBody = responseMessage.Content.ReadAsStringAsync().Result;
|
||||
var responseJson = JObject.Parse(respoinseBody);
|
||||
var reason = responseJson.Value<string>("reason");
|
||||
Console.WriteLine($"failure: '{reason}'");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"exception: '{ex.Message}'");
|
||||
}
|
||||
|
||||
|
||||
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);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -9,5 +9,6 @@ namespace Inotify.Sends
|
||||
public string Token;
|
||||
public string Title;
|
||||
public string? Data;
|
||||
public string? Key;
|
||||
}
|
||||
}
|
||||
|
@ -37,7 +37,6 @@ namespace Inotify.Sends
|
||||
|
||||
private readonly Dictionary<string, Type> m_sendMethodTemplateTypes;
|
||||
|
||||
|
||||
private SendTaskManager()
|
||||
{
|
||||
m_sendMessages = new BlockingCollection<SendMessage>();
|
||||
@ -70,7 +69,6 @@ namespace Inotify.Sends
|
||||
m_analyseThread.Start();
|
||||
}
|
||||
|
||||
|
||||
public EventHandler<SendMessage> OnMessageAdd;
|
||||
|
||||
public EventHandler<SendMessage> OnSendSucessed;
|
||||
@ -152,7 +150,7 @@ namespace Inotify.Sends
|
||||
try
|
||||
{
|
||||
var message = m_sendMessages.Take();
|
||||
DBManager.Instance.GetAuth(message.Token, out SendAuthInfo[] sendAuthInfos);
|
||||
DBManager.Instance.GetSendAuthInfos(message.Token, message.Key, out SendAuthInfo[] sendAuthInfos);
|
||||
foreach (var authInfo in sendAuthInfos)
|
||||
{
|
||||
var authData = authInfo.AuthData;
|
||||
@ -212,7 +210,7 @@ namespace Inotify.Sends
|
||||
{
|
||||
var message = m_analyseMessages.Take();
|
||||
var date = DateTime.Now.ToString("yyyyMMdd");
|
||||
var authData = DBManager.Instance.GetAuth(message.Token, out string temeplateId);
|
||||
var authData = DBManager.Instance.GetSendAuthInfo(message.Token, out string temeplateId);
|
||||
|
||||
if (temeplateId != null)
|
||||
{
|
||||
|
@ -31,16 +31,25 @@ namespace Inotify.Sends
|
||||
|
||||
public int Order;
|
||||
|
||||
public SendMethodKeyAttribute(string key, string name, bool open = true)
|
||||
public string Waring;
|
||||
|
||||
public SendMethodKeyAttribute(string key, string name, bool open = true, string waring = "")
|
||||
{
|
||||
Key = key;
|
||||
Name = name;
|
||||
Open = open;
|
||||
Waring = waring;
|
||||
}
|
||||
}
|
||||
|
||||
public class InputTypeValue
|
||||
{
|
||||
|
||||
public InputTypeValue()
|
||||
{
|
||||
Show = true;
|
||||
Readonly = false;
|
||||
}
|
||||
public string? Name { get; set; }
|
||||
public string? Description { get; set; }
|
||||
public string? Default { get; set; }
|
||||
@ -48,7 +57,11 @@ namespace Inotify.Sends
|
||||
public int? Order { get; set; }
|
||||
public string? Value { get; set; }
|
||||
|
||||
public bool Visuable { get; set; }
|
||||
public string? Warning { get; set; }
|
||||
|
||||
public bool Show { get; set; }
|
||||
|
||||
public bool Readonly { get; set; }
|
||||
}
|
||||
|
||||
public class InputTemeplate
|
||||
@ -57,6 +70,7 @@ namespace Inotify.Sends
|
||||
public string? Type { get; set; }
|
||||
public string? Name { get; set; }
|
||||
public bool IsActive { get; set; }
|
||||
public string Warning { get; set; }
|
||||
public string? AuthData { get; set; }
|
||||
public int? SendAuthId { get; set; }
|
||||
public List<InputTypeValue>? Values { get; set; }
|
||||
@ -112,7 +126,7 @@ namespace Inotify.Sends
|
||||
public InputTypeValue InputTypeData { get; set; }
|
||||
|
||||
|
||||
private InputTypeAttribte(int order, string name, string description, string defaultValue, InputType type,bool visuable=true)
|
||||
private InputTypeAttribte(int order, string name, string description, string defaultValue, InputType type,bool show=true,bool readOnly=false)
|
||||
{
|
||||
InputTypeData = new InputTypeValue
|
||||
{
|
||||
@ -121,18 +135,19 @@ namespace Inotify.Sends
|
||||
Default = defaultValue,
|
||||
Order = order,
|
||||
Type = type,
|
||||
Visuable=visuable
|
||||
Show = show,
|
||||
Readonly = readOnly
|
||||
};
|
||||
}
|
||||
|
||||
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, string defaultValue, bool show = true, bool readOnly = false)
|
||||
: this(order, name, description, defaultValue, InputType.TEXT, show, readOnly)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public InputTypeAttribte(int order, string name, string description, bool defaultValue, bool visuable = true)
|
||||
: this(order, name, description, "", InputType.CHECK, visuable)
|
||||
public InputTypeAttribte(int order, string name, string description, bool defaultValue, bool show = true, bool readOnly = false)
|
||||
: this(order, name, description, "", InputType.CHECK, show, readOnly)
|
||||
{
|
||||
InputTypeData.Default = defaultValue ? "是" : "否";
|
||||
}
|
||||
@ -156,7 +171,6 @@ 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>();
|
||||
@ -168,6 +182,7 @@ namespace Inotify.Sends
|
||||
Name = sendMethodKeyAttribute.Name,
|
||||
Type = sendMethodKeyAttribute.Name,
|
||||
Key = sendMethodKeyAttribute.Key,
|
||||
Warning = sendMethodKeyAttribute.Waring,
|
||||
Values = values
|
||||
};
|
||||
}
|
||||
|
@ -20,6 +20,7 @@ using System.Net.Http;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Text.Unicode;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
@ -96,26 +97,63 @@ namespace Inotify
|
||||
|
||||
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
|
||||
{
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseFileServer();
|
||||
|
||||
if (env.IsDevelopment())
|
||||
{
|
||||
app.UseDeveloperExceptionPage();
|
||||
}
|
||||
|
||||
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);
|
||||
options.Add(rewriteContext =>
|
||||
{
|
||||
Match match;
|
||||
if (rewriteContext.HttpContext.Request.Path == "/")
|
||||
{
|
||||
var queryValue = rewriteContext.HttpContext.Request.QueryString.Value;
|
||||
match = Regex.Match(queryValue, @"^\?act=(.*)/(.*)/(.*)/(.*)$");
|
||||
var groups = match.Groups;
|
||||
if (match.Success)
|
||||
{
|
||||
rewriteContext.HttpContext.Request.Path = @"/api/send";
|
||||
rewriteContext.HttpContext.Request.QueryString = new QueryString($"?token={groups[1]}&key={groups[2]}&title={groups[3]}&date={groups[4]}");
|
||||
}
|
||||
else
|
||||
{
|
||||
match = Regex.Match(queryValue, @"^\?act=(.*)/(.*)/(.*)$");
|
||||
if (match.Success)
|
||||
{
|
||||
rewriteContext.HttpContext.Request.Path = @"/api/send";
|
||||
rewriteContext.HttpContext.Request.QueryString = new QueryString($"?token={groups[1]}&key={groups[2]}&title={groups[3]}");
|
||||
}
|
||||
else
|
||||
{
|
||||
match = Regex.Match(queryValue, @"^\?act=(.*)/(.*)$");
|
||||
if (match.Success)
|
||||
{
|
||||
rewriteContext.HttpContext.Request.Path = @"/api/send";
|
||||
rewriteContext.HttpContext.Request.QueryString = new QueryString($"?token={groups[1]}&key={groups[2]}");
|
||||
}
|
||||
else if(rewriteContext.HttpContext.Request.QueryString.Value.StartsWith("?"))
|
||||
{
|
||||
rewriteContext.HttpContext.Request.Path = @"/info";
|
||||
rewriteContext.HttpContext.Request.QueryString = new QueryString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
rewriteContext.Result = RuleResult.ContinueRules;
|
||||
});
|
||||
|
||||
//https://im.xpnas.com/?act=123456/ZtCLMPWQWtjJQpKmQS6hoV/
|
||||
|
||||
options.AddRewrite(@"^(.*).send/(.*)/(.*)", "api/send?token=$1&title=$2&data=$3", true);
|
||||
options.AddRewrite(@"^(.*).send/(.*)", "api/send?token=$1&title=$2", true);
|
||||
options.AddRewrite(@"^api/(.*).send/(.*)/(.*)", "api/send?token=$1&title=$2&data=$3", true);
|
||||
options.AddRewrite(@"^api/(.*).send/(.*)", "api/send?token=$1&title=$2", true);
|
||||
app.UseRewriter(options);
|
||||
app.UseRouting();
|
||||
|
||||
app.UseStaticFiles();
|
||||
app.UseFileServer();
|
||||
|
||||
app.UseAuthentication();
|
||||
app.UseAuthorization();
|
||||
app.UseEndpoints(endpoints =>
|
||||
|
@ -26,7 +26,7 @@ namespace Inotify.ThridOauth.Service
|
||||
private readonly string _authorizeUrl;
|
||||
|
||||
|
||||
public GitHubLogin(IHttpContextAccessor contextAccessor, IOptions<GitHubCredential> options) : base(
|
||||
public GitHubLogin(IHttpContextAccessor contextAccessor) : base(
|
||||
contextAccessor)
|
||||
{
|
||||
Credential = new CredentialSetting()
|
||||
|
21
README.md
21
README.md
@ -22,16 +22,30 @@
|
||||
- [x] 企业微信应用消息
|
||||
- [x] 电报机器人消息
|
||||
- [x] SMTP邮箱消息
|
||||
- [x] BARK
|
||||
- [ ] 钉钉群机器人
|
||||
- [ ] 飞书群机器人
|
||||
- [x] 自定义
|
||||
|
||||
## 更新日志
|
||||
|
||||
* V1.0
|
||||
* 支持企业微信应用、电报、SMTP消息
|
||||
* V2.0.0.1
|
||||
* 支持自定义Get、POST
|
||||
* V2.0.0.2
|
||||
* 支持BARK
|
||||
|
||||
## 使用方法
|
||||
1. Docker安装
|
||||
* 稳定版V1.0
|
||||
```
|
||||
docker run --name=inotify -d -p 8000:80 -v inotify_data:/inotify_data --restart=always xpnas/inotify:latest
|
||||
```
|
||||
|
||||
* 开发版V2.0.0.2
|
||||
```
|
||||
docker run --name=inotify -d -p 8000:80 -v inotify_data:/inotify_data --restart=always xpnas/inotify:master
|
||||
```
|
||||
2. 配置Nginx代理
|
||||
```
|
||||
server
|
||||
@ -46,6 +60,11 @@
|
||||
4. 使用`默认用户名admin,密码123456`登陆后台/全局参数,修改Github登陆的`应用ID`、`应用密钥`并启动登陆
|
||||
5. 建议将`管理权限`的用户名设置成自己的github用户名,再使用Github登陆后,在用户管理页面`删除默认账号admin`
|
||||
|
||||
## BARK设置
|
||||
1. 本项目依据Bark-Server接口规范实现了内置BARK服务端
|
||||
2. 复制或扫码`消息验证\BARK授权`中的地址,填入BARK应用的服务器地址中,如`https://inotify.cf?act=6D474C0DB1474F19BD8F7342D570C0FC`
|
||||
3. BARK的APP会自动在本系统注册数据,记录将直接出现在`消息通道`
|
||||
|
||||
## 系统截图
|
||||
|
||||

|
||||
|
BIN
public/A.png
BIN
public/A.png
Binary file not shown.
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 104 KiB |
Loading…
Reference in New Issue
Block a user