Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[PM-10394] Add new item type ssh key #4575

Merged
merged 10 commits into from
Nov 5, 2024
22 changes: 21 additions & 1 deletion src/Api/Vault/Controllers/SyncController.cs
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
using Bit.Api.Vault.Models.Response;
using Bit.Core;
using Bit.Core.AdminConsole.Entities;
using Bit.Core.AdminConsole.Enums.Provider;
using Bit.Core.AdminConsole.Repositories;
using Bit.Core.Context;
using Bit.Core.Entities;
using Bit.Core.Enums;
using Bit.Core.Exceptions;
Expand All @@ -10,6 +12,7 @@
using Bit.Core.Services;
using Bit.Core.Settings;
using Bit.Core.Tools.Repositories;
using Bit.Core.Vault.Models.Data;
using Bit.Core.Vault.Repositories;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
Expand All @@ -30,6 +33,8 @@
private readonly IPolicyRepository _policyRepository;
private readonly ISendRepository _sendRepository;
private readonly GlobalSettings _globalSettings;
private readonly ICurrentContext _currentContext;
private readonly Version _sshKeyCipherMinimumVersion = new(Constants.SSHKeyCipherMinimumVersion);
private readonly IFeatureService _featureService;

public SyncController(
Expand All @@ -43,6 +48,7 @@
IPolicyRepository policyRepository,
ISendRepository sendRepository,
GlobalSettings globalSettings,
ICurrentContext currentContext,
IFeatureService featureService)
{
_userService = userService;
Expand All @@ -55,6 +61,7 @@
_policyRepository = policyRepository;
_sendRepository = sendRepository;
_globalSettings = globalSettings;
_currentContext = currentContext;
_featureService = featureService;
}

Expand All @@ -77,7 +84,8 @@
var hasEnabledOrgs = organizationUserDetails.Any(o => o.Enabled);

var folders = await _folderRepository.GetManyByUserIdAsync(user.Id);
var ciphers = await _cipherRepository.GetManyByUserIdAsync(user.Id, withOrganizations: hasEnabledOrgs);
var allCiphers = await _cipherRepository.GetManyByUserIdAsync(user.Id, withOrganizations: hasEnabledOrgs);
var ciphers = FilterSSHKeys(allCiphers);
var sends = await _sendRepository.GetManyByUserIdAsync(user.Id);

IEnumerable<CollectionDetails> collections = null;
Expand All @@ -101,4 +109,16 @@
folders, collections, ciphers, collectionCiphersGroupDict, excludeDomains, policies, sends);
return response;
}

private ICollection<CipherDetails> FilterSSHKeys(ICollection<CipherDetails> ciphers)
{
if (_currentContext.ClientVersion >= _sshKeyCipherMinimumVersion)
{
return ciphers;

Check warning on line 117 in src/Api/Vault/Controllers/SyncController.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/Vault/Controllers/SyncController.cs#L116-L117

Added lines #L116 - L117 were not covered by tests
}
else
{
return ciphers.Where(c => c.Type != Core.Vault.Enums.CipherType.SSHKey).ToList();
}
}
}
26 changes: 26 additions & 0 deletions src/Api/Vault/Models/CipherSSHKeyModel.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
using Bit.Core.Utilities;
using Bit.Core.Vault.Models.Data;

namespace Bit.Api.Vault.Models;

public class CipherSSHKeyModel
{
public CipherSSHKeyModel() { }

public CipherSSHKeyModel(CipherSSHKeyData data)
{
PrivateKey = data.PrivateKey;
PublicKey = data.PublicKey;
KeyFingerprint = data.KeyFingerprint;
}

Check warning on line 15 in src/Api/Vault/Models/CipherSSHKeyModel.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/Vault/Models/CipherSSHKeyModel.cs#L10-L15

Added lines #L10 - L15 were not covered by tests

[EncryptedString]
[EncryptedStringLength(5000)]
public string PrivateKey { get; set; }
[EncryptedString]
[EncryptedStringLength(5000)]
public string PublicKey { get; set; }
[EncryptedString]
[EncryptedStringLength(1000)]
public string KeyFingerprint { get; set; }
}
19 changes: 19 additions & 0 deletions src/Api/Vault/Models/Request/CipherRequestModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
public CipherCardModel Card { get; set; }
public CipherIdentityModel Identity { get; set; }
public CipherSecureNoteModel SecureNote { get; set; }
public CipherSSHKeyModel SSHKey { get; set; }
public DateTime? LastKnownRevisionDate { get; set; } = null;

public CipherDetails ToCipherDetails(Guid userId, bool allowOrgIdSet = true)
Expand Down Expand Up @@ -82,6 +83,9 @@
case CipherType.SecureNote:
existingCipher.Data = JsonSerializer.Serialize(ToCipherSecureNoteData(), JsonHelpers.IgnoreWritingNull);
break;
case CipherType.SSHKey:
existingCipher.Data = JsonSerializer.Serialize(ToCipherSSHKeyData(), JsonHelpers.IgnoreWritingNull);
break;

