1
0
mirror of https://github.com/bitwarden/server.git synced 2025-07-01 08:02:49 -05:00

[EC-243] Grant premium status when member accepts org invite (#2043)

This commit is contained in:
Thomas Rittson
2022-06-17 06:30:50 +10:00
committed by GitHub
parent b2a0aa2860
commit 3360d40592
7 changed files with 73 additions and 14 deletions

View File

@ -441,7 +441,7 @@ namespace Bit.Api.Controllers
await _providerUserRepository.GetManyOrganizationDetailsByUserAsync(user.Id,
ProviderUserStatusType.Confirmed);
var response = new ProfileResponseModel(user, organizationUserDetails, providerUserDetails,
providerUserOrganizationDetails, await _userService.TwoFactorIsEnabledAsync(user));
providerUserOrganizationDetails, await _userService.TwoFactorIsEnabledAsync(user), await _userService.HasPremiumFromOrganization(user));
return response;
}
@ -466,7 +466,7 @@ namespace Bit.Api.Controllers
}
await _userService.SaveUserAsync(model.ToUser(user));
var response = new ProfileResponseModel(user, null, null, null, await _userService.TwoFactorIsEnabledAsync(user));
var response = new ProfileResponseModel(user, null, null, null, await _userService.TwoFactorIsEnabledAsync(user), await _userService.HasPremiumFromOrganization(user));
return response;
}
@ -617,7 +617,7 @@ namespace Bit.Api.Controllers
BillingAddressCountry = model.Country,
BillingAddressPostalCode = model.PostalCode,
});
var profile = new ProfileResponseModel(user, null, null, null, await _userService.TwoFactorIsEnabledAsync(user));
var profile = new ProfileResponseModel(user, null, null, null, await _userService.TwoFactorIsEnabledAsync(user), await _userService.HasPremiumFromOrganization(user));
return new PaymentResponseModel
{
UserProfile = profile,

View File

@ -88,7 +88,8 @@ namespace Bit.Api.Controllers
}
var userTwoFactorEnabled = await _userService.TwoFactorIsEnabledAsync(user);
var response = new SyncResponseModel(_globalSettings, user, userTwoFactorEnabled, organizationUserDetails,
var userHasPremiumFromOrganization = await _userService.HasPremiumFromOrganization(user);
var response = new SyncResponseModel(_globalSettings, user, userTwoFactorEnabled, userHasPremiumFromOrganization, organizationUserDetails,
providerUserDetails, providerUserOrganizationDetails, folders, collections, ciphers,
collectionCiphersGroupDict, excludeDomains, policies, sends);
return response;

View File

@ -15,7 +15,8 @@ namespace Bit.Api.Models.Response
IEnumerable<OrganizationUserOrganizationDetails> organizationsUserDetails,
IEnumerable<ProviderUserProviderDetails> providerUserDetails,
IEnumerable<ProviderUserOrganizationDetails> providerUserOrganizationDetails,
bool twoFactorEnabled) : base("profile")
bool twoFactorEnabled,
bool premiumFromOrganization) : base("profile")
{
if (user == null)
{
@ -27,6 +28,7 @@ namespace Bit.Api.Models.Response
Email = user.Email;
EmailVerified = user.EmailVerified;
Premium = user.Premium;
PremiumFromOrganization = premiumFromOrganization;
MasterPasswordHint = string.IsNullOrWhiteSpace(user.MasterPasswordHint) ? null : user.MasterPasswordHint;
Culture = user.Culture;
TwoFactorEnabled = twoFactorEnabled;
@ -46,6 +48,7 @@ namespace Bit.Api.Models.Response
public string Email { get; set; }
public bool EmailVerified { get; set; }
public bool Premium { get; set; }
public bool PremiumFromOrganization { get; set; }
public string MasterPasswordHint { get; set; }
public string Culture { get; set; }
public bool TwoFactorEnabled { get; set; }

View File

@ -16,6 +16,7 @@ namespace Bit.Api.Models.Response
GlobalSettings globalSettings,
User user,
bool userTwoFactorEnabled,
bool userHasPremiumFromOrganization,
IEnumerable<OrganizationUserOrganizationDetails> organizationUserDetails,
IEnumerable<ProviderUserProviderDetails> providerUserDetails,
IEnumerable<ProviderUserOrganizationDetails> providerUserOrganizationDetails,
@ -29,7 +30,7 @@ namespace Bit.Api.Models.Response
: base("sync")
{
Profile = new ProfileResponseModel(user, organizationUserDetails, providerUserDetails,
providerUserOrganizationDetails, userTwoFactorEnabled);
providerUserOrganizationDetails, userTwoFactorEnabled, userHasPremiumFromOrganization);
Folders = folders.Select(f => new FolderResponseModel(f));
Ciphers = ciphers.Select(c => new CipherDetailsResponseModel(c, globalSettings, collectionCiphersDict));
Collections = collections?.Select(

View File

@ -70,6 +70,7 @@ namespace Bit.Core.Services
int? version = null);
Task<bool> CheckPasswordAsync(User user, string password);
Task<bool> CanAccessPremium(ITwoFactorProvidersUser user);
Task<bool> HasPremiumFromOrganization(ITwoFactorProvidersUser user);
Task<bool> TwoFactorIsEnabledAsync(ITwoFactorProvidersUser user);
Task<bool> TwoFactorProviderIsEnabledAsync(TwoFactorProviderType provider, ITwoFactorProvidersUser user);
Task<string> GenerateSignInTokenAsync(User user, string purpose);

View File

@ -1263,18 +1263,32 @@ namespace Bit.Core.Services
{
return false;
}
if (user.GetPremium())
{
return true;
}
var orgs = await _currentContext.OrganizationMembershipAsync(_organizationUserRepository, userId.Value);
if (!orgs.Any())
return user.GetPremium() || await this.HasPremiumFromOrganization(user);
}
public async Task<bool> HasPremiumFromOrganization(ITwoFactorProvidersUser user)
{
var userId = user.GetUserId();
if (!userId.HasValue)
{
return false;
}
// orgUsers in the Invited status are not associated with a userId yet, so this will get
// orgUsers in Accepted and Confirmed states only
var orgUsers = await _organizationUserRepository.GetManyByUserAsync(userId.Value);
if (!orgUsers.Any())
{
return false;
}
var orgAbilities = await _applicationCacheService.GetOrganizationAbilitiesAsync();
return orgs.Any(o => orgAbilities.ContainsKey(o.Id) &&
orgAbilities[o.Id].UsersGetPremium && orgAbilities[o.Id].Enabled);
return orgUsers.Any(ou =>
orgAbilities.TryGetValue(ou.OrganizationId, out var orgAbility) &&
orgAbility.UsersGetPremium &&
orgAbility.Enabled);
}
public async Task<bool> TwoFactorIsEnabledAsync(ITwoFactorProvidersUser user)