1
0
mirror of https://github.com/bitwarden/browser synced 2026-03-02 03:21:19 +00:00
Files
browser/libs/common/src/vault/models/request/cipher.request.ts
Bernd Schoolmann 081fe83d83 PM-10393 SSH keys (#10825)
* [PM-10395] Add new item type ssh key (#10360)

* Implement ssh-key cipher type

* Fix linting

* Fix edit and view components for ssh-keys on desktop

* Fix tests

* Remove ssh key type references

* Remove add ssh key option

* Fix typo

* Add tests

* [PM-10399] Add ssh key import export for bitwarden json (#10529)

* Add ssh key import export for bitwarden json

* Remove key type from ssh key export

* [PM-10406] Add privatekey publickey and fingerprint to both add-edit and view co… (#11046)

* Add privatekey publickey and fingerprint to both add-edit and view components

* Remove wrong a11y title

* Fix testid

* [PM-10098] SSH Agent & SSH Key creation for Bitwarden Desktop (#10293)

* Add ssh agent, generator & import

* Move ssh agent code to bitwarden-russh crate

* Remove generator component

* Cleanup

* Cleanup

* Remove left over sshGenerator reference

* Cleanup

* Add documentation to sshkeyimportstatus

* Fix outdated variable name

* Update apps/desktop/src/platform/preload.ts

Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com>

* Rename renderersshagent

* Rename MainSshAgentService

* Improve clarity of 'id' variables being used

* Improve clarity of 'id' variables being used

* Update apps/desktop/src/vault/app/vault/add-edit.component.html

Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com>

* Fix outdated cipher/messageid names

* Rename SSH to Ssh

* Make agent syncing more reactive

* Move constants to top of class

* Make sshkey cipher filtering clearer

* Add stricter equality check on ssh key unlock

* Fix build and messages

* Fix incorrect featureflag name

* Replace anonymous async function with switchmap pipe

* Fix build

* Update apps/desktop/desktop_native/napi/src/lib.rs

Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com>

* Revert incorrectly renamed 'Ssh' usages to SSH

* Run cargo fmt

* Clean up ssh agent sock path logic

* Cleanup and split to platform specific files

* Small cleanup

* Pull out generator and importer into core

* Rename renderersshagentservice to sshagentservice

* Rename cipheruuid to cipher_id

* Drop ssh dependencies from napi crate

* Clean up windows build

* Small cleanup

* Small cleanup

* Cleanup

* Add rxjs pipeline for agent services

* [PM-12555] Pkcs8 sshkey import & general ssh key import tests (#11048)

* Add pkcs8 import and tests

* Add key type unsupported error

* Remove unsupported formats

* Remove code for unsupported formats

* Fix encrypted pkcs8 import

* Add ed25519 pkcs8 unencrypted test file

* SSH agent rxjs tweaks (#11148)

* feat: rewrite sshagent.signrequest as purely observable

* feat: fail the request when unlock times out

* chore: clean up, add some clarifying comments

* chore: remove unused dependency

* fix: result `undefined` crashing in NAPI -> Rust

* Allow concurrent SSH requests in rust

* Remove unwraps

* Cleanup and add init service init call

* Fix windows

* Fix timeout behavior on locked vault

---------

Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com>

* Fix libc dependency being duplicated

* fix SSH casing (#11840)

* Move ssh agent behind feature flag (#11841)

* Move ssh agent behind feature flag

* Add separate flag for ssh agent

* [PM-14215] fix unsupported key type error message (#11788)

* Fix error message for import of unsupported ssh keys

* Use triple equals in add-edit component for ssh keys

---------

Co-authored-by: Andreas Coroiu <acoroiu@bitwarden.com>
Co-authored-by: aj-bw <81774843+aj-bw@users.noreply.github.com>
2024-11-08 11:01:31 +01:00

205 lines
9.2 KiB
TypeScript

import { CipherRepromptType } from "../../enums/cipher-reprompt-type";
import { CipherType } from "../../enums/cipher-type";
import { CardApi } from "../api/card.api";
import { Fido2CredentialApi } from "../api/fido2-credential.api";
import { FieldApi } from "../api/field.api";
import { IdentityApi } from "../api/identity.api";
import { LoginUriApi } from "../api/login-uri.api";
import { LoginApi } from "../api/login.api";
import { SecureNoteApi } from "../api/secure-note.api";
import { SshKeyApi } from "../api/ssh-key.api";
import { Cipher } from "../domain/cipher";
import { AttachmentRequest } from "./attachment.request";
import { PasswordHistoryRequest } from "./password-history.request";
export class CipherRequest {
type: CipherType;
folderId: string;
organizationId: string;
name: string;
notes: string;
favorite: boolean;
login: LoginApi;
secureNote: SecureNoteApi;
card: CardApi;
identity: IdentityApi;
sshKey: SshKeyApi;
fields: FieldApi[];
passwordHistory: PasswordHistoryRequest[];
// Deprecated, remove at some point and rename attachments2 to attachments
attachments: { [id: string]: string };
attachments2: { [id: string]: AttachmentRequest };
lastKnownRevisionDate: Date;
reprompt: CipherRepromptType;
key: string;
constructor(cipher: Cipher) {
this.type = cipher.type;
this.folderId = cipher.folderId;
this.organizationId = cipher.organizationId;
this.name = cipher.name ? cipher.name.encryptedString : null;
this.notes = cipher.notes ? cipher.notes.encryptedString : null;
this.favorite = cipher.favorite;
this.lastKnownRevisionDate = cipher.revisionDate;
this.reprompt = cipher.reprompt;
this.key = cipher.key?.encryptedString;
switch (this.type) {
case CipherType.Login:
this.login = new LoginApi();
this.login.uris =
cipher.login.uris?.map((u) => {
const uri = new LoginUriApi();
uri.uri = u.uri != null ? u.uri.encryptedString : null;
uri.match = u.match != null ? u.match : null;
uri.uriChecksum = u.uriChecksum != null ? u.uriChecksum.encryptedString : null;
return uri;
}) ?? [];
this.login.username = cipher.login.username ? cipher.login.username.encryptedString : null;
this.login.password = cipher.login.password ? cipher.login.password.encryptedString : null;
this.login.passwordRevisionDate =
cipher.login.passwordRevisionDate != null
? cipher.login.passwordRevisionDate.toISOString()
: null;
this.login.totp = cipher.login.totp ? cipher.login.totp.encryptedString : null;
this.login.autofillOnPageLoad = cipher.login.autofillOnPageLoad;
if (cipher.login.fido2Credentials != null) {
this.login.fido2Credentials = cipher.login.fido2Credentials.map((key) => {
const keyApi = new Fido2CredentialApi();
keyApi.credentialId =
key.credentialId != null ? key.credentialId.encryptedString : null;
keyApi.keyType =
key.keyType != null ? (key.keyType.encryptedString as "public-key") : null;
keyApi.keyAlgorithm =
key.keyAlgorithm != null ? (key.keyAlgorithm.encryptedString as "ECDSA") : null;
keyApi.keyCurve =
key.keyCurve != null ? (key.keyCurve.encryptedString as "P-256") : null;
keyApi.keyValue = key.keyValue != null ? key.keyValue.encryptedString : null;
keyApi.rpId = key.rpId != null ? key.rpId.encryptedString : null;
keyApi.rpName = key.rpName != null ? key.rpName.encryptedString : null;
keyApi.counter = key.counter != null ? key.counter.encryptedString : null;
keyApi.userHandle = key.userHandle != null ? key.userHandle.encryptedString : null;
keyApi.userName = key.userName != null ? key.userName.encryptedString : null;
keyApi.userDisplayName =
key.userDisplayName != null ? key.userDisplayName.encryptedString : null;
keyApi.discoverable =
key.discoverable != null ? key.discoverable.encryptedString : null;
keyApi.creationDate = key.creationDate != null ? key.creationDate.toISOString() : null;
return keyApi;
});
}
break;
case CipherType.SecureNote:
this.secureNote = new SecureNoteApi();
this.secureNote.type = cipher.secureNote.type;
break;
case CipherType.SshKey:
this.sshKey = new SshKeyApi();
this.sshKey.privateKey =
cipher.sshKey.privateKey != null ? cipher.sshKey.privateKey.encryptedString : null;
this.sshKey.publicKey =
cipher.sshKey.publicKey != null ? cipher.sshKey.publicKey.encryptedString : null;
this.sshKey.keyFingerprint =
cipher.sshKey.keyFingerprint != null
? cipher.sshKey.keyFingerprint.encryptedString
: null;
break;
case CipherType.Card:
this.card = new CardApi();
this.card.cardholderName =
cipher.card.cardholderName != null ? cipher.card.cardholderName.encryptedString : null;
this.card.brand = cipher.card.brand != null ? cipher.card.brand.encryptedString : null;
this.card.number = cipher.card.number != null ? cipher.card.number.encryptedString : null;
this.card.expMonth =
cipher.card.expMonth != null ? cipher.card.expMonth.encryptedString : null;
this.card.expYear =
cipher.card.expYear != null ? cipher.card.expYear.encryptedString : null;
this.card.code = cipher.card.code != null ? cipher.card.code.encryptedString : null;
break;
case CipherType.Identity:
this.identity = new IdentityApi();
this.identity.title =
cipher.identity.title != null ? cipher.identity.title.encryptedString : null;
this.identity.firstName =
cipher.identity.firstName != null ? cipher.identity.firstName.encryptedString : null;
this.identity.middleName =
cipher.identity.middleName != null ? cipher.identity.middleName.encryptedString : null;
this.identity.lastName =
cipher.identity.lastName != null ? cipher.identity.lastName.encryptedString : null;
this.identity.address1 =
cipher.identity.address1 != null ? cipher.identity.address1.encryptedString : null;
this.identity.address2 =
cipher.identity.address2 != null ? cipher.identity.address2.encryptedString : null;
this.identity.address3 =
cipher.identity.address3 != null ? cipher.identity.address3.encryptedString : null;
this.identity.city =
cipher.identity.city != null ? cipher.identity.city.encryptedString : null;
this.identity.state =
cipher.identity.state != null ? cipher.identity.state.encryptedString : null;
this.identity.postalCode =
cipher.identity.postalCode != null ? cipher.identity.postalCode.encryptedString : null;
this.identity.country =
cipher.identity.country != null ? cipher.identity.country.encryptedString : null;
this.identity.company =
cipher.identity.company != null ? cipher.identity.company.encryptedString : null;
this.identity.email =
cipher.identity.email != null ? cipher.identity.email.encryptedString : null;
this.identity.phone =
cipher.identity.phone != null ? cipher.identity.phone.encryptedString : null;
this.identity.ssn =
cipher.identity.ssn != null ? cipher.identity.ssn.encryptedString : null;
this.identity.username =
cipher.identity.username != null ? cipher.identity.username.encryptedString : null;
this.identity.passportNumber =
cipher.identity.passportNumber != null
? cipher.identity.passportNumber.encryptedString
: null;
this.identity.licenseNumber =
cipher.identity.licenseNumber != null
? cipher.identity.licenseNumber.encryptedString
: null;
break;
default:
break;
}
if (cipher.fields != null) {
this.fields = cipher.fields.map((f) => {
const field = new FieldApi();
field.type = f.type;
field.name = f.name ? f.name.encryptedString : null;
field.value = f.value ? f.value.encryptedString : null;
field.linkedId = f.linkedId;
return field;
});
}
if (cipher.passwordHistory != null) {
this.passwordHistory = [];
cipher.passwordHistory.forEach((ph) => {
this.passwordHistory.push({
lastUsedDate: ph.lastUsedDate,
password: ph.password ? ph.password.encryptedString : null,
});
});
}
if (cipher.attachments != null) {
this.attachments = {};
this.attachments2 = {};
cipher.attachments.forEach((attachment) => {
const fileName = attachment.fileName ? attachment.fileName.encryptedString : null;
this.attachments[attachment.id] = fileName;
const attachmentRequest = new AttachmentRequest();
attachmentRequest.fileName = fileName;
if (attachment.key != null) {
attachmentRequest.key = attachment.key.encryptedString;
}
this.attachments2[attachment.id] = attachmentRequest;
});
}
}
}