Merge branch 'feature/backend-refactor' into feature/asc-federatedlogin-refactor

This commit is contained in:
Maksim Chegulov 2022-02-14 17:54:26 +03:00
commit aa102f9435
162 changed files with 7964 additions and 8010 deletions

2
.gitignore vendored
View File

@ -10,7 +10,7 @@
/build/deploy
*.log
/products/ASC.People/Data/
Data/
/Data
Logs/
**/.DS_Store
.eslintcache

View File

@ -76,11 +76,11 @@ public abstract class BaseStartup
if (kafkaConfiguration != null)
{
DIHelper.TryAdd(typeof(ICacheNotify<>), typeof(KafkaCache<>));
DIHelper.TryAdd(typeof(ICacheNotify<>), typeof(KafkaCacheNotify<>));
}
else if (redisConfiguration != null)
{
DIHelper.TryAdd(typeof(ICacheNotify<>), typeof(RedisCache<>));
DIHelper.TryAdd(typeof(ICacheNotify<>), typeof(RedisCacheNotify<>));
services.AddStackExchangeRedisExtensions<NewtonsoftSerializer>(redisConfiguration);
}

View File

@ -18,7 +18,7 @@ global using System.Threading;
global using System.Threading.Tasks;
global using System.Web;
global using System.Xml.Linq;
global using StackExchange.Redis.Extensions.Newtonsoft;
global using ASC.Api.Core;
global using ASC.Api.Core.Auth;
global using ASC.Api.Core.Convention;
@ -81,3 +81,4 @@ global using NLog;
global using NLog.Extensions.Logging;
global using StackExchange.Redis.Extensions.Core.Configuration;
global using StackExchange.Redis.Extensions.Newtonsoft;

View File

@ -24,9 +24,6 @@
<EmbeddedResource Include="Utils\TimeZoneConverter\windowsZones.xml" />
<EmbeddedResource Include="Utils\TimeZoneConverter\timeZoneNames.xml" />
</ItemGroup>
<ItemGroup>
<Compile Remove="Notify\AWSEmail.cs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="ARSoft.Tools.NetStandard.DXSdata" Version="1.0.0" />
<PackageReference Include="Autofac.Configuration" Version="6.0.0" />
@ -64,7 +61,4 @@
<Protobuf Include="protos\distributed_task_cache.proto" />
<Protobuf Include="protos\distributed_task_cancelation.proto" />
</ItemGroup>
<ItemGroup>
<Folder Include="Notify\" />
</ItemGroup>
</Project>

View File

@ -23,24 +23,21 @@
*
*/
namespace ASC.Common.Caching
{
namespace ASC.Common.Caching;
[Singletone]
public class AscCacheNotify
{
private ICacheNotify<AscCacheItem> CacheNotify { get; }
private readonly ICacheNotify<AscCacheItem> _cacheNotify;
public AscCacheNotify(ICacheNotify<AscCacheItem> cacheNotify)
{
CacheNotify = cacheNotify;
_cacheNotify = cacheNotify;
CacheNotify.Subscribe((item) => { OnClearCache(); }, CacheNotifyAction.Any);
_cacheNotify.Subscribe((item) => { OnClearCache(); }, CacheNotifyAction.Any);
}
public void ClearCache()
{
CacheNotify.Publish(new AscCacheItem { Id = Guid.NewGuid().ToString() }, CacheNotifyAction.Any);
}
public void ClearCache() => _cacheNotify.Publish(new AscCacheItem { Id = Guid.NewGuid().ToString() }, CacheNotifyAction.Any);
public static void OnClearCache()
{
@ -56,18 +53,18 @@ namespace ASC.Common.Caching
[Singletone]
public class AscCache : ICache
{
private IMemoryCache MemoryCache { get; }
private ConcurrentDictionary<string, object> MemoryCacheKeys { get; }
private readonly IMemoryCache _memoryCache;
private readonly ConcurrentDictionary<string, object> _memoryCacheKeys;
public AscCache(IMemoryCache memoryCache)
{
MemoryCache = memoryCache;
MemoryCacheKeys = new ConcurrentDictionary<string, object>();
_memoryCache = memoryCache;
_memoryCacheKeys = new ConcurrentDictionary<string, object>();
}
public T Get<T>(string key) where T : class
{
return MemoryCache.Get<T>(key);
return _memoryCache.Get<T>(key);
}
public void Insert(string key, object value, TimeSpan sligingExpiration)
@ -76,8 +73,8 @@ namespace ASC.Common.Caching
.SetSlidingExpiration(sligingExpiration)
.RegisterPostEvictionCallback(EvictionCallback);
MemoryCache.Set(key, value, options);
MemoryCacheKeys.TryAdd(key, null);
_memoryCache.Set(key, value, options);
_memoryCacheKeys.TryAdd(key, null);
}
public void Insert(string key, object value, DateTime absolutExpiration)
@ -86,43 +83,37 @@ namespace ASC.Common.Caching
.SetAbsoluteExpiration(absolutExpiration == DateTime.MaxValue ? DateTimeOffset.MaxValue : new DateTimeOffset(absolutExpiration))
.RegisterPostEvictionCallback(EvictionCallback);
MemoryCache.Set(key, value, options);
MemoryCacheKeys.TryAdd(key, null);
}
private void EvictionCallback(object key, object value, EvictionReason reason, object state)
{
MemoryCacheKeys.TryRemove(key.ToString(), out _);
_memoryCache.Set(key, value, options);
_memoryCacheKeys.TryAdd(key, null);
}
public void Remove(string key)
{
MemoryCache.Remove(key);
_memoryCache.Remove(key);
}
public void Remove(Regex pattern)
{
var copy = MemoryCacheKeys.ToDictionary(p => p.Key, p => p.Value);
var copy = _memoryCacheKeys.ToDictionary(p => p.Key, p => p.Value);
var keys = copy.Select(p => p.Key).Where(k => pattern.IsMatch(k));
foreach (var key in keys)
{
MemoryCache.Remove(key);
_memoryCache.Remove(key);
}
}
public ConcurrentDictionary<string, T> HashGetAll<T>(string key)
{
return MemoryCache.GetOrCreate(key, r => new ConcurrentDictionary<string, T>());
}
public ConcurrentDictionary<string, T> HashGetAll<T>(string key) =>
_memoryCache.GetOrCreate(key, r => new ConcurrentDictionary<string, T>());
public T HashGet<T>(string key, string field)
{
if (MemoryCache.TryGetValue<ConcurrentDictionary<string, T>>(key, out var dic) && dic.TryGetValue(field, out var value))
if (_memoryCache.TryGetValue<ConcurrentDictionary<string, T>>(key, out var dic)
&& dic.TryGetValue(field, out var value))
{
return value;
}
return default;
}
@ -132,20 +123,25 @@ namespace ASC.Common.Caching
if (value != null)
{
dic.AddOrUpdate(field, value, (k, v) => value);
MemoryCache.Set(key, dic, DateTime.MaxValue);
_memoryCache.Set(key, dic, DateTime.MaxValue);
}
else if (dic != null)
{
dic.TryRemove(field, out _);
if (dic.Count == 0)
if (dic.IsEmpty)
{
MemoryCache.Remove(key);
_memoryCache.Remove(key);
}
else
{
MemoryCache.Set(key, dic, DateTime.MaxValue);
_memoryCache.Set(key, dic, DateTime.MaxValue);
}
}
}
private void EvictionCallback(object key, object value, EvictionReason reason, object state)
{
_memoryCacheKeys.TryRemove(key.ToString(), out _);
}
}

View File

@ -23,8 +23,8 @@
*
*/
namespace ASC.Common.Caching
{
namespace ASC.Common.Caching;
[Flags]
public enum CacheNotifyAction
{
@ -34,4 +34,3 @@ namespace ASC.Common.Caching
InsertOrUpdate = Insert | Update,
Any = InsertOrUpdate | Remove,
}
}

View File

@ -23,8 +23,8 @@
*
*/
namespace ASC.Common.Caching
{
namespace ASC.Common.Caching;
[Singletone(typeof(AscCache))]
public interface ICache
{
@ -38,11 +38,9 @@ namespace ASC.Common.Caching
void Remove(Regex pattern);
ConcurrentDictionary<string, T> HashGetAll<T>(string key);
T HashGet<T>(string key, string field);
void HashSet<T>(string key, string field, T value);
}
}

View File

@ -23,8 +23,8 @@
*
*/
namespace ASC.Common.Caching
{
namespace ASC.Common.Caching;
[Singletone]
public interface ICacheNotify<T> where T : IMessage<T>, new()
{
@ -34,4 +34,3 @@ namespace ASC.Common.Caching
void Unsubscribe(CacheNotifyAction action);
}
}

View File

@ -1,199 +0,0 @@
namespace ASC.Common.Caching
{
[Singletone]
public class KafkaCache<T> : IDisposable, ICacheNotify<T> where T : IMessage<T>, new()
{
private ClientConfig ClientConfig { get; set; }
private AdminClientConfig AdminClientConfig { get; set; }
private ILog Log { get; set; }
private ConcurrentDictionary<string, CancellationTokenSource> Cts { get; set; }
private ConcurrentDictionary<string, Action<T>> Actions { get; set; }
private ProtobufSerializer<T> ValueSerializer { get; } = new ProtobufSerializer<T>();
private ProtobufDeserializer<T> ValueDeserializer { get; } = new ProtobufDeserializer<T>();
private ProtobufSerializer<AscCacheItem> KeySerializer { get; } = new ProtobufSerializer<AscCacheItem>();
private ProtobufDeserializer<AscCacheItem> KeyDeserializer { get; } = new ProtobufDeserializer<AscCacheItem>();
private IProducer<AscCacheItem, T> Producer { get; set; }
private Guid Key { get; set; }
public KafkaCache(ConfigurationExtension configuration, IOptionsMonitor<ILog> options)
{
Log = options.CurrentValue;
Cts = new ConcurrentDictionary<string, CancellationTokenSource>();
Actions = new ConcurrentDictionary<string, Action<T>>();
Key = Guid.NewGuid();
var settings = configuration.GetSetting<KafkaSettings>("kafka");
ClientConfig = new ClientConfig { BootstrapServers = settings.BootstrapServers };
AdminClientConfig = new AdminClientConfig { BootstrapServers = settings.BootstrapServers };
}
public void Publish(T obj, CacheNotifyAction cacheNotifyAction)
{
try
{
if (Producer == null)
{
Producer = new ProducerBuilder<AscCacheItem, T>(new ProducerConfig(ClientConfig))
.SetErrorHandler((_, e) => Log.Error(e))
.SetKeySerializer(KeySerializer)
.SetValueSerializer(ValueSerializer)
.Build();
}
var channelName = GetChannelName(cacheNotifyAction);
if (Actions.TryGetValue(channelName, out var onchange))
{
onchange(obj);
}
var message = new Message<AscCacheItem, T>
{
Value = obj,
Key = new AscCacheItem
{
Id = Key.ToString()
}
};
Producer.ProduceAsync(channelName, message);
}
catch (ProduceException<Null, string> e)
{
Log.Error(e);
}
catch (Exception e)
{
Log.Error(e);
}
}
public void Subscribe(Action<T> onchange, CacheNotifyAction cacheNotifyAction)
{
var channelName = GetChannelName(cacheNotifyAction);
Cts[channelName] = new CancellationTokenSource();
Actions[channelName] = onchange;
void action()
{
var conf = new ConsumerConfig(ClientConfig)
{
GroupId = Guid.NewGuid().ToString()
};
using (var adminClient = new AdminClientBuilder(AdminClientConfig)
.SetErrorHandler((_, e) => Log.Error(e))
.Build())
{
try
{
//TODO: must add checking exist
adminClient.CreateTopicsAsync(
new TopicSpecification[]
{
new TopicSpecification
{
Name = channelName,
NumPartitions = 1,
ReplicationFactor = 1
}
}).Wait();
}
catch (AggregateException)
{
}
}
using var c = new ConsumerBuilder<AscCacheItem, T>(conf)
.SetErrorHandler((_, e) => Log.Error(e))
.SetKeyDeserializer(KeyDeserializer)
.SetValueDeserializer(ValueDeserializer)
.Build();
c.Assign(new TopicPartition(channelName, new Partition()));
try
{
while (true)
{
try
{
var cr = c.Consume(Cts[channelName].Token);
if (cr != null && cr.Message != null && cr.Message.Value != null && !(new Guid(cr.Message.Key.Id)).Equals(Key) && Actions.TryGetValue(channelName, out var act))
{
try
{
act(cr.Message.Value);
}
catch (Exception e)
{
Log.Error("Kafka onmessage", e);
}
}
}
catch (ConsumeException e)
{
Log.Error(e);
}
}
}
catch (OperationCanceledException)
{
c.Close();
}
}
var task = new Task(action, TaskCreationOptions.LongRunning);
task.Start();
}
private string GetChannelName(CacheNotifyAction cacheNotifyAction)
{
return $"ascchannel{cacheNotifyAction}{typeof(T).FullName}".ToLower();
}
public void Unsubscribe(CacheNotifyAction action)
{
Cts.TryGetValue(GetChannelName(action), out var source);
if (source != null)
{
source.Cancel();
}
}
private bool disposedValue = false; // To detect redundant calls
protected virtual void Dispose(bool disposing)
{
if (!disposedValue)
{
if (disposing && Producer != null)
{
Producer.Dispose();
}
disposedValue = true;
}
}
~KafkaCache()
{
Dispose(false);
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
public class KafkaSettings
{
public string BootstrapServers { get; set; }
}
}

View File

@ -0,0 +1,196 @@
namespace ASC.Common.Caching;
[Singletone]
public class KafkaCacheNotify<T> : IDisposable, ICacheNotify<T> where T : IMessage<T>, new()
{
private IProducer<AscCacheItem, T> _producer;
private bool _disposedValue = false; // To detect redundant calls
private readonly ClientConfig _clientConfig;
private readonly AdminClientConfig _adminClientConfig;
private readonly ILog _logger;
private readonly ConcurrentDictionary<string, CancellationTokenSource> _cancelationToken;
private readonly ConcurrentDictionary<string, Action<T>> _actions;
private readonly ProtobufSerializer<T> _valueSerializer = new ProtobufSerializer<T>();
private readonly ProtobufDeserializer<T> _valueDeserializer = new ProtobufDeserializer<T>();
private readonly ProtobufSerializer<AscCacheItem> _keySerializer = new ProtobufSerializer<AscCacheItem>();
private readonly ProtobufDeserializer<AscCacheItem> _keyDeserializer = new ProtobufDeserializer<AscCacheItem>();
private readonly Guid _key;
public KafkaCacheNotify(ConfigurationExtension configuration, IOptionsMonitor<ILog> options)
{
_logger = options.CurrentValue;
_cancelationToken = new ConcurrentDictionary<string, CancellationTokenSource>();
_actions = new ConcurrentDictionary<string, Action<T>>();
_key = Guid.NewGuid();
var settings = configuration.GetSetting<KafkaSettings>("kafka");
_clientConfig = new ClientConfig { BootstrapServers = settings.BootstrapServers };
_adminClientConfig = new AdminClientConfig { BootstrapServers = settings.BootstrapServers };
}
public void Publish(T obj, CacheNotifyAction notifyAction)
{
try
{
if (_producer == null)
{
_producer = new ProducerBuilder<AscCacheItem, T>(new ProducerConfig(_clientConfig))
.SetErrorHandler((_, e) => _logger.Error(e))
.SetKeySerializer(_keySerializer)
.SetValueSerializer(_valueSerializer)
.Build();
}
var channelName = GetChannelName(notifyAction);
if (_actions.TryGetValue(channelName, out var onchange))
{
onchange(obj);
}
var message = new Message<AscCacheItem, T>
{
Value = obj,
Key = new AscCacheItem
{
Id = _key.ToString()
}
};
_producer.ProduceAsync(channelName, message);
}
catch (ProduceException<Null, string> e)
{
_logger.Error(e);
}
catch (Exception e)
{
_logger.Error(e);
}
}
public void Subscribe(Action<T> onchange, CacheNotifyAction notifyAction)
{
var channelName = GetChannelName(notifyAction);
_cancelationToken[channelName] = new CancellationTokenSource();
_actions[channelName] = onchange;
void action()
{
var conf = new ConsumerConfig(_clientConfig)
{
GroupId = Guid.NewGuid().ToString()
};
using (var adminClient = new AdminClientBuilder(_adminClientConfig)
.SetErrorHandler((_, e) => _logger.Error(e))
.Build())
{
try
{
//TODO: must add checking exist
adminClient.CreateTopicsAsync(
new TopicSpecification[]
{
new TopicSpecification
{
Name = channelName,
NumPartitions = 1,
ReplicationFactor = 1
}
}).Wait();
}
catch (AggregateException) { }
}
using var c = new ConsumerBuilder<AscCacheItem, T>(conf)
.SetErrorHandler((_, e) => _logger.Error(e))
.SetKeyDeserializer(_keyDeserializer)
.SetValueDeserializer(_valueDeserializer)
.Build();
c.Assign(new TopicPartition(channelName, new Partition()));
try
{
while (true)
{
try
{
var cr = c.Consume(_cancelationToken[channelName].Token);
if (cr != null && cr.Message != null && cr.Message.Value != null && !(new Guid(cr.Message.Key.Id)).Equals(_key) && _actions.TryGetValue(channelName, out var act))
{
try
{
act(cr.Message.Value);
}
catch (Exception e)
{
_logger.Error("Kafka onmessage", e);
}
}
}
catch (ConsumeException e)
{
_logger.Error(e);
}
}
}
catch (OperationCanceledException)
{
c.Close();
}
}
var task = new Task(action, TaskCreationOptions.LongRunning);
task.Start();
}
public void Unsubscribe(CacheNotifyAction notifyAction)
{
_cancelationToken.TryGetValue(GetChannelName(notifyAction), out var source);
if (source != null)
{
source.Cancel();
}
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!_disposedValue)
{
if (disposing && _producer != null)
{
_producer.Dispose();
}
_disposedValue = true;
}
}
~KafkaCacheNotify()
{
Dispose(false);
}
private string GetChannelName(CacheNotifyAction notifyAction)
{
return $"ascchannel{notifyAction}{typeof(T).FullName}".ToLower();
}
}
public class KafkaSettings
{
public string BootstrapServers { get; set; }
}

View File

@ -1,5 +1,5 @@
namespace ASC.Common.Caching
{
namespace ASC.Common.Caching;
[Singletone]
public class MemoryCacheNotify<T> : ICacheNotify<T> where T : IMessage<T>, new()
{
@ -10,9 +10,9 @@
_actions = new ConcurrentDictionary<string, List<Action<T>>>();
}
public void Publish(T obj, CacheNotifyAction action)
public void Publish(T obj, CacheNotifyAction notifyAction)
{
if (_actions.TryGetValue(GetKey(action), out var onchange) && onchange != null)
if (_actions.TryGetValue(GetKey(notifyAction), out var onchange) && onchange != null)
{
Parallel.ForEach(onchange, a => a(obj));
}
@ -27,14 +27,13 @@
}
}
public void Unsubscribe(CacheNotifyAction action)
public void Unsubscribe(CacheNotifyAction notifyAction)
{
_actions.TryRemove(GetKey(action), out _);
_actions.TryRemove(GetKey(notifyAction), out _);
}
private string GetKey(CacheNotifyAction cacheNotifyAction)
private string GetKey(CacheNotifyAction notifyAction)
{
return $"asc:channel:{cacheNotifyAction}:{typeof(T).FullName}".ToLower();
}
return $"asc:channel:{notifyAction}:{typeof(T).FullName}".ToLower();
}
}

