mirror of
https://github.com/bitwarden/browser
synced 2025-12-15 15:53:27 +00:00
Add support for requesting and using otp for verifying some requests (#527)
Co-authored-by: Thomas Rittson <trittson@bitwarden.com>
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
import { PolicyType } from '../enums/policyType';
|
||||
import { SetCryptoAgentKeyRequest } from '../models/request/account/setCryptoAgentKeyRequest';
|
||||
import { SetKeyConnectorKeyRequest } from '../models/request/account/setKeyConnectorKeyRequest';
|
||||
import { VerifyOTPRequest } from '../models/request/account/verifyOTPRequest';
|
||||
|
||||
import { AttachmentRequest } from '../models/request/attachmentRequest';
|
||||
|
||||
@@ -13,7 +14,6 @@ import { CipherCreateRequest } from '../models/request/cipherCreateRequest';
|
||||
import { CipherRequest } from '../models/request/cipherRequest';
|
||||
import { CipherShareRequest } from '../models/request/cipherShareRequest';
|
||||
import { CollectionRequest } from '../models/request/collectionRequest';
|
||||
import { CryptoAgentUserKeyRequest } from '../models/request/cryptoAgentUserKeyRequest';
|
||||
import { DeleteRecoverRequest } from '../models/request/deleteRecoverRequest';
|
||||
import { EmailRequest } from '../models/request/emailRequest';
|
||||
import { EmailTokenRequest } from '../models/request/emailTokenRequest';
|
||||
@@ -30,6 +30,7 @@ import { ImportCiphersRequest } from '../models/request/importCiphersRequest';
|
||||
import { ImportDirectoryRequest } from '../models/request/importDirectoryRequest';
|
||||
import { ImportOrganizationCiphersRequest } from '../models/request/importOrganizationCiphersRequest';
|
||||
import { KdfRequest } from '../models/request/kdfRequest';
|
||||
import { KeyConnectorUserKeyRequest } from '../models/request/keyConnectorUserKeyRequest';
|
||||
import { KeysRequest } from '../models/request/keysRequest';
|
||||
import { OrganizationSsoRequest } from '../models/request/organization/organizationSsoRequest';
|
||||
import { OrganizationCreateRequest } from '../models/request/organizationCreateRequest';
|
||||
@@ -50,7 +51,6 @@ import { OrganizationUserUpdateGroupsRequest } from '../models/request/organizat
|
||||
import { OrganizationUserUpdateRequest } from '../models/request/organizationUserUpdateRequest';
|
||||
import { PasswordHintRequest } from '../models/request/passwordHintRequest';
|
||||
import { PasswordRequest } from '../models/request/passwordRequest';
|
||||
import { PasswordVerificationRequest } from '../models/request/passwordVerificationRequest';
|
||||
import { PaymentRequest } from '../models/request/paymentRequest';
|
||||
import { PolicyRequest } from '../models/request/policyRequest';
|
||||
import { PreloginRequest } from '../models/request/preloginRequest';
|
||||
@@ -66,6 +66,7 @@ import { ProviderUserInviteRequest } from '../models/request/provider/providerUs
|
||||
import { ProviderUserUpdateRequest } from '../models/request/provider/providerUserUpdateRequest';
|
||||
import { RegisterRequest } from '../models/request/registerRequest';
|
||||
import { SeatRequest } from '../models/request/seatRequest';
|
||||
import { SecretVerificationRequest } from '../models/request/secretVerificationRequest';
|
||||
import { SelectionReadOnlyRequest } from '../models/request/selectionReadOnlyRequest';
|
||||
import { SendAccessRequest } from '../models/request/sendAccessRequest';
|
||||
import { SendRequest } from '../models/request/sendRequest';
|
||||
@@ -100,7 +101,6 @@ import {
|
||||
CollectionGroupDetailsResponse,
|
||||
CollectionResponse,
|
||||
} from '../models/response/collectionResponse';
|
||||
import { CryptoAgentUserKeyResponse } from '../models/response/cryptoAgentUserKeyResponse';
|
||||
import { DomainsResponse } from '../models/response/domainsResponse';
|
||||
import {
|
||||
EmergencyAccessGranteeDetailsResponse,
|
||||
@@ -117,6 +117,7 @@ import {
|
||||
import { IdentityCaptchaResponse } from '../models/response/identityCaptchaResponse';
|
||||
import { IdentityTokenResponse } from '../models/response/identityTokenResponse';
|
||||
import { IdentityTwoFactorResponse } from '../models/response/identityTwoFactorResponse';
|
||||
import { KeyConnectorUserKeyResponse } from '../models/response/keyConnectorUserKeyResponse';
|
||||
import { ListResponse } from '../models/response/listResponse';
|
||||
import { OrganizationSsoResponse } from '../models/response/organization/organizationSsoResponse';
|
||||
import { OrganizationAutoEnrollStatusResponse } from '../models/response/organizationAutoEnrollStatusResponse';
|
||||
@@ -175,9 +176,9 @@ export abstract class ApiService {
|
||||
postEmail: (request: EmailRequest) => Promise<any>;
|
||||
postPassword: (request: PasswordRequest) => Promise<any>;
|
||||
setPassword: (request: SetPasswordRequest) => Promise<any>;
|
||||
postSetCryptoAgentKey: (request: SetCryptoAgentKeyRequest) => Promise<any>;
|
||||
postSecurityStamp: (request: PasswordVerificationRequest) => Promise<any>;
|
||||
deleteAccount: (request: PasswordVerificationRequest) => Promise<any>;
|
||||
postSetKeyConnectorKey: (request: SetKeyConnectorKeyRequest) => Promise<any>;
|
||||
postSecurityStamp: (request: SecretVerificationRequest) => Promise<any>;
|
||||
deleteAccount: (request: SecretVerificationRequest) => Promise<any>;
|
||||
getAccountRevisionDate: () => Promise<number>;
|
||||
postPasswordHint: (request: PasswordHintRequest) => Promise<any>;
|
||||
postRegister: (request: RegisterRequest) => Promise<any>;
|
||||
@@ -192,13 +193,16 @@ export abstract class ApiService {
|
||||
postAccountKeys: (request: KeysRequest) => Promise<any>;
|
||||
postAccountVerifyEmail: () => Promise<any>;
|
||||
postAccountVerifyEmailToken: (request: VerifyEmailRequest) => Promise<any>;
|
||||
postAccountVerifyPassword: (request: PasswordVerificationRequest) => Promise<any>;
|
||||
postAccountVerifyPassword: (request: SecretVerificationRequest) => Promise<any>;
|
||||
postAccountRecoverDelete: (request: DeleteRecoverRequest) => Promise<any>;
|
||||
postAccountRecoverDeleteToken: (request: VerifyDeleteRecoverRequest) => Promise<any>;
|
||||
postAccountKdf: (request: KdfRequest) => Promise<any>;
|
||||
postUserApiKey: (id: string, request: PasswordVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
postUserRotateApiKey: (id: string, request: PasswordVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
postUserApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
postUserRotateApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
putUpdateTempPassword: (request: UpdateTempPasswordRequest) => Promise<any>;
|
||||
postAccountRequestOTP: () => Promise<void>;
|
||||
postAccountVerifyOTP: (request: VerifyOTPRequest) => Promise<void>;
|
||||
postConvertToKeyConnector: () => Promise<void>;
|
||||
|
||||
getFolder: (id: string) => Promise<FolderResponse>;
|
||||
postFolder: (request: FolderRequest) => Promise<FolderResponse>;
|
||||
@@ -240,7 +244,7 @@ export abstract class ApiService {
|
||||
putShareCiphers: (request: CipherBulkShareRequest) => Promise<any>;
|
||||
putCipherCollections: (id: string, request: CipherCollectionsRequest) => Promise<any>;
|
||||
putCipherCollectionsAdmin: (id: string, request: CipherCollectionsRequest) => Promise<any>;
|
||||
postPurgeCiphers: (request: PasswordVerificationRequest, organizationId?: string) => 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>;
|
||||
@@ -329,15 +333,15 @@ export abstract class ApiService {
|
||||
|
||||
getTwoFactorProviders: () => Promise<ListResponse<TwoFactorProviderResponse>>;
|
||||
getTwoFactorOrganizationProviders: (organizationId: string) => Promise<ListResponse<TwoFactorProviderResponse>>;
|
||||
getTwoFactorAuthenticator: (request: PasswordVerificationRequest) => Promise<TwoFactorAuthenticatorResponse>;
|
||||
getTwoFactorEmail: (request: PasswordVerificationRequest) => Promise<TwoFactorEmailResponse>;
|
||||
getTwoFactorDuo: (request: PasswordVerificationRequest) => Promise<TwoFactorDuoResponse>;
|
||||
getTwoFactorAuthenticator: (request: SecretVerificationRequest) => Promise<TwoFactorAuthenticatorResponse>;
|
||||
getTwoFactorEmail: (request: SecretVerificationRequest) => Promise<TwoFactorEmailResponse>;
|
||||
getTwoFactorDuo: (request: SecretVerificationRequest) => Promise<TwoFactorDuoResponse>;
|
||||
getTwoFactorOrganizationDuo: (organizationId: string,
|
||||
request: PasswordVerificationRequest) => Promise<TwoFactorDuoResponse>;
|
||||
getTwoFactorYubiKey: (request: PasswordVerificationRequest) => Promise<TwoFactorYubiKeyResponse>;
|
||||
getTwoFactorWebAuthn: (request: PasswordVerificationRequest) => Promise<TwoFactorWebAuthnResponse>;
|
||||
getTwoFactorWebAuthnChallenge: (request: PasswordVerificationRequest) => Promise<ChallengeResponse>;
|
||||
getTwoFactorRecover: (request: PasswordVerificationRequest) => Promise<TwoFactorRecoverResponse>;
|
||||
request: SecretVerificationRequest) => Promise<TwoFactorDuoResponse>;
|
||||
getTwoFactorYubiKey: (request: SecretVerificationRequest) => Promise<TwoFactorYubiKeyResponse>;
|
||||
getTwoFactorWebAuthn: (request: SecretVerificationRequest) => Promise<TwoFactorWebAuthnResponse>;
|
||||
getTwoFactorWebAuthnChallenge: (request: SecretVerificationRequest) => Promise<ChallengeResponse>;
|
||||
getTwoFactorRecover: (request: SecretVerificationRequest) => Promise<TwoFactorRecoverResponse>;
|
||||
putTwoFactorAuthenticator: (
|
||||
request: UpdateTwoFactorAuthenticatorRequest) => Promise<TwoFactorAuthenticatorResponse>;
|
||||
putTwoFactorEmail: (request: UpdateTwoFactorEmailRequest) => Promise<TwoFactorEmailResponse>;
|
||||
@@ -384,8 +388,8 @@ export abstract class ApiService {
|
||||
postLeaveOrganization: (id: string) => Promise<any>;
|
||||
postOrganizationLicense: (data: FormData) => Promise<OrganizationResponse>;
|
||||
postOrganizationLicenseUpdate: (id: string, data: FormData) => Promise<any>;
|
||||
postOrganizationApiKey: (id: string, request: PasswordVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
postOrganizationRotateApiKey: (id: string, request: PasswordVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
postOrganizationApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
postOrganizationRotateApiKey: (id: string, request: SecretVerificationRequest) => Promise<ApiKeyResponse>;
|
||||
postOrganizationSso: (id: string, request: OrganizationSsoRequest) => Promise<OrganizationSsoResponse>;
|
||||
postOrganizationUpgrade: (id: string, request: OrganizationUpgradeRequest) => Promise<PaymentResponse>;
|
||||
postOrganizationUpdateSubscription: (id: string, request: OrganizationSubscriptionUpdateRequest) => Promise<void>;
|
||||
@@ -395,7 +399,7 @@ export abstract class ApiService {
|
||||
postOrganizationVerifyBank: (id: string, request: VerifyBankRequest) => Promise<any>;
|
||||
postOrganizationCancel: (id: string) => Promise<any>;
|
||||
postOrganizationReinstate: (id: string) => Promise<any>;
|
||||
deleteOrganization: (id: string, request: PasswordVerificationRequest) => Promise<any>;
|
||||
deleteOrganization: (id: string, request: SecretVerificationRequest) => Promise<any>;
|
||||
getPlans: () => Promise<ListResponse<PlanResponse>>;
|
||||
getTaxRates: () => Promise<ListResponse<TaxRateResponse>>;
|
||||
getOrganizationKeys: (id: string) => Promise<OrganizationKeysResponse>;
|
||||
@@ -449,6 +453,6 @@ export abstract class ApiService {
|
||||
|
||||
preValidateSso: (identifier: string) => Promise<boolean>;
|
||||
|
||||
getUserKeyFromCryptoAgent: (cryptoAgentUrl: string) => Promise<CryptoAgentUserKeyResponse>;
|
||||
postUserKeyToCryptoAgent: (cryptoAgentUrl: string, request: CryptoAgentUserKeyRequest) => Promise<void>;
|
||||
getUserKeyFromKeyConnector: (keyConnectorUrl: string) => Promise<KeyConnectorUserKeyResponse>;
|
||||
postUserKeyToKeyConnector: (keyConnectorUrl: string, request: KeyConnectorUserKeyRequest) => Promise<void>;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ export type Urls = {
|
||||
icons?: string;
|
||||
notifications?: string;
|
||||
events?: string;
|
||||
keyConnector?: string;
|
||||
};
|
||||
|
||||
export type PayPalConfig = {
|
||||
@@ -26,6 +27,7 @@ export abstract class EnvironmentService {
|
||||
getApiUrl: () => string;
|
||||
getIdentityUrl: () => string;
|
||||
getEventsUrl: () => string;
|
||||
getKeyConnectorUrl: () => string;
|
||||
setUrlsFromStorage: () => Promise<void>;
|
||||
setUrls: (urls: any, saveSettings?: boolean) => Promise<Urls>;
|
||||
getUrls: () => Urls;
|
||||
|
||||
14
common/src/abstractions/keyConnector.service.ts
Normal file
14
common/src/abstractions/keyConnector.service.ts
Normal file
@@ -0,0 +1,14 @@
|
||||
import { Organization } from '../models/domain/organization';
|
||||
|
||||
export abstract class KeyConnectorService {
|
||||
getAndSetKey: (url?: string) => Promise<void>;
|
||||
getManagingOrganization: () => Promise<Organization>;
|
||||
getUsesKeyConnector: () => Promise<boolean>;
|
||||
migrateUser: () => Promise<void>;
|
||||
userNeedsMigration: () => Promise<boolean>;
|
||||
setUsesKeyConnector: (enabled: boolean) => Promise<void>;
|
||||
setConvertAccountRequired: (status: boolean) => Promise<void>;
|
||||
getConvertAccountRequired: () => Promise<boolean>;
|
||||
removeConvertAccountRequired: () => Promise<void>;
|
||||
clear: () => Promise<void>;
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
export abstract class PasswordRepromptService {
|
||||
protectedFields: () => string[];
|
||||
showPasswordPrompt: () => Promise<boolean>;
|
||||
enabled: () => Promise<boolean>;
|
||||
}
|
||||
|
||||
@@ -26,4 +26,5 @@ export abstract class TokenService {
|
||||
getName: () => string;
|
||||
getPremium: () => boolean;
|
||||
getIssuer: () => string;
|
||||
getIsExternal: () => boolean;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { OrganizationData } from '../models/data/organizationData';
|
||||
import { ProviderData } from '../models/data/providerData';
|
||||
|
||||
import { Organization } from '../models/domain/organization';
|
||||
import { Provider } from '../models/domain/provider';
|
||||
|
||||
|
||||
9
common/src/abstractions/userVerification.service.ts
Normal file
9
common/src/abstractions/userVerification.service.ts
Normal file
@@ -0,0 +1,9 @@
|
||||
import { SecretVerificationRequest } from '../models/request/secretVerificationRequest';
|
||||
|
||||
import { Verification } from '../types/verification';
|
||||
|
||||
export abstract class UserVerificationService {
|
||||
buildRequest: <T extends SecretVerificationRequest> (verification: Verification,
|
||||
requestClass?: new () => T, alreadyHashed?: boolean) => Promise<T>;
|
||||
verifyUser: (verification: Verification) => Promise<boolean>;
|
||||
}
|
||||
@@ -8,6 +8,7 @@ export enum EventType {
|
||||
User_FailedLogIn2fa = 1006,
|
||||
User_ClientExportedVault = 1007,
|
||||
User_UpdatedTempPassword = 1008,
|
||||
User_MigratedKeyToKeyConnector = 1009,
|
||||
|
||||
Cipher_Created = 1100,
|
||||
Cipher_Updated = 1101,
|
||||
@@ -51,6 +52,10 @@ export enum EventType {
|
||||
Organization_PurgedVault = 1601,
|
||||
// Organization_ClientExportedVault = 1602,
|
||||
Organization_VaultAccessed = 1603,
|
||||
Organization_EnabledSso = 1604,
|
||||
Organization_DisabledSso = 1605,
|
||||
Organization_EnabledKeyConnector = 1606,
|
||||
Organization_DisabledKeyConnector = 1607,
|
||||
|
||||
Policy_Updated = 1700,
|
||||
|
||||
|
||||
4
common/src/enums/verificationType.ts
Normal file
4
common/src/enums/verificationType.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export enum VerificationType {
|
||||
MasterPassword = 0,
|
||||
OTP = 1,
|
||||
}
|
||||
@@ -37,8 +37,8 @@ enum Saml2SigningBehavior {
|
||||
export class SsoConfigApi extends BaseResponse {
|
||||
configType: SsoType;
|
||||
|
||||
useCryptoAgent: boolean;
|
||||
cryptoAgentUrl: string;
|
||||
useKeyConnector: boolean;
|
||||
keyConnectorUrl: string;
|
||||
|
||||
// OpenId
|
||||
authority: string;
|
||||
@@ -81,8 +81,8 @@ export class SsoConfigApi extends BaseResponse {
|
||||
|
||||
this.configType = this.getResponseProperty('ConfigType');
|
||||
|
||||
this.useCryptoAgent = this.getResponseProperty('UseCryptoAgent');
|
||||
this.cryptoAgentUrl = this.getResponseProperty('CryptoAgentUrl');
|
||||
this.useKeyConnector = this.getResponseProperty('UseKeyConnector');
|
||||
this.keyConnectorUrl = this.getResponseProperty('KeyConnectorUrl');
|
||||
|
||||
this.authority = this.getResponseProperty('Authority');
|
||||
this.clientId = this.getResponseProperty('ClientId');
|
||||
|
||||
@@ -33,6 +33,8 @@ export class OrganizationData {
|
||||
providerId: string;
|
||||
providerName: string;
|
||||
isProviderUser: boolean;
|
||||
usesKeyConnector: boolean;
|
||||
keyConnectorUrl: string;
|
||||
|
||||
constructor(response: ProfileOrganizationResponse) {
|
||||
this.id = response.id;
|
||||
@@ -62,5 +64,7 @@ export class OrganizationData {
|
||||
this.hasPublicAndPrivateKeys = response.hasPublicAndPrivateKeys;
|
||||
this.providerId = response.providerId;
|
||||
this.providerName = response.providerName;
|
||||
this.usesKeyConnector = response.usesKeyConnector;
|
||||
this.keyConnectorUrl = response.keyConnectorUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,6 +34,8 @@ export class Organization {
|
||||
providerId: string;
|
||||
providerName: string;
|
||||
isProviderUser: boolean;
|
||||
usesKeyConnector: boolean;
|
||||
keyConnectorUrl: string;
|
||||
|
||||
constructor(obj?: OrganizationData) {
|
||||
if (obj == null) {
|
||||
@@ -68,6 +70,8 @@ export class Organization {
|
||||
this.providerId = obj.providerId;
|
||||
this.providerName = obj.providerName;
|
||||
this.isProviderUser = obj.isProviderUser;
|
||||
this.usesKeyConnector = obj.usesKeyConnector;
|
||||
this.keyConnectorUrl = obj.keyConnectorUrl;
|
||||
}
|
||||
|
||||
get canAccess() {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { KeysRequest } from '../keysRequest';
|
||||
|
||||
import { KdfType } from '../../../enums/kdfType';
|
||||
|
||||
export class SetCryptoAgentKeyRequest {
|
||||
export class SetKeyConnectorKeyRequest {
|
||||
key: string;
|
||||
keys: KeysRequest;
|
||||
kdf: KdfType;
|
||||
7
common/src/models/request/account/verifyOTPRequest.ts
Normal file
7
common/src/models/request/account/verifyOTPRequest.ts
Normal file
@@ -0,0 +1,7 @@
|
||||
export class VerifyOTPRequest {
|
||||
OTP: string;
|
||||
|
||||
constructor(OTP: string) {
|
||||
this.OTP = OTP;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class EmailTokenRequest extends PasswordVerificationRequest {
|
||||
export class EmailTokenRequest extends SecretVerificationRequest {
|
||||
newEmail: string;
|
||||
masterPasswordHash: string;
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
export class CryptoAgentUserKeyRequest {
|
||||
export class KeyConnectorUserKeyRequest {
|
||||
key: string;
|
||||
|
||||
constructor(key: string) {
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class PasswordRequest extends PasswordVerificationRequest {
|
||||
export class PasswordRequest extends SecretVerificationRequest {
|
||||
newMasterPasswordHash: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
export class PasswordVerificationRequest {
|
||||
masterPasswordHash: string;
|
||||
}
|
||||
4
common/src/models/request/secretVerificationRequest.ts
Normal file
4
common/src/models/request/secretVerificationRequest.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
export class SecretVerificationRequest {
|
||||
masterPasswordHash: string;
|
||||
otp: string;
|
||||
}
|
||||
@@ -1,11 +1,5 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class TwoFactorEmailRequest extends PasswordVerificationRequest {
|
||||
export class TwoFactorEmailRequest extends SecretVerificationRequest {
|
||||
email: string;
|
||||
|
||||
constructor(email: string, masterPasswordHash: string) {
|
||||
super();
|
||||
this.masterPasswordHash = masterPasswordHash;
|
||||
this.email = email;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
import { TwoFactorProviderType } from '../../enums/twoFactorProviderType';
|
||||
|
||||
export class TwoFactorProviderRequest extends PasswordVerificationRequest {
|
||||
export class TwoFactorProviderRequest extends SecretVerificationRequest {
|
||||
type: TwoFactorProviderType;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class TwoFactorRecoveryRequest extends PasswordVerificationRequest {
|
||||
export class TwoFactorRecoveryRequest extends SecretVerificationRequest {
|
||||
recoveryCode: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class UpdateTwoFactorAuthenticatorRequest extends PasswordVerificationRequest {
|
||||
export class UpdateTwoFactorAuthenticatorRequest extends SecretVerificationRequest {
|
||||
token: string;
|
||||
key: string;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class UpdateTwoFactorDuoRequest extends PasswordVerificationRequest {
|
||||
export class UpdateTwoFactorDuoRequest extends SecretVerificationRequest {
|
||||
integrationKey: string;
|
||||
secretKey: string;
|
||||
host: string;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class UpdateTwoFactorEmailRequest extends PasswordVerificationRequest {
|
||||
export class UpdateTwoFactorEmailRequest extends SecretVerificationRequest {
|
||||
token: string;
|
||||
email: string;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class UpdateTwoFactorWebAuthnDeleteRequest extends PasswordVerificationRequest {
|
||||
export class UpdateTwoFactorWebAuthnDeleteRequest extends SecretVerificationRequest {
|
||||
id: number;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class UpdateTwoFactorWebAuthnRequest extends PasswordVerificationRequest {
|
||||
export class UpdateTwoFactorWebAuthnRequest extends SecretVerificationRequest {
|
||||
deviceResponse: PublicKeyCredential;
|
||||
name: string;
|
||||
id: number;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { PasswordVerificationRequest } from './passwordVerificationRequest';
|
||||
import { SecretVerificationRequest } from './secretVerificationRequest';
|
||||
|
||||
export class UpdateTwoFactorYubioOtpRequest extends PasswordVerificationRequest {
|
||||
export class UpdateTwoFactorYubioOtpRequest extends SecretVerificationRequest {
|
||||
key1: string;
|
||||
key2: string;
|
||||
key3: string;
|
||||
|
||||
@@ -15,7 +15,7 @@ export class IdentityTokenResponse extends BaseResponse {
|
||||
kdf: KdfType;
|
||||
kdfIterations: number;
|
||||
forcePasswordReset: boolean;
|
||||
cryptoAgentUrl: string;
|
||||
keyConnectorUrl: string;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
@@ -31,6 +31,6 @@ export class IdentityTokenResponse extends BaseResponse {
|
||||
this.kdf = this.getResponseProperty('Kdf');
|
||||
this.kdfIterations = this.getResponseProperty('KdfIterations');
|
||||
this.forcePasswordReset = this.getResponseProperty('ForcePasswordReset');
|
||||
this.cryptoAgentUrl = this.getResponseProperty('CryptoAgentUrl');
|
||||
this.keyConnectorUrl = this.getResponseProperty('KeyConnectorUrl');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { BaseResponse } from './baseResponse';
|
||||
|
||||
export class CryptoAgentUserKeyResponse extends BaseResponse {
|
||||
export class KeyConnectorUserKeyResponse extends BaseResponse {
|
||||
key: string;
|
||||
|
||||
constructor(response: any) {
|
||||
@@ -33,6 +33,8 @@ export class ProfileOrganizationResponse extends BaseResponse {
|
||||
userId: string;
|
||||
providerId: string;
|
||||
providerName: string;
|
||||
usesKeyConnector: boolean;
|
||||
keyConnectorUrl: string;
|
||||
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
@@ -64,5 +66,7 @@ export class ProfileOrganizationResponse extends BaseResponse {
|
||||
this.userId = this.getResponseProperty('UserId');
|
||||
this.providerId = this.getResponseProperty('ProviderId');
|
||||
this.providerName = this.getResponseProperty('ProviderName');
|
||||
this.usesKeyConnector = this.getResponseProperty('UsesKeyConnector') ?? false;
|
||||
this.keyConnectorUrl = this.getResponseProperty('KeyConnectorUrl');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,68 +1,8 @@
|
||||
import { BaseResponse } from './baseResponse';
|
||||
|
||||
import { OrganizationUserStatusType } from '../../enums/organizationUserStatusType';
|
||||
import { OrganizationUserType } from '../../enums/organizationUserType';
|
||||
import { PermissionsApi } from '../api/permissionsApi';
|
||||
|
||||
export class ProfileProviderOrganizationResponse extends BaseResponse {
|
||||
id: string;
|
||||
name: string;
|
||||
usePolicies: boolean;
|
||||
useGroups: boolean;
|
||||
useDirectory: boolean;
|
||||
useEvents: boolean;
|
||||
useTotp: boolean;
|
||||
use2fa: boolean;
|
||||
useApi: boolean;
|
||||
useSso: boolean;
|
||||
useResetPassword: boolean;
|
||||
selfHost: boolean;
|
||||
usersGetPremium: boolean;
|
||||
seats: number;
|
||||
maxCollections: number;
|
||||
maxStorageGb?: number;
|
||||
key: string;
|
||||
hasPublicAndPrivateKeys: boolean;
|
||||
status: OrganizationUserStatusType;
|
||||
type: OrganizationUserType;
|
||||
enabled: boolean;
|
||||
ssoBound: boolean;
|
||||
identifier: string;
|
||||
permissions: PermissionsApi;
|
||||
resetPasswordEnrolled: boolean;
|
||||
userId: string;
|
||||
providerId: string;
|
||||
providerName: string;
|
||||
import { ProfileOrganizationResponse } from './profileOrganizationResponse';
|
||||
|
||||
export class ProfileProviderOrganizationResponse extends ProfileOrganizationResponse {
|
||||
constructor(response: any) {
|
||||
super(response);
|
||||
this.id = this.getResponseProperty('Id');
|
||||
this.name = this.getResponseProperty('Name');
|
||||
this.usePolicies = this.getResponseProperty('UsePolicies');
|
||||
this.useGroups = this.getResponseProperty('UseGroups');
|
||||
this.useDirectory = this.getResponseProperty('UseDirectory');
|
||||
this.useEvents = this.getResponseProperty('UseEvents');
|
||||
this.useTotp = this.getResponseProperty('UseTotp');
|
||||
this.use2fa = this.getResponseProperty('Use2fa');
|
||||
this.useApi = this.getResponseProperty('UseApi');
|
||||
this.useSso = this.getResponseProperty('UseSso');
|
||||
this.useResetPassword = this.getResponseProperty('UseResetPassword');
|
||||
this.selfHost = this.getResponseProperty('SelfHost');
|
||||
this.usersGetPremium = this.getResponseProperty('UsersGetPremium');
|
||||
this.seats = this.getResponseProperty('Seats');
|
||||
this.maxCollections = this.getResponseProperty('MaxCollections');
|
||||
this.maxStorageGb = this.getResponseProperty('MaxStorageGb');
|
||||
this.key = this.getResponseProperty('Key');
|
||||
this.hasPublicAndPrivateKeys = this.getResponseProperty('HasPublicAndPrivateKeys');
|
||||
this.status = this.getResponseProperty('Status');
|
||||
this.type = this.getResponseProperty('Type');
|
||||
this.enabled = this.getResponseProperty('Enabled');
|
||||
this.ssoBound = this.getResponseProperty('SsoBound');
|
||||
this.identifier = this.getResponseProperty('Identifier');
|
||||
this.permissions = new PermissionsApi(this.getResponseProperty('permissions'));
|
||||
this.resetPasswordEnrolled = this.getResponseProperty('ResetPasswordEnrolled');
|
||||
this.userId = this.getResponseProperty('UserId');
|
||||
this.providerId = this.getResponseProperty('ProviderId');
|
||||
this.providerName = this.getResponseProperty('ProviderName');
|
||||
this.usesKeyConnector = false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ export class ProfileResponse extends BaseResponse {
|
||||
privateKey: string;
|
||||
securityStamp: string;
|
||||
forcePasswordReset: boolean;
|
||||
usesKeyConnector: boolean;
|
||||
organizations: ProfileOrganizationResponse[] = [];
|
||||
providers: ProfileProviderResponse[] = [];
|
||||
providerOrganizations: ProfileProviderOrganizationResponse[] = [];
|
||||
@@ -34,6 +35,7 @@ export class ProfileResponse extends BaseResponse {
|
||||
this.privateKey = this.getResponseProperty('PrivateKey');
|
||||
this.securityStamp = this.getResponseProperty('SecurityStamp');
|
||||
this.forcePasswordReset = this.getResponseProperty('ForcePasswordReset') ?? false;
|
||||
this.usesKeyConnector = this.getResponseProperty('UsesKeyConnector') ?? false;
|
||||
|
||||
const organizations = this.getResponseProperty('Organizations');
|
||||
if (organizations != null) {
|
||||
|
||||
@@ -52,7 +52,6 @@ import { OrganizationUserUpdateGroupsRequest } from '../models/request/organizat
|
||||
import { OrganizationUserUpdateRequest } from '../models/request/organizationUserUpdateRequest';
|
||||
import { PasswordHintRequest } from '../models/request/passwordHintRequest';
|
||||
import { PasswordRequest } from '../models/request/passwordRequest';
|
||||
import { PasswordVerificationRequest } from '../models/request/passwordVerificationRequest';
|
||||
import { PaymentRequest } from '../models/request/paymentRequest';
|
||||
import { PolicyRequest } from '../models/request/policyRequest';
|
||||
import { PreloginRequest } from '../models/request/preloginRequest';
|
||||
@@ -68,6 +67,7 @@ import { ProviderUserInviteRequest } from '../models/request/provider/providerUs
|
||||
import { ProviderUserUpdateRequest } from '../models/request/provider/providerUserUpdateRequest';
|
||||
import { RegisterRequest } from '../models/request/registerRequest';
|
||||
import { SeatRequest } from '../models/request/seatRequest';
|
||||
import { SecretVerificationRequest } from '../models/request/secretVerificationRequest';
|
||||
import { SelectionReadOnlyRequest } from '../models/request/selectionReadOnlyRequest';
|
||||
import { SendAccessRequest } from '../models/request/sendAccessRequest';
|
||||
import { SendRequest } from '../models/request/sendRequest';
|
||||
@@ -166,9 +166,10 @@ import { ChallengeResponse } from '../models/response/twoFactorWebAuthnResponse'
|
||||
import { TwoFactorYubiKeyResponse } from '../models/response/twoFactorYubiKeyResponse';
|
||||
import { UserKeyResponse } from '../models/response/userKeyResponse';
|
||||
|
||||
import { SetCryptoAgentKeyRequest } from '../models/request/account/setCryptoAgentKeyRequest';
|
||||
import { CryptoAgentUserKeyRequest } from '../models/request/cryptoAgentUserKeyRequest';
|
||||
import { CryptoAgentUserKeyResponse } from '../models/response/cryptoAgentUserKeyResponse';
|
||||
import { SetKeyConnectorKeyRequest } from '../models/request/account/setKeyConnectorKeyRequest';
|
||||
import { VerifyOTPRequest } from '../models/request/account/verifyOTPRequest';
|
||||
import { KeyConnectorUserKeyRequest } from '../models/request/keyConnectorUserKeyRequest';
|
||||
import { KeyConnectorUserKeyResponse } from '../models/response/keyConnectorUserKeyResponse';
|
||||
import { SendAccessView } from '../models/view/sendAccessView';
|
||||
|
||||
export class ApiService implements ApiServiceAbstraction {
|
||||
@@ -292,15 +293,15 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
return this.send('POST', '/accounts/set-password', request, true, false);
|
||||
}
|
||||
|
||||
postSetCryptoAgentKey(request: SetCryptoAgentKeyRequest): Promise<any> {
|
||||
return this.send('POST', '/accounts/set-crypto-agent-key', request, true, false);
|
||||
postSetKeyConnectorKey(request: SetKeyConnectorKeyRequest): Promise<any> {
|
||||
return this.send('POST', '/accounts/set-key-connector-key', request, true, false);
|
||||
}
|
||||
|
||||
postSecurityStamp(request: PasswordVerificationRequest): Promise<any> {
|
||||
postSecurityStamp(request: SecretVerificationRequest): Promise<any> {
|
||||
return this.send('POST', '/accounts/security-stamp', request, true, false);
|
||||
}
|
||||
|
||||
deleteAccount(request: PasswordVerificationRequest): Promise<any> {
|
||||
deleteAccount(request: SecretVerificationRequest): Promise<any> {
|
||||
return this.send('DELETE', '/accounts', request, true, false);
|
||||
}
|
||||
|
||||
@@ -363,7 +364,7 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
return this.send('POST', '/accounts/verify-email-token', request, false, false);
|
||||
}
|
||||
|
||||
postAccountVerifyPassword(request: PasswordVerificationRequest): Promise<any> {
|
||||
postAccountVerifyPassword(request: SecretVerificationRequest): Promise<any> {
|
||||
return this.send('POST', '/accounts/verify-password', request, true, false);
|
||||
}
|
||||
|
||||
@@ -387,12 +388,12 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
return this.send('GET', '/accounts/sso/user-identifier', null, true, true);
|
||||
}
|
||||
|
||||
async postUserApiKey(id: string, request: PasswordVerificationRequest): Promise<ApiKeyResponse> {
|
||||
async postUserApiKey(id: string, request: SecretVerificationRequest): Promise<ApiKeyResponse> {
|
||||
const r = await this.send('POST', '/accounts/api-key', request, true, true);
|
||||
return new ApiKeyResponse(r);
|
||||
}
|
||||
|
||||
async postUserRotateApiKey(id: string, request: PasswordVerificationRequest): Promise<ApiKeyResponse> {
|
||||
async postUserRotateApiKey(id: string, request: SecretVerificationRequest): Promise<ApiKeyResponse> {
|
||||
const r = await this.send('POST', '/accounts/rotate-api-key', request, true, true);
|
||||
return new ApiKeyResponse(r);
|
||||
}
|
||||
@@ -401,6 +402,18 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
return this.send('PUT', '/accounts/update-temp-password', request, true, false);
|
||||
}
|
||||
|
||||
postAccountRequestOTP(): Promise<void> {
|
||||
return this.send('POST', '/accounts/request-otp', null, true, false);
|
||||
}
|
||||
|
||||
postAccountVerifyOTP(request: VerifyOTPRequest): Promise<void> {
|
||||
return this.send('POST', '/accounts/verify-otp', request, true, false);
|
||||
}
|
||||
|
||||
postConvertToKeyConnector(): Promise<void> {
|
||||
return this.send('POST', '/accounts/convert-to-key-connector', null, true, false);
|
||||
}
|
||||
|
||||
// Folder APIs
|
||||
|
||||
async getFolder(id: string): Promise<FolderResponse> {
|
||||
@@ -573,7 +586,7 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
return this.send('PUT', '/ciphers/' + id + '/collections-admin', request, true, false);
|
||||
}
|
||||
|
||||
postPurgeCiphers(request: PasswordVerificationRequest, organizationId: string = null): Promise<any> {
|
||||
postPurgeCiphers(request: SecretVerificationRequest, organizationId: string = null): Promise<any> {
|
||||
let path = '/ciphers/purge';
|
||||
if (organizationId != null) {
|
||||
path += '?organizationId=' + organizationId;
|
||||
@@ -939,44 +952,44 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
return new ListResponse(r, TwoFactorProviderResponse);
|
||||
}
|
||||
|
||||
async getTwoFactorAuthenticator(request: PasswordVerificationRequest): Promise<TwoFactorAuthenticatorResponse> {
|
||||
async getTwoFactorAuthenticator(request: SecretVerificationRequest): Promise<TwoFactorAuthenticatorResponse> {
|
||||
const r = await this.send('POST', '/two-factor/get-authenticator', request, true, true);
|
||||
return new TwoFactorAuthenticatorResponse(r);
|
||||
}
|
||||
|
||||
async getTwoFactorEmail(request: PasswordVerificationRequest): Promise<TwoFactorEmailResponse> {
|
||||
async getTwoFactorEmail(request: SecretVerificationRequest): Promise<TwoFactorEmailResponse> {
|
||||
const r = await this.send('POST', '/two-factor/get-email', request, true, true);
|
||||
return new TwoFactorEmailResponse(r);
|
||||
}
|
||||
|
||||
async getTwoFactorDuo(request: PasswordVerificationRequest): Promise<TwoFactorDuoResponse> {
|
||||
async getTwoFactorDuo(request: SecretVerificationRequest): Promise<TwoFactorDuoResponse> {
|
||||
const r = await this.send('POST', '/two-factor/get-duo', request, true, true);
|
||||
return new TwoFactorDuoResponse(r);
|
||||
}
|
||||
|
||||
async getTwoFactorOrganizationDuo(organizationId: string,
|
||||
request: PasswordVerificationRequest): Promise<TwoFactorDuoResponse> {
|
||||
request: SecretVerificationRequest): Promise<TwoFactorDuoResponse> {
|
||||
const r = await this.send('POST', '/organizations/' + organizationId + '/two-factor/get-duo',
|
||||
request, true, true);
|
||||
return new TwoFactorDuoResponse(r);
|
||||
}
|
||||
|
||||
async getTwoFactorYubiKey(request: PasswordVerificationRequest): Promise<TwoFactorYubiKeyResponse> {
|
||||
async getTwoFactorYubiKey(request: SecretVerificationRequest): Promise<TwoFactorYubiKeyResponse> {
|
||||
const r = await this.send('POST', '/two-factor/get-yubikey', request, true, true);
|
||||
return new TwoFactorYubiKeyResponse(r);
|
||||
}
|
||||
|
||||
async getTwoFactorWebAuthn(request: PasswordVerificationRequest): Promise<TwoFactorWebAuthnResponse> {
|
||||
async getTwoFactorWebAuthn(request: SecretVerificationRequest): Promise<TwoFactorWebAuthnResponse> {
|
||||
const r = await this.send('POST', '/two-factor/get-webauthn', request, true, true);
|
||||
return new TwoFactorWebAuthnResponse(r);
|
||||
}
|
||||
|
||||
async getTwoFactorWebAuthnChallenge(request: PasswordVerificationRequest): Promise<ChallengeResponse> {
|
||||
async getTwoFactorWebAuthnChallenge(request: SecretVerificationRequest): Promise<ChallengeResponse> {
|
||||
const r = await this.send('POST', '/two-factor/get-webauthn-challenge', request, true, true);
|
||||
return new ChallengeResponse(r);
|
||||
}
|
||||
|
||||
async getTwoFactorRecover(request: PasswordVerificationRequest): Promise<TwoFactorRecoverResponse> {
|
||||
async getTwoFactorRecover(request: SecretVerificationRequest): Promise<TwoFactorRecoverResponse> {
|
||||
const r = await this.send('POST', '/two-factor/get-recover', request, true, true);
|
||||
return new TwoFactorRecoverResponse(r);
|
||||
}
|
||||
@@ -1187,12 +1200,12 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
return this.send('POST', '/organizations/' + id + '/license', data, true, false);
|
||||
}
|
||||
|
||||
async postOrganizationApiKey(id: string, request: PasswordVerificationRequest): Promise<ApiKeyResponse> {
|
||||
async postOrganizationApiKey(id: string, request: SecretVerificationRequest): Promise<ApiKeyResponse> {
|
||||
const r = await this.send('POST', '/organizations/' + id + '/api-key', request, true, true);
|
||||
return new ApiKeyResponse(r);
|
||||
}
|
||||
|
||||
async postOrganizationRotateApiKey(id: string, request: PasswordVerificationRequest): Promise<ApiKeyResponse> {
|
||||
async postOrganizationRotateApiKey(id: string, request: SecretVerificationRequest): Promise<ApiKeyResponse> {
|
||||
const r = await this.send('POST', '/organizations/' + id + '/rotate-api-key', request, true, true);
|
||||
return new ApiKeyResponse(r);
|
||||
}
|
||||
@@ -1237,7 +1250,7 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
return this.send('POST', '/organizations/' + id + '/reinstate', null, true, false);
|
||||
}
|
||||
|
||||
deleteOrganization(id: string, request: PasswordVerificationRequest): Promise<any> {
|
||||
deleteOrganization(id: string, request: SecretVerificationRequest): Promise<any> {
|
||||
return this.send('DELETE', '/organizations/' + id, request, true, false);
|
||||
}
|
||||
|
||||
@@ -1436,12 +1449,12 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
return r as string;
|
||||
}
|
||||
|
||||
// Crypto Agent
|
||||
// Key Connector
|
||||
|
||||
async getUserKeyFromCryptoAgent(cryptoAgentUrl: string): Promise<CryptoAgentUserKeyResponse> {
|
||||
async getUserKeyFromKeyConnector(keyConnectorUrl: string): Promise<KeyConnectorUserKeyResponse> {
|
||||
const authHeader = await this.getActiveBearerToken();
|
||||
|
||||
const response = await this.fetch(new Request(cryptoAgentUrl + '/user-keys', {
|
||||
const response = await this.fetch(new Request(keyConnectorUrl + '/user-keys', {
|
||||
cache: 'no-store',
|
||||
method: 'GET',
|
||||
headers: new Headers({
|
||||
@@ -1455,13 +1468,13 @@ export class ApiService implements ApiServiceAbstraction {
|
||||
return Promise.reject(error);
|
||||
}
|
||||
|
||||
return new CryptoAgentUserKeyResponse(await response.json());
|
||||
return new KeyConnectorUserKeyResponse(await response.json());
|
||||
}
|
||||
|
||||
async postUserKeyToCryptoAgent(cryptoAgentUrl: string, request: CryptoAgentUserKeyRequest): Promise<void> {
|
||||
async postUserKeyToKeyConnector(keyConnectorUrl: string, request: KeyConnectorUserKeyRequest): Promise<void> {
|
||||
const authHeader = await this.getActiveBearerToken();
|
||||
|
||||
const response = await this.fetch(new Request(cryptoAgentUrl + '/user-keys', {
|
||||
const response = await this.fetch(new Request(keyConnectorUrl + '/user-keys', {
|
||||
cache: 'no-store',
|
||||
method: 'POST',
|
||||
headers: new Headers({
|
||||
|
||||
@@ -5,9 +5,9 @@ import { TwoFactorProviderType } from '../enums/twoFactorProviderType';
|
||||
import { AuthResult } from '../models/domain/authResult';
|
||||
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
|
||||
|
||||
import { SetCryptoAgentKeyRequest } from '../models/request/account/setCryptoAgentKeyRequest';
|
||||
import { CryptoAgentUserKeyRequest } from '../models/request/cryptoAgentUserKeyRequest';
|
||||
import { SetKeyConnectorKeyRequest } from '../models/request/account/setKeyConnectorKeyRequest';
|
||||
import { DeviceRequest } from '../models/request/deviceRequest';
|
||||
import { KeyConnectorUserKeyRequest } from '../models/request/keyConnectorUserKeyRequest';
|
||||
import { KeysRequest } from '../models/request/keysRequest';
|
||||
import { PreloginRequest } from '../models/request/preloginRequest';
|
||||
import { TokenRequest } from '../models/request/tokenRequest';
|
||||
@@ -20,7 +20,9 @@ import { AppIdService } from '../abstractions/appId.service';
|
||||
import { AuthService as AuthServiceAbstraction } from '../abstractions/auth.service';
|
||||
import { CryptoService } from '../abstractions/crypto.service';
|
||||
import { CryptoFunctionService } from '../abstractions/cryptoFunction.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';
|
||||
@@ -101,7 +103,8 @@ export class AuthService implements AuthServiceAbstraction {
|
||||
protected appIdService: AppIdService, private i18nService: I18nService,
|
||||
protected platformUtilsService: PlatformUtilsService, private messagingService: MessagingService,
|
||||
private vaultTimeoutService: VaultTimeoutService, private logService: LogService,
|
||||
private cryptoFunctionService: CryptoFunctionService, private setCryptoKeys = true) {
|
||||
private cryptoFunctionService: CryptoFunctionService, private environmentService: EnvironmentService,
|
||||
private keyConnectorService: KeyConnectorService, private setCryptoKeys = true) {
|
||||
}
|
||||
|
||||
init() {
|
||||
@@ -365,16 +368,10 @@ export class AuthService implements AuthServiceAbstraction {
|
||||
// Skip this step during SSO new user flow. No key is returned from server.
|
||||
if (code == null || tokenResponse.key != null) {
|
||||
|
||||
if (tokenResponse.cryptoAgentUrl != null) {
|
||||
try {
|
||||
const userKeyResponse = await this.apiService.getUserKeyFromCryptoAgent(tokenResponse.cryptoAgentUrl);
|
||||
const keyArr = Utils.fromB64ToArray(userKeyResponse.key);
|
||||
const k = new SymmetricCryptoKey(keyArr);
|
||||
await this.cryptoService.setKey(k);
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
throw new Error('Unable to reach crypto agent');
|
||||
}
|
||||
if (tokenResponse.keyConnectorUrl != null) {
|
||||
await this.keyConnectorService.getAndSetKey(tokenResponse.keyConnectorUrl);
|
||||
} else if (this.environmentService.getKeyConnectorUrl() != null) {
|
||||
await this.keyConnectorService.getAndSetKey();
|
||||
}
|
||||
|
||||
await this.cryptoService.setEncKey(tokenResponse.key);
|
||||
@@ -391,11 +388,11 @@ export class AuthService implements AuthServiceAbstraction {
|
||||
}
|
||||
|
||||
await this.cryptoService.setEncPrivateKey(tokenResponse.privateKey);
|
||||
} else if (tokenResponse.cryptoAgentUrl != null) {
|
||||
} else if (tokenResponse.keyConnectorUrl != null) {
|
||||
const password = await this.cryptoFunctionService.randomBytes(64);
|
||||
|
||||
const k = await this.cryptoService.makeKey(Utils.fromBufferToB64(password), this.tokenService.getEmail(), tokenResponse.kdf, tokenResponse.kdfIterations);
|
||||
const cryptoAgentRequest = new CryptoAgentUserKeyRequest(k.encKeyB64);
|
||||
const keyConnectorRequest = new KeyConnectorUserKeyRequest(k.encKeyB64);
|
||||
await this.cryptoService.setKey(k);
|
||||
|
||||
const encKey = await this.cryptoService.makeEncKey(k);
|
||||
@@ -404,16 +401,16 @@ export class AuthService implements AuthServiceAbstraction {
|
||||
const [pubKey, privKey] = await this.cryptoService.makeKeyPair();
|
||||
|
||||
try {
|
||||
await this.apiService.postUserKeyToCryptoAgent(tokenResponse.cryptoAgentUrl, cryptoAgentRequest);
|
||||
await this.apiService.postUserKeyToKeyConnector(tokenResponse.keyConnectorUrl, keyConnectorRequest);
|
||||
} catch (e) {
|
||||
throw new Error('Unable to reach crypto agent');
|
||||
throw new Error('Unable to reach key connector');
|
||||
}
|
||||
|
||||
const keys = new KeysRequest(pubKey, privKey.encryptedString);
|
||||
const setPasswordRequest = new SetCryptoAgentKeyRequest(
|
||||
const setPasswordRequest = new SetKeyConnectorKeyRequest(
|
||||
encKey[1].encryptedString, tokenResponse.kdf, tokenResponse.kdfIterations, orgId, keys
|
||||
);
|
||||
await this.apiService.postSetCryptoAgentKey(setPasswordRequest);
|
||||
await this.apiService.postSetKeyConnectorKey(setPasswordRequest);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
|
||||
private iconsUrl: string;
|
||||
private notificationsUrl: string;
|
||||
private eventsUrl: string;
|
||||
private keyConnectorUrl: string;
|
||||
|
||||
constructor(private storageService: StorageService) {}
|
||||
|
||||
@@ -103,6 +104,10 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
|
||||
return 'https://events.bitwarden.com';
|
||||
}
|
||||
|
||||
getKeyConnectorUrl() {
|
||||
return this.keyConnectorUrl;
|
||||
}
|
||||
|
||||
async setUrlsFromStorage(): Promise<void> {
|
||||
const urlsObj: any = await this.storageService.get(ConstantsService.environmentUrlsKey);
|
||||
const urls = urlsObj || {
|
||||
@@ -113,6 +118,7 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
|
||||
notifications: null,
|
||||
events: null,
|
||||
webVault: null,
|
||||
keyConnector: null,
|
||||
};
|
||||
|
||||
const envUrls = new EnvironmentUrls();
|
||||
@@ -128,6 +134,7 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
|
||||
this.iconsUrl = urls.icons;
|
||||
this.notificationsUrl = urls.notifications;
|
||||
this.eventsUrl = envUrls.events = urls.events;
|
||||
this.keyConnectorUrl = urls.keyConnector;
|
||||
}
|
||||
|
||||
async setUrls(urls: Urls, saveSettings: boolean = true): Promise<any> {
|
||||
@@ -138,6 +145,7 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
|
||||
urls.icons = this.formatUrl(urls.icons);
|
||||
urls.notifications = this.formatUrl(urls.notifications);
|
||||
urls.events = this.formatUrl(urls.events);
|
||||
urls.keyConnector = this.formatUrl(urls.keyConnector);
|
||||
|
||||
if (saveSettings) {
|
||||
await this.storageService.save(ConstantsService.environmentUrlsKey, {
|
||||
@@ -148,6 +156,7 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
|
||||
icons: urls.icons,
|
||||
notifications: urls.notifications,
|
||||
events: urls.events,
|
||||
keyConnector: urls.keyConnector,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -158,6 +167,7 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
|
||||
this.iconsUrl = urls.icons;
|
||||
this.notificationsUrl = urls.notifications;
|
||||
this.eventsUrl = urls.events;
|
||||
this.keyConnectorUrl = urls.keyConnector;
|
||||
|
||||
this.urlsSubject.next(urls);
|
||||
|
||||
@@ -173,6 +183,7 @@ export class EnvironmentService implements EnvironmentServiceAbstraction {
|
||||
icons: this.iconsUrl,
|
||||
notifications: this.notificationsUrl,
|
||||
events: this.eventsUrl,
|
||||
keyConnector: this.keyConnectorUrl,
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
106
common/src/services/keyConnector.service.ts
Normal file
106
common/src/services/keyConnector.service.ts
Normal file
@@ -0,0 +1,106 @@
|
||||
import { ApiService } from '../abstractions/api.service';
|
||||
import { CryptoService } from '../abstractions/crypto.service';
|
||||
import { EnvironmentService } from '../abstractions/environment.service';
|
||||
import { KeyConnectorService as KeyConnectorServiceAbstraction } from '../abstractions/keyConnector.service';
|
||||
import { LogService } from '../abstractions/log.service';
|
||||
import { StorageService } from '../abstractions/storage.service';
|
||||
import { TokenService } from '../abstractions/token.service';
|
||||
import { UserService } from '../abstractions/user.service';
|
||||
|
||||
import { OrganizationUserType } from '../enums/organizationUserType';
|
||||
|
||||
import { Utils } from '../misc/utils';
|
||||
|
||||
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
|
||||
|
||||
import { KeyConnectorUserKeyRequest } from '../models/request/keyConnectorUserKeyRequest';
|
||||
|
||||
const Keys = {
|
||||
usesKeyConnector: 'usesKeyConnector',
|
||||
convertAccountToKeyConnector: 'convertAccountToKeyConnector',
|
||||
};
|
||||
|
||||
export class KeyConnectorService implements KeyConnectorServiceAbstraction {
|
||||
private usesKeyConnector?: boolean = null;
|
||||
|
||||
constructor(private storageService: StorageService, private userService: UserService,
|
||||
private cryptoService: CryptoService, private apiService: ApiService,
|
||||
private environmentService: EnvironmentService, private tokenService: TokenService,
|
||||
private logService: LogService) { }
|
||||
|
||||
setUsesKeyConnector(usesKeyConnector: boolean) {
|
||||
this.usesKeyConnector = usesKeyConnector;
|
||||
return this.storageService.save(Keys.usesKeyConnector, usesKeyConnector);
|
||||
}
|
||||
|
||||
async getUsesKeyConnector(): Promise<boolean> {
|
||||
return this.usesKeyConnector ??= await this.storageService.get<boolean>(Keys.usesKeyConnector);
|
||||
}
|
||||
|
||||
async userNeedsMigration() {
|
||||
const loggedInUsingSso = this.tokenService.getIsExternal();
|
||||
const requiredByOrganization = await this.getManagingOrganization() != null;
|
||||
const userIsNotUsingKeyConnector = !await this.getUsesKeyConnector();
|
||||
|
||||
return loggedInUsingSso && requiredByOrganization && userIsNotUsingKeyConnector;
|
||||
}
|
||||
|
||||
async migrateUser() {
|
||||
const organization = await this.getManagingOrganization();
|
||||
const key = await this.cryptoService.getKey();
|
||||
|
||||
try {
|
||||
const keyConnectorRequest = new KeyConnectorUserKeyRequest(key.encKeyB64);
|
||||
await this.apiService.postUserKeyToKeyConnector(organization.keyConnectorUrl, keyConnectorRequest);
|
||||
} catch (e) {
|
||||
throw new Error('Unable to reach key connector');
|
||||
}
|
||||
|
||||
await this.apiService.postConvertToKeyConnector();
|
||||
}
|
||||
|
||||
async getAndSetKey(url?: string) {
|
||||
if (url == null) {
|
||||
url = this.environmentService.getKeyConnectorUrl();
|
||||
}
|
||||
|
||||
if (url == null) {
|
||||
throw new Error('No Key Connector URL found.');
|
||||
}
|
||||
|
||||
try {
|
||||
const userKeyResponse = await this.apiService.getUserKeyFromKeyConnector(url);
|
||||
const keyArr = Utils.fromB64ToArray(userKeyResponse.key);
|
||||
const k = new SymmetricCryptoKey(keyArr);
|
||||
await this.cryptoService.setKey(k);
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
throw new Error('Unable to reach key connector');
|
||||
}
|
||||
}
|
||||
|
||||
async getManagingOrganization() {
|
||||
const orgs = await this.userService.getAllOrganizations();
|
||||
return orgs.find(o =>
|
||||
o.usesKeyConnector &&
|
||||
o.type !== OrganizationUserType.Admin &&
|
||||
o.type !== OrganizationUserType.Owner &&
|
||||
!o.isProviderUser);
|
||||
}
|
||||
|
||||
async setConvertAccountRequired(status: boolean) {
|
||||
await this.storageService.save(Keys.convertAccountToKeyConnector, status);
|
||||
}
|
||||
|
||||
async getConvertAccountRequired(): Promise<boolean> {
|
||||
return await this.storageService.get(Keys.convertAccountToKeyConnector);
|
||||
}
|
||||
|
||||
async removeConvertAccountRequired() {
|
||||
await this.storageService.remove(Keys.convertAccountToKeyConnector);
|
||||
}
|
||||
|
||||
async clear() {
|
||||
await this.removeConvertAccountRequired();
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ import { CipherService } from '../abstractions/cipher.service';
|
||||
import { CollectionService } from '../abstractions/collection.service';
|
||||
import { CryptoService } from '../abstractions/crypto.service';
|
||||
import { FolderService } from '../abstractions/folder.service';
|
||||
import { KeyConnectorService } from '../abstractions/keyConnector.service';
|
||||
import { LogService } from '../abstractions/log.service';
|
||||
import { MessagingService } from '../abstractions/messaging.service';
|
||||
import { PolicyService } from '../abstractions/policy.service';
|
||||
@@ -10,6 +11,7 @@ import { SendService } from '../abstractions/send.service';
|
||||
import { SettingsService } from '../abstractions/settings.service';
|
||||
import { StorageService } from '../abstractions/storage.service';
|
||||
import { SyncService as SyncServiceAbstraction } from '../abstractions/sync.service';
|
||||
import { TokenService } from '../abstractions/token.service';
|
||||
import { UserService } from '../abstractions/user.service';
|
||||
|
||||
import { CipherData } from '../models/data/cipherData';
|
||||
@@ -46,6 +48,7 @@ export class SyncService implements SyncServiceAbstraction {
|
||||
private collectionService: CollectionService, private storageService: StorageService,
|
||||
private messagingService: MessagingService, private policyService: PolicyService,
|
||||
private sendService: SendService, private logService: LogService,
|
||||
private tokenService: TokenService, private keyConnectorService: KeyConnectorService,
|
||||
private logoutCallback: (expired: boolean) => Promise<void>) {
|
||||
}
|
||||
|
||||
@@ -299,6 +302,7 @@ export class SyncService implements SyncServiceAbstraction {
|
||||
await this.userService.setSecurityStamp(response.securityStamp);
|
||||
await this.userService.setEmailVerified(response.emailVerified);
|
||||
await this.userService.setForcePasswordReset(response.forcePasswordReset);
|
||||
await this.keyConnectorService.setUsesKeyConnector(response.usesKeyConnector);
|
||||
|
||||
const organizations: { [id: string]: OrganizationData; } = {};
|
||||
response.organizations.forEach(o => {
|
||||
@@ -316,6 +320,13 @@ export class SyncService implements SyncServiceAbstraction {
|
||||
organizations[o.id].isProviderUser = true;
|
||||
}
|
||||
});
|
||||
|
||||
if (await this.keyConnectorService.userNeedsMigration()) {
|
||||
this.messagingService.send('convertAccountToKeyConnector');
|
||||
} else {
|
||||
this.keyConnectorService.removeConvertAccountRequired();
|
||||
}
|
||||
|
||||
return Promise.all([
|
||||
this.userService.replaceOrganizations(organizations),
|
||||
this.userService.replaceProviders(providers),
|
||||
|
||||
@@ -243,6 +243,15 @@ export class TokenService implements TokenServiceAbstraction {
|
||||
return decoded.iss as string;
|
||||
}
|
||||
|
||||
getIsExternal(): boolean {
|
||||
const decoded = this.decodeToken();
|
||||
if (!Array.isArray(decoded.amr)) {
|
||||
throw new Error('No amr found');
|
||||
}
|
||||
|
||||
return decoded.amr.includes('external');
|
||||
}
|
||||
|
||||
private async storeTokenValue(key: string, value: string) {
|
||||
if (await this.skipTokenStorage()) {
|
||||
// if we have a vault timeout and the action is log out, don't store token
|
||||
|
||||
@@ -6,6 +6,7 @@ import { OrganizationData } from '../models/data/organizationData';
|
||||
import { Organization } from '../models/domain/organization';
|
||||
|
||||
import { KdfType } from '../enums/kdfType';
|
||||
|
||||
import { ProviderData } from '../models/data/providerData';
|
||||
import { Provider } from '../models/domain/provider';
|
||||
|
||||
|
||||
70
common/src/services/userVerification.service.ts
Normal file
70
common/src/services/userVerification.service.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
|
||||
import { UserVerificationService as UserVerificationServiceAbstraction } from '../abstractions/userVerification.service';
|
||||
|
||||
import { ApiService } from '../abstractions/api.service';
|
||||
import { CryptoService } from '../abstractions/crypto.service';
|
||||
import { I18nService } from '../abstractions/i18n.service';
|
||||
import { LogService } from '../abstractions/log.service';
|
||||
import { PlatformUtilsService } from '../abstractions/platformUtils.service';
|
||||
|
||||
import { VerificationType } from '../enums/verificationType';
|
||||
|
||||
import { VerifyOTPRequest } from '../models/request/account/verifyOTPRequest';
|
||||
import { SecretVerificationRequest } from '../models/request/secretVerificationRequest';
|
||||
|
||||
import { Verification } from '../types/verification';
|
||||
|
||||
@Injectable()
|
||||
export class UserVerificationService implements UserVerificationServiceAbstraction {
|
||||
constructor(private cryptoService: CryptoService, private i18nService: I18nService,
|
||||
private platformUtilsService: PlatformUtilsService, private apiService: ApiService,
|
||||
private logService: LogService) { }
|
||||
|
||||
async buildRequest<T extends SecretVerificationRequest>(verification: Verification,
|
||||
requestClass?: new () => T, alreadyHashed?: boolean) {
|
||||
if (verification?.secret == null || verification.secret === '') {
|
||||
throw new Error('No secret provided for verification.');
|
||||
}
|
||||
|
||||
const request = requestClass != null
|
||||
? new requestClass()
|
||||
: new SecretVerificationRequest() as T;
|
||||
|
||||
if (verification.type === VerificationType.OTP) {
|
||||
request.otp = verification.secret;
|
||||
} else {
|
||||
request.masterPasswordHash = alreadyHashed
|
||||
? verification.secret
|
||||
: await this.cryptoService.hashPassword(verification.secret, null);
|
||||
}
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
async verifyUser(verification: Verification): Promise<boolean> {
|
||||
if (verification?.secret == null || verification.secret === '') {
|
||||
throw new Error('No secret provided for verification.');
|
||||
}
|
||||
|
||||
if (verification.type === VerificationType.OTP) {
|
||||
const request = new VerifyOTPRequest(verification.secret);
|
||||
try {
|
||||
await this.apiService.postAccountVerifyOTP(request);
|
||||
} catch (e) {
|
||||
this.logService.error(e);
|
||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('invalidVerificationCode'));
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
const passwordValid = await this.cryptoService.compareAndUpdateKeyHash(verification.secret, null);
|
||||
if (!passwordValid) {
|
||||
this.platformUtilsService.showToast('error', this.i18nService.t('errorOccurred'),
|
||||
this.i18nService.t('invalidMasterPassword'));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import { CipherService } from '../abstractions/cipher.service';
|
||||
import { CollectionService } from '../abstractions/collection.service';
|
||||
import { CryptoService } from '../abstractions/crypto.service';
|
||||
import { FolderService } from '../abstractions/folder.service';
|
||||
import { KeyConnectorService } from '../abstractions/keyConnector.service';
|
||||
import { MessagingService } from '../abstractions/messaging.service';
|
||||
import { PlatformUtilsService } from '../abstractions/platformUtils.service';
|
||||
import { PolicyService } from '../abstractions/policy.service';
|
||||
@@ -28,6 +29,7 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
|
||||
protected platformUtilsService: PlatformUtilsService, private storageService: StorageService,
|
||||
private messagingService: MessagingService, private searchService: SearchService,
|
||||
private userService: UserService, private tokenService: TokenService, private policyService: PolicyService,
|
||||
private keyConnectorService: KeyConnectorService,
|
||||
private lockedCallback: () => Promise<void> = null, private loggedOutCallback: () => Promise<void> = null) {
|
||||
}
|
||||
|
||||
@@ -98,6 +100,15 @@ export class VaultTimeoutService implements VaultTimeoutServiceAbstraction {
|
||||
return;
|
||||
}
|
||||
|
||||
if (await this.keyConnectorService.getUsesKeyConnector()) {
|
||||
const pinSet = await this.isPinLockSet();
|
||||
const pinLock = (pinSet[0] && this.pinProtectedKey != null) || pinSet[1];
|
||||
|
||||
if (!pinLock && !await this.isBiometricLockSet()) {
|
||||
await this.logOut();
|
||||
}
|
||||
}
|
||||
|
||||
this.biometricLocked = true;
|
||||
this.everBeenUnlocked = true;
|
||||
await this.cryptoService.clearKey(false);
|
||||
|
||||
6
common/src/types/verification.ts
Normal file
6
common/src/types/verification.ts
Normal file
@@ -0,0 +1,6 @@
|
||||
import { VerificationType } from '../enums/verificationType';
|
||||
|
||||
export type Verification = {
|
||||
type: VerificationType,
|
||||
secret: string,
|
||||
};
|
||||
Reference in New Issue
Block a user