很多修改

This commit is contained in:
snltty
2025-12-11 17:30:07 +08:00
parent 3f9dfe019c
commit 201f61714e
45 changed files with 973 additions and 124 deletions

View File

@@ -19,7 +19,7 @@ jobs:
release_name: v1.9.7.${{ steps.date.outputs.today }}
draft: false
prerelease: false
body: "1. 一些累计更新一些BUG修复\r\n2. 重构中继和穿透的多节点模式\r\n3. 中继连接合并到隧道协议中\r\n4. 修复socks代理模块\r\n5. 发布飞牛fpk安装包(docker+bin)\r\n6. 先不要更新,作者测试中"
body: "1. 一些累计更新一些BUG修复\r\n2. 重构中继和穿透的多节点模式\r\n3. 中继连接合并到隧道协议中\r\n4. 修复socks代理模块\r\n5. 发布飞牛fpk安装包(docker+bin)\r\n6. 优化虚拟网卡自动连接表现\r\n7. 简化加入分组操作\r\n8. 先不要更新,作者测试中"
- name: setup node.js
uses: actions/setup-node@v2
with:

View File

@@ -1,15 +1,41 @@
namespace linker.messenger.node
using System.Net;
namespace linker.messenger.node
{
/// <summary>
/// 禁用的主机
/// </summary>
public interface INodeMasterDenyStore
{
public Task<MasterDenyStoreResponseInfo> Get(MasterDenyStoreRequestInfo request);
public Task<bool> Get(uint ip);
public Task<bool> Add(string str);
public Task<bool> Delete(int id);
public Task<bool> Get(uint ip,int plus);
public Task<bool> Add(MasterDenyAddInfo info);
public Task<bool> Delete(MasterDenyDelInfo info);
}
public sealed class MastersRequestInfo
{
public string NodeId { get; set; }
public int Page { get; set; }
public int Sise { get; set; }
}
public sealed class MastersResponseInfo
{
public int Page { get; set; }
public int Sise { get; set; }
public int Count { get; set; }
public List<MasterConnInfo> List { get; set; } = new List<MasterConnInfo>();
}
public sealed class MasterConnInfo
{
public IPEndPoint Addr { get; set; }
public string NodeId { get; set; }
}
public sealed class MasterDenyStoreRequestInfo
{
public string NodeId { get; set; }
public int Page { get; set; }
public int Sise { get; set; }
public string Str { get; set; }
@@ -27,6 +53,20 @@
public uint Ip { get; set; }
public uint Plus { get; set; }
public string Str { get; set; }
public string Remark { get; set; }
}
public sealed class MasterDenyAddInfo
{
public string NodeId { get; set; }
public int Id { get; set; }
public string Str { get; set; }
public string Remark { get; set; }
}
public sealed class MasterDenyDelInfo
{
public string NodeId { get; set; }
public int Id { get; set; }
}
}

View File