View File

@ -1,5 +1,5 @@
namespace ASC.Common.Caching
{
namespace ASC.Common.Caching;
public class ProtobufSerializer<T> : ISerializer<T> where T : IMessage<T>, new()
{
public byte[] Serialize(T data, SerializationContext context)
@ -10,28 +10,22 @@
public class ProtobufDeserializer<T> : IDeserializer<T> where T : IMessage<T>, new()
{
private readonly MessageParser<T> parser;
private readonly MessageParser<T> _parser;
public ProtobufDeserializer()
{
parser = new MessageParser<T>(() => new T());
_parser = new MessageParser<T>(() => new T());
}
public T Deserialize(ReadOnlySpan<byte> data, bool isNull, SerializationContext context)
{
return parser.ParseFrom(data.ToArray());
return _parser.ParseFrom(data.ToArray());
}
}
public static class GuidExtension
{
public static ByteString ToByteString(this Guid id)
{
return ByteString.CopyFrom(id.ToByteArray());
}
public static Guid FromByteString(this ByteString id)
{
return new Guid(id.ToByteArray());
}
}
public static ByteString ToByteString(this Guid id) => ByteString.CopyFrom(id.ToByteArray());
public static Guid FromByteString(this ByteString id) => new Guid(id.ToByteArray());
}

View File

@ -17,11 +17,11 @@
namespace ASC.Common.Caching;
[Singletone]
public class RedisCache<T> : ICacheNotify<T> where T : IMessage<T>, new()
public class RedisCacheNotify<T> : ICacheNotify<T> where T : IMessage<T>, new()
{
private readonly IRedisDatabase _redis;
public RedisCache(IRedisCacheClient redisCacheClient)
public RedisCacheNotify(IRedisCacheClient redisCacheClient)
{
_redis = redisCacheClient.GetDbFromConfiguration();
}
@ -53,9 +53,9 @@ public class RedisCache<T> : ICacheNotify<T> where T : IMessage<T>, new()
.GetResult();
}
private string GetChannelName(CacheNotifyAction cacheNotifyAction)
private string GetChannelName(CacheNotifyAction action)
{
return $"asc:channel:{cacheNotifyAction}:{typeof(T).FullName}".ToLower();
return $"asc:channel:{action}:{typeof(T).FullName}".ToLower();
}
class RedisCachePubSubItem<T0>
@ -65,6 +65,3 @@ public class RedisCache<T> : ICacheNotify<T> where T : IMessage<T>, new()
public CacheNotifyAction Action { get; set; }
}
}

View File

@ -23,28 +23,22 @@
*
*/
namespace ASC.Collections
{
namespace ASC.Collections;
public abstract class CachedDictionaryBase<T>
{
protected string baseKey;
protected Func<T, bool> condition;
protected string BaseKey { get; set; }
protected Func<T, bool> Condition { get; set; }
public T this[string key]
{
get { return Get(key); }
}
public T this[string key] => Get(key);
public T this[Func<T> @default]
{
get { return Get(@default); }
}
public T this[Func<T> @default] => Get(@default);
protected abstract void InsertRootKey(string rootKey);
public void Clear()
{
InsertRootKey(baseKey);
InsertRootKey(BaseKey);
}
public void Clear(string rootKey)
@ -57,8 +51,6 @@ namespace ASC.Collections
Reset(string.Empty, key);
}
public abstract void Reset(string rootKey, string key);
public T Get(string key)
{
return Get(string.Empty, key, null);
@ -69,26 +61,16 @@ namespace ASC.Collections
return Get(string.Empty, key, defaults);
}
public void Add(string key, T newValue)
{
Add(string.Empty, key, newValue);
}
public abstract void Add(string rootkey, string key, T newValue);
public bool HasItem(string key)
{
return !Equals(Get(key), default(T));
}
protected string BuildKey(string key, string rootkey)
{
return $"{baseKey}-{rootkey}-{key}";
}
protected abstract object GetObjectFromCache(string fullKey);
public T Get(Func<T> @default)
{
var key = string.Format("func {0} {2}.{1}({3})", @default.Method.ReturnType, @default.Method.Name,
@ -99,38 +81,53 @@ namespace ASC.Collections
return Get(key, @default);
}
protected virtual bool FitsCondition(object cached)
{
return cached is T;
}
public virtual T Get(string rootkey, string key, Func<T> defaults)
{
var fullKey = BuildKey(key, rootkey);
var objectCache = GetObjectFromCache(fullKey);
if (FitsCondition(objectCache))
{
OnHit(fullKey);
return ReturnCached(objectCache);
}
if (defaults != null)
{
OnMiss(fullKey);
var newValue = defaults();
if (condition == null || condition(newValue))
{
if (Condition == null || Condition(newValue))
Add(rootkey, key, newValue);
}
return newValue;
}
return default;
}
public abstract void Add(string rootkey, string key, T newValue);
public abstract void Reset(string rootKey, string key);
protected virtual bool FitsCondition(object cached)
{
return cached is T;
}
protected virtual T ReturnCached(object objectCache)
{
return (T)objectCache;
}
protected string BuildKey(string key, string rootkey)
{
return $"{BaseKey}-{rootkey}-{key}";
}
protected abstract object GetObjectFromCache(string fullKey);
[Conditional("DEBUG")]
protected virtual void OnHit(string fullKey)
{
@ -143,4 +140,3 @@ namespace ASC.Collections
Debug.Print("cache miss:{0}", fullKey);
}
}
}

View File

@ -23,10 +23,61 @@
*
*/
namespace ASC.Collections
{
namespace ASC.Collections;
public sealed class HttpRequestDictionary<T> : CachedDictionaryBase<T>
{
private readonly HttpContext _httpContext;
public HttpRequestDictionary(HttpContext httpContext, string baseKey)
{
Condition = (T) => true;
BaseKey = baseKey;
_httpContext = httpContext;
}
public override void Reset(string rootKey, string key)
{
if (_httpContext != null)
{
var builtkey = BuildKey(key, rootKey);
_httpContext.Items[builtkey] = null;
}
}
public override void Add(string rootkey, string key, T newValue)
{
if (_httpContext != null)
{
var builtkey = BuildKey(key, rootkey);
_httpContext.Items[builtkey] = new CachedItem(newValue);
}
}
protected override object GetObjectFromCache(string fullKey)
{
return _httpContext?.Items[fullKey];
}
protected override bool FitsCondition(object cached)
{
return cached is CachedItem;
}
protected override T ReturnCached(object objectCache)
{
return ((CachedItem)objectCache).Value;
}
protected override void OnHit(string fullKey) { }
protected override void OnMiss(string fullKey) { }
protected override void InsertRootKey(string rootKey)
{
//We can't expire in HtppContext in such way
}
private sealed class CachedItem
{
internal T Value { get; set; }
@ -36,60 +87,4 @@ namespace ASC.Collections
Value = value;
}
}
HttpContext HttpContext { get; set; }
public HttpRequestDictionary(HttpContext httpContext, string baseKey)
{
condition = (T) => true;
this.baseKey = baseKey;
HttpContext = httpContext;
}
protected override void InsertRootKey(string rootKey)
{
//We can't expire in HtppContext in such way
}
public override void Reset(string rootKey, string key)
{
if (HttpContext != null)
{
var builtkey = BuildKey(key, rootKey);
HttpContext.Items[builtkey] = null;
}
}
public override void Add(string rootkey, string key, T newValue)
{
if (HttpContext != null)
{
var builtkey = BuildKey(key, rootkey);
HttpContext.Items[builtkey] = new CachedItem(newValue);
}
}
protected override object GetObjectFromCache(string fullKey)
{
return HttpContext?.Items[fullKey];
}
protected override bool FitsCondition(object cached)
{
return cached is CachedItem;
}
protected override T ReturnCached(object objectCache)
{
return ((CachedItem)objectCache).Value;
}
protected override void OnHit(string fullKey)
{
}
protected override void OnMiss(string fullKey)
{
}
}
}

View File

