mirror of
https://github.com/bitwarden/server.git
synced 2024-12-24 17:17:40 +01:00
equivalent domains APIs and data models
This commit is contained in:
parent
90607f6d93
commit
7abde8c771
@ -157,6 +157,13 @@ namespace Bit.Api.Controllers
|
|||||||
return Task.FromResult(response);
|
return Task.FromResult(response);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpGet("domains")]
|
||||||
|
public Task<DomainsResponseModel> GetDomains()
|
||||||
|
{
|
||||||
|
var response = new DomainsResponseModel(_currentContext.User);
|
||||||
|
return Task.FromResult(response);
|
||||||
|
}
|
||||||
|
|
||||||
[HttpPut("profile")]
|
[HttpPut("profile")]
|
||||||
[HttpPost("profile")]
|
[HttpPost("profile")]
|
||||||
public async Task<ProfileResponseModel> PutProfile([FromBody]UpdateProfileRequestModel model)
|
public async Task<ProfileResponseModel> PutProfile([FromBody]UpdateProfileRequestModel model)
|
||||||
@ -167,8 +174,18 @@ namespace Bit.Api.Controllers
|
|||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[HttpPut("domains")]
|
||||||
|
[HttpPost("domains")]
|
||||||
|
public async Task<DomainsResponseModel> PutDomains([FromBody]UpdateDomainsRequestModel model)
|
||||||
|
{
|
||||||
|
await _userService.SaveUserAsync(model.ToUser(_currentContext.User));
|
||||||
|
|
||||||
|
var response = new DomainsResponseModel(_currentContext.User);
|
||||||
|
return response;
|
||||||
|
}
|
||||||
|
|
||||||
[HttpGet("two-factor")]
|
[HttpGet("two-factor")]
|
||||||
public async Task<TwoFactorResponseModel> GetTwoFactor(string masterPasswordHash, TwoFactorProvider provider)
|
public async Task<TwoFactorResponseModel> GetTwoFactor(string masterPasswordHash, TwoFactorProviderType provider)
|
||||||
{
|
{
|
||||||
var user = _currentContext.User;
|
var user = _currentContext.User;
|
||||||
if(!await _userManager.CheckPasswordAsync(user, masterPasswordHash))
|
if(!await _userManager.CheckPasswordAsync(user, masterPasswordHash))
|
||||||
@ -200,7 +217,7 @@ namespace Bit.Api.Controllers
|
|||||||
throw new BadRequestException("Token", "Invalid token.");
|
throw new BadRequestException("Token", "Invalid token.");
|
||||||
}
|
}
|
||||||
|
|
||||||
user.TwoFactorProvider = TwoFactorProvider.Authenticator;
|
user.TwoFactorProvider = TwoFactorProviderType.Authenticator;
|
||||||
user.TwoFactorEnabled = model.Enabled.Value;
|
user.TwoFactorEnabled = model.Enabled.Value;
|
||||||
user.TwoFactorRecoveryCode = user.TwoFactorEnabled ? Guid.NewGuid().ToString("N") : null;
|
user.TwoFactorRecoveryCode = user.TwoFactorEnabled ? Guid.NewGuid().ToString("N") : null;
|
||||||
await _userService.SaveUserAsync(user);
|
await _userService.SaveUserAsync(user);
|
||||||
|
@ -14,7 +14,7 @@ using Bit.Core.Services;
|
|||||||
namespace Bit.Api.Controllers
|
namespace Bit.Api.Controllers
|
||||||
{
|
{
|
||||||
[Route("logins")]
|
[Route("logins")]
|
||||||
// sites route is deprecated
|
// "sites" route is deprecated
|
||||||
[Route("sites")]
|
[Route("sites")]
|
||||||
[Authorize("Application")]
|
[Authorize("Application")]
|
||||||
public class LoginsController : Controller
|
public class LoginsController : Controller
|
||||||
|
21
src/Api/Models/Request/Accounts/UpdateDomainsRequestModel.cs
Normal file
21
src/Api/Models/Request/Accounts/UpdateDomainsRequestModel.cs
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
using Bit.Core.Domains;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
|
||||||
|
namespace Bit.Api.Models
|
||||||
|
{
|
||||||
|
public class UpdateDomainsRequestModel
|
||||||
|
{
|
||||||
|
public IEnumerable<IEnumerable<string>> EquivalentDomains { get; set; }
|
||||||
|
public IEnumerable<GlobalEquivalentDomainsType> ExcludedGlobalEquivalentDomains { get; set; }
|
||||||
|
|
||||||
|
public User ToUser(User existingUser)
|
||||||
|
{
|
||||||
|
existingUser.EquivalentDomains = EquivalentDomains != null ? JsonConvert.SerializeObject(EquivalentDomains) : null;
|
||||||
|
existingUser.ExcludedGlobalEquivalentDomains = ExcludedGlobalEquivalentDomains != null ?
|
||||||
|
JsonConvert.SerializeObject(ExcludedGlobalEquivalentDomains) : null;
|
||||||
|
return existingUser;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
30
src/Api/Models/Response/DomainsResponseModel.cs
Normal file
30
src/Api/Models/Response/DomainsResponseModel.cs
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
using System;
|
||||||
|
using Bit.Core.Domains;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using Bit.Core.Enums;
|
||||||
|
|
||||||
|
namespace Bit.Api.Models
|
||||||
|
{
|
||||||
|
public class DomainsResponseModel : ResponseModel
|
||||||
|
{
|
||||||
|
public DomainsResponseModel(User user)
|
||||||
|
: base("domains")
|
||||||
|
{
|
||||||
|
if(user == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(user));
|
||||||
|
}
|
||||||
|
|
||||||
|
EquivalentDomains = user.EquivalentDomains != null ?
|
||||||
|
JsonConvert.DeserializeObject<List<List<string>>>(user.EquivalentDomains) : null;
|
||||||
|
GlobalEquivalentDomains = Core.Utilities.EquivalentDomains.Global;
|
||||||
|
ExcludedGlobalEquivalentDomains = user.ExcludedGlobalEquivalentDomains != null ?
|
||||||
|
JsonConvert.DeserializeObject<List<GlobalEquivalentDomainsType>>(user.ExcludedGlobalEquivalentDomains) : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<IEnumerable<string>> EquivalentDomains { get; set; }
|
||||||
|
public IDictionary<GlobalEquivalentDomainsType, IEnumerable<string>> GlobalEquivalentDomains { get; set; }
|
||||||
|
public IEnumerable<GlobalEquivalentDomainsType> ExcludedGlobalEquivalentDomains { get; set; }
|
||||||
|
}
|
||||||
|
}
|
@ -21,7 +21,7 @@ namespace Bit.Api.Models
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool TwoFactorEnabled { get; set; }
|
public bool TwoFactorEnabled { get; set; }
|
||||||
public TwoFactorProvider? TwoFactorProvider { get; set; }
|
public TwoFactorProviderType? TwoFactorProvider { get; set; }
|
||||||
public string AuthenticatorKey { get; set; }
|
public string AuthenticatorKey { get; set; }
|
||||||
public string TwoFactorRecoveryCode { get; set; }
|
public string TwoFactorRecoveryCode { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -15,9 +15,11 @@ namespace Bit.Core.Domains
|
|||||||
public string Culture { get; set; } = "en-US";
|
public string Culture { get; set; } = "en-US";
|
||||||
public string SecurityStamp { get; set; }
|
public string SecurityStamp { get; set; }
|
||||||
public bool TwoFactorEnabled { get; set; }
|
public bool TwoFactorEnabled { get; set; }
|
||||||
public TwoFactorProvider? TwoFactorProvider { get; set; }
|
public TwoFactorProviderType? TwoFactorProvider { get; set; }
|
||||||
public string AuthenticatorKey { get; set; }
|
public string AuthenticatorKey { get; set; }
|
||||||
public string TwoFactorRecoveryCode { get; set; }
|
public string TwoFactorRecoveryCode { get; set; }
|
||||||
|
public string EquivalentDomains { get; set; }
|
||||||
|
public string ExcludedGlobalEquivalentDomains { get; set; }
|
||||||
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
|
public DateTime CreationDate { get; internal set; } = DateTime.UtcNow;
|
||||||
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
|
public DateTime RevisionDate { get; internal set; } = DateTime.UtcNow;
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Bit.Core.Enums
|
namespace Bit.Core.Enums
|
||||||
{
|
{
|
||||||
public enum CipherType : short
|
public enum CipherType : byte
|
||||||
{
|
{
|
||||||
Folder = 0,
|
Folder = 0,
|
||||||
Login = 1
|
Login = 1
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Bit.Core.Enums
|
namespace Bit.Core.Enums
|
||||||
{
|
{
|
||||||
public enum DeviceType : short
|
public enum DeviceType : byte
|
||||||
{
|
{
|
||||||
Android = 0,
|
Android = 0,
|
||||||
iOS = 1
|
iOS = 1
|
||||||
|
8
src/Core/Enums/GlobalEquivalentDomainsType.cs
Normal file
8
src/Core/Enums/GlobalEquivalentDomainsType.cs
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
namespace Bit.Core.Enums
|
||||||
|
{
|
||||||
|
public enum GlobalEquivalentDomainsType : byte
|
||||||
|
{
|
||||||
|
Google = 0,
|
||||||
|
Apple = 1
|
||||||
|
}
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
namespace Bit.Core.Enums
|
namespace Bit.Core.Enums
|
||||||
{
|
{
|
||||||
public enum PushType : short
|
public enum PushType : byte
|
||||||
{
|
{
|
||||||
SyncCipherUpdate = 0,
|
SyncCipherUpdate = 0,
|
||||||
SyncCipherCreate = 1,
|
SyncCipherCreate = 1,
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
namespace Bit.Core.Enums
|
namespace Bit.Core.Enums
|
||||||
{
|
{
|
||||||
public enum TwoFactorProvider
|
public enum TwoFactorProviderType : byte
|
||||||
{
|
{
|
||||||
Authenticator = 0
|
Authenticator = 0
|
||||||
}
|
}
|
@ -14,7 +14,7 @@ namespace Bit.Core.Identity
|
|||||||
{
|
{
|
||||||
var canGenerate = user.TwoFactorEnabled
|
var canGenerate = user.TwoFactorEnabled
|
||||||
&& user.TwoFactorProvider.HasValue
|
&& user.TwoFactorProvider.HasValue
|
||||||
&& user.TwoFactorProvider.Value == TwoFactorProvider.Authenticator
|
&& user.TwoFactorProvider.Value == TwoFactorProviderType.Authenticator
|
||||||
&& !string.IsNullOrWhiteSpace(user.AuthenticatorKey);
|
&& !string.IsNullOrWhiteSpace(user.AuthenticatorKey);
|
||||||
|
|
||||||
return Task.FromResult(canGenerate);
|
return Task.FromResult(canGenerate);
|
||||||
|
@ -16,7 +16,7 @@ namespace Bit.Core.Services
|
|||||||
Task<IdentityResult> ChangeEmailAsync(User user, string masterPassword, string newEmail, string newMasterPassword, string token, IEnumerable<Cipher> ciphers);
|
Task<IdentityResult> ChangeEmailAsync(User user, string masterPassword, string newEmail, string newMasterPassword, string token, IEnumerable<Cipher> ciphers);
|
||||||
Task<IdentityResult> ChangePasswordAsync(User user, string currentMasterPasswordHash, string newMasterPasswordHash, IEnumerable<Cipher> ciphers);
|
Task<IdentityResult> ChangePasswordAsync(User user, string currentMasterPasswordHash, string newMasterPasswordHash, IEnumerable<Cipher> ciphers);
|
||||||
Task<IdentityResult> RefreshSecurityStampAsync(User user, string masterPasswordHash);
|
Task<IdentityResult> RefreshSecurityStampAsync(User user, string masterPasswordHash);
|
||||||
Task GetTwoFactorAsync(User user, Enums.TwoFactorProvider provider);
|
Task GetTwoFactorAsync(User user, Enums.TwoFactorProviderType provider);
|
||||||
Task<bool> RecoverTwoFactorAsync(string email, string masterPassword, string recoveryCode);
|
Task<bool> RecoverTwoFactorAsync(string email, string masterPassword, string recoveryCode);
|
||||||
Task<IdentityResult> DeleteAsync(User user);
|
Task<IdentityResult> DeleteAsync(User user);
|
||||||
}
|
}
|
||||||
|
@ -216,13 +216,13 @@ namespace Bit.Core.Services
|
|||||||
return IdentityResult.Failed(_identityErrorDescriber.PasswordMismatch());
|
return IdentityResult.Failed(_identityErrorDescriber.PasswordMismatch());
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task GetTwoFactorAsync(User user, Enums.TwoFactorProvider provider)
|
public async Task GetTwoFactorAsync(User user, Enums.TwoFactorProviderType provider)
|
||||||
{
|
{
|
||||||
if(user.TwoFactorEnabled && user.TwoFactorProvider.HasValue && user.TwoFactorProvider.Value == provider)
|
if(user.TwoFactorEnabled && user.TwoFactorProvider.HasValue && user.TwoFactorProvider.Value == provider)
|
||||||
{
|
{
|
||||||
switch(provider)
|
switch(provider)
|
||||||
{
|
{
|
||||||
case Enums.TwoFactorProvider.Authenticator:
|
case Enums.TwoFactorProviderType.Authenticator:
|
||||||
if(!string.IsNullOrWhiteSpace(user.AuthenticatorKey))
|
if(!string.IsNullOrWhiteSpace(user.AuthenticatorKey))
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -239,7 +239,7 @@ namespace Bit.Core.Services
|
|||||||
|
|
||||||
switch(provider)
|
switch(provider)
|
||||||
{
|
{
|
||||||
case Enums.TwoFactorProvider.Authenticator:
|
case Enums.TwoFactorProviderType.Authenticator:
|
||||||
var key = KeyGeneration.GenerateRandomKey(20);
|
var key = KeyGeneration.GenerateRandomKey(20);
|
||||||
user.AuthenticatorKey = Base32Encoder.Encode(key);
|
user.AuthenticatorKey = Base32Encoder.Encode(key);
|
||||||
break;
|
break;
|
||||||
@ -269,7 +269,7 @@ namespace Bit.Core.Services
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
user.TwoFactorProvider = TwoFactorProvider.Authenticator;
|
user.TwoFactorProvider = TwoFactorProviderType.Authenticator;
|
||||||
user.TwoFactorEnabled = false;
|
user.TwoFactorEnabled = false;
|
||||||
user.TwoFactorRecoveryCode = null;
|
user.TwoFactorRecoveryCode = null;
|
||||||
await SaveUserAsync(user);
|
await SaveUserAsync(user);
|
||||||
|
19
src/Core/Utilities/EquivalentDomains.cs
Normal file
19
src/Core/Utilities/EquivalentDomains.cs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
using Bit.Core.Enums;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Bit.Core.Utilities
|
||||||
|
{
|
||||||
|
public class EquivalentDomains
|
||||||
|
{
|
||||||
|
static EquivalentDomains()
|
||||||
|
{
|
||||||
|
Global = new Dictionary<GlobalEquivalentDomainsType, IEnumerable<string>>();
|
||||||
|
|
||||||
|
Global.Add(GlobalEquivalentDomainsType.Apple, new List<string>() { "apple.com", "icloud.com" });
|
||||||
|
Global.Add(GlobalEquivalentDomainsType.Google, new List<string> { "google.com", "youtube.com", "gmail.com" });
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IDictionary<GlobalEquivalentDomainsType, IEnumerable<string>> Global { get; set; }
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,8 @@
|
|||||||
@TwoFactorProvider TINYINT,
|
@TwoFactorProvider TINYINT,
|
||||||
@AuthenticatorKey NVARCHAR(50),
|
@AuthenticatorKey NVARCHAR(50),
|
||||||
@TwoFactorRecoveryCode NVARCHAR(32),
|
@TwoFactorRecoveryCode NVARCHAR(32),
|
||||||
|
@EquivalentDomains NVARCHAR(MAX),
|
||||||
|
@ExcludedGlobalEquivalentDomains NVARCHAR(MAX),
|
||||||
@CreationDate DATETIME2(7),
|
@CreationDate DATETIME2(7),
|
||||||
@RevisionDate DATETIME2(7)
|
@RevisionDate DATETIME2(7)
|
||||||
AS
|
AS
|
||||||
@ -31,6 +33,8 @@ BEGIN
|
|||||||
[TwoFactorProvider],
|
[TwoFactorProvider],
|
||||||
[AuthenticatorKey],
|
[AuthenticatorKey],
|
||||||
[TwoFactorRecoveryCode],
|
[TwoFactorRecoveryCode],
|
||||||
|
[EquivalentDomains],
|
||||||
|
[ExcludedGlobalEquivalentDomains],
|
||||||
[CreationDate],
|
[CreationDate],
|
||||||
[RevisionDate]
|
[RevisionDate]
|
||||||
)
|
)
|
||||||
@ -48,6 +52,8 @@ BEGIN
|
|||||||
@TwoFactorProvider,
|
@TwoFactorProvider,
|
||||||
@AuthenticatorKey,
|
@AuthenticatorKey,
|
||||||
@TwoFactorRecoveryCode,
|
@TwoFactorRecoveryCode,
|
||||||
|
@EquivalentDomains,
|
||||||
|
@ExcludedGlobalEquivalentDomains,
|
||||||
@CreationDate,
|
@CreationDate,
|
||||||
@RevisionDate
|
@RevisionDate
|
||||||
)
|
)
|
||||||
|
@ -11,6 +11,8 @@
|
|||||||
@TwoFactorProvider TINYINT,
|
@TwoFactorProvider TINYINT,
|
||||||
@AuthenticatorKey NVARCHAR(50),
|
@AuthenticatorKey NVARCHAR(50),
|
||||||
@TwoFactorRecoveryCode NVARCHAR(32),
|
@TwoFactorRecoveryCode NVARCHAR(32),
|
||||||
|
@EquivalentDomains NVARCHAR(MAX),
|
||||||
|
@ExcludedGlobalEquivalentDomains NVARCHAR(MAX),
|
||||||
@CreationDate DATETIME2(7),
|
@CreationDate DATETIME2(7),
|
||||||
@RevisionDate DATETIME2(7)
|
@RevisionDate DATETIME2(7)
|
||||||
AS
|
AS
|
||||||
@ -31,6 +33,8 @@ BEGIN
|
|||||||
[TwoFactorProvider] = @TwoFactorProvider,
|
[TwoFactorProvider] = @TwoFactorProvider,
|
||||||
[AuthenticatorKey] = @AuthenticatorKey,
|
[AuthenticatorKey] = @AuthenticatorKey,
|
||||||
[TwoFactorRecoveryCode] = @TwoFactorRecoveryCode,
|
[TwoFactorRecoveryCode] = @TwoFactorRecoveryCode,
|
||||||
|
[EquivalentDomains] = @EquivalentDomains,
|
||||||
|
[ExcludedGlobalEquivalentDomains] = @ExcludedGlobalEquivalentDomains,
|
||||||
[CreationDate] = @CreationDate,
|
[CreationDate] = @CreationDate,
|
||||||
[RevisionDate] = @RevisionDate
|
[RevisionDate] = @RevisionDate
|
||||||
WHERE
|
WHERE
|
||||||
|
@ -1,18 +1,20 @@
|
|||||||
CREATE TABLE [dbo].[User] (
|
CREATE TABLE [dbo].[User] (
|
||||||
[Id] UNIQUEIDENTIFIER NOT NULL,
|
[Id] UNIQUEIDENTIFIER NOT NULL,
|
||||||
[Name] NVARCHAR (50) NULL,
|
[Name] NVARCHAR (50) NULL,
|
||||||
[Email] NVARCHAR (50) NOT NULL,
|
[Email] NVARCHAR (50) NOT NULL,
|
||||||
[EmailVerified] BIT NOT NULL,
|
[EmailVerified] BIT NOT NULL,
|
||||||
[MasterPassword] NVARCHAR (300) NOT NULL,
|
[MasterPassword] NVARCHAR (300) NOT NULL,
|
||||||
[MasterPasswordHint] NVARCHAR (50) NULL,
|
[MasterPasswordHint] NVARCHAR (50) NULL,
|
||||||
[Culture] NVARCHAR (10) NOT NULL,
|
[Culture] NVARCHAR (10) NOT NULL,
|
||||||
[SecurityStamp] NVARCHAR (50) NOT NULL,
|
[SecurityStamp] NVARCHAR (50) NOT NULL,
|
||||||
[TwoFactorEnabled] BIT NOT NULL,
|
[TwoFactorEnabled] BIT NOT NULL,
|
||||||
[TwoFactorProvider] TINYINT NULL,
|
[TwoFactorProvider] TINYINT NULL,
|
||||||
[AuthenticatorKey] NVARCHAR (50) NULL,
|
[AuthenticatorKey] NVARCHAR (50) NULL,
|
||||||
[TwoFactorRecoveryCode] NVARCHAR (32) NULL,
|
[TwoFactorRecoveryCode] NVARCHAR (32) NULL,
|
||||||
[CreationDate] DATETIME2 (7) NOT NULL,
|
[EquivalentDomains] NVARCHAR (MAX) NULL,
|
||||||
[RevisionDate] DATETIME2 (7) NOT NULL,
|
[ExcludedGlobalEquivalentDomains] NVARCHAR (MAX) NULL,
|
||||||
|
[CreationDate] DATETIME2 (7) NOT NULL,
|
||||||
|
[RevisionDate] DATETIME2 (7) NOT NULL,
|
||||||
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Id] ASC)
|
CONSTRAINT [PK_User] PRIMARY KEY CLUSTERED ([Id] ASC)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user