mirror of
https://github.com/snltty/linker.git
synced 2025-10-06 01:26:54 +08:00
cdkey
This commit is contained in:
2
.github/workflows/dotnet.yml
vendored
2
.github/workflows/dotnet.yml
vendored
@@ -35,7 +35,7 @@ jobs:
|
||||
release_name: v1.6.9.${{ steps.date.outputs.today }}
|
||||
draft: false
|
||||
prerelease: false
|
||||
body: "1. 修复litedb抢锁超时导致客户端登录失败问题\r\n2. 同步信标服务器\r\n3. 其它一些修复优化"
|
||||
body: "1. 优化linux下路由跟踪问题\r\n2. 优化linux下获取本机IP问题\r\n3. 增加ICS,让win7+、win server2008+支持NAT\r\n4. 增加中继卡密\r\n5. 增加内外穿透定时开关功能\r\n6. 优化管理页面连接接口的体验\r\n7. 优化一些UI体验,去除同步页面,将同步功能放置各个实际的位置\r\n8. 其它一些修复优化"
|
||||
- name: publish projects
|
||||
run: ./publish.bat
|
||||
- name: upload-win-x86-oss
|
||||
|
@@ -57,10 +57,11 @@ sidebar_position: 1
|
||||
:::
|
||||
|
||||
:::danger[win10以下]
|
||||
1. win7 或 win8 可能需要安装一些环境,才能运行
|
||||
2. <a href="https://aka.ms/vs/16/release/vc_redist.x64.exe" target="_blank">Microsoft Visual C++ 2015-2019 Redistributable </a>
|
||||
3. <a href="https://www.microsoft.com/download/details.aspx?id=47442" target="_blank">KB3063858 </a>
|
||||
4. <a href="https://www.microsoft.com/zh-cn/download/details.aspx?id=46148" target="_blank">KB3033929 </a>
|
||||
1. win7、win8、win server 2008、win server 2008 R2 可能需要安装一些环境,才能运行
|
||||
2. <a href="https://aka.ms/vs/16/release/vc_redist.x64.exe" target="_blank">Microsoft Visual C++ 2015-2019 Redistributable 运行库</a>
|
||||
3. <a href="https://www.microsoft.com/download/details.aspx?id=47442" target="_blank">KB3063858 运行库</a>
|
||||
4. <a href="https://www.microsoft.com/zh-cn/download/details.aspx?id=46148" target="_blank">KB3033929 全球化补丁</a>
|
||||
5. <a href="https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/thank-you/net462-web-installer" target="_blank">netframework4.6.2 ICS NAT运行库</a>
|
||||
|
||||
:::
|
||||
|
||||
|
@@ -1,24 +0,0 @@
|
||||
---
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
# 1.1.2、RRAS
|
||||
|
||||
:::tip[说明]
|
||||
1. 操作不当可能会导致网络无法访问,请谨慎操作
|
||||
2. 有局限性,创建虚拟网卡后,需要重新`“配置并启用路由和远程访问”`
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
:::
|
@@ -1,12 +1,11 @@
|
||||
---
|
||||
sidebar_position: 5
|
||||
sidebar_position: 4
|
||||
---
|
||||
|
||||
# 1.1.3、ICS
|
||||
|
||||
:::tip[说明]
|
||||
1. 操作不当可能会导致网络无法访问,请谨慎操作
|
||||
|
||||