@ -1,5 +1,5 @@
namespace ASC.Common
{
namespace ASC.Common;
public enum DIAttributeEnum
{
Singletone,
@ -9,7 +9,7 @@
public class TransientAttribute : DIAttribute
{
public override DIAttributeEnum DIAttributeEnum { get => DIAttributeEnum.Transient; }
public override DIAttributeEnum DIAttributeEnum => DIAttributeEnum.Transient;
public TransientAttribute() { }
@ -32,7 +32,7 @@
public class ScopeAttribute : DIAttribute
{
public override DIAttributeEnum DIAttributeEnum { get => DIAttributeEnum.Scope; }
public override DIAttributeEnum DIAttributeEnum => DIAttributeEnum.Scope;
public ScopeAttribute() { }
@ -55,7 +55,7 @@
public class SingletoneAttribute : DIAttribute
{
public override DIAttributeEnum DIAttributeEnum { get => DIAttributeEnum.Singletone; }
public override DIAttributeEnum DIAttributeEnum => DIAttributeEnum.Singletone;
public SingletoneAttribute() { }
@ -114,6 +114,7 @@
{ DIAttributeEnum.Scope, new List<string>() },
{ DIAttributeEnum.Transient, new List<string>() }
};
Added = new List<string>();
Configured = new List<string>();
}
@ -157,6 +158,7 @@
))
{
service = service.GetGenericArguments().FirstOrDefault();
if (service == null)
{
return false;
@ -164,7 +166,12 @@
}
var serviceName = $"{service}{implementation}";
if (Added.Contains(serviceName)) return false;
if (Added.Contains(serviceName))
{
return false;
}
Added.Add(serviceName);
var di = service.IsGenericType && (
@ -172,6 +179,7 @@
service.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
) && implementation != null ? implementation.GetCustomAttribute<DIAttribute>() : service.GetCustomAttribute<DIAttribute>();
var isnew = false;
if (di != null)
@ -185,7 +193,10 @@
if (!service.IsInterface || implementation != null)
{
isnew = implementation != null ? Register(service, implementation) : Register(service);
if (!isnew) return false;
if (!isnew)
{
return false;
}
}
if (service.IsInterface && implementation == null || !service.IsInterface)
@ -197,6 +208,7 @@
x.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
x.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
));
if (a != null)
{
if (!a.ContainsGenericParameters)
@ -208,6 +220,7 @@
if (g != service)
{
TryAdd(g);
if (service.IsInterface && di.Implementation == null)
{
TryAdd(service, g);
@ -250,7 +263,6 @@
{
Register(di.Service);
}
}
}
@ -303,6 +315,7 @@
//a, di.Service
}
}
else
{
isnew = TryAdd(service, di.Implementation);
@ -331,6 +344,7 @@
if (props != null)
{
var par = props.SelectMany(r => r.GetParameters()).Distinct();
foreach (var p1 in par)
{
TryAdd(p1.ParameterType);
@ -341,29 +355,10 @@
return isnew;
}
private bool Register(Type service, Type implementation = null)
{
if (service.IsSubclassOf(typeof(ControllerBase)) || service.GetInterfaces().Contains(typeof(IResourceFilter)) || service.GetInterfaces().Contains(typeof(IDictionary<string, string>))) return true;
var c = service.IsGenericType && (
service.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
) && implementation != null ? implementation.GetCustomAttribute<DIAttribute>() : service.GetCustomAttribute<DIAttribute>();
var serviceName = $"{service}{implementation}";
if (!Services[c.DIAttributeEnum].Contains(serviceName))
{
c.TryAdd(ServiceCollection, service, implementation);
Services[c.DIAttributeEnum].Add(serviceName);
return true;
}
return false;
}
public DIHelper TryAddSingleton<TService>(Func<IServiceProvider, TService> implementationFactory) where TService : class
{
var serviceName = $"{typeof(TService)}";
if (!Services[DIAttributeEnum.Singletone].Contains(serviceName))
{
Services[DIAttributeEnum.Singletone].Add(serviceName);
@ -376,6 +371,7 @@
public DIHelper TryAddSingleton<TService, TImplementation>() where TService : class where TImplementation : class, TService
{
var serviceName = $"{typeof(TService)}{typeof(TImplementation)}";
if (!Services[DIAttributeEnum.Singletone].Contains(serviceName))
{
Services[DIAttributeEnum.Singletone].Add(serviceName);
@ -388,6 +384,7 @@
public DIHelper Configure<TOptions>(Action<TOptions> configureOptions) where TOptions : class
{
var serviceName = $"{typeof(TOptions)}";
if (!Configured.Contains(serviceName))
{
Configured.Add(serviceName);
@ -400,6 +397,7 @@
public DIHelper Configure<TOptions>(string name, Action<TOptions> configureOptions) where TOptions : class
{
var serviceName = $"{typeof(TOptions)}{name}";
if (!Configured.Contains(serviceName))
{
Configured.Add(serviceName);
@ -408,5 +406,31 @@
return this;
}
private bool Register(Type service, Type implementation = null)
{
if (service.IsSubclassOf(typeof(ControllerBase)) || service.GetInterfaces().Contains(typeof(IResourceFilter))
|| service.GetInterfaces().Contains(typeof(IDictionary<string, string>)))
{
return true;
}
var c = service.IsGenericType && (
service.GetGenericTypeDefinition() == typeof(IConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IPostConfigureOptions<>) ||
service.GetGenericTypeDefinition() == typeof(IOptionsMonitor<>)
) && implementation != null ? implementation.GetCustomAttribute<DIAttribute>() : service.GetCustomAttribute<DIAttribute>();
var serviceName = $"{service}{implementation}";
if (!Services[c.DIAttributeEnum].Contains(serviceName))
{
c.TryAdd(ServiceCollection, service, implementation);
Services[c.DIAttributeEnum].Add(serviceName);
return true;
}
return false;
}
}

View File

@ -23,9 +23,8 @@
*
*/
namespace ASC.Common.Data;
namespace ASC.Common.Data
{
public static class StreamExtension
{
public const int BufferSize = 2048; //NOTE: set to 2048 to fit in minimum tcp window
@ -38,6 +37,7 @@ namespace ASC.Common.Data
var buffer = new byte[BufferSize];
int totalRead = 0;
int readed;
while ((readed = srcStream.Read(buffer, 0, length - totalRead > BufferSize ? BufferSize : length - totalRead)) > 0 && totalRead < length)
{
dstStream.Write(buffer, 0, readed);
@ -45,4 +45,3 @@ namespace ASC.Common.Data
}
}
}
}

View File

@ -14,38 +14,36 @@
*
*/
namespace System.IO
{
namespace System.IO;
[Singletone]
public class TempPath
{
readonly string tempFolder;
private readonly string _tempFolder;
public TempPath(IConfiguration configuration)
{
string rootFolder = AppContext.BaseDirectory;
if (string.IsNullOrEmpty(rootFolder))
{
rootFolder = Assembly.GetEntryAssembly().Location;
}
tempFolder = configuration["temp"] ?? Path.Combine("..", "Data", "temp");
if (!Path.IsPathRooted(tempFolder))
_tempFolder = configuration["temp"] ?? Path.Combine("..", "Data", "temp");
if (!Path.IsPathRooted(_tempFolder))
{
tempFolder = Path.GetFullPath(Path.Combine(rootFolder, tempFolder));
_tempFolder = Path.GetFullPath(Path.Combine(rootFolder, _tempFolder));
}
if (!Directory.Exists(tempFolder))
if (!Directory.Exists(_tempFolder))
{
Directory.CreateDirectory(tempFolder);
Directory.CreateDirectory(_tempFolder);
}
}
public string GetTempPath()
{
return tempFolder;
return _tempFolder;
}
public string GetTempFileName()
@ -56,7 +54,7 @@ namespace System.IO
do
{
path = Path.Combine(tempFolder, Path.GetRandomFileName());
path = Path.Combine(_tempFolder, Path.GetRandomFileName());
try
{
@ -68,16 +66,19 @@ namespace System.IO
catch (IOException ex)
{
if (ex.HResult != -2147024816 || count++ > 65536)
{
throw;
}
}
catch (UnauthorizedAccessException ex)
{
if (count++ > 65536)
{
throw new IOException(ex.Message, ex);
}
}
} while (f == null);
return path;
}
}
}

View File

@ -14,16 +14,16 @@
*
*/
namespace ASC.Common
{
namespace ASC.Common;
[Singletone]
public class TempStream
{
private TempPath TempPath { get; }
private readonly TempPath _tempPath;
public TempStream(TempPath tempPath)
{
TempPath = tempPath;
_tempPath = tempPath;
}
public Stream GetBuffered(Stream srcStream)
@ -35,14 +35,16 @@ namespace ASC.Common
var memStream = Create();
srcStream.CopyTo(memStream);
memStream.Position = 0;
return memStream;
}
return srcStream;
}
public Stream Create()
{
return new FileStream(TempPath.GetTempFileName(), FileMode.OpenOrCreate, FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose);
}
return new FileStream(_tempPath.GetTempFileName(), FileMode.OpenOrCreate,
FileAccess.ReadWrite, FileShare.Read, 4096, FileOptions.DeleteOnClose);
}
}

View File

@ -1,10 +1,11 @@
namespace ASC.Common.DependencyInjection
{
namespace ASC.Common.DependencyInjection;
internal class AutofacComponent
{
public string Type { get; set; }
public IEnumerable<AutofacService> Services { get; set; }
}
internal class AutofacService
{
public string Type { get; set; }
@ -12,7 +13,8 @@
public static class AutofacExtension
{
public static void Register(this ContainerBuilder builder, IConfiguration configuration, bool loadproducts = true, bool loadconsumers = true, params string[] intern)
public static void Register(this ContainerBuilder builder, IConfiguration configuration,
bool loadproducts = true, bool loadconsumers = true, params string[] intern)
{
var modules = new List<(bool, string)>
{
@ -37,10 +39,12 @@
foreach (var p in modules)
{
var config = new ConfigurationBuilder();
if (p.Item1)
{
config.SetBasePath(configuration["pathToConf"]);
}
config.AddJsonFile(p.Item2);
var root = config.Build();
@ -59,7 +63,6 @@
var root = config.Build();
var sectionSettings = root.GetSection("components");
if (sectionSettings == null)
{
return new List<string>();
@ -119,36 +122,41 @@
string GetFullPath(string n)
{
var productPath = CrossPlatform.PathCombine(productsDir, n, subfolder);
return GetPath(CrossPlatform.PathCombine(productPath, "bin"), n, SearchOption.AllDirectories) ?? GetPath(productPath, n, SearchOption.TopDirectoryOnly);
return GetPath(CrossPlatform.PathCombine(productPath, "bin"), n, SearchOption.AllDirectories)
?? GetPath(productPath, n, SearchOption.TopDirectoryOnly);
}
static string GetPath(string dirPath, string dll, SearchOption searchOption)
{
if (!Directory.Exists(dirPath)) return null;
if (!Directory.Exists(dirPath))
{
return null;
}
return Directory.GetFiles(dirPath, $"{dll}.dll", searchOption).FirstOrDefault();
}
}
}
class Resolver
{
private string ResolvePath { get; set; }
private readonly string _resolvePath;
public Resolver(string assemblyPath)
{
ResolvePath = assemblyPath;
_resolvePath = assemblyPath;
}
public Assembly Resolving(AssemblyLoadContext context, AssemblyName assemblyName)
{
var path = CrossPlatform.PathCombine(Path.GetDirectoryName(ResolvePath), $"{assemblyName.Name}.dll");
var path = CrossPlatform.PathCombine(Path.GetDirectoryName(_resolvePath), $"{assemblyName.Name}.dll");
if (!File.Exists(path)) return null;
if (!File.Exists(path))
{
return null;
}
return context.LoadFromAssemblyPath(path);
}
}
}

View File

@ -23,23 +23,17 @@
*
*/
namespace ASC.Geolocation
{
namespace ASC.Geolocation;
public class IPGeolocationInfo
{
public string Key { get; set; }
public string City { get; set; }
public double TimezoneOffset { get; set; }
public string TimezoneName { get; set; }
public string IPStart { get; set; }
public string IPEnd { get; set; }
public readonly static IPGeolocationInfo Default = new IPGeolocationInfo
{
Key = string.Empty,
@ -49,4 +43,3 @@ namespace ASC.Geolocation
TimezoneName = string.Empty,
};
}
}

View File

@ -21,6 +21,8 @@ global using System.Threading.Tasks;
global using System.Web;
global using System.Xml.Linq;
global using System.Xml.XPath;
global using System.ServiceModel;
global using System.Runtime.Serialization;
global using ARSoft.Tools.Net;
global using ARSoft.Tools.Net.Dns;

View File

@ -1,18 +1,18 @@
using ILogger = Microsoft.Extensions.Logging.ILogger;
using LogLevel = Microsoft.Extensions.Logging.LogLevel;
namespace ASC.Common.Logging
{
namespace ASC.Common.Logging;
[Singletone]
public class EFLoggerFactory : ILoggerFactory
{
Lazy<ILogger> Logger { get; set; }
ILoggerProvider LoggerProvider { get; set; }
private readonly Lazy<ILogger> _logger;
private readonly ILoggerProvider _loggerProvider;
public EFLoggerFactory(EFLoggerProvider loggerProvider)
{
LoggerProvider = loggerProvider;
Logger = new Lazy<ILogger>(() => LoggerProvider.CreateLogger(""));
_loggerProvider = loggerProvider;
_logger = new Lazy<ILogger>(() => _loggerProvider.CreateLogger(""));
}
public void AddProvider(ILoggerProvider provider)
@ -22,27 +22,25 @@ namespace ASC.Common.Logging
public ILogger CreateLogger(string categoryName)
{
return Logger.Value;
return _logger.Value;
}
public void Dispose()
{
}
public void Dispose() { }
}
[Singletone]
public class EFLoggerProvider : ILoggerProvider
{
private IOptionsMonitor<ILog> Option { get; }
private readonly IOptionsMonitor<ILog> _option;
public EFLoggerProvider(IOptionsMonitor<ILog> option)
{
Option = option;
_option = option;
}
public ILogger CreateLogger(string categoryName)
{
return new EFLogger(Option.Get("ASC.SQL"));
return new EFLogger(_option.Get("ASC.SQL"));
}
public void Dispose() { }
@ -57,7 +55,11 @@ namespace ASC.Common.Logging
CustomLogger = customLogger;
}
public IDisposable BeginScope<TState>(TState state) { return null; }
public IDisposable BeginScope<TState>(TState state)
{
return null;
}
public bool IsEnabled(LogLevel logLevel)
{
return logLevel switch
@ -89,4 +91,3 @@ namespace ASC.Common.Logging
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -23,67 +23,13 @@
*
*/
namespace ASC.Common.Logging
{
namespace ASC.Common.Logging;
public class SelfCleaningAppender : RollingFileAppender
{
private static DateTime _lastCleanDate;
private static int? _cleanPeriod;
private static int GetCleanPeriod()
{
if (_cleanPeriod != null)
return _cleanPeriod.Value;
const string key = "CleanPeriod";
var value = 30;
var repo = log4net.LogManager.GetRepository(Assembly.GetCallingAssembly());
if (repo != null && repo.Properties.GetKeys().Contains(key))
{
int.TryParse(repo.Properties[key].ToString(), out value);
}
_cleanPeriod = value;
return value;
}
private void Clean()
{
try
{
if (string.IsNullOrEmpty(File))
return;
var fileInfo = new FileInfo(File);
if (!fileInfo.Exists)
return;
var directory = fileInfo.Directory;
if (directory == null || !directory.Exists)
return;
var files = directory.GetFiles();
var cleanPeriod = GetCleanPeriod();
foreach (var file in files.Where(file => (DateTime.UtcNow.Date - file.CreationTimeUtc.Date).Days > cleanPeriod))
{
file.Delete();
}
}
catch (Exception err)
{
LogLog.Error(GetType(), err.Message, err);
}
}
protected override void Append(LoggingEvent loggingEvent)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
@ -105,5 +51,61 @@ namespace ASC.Common.Logging
base.Append(loggingEvents);
}
private static int GetCleanPeriod()
{
if (_cleanPeriod != null)
{
return _cleanPeriod.Value;
}
const string key = "CleanPeriod";
var value = 30;
var repo = log4net.LogManager.GetRepository(Assembly.GetCallingAssembly());
if (repo != null && repo.Properties.GetKeys().Contains(key))
{
int.TryParse(repo.Properties[key].ToString(), out value);
}
_cleanPeriod = value;
return value;
}
private void Clean()
{
try
{
if (string.IsNullOrEmpty(File))
{
return;
}
var fileInfo = new FileInfo(File);
if (!fileInfo.Exists)
{
return;
}
var directory = fileInfo.Directory;
if (directory == null || !directory.Exists)
{
return;
}
var files = directory.GetFiles();
var cleanPeriod = GetCleanPeriod();
foreach (var file in files.Where(file => (DateTime.UtcNow.Date - file.CreationTimeUtc.Date).Days > cleanPeriod))
{
file.Delete();
}
}
catch (Exception err)
{
LogLog.Error(GetType(), err.Message, err);
}
}
}

View File

@ -25,19 +25,56 @@
using LogLevel = NLog.LogLevel;
namespace ASC.Common.Logging
{
namespace ASC.Common.Logging;
[Target("SelfCleaning")]
public class SelfCleaningTarget : FileTarget
{
private static DateTime _lastCleanDate;
private static int? _cleanPeriod;
protected override void Write(IList<AsyncLogEventInfo> logEvents)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
var buffer = new List<AsyncLogEventInfo>();
foreach (var logEvent in logEvents)
{
buffer.Add(logEvent);
if (buffer.Count < 10)
{
continue;
}
base.Write(buffer);
buffer.Clear();
}
base.Write(buffer);
}
protected override void Write(LogEventInfo logEvent)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
base.Write(logEvent);
}
private static int GetCleanPeriod()
{
if (_cleanPeriod != null)
{
return _cleanPeriod.Value;
}
var value = 30;
@ -64,28 +101,33 @@ namespace ASC.Common.Logging
try
{
if (FileName == null)
{
return;
}
filePath = ((NLog.Layouts.SimpleLayout)FileName).Text;
if (string.IsNullOrEmpty(filePath))
{
return;
}
dirPath = Path.GetDirectoryName(filePath);
if (string.IsNullOrEmpty(dirPath))
{
return;
}
if (!Path.IsPathRooted(dirPath))
{
dirPath = CrossPlatform.PathCombine(AppDomain.CurrentDomain.BaseDirectory, dirPath);
}
var directory = new DirectoryInfo(dirPath);
if (!directory.Exists)
{
return;
}
var files = directory.GetFiles();
var cleanPeriod = GetCleanPeriod();
foreach (var file in files.Where(file => (DateTime.UtcNow.Date - file.CreationTimeUtc.Date).Days > cleanPeriod))
@ -104,37 +146,4 @@ namespace ASC.Common.Logging
});
}
}
protected override void Write(IList<AsyncLogEventInfo> logEvents)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
var buffer = new List<AsyncLogEventInfo>();
foreach (var logEvent in logEvents)
{
buffer.Add(logEvent);
if (buffer.Count < 10) continue;
base.Write(buffer);
buffer.Clear();
}
base.Write(buffer);
}
protected override void Write(LogEventInfo logEvent)
{
if (DateTime.UtcNow.Date > _lastCleanDate.Date)
{
_lastCleanDate = DateTime.UtcNow.Date;
Clean();
}
base.Write(logEvent);
}
}
}

View File

@ -23,8 +23,8 @@
*
*/
namespace ASC.Common.Logging
{
namespace ASC.Common.Logging;
public class SpecialFolderPathConverter : PatternConverter
{
protected override void Convert(TextWriter writer, object state)
@ -33,10 +33,12 @@ namespace ASC.Common.Logging
{
return;
}
try
{
var result = string.Empty;
const string CMD_LINE = "CommandLine:";
if (Option.StartsWith(CMD_LINE))
{
var args = Environment.CommandLine.Split(' ');
@ -60,6 +62,7 @@ namespace ASC.Common.Logging
{
realKey = "UNIX:" + Option;
}
if (Path.DirectorySeparatorChar == '\\' && key == "WINDOWS:" + Option)
{
realKey = "WINDOWS:" + Option;
@ -91,4 +94,3 @@ namespace ASC.Common.Logging
}
}
}
}

View File

@ -23,10 +23,12 @@
*
*/
namespace ASC.Common.Mapping
{
namespace ASC.Common.Mapping;
public interface IMapFrom<T>
{
void Mapping(Profile profile) => profile.CreateMap(typeof(T), GetType());
void Mapping(Profile profile)
{
profile.CreateMap(typeof(T), GetType());
}
}

View File

@ -23,18 +23,18 @@
*
*/
namespace ASC.Common.Mapping
{
namespace ASC.Common.Mapping;
public class MappingProfile : Profile
{
public MappingProfile()
{
Array.ForEach(AppDomain.CurrentDomain.GetAssemblies(), a => ApplyMappingsFromAssembly(a));
}
public MappingProfile() => Array.ForEach(AppDomain.CurrentDomain.GetAssemblies(), a => ApplyMappingsFromAssembly(a));
private void ApplyMappingsFromAssembly(Assembly assembly)
{
if (!assembly.GetName().Name.StartsWith("ASC.")) return;
if (!assembly.GetName().Name.StartsWith("ASC."))
{
return;
}
var types = assembly.GetExportedTypes()
.Where(t => t.GetInterfaces().Any(i =>
@ -48,8 +48,6 @@ namespace ASC.Common.Mapping
?? type.GetInterface("IMapFrom`1").GetMethod("Mapping");
methodInfo?.Invoke(instance, new object[] { this });
}
}
}
}

View File

@ -23,16 +23,11 @@
*
*/
namespace ASC.Common.Module;
using System.ServiceModel;
namespace ASC.Common.Module
{
public class BaseWcfClient<TService> : ClientBase<TService>, IDisposable where TService : class
{
public BaseWcfClient()
{
}
public BaseWcfClient() { }
void IDisposable.Dispose()
{
@ -56,4 +51,3 @@ namespace ASC.Common.Module
}
}
}
}

View File

@ -24,12 +24,11 @@
*/
namespace ASC.Common.Module
{
namespace ASC.Common.Module;
public interface IServiceController
{
void Start();
void Stop();
}
}

View File

@ -1,192 +0,0 @@
/*
*
* (c) Copyright Ascensio System Limited 2010-2018
*
* This program is freeware. You can redistribute it and/or modify it under the terms of the GNU
* General Public License (GPL) version 3 as published by the Free Software Foundation (https://www.gnu.org/copyleft/gpl.html).
* In accordance with Section 7(a) of the GNU GPL its Section 15 shall be amended to the effect that
* Ascensio System SIA expressly excludes the warranty of non-infringement of any third-party rights.
*
* THIS PROGRAM IS DISTRIBUTED WITHOUT ANY WARRANTY; WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR
* FITNESS FOR A PARTICULAR PURPOSE. For more details, see GNU GPL at https://www.gnu.org/copyleft/gpl.html
*
* You can contact Ascensio System SIA by email at sales@onlyoffice.com
*
* The interactive user interfaces in modified source and object code versions of ONLYOFFICE must display
* Appropriate Legal Notices, as required under Section 5 of the GNU GPL version 3.
*
* Pursuant to Section 7 § 3(b) of the GNU GPL you must retain the original ONLYOFFICE logo which contains
* relevant author attributions when distributing the software. If the display of the logo in its graphic
* form is not reasonably feasible for technical reasons, you must include the words "Powered by ONLYOFFICE"
* in every copy of the program you distribute.
* Pursuant to Section 7 § 3(e) we decline to grant you any rights under trademark law for use of our trademarks.
*
*/
using System;
using System.Configuration;
using System.IO;
using System.Linq;
using System.Net.Mail;
using System.Text;
using System.Threading;
using ASC.Common.Utils;
using Amazon.SimpleEmail;
using Amazon.SimpleEmail.Model;
using log4net;
namespace ASC.Common.Notify
{
public class AWSEmail
{
public enum SendStatus
{
Ok,
Failed,
QuotaLimit
}
private readonly AmazonSimpleEmailServiceClient _emailService;
private readonly ILog _log = LogHolder.Log("ASC.Notify.AmazonSES");
//Static fields
private static readonly TimeSpan RefreshTimeout;
private static DateTime _lastRefresh;
private static DateTime _lastSend;
private static TimeSpan _sendWindow = TimeSpan.MinValue;
private static GetSendQuotaResult _quota;
private static readonly object SynchRoot = new object();
static AWSEmail()
{
RefreshTimeout = TimeSpan.FromMinutes(30);
if (!string.IsNullOrEmpty(ConfigurationManager.AppSettings["ses.refreshTimeout"]))
{
TimeSpan.TryParse(ConfigurationManager.AppSettings["ses.refreshTimeout"], out RefreshTimeout);
}
_lastRefresh = DateTime.UtcNow - RefreshTimeout;//Set to refresh on first send
}
public AWSEmail()
{
var accessKey = ConfigurationManager.AppSettings["ses.accessKey"];
var secretKey = ConfigurationManager.AppSettings["ses.secretKey"];
_emailService = new AmazonSimpleEmailServiceClient(accessKey, secretKey);
}
public SendStatus SendEmail(MailMessage mailMessage)
{
//Check if we need to query stats
RefreshQuotaIfNeeded();
if (_quota != null)
{
lock (SynchRoot)
{
if (_quota.Max24HourSend <= _quota.SentLast24Hours)
{
//Quota exceeded
//Queu next refresh to +24 hours
_lastRefresh = DateTime.UtcNow.AddHours(24);
_log.WarnFormat("quota limit reached. setting next check to: {0}", _lastRefresh);
return SendStatus.QuotaLimit;
}
}
}
var destination = new Destination
{
ToAddresses = mailMessage.To.Select(adresses => adresses.Address).ToList(),
BccAddresses = mailMessage.Bcc.Select(adresses => adresses.Address).ToList(),
CcAddresses = mailMessage.CC.Select(adresses => adresses.Address).ToList(),
};
var body = new Body(new Content(mailMessage.Body) { Charset = Encoding.UTF8.WebName });
if (mailMessage.AlternateViews.Count > 0)
{
//Get html body
foreach (var alternateView in mailMessage.AlternateViews)
{
if ("text/html".Equals(alternateView.ContentType.MediaType, StringComparison.OrdinalIgnoreCase))
{
var stream = alternateView.ContentStream;
var buf = new byte[stream.Length];
stream.Read(buf, 0, buf.Length);
stream.Seek(0, SeekOrigin.Begin);//NOTE:seek to begin to keep HTML body
body.Html = new Content(Encoding.UTF8.GetString(buf)) { Charset = Encoding.UTF8.WebName };
break;
}
}
}
var message = new Message(new Content(mailMessage.Subject), body);
var seRequest = new SendEmailRequest(mailMessage.From.ToEncodedStringEx(), destination, message);
if (mailMessage.ReplyTo != null)
seRequest.ReplyToAddresses.Add(mailMessage.ReplyTo.Address);
ThrottleIfNeeded();
var response = _emailService.SendEmail(seRequest);
_lastSend = DateTime.UtcNow;
return response != null ? SendStatus.Ok : SendStatus.Failed;
}
private void ThrottleIfNeeded()
{
//Check last send and throttle if needed
if (_sendWindow != TimeSpan.MinValue)
{
if (DateTime.UtcNow - _lastSend <= _sendWindow)
//Possible BUG: at high frequncies maybe bug with to little differences
{
//This means that time passed from last send is less then message per second
_log.DebugFormat("send rate doesn't fit in send window. sleeping for:{0}", _sendWindow);
Thread.Sleep(_sendWindow);
}
}
}
private void RefreshQuotaIfNeeded()
{
if (!IsRefreshNeeded()) return;
lock (SynchRoot)
{
if (IsRefreshNeeded())//Double check
{
_log.DebugFormat("refreshing qouta. interval: {0} Last refresh was at: {1}", RefreshTimeout,
_lastRefresh);
//Do quota refresh
_lastRefresh = DateTime.UtcNow.AddMinutes(1);
try
{
var quotaRequest = new GetSendQuotaRequest();
_quota = _emailService.GetSendQuota(quotaRequest).GetSendQuotaResult;
_sendWindow = TimeSpan.FromSeconds(1.0 / _quota.MaxSendRate);
_log.DebugFormat("quota: {0}/{1} at {2} mps. send window:{3}", _quota.SentLast24Hours,
_quota.Max24HourSend, _quota.MaxSendRate, _sendWindow);
}
catch (Exception e)
{
_log.Error("error refreshing quota", e);
}
}
}
}
private static bool IsRefreshNeeded()
{
return (DateTime.UtcNow - _lastRefresh) > RefreshTimeout || _quota == null;
}
}
}

View File

@ -23,51 +23,55 @@
*
*/
namespace ASC.Common.Security
{
namespace ASC.Common.Security;
public class AscRandom : Random
{
private const int Mbig = int.MaxValue;
private const int Mseed = 161803398;
private const int Mz = 0;
private int _inext;
private int _inextp;
private const int MBIG = int.MaxValue;
private const int MSEED = 161803398;
private const int MZ = 0;
private readonly int[] seeds;
private readonly int[] _seeds;
public AscRandom() : this(Environment.TickCount)
{
}
public AscRandom() : this(Environment.TickCount) { }
public AscRandom(int seed)
{
seeds = new int[56];
_seeds = new int[56];
var num4 = (seed == int.MinValue) ? int.MaxValue : Math.Abs(seed);
var num2 = 161803398 - num4;
seeds[^1] = num2;
_seeds[^1] = num2;
var num3 = 1;
for (var i = 1; i < seeds.Length - 1; i++)
for (var i = 1; i < _seeds.Length - 1; i++)
{
var index = 21 * i % (seeds.Length - 1);
seeds[index] = num3;
var index = 21 * i % (_seeds.Length - 1);
_seeds[index] = num3;
num3 = num2 - num3;
if (num3 < 0)
{
num3 += int.MaxValue;
}
num2 = seeds[index];
num2 = _seeds[index];
}
for (var j = 1; j < 5; j++)
{
for (var k = 1; k < seeds.Length; k++)
for (var k = 1; k < _seeds.Length; k++)
{
seeds[k] -= seeds[1 + ((k + 30) % (seeds.Length - 1))];
if (seeds[k] < 0)
_seeds[k] -= _seeds[1 + ((k + 30) % (_seeds.Length - 1))];
if (_seeds[k] < 0)
{
seeds[k] += int.MaxValue;
_seeds[k] += int.MaxValue;
}
}
}
_inext = 0;
_inextp = 21;
}
@ -78,12 +82,16 @@ namespace ASC.Common.Security
{
throw new ArgumentOutOfRangeException(nameof(maxValue));
}
return (int)(InternalSample() * 4.6566128752457969E-10 * maxValue);
}
public override void NextBytes(byte[] buffer)
{
if (buffer == null) throw new ArgumentNullException(nameof(buffer));
if (buffer == null)
{
throw new ArgumentNullException(nameof(buffer));
}
for (var i = 0; i < buffer.Length; i++)
{
@ -93,29 +101,35 @@ namespace ASC.Common.Security
private int InternalSample()
{
var inext = this._inext;
var inextp = this._inextp;
if (++inext >= seeds.Length - 1)
var inext = _inext;
var inextp = _inextp;
if (++inext >= _seeds.Length - 1)
{
inext = 1;
}
if (++inextp >= seeds.Length - 1)
if (++inextp >= _seeds.Length - 1)
{
inextp = 1;
}
var num = seeds[inext] - seeds[inextp];
var num = _seeds[inext] - _seeds[inextp];
if (num == int.MaxValue)
{
num--;
}
if (num < 0)
{
num += int.MaxValue;
}
seeds[inext] = num;
this._inext = inext;
this._inextp = inextp;
_seeds[inext] = num;
_inext = inext;
_inextp = inextp;
return num;
}
}
}

View File

@ -23,11 +23,16 @@
*
*/
namespace ASC.Common.Security.Authentication
{
namespace ASC.Common.Security.Authentication;
[Serializable]
public class Account : IAccount
{
public Guid ID { get; private set; }
public string Name { get; private set; }
public virtual bool IsAuthenticated { get; private set; }
public string AuthenticationType => "ASC";
public Account(Guid id, string name, bool authenticated)
{
ID = id;
@ -35,31 +40,11 @@ namespace ASC.Common.Security.Authentication
IsAuthenticated = authenticated;
}
#region IAccount Members
public Guid ID { get; private set; }
public string Name { get; private set; }
public object Clone()
{
return MemberwiseClone();
}
public string AuthenticationType
{
get { return "ASC"; }
}
public virtual bool IsAuthenticated
{
get;
private set;
}
#endregion
public override bool Equals(object obj)
{
return obj is IAccount a && ID.Equals(a.ID);
@ -75,4 +60,3 @@ namespace ASC.Common.Security.Authentication
return Name;
}
}
}

View File

@ -23,10 +23,6 @@
*
*/
namespace ASC.Common.Security.Authentication
{
public interface IAccount : ISubject, ICloneable
{
namespace ASC.Common.Security.Authentication;
}
}
public interface IAccount : ISubject, ICloneable { }

View File

@ -24,9 +24,6 @@
*/
namespace ASC.Common.Security.Authentication
{
public interface ISystemAccount : IAccount
{
}
}
namespace ASC.Common.Security.Authentication;
public interface ISystemAccount : IAccount { }

View File

@ -24,16 +24,13 @@
*/
namespace ASC.Common.Security.Authentication
{
namespace ASC.Common.Security.Authentication;
public interface IUserAccount : IAccount
{
string Email { get; }
string FirstName { get; }
string LastName { get; }
string Title { get; }
int Tenant { get; }
}
}

View File

@ -23,14 +23,11 @@
*
*/
namespace ASC.Common.Security.Authentication
{
namespace ASC.Common.Security.Authentication;
[Serializable]
public class SystemAccount : Account, ISystemAccount
{
public SystemAccount(Guid id, string name, bool authenticated)
: base(id, name, authenticated)
{
}
}
: base(id, name, authenticated) { }
}

View File

@ -24,64 +24,55 @@
*/
#region usings
namespace ASC.Common.Security.Authorizing;
using System.Runtime.Serialization;
using System.Text;
#endregion
namespace ASC.Common.Security.Authorizing
{
[Serializable]
public class AuthorizingException : Exception
{
private readonly string _Message;
public ISubject Subject { get; internal set; }
public IAction[] Actions { get; internal set; }
public override string Message => _message;
private readonly string _message;
public AuthorizingException(string message)
: base(message)
{
}
: base(message) { }
public AuthorizingException(ISubject subject, IAction[] actions)
{
if (actions == null || actions.Length == 0) throw new ArgumentNullException(nameof(actions));
if (actions == null || actions.Length == 0)
{
throw new ArgumentNullException(nameof(actions));
}
Subject = subject ?? throw new ArgumentNullException(nameof(subject));
Actions = actions;
var sactions = "";
Array.ForEach(actions, action => { sactions += action.ToString() + ", "; });
_Message = string.Format(
_message = string.Format(
"\"{0}\" access denied \"{1}\"",
subject,
sactions
);
}
public AuthorizingException(ISubject subject, IAction[] actions, ISubject[] denySubjects, IAction[] denyActions)
{
_Message = FormatErrorMessage(subject, actions, denySubjects, denyActions);
}
public AuthorizingException(ISubject subject, IAction[] actions, ISubject[] denySubjects, IAction[] denyActions) =>
_message = FormatErrorMessage(subject, actions, denySubjects, denyActions);
protected AuthorizingException(SerializationInfo info, StreamingContext context)
: base(info, context)
{
_Message = info.GetValue("_Message", typeof(string)) as string;
_message = info.GetValue("_Message", typeof(string)) as string;
Subject = info.GetValue("Subject", typeof(ISubject)) as ISubject;
Actions = info.GetValue("Actions", typeof(IAction[])) as IAction[];
}
public override string Message
{
get { return _Message; }
}
public ISubject Subject { get; internal set; }
public IAction[] Actions { get; internal set; }
public override void GetObjectData(SerializationInfo info, StreamingContext context)
{
info.AddValue("Subject", Subject, typeof(ISubject));
info.AddValue("_Message", _Message, typeof(string));
info.AddValue("_Message", _message, typeof(string));
info.AddValue("Actions", Actions, typeof(IAction[]));
base.GetObjectData(info, context);
}
@ -89,12 +80,26 @@ namespace ASC.Common.Security.Authorizing
internal static string FormatErrorMessage(ISubject subject, IAction[] actions, ISubject[] denySubjects,
IAction[] denyActions)
{
if (subject == null) throw new ArgumentNullException(nameof(subject));
if (actions == null || actions.Length == 0) throw new ArgumentNullException(nameof(actions));
if (denySubjects == null || denySubjects.Length == 0) throw new ArgumentNullException(nameof(denySubjects));
if (denyActions == null || denyActions.Length == 0) throw new ArgumentNullException(nameof(denyActions));
if (subject == null)
{
throw new ArgumentNullException(nameof(subject));
}
if (actions == null || actions.Length == 0)
{
throw new ArgumentNullException(nameof(actions));
}
if (denySubjects == null || denySubjects.Length == 0)
{
throw new ArgumentNullException(nameof(denySubjects));
}
if (denyActions == null || denyActions.Length == 0)
{
throw new ArgumentNullException(nameof(denyActions));
}
if (actions.Length != denySubjects.Length || actions.Length != denyActions.Length)
{
throw new ArgumentException();
}
var sb = new StringBuilder();
for (var i = 0; i < actions.Length; i++)
@ -105,18 +110,25 @@ namespace ASC.Common.Security.Authorizing
string reason;
if (denySubject != null && denyAction != null)
{
reason = $"{action.Name}:{(denySubject is IRole ? "role:" : "") + denySubject.Name} access denied {denyAction.Name}.";
}
else
{
reason = $"{action.Name}: access denied.";
}
if (i != actions.Length - 1)
{
reason += ", ";
}
sb.Append(reason);
}
var reasons = sb.ToString();
var sactions = "";
Array.ForEach(actions, action => { sactions += action.ToString() + ", "; });
var message = $"\"{(subject is IRole ? "role:" : "") + subject.Name}\" access denied \"{sactions}\". Cause: {reasons}.";
return message;
}
}
}

View File

@ -24,16 +24,19 @@
*/
namespace ASC.Common.Security.Authorizing
{
namespace ASC.Common.Security.Authorizing;
public static class AzObjectIdHelper
{
private static readonly string separator = "|";
private static readonly string _separator = "|";
public static string GetFullObjectId(ISecurityObjectId objectId)
{
if (objectId == null) return null;
return string.Format("{0}{1}{2}", objectId.ObjectType.FullName, separator, objectId.SecurityId);
}
if (objectId == null)
{
return null;
}
return $"{objectId.ObjectType.FullName}{_separator}{objectId.SecurityId}";
}
}

View File

@ -23,61 +23,67 @@
*
*/
namespace ASC.Common.Security.Authorizing;
#region usings
#endregion
namespace ASC.Common.Security.Authorizing
{
public class AzObjectSecurityProviderHelper
{
private readonly SecurityCallContext callContext;
private readonly bool currObjIdAsProvider;
private ISecurityObjectProvider currSecObjProvider;
public ISecurityObjectId CurrentObjectId { get; private set; }
public bool ObjectRolesSupported => _currSecObjProvider != null && _currSecObjProvider.ObjectRolesSupported;
private readonly SecurityCallContext _callContext;
private readonly bool _currObjIdAsProvider;
private ISecurityObjectProvider _currSecObjProvider;
public AzObjectSecurityProviderHelper(ISecurityObjectId objectId, ISecurityObjectProvider secObjProvider)
{
currObjIdAsProvider = false;
_currObjIdAsProvider = false;
CurrentObjectId = objectId ?? throw new ArgumentNullException(nameof(objectId));
currSecObjProvider = secObjProvider;
if (currSecObjProvider == null && CurrentObjectId is ISecurityObjectProvider securityObjectProvider)
_currSecObjProvider = secObjProvider;
if (_currSecObjProvider == null && CurrentObjectId is ISecurityObjectProvider securityObjectProvider)
{
currObjIdAsProvider = true;
currSecObjProvider = securityObjectProvider;
}
callContext = new SecurityCallContext();
_currObjIdAsProvider = true;
_currSecObjProvider = securityObjectProvider;
}
public ISecurityObjectId CurrentObjectId { get; private set; }
public bool ObjectRolesSupported
{
get { return currSecObjProvider != null && currSecObjProvider.ObjectRolesSupported; }
_callContext = new SecurityCallContext();
}
public IEnumerable<IRole> GetObjectRoles(ISubject account)
{
var roles = currSecObjProvider.GetObjectRoles(account, CurrentObjectId, callContext);
var roles = _currSecObjProvider.GetObjectRoles(account, CurrentObjectId, _callContext);
foreach (var role in roles)
{
if (!callContext.RolesList.Contains(role)) callContext.RolesList.Add(role);
if (!_callContext.RolesList.Contains(role))
{
_callContext.RolesList.Add(role);
}
}
return roles;
}
public bool NextInherit()
{
if (currSecObjProvider == null || !currSecObjProvider.InheritSupported) return false;
CurrentObjectId = currSecObjProvider.InheritFrom(CurrentObjectId);
if (CurrentObjectId == null) return false;
if (currObjIdAsProvider)
if (_currSecObjProvider == null || !_currSecObjProvider.InheritSupported)
{
currSecObjProvider = CurrentObjectId as ISecurityObjectProvider;
}
callContext.ObjectsStack.Insert(0, CurrentObjectId);
return currSecObjProvider != null;
return false;
}
CurrentObjectId = _currSecObjProvider.InheritFrom(CurrentObjectId);
if (CurrentObjectId == null)
{
return false;
}
if (_currObjIdAsProvider)
{
_currSecObjProvider = CurrentObjectId as ISecurityObjectProvider;
}
_callContext.ObjectsStack.Insert(0, CurrentObjectId);
return _currSecObjProvider != null;
}
}

View File

@ -23,8 +23,8 @@
*
*/
namespace ASC.Common.Security.Authorizing
{
namespace ASC.Common.Security.Authorizing;
public static class Constants
{
public static readonly Role Admin = new Role(new Guid("cd84e66b-b803-40fc-99f9-b2969a54a1de"), "Admin");
@ -43,4 +43,3 @@ namespace ASC.Common.Security.Authorizing
public static readonly Role Self = new Role(new Guid("5d5b7260-f7f7-49f1-a1c9-95fbb6a12604"), "Self");
}
}

View File

@ -23,20 +23,17 @@
*
*/
namespace ASC.Common.Security.Authorizing
{
namespace ASC.Common.Security.Authorizing;
[Serializable]
public class Ace
{
public Guid ActionId { get; set; }
public AceType Reaction { get; set; }
public Ace(Guid actionId, AceType reaction)
{
ActionId = actionId;
Reaction = reaction;
}
}
}

View File

@ -24,11 +24,10 @@
*/
namespace ASC.Common.Security.Authorizing
{
namespace ASC.Common.Security.Authorizing;
public enum AceType
{
Allow,
Deny,
}
}

View File

@ -23,28 +23,25 @@
*
*/
namespace ASC.Common.Security.Authorizing
{
namespace ASC.Common.Security.Authorizing;
[Serializable]
public class Action : IAction
{
public Guid ID { get; private set; }
public string Name { get; private set; }
public bool AdministratorAlwaysAllow { get; private set; }
public bool Conjunction { get; private set; }
public Action(Guid id, string name)
: this(id, name, true, true)
{
}
: this(id, name, true, true) { }
public Action(Guid id, string name, bool administratorAlwaysAllow, bool conjunction)
{
if (id == Guid.Empty) throw new ArgumentNullException(nameof(id));
if (id == Guid.Empty)
{
throw new ArgumentNullException(nameof(id));
}
ID = id;
Name = name;
@ -67,4 +64,3 @@ namespace ASC.Common.Security.Authorizing
return Name;
}
}
}

View File

@ -23,8 +23,8 @@
*
*/
namespace ASC.Common.Security.Authorizing
{
namespace ASC.Common.Security.Authorizing;
[Serializable]
public sealed class Role : IRole
{
@ -34,32 +34,27 @@ namespace ASC.Common.Security.Authorizing
public const string Administrators = "Administrators";
public const string System = "System";
public Guid ID { get; internal set; }
public string Name { get; internal set; }
public string AuthenticationType
{
get { return "ASC"; }
}
public bool IsAuthenticated
{
get { return false; }
}
public string AuthenticationType => "ASC";
public bool IsAuthenticated => false;
public Role(Guid id, string name)
{
if (id == Guid.Empty) throw new ArgumentException("id");
if (string.IsNullOrEmpty(name)) throw new ArgumentNullException(nameof(name));
if (id == Guid.Empty)
{
throw new ArgumentException(nameof(id));
}
if (string.IsNullOrEmpty(name))
{
throw new ArgumentNullException(nameof(name));
}
ID = id;
Name = name;
}
public override int GetHashCode()
{
return ID.GetHashCode();
@ -75,4 +70,3 @@ namespace ASC.Common.Security.Authorizing
return $"Role: {Name}";
}
}
}

View File

@ -23,16 +23,12 @@
*
*/
namespace ASC.Common.Security.Authorizing
{
namespace ASC.Common.Security.Authorizing;
public interface IAction
{
Guid ID { get; }
string Name { get; }
bool AdministratorAlwaysAllow { get; }
bool Conjunction { get; }
}
}

View File

@ -24,9 +24,6 @@
*/
namespace ASC.Common.Security.Authorizing
{
public interface IRole : ISubject
{
}
}
namespace ASC.Common.Security.Authorizing;
public interface IRole : ISubject { }

View File

@ -23,10 +23,9 @@
*
*/
namespace ASC.Common.Security.Authorizing
{
namespace ASC.Common.Security.Authorizing;
public interface ISubject : IIdentity
{
Guid ID { get; }
}
}

View File

@ -24,16 +24,12 @@
*/
namespace ASC.Security.Cryptography
{
namespace ASC.Security.Cryptography;
public enum HashAlg
{
MD5,
SHA1,
SHA256,
SHA512
}
}

View File

@ -23,13 +23,12 @@
*
*/
namespace ASC.Security.Cryptography
{
namespace ASC.Security.Cryptography;
public static class Hasher
{
private const HashAlg DefaultAlg = HashAlg.SHA256;
public static byte[] Hash(string data, HashAlg hashAlg)
{
return ComputeHash(data, hashAlg);
@ -70,14 +69,6 @@ namespace ASC.Security.Cryptography
return Base64Hash(data, DefaultAlg);
}
public static bool EqualHash(byte[] dataToCompare, byte[] hash, HashAlg hashAlg)
{
return string.Equals(
ComputeHash64(dataToCompare, hashAlg),
B2S64(hash)
);
}
public static bool EqualHash(byte[] dataToCompare, byte[] hash)
{
return EqualHash(dataToCompare, hash, DefaultAlg);
@ -93,6 +84,13 @@ namespace ASC.Security.Cryptography
return EqualHash(dataToCompare, hash, DefaultAlg);
}
public static bool EqualHash(byte[] dataToCompare, byte[] hash, HashAlg hashAlg)
{
return string.Equals(
ComputeHash64(dataToCompare, hashAlg),
B2S64(hash)
);
}
private static HashAlgorithm GetAlg(HashAlg hashAlg)
{
@ -108,31 +106,48 @@ namespace ASC.Security.Cryptography
private static byte[] S2B(string str)
{
if (str == null) throw new ArgumentNullException(nameof(str));
if (str == null)
{
throw new ArgumentNullException(nameof(str));
}
return Encoding.UTF8.GetBytes(str);
}
private static string B2S(byte[] data)
{
if (data == null) throw new ArgumentNullException(nameof(data));
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
return Encoding.UTF8.GetString(data);
}
private static byte[] S642B(string str)
{
if (str == null) throw new ArgumentNullException(nameof(str));
if (str == null)
{
throw new ArgumentNullException(nameof(str));
}
return Convert.FromBase64String(str);
}
private static string B2S64(byte[] data)
{
if (data == null) throw new ArgumentNullException(nameof(data));
if (data == null)
{
throw new ArgumentNullException(nameof(data));
}
return Convert.ToBase64String(data);
}
private static byte[] ComputeHash(byte[] data, HashAlg hashAlg)
{
using var alg = GetAlg(hashAlg);
return alg.ComputeHash(data);
}
@ -151,4 +166,3 @@ namespace ASC.Security.Cryptography
return ComputeHash64(S2B(data), hashAlg);
}
}
}

View File

@ -23,16 +23,16 @@
*
*/
namespace ASC.Security.Cryptography
{
namespace ASC.Security.Cryptography;
[Singletone]
public class InstanceCrypto
{
private byte[] EKey { get; }
private readonly byte[] _eKey;
public InstanceCrypto(MachinePseudoKeys machinePseudoKeys)
{
EKey = machinePseudoKeys.GetMachineConstant(32);
_eKey = machinePseudoKeys.GetMachineConstant(32);
}
public string Encrypt(string data)
@ -43,27 +43,26 @@ namespace ASC.Security.Cryptography
public byte[] Encrypt(byte[] data)
{
using var hasher = Aes.Create();
hasher.Key = EKey;
hasher.Key = _eKey;
hasher.IV = new byte[hasher.BlockSize >> 3];
using var ms = new MemoryStream();
using var ss = new CryptoStream(ms, hasher.CreateEncryptor(), CryptoStreamMode.Write);
using var plainTextStream = new MemoryStream(data);
plainTextStream.CopyTo(ss);
ss.FlushFinalBlock();
hasher.Clear();
return ms.ToArray();
}
public string Decrypt(string data)
{
return Decrypt(Convert.FromBase64String(data));
}
public string Decrypt(string data) => Decrypt(Convert.FromBase64String(data));
public string Decrypt(byte[] data)
{
using var hasher = Aes.Create();
hasher.Key = EKey;
hasher.Key = _eKey;
hasher.IV = new byte[hasher.BlockSize >> 3];
using var msDecrypt = new MemoryStream(data);
@ -75,4 +74,3 @@ namespace ASC.Security.Cryptography
return srDecrypt.ReadToEnd();
}
}
}

View File

@ -23,36 +23,39 @@
*
*/
namespace ASC.Security.Cryptography
{
namespace ASC.Security.Cryptography;
[Singletone]
public class MachinePseudoKeys
{
private readonly byte[] confkey = null;
private readonly byte[] _confKey = null;
public MachinePseudoKeys(IConfiguration configuration)
{
var key = configuration["core:machinekey"];
if (string.IsNullOrEmpty(key))
{
key = configuration["asc:common.machinekey"];
}
if (!string.IsNullOrEmpty(key))
{
confkey = Encoding.UTF8.GetBytes(key);
_confKey = Encoding.UTF8.GetBytes(key);
}
}
public byte[] GetMachineConstant()
{
if (confkey != null)
if (_confKey != null)
{
return confkey;
return _confKey;
}
var path = typeof(MachinePseudoKeys).Assembly.Location;
var fi = new FileInfo(path);
return BitConverter.GetBytes(fi.CreationTime.ToOADate());
}
@ -63,7 +66,7 @@ namespace ASC.Security.Cryptography
var rnd = new AscRandom(icnst);
var buff = new byte[bytesCount];
rnd.NextBytes(buff);
return buff;
}
}
}

View File

@ -23,17 +23,29 @@
*
*/
namespace ASC.Security.Cryptography
{
namespace ASC.Security.Cryptography;
[Singletone]
public class PasswordHasher
{
public int Size { get; private set; }
public int Iterations { get; private set; }
public string Salt { get; private set; }
public PasswordHasher(IConfiguration configuration, MachinePseudoKeys machinePseudoKeys)
{
if (!int.TryParse(configuration["core:password:size"], out var size)) size = 256;
if (!int.TryParse(configuration["core:password:size"], out var size))
{
size = 256;
}
Size = size;
if (!int.TryParse(configuration["core.password.iterations"], out var iterations)) iterations = 100000;
if (!int.TryParse(configuration["core.password.iterations"], out var iterations))
{
iterations = 100000;
}
Iterations = iterations;
Salt = (configuration["core:password:salt"] ?? "").Trim();
@ -51,27 +63,12 @@ namespace ASC.Security.Cryptography
}
}
public int Size
{
get;
private set;
}
public int Iterations
{
get;
private set;
}
public string Salt
{
get;
private set;
}
public string GetClientPassword(string password)
{
if (string.IsNullOrWhiteSpace(password)) password = Guid.NewGuid().ToString();
if (string.IsNullOrWhiteSpace(password))
{
password = Guid.NewGuid().ToString();
}
var salt = new UTF8Encoding(false).GetBytes(Salt);
@ -87,5 +84,3 @@ namespace ASC.Security.Cryptography
return hash;
}
}
}

View File

@ -24,9 +24,6 @@
*/
namespace ASC.Common.Security
{
public interface ISecurityObject : ISecurityObjectId, ISecurityObjectProvider
{
}
}
namespace ASC.Common.Security;
public interface ISecurityObject : ISecurityObjectId, ISecurityObjectProvider { }

View File

@ -24,11 +24,10 @@
*/
namespace ASC.Common.Security
{
namespace ASC.Common.Security;
public interface ISecurityObjectId
{
object SecurityId { get; }
Type ObjectType { get; }
}
}

View File

@ -24,15 +24,13 @@
*/
namespace ASC.Common.Security
{
namespace ASC.Common.Security;
public interface ISecurityObjectProvider
{
bool InheritSupported { get; }
bool ObjectRolesSupported { get; }
ISecurityObjectId InheritFrom(ISecurityObjectId objectId);
ISecurityObjectId InheritFrom(ISecurityObjectId objectId);
IEnumerable<IRole> GetObjectRoles(ISubject account, ISecurityObjectId objectId, SecurityCallContext callContext);
}
}

View File

@ -23,20 +23,17 @@
*
*/
namespace ASC.Common.Security
{
namespace ASC.Common.Security;
public class SecurityCallContext
{
public object UserData { get; set; }
public List<ISecurityObjectId> ObjectsStack { get; private set; }
public List<IRole> RolesList { get; private set; }
public SecurityCallContext()
{
ObjectsStack = new List<ISecurityObjectId>();
RolesList = new List<IRole>();
}
public List<ISecurityObjectId> ObjectsStack { get; private set; }
public List<IRole> RolesList { get; private set; }
public object UserData { get; set; }
}
}

View File

@ -23,16 +23,14 @@
*
*/
namespace ASC.Common.Security
{
namespace ASC.Common.Security;
[DebuggerDisplay("ObjectType: {ObjectType.Name}, SecurityId: {SecurityId}")]
public class SecurityObjectId : ISecurityObjectId
{
public object SecurityId { get; private set; }
public Type ObjectType { get; private set; }
public SecurityObjectId(object id, Type objType)
{
SecurityId = id;
@ -50,4 +48,3 @@ namespace ASC.Common.Security
Equals(AzObjectIdHelper.GetFullObjectId(other), AzObjectIdHelper.GetFullObjectId(this));
}
}
}

View File

@ -25,60 +25,32 @@
using JsonSerializer = System.Text.Json.JsonSerializer;
namespace ASC.Common.Threading
{
namespace ASC.Common.Threading;
public class DistributedTask
{
public Action<DistributedTask> Publication { get; set; }
protected internal DistributedTaskCache DistributedTaskCache { get; internal set; }
public int InstanceId
{
get
{
return DistributedTaskCache.InstanceId;
}
set
{
DistributedTaskCache.InstanceId = value;
}
get => DistributedTaskCache.InstanceId;
set => DistributedTaskCache.InstanceId = value;
}
public string Id
{
get
{
return DistributedTaskCache.Id;
get => DistributedTaskCache.Id;
protected set => DistributedTaskCache.Id = value ?? "";
}
protected set
{
DistributedTaskCache.Id = value ?? "";
}
}
public DistributedTaskStatus Status
{
get
{
return Enum.Parse<DistributedTaskStatus>(DistributedTaskCache.Status);
get => Enum.Parse<DistributedTaskStatus>(DistributedTaskCache.Status);
set => DistributedTaskCache.Status = value.ToString();
}
set
{
DistributedTaskCache.Status = value.ToString();
}
}
public Exception Exception
{
get
{
return new Exception(DistributedTaskCache.Exception);
}
set
{
DistributedTaskCache.Exception = value?.ToString() ?? "";
}
get => new Exception(DistributedTaskCache.Exception);
set => DistributedTaskCache.Exception = value?.ToString() ?? "";
}
protected internal DistributedTaskCache DistributedTaskCache { get; internal set; }
public DistributedTask()
{
@ -87,17 +59,19 @@ namespace ASC.Common.Threading
Id = Guid.NewGuid().ToString()
};
}
public DistributedTask(DistributedTaskCache distributedTaskCache)
{
DistributedTaskCache = distributedTaskCache;
}
public T GetProperty<T>(string name)
{
var prop = DistributedTaskCache.Props.FirstOrDefault(r => r.Key == name);
if (prop == null) return default;
if (prop == null)
{
return default;
}
return JsonSerializer.Deserialize<T>(prop.Value);
}
@ -128,7 +102,7 @@ namespace ASC.Common.Threading
{
throw new InvalidOperationException("Publication not found.");
}
Publication(this);
}
}
}

View File

@ -1,44 +1,34 @@
namespace ASC.Common.Threading
{
namespace ASC.Common.Threading;
[Transient]
public class DistributedTaskProgress : DistributedTask
{
public double Percentage
{
get
{
return Math.Min(100.0, Math.Max(0, DistributedTaskCache.Percentage));
get => Math.Min(100.0, Math.Max(0, DistributedTaskCache.Percentage));
set => DistributedTaskCache.Percentage = value;
}
set
{
DistributedTaskCache.Percentage = value;
}
}
public bool IsCompleted
{
get
{
return DistributedTaskCache.IsCompleted;
get => DistributedTaskCache.IsCompleted;
set => DistributedTaskCache.IsCompleted = value;
}
set
{
DistributedTaskCache.IsCompleted = value;
}
}
protected int StepCount
{
get
get => DistributedTaskCache.StepCount;
set => DistributedTaskCache.StepCount = value;
}
public void RunJob()
{
return DistributedTaskCache.StepCount;
}
set
{
DistributedTaskCache.StepCount = value;
}
Percentage = 0;
Status = DistributedTaskStatus.Running;
DoJob();
}
protected virtual void DoJob() { }
protected void StepDone()
{
if (StepCount > 0)
@ -48,17 +38,4 @@
PublishChanges();
}
public void RunJob()
{
Percentage = 0;
Status = DistributedTaskStatus.Running;
DoJob();
}
protected virtual void DoJob()
{
}
}
}

View File

@ -23,28 +23,29 @@
*
*/
namespace ASC.Common.Threading
{
namespace ASC.Common.Threading;
[Singletone]
public class DistributedTaskCacheNotify
{
public ConcurrentDictionary<string, CancellationTokenSource> Cancelations { get; }
public ICache Cache { get; }
private readonly ICacheNotify<DistributedTaskCancelation> notify;
private readonly ICacheNotify<DistributedTaskCache> notifyCache;
private readonly ICacheNotify<DistributedTaskCancelation> _cancelTaskNotify;
private readonly ICacheNotify<DistributedTaskCache> _taskCacheNotify;
public DistributedTaskCacheNotify(
ICacheNotify<DistributedTaskCancelation> notify,
ICacheNotify<DistributedTaskCache> notifyCache,
ICacheNotify<DistributedTaskCancelation> cancelTaskNotify,
ICacheNotify<DistributedTaskCache> taskCacheNotify,
ICache cache)
{
Cancelations = new ConcurrentDictionary<string, CancellationTokenSource>();
Cache = cache;
this.notify = notify;
_cancelTaskNotify = cancelTaskNotify;
notify.Subscribe((c) =>
cancelTaskNotify.Subscribe((c) =>
{
if (Cancelations.TryGetValue(c.Id, out var s))
{
@ -52,14 +53,14 @@ namespace ASC.Common.Threading
}
}, CacheNotifyAction.Remove);
this.notifyCache = notifyCache;
_taskCacheNotify = taskCacheNotify;
notifyCache.Subscribe((c) =>
taskCacheNotify.Subscribe((c) =>
{
Cache.HashSet(c.Key, c.Id, (DistributedTaskCache)null);
}, CacheNotifyAction.Remove);
notifyCache.Subscribe((c) =>
taskCacheNotify.Subscribe((c) =>
{
Cache.HashSet(c.Key, c.Id, c);
}, CacheNotifyAction.InsertOrUpdate);
@ -67,26 +68,24 @@ namespace ASC.Common.Threading
public void CancelTask(string id)
{
notify.Publish(new DistributedTaskCancelation() { Id = id }, CacheNotifyAction.Remove);
_cancelTaskNotify.Publish(new DistributedTaskCancelation() { Id = id }, CacheNotifyAction.Remove);
}
public void SetTask(DistributedTask task)
{
notifyCache.Publish(task.DistributedTaskCache, CacheNotifyAction.InsertOrUpdate);
_taskCacheNotify.Publish(task.DistributedTaskCache, CacheNotifyAction.InsertOrUpdate);
}
public void RemoveTask(string id, string key)
{
notifyCache.Publish(new DistributedTaskCache() { Id = id, Key = key }, CacheNotifyAction.Remove);
_taskCacheNotify.Publish(new DistributedTaskCache() { Id = id, Key = key }, CacheNotifyAction.Remove);
}
}
[Singletone(typeof(ConfigureDistributedTaskQueue))]
public class DistributedTaskQueueOptionsManager : OptionsManager<DistributedTaskQueue>
{
public DistributedTaskQueueOptionsManager(IOptionsFactory<DistributedTaskQueue> factory) : base(factory)
{
}
public DistributedTaskQueueOptionsManager(IOptionsFactory<DistributedTaskQueue> factory) : base(factory) { }
public DistributedTaskQueue Get<T>() where T : DistributedTask
{
@ -97,19 +96,21 @@ namespace ASC.Common.Threading
[Scope]
public class ConfigureDistributedTaskQueue : IConfigureNamedOptions<DistributedTaskQueue>
{
private DistributedTaskCacheNotify DistributedTaskCacheNotify { get; }
public IServiceProvider ServiceProvider { get; }
private readonly DistributedTaskCacheNotify _distributedTaskCacheNotify;
public readonly IServiceProvider _serviceProvider;
public ConfigureDistributedTaskQueue(DistributedTaskCacheNotify distributedTaskCacheNotify, IServiceProvider serviceProvider)
public ConfigureDistributedTaskQueue(
DistributedTaskCacheNotify distributedTaskCacheNotify,
IServiceProvider serviceProvider)
{
DistributedTaskCacheNotify = distributedTaskCacheNotify;
ServiceProvider = serviceProvider;
_distributedTaskCacheNotify = distributedTaskCacheNotify;
_serviceProvider = serviceProvider;
}
public void Configure(DistributedTaskQueue queue)
{
queue.DistributedTaskCacheNotify = DistributedTaskCacheNotify;
queue.ServiceProvider = ServiceProvider;
queue.DistributedTaskCacheNotify = _distributedTaskCacheNotify;
queue.ServiceProvider = _serviceProvider;
}
public void Configure(string name, DistributedTaskQueue options)
@ -121,27 +122,33 @@ namespace ASC.Common.Threading
public class DistributedTaskQueue
{
public static readonly int InstanceId = Process.GetCurrentProcess().Id;
private string key;
private TaskScheduler Scheduler { get; set; } = TaskScheduler.Default;
public IServiceProvider ServiceProvider { get; set; }
public string Name { get { return key; } set { key = value + GetType().Name; } }
private ICache Cache { get => DistributedTaskCacheNotify.Cache; }
private ConcurrentDictionary<string, CancellationTokenSource> Cancelations { get => DistributedTaskCacheNotify.Cancelations; }
public DistributedTaskCacheNotify DistributedTaskCacheNotify { get; set; }
public string Name
{
get => _name;
set => _name = value + GetType().Name;
}
public int MaxThreadsCount
{
set
{
Scheduler = value <= 0
set => Scheduler = value <= 0
? TaskScheduler.Default
: new ConcurrentExclusiveSchedulerPair(TaskScheduler.Default, value).ConcurrentScheduler;
}
}
public DistributedTaskCacheNotify DistributedTaskCacheNotify { get; set; }
private ICache Cache => DistributedTaskCacheNotify.Cache;
private TaskScheduler Scheduler { get; set; } = TaskScheduler.Default;
public static readonly int InstanceId = Process.GetCurrentProcess().Id;
private string _name;
private ConcurrentDictionary<string, CancellationTokenSource> Cancelations
{
get
{
return DistributedTaskCacheNotify.Cancelations;
}
}
public void QueueTask(DistributedTaskProgress taskProgress)
{
@ -162,8 +169,8 @@ namespace ASC.Common.Threading
Cancelations[distributedTask.Id] = cancelation;
var task = new Task(() => { action(distributedTask, token); }, token, TaskCreationOptions.LongRunning);
task
.ConfigureAwait(false)
task.ConfigureAwait(false)
.GetAwaiter()
.OnCompleted(() => OnCompleted(task, distributedTask.Id));
@ -173,6 +180,7 @@ namespace ASC.Common.Threading
{
distributedTask.Publication = GetPublication();
}
distributedTask.PublishChanges();
task.Start(Scheduler);
@ -180,7 +188,8 @@ namespace ASC.Common.Threading
public IEnumerable<DistributedTask> GetTasks()
{
var tasks = Cache.HashGetAll<DistributedTaskCache>(key).Values.Select(r => new DistributedTask(r)).ToList();
var tasks = Cache.HashGetAll<DistributedTaskCache>(_name).Values.Select(r => new DistributedTask(r)).ToList();
tasks.ForEach(t =>
{
if (t.Publication == null)
@ -188,15 +197,17 @@ namespace ASC.Common.Threading
t.Publication = GetPublication();
}
});
return tasks;
}
public IEnumerable<T> GetTasks<T>() where T : DistributedTask
{
var tasks = Cache.HashGetAll<DistributedTaskCache>(key).Values.Select(r =>
var tasks = Cache.HashGetAll<DistributedTaskCache>(_name).Values.Select(r =>
{
var result = ServiceProvider.GetService<T>();
result.DistributedTaskCache = r;
return result;
}).ToList();
@ -207,12 +218,13 @@ namespace ASC.Common.Threading
t.Publication = GetPublication();
}
});
return tasks;
}
public T GetTask<T>(string id) where T : DistributedTask
{
var cache = Cache.HashGet<DistributedTaskCache>(key, id);
var cache = Cache.HashGet<DistributedTaskCache>(_name, id);
if (cache != null)
{
using var scope = ServiceProvider.CreateScope();
@ -222,6 +234,7 @@ namespace ASC.Common.Threading
{
task.Publication = GetPublication();
}
return task;
}
@ -230,7 +243,7 @@ namespace ASC.Common.Threading
public DistributedTask GetTask(string id)
{
var cache = Cache.HashGet<DistributedTaskCache>(key, id);
var cache = Cache.HashGet<DistributedTaskCache>(_name, id);
if (cache != null)
{
var task = new DistributedTask();
@ -239,6 +252,7 @@ namespace ASC.Common.Threading
{
task.Publication = GetPublication();
}
return task;
}
@ -252,7 +266,7 @@ namespace ASC.Common.Threading
public void RemoveTask(string id)
{
DistributedTaskCacheNotify.RemoveTask(id, key);
DistributedTaskCacheNotify.RemoveTask(id, _name);
}
public void CancelTask(string id)
@ -267,10 +281,12 @@ namespace ASC.Common.Threading
{
distributedTask.Status = DistributedTaskStatus.Completed;
distributedTask.Exception = task.Exception;
if (task.IsFaulted)
{
distributedTask.Status = DistributedTaskStatus.Failted;
}
if (task.IsCanceled)
{
distributedTask.Status = DistributedTaskStatus.Canceled;
@ -288,8 +304,9 @@ namespace ASC.Common.Threading
{
if (t.DistributedTaskCache != null)
{
t.DistributedTaskCache.Key = key;
t.DistributedTaskCache.Key = _name;
}
DistributedTaskCacheNotify.SetTask(t);
};
}
@ -304,6 +321,7 @@ namespace ASC.Common.Threading
services.TryAdd<DistributedTaskQueue>();
var type = typeof(T);
if (!type.IsAbstract)
{
services.TryAdd<T>();
@ -320,4 +338,3 @@ namespace ASC.Common.Threading
return services;
}
}
}

View File

@ -24,8 +24,8 @@
*/
namespace ASC.Common.Threading
{
namespace ASC.Common.Threading;
public enum DistributedTaskStatus
{
Created,
@ -34,4 +34,3 @@ namespace ASC.Common.Threading
Canceled,
Failted
}
}

View File

@ -23,8 +23,8 @@
*
*/
namespace ASC.Common.Threading.Progress
{
namespace ASC.Common.Threading.Progress;
public interface IProgressItem : ICloneable
{
string Id { get; }
@ -35,4 +35,3 @@ namespace ASC.Common.Threading.Progress
void RunJob();
}
}

View File

@ -1,47 +1,50 @@
namespace ASC.Common.Utils
{
namespace ASC.Common.Utils;
public class ConnectionStringCollection : IEnumerable<ConnectionStringSettings>
{
private List<ConnectionStringSettings> Data { get; set; }
private List<ConnectionStringSettings> _data;
public ConnectionStringCollection(IEnumerable<ConnectionStringSettings> data) => Data = data.ToList();
public ConnectionStringSettings this[string name] => _data.FirstOrDefault(r => r.Name == name);
public ConnectionStringCollection(IEnumerable<ConnectionStringSettings> data)
{
_data = data.ToList();
}
public IEnumerator<ConnectionStringSettings> GetEnumerator()
{
return Data.GetEnumerator();
return _data.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
public ConnectionStringSettings this[string name]
{
get
{
return Data.FirstOrDefault(r => r.Name == name);
}
}
}
[Singletone]
public class ConfigurationExtension
{
private IConfiguration Configuration { get; }
private Lazy<ConnectionStringCollection> ConnectionStringSettings { get; }
public string this[string key]
{
get => _configuration[key];
set => _configuration[key] = value;
}
private readonly IConfiguration _configuration;
private readonly Lazy<ConnectionStringCollection> _connectionStringSettings;
public ConfigurationExtension(IConfiguration configuration)
{
Configuration = configuration;
ConnectionStringSettings = new Lazy<ConnectionStringCollection>(new ConnectionStringCollection(GetSettings<ConnectionStringSettings>("ConnectionStrings")));
_configuration = configuration;
_connectionStringSettings = new Lazy<ConnectionStringCollection>(new ConnectionStringCollection(GetSettings<ConnectionStringSettings>("ConnectionStrings")));
}
public IEnumerable<T> GetSettings<T>(string section) where T : new()
{
var result = new List<T>();
var sectionSettings = Configuration.GetSection(section);
var sectionSettings = _configuration.GetSection(section);
foreach (var ch in sectionSettings.GetChildren())
{
@ -60,7 +63,7 @@
public T GetSetting<T>(string section, T instance)
{
var sectionSettings = Configuration.GetSection(section);
var sectionSettings = _configuration.GetSection(section);
sectionSettings.Bind(instance);
@ -69,18 +72,11 @@
public ConnectionStringCollection GetConnectionStrings()
{
return ConnectionStringSettings.Value;
return _connectionStringSettings.Value;
}
public ConnectionStringSettings GetConnectionStrings(string key)
{
return GetConnectionStrings()[key];
}
public string this[string key]
{
get => Configuration[key];
set => Configuration[key] = value;
}
}
}

View File

@ -23,17 +23,20 @@
*
*/
namespace ASC.Common.Utils
{
namespace ASC.Common.Utils;
public static class CrossPlatform
{
private static char[] _pathSplitCharacters = new char[] { '/', '\\' };
public static string PathCombine(string basePath, params string[] additional)
{
var splits = additional.Select(s => s.Split(pathSplitCharacters)).ToArray();
var splits = additional.Select(s => s.Split(_pathSplitCharacters)).ToArray();
var totalLength = splits.Sum(arr => arr.Length);
var segments = new string[totalLength + 1];
segments[0] = basePath;
var i = 0;
foreach (var split in splits)
{
foreach (var value in split)
@ -42,9 +45,7 @@ namespace ASC.Common.Utils
segments[i] = value;
}
}
return Path.Combine(segments);
}
static char[] pathSplitCharacters = new char[] { '/', '\\' };
}
}

View File

@ -23,8 +23,8 @@
*
*/
namespace ASC.Common.Utils
{
namespace ASC.Common.Utils;
public class DnsLookup
{
private readonly IDnsResolver _sDnsResolver;
@ -46,7 +46,9 @@ namespace ASC.Common.Utils
public List<MxRecord> GetDomainMxRecords(string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var mxRecords = DnsResolve<MxRecord>(domainName, RecordType.Mx);
@ -64,10 +66,14 @@ namespace ASC.Common.Utils
public bool IsDomainMxRecordExists(string domainName, string mxRecord)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
if (string.IsNullOrEmpty(mxRecord))
{
throw new ArgumentNullException(nameof(mxRecord));
}
var mxDomain = DomainName.Parse(mxRecord);
@ -88,7 +94,9 @@ namespace ASC.Common.Utils
public bool IsDomainExists(string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var dnsMessage = GetDnsMessage(domainName);
@ -105,7 +113,9 @@ namespace ASC.Common.Utils
public List<ARecord> GetDomainARecords(string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var aRecords = DnsResolve<ARecord>(domainName, RecordType.A);
@ -122,7 +132,9 @@ namespace ASC.Common.Utils
public List<IPAddress> GetDomainIPs(string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var addresses = _sDnsResolver.ResolveHost(domainName);
@ -139,7 +151,9 @@ namespace ASC.Common.Utils
public List<TxtRecord> GetDomainTxtRecords(string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var txtRecords = DnsResolve<TxtRecord>(domainName, RecordType.Txt);
@ -193,10 +207,13 @@ namespace ASC.Common.Utils
public bool IsDomainPtrRecordExists(IPAddress ipAddress, string domainName)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
if (ipAddress == null)
{
throw new ArgumentNullException(nameof(ipAddress));
}
var domain = DomainName.Parse(domainName);
@ -222,12 +239,13 @@ namespace ASC.Common.Utils
private DnsMessage GetDnsMessage(string domainName, RecordType? type = null)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var domain = DomainName.Parse(domainName);
var dnsMessage = type.HasValue ? _dnsClient.Resolve(domain, type.Value) : _dnsClient.Resolve(domain);
if ((dnsMessage == null) ||
((dnsMessage.ReturnCode != ReturnCode.NoError) && (dnsMessage.ReturnCode != ReturnCode.NxDomain)))
{
@ -240,11 +258,12 @@ namespace ASC.Common.Utils
private List<T> DnsResolve<T>(string domainName, RecordType type)
{
if (string.IsNullOrEmpty(domainName))
{
throw new ArgumentNullException(nameof(domainName));
}
var dnsMessage = GetDnsMessage(domainName, type);
return dnsMessage.AnswerRecords.Where(r => r.RecordType == type).Cast<T>().ToList();
}
}
}

View File

@ -23,34 +23,42 @@
*
*/
namespace ASC.Common.Utils
{
namespace ASC.Common.Utils;
public static class HtmlUtil
{
private static readonly Regex tagReplacer = new Regex("<[^>]*>", RegexOptions.Multiline | RegexOptions.Compiled);
private static readonly Regex commentsReplacer = new Regex("<!--(?s).*?-->", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex xssReplacer = new Regex(@"<\s*(style|script)[^>]*>(.*?)<\s*/\s*(style|script)>", RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.Singleline);
private static readonly Regex Worder = new Regex(@"\S+", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
private static readonly Regex _tagReplacer
= new Regex("<[^>]*>", RegexOptions.Multiline | RegexOptions.Compiled);
private static readonly Regex _commentsReplacer
= new Regex("<!--(?s).*?-->", RegexOptions.Singleline | RegexOptions.IgnoreCase | RegexOptions.Compiled);
private static readonly Regex _xssReplacer
= new Regex(@"<\s*(style|script)[^>]*>(.*?)<\s*/\s*(style|script)>", RegexOptions.IgnoreCase
| RegexOptions.CultureInvariant | RegexOptions.Compiled | RegexOptions.Singleline);
private static readonly Regex _worder =
new Regex(@"\S+", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant);
public static string GetText(string html, int maxLength = 0, string endBlockTemplate = "...")
{
var unformatedText = string.Empty;
if (!string.IsNullOrEmpty(html))
{
html = xssReplacer.Replace(html, string.Empty); //Clean malicious tags. <script> <style>
html = _xssReplacer.Replace(html, string.Empty); //Clean malicious tags. <script> <style>
if (string.IsNullOrEmpty(html))
{
return html;
}
unformatedText = tagReplacer.Replace(html, string.Empty);
unformatedText = _tagReplacer.Replace(html, string.Empty);
if (!string.IsNullOrEmpty(unformatedText))
{
// kill comments
unformatedText = commentsReplacer.Replace(unformatedText, string.Empty);
unformatedText = _commentsReplacer.Replace(unformatedText, string.Empty);
unformatedText = unformatedText.Trim();
if (!string.IsNullOrEmpty(unformatedText))
@ -70,6 +78,7 @@ namespace ASC.Common.Utils
unformatedText = lastSpaceIndex > 0 && lastSpaceIndex < unformatedText.Length
? unformatedText.Remove(lastSpaceIndex)
: unformatedText.Substring(0, maxLength);
if (!string.IsNullOrEmpty(endBlockTemplate))
{
unformatedText += endBlockTemplate;
@ -77,6 +86,7 @@ namespace ASC.Common.Utils
}
}
}
return HttpUtility.HtmlDecode(unformatedText);//TODO:!!!
}
@ -94,11 +104,13 @@ namespace ASC.Common.Utils
/// <returns>highlighted html</returns>
public static string SearchTextHighlight(string searchText, string htmlText, bool withoutLink = false)
{
if (string.IsNullOrEmpty(searchText) || string.IsNullOrEmpty(htmlText)) return htmlText;
if (string.IsNullOrEmpty(searchText) || string.IsNullOrEmpty(htmlText))
{
return htmlText;
}
var regexpstr = Worder.Matches(searchText).Select(m => m.Value).Distinct().Aggregate((r, n) => r + "|" + n);
var regexpstr = _worder.Matches(searchText).Select(m => m.Value).Distinct().Aggregate((r, n) => r + "|" + n);
var wordsFinder = new Regex(Regex.Escape(regexpstr), RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.CultureInvariant | RegexOptions.Multiline);
return wordsFinder.Replace(htmlText, m => "<span class='searchTextHighlight" + (withoutLink ? " bold" : string.Empty) + "'>" + m.Value + "</span>");
}
}
}

View File

@ -26,17 +26,17 @@
using HttpContext = Microsoft.AspNetCore.Http.HttpContext;
namespace System.Web
{
namespace System.Web;
public static class HttpRequestExtensions
{
public static readonly string UrlRewriterHeader = "X-REWRITER-URL";
public static Uri GetUrlRewriter(this HttpRequest request)
{
return request != null ? GetUrlRewriter(request.Headers, request) : null;
}
public static Uri Url(this HttpRequest request)
{
return request != null ? new Uri(request.GetDisplayUrl()) : null;
@ -53,6 +53,7 @@ namespace System.Web
{
var h = headers[UrlRewriterHeader];
var rewriterUri = !string.IsNullOrEmpty(h) ? ParseRewriterUrl(h) : null;
if (request != null && rewriterUri != null)
{
var result = new UriBuilder()
@ -61,8 +62,10 @@ namespace System.Web
Host = rewriterUri.Host,
Port = rewriterUri.Port
};
result.Query = request.QueryString.Value;
result.Path = request.Path.Value;
return result.Uri;
}
}
@ -97,6 +100,7 @@ namespace System.Web
public static Uri PushRewritenUri(this HttpContext context, Uri rewrittenUri)
{
Uri oldUri = null;
if (context != null)
{
var request = context.Request;
@ -134,11 +138,10 @@ namespace System.Web
context.Items["oldUri"] = oldUri;
}
catch (Exception)
{
}
catch (Exception) { }
}
}
return oldUri;
}
@ -147,11 +150,13 @@ namespace System.Web
if (context != null && context.Items["oldUri"] != null)
{
var rewriteTo = context.Items["oldUri"] as Uri;
if (rewriteTo != null)
{
return PushRewritenUri(context, rewriteTo);
}
}
return null;
}
@ -169,6 +174,10 @@ namespace System.Web
|| !string.IsNullOrEmpty(request.Headers[HeaderNames.UserAgent]) && request.Headers[HeaderNames.UserAgent].ToString().Contains("SailfishOS"));
}
public static string GetUserHostAddress(this HttpRequest request)
{
return request.HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress.ToString();
}
private static Uri ParseRewriterUrl(string s)
{
@ -200,12 +209,7 @@ namespace System.Web
}
Uri.TryCreate(s, UriKind.Absolute, out var result);
return result;
}
public static string GetUserHostAddress(this HttpRequest request)
{
return request.HttpContext.Features.Get<IHttpConnectionFeature>()?.RemoteIpAddress.ToString();
}
}
}

View File

@ -27,8 +27,8 @@
using Formatting = Newtonsoft.Json.Formatting;
using IJsonSerializer = JWT.IJsonSerializer;
namespace ASC.Web.Core.Files
{
namespace ASC.Web.Core.Files;
public static class JsonWebToken
{
public static string Encode(object payload, string key)
@ -93,4 +93,3 @@ namespace ASC.Web.Core.Files
return JsonConvert.DeserializeObject<T>(json, settings);
}
}
}

View File

@ -23,8 +23,8 @@
*
*/
namespace ASC.Common.Utils
{
namespace ASC.Common.Utils;
public static class MailAddressUtils
{
public static MailAddress Create(string address)
@ -33,11 +33,13 @@ namespace ASC.Common.Utils
{
var firstPos = address.IndexOf('"');
var lastPos = address.LastIndexOf('"');
if (firstPos != -1 && firstPos < lastPos && address.IndexOf('"', firstPos + 1, lastPos - firstPos - 1) != -1)
{
address = new StringBuilder(address).Replace("\"", string.Empty, firstPos + 1, lastPos - firstPos - 1).ToString();
}
}
return new MailAddress(address);
}
@ -46,11 +48,13 @@ namespace ASC.Common.Utils
if (!string.IsNullOrEmpty(displayName))
{
displayName = displayName.Replace("\"", string.Empty);
if (125 < displayName.Length)
{
displayName = displayName.Substring(0, 125);
}
}
return Create(ToSmtpAddress(address, displayName));
}
@ -59,10 +63,8 @@ namespace ASC.Common.Utils
return ToSmtpAddress(m.Address, MimeHeaderUtils.EncodeMime(m.DisplayName));
}
private static string ToSmtpAddress(string address, string displayName)
{
return $"\"{displayName}\" <{address}>";
}
}
}

View File

@ -23,8 +23,8 @@
*
*/
namespace ASC.Common.Utils
{
namespace ASC.Common.Utils;
public static class MimeHeaderUtils
{
public static string EncodeMime(string mimeHeaderValue)
@ -43,6 +43,7 @@ namespace ASC.Common.Utils
result.Append("=?" + charset.WebName + "?B?");
var stored = 0;
var base64 = Convert.ToBase64String(data);
for (var i = 0; i < base64.Length; i += 4)
{
// Encoding buffer full, create new encoded-word.
@ -55,9 +56,12 @@ namespace ASC.Common.Utils
result.Append(base64, i, 4);
stored += 4;
}
result.Append("?=");
return result.ToString();
}
return mimeHeaderValue;
}
@ -66,4 +70,3 @@ namespace ASC.Common.Utils
return !string.IsNullOrEmpty(text) && text.Any(c => c > 127);
}
}
}

View File

@ -23,19 +23,20 @@
*
*/
namespace ASC.Common.Utils
{
namespace ASC.Common.Utils;
public static class RandomString
{
public static string Generate(int length)
{
const string valid = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890";
var res = new StringBuilder();
while (0 < length--)
{
res.Append(valid[RandomNumberGenerator.GetInt32(valid.Length)]);
}
return res.ToString();
}
}
}

View File

@ -23,33 +23,34 @@
*
*/
namespace ASC.Common.Utils
{
namespace ASC.Common.Utils;
[Singletone]
public class Signature
{
private readonly MachinePseudoKeys _machinePseudoKeys;
public Signature(MachinePseudoKeys machinePseudoKeys)
{
MachinePseudoKeys = machinePseudoKeys;
_machinePseudoKeys = machinePseudoKeys;
}
private MachinePseudoKeys MachinePseudoKeys { get; }
public string Create<T>(T obj)
{
return Create(obj, Encoding.UTF8.GetString(MachinePseudoKeys.GetMachineConstant()));
return Create(obj, Encoding.UTF8.GetString(_machinePseudoKeys.GetMachineConstant()));
}
public static string Create<T>(T obj, string secret)
{
var str = JsonConvert.SerializeObject(obj);
var payload = GetHashBase64(str + secret) + "?" + str;
return WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(payload));
}
public T Read<T>(string signature)
{
return Read<T>(signature, Encoding.UTF8.GetString(MachinePseudoKeys.GetMachineConstant()));
return Read<T>(signature, Encoding.UTF8.GetString(_machinePseudoKeys.GetMachineConstant()));
}
public static T Read<T>(string signature, string secret)
@ -58,28 +59,28 @@ namespace ASC.Common.Utils
{
var rightSignature = signature.Replace("\"", "");
var payloadParts = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(rightSignature)).Split('?');
if (GetHashBase64(payloadParts[1] + secret) == payloadParts[0])
{
//Sig correct
return JsonConvert.DeserializeObject<T>(payloadParts[1]);
return JsonConvert.DeserializeObject<T>(payloadParts[1]); //Sig correct
}
}
catch (Exception)
{
}
catch (Exception) { }
return default;
}
private static string GetHashBase64(string str)
{
using var sha256 = SHA256.Create();
return Convert.ToBase64String(sha256.ComputeHash(Encoding.UTF8.GetBytes(str)));
}
private static string GetHashBase64MD5(string str)
{
using var md5 = MD5.Create();
return Convert.ToBase64String(md5.ComputeHash(Encoding.UTF8.GetBytes(str)));
}
}
}

View File

@ -23,57 +23,27 @@
*
*/
namespace ASC.Common.Utils
{
namespace ASC.Common.Utils;
[Singletone]
public class TimeZoneConverter
{
private TimeZoneInfo defaultTimeZone;
private TimeZoneInfo _defaultTimeZone;
private IEnumerable<MapZone> _mapZones;
private bool _customMode;
private bool _isMono;
private Dictionary<string, string> _translations;
private IConfiguration Configuration { get; }
private ILog Log { get; }
private readonly IConfiguration _configuration;
private readonly ILog _logger;
public TimeZoneConverter(IConfiguration configuration, IOptionsMonitor<ILog> option)
{
Log = option.CurrentValue;
Configuration = configuration;
_logger = option.CurrentValue;
_configuration = configuration;
InitMapZones();
InitTranslations();
}
private void InitMapZones()
{
try
{
var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream("ASC.Common.Utils.TimeZoneConverter.windowsZones.xml");
var xml = XElement.Load(stream);
_mapZones = from row in xml.XPathSelectElements("*/mapTimezones/mapZone")
let olsonTimeZones = row.Attribute("type").Value.Split(' ')
from olsonTimeZone in olsonTimeZones
select new MapZone
{
OlsonTimeZoneId = olsonTimeZone,
WindowsTimeZoneId = row.Attribute("other").Value,
Territory = row.Attribute("territory").Value
};
_mapZones = _mapZones.ToList();
}
catch (Exception error)
{
_mapZones = new MapZone[0];
Log.Error(error);
}
}
public string GetTimeZoneDisplayName(TimeZoneInfo tz)
{
var displayName = GetTimeZoneName(tz);
@ -99,14 +69,18 @@ namespace ASC.Common.Utils
var mapZone = GetMapZoneByWindowsTzId(olsonTimeZoneId);
if (mapZone != null)
{
return olsonTimeZoneId; //already Windows
}
mapZone = GetMapZoneByOlsonTzId(olsonTimeZoneId);
if (mapZone != null)
{
return mapZone.WindowsTimeZoneId;
}
Log.Error("OlsonTimeZone " + olsonTimeZoneId + " not found");
_logger.Error($"OlsonTimeZone {olsonTimeZoneId} not found");
return defaultIfNoMatch ? "UTC" : null;
}
@ -116,14 +90,18 @@ namespace ASC.Common.Utils
var mapZone = GetMapZoneByOlsonTzId(windowsTimeZoneId);
if (mapZone != null)
{
return windowsTimeZoneId; //already Olson
}
mapZone = GetMapZoneByWindowsTzId(windowsTimeZoneId);
if (mapZone != null)
{
return mapZone.OlsonTimeZoneId;
}
Log.Error("WindowsTimeZone " + windowsTimeZoneId + " not found");
_logger.Error($"WindowsTimeZone {windowsTimeZoneId} not found");
return defaultIfNoMatch ? "Etc/GMT" : null;
}
@ -146,35 +124,37 @@ namespace ASC.Common.Utils
try
{
var mapZone = GetMapZoneByOlsonTzId(timeZoneId);
if (mapZone != null)
{
return TimeZoneInfo.FindSystemTimeZoneById(mapZone.WindowsTimeZoneId);
}
mapZone = GetMapZoneByWindowsTzId(timeZoneId);
if (mapZone != null)
{
return TimeZoneInfo.FindSystemTimeZoneById(mapZone.OlsonTimeZoneId);
}
Log.InfoFormat("TimeZone {0} not found", timeZoneId);
_logger.InfoFormat("TimeZone {0} not found", timeZoneId);
return defaultIfNoMatch ? GetTimeZoneByOffset(timeZoneId) ?? defaultTimezone : null;
}
catch (Exception error)
{
Log.Error(error);
_logger.Error(error);
return defaultIfNoMatch ? defaultTimezone : null;
}
}
catch (Exception error)
{
Log.Error(error);
_logger.Error(error);
return defaultIfNoMatch ? defaultTimezone : null;
}
}
private MapZone GetMapZoneByOlsonTzId(string olsonTimeZoneId)
{
return _mapZones.FirstOrDefault(x =>
@ -197,59 +177,69 @@ namespace ASC.Common.Utils
tz.StandardName == timeZoneId ||
tz.DaylightName == timeZoneId);
if (timeZone != null) return timeZone;
if (timeZone != null)
{
return timeZone;
}
var regex = new Regex(@"[+-][0-9]{2}:[0-9]{2}\b");
var offsetStr = regex.Match(timeZoneId).Value.TrimStart('+');
if (string.IsNullOrEmpty(offsetStr)) return null;
if (string.IsNullOrEmpty(offsetStr))
{
return null;
}
if (!TimeSpan.TryParse(offsetStr, out var offset))
{
return null;
}
return systemTimeZones.FirstOrDefault(tz => tz.BaseUtcOffset == offset);
}
private void InitTranslations()
private void InitMapZones()
{
try
{
_customMode = Configuration["core:custom-mode"] == "true";
if (!_customMode)
{
_translations = new Dictionary<string, string>();
return;
}
var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream("ASC.Common.Utils.TimeZoneConverter.timeZoneNames.xml");
using var stream = assembly.GetManifestResourceStream("ASC.Common.Utils.TimeZoneConverter.windowsZones.xml");
var xml = XElement.Load(stream);
_translations = (from row in xml.XPathSelectElements("*/zone")
select new KeyValuePair<string, string>(row.Attribute("type").Value, row.Value)
).ToDictionary(item => item.Key, item => item.Value);
_mapZones = from row in xml.XPathSelectElements("*/mapTimezones/mapZone")
let olsonTimeZones = row.Attribute("type").Value.Split(' ')
from olsonTimeZone in olsonTimeZones
select new MapZone
{
OlsonTimeZoneId = olsonTimeZone,
WindowsTimeZoneId = row.Attribute("other").Value,
Territory = row.Attribute("territory").Value
};
_mapZones = _mapZones.ToList();
}
catch (Exception error)
{
_translations = new Dictionary<string, string>();
Log.Error(error);
_mapZones = new MapZone[0];
_logger.Error(error);
}
}
public string GetTimeZoneName(TimeZoneInfo timeZone)
{
if (!_customMode)
{
return _isMono ? timeZone.Id : timeZone.DisplayName;
}
return _translations.ContainsKey(timeZone.Id) ? _translations[timeZone.Id] : timeZone.DisplayName;
}
private TimeZoneInfo GetTimeZoneDefault()
{
if (defaultTimeZone == null)
if (_defaultTimeZone == null)
{
try
{
@ -263,6 +253,7 @@ namespace ASC.Common.Utils
else
{
var id = string.Empty;
if (File.Exists("/etc/timezone"))
{
_isMono = true;
@ -278,29 +269,62 @@ namespace ASC.Common.Utils
RedirectStandardOutput = true,
UseShellExecute = false,
};
using var p = Process.Start(psi);
if (p.WaitForExit(1000))
{
id = p.StandardOutput.ReadToEnd();
}
p.Close();
}
if (!string.IsNullOrEmpty(id))
{
tz = TimeZoneInfo.GetSystemTimeZones().FirstOrDefault(z => z.Id == id) ?? tz;
}
}
}
defaultTimeZone = tz;
_defaultTimeZone = tz;
}
catch (Exception)
{
// ignore
defaultTimeZone = TimeZoneInfo.Utc;
_defaultTimeZone = TimeZoneInfo.Utc;
}
}
return defaultTimeZone;
return _defaultTimeZone;
}
private void InitTranslations()
{
try
{
_customMode = _configuration["core:custom-mode"] == "true";
if (!_customMode)
{
_translations = new Dictionary<string, string>();
return;
}
var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream("ASC.Common.Utils.TimeZoneConverter.timeZoneNames.xml");
var xml = XElement.Load(stream);
_translations = (from row in xml.XPathSelectElements("*/zone")
select new KeyValuePair<string, string>(row.Attribute("type").Value, row.Value)
).ToDictionary(item => item.Key, item => item.Value);
}
catch (Exception error)
{
_translations = new Dictionary<string, string>();
_logger.Error(error);
}
}
private class MapZone
@ -310,4 +334,3 @@ namespace ASC.Common.Utils
public string Territory { get; set; }
}
}
}

View File

@ -23,8 +23,8 @@
*
*/
namespace ASC.Common.Utils
{
namespace ASC.Common.Utils;
public class TextLoader : ResourceLoader
{
public override void Init(Commons.Collections.ExtendedProperties configuration)
@ -50,20 +50,24 @@ namespace ASC.Common.Utils
public static class VelocityFormatter
{
private static bool initialized;
private static readonly ConcurrentDictionary<string, Template> patterns = new ConcurrentDictionary<string, Template>();
private static bool _initialized;
private static readonly ConcurrentDictionary<string, Template> _patterns = new ConcurrentDictionary<string, Template>();
public static string FormatText(string templateText, IDictionary<string, object> values)
{
var nvelocityContext = new VelocityContext();
foreach (var tagValue in values)
{
nvelocityContext.Put(tagValue.Key, tagValue.Value);
}
return FormatText(templateText, nvelocityContext);
}
public static string FormatText(string templateText, VelocityContext context)
{
if (!initialized)
if (!_initialized)
{
var properties = new Commons.Collections.ExtendedProperties();
properties.AddProperty("resource.loader", "custom");
@ -71,18 +75,20 @@ namespace ASC.Common.Utils
properties.AddProperty("input.encoding", Encoding.UTF8.WebName);
properties.AddProperty("output.encoding", Encoding.UTF8.WebName);
Velocity.Init(properties);
initialized = true;
_initialized = true;
}
using var writer = new StringWriter();
var key = templateText.GetHashCode().ToString();
if (!patterns.TryGetValue(key, out var template))
if (!_patterns.TryGetValue(key, out var template))
{
template = Velocity.GetTemplate(templateText);
patterns.TryAdd(key, template);
_patterns.TryAdd(key, template);
}
template.Merge(context, writer);
return writer.GetStringBuilder().ToString();
}
}
}

View File

@ -24,8 +24,8 @@
*/
namespace ASC.Common.Utils
{
namespace ASC.Common.Utils;
public static class Wildcard
{
public static bool WildcardMatch(this string input, string pattern)
@ -39,6 +39,7 @@ namespace ASC.Common.Utils
{
return IsMatch(pattern, input, ignoreCase);
}
return false;
}
@ -62,17 +63,25 @@ namespace ASC.Common.Utils
break;
case '*':
isAsterix = true;
while (i < pattern.Length &&
pattern[i] == '*')
{
i++;
}
if (i >= pattern.Length)
{
return true;
}
continue;
default:
if (offsetInput >= input.Length)
{
return false;
}
if ((ignoreCase
? char.ToLower(input[offsetInput])
: input[offsetInput])
@ -82,8 +91,12 @@ namespace ASC.Common.Utils
: pattern[i]))
{
if (!isAsterix)
{
return false;
}
offsetInput++;
continue;
}
offsetInput++;
@ -93,12 +106,15 @@ namespace ASC.Common.Utils
}
if (i > input.Length)
{
return false;
}
while (i < pattern.Length && pattern[i] == '*')
{
++i;
}
return offsetInput == input.Length;
}
}
}

