* LCIMClient.cs:

* LCIMSignature.cs:
* LCIMConversation.cs:
* LCIMSignatureAction.cs:
* ILCIMSignatureFactory.cs:
* LocalSignatureFactory.cs:

* Realtime.csproj: chore: 完善签名逻辑
oneRain 2020-03-23 16:21:32 +08:00
parent b0b85274ca
commit 92ee97d236
7 changed files with 244 additions and 10 deletions

View File

@ -115,8 +115,16 @@ namespace LeanCloud.Realtime {
Cid = Id,
};
conv.M.AddRange(clientIds);
// TODO 签名参数
// 签名参数
if (client.SignatureFactory != null) {
LCIMSignature signature = client.SignatureFactory.CreateConversationSignature(Id,
client.ClientId,
clientIds,
LCIMSignatureAction.Invite);
conv.S = signature.Signature;
conv.T = signature.Timestamp;
conv.N = signature.Nonce;
}
GenericCommand request = client.NewCommand(CommandType.Conv, OpType.Add);
request.ConvMessage = conv;
GenericCommand response = await client.connection.SendRequest(request);
@ -138,8 +146,16 @@ namespace LeanCloud.Realtime {
Cid = Id,
};
conv.M.AddRange(removeIds);
// TODO 签名参数
// 签名参数
if (client.SignatureFactory != null) {
LCIMSignature signature = client.SignatureFactory.CreateConversationSignature(Id,
client.ClientId,
removeIds,
LCIMSignatureAction.Kick);
conv.S = signature.Signature;
conv.T = signature.Timestamp;
conv.N = signature.Nonce;
}
GenericCommand request = client.NewCommand(CommandType.Conv, OpType.Remove);
request.ConvMessage = conv;
GenericCommand response = await client.connection.SendRequest(request);
@ -282,6 +298,15 @@ namespace LeanCloud.Realtime {
SrcCid = Id,
};
blacklist.ToPids.AddRange(clientIds);
if (client.SignatureFactory != null) {
LCIMSignature signature = client.SignatureFactory.CreateBlacklistSignature(Id,
client.ClientId,
clientIds,
LCIMSignatureAction.ConversationBlockClients);
blacklist.S = signature.Signature;
blacklist.T = signature.Timestamp;
blacklist.N = signature.Nonce;
}
GenericCommand request = client.NewCommand(CommandType.Blacklist, OpType.Block);
request.BlacklistMessage = blacklist;
GenericCommand response = await client.connection.SendRequest(request);
@ -296,6 +321,15 @@ namespace LeanCloud.Realtime {
SrcCid = Id,
};
blacklist.ToPids.AddRange(clientIds);
if (client.SignatureFactory != null) {
LCIMSignature signature = client.SignatureFactory.CreateBlacklistSignature(Id,
client.ClientId,
clientIds,
LCIMSignatureAction.ConversationUnblockClients);
blacklist.S = signature.Signature;
blacklist.T = signature.Timestamp;
blacklist.N = signature.Nonce;
}
GenericCommand request = client.NewCommand(CommandType.Blacklist, OpType.Unblock);
request.BlacklistMessage = blacklist;
GenericCommand response = await client.connection.SendRequest(request);
@ -467,5 +501,16 @@ namespace LeanCloud.Realtime {
MemberIdList = conv.M.ToList();
}
}
internal void MergeFrom(Dictionary<string, object> conv) {
if (conv.TryGetValue("objectId", out object idObj)) {
Id = idObj as string;
}
if (conv.TryGetValue("unique", out object uniqueObj)) {
}
}
}
}

View File

