1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-18 01:03:35 +00:00

Merge branch 'master' into EC-598-beeep-properly-store-passkeys-in-bitwarden

This commit is contained in:
Andreas Coroiu
2023-02-10 13:08:19 +01:00
1211 changed files with 44762 additions and 10346 deletions

View File

@@ -1,44 +1,72 @@
import { DeviceVerificationRequest } from "../auth/models/request/device-verification.request";
import { EmailTokenRequest } from "../auth/models/request/email-token.request";
import { EmailRequest } from "../auth/models/request/email.request";
import { EmergencyAccessAcceptRequest } from "../auth/models/request/emergency-access-accept.request";
import { EmergencyAccessConfirmRequest } from "../auth/models/request/emergency-access-confirm.request";
import { EmergencyAccessInviteRequest } from "../auth/models/request/emergency-access-invite.request";
import { EmergencyAccessPasswordRequest } from "../auth/models/request/emergency-access-password.request";
import { EmergencyAccessUpdateRequest } from "../auth/models/request/emergency-access-update.request";
import { PasswordTokenRequest } from "../auth/models/request/identity-token/password-token.request";
import { SsoTokenRequest } from "../auth/models/request/identity-token/sso-token.request";
import { UserApiTokenRequest } from "../auth/models/request/identity-token/user-api-token.request";
import { KeyConnectorUserKeyRequest } from "../auth/models/request/key-connector-user-key.request";
import { PasswordHintRequest } from "../auth/models/request/password-hint.request";
import { PasswordRequest } from "../auth/models/request/password.request";
import { PasswordlessAuthRequest } from "../auth/models/request/passwordless-auth.request";
import { PasswordlessCreateAuthRequest } from "../auth/models/request/passwordless-create-auth.request";
import { SecretVerificationRequest } from "../auth/models/request/secret-verification.request";
import { SetKeyConnectorKeyRequest } from "../auth/models/request/set-key-connector-key.request";
import { SetPasswordRequest } from "../auth/models/request/set-password.request";
import { TwoFactorEmailRequest } from "../auth/models/request/two-factor-email.request";
import { TwoFactorProviderRequest } from "../auth/models/request/two-factor-provider.request";
import { TwoFactorRecoveryRequest } from "../auth/models/request/two-factor-recovery.request";
import { UpdateProfileRequest } from "../auth/models/request/update-profile.request";
import { UpdateTempPasswordRequest } from "../auth/models/request/update-temp-password.request";
import { UpdateTwoFactorAuthenticatorRequest } from "../auth/models/request/update-two-factor-authenticator.request";
import { UpdateTwoFactorDuoRequest } from "../auth/models/request/update-two-factor-duo.request";
import { UpdateTwoFactorEmailRequest } from "../auth/models/request/update-two-factor-email.request";
import { UpdateTwoFactorWebAuthnDeleteRequest } from "../auth/models/request/update-two-factor-web-authn-delete.request";
import { UpdateTwoFactorWebAuthnRequest } from "../auth/models/request/update-two-factor-web-authn.request";
import { UpdateTwoFactorYubioOtpRequest } from "../auth/models/request/update-two-factor-yubio-otp.request";
import { ApiKeyResponse } from "../auth/models/response/api-key.response";
import { AuthRequestResponse } from "../auth/models/response/auth-request.response";
import { DeviceVerificationResponse } from "../auth/models/response/device-verification.response";
import {
EmergencyAccessGranteeDetailsResponse,
EmergencyAccessGrantorDetailsResponse,
EmergencyAccessTakeoverResponse,
EmergencyAccessViewResponse,
} from "../auth/models/response/emergency-access.response";
import { IdentityCaptchaResponse } from "../auth/models/response/identity-captcha.response";
import { IdentityTokenResponse } from "../auth/models/response/identity-token.response";
import { IdentityTwoFactorResponse } from "../auth/models/response/identity-two-factor.response";
import { KeyConnectorUserKeyResponse } from "../auth/models/response/key-connector-user-key.response";
import { PreloginResponse } from "../auth/models/response/prelogin.response";
import { RegisterResponse } from "../auth/models/response/register.response";
import { SsoPreValidateResponse } from "../auth/models/response/sso-pre-validate.response";
import { TwoFactorAuthenticatorResponse } from "../auth/models/response/two-factor-authenticator.response";
import { TwoFactorDuoResponse } from "../auth/models/response/two-factor-duo.response";
import { TwoFactorEmailResponse } from "../auth/models/response/two-factor-email.response";
import { TwoFactorProviderResponse } from "../auth/models/response/two-factor-provider.response";
import { TwoFactorRecoverResponse } from "../auth/models/response/two-factor-recover.response";
import {
ChallengeResponse,
TwoFactorWebAuthnResponse,
} from "../auth/models/response/two-factor-web-authn.response";
import { TwoFactorYubiKeyResponse } from "../auth/models/response/two-factor-yubi-key.response";
import { OrganizationConnectionType } from "../enums/organizationConnectionType";
import { SetKeyConnectorKeyRequest } from "../models/request/account/set-key-connector-key.request";
import { AttachmentRequest } from "../models/request/attachment.request";
import { BitPayInvoiceRequest } from "../models/request/bit-pay-invoice.request";
import { CipherBulkDeleteRequest } from "../models/request/cipher-bulk-delete.request";
import { CipherBulkMoveRequest } from "../models/request/cipher-bulk-move.request";
import { CipherBulkRestoreRequest } from "../models/request/cipher-bulk-restore.request";
import { CipherBulkShareRequest } from "../models/request/cipher-bulk-share.request";
import { CipherCollectionsRequest } from "../models/request/cipher-collections.request";
import { CipherCreateRequest } from "../models/request/cipher-create.request";
import { CipherPartialRequest } from "../models/request/cipher-partial.request";
import { CipherShareRequest } from "../models/request/cipher-share.request";
import { CipherRequest } from "../models/request/cipher.request";
import { CollectionBulkDeleteRequest } from "../models/request/collection-bulk-delete.request";
import { CollectionRequest } from "../models/request/collection.request";
import { DeleteRecoverRequest } from "../models/request/delete-recover.request";
import { DeviceVerificationRequest } from "../models/request/device-verification.request";
import { EmailTokenRequest } from "../models/request/email-token.request";
import { EmailRequest } from "../models/request/email.request";
import { EmergencyAccessAcceptRequest } from "../models/request/emergency-access-accept.request";
import { EmergencyAccessConfirmRequest } from "../models/request/emergency-access-confirm.request";
import { EmergencyAccessInviteRequest } from "../models/request/emergency-access-invite.request";
import { EmergencyAccessPasswordRequest } from "../models/request/emergency-access-password.request";
import { EmergencyAccessUpdateRequest } from "../models/request/emergency-access-update.request";
import { EventRequest } from "../models/request/event.request";
import { IapCheckRequest } from "../models/request/iap-check.request";
import { PasswordTokenRequest } from "../models/request/identity-token/password-token.request";
import { SsoTokenRequest } from "../models/request/identity-token/sso-token.request";
import { UserApiTokenRequest } from "../models/request/identity-token/user-api-token.request";
import { ImportCiphersRequest } from "../models/request/import-ciphers.request";
import { ImportOrganizationCiphersRequest } from "../models/request/import-organization-ciphers.request";
import { KdfRequest } from "../models/request/kdf.request";
import { KeyConnectorUserKeyRequest } from "../models/request/key-connector-user-key.request";
import { KeysRequest } from "../models/request/keys.request";
import { OrganizationConnectionRequest } from "../models/request/organization-connection.request";
import { OrganizationImportRequest } from "../models/request/organization-import.request";
import { OrganizationSponsorshipCreateRequest } from "../models/request/organization/organization-sponsorship-create.request";
import { OrganizationSponsorshipRedeemRequest } from "../models/request/organization/organization-sponsorship-redeem.request";
import { PasswordHintRequest } from "../models/request/password-hint.request";
import { PasswordRequest } from "../models/request/password.request";
import { PasswordlessCreateAuthRequest } from "../models/request/passwordless-create-auth.request";
import { PaymentRequest } from "../models/request/payment.request";
import { PreloginRequest } from "../models/request/prelogin.request";
import { ProviderAddOrganizationRequest } from "../models/request/provider/provider-add-organization.request";
@@ -52,55 +80,25 @@ import { ProviderUserConfirmRequest } from "../models/request/provider/provider-
import { ProviderUserInviteRequest } from "../models/request/provider/provider-user-invite.request";
import { ProviderUserUpdateRequest } from "../models/request/provider/provider-user-update.request";
import { RegisterRequest } from "../models/request/register.request";
import { SecretVerificationRequest } from "../models/request/secret-verification.request";
import { SelectionReadOnlyRequest } from "../models/request/selection-read-only.request";
import { SendAccessRequest } from "../models/request/send-access.request";
import { SendRequest } from "../models/request/send.request";
import { SetPasswordRequest } from "../models/request/set-password.request";
import { StorageRequest } from "../models/request/storage.request";
import { TaxInfoUpdateRequest } from "../models/request/tax-info-update.request";
import { TwoFactorEmailRequest } from "../models/request/two-factor-email.request";
import { TwoFactorProviderRequest } from "../models/request/two-factor-provider.request";
import { TwoFactorRecoveryRequest } from "../models/request/two-factor-recovery.request";
import { UpdateAvatarRequest } from "../models/request/update-avatar.request";
import { UpdateDomainsRequest } from "../models/request/update-domains.request";
import { UpdateKeyRequest } from "../models/request/update-key.request";
import { UpdateProfileRequest } from "../models/request/update-profile.request";
import { UpdateTempPasswordRequest } from "../models/request/update-temp-password.request";
import { UpdateTwoFactorAuthenticatorRequest } from "../models/request/update-two-factor-authenticator.request";
import { UpdateTwoFactorDuoRequest } from "../models/request/update-two-factor-duo.request";
import { UpdateTwoFactorEmailRequest } from "../models/request/update-two-factor-email.request";
import { UpdateTwoFactorWebAuthnDeleteRequest } from "../models/request/update-two-factor-web-authn-delete.request";
import { UpdateTwoFactorWebAuthnRequest } from "../models/request/update-two-factor-web-authn.request";
import { UpdateTwoFactorYubioOtpRequest } from "../models/request/update-two-factor-yubio-otp.request";
import { VerifyDeleteRecoverRequest } from "../models/request/verify-delete-recover.request";
import { VerifyEmailRequest } from "../models/request/verify-email.request";
import { ApiKeyResponse } from "../models/response/api-key.response";
import { AttachmentUploadDataResponse } from "../models/response/attachment-upload-data.response";
import { AttachmentResponse } from "../models/response/attachment.response";
import { AuthRequestResponse } from "../models/response/auth-request.response";
import { RegisterResponse } from "../models/response/authentication/register.response";
import { BillingHistoryResponse } from "../models/response/billing-history.response";
import { BillingPaymentResponse } from "../models/response/billing-payment.response";
import { BreachAccountResponse } from "../models/response/breach-account.response";
import { CipherResponse } from "../models/response/cipher.response";
import {
CollectionAccessDetailsResponse,
CollectionResponse,
} from "../models/response/collection.response";
import { DeviceVerificationResponse } from "../models/response/device-verification.response";
import { DomainsResponse } from "../models/response/domains.response";
import {
EmergencyAccessGranteeDetailsResponse,
EmergencyAccessGrantorDetailsResponse,
EmergencyAccessTakeoverResponse,
EmergencyAccessViewResponse,
} from "../models/response/emergency-access.response";
import { EventResponse } from "../models/response/event.response";
import { IdentityCaptchaResponse } from "../models/response/identity-captcha.response";
import { IdentityTokenResponse } from "../models/response/identity-token.response";
import { IdentityTwoFactorResponse } from "../models/response/identity-two-factor.response";
import { KeyConnectorUserKeyResponse } from "../models/response/key-connector-user-key.response";
import { ListResponse } from "../models/response/list.response";
import {
OrganizationConnectionConfigApis,
@@ -111,7 +109,6 @@ import { OrganizationSponsorshipSyncStatusResponse } from "../models/response/or
import { PaymentResponse } from "../models/response/payment.response";
import { PlanResponse } from "../models/response/plan.response";
import { PolicyResponse } from "../models/response/policy.response";
import { PreloginResponse } from "../models/response/prelogin.response";
import { ProfileResponse } from "../models/response/profile.response";
import {
ProviderOrganizationOrganizationDetailsResponse,
@@ -129,23 +126,25 @@ import { SendAccessResponse } from "../models/response/send-access.response";
import { SendFileDownloadDataResponse } from "../models/response/send-file-download-data.response";
import { SendFileUploadDataResponse } from "../models/response/send-file-upload-data.response";
import { SendResponse } from "../models/response/send.response";
import { SsoPreValidateResponse } from "../models/response/sso-pre-validate.response";
import { SubscriptionResponse } from "../models/response/subscription.response";
import { SyncResponse } from "../models/response/sync.response";
import { TaxInfoResponse } from "../models/response/tax-info.response";
import { TaxRateResponse } from "../models/response/tax-rate.response";
import { TwoFactorAuthenticatorResponse } from "../models/response/two-factor-authenticator.response";
import { TwoFactorDuoResponse } from "../models/response/two-factor-duo.response";
import { TwoFactorEmailResponse } from "../models/response/two-factor-email.response";
import { TwoFactorProviderResponse } from "../models/response/two-factor-provider.response";
import { TwoFactorRecoverResponse } from "../models/response/two-factor-recover.response";
import {
ChallengeResponse,
TwoFactorWebAuthnResponse,
} from "../models/response/two-factor-web-authn.response";
import { TwoFactorYubiKeyResponse } from "../models/response/two-factor-yubi-key.response";
import { UserKeyResponse } from "../models/response/user-key.response";
import { SendAccessView } from "../models/view/send-access.view";
import { AttachmentRequest } from "../vault/models/request/attachment.request";
import { CipherBulkDeleteRequest } from "../vault/models/request/cipher-bulk-delete.request";
import { CipherBulkMoveRequest } from "../vault/models/request/cipher-bulk-move.request";
import { CipherBulkRestoreRequest } from "../vault/models/request/cipher-bulk-restore.request";
import { CipherBulkShareRequest } from "../vault/models/request/cipher-bulk-share.request";
import { CipherCollectionsRequest } from "../vault/models/request/cipher-collections.request";
import { CipherCreateRequest } from "../vault/models/request/cipher-create.request";
import { CipherPartialRequest } from "../vault/models/request/cipher-partial.request";
import { CipherShareRequest } from "../vault/models/request/cipher-share.request";
import { CipherRequest } from "../vault/models/request/cipher.request";
import { AttachmentUploadDataResponse } from "../vault/models/response/attachment-upload-data.response";
import { AttachmentResponse } from "../vault/models/response/attachment.response";
import { CipherResponse } from "../vault/models/response/cipher.response";
import { SyncResponse } from "../vault/models/response/sync.response";
/**
* @deprecated The `ApiService` class is deprecated and calls should be extracted into individual
@@ -206,6 +205,10 @@ export abstract class ApiService {
//passwordless
postAuthRequest: (request: PasswordlessCreateAuthRequest) => Promise<AuthRequestResponse>;
getAuthResponse: (id: string, accessCode: string) => Promise<AuthRequestResponse>;
getAuthRequest: (id: string) => Promise<AuthRequestResponse>;
putAuthRequest: (id: string, request: PasswordlessAuthRequest) => Promise<AuthRequestResponse>;
getAuthRequests: () => Promise<ListResponse<AuthRequestResponse>>;
getLastAuthRequest: () => Promise<AuthRequestResponse>;
getUserBillingHistory: () => Promise<BillingHistoryResponse>;
getUserBillingPayment: () => Promise<BillingPaymentResponse>;
@@ -260,11 +263,6 @@ export abstract class ApiService {
putCipherCollections: (id: string, request: CipherCollectionsRequest) => Promise<any>;
putCipherCollectionsAdmin: (id: string, request: CipherCollectionsRequest) => Promise<any>;
postPurgeCiphers: (request: SecretVerificationRequest, organizationId?: string) => Promise<any>;
postImportCiphers: (request: ImportCiphersRequest) => Promise<any>;
postImportOrganizationCiphers: (
organizationId: string,
request: ImportOrganizationCiphersRequest
) => Promise<any>;
putDeleteCipher: (id: string) => Promise<any>;
putDeleteCipherAdmin: (id: string) => Promise<any>;
putDeleteManyCiphers: (request: CipherBulkDeleteRequest) => Promise<any>;

View File

@@ -1,3 +1,5 @@
import { Jsonify } from "type-fest";
import {
ServerConfigData,
ThirdPartyServerConfigData,
@@ -37,4 +39,12 @@ export class ServerConfig {
expiresSoon(): boolean {
return this.getAgeInMilliseconds() >= eighteenHoursInMilliseconds;
}
static fromJSON(obj: Jsonify<ServerConfig>): ServerConfig {
if (obj == null) {
return null;
}
return new ServerConfig(obj);
}
}

View File

@@ -1,3 +1,4 @@
import { KdfConfig } from "../auth/models/domain/kdf-config";
import { HashPurpose } from "../enums/hashPurpose";
import { KdfType } from "../enums/kdfType";
import { KeySuffixOptions } from "../enums/keySuffixOptions";
@@ -47,13 +48,13 @@ export abstract class CryptoService {
password: string,
salt: string,
kdf: KdfType,
kdfIterations: number
kdfConfig: KdfConfig
) => Promise<SymmetricCryptoKey>;
makeKeyFromPin: (
pin: string,
salt: string,
kdf: KdfType,
kdfIterations: number,
kdfConfig: KdfConfig,
protectedKeyCs?: EncString
) => Promise<SymmetricCryptoKey>;
makeShareKey: () => Promise<[EncString, SymmetricCryptoKey]>;
@@ -62,7 +63,7 @@ export abstract class CryptoService {
pin: string,
salt: string,
kdf: KdfType,
kdfIterations: number
kdfConfig: KdfConfig
) => Promise<SymmetricCryptoKey>;
makeSendKey: (keyMaterial: ArrayBuffer) => Promise<SymmetricCryptoKey>;
hashPassword: (

View File

@@ -8,6 +8,13 @@ export abstract class CryptoFunctionService {
algorithm: "sha256" | "sha512",
iterations: number
) => Promise<ArrayBuffer>;
argon2: (
password: string | ArrayBuffer,
salt: string | ArrayBuffer,
iterations: number,
memory: number,
parallelism: number
) => Promise<ArrayBuffer>;
hkdf: (
ikm: ArrayBuffer,
salt: string | ArrayBuffer,

View File

@@ -34,4 +34,9 @@ export abstract class EnvironmentService {
setUrls: (urls: Urls) => Promise<Urls>;
getUrls: () => Urls;
isCloud: () => boolean;
/**
* @remarks For desktop and browser use only.
* For web, use PlatformUtilsService.isSelfHost()
*/
isSelfHosted: () => boolean;
}

View File

@@ -1,7 +1,7 @@
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
import { EncString } from "../models/domain/enc-string";
import { AttachmentUploadDataResponse } from "../models/response/attachment-upload-data.response";
import { SendFileUploadDataResponse } from "../models/response/send-file-upload-data.response";
import { AttachmentUploadDataResponse } from "../vault/models/response/attachment-upload-data.response";
export abstract class FileUploadService {
uploadSendFile: (

View File

@@ -1,11 +1,7 @@
import { Observable } from "rxjs";
export abstract class I18nService {
import { TranslationService } from "./translation.service";
export abstract class I18nService extends TranslationService {
locale$: Observable<string>;
supportedTranslationLocales: string[];
translationLocale: string;
collator: Intl.Collator;
localeNames: Map<string, string>;
t: (id: string, p1?: string | number, p2?: string | number, p3?: string | number) => string;
translate: (id: string, p1?: string, p2?: string, p3?: string) => string;
}

View File

@@ -0,0 +1,10 @@
import { ImportCiphersRequest } from "../../models/request/import-ciphers.request";
import { ImportOrganizationCiphersRequest } from "../../models/request/import-organization-ciphers.request";
export abstract class ImportApiServiceAbstraction {
postImportCiphers: (request: ImportCiphersRequest) => Promise<any>;
postImportOrganizationCiphers: (
organizationId: string,
request: ImportOrganizationCiphersRequest
) => Promise<any>;
}

View File

@@ -1,6 +1,6 @@
import { ImportOption, ImportType } from "../enums/importOptions";
import { ImportError } from "../importers/import-error";
import { Importer } from "../importers/importer";
import { ImportOption, ImportType } from "../../enums/importOptions";
import { ImportError } from "../../importers/import-error";
import { Importer } from "../../importers/importer";
export abstract class ImportService {
featuredImportOptions: readonly ImportOption[];

View File

@@ -6,6 +6,7 @@ export class OrganizationUserInviteRequest {
emails: string[] = [];
type: OrganizationUserType;
accessAll: boolean;
accessSecretsManager: boolean;
collections: SelectionReadOnlyRequest[] = [];
groups: string[];
permissions: PermissionsApi;

View File

@@ -1,4 +1,4 @@
import { SecretVerificationRequest } from "../../../models/request/secret-verification.request";
import { SecretVerificationRequest } from "../../../auth/models/request/secret-verification.request";
export class OrganizationUserResetPasswordEnrollmentRequest extends SecretVerificationRequest {
resetPasswordKey: string;

View File

@@ -5,6 +5,7 @@ import { SelectionReadOnlyRequest } from "../../../models/request/selection-read
export class OrganizationUserUpdateRequest {
type: OrganizationUserType;
accessAll: boolean;
accessSecretsManager: boolean;
collections: SelectionReadOnlyRequest[] = [];
groups: string[] = [];
permissions: PermissionsApi;

View File

@@ -10,7 +10,9 @@ export class OrganizationUserResponse extends BaseResponse {
userId: string;
type: OrganizationUserType;
status: OrganizationUserStatusType;
externalId: string;
accessAll: boolean;
accessSecretsManager: boolean;
permissions: PermissionsApi;
resetPasswordEnrolled: boolean;
collections: SelectionReadOnlyResponse[] = [];
@@ -23,7 +25,9 @@ export class OrganizationUserResponse extends BaseResponse {
this.type = this.getResponseProperty("Type");
this.status = this.getResponseProperty("Status");
this.permissions = new PermissionsApi(this.getResponseProperty("Permissions"));
this.externalId = this.getResponseProperty("ExternalId");
this.accessAll = this.getResponseProperty("AccessAll");
this.accessSecretsManager = this.getResponseProperty("AccessSecretsManager");
this.resetPasswordEnrolled = this.getResponseProperty("ResetPasswordEnrolled");
const collections = this.getResponseProperty("Collections");
@@ -61,6 +65,8 @@ export class OrganizationUserDetailsResponse extends OrganizationUserResponse {
export class OrganizationUserResetPasswordDetailsReponse extends BaseResponse {
kdf: KdfType;
kdfIterations: number;
kdfMemory?: number;
kdfParallelism?: number;
resetPasswordKey: string;
encryptedPrivateKey: string;
@@ -68,6 +74,8 @@ export class OrganizationUserResetPasswordDetailsReponse extends BaseResponse {
super(response);
this.kdf = this.getResponseProperty("Kdf");
this.kdfIterations = this.getResponseProperty("KdfIterations");
this.kdfMemory = this.getResponseProperty("KdfMemory");
this.kdfParallelism = this.getResponseProperty("KdfParallelism");
this.resetPasswordKey = this.getResponseProperty("ResetPasswordKey");
this.encryptedPrivateKey = this.getResponseProperty("EncryptedPrivateKey");
}

View File

@@ -1,4 +1,8 @@
import { OrganizationApiKeyType } from "../../enums/organizationApiKeyType";
import { OrganizationApiKeyType } from "../../auth/enums/organization-api-key-type";
import { OrganizationSsoRequest } from "../../auth/models/request/organization-sso.request";
import { SecretVerificationRequest } from "../../auth/models/request/secret-verification.request";
import { ApiKeyResponse } from "../../auth/models/response/api-key.response";
import { OrganizationSsoResponse } from "../../auth/models/response/organization-sso.response";
import { ImportDirectoryRequest } from "../../models/request/import-directory.request";
import { OrganizationApiKeyRequest } from "../../models/request/organization-api-key.request";
import { OrganizationCreateRequest } from "../../models/request/organization-create.request";
@@ -7,13 +11,10 @@ import { OrganizationSubscriptionUpdateRequest } from "../../models/request/orga
import { OrganizationTaxInfoUpdateRequest } from "../../models/request/organization-tax-info-update.request";
import { OrganizationUpdateRequest } from "../../models/request/organization-update.request";
import { OrganizationUpgradeRequest } from "../../models/request/organization-upgrade.request";
import { OrganizationSsoRequest } from "../../models/request/organization/organization-sso.request";
import { PaymentRequest } from "../../models/request/payment.request";
import { SeatRequest } from "../../models/request/seat.request";
import { SecretVerificationRequest } from "../../models/request/secret-verification.request";
import { StorageRequest } from "../../models/request/storage.request";
import { VerifyBankRequest } from "../../models/request/verify-bank.request";
import { ApiKeyResponse } from "../../models/response/api-key.response";
import { BillingResponse } from "../../models/response/billing.response";
import { ListResponse } from "../../models/response/list.response";
import { OrganizationApiKeyInformationResponse } from "../../models/response/organization-api-key-information.response";
@@ -21,7 +22,6 @@ import { OrganizationAutoEnrollStatusResponse } from "../../models/response/orga
import { OrganizationKeysResponse } from "../../models/response/organization-keys.response";
import { OrganizationSubscriptionResponse } from "../../models/response/organization-subscription.response";
import { OrganizationResponse } from "../../models/response/organization.response";
import { OrganizationSsoResponse } from "../../models/response/organization/organization-sso.response";
import { PaymentResponse } from "../../models/response/payment.response";
import { TaxInfoResponse } from "../../models/response/tax-info.response";
@@ -58,4 +58,5 @@ export class OrganizationApiServiceAbstraction {
updateKeys: (id: string, request: OrganizationKeysRequest) => Promise<OrganizationKeysResponse>;
getSso: (id: string) => Promise<OrganizationSsoResponse>;
updateSso: (id: string, request: OrganizationSsoRequest) => Promise<OrganizationSsoResponse>;
selfHostedSyncLicense: (id: string) => Promise<void>;
}

View File

@@ -1,5 +1,5 @@
import { CipherView } from "../models/view/cipher.view";
import { SendView } from "../models/view/send.view";
import { CipherView } from "../vault/models/view/cipher.view";
export abstract class SearchService {
indexedEntityId?: string = null;

View File

@@ -1,14 +1,13 @@
import { Observable } from "rxjs";
import { EnvironmentUrls } from "../auth/models/domain/environment-urls";
import { KdfConfig } from "../auth/models/domain/kdf-config";
import { KdfType } from "../enums/kdfType";
import { ThemeType } from "../enums/themeType";
import { UriMatchType } from "../enums/uriMatchType";
import { CipherData } from "../models/data/cipher.data";
import { CollectionData } from "../models/data/collection.data";
import { EncryptedOrganizationKeyData } from "../models/data/encrypted-organization-key.data";
import { EventData } from "../models/data/event.data";
import { FolderData } from "../models/data/folder.data";
import { LocalData } from "../models/data/local.data";
import { OrganizationData } from "../models/data/organization.data";
import { PolicyData } from "../models/data/policy.data";
import { ProviderData } from "../models/data/provider.data";
@@ -16,15 +15,17 @@ import { SendData } from "../models/data/send.data";
import { ServerConfigData } from "../models/data/server-config.data";
import { Account, AccountSettingsSettings } from "../models/domain/account";
import { EncString } from "../models/domain/enc-string";
import { EnvironmentUrls } from "../models/domain/environment-urls";
import { GeneratedPasswordHistory } from "../models/domain/generated-password-history";
import { Policy } from "../models/domain/policy";
import { StorageOptions } from "../models/domain/storage-options";
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
import { WindowState } from "../models/domain/window-state";
import { CipherView } from "../models/view/cipher.view";
import { CollectionView } from "../models/view/collection.view";
import { SendView } from "../models/view/send.view";
import { CipherData } from "../vault/models/data/cipher.data";
import { FolderData } from "../vault/models/data/folder.data";
import { LocalData } from "../vault/models/data/local.data";
import { CipherView } from "../vault/models/view/cipher.view";
export abstract class StateService<T extends Account = Account> {
accounts$: Observable<{ [userId: string]: T }>;
@@ -141,6 +142,8 @@ export abstract class StateService<T extends Account = Account> {
setDisableFavicon: (value: boolean, options?: StorageOptions) => Promise<void>;
getDisableGa: (options?: StorageOptions) => Promise<boolean>;
setDisableGa: (value: boolean, options?: StorageOptions) => Promise<void>;
getDismissedAutofillCallout: (options?: StorageOptions) => Promise<boolean>;
setDismissedAutofillCallout: (value: boolean, options?: StorageOptions) => Promise<void>;
getDontShowCardsCurrentTab: (options?: StorageOptions) => Promise<boolean>;
setDontShowCardsCurrentTab: (value: boolean, options?: StorageOptions) => Promise<void>;
getDontShowIdentitiesCurrentTab: (options?: StorageOptions) => Promise<boolean>;
@@ -252,8 +255,8 @@ export abstract class StateService<T extends Account = Account> {
getInstalledVersion: (options?: StorageOptions) => Promise<string>;
setInstalledVersion: (value: string, options?: StorageOptions) => Promise<void>;
getIsAuthenticated: (options?: StorageOptions) => Promise<boolean>;
getKdfIterations: (options?: StorageOptions) => Promise<number>;
setKdfIterations: (value: number, options?: StorageOptions) => Promise<void>;
getKdfConfig: (options?: StorageOptions) => Promise<KdfConfig>;
setKdfConfig: (kdfConfig: KdfConfig, options?: StorageOptions) => Promise<void>;
getKdfType: (options?: StorageOptions) => Promise<KdfType>;
setKdfType: (value: KdfType, options?: StorageOptions) => Promise<void>;
getKeyHash: (options?: StorageOptions) => Promise<string>;
@@ -337,6 +340,8 @@ export abstract class StateService<T extends Account = Account> {
setVaultTimeout: (value: number, options?: StorageOptions) => Promise<void>;
getVaultTimeoutAction: (options?: StorageOptions) => Promise<string>;
setVaultTimeoutAction: (value: string, options?: StorageOptions) => Promise<void>;
getApproveLoginRequests: (options?: StorageOptions) => Promise<boolean>;
setApproveLoginRequests: (value: boolean, options?: StorageOptions) => Promise<void>;
getStateVersion: () => Promise<number>;
setStateVersion: (value: number) => Promise<void>;
getWindow: () => Promise<WindowState>;

View File

@@ -1,4 +1,4 @@
import { AuthService } from "./auth.service";
import { AuthService } from "../auth/abstractions/auth.service";
export abstract class SystemService {
startProcessReload: (authService: AuthService) => Promise<void>;

View File

@@ -0,0 +1,8 @@
export abstract class TranslationService {
supportedTranslationLocales: string[];
translationLocale: string;
collator: Intl.Collator;
localeNames: Map<string, string>;
t: (id: string, p1?: string | number, p2?: string | number, p3?: string | number) => string;
translate: (id: string, p1?: string, p2?: string, p3?: string) => string;
}

View File

@@ -1,4 +1,4 @@
import { VerifyOTPRequest } from "../../models/request/account/verify-otp.request";
import { VerifyOTPRequest } from "../../auth/models/request/verify-otp.request";
export abstract class UserVerificationApiServiceAbstraction {
postAccountVerifyOTP: (request: VerifyOTPRequest) => Promise<void>;

View File

@@ -1,4 +1,4 @@
import { SecretVerificationRequest } from "../../models/request/secret-verification.request";
import { SecretVerificationRequest } from "../../auth/models/request/secret-verification.request";
import { Verification } from "../../types/verification";
export abstract class UserVerificationService {

View File

@@ -1,4 +1,4 @@
import { SecretVerificationRequest } from "../../models/request/secret-verification.request";
import { SecretVerificationRequest } from "../models/request/secret-verification.request";
export abstract class AccountApiService {
abstract deleteAccount(request: SecretVerificationRequest): Promise<void>;

View File

@@ -1,6 +1,8 @@
import { Observable } from "rxjs";
import { AuthenticationStatus } from "../enums/authenticationStatus";
import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
import { AuthRequestPushNotification } from "../../models/response/notification.response";
import { AuthenticationStatus } from "../enums/authentication-status";
import { AuthResult } from "../models/domain/auth-result";
import {
UserApiLogInCredentials,
@@ -8,9 +10,8 @@ import {
SsoLogInCredentials,
PasswordlessLogInCredentials,
} from "../models/domain/log-in-credentials";
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
import { TokenTwoFactorRequest } from "../models/request/identity-token/token-two-factor.request";
import { AuthRequestPushNotification } from "../models/response/notification.response";
import { AuthRequestResponse } from "../models/response/auth-request.response";
export abstract class AuthService {
masterPasswordHash: string;
@@ -37,6 +38,10 @@ export abstract class AuthService {
authingWithPasswordless: () => boolean;
getAuthStatus: (userId?: string) => Promise<AuthenticationStatus>;
authResponsePushNotifiction: (notification: AuthRequestPushNotification) => Promise<any>;
passwordlessLogin: (
id: string,
key: string,
requestApproved: boolean
) => Promise<AuthRequestResponse>;
getPushNotifcationObs$: () => Observable<any>;
}

View File

@@ -1,4 +1,4 @@
import { Organization } from "../models/domain/organization";
import { Organization } from "../../models/domain/organization";
import { IdentityTokenResponse } from "../models/response/identity-token.response";
export abstract class KeyConnectorService {

View File

@@ -1,4 +1,4 @@
import { TwoFactorProviderType } from "../enums/twoFactorProviderType";
import { TwoFactorProviderType } from "../enums/two-factor-provider-type";
import { IdentityTwoFactorResponse } from "../models/response/identity-two-factor.response";
export interface TwoFactorProviderDetails {

View File

@@ -1,6 +1,5 @@
import { I18nService } from "../abstractions/i18n.service";
import { IFrameComponent } from "./iframe_component";
import { IFrameComponent } from "../misc/iframe_component";
export class CaptchaIFrame extends IFrameComponent {
constructor(

View File

@@ -0,0 +1,294 @@
import { mock, MockProxy } from "jest-mock-extended";
import { ApiService } from "../../abstractions/api.service";
import { AppIdService } from "../../abstractions/appId.service";
import { CryptoService } from "../../abstractions/crypto.service";
import { LogService } from "../../abstractions/log.service";
import { MessagingService } from "../../abstractions/messaging.service";
import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
import { StateService } from "../../abstractions/state.service";
import { Utils } from "../../misc/utils";
import { Account, AccountProfile, AccountTokens } from "../../models/domain/account";
import { EncString } from "../../models/domain/enc-string";
import { AuthService } from "../abstractions/auth.service";
import { TokenService } from "../abstractions/token.service";
import { TwoFactorService } from "../abstractions/two-factor.service";
import { TwoFactorProviderType } from "../enums/two-factor-provider-type";
import { AuthResult } from "../models/domain/auth-result";
import { PasswordLogInCredentials } from "../models/domain/log-in-credentials";
import { PasswordTokenRequest } from "../models/request/identity-token/password-token.request";
import { TokenTwoFactorRequest } from "../models/request/identity-token/token-two-factor.request";
import { IdentityCaptchaResponse } from "../models/response/identity-captcha.response";
import { IdentityTokenResponse } from "../models/response/identity-token.response";
import { IdentityTwoFactorResponse } from "../models/response/identity-two-factor.response";
import { PasswordLogInStrategy } from "./password-login.strategy";
const email = "hello@world.com";
const masterPassword = "password";
const deviceId = Utils.newGuid();
const accessToken = "ACCESS_TOKEN";
const refreshToken = "REFRESH_TOKEN";
const encKey = "ENC_KEY";
const privateKey = "PRIVATE_KEY";
const captchaSiteKey = "CAPTCHA_SITE_KEY";
const kdf = 0;
const kdfIterations = 10000;
const userId = Utils.newGuid();
const masterPasswordHash = "MASTER_PASSWORD_HASH";
const name = "NAME";
const decodedToken = {
sub: userId,
name: name,
email: email,
premium: false,
};
const twoFactorProviderType = TwoFactorProviderType.Authenticator;
const twoFactorToken = "TWO_FACTOR_TOKEN";
const twoFactorRemember = true;
export function identityTokenResponseFactory() {
return new IdentityTokenResponse({
ForcePasswordReset: false,
Kdf: kdf,
KdfIterations: kdfIterations,
Key: encKey,
PrivateKey: privateKey,
ResetMasterPassword: false,
access_token: accessToken,
expires_in: 3600,
refresh_token: refreshToken,
scope: "api offline_access",
token_type: "Bearer",
});
}
describe("LogInStrategy", () => {
let cryptoService: MockProxy<CryptoService>;
let apiService: MockProxy<ApiService>;
let tokenService: MockProxy<TokenService>;
let appIdService: MockProxy<AppIdService>;
let platformUtilsService: MockProxy<PlatformUtilsService>;
let messagingService: MockProxy<MessagingService>;
let logService: MockProxy<LogService>;
let stateService: MockProxy<StateService>;
let twoFactorService: MockProxy<TwoFactorService>;
let authService: MockProxy<AuthService>;
let passwordLogInStrategy: PasswordLogInStrategy;
let credentials: PasswordLogInCredentials;
beforeEach(async () => {
cryptoService = mock<CryptoService>();
apiService = mock<ApiService>();
tokenService = mock<TokenService>();
appIdService = mock<AppIdService>();
platformUtilsService = mock<PlatformUtilsService>();
messagingService = mock<MessagingService>();
logService = mock<LogService>();
stateService = mock<StateService>();
twoFactorService = mock<TwoFactorService>();
authService = mock<AuthService>();
appIdService.getAppId.mockResolvedValue(deviceId);
tokenService.decodeToken.calledWith(accessToken).mockResolvedValue(decodedToken);
// The base class is abstract so we test it via PasswordLogInStrategy
passwordLogInStrategy = new PasswordLogInStrategy(
cryptoService,
apiService,
tokenService,
appIdService,
platformUtilsService,
messagingService,
logService,
stateService,
twoFactorService,
authService
);
credentials = new PasswordLogInCredentials(email, masterPassword);
});
describe("base class", () => {
it("sets the local environment after a successful login", async () => {
apiService.postIdentityToken.mockResolvedValue(identityTokenResponseFactory());
await passwordLogInStrategy.logIn(credentials);
expect(stateService.addAccount).toHaveBeenCalledWith(
new Account({
profile: {
...new AccountProfile(),
...{
userId: userId,
name: name,
email: email,
hasPremiumPersonally: false,
kdfIterations: kdfIterations,
kdfType: kdf,
},
},
tokens: {
...new AccountTokens(),
...{
accessToken: accessToken,
refreshToken: refreshToken,
},
},
})
);
expect(cryptoService.setEncKey).toHaveBeenCalledWith(encKey);
expect(cryptoService.setEncPrivateKey).toHaveBeenCalledWith(privateKey);
expect(messagingService.send).toHaveBeenCalledWith("loggedIn");
});
it("builds AuthResult", async () => {
const tokenResponse = identityTokenResponseFactory();
tokenResponse.forcePasswordReset = true;
tokenResponse.resetMasterPassword = true;
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
const result = await passwordLogInStrategy.logIn(credentials);
expect(result).toEqual({
forcePasswordReset: true,
resetMasterPassword: true,
twoFactorProviders: null,
captchaSiteKey: "",
} as AuthResult);
});
it("rejects login if CAPTCHA is required", async () => {
// Sample CAPTCHA response
const tokenResponse = new IdentityCaptchaResponse({
error: "invalid_grant",
error_description: "Captcha required.",
HCaptcha_SiteKey: captchaSiteKey,
});
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
const result = await passwordLogInStrategy.logIn(credentials);
expect(stateService.addAccount).not.toHaveBeenCalled();
expect(messagingService.send).not.toHaveBeenCalled();
const expected = new AuthResult();
expected.captchaSiteKey = captchaSiteKey;
expect(result).toEqual(expected);
});
it("makes a new public and private key for an old account", async () => {
const tokenResponse = identityTokenResponseFactory();
tokenResponse.privateKey = null;
cryptoService.makeKeyPair.mockResolvedValue(["PUBLIC_KEY", new EncString("PRIVATE_KEY")]);
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
await passwordLogInStrategy.logIn(credentials);
// User key must be set before the new RSA keypair is generated, otherwise we can't decrypt the EncKey
expect(cryptoService.setKey).toHaveBeenCalled();
expect(cryptoService.makeKeyPair).toHaveBeenCalled();
expect(cryptoService.setKey.mock.invocationCallOrder[0]).toBeLessThan(
cryptoService.makeKeyPair.mock.invocationCallOrder[0]
);
expect(apiService.postAccountKeys).toHaveBeenCalled();
});
});
describe("Two-factor authentication", () => {
it("rejects login if 2FA is required", async () => {
// Sample response where TOTP 2FA required
const tokenResponse = new IdentityTwoFactorResponse({
TwoFactorProviders: ["0"],
TwoFactorProviders2: { 0: null },
error: "invalid_grant",
error_description: "Two factor required.",
});
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
const result = await passwordLogInStrategy.logIn(credentials);
expect(stateService.addAccount).not.toHaveBeenCalled();
expect(messagingService.send).not.toHaveBeenCalled();
const expected = new AuthResult();
expected.twoFactorProviders = new Map<TwoFactorProviderType, { [key: string]: string }>();
expected.twoFactorProviders.set(0, null);
expect(result).toEqual(expected);
});
it("sends stored 2FA token to server", async () => {
tokenService.getTwoFactorToken.mockResolvedValue(twoFactorToken);
apiService.postIdentityToken.mockResolvedValue(identityTokenResponseFactory());
await passwordLogInStrategy.logIn(credentials);
expect(apiService.postIdentityToken).toHaveBeenCalledWith(
expect.objectContaining({
twoFactor: {
provider: TwoFactorProviderType.Remember,
token: twoFactorToken,
remember: false,
} as TokenTwoFactorRequest,
})
);
});
it("sends 2FA token provided by user to server (single step)", async () => {
// This occurs if the user enters the 2FA code as an argument in the CLI
apiService.postIdentityToken.mockResolvedValue(identityTokenResponseFactory());
credentials.twoFactor = new TokenTwoFactorRequest(
twoFactorProviderType,
twoFactorToken,
twoFactorRemember
);
await passwordLogInStrategy.logIn(credentials);
expect(apiService.postIdentityToken).toHaveBeenCalledWith(
expect.objectContaining({
twoFactor: {
provider: twoFactorProviderType,
token: twoFactorToken,
remember: twoFactorRemember,
} as TokenTwoFactorRequest,
})
);
});
it("sends 2FA token provided by user to server (two-step)", async () => {
// Simulate a partially completed login
passwordLogInStrategy.tokenRequest = new PasswordTokenRequest(
email,
masterPasswordHash,
null,
null
);
apiService.postIdentityToken.mockResolvedValue(identityTokenResponseFactory());
await passwordLogInStrategy.logInTwoFactor(
new TokenTwoFactorRequest(twoFactorProviderType, twoFactorToken, twoFactorRemember),
null
);
expect(apiService.postIdentityToken).toHaveBeenCalledWith(
expect.objectContaining({
twoFactor: {
provider: twoFactorProviderType,
token: twoFactorToken,
remember: twoFactorRemember,
} as TokenTwoFactorRequest,
})
);
});
});
});

View File

@@ -5,26 +5,26 @@ import { LogService } from "../../abstractions/log.service";
import { MessagingService } from "../../abstractions/messaging.service";
import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
import { StateService } from "../../abstractions/state.service";
import { TokenService } from "../../abstractions/token.service";
import { TwoFactorService } from "../../abstractions/twoFactor.service";
import { TwoFactorProviderType } from "../../enums/twoFactorProviderType";
import { Account, AccountProfile, AccountTokens } from "../../models/domain/account";
import { AuthResult } from "../../models/domain/auth-result";
import { KeysRequest } from "../../models/request/keys.request";
import { TokenService } from "../abstractions/token.service";
import { TwoFactorService } from "../abstractions/two-factor.service";
import { TwoFactorProviderType } from "../enums/two-factor-provider-type";
import { AuthResult } from "../models/domain/auth-result";
import {
UserApiLogInCredentials,
PasswordLogInCredentials,
SsoLogInCredentials,
PasswordlessLogInCredentials,
} from "../../models/domain/log-in-credentials";
import { DeviceRequest } from "../../models/request/device.request";
import { PasswordTokenRequest } from "../../models/request/identity-token/password-token.request";
import { SsoTokenRequest } from "../../models/request/identity-token/sso-token.request";
import { TokenTwoFactorRequest } from "../../models/request/identity-token/token-two-factor.request";
import { UserApiTokenRequest } from "../../models/request/identity-token/user-api-token.request";
import { KeysRequest } from "../../models/request/keys.request";
import { IdentityCaptchaResponse } from "../../models/response/identity-captcha.response";
import { IdentityTokenResponse } from "../../models/response/identity-token.response";
import { IdentityTwoFactorResponse } from "../../models/response/identity-two-factor.response";
} from "../models/domain/log-in-credentials";
import { DeviceRequest } from "../models/request/identity-token/device.request";
import { PasswordTokenRequest } from "../models/request/identity-token/password-token.request";
import { SsoTokenRequest } from "../models/request/identity-token/sso-token.request";
import { TokenTwoFactorRequest } from "../models/request/identity-token/token-two-factor.request";
import { UserApiTokenRequest } from "../models/request/identity-token/user-api-token.request";
import { IdentityCaptchaResponse } from "../models/response/identity-captcha.response";
import { IdentityTokenResponse } from "../models/response/identity-token.response";
import { IdentityTwoFactorResponse } from "../models/response/identity-two-factor.response";
export abstract class LogInStrategy {
protected abstract tokenRequest: UserApiTokenRequest | PasswordTokenRequest | SsoTokenRequest;
@@ -107,6 +107,8 @@ export abstract class LogInStrategy {
email: accountInformation.email,
hasPremiumPersonally: accountInformation.premium,
kdfIterations: tokenResponse.kdfIterations,
kdfMemory: tokenResponse.kdfMemory,
kdfParallelism: tokenResponse.kdfParallelism,
kdfType: tokenResponse.kdf,
},
},

View File

@@ -0,0 +1,113 @@
import { mock, MockProxy } from "jest-mock-extended";
import { ApiService } from "../../abstractions/api.service";
import { AppIdService } from "../../abstractions/appId.service";
import { CryptoService } from "../../abstractions/crypto.service";
import { LogService } from "../../abstractions/log.service";
import { MessagingService } from "../../abstractions/messaging.service";
import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
import { StateService } from "../../abstractions/state.service";
import { HashPurpose } from "../../enums/hashPurpose";
import { Utils } from "../../misc/utils";
import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
import { AuthService } from "../abstractions/auth.service";
import { TokenService } from "../abstractions/token.service";
import { TwoFactorService } from "../abstractions/two-factor.service";
import { PasswordLogInCredentials } from "../models/domain/log-in-credentials";
import { identityTokenResponseFactory } from "./login.strategy.spec";
import { PasswordLogInStrategy } from "./password-login.strategy";
const email = "hello@world.com";
const masterPassword = "password";
const hashedPassword = "HASHED_PASSWORD";
const localHashedPassword = "LOCAL_HASHED_PASSWORD";
const preloginKey = new SymmetricCryptoKey(
Utils.fromB64ToArray(
"N2KWjlLpfi5uHjv+YcfUKIpZ1l+W+6HRensmIqD+BFYBf6N/dvFpJfWwYnVBdgFCK2tJTAIMLhqzIQQEUmGFgg=="
)
);
const deviceId = Utils.newGuid();
describe("PasswordLogInStrategy", () => {
let cryptoService: MockProxy<CryptoService>;
let apiService: MockProxy<ApiService>;
let tokenService: MockProxy<TokenService>;
let appIdService: MockProxy<AppIdService>;
let platformUtilsService: MockProxy<PlatformUtilsService>;
let messagingService: MockProxy<MessagingService>;
let logService: MockProxy<LogService>;
let stateService: MockProxy<StateService>;
let twoFactorService: MockProxy<TwoFactorService>;
let authService: MockProxy<AuthService>;
let passwordLogInStrategy: PasswordLogInStrategy;
let credentials: PasswordLogInCredentials;
beforeEach(async () => {
cryptoService = mock<CryptoService>();
apiService = mock<ApiService>();
tokenService = mock<TokenService>();
appIdService = mock<AppIdService>();
platformUtilsService = mock<PlatformUtilsService>();
messagingService = mock<MessagingService>();
logService = mock<LogService>();
stateService = mock<StateService>();
twoFactorService = mock<TwoFactorService>();
authService = mock<AuthService>();
appIdService.getAppId.mockResolvedValue(deviceId);
tokenService.decodeToken.mockResolvedValue({});
authService.makePreloginKey.mockResolvedValue(preloginKey);
cryptoService.hashPassword
.calledWith(masterPassword, expect.anything(), undefined)
.mockResolvedValue(hashedPassword);
cryptoService.hashPassword
.calledWith(masterPassword, expect.anything(), HashPurpose.LocalAuthorization)
.mockResolvedValue(localHashedPassword);
passwordLogInStrategy = new PasswordLogInStrategy(
cryptoService,
apiService,
tokenService,
appIdService,
platformUtilsService,
messagingService,
logService,
stateService,
twoFactorService,
authService
);
credentials = new PasswordLogInCredentials(email, masterPassword);
apiService.postIdentityToken.mockResolvedValue(identityTokenResponseFactory());
});
it("sends master password credentials to the server", async () => {
await passwordLogInStrategy.logIn(credentials);
expect(apiService.postIdentityToken).toHaveBeenCalledWith(
expect.objectContaining({
email: email,
masterPasswordHash: hashedPassword,
device: expect.objectContaining({
identifier: deviceId,
}),
twoFactor: expect.objectContaining({
provider: null,
token: null,
}),
captchaResponse: undefined,
})
);
});
it("sets the local environment after a successful login", async () => {
await passwordLogInStrategy.logIn(credentials);
expect(cryptoService.setKey).toHaveBeenCalledWith(preloginKey);
expect(cryptoService.setKeyHash).toHaveBeenCalledWith(localHashedPassword);
});
});

View File

@@ -1,21 +1,21 @@
import { ApiService } from "../../abstractions/api.service";
import { AppIdService } from "../../abstractions/appId.service";
import { AuthService } from "../../abstractions/auth.service";
import { CryptoService } from "../../abstractions/crypto.service";
import { LogService } from "../../abstractions/log.service";
import { MessagingService } from "../../abstractions/messaging.service";
import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
import { StateService } from "../../abstractions/state.service";
import { TokenService } from "../../abstractions/token.service";
import { TwoFactorService } from "../../abstractions/twoFactor.service";
import { HashPurpose } from "../../enums/hashPurpose";
import { AuthResult } from "../../models/domain/auth-result";
import { PasswordLogInCredentials } from "../../models/domain/log-in-credentials";
import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
import { PasswordTokenRequest } from "../../models/request/identity-token/password-token.request";
import { TokenTwoFactorRequest } from "../../models/request/identity-token/token-two-factor.request";
import { AuthService } from "../abstractions/auth.service";
import { TokenService } from "../abstractions/token.service";
import { TwoFactorService } from "../abstractions/two-factor.service";
import { AuthResult } from "../models/domain/auth-result";
import { PasswordLogInCredentials } from "../models/domain/log-in-credentials";
import { PasswordTokenRequest } from "../models/request/identity-token/password-token.request";
import { TokenTwoFactorRequest } from "../models/request/identity-token/token-two-factor.request";
import { LogInStrategy } from "./logIn.strategy";
import { LogInStrategy } from "./login.strategy";
export class PasswordLogInStrategy extends LogInStrategy {
get email() {

View File

@@ -1,19 +1,19 @@
import { ApiService } from "../../abstractions/api.service";
import { AppIdService } from "../../abstractions/appId.service";
import { AuthService } from "../../abstractions/auth.service";
import { CryptoService } from "../../abstractions/crypto.service";
import { LogService } from "../../abstractions/log.service";
import { MessagingService } from "../../abstractions/messaging.service";
import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
import { StateService } from "../../abstractions/state.service";
import { TokenService } from "../../abstractions/token.service";
import { TwoFactorService } from "../../abstractions/twoFactor.service";
import { AuthResult } from "../../models/domain/auth-result";
import { PasswordlessLogInCredentials } from "../../models/domain/log-in-credentials";
import { PasswordTokenRequest } from "../../models/request/identity-token/password-token.request";
import { TokenTwoFactorRequest } from "../../models/request/identity-token/token-two-factor.request";
import { AuthService } from "../abstractions/auth.service";
import { TokenService } from "../abstractions/token.service";
import { TwoFactorService } from "../abstractions/two-factor.service";
import { AuthResult } from "../models/domain/auth-result";
import { PasswordlessLogInCredentials } from "../models/domain/log-in-credentials";
import { PasswordTokenRequest } from "../models/request/identity-token/password-token.request";
import { TokenTwoFactorRequest } from "../models/request/identity-token/token-two-factor.request";
import { LogInStrategy } from "./logIn.strategy";
import { LogInStrategy } from "./login.strategy";
export class PasswordlessLogInStrategy extends LogInStrategy {
get email() {

View File

@@ -0,0 +1,130 @@
import { mock, MockProxy } from "jest-mock-extended";
import { ApiService } from "../../abstractions/api.service";
import { AppIdService } from "../../abstractions/appId.service";
import { CryptoService } from "../../abstractions/crypto.service";
import { LogService } from "../../abstractions/log.service";
import { MessagingService } from "../../abstractions/messaging.service";
import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
import { StateService } from "../../abstractions/state.service";
import { Utils } from "../../misc/utils";
import { KeyConnectorService } from "../abstractions/key-connector.service";
import { TokenService } from "../abstractions/token.service";
import { TwoFactorService } from "../abstractions/two-factor.service";
import { SsoLogInCredentials } from "../models/domain/log-in-credentials";
import { identityTokenResponseFactory } from "./login.strategy.spec";
import { SsoLogInStrategy } from "./sso-login.strategy";
describe("SsoLogInStrategy", () => {
let cryptoService: MockProxy<CryptoService>;
let apiService: MockProxy<ApiService>;
let tokenService: MockProxy<TokenService>;
let appIdService: MockProxy<AppIdService>;
let platformUtilsService: MockProxy<PlatformUtilsService>;
let messagingService: MockProxy<MessagingService>;
let logService: MockProxy<LogService>;
let stateService: MockProxy<StateService>;
let twoFactorService: MockProxy<TwoFactorService>;
let keyConnectorService: MockProxy<KeyConnectorService>;
let ssoLogInStrategy: SsoLogInStrategy;
let credentials: SsoLogInCredentials;
const deviceId = Utils.newGuid();
const keyConnectorUrl = "KEY_CONNECTOR_URL";
const ssoCode = "SSO_CODE";
const ssoCodeVerifier = "SSO_CODE_VERIFIER";
const ssoRedirectUrl = "SSO_REDIRECT_URL";
const ssoOrgId = "SSO_ORG_ID";
beforeEach(async () => {
cryptoService = mock<CryptoService>();
apiService = mock<ApiService>();
tokenService = mock<TokenService>();
appIdService = mock<AppIdService>();
platformUtilsService = mock<PlatformUtilsService>();
messagingService = mock<MessagingService>();
logService = mock<LogService>();
stateService = mock<StateService>();
twoFactorService = mock<TwoFactorService>();
keyConnectorService = mock<KeyConnectorService>();
tokenService.getTwoFactorToken.mockResolvedValue(null);
appIdService.getAppId.mockResolvedValue(deviceId);
tokenService.decodeToken.mockResolvedValue({});
ssoLogInStrategy = new SsoLogInStrategy(
cryptoService,
apiService,
tokenService,
appIdService,
platformUtilsService,
messagingService,
logService,
stateService,
twoFactorService,
keyConnectorService
);
credentials = new SsoLogInCredentials(ssoCode, ssoCodeVerifier, ssoRedirectUrl, ssoOrgId);
});
it("sends SSO information to server", async () => {
apiService.postIdentityToken.mockResolvedValue(identityTokenResponseFactory());
await ssoLogInStrategy.logIn(credentials);
expect(apiService.postIdentityToken).toHaveBeenCalledWith(
expect.objectContaining({
code: ssoCode,
codeVerifier: ssoCodeVerifier,
redirectUri: ssoRedirectUrl,
device: expect.objectContaining({
identifier: deviceId,
}),
twoFactor: expect.objectContaining({
provider: null,
token: null,
}),
})
);
});
it("does not set keys for new SSO user flow", async () => {
const tokenResponse = identityTokenResponseFactory();
tokenResponse.key = null;
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
await ssoLogInStrategy.logIn(credentials);
expect(cryptoService.setEncPrivateKey).not.toHaveBeenCalled();
expect(cryptoService.setEncKey).not.toHaveBeenCalled();
});
it("gets and sets KeyConnector key for enrolled user", async () => {
const tokenResponse = identityTokenResponseFactory();
tokenResponse.keyConnectorUrl = keyConnectorUrl;
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
await ssoLogInStrategy.logIn(credentials);
expect(keyConnectorService.getAndSetKey).toHaveBeenCalledWith(keyConnectorUrl);
});
it("converts new SSO user to Key Connector on first login", async () => {
const tokenResponse = identityTokenResponseFactory();
tokenResponse.keyConnectorUrl = keyConnectorUrl;
tokenResponse.key = null;
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
await ssoLogInStrategy.logIn(credentials);
expect(keyConnectorService.convertNewSsoUserToKeyConnector).toHaveBeenCalledWith(
tokenResponse,
ssoOrgId
);
});
});

View File

@@ -1,18 +1,18 @@
import { ApiService } from "../../abstractions/api.service";
import { AppIdService } from "../../abstractions/appId.service";
import { CryptoService } from "../../abstractions/crypto.service";
import { KeyConnectorService } from "../../abstractions/keyConnector.service";
import { LogService } from "../../abstractions/log.service";
import { MessagingService } from "../../abstractions/messaging.service";
import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
import { StateService } from "../../abstractions/state.service";
import { TokenService } from "../../abstractions/token.service";
import { TwoFactorService } from "../../abstractions/twoFactor.service";
import { SsoLogInCredentials } from "../../models/domain/log-in-credentials";
import { SsoTokenRequest } from "../../models/request/identity-token/sso-token.request";
import { IdentityTokenResponse } from "../../models/response/identity-token.response";
import { KeyConnectorService } from "../abstractions/key-connector.service";
import { TokenService } from "../abstractions/token.service";
import { TwoFactorService } from "../abstractions/two-factor.service";
import { SsoLogInCredentials } from "../models/domain/log-in-credentials";
import { SsoTokenRequest } from "../models/request/identity-token/sso-token.request";
import { IdentityTokenResponse } from "../models/response/identity-token.response";
import { LogInStrategy } from "./logIn.strategy";
import { LogInStrategy } from "./login.strategy";
export class SsoLogInStrategy extends LogInStrategy {
tokenRequest: SsoTokenRequest;

View File

@@ -0,0 +1,115 @@
import { mock, MockProxy } from "jest-mock-extended";
import { ApiService } from "../../abstractions/api.service";
import { AppIdService } from "../../abstractions/appId.service";
import { CryptoService } from "../../abstractions/crypto.service";
import { EnvironmentService } from "../../abstractions/environment.service";
import { LogService } from "../../abstractions/log.service";
import { MessagingService } from "../../abstractions/messaging.service";
import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
import { StateService } from "../../abstractions/state.service";
import { Utils } from "../../misc/utils";
import { KeyConnectorService } from "../abstractions/key-connector.service";
import { TokenService } from "../abstractions/token.service";
import { TwoFactorService } from "../abstractions/two-factor.service";
import { UserApiLogInCredentials } from "../models/domain/log-in-credentials";
import { identityTokenResponseFactory } from "./login.strategy.spec";
import { UserApiLogInStrategy } from "./user-api-login.strategy";
describe("UserApiLogInStrategy", () => {
let cryptoService: MockProxy<CryptoService>;
let apiService: MockProxy<ApiService>;
let tokenService: MockProxy<TokenService>;
let appIdService: MockProxy<AppIdService>;
let platformUtilsService: MockProxy<PlatformUtilsService>;
let messagingService: MockProxy<MessagingService>;
let logService: MockProxy<LogService>;
let stateService: MockProxy<StateService>;
let twoFactorService: MockProxy<TwoFactorService>;
let keyConnectorService: MockProxy<KeyConnectorService>;
let environmentService: MockProxy<EnvironmentService>;
let apiLogInStrategy: UserApiLogInStrategy;
let credentials: UserApiLogInCredentials;
const deviceId = Utils.newGuid();
const keyConnectorUrl = "KEY_CONNECTOR_URL";
const apiClientId = "API_CLIENT_ID";
const apiClientSecret = "API_CLIENT_SECRET";
beforeEach(async () => {
cryptoService = mock<CryptoService>();
apiService = mock<ApiService>();
tokenService = mock<TokenService>();
appIdService = mock<AppIdService>();
platformUtilsService = mock<PlatformUtilsService>();
messagingService = mock<MessagingService>();
logService = mock<LogService>();
stateService = mock<StateService>();
twoFactorService = mock<TwoFactorService>();
keyConnectorService = mock<KeyConnectorService>();
environmentService = mock<EnvironmentService>();
appIdService.getAppId.mockResolvedValue(deviceId);
tokenService.getTwoFactorToken.mockResolvedValue(null);
tokenService.decodeToken.mockResolvedValue({});
apiLogInStrategy = new UserApiLogInStrategy(
cryptoService,
apiService,
tokenService,
appIdService,
platformUtilsService,
messagingService,
logService,
stateService,
twoFactorService,
environmentService,
keyConnectorService
);
credentials = new UserApiLogInCredentials(apiClientId, apiClientSecret);
});
it("sends api key credentials to the server", async () => {
apiService.postIdentityToken.mockResolvedValue(identityTokenResponseFactory());
await apiLogInStrategy.logIn(credentials);
expect(apiService.postIdentityToken).toHaveBeenCalledWith(
expect.objectContaining({
clientId: apiClientId,
clientSecret: apiClientSecret,
device: expect.objectContaining({
identifier: deviceId,
}),
twoFactor: expect.objectContaining({
provider: null,
token: null,
}),
})
);
});
it("sets the local environment after a successful login", async () => {
apiService.postIdentityToken.mockResolvedValue(identityTokenResponseFactory());
await apiLogInStrategy.logIn(credentials);
expect(stateService.setApiKeyClientId).toHaveBeenCalledWith(apiClientId);
expect(stateService.setApiKeyClientSecret).toHaveBeenCalledWith(apiClientSecret);
expect(stateService.addAccount).toHaveBeenCalled();
});
it("gets and sets the Key Connector key from environmentUrl", async () => {
const tokenResponse = identityTokenResponseFactory();
tokenResponse.apiUseKeyConnector = true;
apiService.postIdentityToken.mockResolvedValue(tokenResponse);
environmentService.getKeyConnectorUrl.mockReturnValue(keyConnectorUrl);
await apiLogInStrategy.logIn(credentials);
expect(keyConnectorService.getAndSetKey).toHaveBeenCalledWith(keyConnectorUrl);
});
});

View File

@@ -2,18 +2,18 @@ import { ApiService } from "../../abstractions/api.service";
import { AppIdService } from "../../abstractions/appId.service";
import { CryptoService } from "../../abstractions/crypto.service";
import { EnvironmentService } from "../../abstractions/environment.service";
import { KeyConnectorService } from "../../abstractions/keyConnector.service";
import { LogService } from "../../abstractions/log.service";
import { MessagingService } from "../../abstractions/messaging.service";
import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
import { StateService } from "../../abstractions/state.service";
import { TokenService } from "../../abstractions/token.service";
import { TwoFactorService } from "../../abstractions/twoFactor.service";
import { UserApiLogInCredentials } from "../../models/domain/log-in-credentials";
import { UserApiTokenRequest } from "../../models/request/identity-token/user-api-token.request";
import { IdentityTokenResponse } from "../../models/response/identity-token.response";
import { TokenService } from "../../auth/abstractions/token.service";
import { TwoFactorService } from "../../auth/abstractions/two-factor.service";
import { KeyConnectorService } from "../abstractions/key-connector.service";
import { UserApiLogInCredentials } from "../models/domain/log-in-credentials";
import { UserApiTokenRequest } from "../models/request/identity-token/user-api-token.request";
import { IdentityTokenResponse } from "../models/response/identity-token.response";
import { LogInStrategy } from "./logIn.strategy";
import { LogInStrategy } from "./login.strategy";
export class UserApiLogInStrategy extends LogInStrategy {
tokenRequest: UserApiTokenRequest;

View File

@@ -1,11 +1,11 @@
import { BaseResponse } from "../../../models/response/base.response";
import {
OpenIdConnectRedirectBehavior,
Saml2BindingType,
Saml2NameIdFormat,
Saml2SigningBehavior,
SsoType,
} from "../../enums/ssoEnums";
import { BaseResponse } from "../response/base.response";
} from "../../enums/sso";
import { SsoConfigView } from "../view/sso-config.view";
export class SsoConfigApi extends BaseResponse {

View File

@@ -1,5 +1,5 @@
import { TwoFactorProviderType } from "../../enums/twoFactorProviderType";
import { Utils } from "../../misc/utils";
import { Utils } from "../../../misc/utils";
import { TwoFactorProviderType } from "../../enums/two-factor-provider-type";
export class AuthResult {
captchaSiteKey = "";

View File

@@ -0,0 +1,11 @@
export class KdfConfig {
iterations: number;
memory?: number;
parallelism?: number;
constructor(iterations: number, memory?: number, parallelism?: number) {
this.iterations = iterations;
this.memory = memory;
this.parallelism = parallelism;
}
}

View File

@@ -1,8 +1,7 @@
import { AuthenticationType } from "../../enums/authenticationType";
import { SymmetricCryptoKey } from "../../../models/domain/symmetric-crypto-key";
import { AuthenticationType } from "../../enums/authentication-type";
import { TokenTwoFactorRequest } from "../request/identity-token/token-two-factor.request";
import { SymmetricCryptoKey } from "./symmetric-crypto-key";
export class PasswordLogInCredentials {
readonly type = AuthenticationType.Password;

View File

@@ -1,4 +1,4 @@
import { EmergencyAccessType } from "../../enums/emergencyAccessType";
import { EmergencyAccessType } from "../../enums/emergency-access-type";
export class EmergencyAccessInviteRequest {
email: string;

View File

@@ -1,4 +1,4 @@
import { EmergencyAccessType } from "../../enums/emergencyAccessType";
import { EmergencyAccessType } from "../../enums/emergency-access-type";
export class EmergencyAccessUpdateRequest {
type: EmergencyAccessType;

View File

@@ -1,5 +1,5 @@
import { PlatformUtilsService } from "../../abstractions/platformUtils.service";
import { DeviceType } from "../../enums/deviceType";
import { PlatformUtilsService } from "../../../../abstractions/platformUtils.service";
import { DeviceType } from "../../../../enums/deviceType";
export class DeviceRequest {
type: DeviceType;

View File

@@ -1,8 +1,8 @@
import { ClientType } from "../../../enums/clientType";
import { Utils } from "../../../misc/utils";
import { ClientType } from "../../../../enums/clientType";
import { Utils } from "../../../../misc/utils";
import { CaptchaProtectedRequest } from "../captcha-protected.request";
import { DeviceRequest } from "../device.request";
import { DeviceRequest } from "./device.request";
import { TokenTwoFactorRequest } from "./token-two-factor.request";
import { TokenRequest } from "./token.request";

View File

@@ -1,5 +1,4 @@
import { DeviceRequest } from "../device.request";
import { DeviceRequest } from "./device.request";
import { TokenTwoFactorRequest } from "./token-two-factor.request";
import { TokenRequest } from "./token.request";

View File

@@ -1,4 +1,4 @@
import { TwoFactorProviderType } from "../../../enums/twoFactorProviderType";
import { TwoFactorProviderType } from "../../../enums/two-factor-provider-type";
export class TokenTwoFactorRequest {
constructor(

View File

@@ -1,5 +1,4 @@
import { DeviceRequest } from "../device.request";
import { DeviceRequest } from "./device.request";
import { TokenTwoFactorRequest } from "./token-two-factor.request";
export abstract class TokenRequest {

View File

@@ -1,5 +1,4 @@
import { DeviceRequest } from "../device.request";
import { DeviceRequest } from "./device.request";
import { TokenTwoFactorRequest } from "./token-two-factor.request";
import { TokenRequest } from "./token.request";

View File

@@ -1,4 +1,4 @@
import { SsoConfigApi } from "../../api/sso-config.api";
import { SsoConfigApi } from "../api/sso-config.api";
export class OrganizationSsoRequest {
enabled = false;

View File

@@ -0,0 +1,8 @@
export class PasswordlessAuthRequest {
constructor(
readonly key: string,
readonly masterPasswordHash: string,
readonly deviceIdentifier: string,
readonly requestApproved: boolean
) {}
}

View File

@@ -1,4 +1,4 @@
import { AuthRequestType } from "../../enums/authRequestType";
import { AuthRequestType } from "../../enums/auth-request-type";
export class PasswordlessCreateAuthRequest {
constructor(

View File

@@ -1,23 +1,28 @@
import { KdfType } from "../../../enums/kdfType";
import { KeysRequest } from "../keys.request";
import { KeysRequest } from "../../../models/request/keys.request";
import { KdfConfig } from "../domain/kdf-config";
export class SetKeyConnectorKeyRequest {
key: string;
keys: KeysRequest;
kdf: KdfType;
kdfIterations: number;
kdfMemory?: number;
kdfParallelism?: number;
orgIdentifier: string;
constructor(
key: string,
kdf: KdfType,
kdfIterations: number,
kdfConfig: KdfConfig,
orgIdentifier: string,
keys: KeysRequest
) {
this.key = key;
this.kdf = kdf;
this.kdfIterations = kdfIterations;
this.kdfIterations = kdfConfig.iterations;
this.kdfMemory = kdfConfig.memory;
this.kdfParallelism = kdfConfig.parallelism;
this.orgIdentifier = orgIdentifier;
this.keys = keys;
}

View File

@@ -1,6 +1,5 @@
import { KdfType } from "../../enums/kdfType";
import { KeysRequest } from "./keys.request";
import { KdfType } from "../../../enums/kdfType";
import { KeysRequest } from "../../../models/request/keys.request";
export class SetPasswordRequest {
masterPasswordHash: string;
@@ -9,22 +8,28 @@ export class SetPasswordRequest {
keys: KeysRequest;
kdf: KdfType;
kdfIterations: number;
kdfMemory?: number;
kdfParallelism?: number;
orgIdentifier: string;
constructor(
masterPasswordHash: string,
key: string,
masterPasswordHint: string,
orgIdentifier: string,
keys: KeysRequest,
kdf: KdfType,
kdfIterations: number,
orgIdentifier: string,
keys: KeysRequest
kdfMemory?: number,
kdfParallelism?: number
) {
this.masterPasswordHash = masterPasswordHash;
this.key = key;
this.masterPasswordHint = masterPasswordHint;
this.kdf = kdf;
this.kdfIterations = kdfIterations;
this.kdfMemory = kdfMemory;
this.kdfParallelism = kdfParallelism;
this.orgIdentifier = orgIdentifier;
this.keys = keys;
}

View File

@@ -1,4 +1,4 @@
import { TwoFactorProviderType } from "../../enums/twoFactorProviderType";
import { TwoFactorProviderType } from "../../enums/two-factor-provider-type";
import { SecretVerificationRequest } from "./secret-verification.request";

View File

@@ -1,4 +1,4 @@
import { OrganizationUserResetPasswordRequest } from "../../abstractions/organization-user/requests";
import { OrganizationUserResetPasswordRequest } from "../../../abstractions/organization-user/requests";
export class UpdateTempPasswordRequest extends OrganizationUserResetPasswordRequest {
masterPasswordHint: string;

View File

@@ -1,4 +1,4 @@
import { BaseResponse } from "./base.response";
import { BaseResponse } from "../../../models/response/base.response";
export class ApiKeyResponse extends BaseResponse {
apiKey: string;

View File

@@ -0,0 +1,58 @@
import { DeviceType } from "../../../enums/deviceType";
import { BaseResponse } from "../../../models/response/base.response";
const RequestTimeOut = 60000 * 15; //15 Minutes
export class AuthRequestResponse extends BaseResponse {
id: string;
publicKey: string;
requestDeviceType: DeviceType;
requestIpAddress: string;
key: string;
masterPasswordHash: string;
creationDate: string;
requestApproved?: boolean;
requestFingerprint?: string;
responseDate?: string;
isAnswered: boolean;
isExpired: boolean;
constructor(response: any) {
super(response);
this.id = this.getResponseProperty("Id");
this.publicKey = this.getResponseProperty("PublicKey");
this.requestDeviceType = this.getResponseProperty("RequestDeviceType");
this.requestIpAddress = this.getResponseProperty("RequestIpAddress");
this.key = this.getResponseProperty("Key");
this.masterPasswordHash = this.getResponseProperty("MasterPasswordHash");
this.creationDate = this.getResponseProperty("CreationDate");
this.requestApproved = this.getResponseProperty("RequestApproved");
this.requestFingerprint = this.getResponseProperty("RequestFingerprint");
this.responseDate = this.getResponseProperty("ResponseDate");
const requestDate = new Date(this.creationDate);
const requestDateUTC = Date.UTC(
requestDate.getUTCFullYear(),
requestDate.getUTCMonth(),
requestDate.getDate(),
requestDate.getUTCHours(),
requestDate.getUTCMinutes(),
requestDate.getUTCSeconds(),
requestDate.getUTCMilliseconds()
);
const dateNow = new Date(Date.now());
const dateNowUTC = Date.UTC(
dateNow.getUTCFullYear(),
dateNow.getUTCMonth(),
dateNow.getDate(),
dateNow.getUTCHours(),
dateNow.getUTCMinutes(),
dateNow.getUTCSeconds(),
dateNow.getUTCMilliseconds()
);
this.isExpired = dateNowUTC - requestDateUTC >= RequestTimeOut;
this.isAnswered = this.requestApproved != null && this.responseDate != null;
}
}

View File

@@ -1,4 +1,4 @@
import { BaseResponse } from "./base.response";
import { BaseResponse } from "../../../models/response/base.response";
export class DeviceVerificationResponse extends BaseResponse {
isDeviceVerificationSectionEnabled: boolean;

View File

@@ -1,6 +1,5 @@
import { DeviceType } from "../../enums/deviceType";
import { BaseResponse } from "./base.response";
import { DeviceType } from "../../../enums/deviceType";
import { BaseResponse } from "../../../models/response/base.response";
export class DeviceResponse extends BaseResponse {
id: string;

View File

@@ -1,9 +1,8 @@
import { EmergencyAccessStatusType } from "../../enums/emergencyAccessStatusType";
import { EmergencyAccessType } from "../../enums/emergencyAccessType";
import { KdfType } from "../../enums/kdfType";
import { BaseResponse } from "./base.response";
import { CipherResponse } from "./cipher.response";
import { KdfType } from "../../../enums/kdfType";
import { BaseResponse } from "../../../models/response/base.response";
import { CipherResponse } from "../../../vault/models/response/cipher.response";
import { EmergencyAccessStatusType } from "../../enums/emergency-access-status-type";
import { EmergencyAccessType } from "../../enums/emergency-access-type";
export class EmergencyAccessGranteeDetailsResponse extends BaseResponse {
id: string;
@@ -59,6 +58,8 @@ export class EmergencyAccessTakeoverResponse extends BaseResponse {
keyEncrypted: string;
kdf: KdfType;
kdfIterations: number;
kdfMemory?: number;
kdfParallelism?: number;
constructor(response: any) {
super(response);
@@ -66,6 +67,8 @@ export class EmergencyAccessTakeoverResponse extends BaseResponse {
this.keyEncrypted = this.getResponseProperty("KeyEncrypted");
this.kdf = this.getResponseProperty("Kdf");
this.kdfIterations = this.getResponseProperty("KdfIterations");
this.kdfMemory = this.getResponseProperty("KdfMemory");
this.kdfParallelism = this.getResponseProperty("KdfParallelism");
}
}

View File

@@ -1,4 +1,4 @@
import { BaseResponse } from "./base.response";
import { BaseResponse } from "../../../models/response/base.response";
export class IdentityCaptchaResponse extends BaseResponse {
siteKey: string;

View File

@@ -1,6 +1,5 @@
import { KdfType } from "../../enums/kdfType";
import { BaseResponse } from "./base.response";
import { KdfType } from "../../../enums/kdfType";
import { BaseResponse } from "../../../models/response/base.response";
export class IdentityTokenResponse extends BaseResponse {
accessToken: string;
@@ -14,6 +13,8 @@ export class IdentityTokenResponse extends BaseResponse {
twoFactorToken: string;
kdf: KdfType;
kdfIterations: number;
kdfMemory?: number;
kdfParallelism?: number;
forcePasswordReset: boolean;
apiUseKeyConnector: boolean;
keyConnectorUrl: string;
@@ -31,6 +32,8 @@ export class IdentityTokenResponse extends BaseResponse {
this.twoFactorToken = this.getResponseProperty("TwoFactorToken");
this.kdf = this.getResponseProperty("Kdf");
this.kdfIterations = this.getResponseProperty("KdfIterations");
this.kdfMemory = this.getResponseProperty("KdfMemory");
this.kdfParallelism = this.getResponseProperty("KdfParallelism");
this.forcePasswordReset = this.getResponseProperty("ForcePasswordReset");
this.apiUseKeyConnector = this.getResponseProperty("ApiUseKeyConnector");
this.keyConnectorUrl = this.getResponseProperty("KeyConnectorUrl");

View File

@@ -1,6 +1,5 @@
import { TwoFactorProviderType } from "../../enums/twoFactorProviderType";
import { BaseResponse } from "./base.response";
import { BaseResponse } from "../../../models/response/base.response";
import { TwoFactorProviderType } from "../../enums/two-factor-provider-type";
export class IdentityTwoFactorResponse extends BaseResponse {
twoFactorProviders: TwoFactorProviderType[];

View File

@@ -1,4 +1,4 @@
import { BaseResponse } from "./base.response";
import { BaseResponse } from "../../../models/response/base.response";
export class KeyConnectorUserKeyResponse extends BaseResponse {
key: string;

View File

@@ -1,5 +1,5 @@
import { SsoConfigApi } from "../../api/sso-config.api";
import { BaseResponse } from "../base.response";
import { BaseResponse } from "../../../models/response/base.response";
import { SsoConfigApi } from "../api/sso-config.api";
export class OrganizationSsoResponse extends BaseResponse {
enabled: boolean;

View File

@@ -0,0 +1,17 @@
import { KdfType } from "../../../enums/kdfType";
import { BaseResponse } from "../../../models/response/base.response";
export class PreloginResponse extends BaseResponse {
kdf: KdfType;
kdfIterations: number;
kdfMemory?: number;
kdfParallelism?: number;
constructor(response: any) {
super(response);
this.kdf = this.getResponseProperty("Kdf");
this.kdfIterations = this.getResponseProperty("KdfIterations");
this.kdfMemory = this.getResponseProperty("KdfMemory");
this.kdfParallelism = this.getResponseProperty("KdfParallelism");
}
}

Some files were not shown because too many files have changed in this diff Show More