View File

@ -23,44 +23,38 @@
*
*/
namespace ASC.Common.Web
{
namespace ASC.Common.Web;
public abstract class AbstractHttpAsyncHandler // : IHttpAsyncHandler, IReadOnlySessionState
{
private Action<Microsoft.AspNetCore.Http.HttpContext> processRequest;
private IPrincipal principal;
private CultureInfo culture;
public bool IsReusable => false;
private Action<HttpContext> _processRequest;
private IPrincipal _principal;
private CultureInfo _culture;
public bool IsReusable
public void ProcessRequest(HttpContext context)
{
get { return false; }
}
public void ProcessRequest(Microsoft.AspNetCore.Http.HttpContext context)
{
Thread.CurrentThread.CurrentCulture = culture;
Thread.CurrentThread.CurrentUICulture = culture;
Thread.CurrentPrincipal = principal;
Thread.CurrentThread.CurrentCulture = _culture;
Thread.CurrentThread.CurrentUICulture = _culture;
Thread.CurrentPrincipal = _principal;
//HttpContext.Current = context;
OnProcessRequest(context);
}
public IAsyncResult BeginProcessRequest(Microsoft.AspNetCore.Http.HttpContext context, AsyncCallback cb, object extraData)
public IAsyncResult BeginProcessRequest(HttpContext context, AsyncCallback cb, object extraData)
{
culture = Thread.CurrentThread.CurrentCulture;
principal = Thread.CurrentPrincipal;
processRequest = ProcessRequest;
return processRequest.BeginInvoke(context, cb, extraData);
_culture = Thread.CurrentThread.CurrentCulture;
_principal = Thread.CurrentPrincipal;
_processRequest = ProcessRequest;
return _processRequest.BeginInvoke(context, cb, extraData);
}
public void EndProcessRequest(IAsyncResult result)
{
processRequest.EndInvoke(result);
_processRequest.EndInvoke(result);
}
public abstract void OnProcessRequest(Microsoft.AspNetCore.Http.HttpContext context);
}
public abstract void OnProcessRequest(HttpContext context);
}