Check warning on line 88 in src/Api/Vault/Models/Request/CipherRequestModel.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/Vault/Models/Request/CipherRequestModel.cs#L87-L88

Added lines #L87 - L88 were not covered by tests
default:
throw new ArgumentException("Unsupported type: " + nameof(Type) + ".");
}
Expand Down Expand Up @@ -230,6 +234,21 @@
Type = SecureNote.Type,
};
}

private CipherSSHKeyData ToCipherSSHKeyData()
{

Check warning on line 239 in src/Api/Vault/Models/Request/CipherRequestModel.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/Vault/Models/Request/CipherRequestModel.cs#L239

Added line #L239 was not covered by tests
return new CipherSSHKeyData
{
Name = Name,
Notes = Notes,
Fields = Fields?.Select(f => f.ToCipherFieldData()),
PasswordHistory = PasswordHistory?.Select(ph => ph.ToCipherPasswordHistoryData()),

PrivateKey = SSHKey.PrivateKey,
PublicKey = SSHKey.PublicKey,
KeyFingerprint = SSHKey.KeyFingerprint,
};
}

Check warning on line 251 in src/Api/Vault/Models/Request/CipherRequestModel.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/Vault/Models/Request/CipherRequestModel.cs#L241-L251

Added lines #L241 - L251 were not covered by tests
}

public class CipherWithIdRequestModel : CipherRequestModel
Expand Down
7 changes: 7 additions & 0 deletions src/Api/Vault/Models/Response/CipherResponseModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,12 @@
cipherData = identityData;
Identity = new CipherIdentityModel(identityData);
break;
case CipherType.SSHKey:
var sshKeyData = JsonSerializer.Deserialize<CipherSSHKeyData>(cipher.Data);
Data = sshKeyData;
cipherData = sshKeyData;
SSHKey = new CipherSSHKeyModel(sshKeyData);
break;

Check warning on line 56 in src/Api/Vault/Models/Response/CipherResponseModel.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/Vault/Models/Response/CipherResponseModel.cs#L52-L56

Added lines #L52 - L56 were not covered by tests
default:
throw new ArgumentException("Unsupported " + nameof(Type) + ".");
}
Expand Down Expand Up @@ -76,6 +82,7 @@
public CipherCardModel Card { get; set; }
public CipherIdentityModel Identity { get; set; }
public CipherSecureNoteModel SecureNote { get; set; }
public CipherSSHKeyModel SSHKey { get; set; }

Check warning on line 85 in src/Api/Vault/Models/Response/CipherResponseModel.cs

View check run for this annotation

Codecov / codecov/patch

src/Api/Vault/Models/Response/CipherResponseModel.cs#L85

Added line #L85 was not covered by tests
public IEnumerable<CipherFieldModel> Fields { get; set; }
public IEnumerable<CipherPasswordHistoryModel> PasswordHistory { get; set; }
public IEnumerable<AttachmentResponseModel> Attachments { get; set; }
Expand Down
3 changes: 3 additions & 0 deletions src/Core/Constants.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ public static class Constants
public const int OrganizationSelfHostSubscriptionGracePeriodDays = 60;

public const string Fido2KeyCipherMinimumVersion = "2023.10.0";
public const string SSHKeyCipherMinimumVersion = "2024.12.0";

/// <summary>
/// Used by IdentityServer to identify our own provider.
Expand Down Expand Up @@ -122,6 +123,8 @@ public static class FeatureFlagKeys
public const string InlineMenuPositioningImprovements = "inline-menu-positioning-improvements";
public const string ProviderClientVaultPrivacyBanner = "ac-2833-provider-client-vault-privacy-banner";
public const string DeviceTrustLogging = "pm-8285-device-trust-logging";
public const string SSHKeyItemVaultItem = "ssh-key-vault-item";
public const string SSHAgent = "ssh-agent";
public const string AuthenticatorTwoFactorToken = "authenticator-2fa-token";
public const string EnableUpgradePasswordManagerSub = "AC-2708-upgrade-password-manager-sub";
public const string IdpAutoSubmitLogin = "idp-auto-submit-login";
Expand Down
1 change: 1 addition & 0 deletions src/Core/Vault/Enums/CipherType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ public enum CipherType : byte
SecureNote = 2,
Card = 3,
Identity = 4,
SSHKey = 5,
}
10 changes: 10 additions & 0 deletions src/Core/Vault/Models/Data/CipherSSHKeyData.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
namespace Bit.Core.Vault.Models.Data;

public class CipherSSHKeyData : CipherData
{
public CipherSSHKeyData() { }

Check warning on line 5 in src/Core/Vault/Models/Data/CipherSSHKeyData.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/Vault/Models/Data/CipherSSHKeyData.cs#L5

Added line #L5 was not covered by tests

public string PrivateKey { get; set; }
public string PublicKey { get; set; }
public string KeyFingerprint { get; set; }

Check warning on line 9 in src/Core/Vault/Models/Data/CipherSSHKeyData.cs

View check run for this annotation

Codecov / codecov/patch

src/Core/Vault/Models/Data/CipherSSHKeyData.cs#L7-L9

Added lines #L7 - L9 were not covered by tests
}
Loading