@@ -21,6 +21,10 @@ namespace linker.messenger.node
public virtual ushort MessengerIdExitForward { get; }
public virtual ushort MessengerIdReport { get; }
public virtual ushort MessengerIdSignIn { get; }
public virtual ushort MessengerIdMastersForward { get; }
public virtual ushort MessengerIdDenysForward { get; }
public virtual ushort MessengerIdDenysAddForward { get; }
public virtual ushort MessengerIdDenysDelForward { get; }
private int connectionNum = 0;
@@ -36,10 +40,11 @@ namespace linker.messenger.node
private readonly IMessengerSender messengerSender;
private readonly INodeStore<TStore, TReport> nodeStore;
private readonly IMessengerResolver messengerResolver;
private readonly INodeMasterDenyStore nodeMasterDenyStore;
public NodeReportTransfer(NodeConnectionTransfer nodeConnectionTransfer, INodeConfigStore<TConfig> nodeConfigStore,
ISerializer serializer, IMessengerSender messengerSender, INodeStore<TStore, TReport> nodeStore,
IMessengerResolver messengerResolver, ICommonStore commonStore)
IMessengerResolver messengerResolver, ICommonStore commonStore, INodeMasterDenyStore nodeMasterDenyStore)
{
this.nodeConnectionTransfer = nodeConnectionTransfer;
this.nodeConfigStore = nodeConfigStore;
@@ -47,6 +52,7 @@ namespace linker.messenger.node
this.messengerSender = messengerSender;
this.nodeStore = nodeStore;
this.messengerResolver = messengerResolver;
this.nodeMasterDenyStore = nodeMasterDenyStore;
md5 = Config.NodeId.Md5();
@@ -97,6 +103,10 @@ namespace linker.messenger.node
{
return false;
}
if (await nodeMasterDenyStore.Get(NetworkHelper.ToValue(connection.Address.Address), 0).ConfigureAwait(false))
{
return false;
}
connection.Id = serverId;
nodeConnectionTransfer.TryAdd(ConnectionSideType.Master, connection.Id, connection);
@@ -116,7 +126,7 @@ namespace linker.messenger.node
Connection = connection,
MessengerId = MessengerIdSahre,
Payload = serializer.Serialize(store.MasterKey)
});
}).ConfigureAwait(false);
if (resp.Code == MessageResponeCodes.OK)
{
return serializer.Deserialize<string>(resp.Data.Span);
@@ -172,7 +182,7 @@ namespace linker.messenger.node
Connection = connection,
MessengerId = MessengerIdUpdateForward,
Payload = serializer.Serialize(info)
});
}).ConfigureAwait(false);
}
return await nodeStore.Update(info).ConfigureAwait(false);
@@ -192,7 +202,7 @@ namespace linker.messenger.node
Connection = connection,
MessengerId = MessengerIdUpgradeForward,
Payload = serializer.Serialize(new KeyValuePair<string, string>(store.MasterKey, version))
});
}).ConfigureAwait(false);
return true;
}
@@ -209,7 +219,6 @@ namespace linker.messenger.node
public async Task<bool> ExitForward(string nodeId)
{
TStore store = await nodeStore.GetByNodeId(nodeId);
if (store != null && store.Manageable && nodeConnectionTransfer.TryGet(ConnectionSideType.Node, nodeId, out var connection))
{
await messengerSender.SendOnly(new MessageRequestWrap
@@ -217,7 +226,7 @@ namespace linker.messenger.node
Connection = connection,
MessengerId = MessengerIdExitForward,
Payload = serializer.Serialize(new KeyValuePair<string, string>(store.MasterKey, nodeId))
});
}).ConfigureAwait(false);
return true;
}
@@ -232,11 +241,123 @@ namespace linker.messenger.node
return true;
}
/// <summary>
/// 获取节点列表
/// </summary>
/// <param name="super">是否已认证</param>
/// <returns></returns>
public async Task<MastersResponseInfo> MastersForward(MastersRequestInfo info)
{
TStore store = await nodeStore.GetByNodeId(info.NodeId);
if (store != null && store.Manageable && nodeConnectionTransfer.TryGet(ConnectionSideType.Node, info.NodeId, out var connection))
{
info.NodeId = store.MasterKey;
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = connection,
MessengerId = MessengerIdMastersForward,
Payload = serializer.Serialize(info)
}).ConfigureAwait(false);
if (resp.Code == MessageResponeCodes.OK)
{
return serializer.Deserialize<MastersResponseInfo>(resp.Data.Span);
}
}
return new MastersResponseInfo();
}
public async Task<MastersResponseInfo> Masters(MastersRequestInfo info)
{
if (info.NodeId != Config.MasterKey)
{
return new MastersResponseInfo();
}
var connections = nodeConnectionTransfer.Get(ConnectionSideType.Master);
return new MastersResponseInfo
{
Page = info.Page,
Sise = info.Sise,
Count = connections.Count,
List = connections.Skip((info.Page - 1) * info.Sise).Take(info.Sise).Select(c => new MasterConnInfo { Addr = c.Address, NodeId = c.Id }).ToList()
};
}
public async Task<MasterDenyStoreResponseInfo> DenysForward(MasterDenyStoreRequestInfo info)
{
TStore store = await nodeStore.GetByNodeId(info.NodeId);
if (store != null && store.Manageable && nodeConnectionTransfer.TryGet(ConnectionSideType.Node, info.NodeId, out var connection))
{
info.NodeId = store.MasterKey;
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = connection,
MessengerId = MessengerIdDenysForward,
Payload = serializer.Serialize(info)
}).ConfigureAwait(false);
if (resp.Code == MessageResponeCodes.OK)
{
return serializer.Deserialize<MasterDenyStoreResponseInfo>(resp.Data.Span);
}
}
return new MasterDenyStoreResponseInfo();
}
public async Task<MasterDenyStoreResponseInfo> Denys(MasterDenyStoreRequestInfo info)
{
if (info.NodeId != Config.MasterKey)
{
return new MasterDenyStoreResponseInfo();
}
return await nodeMasterDenyStore.Get(info).ConfigureAwait(false);
}
public async Task<bool> DenysAddForward(MasterDenyAddInfo info)
{
TStore store = await nodeStore.GetByNodeId(info.NodeId);
if (store != null && store.Manageable && nodeConnectionTransfer.TryGet(ConnectionSideType.Node, info.NodeId, out var connection))
{
info.NodeId = store.MasterKey;
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = connection,
MessengerId = MessengerIdDenysAddForward,
Payload = serializer.Serialize(info)
}).ConfigureAwait(false);
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
return false;
}
public async Task<bool> DenysAdd(MasterDenyAddInfo info)
{
if (info.NodeId != Config.MasterKey)
{
return false;
}
return await nodeMasterDenyStore.Add(info).ConfigureAwait(false);
}
public async Task<bool> DenysDelForward(MasterDenyDelInfo info)
{
TStore store = await nodeStore.GetByNodeId(info.NodeId);
if (store != null && store.Manageable && nodeConnectionTransfer.TryGet(ConnectionSideType.Node, info.NodeId, out var connection))
{
info.NodeId = store.MasterKey;
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = connection,
MessengerId = MessengerIdDenysDelForward,
Payload = serializer.Serialize(info)
}).ConfigureAwait(false);
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
return false;
}
public async Task<bool> DenysDel(MasterDenyDelInfo info)
{
if (info.NodeId != Config.MasterKey)
{
return false;
}
return await nodeMasterDenyStore.Delete(info).ConfigureAwait(false);
}
public virtual async Task<List<TStore>> GetNodes(bool super, string userid, string machineId)
{
return [];
@@ -256,7 +377,6 @@ namespace linker.messenger.node
{
}
private async Task BuildShareKey()
{
try

View File

@@ -1,8 +1,10 @@
v1.9.7
2025-12-10 17:13:38
2025-12-11 17:30:06
1. 一些累计更新一些BUG修复
2. 重构中继和穿透的多节点模式
3. 中继连接合并到隧道协议中
4. 修复socks代理模块
5. 发布飞牛fpk安装包(docker+bin)
6. 先不要更新,作者测试中
6. 优化虚拟网卡自动连接表现
7. 简化加入分组操作
8. 先不要更新,作者测试中

View File

@@ -18,7 +18,7 @@ slug: /question
3. `Windows 无法验证此文件的数字签名`大概率出现再win7/8可以尝试安装<a href="https://www.microsoft.com/zh-cn/download/details.aspx?id=46148" target="_blank">KB3033929 全球化补丁</a>
4. `group id are empty` 客户端尚未初始化
5. `rtsp`关于rtsp默认使用UDP协议传输音视频在rtsp握手的SETUP阶段报告客户端UDP端口所以在经过NAT后服务端无法正确向客户端发送数据请使用TCP
6. 在windows如果1802-1804端口被占用但是`netstat -ano` 又查不到那可能是hyper-v占用的可以尝试重启winnat服务解决
6. 在windows如果1802-1804端口被占用但是`netstat -ano` 又查不到那可能是hyper-v占用的可以尝试重启winnat服务解决
```
net stop winnat
net start winnat

View File

@@ -1,6 +1,7 @@
using linker.libs;
using linker.libs.extends;
using linker.libs.web;
using linker.messenger.node;
using linker.messenger.relay.messenger;
using linker.messenger.relay.server;
using linker.messenger.signin;
@@ -130,6 +131,55 @@ namespace linker.messenger.relay.client
});
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
public async Task<MastersResponseInfo> Masters(ApiControllerParamsInfo param)
{
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.MastersForward,
Payload = serializer.Serialize(param.Content.DeJson<MastersRequestInfo>())
});
if (resp.Code == MessageResponeCodes.OK)
{
return serializer.Deserialize<MastersResponseInfo>(resp.Data.Span);
}
return new MastersResponseInfo();
}
public async Task<MasterDenyStoreResponseInfo> Denys(ApiControllerParamsInfo param)
{
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.DenysForward,
Payload = serializer.Serialize(param.Content.DeJson<MasterDenyStoreRequestInfo>())
});
if (resp.Code == MessageResponeCodes.OK)
{
return serializer.Deserialize<MasterDenyStoreResponseInfo>(resp.Data.Span);
}
return new MasterDenyStoreResponseInfo();
}
public async Task<bool> DenysAdd(ApiControllerParamsInfo param)
{
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.DenysAddForward,
Payload = serializer.Serialize(param.Content.DeJson<MasterDenyAddInfo>())
});
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
public async Task<bool> DenysDel(ApiControllerParamsInfo param)
{
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)RelayMessengerIds.DenysDelForward,
Payload = serializer.Serialize(param.Content.DeJson<MasterDenyDelInfo>())
});
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
}

View File

@@ -1,5 +1,6 @@

using linker.libs;
using linker.messenger.node;
using linker.messenger.relay.server;
using linker.messenger.relay.server.validator;
using linker.messenger.signin;
@@ -16,7 +17,7 @@ namespace linker.messenger.relay.messenger
public RelayClientMessenger()
{
}
}
/// <summary>
@@ -230,6 +231,91 @@ namespace linker.messenger.relay.messenger
}
[MessengerId((ushort)RelayMessengerIds.MastersForward)]
public async Task MastersForward(IConnection connection)
{
MastersRequestInfo info = serializer.Deserialize<MastersRequestInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo from) == false || from.Super == false)
{
connection.Write(serializer.Serialize(new MastersResponseInfo()));
return;
}
MastersResponseInfo resp = await relayServerNodeReportTransfer.MastersForward(info).ConfigureAwait(false);
connection.Write(serializer.Serialize(resp));
}
[MessengerId((ushort)RelayMessengerIds.Masters)]
public async Task Masters(IConnection connection)
{
MastersRequestInfo info = serializer.Deserialize<MastersRequestInfo>(connection.ReceiveRequestWrap.Payload.Span);
MastersResponseInfo resp = await relayServerNodeReportTransfer.Masters(info).ConfigureAwait(false);
connection.Write(serializer.Serialize(resp));
}
[MessengerId((ushort)RelayMessengerIds.DenysForward)]
public async Task DenysForward(IConnection connection)
{
MasterDenyStoreRequestInfo info = serializer.Deserialize<MasterDenyStoreRequestInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo from) == false || from.Super == false)
{
connection.Write(serializer.Serialize(new MasterDenyStoreResponseInfo()));
return;
}
MasterDenyStoreResponseInfo resp = await relayServerNodeReportTransfer.DenysForward(info).ConfigureAwait(false);
connection.Write(serializer.Serialize(resp));
}
[MessengerId((ushort)RelayMessengerIds.Denys)]
public async Task Denys(IConnection connection)
{
MasterDenyStoreRequestInfo info = serializer.Deserialize<MasterDenyStoreRequestInfo>(connection.ReceiveRequestWrap.Payload.Span);
MasterDenyStoreResponseInfo resp = await relayServerNodeReportTransfer.Denys(info).ConfigureAwait(false);
connection.Write(serializer.Serialize(resp));
}
[MessengerId((ushort)RelayMessengerIds.DenysAddForward)]
public async Task DenysAddForward(IConnection connection)
{
MasterDenyAddInfo info = serializer.Deserialize<MasterDenyAddInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo from) == false || from.Super == false)
{
connection.Write(Helper.FalseArray);
return;
}
bool resp = await relayServerNodeReportTransfer.DenysAddForward(info).ConfigureAwait(false);
connection.Write(resp ? Helper.TrueArray : Helper.FalseArray);
}
[MessengerId((ushort)RelayMessengerIds.DenysAdd)]
public async Task DenysAdd(IConnection connection)
{
MasterDenyAddInfo info = serializer.Deserialize<MasterDenyAddInfo>(connection.ReceiveRequestWrap.Payload.Span);
bool resp = await relayServerNodeReportTransfer.DenysAdd(info).ConfigureAwait(false);
connection.Write(resp ? Helper.TrueArray : Helper.FalseArray);
}
[MessengerId((ushort)RelayMessengerIds.DenysDelForward)]
public async Task DenysDelForward(IConnection connection)
{
MasterDenyDelInfo info = serializer.Deserialize<MasterDenyDelInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo from) == false || from.Super == false)
{
connection.Write(Helper.FalseArray);
return;
}
bool resp = await relayServerNodeReportTransfer.DenysDelForward(info).ConfigureAwait(false);
connection.Write(resp ? Helper.TrueArray : Helper.FalseArray);
}
[MessengerId((ushort)RelayMessengerIds.DenysDel)]
public async Task DenysDel(IConnection connection)
{
MasterDenyDelInfo info = serializer.Deserialize<MasterDenyDelInfo>(connection.ReceiveRequestWrap.Payload.Span);
bool resp = await relayServerNodeReportTransfer.DenysDel(info).ConfigureAwait(false);
connection.Write(resp ? Helper.TrueArray : Helper.FalseArray);
}
[MessengerId((ushort)RelayMessengerIds.NodeReport)]
public async Task NodeReport(IConnection connection)
{
@@ -251,5 +337,9 @@ namespace linker.messenger.relay.messenger
}
connection.Write(serializer.Serialize(VersionHelper.Version));
}
}
}

View File

@@ -28,6 +28,16 @@
UpgradeForward = 2144,
Upgrade = 2145,
MastersForward = 2146,
Masters = 2147,
DenysForward = 2148,
Denys = 2149,
DenysAddForward = 2150,
DenysAdd = 2151,
DenysDelForward = 2152,
DenysDel = 2153,
Max = 2199
}
}

View File

@@ -0,0 +1,8 @@
using linker.messenger.node;
namespace linker.messenger.relay.server
{
public interface IRelayServerMasterDenyStore:INodeMasterDenyStore
{
}
}

View File

@@ -12,6 +12,10 @@ namespace linker.messenger.relay.server
public override ushort MessengerIdExitForward => (ushort)RelayMessengerIds.ExitForward;
public override ushort MessengerIdReport => (ushort)RelayMessengerIds.Report;
public override ushort MessengerIdSignIn => (ushort)RelayMessengerIds.SignIn;
public override ushort MessengerIdMastersForward => (ushort)RelayMessengerIds.MastersForward;
public override ushort MessengerIdDenysForward => (ushort)RelayMessengerIds.DenysForward;
public override ushort MessengerIdDenysAddForward => (ushort)RelayMessengerIds.DenysAddForward;
public override ushort MessengerIdDenysDelForward => (ushort)RelayMessengerIds.DenysDelForward;
private readonly IRelayServerWhiteListStore relayServerWhiteListStore;
private readonly INodeConfigStore<RelayServerConfigInfo> nodeConfigStore;
@@ -21,8 +25,8 @@ namespace linker.messenger.relay.server
public RelayServerNodeReportTransfer(IRelayServerWhiteListStore relayServerWhiteListStore, RelayServerConnectionTransfer nodeConnectionTransfer,
INodeConfigStore<RelayServerConfigInfo> nodeConfigStore,
ISerializer serializer, IMessengerSender messengerSender, INodeStore<RelayServerNodeStoreInfo, RelayServerNodeReportInfo> nodeStore,
IMessengerResolver messengerResolver, ICommonStore commonStore)
: base(nodeConnectionTransfer, nodeConfigStore, serializer, messengerSender, nodeStore, messengerResolver, commonStore)
IMessengerResolver messengerResolver, ICommonStore commonStore,IRelayServerMasterDenyStore relayServerMasterDenyStore)
: base(nodeConnectionTransfer, nodeConfigStore, serializer, messengerSender, nodeStore, messengerResolver, commonStore, relayServerMasterDenyStore)
{
this.relayServerWhiteListStore = relayServerWhiteListStore;
this.nodeConfigStore = nodeConfigStore;

View File

@@ -1,10 +1,11 @@
using linker.libs.extends;
using linker.messenger.signin;
using linker.libs;
using linker.messenger.api;
using linker.libs;
using linker.libs.extends;
using linker.libs.web;
using linker.messenger.sforward.server;
using linker.messenger.api;
using linker.messenger.node;
using linker.messenger.sforward.messenger;
using linker.messenger.sforward.server;
using linker.messenger.signin;
namespace linker.messenger.sforward.client
{
@@ -236,5 +237,54 @@ namespace linker.messenger.sforward.client
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
public async Task<MastersResponseInfo> Masters(ApiControllerParamsInfo param)
{
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)SForwardMessengerIds.MastersForward,
Payload = serializer.Serialize(param.Content.DeJson<MastersRequestInfo>())
});
if (resp.Code == MessageResponeCodes.OK)
{
return serializer.Deserialize<MastersResponseInfo>(resp.Data.Span);
}
return new MastersResponseInfo();
}
public async Task<MasterDenyStoreResponseInfo> Denys(ApiControllerParamsInfo param)
{
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)SForwardMessengerIds.DenysForward,
Payload = serializer.Serialize(param.Content.DeJson<MasterDenyStoreRequestInfo>())
});
if (resp.Code == MessageResponeCodes.OK)
{
return serializer.Deserialize<MasterDenyStoreResponseInfo>(resp.Data.Span);
}
return new MasterDenyStoreResponseInfo();
}
public async Task<bool> DenysAdd(ApiControllerParamsInfo param)
{
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)SForwardMessengerIds.DenysAddForward,
Payload = serializer.Serialize(param.Content.DeJson<MasterDenyAddInfo>())
});
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
public async Task<bool> DenysDel(ApiControllerParamsInfo param)
{
var resp = await messengerSender.SendReply(new MessageRequestWrap
{
Connection = signInClientState.Connection,
MessengerId = (ushort)SForwardMessengerIds.DenysDelForward,
Payload = serializer.Serialize(param.Content.DeJson<MasterDenyDelInfo>())
});
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
}
}
}

View File

@@ -1,6 +1,7 @@
using linker.libs;
using linker.libs.extends;
using linker.libs.timer;
using linker.messenger.node;
using linker.messenger.sforward.client;
using linker.messenger.sforward.server;
using linker.messenger.sforward.server.validator;
@@ -695,6 +696,68 @@ namespace linker.messenger.sforward.messenger
await sForwardServerNodeReportTransfer.Exit(masterKey).ConfigureAwait(false);
}
/// <summary>
/// 信标服务器
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
[MessengerId((ushort)SForwardMessengerIds.MastersForward)]
public async Task MastersForward(IConnection connection)
{
MastersRequestInfo info = serializer.Deserialize<MastersRequestInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo from) == false || from.Super == false)
{
connection.Write(serializer.Serialize(new MastersResponseInfo()));
return;
}
MastersResponseInfo resp = await sForwardServerNodeReportTransfer.MastersForward(info).ConfigureAwait(false);
connection.Write(serializer.Serialize(resp));
}
/// <summary>
/// 节点服务器
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
[MessengerId((ushort)SForwardMessengerIds.Masters)]
public async Task Masters(IConnection connection)
{
MastersRequestInfo info = serializer.Deserialize<MastersRequestInfo>(connection.ReceiveRequestWrap.Payload.Span);
MastersResponseInfo resp = await sForwardServerNodeReportTransfer.Masters(info).ConfigureAwait(false);
connection.Write(serializer.Serialize(resp));
}
/// <summary>
/// 信标服务器
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
[MessengerId((ushort)SForwardMessengerIds.DenysForward)]
public async Task DenysForward(IConnection connection)
{
MasterDenyStoreRequestInfo info = serializer.Deserialize<MasterDenyStoreRequestInfo>(connection.ReceiveRequestWrap.Payload.Span);
if (signCaching.TryGet(connection.Id, out SignCacheInfo from) == false || from.Super == false)
{
connection.Write(serializer.Serialize(new MasterDenyStoreResponseInfo()));
return;
}
MasterDenyStoreResponseInfo resp = await sForwardServerNodeReportTransfer.DenysForward(info).ConfigureAwait(false);
connection.Write(serializer.Serialize(resp));
}
/// <summary>
/// 节点服务器
/// </summary>
/// <param name="connection"></param>
/// <returns></returns>
[MessengerId((ushort)SForwardMessengerIds.Denys)]
public async Task Denys(IConnection connection)
{
MasterDenyStoreRequestInfo info = serializer.Deserialize<MasterDenyStoreRequestInfo>(connection.ReceiveRequestWrap.Payload.Span);
MasterDenyStoreResponseInfo resp = await sForwardServerNodeReportTransfer.Denys(info).ConfigureAwait(false);
connection.Write(serializer.Serialize(resp));
}
/// <summary>

View File

@@ -50,6 +50,16 @@
Proxy = 2352,
ProxyForward = 2353,
MastersForward = 2354,
Masters = 2355,
DenysForward = 2356,
Denys = 2357,
DenysAddForward = 2358,
DenysAdd = 2359,
DenysDelForward = 2360,
DenysDel = 2361,
Max = 2399
}
}

View File

@@ -0,0 +1,8 @@
using linker.messenger.node;
namespace linker.messenger.sforward.server
{
public interface ISForwardServerMasterDenyStore : INodeMasterDenyStore
{
}
}

View File

@@ -12,17 +12,20 @@ namespace linker.messenger.sforward.server
public override ushort MessengerIdExitForward => (ushort)SForwardMessengerIds.ExitForward;
public override ushort MessengerIdReport => (ushort)SForwardMessengerIds.Report;
public override ushort MessengerIdSignIn => (ushort)SForwardMessengerIds.SignIn;
public override ushort MessengerIdMastersForward => (ushort)SForwardMessengerIds.MastersForward;
public override ushort MessengerIdDenysForward => (ushort)SForwardMessengerIds.DenysForward;
public override ushort MessengerIdDenysAddForward => (ushort)SForwardMessengerIds.DenysAddForward;
public override ushort MessengerIdDenysDelForward => (ushort)SForwardMessengerIds.DenysDelForward;
private readonly ISForwardServerWhiteListStore sforwardServerWhiteListStore;
private readonly INodeConfigStore<SForwardServerConfigInfo> nodeConfigStore;
private readonly INodeStore<SForwardServerNodeStoreInfo, SForwardServerNodeReportInfo> nodeStore;
public SForwardServerNodeReportTransfer(ISForwardServerWhiteListStore sforwardServerWhiteListStore, SForwardServerConnectionTransfer nodeConnectionTransfer,
INodeConfigStore<SForwardServerConfigInfo> nodeConfigStore,
ISerializer serializer, IMessengerSender messengerSender, INodeStore<SForwardServerNodeStoreInfo, SForwardServerNodeReportInfo> nodeStore,
IMessengerResolver messengerResolver, ICommonStore commonStore)
: base(nodeConnectionTransfer, nodeConfigStore, serializer, messengerSender, nodeStore, messengerResolver, commonStore)
IMessengerResolver messengerResolver, ICommonStore commonStore,ISForwardServerMasterDenyStore sforwardServerMasterDenyStore)
: base(nodeConnectionTransfer, nodeConfigStore, serializer, messengerSender, nodeStore, messengerResolver, commonStore, sforwardServerMasterDenyStore)
{
this.sforwardServerWhiteListStore = sforwardServerWhiteListStore;
this.nodeConfigStore = nodeConfigStore;

View File

@@ -12,7 +12,7 @@ namespace linker.messenger.signin
#if DEBUG
private string id = Helper.GlobalString;
#else
private string id = string.Empty;
private string id = Guid.NewGuid().ToString();
#endif
public string Id
{
@@ -25,7 +25,7 @@ namespace linker.messenger.signin
#if DEBUG
private string passord = Helper.GlobalString;
#else
private string passord = string.Empty;
private string passord = Guid.NewGuid().ToString();
#endif
public string Password
{

View File

@@ -157,8 +157,12 @@ namespace linker.messenger.signin
{
await signInClientTransfer.CheckSuper().ConfigureAwait(false);
}
}
public sealed class ConfigSetInfo
{

View File

@@ -20,9 +20,10 @@ namespace linker.messenger.signin
private readonly SignInArgsTransfer signInArgsTransfer;
private readonly ISignInClientStore signInClientStore;
private readonly ISerializer serializer;
private readonly ICommonStore commonStore;
public SignInClientTransfer(SignInClientState clientSignInState, IMessengerSender messengerSender, IMessengerResolver messengerResolver,
SignInArgsTransfer signInArgsTransfer, ISignInClientStore signInClientStore, ISerializer serializer)
SignInArgsTransfer signInArgsTransfer, ISignInClientStore signInClientStore, ISerializer serializer, ICommonStore commonStore)
{
this.clientSignInState = clientSignInState;
this.messengerSender = messengerSender;
@@ -30,6 +31,7 @@ namespace linker.messenger.signin
this.signInArgsTransfer = signInArgsTransfer;
this.signInClientStore = signInClientStore;
this.serializer = serializer;
this.commonStore = commonStore;
}
/// <summary>
@@ -105,6 +107,11 @@ namespace linker.messenger.signin
/// <returns></returns>
private async Task<int> SignIn(string host)
{
if(commonStore.Installed == false)
{
LoggerHelper.Instance.Error($"not initialized");
return 1;
}
if (string.IsNullOrWhiteSpace(signInClientStore.Group.Id))
{
LoggerHelper.Instance.Error($"group id are empty");

View File

@@ -56,7 +56,5 @@ namespace linker.messenger.signin.args
}
return await Task.FromResult(string.Empty);
}
}
}

View File

@@ -77,8 +77,8 @@ namespace linker.messenger.store.file
config.Data.Server.SignIn.Anonymous = info.Server.Anonymous;
config.Data.Server.SignIn.SuperKey = info.Server.SuperKey;
config.Data.Server.SignIn.SuperPassword = info.Server.SuperPassword;
config.Data.Server.SForward.WebPort = info.Server.SForward.WebPort;
config.Data.Server.SForward.TunnelPorts = info.Server.SForward.TunnelPorts;
//config.Data.Server.SForward.WebPort = info.Server.SForward.WebPort;
//config.Data.Server.SForward.TunnelPorts = info.Server.SForward.TunnelPorts;
}
config.Data.Common.Modes = info.Common.Modes;
@@ -300,6 +300,61 @@ namespace linker.messenger.store.file
}, common, new { Install = true, Modes = new string[] { "client" } });
}
[Access(AccessValue.Export)]
public string ShareGroup(ApiControllerParamsInfo param)
{
ICrypto crypto = CryptoFactory.CreateSymmetric(Helper.GlobalString);
try
{
return Convert.ToBase64String(crypto.Encode(new ShareGroupInfo
{
Server = config.Data.Client.Server.Host,
Id = config.Data.Client.Group.Id,
Pwd = config.Data.Client.Group.Password
}.ToJson().ToBytes()));
}
catch (Exception)
{
}
finally
{
crypto.Dispose();
}
return string.Empty;
}
public bool JoinGroup(ApiControllerParamsInfo param)
{
ICrypto crypto = CryptoFactory.CreateSymmetric(Helper.GlobalString);
try
{
ShareGroupInfo info = crypto.Decode(Convert.FromBase64String(param.Content)).GetString().DeJson<ShareGroupInfo>();
config.Data.Client.Server.Host = info.Server;
config.Data.Client.Group.Id = info.Id;
config.Data.Client.Group.Password = info.Pwd;
config.Data.Update();
signInClientTransfer.ReSignIn();
return true;
}
catch (Exception)
{
}
finally
{
crypto.Dispose();
}
return false;
}
}
public sealed class ShareGroupInfo
{
public string Server { get; set; }
public string Id { get; set; }
public string Pwd { get; set; }
}
public sealed class GetConfigParamsInfo

View File

@@ -73,7 +73,8 @@ namespace linker.messenger.store.file
serviceCollection.AddSingleton<INodeConfigStore<RelayServerConfigInfo>, RelayServerConfigStore>();
serviceCollection.AddSingleton<INodeStore<RelayServerNodeStoreInfo, RelayServerNodeReportInfo>, RelayServerNodeStore>();
serviceCollection.AddSingleton<IRelayServerWhiteListStore, RelayNodeWhiteListStore>();
serviceCollection.AddSingleton<IRelayServerMasterDenyStore, RelayServerMasterDenyStore>();
serviceCollection.AddSingleton<ITunnelClientStore, TunnelClientStore>();
@@ -101,6 +102,7 @@ namespace linker.messenger.store.file
serviceCollection.AddSingleton<INodeConfigStore<SForwardServerConfigInfo>, SForwardServerConfigStore>();
serviceCollection.AddSingleton<INodeStore<SForwardServerNodeStoreInfo, SForwardServerNodeReportInfo>, SForwardServerNodeStore>();
serviceCollection.AddSingleton<ISForwardServerWhiteListStore, SForwardNodeWhiteListStore>();
serviceCollection.AddSingleton<ISForwardServerMasterDenyStore, SForwardServerMasterDenyStore>();
serviceCollection.AddSingleton<ILoggerStore, LoggerStore>();

View File

@@ -0,0 +1,63 @@
using linker.libs;
using linker.messenger.node;
using LiteDB;
using System.Net;
using IPNetwork = System.Net.IPNetwork;
namespace linker.messenger.store.file.node
{
public class NodeMasterDenyStore : INodeMasterDenyStore
{
public virtual string StoreName => "relay";
protected readonly ILiteCollection<MasterDenyStoreInfo> liteCollection;
public NodeMasterDenyStore(Storefactory storefactory)
{
liteCollection = storefactory.GetCollection<MasterDenyStoreInfo>($"{StoreName}_server_master_deny");
}
public async Task<bool> Add(MasterDenyAddInfo info)
{
IPNetwork net = info.Str.AsSpan().IndexOf('/') < 0 ? new IPNetwork(IPAddress.Parse(info.Str), 32) : IPNetwork.Parse(info.Str);
uint ip = NetworkHelper.ToValue(net.BaseAddress);
uint prefixValue = NetworkHelper.ToPrefixValue((byte)net.PrefixLength);
uint network = NetworkHelper.ToNetworkValue(ip, prefixValue);
uint broadcast = NetworkHelper.ToBroadcastValue(ip, prefixValue);
liteCollection.Insert(new MasterDenyStoreInfo
{
Str = info.Str,
Ip = ip,
Plus = broadcast - network,
Remark = info.Remark,
});
return true;
}
public async Task<bool> Delete(MasterDenyDelInfo info)
{
return liteCollection.Delete(info.Id);
}
public async Task<MasterDenyStoreResponseInfo> Get(MasterDenyStoreRequestInfo request)
{
var query = liteCollection.FindAll();
if (string.IsNullOrWhiteSpace(request.Str) == false)
{
query = query.Where(c => (string.IsNullOrWhiteSpace(c.Str) == false && c.Str.Contains(request.Str)) || string.IsNullOrWhiteSpace(c.Remark) == false && c.Remark.Contains(request.Str));
}
return new MasterDenyStoreResponseInfo
{
Page = request.Page,
Sise = request.Sise,
Count = query.Count(),
List = query.Skip((request.Page - 1) * request.Sise).Take(request.Sise).ToList()
};
}
public async Task<bool> Get(uint ip, int plus)
{
return liteCollection.Find(c => ip >= c.Ip && ip <= c.Ip + c.Plus).Any();
}
}
}

View File

@@ -5,8 +5,9 @@ namespace linker.messenger.store.file.relay
{
public class RelayNodeWhiteListStore : node.NodeWhiteListStore, IRelayServerWhiteListStore
{
public override string TypeName => "Relay";
public RelayNodeWhiteListStore(IWhiteListServerStore whiteListServerStore) : base(whiteListServerStore) { }
public override string TypeName => "Relay";
}
}

View File

@@ -0,0 +1,12 @@
using linker.messenger.relay.server;
using linker.messenger.store.file.node;
namespace linker.messenger.store.file.relay
{
public class RelayServerMasterDenyStore : NodeMasterDenyStore, IRelayServerMasterDenyStore
{
public override string StoreName => "relay";
public RelayServerMasterDenyStore(Storefactory storefactory) : base(storefactory)
{ }
}
}

View File

@@ -6,8 +6,9 @@ namespace linker.messenger.store.file.sforward
{
public class SForwardNodeWhiteListStore : node.NodeWhiteListStore, ISForwardServerWhiteListStore
{
public override string TypeName => "SForward";
public SForwardNodeWhiteListStore(IWhiteListServerStore whiteListServerStore) : base(whiteListServerStore) { }
public override string TypeName => "SForward";
}
}

View File

@@ -0,0 +1,12 @@
using linker.messenger.sforward.server;
using linker.messenger.store.file.node;
namespace linker.messenger.store.file.sforward
{
public class SForwardServerMasterDenyStore : NodeMasterDenyStore, ISForwardServerMasterDenyStore
{
public override string StoreName => "sforward";
public SForwardServerMasterDenyStore(Storefactory storefactory) :base(storefactory)
{ }
}
}

View File

@@ -1,9 +1,7 @@
using linker.libs.extends;
using linker.messenger.node;
using linker.messenger.relay.server;
using linker.messenger.sforward.server;
using linker.messenger.store.file.node;
using LiteDB;
namespace linker.messenger.store.file.sforward
{

View File

@@ -21,4 +21,10 @@ export const copyConfig = (data) => {
}
export const saveConfig = (data) => {
return sendWebsocketMsg('config/save', data);
}
export const shareGroup = () => {
return sendWebsocketMsg('config/sharegroup');
}
export const joinGroup = (data) => {
return sendWebsocketMsg('config/joingroup', data);
}

View File

@@ -29,4 +29,16 @@ export const relayImport = (data) => {
}
export const relayShare = (id) => {
return sendWebsocketMsg('relay/Share', id);
}
export const relayMasters = (data) => {
return sendWebsocketMsg('relay/Masters', data);
}
export const relayDenys = (data) => {
return sendWebsocketMsg('relay/Denys', data);
}
export const relayDenysAdd = (data) => {
return sendWebsocketMsg('relay/DenysAdd', data);
}
export const relayDenysDel = (data) => {
return sendWebsocketMsg('relay/DenysDel', data);
}

View File

@@ -44,4 +44,16 @@ export const sforwardImport = (data) => {
}
export const sforwardShare = (id) => {
return sendWebsocketMsg('sforward/Share', id);
}
export const sforwardMasters = (data) => {
return sendWebsocketMsg('sforward/Masters', data);
}
export const sforwardDenys = (data) => {
return sendWebsocketMsg('sforward/Denys', data);
}
export const sforwardDenysAdd = (data) => {
return sendWebsocketMsg('sforward/DenysAdd', data);
}
export const sforwardDenysDel = (data) => {
return sendWebsocketMsg('sforward/DenysDel', data);
}

View File

@@ -11,6 +11,7 @@ export default {
'common.relay': 'Relay',
'common.p2p': 'P2P',
'common.refresh': 'Refresh',
'common.copied': 'Copied',
'head.home': 'Home',
'head.server': 'Server',
@@ -85,6 +86,8 @@ export default {
'permission.clear': 'Clear connection',
'status.group': 'Group manager',
'status.groupShare': 'Group share',
'status.groupPlus': 'Group join',
'status.groupName': 'Name',
'status.groupPassword': 'Password',
'status.groupOper': 'Oper',
@@ -349,6 +352,10 @@ export default {
'server.sforwardLogo': 'Logo',
'server.sforwardHost': 'Host',
'server.denyTitle':'connections on 【{0}】',
'server.denyMasters':'Online',
'server.denyList':'Deny list',
'server.updater':'Updater',
'server.updaterSecretKey': 'Server update secretKey',
'server.updaterSync2Server': 'Auto update to server version',

View File

@@ -11,6 +11,7 @@ export default {
'common.relay': '中继',
'common.p2p': '打洞',
'common.refresh': '刷新',
'common.copied': '已复制',
'head.home': '首页',
'head.server': '服务器',
@@ -86,6 +87,8 @@ export default {
'permission.clear': '清除连接',
'status.group': '管理分组',
'status.groupShare': '分享分组',
'status.groupPlus': '加入分组',
'status.groupName': '名称',
'status.groupPassword': '密码',
'status.groupOper': '操作',
@@ -440,6 +443,10 @@ export default {
'server.sforwardLogo': 'Logo',
'server.sforwardHost': '主机',
'server.denyTitle':'【{0}】上的主机',
'server.denyMasters':'在线的主机',
'server.denyList':'禁用列表',
'server.updater': '更新',
'server.updaterSecretKey': '服务器更新密钥',
'server.updaterSync2Server': '自动更新到服务器版本',

View File

@@ -24,7 +24,7 @@
</div>
<div class="flex-1">
<p class="flex">
<el-badge @click.stop type="success" :value="scope.row.MasterCount" :offset="[20, 10]">
<el-badge @click="handleDeny(scope.row)" type="success" :value="scope.row.MasterCount" :offset="[20, 10]">
<a :href="scope.row.Url" class="a-line" target="_blank">
<strong>{{ scope.row.Name }}</strong>
</a>
@@ -112,6 +112,7 @@
</div>
</el-dialog>
<EditNode v-if="state.showEdit" v-model="state.showEdit" :data="state.current"></EditNode>
<NodeDeny v-model="state.showDeny" v-if="state.showDeny" type="sforward" :data="state.current"></NodeDeny>
</div>
</template>
<script>
@@ -122,11 +123,11 @@ import { computed, onUnmounted, reactive, ref, watch } from 'vue'
import { useI18n } from 'vue-i18n';
import EditNode from './EditNode.vue';
import { Edit,ArrowDown,Refresh,CircleClose,Plus,Share } from '@element-plus/icons-vue';
import NodeDeny from '../node/Index.vue'
export default {
props: ['modelValue','data'],
emits: ['update:modelValue','success'],
components:{EditNode,Edit,ArrowDown,Refresh,CircleClose,Plus,Share},
components:{EditNode,Edit,ArrowDown,Refresh,CircleClose,Plus,Share,NodeDeny},
setup(props,{emit}) {
const {t} = useI18n();
const globalData = injectGlobalData();
@@ -136,7 +137,9 @@ export default {
showEdit:false,
current:{},
super:computed(()=>globalData.value.signin.Super)
super:computed(()=>globalData.value.signin.Super),
showDeny:false
});
watch(() => state.show, (val) => {
if (!val) {
@@ -228,11 +231,16 @@ export default {
});
}
const handleDeny = (row)=>{
state.current = row;
state.showDeny = true;
}
onUnmounted(()=>{
clearTimeout(state.timer);
});
return {globalData,state,handleEdit,handleExit,handleUpgrade,handleRemove,handleImport,handleShare}
return {globalData,state,handleEdit,handleExit,handleUpgrade,handleRemove,handleImport,handleShare,handleDeny}
}
}
</script>

View File

@@ -6,12 +6,14 @@
<el-icon class="right"><ArrowDown /></el-icon>
</span>
<template #dropdown>
<AccessShow value="Group">
<el-dropdown-menu>
<el-dropdown-item v-for="item in state.groups" @click="handleGroupChange(item.Id)">{{item.Name || '未知'}}</el-dropdown-item>
<el-dropdown-item @click="state.showGroups = true">{{$t('status.group')}}</el-dropdown-item>
</el-dropdown-menu>
</AccessShow>
<el-dropdown-menu>
<AccessShow value="Group">
<el-dropdown-item v-for="item in state.groups" @click="handleGroupChange(item.Id)">{{item.Name || '未知'}}</el-dropdown-item>
<el-dropdown-item @click="handleGroups"><el-icon><Setting /></el-icon>{{$t('status.group')}}</el-dropdown-item>
<el-dropdown-item @click="handleShare"><el-icon><Share /></el-icon>{{$t('status.groupShare')}}</el-dropdown-item>
</AccessShow>
<el-dropdown-item @click="handleJoin"><el-icon><Plus /></el-icon>{{$t('status.groupPlus')}}</el-dropdown-item>
</el-dropdown-menu>
</template>
</el-dropdown>
<Groups v-if="state.showGroups" v-model="state.showGroups"></Groups>
@@ -19,13 +21,14 @@
<script>
import { setSignIn } from '@/apis/signin';
import { injectGlobalData } from '@/provide';
import { ElMessage } from 'element-plus';
import { ElMessage, ElMessageBox } from 'element-plus';
import { computed, reactive, ref } from 'vue';
import {ArrowDown,Avatar} from '@element-plus/icons-vue'
import {ArrowDown,Avatar,Setting,Share,Plus} from '@element-plus/icons-vue'
import { useI18n } from 'vue-i18n';
import Groups from './Groups.vue';
import { joinGroup, shareGroup } from '@/apis/config';
export default {
components:{ArrowDown,Avatar,Groups},
components:{ArrowDown,Avatar,Groups,Setting,Share,Plus},
props:['config'],
setup(props) {
const { t } = useI18n();
@@ -66,8 +69,45 @@ export default {
ElMessage.error(t('common.operFail'));
});
}
const handleGroups = ()=>{
state.showGroups = true;
}
const handleShare = ()=>{
shareGroup().then((res)=>{
if(res){
navigator.clipboard.writeText(res);
ElMessage.success(t('common.copied'));
}else{
ElMessage.error(t('common.operFail'));
}
}).catch(()=>{
ElMessage.error(t('common.operFail'));
})
}
const handleJoin = ()=>{
ElMessageBox.prompt(t('status.groupPlus'), t('common.tips'), {
confirmButtonText: t('common.confirm'),
cancelButtonText: t('common.cancel'),
}).then(({ value }) => {
joinGroup(value).then((res)=>{
if(res){
ElMessage.success(t('common.oper'));
setTimeout(()=>{
window.location.reload();
},1000);
}else{
ElMessage.error(t('common.operFail'));
}
}).catch(()=>{
ElMessage.error(t('common.operFail'));
})
}).catch(() => {
})
}
return {
config:props.config,state,handleGroupChange
state,handleGroupChange,handleGroups,handleShare,handleJoin
}
}
}
@@ -80,7 +120,7 @@ export default {
color:green;font-weight:bold;
}
.el-icon{
vertical-align:bottom;
vertical-align:top;
}
}

View File

@@ -0,0 +1,20 @@
<template>
<div>
</div>
</template>
<script>
export default {
props: ['type','data'],
setup () {
return {}
}
}
</script>
<style lang="stylus" scoped>
</style>

View File

@@ -0,0 +1,39 @@
<template>
<el-dialog v-model="state.show" :title="$t('server.denyTitle',[data.Name])" top="1vh" width="400">
<div>
<el-tabs type="border-card">
<el-tab-pane :label="$t('server.denyMasters')"><Masters :type="type" :data="data"></Masters></el-tab-pane>
<el-tab-pane :label="$t('server.denyList')"><Denys :type="type" :data="data"></Denys></el-tab-pane>
</el-tabs>
</div>
</el-dialog>
</template>
<script>
import { reactive, watch } from 'vue';
import Masters from './Masters.vue';
import Denys from './Denys.vue';
export default {
props: ['type','data','modelValue'],
emits: ['update:modelValue'],
components: {Masters,Denys},
setup (props,{emit}) {
const state = reactive({
show: true
});
watch(() => state.show, (val) => {
if (!val) {
setTimeout(() => {
emit('update:modelValue', val);
}, 300);
}
});
return {state}
}
}
</script>
<style lang="stylus" scoped>
</style>

View File

@@ -0,0 +1,70 @@
<template>
<div>
<el-table :data="state.request.List" stripe border size="small" width="100%">
<el-table-column prop="Addr" label="IP"></el-table-column>
</el-table>
<div class="page t-c">
<div class="page-wrap">
<el-pagination small background layout="total,prev,pager, next" :total="state.request.Count"
:page-size="state.request.Size" :current-page="state.request.Page" @current-change="handlePageChange"/>
</div>
</div>
</div>
</template>
<script>
import { relayMasters } from '@/apis/relay';
import { sforwardMasters } from '@/apis/sforward';
import { onMounted, reactive } from 'vue';
export default {
props: ['type','data'],
setup (props,{emit}) {
const getDataFn = props.type == 'relay' ? relayMasters : sforwardMasters;
const state = reactive({
request:{
Page: 1,
Size: 10,
Count:0,
List:[]
}
});
const getData = ()=>{
getDataFn(state.request).then(res=>{
state.request.Page = res.Page;
state.request.Size = res.Size;
state.request.Count = res.Count;
state.request.List = res.List;
})
}
const handlePageChange = (page)=>{
if (page) {
state.request.Page = page;
}
getData();
}
onMounted(()=>{
getData();
});
return {state,handlePageChange}
}
}
</script>
<style lang="stylus" scoped>
.head{
padding-bottom:1rem;
text-align:center;
.el-input{width:20rem}
}
.page{padding-top:1rem}
.page-wrap{
display:inline-block;
}
</style>

View File

@@ -24,7 +24,7 @@
</div>
<div class="flex-1">
<p class="flex">
<el-badge @click.stop type="success" :value="scope.row.MasterCount" :offset="[20, 10]">
<el-badge @click="handleDeny(scope.row)" type="success" :value="scope.row.MasterCount" :offset="[20, 10]">
<a :href="scope.row.Url" class="a-line" :class="{green:scope.row.Public}" target="_blank" >
<strong>{{ scope.row.Name }}</strong>
</a>
@@ -128,6 +128,7 @@
</div>
</div>
</el-dialog>
<NodeDeny v-model="state.showDeny" v-if="state.showDeny" type="relay" :data="state.current"></NodeDeny>
</div>
</template>
<script>
@@ -139,11 +140,11 @@ import { useI18n } from 'vue-i18n';
import Ids from '../sync/Ids.vue';
import EditNode from './EditNode.vue';
import { Edit,ArrowDown,Refresh,CircleClose,Plus,Share } from '@element-plus/icons-vue';
import NodeDeny from '../node/Index.vue'
export default {
props: ['modelValue','data'],
emits: ['update:modelValue','success'],
components:{Ids,EditNode,Edit,ArrowDown,Refresh,CircleClose,Plus,Share},
components:{Ids,EditNode,Edit,ArrowDown,Refresh,CircleClose,Plus,Share,NodeDeny},
setup(props,{emit}) {
const {t} = useI18n();
const globalData = injectGlobalData();
@@ -158,7 +159,9 @@ export default {
Key:'',
Value:0
},
super:computed(()=>globalData.value.signin.Super)
super:computed(()=>globalData.value.signin.Super),
showDeny:false
});
watch(() => state.show, (val) => {
if (!val) {
@@ -280,6 +283,10 @@ export default {
ElMessage.error(t('common.operFail'));
});
}
const handleDeny = (row)=>{
state.current = row;
state.showDeny = true;
}
onMounted(()=>{
_getDefault();
@@ -290,7 +297,7 @@ export default {
return {globalData,state,
handleEdit,domIds,handleShowSync,handleSync,handleCancelSync,
handleExit,handleUpgrade,handleRemove,handleImport,handleShare}
handleExit,handleUpgrade,handleRemove,handleImport,handleShare,handleDeny}
}
}
</script>

View File

@@ -6,7 +6,7 @@
:title="$t('status.apiAlterConfirm')" @cancel="handleShow" @confirm="handleResetConnect" >
<template #reference>
<a href="javascript:;">
<el-icon size="16"><Tools /></el-icon>
<el-icon size="16"><Flag /></el-icon>
<span>{{$t('status.api')}}</span>
</a>
</template>
@@ -17,9 +17,9 @@
import {injectGlobalData} from '@/provide'
import { computed} from 'vue';
import { initWebsocket,closeWebsocket } from '@/apis/request'
import {Tools} from '@element-plus/icons-vue'
import {Flag} from '@element-plus/icons-vue'
export default {
components:{Tools},
components:{Flag},
props:['config'],
setup(props) {
const globalData = injectGlobalData();

View File

@@ -1,11 +1,7 @@
<template>
<div class="status-wrap flex">
<div class="copy flex">
<a href="javascript:;" class="memory" :title="$t('status.support')" @click="state.showPay = true">
<!-- <a href="https://afdian.com/a/snltty" class="memory" :title="$t('status.support')" target="_blank"> -->
<img src="@/assets/dianchi.svg" alt="memory" />
<span>{{$t('status.support')}}</span>
</a>
<Support></Support>
<a href="javascript:;">©linker {{ self.Version }}</a>
<PcShow>
<a href="https://github.com/snltty/linker" target="_blank">Github</a>
@@ -14,46 +10,27 @@
</PcShow>
</div>
<div class="flex-1"></div>
<div class="export"><Export :config="config"></Export></div>
<PcShow>
<div class="api"><Api :config="config"></Api></div>
</PcShow>
<div class="server"><Server :config="config"></Server></div>
<el-dialog v-model="state.showPay" :title="$t('status.support')" width="80%">
<div class="pay">
<p class="t-c">
<a href="https://afdian.com/a/snltty" class="memory a-line" :title="$t('status.support')" target="_blank">
<img src="@/assets/dianchi.svg" alt="memory" />
<span>{{$t('status.support')}}</span>
</a>
</p>
<p class="t-c">
OR
</p>
<p>
<img src="@/assets/pay.jpg" alt="pay" width="100%"/>
</p>
</div>
</el-dialog>
</div>
</template>
<script>
import { computed, reactive } from 'vue';
import Api from './Api.vue'
import Server from './server/Index.vue'
import Export from './Export.vue'
import UpdaterBtn from '../updater/UpdaterBtn.vue';
import { injectGlobalData } from '@/provide';
import Support from './Support.vue';
export default {
components:{Api,Server,Export,UpdaterBtn},
components:{Api,Server,UpdaterBtn,Support},
props:['config'],
setup(props) {
const globalData = injectGlobalData();
const self = computed(()=>globalData.value.self);
const state = reactive({
showPay:false
});
return {
state,config:props.config,self
@@ -78,9 +55,6 @@ html.dark .status-wrap .copy a{color:#ccc;}
a{color:#555;margin-right:1rem}
}
a.memory{
img{height:2rem;vertical-align:sub;margin-right:.1rem;}
margin-right:.6rem;
}
}
</style>

View File

@@ -0,0 +1,42 @@
<template>
<a href="javascript:;" class="memory" :title="$t('status.support')" @click="state.showPay = true">
<img src="@/assets/dianchi.svg" alt="memory" />
<span>{{$t('status.support')}}</span>
</a>
<el-dialog v-model="state.showPay" :title="$t('status.support')" width="80%">
<div class="pay">
<p class="t-c">
<a href="https://afdian.com/a/snltty" class="memory a-line" :title="$t('status.support')" target="_blank">
<img src="@/assets/dianchi.svg" alt="memory" />
<span>{{$t('status.support')}}</span>
</a>
</p>
<p class="t-c">
OR
</p>
<p>
<img src="@/assets/pay.jpg" alt="pay" width="100%"/>
</p>
</div>
</el-dialog>
</template>
<script>
import { reactive } from 'vue';
export default {
setup () {
const state = reactive({
showPay:false
});
return {state}
}
}
</script>
<style lang="stylus" scoped>
a.memory{
img{height:2rem;vertical-align:sub;margin-right:.1rem;}
margin-right:.6rem;
}
</style>

View File

@@ -1,7 +1,13 @@
<template>
<div class="signin-wrap" :style="{height:`${state.height}px`}">
<el-card shadow="never">
<template #header>{{$t('server.messenger')}}</template>
<template #header>
<div class="flex">
<span>{{$t('server.messenger')}}</span>
<span class="flex-1"></span>
<Export></Export>
</div>
</template>
<div>
<el-form label-width="auto" :label-position="state.position">
<el-form-item :label="$t('server.messengerAddr')">
@@ -68,9 +74,9 @@ import SForwardServers from '../../../components/forward/Config.vue';
import { useI18n } from 'vue-i18n';
import Sync from '../../../components/sync/Index.vue'
import WhiteList from '../../../components/wlist/Index.vue';
import Export from './Export.vue';
export default {
components:{Updater,RelayServers,SForwardServers,Sync,WhiteList},
components:{Updater,RelayServers,SForwardServers,Sync,WhiteList,Export},
setup(props) {
const {t} = useI18n();
const globalData = injectGlobalData();

View File

@@ -1,7 +1,7 @@
<template>
<AccessShow value="Export">
<div v-if="config" class="status-export-wrap">
<a href="javascript:;" :title="$t('status.export')" @click="state.show = true">
<div class="status-export-wrap">
<a href="javascript:;" class="a-line" :title="$t('status.export')" @click="state.show = true">
<el-icon size="16"><Share /></el-icon>
<PcShow>
<span>{{$t('status.export')}}</span>
@@ -93,11 +93,10 @@ import {Share} from '@element-plus/icons-vue'
import { exportConfig,copyConfig,saveConfig } from '@/apis/config';
import { ElMessage } from 'element-plus';
import { injectGlobalData } from '@/provide';
import Access from '../accesss/Access.vue'
import Access from '../../../components/accesss/Access.vue'
import { useI18n } from 'vue-i18n'
export default {
components:{Share,Access},
props:['config'],
setup(props) {
const { t } = useI18n();
@@ -257,7 +256,7 @@ export default {
}
}
return {globalData,config:props.config,onlyNode, state,accessDom,
return {globalData,onlyNode, state,accessDom,
handleSave,handleExport,handleCopy,copyToClipboard,copySaveToClipboard};
}
}

View File

@@ -9,14 +9,13 @@
</el-form-item>
</el-col>
<el-col :span="12">
<el-form-item label="web穿透端口" prop="webPort">
<el-input v-trim v-model="state.form.webPort" />
</el-form-item>
<el-col :span="12">
<el-form-item label="匿名登录" prop="anonymous">
<el-checkbox v-model="state.form.anonymous">匿名登录</el-checkbox>
</el-form-item>
</el-col>
</el-col>
</el-row>
</el-form-item>
<el-form-item label="穿透端口" prop="TunnelPorts">
<el-input v-trim v-model="state.form.TunnelPorts" />
</el-form-item>
<el-form-item label="" label-width="0">
<el-row>
@@ -32,18 +31,6 @@
</el-col>
</el-row>
</el-form-item>
<el-form-item label="" label-width="0">
<el-row>
<el-col :span="12">
<el-form-item label="匿名登录" prop="anonymous">
<el-checkbox v-model="state.form.anonymous">匿名登录</el-checkbox>
</el-form-item>
</el-col>
<el-col :span="12">
</el-col>
</el-row>
</el-form-item>
</el-form>
</div>
</template>

View File

@@ -24,7 +24,9 @@
3. 中继连接合并到隧道协议中
4. 修复socks代理模块
5. 发布飞牛fpk安装包(docker+bin)
6. 先不要更新,作者测试中</Description>
6. 优化虚拟网卡自动连接表现
7. 简化加入分组操作
8. 先不要更新,作者测试中</Description>
<Copyright>snltty</Copyright>
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>