View File

@ -23,31 +23,27 @@
*
*/
namespace ASC.Common.Web;
#region usings
#endregion
namespace ASC.Common.Web
{
public class DisposableHttpContext : IDisposable
{
private const string key = "disposable.key";
private readonly Microsoft.AspNetCore.Http.HttpContext ctx;
public DisposableHttpContext(Microsoft.AspNetCore.Http.HttpContext ctx)
{
this.ctx = ctx ?? throw new ArgumentNullException();
}
private const string Key = "disposable.key";
public object this[string key]
{
get { return Items.ContainsKey(key) ? Items[key] : null; }
get => Items.ContainsKey(key) ? Items[key] : null;
set
{
if (value == null) throw new ArgumentNullException();
if (!(value is IDisposable)) throw new ArgumentException("Only IDisposable may be added!");
if (value == null)
{
throw new ArgumentNullException();
}
if (!(value is IDisposable))
{
throw new ArgumentException("Only IDisposable may be added!");
}
Items[key] = (IDisposable)value;
}
}
@ -56,20 +52,26 @@ namespace ASC.Common.Web
{
get
{
var table = (Dictionary<string, IDisposable>)ctx.Items[key];
var table = (Dictionary<string, IDisposable>)_context.Items[Key];
if (table == null)
{
table = new Dictionary<string, IDisposable>(1);
ctx.Items.Add(key, table);
_context.Items.Add(Key, table);
}
return table;
}
}
#region IDisposable Members
private readonly HttpContext _context;
private bool _isDisposed;
public DisposableHttpContext(HttpContext ctx)
{
_context = ctx ?? throw new ArgumentNullException(nameof(ctx));
}
public void Dispose()
{
if (!_isDisposed)
@ -80,14 +82,10 @@ namespace ASC.Common.Web
{
item.Dispose();
}
catch
{
}
catch { }
}
_isDisposed = true;
}
}
#endregion
}
}