@ -79,8 +79,13 @@ namespace LeanCloud.Realtime {
get; set;
}
public LCIMClient(string clientId) {
internal ILCIMSignatureFactory SignatureFactory {
get; private set;
}
public LCIMClient(string clientId, ILCIMSignatureFactory signatureFactory = null) {
ClientId = clientId;
SignatureFactory = signatureFactory;
conversationDict = new Dictionary<string, LCIMConversation>();
}
@ -95,7 +100,14 @@ namespace LeanCloud.Realtime {
await connection.Connect();
// Open Session
GenericCommand request = NewCommand(CommandType.Session, OpType.Open);
request.SessionMessage = new SessionCommand();
SessionCommand session = new SessionCommand();
if (SignatureFactory != null) {
LCIMSignature signature = SignatureFactory.CreateConnectSignature(ClientId);
session.S = signature.Signature;
session.T = signature.Timestamp;
session.N = signature.Nonce;
}
request.SessionMessage = session;
GenericCommand response = await connection.SendRequest(request);
SessionToken = response.SessionMessage.St;
}
@ -139,7 +151,7 @@ namespace LeanCloud.Realtime {
bool temporary = false,
int temporaryTtl = 86400,
Dictionary<string, object> properties = null) {
GenericCommand command = NewCommand(CommandType.Conv, OpType.Start);
GenericCommand request = NewCommand(CommandType.Conv, OpType.Start);
ConvCommand conv = new ConvCommand {
Transient = transient,
Unique = unique,
@ -159,8 +171,14 @@ namespace LeanCloud.Realtime {
Data = JsonConvert.SerializeObject(LCEncoder.Encode(properties))
};
}
command.ConvMessage = conv;
GenericCommand response = await connection.SendRequest(command);
if (SignatureFactory != null) {
LCIMSignature signature = SignatureFactory.CreateStartConversationSignature(ClientId, members);
conv.S = signature.Signature;
conv.T = signature.Timestamp;
conv.N = signature.Nonce;
}
request.ConvMessage = conv;
GenericCommand response = await connection.SendRequest(request);
string convId = response.ConvMessage.Cid;
if (!conversationDict.TryGetValue(convId, out LCIMConversation conversation)) {
if (transient) {
@ -334,7 +352,7 @@ namespace LeanCloud.Realtime {
OnMessageReceived?.Invoke(null, message);
}
private LCIMConversation GetOrCreateConversation(string convId) {
internal LCIMConversation GetOrCreateConversation(string convId) {
if (!conversationDict.TryGetValue(convId, out LCIMConversation conversation)) {
conversation = new LCIMConversation(this);
conversationDict.Add(convId, conversation);

View File

@ -19,5 +19,6 @@
<Folder Include="Conversation\" />
<Folder Include="Message\" />
<Folder Include="Internal\WebSocket\" />
<Folder Include="Signature\" />
</ItemGroup>
</Project>

View File

@ -0,0 +1,38 @@
using System.Collections.Generic;
namespace LeanCloud.Realtime {
public interface ILCIMSignatureFactory {
/// <summary>
/// 登录签名
/// </summary>
/// <param name="clientId"></param>
/// <returns></returns>
LCIMSignature CreateConnectSignature(string clientId);
/// <summary>
/// 创建开启对话签名
/// </summary>
/// <returns></returns>
LCIMSignature CreateStartConversationSignature(string clientId, IEnumerable<string> memberIds);
/// <summary>
/// 创建会话相关签名
/// </summary>
/// <param name="conversationId"></param>
/// <param name="clientId"></param>
/// <param name="memberIds"></param>
/// <param name="action"></param>
/// <returns></returns>
LCIMSignature CreateConversationSignature(string conversationId, string clientId, IEnumerable<string> memberIds, string action);
/// <summary>
/// 创建黑名单相关签名
/// </summary>
/// <param name="conversationId"></param>
/// <param name="clientId"></param>
/// <param name="memberIds"></param>
/// <param name="action"></param>
/// <returns></returns>
LCIMSignature CreateBlacklistSignature(string conversationId, string clientId, IEnumerable<string> memberIds, string action);
}
}

View File

@ -0,0 +1,19 @@
namespace LeanCloud.Realtime {
public class LCIMSignature {
public string Signature {
get; set;
}
public long Timestamp {
get; set;
}
public string Nonce {
get; set;
}
public LCIMSignature() {
}
}
}

View File

@ -0,0 +1,17 @@
namespace LeanCloud.Realtime {
public static class LCIMSignatureAction {
// 邀请
public const string Invite = "invite";
// 踢出
public const string Kick = "kick";
//
public const string ClientBlockConversations = "client-block-conversations";
public const string ClientUnblockConversations = "client-unblock-conversations";
public const string ConversationBlockClients = "conversation-block-clients";
public const string ConversationUnblockClients = "conversation-unblock-clients";
}
}

View File

@ -0,0 +1,96 @@
using System;
using System.Text;
using System.Linq;
using System.Collections.Generic;
using System.Security.Cryptography;
using LeanCloud.Realtime;
using LeanCloud;
namespace RealtimeConsole {
public class LocalSignatureFactory : ILCIMSignatureFactory {
const string MasterKey = "pyvbNSh5jXsuFQ3C8EgnIdhw";
public LCIMSignature CreateConnectSignature(string clientId) {
long timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
string nonce = NewNonce();
string signature = GenerateSignature(LCApplication.AppId, clientId, string.Empty, timestamp.ToString(), nonce);
return new LCIMSignature {
Signature = signature,
Timestamp = timestamp,
Nonce = nonce
};
}
public LCIMSignature CreateStartConversationSignature(string clientId, IEnumerable<string> memberIds) {
string sortedMemberIds = string.Empty;
if (memberIds != null) {
List<string> sortedMemberList = memberIds.ToList();
sortedMemberList.Sort();
sortedMemberIds = string.Join(":", sortedMemberList);
}
long timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
string nonce = NewNonce();
string signature = GenerateSignature(LCApplication.AppId, clientId, sortedMemberIds, timestamp.ToString(), nonce);
return new LCIMSignature {
Signature = signature,
Timestamp = timestamp,
Nonce = nonce
};
}
public LCIMSignature CreateConversationSignature(string conversationId, string clientId, IEnumerable<string> memberIds, string action) {
string sortedMemberIds = string.Empty;
if (memberIds != null) {
List<string> sortedMemberList = memberIds.ToList();
sortedMemberList.Sort();
sortedMemberIds = string.Join(":", sortedMemberList);
}
long timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
string nonce = NewNonce();
string signature = GenerateSignature(LCApplication.AppId, clientId, conversationId, sortedMemberIds, timestamp.ToString(), nonce, action);
return new LCIMSignature {
Signature = signature,
Timestamp = timestamp,
Nonce = nonce
};
}
public LCIMSignature CreateBlacklistSignature(string conversationId, string clientId, IEnumerable<string> memberIds, string action) {
string sortedMemberIds = string.Empty;
if (memberIds != null) {
List<string> sortedMemberList = memberIds.ToList();
sortedMemberList.Sort();
sortedMemberIds = string.Join(":", sortedMemberList);
}
long timestamp = DateTimeOffset.Now.ToUnixTimeSeconds();
string nonce = NewNonce();
string signature = GenerateSignature(LCApplication.AppId, clientId, conversationId, sortedMemberIds, timestamp.ToString(), nonce, action);
return new LCIMSignature {
Signature = signature,
Timestamp = timestamp,
Nonce = nonce
};
}
private static string SignSHA1(string key, string text) {
HMACSHA1 hmac = new HMACSHA1(Encoding.UTF8.GetBytes(key));
byte[] bytes = hmac.ComputeHash(Encoding.UTF8.GetBytes(text));
string signature = BitConverter.ToString(bytes).Replace("-", string.Empty);
return signature;
}
private static string NewNonce() {
byte[] bytes = new byte[10];
using (RandomNumberGenerator generator = RandomNumberGenerator.Create()) {
generator.GetBytes(bytes);
}
return Convert.ToBase64String(bytes);
}
private static string GenerateSignature(params string[] args) {
string text = string.Join(":", args);
string signature = SignSHA1(MasterKey, text);
return signature;
}
}
}