using System;
using System.Collections.Generic;
using Top.Api.Util;
using System.Threading;
using Top.Api.Report;
namespace Top.Api.Security
{
///
/// 加、解密核心类
///
public class SecurityCore : SecurityConstants
{
private static readonly ITopLogger Log = Top.Api.Log.Instance;
// 缓存用户单独分配秘钥,需要加同步锁
private static readonly IDictionary AppUserSecretCache = new Dictionary();
private static readonly IDictionary AppSecretCache = new Dictionary();
private static readonly object EmptyObject = new object();
private static readonly object CacheLock = new object();
private static readonly object AppLock = new object();
private static readonly object AsynQueueKeyLock = new object();
private string randomNum;// 伪随机码
private DefaultTopClient topClient;
private static IDictionary asynQueueKey = new Dictionary();
private static readonly IDictionary> AllAppConfig = new Dictionary>();
private bool streetest;
public static IDictionary GetAppUserSecretCache()
{
return AppUserSecretCache;
}
///
/// 判断密文是否支持检索
///
///
///
///
public bool IsIndexEncrypt(string key, Nullable version)
{
if (version != null && version < 0)
{
key = PREVIOUS + key;
}
else
{
key = CURRENT + key;
}
IDictionary appConfig = getAppConfig();
if (appConfig == null)
{
return false;
}
object encryptType = null;
appConfig.TryGetValue(key, out encryptType);
return INDEX_ENCRYPT_TYPE.Equals(encryptType);
}
private IDictionary getAppConfig()
{
IDictionary appConfig = null;
AllAppConfig.TryGetValue(topClient.appKey, out appConfig);
return appConfig;
}
///
/// 获取压缩长度
///
///
public int GetCompressLen()
{
IDictionary appConfig = getAppConfig();
if (appConfig != null)
{
object compressLen = null;
appConfig.TryGetValue(ENCRYPT_INDEX_COMPRESS_LEN, out compressLen);
if (compressLen != null)
{
return Convert.ToInt32(compressLen);
}
}
return DEFAULT_INDEX_ENCRYPT_COMPRESS_LEN;
}
///
/// 获取滑动窗口大小
///
///
public int GetSlideSize()
{
IDictionary appConfig = getAppConfig();
if (appConfig != null)
{
object encryptSlideSize = null;
appConfig.TryGetValue(ENCRYPT_SLIDE_SIZE, out encryptSlideSize);
if (encryptSlideSize != null)
{
return Convert.ToInt32(encryptSlideSize);
}
}
return DEFAULT_ENCRYPT_SLIDE_SIZE;
}
public SecurityCore(DefaultTopClient topClient, string randomNum, bool streetest)
{
this.streetest = streetest;
this.topClient = topClient;
this.randomNum = randomNum;
// 初始化报表
ApiReporter apiReporter = new ApiReporter();
apiReporter.InitSecret(topClient);
}
public void SetRandomNum(string randomNum)
{
this.randomNum = randomNum;
}
///
/// 获取秘钥
///
///
///
///
public SecretContext GetSecret(string session, Nullable secretVersion)
{
SecretContext secretContext = GetSecret(session, GenerateSecretKey(session, secretVersion));
if (secretContext != null)
{
if (secretContext.IsValid())
{
return secretContext;
}
if (secretContext.IsMaxValid())
{
// 异步更新秘钥
AsynUpdateSecret(session, secretVersion);
return secretContext;
}
string cacheKey = GenerateSecretKey(session, secretVersion);
lock (CacheLock)
{
if (session != null)
{
AppUserSecretCache.Remove(cacheKey);
}
else
{
AppSecretCache.Remove(cacheKey);
}
}
// 同步调用获取秘钥
return CallSecretApi(session, secretVersion);
}
else
{
// 同步调用获取秘钥
return CallSecretApi(session, secretVersion);
}
}
private string GenerateSecretKey(string session, Nullable secretVersion)
{
if (session == null)
{
return this.topClient.appKey;
}
if (secretVersion == null)
{
return session;
}
return session + "_" + secretVersion;
}
///
/// 从本地获取秘钥信息
///
///
///
///
private SecretContext GetSecret(string session, string cacheKey)
{
SecretContext secretContext;
if (session != null)
{
AppUserSecretCache.TryGetValue(cacheKey, out secretContext);
}
else
{
AppSecretCache.TryGetValue(cacheKey, out secretContext);
}
return secretContext;
}
///
/// 调用获取秘钥api
///
///
///
///
private SecretContext CallSecretApi(string session, Nullable secretVersion)
{
// 获取伪随机码
if (string.IsNullOrEmpty(randomNum))
{
throw new ArgumentException("randomNum can`t be empty");
}
TopSecretGetRequest request = new TopSecretGetRequest();
request.RandomNum = randomNum;
request.SecretVersion = secretVersion;
if (streetest)
{
request.AddOtherParameter("tb_eagleeyex_t", "1");
}
TopSecretGetResponse response;
if (session != null && session.StartsWith(UNDERLINE))
{
string customerUserId = session.Substring(1);
if (!StringUtil.IsDigits(customerUserId))
{
throw new ArgumentException("session invalid");
}
request.CustomerUserId = Convert.ToInt64(customerUserId);
response = topClient.Execute(request, null);
}
else
{
response = topClient.Execute(request, session);
}
if (!response.IsError)
{
IDictionary appConfig = null;
if (!string.IsNullOrEmpty(response.AppConfig))
{
appConfig = (IDictionary)TopUtils.JsonToObject(response.AppConfig);
putAppConfig(appConfig);
}
SecretContext secretContext = new SecretContext();
if (response.Secret != null)
{
long currentTime = TopUtils.GetCurrentTimeMillis();
secretContext.InvalidTime = currentTime + (response.Interval * 1000);
secretContext.MaxInvalidTime = (currentTime + (response.MaxInterval * 1000));
secretContext.Secret = Convert.FromBase64String(response.Secret);
secretContext.SecretVersion = response.SecretVersion;
}
else
{
if (appConfig != null)
{
object publishStatus = null;
appConfig.TryGetValue(PUBLISH_STATUS, out publishStatus);
if (BETA_STATUS.Equals(publishStatus))
{
// 设置空缓存
SetNullCache(secretContext);
}
}
}
PutToCache(session, secretVersion, secretContext);
return secretContext;
}
else
{
// 查找不到历史秘钥
if ("20005".Equals(response.SubErrCode))
{
SecretContext secretContext = new SecretContext();
// 设置空缓存
SetNullCache(secretContext);
PutToCache(session, secretVersion, secretContext);
return secretContext;
}
throw new SecretException(response.ErrCode, response.ErrMsg, response.SubErrCode, response.SubErrMsg);
}
}
private void putAppConfig(IDictionary appConfig)
{
lock (AppLock)
{
if (!AllAppConfig.ContainsKey(topClient.appKey))
{
AllAppConfig.Add(topClient.appKey, appConfig);
}
}
}
private void PutToCache(string session, Nullable secretVersion, SecretContext secretContext)
{
string cacheKey = GenerateSecretKey(session, secretVersion);
lock (CacheLock)
{
if (session != null)
{
if (AppUserSecretCache.ContainsKey(cacheKey))
{
AppUserSecretCache[cacheKey] = secretContext;
}
else
{
AppUserSecretCache.Add(cacheKey, secretContext);
}
}
else
{
if (AppSecretCache.ContainsKey(cacheKey))
{
AppSecretCache[cacheKey] = secretContext;
}
else
{
AppSecretCache.Add(cacheKey, secretContext);
}
}
}
}
///
/// 设置空缓存
///
///
private void SetNullCache(SecretContext secretContext)
{
long currentTime = TopUtils.GetCurrentTimeMillis();
secretContext.InvalidTime = currentTime + (DEFAULT_INTERVAL * 1000);
secretContext.MaxInvalidTime = currentTime + (DEFAULT_MAX_INTERVAL * 1000);
}
///
/// 异步更新秘钥
///
///
///
private void AsynUpdateSecret(string session, Nullable secretVersion)
{
string cacheKey = GenerateSecretKey(session, secretVersion);
lock (AsynQueueKeyLock)
{
// 不需要重复提交秘钥请求
if (asynQueueKey.ContainsKey(cacheKey))
{
return;
}
SecretContext secretContext = GetSecret(session, GenerateSecretKey(session, secretVersion));
if (secretContext != null && secretContext.IsValid())
{
return;
}
asynQueueKey.Add(cacheKey, EmptyObject);
}
WaitCallback secretApiCallback = (state) =>
{
try
{
CallSecretApi(session, secretVersion);
}
catch (Exception e)
{
Log.Error(string.Format("asyn update secret error: {0}", e.Message));
}
finally
{
lock (AsynQueueKeyLock)
{
asynQueueKey.Remove(cacheKey);
}
}
};
try
{
ThreadPool.QueueUserWorkItem(secretApiCallback);
}
catch (Exception e)
{
lock (AsynQueueKeyLock)
{
asynQueueKey.Remove(cacheKey);
}
Log.Error(string.Format("add QueueUserWorkItem error: {0}", e.Message));
}
}
}
}