View File

@ -1,7 +1,9 @@
namespace ASC.Common.Web
{
namespace ASC.Common.Web;
public class HttpException : Exception
{
public int StatusCode { get; }
public HttpException(int httpStatusCode)
{
StatusCode = httpStatusCode;
@ -31,7 +33,4 @@
{
StatusCode = (int)httpStatusCode;
}
public int StatusCode { get; }
}
}

View File

@ -1,19 +1,11 @@
namespace ASC.Common.Web
{
namespace ASC.Common.Web;
[Serializable]
public class ItemNotFoundException : HttpException
{
public ItemNotFoundException() : base(404, "Not found") { }
public ItemNotFoundException() : base(404, "Not found")
{
}
public ItemNotFoundException(string message) : base(404, message) { }
public ItemNotFoundException(string message) : base(404, message)
{
}
public ItemNotFoundException(string message, Exception inner) : base(404, message, inner)
{
}
}
public ItemNotFoundException(string message, Exception inner) : base(404, message, inner) { }
}

View File

@ -23,13 +23,12 @@
*
*/
namespace ASC.Common.Web
{
namespace ASC.Common.Web;
public static class MimeMapping
{
private static readonly Hashtable extensionToMimeMappingTable = new Hashtable(200, StringComparer.CurrentCultureIgnoreCase);
private static readonly IDictionary<string, IList<string>> mimeSynonyms = new Dictionary<string, IList<string>>();
private static readonly Hashtable _extensionToMimeMappingTable = new Hashtable(200, StringComparer.CurrentCultureIgnoreCase);
private static readonly IDictionary<string, IList<string>> _mimeSynonyms = new Dictionary<string, IList<string>>();
static MimeMapping()
{
@ -807,56 +806,48 @@ namespace ASC.Common.Web
AddMimeMapping(".*", "application/octet-stream");
}
private static void AddMimeMapping(string extension, string MimeType)
public static string GetExtention(string mimeMapping)
{
if (extensionToMimeMappingTable.ContainsKey(extension))
if (string.IsNullOrEmpty(mimeMapping)) return null;
foreach (DictionaryEntry entry in _extensionToMimeMappingTable)
{
AddMimeSynonym((string)extensionToMimeMappingTable[extension], MimeType);
}
else
{
extensionToMimeMappingTable.Add(extension, MimeType);
}
var mime = (string)entry.Value;
if (mime.Equals(mimeMapping, StringComparison.OrdinalIgnoreCase)) return (string)entry.Key;
if (!_mimeSynonyms.ContainsKey(mime)) continue;
if (_mimeSynonyms[mime].Contains(mimeMapping.ToLowerInvariant())) return (string)entry.Key;
}
private static void AddMimeSynonym(string mime, string synonym)
{
if (!mimeSynonyms.ContainsKey(mime))
{
mimeSynonyms[mime] = new List<string>();
}
if (!mimeSynonyms[mime].Contains(synonym))
{
mimeSynonyms[mime].Add(synonym);
}
return null;
}
public static string GetMimeMapping(string fileName)
{
string str = null;
var startIndex = fileName.LastIndexOf('.');
if (0 <= startIndex && fileName.LastIndexOf('\\') < startIndex)
{
str = (string)extensionToMimeMappingTable[fileName.Substring(startIndex)];
}
if (str == null)
{
str = (string)extensionToMimeMappingTable[".*"];
}
str = (string)_extensionToMimeMappingTable[fileName.Substring(startIndex)];
if (str == null) str = (string)_extensionToMimeMappingTable[".*"];
return str;
}
public static string GetExtention(string mimeMapping)
private static void AddMimeMapping(string extension, string MimeType)
{
if (string.IsNullOrEmpty(mimeMapping)) return null;
foreach (DictionaryEntry entry in extensionToMimeMappingTable)
if (_extensionToMimeMappingTable.ContainsKey(extension))
AddMimeSynonym((string)_extensionToMimeMappingTable[extension], MimeType);
else _extensionToMimeMappingTable.Add(extension, MimeType);
}
private static void AddMimeSynonym(string mime, string synonym)
{
var mime = (string)entry.Value;
if (mime.Equals(mimeMapping, StringComparison.OrdinalIgnoreCase)) return (string)entry.Key;
if (!mimeSynonyms.ContainsKey(mime)) continue;
if (mimeSynonyms[mime].Contains(mimeMapping.ToLowerInvariant())) return (string)entry.Key;
}
return null;
}
if (!_mimeSynonyms.ContainsKey(mime))
_mimeSynonyms[mime] = new List<string>();
if (!_mimeSynonyms[mime].Contains(synonym))
_mimeSynonyms[mime].Add(synonym);
}
}

