1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-27 21:53:25 +00:00

Auth/ps 2298 reorg auth (#4564)

* Move auth service factories to Auth team

* Move authentication componenets to Auth team

* Move auth guard services to Auth team

* Move Duo content script to Auth team

* Move auth CLI commands to Auth team

* Move Desktop Account components to Auth Team

* Move Desktop guards to Auth team

* Move two-factor provider images to Auth team

* Move web Accounts components to Auth Team

* Move web settings components to Auth Team

* Move web two factor images to Auth Team

* Fix missed import changes for Auth Team

* Fix Linting errors

* Fix missed CLI imports

* Fix missed Desktop imports

* Revert images move

* Fix missed imports in Web

* Move angular lib components to Auth Team

* Move angular auth guards to Auth team

* Move strategy specs to Auth team

* Update .eslintignore for new paths

* Move lib common abstractions to Auth team

* Move services to Auth team

* Move common lib enums to Auth team

* Move webauthn iframe to Auth team

* Move lib common domain models to Auth team

* Move common lib requests to Auth team

* Move response models to Auth team

* Clean up whitelist

* Move bit web components to Auth team

* Move SSO and SCIM files to Auth team

* Revert move SCIM to Auth team

SCIM belongs to Admin Console team

* Move captcha to Auth team

* Move key connector to Auth team

* Move emergency access to auth team

* Delete extra file

* linter fixes

* Move kdf config to auth team

* Fix whitelist

* Fix duo autoformat

* Complete two factor provider request move

* Fix whitelist names

* Fix login capitalization

* Revert hint dependency reordering

* Revert hint dependency reordering

* Revert hint component

This components is being picked up as a move between clients

* Move web hint component to Auth team

* Move new files to auth team

* Fix desktop build

* Fix browser build
This commit is contained in:
Matt Gibson
2023-02-06 16:53:37 -05:00
committed by GitHub
parent 084c89107e
commit cf972e784c
377 changed files with 1030 additions and 998 deletions

View File

@@ -1,33 +1,71 @@
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 { 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 { BitPayInvoiceRequest } from "../models/request/bit-pay-invoice.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 { 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 { PasswordlessAuthRequest } from "../models/request/passwordless-auth.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";
@@ -41,32 +79,17 @@ 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 { 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";
@@ -74,19 +97,8 @@ 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,
@@ -97,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,
@@ -115,20 +126,9 @@ 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 { 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";

View File

@@ -1,9 +1,9 @@
import { KdfConfig } from "../auth/models/domain/kdf-config";
import { HashPurpose } from "../enums/hashPurpose";
import { KdfType } from "../enums/kdfType";
import { KeySuffixOptions } from "../enums/keySuffixOptions";
import { EncArrayBuffer } from "../models/domain/enc-array-buffer";
import { EncString } from "../models/domain/enc-string";
import { KdfConfig } from "../models/domain/kdf-config";
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";
import { ProfileOrganizationResponse } from "../models/response/profile-organization.response";
import { ProfileProviderOrganizationResponse } from "../models/response/profile-provider-organization.response";

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

@@ -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";

View File

@@ -1,5 +1,7 @@
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";
@@ -13,9 +15,7 @@ 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 { KdfConfig } from "../models/domain/kdf-config";
import { Policy } from "../models/domain/policy";
import { StorageOptions } from "../models/domain/storage-options";
import { SymmetricCryptoKey } from "../models/domain/symmetric-crypto-key";

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

@@ -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,10 +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 { AuthRequestResponse } from "../models/response/auth-request.response";
import { AuthRequestPushNotification } from "../models/response/notification.response";
export abstract class AuthService {
masterPasswordHash: string;

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;

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

@@ -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

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

View File

@@ -1,6 +1,6 @@
import { KdfType } from "../../../enums/kdfType";
import { KdfConfig } from "../../domain/kdf-config";
import { KeysRequest } from "../keys.request";
import { KeysRequest } from "../../../models/request/keys.request";
import { KdfConfig } from "../domain/kdf-config";
export class SetKeyConnectorKeyRequest {
key: string;

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;

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 { BaseResponse } from "./base.response";
import { BaseResponse } from "../../../models/response/base.response";
export class ApiKeyResponse extends BaseResponse {
apiKey: string;

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";
const RequestTimeOut = 60000 * 15; //15 Minutes

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 { CipherResponse } from "../../vault/models/response/cipher.response";
import { BaseResponse } from "./base.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;

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;

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

@@ -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 PreloginResponse extends BaseResponse {
kdf: KdfType;

View File

@@ -1,4 +1,4 @@
import { BaseResponse } from "../base.response";
import { BaseResponse } from "../../../models/response/base.response";
import { ICaptchaProtectedResponse } from "./captcha-protected.response";

View File

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

View File

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

View File

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

View File

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

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 TwoFactorProviderResponse extends BaseResponse {
enabled: boolean;

View File

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

View File

@@ -1,6 +1,5 @@
import { Utils } from "../../misc/utils";
import { BaseResponse } from "./base.response";
import { Utils } from "../../../misc/utils";
import { BaseResponse } from "../../../models/response/base.response";
export class TwoFactorWebAuthnResponse extends BaseResponse {
enabled: boolean;

View File

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

View File

@@ -1,14 +1,13 @@
import { View } from "../../../models/view/view";
import {
OpenIdConnectRedirectBehavior,
Saml2BindingType,
Saml2NameIdFormat,
Saml2SigningBehavior,
SsoType,
} from "../../enums/ssoEnums";
} from "../../enums/sso";
import { SsoConfigApi } from "../api/sso-config.api";
import { View } from "./view";
export class SsoConfigView extends View {
configType: SsoType;

View File

@@ -1,9 +1,9 @@
import { AccountApiService } from "../../abstractions/account/account-api.service";
import { InternalAccountService } from "../../abstractions/account/account.service";
import { ApiService } from "../../abstractions/api.service";
import { LogService } from "../../abstractions/log.service";
import { UserVerificationService } from "../../abstractions/userVerification/userVerification.service.abstraction";
import { Verification } from "../../types/verification";
import { AccountApiService } from "../abstractions/account-api.service";
import { InternalAccountService } from "../abstractions/account.service";
export class AccountApiServiceImplementation implements AccountApiService {
constructor(

View File

@@ -1,6 +1,6 @@
import { InternalAccountService } from "../../abstractions/account/account.service";
import { LogService } from "../../abstractions/log.service";
import { MessagingService } from "../../abstractions/messaging.service";
import { InternalAccountService } from "../../auth/abstractions/account.service";
export class AccountServiceImplementation implements InternalAccountService {
constructor(private messagingService: MessagingService, private logService: LogService) {}

View File

@@ -1,28 +1,32 @@
import { Observable, Subject } from "rxjs";
import { ApiService } from "../abstractions/api.service";
import { AppIdService } from "../abstractions/appId.service";
import { ApiService } from "../../abstractions/api.service";
import { AppIdService } from "../../abstractions/appId.service";
import { CryptoService } from "../../abstractions/crypto.service";
import { EncryptService } from "../../abstractions/encrypt.service";
import { EnvironmentService } from "../../abstractions/environment.service";
import { I18nService } from "../../abstractions/i18n.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 { KdfType } from "../../enums/kdfType";
import { KeySuffixOptions } from "../../enums/keySuffixOptions";
import { Utils } from "../../misc/utils";
import { SymmetricCryptoKey } from "../../models/domain/symmetric-crypto-key";
import { PreloginRequest } from "../../models/request/prelogin.request";
import { ErrorResponse } from "../../models/response/error.response";
import { AuthRequestPushNotification } from "../../models/response/notification.response";
import { AuthService as AuthServiceAbstraction } from "../abstractions/auth.service";
import { CryptoService } from "../abstractions/crypto.service";
import { EncryptService } from "../abstractions/encrypt.service";
import { EnvironmentService } from "../abstractions/environment.service";
import { I18nService } from "../abstractions/i18n.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 { KeyConnectorService } from "../abstractions/key-connector.service";
import { TokenService } from "../abstractions/token.service";
import { TwoFactorService } from "../abstractions/twoFactor.service";
import { AuthenticationStatus } from "../enums/authenticationStatus";
import { AuthenticationType } from "../enums/authenticationType";
import { KdfType } from "../enums/kdfType";
import { KeySuffixOptions } from "../enums/keySuffixOptions";
import { PasswordLogInStrategy } from "../misc/logInStrategies/passwordLogin.strategy";
import { PasswordlessLogInStrategy } from "../misc/logInStrategies/passwordlessLogin.strategy";
import { SsoLogInStrategy } from "../misc/logInStrategies/ssoLogin.strategy";
import { UserApiLogInStrategy } from "../misc/logInStrategies/user-api-login.strategy";
import { Utils } from "../misc/utils";
import { TwoFactorService } from "../abstractions/two-factor.service";
import { AuthenticationStatus } from "../enums/authentication-status";
import { AuthenticationType } from "../enums/authentication-type";
import { PasswordLogInStrategy } from "../login-strategies/password-login.strategy";
import { PasswordlessLogInStrategy } from "../login-strategies/passwordless-login.strategy";
import { SsoLogInStrategy } from "../login-strategies/sso-login.strategy";
import { UserApiLogInStrategy } from "../login-strategies/user-api-login.strategy";
import { AuthResult } from "../models/domain/auth-result";
import { KdfConfig } from "../models/domain/kdf-config";
import {
@@ -31,13 +35,9 @@ 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 { PasswordlessAuthRequest } from "../models/request/passwordless-auth.request";
import { PreloginRequest } from "../models/request/prelogin.request";
import { AuthRequestResponse } from "../models/response/auth-request.response";
import { ErrorResponse } from "../models/response/error.response";
import { AuthRequestPushNotification } from "../models/response/notification.response";
const sessionTimeoutLength = 2 * 60 * 1000; // 2 minutes

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