|
||||
|
||||
1. 如果系统没有<a href="https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/thank-you/net462-web-installer" target="_blank">netframework4.6.2</a>,就下载安装一下
|
||||
2. 需要linker v1.7.0+版本
|
||||
3. 剩下的交给linker
|
||||
:::
|
@@ -1,5 +1,5 @@
|
||||
---
|
||||
sidebar_position: 6
|
||||
sidebar_position: 5
|
||||
---
|
||||
|
||||
# 1.2、网对网
|
||||
|
@@ -80,12 +80,9 @@ namespace linker.libs
|
||||
proc.StandardInput.WriteLine("exit");
|
||||
proc.StandardInput.Close();
|
||||
|
||||
string output = proc.StandardOutput.ReadToEnd();
|
||||
error = proc.StandardError.ReadToEnd();
|
||||
string output = string.Empty;
|
||||
if (string.IsNullOrWhiteSpace(error))
|
||||
{
|
||||
output = proc.StandardOutput.ReadToEnd();
|
||||
}
|
||||
|
||||
proc.WaitForExit();
|
||||
proc.Close();
|
||||
proc.Dispose();
|
||||
|
@@ -142,7 +142,7 @@ namespace linker.libs
|
||||
{
|
||||
result = new List<IPAddress>();
|
||||
|
||||
string str = CommandHelper.Linux(string.Empty, new string[] { $"traceroute {server} -4 -m 5" });
|
||||
string str = CommandHelper.Linux(string.Empty, new string[] { $"traceroute {server} -4 -m 5 -w 1" });
|
||||
string[] lines = str.Split(Environment.NewLine);
|
||||
|
||||
Regex regex = new Regex(@"(\d+\.\d+\.\d+\.\d+)");
|
||||
@@ -191,34 +191,42 @@ namespace linker.libs
|
||||
|
||||
|
||||
private static byte[] ipv6LocalBytes = new byte[] { 254, 128, 0, 0, 0, 0, 0, 0 };
|
||||
public static IPAddress[] GetIPV6()
|
||||
|
||||
private static IPAddress[] GetIP()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Dns.GetHostAddresses(Dns.GetHostName())
|
||||
.Where(c => c.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
.Where(c => c.GetAddressBytes().AsSpan(0, 8).SequenceEqual(ipv6LocalBytes) == false).Distinct().ToArray();
|
||||
return Dns.GetHostEntry(Dns.GetHostName()).AddressList;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
try
|
||||
{
|
||||
return NetworkInterface.GetAllNetworkInterfaces()
|
||||
.SelectMany(c => c.GetIPProperties().UnicastAddresses)
|
||||
.Select(c => c.Address)
|
||||
.ToArray();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
return Array.Empty<IPAddress>();
|
||||
}
|
||||
public static IPAddress[] GetIPV6()
|
||||
{
|
||||
return GetIP()
|
||||
.Where(c => c.AddressFamily == AddressFamily.InterNetworkV6)
|
||||
.Where(c => c.GetAddressBytes().AsSpan(0, 8).SequenceEqual(ipv6LocalBytes) == false).Distinct().ToArray(); ;
|
||||
}
|
||||
public static IPAddress[] GetIPV4()
|
||||
{
|
||||
try
|
||||
{
|
||||
return Dns.GetHostEntry(Dns.GetHostName()).AddressList
|
||||
.Where(c => c.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork)
|
||||
return GetIP()
|
||||
.Where(c => c.AddressFamily == AddressFamily.InterNetwork)
|
||||
.Where(c => c.IsIPv4MappedToIPv6 == false)
|
||||
.Where(c => c.Equals(IPAddress.Loopback) == false)
|
||||
.Distinct().ToArray();
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
return Array.Empty<IPAddress>();
|
||||
}
|
||||
|
||||
public static byte ToPrefixLength(uint ip)
|
||||
{
|
||||
|
@@ -51,6 +51,13 @@ namespace linker.libs.api
|
||||
{
|
||||
header.SetHeaderValue(WebsocketHeaderKey.SecWebSocketExtensions, string.Empty);
|
||||
}
|
||||
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
{
|
||||
header.TryGetHeaderValue(WebsocketHeaderKey.SecWebSocketProtocol, out string _password1);
|
||||
LoggerHelper.Instance.Info($"websocket client password {_password1} eq {password}");
|
||||
}
|
||||
|
||||
return res;
|
||||
};
|
||||
server.OnOpen = (connection) =>
|
||||
|
@@ -313,6 +313,8 @@ namespace linker.libs.websocket
|
||||
{
|
||||
token.Connectrion.SendFrameClose(WebSocketFrameInfo.EnumCloseStatus.ExtendsError);
|
||||
token.Connectrion.Close();
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Error($"websocket opcode error:{token.FrameInfo.Opcode}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -356,6 +358,8 @@ namespace linker.libs.websocket
|
||||
header.StatusCode = HttpStatusCode.MethodNotAllowed;
|
||||
token.Connectrion.ConnectResponse(header);
|
||||
token.Connectrion.Close();
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Error("websocket SecWebSocketKey error");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -370,6 +374,8 @@ namespace linker.libs.websocket
|
||||
header.StatusCode = HttpStatusCode.Unauthorized;
|
||||
token.Connectrion.ConnectResponse(header);
|
||||
token.Connectrion.Close();
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Error("websocket OnConnecting false");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -479,6 +485,9 @@ namespace linker.libs.websocket
|
||||
{
|
||||
Disposabled = true;
|
||||
Connectrion.Close();
|
||||
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
LoggerHelper.Instance.Error($"websocket connection clear");
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -136,6 +136,9 @@
|
||||
[AccessDisplay("重置所有接口密码")]
|
||||
SetApiPasswordOther = (ulong)1 << 42,
|
||||
|
||||
[AccessDisplay("管理中继CDKEY")]
|
||||
RelayCdkey = (ulong)1 << 43,
|
||||
|
||||
Full = ulong.MaxValue >> 64 - 52,
|
||||
}
|
||||
|
||||
|
@@ -1,9 +1,12 @@
|
||||
using linker.libs.api;
|
||||
using linker.libs;
|
||||
using linker.libs.api;
|
||||
using linker.libs.extends;
|
||||
using linker.messenger.api;
|
||||
using linker.messenger.relay.client;
|
||||
using linker.messenger.relay.client.transport;
|
||||
using linker.messenger.relay.messenger;
|
||||
using linker.messenger.relay.server;
|
||||
using linker.messenger.signin;
|
||||
|
||||
namespace linker.messenger.relay
|
||||
{
|
||||
@@ -15,19 +18,23 @@ namespace linker.messenger.relay
|
||||
private readonly RelayClientTestTransfer relayTestTransfer;
|
||||
private readonly RelayClientTransfer relayTransfer;
|
||||
private readonly IRelayClientStore relayClientStore;
|
||||
private readonly SignInClientState signInClientState;
|
||||
private readonly IMessengerSender messengerSender;
|
||||
private readonly ISerializer serializer;
|
||||
private readonly ISignInClientStore signInClientStore;
|
||||
|
||||
public RelayApiController(RelayClientTestTransfer relayTestTransfer, RelayClientTransfer relayTransfer, IRelayClientStore relayClientStore)
|
||||
public RelayApiController(RelayClientTestTransfer relayTestTransfer, RelayClientTransfer relayTransfer, IRelayClientStore relayClientStore,
|
||||
SignInClientState signInClientState, IMessengerSender messengerSender, ISerializer serializer, ISignInClientStore signInClientStore)
|
||||
{
|
||||
this.relayTestTransfer = relayTestTransfer;
|
||||
this.relayTransfer = relayTransfer;
|
||||
this.relayClientStore = relayClientStore;
|
||||
this.signInClientState = signInClientState;
|
||||
this.messengerSender = messengerSender;
|
||||
this.serializer = serializer;
|
||||
this.signInClientStore = signInClientStore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置中继协议
|
||||
/// </summary>
|
||||
/// <param name="param"></param>
|
||||
/// <returns></returns>
|
||||
[Access(AccessValue.Config)]
|
||||
public bool SetServers(ApiControllerParamsInfo param)
|
||||
{
|
||||
@@ -50,6 +57,90 @@ namespace linker.messenger.relay
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
public async Task<bool> AccessCdkey(ApiControllerParamsInfo param)
|
||||
{
|
||||
var resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = signInClientState.Connection,
|
||||
MessengerId = (ushort)RelayMessengerIds.AccessCdkey,
|
||||
Payload = serializer.Serialize(relayClientStore.Server.SecretKey)
|
||||
});
|
||||
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
|
||||
}
|
||||
|
||||
[Access(AccessValue.RelayCdkey)]
|
||||
public async Task<bool> AddCdkey(ApiControllerParamsInfo param)
|
||||
{
|
||||
RelayServerCdkeyInfo info = param.Content.DeJson<RelayServerCdkeyInfo>();
|
||||
var resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = signInClientState.Connection,
|
||||
MessengerId = (ushort)RelayMessengerIds.AddCdkey,
|
||||
Payload = serializer.Serialize(new RelayServerCdkeyAddInfo
|
||||
{
|
||||
Data = info,
|
||||
SecretKey = relayClientStore.Server.SecretKey
|
||||
})
|
||||
});
|
||||
|
||||
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
|
||||
}
|
||||
|
||||
[Access(AccessValue.RelayCdkey)]
|
||||
public async Task<bool> DelCdkey(ApiControllerParamsInfo param)
|
||||
{
|
||||
var resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = signInClientState.Connection,
|
||||
MessengerId = (ushort)RelayMessengerIds.DelCdkey,
|
||||
Payload = serializer.Serialize(new RelayServerCdkeyDelInfo
|
||||
{
|
||||
Id = param.Content,
|
||||
SecretKey = relayClientStore.Server.SecretKey
|
||||
})
|
||||
});
|
||||
|
||||
return resp.Code == MessageResponeCodes.OK && resp.Data.Span.SequenceEqual(Helper.TrueArray);
|
||||
}
|
||||
|
||||
[Access(AccessValue.RelayCdkey)]
|
||||
public async Task<RelayServerCdkeyPageResultInfo> PageCdkey(ApiControllerParamsInfo param)
|
||||
{
|
||||
RelayServerCdkeyPageRequestInfo info = param.Content.DeJson<RelayServerCdkeyPageRequestInfo>();
|
||||
info.SecretKey = relayClientStore.Server.SecretKey;
|
||||
var resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = signInClientState.Connection,
|
||||
MessengerId = (ushort)RelayMessengerIds.PageCdkey,
|
||||
Payload = serializer.Serialize(info)
|
||||
});
|
||||
if (resp.Code == MessageResponeCodes.OK)
|
||||
{
|
||||
return serializer.Deserialize<RelayServerCdkeyPageResultInfo>(resp.Data.Span);
|
||||
}
|
||||
|
||||
return new RelayServerCdkeyPageResultInfo();
|
||||
}
|
||||
|
||||
public async Task<RelayServerCdkeyPageResultInfo> MyCdkey(ApiControllerParamsInfo param)
|
||||
{
|
||||
RelayServerCdkeyPageRequestInfo info = param.Content.DeJson<RelayServerCdkeyPageRequestInfo>();
|
||||
info.SecretKey = relayClientStore.Server.SecretKey;
|
||||
info.UserId = signInClientStore.Server.UserId;
|
||||
var resp = await messengerSender.SendReply(new MessageRequestWrap
|
||||
{
|
||||
Connection = signInClientState.Connection,
|
||||
MessengerId = (ushort)RelayMessengerIds.PageCdkey,
|
||||
Payload = serializer.Serialize(info)
|
||||
});
|
||||
if (resp.Code == MessageResponeCodes.OK)
|
||||
{
|
||||
return serializer.Deserialize<RelayServerCdkeyPageResultInfo>(resp.Data.Span);
|
||||
}
|
||||
|
||||
return new RelayServerCdkeyPageResultInfo();
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RelayConnectInfo
|
||||
|
@@ -18,9 +18,11 @@ namespace linker.messenger.relay.client
|
||||
private Dictionary<string, List<Action<ITunnelConnection>>> OnConnected { get; } = new Dictionary<string, List<Action<ITunnelConnection>>>();
|
||||
|
||||
private readonly IRelayClientStore relayClientStore;
|
||||
public RelayClientTransfer(IMessengerSender messengerSender,ISerializer serializer,IRelayClientStore relayClientStore,SignInClientState signInClientState,IMessengerStore messengerStore)
|
||||
private readonly ISignInClientStore signInClientStore;
|
||||
public RelayClientTransfer(IMessengerSender messengerSender, ISerializer serializer, IRelayClientStore relayClientStore, SignInClientState signInClientState, IMessengerStore messengerStore, ISignInClientStore signInClientStore)
|
||||
{
|
||||
this.relayClientStore = relayClientStore;
|
||||
this.signInClientStore = signInClientStore;
|
||||
Transports = new List<IRelayClientTransport> {
|
||||
new RelayClientTransportSelfHost(messengerSender,serializer,relayClientStore,signInClientState,messengerStore),
|
||||
};
|
||||
@@ -87,7 +89,8 @@ namespace linker.messenger.relay.client
|
||||
TransactionId = transactionId,
|
||||
TransportName = transport.Name,
|
||||
SSL = relayClientStore.Server.SSL,
|
||||
NodeId = nodeId
|
||||
NodeId = nodeId,
|
||||
UserId = signInClientStore.Server.UserId,
|
||||
};
|
||||
|
||||
if (LoggerHelper.Instance.LoggerLevel <= LoggerTypes.DEBUG)
|
||||
|
@@ -112,6 +112,11 @@ namespace linker.messenger.relay.client.transport
|
||||
/// 是否ssl
|
||||
/// </summary>
|
||||
public bool SSL { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// UserId
|
||||
/// </summary>
|
||||
public string UserId { get; set; }
|
||||
}
|
||||
|
||||
|
||||
|
@@ -45,14 +45,18 @@ namespace linker.messenger.relay.messenger
|
||||
private readonly RelayServerMasterTransfer relayServerTransfer;
|
||||
private readonly RelayServerValidatorTransfer relayValidatorTransfer;
|
||||
private readonly ISerializer serializer;
|
||||
private readonly IRelayServerCdkeyStore relayServerCdkeyStore;
|
||||
private readonly IRelayServerStore relayServerStore;
|
||||
|
||||
public RelayServerMessenger(IMessengerSender messengerSender, SignInServerCaching signCaching, ISerializer serializer, RelayServerMasterTransfer relayServerTransfer, RelayServerValidatorTransfer relayValidatorTransfer)
|
||||
public RelayServerMessenger(IMessengerSender messengerSender, SignInServerCaching signCaching, ISerializer serializer, RelayServerMasterTransfer relayServerTransfer, RelayServerValidatorTransfer relayValidatorTransfer, IRelayServerCdkeyStore relayServerCdkeyStore, IRelayServerStore relayServerStore)
|
||||
{
|
||||
this.messengerSender = messengerSender;
|
||||
this.signCaching = signCaching;
|
||||
this.relayServerTransfer = relayServerTransfer;
|
||||
this.relayValidatorTransfer = relayValidatorTransfer;
|
||||
this.serializer = serializer;
|
||||
this.relayServerCdkeyStore = relayServerCdkeyStore;
|
||||
this.relayServerStore = relayServerStore;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -89,7 +93,7 @@ namespace linker.messenger.relay.messenger
|
||||
[MessengerId((ushort)RelayMessengerIds.RelayAsk)]
|
||||
public async Task RelayAsk(IConnection connection)
|
||||
{
|
||||
client.transport.RelayInfo info = serializer.Deserialize<client.transport.RelayInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
RelayInfo info = serializer.Deserialize<RelayInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cacheFrom) == false || signCaching.TryGet(info.RemoteMachineId, out SignCacheInfo cacheTo) == false || cacheFrom.GroupId != cacheTo.GroupId)
|
||||
{
|
||||
connection.Write(serializer.Serialize(new RelayAskResultInfo { }));
|
||||
@@ -105,9 +109,11 @@ namespace linker.messenger.relay.messenger
|
||||
string error = await relayValidatorTransfer.Validate(info, cacheFrom, cacheTo);
|
||||
result.Nodes = relayServerTransfer.GetNodes(string.IsNullOrWhiteSpace(error));
|
||||
|
||||
List<RelayServerCdkeyInfo> cdkeys = await relayServerCdkeyStore.Get(info.UserId);
|
||||
|
||||
if (result.Nodes.Count > 0)
|
||||
{
|
||||
result.FlowingId = relayServerTransfer.AddRelay(cacheFrom.MachineId, cacheFrom.MachineName, cacheTo.MachineId, cacheTo.MachineName, cacheFrom.GroupId);
|
||||
result.FlowingId = relayServerTransfer.AddRelay(cacheFrom.MachineId, cacheFrom.MachineName, cacheTo.MachineId, cacheTo.MachineName, cacheFrom.GroupId, cdkeys);
|
||||
}
|
||||
|
||||
connection.Write(serializer.Serialize(result));
|
||||
@@ -167,5 +173,89 @@ namespace linker.messenger.relay.messenger
|
||||
connection.Write(Helper.FalseArray);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// 检查权限
|
||||
/// </summary>
|
||||
/// <param name="connection"></param>
|
||||
/// <returns></returns>
|
||||
[MessengerId((ushort)RelayMessengerIds.AccessCdkey)]
|
||||
public void AccessCdkey(IConnection connection)
|
||||
{
|
||||
string secretKey = serializer.Deserialize<string>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
connection.Write(relayServerStore.SecretKey == secretKey ? Helper.TrueArray : Helper.FalseArray);
|
||||
}
|
||||
/// <summary>
|
||||
/// 添加CDKEY
|
||||
/// </summary>
|
||||
/// <param name="connection"></param>
|
||||
[MessengerId((ushort)RelayMessengerIds.AddCdkey)]
|
||||
public async Task AddCdkey(IConnection connection)
|
||||
{
|
||||
RelayServerCdkeyAddInfo info = serializer.Deserialize<RelayServerCdkeyAddInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) == false)
|
||||
{
|
||||
connection.Write(Helper.FalseArray);
|
||||
return;
|
||||
}
|
||||
if (relayServerStore.SecretKey != info.SecretKey)
|
||||
{
|
||||
connection.Write(Helper.FalseArray);
|
||||
return;
|
||||
}
|
||||
|
||||
await relayServerCdkeyStore.Add(info.Data);
|
||||
connection.Write(Helper.TrueArray);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 删除Cdkey
|
||||
/// </summary>
|
||||
/// <param name="connection"></param>
|
||||
/// <returns></returns>
|
||||
[MessengerId((ushort)RelayMessengerIds.DelCdkey)]
|
||||
public async Task DelCdkey(IConnection connection)
|
||||
{
|
||||
RelayServerCdkeyDelInfo info = serializer.Deserialize<RelayServerCdkeyDelInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) == false)
|
||||
{
|
||||
connection.Write(Helper.FalseArray);
|
||||
return;
|
||||
}
|
||||
if (relayServerStore.SecretKey != info.SecretKey)
|
||||
{
|
||||
connection.Write(Helper.FalseArray);
|
||||
return;
|
||||
}
|
||||
|
||||
await relayServerCdkeyStore.Del(info.Id);
|
||||
connection.Write(Helper.TrueArray);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 查询CDKEY
|
||||
/// </summary>
|
||||
/// <param name="connection"></param>
|
||||
/// <returns></returns>
|
||||
[MessengerId((ushort)RelayMessengerIds.PageCdkey)]
|
||||
public async Task PageCdkey(IConnection connection)
|
||||
{
|
||||
RelayServerCdkeyPageRequestInfo info = serializer.Deserialize<RelayServerCdkeyPageRequestInfo>(connection.ReceiveRequestWrap.Payload.Span);
|
||||
if (signCaching.TryGet(connection.Id, out SignCacheInfo cache) == false)
|
||||
{
|
||||
connection.Write(serializer.Serialize(new RelayServerCdkeyPageResultInfo { }));
|
||||
return;
|
||||
}
|
||||
if (relayServerStore.SecretKey != info.SecretKey && string.IsNullOrWhiteSpace(info.UserId))
|
||||
{
|
||||
connection.Write(serializer.Serialize(new RelayServerCdkeyPageResultInfo { }));
|
||||
return;
|
||||
}
|
||||
|
||||
var page = await relayServerCdkeyStore.Get(info);
|
||||
|
||||
connection.Write(serializer.Serialize(page));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -15,6 +15,11 @@
|
||||
NodeDelay = 2106,
|
||||
NodeDelayForward = 2107,
|
||||
|
||||
AddCdkey = 2108,
|
||||
PageCdkey = 2109,
|
||||
DelCdkey = 2110,
|
||||
AccessCdkey = 2111,
|
||||
|
||||
Max = 2199
|
||||
}
|
||||
}
|
||||
|
104
src/linker.messenger.relay/server/IRelayServerCdkeyStore.cs
Normal file
104
src/linker.messenger.relay/server/IRelayServerCdkeyStore.cs
Normal file
@@ -0,0 +1,104 @@
|
||||
namespace linker.messenger.relay.server
|
||||
{
|
||||
public interface IRelayServerCdkeyStore
|
||||
{
|
||||
public Task<bool> Add(RelayServerCdkeyInfo info);
|
||||
public Task<bool> Del(string id);
|
||||
|
||||
/// <summary>
|
||||
/// 获取有效的CDKEY
|
||||
/// </summary>
|
||||
/// <param name="userid"></param>
|
||||
/// <returns></returns>
|
||||
public Task<List<RelayServerCdkeyInfo>> Get(string userid);
|
||||
public Task<RelayServerCdkeyPageResultInfo> Get(RelayServerCdkeyPageRequestInfo relayServerCdkeyPageRequestInfo);
|
||||
}
|
||||
|
||||
public sealed partial class RelayServerCdkeyPageRequestInfo
|
||||
{
|
||||
public int Page { get; set; }
|
||||
public int Size { get; set; }
|
||||
public string Order { get; set; }
|
||||
public string Sort { get; set; }
|
||||
public string UserId { get; set; }
|
||||
public string Remark { get; set; }
|
||||
public string SecretKey { get; set; }
|
||||
}
|
||||
public sealed partial class RelayServerCdkeyPageResultInfo
|
||||
{
|
||||
public int Page { get; set; }
|
||||
public int Size { get; set; }
|
||||
public int Count { get; set; }
|
||||
public List<RelayServerCdkeyInfo> List { get; set; }
|
||||
}
|
||||
|
||||
public sealed partial class RelayServerCdkeyAddInfo
|
||||
{
|
||||
public string SecretKey { get; set; }
|
||||
public RelayServerCdkeyInfo Data { get; set; }
|
||||
}
|
||||
public sealed partial class RelayServerCdkeyDelInfo
|
||||
{
|
||||
public string SecretKey { get; set; }
|
||||
public string Id { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 中继CDKEY
|
||||
/// </summary>
|
||||
public sealed partial class RelayServerCdkeyInfo
|
||||
{
|
||||
public string Id { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 用户标识
|
||||
/// </summary>
|
||||
public string UserId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// KEY
|
||||
/// </summary>
|
||||
public string CdKey { get; set; }
|
||||
/// <summary>
|
||||
/// 添加时间
|
||||
/// </summary>
|
||||
public DateTime AddTime { get; set; }
|
||||
/// <summary>
|
||||
/// 开始时间
|
||||
/// </summary>
|
||||
public DateTime StartTime { get; set; }
|
||||
/// <summary>
|
||||
/// 结束时间
|
||||
/// </summary>
|
||||
public DateTime EndTime { get; set; }
|
||||
/// <summary>
|
||||
/// 允许节点
|
||||
/// </summary>
|
||||
public List<string> Nodes { get; set; }
|
||||
/// <summary>
|
||||
/// 带宽Mbps
|
||||
/// </summary>
|
||||
public double Bandwidth { get; set; }
|
||||
/// <summary>
|
||||
/// 流量
|
||||
/// </summary>
|
||||
public ulong MaxBytes { get; set; }
|
||||
/// <summary>
|
||||
/// 剩余流量
|
||||
/// </summary>
|
||||
public ulong LastBytes { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// 原价
|
||||
/// </summary>
|
||||
public double Memory { get; set; }
|
||||
/// <summary>
|
||||
/// 支付金额
|
||||
/// </summary>
|
||||
public double PayMemory { get; set; }
|
||||
/// <summary>
|
||||
/// 备注
|
||||
/// </summary>
|
||||
public string Remark { get; set; }
|
||||
}
|
||||
}
|
@@ -26,7 +26,7 @@ namespace linker.messenger.relay.server
|
||||
}
|
||||
|
||||
|
||||
public ulong AddRelay(string fromid, string fromName, string toid, string toName, string groupid)
|
||||
public ulong AddRelay(string fromid, string fromName, string toid, string toName, string groupid, List<RelayServerCdkeyInfo> cdkeys)
|
||||
{
|
||||
ulong flowingId = Interlocked.Increment(ref relayFlowingId);
|
||||
|
||||
@@ -37,7 +37,8 @@ namespace linker.messenger.relay.server
|
||||
FromName = fromName,
|
||||
ToId = toid,
|
||||
ToName = toName,
|
||||
GroupId = groupid
|
||||
GroupId = groupid,
|
||||
Cdkey = cdkeys
|
||||
};
|
||||
bool added = relayCaching.TryAdd($"{fromid}->{toid}->{flowingId}", cache, 15000);
|
||||
if (added == false) return 0;
|
||||
|
@@ -256,6 +256,8 @@ namespace linker.messenger.relay.server
|
||||
public string ToId { get; set; }
|
||||
public string ToName { get; set; }
|
||||
public string GroupId { get; set; }
|
||||
|
||||
public List<RelayServerCdkeyInfo> Cdkey { get; set; }
|
||||
}
|
||||
|
||||
public sealed class RelayWrapInfo
|
||||
|
@@ -55,6 +55,12 @@ namespace linker.messenger.serializer.memorypack
|
||||
MemoryPackFormatterProvider.Register(new RelayAskResultInfoFormatter());
|
||||
MemoryPackFormatterProvider.Register(new RelayCacheInfoFormatter());
|
||||
MemoryPackFormatterProvider.Register(new RelayMessageInfoFormatter());
|
||||
MemoryPackFormatterProvider.Register(new RelayServerCdkeyInfoFormatter());
|
||||
MemoryPackFormatterProvider.Register(new RelayServerCdkeyPageRequestInfoFormatter());
|
||||
MemoryPackFormatterProvider.Register(new RelayServerCdkeyPageResultInfoFormatter());
|
||||
MemoryPackFormatterProvider.Register(new RelayServerCdkeyAddInfoFormatter());
|
||||
MemoryPackFormatterProvider.Register(new RelayServerCdkeyDelInfoFormatter());
|
||||
|
||||
|
||||
MemoryPackFormatterProvider.Register(new AccessUpdateInfoFormatter());
|
||||
MemoryPackFormatterProvider.Register(new AccessInfoFormatter());
|
||||
|
@@ -89,11 +89,14 @@ namespace linker.messenger.serializer.memorypack
|
||||
[MemoryPackInclude]
|
||||
bool SSL => info.SSL;
|
||||
|
||||
[MemoryPackInclude]
|
||||
string UserId => info.UserId;
|
||||
|
||||
[MemoryPackConstructor]
|
||||
SerializableRelayInfo(string fromMachineId, string fromMachineName,
|
||||
string remoteMachineId, string remoteMachineName,
|
||||
string transactionId, string secretKey, string transportName, ulong flowingId,
|
||||
string nodeId, IPEndPoint server, bool ssl)
|
||||
string nodeId, IPEndPoint server, bool ssl, string userid)
|
||||
{
|
||||
var info = new RelayInfo
|
||||
{
|
||||
@@ -107,7 +110,8 @@ namespace linker.messenger.serializer.memorypack
|
||||
TransactionId = transactionId,
|
||||
TransportName = transportName,
|
||||
SecretKey = secretKey,
|
||||
Server = server
|
||||
Server = server,
|
||||
UserId = userid
|
||||
};
|
||||
this.info = info;
|
||||
}
|
||||
@@ -295,7 +299,6 @@ namespace linker.messenger.serializer.memorypack
|
||||
|
||||
|
||||
|
||||
|
||||
[MemoryPackable]
|
||||
public readonly partial struct SerializableRelayCacheInfo
|
||||
{
|
||||
@@ -315,8 +318,11 @@ namespace linker.messenger.serializer.memorypack
|
||||
[MemoryPackInclude]
|
||||
string GroupId => info.GroupId;
|
||||
|
||||
[MemoryPackInclude, MemoryPackAllowSerialize]
|
||||
List<RelayServerCdkeyInfo> Cdkey => info.Cdkey;
|
||||
|
||||
[MemoryPackConstructor]
|
||||
SerializableRelayCacheInfo(ulong flowId, string fromId, string fromName, string toId, string toName, string groupId)
|
||||
SerializableRelayCacheInfo(ulong flowId, string fromId, string fromName, string toId, string toName, string groupId, List<RelayServerCdkeyInfo> cdkey)
|
||||
{
|
||||
var info = new RelayCacheInfo
|
||||
{
|
||||
@@ -326,6 +332,7 @@ namespace linker.messenger.serializer.memorypack
|
||||
GroupId = groupId,
|
||||
ToId = toId,
|
||||
ToName = toName,
|
||||
Cdkey = cdkey
|
||||
};
|
||||
this.info = info;
|
||||
}
|
||||
@@ -427,4 +434,340 @@ namespace linker.messenger.serializer.memorypack
|
||||
value = wrapped.info;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[MemoryPackable]
|
||||
public readonly partial struct SerializableRelayServerCdkeyInfo
|
||||
{
|
||||
[MemoryPackIgnore]
|
||||
public readonly RelayServerCdkeyInfo info;
|
||||
|
||||
[MemoryPackInclude]
|
||||
string Id => info.Id;
|
||||
[MemoryPackInclude]
|
||||
string UserId => info.UserId;
|
||||
|
||||
|
||||
[MemoryPackInclude]
|
||||
string CdKey => info.CdKey;
|
||||
[MemoryPackInclude]
|
||||
DateTime AddTime => info.AddTime;
|
||||
[MemoryPackInclude]
|
||||
DateTime StartTime => info.StartTime;
|
||||
[MemoryPackInclude]
|
||||
DateTime EndTime => info.EndTime;
|
||||
[MemoryPackInclude]
|
||||
List<string> Nodes => info.Nodes;
|
||||
[MemoryPackInclude]
|
||||
double Bandwidth => info.Bandwidth;
|
||||
[MemoryPackInclude]
|
||||
ulong MaxBytes => info.MaxBytes;
|
||||
[MemoryPackInclude]
|
||||
ulong LastBytes => info.LastBytes;
|
||||
[MemoryPackInclude]
|
||||
double Memory => info.Memory;
|
||||
[MemoryPackInclude]
|
||||
double PayMemory => info.PayMemory;
|
||||
[MemoryPackInclude]
|
||||
string Remark => info.Remark;
|
||||
|
||||
[MemoryPackConstructor]
|
||||
SerializableRelayServerCdkeyInfo(string id, string userid, string cdKey, DateTime addTime, DateTime startTime, DateTime endTime,
|
||||
List<string> nodes, double bandwidth, ulong maxBytes, ulong lastBytes, double memory, double payMemory, string remark)
|
||||
{
|
||||
var info = new RelayServerCdkeyInfo
|
||||
{
|
||||
Id = id,
|
||||
UserId = userid,
|
||||
CdKey = cdKey,
|
||||
AddTime = addTime,
|
||||
StartTime = startTime,
|
||||
EndTime = endTime,
|
||||
Nodes = nodes,
|
||||
Bandwidth = bandwidth,
|
||||
MaxBytes = maxBytes,
|
||||
LastBytes = lastBytes,
|
||||
Memory = memory,
|
||||
PayMemory = payMemory,
|
||||
Remark = remark
|
||||
};
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public SerializableRelayServerCdkeyInfo(RelayServerCdkeyInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
}
|
||||
public class RelayServerCdkeyInfoFormatter : MemoryPackFormatter<RelayServerCdkeyInfo>
|
||||
{
|
||||
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref RelayServerCdkeyInfo value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNullObjectHeader();
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WritePackable(new SerializableRelayServerCdkeyInfo(value));
|
||||
}
|
||||
|
||||
public override void Deserialize(ref MemoryPackReader reader, scoped ref RelayServerCdkeyInfo value)
|
||||
{
|
||||
if (reader.PeekIsNull())
|
||||
{
|
||||
reader.Advance(1); // skip null block
|
||||
value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapped = reader.ReadPackable<SerializableRelayServerCdkeyInfo>();
|
||||
value = wrapped.info;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[MemoryPackable]
|
||||
public readonly partial struct SerializableRelayServerCdkeyAddInfo
|
||||
{
|
||||
[MemoryPackIgnore]
|
||||
public readonly RelayServerCdkeyAddInfo info;
|
||||
|
||||
[MemoryPackInclude]
|
||||
string SecretKey => info.SecretKey;
|
||||
[MemoryPackInclude, MemoryPackAllowSerialize]
|
||||
RelayServerCdkeyInfo Data => info.Data;
|
||||
|
||||
[MemoryPackConstructor]
|
||||
SerializableRelayServerCdkeyAddInfo(string secretKey, RelayServerCdkeyInfo data)
|
||||
{
|
||||
var info = new RelayServerCdkeyAddInfo
|
||||
{
|
||||
SecretKey = secretKey,
|
||||
Data = data
|
||||
};
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public SerializableRelayServerCdkeyAddInfo(RelayServerCdkeyAddInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
}
|
||||
public class RelayServerCdkeyAddInfoFormatter : MemoryPackFormatter<RelayServerCdkeyAddInfo>
|
||||
{
|
||||
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref RelayServerCdkeyAddInfo value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNullObjectHeader();
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WritePackable(new SerializableRelayServerCdkeyAddInfo(value));
|
||||
}
|
||||
|
||||
public override void Deserialize(ref MemoryPackReader reader, scoped ref RelayServerCdkeyAddInfo value)
|
||||
{
|
||||
if (reader.PeekIsNull())
|
||||
{
|
||||
reader.Advance(1); // skip null block
|
||||
value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapped = reader.ReadPackable<SerializableRelayServerCdkeyAddInfo>();
|
||||
value = wrapped.info;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[MemoryPackable]
|
||||
public readonly partial struct SerializableRelayServerCdkeyDelInfo
|
||||
{
|
||||
[MemoryPackIgnore]
|
||||
public readonly RelayServerCdkeyDelInfo info;
|
||||
|
||||
[MemoryPackInclude]
|
||||
string SecretKey => info.SecretKey;
|
||||
[MemoryPackInclude]
|
||||
string Id => info.Id;
|
||||
|
||||
[MemoryPackConstructor]
|
||||
SerializableRelayServerCdkeyDelInfo(string secretKey, string id)
|
||||
{
|
||||
var info = new RelayServerCdkeyDelInfo
|
||||
{
|
||||
SecretKey = secretKey,
|
||||
Id = id
|
||||
};
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public SerializableRelayServerCdkeyDelInfo(RelayServerCdkeyDelInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
}
|
||||
public class RelayServerCdkeyDelInfoFormatter : MemoryPackFormatter<RelayServerCdkeyDelInfo>
|
||||
{
|
||||
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref RelayServerCdkeyDelInfo value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNullObjectHeader();
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WritePackable(new SerializableRelayServerCdkeyDelInfo(value));
|
||||
}
|
||||
|
||||
public override void Deserialize(ref MemoryPackReader reader, scoped ref RelayServerCdkeyDelInfo value)
|
||||
{
|
||||
if (reader.PeekIsNull())
|
||||
{
|
||||
reader.Advance(1); // skip null block
|
||||
value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapped = reader.ReadPackable<SerializableRelayServerCdkeyDelInfo>();
|
||||
value = wrapped.info;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
[MemoryPackable]
|
||||
public readonly partial struct SerializableRelayServerCdkeyPageRequestInfo
|
||||
{
|
||||
[MemoryPackIgnore]
|
||||
public readonly RelayServerCdkeyPageRequestInfo info;
|
||||
|
||||
[MemoryPackInclude]
|
||||
int Page => info.Page;
|
||||
[MemoryPackInclude]
|
||||
int Size => info.Size;
|
||||
[MemoryPackInclude]
|
||||
string Order => info.Order;
|
||||
[MemoryPackInclude]
|
||||
string Sort => info.Sort;
|
||||
|
||||
[MemoryPackInclude]
|
||||
string UserId => info.UserId;
|
||||
[MemoryPackInclude]
|
||||
string Remark => info.Remark;
|
||||
[MemoryPackInclude]
|
||||
string SecretKey => info.SecretKey;
|
||||
|
||||
[MemoryPackConstructor]
|
||||
SerializableRelayServerCdkeyPageRequestInfo(int page, int size, string order, string sort, string userid, string remark, string secretKey)
|
||||
{
|
||||
var info = new RelayServerCdkeyPageRequestInfo
|
||||
{
|
||||
Sort = sort,
|
||||
Order = order,
|
||||
Size = size,
|
||||
Page = page,
|
||||
UserId = userid,
|
||||
Remark = remark,
|
||||
SecretKey = secretKey
|
||||
};
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public SerializableRelayServerCdkeyPageRequestInfo(RelayServerCdkeyPageRequestInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
}
|
||||
public class RelayServerCdkeyPageRequestInfoFormatter : MemoryPackFormatter<RelayServerCdkeyPageRequestInfo>
|
||||
{
|
||||
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref RelayServerCdkeyPageRequestInfo value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNullObjectHeader();
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WritePackable(new SerializableRelayServerCdkeyPageRequestInfo(value));
|
||||
}
|
||||
|
||||
public override void Deserialize(ref MemoryPackReader reader, scoped ref RelayServerCdkeyPageRequestInfo value)
|
||||
{
|
||||
if (reader.PeekIsNull())
|
||||
{
|
||||
reader.Advance(1); // skip null block
|
||||
value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapped = reader.ReadPackable<SerializableRelayServerCdkeyPageRequestInfo>();
|
||||
value = wrapped.info;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
[MemoryPackable]
|
||||
public readonly partial struct SerializableRelayServerCdkeyPageResultInfo
|
||||
{
|
||||
[MemoryPackIgnore]
|
||||
public readonly RelayServerCdkeyPageResultInfo info;
|
||||
|
||||
[MemoryPackInclude]
|
||||
int Page => info.Page;
|
||||
[MemoryPackInclude]
|
||||
int Size => info.Size;
|
||||
[MemoryPackInclude]
|
||||
int Count => info.Count;
|
||||
[MemoryPackInclude]
|
||||
List<RelayServerCdkeyInfo> List => info.List;
|
||||
|
||||
[MemoryPackConstructor]
|
||||
SerializableRelayServerCdkeyPageResultInfo(int page, int size, int count, List<RelayServerCdkeyInfo> list)
|
||||
{
|
||||
var info = new RelayServerCdkeyPageResultInfo
|
||||
{
|
||||
Count = count,
|
||||
List = list,
|
||||
Size = size,
|
||||
Page = page
|
||||
};
|
||||
this.info = info;
|
||||
}
|
||||
|
||||
public SerializableRelayServerCdkeyPageResultInfo(RelayServerCdkeyPageResultInfo info)
|
||||
{
|
||||
this.info = info;
|
||||
}
|
||||
}
|
||||
public class RelayServerCdkeyPageResultInfoFormatter : MemoryPackFormatter<RelayServerCdkeyPageResultInfo>
|
||||
{
|
||||
public override void Serialize<TBufferWriter>(ref MemoryPackWriter<TBufferWriter> writer, scoped ref RelayServerCdkeyPageResultInfo value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
writer.WriteNullObjectHeader();
|
||||
return;
|
||||
}
|
||||
|
||||
writer.WritePackable(new SerializableRelayServerCdkeyPageResultInfo(value));
|
||||
}
|
||||
|
||||
public override void Deserialize(ref MemoryPackReader reader, scoped ref RelayServerCdkeyPageResultInfo value)
|
||||
{
|
||||
if (reader.PeekIsNull())
|
||||
{
|
||||
reader.Advance(1); // skip null block
|
||||
value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
var wrapped = reader.ReadPackable<SerializableRelayServerCdkeyPageResultInfo>();
|
||||
value = wrapped.info;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
@@ -42,6 +42,7 @@ namespace linker.messenger.signin
|
||||
public string Name { get; set; } = string.Empty;
|
||||
public string Host { get; set; } = string.Empty;
|
||||
public string SecretKey { get; set; } = string.Empty;
|
||||
public string UserId { get; set; } = Guid.NewGuid().ToString();
|
||||
|
||||
}
|
||||
|
||||
|
@@ -45,6 +45,11 @@
|
||||
/// <param name="secretKey"></param>
|
||||
public void SetSecretKey(string secretKey);
|
||||
/// <summary>
|
||||
/// 设置用户id
|
||||
/// </summary>
|
||||
/// <param name="userid"></param>
|
||||
public void SetUserId(string userid);
|
||||
/// <summary>
|
||||
/// 信标服务器
|
||||
/// </summary>
|
||||
/// <param name="host"></param>
|
||||
|
@@ -59,6 +59,7 @@ namespace linker.messenger.store.file
|
||||
serviceCollection.AddSingleton<IRelayServerStore, RelayServerStore>();
|
||||
serviceCollection.AddSingleton<IRelayServerNodeStore, RelayServerNodeStore>();
|
||||
serviceCollection.AddSingleton<IRelayServerMasterStore, RelayServerMasterStore>();
|
||||
serviceCollection.AddSingleton<IRelayServerCdkeyStore, RelayServerCdkeyStore>();
|
||||
|
||||
|
||||
serviceCollection.AddSingleton<ITunnelClientStore, TunnelClientStore>();
|
||||
@@ -66,6 +67,7 @@ namespace linker.messenger.store.file
|
||||
serviceCollection.AddSingleton<ISignInClientStore, SignInClientStore>();
|
||||
serviceCollection.AddSingleton<ISignInServerStore, SignInServerStore>();
|
||||
serviceCollection.AddSingleton<SignInSyncSecretKey>();
|
||||
serviceCollection.AddSingleton<SignInSyncUserId>();
|
||||
serviceCollection.AddSingleton<SignInSyncServer>();
|
||||
|
||||
serviceCollection.AddSingleton<SignInSyncGroupSecretKey>();
|
||||
@@ -107,6 +109,7 @@ namespace linker.messenger.store.file
|
||||
SyncTreansfer syncTreansfer = serviceProvider.GetService<SyncTreansfer>();
|
||||
syncTreansfer.AddSyncs(new List<ISync> {
|
||||
serviceProvider.GetService<SignInSyncSecretKey>(),
|
||||
serviceProvider.GetService<SignInSyncUserId>(),
|
||||
serviceProvider.GetService<SignInSyncGroupSecretKey>(),
|
||||
serviceProvider.GetService<SignInSyncServer>(),
|
||||
|
||||
|
@@ -0,0 +1,65 @@
|
||||
using linker.messenger.relay.server;
|
||||
using LiteDB;
|
||||
|
||||
namespace linker.messenger.store.file.relay
|
||||
{
|
||||
public sealed class RelayServerCdkeyStore : IRelayServerCdkeyStore
|
||||
{
|
||||
private readonly Storefactory dBfactory;
|
||||
private readonly ILiteCollection<RelayServerCdkeyInfo> liteCollection;
|
||||
public RelayServerCdkeyStore(Storefactory dBfactory, FileConfig fileConfig)
|
||||
{
|
||||
this.dBfactory = dBfactory;
|
||||
liteCollection = dBfactory.GetCollection<RelayServerCdkeyInfo>("relayCdkey");
|
||||
}
|
||||
|
||||
public async Task<bool> Add(RelayServerCdkeyInfo info)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(info.Id))
|
||||
{
|
||||
info.Id = ObjectId.NewObjectId().ToString();
|
||||
liteCollection.Insert(info);
|
||||
}
|
||||
else
|
||||
{
|
||||
liteCollection.Update(info);
|
||||
}
|
||||
return await Task.FromResult(true);
|
||||
}
|
||||
public async Task<bool> Del(string id)
|
||||
{
|
||||
return await Task.FromResult(liteCollection.Delete(id));
|
||||
}
|
||||
|
||||
public async Task<List<RelayServerCdkeyInfo>> Get(string userid)
|
||||
{
|
||||
return await Task.FromResult(liteCollection.Find(x => x.UserId == userid && x.LastBytes > 0 && x.StartTime <= DateTime.Now && x.EndTime < DateTime.Now).ToList());
|
||||
}
|
||||
|
||||
public async Task<RelayServerCdkeyPageResultInfo> Get(RelayServerCdkeyPageRequestInfo relayServerCdkeyPageRequestInfo)
|
||||
{
|
||||
ILiteQueryable<RelayServerCdkeyInfo> query = liteCollection.Query();
|
||||
|
||||
if (string.IsNullOrWhiteSpace(relayServerCdkeyPageRequestInfo.Order) == false)
|
||||
{
|
||||
query = query.OrderBy(relayServerCdkeyPageRequestInfo.Order, relayServerCdkeyPageRequestInfo.Sort == "asc" ? Query.Ascending : Query.Descending);
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(relayServerCdkeyPageRequestInfo.UserId) == false)
|
||||
{
|
||||
query = query.Where(x => x.UserId == relayServerCdkeyPageRequestInfo.UserId);
|
||||
}
|
||||
if (string.IsNullOrWhiteSpace(relayServerCdkeyPageRequestInfo.Remark) == false)
|
||||
{
|
||||
query = query.Where(x => x.Remark.Contains(relayServerCdkeyPageRequestInfo.Remark));
|
||||
}
|
||||
|
||||
return await Task.FromResult(new RelayServerCdkeyPageResultInfo
|
||||
{
|
||||
Page = relayServerCdkeyPageRequestInfo.Page,
|
||||
Size = relayServerCdkeyPageRequestInfo.Size,
|
||||
Count = query.Count(),
|
||||
List = query.Skip((relayServerCdkeyPageRequestInfo.Page - 1) * relayServerCdkeyPageRequestInfo.Size).Limit(relayServerCdkeyPageRequestInfo.Size).ToList()
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
@@ -43,6 +43,11 @@ namespace linker.messenger.store.file.signIn
|
||||
Server.SecretKey = secretKey;
|
||||
config.Data.Update();
|
||||
}
|
||||
public void SetUserId(string userid)
|
||||
{
|
||||
Server.UserId = userid;
|
||||
config.Data.Update();
|
||||
}
|
||||
public void SetHost(string host)
|
||||
{
|
||||
Server.Host = host;
|
||||
|
@@ -46,6 +46,27 @@ namespace linker.messenger.store.file.signIn
|
||||
signInClientStore.SetSecretKey(serializer.Deserialize<string>(data.Span));
|
||||
}
|
||||
}
|
||||
public sealed class SignInSyncUserId : ISync
|
||||
{
|
||||
public string Name => "SignInUserId";
|
||||
|
||||
private readonly ISignInClientStore signInClientStore;
|
||||
private readonly ISerializer serializer;
|
||||
public SignInSyncUserId(ISignInClientStore signInClientStore, ISerializer serializer)
|
||||
{
|
||||
this.signInClientStore = signInClientStore;
|
||||
this.serializer = serializer;
|
||||
}
|
||||
public Memory<byte> GetData()
|
||||
{
|
||||
return serializer.Serialize(signInClientStore.Server.UserId);
|
||||
}
|
||||
|
||||
public void SetData(Memory<byte> data)
|
||||
{
|
||||
signInClientStore.SetUserId(serializer.Deserialize<string>(data.Span));
|
||||
}
|
||||
}
|
||||
public sealed class SignInSyncGroupSecretKey : ISync
|
||||
{
|
||||
public string Name => "GroupSecretKey";
|
||||
|
@@ -35,10 +35,13 @@ namespace linker.messenger.tunnel
|
||||
{
|
||||
LoggerHelper.Instance.Info($"tunnel route level getting.");
|
||||
Info.RouteLevel = NetworkHelper.GetRouteLevel(signInClientStore.Server.Host, out List<IPAddress> ips);
|
||||
Info.RouteIPs = ips.ToArray();
|
||||
Info.LocalIPs = NetworkHelper.GetIPV6().Concat(NetworkHelper.GetIPV4()).ToArray();
|
||||
LoggerHelper.Instance.Warning($"route ips:{string.Join(",", ips.Select(c => c.ToString()))}");
|
||||
LoggerHelper.Instance.Warning($"tunnel local ips :{string.Join(",", Info.LocalIPs.Select(c => c.ToString()))}");
|
||||
Info.RouteIPs = ips.ToArray();
|
||||
var ipv6 = NetworkHelper.GetIPV6();
|
||||
LoggerHelper.Instance.Warning($"tunnel local ip6 :{string.Join(",", ipv6.Select(c => c.ToString()))}");
|
||||
var ipv4 = NetworkHelper.GetIPV4();
|
||||
LoggerHelper.Instance.Warning($"tunnel local ip4 :{string.Join(",", ipv4.Select(c => c.ToString()))}");
|
||||
Info.LocalIPs = ipv6.Concat(ipv4).ToArray();
|
||||
LoggerHelper.Instance.Warning($"tunnel route level:{Info.RouteLevel}");
|
||||
}
|
||||
|
||||
|
@@ -22,6 +22,8 @@ namespace linker.tun
|
||||
private IPAddress address;
|
||||
private byte prefixLength = 24;
|
||||
|
||||
private string defaultInterfaceName = string.Empty;
|
||||
|
||||
private CancellationTokenSource tokenSource;
|
||||
|
||||
public LinkerWinTunDevice()
|
||||
@@ -67,6 +69,7 @@ namespace linker.tun
|
||||
AddIPV6();
|
||||
|
||||
GetWindowsInterfaceNum();
|
||||
GetDefaultInterface();
|
||||
tokenSource = new CancellationTokenSource();
|
||||
|
||||
return true;
|
||||
@@ -115,7 +118,6 @@ namespace linker.tun
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void Shutdown()
|
||||
{
|
||||
tokenSource?.Cancel();
|
||||
@@ -137,7 +139,6 @@ namespace linker.tun
|
||||
interfaceNumber = 0;
|
||||
}
|
||||
|
||||
|
||||
public void SetMtu(int value)
|
||||
{
|
||||
CommandHelper.Windows(string.Empty, new string[] {
|
||||
@@ -157,20 +158,18 @@ namespace linker.tun
|
||||
|
||||
IPAddress network = NetworkHelper.ToNetworkIP(this.address, NetworkHelper.ToPrefixValue(prefixLength));
|
||||
CommandHelper.PowerShell($"New-NetNat -Name {Name} -InternalIPInterfaceAddressPrefix {network}/{prefixLength}", [], out error);
|
||||
if (string.IsNullOrWhiteSpace(error))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (string.IsNullOrWhiteSpace(error) == false)
|
||||
CommandHelper.Windows(string.Empty, [$"net start SharedAccess"]);
|
||||
string result = CommandHelper.Windows(string.Empty, [$"linker.ics.exe {defaultInterfaceName} {Name} enable"]);
|
||||
if (result.Contains($"enable success"))
|
||||
{
|
||||
error = "NetNat Not Supported";
|
||||
string result = CommandHelper.Windows(string.Empty, ["netsh routing"]);
|
||||
if (result.Contains("netsh routing ip"))
|
||||
{
|
||||
error = string.Empty;
|
||||
}
|
||||
else
|
||||
{
|
||||
error += ",RRAS Not Supported";
|
||||
}
|
||||
return;
|
||||
}
|
||||
error = "NetNat and ICS not supported";
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -186,6 +185,7 @@ namespace linker.tun
|
||||
{
|
||||
CommandHelper.PowerShell($"start-service WinNat", [], out error);
|
||||
CommandHelper.PowerShell($"Remove-NetNat -Name {Name} -Confirm:$false", [], out error);
|
||||
CommandHelper.Windows(string.Empty, [$"linker.ics.exe {Name} disable"]);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
@@ -327,6 +327,33 @@ namespace linker.tun
|
||||
}
|
||||
|
||||
}
|
||||
private void GetDefaultInterface()
|
||||
{
|
||||
string[] lines = CommandHelper.Windows(string.Empty, new string[] { $"route print" }).Split(Environment.NewLine);
|
||||
foreach (var item in lines)
|
||||
{
|
||||
if (item.Trim().StartsWith("0.0.0.0"))
|
||||
{
|
||||
string[] arr = Regex.Replace(item.Trim(), @"\s+", " ").Split(' ');
|
||||
IPAddress ip = IPAddress.Parse(arr[arr.Length - 2]);
|
||||
|
||||
foreach (var inter in NetworkInterface.GetAllNetworkInterfaces())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (ip.Equals(inter.GetIPProperties().UnicastAddresses.FirstOrDefault(c => c.Address.AddressFamily == System.Net.Sockets.AddressFamily.InterNetwork).Address))
|
||||
{
|
||||
defaultInterfaceName = inter.Name;
|
||||
return;
|
||||
}
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ClearRegistry()
|
||||
{
|
||||
|
@@ -9,3 +9,6 @@ export const setRelaySubscribe = () => {
|
||||
export const relayConnect = (data) => {
|
||||
return sendWebsocketMsg('relay/Connect', data);
|
||||
}
|
||||
export const relayCdkeyAccess = () => {
|
||||
return sendWebsocketMsg('relay/AccessCdkey');
|
||||
}
|
@@ -119,18 +119,34 @@ a.a-line {
|
||||
padding-right: 1rem;
|
||||
}
|
||||
|
||||
.m-r-1 {
|
||||
margin-right: 1rem;
|
||||
.mgr-1 {
|
||||
margin-right: 1rem !important;
|
||||
}
|
||||
|
||||
.m-l-1 {
|
||||
.mgl-1 {
|
||||
margin-left: 1rem;
|
||||
}
|
||||
|
||||
.m-b-0 {
|
||||
.mgl-2 {
|
||||
margin-left: 2rem;
|
||||
}
|
||||
|
||||
.mgl-3 {
|
||||
margin-left: 3rem;
|
||||
}
|
||||
|
||||
.mgb-0 {
|
||||
margin-bottom: 0 !important;
|
||||
}
|
||||
|
||||
.mgb-3 {
|
||||
margin-bottom: 3rem;
|
||||
}
|
||||
|
||||
.mgt-3 {
|
||||
margin-top: 3rem;
|
||||
}
|
||||
|
||||
table {
|
||||
border-spacing: 0;
|
||||
border-collapse: collapse;
|
||||
@@ -174,6 +190,10 @@ span.split-pad10 {
|
||||
color: #e68906 !important;
|
||||
}
|
||||
|
||||
.disable {
|
||||
color: #ddd !important;
|
||||
}
|
||||
|
||||
.gateway {
|
||||
&.green {
|
||||
/* background: linear-gradient(270deg, #caff00, green, #0d6d23, #e38a00, green); */
|
||||
|
@@ -7,6 +7,7 @@ export default {
|
||||
'common.operating': 'In operation',
|
||||
'common.tips': 'Tips',
|
||||
'common.option': 'Option',
|
||||
'common.access': 'No access',
|
||||
|
||||
'head.home': 'Home',
|
||||
'head.server': 'Server',
|
||||
@@ -36,6 +37,8 @@ export default {
|
||||
'server.messengerText': 'ip:port or domain:port',
|
||||
'server.messengerSecretKey': 'Messenger SecretKey',
|
||||
'server.messengerSecretKeyText': 'Messenger SecretKey',
|
||||
'server.messengerUserId': 'User Id',
|
||||
'server.messengerUserIdText': 'Your unique identifier,for card key (CDKEY).',
|
||||
|
||||
'permission.closed': 'Closed',
|
||||
'permission.simple': 'Simple',
|
||||
@@ -120,6 +123,8 @@ export default {
|
||||
'server.relayPublic': 'Public',
|
||||
'server.relayOper': 'Oper',
|
||||
'server.relayUse': 'Use',
|
||||
'server.relayMyCdkey': 'My CDKEY',
|
||||
'server.relayCdkey': 'Manager CDKEY',
|
||||
|
||||
'server.sforwardSecretKey': 'Server forward secretKey',
|
||||
'server.sforwardText': 'The server forward can be used when the key is correct',
|
||||
@@ -148,5 +153,7 @@ export default {
|
||||
'server.asyncRelaySecretKey': 'Relay secretKey',
|
||||
'server.asyncSForwardSecretKey': 'Server forward secretKey',
|
||||
'server.asyncUpdaterSecretKey': 'Update secretKey',
|
||||
'server.asyncTunnelTransports': 'Tunnel transports'
|
||||
'server.asyncTunnelTransports': 'Tunnel transports',
|
||||
'server.asyncSignInUserId': 'User Id',
|
||||
|
||||
}
|
@@ -7,6 +7,7 @@ export default {
|
||||
'common.operating': '正在操作',
|
||||
'common.tips': '提示',
|
||||
'common.option': '选项',
|
||||
'common.access': '无权限',
|
||||
|
||||
'head.home': '首页',
|
||||
'head.server': '服务器',
|
||||
@@ -35,6 +36,8 @@ export default {
|
||||
'server.messengerText': 'ip:端口 或者 域名:端口',
|
||||
'server.messengerSecretKey': '信标密钥',
|
||||
'server.messengerSecretKeyText': '密钥正确时可连接服务器',
|
||||
'server.messengerUserId': '用户id',
|
||||
'server.messengerUserIdText': '你的唯一标识,用于流量卡密CDKEY',
|
||||
|
||||
'permission.closed': '禁止通行',
|
||||
'permission.simple': '简单管理',
|
||||
@@ -122,6 +125,8 @@ export default {
|
||||
'server.relayPublic': '公开',
|
||||
'server.relayOper': '操作',
|
||||
'server.relayUse': '使用',
|
||||
'server.relayMyCdkey': '我的CDKEY',
|
||||
'server.relayCdkey': '管理CDKEY',
|
||||
|
||||
'server.sforwardSecretKey': '服务器穿透密钥',
|
||||
'server.sforwardText': '当密钥正确是可用',
|
||||
@@ -150,5 +155,6 @@ export default {
|
||||
'server.asyncRelaySecretKey': '中继密钥',
|
||||
'server.asyncSForwardSecretKey': '服务器穿透密钥',
|
||||
'server.asyncUpdaterSecretKey': '更新密钥',
|
||||
'server.asyncTunnelTransports': '打洞协议'
|
||||
'server.asyncTunnelTransports': '打洞协议',
|
||||
'server.asyncSignInUserId': '用户唯一标识',
|
||||
}
|
@@ -6,7 +6,7 @@
|
||||
接口 : <el-input v-model="state.api" style="width:70%"></el-input>
|
||||
</div>
|
||||
<div class="pdt-10">
|
||||
秘钥 : <el-input type="password" v-model="state.psd" style="width:70%"></el-input>
|
||||
秘钥 : <el-input show-password type="password" v-model="state.psd" style="width:70%"></el-input>
|
||||
</div>
|
||||
<div class="pdt-10">
|
||||
<el-checkbox v-model="state.save" >保存密码</el-checkbox>
|
||||
|
@@ -16,7 +16,7 @@
|
||||
<el-checkbox v-model="state.ruleForm.Multicast" label="禁用广播" size="large" />
|
||||
<el-checkbox v-model="state.ruleForm.Nat" label="禁用NAT" size="large" />
|
||||
</el-form-item>
|
||||
<el-form-item prop="upgrade" class="m-b-0">
|
||||
<el-form-item prop="upgrade" class="mgb-0">
|
||||
<el-checkbox v-model="state.ruleForm.Upgrade" label="我很懂,我要使用高级功能(点对网和网对网)" size="large" />
|
||||
</el-form-item>
|
||||
<div class="upgrade-wrap" v-if="state.ruleForm.Upgrade">
|
||||
|
@@ -34,13 +34,13 @@
|
||||
<div>
|
||||
<template v-for="(item1,index) in tuntap.list[item.MachineId].Lans" :key="index">
|
||||
<template v-if="item1.Disabled">
|
||||
<div class="flex yellow" title="已禁用">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
|
||||
<div class="flex disable" title="已禁用">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
|
||||
</template>
|
||||
<template v-else-if="item1.Exists">
|
||||
<div class="flex yellow" title="与其它设备填写IP、或本机局域网IP有冲突">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
|
||||
</template>
|
||||
<template v-else>
|
||||
<div class="flex" title="正常使用" :class="{green:tuntap.list[item.MachineId].running}">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
|
||||
<div class="flex green" title="正常使用">{{ item1.IP }} / {{ item1.PrefixLength }}</div>
|
||||
</template>
|
||||
</template>
|
||||
</div>
|
||||
|
@@ -32,6 +32,11 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="Oper" :label="$t('server.groupOper')" width="160">
|
||||
<template #header>
|
||||
<div class="flex">
|
||||
<strong>{{ $t('server.groupOper') }}</strong><span class="flex-1"></span><Sync name="GroupSecretKey"></Sync>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div>
|
||||
<el-popconfirm :title="$t('server.groupDelConfirm')" @confirm="handleDel(scope.$index)">
|
||||
@@ -60,8 +65,9 @@ import { ElMessage } from 'element-plus';
|
||||
import { computed, reactive, watch } from 'vue'
|
||||
import { Delete,Plus,Select } from '@element-plus/icons-vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import Sync from '../sync/Index.vue'
|
||||
export default {
|
||||
components:{Delete,Plus,Select },
|
||||
components:{Delete,Plus,Select,Sync },
|
||||
setup(props) {
|
||||
const {t} = useI18n();
|
||||
const globalData = injectGlobalData();
|
||||
|
@@ -5,7 +5,7 @@
|
||||
<div class="inner">
|
||||
<div class="head flex">
|
||||
<div>
|
||||
<el-select v-model="state.type" @change="loadData" size="small" class="m-r-1" style="width: 6rem;">
|
||||
<el-select v-model="state.type" @change="loadData" size="small" class="mgr-1" style="width: 6rem;">
|
||||
<el-option :value="-1" label="all"></el-option>
|
||||
<el-option :value="0" label="debug"></el-option>
|
||||
<el-option :value="1" label="info"></el-option>
|
||||
|
@@ -1,88 +0,0 @@
|
||||
<template>
|
||||
<div :style="{ height: `${state.height}px` }">
|
||||
<el-card shadow="never">
|
||||
<template #header>{{ $t('server.asyncText') }}</template>
|
||||
<div>
|
||||
<el-checkbox v-model="state.checkAll" :indeterminate="state.isIndeterminate"
|
||||
@change="handleCheckAllChange">{{
|
||||
$t('server.asyncCheckAll') }}</el-checkbox>
|
||||
<el-checkbox-group v-model="state.checkeds" @change="handleCheckedsChange">
|
||||
<el-row>
|
||||
<template v-for="name in state.names">
|
||||
<el-col :span="8">
|
||||
<el-checkbox :key="name.name" :label="name.label" :value="name.name">{{ name.label
|
||||
}}</el-checkbox>
|
||||
</el-col>
|
||||
</template>
|
||||
</el-row>
|
||||
</el-checkbox-group>
|
||||
</div>
|
||||
<template #footer>
|
||||
<div class="t-c">
|
||||
<el-button type="success" @click="handleSync">{{ $t('common.confirm') }}</el-button>
|
||||
</div>
|
||||
</template>
|
||||
</el-card>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { computed, onMounted, reactive } from 'vue'
|
||||
import { getSyncNames, setSync } from '@/apis/sync';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
export default {
|
||||
setup(props) {
|
||||
const { t } = useI18n();
|
||||
const globalData = injectGlobalData();
|
||||
const state = reactive({
|
||||
names: [],
|
||||
checkAll: false,
|
||||
isIndeterminate: false,
|
||||
checkeds: [],
|
||||
height: computed(() => globalData.value.height - 90),
|
||||
});
|
||||
|
||||
const handleCheckAllChange = (val) => {
|
||||
state.checkeds = val ? state.names.map(c => c.name) : [];
|
||||
state.isIndeterminate = false
|
||||
}
|
||||
const handleCheckedsChange = (value) => {
|
||||
const checkedCount = value.length
|
||||
state.checkAll = checkedCount === state.names.length
|
||||
state.isIndeterminate = checkedCount > 0 && checkedCount < state.names.length;
|
||||
}
|
||||
|
||||
const labels = {
|
||||
'SignInServer': t('server.asyncSignInServer'),
|
||||
'SignInSecretKey': t('server.asyncSignInSecretKey'),
|
||||
'GroupSecretKey': t('server.asyncGroupSecretKey'),
|
||||
'RelaySecretKey': t('server.asyncRelaySecretKey'),
|
||||
'SForwardSecretKey': t('server.asyncSForwardSecretKey'),
|
||||
'UpdaterSecretKey': t('server.asyncUpdaterSecretKey'),
|
||||
'TunnelTransports': t('server.asyncTunnelTransports')
|
||||
}
|
||||
onMounted(() => {
|
||||
getSyncNames().then(res => {
|
||||
state.names = res.map(c => {
|
||||
return { name: c, label: labels[c] }
|
||||
});
|
||||
});
|
||||
});
|
||||
const handleSync = () => {
|
||||
if (state.checkeds.length == 0) {
|
||||
ElMessage.error(t('server.asyncSelect'));
|
||||
return;
|
||||
}
|
||||
setSync(state.checkeds).then(res => {
|
||||
ElMessage.success(t('common.oper'));
|
||||
});
|
||||
}
|
||||
|
||||
return { state, handleCheckAllChange, handleCheckedsChange, handleSync }
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
|
||||
</style>
|
@@ -1,32 +1,20 @@
|
||||
<template>
|
||||
<div class="servers-wrap" >
|
||||
<el-tabs type="border-card" style="width:100%" v-model="state.tab">
|
||||
<el-tab-pane :label="$t('server.messenger')" name="signin" v-if="hasConfig">
|
||||
<SignInServers></SignInServers>
|
||||
</el-tab-pane>
|
||||
<el-tab-pane :label="$t('server.sync')" name="async" v-if="hasSync">
|
||||
<Async></Async>
|
||||
</el-tab-pane>
|
||||
</el-tabs>
|
||||
<SignInServers v-if="hasConfig"></SignInServers>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { computed, reactive } from 'vue';
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import SignInServers from './SignInServers.vue';
|
||||
import Async from './Async.vue';
|
||||
export default {
|
||||
components:{SignInServers,Async},
|
||||
components:{SignInServers},
|
||||
setup(props) {
|
||||
|
||||
const globalData = injectGlobalData();
|
||||
const hasConfig = computed(()=>globalData.value.hasAccess('Config'))
|
||||
const hasSync = computed(()=>globalData.value.hasAccess('Sync'));
|
||||
const state = reactive({
|
||||
tab:'signin'
|
||||
});
|
||||
const state = reactive({});
|
||||
return {
|
||||
state,hasConfig,hasSync
|
||||
state,hasConfig
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,9 +26,4 @@ export default {
|
||||
color:#555;
|
||||
a{color:#333;}
|
||||
}
|
||||
.el-checkbox{
|
||||
vertical-align:middle;
|
||||
margin-right:1rem;
|
||||
}
|
||||
|
||||
</style>
|
@@ -1,11 +1,18 @@
|
||||
<template>
|
||||
<el-form-item :label="$t('server.relaySecretKey')">
|
||||
<el-input type="password" show-password v-model="state.list.SecretKey" maxlength="36" @change="handleSave" />
|
||||
<el-checkbox v-model="state.list.SSL" :label="$t('server.relaySSL')" size="large" @change="handleSave" />
|
||||
<el-checkbox v-model="state.list.Disabled" :label="$t('server.relayDisable')" size="large" @change="handleSave" />
|
||||
<a href="javascript:;" @click="state.show=true" class="delay a-line" :class="{red:state.nodes.length==0,green:state.nodes.length>0}">
|
||||
<div class="flex">
|
||||
<el-input class="flex-1" type="password" show-password v-model="state.list.SecretKey" maxlength="36" @change="handleSave" />
|
||||
<Sync class="mgl-1" name="RelaySecretKey"></Sync>
|
||||
<div class="mgl-1">
|
||||
<el-checkbox class="mgr-1" v-model="state.list.SSL" :label="$t('server.relaySSL')" @change="handleSave" />
|
||||
<el-checkbox v-model="state.list.Disabled" :label="$t('server.relayDisable')" @change="handleSave" />
|
||||
</div>
|
||||
<a href="javascript:;" @click="state.show=true" class="mgl-1 delay a-line" :class="{red:state.nodes.length==0,green:state.nodes.length>0}">
|
||||
{{$t('server.relayNodes')}} : {{state.nodes.length}}
|
||||
</a>
|
||||
<Relay></Relay>
|
||||
</div>
|
||||
|
||||
</el-form-item>
|
||||
|
||||
<el-dialog v-model="state.show" :title="$t('server.relayTitle')" width="760" top="2vh">
|
||||
@@ -60,7 +67,10 @@ import { injectGlobalData } from '@/provide';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { onMounted, onUnmounted, reactive, watch } from 'vue'
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import Sync from '../sync/Index.vue'
|
||||
import Relay from './relay/Index.vue'
|
||||
export default {
|
||||
components:{Sync,Relay},
|
||||
setup(props) {
|
||||
const {t} = useI18n();
|
||||
const globalData = injectGlobalData();
|
||||
@@ -103,5 +113,4 @@ export default {
|
||||
}
|
||||
</script>
|
||||
<style lang="stylus" scoped>
|
||||
.delay{margin-left:3rem;}
|
||||
</style>
|
@@ -2,7 +2,8 @@
|
||||
<el-form-item :label="$t('server.sforwardSecretKey')">
|
||||
<div class="flex">
|
||||
<el-input class="flex-1" type="password" show-password v-model="state.SForwardSecretKey" maxlength="36" @blur="handleChange" />
|
||||
<span>{{$t('server.sforwardText')}}</span>
|
||||
<Sync class="mgl-1" name="SForwardSecretKey"></Sync>
|
||||
<span class="mgl-1">{{$t('server.sforwardText')}}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</template>
|
||||
@@ -11,7 +12,9 @@ import { getSForwardSecretKey,setSForwardSecretKey } from '@/apis/sforward';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import {onMounted, reactive } from 'vue'
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import Sync from '../sync/Index.vue'
|
||||
export default {
|
||||
components:{Sync},
|
||||
setup(props) {
|
||||
const {t} = useI18n();
|
||||
const state = reactive({
|
||||
|
@@ -7,16 +7,25 @@
|
||||
<el-form-item :label="$t('server.messengerAddr')">
|
||||
<div class="flex">
|
||||
<el-input class="flex-1" v-model="state.list.Host" @change="handleSave" />
|
||||
<span>{{$t('server.messengerText')}}</span>
|
||||
<Sync class="mgl-1" name="SignInServer"></Sync>
|
||||
<span class="mgl-1">{{$t('server.messengerText')}}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('server.messengerSecretKey')">
|
||||
<div class="flex">
|
||||
<el-input class="flex-1" type="password" show-password maxlength="36" v-model="state.list.SecretKey" @change="handleSave" />
|
||||
<span>{{$t('server.messengerSecretKeyText')}}</span>
|
||||
<Sync class="mgl-1" name="SignInSecretKey"></Sync>
|
||||
<span class="mgl-1">{{$t('server.messengerSecretKeyText')}}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<RelayServers></RelayServers>
|
||||
<el-form-item :label="$t('server.messengerUserId')">
|
||||
<div class="flex">
|
||||
<el-input class="flex-1" type="password" show-password maxlength="36" v-model="state.list.UserId" @change="handleSave" />
|
||||
<Sync class="mgl-1" name="SignInUserId"></Sync>
|
||||
<span class="mgl-1">{{$t('server.messengerUserIdText')}}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<RelayServers class="mgt-2"></RelayServers>
|
||||
<SForward></SForward>
|
||||
<Updater></Updater>
|
||||
</el-form>
|
||||
@@ -38,8 +47,9 @@ import SForward from './SForward.vue';
|
||||
import Updater from './Updater.vue';
|
||||
import RelayServers from './RelayServers.vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import Sync from '../sync/Index.vue'
|
||||
export default {
|
||||
components:{SForward,Updater,RelayServers},
|
||||
components:{SForward,Updater,RelayServers,Sync},
|
||||
setup(props) {
|
||||
const {t} = useI18n();
|
||||
const globalData = injectGlobalData();
|
||||
|
@@ -2,10 +2,11 @@
|
||||
<el-form-item :label="$t('server.updaterSecretKey')">
|
||||
<div class="flex">
|
||||
<el-input class="flex-1" type="password" show-password v-model="state.secretKey" maxlength="36" @blur="handleChange"/>
|
||||
<span>{{$t('server.updaterText')}}</span>
|
||||
<Sync class="mgl-1" name="UpdaterSecretKey"></Sync>
|
||||
<span class="mgl-1">{{$t('server.updaterText')}}</span>
|
||||
</div>
|
||||
</el-form-item>
|
||||
<el-form-item :label="$t('server.updaterRate')">
|
||||
<!-- <el-form-item :label="$t('server.updaterRate')">
|
||||
<div>
|
||||
<div>
|
||||
<el-input-number v-model="state.year" :min="0" :max="99" style="width:12rem" @change="handleSecChange" /> {{$t('server.updaterY') }}
|
||||
@@ -18,7 +19,7 @@
|
||||
<el-input-number v-model="state.sec" :min="0" :max="99" style="width:12rem" @change="handleSecChange"/> {{$t('server.updaterS') }}
|
||||
</div>
|
||||
</div>
|
||||
</el-form-item>
|
||||
</el-form-item> -->
|
||||
</template>
|
||||
<script>
|
||||
import { getSecretKey,setSecretKey, setUpdateInterval } from '@/apis/updater';
|
||||
@@ -26,7 +27,9 @@ import { injectGlobalData } from '@/provide';
|
||||
import { ElMessage } from 'element-plus';
|
||||
import { onMounted, reactive } from 'vue'
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import Sync from '../sync/Index.vue'
|
||||
export default {
|
||||
components:{Sync},
|
||||
setup(props) {
|
||||
const {t} = useI18n();
|
||||
const globalData = injectGlobalData();
|
||||
|
33
src/linker.web/src/views/full/server/relay/Index.vue
Normal file
33
src/linker.web/src/views/full/server/relay/Index.vue
Normal file
@@ -0,0 +1,33 @@
|
||||
<template>
|
||||
<a href="javascript:;" class="mgl-1 a-line">{{$t('server.relayMyCdkey')}}</a>
|
||||
<a v-if="state.showManager && hasRelayCdkey" href="javascript:;" class="mgl-1 a-line">{{$t('server.relayCdkey')}}</a>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { relayCdkeyAccess } from '@/apis/relay';
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import { computed, onMounted, reactive } from 'vue';
|
||||
|
||||
export default {
|
||||
setup () {
|
||||
|
||||
const globalData = injectGlobalData();
|
||||
const hasRelayCdkey = computed(()=>globalData.value.hasAccess('RelayCdkey'));
|
||||
const state = reactive({
|
||||
showManager:false
|
||||
});
|
||||
|
||||
onMounted(()=>{
|
||||
relayCdkeyAccess().then(res=>{
|
||||
state.showManager = res;
|
||||
}).catch(()=>{})
|
||||
})
|
||||
|
||||
return {state,hasRelayCdkey}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
</style>
|
@@ -56,7 +56,6 @@ export default {
|
||||
const hasExport = computed(()=>globalData.value.hasAccess('Export'));
|
||||
const onlyNode = computed(()=>globalData.value.config.Client.OnlyNode);
|
||||
const machineId = computed(()=>globalData.value.config.Client.Id);
|
||||
console.log(globalData.value.config.Client);
|
||||
const state = reactive({
|
||||
show: false,
|
||||
loading:false,
|
||||
|
45
src/linker.web/src/views/full/sync/Index.vue
Normal file
45
src/linker.web/src/views/full/sync/Index.vue
Normal file
@@ -0,0 +1,45 @@
|
||||
<template>
|
||||
<div>
|
||||
<el-button class="btn" size="small" @click="handleSync"><el-icon><Share /></el-icon></el-button>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { setSync } from '@/apis/sync';
|
||||
import { injectGlobalData } from '@/provide';
|
||||
import {Share} from '@element-plus/icons-vue'
|
||||
import { ElMessage, ElMessageBox } from 'element-plus';
|
||||
import { computed } from 'vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
export default {
|
||||
props:['name'],
|
||||
components: {Share},
|
||||
setup (props) {
|
||||
const { t } = useI18n();
|
||||
const globalData = injectGlobalData();
|
||||
const hasSync = computed(()=>globalData.value.hasAccess('Sync'));
|
||||
const handleSync = ()=>{
|
||||
if(!hasSync.value){
|
||||
ElMessage.success(t('common.access'));
|
||||
return;
|
||||
}
|
||||
ElMessageBox.confirm(`${t('server.sync')} ${t(`server.async${props.name}`)} ? `, t('common.tips'), {
|
||||
confirmButtonText: t('common.confirm'),
|
||||
cancelButtonText:t('common.cancel'),
|
||||
type: 'warning'
|
||||
}).then(() => {
|
||||
setSync([props.name]).then(res => {
|
||||
ElMessage.success(t('common.oper'));
|
||||
});
|
||||
}).catch(() => {});
|
||||
|
||||
}
|
||||
return {
|
||||
handleSync
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="stylus" scoped>
|
||||
</style>
|
@@ -27,6 +27,11 @@
|
||||
</template>
|
||||
</el-table-column>
|
||||
<el-table-column prop="Order" :label="$t('status.tunnelSort')" width="104" fixed="right">
|
||||
<template #header>
|
||||
<div class="flex">
|
||||
<strong>{{ $t('status.tunnelSort') }}</strong><span class="flex-1"></span><Sync name="TunnelTransports"></Sync>
|
||||
</div>
|
||||
</template>
|
||||
<template #default="scope">
|
||||
<div>
|
||||
<el-input-number v-model="scope.row.Order" :min="1" :max="255" @change="handleOrderChange" size="small" />
|
||||
@@ -43,11 +48,12 @@ import { ElMessage } from 'element-plus';
|
||||
import { computed,reactive, watch } from 'vue'
|
||||
import { Delete,Plus,Top,Bottom } from '@element-plus/icons-vue';
|
||||
import { useI18n } from 'vue-i18n';
|
||||
import Sync from '../sync/Index.vue'
|
||||
export default {
|
||||
label:'打洞协议',
|
||||
name:'transports',
|
||||
order:2,
|
||||
components:{Delete,Plus,Top,Bottom},
|
||||
components:{Delete,Plus,Top,Bottom,Sync},
|
||||
setup(props) {
|
||||
const {t} = useI18n();
|
||||
const globalData = injectGlobalData();
|
||||
|
@@ -20,9 +20,14 @@
|
||||
<Title>linker</Title>
|
||||
<Authors>snltty</Authors>
|
||||
<Company>snltty</Company>
|
||||
<Description>1. 修复litedb抢锁超时导致客户端登录失败问题
|
||||
2. 同步信标服务器
|
||||
3. 其它一些修复优化</Description>
|
||||
<Description>1. 优化linux下路由跟踪问题
|
||||
2. 优化linux下获取本机IP问题
|
||||
3. 增加ICS,让win7+、win server2008+支持NAT
|
||||
4. 增加中继卡密
|
||||
5. 增加内外穿透定时开关功能
|
||||
6. 优化管理页面连接接口的体验
|
||||
7. 优化一些UI体验,去除同步页面,将同步功能放置各个实际的位置
|
||||
8. 其它一些修复优化</Description>
|
||||
<Copyright>snltty</Copyright>
|
||||
<PackageProjectUrl>https://github.com/snltty/linker</PackageProjectUrl>
|
||||
<RepositoryUrl>https://github.com/snltty/linker</RepositoryUrl>
|
||||
|
13
version.txt
13
version.txt
@@ -1,5 +1,10 @@
|
||||
v1.6.9
|
||||
2025-03-01 02:24:18
|
||||
1. 修复litedb抢锁超时导致客户端登录失败问题
|
||||
2. 同步信标服务器
|
||||
3. 其它一些修复优化
|
||||
2025-03-02 17:55:03
|
||||
1. 优化linux下路由跟踪问题
|
||||
2. 优化linux下获取本机IP问题
|
||||
3. 增加ICS,让win7+、win server2008+支持NAT
|
||||
4. 增加中继卡密
|
||||
5. 增加内外穿透定时开关功能
|
||||
6. 优化管理页面连接接口的体验
|
||||
7. 优化一些UI体验,去除同步页面,将同步功能放置各个实际的位置
|
||||
8. 其它一些修复优化
|
Reference in New Issue
Block a user