View File

@ -23,19 +23,16 @@
*
*/
namespace ASC.Common.Web
{
namespace ASC.Common.Web;
public class RouteCallInfo
{
public int? Tid { get; set; }
public string Url { get; set; }
public string AttachmentUrl { get; set; }
public bool IsNewRequest { get; set; }
public string Method { get; set; }
public Dictionary<string, object> Params { get; set; }
public bool CleanupHtml { get; set; }
public RouteCallInfo()
@ -45,7 +42,8 @@ namespace ASC.Common.Web
public override string ToString()
{
return string.Format("{0} {1} T:{2},{3}", Method.ToUpper(), Url, Tid, string.Join(",", Params.Select(x => string.Format("{0}={1}", x.Key, x.Value)).ToArray()));
}
return string.Format("{0} {1} T:{2},{3}", Method.ToUpper(), Url, Tid,
string.Join(",",
Params.Select(x => string.Format("{0}={1}", x.Key, x.Value)).ToArray()));
}
}

View File

@ -1,16 +1,19 @@
namespace ASC.Common.Web
{
namespace ASC.Common.Web;
public static class VirtualPathUtility
{
public static string ToAbsolute(string virtualPath)
{
if (string.IsNullOrEmpty(virtualPath))
{
return virtualPath;
}
if (Uri.IsWellFormedUriString(virtualPath, UriKind.Absolute))
{
return virtualPath;
}
return "/" + virtualPath.TrimStart('~', '/');
}
}
}

