Merge branch 'master' into feature/files
# Conflicts: # products/ASC.Files/Core/Core/Dao/TeamlabDao/FileDao.cs # products/ASC.Files/Core/Core/Dao/TeamlabDao/FolderDao.cs # products/ASC.Files/Core/Core/FileStorageService.cs # products/ASC.Files/Server/Controllers/FilesController.cs
This commit is contained in:
commit
2c1d473314
@ -66,6 +66,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Data.Storage.Migration"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.Data.Storage.Encryption", "common\services\ASC.Data.Storage.Encryption\ASC.Data.Storage.Encryption.csproj", "{17A05AE2-21C8-4C1C-B422-6AB80F13F63E}"
|
||||
EndProject
|
||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ASC.TelegramService", "common\services\ASC.TelegramService\ASC.TelegramService.csproj", "{95CE7371-17B6-4EEE-8E38-2FDE6347E955}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
@ -192,6 +194,10 @@ Global
|
||||
{17A05AE2-21C8-4C1C-B422-6AB80F13F63E}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{17A05AE2-21C8-4C1C-B422-6AB80F13F63E}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{17A05AE2-21C8-4C1C-B422-6AB80F13F63E}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{95CE7371-17B6-4EEE-8E38-2FDE6347E955}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{95CE7371-17B6-4EEE-8E38-2FDE6347E955}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{95CE7371-17B6-4EEE-8E38-2FDE6347E955}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{95CE7371-17B6-4EEE-8E38-2FDE6347E955}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
|
2
build/run/TelegramService.bat
Normal file
2
build/run/TelegramService.bat
Normal file
@ -0,0 +1,2 @@
|
||||
echo "RUN ASC.TelegramService"
|
||||
call dotnet run --project ..\..\common\services\ASC.TelegramService\ASC.TelegramService.csproj --no-build --$STORAGE_ROOT=..\..\Data --log__dir=..\..\Logs --log__name=telegram
|
@ -40,6 +40,7 @@
|
||||
</PackageReference>
|
||||
<PackageReference Include="JWT" Version="6.1.4" />
|
||||
<PackageReference Include="log4net" Version="2.0.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation" Version="3.1.8" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http" Version="2.2.2" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Abstractions" Version="2.2.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Http.Extensions" Version="2.2.0" />
|
||||
|
@ -121,9 +121,19 @@ namespace ASC.Common.Logging
|
||||
{
|
||||
_lastCleanDate = DateTime.UtcNow.Date;
|
||||
Clean();
|
||||
}
|
||||
|
||||
base.Write(logEvents);
|
||||
}
|
||||
|
||||
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)
|
||||
|
108
common/ASC.Common/Security/Cryptography/PasswordHasher.cs
Normal file
108
common/ASC.Common/Security/Cryptography/PasswordHasher.cs
Normal file
@ -0,0 +1,108 @@
|
||||
/*
|
||||
*
|
||||
* (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.Text;
|
||||
|
||||
using ASC.Common;
|
||||
|
||||
using Microsoft.AspNetCore.Cryptography.KeyDerivation;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace ASC.Security.Cryptography
|
||||
{
|
||||
public class PasswordHasher
|
||||
{
|
||||
public PasswordHasher(IConfiguration configuration, MachinePseudoKeys machinePseudoKeys)
|
||||
{
|
||||
if (!int.TryParse(configuration["core:password:size"], out var size)) size = 256;
|
||||
PasswordHashSize = size;
|
||||
|
||||
if (!int.TryParse(configuration["core.password.iterations"], out var iterations)) iterations = 100000;
|
||||
PasswordHashIterations = iterations;
|
||||
|
||||
PasswordHashSalt = (configuration["core:password:salt"] ?? "").Trim();
|
||||
if (string.IsNullOrEmpty(PasswordHashSalt))
|
||||
{
|
||||
var salt = Hasher.Hash("{9450BEF7-7D9F-4E4F-A18A-971D8681722D}", HashAlg.SHA256);
|
||||
|
||||
var PasswordHashSaltBytes = KeyDerivation.Pbkdf2(
|
||||
Encoding.UTF8.GetString(machinePseudoKeys.GetMachineConstant()),
|
||||
salt,
|
||||
KeyDerivationPrf.HMACSHA256,
|
||||
PasswordHashIterations,
|
||||
PasswordHashSize / 8);
|
||||
PasswordHashSalt = BitConverter.ToString(PasswordHashSaltBytes).Replace("-", string.Empty).ToLower();
|
||||
}
|
||||
}
|
||||
|
||||
public int PasswordHashSize
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public int PasswordHashIterations
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public string PasswordHashSalt
|
||||
{
|
||||
get;
|
||||
private set;
|
||||
}
|
||||
|
||||
public string GetClientPassword(string password)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(password)) password = Guid.NewGuid().ToString();
|
||||
|
||||
var salt = new UTF8Encoding(false).GetBytes(PasswordHashSalt);
|
||||
|
||||
var hashBytes = KeyDerivation.Pbkdf2(
|
||||
password,
|
||||
salt,
|
||||
KeyDerivationPrf.HMACSHA256,
|
||||
PasswordHashIterations,
|
||||
PasswordHashSize / 8);
|
||||
|
||||
var hash = BitConverter.ToString(hashBytes).Replace("-", string.Empty).ToLower();
|
||||
|
||||
return hash;
|
||||
}
|
||||
}
|
||||
public static class PasswordHasherExtension
|
||||
{
|
||||
public static DIHelper AddPasswordHasherService(this DIHelper services)
|
||||
{
|
||||
services.TryAddSingleton<PasswordHasher>();
|
||||
|
||||
return services.AddMachinePseudoKeysService();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -63,18 +63,11 @@ namespace ASC.Common.Utils
|
||||
}
|
||||
|
||||
public static T Read<T>(string signature, string secret)
|
||||
{
|
||||
return Read<T>(signature, secret, true);
|
||||
}
|
||||
|
||||
public static T Read<T>(string signature, string secret, bool useSecret)
|
||||
{
|
||||
try
|
||||
{
|
||||
var payloadParts = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(signature)).Split('?');
|
||||
if (!useSecret || GetHashBase64(payloadParts[1] + secret) == payloadParts[0]
|
||||
|| GetHashBase64MD5(payloadParts[1] + secret) == payloadParts[0] //todo: delete
|
||||
)
|
||||
if (GetHashBase64(payloadParts[1] + secret) == payloadParts[0])
|
||||
{
|
||||
//Sig correct
|
||||
return JsonConvert.DeserializeObject<T>(payloadParts[1]);
|
||||
|
@ -700,7 +700,8 @@ namespace ASC.Common.Web
|
||||
AddMimeMapping(".wcm", "application/vnd.ms-works");
|
||||
AddMimeMapping(".wdb", "application/vnd.ms-works");
|
||||
AddMimeMapping(".web", "application/vnd.xara");
|
||||
AddMimeMapping(".webm", "video/webm");
|
||||
AddMimeMapping(".webm", "video/webm");
|
||||
AddMimeMapping(".webp", "image/webp");
|
||||
AddMimeMapping(".wiz", "application/msword");
|
||||
AddMimeMapping(".wk1", "application/x-123");
|
||||
AddMimeMapping(".wks", "application/vnd.ms-works");
|
||||
|
@ -30,10 +30,13 @@
|
||||
<ItemGroup>
|
||||
<None Remove="protos\AzRecordCache.proto" />
|
||||
<None Remove="protos\ConsumerCacheItem.proto" />
|
||||
<None Remove="protos\CreateClientProto.proto" />
|
||||
<None Remove="protos\DisableClientProto.proto" />
|
||||
<None Remove="protos\GroupCacheItem.proto" />
|
||||
<None Remove="protos\NotifyInvoke.proto" />
|
||||
<None Remove="protos\NotifyMessage.proto" />
|
||||
<None Remove="protos\QuotaCacheItem.proto" />
|
||||
<None Remove="protos\RegisterUserProto.proto" />
|
||||
<None Remove="protos\SettingsCacheItem.proto" />
|
||||
<None Remove="protos\SubscriptionMethodCache.proto" />
|
||||
<None Remove="protos\SubscriptionRecord.proto" />
|
||||
@ -57,10 +60,14 @@
|
||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Relational" Version="3.1.5" />
|
||||
<PackageReference Include="Pomelo.EntityFrameworkCore.MySql" Version="3.1.1" />
|
||||
<PackageReference Include="System.Text.Json" Version="4.7.2" />
|
||||
<PackageReference Include="Telegram.Bot" Version="15.7.1" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Protobuf Include="protos\CreateClientProto.proto" />
|
||||
<Protobuf Include="protos\NotifyInvoke.proto" />
|
||||
<Protobuf Include="protos\NotifyMessage.proto" />
|
||||
<Protobuf Include="protos\DisableClientProto.proto" />
|
||||
<Protobuf Include="protos\RegisterUserProto.proto" />
|
||||
<Protobuf Include="protos\SettingsCacheItem.proto" />
|
||||
<Protobuf Include="protos\ConsumerCacheItem.proto" />
|
||||
<Protobuf Include="protos\TenantCacheItem.proto" />
|
||||
|
@ -223,6 +223,10 @@ namespace ASC.Core.Common
|
||||
|
||||
//--remove redundant slashes
|
||||
var uri = new Uri(url);
|
||||
|
||||
if (uri.Scheme == "mailto")
|
||||
return uri.OriginalString;
|
||||
|
||||
var baseUri = new UriBuilder(uri.Scheme, uri.Host, uri.Port).Uri;
|
||||
baseUri = uri.Segments.Aggregate(baseUri, (current, segment) => new Uri(current, segment));
|
||||
//--
|
||||
|
@ -43,7 +43,11 @@ namespace ASC.Core.Billing
|
||||
//[Obsolete]
|
||||
public bool WhiteLabel { get; set; }
|
||||
|
||||
public bool Customization { get; set; }
|
||||
public bool Customization { get; set; }
|
||||
|
||||
public bool Branding { get; set; }
|
||||
|
||||
public bool SSBranding { get; set; }
|
||||
|
||||
[JsonPropertyName("end_date")]
|
||||
public DateTime DueDate { get; set; }
|
||||
@ -60,7 +64,8 @@ namespace ASC.Core.Billing
|
||||
public string CustomerId { get; set; }
|
||||
|
||||
public string Signature { get; set; }
|
||||
|
||||
|
||||
public bool? DiscEncryption { get; set; }
|
||||
|
||||
public static License Parse(string licenseString)
|
||||
{
|
||||
|
@ -41,7 +41,7 @@ namespace ASC.Core.Billing
|
||||
public class LicenseReader
|
||||
{
|
||||
private readonly ILog Log;
|
||||
private readonly string LicensePath;
|
||||
public readonly string LicensePath;
|
||||
private readonly string LicensePathTemp;
|
||||
|
||||
public const string CustomerIdKey = "CustomerId";
|
||||
@ -60,7 +60,7 @@ namespace ASC.Core.Billing
|
||||
PaymentManager = paymentManager;
|
||||
CoreSettings = coreSettings;
|
||||
Configuration = configuration;
|
||||
LicensePath = Configuration["license:file:path"];
|
||||
LicensePath = Configuration["license:file:path"] ?? "";
|
||||
LicensePathTemp = LicensePath + ".tmp";
|
||||
Log = options.CurrentValue;
|
||||
}
|
||||
@ -199,52 +199,62 @@ namespace ASC.Core.Billing
|
||||
|
||||
private void LicenseToDB(License license)
|
||||
{
|
||||
Validate(license);
|
||||
|
||||
CustomerId = license.CustomerId;
|
||||
|
||||
var defaultQuota = TenantManager.GetTenantQuota(Tenant.DEFAULT_TENANT);
|
||||
|
||||
var quota = new TenantQuota(-1000)
|
||||
{
|
||||
ActiveUsers = license.ActiveUsers,
|
||||
MaxFileSize = defaultQuota.MaxFileSize,
|
||||
MaxTotalSize = defaultQuota.MaxTotalSize,
|
||||
Name = "license",
|
||||
HasDomain = true,
|
||||
Audit = true,
|
||||
ControlPanel = true,
|
||||
HealthCheck = true,
|
||||
Ldap = true,
|
||||
Sso = true,
|
||||
WhiteLabel = license.WhiteLabel || license.Customization,
|
||||
Update = true,
|
||||
Support = true,
|
||||
Trial = license.Trial,
|
||||
CountPortals = license.PortalCount,
|
||||
};
|
||||
|
||||
TenantManager.SaveTenantQuota(quota);
|
||||
|
||||
if (defaultQuota.CountPortals != license.PortalCount)
|
||||
{
|
||||
defaultQuota.CountPortals = license.PortalCount;
|
||||
TenantManager.SaveTenantQuota(defaultQuota);
|
||||
}
|
||||
|
||||
var tariff = new Tariff
|
||||
{
|
||||
QuotaId = quota.Id,
|
||||
DueDate = license.DueDate,
|
||||
};
|
||||
|
||||
PaymentManager.SetTariff(-1, tariff);
|
||||
|
||||
if (!string.IsNullOrEmpty(license.AffiliateId))
|
||||
{
|
||||
var tenant = TenantManager.GetCurrentTenant();
|
||||
tenant.AffiliateId = license.AffiliateId;
|
||||
TenantManager.SaveTenant(tenant);
|
||||
Validate(license);
|
||||
|
||||
CustomerId = license.CustomerId;
|
||||
|
||||
var defaultQuota = TenantManager.GetTenantQuota(Tenant.DEFAULT_TENANT);
|
||||
|
||||
var quota = new TenantQuota(-1000)
|
||||
{
|
||||
ActiveUsers = license.ActiveUsers,
|
||||
MaxFileSize = defaultQuota.MaxFileSize,
|
||||
MaxTotalSize = defaultQuota.MaxTotalSize,
|
||||
Name = "license",
|
||||
DocsEdition = true,
|
||||
HasDomain = true,
|
||||
Audit = true,
|
||||
ControlPanel = true,
|
||||
HealthCheck = true,
|
||||
Ldap = true,
|
||||
Sso = true,
|
||||
Customization = license.Customization,
|
||||
WhiteLabel = license.WhiteLabel || license.Customization,
|
||||
Branding = license.Branding,
|
||||
SSBranding = license.SSBranding,
|
||||
Update = true,
|
||||
Support = true,
|
||||
Trial = license.Trial,
|
||||
CountPortals = license.PortalCount,
|
||||
DiscEncryption = license.DiscEncryption ?? !license.Trial,
|
||||
PrivacyRoom = !license.Trial,
|
||||
};
|
||||
|
||||
if (defaultQuota.Name != "overdue" && !defaultQuota.Trial)
|
||||
{
|
||||
quota.WhiteLabel |= defaultQuota.WhiteLabel;
|
||||
quota.Branding |= defaultQuota.Branding;
|
||||
quota.SSBranding |= defaultQuota.SSBranding;
|
||||
quota.DiscEncryption |= defaultQuota.DiscEncryption;
|
||||
|
||||
quota.CountPortals = Math.Max(defaultQuota.CountPortals, quota.CountPortals);
|
||||
}
|
||||
|
||||
TenantManager.SaveTenantQuota(quota);
|
||||
|
||||
var tariff = new Tariff
|
||||
{
|
||||
QuotaId = quota.Id,
|
||||
DueDate = license.DueDate,
|
||||
};
|
||||
|
||||
PaymentManager.SetTariff(-1, tariff);
|
||||
|
||||
if (!string.IsNullOrEmpty(license.AffiliateId))
|
||||
{
|
||||
var tenant = TenantManager.GetCurrentTenant();
|
||||
tenant.AffiliateId = license.AffiliateId;
|
||||
TenantManager.SaveTenant(tenant);
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,52 +285,52 @@ namespace ASC.Core.Billing
|
||||
{
|
||||
// release sign is not longer requered
|
||||
return _date;
|
||||
|
||||
//if (_date != DateTime.MinValue) return _date;
|
||||
|
||||
//_date = DateTime.MaxValue;
|
||||
//try
|
||||
//{
|
||||
// var versionDate = Configuration["version:release:date"];
|
||||
// var sign = Configuration["version:release:sign"];
|
||||
|
||||
// if (!sign.StartsWith("ASC "))
|
||||
// {
|
||||
// throw new Exception("sign without ASC");
|
||||
// }
|
||||
|
||||
// var splitted = sign.Substring(4).Split(':');
|
||||
// var pkey = splitted[0];
|
||||
// if (pkey != versionDate)
|
||||
// {
|
||||
// throw new Exception("sign with different date");
|
||||
// }
|
||||
|
||||
// var date = splitted[1];
|
||||
// var orighash = splitted[2];
|
||||
|
||||
// var skey = Configuration["core:machinekey"];
|
||||
|
||||
// using (var hasher = new HMACSHA1(Encoding.UTF8.GetBytes(skey)))
|
||||
// {
|
||||
// var data = string.Join("\n", date, pkey);
|
||||
// var hash = hasher.ComputeHash(Encoding.UTF8.GetBytes(data));
|
||||
// if (WebEncoders.Base64UrlEncode(hash) != orighash && Convert.ToBase64String(hash) != orighash)
|
||||
// {
|
||||
// throw new Exception("incorrect hash");
|
||||
// }
|
||||
// }
|
||||
|
||||
// var year = int.Parse(versionDate.Substring(0, 4));
|
||||
// var month = int.Parse(versionDate.Substring(4, 2));
|
||||
// var day = int.Parse(versionDate.Substring(6, 2));
|
||||
// _date = new DateTime(year, month, day);
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// Log.Error("VersionReleaseDate", ex);
|
||||
//}
|
||||
//return _date;
|
||||
|
||||
//if (_date != DateTime.MinValue) return _date;
|
||||
|
||||
//_date = DateTime.MaxValue;
|
||||
//try
|
||||
//{
|
||||
// var versionDate = Configuration["version:release:date"];
|
||||
// var sign = Configuration["version:release:sign"];
|
||||
|
||||
// if (!sign.StartsWith("ASC "))
|
||||
// {
|
||||
// throw new Exception("sign without ASC");
|
||||
// }
|
||||
|
||||
// var splitted = sign.Substring(4).Split(':');
|
||||
// var pkey = splitted[0];
|
||||
// if (pkey != versionDate)
|
||||
// {
|
||||
// throw new Exception("sign with different date");
|
||||
// }
|
||||
|
||||
// var date = splitted[1];
|
||||
// var orighash = splitted[2];
|
||||
|
||||
//var skey = MachinePseudoKeys.GetMachineConstant();
|
||||
|
||||
//using (var hasher = new HMACSHA1(skey))
|
||||
// {
|
||||
// var data = string.Join("\n", date, pkey);
|
||||
// var hash = hasher.ComputeHash(Encoding.UTF8.GetBytes(data));
|
||||
// if (WebEncoders.Base64UrlEncode(hash) != orighash && Convert.ToBase64String(hash) != orighash)
|
||||
// {
|
||||
// throw new Exception("incorrect hash");
|
||||
// }
|
||||
// }
|
||||
|
||||
// var year = int.Parse(versionDate.Substring(0, 4));
|
||||
// var month = int.Parse(versionDate.Substring(4, 2));
|
||||
// var day = int.Parse(versionDate.Substring(6, 2));
|
||||
// _date = new DateTime(year, month, day);
|
||||
//}
|
||||
//catch (Exception ex)
|
||||
//{
|
||||
// Log.Error("VersionReleaseDate", ex);
|
||||
//}
|
||||
//return _date;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -577,16 +577,17 @@ namespace ASC.Core.Billing
|
||||
{
|
||||
tariff.State = TariffState.NotPaid;
|
||||
|
||||
if ((q == null || !q.Trial) && CoreBaseSettings.Standalone)
|
||||
{
|
||||
if (q != null)
|
||||
{
|
||||
var defaultQuota = QuotaService.GetTenantQuota(Tenant.DEFAULT_TENANT);
|
||||
if (defaultQuota.CountPortals != q.CountPortals)
|
||||
{
|
||||
defaultQuota.CountPortals = q.CountPortals;
|
||||
QuotaService.SaveTenantQuota(defaultQuota);
|
||||
}
|
||||
if (CoreBaseSettings.Standalone)
|
||||
{
|
||||
if (q != null)
|
||||
{
|
||||
var defaultQuota = QuotaService.GetTenantQuota(Tenant.DEFAULT_TENANT);
|
||||
defaultQuota.Name = "overdue";
|
||||
|
||||
defaultQuota.Features = q.Features;
|
||||
defaultQuota.Support = false;
|
||||
|
||||
QuotaService.SaveTenantQuota(defaultQuota);
|
||||
}
|
||||
|
||||
var unlimTariff = Tariff.CreateDefault();
|
||||
|
@ -37,6 +37,7 @@ using ASC.Core.Common.EF;
|
||||
using ASC.Core.Data;
|
||||
using ASC.Core.Tenants;
|
||||
using ASC.Core.Users;
|
||||
using ASC.Security.Cryptography;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
@ -283,9 +284,9 @@ namespace ASC.Core.Caching
|
||||
return user;
|
||||
}
|
||||
|
||||
public UserInfo GetUser(int tenant, string login, string passwordHash)
|
||||
{
|
||||
return Service.GetUser(tenant, login, passwordHash);
|
||||
public UserInfo GetUserByPasswordHash(int tenant, string login, string passwordHash)
|
||||
{
|
||||
return Service.GetUserByPasswordHash(tenant, login, passwordHash);
|
||||
}
|
||||
|
||||
public UserInfo SaveUser(int tenant, UserInfo user)
|
||||
@ -318,15 +319,16 @@ namespace ASC.Core.Caching
|
||||
CacheUserPhotoItem.Publish(new UserPhotoCacheItem { Key = UserServiceCache.GetUserPhotoCacheKey(tenant, id) }, CacheNotifyAction.Remove);
|
||||
}
|
||||
|
||||
public string GetUserPassword(int tenant, Guid id)
|
||||
{
|
||||
return Service.GetUserPassword(tenant, id);
|
||||
}
|
||||
public DateTime GetUserPasswordStamp(int tenant, Guid id)
|
||||
{
|
||||
return Service.GetUserPasswordStamp(tenant, id);
|
||||
}
|
||||
|
||||
public void SetUserPasswordHash(int tenant, Guid id, string passwordHash)
|
||||
{
|
||||
Service.SetUserPasswordHash(tenant, id, passwordHash);
|
||||
}
|
||||
|
||||
public void SetUserPassword(int tenant, Guid id, string password)
|
||||
{
|
||||
Service.SetUserPassword(tenant, id, password);
|
||||
}
|
||||
|
||||
|
||||
public IDictionary<Guid, Group> GetGroups(int tenant, DateTime from)
|
||||
@ -535,7 +537,8 @@ namespace ASC.Core.Caching
|
||||
services
|
||||
.AddCoreSettingsService()
|
||||
.AddLoggerService()
|
||||
.AddUserDbContextService();
|
||||
.AddUserDbContextService()
|
||||
.AddPasswordHasherService();
|
||||
}
|
||||
|
||||
return services;
|
||||
|
@ -39,6 +39,8 @@ namespace ASC.Core.Configuration
|
||||
public static readonly string NotifyMessengerSenderSysName = "messanger.sender";
|
||||
|
||||
public static readonly string NotifyPushSenderSysName = "push.sender";
|
||||
|
||||
public static readonly string NotifyTelegramSenderSysName = "telegram.sender";
|
||||
|
||||
public static readonly ISystemAccount CoreSystem = new SystemAccount(new Guid("A37EE56E-3302-4a7b-B67E-DDBEA64CD032"), "asc system", true);
|
||||
|
||||
|
@ -41,13 +41,15 @@ namespace ASC.Core
|
||||
private readonly IUserService userService;
|
||||
|
||||
private UserManager UserManager { get; }
|
||||
private UserFormatter UserFormatter { get; }
|
||||
|
||||
public AuthManager(IUserService service, UserManager userManager, UserFormatter userFormatter)
|
||||
private UserFormatter UserFormatter { get; }
|
||||
private TenantManager TenantManager { get; }
|
||||
|
||||
public AuthManager(IUserService service, UserManager userManager, UserFormatter userFormatter, TenantManager tenantManager)
|
||||
{
|
||||
userService = service;
|
||||
UserManager = userManager;
|
||||
UserFormatter = userFormatter;
|
||||
UserFormatter = userFormatter;
|
||||
TenantManager = tenantManager;
|
||||
}
|
||||
|
||||
|
||||
@ -56,14 +58,14 @@ namespace ASC.Core
|
||||
return UserManager.GetUsers(EmployeeStatus.Active).Select(u => ToAccount(tenant.TenantId, u)).ToArray();
|
||||
}
|
||||
|
||||
public void SetUserPassword(int tenantId, Guid userID, string password)
|
||||
{
|
||||
userService.SetUserPassword(tenantId, userID, password);
|
||||
}
|
||||
|
||||
public string GetUserPasswordHash(int tenantId, Guid userID)
|
||||
{
|
||||
return userService.GetUserPassword(tenantId, userID);
|
||||
public void SetUserPasswordHash(Guid userID, string passwordHash)
|
||||
{
|
||||
userService.SetUserPasswordHash(TenantManager.GetCurrentTenant().TenantId, userID, passwordHash);
|
||||
}
|
||||
|
||||
public DateTime GetUserPasswordStamp(Guid userID)
|
||||
{
|
||||
return userService.GetUserPasswordStamp(TenantManager.GetCurrentTenant().TenantId, userID);
|
||||
}
|
||||
|
||||
public IAccount GetAccountByID(int tenantId, Guid id)
|
||||
|
@ -93,7 +93,12 @@ namespace ASC.Core
|
||||
public Invoice GetPaymentInvoice(string paymentId)
|
||||
{
|
||||
return tariffService.GetInvoice(paymentId);
|
||||
}
|
||||
}
|
||||
|
||||
public IDictionary<string, IEnumerable<Tuple<string, decimal>>> GetProductPriceInfo(params string[] productIds)
|
||||
{
|
||||
return tariffService.GetProductPriceInfo(productIds);
|
||||
}
|
||||
|
||||
public Uri GetShoppingUri(int tenant, int quotaId, string currency = null, string language = null, string customerId = null)
|
||||
{
|
||||
|
@ -205,9 +205,9 @@ namespace ASC.Core
|
||||
return u != null && !u.Removed ? u : Constants.LostUser;
|
||||
}
|
||||
|
||||
public UserInfo GetUsers(int tenant, string login, string passwordHash)
|
||||
{
|
||||
var u = UserService.GetUser(tenant, login, passwordHash);
|
||||
public UserInfo GetUsersByPasswordHash(int tenant, string login, string passwordHash)
|
||||
{
|
||||
var u = UserService.GetUserByPasswordHash(tenant, login, passwordHash);
|
||||
return u != null && !u.Removed ? u : Constants.LostUser;
|
||||
}
|
||||
|
||||
|
@ -44,7 +44,6 @@ using ASC.Core.Security.Authentication;
|
||||
using ASC.Core.Security.Authorizing;
|
||||
using ASC.Core.Tenants;
|
||||
using ASC.Core.Users;
|
||||
using ASC.Security.Cryptography;
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Options;
|
||||
@ -112,13 +111,13 @@ namespace ASC.Core
|
||||
}
|
||||
|
||||
|
||||
public string AuthenticateMe(string login, string password)
|
||||
public string AuthenticateMe(string login, string passwordHash)
|
||||
{
|
||||
if (login == null) throw new ArgumentNullException("login");
|
||||
if (password == null) throw new ArgumentNullException("password");
|
||||
if (passwordHash == null) throw new ArgumentNullException("passwordHash");
|
||||
|
||||
var tenantid = TenantManager.GetCurrentTenant().TenantId;
|
||||
var u = UserManager.GetUsers(tenantid, login, Hasher.Base64Hash(password, HashAlg.SHA256));
|
||||
var u = UserManager.GetUsersByPasswordHash(tenantid, login, passwordHash);
|
||||
|
||||
return AuthenticateMe(new UserAccount(u, tenantid, UserFormatter));
|
||||
}
|
||||
@ -140,7 +139,7 @@ namespace ASC.Core
|
||||
}
|
||||
log.InfoFormat("Empty Bearer cookie: {0} {1}", ipFrom, address);
|
||||
}
|
||||
else if (CookieStorage.DecryptCookie(cookie, out var tenant, out var userid, out var login, out var password, out var indexTenant, out var expire, out var indexUser))
|
||||
else if (CookieStorage.DecryptCookie(cookie, out var tenant, out var userid, out var indexTenant, out var expire, out var indexUser))
|
||||
{
|
||||
if (tenant != TenantManager.GetCurrentTenant().TenantId)
|
||||
{
|
||||
@ -160,36 +159,27 @@ namespace ASC.Core
|
||||
|
||||
try
|
||||
{
|
||||
if (userid != Guid.Empty)
|
||||
var settingsUser = TenantCookieSettingsHelper.GetForUser(userid);
|
||||
if (indexUser != settingsUser.Index)
|
||||
{
|
||||
var settingsUser = TenantCookieSettingsHelper.GetForUser(userid);
|
||||
if (indexUser != settingsUser.Index)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
AuthenticateMe(new UserAccount(new UserInfo { ID = userid }, tenant, UserFormatter));
|
||||
|
||||
AuthenticateMe(new UserAccount(new UserInfo { ID = userid }, tenant, UserFormatter));
|
||||
}
|
||||
else
|
||||
{
|
||||
AuthenticateMe(login, password);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
catch (InvalidCredentialException ice)
|
||||
{
|
||||
log.DebugFormat("{0}: cookie {1}, tenant {2}, userid {3}, login {4}, pass {5}",
|
||||
ice.Message, cookie, tenant, userid, login, password);
|
||||
log.DebugFormat("{0}: cookie {1}, tenant {2}, userid {3}", ice.Message, cookie, tenant, userid);
|
||||
}
|
||||
catch (SecurityException se)
|
||||
{
|
||||
log.DebugFormat("{0}: cookie {1}, tenant {2}, userid {3}, login {4}, pass {5}",
|
||||
se.Message, cookie, tenant, userid, login, password);
|
||||
log.DebugFormat("{0}: cookie {1}, tenant {2}, userid {3}", se.Message, cookie, tenant, userid);
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
log.ErrorFormat("Authenticate error: cookie {0}, tenant {1}, userid {2}, login {3}, pass {4}: {5}",
|
||||
cookie, tenant, userid, login, password, err);
|
||||
log.ErrorFormat("Authenticate error: cookie {0}, tenant {1}, userid {2}, : {3}", cookie, tenant, userid, err);
|
||||
}
|
||||
}
|
||||
else
|
||||
@ -280,9 +270,23 @@ namespace ASC.Core
|
||||
AuthContext.Logout();
|
||||
}
|
||||
|
||||
public void SetUserPassword(Guid userID, string password)
|
||||
public void SetUserPasswordHash(Guid userID, string passwordHash)
|
||||
{
|
||||
Authentication.SetUserPassword(TenantManager.GetCurrentTenant().TenantId, userID, password);
|
||||
var tenantid = TenantManager.GetCurrentTenant().TenantId;
|
||||
var u = UserManager.GetUsersByPasswordHash(tenantid, userID.ToString(), passwordHash);
|
||||
if (!Equals(u, Users.Constants.LostUser))
|
||||
{
|
||||
throw new PasswordException("A new password must be used");
|
||||
}
|
||||
|
||||
Authentication.SetUserPasswordHash(userID, passwordHash);
|
||||
}
|
||||
|
||||
public class PasswordException : Exception
|
||||
{
|
||||
public PasswordException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -30,6 +30,7 @@ using System.Reflection;
|
||||
|
||||
using ASC.Common.Caching;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Core.Common.Notify;
|
||||
using ASC.Core.Notify;
|
||||
using ASC.Core.Notify.Senders;
|
||||
using ASC.Core.Tenants;
|
||||
@ -102,12 +103,14 @@ namespace ASC.Core
|
||||
var configuration = serviceProvider.GetService<IConfiguration>();
|
||||
var cacheNotify = serviceProvider.GetService<ICacheNotify<NotifyMessage>>();
|
||||
var cacheInvoke = serviceProvider.GetService<ICacheNotify<NotifyInvoke>>();
|
||||
var options = serviceProvider.GetService<IOptionsMonitor<ILog>>();
|
||||
var options = serviceProvider.GetService<IOptionsMonitor<ILog>>();
|
||||
var telegramHelper = serviceProvider.GetService<TelegramHelper>();
|
||||
|
||||
NotifyContext = new NotifyContext(serviceProvider);
|
||||
|
||||
INotifySender jabberSender = new NotifyServiceSender(cacheNotify, cacheInvoke);
|
||||
INotifySender emailSender = new NotifyServiceSender(cacheNotify, cacheInvoke);
|
||||
INotifySender telegramSender = new TelegramSender(options, telegramHelper);
|
||||
|
||||
var postman = configuration["core:notify:postman"];
|
||||
|
||||
@ -133,8 +136,9 @@ namespace ASC.Core
|
||||
emailSender.Init(properties);
|
||||
}
|
||||
|
||||
NotifyContext.NotifyService.RegisterSender(Constants.NotifyEMailSenderSysName, new EmailSenderSink(emailSender, serviceProvider));
|
||||
NotifyContext.NotifyService.RegisterSender(Constants.NotifyEMailSenderSysName, new EmailSenderSink(emailSender, serviceProvider, options));
|
||||
NotifyContext.NotifyService.RegisterSender(Constants.NotifyMessengerSenderSysName, new JabberSenderSink(jabberSender, serviceProvider));
|
||||
NotifyContext.NotifyService.RegisterSender(Constants.NotifyTelegramSenderSysName, new TelegramSenderSink(telegramSender, serviceProvider));
|
||||
|
||||
NotifyContext.NotifyEngine.BeforeTransferRequest += NotifyEngine_BeforeTransferRequest;
|
||||
NotifyContext.NotifyEngine.AfterTransferRequest += NotifyEngine_AfterTransferRequest;
|
||||
|
@ -55,7 +55,7 @@ namespace ASC.Core
|
||||
|
||||
UserInfo GetUser(int tenant, Guid id, Expression<Func<User, UserInfo>> exp);
|
||||
|
||||
UserInfo GetUser(int tenant, string login, string passwordHash);
|
||||
UserInfo GetUserByPasswordHash(int tenant, string login, string passwordHash);
|
||||
|
||||
UserInfo SaveUser(int tenant, UserInfo user);
|
||||
|
||||
@ -65,9 +65,9 @@ namespace ASC.Core
|
||||
|
||||
void SetUserPhoto(int tenant, Guid id, byte[] photo);
|
||||
|
||||
string GetUserPassword(int tenant, Guid id);
|
||||
|
||||
void SetUserPassword(int tenant, Guid id, string password);
|
||||
DateTime GetUserPasswordStamp(int tenant, Guid id);
|
||||
|
||||
void SetUserPasswordHash(int tenant, Guid id, string passwordHash);
|
||||
|
||||
|
||||
IDictionary<Guid, Group> GetGroups(int tenant, DateTime from);
|
||||
|
@ -37,7 +37,8 @@ using ASC.Core.Common.EF.Model;
|
||||
using ASC.Core.Common.Settings;
|
||||
using ASC.Core.Tenants;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Core.Data
|
||||
{
|
||||
@ -148,7 +149,7 @@ namespace ASC.Core.Data
|
||||
private Guid? currentUserID;
|
||||
private Guid CurrentUserID
|
||||
{
|
||||
get { return (currentUserID ?? (currentUserID = AuthContext.CurrentAccount.ID)).Value; }
|
||||
get { return ((Guid?)(currentUserID ??= AuthContext.CurrentAccount.ID)).Value; }
|
||||
}
|
||||
|
||||
public bool SaveSettings<T>(T settings, int tenantId) where T : ISettings
|
||||
@ -227,7 +228,7 @@ namespace ASC.Core.Data
|
||||
|
||||
internal T LoadSettingsFor<T>(int tenantId, Guid userId) where T : class, ISettings
|
||||
{
|
||||
var settingsInstance = Activator.CreateInstance<T>();
|
||||
var settingsInstance = ActivatorUtilities.CreateInstance<T>(ServiceProvider);
|
||||
var key = settingsInstance.ID.ToString() + tenantId + userId;
|
||||
var def = (T)settingsInstance.GetDefault(ServiceProvider);
|
||||
|
||||
|
@ -28,12 +28,14 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
|
||||
using ASC.Core.Common.EF;
|
||||
using ASC.Core.Common.EF.Context;
|
||||
using ASC.Core.Common.EF.Model;
|
||||
using ASC.Core.Tenants;
|
||||
using ASC.Core.Users;
|
||||
using ASC.Security.Cryptography;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
@ -71,7 +73,7 @@ namespace ASC.Core.Data
|
||||
private List<string> forbiddenDomains;
|
||||
|
||||
internal TenantDomainValidator TenantDomainValidator { get; set; }
|
||||
|
||||
public MachinePseudoKeys MachinePseudoKeys { get; }
|
||||
internal TenantDbContext TenantDbContext { get; set; }
|
||||
|
||||
public Expression<Func<DbTenant, Tenant>> FromDbTenantToTenant { get; set; }
|
||||
@ -109,10 +111,15 @@ namespace ASC.Core.Data
|
||||
FromTenantUserToTenant = r => fromDbTenantToTenant(r.DbTenant);
|
||||
}
|
||||
|
||||
public DbTenantService(DbContextManager<TenantDbContext> dbContextManager, TenantDomainValidator tenantDomainValidator) : this()
|
||||
public DbTenantService(
|
||||
DbContextManager<TenantDbContext> dbContextManager,
|
||||
TenantDomainValidator tenantDomainValidator,
|
||||
MachinePseudoKeys machinePseudoKeys)
|
||||
: this()
|
||||
{
|
||||
TenantDbContext = dbContextManager.Value;
|
||||
TenantDomainValidator = tenantDomainValidator;
|
||||
MachinePseudoKeys = machinePseudoKeys;
|
||||
}
|
||||
|
||||
public void ValidateDomain(string domain)
|
||||
@ -141,32 +148,82 @@ namespace ASC.Core.Data
|
||||
public IEnumerable<Tenant> GetTenants(string login, string passwordHash)
|
||||
{
|
||||
if (string.IsNullOrEmpty(login)) throw new ArgumentNullException("login");
|
||||
|
||||
var q = TenantsQuery()
|
||||
.Where(r => r.Status == TenantStatus.Active)
|
||||
.Join(TenantDbContext.Users, r => r.Id, r => r.Tenant, (tenant, user) => new
|
||||
{
|
||||
tenant,
|
||||
user
|
||||
})
|
||||
.Join(TenantDbContext.UserSecurity, r => r.user.Id, r => r.UserId, (tenantUser, security) => new TenantUserSecurity
|
||||
{
|
||||
DbTenant = tenantUser.tenant,
|
||||
User = tenantUser.user,
|
||||
UserSecurity = security
|
||||
|
||||
})
|
||||
.Where(r => r.User.Status == EmployeeStatus.Active)
|
||||
.Where(r => r.User.Removed == false)
|
||||
.Where(r => login.Contains('@') ? r.User.Email == login : r.User.Id.ToString() == login);
|
||||
Func<IQueryable<TenantUserSecurity>> query = () => TenantsQuery()
|
||||
.Where(r => r.Status == TenantStatus.Active)
|
||||
.Join(TenantDbContext.Users, r => r.Id, r => r.Tenant, (tenant, user) => new
|
||||
{
|
||||
tenant,
|
||||
user
|
||||
})
|
||||
.Join(TenantDbContext.UserSecurity, r => r.user.Id, r => r.UserId, (tenantUser, security) => new TenantUserSecurity
|
||||
{
|
||||
DbTenant = tenantUser.tenant,
|
||||
User = tenantUser.user,
|
||||
UserSecurity = security
|
||||
|
||||
})
|
||||
.Where(r => r.User.Status == EmployeeStatus.Active)
|
||||
.Where(r => r.DbTenant.Status == TenantStatus.Active)
|
||||
.Where(r => r.User.Removed == false);
|
||||
|
||||
if (passwordHash != null)
|
||||
if (passwordHash == null)
|
||||
{
|
||||
q.Where(r => r.UserSecurity.PwdHash == passwordHash);
|
||||
var q = query()
|
||||
.Where(r => login.Contains('@') ? r.User.Email == login : r.User.Id.ToString() == login);
|
||||
|
||||
return q.Select(FromTenantUserToTenant).ToList();
|
||||
}
|
||||
|
||||
return q.Select(FromTenantUserToTenant).ToList();
|
||||
if (Guid.TryParse(login, out var userId))
|
||||
{
|
||||
var pwdHash = GetPasswordHash(userId, passwordHash);
|
||||
var oldHash = Hasher.Base64Hash(passwordHash, HashAlg.SHA256);
|
||||
var q = query()
|
||||
.Where(r => r.User.Id == userId)
|
||||
.Where(r => r.UserSecurity.PwdHash == pwdHash || r.UserSecurity.PwdHash == oldHash) //todo: remove old scheme
|
||||
;
|
||||
|
||||
return q.Select(FromTenantUserToTenant).ToList();
|
||||
}
|
||||
else
|
||||
{
|
||||
var oldHash = Hasher.Base64Hash(passwordHash, HashAlg.SHA256);
|
||||
|
||||
var q =
|
||||
query()
|
||||
.Where(r => r.UserSecurity.PwdHash == oldHash);
|
||||
|
||||
if (login.Contains('@'))
|
||||
{
|
||||
q = q.Where(r => r.User.Email == login);
|
||||
}
|
||||
else if (Guid.TryParse(login, out var uId))
|
||||
{
|
||||
q = q.Where(r => r.User.Id == uId);
|
||||
}
|
||||
|
||||
//old password
|
||||
var result = q.Select(FromTenantUserToTenant).ToList();
|
||||
|
||||
var usersQuery = TenantDbContext.Users
|
||||
.Where(r => r.Email == login)
|
||||
.Where(r => r.Status == EmployeeStatus.Active)
|
||||
.Where(r => !r.Removed)
|
||||
.Select(r => r.Id)
|
||||
.ToList();
|
||||
|
||||
var passwordHashs = usersQuery.Select(r => GetPasswordHash(r, passwordHash)).ToList();
|
||||
|
||||
q = query()
|
||||
.Where(r => passwordHashs.Any(p => r.UserSecurity.PwdHash == p));
|
||||
|
||||
//new password
|
||||
result = result.Concat(q.Select(FromTenantUserToTenant)).ToList();
|
||||
result.Distinct();
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
public Tenant GetTenant(int id)
|
||||
@ -450,6 +507,11 @@ namespace ASC.Core.Data
|
||||
|
||||
throw new TenantAlreadyExistsException("Address busy.", existsTenants);
|
||||
}
|
||||
}
|
||||
|
||||
protected string GetPasswordHash(Guid userId, string password)
|
||||
{
|
||||
return Hasher.Base64Hash(password + userId + Encoding.UTF8.GetString(MachinePseudoKeys.GetMachineConstant()), HashAlg.SHA512);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,6 +28,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Text;
|
||||
|
||||
using ASC.Core.Common.EF;
|
||||
using ASC.Core.Tenants;
|
||||
@ -66,6 +67,7 @@ namespace ASC.Core.Data
|
||||
public class EFUserService : IUserService
|
||||
{
|
||||
public Expression<Func<User, UserInfo>> FromUserToUserInfo { get; set; }
|
||||
public Expression<Func<DbUserSecurity, UserInfo>> FromDbUserSecurityToUserInfo { get; set; }
|
||||
public Func<UserInfo, User> FromUserInfoToUser { get; set; }
|
||||
public Expression<Func<DbGroup, Group>> FromDbGroupToGroup { get; set; }
|
||||
public Func<Group, DbGroup> FromGroupToDbGroup { get; set; }
|
||||
@ -74,7 +76,8 @@ namespace ASC.Core.Data
|
||||
|
||||
internal UserDbContext UserDbContext { get; set; }
|
||||
internal DbContextManager<UserDbContext> UserDbContextManager { get; set; }
|
||||
|
||||
private PasswordHasher PasswordHasher { get; }
|
||||
public MachinePseudoKeys MachinePseudoKeys { get; }
|
||||
internal string DbId { get; set; }
|
||||
|
||||
public EFUserService()
|
||||
@ -108,6 +111,9 @@ namespace ASC.Core.Data
|
||||
Contacts = user.Contacts
|
||||
};
|
||||
|
||||
var fromUserToUserInfo = FromUserToUserInfo.Compile();
|
||||
FromDbUserSecurityToUserInfo = r => fromUserToUserInfo(r.User);
|
||||
|
||||
FromUserInfoToUser = user => new User
|
||||
{
|
||||
ActivationStatus = user.ActivationStatus,
|
||||
@ -141,8 +147,8 @@ namespace ASC.Core.Data
|
||||
{
|
||||
Id = group.Id,
|
||||
Name = group.Name,
|
||||
CategoryId = group.CategoryId.HasValue ? group.CategoryId.Value : Guid.Empty,
|
||||
ParentId = group.ParentId.HasValue ? group.ParentId.Value : Guid.Empty,
|
||||
CategoryId = group.CategoryId ?? Guid.Empty,
|
||||
ParentId = group.ParentId ?? Guid.Empty,
|
||||
Sid = group.Sid,
|
||||
Removed = group.Removed,
|
||||
LastModified = group.LastModified,
|
||||
@ -182,9 +188,11 @@ namespace ASC.Core.Data
|
||||
};
|
||||
}
|
||||
|
||||
public EFUserService(DbContextManager<UserDbContext> userDbContextManager) : this()
|
||||
public EFUserService(DbContextManager<UserDbContext> userDbContextManager, PasswordHasher passwordHasher, MachinePseudoKeys machinePseudoKeys) : this()
|
||||
{
|
||||
UserDbContextManager = userDbContextManager;
|
||||
PasswordHasher = passwordHasher;
|
||||
MachinePseudoKeys = machinePseudoKeys;
|
||||
UserDbContext = UserDbContextManager.Value;
|
||||
}
|
||||
|
||||
@ -211,28 +219,78 @@ namespace ASC.Core.Data
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
public UserInfo GetUser(int tenant, string login, string passwordHash)
|
||||
public UserInfo GetUserByPasswordHash(int tenant, string login, string passwordHash)
|
||||
{
|
||||
if (string.IsNullOrEmpty(login)) throw new ArgumentNullException("login");
|
||||
var q = UserDbContext.Users
|
||||
.Where(r => !r.Removed)
|
||||
.Where(r => r.UserSecurity.PwdHash == passwordHash);
|
||||
|
||||
if (login.Contains('@'))
|
||||
if (Guid.TryParse(login, out var userId))
|
||||
{
|
||||
q = q.Where(r => r.Email == login);
|
||||
RegeneratePassword(tenant, userId);
|
||||
|
||||
var pwdHash = GetPasswordHash(userId, passwordHash);
|
||||
var oldHash = Hasher.Base64Hash(passwordHash, HashAlg.SHA256);
|
||||
|
||||
var q = UserDbContext.Users
|
||||
.Where(r => !r.Removed)
|
||||
.Where(r => r.Id == userId)
|
||||
.Join(UserDbContext.UserSecurity, r => r.Id, r => r.UserId, (user, security) => new DbUserSecurity
|
||||
{
|
||||
User = user,
|
||||
UserSecurity = security
|
||||
})
|
||||
.Where(r => r.UserSecurity.PwdHash == pwdHash || r.UserSecurity.PwdHash == oldHash) //todo: remove old scheme
|
||||
;
|
||||
|
||||
if (tenant != Tenant.DEFAULT_TENANT)
|
||||
{
|
||||
q = q.Where(r => r.User.Tenant == tenant);
|
||||
}
|
||||
|
||||
return q.Select(FromDbUserSecurityToUserInfo).FirstOrDefault();
|
||||
}
|
||||
else if (Guid.TryParse(login, out var userId))
|
||||
else
|
||||
{
|
||||
q = q.Where(r => r.Id == userId);
|
||||
}
|
||||
var q = UserDbContext.Users
|
||||
.Where(r => !r.Removed)
|
||||
.Where(r => r.Email == login)
|
||||
;
|
||||
if (tenant != Tenant.DEFAULT_TENANT)
|
||||
{
|
||||
q = q.Where(r => r.Tenant == tenant);
|
||||
}
|
||||
var user = q.Select(FromUserToUserInfo).FirstOrDefault();
|
||||
if (user != null)
|
||||
{
|
||||
RegeneratePassword(tenant, user.ID);
|
||||
|
||||
if (tenant != Tenant.DEFAULT_TENANT)
|
||||
{
|
||||
q = q.Where(r => r.Tenant == tenant);
|
||||
}
|
||||
var pwdHash = GetPasswordHash(user.ID, passwordHash);
|
||||
var oldHash = Hasher.Base64Hash(passwordHash, HashAlg.SHA256);
|
||||
|
||||
return q.Select(FromUserToUserInfo).FirstOrDefault();
|
||||
var count = UserDbContext.UserSecurity
|
||||
.Where(r => r.UserId == user.ID)
|
||||
.Where(r => r.PwdHash == pwdHash || r.PwdHash == oldHash)
|
||||
.Count();//todo: remove old scheme
|
||||
|
||||
if (count > 0) return user;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
//todo: remove
|
||||
private void RegeneratePassword(int tenant, Guid userId)
|
||||
{
|
||||
var h2 = UserDbContext.UserSecurity
|
||||
.Where(r => r.Tenant == tenant)
|
||||
.Where(r => r.UserId == userId)
|
||||
.Select(r => r.PwdHashSha512)
|
||||
.FirstOrDefault();
|
||||
if (string.IsNullOrEmpty(h2)) return;
|
||||
|
||||
var password = Crypto.GetV(h2, 1, false);
|
||||
var passwordHash = PasswordHasher.GetClientPassword(password);
|
||||
SetUserPasswordHash(tenant, userId, passwordHash);
|
||||
}
|
||||
|
||||
public IDictionary<string, UserGroupRef> GetUserGroupRefs(int tenant, DateTime from)
|
||||
@ -252,14 +310,15 @@ namespace ASC.Core.Data
|
||||
return q.Select(FromUserGroupToUserGroupRef).ToDictionary(r => r.CreateKey(), r => r);
|
||||
}
|
||||
|
||||
public string GetUserPassword(int tenant, Guid id)
|
||||
public DateTime GetUserPasswordStamp(int tenant, Guid id)
|
||||
{
|
||||
var h2 = UserDbContext.UserSecurity
|
||||
var stamp = UserDbContext.UserSecurity
|
||||
.Where(r => r.Tenant == tenant)
|
||||
.Select(r => r.PwdHashSha512)
|
||||
.Where(r => r.UserId == id)
|
||||
.Select(r => r.LastModified)
|
||||
.FirstOrDefault();
|
||||
|
||||
return !string.IsNullOrEmpty(h2) ? Crypto.GetV(h2, 1, false) : null;
|
||||
return stamp ?? DateTime.MinValue;
|
||||
}
|
||||
|
||||
public byte[] GetUserPhoto(int tenant, Guid id)
|
||||
@ -508,16 +567,16 @@ namespace ASC.Core.Data
|
||||
return r;
|
||||
}
|
||||
|
||||
public void SetUserPassword(int tenant, Guid id, string password)
|
||||
public void SetUserPasswordHash(int tenant, Guid id, string passwordHash)
|
||||
{
|
||||
var h1 = !string.IsNullOrEmpty(password) ? Hasher.Base64Hash(password, HashAlg.SHA256) : null;
|
||||
var h2 = !string.IsNullOrEmpty(password) ? Crypto.GetV(password, 1, true) : null;
|
||||
var h1 = GetPasswordHash(id, passwordHash);
|
||||
|
||||
var us = new UserSecurity
|
||||
{
|
||||
Tenant = tenant,
|
||||
UserId = id,
|
||||
PwdHash = h1,
|
||||
PwdHashSha512 = h2
|
||||
PwdHashSha512 = null //todo: remove
|
||||
};
|
||||
|
||||
UserDbContext.AddOrUpdate(r => r.UserSecurity, us);
|
||||
@ -693,5 +752,16 @@ namespace ASC.Core.Data
|
||||
.Select(exp ?? FromUserToUserInfo)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
protected string GetPasswordHash(Guid userId, string password)
|
||||
{
|
||||
return Hasher.Base64Hash(password + userId + Encoding.UTF8.GetString(MachinePseudoKeys.GetMachineConstant()), HashAlg.SHA512);
|
||||
}
|
||||
}
|
||||
|
||||
public class DbUserSecurity
|
||||
{
|
||||
public User User { get; set; }
|
||||
public UserSecurity UserSecurity { get; set; }
|
||||
}
|
||||
}
|
32
common/ASC.Core.Common/EF/Context/TelegramDbContext.cs
Normal file
32
common/ASC.Core.Common/EF/Context/TelegramDbContext.cs
Normal file
@ -0,0 +1,32 @@
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Core.Common.EF.Model;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ASC.Core.Common.EF.Context
|
||||
{
|
||||
public class TelegramDbContext : BaseDbContext
|
||||
{
|
||||
public DbSet<TelegramUser> Users { get; set; }
|
||||
|
||||
public TelegramDbContext() { }
|
||||
public TelegramDbContext(DbContextOptions<TelegramDbContext> options)
|
||||
: base(options)
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnModelCreating(ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.AddTelegramUsers();
|
||||
}
|
||||
}
|
||||
|
||||
public static class TelegramDbContextExtension
|
||||
{
|
||||
public static DIHelper AddTelegramDbContextService(this DIHelper services)
|
||||
{
|
||||
return services.AddDbContextManagerService<TelegramDbContext>();
|
||||
}
|
||||
}
|
||||
}
|
@ -30,5 +30,6 @@ namespace ASC.Core.Common.EF.Model
|
||||
[Column("creation_date")]
|
||||
public DateTime CreationDate { get; set; }
|
||||
public string Attachments { get; set; }
|
||||
public string AutoSubmitted { get; set; }
|
||||
}
|
||||
}
|
||||
|
36
common/ASC.Core.Common/EF/Model/TelegramUser.cs
Normal file
36
common/ASC.Core.Common/EF/Model/TelegramUser.cs
Normal file
@ -0,0 +1,36 @@
|
||||
using System;
|
||||
using System.ComponentModel.DataAnnotations.Schema;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
|
||||
namespace ASC.Core.Common.EF.Model
|
||||
{
|
||||
[Table("telegram_users")]
|
||||
public class TelegramUser : BaseEntity
|
||||
{
|
||||
[Column("portal_user_id")]
|
||||
public Guid PortalUserId { get; set; }
|
||||
|
||||
[Column("tenant_id")]
|
||||
public int TenantId { get; set; }
|
||||
|
||||
[Column("telegram_user_id")]
|
||||
public int TelegramUserId { get; set; }
|
||||
|
||||
public override object[] GetKeys()
|
||||
{
|
||||
return new object[] { TenantId, PortalUserId };
|
||||
}
|
||||
}
|
||||
|
||||
public static class TelegramUsersExtension
|
||||
{
|
||||
public static ModelBuilder AddTelegramUsers(this ModelBuilder modelBuilder)
|
||||
{
|
||||
modelBuilder.Entity<TelegramUser>()
|
||||
.HasKey(c => new { c.TenantId, c.PortalUserId });
|
||||
|
||||
return modelBuilder;
|
||||
}
|
||||
}
|
||||
}
|
@ -16,6 +16,8 @@ namespace ASC.Core.Common.EF
|
||||
|
||||
public string PwdHashSha512 { get; set; }
|
||||
|
||||
public DateTime? LastModified { get; set; }
|
||||
|
||||
public override object[] GetKeys()
|
||||
{
|
||||
return new object[] { UserId };
|
||||
|
@ -36,7 +36,6 @@ using ASC.Core.Data;
|
||||
using ASC.Core.Security.Authentication;
|
||||
using ASC.Core.Tenants;
|
||||
using ASC.Core.Users;
|
||||
using ASC.Security.Cryptography;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
@ -134,14 +133,13 @@ namespace ASC.Core
|
||||
return FindTenants(login, null);
|
||||
}
|
||||
|
||||
public List<Tenant> FindTenants(string login, string password)
|
||||
{
|
||||
var hash = !string.IsNullOrEmpty(password) ? Hasher.Base64Hash(password, HashAlg.SHA256) : null;
|
||||
if (hash != null && UserService.GetUser(Tenant.DEFAULT_TENANT, login, hash) == null)
|
||||
public List<Tenant> FindTenants(string login, string passwordHash)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(passwordHash) && UserService.GetUserByPasswordHash(Tenant.DEFAULT_TENANT, login, passwordHash) == null)
|
||||
{
|
||||
throw new SecurityException("Invalid login or password.");
|
||||
}
|
||||
return TenantService.GetTenants(login, hash).Select(AddRegion).ToList();
|
||||
return TenantService.GetTenants(login, passwordHash).Select(AddRegion).ToList();
|
||||
}
|
||||
|
||||
public Tenant GetTenant(string domain)
|
||||
@ -167,9 +165,9 @@ namespace ASC.Core
|
||||
if (string.IsNullOrEmpty(ri.Email)) throw new Exception("Account email can not be empty");
|
||||
if (ri.FirstName == null) throw new Exception("Account firstname can not be empty");
|
||||
if (ri.LastName == null) throw new Exception("Account lastname can not be empty");
|
||||
if (!UserFormatter.IsValidUserName(ri.FirstName, ri.LastName)) throw new Exception("Incorrect firstname or lastname");
|
||||
|
||||
if (string.IsNullOrEmpty(ri.Password)) ri.Password = Crypto.GeneratePassword(6);
|
||||
if (!UserFormatter.IsValidUserName(ri.FirstName, ri.LastName)) throw new Exception("Incorrect firstname or lastname");
|
||||
|
||||
if (string.IsNullOrEmpty(ri.PasswordHash)) ri.PasswordHash = Guid.NewGuid().ToString();
|
||||
|
||||
// create tenant
|
||||
tenant = new Tenant(ri.Address.ToLowerInvariant())
|
||||
@ -200,14 +198,15 @@ namespace ASC.Core
|
||||
ActivationStatus = ri.ActivationStatus
|
||||
};
|
||||
user = UserService.SaveUser(tenant.TenantId, user);
|
||||
UserService.SetUserPassword(tenant.TenantId, user.ID, ri.Password);
|
||||
UserService.SetUserPasswordHash(tenant.TenantId, user.ID, ri.PasswordHash);
|
||||
UserService.SaveUserGroupRef(tenant.TenantId, new UserGroupRef(user.ID, Constants.GroupAdmin.ID, UserGroupRefType.Contains));
|
||||
|
||||
// save tenant owner
|
||||
tenant.OwnerId = user.ID;
|
||||
tenant = TenantService.SaveTenant(CoreSettings, tenant);
|
||||
|
||||
SettingsManager.SaveSettings(new TenantAnalyticsSettings() { Analytics = ri.Analytics }, tenant.TenantId);
|
||||
SettingsManager.SaveSettings(new TenantAnalyticsSettings() { Analytics = ri.Analytics }, tenant.TenantId);
|
||||
SettingsManager.SaveSettings(new TenantControlPanelSettings { LimitedAccess = ri.LimitedControlPanel }, tenant.TenantId);
|
||||
}
|
||||
|
||||
public Tenant SaveTenant(Tenant tenant)
|
||||
@ -220,27 +219,20 @@ namespace ASC.Core
|
||||
TenantService.RemoveTenant(tenant.TenantId);
|
||||
}
|
||||
|
||||
public string CreateAuthenticationCookie(CookieStorage cookieStorage, int tenantId, string login, string password)
|
||||
{
|
||||
var passwordhash = Hasher.Base64Hash(password, HashAlg.SHA256);
|
||||
var u = UserService.GetUser(tenantId, login, passwordhash);
|
||||
return u != null ? CreateAuthenticationCookie(cookieStorage, tenantId, u.ID, login, passwordhash) : null;
|
||||
}
|
||||
|
||||
public string CreateAuthenticationCookie(CookieStorage cookieStorage, int tenantId, Guid userId)
|
||||
{
|
||||
var u = UserService.GetUser(tenantId, userId);
|
||||
var password = UserService.GetUserPassword(tenantId, userId);
|
||||
var passwordhash = Hasher.Base64Hash(password, HashAlg.SHA256);
|
||||
return u != null ? CreateAuthenticationCookie(cookieStorage, tenantId, userId, u.Email, passwordhash) : null;
|
||||
var u = UserService.GetUser(tenantId, userId);
|
||||
return CreateAuthenticationCookie(cookieStorage, tenantId, u);
|
||||
}
|
||||
|
||||
private string CreateAuthenticationCookie(CookieStorage cookieStorage, int tenantId, Guid userId, string login, string passwordhash)
|
||||
{
|
||||
private string CreateAuthenticationCookie(CookieStorage cookieStorage, int tenantId, UserInfo user)
|
||||
{
|
||||
if (user == null) return null;
|
||||
|
||||
var tenantSettings = SettingsManager.LoadSettingsFor<TenantCookieSettings>(tenantId, Guid.Empty);
|
||||
var expires = tenantSettings.IsDefault() ? DateTime.UtcNow.AddYears(1) : DateTime.UtcNow.AddMinutes(tenantSettings.LifeTime);
|
||||
var userSettings = SettingsManager.LoadSettingsFor<TenantCookieSettings>(tenantId, userId);
|
||||
return cookieStorage.EncryptCookie(tenantId, userId, login, passwordhash, tenantSettings.Index, expires, userSettings.Index);
|
||||
var userSettings = SettingsManager.LoadSettingsFor<TenantCookieSettings>(tenantId, user.ID);
|
||||
return cookieStorage.EncryptCookie(tenantId, user.ID, tenantSettings.Index, expires, userSettings.Index);
|
||||
}
|
||||
|
||||
public Tariff GetTariff(int tenant, bool withRequestToPaymentSystem = true)
|
||||
|
@ -35,6 +35,7 @@ using ASC.Common.Utils;
|
||||
using ASC.Core.Billing;
|
||||
using ASC.Core.Security.Authentication;
|
||||
using ASC.Core.Tenants;
|
||||
using ASC.Security.Cryptography;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
@ -52,18 +53,21 @@ namespace ASC.Core
|
||||
private IConfiguration Configuraion { get; }
|
||||
private CookieStorage CookieStorage { get; }
|
||||
private EFLoggerFactory LoggerFactory { get; }
|
||||
private PasswordHasher PasswordHasher { get; }
|
||||
private IOptionsSnapshot<HostedSolution> HostedSolutionOptions { get; }
|
||||
|
||||
public MultiRegionHostedSolution(string dbid,
|
||||
IConfiguration configuraion,
|
||||
CookieStorage cookieStorage,
|
||||
EFLoggerFactory loggerFactory,
|
||||
PasswordHasher passwordHasher,
|
||||
IOptionsSnapshot<HostedSolution> hostedSolutionOptions)
|
||||
{
|
||||
this.dbid = dbid;
|
||||
Configuraion = configuraion;
|
||||
CookieStorage = cookieStorage;
|
||||
LoggerFactory = loggerFactory;
|
||||
PasswordHasher = passwordHasher;
|
||||
HostedSolutionOptions = hostedSolutionOptions;
|
||||
Initialize();
|
||||
}
|
||||
@ -80,7 +84,7 @@ namespace ASC.Core
|
||||
return FindTenants(login, null);
|
||||
}
|
||||
|
||||
public List<Tenant> FindTenants(string login, string password)
|
||||
public List<Tenant> FindTenants(string login, string password, string passwordHash = null)
|
||||
{
|
||||
var result = new List<Tenant>();
|
||||
Exception error = null;
|
||||
@ -88,8 +92,12 @@ namespace ASC.Core
|
||||
foreach (var service in GetRegionServices())
|
||||
{
|
||||
try
|
||||
{
|
||||
result.AddRange(service.FindTenants(login, password));
|
||||
{
|
||||
if (string.IsNullOrEmpty(passwordHash) && !string.IsNullOrEmpty(password))
|
||||
{
|
||||
passwordHash = PasswordHasher.GetClientPassword(password);
|
||||
}
|
||||
result.AddRange(service.FindTenants(login, passwordHash));
|
||||
}
|
||||
catch (SecurityException exception)
|
||||
{
|
||||
@ -133,11 +141,6 @@ namespace ASC.Core
|
||||
}
|
||||
|
||||
|
||||
public string CreateAuthenticationCookie(string region, int tenantId, string login, string password)
|
||||
{
|
||||
return GetRegionService(region).CreateAuthenticationCookie(CookieStorage, tenantId, login, password);
|
||||
}
|
||||
|
||||
public string CreateAuthenticationCookie(string region, int tenantId, Guid userId)
|
||||
{
|
||||
return GetRegionService(region).CreateAuthenticationCookie(CookieStorage, tenantId, userId);
|
||||
|
@ -47,14 +47,16 @@ namespace ASC.Core.Notify
|
||||
private readonly INotifySender sender;
|
||||
|
||||
|
||||
public EmailSenderSink(INotifySender sender, IServiceProvider serviceProvider)
|
||||
public EmailSenderSink(INotifySender sender, IServiceProvider serviceProvider, IOptionsMonitor<ILog> options)
|
||||
{
|
||||
this.sender = sender ?? throw new ArgumentNullException("sender");
|
||||
ServiceProvider = serviceProvider;
|
||||
ServiceProvider = serviceProvider;
|
||||
Log = options.Get("ASC.Notify");
|
||||
}
|
||||
|
||||
private IServiceProvider ServiceProvider { get; }
|
||||
|
||||
private IServiceProvider ServiceProvider { get; }
|
||||
private ILog Log { get; }
|
||||
|
||||
public override SendResponse ProcessMessage(INoticeMessage message)
|
||||
{
|
||||
if (message.Recipient.Addresses == null || message.Recipient.Addresses.Length == 0)
|
||||
@ -146,6 +148,19 @@ namespace ASC.Core.Notify
|
||||
if (attachmentTag != null && attachmentTag.Value != null)
|
||||
{
|
||||
m.EmbeddedAttachments.AddRange(attachmentTag.Value as NotifyMessageAttachment[]);
|
||||
}
|
||||
|
||||
var autoSubmittedTag = message.Arguments.FirstOrDefault(x => x.Tag == "AutoSubmitted");
|
||||
if (autoSubmittedTag != null && autoSubmittedTag.Value is string)
|
||||
{
|
||||
try
|
||||
{
|
||||
m.AutoSubmitted = autoSubmittedTag.Value.ToString();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.Error("Error creating AutoSubmitted tag for: " + autoSubmittedTag.Value, e);
|
||||
}
|
||||
}
|
||||
|
||||
return m;
|
||||
|
@ -109,7 +109,8 @@ namespace ASC.Core.Notify
|
||||
{
|
||||
if (senderName == ASC.Core.Configuration.Constants.NotifyEMailSenderSysName) return new[] { user.Email };
|
||||
if (senderName == ASC.Core.Configuration.Constants.NotifyMessengerSenderSysName) return new[] { user.UserName };
|
||||
if (senderName == ASC.Core.Configuration.Constants.NotifyPushSenderSysName) return new[] { user.UserName };
|
||||
if (senderName == ASC.Core.Configuration.Constants.NotifyPushSenderSysName) return new[] { user.UserName };
|
||||
if (senderName == ASC.Core.Configuration.Constants.NotifyTelegramSenderSysName) return new[] { user.ID.ToString() };
|
||||
}
|
||||
}
|
||||
return new string[0];
|
||||
|
@ -267,9 +267,9 @@ namespace ASC.Core.Notify.Senders
|
||||
if (!string.IsNullOrEmpty(m.ReplyTo))
|
||||
{
|
||||
mimeMessage.ReplyTo.Add(MailboxAddress.Parse(ParserOptions.Default, m.ReplyTo));
|
||||
}
|
||||
|
||||
mimeMessage.Headers.Add("Auto-Submitted", "auto-generated");
|
||||
}
|
||||
|
||||
mimeMessage.Headers.Add("Auto-Submitted", string.IsNullOrEmpty(m.AutoSubmitted) ? "auto-generated" : m.AutoSubmitted);
|
||||
|
||||
return mimeMessage;
|
||||
}
|
||||
|
73
common/ASC.Core.Common/Notify/Senders/TelegramSender.cs
Normal file
73
common/ASC.Core.Common/Notify/Senders/TelegramSender.cs
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
*
|
||||
* (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.Collections.Generic;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Core.Common.Notify;
|
||||
using ASC.Notify.Messages;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Core.Notify.Senders
|
||||
{
|
||||
public class TelegramSender : INotifySender
|
||||
{
|
||||
private readonly ILog log;
|
||||
private TelegramHelper TelegramHelper { get; }
|
||||
|
||||
public TelegramSender(IOptionsMonitor<ILog> options, TelegramHelper telegramHelper)
|
||||
{
|
||||
log = options.Get("ASC");
|
||||
TelegramHelper = telegramHelper;
|
||||
}
|
||||
|
||||
|
||||
public void Init(IDictionary<string, string> properties)
|
||||
{
|
||||
}
|
||||
|
||||
public NoticeSendResult Send(NotifyMessage m)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(m.Content))
|
||||
{
|
||||
m.Content = m.Content.Replace("\r\n", "\n").Trim('\n', '\r', ' ');
|
||||
m.Content = Regex.Replace(m.Content, "\n{3,}", "\n\n");
|
||||
}
|
||||
try
|
||||
{
|
||||
TelegramHelper.SendMessage(m);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
log.ErrorFormat("Unexpected error, {0}, {1}, {2}",
|
||||
e.Message, e.StackTrace, e.InnerException != null ? e.InnerException.Message : string.Empty);
|
||||
}
|
||||
return NoticeSendResult.OK;
|
||||
}
|
||||
}
|
||||
}
|
@ -35,7 +35,8 @@ using System.Text;
|
||||
using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Core.Common.Notify.Jabber;
|
||||
|
||||
using ASC.Security.Cryptography;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
@ -46,18 +47,21 @@ namespace ASC.Core.Notify.Signalr
|
||||
public class ConfigureSignalrServiceClient : IConfigureNamedOptions<SignalrServiceClient>
|
||||
{
|
||||
internal TenantManager TenantManager { get; }
|
||||
internal CoreSettings CoreSettings { get; }
|
||||
internal CoreSettings CoreSettings { get; }
|
||||
internal MachinePseudoKeys MachinePseudoKeys { get; }
|
||||
internal IConfiguration Configuration { get; }
|
||||
internal IOptionsMonitor<ILog> Options { get; }
|
||||
|
||||
public ConfigureSignalrServiceClient(
|
||||
TenantManager tenantManager,
|
||||
CoreSettings coreSettings,
|
||||
CoreSettings coreSettings,
|
||||
MachinePseudoKeys machinePseudoKeys,
|
||||
IConfiguration configuration,
|
||||
IOptionsMonitor<ILog> options)
|
||||
{
|
||||
TenantManager = tenantManager;
|
||||
CoreSettings = coreSettings;
|
||||
CoreSettings = coreSettings;
|
||||
MachinePseudoKeys = machinePseudoKeys;
|
||||
Configuration = configuration;
|
||||
Options = options;
|
||||
}
|
||||
@ -68,7 +72,7 @@ namespace ASC.Core.Notify.Signalr
|
||||
options.hub = name.Trim('/');
|
||||
options.TenantManager = TenantManager;
|
||||
options.CoreSettings = CoreSettings;
|
||||
options.CoreMachineKey = Configuration["core:machinekey"];
|
||||
options.SKey = MachinePseudoKeys.GetMachineConstant();
|
||||
options.Url = Configuration["web:hub:internal"];
|
||||
options.EnableSignalr = !string.IsNullOrEmpty(options.Url);
|
||||
|
||||
@ -103,7 +107,7 @@ namespace ASC.Core.Notify.Signalr
|
||||
internal ILog Log;
|
||||
private static DateTime lastErrorTime;
|
||||
public bool EnableSignalr;
|
||||
internal string CoreMachineKey;
|
||||
internal byte[] SKey;
|
||||
internal string Url;
|
||||
internal bool JabberReplaceDomain;
|
||||
internal string JabberReplaceFromDomain;
|
||||
@ -384,7 +388,7 @@ namespace ASC.Core.Notify.Signalr
|
||||
|
||||
public string CreateAuthToken(string pkey = "socketio")
|
||||
{
|
||||
using var hasher = new HMACSHA1(Encoding.UTF8.GetBytes(CoreMachineKey));
|
||||
using var hasher = new HMACSHA1(SKey);
|
||||
var now = DateTime.UtcNow.ToString("yyyyMMddHHmmss");
|
||||
var hash = Convert.ToBase64String(hasher.ComputeHash(Encoding.UTF8.GetBytes(string.Join("\n", now, pkey))));
|
||||
return string.Format("ASC {0}:{1}:{2}", pkey, now, hash);
|
||||
@ -401,7 +405,8 @@ namespace ASC.Core.Notify.Signalr
|
||||
|
||||
return services
|
||||
.AddTenantManagerService()
|
||||
.AddCoreSettingsService();
|
||||
.AddCoreSettingsService()
|
||||
.AddMachinePseudoKeysService();
|
||||
}
|
||||
|
||||
return services;
|
||||
|
139
common/ASC.Core.Common/Notify/Telegram/Dao/CachedTelegramDao.cs
Normal file
139
common/ASC.Core.Common/Notify/Telegram/Dao/CachedTelegramDao.cs
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
*
|
||||
* (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.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Caching;
|
||||
using ASC.Core.Common.EF.Context;
|
||||
using ASC.Core.Common.EF.Model;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Core.Common.Notify.Telegram
|
||||
{
|
||||
class ConfigureCachedTelegramDao : IConfigureNamedOptions<CachedTelegramDao>
|
||||
{
|
||||
private IOptionsSnapshot<TelegramDao> Service { get; }
|
||||
|
||||
public ConfigureCachedTelegramDao(IOptionsSnapshot<TelegramDao> service)
|
||||
{
|
||||
Service = service;
|
||||
}
|
||||
|
||||
public void Configure(string name, CachedTelegramDao options)
|
||||
{
|
||||
Configure(options);
|
||||
options.tgDao = Service.Get(name);
|
||||
}
|
||||
|
||||
public void Configure(CachedTelegramDao options)
|
||||
{
|
||||
options.tgDao = Service.Value;
|
||||
options.cache = AscCache.Memory;
|
||||
options.Expiration = TimeSpan.FromMinutes(20);
|
||||
|
||||
options.PairKeyFormat = "tgUser:{0}:{1}";
|
||||
options.SingleKeyFormat = "tgUser:{0}";
|
||||
}
|
||||
}
|
||||
|
||||
public class CachedTelegramDao
|
||||
{
|
||||
public TelegramDao tgDao { get; set; }
|
||||
public ICache cache { get; set; }
|
||||
public TimeSpan Expiration { get; set; }
|
||||
|
||||
public string PairKeyFormat { get; set; }
|
||||
public string SingleKeyFormat { get; set; }
|
||||
|
||||
|
||||
public void Delete(Guid userId, int tenantId)
|
||||
{
|
||||
cache.Remove(string.Format(PairKeyFormat, userId, tenantId));
|
||||
tgDao.Delete(userId, tenantId);
|
||||
}
|
||||
|
||||
public void Delete(int telegramId)
|
||||
{
|
||||
cache.Remove(string.Format(SingleKeyFormat, telegramId));
|
||||
tgDao.Delete(telegramId);
|
||||
}
|
||||
|
||||
public TelegramUser GetUser(Guid userId, int tenantId)
|
||||
{
|
||||
var key = string.Format(PairKeyFormat, userId, tenantId);
|
||||
|
||||
var user = cache.Get<TelegramUser>(key);
|
||||
if (user != null) return user;
|
||||
|
||||
user = tgDao.GetUser(userId, tenantId);
|
||||
if (user != null) cache.Insert(key, user, Expiration);
|
||||
return user;
|
||||
}
|
||||
|
||||
public List<TelegramUser> GetUser(int telegramId)
|
||||
{
|
||||
var key = string.Format(SingleKeyFormat, telegramId);
|
||||
|
||||
var users = cache.Get<List<TelegramUser>>(key);
|
||||
if (users != null) return users;
|
||||
|
||||
users = tgDao.GetUser(telegramId);
|
||||
if (users.Any()) cache.Insert(key, users, Expiration);
|
||||
return users;
|
||||
}
|
||||
|
||||
public void RegisterUser(Guid userId, int tenantId, int telegramId)
|
||||
{
|
||||
tgDao.RegisterUser(userId, tenantId, telegramId);
|
||||
|
||||
var key = string.Format(PairKeyFormat, userId, tenantId);
|
||||
cache.Insert(key, new TelegramUser { PortalUserId = userId, TenantId = tenantId, TelegramUserId = telegramId }, Expiration);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CachedTelegramDaoExtension
|
||||
{
|
||||
public static DIHelper AddCachedTelegramDaoService(this DIHelper services)
|
||||
{
|
||||
if (services.TryAddScoped<TelegramDao>())
|
||||
{
|
||||
|
||||
services.TryAddScoped<IConfigureOptions<TelegramDao>, ConfigureTelegramDaoService>();
|
||||
services.TryAddScoped<IConfigureOptions<CachedTelegramDao>, ConfigureCachedTelegramDao>();
|
||||
|
||||
services.TryAddSingleton(typeof(ICacheNotify<>), typeof(KafkaCache<>));
|
||||
|
||||
return services.AddTelegramDbContextService();
|
||||
}
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
125
common/ASC.Core.Common/Notify/Telegram/Dao/TelegramDao.cs
Normal file
125
common/ASC.Core.Common/Notify/Telegram/Dao/TelegramDao.cs
Normal file
@ -0,0 +1,125 @@
|
||||
/*
|
||||
*
|
||||
* (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.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using ASC.Core.Common.EF;
|
||||
using ASC.Core.Common.EF.Context;
|
||||
using ASC.Core.Common.EF.Model;
|
||||
|
||||
using Microsoft.EntityFrameworkCore;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.Core.Common.Notify.Telegram
|
||||
{
|
||||
public class ConfigureTelegramDaoService : IConfigureNamedOptions<TelegramDao>
|
||||
{
|
||||
private DbContextManager<TelegramDbContext> DbContextManager { get; }
|
||||
|
||||
public ConfigureTelegramDaoService(DbContextManager<TelegramDbContext> dbContextManager)
|
||||
{
|
||||
DbContextManager = dbContextManager;
|
||||
}
|
||||
|
||||
public void Configure(string name, TelegramDao options)
|
||||
{
|
||||
Configure(options);
|
||||
options.TelegramDbContext = DbContextManager.Get(name);
|
||||
}
|
||||
|
||||
public void Configure(TelegramDao options)
|
||||
{
|
||||
options.TelegramDbContext = DbContextManager.Value;
|
||||
}
|
||||
}
|
||||
|
||||
public class TelegramDao
|
||||
{
|
||||
public TelegramDbContext TelegramDbContext { get; set; }
|
||||
public TelegramDao()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public TelegramDao(DbContextManager<TelegramDbContext> dbContextManager)
|
||||
{
|
||||
TelegramDbContext = dbContextManager.Value;
|
||||
}
|
||||
|
||||
public void RegisterUser(Guid userId, int tenantId, int telegramId)
|
||||
{
|
||||
var user = new TelegramUser
|
||||
{
|
||||
PortalUserId = userId,
|
||||
TenantId = tenantId,
|
||||
TelegramUserId = telegramId
|
||||
};
|
||||
|
||||
TelegramDbContext.AddOrUpdate(r => r.Users, user);
|
||||
TelegramDbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public TelegramUser GetUser(Guid userId, int tenantId)
|
||||
{
|
||||
return TelegramDbContext.Users
|
||||
.AsNoTracking()
|
||||
.Where(r => r.PortalUserId == userId)
|
||||
.Where(r => r.TenantId == tenantId)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
|
||||
public List<TelegramUser> GetUser(int telegramId)
|
||||
{
|
||||
return TelegramDbContext.Users
|
||||
.AsNoTracking()
|
||||
.Where(r => r.TelegramUserId == telegramId)
|
||||
.ToList();
|
||||
}
|
||||
|
||||
public void Delete(Guid userId, int tenantId)
|
||||
{
|
||||
var toRemove = TelegramDbContext.Users
|
||||
.Where(r => r.PortalUserId == userId)
|
||||
.Where(r => r.TenantId == tenantId)
|
||||
.ToList();
|
||||
|
||||
TelegramDbContext.Users.RemoveRange(toRemove);
|
||||
TelegramDbContext.SaveChanges();
|
||||
}
|
||||
|
||||
public void Delete(int telegramId)
|
||||
{
|
||||
var toRemove = TelegramDbContext.Users
|
||||
.Where(r => r.TelegramUserId == telegramId)
|
||||
.ToList();
|
||||
|
||||
TelegramDbContext.Users.RemoveRange(toRemove);
|
||||
TelegramDbContext.SaveChanges();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/*
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2018
|
||||
*
|
||||
@ -23,14 +23,16 @@
|
||||
*
|
||||
*/
|
||||
|
||||
namespace ASC.Web.Files.Core.Entries
|
||||
namespace ASC.Core.Common.Notify.Telegram
|
||||
{
|
||||
public class EncryptedData
|
||||
public interface ITelegramLoginProvider
|
||||
{
|
||||
public string PublicKey { get; set; }
|
||||
string TelegramBotToken { get; }
|
||||
|
||||
public string FileHash { get; set; }
|
||||
string TelegramBotName { get; }
|
||||
|
||||
public string Data { get; set; }
|
||||
int TelegramAuthTokenLifespan { get; }
|
||||
|
||||
string TelegramProxy { get; }
|
||||
}
|
||||
}
|
||||
}
|
@ -1,60 +1,42 @@
|
||||
/*
|
||||
*
|
||||
* (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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace ASC.Data.Storage.Configuration
|
||||
{
|
||||
static class Schema
|
||||
{
|
||||
public const string SECTION_NAME = "storage";
|
||||
public const string FILE_PATH = "file";
|
||||
|
||||
public const string APPENDERS = "appender";
|
||||
public const string APPEND = "append";
|
||||
public const string APPENDSECURE = "appendssl";
|
||||
public const string EXTs = "exts";
|
||||
|
||||
public const string HANDLERS = "handler";
|
||||
public const string PROPERTIES = "properties";
|
||||
public const string PROPERTY = "property";
|
||||
|
||||
public const string MODULES = "module";
|
||||
public const string TYPE = "type";
|
||||
public const string NAME = "name";
|
||||
public const string VALUE = "value";
|
||||
public const string PATH = "path";
|
||||
public const string DATA = "data";
|
||||
public const string VIRTUALPATH = "virtualpath";
|
||||
public const string VISIBLE = "visible";
|
||||
public const string COUNT_QUOTA = "count";
|
||||
public const string APPEND_TENANT_ID = "appendTenantId";
|
||||
public const string ACL = "acl";
|
||||
public const string EXPIRES = "expires";
|
||||
public const string DOMAINS = "domain";
|
||||
public const string PUBLIC = "public";
|
||||
public const string DISABLEDMIGRATE = "disableMigrate";
|
||||
|
||||
}
|
||||
}
|
||||
/*
|
||||
*
|
||||
* (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 ASC.Notify.Messages;
|
||||
|
||||
namespace ASC.Core.Common.Notify
|
||||
{
|
||||
public interface ITelegramService
|
||||
{
|
||||
void SendMessage(NotifyMessage m);
|
||||
|
||||
void RegisterUser(string userId, int tenantId, string token);
|
||||
|
||||
void CreateOrUpdateClient(int tenantId, string token, int tokenLifespan, string proxy);
|
||||
|
||||
void DisableClient(int tenantId);
|
||||
|
||||
}
|
||||
}
|
188
common/ASC.Core.Common/Notify/Telegram/TelegramHelper.cs
Normal file
188
common/ASC.Core.Common/Notify/Telegram/TelegramHelper.cs
Normal file
@ -0,0 +1,188 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2020
|
||||
*
|
||||
* 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.Linq;
|
||||
using System.Net;
|
||||
using System.Security.Cryptography;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Core.Common.Configuration;
|
||||
using ASC.Core.Common.Notify.Telegram;
|
||||
using ASC.Notify.Messages;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Telegram.Bot;
|
||||
|
||||
namespace ASC.Core.Common.Notify
|
||||
{
|
||||
public class TelegramHelper
|
||||
{
|
||||
public enum RegStatus
|
||||
{
|
||||
NotRegistered,
|
||||
Registered,
|
||||
AwaitingConfirmation
|
||||
}
|
||||
|
||||
private ConsumerFactory ConsumerFactory { get; }
|
||||
private CachedTelegramDao CachedTelegramDao { get; }
|
||||
private TelegramServiceClient TelegramServiceClient { get; }
|
||||
private ILog Log { get; }
|
||||
|
||||
public TelegramHelper(
|
||||
ConsumerFactory consumerFactory,
|
||||
IOptionsSnapshot<CachedTelegramDao> cachedTelegramDao,
|
||||
TelegramServiceClient telegramServiceClient,
|
||||
IOptionsMonitor<ILog> options)
|
||||
{
|
||||
ConsumerFactory = consumerFactory;
|
||||
CachedTelegramDao = cachedTelegramDao.Value;
|
||||
TelegramServiceClient = telegramServiceClient;
|
||||
Log = options.CurrentValue;
|
||||
}
|
||||
|
||||
public string RegisterUser(Guid userId, int tenantId)
|
||||
{
|
||||
var token = GenerateToken(userId);
|
||||
|
||||
TelegramServiceClient.RegisterUser(userId.ToString(), tenantId, token);
|
||||
|
||||
return GetLink(token);
|
||||
}
|
||||
|
||||
public void SendMessage(NotifyMessage msg)
|
||||
{
|
||||
TelegramServiceClient.SendMessage(msg);
|
||||
}
|
||||
|
||||
public bool CreateClient(int tenantId, string token, int tokenLifespan, string proxy)
|
||||
{
|
||||
var client = InitClient(token, proxy);
|
||||
if (TestingClient(client))
|
||||
{
|
||||
TelegramServiceClient.CreateOrUpdateClient(tenantId, token, tokenLifespan, proxy);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public RegStatus UserIsConnected(Guid userId, int tenantId)
|
||||
{
|
||||
if (CachedTelegramDao.GetUser(userId, tenantId) != null) return RegStatus.Registered;
|
||||
|
||||
return IsAwaitingRegistration(userId, tenantId) ? RegStatus.AwaitingConfirmation : RegStatus.NotRegistered;
|
||||
}
|
||||
|
||||
public string CurrentRegistrationLink(Guid userId, int tenantId)
|
||||
{
|
||||
var token = GetCurrentToken(userId, tenantId);
|
||||
if (token == null || token == "") return "";
|
||||
|
||||
return GetLink(token);
|
||||
}
|
||||
|
||||
public void DisableClient(int tenantId)
|
||||
{
|
||||
TelegramServiceClient.DisableClient(tenantId);
|
||||
}
|
||||
|
||||
public void Disconnect(Guid userId, int tenantId)
|
||||
{
|
||||
CachedTelegramDao.Delete(userId, tenantId);
|
||||
}
|
||||
|
||||
private bool IsAwaitingRegistration(Guid userId, int tenantId)
|
||||
{
|
||||
return GetCurrentToken(userId, tenantId) == null ? false : true;
|
||||
}
|
||||
|
||||
private string GetCurrentToken(Guid userId, int tenantId)
|
||||
{
|
||||
return TelegramServiceClient.RegistrationToken(userId.ToString(), tenantId);
|
||||
}
|
||||
|
||||
private string GenerateToken(Guid userId)
|
||||
{
|
||||
var id = userId.ToByteArray();
|
||||
var d = BitConverter.GetBytes(DateTime.Now.Ticks);
|
||||
|
||||
var buf = id.Concat(d).ToArray();
|
||||
|
||||
using (var sha = new SHA256CryptoServiceProvider())
|
||||
{
|
||||
return Convert.ToBase64String(sha.ComputeHash(buf))
|
||||
.Replace('+', '-').Replace('/', '_').Replace("=", ""); // make base64 url safe
|
||||
}
|
||||
}
|
||||
|
||||
private string GetLink(string token)
|
||||
{
|
||||
var tgProvider = (ITelegramLoginProvider)ConsumerFactory.GetByKey("Telegram");
|
||||
var botname = tgProvider == null ? default(string) : tgProvider.TelegramBotName;
|
||||
if (string.IsNullOrEmpty(botname)) return null;
|
||||
|
||||
return string.Format("t.me/{0}?start={1}", botname, token);
|
||||
}
|
||||
|
||||
public bool TestingClient(TelegramBotClient telegramBotClient)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!telegramBotClient.TestApiAsync().GetAwaiter().GetResult()) return false;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.DebugFormat("Couldn't test api connection: {0}", e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public TelegramBotClient InitClient(string token, string proxy)
|
||||
{
|
||||
return string.IsNullOrEmpty(proxy) ? new TelegramBotClient(token) : new TelegramBotClient(token, new WebProxy(proxy));
|
||||
}
|
||||
}
|
||||
|
||||
public static class TelegramHelperExtension
|
||||
{
|
||||
public static DIHelper AddTelegramHelperSerivce(this DIHelper services)
|
||||
{
|
||||
if (services.TryAddScoped<TelegramHelper>())
|
||||
{
|
||||
return services.AddTelegramServiceClient()
|
||||
.AddCachedTelegramDaoService();
|
||||
}
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
82
common/ASC.Core.Common/Notify/Telegram/TelegramSenderSink.cs
Normal file
82
common/ASC.Core.Common/Notify/Telegram/TelegramSenderSink.cs
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
*
|
||||
* (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 ASC.Core.Notify.Senders;
|
||||
using ASC.Core.Tenants;
|
||||
using ASC.Notify.Messages;
|
||||
using ASC.Notify.Sinks;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ASC.Core.Notify
|
||||
{
|
||||
class TelegramSenderSink : Sink
|
||||
{
|
||||
private string senderName = Configuration.Constants.NotifyTelegramSenderSysName;
|
||||
private readonly INotifySender sender;
|
||||
private readonly IServiceProvider serviceProvider;
|
||||
|
||||
public TelegramSenderSink(INotifySender sender, IServiceProvider serviceProvider)
|
||||
{
|
||||
this.sender = sender ?? throw new ArgumentNullException("sender");
|
||||
this.serviceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
|
||||
public override SendResponse ProcessMessage(INoticeMessage message)
|
||||
{
|
||||
try
|
||||
{
|
||||
var result = SendResult.OK;
|
||||
var m = new NotifyMessage
|
||||
{
|
||||
To = message.Recipient.ID,
|
||||
Subject = message.Subject,
|
||||
ContentType = message.ContentType,
|
||||
Content = message.Body,
|
||||
Sender = senderName,
|
||||
CreationDate = DateTime.UtcNow.Ticks,
|
||||
};
|
||||
|
||||
using var scope = serviceProvider.CreateScope();
|
||||
var tenantManager = scope.ServiceProvider.GetService<TenantManager>();
|
||||
|
||||
var tenant = tenantManager.GetCurrentTenant(false);
|
||||
m.Tenant = tenant == null ? Tenant.DEFAULT_TENANT : tenant.TenantId;
|
||||
|
||||
sender.Send(m);
|
||||
|
||||
return new SendResponse(message, senderName, result);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
return new SendResponse(message, senderName, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
106
common/ASC.Core.Common/Notify/Telegram/TelegramServiceClient.cs
Normal file
106
common/ASC.Core.Common/Notify/Telegram/TelegramServiceClient.cs
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2020
|
||||
*
|
||||
* 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 ASC.Common;
|
||||
using ASC.Common.Caching;
|
||||
using ASC.Notify.Messages;
|
||||
|
||||
namespace ASC.Core.Common.Notify
|
||||
{
|
||||
public class TelegramServiceClient : ITelegramService
|
||||
{
|
||||
private ICacheNotify<NotifyMessage> CacheMessage { get; }
|
||||
private ICacheNotify<RegisterUserProto> CacheRegisterUser { get; }
|
||||
private ICacheNotify<CreateClientProto> CacheCreateClient { get; }
|
||||
private ICacheNotify<DisableClientProto> CacheDisableClient { get; }
|
||||
|
||||
private ICache Cache { get; }
|
||||
|
||||
public TelegramServiceClient(ICacheNotify<NotifyMessage> cacheMessage,
|
||||
ICacheNotify<RegisterUserProto> cacheRegisterUser,
|
||||
ICacheNotify<CreateClientProto> cacheCreateClient,
|
||||
ICacheNotify<DisableClientProto> cacheDisableClient)
|
||||
{
|
||||
CacheMessage = cacheMessage;
|
||||
CacheRegisterUser = cacheRegisterUser;
|
||||
CacheCreateClient = cacheCreateClient;
|
||||
CacheDisableClient = cacheDisableClient;
|
||||
Cache = AscCache.Memory;
|
||||
}
|
||||
|
||||
public void SendMessage(NotifyMessage m)
|
||||
{
|
||||
CacheMessage.Publish(m, CacheNotifyAction.Insert);
|
||||
}
|
||||
|
||||
public void RegisterUser(string userId, int tenantId, string token)
|
||||
{
|
||||
Cache.Insert(GetCacheTokenKey(tenantId, userId), token, DateTime.MaxValue);
|
||||
CacheRegisterUser.Publish(new RegisterUserProto() {
|
||||
UserId = userId,
|
||||
TenantId = tenantId,
|
||||
Token = token
|
||||
} , CacheNotifyAction.Insert);
|
||||
}
|
||||
|
||||
public void CreateOrUpdateClient(int tenantId, string token, int tokenLifespan, string proxy)
|
||||
{
|
||||
CacheCreateClient.Publish(new CreateClientProto()
|
||||
{
|
||||
TenantId = tenantId,
|
||||
Token = token,
|
||||
TokenLifespan = tokenLifespan,
|
||||
Proxy = proxy
|
||||
}, CacheNotifyAction.Insert);
|
||||
}
|
||||
|
||||
public void DisableClient(int tenantId)
|
||||
{
|
||||
CacheDisableClient.Publish(new DisableClientProto() { TenantId = tenantId }, CacheNotifyAction.Insert);
|
||||
}
|
||||
|
||||
public string RegistrationToken(string userId, int tenantId)
|
||||
{
|
||||
return Cache.Get<string>(GetCacheTokenKey(tenantId, userId));
|
||||
}
|
||||
|
||||
private string GetCacheTokenKey(int tenantId, string userId)
|
||||
{
|
||||
return "Token" + userId + tenantId;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TelegramServiceClientExtension
|
||||
{
|
||||
public static DIHelper AddTelegramServiceClient(this DIHelper services)
|
||||
{
|
||||
services.TryAddSingleton<TelegramServiceClient>();
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
@ -67,12 +67,10 @@ namespace ASC.Core.Security.Authentication
|
||||
HttpContext = httpContextAccessor.HttpContext;
|
||||
}
|
||||
|
||||
public bool DecryptCookie(string cookie, out int tenant, out Guid userid, out string login, out string password, out int indexTenant, out DateTime expire, out int indexUser)
|
||||
public bool DecryptCookie(string cookie, out int tenant, out Guid userid, out int indexTenant, out DateTime expire, out int indexUser)
|
||||
{
|
||||
tenant = Tenant.DEFAULT_TENANT;
|
||||
userid = Guid.Empty;
|
||||
login = null;
|
||||
password = null;
|
||||
indexTenant = 0;
|
||||
expire = DateTime.MaxValue;
|
||||
indexUser = 0;
|
||||
@ -87,9 +85,7 @@ namespace ASC.Core.Security.Authentication
|
||||
cookie = (HttpUtility.UrlDecode(cookie) ?? "").Replace(' ', '+');
|
||||
var s = InstanceCrypto.Decrypt(cookie).Split('$');
|
||||
|
||||
if (0 < s.Length) login = s[0];
|
||||
if (1 < s.Length) tenant = int.Parse(s[1]);
|
||||
if (2 < s.Length) password = s[2];
|
||||
if (4 < s.Length) userid = new Guid(s[4]);
|
||||
if (5 < s.Length) indexTenant = int.Parse(s[5]);
|
||||
if (6 < s.Length) expire = DateTime.ParseExact(s[6], DateTimeFormat, CultureInfo.InvariantCulture);
|
||||
@ -99,27 +95,27 @@ namespace ASC.Core.Security.Authentication
|
||||
}
|
||||
catch (Exception err)
|
||||
{
|
||||
Log.ErrorFormat("Authenticate error: cookie {0}, tenant {1}, userid {2}, login {3}, pass {4}, indexTenant {5}, expire {6}: {7}",
|
||||
cookie, tenant, userid, login, password, indexTenant, expire.ToString(DateTimeFormat), err);
|
||||
Log.ErrorFormat("Authenticate error: cookie {0}, tenant {1}, userid {2}, indexTenant {3}, expire {4}: {5}",
|
||||
cookie, tenant, userid, indexTenant, expire.ToString(DateTimeFormat), err);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
public string EncryptCookie(int tenant, Guid userid, string login = null, string password = null)
|
||||
public string EncryptCookie(int tenant, Guid userid)
|
||||
{
|
||||
var settingsTenant = TenantCookieSettingsHelper.GetForTenant(tenant);
|
||||
var expires = TenantCookieSettingsHelper.GetExpiresTime(tenant);
|
||||
var settingsUser = TenantCookieSettingsHelper.GetForUser(tenant, userid);
|
||||
return EncryptCookie(tenant, userid, login, password, settingsTenant.Index, expires, settingsUser.Index);
|
||||
return EncryptCookie(tenant, userid, settingsTenant.Index, expires, settingsUser.Index);
|
||||
}
|
||||
|
||||
public string EncryptCookie(int tenant, Guid userid, string login, string password, int indexTenant, DateTime expires, int indexUser)
|
||||
public string EncryptCookie(int tenant, Guid userid, int indexTenant, DateTime expires, int indexUser)
|
||||
{
|
||||
var s = string.Format("{0}${1}${2}${3}${4}${5}${6}${7}",
|
||||
(login ?? string.Empty).ToLowerInvariant(),
|
||||
string.Empty, //login
|
||||
tenant,
|
||||
password,
|
||||
string.Empty, //password
|
||||
GetUserDepenencySalt(),
|
||||
userid.ToString("N"),
|
||||
indexTenant,
|
||||
|
@ -121,14 +121,5 @@ namespace ASC.Core
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static string GeneratePassword(int length)
|
||||
{
|
||||
const string noise = "1234567890mnbasdflkjqwerpoiqweyuvcxnzhdkqpsdk";
|
||||
var random = new AscRandom();
|
||||
var pwd = string.Empty;
|
||||
while (0 < length--) pwd += noise[random.Next(noise.Length)];
|
||||
return pwd;
|
||||
}
|
||||
}
|
||||
}
|
@ -53,15 +53,15 @@ namespace ASC.Security.Cryptography
|
||||
|
||||
private readonly ILog log;
|
||||
private static readonly DateTime _from = new DateTime(2010, 01, 01, 0, 0, 0, DateTimeKind.Utc);
|
||||
internal readonly TimeSpan ValidInterval;
|
||||
|
||||
internal readonly TimeSpan ValidInterval;
|
||||
|
||||
private MachinePseudoKeys MachinePseudoKeys { get; }
|
||||
private TenantManager TenantManager { get; }
|
||||
private IConfiguration Configuration { get; }
|
||||
|
||||
public EmailValidationKeyProvider(TenantManager tenantManager, IConfiguration configuration, IOptionsMonitor<ILog> options)
|
||||
{
|
||||
public EmailValidationKeyProvider(MachinePseudoKeys machinePseudoKeys, TenantManager tenantManager, IConfiguration configuration, IOptionsMonitor<ILog> options)
|
||||
{
|
||||
MachinePseudoKeys = machinePseudoKeys;
|
||||
TenantManager = tenantManager;
|
||||
Configuration = configuration;
|
||||
if (!TimeSpan.TryParse(configuration["email:validinterval"], out var validInterval))
|
||||
{
|
||||
validInterval = TimeSpan.FromDays(7);
|
||||
@ -92,7 +92,7 @@ namespace ASC.Security.Cryptography
|
||||
if (email == null) throw new ArgumentNullException("email");
|
||||
try
|
||||
{
|
||||
return string.Format("{0}|{1}|{2}", email.ToLowerInvariant(), tenantId, Configuration["core:machinekey"]);
|
||||
return string.Format("{0}|{1}|{2}", email.ToLowerInvariant(), tenantId, Encoding.UTF8.GetString(MachinePseudoKeys.GetMachineConstant()));
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -225,16 +225,11 @@ namespace ASC.Security.Cryptography
|
||||
case ConfirmType.EmailChange:
|
||||
checkKeyResult = Provider.ValidateEmailKey(Email + Type + AuthContext.CurrentAccount.ID, Key, Provider.ValidInterval);
|
||||
break;
|
||||
case ConfirmType.PasswordChange:
|
||||
var hash = string.Empty;
|
||||
|
||||
if (P == 1)
|
||||
{
|
||||
var tenantId = TenantManager.GetCurrentTenant().TenantId;
|
||||
hash = Authentication.GetUserPasswordHash(tenantId, UiD.Value);
|
||||
}
|
||||
|
||||
checkKeyResult = Provider.ValidateEmailKey(Email + Type + (string.IsNullOrEmpty(hash) ? string.Empty : Hasher.Base64Hash(hash)) + UiD, Key, Provider.ValidInterval);
|
||||
case ConfirmType.PasswordChange:
|
||||
|
||||
var hash = Authentication.GetUserPasswordStamp(UserManager.GetUserByEmail(Email).ID).ToString("s");
|
||||
|
||||
checkKeyResult = Provider.ValidateEmailKey(Email + Type + hash, Key, Provider.ValidInterval);
|
||||
break;
|
||||
case ConfirmType.Activation:
|
||||
checkKeyResult = Provider.ValidateEmailKey(Email + Type + UiD, Key, Provider.ValidInterval);
|
||||
@ -268,12 +263,17 @@ namespace ASC.Security.Cryptography
|
||||
public static class EmailValidationKeyProviderExtension
|
||||
{
|
||||
public static DIHelper AddEmailValidationKeyProviderService(this DIHelper services)
|
||||
{
|
||||
services.TryAddTransient<EmailValidationKeyModel>();
|
||||
services.TryAddScoped<EmailValidationKeyProvider>();
|
||||
|
||||
return services
|
||||
.AddTenantManagerService();
|
||||
{
|
||||
if (services.TryAddScoped<EmailValidationKeyProvider>())
|
||||
{
|
||||
services.TryAddTransient<EmailValidationKeyModel>();
|
||||
|
||||
return services
|
||||
.AddTenantManagerService()
|
||||
.AddMachinePseudoKeysService();
|
||||
}
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,124 +1,124 @@
|
||||
/*
|
||||
*
|
||||
* (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.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace ASC.Core.Tenants
|
||||
{
|
||||
[DebuggerDisplay("{Name}")]
|
||||
public class TenantQuota : ICloneable
|
||||
{
|
||||
/*
|
||||
*
|
||||
* (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.Diagnostics;
|
||||
using System.Linq;
|
||||
|
||||
namespace ASC.Core.Tenants
|
||||
{
|
||||
[DebuggerDisplay("{Name}")]
|
||||
public class TenantQuota : ICloneable
|
||||
{
|
||||
public static readonly TenantQuota Default = new TenantQuota(Tenant.DEFAULT_TENANT)
|
||||
{
|
||||
Name = "Default",
|
||||
MaxFileSize = 25 * 1024 * 1024, // 25Mb
|
||||
MaxTotalSize = long.MaxValue,
|
||||
ActiveUsers = int.MaxValue,
|
||||
};
|
||||
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public long MaxFileSize { get; set; }
|
||||
|
||||
public long MaxTotalSize { get; set; }
|
||||
|
||||
public int ActiveUsers { get; set; }
|
||||
|
||||
public string Features { get; set; }
|
||||
|
||||
public decimal Price { get; set; }
|
||||
|
||||
public decimal Price2 { get; set; }
|
||||
|
||||
public string AvangateId { get; set; }
|
||||
|
||||
public bool Visible { get; set; }
|
||||
|
||||
public bool Year
|
||||
{
|
||||
get { return GetFeature("year"); }
|
||||
set { SetFeature("year", value); }
|
||||
}
|
||||
|
||||
public bool Year3
|
||||
{
|
||||
get { return GetFeature("year3"); }
|
||||
set { SetFeature("year3", value); }
|
||||
}
|
||||
|
||||
public bool NonProfit
|
||||
{
|
||||
get { return GetFeature("non-profit"); }
|
||||
set { SetFeature("non-profit", value); }
|
||||
}
|
||||
|
||||
public bool Trial
|
||||
{
|
||||
get { return GetFeature("trial"); }
|
||||
set { SetFeature("trial", value); }
|
||||
}
|
||||
|
||||
public bool Free
|
||||
{
|
||||
get { return GetFeature("free"); }
|
||||
set { SetFeature("free", value); }
|
||||
}
|
||||
|
||||
public bool Open
|
||||
{
|
||||
get { return GetFeature("open"); }
|
||||
set { SetFeature("open", value); }
|
||||
}
|
||||
|
||||
public bool ControlPanel
|
||||
{
|
||||
get { return GetFeature("controlpanel"); }
|
||||
set { SetFeature("controlpanel", value); }
|
||||
}
|
||||
|
||||
public bool Update
|
||||
{
|
||||
get { return GetFeature("update"); }
|
||||
set { SetFeature("update", value); }
|
||||
}
|
||||
|
||||
public bool Support
|
||||
{
|
||||
get { return GetFeature("support"); }
|
||||
set { SetFeature("support", value); }
|
||||
}
|
||||
|
||||
public bool Audit
|
||||
{
|
||||
get { return GetFeature("audit"); }
|
||||
set { SetFeature("audit", value); }
|
||||
};
|
||||
|
||||
public int Id { get; set; }
|
||||
|
||||
public string Name { get; set; }
|
||||
|
||||
public long MaxFileSize { get; set; }
|
||||
|
||||
public long MaxTotalSize { get; set; }
|
||||
|
||||
public int ActiveUsers { get; set; }
|
||||
|
||||
public string Features { get; set; }
|
||||
|
||||
public decimal Price { get; set; }
|
||||
|
||||
public decimal Price2 { get; set; }
|
||||
|
||||
public string AvangateId { get; set; }
|
||||
|
||||
public bool Visible { get; set; }
|
||||
|
||||
public bool Year
|
||||
{
|
||||
get { return GetFeature("year"); }
|
||||
set { SetFeature("year", value); }
|
||||
}
|
||||
|
||||
public bool Year3
|
||||
{
|
||||
get { return GetFeature("year3"); }
|
||||
set { SetFeature("year3", value); }
|
||||
}
|
||||
|
||||
public bool NonProfit
|
||||
{
|
||||
get { return GetFeature("non-profit"); }
|
||||
set { SetFeature("non-profit", value); }
|
||||
}
|
||||
|
||||
public bool Trial
|
||||
{
|
||||
get { return GetFeature("trial"); }
|
||||
set { SetFeature("trial", value); }
|
||||
}
|
||||
|
||||
public bool Free
|
||||
{
|
||||
get { return GetFeature("free"); }
|
||||
set { SetFeature("free", value); }
|
||||
}
|
||||
|
||||
public bool Open
|
||||
{
|
||||
get { return GetFeature("open"); }
|
||||
set { SetFeature("open", value); }
|
||||
}
|
||||
|
||||
public bool ControlPanel
|
||||
{
|
||||
get { return GetFeature("controlpanel"); }
|
||||
set { SetFeature("controlpanel", value); }
|
||||
}
|
||||
|
||||
public bool Update
|
||||
{
|
||||
get { return GetFeature("update"); }
|
||||
set { SetFeature("update", value); }
|
||||
}
|
||||
|
||||
public bool Support
|
||||
{
|
||||
get { return GetFeature("support"); }
|
||||
set { SetFeature("support", value); }
|
||||
}
|
||||
|
||||
public bool Audit
|
||||
{
|
||||
get { return GetFeature("audit"); }
|
||||
set { SetFeature("audit", value); }
|
||||
}
|
||||
|
||||
public bool DocsEdition
|
||||
@ -126,35 +126,35 @@ namespace ASC.Core.Tenants
|
||||
get { return GetFeature("docs"); }
|
||||
set { SetFeature("docs", value); }
|
||||
}
|
||||
|
||||
public bool HasDomain
|
||||
{
|
||||
get { return GetFeature("domain"); }
|
||||
set { SetFeature("domain", value); }
|
||||
}
|
||||
|
||||
public bool HealthCheck
|
||||
{
|
||||
get { return GetFeature("healthcheck"); }
|
||||
set { SetFeature("healthcheck", value); }
|
||||
}
|
||||
|
||||
public bool HasMigration
|
||||
{
|
||||
get { return GetFeature("migration"); }
|
||||
set { SetFeature("migration", value); }
|
||||
}
|
||||
|
||||
public bool Ldap
|
||||
{
|
||||
get { return GetFeature("ldap"); }
|
||||
set { SetFeature("ldap", value); }
|
||||
}
|
||||
|
||||
public bool Sso
|
||||
{
|
||||
get { return GetFeature("sso"); }
|
||||
set { SetFeature("sso", value); }
|
||||
|
||||
public bool HasDomain
|
||||
{
|
||||
get { return GetFeature("domain"); }
|
||||
set { SetFeature("domain", value); }
|
||||
}
|
||||
|
||||
public bool HealthCheck
|
||||
{
|
||||
get { return GetFeature("healthcheck"); }
|
||||
set { SetFeature("healthcheck", value); }
|
||||
}
|
||||
|
||||
public bool HasMigration
|
||||
{
|
||||
get { return GetFeature("migration"); }
|
||||
set { SetFeature("migration", value); }
|
||||
}
|
||||
|
||||
public bool Ldap
|
||||
{
|
||||
get { return GetFeature("ldap"); }
|
||||
set { SetFeature("ldap", value); }
|
||||
}
|
||||
|
||||
public bool Sso
|
||||
{
|
||||
get { return GetFeature("sso"); }
|
||||
set { SetFeature("sso", value); }
|
||||
}
|
||||
|
||||
public bool Branding
|
||||
@ -167,12 +167,12 @@ namespace ASC.Core.Tenants
|
||||
{
|
||||
get { return GetFeature("ssbranding"); }
|
||||
set { SetFeature("ssbranding", value); }
|
||||
}
|
||||
|
||||
public bool WhiteLabel
|
||||
{
|
||||
get { return GetFeature("whitelabel"); }
|
||||
set { SetFeature("whitelabel", value); }
|
||||
}
|
||||
|
||||
public bool WhiteLabel
|
||||
{
|
||||
get { return GetFeature("whitelabel"); }
|
||||
set { SetFeature("whitelabel", value); }
|
||||
}
|
||||
|
||||
public bool Customization
|
||||
@ -191,77 +191,77 @@ namespace ASC.Core.Tenants
|
||||
{
|
||||
get { return GetFeature("privacyroom"); }
|
||||
set { SetFeature("privacyroom", value); }
|
||||
}
|
||||
public int CountPortals
|
||||
{
|
||||
get
|
||||
{
|
||||
var features = (Features ?? string.Empty).Split(' ', ',', ';').ToList();
|
||||
var portals = features.FirstOrDefault(f => f.StartsWith("portals:"));
|
||||
if (portals == null || !int.TryParse(portals.Replace("portals:", ""), out var countPortals) || countPortals <= 0)
|
||||
{
|
||||
countPortals = 0;
|
||||
}
|
||||
return countPortals;
|
||||
}
|
||||
set
|
||||
{
|
||||
var features = (Features ?? string.Empty).Split(' ', ',', ';').ToList();
|
||||
var portals = features.FirstOrDefault(f => f.StartsWith("portals:"));
|
||||
features.Remove(portals);
|
||||
if (value > 0)
|
||||
{
|
||||
features.Add("portals:" + value);
|
||||
}
|
||||
Features = string.Join(",", features.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public TenantQuota()
|
||||
{
|
||||
}
|
||||
public TenantQuota(int tenant)
|
||||
{
|
||||
Id = tenant;
|
||||
}
|
||||
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Id.GetHashCode();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is TenantQuota q && q.Id == Id;
|
||||
}
|
||||
|
||||
|
||||
public bool GetFeature(string feature)
|
||||
{
|
||||
return !string.IsNullOrEmpty(Features) && Features.Split(' ', ',', ';').Contains(feature);
|
||||
}
|
||||
|
||||
internal void SetFeature(string feature, bool set)
|
||||
{
|
||||
var features = (Features == null
|
||||
? new string[] { }
|
||||
: Features.Split(' ', ',', ';')).ToList();
|
||||
if (set && !features.Contains(feature))
|
||||
{
|
||||
features.Add(feature);
|
||||
}
|
||||
else if (!set && features.Contains(feature))
|
||||
{
|
||||
features.Remove(feature);
|
||||
}
|
||||
Features = string.Join(",", features.ToArray());
|
||||
}
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return MemberwiseClone();
|
||||
}
|
||||
}
|
||||
}
|
||||
public int CountPortals
|
||||
{
|
||||
get
|
||||
{
|
||||
var features = (Features ?? string.Empty).Split(' ', ',', ';').ToList();
|
||||
var portals = features.FirstOrDefault(f => f.StartsWith("portals:"));
|
||||
if (portals == null || !int.TryParse(portals.Replace("portals:", ""), out var countPortals) || countPortals <= 0)
|
||||
{
|
||||
countPortals = 0;
|
||||
}
|
||||
return countPortals;
|
||||
}
|
||||
set
|
||||
{
|
||||
var features = (Features ?? string.Empty).Split(' ', ',', ';').ToList();
|
||||
var portals = features.FirstOrDefault(f => f.StartsWith("portals:"));
|
||||
features.Remove(portals);
|
||||
if (value > 0)
|
||||
{
|
||||
features.Add("portals:" + value);
|
||||
}
|
||||
Features = string.Join(",", features.ToArray());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public TenantQuota()
|
||||
{
|
||||
}
|
||||
public TenantQuota(int tenant)
|
||||
{
|
||||
Id = tenant;
|
||||
}
|
||||
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Id.GetHashCode();
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
return obj is TenantQuota q && q.Id == Id;
|
||||
}
|
||||
|
||||
|
||||
public bool GetFeature(string feature)
|
||||
{
|
||||
return !string.IsNullOrEmpty(Features) && Features.Split(' ', ',', ';').Contains(feature);
|
||||
}
|
||||
|
||||
internal void SetFeature(string feature, bool set)
|
||||
{
|
||||
var features = (Features == null
|
||||
? new string[] { }
|
||||
: Features.Split(' ', ',', ';')).ToList();
|
||||
if (set && !features.Contains(feature))
|
||||
{
|
||||
features.Add(feature);
|
||||
}
|
||||
else if (!set && features.Contains(feature))
|
||||
{
|
||||
features.Remove(feature);
|
||||
}
|
||||
Features = string.Join(",", features.ToArray());
|
||||
}
|
||||
|
||||
public object Clone()
|
||||
{
|
||||
return MemberwiseClone();
|
||||
}
|
||||
}
|
||||
}
|
@ -49,7 +49,7 @@ namespace ASC.Core.Tenants
|
||||
|
||||
public string MobilePhone { get; set; }
|
||||
|
||||
public string Password { get; set; }
|
||||
public string PasswordHash { get; set; }
|
||||
|
||||
public EmployeeActivationStatus ActivationStatus { get; set; }
|
||||
|
||||
@ -69,6 +69,7 @@ namespace ASC.Core.Tenants
|
||||
|
||||
public string Campaign { get; set; }
|
||||
|
||||
public bool LimitedControlPanel { get; set; }
|
||||
|
||||
public TenantRegistrationInfo()
|
||||
{
|
||||
|
@ -27,7 +27,6 @@
|
||||
#if DEBUG
|
||||
namespace ASC.Core.Common.Tests
|
||||
{
|
||||
using System;
|
||||
|
||||
using ASC.Core.Security.Authentication;
|
||||
|
||||
@ -39,26 +38,26 @@ namespace ASC.Core.Common.Tests
|
||||
[Test]
|
||||
public void Validate(CookieStorage cookieStorage)
|
||||
{
|
||||
var t1 = 1;
|
||||
var id1 = Guid.NewGuid();
|
||||
var login1 = "l1";
|
||||
var pwd1 = "p1";
|
||||
var it1 = 1;
|
||||
var expire1 = DateTime.UtcNow;
|
||||
var iu1 = 1;
|
||||
//var t1 = 1;
|
||||
//var id1 = Guid.NewGuid();
|
||||
//var login1 = "l1";
|
||||
//var pwd1 = "p1";
|
||||
//var it1 = 1;
|
||||
//var expire1 = DateTime.UtcNow;
|
||||
//var iu1 = 1;
|
||||
|
||||
var cookie = cookieStorage.EncryptCookie(t1, id1, login1, pwd1, it1, expire1, iu1);
|
||||
//var cookie = cookieStorage.EncryptCookie(t1, id1, login1, pwd1, it1, expire1, iu1);
|
||||
|
||||
|
||||
cookieStorage.DecryptCookie(cookie, out var t2, out var id2, out var login2, out var pwd2, out var it2, out var expire2, out var iu2);
|
||||
//cookieStorage.DecryptCookie(cookie, out var t2, out var id2, out var login2, out var pwd2, out var it2, out var expire2, out var iu2);
|
||||
|
||||
Assert.AreEqual(t1, t2);
|
||||
Assert.AreEqual(id1, id2);
|
||||
Assert.AreEqual(login1, login2);
|
||||
Assert.AreEqual(pwd1, pwd2);
|
||||
Assert.AreEqual(it1, it2);
|
||||
Assert.AreEqual(expire1, expire2);
|
||||
Assert.AreEqual(iu1, iu2);
|
||||
//Assert.AreEqual(t1, t2);
|
||||
//Assert.AreEqual(id1, id2);
|
||||
//Assert.AreEqual(login1, login2);
|
||||
//Assert.AreEqual(pwd1, pwd2);
|
||||
//Assert.AreEqual(it1, it2);
|
||||
//Assert.AreEqual(expire1, expire2);
|
||||
//Assert.AreEqual(iu1, iu2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -111,7 +111,7 @@ namespace ASC.Core.Common.Tests
|
||||
userService.SaveUser(t1.TenantId, user);
|
||||
|
||||
var password = "password";
|
||||
userService.SetUserPassword(t1.TenantId, user.ID, password);
|
||||
//userService.SetUserPassword(t1.TenantId, user.ID, password);
|
||||
|
||||
tenants = Service.GetTenants(user.Email, Hasher.Base64Hash(password, HashAlg.SHA256));
|
||||
CollectionAssert.AreEqual(new[] { t1 }, tenants.ToList());
|
||||
|
@ -32,7 +32,6 @@ namespace ASC.Core.Common.Tests
|
||||
|
||||
using ASC.Core.Data;
|
||||
using ASC.Core.Users;
|
||||
using ASC.Security.Cryptography;
|
||||
|
||||
using NUnit.Framework;
|
||||
|
||||
@ -133,18 +132,18 @@ namespace ASC.Core.Common.Tests
|
||||
CollectionAssert.AreEquivalent(new byte[] { 1, 2, 3 }, Service.GetUserPhoto(Tenant, user1.ID));
|
||||
|
||||
var password = "password";
|
||||
Service.SetUserPassword(Tenant, user1.ID, password);
|
||||
Assert.AreEqual(password, Service.GetUserPassword(Tenant, user1.ID));
|
||||
//Service.SetUserPassword(Tenant, user1.ID, password);
|
||||
//Assert.AreEqual(password, Service.GetUserPassword(Tenant, user1.ID));
|
||||
|
||||
CompareUsers(user1, Service.GetUser(Tenant, user1.Email, Hasher.Base64Hash(password, HashAlg.SHA256)));
|
||||
//CompareUsers(user1, Service.GetUser(Tenant, user1.Email, Hasher.Base64Hash(password, HashAlg.SHA256)));
|
||||
|
||||
Service.RemoveUser(Tenant, user1.ID);
|
||||
Assert.IsTrue(Service.GetUser(Tenant, user1.ID).Removed);
|
||||
|
||||
Service.RemoveUser(Tenant, user1.ID, true);
|
||||
|
||||
Assert.AreEqual(0, Service.GetUserPhoto(Tenant, user1.ID).Count());
|
||||
Assert.IsNull(Service.GetUserPassword(Tenant, user1.ID));
|
||||
Assert.AreEqual(0, Service.GetUserPhoto(Tenant, user1.ID).Count());
|
||||
// Assert.IsNull(Service.GetUserPassword(Tenant, user1.ID));
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -57,13 +57,13 @@ namespace ASC.Core.Common.Tests
|
||||
[Test]
|
||||
public void RegionsTest()
|
||||
{
|
||||
var regionSerice = new MultiRegionHostedSolution("site", null, null, null, null);
|
||||
//var regionSerice = new MultiRegionHostedSolution("site", null, null, null, null);
|
||||
|
||||
var t1 = regionSerice.GetTenant("teamlab.com", 50001);
|
||||
Assert.AreEqual("alias_test2.teamlab.com", t1.GetTenantDomain(null));
|
||||
//var t1 = regionSerice.GetTenant("teamlab.com", 50001);
|
||||
//Assert.AreEqual("alias_test2.teamlab.com", t1.GetTenantDomain(null));
|
||||
|
||||
var t2 = regionSerice.GetTenant("teamlab.eu.com", 50001);
|
||||
Assert.AreEqual("tscherb.teamlab.eu.com", t2.GetTenantDomain(null));
|
||||
//var t2 = regionSerice.GetTenant("teamlab.eu.com", 50001);
|
||||
//Assert.AreEqual("tscherb.teamlab.eu.com", t2.GetTenantDomain(null));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -25,6 +25,7 @@
|
||||
|
||||
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Web;
|
||||
|
||||
using ASC.Common;
|
||||
@ -32,6 +33,8 @@ using ASC.Core;
|
||||
using ASC.Core.Common.Settings;
|
||||
using ASC.Core.Users;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace ASC.Web.Core.Users
|
||||
{
|
||||
[Serializable]
|
||||
@ -55,10 +58,12 @@ namespace ASC.Web.Core.Users
|
||||
|
||||
public class DisplayUserSettingsHelper
|
||||
{
|
||||
public DisplayUserSettingsHelper(UserManager userManager, UserFormatter userFormatter)
|
||||
private string RemovedProfileName;
|
||||
public DisplayUserSettingsHelper(UserManager userManager, UserFormatter userFormatter, IConfiguration configuration)
|
||||
{
|
||||
UserManager = userManager;
|
||||
UserFormatter = userFormatter;
|
||||
RemovedProfileName = configuration["web:removed-profile-name"] ?? "profile removed";
|
||||
}
|
||||
|
||||
private UserManager UserManager { get; }
|
||||
@ -82,7 +87,18 @@ namespace ASC.Web.Core.Users
|
||||
}
|
||||
if (!userInfo.ID.Equals(Guid.Empty) && !UserManager.UserExists(userInfo))
|
||||
{
|
||||
return "profile removed";
|
||||
try
|
||||
{
|
||||
var resourceType = Type.GetType("Resources.Resource, ASC.Web.Studio");
|
||||
var resourceProperty = resourceType.GetProperty("ProfileRemoved", BindingFlags.Static | BindingFlags.Public);
|
||||
var resourceValue = (string)resourceProperty.GetValue(null);
|
||||
|
||||
return string.IsNullOrEmpty(resourceValue) ? RemovedProfileName : resourceValue;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
return RemovedProfileName;
|
||||
}
|
||||
}
|
||||
var result = UserFormatter.GetUserName(userInfo, format);
|
||||
return withHtmlEncode ? HtmlEncode(result) : result;
|
||||
|
@ -48,7 +48,7 @@ namespace ASC.Web.Core.WhiteLabel
|
||||
|
||||
public string SalesEmail { get; set; }
|
||||
|
||||
public string DemotUrl { get; set; }
|
||||
public string DemoUrl { get; set; }
|
||||
|
||||
public string SiteUrl { get; set; }
|
||||
|
||||
@ -68,7 +68,7 @@ namespace ASC.Web.Core.WhiteLabel
|
||||
SupportUrl = mailWhiteLabelSettingsHelper.DefaultMailSupportUrl,
|
||||
SupportEmail = mailWhiteLabelSettingsHelper.DefaultMailSupportEmail,
|
||||
SalesEmail = mailWhiteLabelSettingsHelper.DefaultMailSalesEmail,
|
||||
DemotUrl = mailWhiteLabelSettingsHelper.DefaultMailDemotUrl,
|
||||
DemoUrl = mailWhiteLabelSettingsHelper.DefaultMailDemoUrl,
|
||||
SiteUrl = mailWhiteLabelSettingsHelper.DefaultMailSiteUrl
|
||||
};
|
||||
}
|
||||
@ -82,7 +82,7 @@ namespace ASC.Web.Core.WhiteLabel
|
||||
SupportUrl == defaultSettings.SupportUrl &&
|
||||
SupportEmail == defaultSettings.SupportEmail &&
|
||||
SalesEmail == defaultSettings.SalesEmail &&
|
||||
DemotUrl == defaultSettings.DemotUrl &&
|
||||
DemoUrl == defaultSettings.DemoUrl &&
|
||||
SiteUrl == defaultSettings.SiteUrl;
|
||||
}
|
||||
|
||||
@ -113,7 +113,7 @@ namespace ASC.Web.Core.WhiteLabel
|
||||
get
|
||||
{
|
||||
var url = BaseCommonLinkUtility.GetRegionalUrl(Configuration["web:support-feedback"] ?? string.Empty, null);
|
||||
return !string.IsNullOrEmpty(url) ? url : "http://support.onlyoffice.com";
|
||||
return !string.IsNullOrEmpty(url) ? url : "http://helpdesk.onlyoffice.com";
|
||||
}
|
||||
}
|
||||
|
||||
@ -135,7 +135,7 @@ namespace ASC.Web.Core.WhiteLabel
|
||||
}
|
||||
}
|
||||
|
||||
public string DefaultMailDemotUrl
|
||||
public string DefaultMailDemoUrl
|
||||
{
|
||||
get
|
||||
{
|
||||
|
11
common/ASC.Core.Common/protos/CreateClientProto.proto
Normal file
11
common/ASC.Core.Common/protos/CreateClientProto.proto
Normal file
@ -0,0 +1,11 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package ASC.Core.Common.Notify;
|
||||
|
||||
message CreateClientProto {
|
||||
int32 TenantId = 1;
|
||||
string Token = 2;
|
||||
int32 TokenLifespan = 3;
|
||||
string Proxy = 4;
|
||||
string Time = 5;
|
||||
}
|
7
common/ASC.Core.Common/protos/DisableClientProto.proto
Normal file
7
common/ASC.Core.Common/protos/DisableClientProto.proto
Normal file
@ -0,0 +1,7 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package ASC.Core.Common.Notify;
|
||||
|
||||
message DisableClientProto {
|
||||
int32 TenantId= 1;
|
||||
}
|
@ -14,6 +14,7 @@ message NotifyMessage {
|
||||
int64 CreationDate = 9;
|
||||
int32 Priority = 10;
|
||||
repeated NotifyMessageAttachment EmbeddedAttachments = 11;
|
||||
string AutoSubmitted = 12;
|
||||
}
|
||||
message NotifyMessageAttachment {
|
||||
string FileName = 1;
|
||||
|
9
common/ASC.Core.Common/protos/RegisterUserProto.proto
Normal file
9
common/ASC.Core.Common/protos/RegisterUserProto.proto
Normal file
@ -0,0 +1,9 @@
|
||||
syntax = "proto3";
|
||||
|
||||
package ASC.Core.Common.Notify;
|
||||
|
||||
message RegisterUserProto {
|
||||
string UserId= 1;
|
||||
int32 TenantId= 2;
|
||||
string Token= 3;
|
||||
}
|
@ -167,7 +167,7 @@ namespace ASC.Core.ChunkedUploader
|
||||
|
||||
if (uploadSession.BytesTotal == uploadSession.BytesUploaded)
|
||||
{
|
||||
return new FileStream(uploadSession.ChunksBuffer, FileMode.Open, FileAccess.Read, FileShare.ReadWrite,
|
||||
return new FileStream(uploadSession.ChunksBuffer, FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite,
|
||||
4096, FileOptions.DeleteOnClose);
|
||||
}
|
||||
}
|
||||
|
@ -310,7 +310,7 @@ namespace ASC.Data.Storage.DiscStorage
|
||||
var entries = Directory.GetFiles(targetDir, pattern, recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
|
||||
foreach (var entry in entries)
|
||||
{
|
||||
var size = new FileInfo(entry).Length;
|
||||
var size = Crypt.GetFileSize(entry);
|
||||
File.Delete(entry);
|
||||
QuotaUsedDelete(domain, size);
|
||||
}
|
||||
|
@ -26,8 +26,8 @@
|
||||
|
||||
using System;
|
||||
|
||||
using ASC.Common;
|
||||
|
||||
using ASC.Common;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
namespace ASC.Data.Storage.Encryption
|
||||
|
@ -30,8 +30,8 @@ using System.Security.Cryptography;
|
||||
using ASC.Common;
|
||||
using ASC.Common.Caching;
|
||||
using ASC.Core;
|
||||
using ASC.Security.Cryptography;
|
||||
|
||||
using ASC.Security.Cryptography;
|
||||
|
||||
namespace ASC.Data.Storage.Encryption
|
||||
{
|
||||
public class EncryptionSettings
|
||||
@ -64,19 +64,19 @@ namespace ASC.Data.Storage.Encryption
|
||||
}
|
||||
}
|
||||
|
||||
public class EncryptionSettingsHelper
|
||||
public class EncryptionSettingsHelper
|
||||
{
|
||||
private const string key = "EncryptionSettings";
|
||||
|
||||
private CoreConfiguration CoreConfiguration { get; }
|
||||
private AscCacheNotify AscCacheNotify { get; }
|
||||
private InstanceCrypto InstanceCrypto { get; }
|
||||
|
||||
private AscCacheNotify AscCacheNotify { get; }
|
||||
private InstanceCrypto InstanceCrypto { get; }
|
||||
|
||||
public EncryptionSettingsHelper(CoreConfiguration coreConfiguration, AscCacheNotify ascCacheNotify, InstanceCrypto instanceCrypto)
|
||||
{
|
||||
CoreConfiguration = coreConfiguration;
|
||||
AscCacheNotify = ascCacheNotify;
|
||||
InstanceCrypto = instanceCrypto;
|
||||
AscCacheNotify = ascCacheNotify;
|
||||
InstanceCrypto = instanceCrypto;
|
||||
}
|
||||
|
||||
public void Save(EncryptionSettings encryptionSettings)
|
||||
|
@ -1016,27 +1016,33 @@ namespace ASC.Data.Storage.S3
|
||||
_recycleDir = props["recycleDir"];
|
||||
}
|
||||
|
||||
if (props.ContainsKey("region"))
|
||||
if (props.ContainsKey("region") && !string.IsNullOrEmpty(props["region"]))
|
||||
{
|
||||
_region = props["region"];
|
||||
}
|
||||
|
||||
if (props.ContainsKey("serviceurl"))
|
||||
if (props.ContainsKey("serviceurl") && !string.IsNullOrEmpty(props["serviceurl"]))
|
||||
{
|
||||
_serviceurl = props["serviceurl"];
|
||||
}
|
||||
|
||||
if (props.ContainsKey("forcepathstyle"))
|
||||
{
|
||||
_forcepathstyle = bool.Parse(props["forcepathstyle"]);
|
||||
if (bool.TryParse(props["forcepathstyle"], out var fps))
|
||||
{
|
||||
_forcepathstyle = fps;
|
||||
}
|
||||
}
|
||||
|
||||
if (props.ContainsKey("usehttp"))
|
||||
{
|
||||
_useHttp = bool.Parse(props["usehttp"]);
|
||||
if (bool.TryParse(props["usehttp"], out var uh))
|
||||
{
|
||||
_useHttp = uh;
|
||||
}
|
||||
}
|
||||
|
||||
if (props.ContainsKey("sse"))
|
||||
if (props.ContainsKey("sse") && !string.IsNullOrEmpty(props["sse"]))
|
||||
{
|
||||
switch (props["sse"].ToLower())
|
||||
{
|
||||
|
@ -26,12 +26,10 @@
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Security;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Utils;
|
||||
using ASC.Core;
|
||||
using ASC.Core.Users;
|
||||
using ASC.FederatedLogin;
|
||||
using ASC.FederatedLogin.Profile;
|
||||
using ASC.Security.Cryptography;
|
||||
@ -66,44 +64,36 @@ namespace ASC.Web.Studio.Core
|
||||
InstanceCrypto = instanceCrypto;
|
||||
Snapshot = snapshot;
|
||||
}
|
||||
|
||||
|
||||
public void UpdateAddress(string account)
|
||||
{
|
||||
var tenant = TenantManager.GetCurrentTenant();
|
||||
var user = UserManager.GetUsers(SecurityContext.CurrentAccount.ID);
|
||||
if (!SecurityContext.IsAuthenticated || user.IsVisitor(UserManager)) throw new SecurityException();
|
||||
public void SetKeys(Guid userId, string keys)
|
||||
{
|
||||
if (string.IsNullOrEmpty(keys)) return;
|
||||
|
||||
var loginProfile = new LoginProfile(Signature, InstanceCrypto)
|
||||
{
|
||||
Provider = ProviderConstants.Encryption,
|
||||
Provider = ProviderConstants.Encryption,
|
||||
Name = InstanceCrypto.Encrypt(keys)
|
||||
};
|
||||
|
||||
var linker = Snapshot.Get("webstudio");
|
||||
if (string.IsNullOrEmpty(account))
|
||||
{
|
||||
linker.RemoveLink(user.ID.ToString(), loginProfile);
|
||||
}
|
||||
else
|
||||
{
|
||||
loginProfile.Name = Crypto.GetV(account, 1, true);
|
||||
linker.AddLink(user.ID.ToString(), loginProfile);
|
||||
}
|
||||
var linker = Snapshot.Get("webstudio");
|
||||
linker.AddLink(userId.ToString(), loginProfile);
|
||||
}
|
||||
|
||||
|
||||
public string GetAddress()
|
||||
public string GetKeys()
|
||||
{
|
||||
return GetAddress(SecurityContext.CurrentAccount.ID);
|
||||
return GetKeys(SecurityContext.CurrentAccount.ID);
|
||||
}
|
||||
|
||||
public string GetAddress(Guid userId)
|
||||
public string GetKeys(Guid userId)
|
||||
{
|
||||
var linker = Snapshot.Get("webstudio");
|
||||
var profile = linker.GetLinkedProfiles(userId.ToString(), ProviderConstants.Encryption).FirstOrDefault();
|
||||
if (profile == null) return null;
|
||||
|
||||
var account = Crypto.GetV(profile.Name, 1, false);
|
||||
return account;
|
||||
if (profile == null) return null;
|
||||
|
||||
var keys = InstanceCrypto.Decrypt(profile.Name);
|
||||
return keys;
|
||||
}
|
||||
}
|
||||
public static class EncryptionLoginProviderExtension
|
||||
|
@ -0,0 +1,109 @@
|
||||
/*
|
||||
*
|
||||
* (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.Collections.Generic;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Caching;
|
||||
using ASC.Core;
|
||||
using ASC.Core.Common.Configuration;
|
||||
using ASC.Core.Common.Notify;
|
||||
using ASC.Core.Common.Notify.Telegram;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace ASC.FederatedLogin.LoginProviders
|
||||
{
|
||||
public class TelegramLoginProvider : Consumer, IValidateKeysProvider, ITelegramLoginProvider
|
||||
{
|
||||
public string TelegramBotToken
|
||||
{
|
||||
get { return this["telegramBotToken"]; }
|
||||
}
|
||||
|
||||
public string TelegramBotName
|
||||
{
|
||||
get { return this["telegramBotName"]; }
|
||||
}
|
||||
|
||||
public int TelegramAuthTokenLifespan
|
||||
{
|
||||
get { return int.Parse(this["telegramAuthTokenLifespan"]); }
|
||||
}
|
||||
|
||||
public string TelegramProxy
|
||||
{
|
||||
get { return this["telegramProxy"]; }
|
||||
}
|
||||
|
||||
public bool IsEnabled()
|
||||
{
|
||||
return !string.IsNullOrEmpty(TelegramBotToken) && !string.IsNullOrEmpty(TelegramBotName);
|
||||
}
|
||||
|
||||
private TelegramHelper TelegramHelper { get; }
|
||||
|
||||
public TelegramLoginProvider() { }
|
||||
|
||||
public TelegramLoginProvider(
|
||||
TelegramHelper telegramHelper,
|
||||
TenantManager tenantManager,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
CoreSettings coreSettings,
|
||||
IConfiguration configuration,
|
||||
ICacheNotify<ConsumerCacheItem> cache,
|
||||
ConsumerFactory consumerFactory,
|
||||
string name, int order, Dictionary<string, string> props, Dictionary<string, string> additional = null)
|
||||
: base(tenantManager, coreBaseSettings, coreSettings, configuration, cache, consumerFactory, name, order, props, additional)
|
||||
{
|
||||
TelegramHelper = telegramHelper;
|
||||
}
|
||||
|
||||
public bool ValidateKeys()
|
||||
{
|
||||
if (TelegramBotToken == "")
|
||||
{
|
||||
TelegramHelper.DisableClient(TenantManager.GetCurrentTenant().TenantId);
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
return TelegramHelper.CreateClient(TenantManager.GetCurrentTenant().TenantId, TelegramBotToken, TelegramAuthTokenLifespan, TelegramProxy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class TelegramLoginProviderExtension
|
||||
{
|
||||
public static DIHelper AddTelegramLoginProviderService(this DIHelper services)
|
||||
{
|
||||
return services.AddTelegramHelperSerivce()
|
||||
.AddTenantManagerService()
|
||||
.AddCoreBaseSettingsService()
|
||||
.AddCoreSettingsService();
|
||||
}
|
||||
}
|
||||
}
|
@ -38,6 +38,6 @@ namespace ASC.FederatedLogin
|
||||
public const string MailRu = "mailru";
|
||||
public const string VK = "vk";
|
||||
public const string GosUslugi = "gosuslugi";
|
||||
public const string Encryption = "blockchain";
|
||||
public const string Encryption = "e2e";
|
||||
}
|
||||
}
|
||||
|
@ -508,6 +508,9 @@ namespace ASC.MessagingSystem
|
||||
|
||||
StartStorageEncryption = 5050,
|
||||
|
||||
PrivacyRoomEnable = 5051,
|
||||
PrivacyRoomDisable = 5052,
|
||||
|
||||
StartStorageDecryption = 5053,
|
||||
|
||||
#endregion
|
||||
|
@ -242,7 +242,7 @@ namespace ASC.Notify.Textile
|
||||
NotifyTemplateResource.FooterCommonV10
|
||||
.Replace("%SUPPORTURL%", MailWhiteLabelSettingsHelper.DefaultMailSupportUrl)
|
||||
.Replace("%SALESEMAIL%", MailWhiteLabelSettingsHelper.DefaultMailSalesEmail)
|
||||
.Replace("%DEMOURL%", MailWhiteLabelSettingsHelper.DefaultMailDemotUrl);
|
||||
.Replace("%DEMOURL%", MailWhiteLabelSettingsHelper.DefaultMailDemoUrl);
|
||||
footerSocialContent = NotifyTemplateResource.SocialNetworksFooterV10;
|
||||
|
||||
}
|
||||
@ -252,7 +252,7 @@ namespace ASC.Notify.Textile
|
||||
NotifyTemplateResource.FooterCommonV10
|
||||
.Replace("%SUPPORTURL%", string.IsNullOrEmpty(settings.SupportUrl) ? "mailto:" + settings.SalesEmail : settings.SupportUrl)
|
||||
.Replace("%SALESEMAIL%", settings.SalesEmail)
|
||||
.Replace("%DEMOURL%", string.IsNullOrEmpty(settings.DemotUrl) ? "mailto:" + settings.SalesEmail : settings.DemotUrl);
|
||||
.Replace("%DEMOURL%", string.IsNullOrEmpty(settings.DemoUrl) ? "mailto:" + settings.SalesEmail : settings.DemoUrl);
|
||||
footerSocialContent = settings.FooterSocialEnabled ? NotifyTemplateResource.SocialNetworksFooterV10 : string.Empty;
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ namespace ASC.Resource.Manager
|
||||
{
|
||||
Parser.Default.ParseArguments<Options>(args).WithParsed(Export);
|
||||
}
|
||||
|
||||
|
||||
public static void Export(Options options)
|
||||
{
|
||||
var services = new ServiceCollection();
|
||||
@ -42,10 +42,11 @@ namespace ASC.Resource.Manager
|
||||
{
|
||||
var (project, module, filePath, exportPath, culture, format, key) = options;
|
||||
|
||||
//project = "Files";
|
||||
//module = "JavaScript";
|
||||
//filePath = "FilesJSResource.resx";
|
||||
//exportPath = @"C:\Git\portals_core\products\ASC.Files\Server\Resources";
|
||||
project = "Files";
|
||||
module = "Common";
|
||||
filePath = "FilesCommonResource.resx";
|
||||
exportPath = @"C:\Git\portals_core\products\ASC.Files\Core\Resources";
|
||||
key = "AceStatusEnum_CustomFilter";
|
||||
|
||||
if (format == "json")
|
||||
{
|
||||
|
@ -25,11 +25,12 @@ namespace ASC.Resource.Manager
|
||||
var diHelper = new DIHelper(services);
|
||||
services.AddLogging();
|
||||
diHelper.TryAddScoped<ResourceData>();
|
||||
diHelper.TryAddScoped<Program.Scope>();
|
||||
diHelper.TryAddScoped<ProgramScope>();
|
||||
|
||||
diHelper.AddDbContextManagerService<ResourceDbContext>();
|
||||
diHelper.AddLoggerService();
|
||||
diHelper.AddNLogManager();
|
||||
diHelper.TryAddSingleton(Configuration); }
|
||||
diHelper.TryAddSingleton(Configuration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,6 +36,7 @@ using System.Threading.Tasks;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Security.Cryptography;
|
||||
using ASC.Web.Core.Helpers;
|
||||
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
@ -59,22 +60,25 @@ namespace ASC.ApiSystem.Classes
|
||||
ISystemClock clock,
|
||||
IConfiguration configuration,
|
||||
IOptionsMonitor<ILog> option,
|
||||
ApiSystemHelper apiSystemHelper) :
|
||||
ApiSystemHelper apiSystemHelper,
|
||||
MachinePseudoKeys machinePseudoKeys) :
|
||||
base(options, logger, encoder, clock)
|
||||
{
|
||||
Configuration = configuration;
|
||||
|
||||
Log = option.Get("ASC.ApiSystem");
|
||||
|
||||
ApiSystemHelper = apiSystemHelper;
|
||||
ApiSystemHelper = apiSystemHelper;
|
||||
MachinePseudoKeys = machinePseudoKeys;
|
||||
}
|
||||
|
||||
private ILog Log { get; }
|
||||
|
||||
private IConfiguration Configuration { get; }
|
||||
|
||||
private ApiSystemHelper ApiSystemHelper { get; }
|
||||
|
||||
private ApiSystemHelper ApiSystemHelper { get; }
|
||||
private MachinePseudoKeys MachinePseudoKeys { get; }
|
||||
|
||||
protected override Task<AuthenticateResult> HandleAuthenticateAsync()
|
||||
{
|
||||
if (Convert.ToBoolean(Configuration[Scheme.Name] ?? "false"))
|
||||
@ -130,8 +134,8 @@ namespace ASC.ApiSystem.Classes
|
||||
}
|
||||
}
|
||||
|
||||
var skey = Configuration["core:machinekey"];
|
||||
using var hasher = new HMACSHA1(Encoding.UTF8.GetBytes(skey));
|
||||
var skey = MachinePseudoKeys.GetMachineConstant();
|
||||
using var hasher = new HMACSHA1(skey);
|
||||
var data = string.Join("\n", date, pkey);
|
||||
var hash = hasher.ComputeHash(Encoding.UTF8.GetBytes(data));
|
||||
|
||||
|
@ -77,8 +77,10 @@ namespace ASC.ApiSystem.Controllers
|
||||
|
||||
private HostedSolution HostedSolution { get; }
|
||||
|
||||
private IMemoryCache MemoryCache { get; }
|
||||
|
||||
private IMemoryCache MemoryCache { get; }
|
||||
public CoreBaseSettings CoreBaseSettings { get; }
|
||||
public TenantManager TenantManager { get; }
|
||||
|
||||
public CommonMethods(
|
||||
IHttpContextAccessor httpContextAccessor,
|
||||
IConfiguration configuration,
|
||||
@ -88,7 +90,9 @@ namespace ASC.ApiSystem.Controllers
|
||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||
TimeZoneConverter timeZoneConverter, CommonConstants commonConstants,
|
||||
IMemoryCache memoryCache,
|
||||
IOptionsSnapshot<HostedSolution> hostedSolutionOptions)
|
||||
IOptionsSnapshot<HostedSolution> hostedSolutionOptions,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
TenantManager tenantManager)
|
||||
{
|
||||
HttpContextAccessor = httpContextAccessor;
|
||||
|
||||
@ -106,8 +110,9 @@ namespace ASC.ApiSystem.Controllers
|
||||
|
||||
CommonConstants = commonConstants;
|
||||
|
||||
MemoryCache = memoryCache;
|
||||
|
||||
MemoryCache = memoryCache;
|
||||
CoreBaseSettings = coreBaseSettings;
|
||||
TenantManager = tenantManager;
|
||||
HostedSolution = hostedSolutionOptions.Get(CommonConstants.BaseDbConnKeyString);
|
||||
}
|
||||
|
||||
@ -200,7 +205,13 @@ namespace ASC.ApiSystem.Controllers
|
||||
}
|
||||
|
||||
public bool GetTenant(IModel model, out Tenant tenant)
|
||||
{
|
||||
{
|
||||
if (CoreBaseSettings.Standalone && model != null && !string.IsNullOrEmpty((model.PortalName ?? "").Trim()))
|
||||
{
|
||||
tenant = TenantManager.GetTenant((model.PortalName ?? "").Trim());
|
||||
return true;
|
||||
}
|
||||
|
||||
if (model != null && model.TenantId.HasValue)
|
||||
{
|
||||
tenant = HostedSolution.GetTenant(model.TenantId.Value);
|
||||
@ -218,9 +229,14 @@ namespace ASC.ApiSystem.Controllers
|
||||
}
|
||||
|
||||
public bool IsTestEmail(string email)
|
||||
{
|
||||
var regex = new Regex(CommonConstants.AutotestSecretEmails, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
return regex.IsMatch((email ?? "").ToLower());
|
||||
{
|
||||
//the point is not needed in gmail.com
|
||||
email = Regex.Replace(email ?? "", "\\.*(?=\\S*(@gmail.com$))", "").ToLower();
|
||||
if (string.IsNullOrEmpty(email) || string.IsNullOrEmpty(CommonConstants.AutotestSecretEmails))
|
||||
return false;
|
||||
|
||||
var regex = new Regex(CommonConstants.AutotestSecretEmails, RegexOptions.IgnoreCase | RegexOptions.Singleline | RegexOptions.Compiled);
|
||||
return regex.IsMatch(email);
|
||||
}
|
||||
|
||||
public bool CheckMuchRegistration(TenantModel model, string clientIP, Stopwatch sw)
|
||||
|
@ -44,8 +44,6 @@ using Microsoft.AspNetCore.Authorization;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
using Newtonsoft.Json.Linq;
|
||||
|
||||
namespace ASC.ApiSystem.Controllers
|
||||
{
|
||||
@ -57,6 +55,7 @@ namespace ASC.ApiSystem.Controllers
|
||||
private EmailValidationKeyProvider EmailValidationKeyProvider { get; }
|
||||
private CoreSettings CoreSettings { get; }
|
||||
private CommonConstants CommonConstants { get; }
|
||||
public InstanceCrypto InstanceCrypto { get; }
|
||||
private ILog Log { get; }
|
||||
|
||||
public CalDavController(
|
||||
@ -64,12 +63,14 @@ namespace ASC.ApiSystem.Controllers
|
||||
EmailValidationKeyProvider emailValidationKeyProvider,
|
||||
CoreSettings coreSettings,
|
||||
CommonConstants commonConstants,
|
||||
InstanceCrypto instanceCrypto,
|
||||
IOptionsMonitor<ILog> option)
|
||||
{
|
||||
CommonMethods = commonMethods;
|
||||
EmailValidationKeyProvider = emailValidationKeyProvider;
|
||||
CoreSettings = coreSettings;
|
||||
CommonConstants = commonConstants;
|
||||
InstanceCrypto = instanceCrypto;
|
||||
Log = option.Get("ASC.ApiSystem");
|
||||
}
|
||||
|
||||
@ -147,9 +148,9 @@ namespace ASC.ApiSystem.Controllers
|
||||
|
||||
[HttpPost("is_caldav_authenticated")]
|
||||
[Authorize(AuthenticationSchemes = "auth.allowskip")]
|
||||
public IActionResult IsCaldavAuthenticated(JObject data)
|
||||
public IActionResult IsCaldavAuthenticated(UserPassword userPassword)
|
||||
{
|
||||
if (data == null)
|
||||
if (userPassword == null || string.IsNullOrEmpty(userPassword.User) || string.IsNullOrEmpty(userPassword.Password))
|
||||
{
|
||||
Log.Error("CalDav authenticated data is null");
|
||||
|
||||
@ -161,10 +162,7 @@ namespace ASC.ApiSystem.Controllers
|
||||
});
|
||||
}
|
||||
|
||||
var username = data.Value<string>("User");
|
||||
var password = data.Value<string>("Password");
|
||||
|
||||
if (!GetUserData(username, out string email, out Tenant tenant, out object error))
|
||||
if (!GetUserData(userPassword.User, out var email, out var tenant, out var error))
|
||||
{
|
||||
return BadRequest(error);
|
||||
}
|
||||
@ -173,19 +171,19 @@ namespace ASC.ApiSystem.Controllers
|
||||
{
|
||||
Log.Info(string.Format("Caldav auth user: {0}, tenant: {1}", email, tenant.TenantId));
|
||||
|
||||
if (email == "admin@ascsystem" && Core.Configuration.Constants.CoreSystem.ID.ToString() == password)
|
||||
if (InstanceCrypto.Encrypt(email) == userPassword.Password)
|
||||
{
|
||||
return Ok(new
|
||||
{
|
||||
value = "true"
|
||||
});
|
||||
}
|
||||
|
||||
var validationKey = EmailValidationKeyProvider.GetEmailKey(tenant.TenantId, email + password + ConfirmType.Auth);
|
||||
}
|
||||
|
||||
var validationKey = EmailValidationKeyProvider.GetEmailKey(tenant.TenantId, email + userPassword.Password + ConfirmType.Auth);
|
||||
|
||||
var authData = string.Format("userName={0}&password={1}&key={2}",
|
||||
HttpUtility.UrlEncode(email),
|
||||
HttpUtility.UrlEncode(password),
|
||||
HttpUtility.UrlEncode(userPassword.Password),
|
||||
HttpUtility.UrlEncode(validationKey));
|
||||
|
||||
SendToApi(Request.Scheme, tenant, "authentication/login", null, WebRequestMethods.Http.Post, authData);
|
||||
@ -357,9 +355,15 @@ namespace ASC.ApiSystem.Controllers
|
||||
using (webRequest.GetResponse())
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public class UserPassword
|
||||
{
|
||||
public string User { get; set; }
|
||||
public string Password { get; set; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public static class CalDavControllerExtention
|
||||
|
@ -40,6 +40,7 @@ using ASC.Core.Billing;
|
||||
using ASC.Core.Common.Settings;
|
||||
using ASC.Core.Tenants;
|
||||
using ASC.Core.Users;
|
||||
using ASC.Security.Cryptography;
|
||||
using ASC.Web.Core.Helpers;
|
||||
using ASC.Web.Core.Users;
|
||||
using ASC.Web.Core.Utility;
|
||||
@ -74,6 +75,7 @@ namespace ASC.ApiSystem.Controllers
|
||||
private CommonConstants CommonConstants { get; }
|
||||
private TimeZonesProvider TimeZonesProvider { get; }
|
||||
private TimeZoneConverter TimeZoneConverter { get; }
|
||||
public PasswordHasher PasswordHasher { get; }
|
||||
private ILog Log { get; }
|
||||
|
||||
public PortalController(
|
||||
@ -91,7 +93,8 @@ namespace ASC.ApiSystem.Controllers
|
||||
CommonConstants commonConstants,
|
||||
IOptionsMonitor<ILog> option,
|
||||
TimeZonesProvider timeZonesProvider,
|
||||
TimeZoneConverter timeZoneConverter)
|
||||
TimeZoneConverter timeZoneConverter,
|
||||
PasswordHasher passwordHasher)
|
||||
{
|
||||
Configuration = configuration;
|
||||
SecurityContext = securityContext;
|
||||
@ -107,6 +110,7 @@ namespace ASC.ApiSystem.Controllers
|
||||
CommonConstants = commonConstants;
|
||||
TimeZonesProvider = timeZonesProvider;
|
||||
TimeZoneConverter = timeZoneConverter;
|
||||
PasswordHasher = passwordHasher;
|
||||
Log = option.Get("ASC.ApiSystem");
|
||||
}
|
||||
|
||||
@ -156,18 +160,25 @@ namespace ASC.ApiSystem.Controllers
|
||||
}
|
||||
|
||||
var sw = Stopwatch.StartNew();
|
||||
|
||||
if (!CheckPasswordPolicy(model.Password, out object error))
|
||||
{
|
||||
sw.Stop();
|
||||
|
||||
return BadRequest(error);
|
||||
|
||||
if (string.IsNullOrEmpty(model.PasswordHash))
|
||||
{
|
||||
if (!CheckPasswordPolicy(model.Password, out var error1))
|
||||
{
|
||||
sw.Stop();
|
||||
return BadRequest(error1);
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(model.Password))
|
||||
{
|
||||
model.PasswordHash = PasswordHasher.GetClientPassword(model.Password);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
model.FirstName = (model.FirstName ?? "").Trim();
|
||||
model.LastName = (model.LastName ?? "").Trim();
|
||||
|
||||
if (!CheckValidName(model.FirstName + model.LastName, out error))
|
||||
if (!CheckValidName(model.FirstName + model.LastName, out var error))
|
||||
{
|
||||
sw.Stop();
|
||||
|
||||
@ -230,14 +241,15 @@ namespace ASC.ApiSystem.Controllers
|
||||
Culture = lang,
|
||||
FirstName = model.FirstName,
|
||||
LastName = model.LastName,
|
||||
Password = string.IsNullOrEmpty(model.Password) ? null : model.Password,
|
||||
PasswordHash = string.IsNullOrEmpty(model.PasswordHash) ? null : model.PasswordHash,
|
||||
Email = (model.Email ?? "").Trim(),
|
||||
TimeZoneInfo = tz,
|
||||
MobilePhone = string.IsNullOrEmpty(model.Phone) ? null : model.Phone.Trim(),
|
||||
Industry = (TenantIndustry)model.Industry,
|
||||
Spam = model.Spam,
|
||||
Calls = model.Calls,
|
||||
Analytics = model.Analytics
|
||||
Analytics = model.Analytics,
|
||||
LimitedControlPanel = model.LimitedControlPanel
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(model.PartnerId))
|
||||
@ -315,7 +327,7 @@ namespace ASC.ApiSystem.Controllers
|
||||
var isFirst = true;
|
||||
string sendCongratulationsAddress = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(model.Password))
|
||||
if (!string.IsNullOrEmpty(model.PasswordHash))
|
||||
{
|
||||
isFirst = !CommonMethods.SendCongratulations(Request.Scheme, t, model.SkipWelcome, out sendCongratulationsAddress);
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ using ASC.Core.Billing;
|
||||
using ASC.Core.Common.Settings;
|
||||
using ASC.Core.Tenants;
|
||||
using ASC.Core.Users;
|
||||
using ASC.Security.Cryptography;
|
||||
using ASC.Web.Core.Helpers;
|
||||
using ASC.Web.Core.Users;
|
||||
using ASC.Web.Core.Utility;
|
||||
@ -72,6 +73,7 @@ namespace ASC.ApiSystem.Controllers
|
||||
private UserFormatter UserFormatter { get; }
|
||||
private UserManagerWrapper UserManagerWrapper { get; }
|
||||
private IConfiguration Configuration { get; }
|
||||
public PasswordHasher PasswordHasher { get; }
|
||||
private ILog Log { get; }
|
||||
|
||||
public RegistrationController(
|
||||
@ -89,7 +91,8 @@ namespace ASC.ApiSystem.Controllers
|
||||
UserFormatter userFormatter,
|
||||
UserManagerWrapper userManagerWrapper,
|
||||
IConfiguration configuration,
|
||||
IOptionsMonitor<ILog> option)
|
||||
IOptionsMonitor<ILog> option,
|
||||
PasswordHasher passwordHasher)
|
||||
{
|
||||
CommonMethods = commonMethods;
|
||||
CommonConstants = commonConstants;
|
||||
@ -105,6 +108,7 @@ namespace ASC.ApiSystem.Controllers
|
||||
UserFormatter = userFormatter;
|
||||
UserManagerWrapper = userManagerWrapper;
|
||||
Configuration = configuration;
|
||||
PasswordHasher = passwordHasher;
|
||||
Log = option.Get("ASC.ApiSystem");
|
||||
}
|
||||
|
||||
@ -155,14 +159,15 @@ namespace ASC.ApiSystem.Controllers
|
||||
|
||||
object error;
|
||||
|
||||
if (!string.IsNullOrEmpty(model.Password))
|
||||
if (string.IsNullOrEmpty(model.PasswordHash) && !string.IsNullOrEmpty(model.Password))
|
||||
{
|
||||
if (!CheckPasswordPolicy(model.Password, out error))
|
||||
{
|
||||
sw.Stop();
|
||||
|
||||
return BadRequest(error);
|
||||
}
|
||||
}
|
||||
model.PasswordHash = PasswordHasher.GetClientPassword(model.Password);
|
||||
}
|
||||
|
||||
if (!CheckValidName(model.FirstName.Trim() + model.LastName.Trim(), out error))
|
||||
@ -262,14 +267,15 @@ namespace ASC.ApiSystem.Controllers
|
||||
Culture = lang,
|
||||
FirstName = model.FirstName.Trim(),
|
||||
LastName = model.LastName.Trim(),
|
||||
Password = string.IsNullOrEmpty(model.Password) ? null : model.Password,
|
||||
PasswordHash = String.IsNullOrEmpty(model.PasswordHash) ? null : model.PasswordHash,
|
||||
Email = model.Email.Trim(),
|
||||
TimeZoneInfo = tz,
|
||||
MobilePhone = string.IsNullOrEmpty(model.Phone) ? null : model.Phone.Trim(),
|
||||
Industry = (TenantIndustry)model.Industry,
|
||||
Spam = model.Spam,
|
||||
Calls = model.Calls,
|
||||
Analytics = model.Analytics
|
||||
Analytics = model.Analytics,
|
||||
LimitedControlPanel = model.LimitedControlPanel
|
||||
};
|
||||
|
||||
if (!string.IsNullOrEmpty(model.PartnerId))
|
||||
@ -322,7 +328,7 @@ namespace ASC.ApiSystem.Controllers
|
||||
|
||||
string sendCongratulationsAddress = null;
|
||||
|
||||
if (!string.IsNullOrEmpty(model.Password))
|
||||
if (!String.IsNullOrEmpty(model.PasswordHash))
|
||||
{
|
||||
isFirst = !CommonMethods.SendCongratulations(Request.Scheme, t, model.SkipWelcome, out sendCongratulationsAddress);
|
||||
}
|
||||
|
@ -61,9 +61,12 @@ namespace ASC.ApiSystem.Models
|
||||
|
||||
[StringLength(38)]
|
||||
public string Module { get; set; }
|
||||
|
||||
|
||||
//todo: delete after www update
|
||||
[StringLength(Web.Core.Utility.PasswordSettings.MaxLength)]
|
||||
public string Password { get; set; }
|
||||
public string Password { get; set; }
|
||||
|
||||
public string PasswordHash { get; set; }
|
||||
|
||||
[StringLength(255)]
|
||||
public string PartnerId { get; set; }
|
||||
@ -89,6 +92,8 @@ namespace ASC.ApiSystem.Models
|
||||
|
||||
public bool Analytics { get; set; }
|
||||
|
||||
public string AppKey { get; set; }
|
||||
public string AppKey { get; set; }
|
||||
|
||||
public bool LimitedControlPanel { get; set; }
|
||||
}
|
||||
}
|
@ -4,9 +4,11 @@ using System.Collections.Generic;
|
||||
|
||||
using ASC.Api.Core.Middleware;
|
||||
using ASC.Common;
|
||||
using ASC.Core;
|
||||
using ASC.Data.Backup.Contracts;
|
||||
using ASC.Data.Backup.Models;
|
||||
using ASC.Web.Api.Routing;
|
||||
using ASC.Web.Studio.Utility;
|
||||
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
|
||||
@ -17,9 +19,17 @@ namespace ASC.Data.Backup.Controllers
|
||||
public class BackupController
|
||||
{
|
||||
private BackupAjaxHandler BackupHandler { get; }
|
||||
public BackupController(BackupAjaxHandler backupAjaxHandler)
|
||||
private CoreBaseSettings CoreBaseSettings { get; }
|
||||
private TenantExtra TenantExtra { get; }
|
||||
|
||||
public BackupController(
|
||||
BackupAjaxHandler backupAjaxHandler,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
TenantExtra tenantExtra)
|
||||
{
|
||||
BackupHandler = backupAjaxHandler;
|
||||
CoreBaseSettings = coreBaseSettings;
|
||||
TenantExtra = tenantExtra;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns the backup schedule of the current portal
|
||||
@ -29,6 +39,11 @@ namespace ASC.Data.Backup.Controllers
|
||||
[Read("getbackupschedule")]
|
||||
public BackupAjaxHandler.Schedule GetBackupSchedule()
|
||||
{
|
||||
if (CoreBaseSettings.Standalone)
|
||||
{
|
||||
TenantExtra.DemandControlPanelPermission();
|
||||
}
|
||||
|
||||
return BackupHandler.GetSchedule();
|
||||
}
|
||||
|
||||
@ -44,6 +59,11 @@ namespace ASC.Data.Backup.Controllers
|
||||
[Create("createbackupschedule")]
|
||||
public void CreateBackupSchedule(BackupStorageType storageType, [FromQuery] Dictionary<string, string> storageParams, int backupsStored, [FromBody] BackupAjaxHandler.CronParams cronParams, bool backupMail)
|
||||
{
|
||||
if (CoreBaseSettings.Standalone)
|
||||
{
|
||||
TenantExtra.DemandControlPanelPermission();
|
||||
}
|
||||
|
||||
BackupHandler.CreateSchedule(storageType, storageParams, backupsStored, cronParams, backupMail);
|
||||
}
|
||||
|
||||
@ -54,6 +74,11 @@ namespace ASC.Data.Backup.Controllers
|
||||
[Delete("deletebackupschedule")]
|
||||
public void DeleteBackupSchedule()
|
||||
{
|
||||
if (CoreBaseSettings.Standalone)
|
||||
{
|
||||
TenantExtra.DemandControlPanelPermission();
|
||||
}
|
||||
|
||||
BackupHandler.DeleteSchedule();
|
||||
}
|
||||
|
||||
@ -68,6 +93,11 @@ namespace ASC.Data.Backup.Controllers
|
||||
[Create("startbackup")]
|
||||
public BackupProgress StartBackup(Models.Backup backup)
|
||||
{
|
||||
if (CoreBaseSettings.Standalone)
|
||||
{
|
||||
TenantExtra.DemandControlPanelPermission();
|
||||
}
|
||||
|
||||
BackupHandler.StartBackup(backup.StorageType, backup.StorageParams ?? new Dictionary<string, string>(), backup.BackupMail);
|
||||
return BackupHandler.GetBackupProgress();
|
||||
}
|
||||
@ -80,6 +110,11 @@ namespace ASC.Data.Backup.Controllers
|
||||
[Read("getbackupprogress")]
|
||||
public BackupProgress GetBackupProgress()
|
||||
{
|
||||
if (CoreBaseSettings.Standalone)
|
||||
{
|
||||
TenantExtra.DemandControlPanelPermission();
|
||||
}
|
||||
|
||||
return BackupHandler.GetBackupProgress();
|
||||
}
|
||||
|
||||
@ -91,6 +126,11 @@ namespace ASC.Data.Backup.Controllers
|
||||
[Read("getbackuphistory")]
|
||||
public List<BackupHistoryRecord> GetBackupHistory()
|
||||
{
|
||||
if (CoreBaseSettings.Standalone)
|
||||
{
|
||||
TenantExtra.DemandControlPanelPermission();
|
||||
}
|
||||
|
||||
return BackupHandler.GetBackupHistory();
|
||||
}
|
||||
|
||||
@ -101,6 +141,11 @@ namespace ASC.Data.Backup.Controllers
|
||||
[Delete("deletebackup/{id}")]
|
||||
public void DeleteBackup(Guid id)
|
||||
{
|
||||
if (CoreBaseSettings.Standalone)
|
||||
{
|
||||
TenantExtra.DemandControlPanelPermission();
|
||||
}
|
||||
|
||||
BackupHandler.DeleteBackup(id);
|
||||
}
|
||||
|
||||
@ -112,6 +157,11 @@ namespace ASC.Data.Backup.Controllers
|
||||
[Delete("deletebackuphistory")]
|
||||
public void DeleteBackupHistory()
|
||||
{
|
||||
if (CoreBaseSettings.Standalone)
|
||||
{
|
||||
TenantExtra.DemandControlPanelPermission();
|
||||
}
|
||||
|
||||
BackupHandler.DeleteAllBackups();
|
||||
}
|
||||
|
||||
@ -127,6 +177,11 @@ namespace ASC.Data.Backup.Controllers
|
||||
[Create("startrestore")]
|
||||
public BackupProgress StartBackupRestore(BackupRestore backupRestore)
|
||||
{
|
||||
if (CoreBaseSettings.Standalone)
|
||||
{
|
||||
TenantExtra.DemandControlPanelPermission();
|
||||
}
|
||||
|
||||
BackupHandler.StartRestore(backupRestore.BackupId, backupRestore.StorageType, backupRestore.StorageParams, backupRestore.Notify);
|
||||
return BackupHandler.GetBackupProgress();
|
||||
}
|
||||
@ -139,6 +194,11 @@ namespace ASC.Data.Backup.Controllers
|
||||
[Read("getrestoreprogress", true)] //NOTE: this method doesn't check payment!!!
|
||||
public BackupProgress GetRestoreProgress()
|
||||
{
|
||||
if (CoreBaseSettings.Standalone)
|
||||
{
|
||||
TenantExtra.DemandControlPanelPermission();
|
||||
}
|
||||
|
||||
return BackupHandler.GetRestoreProgress();
|
||||
}
|
||||
|
||||
@ -146,6 +206,11 @@ namespace ASC.Data.Backup.Controllers
|
||||
[Read("backuptmp")]
|
||||
public string GetTempPath()
|
||||
{
|
||||
if (CoreBaseSettings.Standalone)
|
||||
{
|
||||
TenantExtra.DemandControlPanelPermission();
|
||||
}
|
||||
|
||||
return BackupHandler.GetTmpFolder();
|
||||
}
|
||||
}
|
||||
@ -155,7 +220,9 @@ namespace ASC.Data.Backup.Controllers
|
||||
{
|
||||
return services
|
||||
.AddBackupAjaxHandler()
|
||||
.AddIpSecurityFilter();
|
||||
.AddIpSecurityFilter()
|
||||
.AddCoreBaseSettingsService()
|
||||
.AddTenantExtraService();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -370,10 +370,12 @@ namespace ASC.Data.Backup.Service
|
||||
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
var scopeClass = scope.ServiceProvider.GetService<BackupWorkerScope>();
|
||||
var (tenantManager, backupStorageFactory, notifyHelper, backupRepository, backupWorker, backupPortalTask, _, _) = scopeClass;
|
||||
var (tenantManager, backupStorageFactory, notifyHelper, backupRepository, backupWorker, backupPortalTask, _, _, coreBaseSettings) = scopeClass;
|
||||
|
||||
var tenant = tenantManager.GetTenant(TenantId);
|
||||
var backupName = string.Format("{0}_{1:yyyy-MM-dd_HH-mm-ss}.{2}", tenant.TenantAlias, DateTime.UtcNow, ArchiveFormat);
|
||||
var dateTime = coreBaseSettings.Standalone ? DateTime.Now : DateTime.UtcNow;
|
||||
var backupName = string.Format("{0}_{1:yyyy-MM-dd_HH-mm-ss}.{2}", tenantManager.GetTenant(TenantId).TenantAlias, dateTime, ArchiveFormat);
|
||||
|
||||
var tempFile = Path.Combine(TempFolder, backupName);
|
||||
var storagePath = tempFile;
|
||||
try
|
||||
@ -502,7 +504,7 @@ namespace ASC.Data.Backup.Service
|
||||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
var scopeClass = scope.ServiceProvider.GetService<BackupWorkerScope>();
|
||||
var (tenantManager, backupStorageFactory, notifyHelper, _, backupWorker, _, restorePortalTask, _) = scopeClass;
|
||||
var (tenantManager, backupStorageFactory, notifyHelper, _, backupWorker, _, restorePortalTask, _, _) = scopeClass;
|
||||
Tenant tenant = null;
|
||||
var tempFile = PathHelper.GetTempFileName(TempFolder);
|
||||
try
|
||||
@ -661,7 +663,7 @@ namespace ASC.Data.Backup.Service
|
||||
{
|
||||
using var scope = ServiceProvider.CreateScope();
|
||||
var scopeClass = scope.ServiceProvider.GetService<BackupWorkerScope>();
|
||||
var (tenantManager, _, notifyHelper, _, backupWorker, _, _, transferPortalTask) = scopeClass;
|
||||
var (tenantManager, _, notifyHelper, _, backupWorker, _, _, transferPortalTask, _) = scopeClass;
|
||||
var tempFile = PathHelper.GetTempFileName(TempFolder);
|
||||
var tenant = tenantManager.GetTenant(TenantId);
|
||||
var alias = tenant.TenantAlias;
|
||||
@ -800,6 +802,7 @@ namespace ASC.Data.Backup.Service
|
||||
private BackupPortalTask BackupPortalTask { get; }
|
||||
private RestorePortalTask RestorePortalTask { get; }
|
||||
private TransferPortalTask TransferPortalTask { get; }
|
||||
public CoreBaseSettings CoreBaseSettings { get; }
|
||||
|
||||
public BackupWorkerScope(TenantManager tenantManager,
|
||||
BackupStorageFactory backupStorageFactory,
|
||||
@ -808,7 +811,8 @@ namespace ASC.Data.Backup.Service
|
||||
BackupWorker backupWorker,
|
||||
BackupPortalTask backupPortalTask,
|
||||
RestorePortalTask restorePortalTask,
|
||||
TransferPortalTask transferPortalTask)
|
||||
TransferPortalTask transferPortalTask,
|
||||
CoreBaseSettings coreBaseSettings)
|
||||
{
|
||||
TenantManager = tenantManager;
|
||||
BackupStorageFactory = backupStorageFactory;
|
||||
@ -818,6 +822,7 @@ namespace ASC.Data.Backup.Service
|
||||
BackupPortalTask = backupPortalTask;
|
||||
RestorePortalTask = restorePortalTask;
|
||||
TransferPortalTask = transferPortalTask;
|
||||
CoreBaseSettings = coreBaseSettings;
|
||||
}
|
||||
|
||||
public void Deconstruct(out TenantManager tenantManager,
|
||||
@ -827,7 +832,8 @@ namespace ASC.Data.Backup.Service
|
||||
out BackupWorker backupWorker,
|
||||
out BackupPortalTask backupPortalTask,
|
||||
out RestorePortalTask restorePortalTask,
|
||||
out TransferPortalTask transferPortalTask)
|
||||
out TransferPortalTask transferPortalTask,
|
||||
out CoreBaseSettings coreBaseSettings)
|
||||
{
|
||||
tenantManager = TenantManager;
|
||||
backupStorageFactory = BackupStorageFactory;
|
||||
@ -837,6 +843,7 @@ namespace ASC.Data.Backup.Service
|
||||
backupPortalTask = BackupPortalTask;
|
||||
restorePortalTask = RestorePortalTask;
|
||||
transferPortalTask = TransferPortalTask;
|
||||
coreBaseSettings = CoreBaseSettings;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -261,7 +261,7 @@ namespace ASC.Data.Backup.Tasks.Modules
|
||||
{
|
||||
value = Regex.Replace(
|
||||
Convert.ToString(value),
|
||||
@"(?<=""message_id"":|/products/crm/httphandlers/filehandler\.ashx\?action=mailmessage&message_id=)\d+",
|
||||
@"(?<=""message_id"":|/Products/CRM/HttpHandlers/filehandler\.ashx\?action=mailmessage&message_id=)\d+",
|
||||
match =>
|
||||
{
|
||||
var mappedMessageId = Convert.ToString(columnMapper.GetMapping(relation.ParentTable, relation.ParentColumn, match.Value));
|
||||
|
@ -129,7 +129,7 @@ namespace ASC.Data.Backup.Tasks
|
||||
return files.Distinct();
|
||||
}
|
||||
|
||||
protected virtual bool IsStorageModuleAllowed(string storageModuleName)
|
||||
protected bool IsStorageModuleAllowed(string storageModuleName)
|
||||
{
|
||||
var allowedStorageModules = new List<string>
|
||||
{
|
||||
@ -144,7 +144,9 @@ namespace ASC.Data.Backup.Tasks
|
||||
"fckuploaders",
|
||||
"talk",
|
||||
"mailaggregator",
|
||||
"whitelabel"
|
||||
"whitelabel",
|
||||
"customnavigation",
|
||||
"userPhotos"
|
||||
};
|
||||
|
||||
if (!allowedStorageModules.Contains(storageModuleName))
|
||||
|
@ -55,15 +55,26 @@ namespace ASC.Data.Backup.Tasks
|
||||
public bool ReplaceDate { get; set; }
|
||||
public bool Dump { get; set; }
|
||||
private CoreBaseSettings CoreBaseSettings { get; set; }
|
||||
private LicenseReader LicenseReader { get; set; }
|
||||
private LicenseReader LicenseReader { get; set; }
|
||||
public TenantManager TenantManager { get; }
|
||||
private AscCacheNotify AscCacheNotify { get; set; }
|
||||
private IOptionsMonitor<ILog> Options { get; set; }
|
||||
|
||||
public RestorePortalTask(DbFactory dbFactory, IOptionsMonitor<ILog> options, StorageFactory storageFactory, StorageFactoryConfig storageFactoryConfig, CoreBaseSettings coreBaseSettings, LicenseReader licenseReader, AscCacheNotify ascCacheNotify, ModuleProvider moduleProvider)
|
||||
public RestorePortalTask(
|
||||
DbFactory dbFactory,
|
||||
IOptionsMonitor<ILog> options,
|
||||
StorageFactory storageFactory,
|
||||
StorageFactoryConfig storageFactoryConfig,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
LicenseReader licenseReader,
|
||||
TenantManager tenantManager,
|
||||
AscCacheNotify ascCacheNotify,
|
||||
ModuleProvider moduleProvider)
|
||||
: base(dbFactory, options, storageFactory, storageFactoryConfig, moduleProvider)
|
||||
{
|
||||
CoreBaseSettings = coreBaseSettings;
|
||||
LicenseReader = licenseReader;
|
||||
LicenseReader = licenseReader;
|
||||
TenantManager = tenantManager;
|
||||
AscCacheNotify = ascCacheNotify;
|
||||
Options = options;
|
||||
}
|
||||
@ -119,7 +130,13 @@ namespace ASC.Data.Backup.Tasks
|
||||
Logger.Debug("end restore data");
|
||||
|
||||
if (ProcessStorage)
|
||||
{
|
||||
{
|
||||
if (CoreBaseSettings.Standalone)
|
||||
{
|
||||
Logger.Debug("clear cache");
|
||||
AscCacheNotify.ClearCache();
|
||||
}
|
||||
|
||||
DoRestoreStorage(dataReader);
|
||||
}
|
||||
if (UnblockPortalAfterCompleted)
|
||||
@ -160,7 +177,23 @@ namespace ASC.Data.Backup.Tasks
|
||||
|
||||
var stepscount = keys.Count * 2 + upgrades.Count;
|
||||
|
||||
SetStepsCount(ProcessStorage ? stepscount + 1 : stepscount);
|
||||
SetStepsCount(ProcessStorage ? stepscount + 1 : stepscount);
|
||||
|
||||
if (ProcessStorage)
|
||||
{
|
||||
var storageModules = StorageFactoryConfig.GetModuleList(ConfigPath).Where(IsStorageModuleAllowed);
|
||||
var tenants = TenantManager.GetTenants(false);
|
||||
|
||||
stepscount += storageModules.Count() * tenants.Count;
|
||||
|
||||
SetStepsCount(stepscount + 1);
|
||||
|
||||
DoDeleteStorage(storageModules, tenants);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetStepsCount(stepscount);
|
||||
}
|
||||
|
||||
for (var i = 0; i < keys.Count; i += TasksLimit)
|
||||
{
|
||||
@ -284,6 +317,42 @@ namespace ASC.Data.Backup.Tasks
|
||||
SetStepCompleted();
|
||||
}
|
||||
Logger.Debug("end restore storage");
|
||||
}
|
||||
|
||||
private void DoDeleteStorage(IEnumerable<string> storageModules, IEnumerable<Tenant> tenants)
|
||||
{
|
||||
Logger.Debug("begin delete storage");
|
||||
|
||||
foreach (var tenant in tenants)
|
||||
{
|
||||
foreach (var module in storageModules)
|
||||
{
|
||||
var storage = StorageFactory.GetStorage(ConfigPath, tenant.TenantId.ToString(), module);
|
||||
var domains = StorageFactoryConfig.GetDomainList(ConfigPath, module).ToList();
|
||||
|
||||
domains.Add(string.Empty); //instead storage.DeleteFiles("\\", "*.*", true);
|
||||
|
||||
foreach (var domain in domains)
|
||||
{
|
||||
ActionInvoker.Try(
|
||||
state =>
|
||||
{
|
||||
if (storage.IsDirectory((string)state))
|
||||
{
|
||||
storage.DeleteFiles((string)state, "\\", "*.*", true);
|
||||
}
|
||||
},
|
||||
domain,
|
||||
5,
|
||||
onFailure: error => Logger.WarnFormat("Can't delete files for domain {0}: \r\n{1}", domain, error)
|
||||
);
|
||||
}
|
||||
|
||||
SetStepCompleted();
|
||||
}
|
||||
}
|
||||
|
||||
Logger.Debug("end delete storage");
|
||||
}
|
||||
|
||||
private IEnumerable<BackupFileInfo> GetFilesToProcess(IDataReadOperator dataReader)
|
||||
@ -299,14 +368,6 @@ namespace ASC.Data.Backup.Tasks
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override bool IsStorageModuleAllowed(string storageModuleName)
|
||||
{
|
||||
if (storageModuleName == "fckuploaders")
|
||||
return false;
|
||||
return base.IsStorageModuleAllowed(storageModuleName);
|
||||
}
|
||||
|
||||
private void SetTenantActive(int tenantId)
|
||||
{
|
||||
using (var connection = DbFactory.OpenConnection())
|
||||
|
@ -79,7 +79,8 @@ namespace ASC.Notify
|
||||
SenderType = m.Sender,
|
||||
CreationDate = new DateTime(m.CreationDate),
|
||||
ReplyTo = m.ReplyTo,
|
||||
Attachments = m.EmbeddedAttachments.ToString()
|
||||
Attachments = m.EmbeddedAttachments.ToString(),
|
||||
AutoSubmitted = m.AutoSubmitted
|
||||
};
|
||||
|
||||
notifyQueue = dbContext.NotifyQueue.Add(notifyQueue).Entity;
|
||||
@ -135,7 +136,8 @@ namespace ASC.Notify
|
||||
Content = r.queue.Content,
|
||||
Sender = r.queue.SenderType,
|
||||
CreationDate = r.queue.CreationDate.Ticks,
|
||||
ReplyTo = r.queue.ReplyTo
|
||||
ReplyTo = r.queue.ReplyTo,
|
||||
AutoSubmitted = r.queue.AutoSubmitted
|
||||
};
|
||||
try
|
||||
{
|
||||
|
@ -0,0 +1,30 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk.Web">
|
||||
|
||||
<PropertyGroup>
|
||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||
<ApplicationIcon />
|
||||
<OutputType>Exe</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<DebugType>none</DebugType>
|
||||
<DebugSymbols>false</DebugSymbols>
|
||||
<NoWarn>1701;1702;NU1701</NoWarn>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
<PackageReference Include="Telegram.Bot" Version="15.7.1" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\ASC.Api.Core\ASC.Api.Core.csproj" />
|
||||
<ProjectReference Include="..\..\ASC.Common\ASC.Common.csproj" />
|
||||
<ProjectReference Include="..\..\ASC.Core.Common\ASC.Core.Common.csproj" />
|
||||
<ProjectReference Include="..\..\ASC.FederatedLogin\ASC.FederatedLogin.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<Folder Include="Properties\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
82
common/services/ASC.TelegramService/Commands/UserCommands.cs
Normal file
82
common/services/ASC.TelegramService/Commands/UserCommands.cs
Normal file
@ -0,0 +1,82 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2020
|
||||
*
|
||||
* 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.Runtime.Caching;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Core.Common.Notify.Telegram;
|
||||
using ASC.TelegramService.Core;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
|
||||
namespace ASC.TelegramService.Commands
|
||||
{
|
||||
public class UserCommands : CommandContext
|
||||
{
|
||||
private CachedTelegramDao CachedTelegramDao { get; }
|
||||
|
||||
public UserCommands(IOptionsSnapshot<CachedTelegramDao> cachedTelegramDao)
|
||||
{
|
||||
CachedTelegramDao = cachedTelegramDao.Value;
|
||||
}
|
||||
|
||||
[Command("start")]
|
||||
public async Task StartCommand(string token)
|
||||
{
|
||||
if (string.IsNullOrEmpty(token)) return;
|
||||
|
||||
var user = MemoryCache.Default.Get(token);
|
||||
if (user != null)
|
||||
{
|
||||
MemoryCache.Default.Remove(token);
|
||||
MemoryCache.Default.Remove((string)user);
|
||||
var split = ((string)user).Split(':');
|
||||
|
||||
var guid = Guid.Parse(split[0]);
|
||||
var tenant = int.Parse(split[1]);
|
||||
|
||||
if (tenant == TenantId)
|
||||
{
|
||||
CachedTelegramDao.RegisterUser(guid, tenant, Context.User.Id);
|
||||
await ReplyAsync("Ok!");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
await ReplyAsync("Error");
|
||||
}
|
||||
}
|
||||
|
||||
public static class UserCommandsExtension
|
||||
{
|
||||
public static DIHelper AddUserCommandsService(this DIHelper services)
|
||||
{
|
||||
services.TryAddScoped<UserCommands>();
|
||||
return services.AddCachedTelegramDaoService();
|
||||
}
|
||||
}
|
||||
}
|
51
common/services/ASC.TelegramService/Core/Attributes.cs
Normal file
51
common/services/ASC.TelegramService/Core/Attributes.cs
Normal file
@ -0,0 +1,51 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2020
|
||||
*
|
||||
* 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;
|
||||
|
||||
namespace ASC.TelegramService.Core
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Method, Inherited = false, AllowMultiple = false)]
|
||||
public class CommandAttribute : Attribute
|
||||
{
|
||||
public CommandAttribute(string name)
|
||||
{
|
||||
Name = name.ToLowerInvariant();
|
||||
}
|
||||
|
||||
public string Name { get; private set; }
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class, Inherited = false, AllowMultiple = false)]
|
||||
public class ParamParserAttribute : Attribute
|
||||
{
|
||||
public ParamParserAttribute(Type type)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public Type Type { get; private set; }
|
||||
}
|
||||
}
|
203
common/services/ASC.TelegramService/Core/Core.cs
Normal file
203
common/services/ASC.TelegramService/Core/Core.cs
Normal file
@ -0,0 +1,203 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2020
|
||||
*
|
||||
* 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.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Common.Logging;
|
||||
using ASC.TelegramService.Commands;
|
||||
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Types;
|
||||
|
||||
namespace ASC.TelegramService.Core
|
||||
{
|
||||
public class TelegramCommand
|
||||
{
|
||||
public string CommandName { get; private set; }
|
||||
public string[] Args { get; private set; }
|
||||
|
||||
public Message Message { get; private set; }
|
||||
public User User { get { return Message.From; } }
|
||||
public Chat Chat { get { return Message.Chat; } }
|
||||
|
||||
public TelegramCommand(Message msg, string cmdName, string[] args = null)
|
||||
{
|
||||
Message = msg;
|
||||
CommandName = cmdName;
|
||||
Args = args;
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandModule
|
||||
{
|
||||
private ILog Log { get; }
|
||||
|
||||
private readonly Regex cmdReg = new Regex(@"^\/([^\s]+)\s?(.*)");
|
||||
private readonly Regex argsReg = new Regex(@"[^""\s]\S*|"".+?""");
|
||||
|
||||
private readonly Dictionary<string, MethodInfo> commands = new Dictionary<string, MethodInfo>();
|
||||
private readonly Dictionary<string, Type> contexts = new Dictionary<string, Type>();
|
||||
private readonly Dictionary<Type, ParamParser> parsers = new Dictionary<Type, ParamParser>();
|
||||
|
||||
private IServiceProvider ServiceProvider { get; }
|
||||
public CommandModule(IOptionsMonitor<ILog> options, IServiceProvider serviceProvider)
|
||||
{
|
||||
ServiceProvider = serviceProvider;
|
||||
Log = options.CurrentValue;
|
||||
|
||||
var assembly = Assembly.GetExecutingAssembly();
|
||||
|
||||
foreach (var t in assembly.GetExportedTypes())
|
||||
{
|
||||
if (t.IsAbstract) continue;
|
||||
|
||||
if (t.IsSubclassOf(typeof(CommandContext)))
|
||||
{
|
||||
foreach (var method in t.GetRuntimeMethods())
|
||||
{
|
||||
if (method.IsPublic && Attribute.IsDefined(method, typeof(CommandAttribute)))
|
||||
{
|
||||
var attr = method.GetCustomAttribute<CommandAttribute>();
|
||||
commands.Add(attr.Name, method);
|
||||
contexts.Add(attr.Name, t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (t.IsSubclassOf(typeof(ParamParser)) && Attribute.IsDefined(t, typeof(ParamParserAttribute)))
|
||||
{
|
||||
parsers.Add(t.GetCustomAttribute<ParamParserAttribute>().Type, (ParamParser)Activator.CreateInstance(t));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private TelegramCommand ParseCommand(Message msg)
|
||||
{
|
||||
var reg = cmdReg.Match(msg.Text);
|
||||
var args = argsReg.Matches(reg.Groups[2].Value);
|
||||
|
||||
return new TelegramCommand(msg, reg.Groups[1].Value.ToLowerInvariant(), args.Count > 0 ? args.Cast<Match>().Select(a => a.Value).ToArray() : null);
|
||||
}
|
||||
|
||||
private object[] ParseParams(MethodInfo cmd, string[] args)
|
||||
{
|
||||
List<object> parsedParams = new List<object>();
|
||||
|
||||
var cmdArgs = cmd.GetParameters();
|
||||
|
||||
if (cmdArgs.Any() && args == null || cmdArgs.Count() != args.Count()) throw new Exception("Wrong parameters count");
|
||||
for (var i = 0; i < cmdArgs.Count(); i++)
|
||||
{
|
||||
var type = cmdArgs[i].ParameterType;
|
||||
|
||||
if (type == typeof(string))
|
||||
{
|
||||
parsedParams.Add(args[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!parsers.ContainsKey(type)) throw new Exception(string.Format("No parser found for type '{0}'", type));
|
||||
|
||||
parsedParams.Add(parsers[cmdArgs[i].ParameterType].FromString(args[i]));
|
||||
}
|
||||
|
||||
return parsedParams.ToArray();
|
||||
}
|
||||
|
||||
public async Task HandleCommand(Message msg, TelegramBotClient client, int tenantId)
|
||||
{
|
||||
try
|
||||
{
|
||||
var cmd = ParseCommand(msg);
|
||||
|
||||
if (!commands.ContainsKey(cmd.CommandName)) throw new Exception(string.Format("No handler found for command '{0}'", cmd.CommandName));
|
||||
|
||||
var command = commands[cmd.CommandName];
|
||||
var context = (CommandContext)ServiceProvider.CreateScope().ServiceProvider.GetService(contexts[cmd.CommandName]);
|
||||
var param = ParseParams(command, cmd.Args);
|
||||
|
||||
context.Context = cmd;
|
||||
context.Client = client;
|
||||
context.TenantId = tenantId;
|
||||
await Task.FromResult(command.Invoke(context, param));
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.DebugFormat("Couldn't handle ({0}) message ({1})", msg.Text, ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class CommandContext
|
||||
{
|
||||
public ITelegramBotClient Client { get; set; }
|
||||
public TelegramCommand Context { get; set; }
|
||||
public int TenantId { get; set; }
|
||||
|
||||
protected async Task ReplyAsync(string message)
|
||||
{
|
||||
await Client.SendTextMessageAsync(Context.Chat, message);
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class ParamParser
|
||||
{
|
||||
protected Type type;
|
||||
|
||||
protected ParamParser(Type type)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public abstract object FromString(string arg);
|
||||
public abstract string ToString(object arg);
|
||||
}
|
||||
|
||||
public abstract class ParamParser<T> : ParamParser
|
||||
{
|
||||
public ParamParser() : base(typeof(T)) { }
|
||||
|
||||
public override abstract object FromString(string arg);
|
||||
public override abstract string ToString(object arg);
|
||||
}
|
||||
|
||||
public static class CommandModuleExtension
|
||||
{
|
||||
public static DIHelper AddCommandModuleService(this DIHelper services)
|
||||
{
|
||||
services.TryAddSingleton<CommandModule>();
|
||||
return services.AddUserCommandsService();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,42 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2020
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
namespace ASC.TelegramService.Core.Parsers
|
||||
{
|
||||
[ParamParser(typeof(int))]
|
||||
public class IntParser : ParamParser<int>
|
||||
{
|
||||
public override object FromString(string arg)
|
||||
{
|
||||
return int.Parse(arg);
|
||||
}
|
||||
|
||||
public override string ToString(object arg)
|
||||
{
|
||||
return arg.ToString();
|
||||
}
|
||||
}
|
||||
}
|
37
common/services/ASC.TelegramService/Core/TenantTgClient.cs
Normal file
37
common/services/ASC.TelegramService/Core/TenantTgClient.cs
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2020
|
||||
*
|
||||
* 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 Telegram.Bot;
|
||||
|
||||
namespace ASC.TelegramService.Core
|
||||
{
|
||||
public class TenantTgClient
|
||||
{
|
||||
public string Token { get; set; }
|
||||
public TelegramBotClient Client { get; set; }
|
||||
public string Proxy { get; set; }
|
||||
public int TokenLifeSpan { get; set; }
|
||||
public int TenantId { get; set; }
|
||||
}
|
||||
}
|
73
common/services/ASC.TelegramService/Program.cs
Normal file
73
common/services/ASC.TelegramService/Program.cs
Normal file
@ -0,0 +1,73 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2020
|
||||
*
|
||||
* 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.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace ASC.TelegramService
|
||||
{
|
||||
public class Program
|
||||
{
|
||||
public static async Task Main(string[] args)
|
||||
{
|
||||
Host.CreateDefaultBuilder(args)
|
||||
.ConfigureWebHostDefaults(webBuilder =>
|
||||
{
|
||||
webBuilder.UseStartup<Startup>();
|
||||
})
|
||||
.ConfigureAppConfiguration((hostContext, config) =>
|
||||
{
|
||||
var buided = config.Build();
|
||||
var path = buided["pathToConf"];
|
||||
if (!Path.IsPathRooted(path))
|
||||
{
|
||||
path = Path.GetFullPath(Path.Combine(hostContext.HostingEnvironment.ContentRootPath, path));
|
||||
}
|
||||
config.SetBasePath(path);
|
||||
var env = hostContext.Configuration.GetValue("ENVIRONMENT", "Production");
|
||||
config
|
||||
.AddInMemoryCollection(new Dictionary<string, string>
|
||||
{
|
||||
{"pathToConf", path }
|
||||
}
|
||||
)
|
||||
.AddJsonFile("appsettings.json")
|
||||
.AddJsonFile($"appsettings.{env}.json", true)
|
||||
.AddJsonFile("storage.json")
|
||||
.AddJsonFile("notify.json")
|
||||
.AddJsonFile("kafka.json")
|
||||
.AddJsonFile($"kafka.{env}.json", true)
|
||||
.AddEnvironmentVariables();
|
||||
})
|
||||
.UseConsoleLifetime()
|
||||
.Build()
|
||||
.Run();
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,35 @@
|
||||
{
|
||||
"iisSettings": {
|
||||
"windowsAuthentication": false,
|
||||
"anonymousAuthentication": true,
|
||||
"iisExpress": {
|
||||
"applicationUrl": "http://localhost:51702/",
|
||||
"sslPort": 0
|
||||
}
|
||||
},
|
||||
"profiles": {
|
||||
"IIS Express": {
|
||||
"commandName": "IISExpress",
|
||||
"launchBrowser": false,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"$STORAGE_ROOT": "../../../Data",
|
||||
"log__name": "telegram",
|
||||
"log__dir": "../../../Logs",
|
||||
"core__products__folder": "../../../products"
|
||||
}
|
||||
},
|
||||
"ASC.TelegramService": {
|
||||
"commandName": "Project",
|
||||
"launchBrowser": false,
|
||||
"environmentVariables": {
|
||||
"ASPNETCORE_ENVIRONMENT": "Development",
|
||||
"$STORAGE_ROOT": "../../../Data",
|
||||
"log__name": "telegram",
|
||||
"log__dir": "../../../Logs",
|
||||
"core__products__folder": "../../../products"
|
||||
},
|
||||
"applicationUrl": "http://localhost:51702/"
|
||||
}
|
||||
}
|
||||
}
|
60
common/services/ASC.TelegramService/Startup.cs
Normal file
60
common/services/ASC.TelegramService/Startup.cs
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2020
|
||||
*
|
||||
* 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 ASC.Api.Core;
|
||||
using ASC.Common;
|
||||
|
||||
using Autofac.Extensions.DependencyInjection;
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
using ASC.Common.DependencyInjection;
|
||||
|
||||
namespace ASC.TelegramService
|
||||
{
|
||||
public class Startup : BaseStartup
|
||||
{
|
||||
public override string[] LogParams { get => new string[] { "ASC.TelegramService" }; }
|
||||
|
||||
public Startup(IConfiguration configuration, IHostEnvironment hostEnvironment) : base(configuration, hostEnvironment)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public override void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
var diHelper = new DIHelper(services);
|
||||
|
||||
diHelper.AddTelegramLauncher();
|
||||
|
||||
services.AddHostedService<TelegramLauncher>();
|
||||
|
||||
base.ConfigureServices(services);
|
||||
|
||||
services.AddAutofac(Configuration, HostEnvironment.ContentRootPath);
|
||||
}
|
||||
}
|
||||
}
|
186
common/services/ASC.TelegramService/TelegramHandler.cs
Normal file
186
common/services/ASC.TelegramService/TelegramHandler.cs
Normal file
@ -0,0 +1,186 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2020
|
||||
*
|
||||
* 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.Collections.Generic;
|
||||
using System.Net;
|
||||
using System.Runtime.Caching;
|
||||
|
||||
using ASC.Common.Logging;
|
||||
using ASC.Core.Common.Notify.Telegram;
|
||||
using ASC.Notify.Messages;
|
||||
using ASC.TelegramService.Core;
|
||||
|
||||
using Telegram.Bot;
|
||||
using Telegram.Bot.Args;
|
||||
using ASC.Common;
|
||||
using Microsoft.Extensions.Options;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using ASC.Core.Common.Notify;
|
||||
|
||||
namespace ASC.TelegramService
|
||||
{
|
||||
public class TelegramHandler
|
||||
{
|
||||
private Dictionary<int, TenantTgClient> Clients { get; set; }
|
||||
private CommandModule Command { get; set; }
|
||||
private ILog Log { get; set; }
|
||||
private IServiceProvider ServiceProvider { get; set; }
|
||||
|
||||
public TelegramHandler(CommandModule command, IOptionsMonitor<ILog> option, IServiceProvider serviceProvider)
|
||||
{
|
||||
Command = command;
|
||||
Log = option.CurrentValue;
|
||||
ServiceProvider = serviceProvider;
|
||||
Clients = new Dictionary<int, TenantTgClient>();
|
||||
ServicePointManager.SecurityProtocol |= SecurityProtocolType.Tls12 | SecurityProtocolType.Tls13;
|
||||
}
|
||||
|
||||
public async void SendMessage(NotifyMessage msg)
|
||||
{
|
||||
var scope = ServiceProvider.CreateScope();
|
||||
var cachedTelegramDao = scope.ServiceProvider.GetService<IOptionsSnapshot<CachedTelegramDao>>().Value;
|
||||
if (string.IsNullOrEmpty(msg.To)) return;
|
||||
if (!Clients.ContainsKey(msg.Tenant)) return;
|
||||
|
||||
var client = Clients[msg.Tenant].Client;
|
||||
|
||||
try
|
||||
{
|
||||
var tgUser = cachedTelegramDao.GetUser(Guid.Parse(msg.To), msg.Tenant);
|
||||
|
||||
if (tgUser == null)
|
||||
{
|
||||
Log.DebugFormat("Couldn't find telegramId for user '{0}'", msg.To);
|
||||
return;
|
||||
}
|
||||
|
||||
var chat = await client.GetChatAsync(tgUser.TelegramUserId);
|
||||
await client.SendTextMessageAsync(chat, msg.Content, Telegram.Bot.Types.Enums.ParseMode.Markdown);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Log.DebugFormat("Couldn't send message for user '{0}' got an '{1}'", msg.To, e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
public void DisableClient(int tenantId)
|
||||
{
|
||||
if (!Clients.ContainsKey(tenantId)) return;
|
||||
|
||||
var client = Clients[tenantId];
|
||||
client.Client.StopReceiving();
|
||||
|
||||
Clients.Remove(tenantId);
|
||||
}
|
||||
|
||||
public void CreateOrUpdateClientForTenant(int tenantId, string token, int tokenLifespan, string proxy, bool startTelegramService, bool force = false)
|
||||
{
|
||||
var scope = ServiceProvider.CreateScope();
|
||||
var telegramHelper = scope.ServiceProvider.GetService<TelegramHelper>();
|
||||
var newClient = telegramHelper.InitClient(token, proxy);
|
||||
|
||||
if (Clients.ContainsKey(tenantId))
|
||||
{
|
||||
var client = Clients[tenantId];
|
||||
client.TokenLifeSpan = tokenLifespan;
|
||||
|
||||
if (token != client.Token || proxy != client.Proxy)
|
||||
{
|
||||
if (startTelegramService)
|
||||
{
|
||||
if (!telegramHelper.TestingClient(newClient)) return;
|
||||
}
|
||||
|
||||
client.Client.StopReceiving();
|
||||
|
||||
BindClient(newClient, tenantId);
|
||||
|
||||
client.Client = newClient;
|
||||
client.Token = token;
|
||||
client.Proxy = proxy;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!force && startTelegramService)
|
||||
{
|
||||
if (!telegramHelper.TestingClient(newClient)) return;
|
||||
}
|
||||
|
||||
BindClient(newClient, tenantId);
|
||||
|
||||
Clients.Add(tenantId, new TenantTgClient()
|
||||
{
|
||||
Token = token,
|
||||
Client = newClient,
|
||||
Proxy = proxy,
|
||||
TenantId = tenantId,
|
||||
TokenLifeSpan = tokenLifespan
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void RegisterUser(string userId, int tenantId, string token)
|
||||
{
|
||||
if (!Clients.ContainsKey(tenantId)) return;
|
||||
|
||||
var userKey = UserKey(userId, tenantId);
|
||||
var dateExpires = DateTimeOffset.Now.AddMinutes(Clients[tenantId].TokenLifeSpan);
|
||||
MemoryCache.Default.Set(token, userKey, dateExpires);
|
||||
}
|
||||
|
||||
|
||||
private async void OnMessage(object sender, MessageEventArgs e, TelegramBotClient client, int tenantId)
|
||||
{
|
||||
if (string.IsNullOrEmpty(e.Message.Text) || e.Message.Text[0] != '/') return;
|
||||
await Command.HandleCommand(e.Message, client, tenantId);
|
||||
}
|
||||
|
||||
|
||||
private void BindClient(TelegramBotClient client, int tenantId)
|
||||
{
|
||||
client.OnMessage += (sender, e) => { OnMessage(sender, e, client, tenantId); };
|
||||
client.StartReceiving();
|
||||
}
|
||||
|
||||
private string UserKey(string userId, int tenantId)
|
||||
{
|
||||
return string.Format("{0}:{1}", userId, tenantId);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TelegramHandlerExtension
|
||||
{
|
||||
public static DIHelper AddTelegramHandlerService(this DIHelper services)
|
||||
{
|
||||
services.TryAddSingleton<TelegramHandler>();
|
||||
return services.AddCachedTelegramDaoService()
|
||||
.AddCommandModuleService()
|
||||
.AddTelegramHelperSerivce();
|
||||
}
|
||||
}
|
||||
}
|
120
common/services/ASC.TelegramService/TelegramLauncher.cs
Normal file
120
common/services/ASC.TelegramService/TelegramLauncher.cs
Normal file
@ -0,0 +1,120 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2020
|
||||
*
|
||||
* 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.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Core;
|
||||
using ASC.Core.Common.Configuration;
|
||||
using ASC.Core.Common.Notify;
|
||||
using ASC.FederatedLogin.LoginProviders;
|
||||
using ASC.TelegramService.Commands;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Hosting;
|
||||
|
||||
namespace ASC.TelegramService
|
||||
{
|
||||
public class TelegramLauncher : IHostedService
|
||||
{
|
||||
private TelegramListener TelegramListener { get; set; }
|
||||
private IServiceProvider ServiceProvider { get; set; }
|
||||
|
||||
public TelegramLauncher(TelegramListener telegramListener, IServiceProvider serviceProvider)
|
||||
{
|
||||
TelegramListener = telegramListener;
|
||||
ServiceProvider = serviceProvider;
|
||||
}
|
||||
|
||||
public Task StartAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
Task.Run(CreateClients);
|
||||
TelegramListener.Start();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
public Task StopAsync(CancellationToken cancellationToken)
|
||||
{
|
||||
TelegramListener.Stop();
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
|
||||
private void CreateClients()
|
||||
{
|
||||
var scopeClass = ServiceProvider.CreateScope().ServiceProvider.GetService<ScopeTelegramLauncher>();
|
||||
var (tenantManager, handler, telegramLoginProvider) = scopeClass;
|
||||
var tenants = tenantManager.GetTenants();
|
||||
foreach (var tenant in tenants)
|
||||
{
|
||||
tenantManager.SetCurrentTenant(tenant);
|
||||
if (telegramLoginProvider.IsEnabled())
|
||||
{
|
||||
handler.CreateOrUpdateClientForTenant(tenant.TenantId, telegramLoginProvider.TelegramBotToken, telegramLoginProvider.TelegramAuthTokenLifespan, telegramLoginProvider.TelegramProxy, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ScopeTelegramLauncher
|
||||
{
|
||||
private TelegramHandler Handler { get; set; }
|
||||
private TenantManager TenantManager { get; set; }
|
||||
private TelegramLoginProvider TelegramLoginProvider { get; set; }
|
||||
|
||||
public ScopeTelegramLauncher(TenantManager tenantManager, TelegramHandler telegramHandler, ConsumerFactory consumerFactory)
|
||||
{
|
||||
TelegramLoginProvider = consumerFactory.Get<TelegramLoginProvider>();
|
||||
TenantManager = tenantManager;
|
||||
Handler = telegramHandler;
|
||||
}
|
||||
|
||||
public void Deconstruct(out TenantManager tenantManager, out TelegramHandler handler, out TelegramLoginProvider telegramLoginProvider)
|
||||
{
|
||||
tenantManager = TenantManager;
|
||||
handler = Handler;
|
||||
telegramLoginProvider = TelegramLoginProvider;
|
||||
}
|
||||
}
|
||||
|
||||
public static class TelegramLauncherExtension
|
||||
{
|
||||
public static DIHelper AddTelegramLauncher(this DIHelper services)
|
||||
{
|
||||
services.TryAddSingleton<TelegramLauncher>();
|
||||
services.TryAddScoped<ScopeTelegramLauncher>();
|
||||
return services.AddTelegramService()
|
||||
.AddTelegramListenerService()
|
||||
.AddTelegramHandlerService()
|
||||
.AddTenantManagerService()
|
||||
.AddTelegramLoginProviderService()
|
||||
.AddTelegramHelperSerivce()
|
||||
.AddTelegramServiceClient()
|
||||
.AddConsumerFactoryService()
|
||||
.AddUserCommandsService();
|
||||
}
|
||||
}
|
||||
}
|
102
common/services/ASC.TelegramService/TelegramListener.cs
Normal file
102
common/services/ASC.TelegramService/TelegramListener.cs
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2020
|
||||
*
|
||||
* 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 ASC.Common;
|
||||
using ASC.Common.Caching;
|
||||
using ASC.Core.Common.Notify;
|
||||
using ASC.Notify.Messages;
|
||||
|
||||
namespace ASC.TelegramService
|
||||
{
|
||||
public class TelegramListener
|
||||
{
|
||||
private ICacheNotify<NotifyMessage> CacheMessage { get; }
|
||||
private ICacheNotify<RegisterUserProto> CacheRegisterUser { get; }
|
||||
private ICacheNotify<CreateClientProto> CacheCreateClient { get; }
|
||||
private ICacheNotify<DisableClientProto> CacheDisableClient { get; }
|
||||
|
||||
private TelegramService TelegramService { get; set; }
|
||||
|
||||
public TelegramListener(ICacheNotify<NotifyMessage> cacheMessage,
|
||||
ICacheNotify<RegisterUserProto> cacheRegisterUser,
|
||||
ICacheNotify<CreateClientProto> cacheCreateClient,
|
||||
TelegramService telegramService,
|
||||
ICacheNotify<DisableClientProto> cacheDisableClient)
|
||||
{
|
||||
CacheMessage = cacheMessage;
|
||||
CacheRegisterUser = cacheRegisterUser;
|
||||
CacheCreateClient = cacheCreateClient;
|
||||
CacheDisableClient = cacheDisableClient;
|
||||
|
||||
TelegramService = telegramService;
|
||||
}
|
||||
|
||||
public void Start()
|
||||
{
|
||||
CacheMessage.Subscribe(n=> SendMessage(n), CacheNotifyAction.Insert);
|
||||
CacheRegisterUser.Subscribe(n=> RegisterUser(n), CacheNotifyAction.Insert);
|
||||
CacheCreateClient.Subscribe(n=> CreateOrUpdateClient(n), CacheNotifyAction.Insert);
|
||||
CacheDisableClient.Subscribe(n=> DisableClient(n), CacheNotifyAction.Insert);
|
||||
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
CacheMessage.Unsubscribe(CacheNotifyAction.Insert);
|
||||
CacheRegisterUser.Unsubscribe(CacheNotifyAction.Insert);
|
||||
CacheCreateClient.Unsubscribe(CacheNotifyAction.Insert);
|
||||
CacheDisableClient.Unsubscribe(CacheNotifyAction.Insert);
|
||||
}
|
||||
|
||||
private void DisableClient(DisableClientProto n)
|
||||
{
|
||||
TelegramService.DisableClient(n.TenantId);
|
||||
}
|
||||
|
||||
private void SendMessage(NotifyMessage notifyMessage)
|
||||
{
|
||||
TelegramService.SendMessage(notifyMessage);
|
||||
}
|
||||
|
||||
private void RegisterUser(RegisterUserProto registerUserProto)
|
||||
{
|
||||
TelegramService.RegisterUser(registerUserProto.UserId, registerUserProto.TenantId, registerUserProto.Token);
|
||||
}
|
||||
|
||||
private void CreateOrUpdateClient(CreateClientProto createClientProto)
|
||||
{
|
||||
TelegramService.CreateOrUpdateClient(createClientProto.TenantId, createClientProto.Token, createClientProto.TokenLifespan, createClientProto.Proxy);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TelegramListenerExtension
|
||||
{
|
||||
public static DIHelper AddTelegramListenerService(this DIHelper services)
|
||||
{
|
||||
services.TryAddSingleton<TelegramListener>();
|
||||
return services.AddTelegramService();
|
||||
}
|
||||
}
|
||||
}
|
71
common/services/ASC.TelegramService/TelegramService.cs
Normal file
71
common/services/ASC.TelegramService/TelegramService.cs
Normal file
@ -0,0 +1,71 @@
|
||||
/*
|
||||
*
|
||||
* (c) Copyright Ascensio System Limited 2010-2020
|
||||
*
|
||||
* 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 ASC.Common;
|
||||
using ASC.Core.Common.Notify;
|
||||
using ASC.Notify.Messages;
|
||||
|
||||
namespace ASC.TelegramService
|
||||
{
|
||||
public class TelegramService : ITelegramService
|
||||
{
|
||||
private TelegramHandler TelegramHandler { get; set; }
|
||||
|
||||
public TelegramService(TelegramHandler telegramHandler)
|
||||
{
|
||||
TelegramHandler = telegramHandler;
|
||||
}
|
||||
|
||||
public void SendMessage(NotifyMessage m)
|
||||
{
|
||||
TelegramHandler.SendMessage(m);
|
||||
}
|
||||
|
||||
public void RegisterUser(string userId, int tenantId, string token)
|
||||
{
|
||||
TelegramHandler.RegisterUser(userId, tenantId, token);
|
||||
}
|
||||
|
||||
public void DisableClient(int tenantId)
|
||||
{
|
||||
TelegramHandler.DisableClient(tenantId);
|
||||
}
|
||||
|
||||
public void CreateOrUpdateClient(int tenantId, string token, int tokenLifespan, string proxy)
|
||||
{
|
||||
TelegramHandler.CreateOrUpdateClientForTenant(tenantId, token, tokenLifespan, proxy, false);
|
||||
}
|
||||
}
|
||||
|
||||
public static class TelegramServiceExtension
|
||||
{
|
||||
public static DIHelper AddTelegramService(this DIHelper services)
|
||||
{
|
||||
services.TryAddSingleton<TelegramService>();
|
||||
return services.AddTelegramHandlerService();
|
||||
}
|
||||
}
|
||||
}
|
3
common/services/ASC.TelegramService/appsettings.json
Normal file
3
common/services/ASC.TelegramService/appsettings.json
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"pathToConf": "..\\..\\..\\config"
|
||||
}
|
@ -54,6 +54,7 @@
|
||||
"edited-docs" : [ ".pptx",".pptm",".ppt",".ppsx",".ppsm",".pps",".potx",".potm",".pot",".odp",".fodp",".otp",".xlsx",".xlsm",".xls",".xltx",".xltm",".xlt",".ods",".fods",".ots",".csv",".docx",".docm",".doc",".dotx",".dotm",".dot",".odt",".fodt",".ott",".txt",".rtf",".mht",".html",".htm" ],
|
||||
"encrypted-docs" : [ ".docx",".xlsx",".pptx" ],
|
||||
"formfilling-docs" : [ ".docx" ],
|
||||
"customfilter-docs": [ ".xlsx" ],
|
||||
"reviewed-docs" : [ ".docx" ],
|
||||
"viewed-docs" : [ ".pptx",".pptm",".ppt",".ppsx",".ppsm",".pps",".potx",".potm",".pot",".odp",".fodp",".otp",".gslides",".xlsx",".xlsm",".xls",".xltx",".xltm",".xlt",".ods",".fods",".ots",".gsheet",".csv",".docx",".docm",".doc",".dotx",".dotm",".dot",".odt",".fodt",".ott",".gdoc",".txt",".rtf",".mht",".html",".htm",".epub",".pdf",".djvu",".xps" ],
|
||||
"secret" :
|
||||
@ -63,7 +64,7 @@
|
||||
},
|
||||
"url":
|
||||
{
|
||||
"public": "http://192.168.3.142/",
|
||||
"public": "http://192.168.0.142/",
|
||||
"internal": "",
|
||||
"portal": ""
|
||||
}
|
||||
|
@ -30,6 +30,38 @@
|
||||
"bitlyUrl" : "https://api-ssl.bitly.com/v3/shorten?format=xml&login={0}&apiKey={1}&longUrl={2}"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ASC.FederatedLogin.LoginProviders.TelegramLoginProvider, ASC.FederatedLogin",
|
||||
"services": [
|
||||
{
|
||||
"type": "ASC.Core.Common.Configuration.Consumer, ASC.Core.Common"
|
||||
},
|
||||
{
|
||||
"type": "ASC.FederatedLogin.LoginProviders.TelegramLoginProvider, ASC.FederatedLogin"
|
||||
},
|
||||
{
|
||||
"key": "Telegram",
|
||||
"type": "ASC.Core.Common.Configuration.Consumer, ASC.Core.Common"
|
||||
},
|
||||
{
|
||||
"key": "Telegram",
|
||||
"type": "ASC.FederatedLogin.LoginProviders.TelegramLoginProvider, ASC.FederatedLogin"
|
||||
}
|
||||
],
|
||||
"instanceScope": "perlifetimescope",
|
||||
"parameters": {
|
||||
"name": "Telegram",
|
||||
"order": "13",
|
||||
"props": {
|
||||
"telegramBotToken": "",
|
||||
"telegramBotName": ""
|
||||
},
|
||||
"additional": {
|
||||
"telegramAuthTokenLifespan" : 20,
|
||||
"telegramProxy": ""
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "ASC.FederatedLogin.LoginProviders.BoxLoginProvider, ASC.FederatedLogin",
|
||||
@ -613,7 +645,12 @@
|
||||
"additional": {
|
||||
"handlerType" : "ASC.Data.Storage.S3.S3Storage, ASC.Data.Storage",
|
||||
"bucket" : "",
|
||||
"region" : ""
|
||||
"region" : "",
|
||||
"serviceurl": "",
|
||||
"forcepathstyle": "",
|
||||
"usehttp": "",
|
||||
"sse": "",
|
||||
"cdn": "S3Cdn"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -68,7 +68,17 @@ namespace ASC.Web.Files.Classes
|
||||
public bool ForcesaveSetting { get; set; }
|
||||
|
||||
[JsonPropertyName("StoreForcesave")]
|
||||
public bool StoreForcesaveSetting { get; set; }
|
||||
public bool StoreForcesaveSetting { get; set; }
|
||||
|
||||
[JsonPropertyName("HideRecent")]
|
||||
public bool HideRecentSetting { get; set; }
|
||||
|
||||
[JsonPropertyName("HideFavorites")]
|
||||
public bool HideFavoritesSetting { get; set; }
|
||||
|
||||
[JsonPropertyName("HideTemplates")]
|
||||
public bool HideTemplatesSetting { get; set; }
|
||||
|
||||
|
||||
public ISettings GetDefault(IServiceProvider serviceProvider)
|
||||
{
|
||||
@ -84,7 +94,10 @@ namespace ASC.Web.Files.Classes
|
||||
HideConfirmConvertSaveSetting = false,
|
||||
HideConfirmConvertOpenSetting = false,
|
||||
ForcesaveSetting = false,
|
||||
StoreForcesaveSetting = false
|
||||
StoreForcesaveSetting = false,
|
||||
HideRecentSetting = false,
|
||||
HideFavoritesSetting = false,
|
||||
HideTemplatesSetting = false
|
||||
};
|
||||
}
|
||||
|
||||
@ -109,11 +122,11 @@ namespace ASC.Web.Files.Classes
|
||||
{
|
||||
set
|
||||
{
|
||||
var setting = SettingsManager.LoadForCurrentUser<FilesSettings>();
|
||||
var setting = LoadForCurrentUser();
|
||||
setting.FastDeleteSetting = !value;
|
||||
SettingsManager.SaveForCurrentUser(setting);
|
||||
SaveForCurrentUser(setting);
|
||||
}
|
||||
get { return !SettingsManager.LoadForCurrentUser<FilesSettings>().FastDeleteSetting; }
|
||||
get { return !LoadForCurrentUser().FastDeleteSetting; }
|
||||
}
|
||||
|
||||
public bool EnableThirdParty
|
||||
@ -131,69 +144,69 @@ namespace ASC.Web.Files.Classes
|
||||
{
|
||||
set
|
||||
{
|
||||
var setting = SettingsManager.LoadForCurrentUser<FilesSettings>();
|
||||
var setting = LoadForCurrentUser();
|
||||
setting.StoreOriginalFilesSetting = value;
|
||||
SettingsManager.SaveForCurrentUser(setting);
|
||||
SaveForCurrentUser(setting);
|
||||
}
|
||||
get { return SettingsManager.LoadForCurrentUser<FilesSettings>().StoreOriginalFilesSetting; }
|
||||
get { return LoadForCurrentUser().StoreOriginalFilesSetting; }
|
||||
}
|
||||
|
||||
public bool UpdateIfExist
|
||||
{
|
||||
set
|
||||
{
|
||||
var setting = SettingsManager.LoadForCurrentUser<FilesSettings>();
|
||||
var setting = LoadForCurrentUser();
|
||||
setting.UpdateIfExistSetting = value;
|
||||
SettingsManager.SaveForCurrentUser(setting);
|
||||
SaveForCurrentUser(setting);
|
||||
}
|
||||
get { return SettingsManager.LoadForCurrentUser<FilesSettings>().UpdateIfExistSetting; }
|
||||
get { return LoadForCurrentUser().UpdateIfExistSetting; }
|
||||
}
|
||||
|
||||
public bool ConvertNotify
|
||||
{
|
||||
set
|
||||
{
|
||||
var setting = SettingsManager.LoadForCurrentUser<FilesSettings>();
|
||||
var setting = LoadForCurrentUser();
|
||||
setting.ConvertNotifySetting = value;
|
||||
SettingsManager.SaveForCurrentUser(setting);
|
||||
SaveForCurrentUser(setting);
|
||||
}
|
||||
get { return SettingsManager.LoadForCurrentUser<FilesSettings>().ConvertNotifySetting; }
|
||||
get { return LoadForCurrentUser().ConvertNotifySetting; }
|
||||
}
|
||||
|
||||
public bool HideConfirmConvertSave
|
||||
{
|
||||
set
|
||||
{
|
||||
var setting = SettingsManager.LoadForCurrentUser<FilesSettings>();
|
||||
var setting = LoadForCurrentUser();
|
||||
setting.HideConfirmConvertSaveSetting = value;
|
||||
SettingsManager.SaveForCurrentUser(setting);
|
||||
SaveForCurrentUser(setting);
|
||||
}
|
||||
get { return SettingsManager.LoadForCurrentUser<FilesSettings>().HideConfirmConvertSaveSetting; }
|
||||
get { return LoadForCurrentUser().HideConfirmConvertSaveSetting; }
|
||||
}
|
||||
|
||||
public bool HideConfirmConvertOpen
|
||||
{
|
||||
set
|
||||
{
|
||||
var setting = SettingsManager.LoadForCurrentUser<FilesSettings>();
|
||||
var setting = LoadForCurrentUser();
|
||||
setting.HideConfirmConvertOpenSetting = value;
|
||||
SettingsManager.SaveForCurrentUser(setting);
|
||||
SaveForCurrentUser(setting);
|
||||
}
|
||||
get { return SettingsManager.LoadForCurrentUser<FilesSettings>().HideConfirmConvertOpenSetting; }
|
||||
get { return LoadForCurrentUser().HideConfirmConvertOpenSetting; }
|
||||
}
|
||||
|
||||
public OrderBy DefaultOrder
|
||||
{
|
||||
set
|
||||
{
|
||||
var setting = SettingsManager.LoadForCurrentUser<FilesSettings>();
|
||||
var setting = LoadForCurrentUser();
|
||||
setting.DefaultSortedBySetting = value.SortedBy;
|
||||
setting.DefaultSortedAscSetting = value.IsAsc;
|
||||
SettingsManager.SaveForCurrentUser(setting);
|
||||
SaveForCurrentUser(setting);
|
||||
}
|
||||
get
|
||||
{
|
||||
var setting = SettingsManager.LoadForCurrentUser<FilesSettings>();
|
||||
var setting = LoadForCurrentUser();
|
||||
return new OrderBy(setting.DefaultSortedBySetting, setting.DefaultSortedAscSetting);
|
||||
}
|
||||
}
|
||||
@ -202,11 +215,11 @@ namespace ASC.Web.Files.Classes
|
||||
{
|
||||
set
|
||||
{
|
||||
var setting = SettingsManager.LoadForCurrentUser<FilesSettings>();
|
||||
var setting = LoadForCurrentUser();
|
||||
setting.ForcesaveSetting = value;
|
||||
SettingsManager.SaveForCurrentUser(setting);
|
||||
SaveForCurrentUser(setting);
|
||||
}
|
||||
get { return SettingsManager.LoadForCurrentUser<FilesSettings>().ForcesaveSetting; }
|
||||
get { return LoadForCurrentUser().ForcesaveSetting; }
|
||||
}
|
||||
|
||||
public bool StoreForcesave
|
||||
@ -219,8 +232,52 @@ namespace ASC.Web.Files.Classes
|
||||
SettingsManager.Save(setting);
|
||||
}
|
||||
get { return !CoreBaseSettings.Personal && SettingsManager.Load<FilesSettings>().StoreForcesaveSetting; }
|
||||
}
|
||||
|
||||
public bool RecentSection
|
||||
{
|
||||
set
|
||||
{
|
||||
var setting = LoadForCurrentUser();
|
||||
setting.HideRecentSetting = !value;
|
||||
SaveForCurrentUser(setting);
|
||||
}
|
||||
get { return !LoadForCurrentUser().HideRecentSetting; }
|
||||
}
|
||||
|
||||
public bool FavoritesSection
|
||||
{
|
||||
set
|
||||
{
|
||||
var setting = LoadForCurrentUser();
|
||||
setting.HideFavoritesSetting = !value;
|
||||
SaveForCurrentUser(setting);
|
||||
}
|
||||
get { return !LoadForCurrentUser().HideFavoritesSetting; }
|
||||
}
|
||||
|
||||
public bool TemplatesSection
|
||||
{
|
||||
set
|
||||
{
|
||||
var setting = LoadForCurrentUser();
|
||||
setting.HideTemplatesSetting = !value;
|
||||
SaveForCurrentUser(setting);
|
||||
}
|
||||
get { return !LoadForCurrentUser().HideTemplatesSetting; }
|
||||
}
|
||||
|
||||
private FilesSettings LoadForCurrentUser()
|
||||
{
|
||||
return SettingsManager.LoadForCurrentUser<FilesSettings>();
|
||||
}
|
||||
|
||||
private void SaveForCurrentUser(FilesSettings settings)
|
||||
{
|
||||
_ = SettingsManager.SaveForCurrentUser(settings);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class FilesSettingsHelperExtention
|
||||
{
|
||||
public static DIHelper AddFilesSettingsHelperService(this DIHelper services)
|
||||
|
@ -1,148 +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.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
using ASC.Common;
|
||||
using ASC.Core;
|
||||
using ASC.Core.Common.EF;
|
||||
using ASC.Core.Common.Settings;
|
||||
using ASC.Core.Tenants;
|
||||
using ASC.Files.Core.EF;
|
||||
using ASC.Web.Files.Core.Entries;
|
||||
using ASC.Web.Studio.Core;
|
||||
using ASC.Web.Studio.UserControls.Statistics;
|
||||
using ASC.Web.Studio.Utility;
|
||||
|
||||
namespace ASC.Files.Core.Data
|
||||
{
|
||||
public class EncryptedDataDao : AbstractDao
|
||||
{
|
||||
private static readonly object SyncRoot = new object();
|
||||
|
||||
public EncryptedDataDao(
|
||||
DbContextManager<FilesDbContext> dbContextManager,
|
||||
UserManager userManager,
|
||||
TenantManager tenantManager,
|
||||
TenantUtil tenantUtil,
|
||||
SetupInfo setupInfo,
|
||||
TenantExtra tenantExtra,
|
||||
TenantStatisticsProvider tenantStatisticProvider,
|
||||
CoreBaseSettings coreBaseSettings,
|
||||
CoreConfiguration coreConfiguration,
|
||||
SettingsManager settingsManager,
|
||||
AuthContext authContext,
|
||||
IServiceProvider serviceProvider
|
||||
)
|
||||
: base(dbContextManager,
|
||||
userManager,
|
||||
tenantManager,
|
||||
tenantUtil,
|
||||
setupInfo,
|
||||
tenantExtra,
|
||||
tenantStatisticProvider,
|
||||
coreBaseSettings,
|
||||
coreConfiguration,
|
||||
settingsManager,
|
||||
authContext,
|
||||
serviceProvider)
|
||||
{
|
||||
}
|
||||
|
||||
public bool SaveEncryptedData(IEnumerable<EncryptedData> ecnryptedDatas)
|
||||
{
|
||||
if (ecnryptedDatas == null)
|
||||
{
|
||||
throw new ArgumentNullException("ecnryptedDatas");
|
||||
}
|
||||
|
||||
lock (SyncRoot)
|
||||
{
|
||||
using var tx = FilesDbContext.Database.BeginTransaction();
|
||||
foreach (var test in ecnryptedDatas)
|
||||
{
|
||||
if (string.IsNullOrEmpty(test.PublicKey)
|
||||
|| string.IsNullOrEmpty(test.FileHash)
|
||||
|| string.IsNullOrEmpty(test.Data))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
var encryptedData = new DbEncryptedData
|
||||
{
|
||||
PublicKey = test.PublicKey,
|
||||
FileHash = test.FileHash,
|
||||
Data = test.Data
|
||||
};
|
||||
|
||||
FilesDbContext.AddOrUpdate(r => r.EncryptedData, encryptedData);
|
||||
}
|
||||
|
||||
tx.Commit();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public string GetData(string publicKey, string fileHash)
|
||||
{
|
||||
if (string.IsNullOrEmpty(publicKey)) throw new ArgumentException("publicKey is empty", "publicKey");
|
||||
if (string.IsNullOrEmpty(fileHash)) throw new ArgumentException("fileHash is empty", "hash");
|
||||
|
||||
lock (SyncRoot)
|
||||
{
|
||||
return FilesDbContext.EncryptedData
|
||||
.Where(r => r.PublicKey == publicKey)
|
||||
.Where(r => r.FileHash == fileHash)
|
||||
.Select(r => r.Data)
|
||||
.SingleOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
public static class EncryptedDataDaoExtention
|
||||
{
|
||||
public static DIHelper AddEncryptedDataDaoService(this DIHelper services)
|
||||
{
|
||||
if (services.TryAddScoped<EncryptedDataDao>())
|
||||
{
|
||||
return services
|
||||
.AddFilesDbContextService()
|
||||
.AddUserManagerService()
|
||||
.AddTenantManagerService()
|
||||
.AddTenantUtilService()
|
||||
.AddSetupInfo()
|
||||
.AddTenantExtraService()
|
||||
.AddTenantStatisticsProviderService()
|
||||
.AddCoreBaseSettingsService()
|
||||
.AddCoreConfigurationService()
|
||||
.AddSettingsManagerService()
|
||||
.AddAuthContextService();
|
||||
}
|
||||
|
||||
return services;
|
||||
}
|
||||
}
|
||||
}
|
@ -97,7 +97,7 @@ namespace ASC.Files.Core
|
||||
/// <param name="searchText"></param>
|
||||
/// <param name="searchInContent"></param>
|
||||
/// <returns></returns>
|
||||
List<File<T>> GetFilesForShare(T[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent);
|
||||
List<File<T>> GetFilesFiltered(T[] fileIds, FilterType filterType, bool subjectGroup, Guid subjectID, string searchText, bool searchInContent);
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
|
@ -258,7 +258,41 @@ namespace ASC.Files.Core
|
||||
/// </summary>
|
||||
/// <param name="createIfNotExists"></param>
|
||||
/// <returns></returns>
|
||||
T GetFolderIDShare(bool createIfNotExists);
|
||||
T GetFolderIDShare(bool createIfNotExists);
|
||||
|
||||
/// <summary>
|
||||
/// Returns id folder "Recent"
|
||||
/// Only in TMFolderDao
|
||||
/// </summary>
|
||||
/// <param name="createIfNotExists"></param>
|
||||
/// <returns></returns>
|
||||
T GetFolderIDRecent(bool createIfNotExists);
|
||||
|
||||
/// <summary>
|
||||
|
||||
/// <summary>
|
||||
/// Returns id folder "Favorites"
|
||||
/// Only in TMFolderDao
|
||||
/// </summary>
|
||||
/// <param name="createIfNotExists"></param>
|
||||
/// <returns></returns>
|
||||
T GetFolderIDFavorites(bool createIfNotExists);
|
||||
|
||||
/// <summary>
|
||||
/// Returns id folder "Templates"
|
||||
/// Only in TMFolderDao
|
||||
/// </summary>
|
||||
/// <param name="createIfNotExists"></param>
|
||||
/// <returns></returns>
|
||||
T GetFolderIDTemplates(bool createIfNotExists);
|
||||
|
||||
/// <summary>
|
||||
/// Returns id folder "Privacy"
|
||||
/// Only in TMFolderDao
|
||||
/// </summary>
|
||||
/// <param name="createIfNotExists"></param>
|
||||
/// <returns></returns>
|
||||
T GetFolderIDPrivacy(bool createIfNotExists, Guid? userId = null);
|
||||
|
||||
/// <summary>
|
||||
/// Returns id folder "Trash"
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user