View File

@ -40,7 +40,7 @@ namespace ASC.Core.Billing
Cache.Remove(TariffService.GetTariffCacheKey(i.TenantId));
Cache.Remove(TariffService.GetBillingUrlCacheKey(i.TenantId));
Cache.Remove(TariffService.GetBillingPaymentCacheKey(i.TenantId)); // clear all payments
}, CacheNotifyAction.Remove);
}, ASC.Common.Caching.CacheNotifyAction.Remove);
//TODO: Change code of WCF -> not supported in .NET standard/.Net Core
/*try
@ -297,7 +297,7 @@ namespace ASC.Core.Billing
public void ClearCache(int tenantId)
{
Notify.Publish(new TariffCacheItem { TenantId = tenantId }, CacheNotifyAction.Remove);
Notify.Publish(new TariffCacheItem { TenantId = tenantId }, ASC.Common.Caching.CacheNotifyAction.Remove);
}
public IEnumerable<PaymentInfo> GetPayments(int tenantId)

View File

@ -36,8 +36,8 @@ namespace ASC.Core.Caching
CacheNotify = cacheNotify;
Cache = cache;
cacheNotify.Subscribe((r) => UpdateCache(r, true), CacheNotifyAction.Remove);
cacheNotify.Subscribe((r) => UpdateCache(r, false), CacheNotifyAction.InsertOrUpdate);
cacheNotify.Subscribe((r) => UpdateCache(r, true), ASC.Common.Caching.CacheNotifyAction.Remove);
cacheNotify.Subscribe((r) => UpdateCache(r, false), ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
}
private void UpdateCache(AzRecord r, bool remove)
@ -102,14 +102,14 @@ namespace ASC.Core.Caching
public AzRecord SaveAce(int tenant, AzRecord r)
{
r = service.SaveAce(tenant, r);
cacheNotify.Publish(r, CacheNotifyAction.InsertOrUpdate);
cacheNotify.Publish(r, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
return r;
}
public void RemoveAce(int tenant, AzRecord r)
{
service.RemoveAce(tenant, r);
cacheNotify.Publish(r, CacheNotifyAction.Remove);
cacheNotify.Publish(r, ASC.Common.Caching.CacheNotifyAction.Remove);
}
}
}

View File

@ -62,7 +62,7 @@ namespace ASC.Core.Caching
{
Cache.Remove(i.Key);
}
}, CacheNotifyAction.Any);
}, ASC.Common.Caching.CacheNotifyAction.Any);
}
}
@ -142,7 +142,7 @@ namespace ASC.Core.Caching
public TenantQuota SaveTenantQuota(TenantQuota quota)
{
var q = Service.SaveTenantQuota(quota);
CacheNotify.Publish(new QuotaCacheItem { Key = QuotaServiceCache.KEY_QUOTA }, CacheNotifyAction.Any);
CacheNotify.Publish(new QuotaCacheItem { Key = QuotaServiceCache.KEY_QUOTA }, ASC.Common.Caching.CacheNotifyAction.Any);
return q;
}
@ -155,7 +155,7 @@ namespace ASC.Core.Caching
public void SetTenantQuotaRow(TenantQuotaRow row, bool exchange)
{
Service.SetTenantQuotaRow(row, exchange);
CacheNotify.Publish(new QuotaCacheItem { Key = GetKey(row.Tenant) }, CacheNotifyAction.InsertOrUpdate);
CacheNotify.Publish(new QuotaCacheItem { Key = GetKey(row.Tenant) }, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
}
public IEnumerable<TenantQuotaRow> FindTenantQuotaRows(int tenantId)

View File

@ -48,7 +48,7 @@ namespace ASC.Core.Caching
store.SaveSubscription(s);
}
}
}, CacheNotifyAction.InsertOrUpdate);
}, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
notifyRecord.Subscribe((s) =>
{
@ -67,7 +67,7 @@ namespace ASC.Core.Caching
}
}
}
}, CacheNotifyAction.Remove);
}, ASC.Common.Caching.CacheNotifyAction.Remove);
notifyMethod.Subscribe((m) =>
{
@ -79,7 +79,7 @@ namespace ASC.Core.Caching
store.SetSubscriptionMethod(m);
}
}
}, CacheNotifyAction.Any);
}, ASC.Common.Caching.CacheNotifyAction.Any);
}
private SubsciptionsStore GetSubsciptionsStore(int tenant, string sourceId, string actionId)
@ -153,19 +153,19 @@ namespace ASC.Core.Caching
public void SaveSubscription(SubscriptionRecord s)
{
service.SaveSubscription(s);
notifyRecord.Publish(s, CacheNotifyAction.InsertOrUpdate);
notifyRecord.Publish(s, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
}
public void RemoveSubscriptions(int tenant, string sourceId, string actionId)
{
service.RemoveSubscriptions(tenant, sourceId, actionId);
notifyRecord.Publish(new SubscriptionRecord { Tenant = tenant, SourceId = sourceId, ActionId = actionId }, CacheNotifyAction.Remove);
notifyRecord.Publish(new SubscriptionRecord { Tenant = tenant, SourceId = sourceId, ActionId = actionId }, ASC.Common.Caching.CacheNotifyAction.Remove);
}
public void RemoveSubscriptions(int tenant, string sourceId, string actionId, string objectId)
{
service.RemoveSubscriptions(tenant, sourceId, actionId, objectId);
notifyRecord.Publish(new SubscriptionRecord { Tenant = tenant, SourceId = sourceId, ActionId = actionId, ObjectId = objectId }, CacheNotifyAction.Remove);
notifyRecord.Publish(new SubscriptionRecord { Tenant = tenant, SourceId = sourceId, ActionId = actionId, ObjectId = objectId }, ASC.Common.Caching.CacheNotifyAction.Remove);
}
public IEnumerable<SubscriptionMethod> GetSubscriptionMethods(int tenant, string sourceId, string actionId, string recipientId)
@ -180,7 +180,7 @@ namespace ASC.Core.Caching
public void SetSubscriptionMethod(SubscriptionMethod m)
{
service.SetSubscriptionMethod(m);
notifyMethod.Publish(m, CacheNotifyAction.Any);
notifyMethod.Publish(m, ASC.Common.Caching.CacheNotifyAction.Any);
}

View File

@ -50,12 +50,12 @@ namespace ASC.Core.Caching
var tenants = GetTenantStore();
tenants.Remove(t.TenantId);
tenants.Clear(coreBaseSettings);
}, CacheNotifyAction.InsertOrUpdate);
}, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
cacheNotifySettings.Subscribe((s) =>
{
Cache.Remove(s.Key);
}, CacheNotifyAction.Remove);
}, ASC.Common.Caching.CacheNotifyAction.Remove);
}
internal TenantStore GetTenantStore()
@ -267,14 +267,14 @@ namespace ASC.Core.Caching
public Tenant SaveTenant(CoreSettings coreSettings, Tenant tenant)
{
tenant = Service.SaveTenant(coreSettings, tenant);
CacheNotifyItem.Publish(new TenantCacheItem() { TenantId = tenant.TenantId }, CacheNotifyAction.InsertOrUpdate);
CacheNotifyItem.Publish(new TenantCacheItem() { TenantId = tenant.TenantId }, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
return tenant;
}
public void RemoveTenant(int id, bool auto = false)
{
Service.RemoveTenant(id, auto);
CacheNotifyItem.Publish(new TenantCacheItem() { TenantId = id }, CacheNotifyAction.InsertOrUpdate);
CacheNotifyItem.Publish(new TenantCacheItem() { TenantId = id }, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
}
public IEnumerable<TenantVersion> GetTenantVersions()
@ -299,7 +299,7 @@ namespace ASC.Core.Caching
{
Service.SetTenantSettings(tenant, key, data);
var cacheKey = string.Format("settings/{0}/{1}", tenant, key);
CacheNotifySettings.Publish(new TenantSetting { Key = cacheKey }, CacheNotifyAction.Remove);
CacheNotifySettings.Publish(new TenantSetting { Key = cacheKey }, ASC.Common.Caching.CacheNotifyAction.Remove);
}
}
}

View File

@ -54,12 +54,12 @@ namespace ASC.Core.Caching
CacheGroupCacheItem = cacheGroupCacheItem;
CacheUserGroupRefItem = cacheUserGroupRefItem;
cacheUserInfoItem.Subscribe((u) => InvalidateCache(u), CacheNotifyAction.Any);
cacheUserPhotoItem.Subscribe((p) => Cache.Remove(p.Key), CacheNotifyAction.Remove);
cacheGroupCacheItem.Subscribe((g) => InvalidateCache(), CacheNotifyAction.Any);
cacheUserInfoItem.Subscribe((u) => InvalidateCache(u), ASC.Common.Caching.CacheNotifyAction.Any);
cacheUserPhotoItem.Subscribe((p) => Cache.Remove(p.Key), ASC.Common.Caching.CacheNotifyAction.Remove);
cacheGroupCacheItem.Subscribe((g) => InvalidateCache(), ASC.Common.Caching.CacheNotifyAction.Any);
cacheUserGroupRefItem.Subscribe((r) => UpdateUserGroupRefCache(r, true), CacheNotifyAction.Remove);
cacheUserGroupRefItem.Subscribe((r) => UpdateUserGroupRefCache(r, false), CacheNotifyAction.InsertOrUpdate);
cacheUserGroupRefItem.Subscribe((r) => UpdateUserGroupRefCache(r, true), ASC.Common.Caching.CacheNotifyAction.Remove);
cacheUserGroupRefItem.Subscribe((r) => UpdateUserGroupRefCache(r, false), ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
}
public void InvalidateCache()
@ -261,14 +261,14 @@ namespace ASC.Core.Caching
public UserInfo SaveUser(int tenant, UserInfo user)
{
user = Service.SaveUser(tenant, user);
CacheUserInfoItem.Publish(new UserInfoCacheItem { Id = user.ID.ToString(), Tenant = tenant }, CacheNotifyAction.Any);
CacheUserInfoItem.Publish(new UserInfoCacheItem { Id = user.ID.ToString(), Tenant = tenant }, ASC.Common.Caching.CacheNotifyAction.Any);
return user;
}
public void RemoveUser(int tenant, Guid id)
{
Service.RemoveUser(tenant, id);
CacheUserInfoItem.Publish(new UserInfoCacheItem { Tenant = tenant, Id = id.ToString() }, CacheNotifyAction.Any);
CacheUserInfoItem.Publish(new UserInfoCacheItem { Tenant = tenant, Id = id.ToString() }, ASC.Common.Caching.CacheNotifyAction.Any);
}
public byte[] GetUserPhoto(int tenant, Guid id)
@ -285,7 +285,7 @@ namespace ASC.Core.Caching
public void SetUserPhoto(int tenant, Guid id, byte[] photo)
{
Service.SetUserPhoto(tenant, id, photo);
CacheUserPhotoItem.Publish(new UserPhotoCacheItem { Key = UserServiceCache.GetUserPhotoCacheKey(tenant, id) }, CacheNotifyAction.Remove);
CacheUserPhotoItem.Publish(new UserPhotoCacheItem { Key = UserServiceCache.GetUserPhotoCacheKey(tenant, id) }, ASC.Common.Caching.CacheNotifyAction.Remove);
}
public DateTime GetUserPasswordStamp(int tenant, Guid id)
@ -316,14 +316,14 @@ namespace ASC.Core.Caching
public Group SaveGroup(int tenant, Group group)
{
group = Service.SaveGroup(tenant, group);
CacheGroupCacheItem.Publish(new GroupCacheItem { Id = group.Id.ToString() }, CacheNotifyAction.Any);
CacheGroupCacheItem.Publish(new GroupCacheItem { Id = group.Id.ToString() }, ASC.Common.Caching.CacheNotifyAction.Any);
return group;
}
public void RemoveGroup(int tenant, Guid id)
{
Service.RemoveGroup(tenant, id);
CacheGroupCacheItem.Publish(new GroupCacheItem { Id = id.ToString() }, CacheNotifyAction.Any);
CacheGroupCacheItem.Publish(new GroupCacheItem { Id = id.ToString() }, ASC.Common.Caching.CacheNotifyAction.Any);
}
@ -357,7 +357,7 @@ namespace ASC.Core.Caching
public UserGroupRef SaveUserGroupRef(int tenant, UserGroupRef r)
{
r = Service.SaveUserGroupRef(tenant, r);
CacheUserGroupRefItem.Publish(r, CacheNotifyAction.InsertOrUpdate);
CacheUserGroupRefItem.Publish(r, ASC.Common.Caching.CacheNotifyAction.InsertOrUpdate);
return r;
}
@ -366,7 +366,7 @@ namespace ASC.Core.Caching
Service.RemoveUserGroupRef(tenant, userId, groupId, refType);
var r = new UserGroupRef(userId, groupId, refType) { Tenant = tenant };
CacheUserGroupRefItem.Publish(r, CacheNotifyAction.Remove);
CacheUserGroupRefItem.Publish(r, ASC.Common.Caching.CacheNotifyAction.Remove);
}

View File

@ -170,7 +170,7 @@ namespace ASC.Core.Common.Configuration
this[providerProp.Key] = null;
}
Cache.Publish(new ConsumerCacheItem() { Name = this.Name }, CacheNotifyAction.Remove);
Cache.Publish(new ConsumerCacheItem() { Name = this.Name }, ASC.Common.Caching.CacheNotifyAction.Remove);
}
public bool Contains(KeyValuePair<string, string> item)

View File

@ -37,12 +37,12 @@ namespace ASC.Core.Data
{
Cache = cache;
Notify = notify;
Notify.Subscribe((i) => Cache.Remove(i.Key), CacheNotifyAction.Remove);
Notify.Subscribe((i) => Cache.Remove(i.Key), ASC.Common.Caching.CacheNotifyAction.Remove);
}
public void Remove(string key)
{
Notify.Publish(new SettingsCacheItem { Key = key }, CacheNotifyAction.Remove);
Notify.Publish(new SettingsCacheItem { Key = key }, ASC.Common.Caching.CacheNotifyAction.Remove);
}
}

View File

@ -4,7 +4,8 @@
public class PostgreSqlMessagesContext : MessagesContext { }
public class MessagesContext : BaseDbContext
{
public DbSet<LoginEvents> LoginEvents { get; set; }
public DbSet<AuditEvent> AuditEvents { get; set; }
public DbSet<LoginEvent> LoginEvents { get; set; }
public DbSet<User> Users { get; set; }
protected override Dictionary<Provider, Func<BaseDbContext>> ProviderContext
@ -23,6 +24,7 @@
{
ModelBuilderWrapper
.From(modelBuilder, Provider)
.AddAuditEvent()
.AddLoginEvents()
.AddUser()
.AddDbFunction();

View File

@ -40,7 +40,7 @@
.HasColumnName("date")
.HasColumnType("datetime");
entity.Property(e => e.Description)
entity.Property(e => e.DescriptionRaw)
.HasColumnName("description")
.HasColumnType("varchar(20000)")
.HasCharSet("utf8")
@ -105,7 +105,7 @@
entity.Property(e => e.Date).HasColumnName("date");
entity.Property(e => e.Description)
entity.Property(e => e.DescriptionRaw)
.HasColumnName("description")
.HasMaxLength(20000)
.HasDefaultValueSql("NULL");

View File

@ -1,9 +1,10 @@
namespace ASC.Core.Common.EF.Model
{
public class LoginEvents : MessageEvent
public class LoginEvent : MessageEvent
{
public string Login { get; set; }
}
public static class LoginEventsExtension
{
public static ModelBuilderWrapper AddLoginEvents(this ModelBuilderWrapper modelBuilder)
@ -15,7 +16,7 @@
}
public static void MySqlAddLoginEvents(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<LoginEvents>(entity =>
modelBuilder.Entity<LoginEvent>(entity =>
{
entity.ToTable("login_events");
@ -39,7 +40,7 @@
.HasColumnName("date")
.HasColumnType("datetime");
entity.Property(e => e.Description)
entity.Property(e => e.DescriptionRaw)
.HasColumnName("description")
.HasColumnType("varchar(500)")
.HasCharSet("utf8")
@ -81,7 +82,7 @@
}
public static void PgSqlAddLoginEvents(this ModelBuilder modelBuilder)
{
modelBuilder.Entity<LoginEvents>(entity =>
modelBuilder.Entity<LoginEvent>(entity =>
{
entity.ToTable("login_events", "onlyoffice");
@ -102,7 +103,7 @@
entity.Property(e => e.Date).HasColumnName("date");
entity.Property(e => e.Description)
entity.Property(e => e.DescriptionRaw)
.HasColumnName("description")
.HasMaxLength(500)
.HasDefaultValueSql("NULL");

View File

@ -11,6 +11,6 @@
public Guid UserId { get; set; }
public string Page { get; set; }
public int Action { get; set; }
public string Description { get; set; }
public string DescriptionRaw { get; set; }
}
}

View File

@ -23,6 +23,8 @@
*
*/
using CacheNotifyAction = ASC.Common.Caching.CacheNotifyAction;
namespace ASC.Core.Notify
{
[Scope]

View File

@ -50,7 +50,7 @@ namespace ASC.Core.Common.Notify
public void SendMessage(NotifyMessage m)
{
CacheMessage.Publish(m, CacheNotifyAction.Insert);
CacheMessage.Publish(m, ASC.Common.Caching.CacheNotifyAction.Insert);
}
public void RegisterUser(string userId, int tenantId, string token)
@ -61,7 +61,7 @@ namespace ASC.Core.Common.Notify
UserId = userId,
TenantId = tenantId,
Token = token
}, CacheNotifyAction.Insert);
}, ASC.Common.Caching.CacheNotifyAction.Insert);
}
public void CreateOrUpdateClient(int tenantId, string token, int tokenLifespan, string proxy)
@ -72,12 +72,12 @@ namespace ASC.Core.Common.Notify
Token = token,
TokenLifespan = tokenLifespan,
Proxy = proxy
}, CacheNotifyAction.Insert);
}, ASC.Common.Caching.CacheNotifyAction.Insert);
}
public void DisableClient(int tenantId)
{
CacheDisableClient.Publish(new DisableClientProto() { TenantId = tenantId }, CacheNotifyAction.Insert);
CacheDisableClient.Publish(new DisableClientProto() { TenantId = tenantId }, ASC.Common.Caching.CacheNotifyAction.Insert);
}
public string RegistrationToken(string userId, int tenantId)

View File

@ -65,7 +65,7 @@ namespace ASC.Data.Storage.Configuration
{
storageSettingsHelper.Clear(cdnSettings);
}
}, CacheNotifyAction.Remove);
}, Common.Caching.CacheNotifyAction.Remove);
}
}
}
@ -168,7 +168,7 @@ namespace ASC.Data.Storage.Configuration
var path = TenantPath.CreatePath(tenantId);
foreach (var module in StorageFactoryConfig.GetModuleList("", true))
{
Cache.Publish(new DataStoreCacheItem() { TenantId = path, Module = module }, CacheNotifyAction.Remove);
Cache.Publish(new DataStoreCacheItem() { TenantId = path, Module = module }, Common.Caching.CacheNotifyAction.Remove);
}
}

View File

@ -23,6 +23,8 @@
*
*/
using CacheNotifyAction = ASC.Common.Caching.CacheNotifyAction;
namespace ASC.Data.Storage.Encryption
{
[Scope]

Some files were not shown because too many files have changed in this diff Show More