1
0
mirror of https://github.com/bitwarden/browser synced 2025-12-14 23:33:31 +00:00

Split jslib into multiple modules (#363)

* Split jslib into multiple modules
This commit is contained in:
Oscar Hinton
2021-06-03 18:58:57 +02:00
committed by GitHub
parent b1d9b84eae
commit 1016bbfb9e
509 changed files with 8838 additions and 1887 deletions

1495
common/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

43
common/package.json Normal file
View File

@@ -0,0 +1,43 @@
{
"name": "@bitwarden/jslib-common",
"version": "0.0.0",
"description": "Common code used across Bitwarden JavaScript projects.",
"keywords": [
"bitwarden"
],
"author": "Bitwarden Inc.",
"homepage": "https://bitwarden.com",
"repository": {
"type": "git",
"url": "https://github.com/bitwarden/jslib"
},
"license": "GPL-3.0",
"scripts": {
"clean": "rimraf dist/**/*",
"build": "npm run clean && tsc",
"build:watch": "npm run clean && tsc -watch",
"lint": "tslint 'src/**/*.ts' 'spec/**/*.ts'",
"lint:fix": "tslint 'src/**/*.ts' 'spec/**/*.ts' --fix"
},
"devDependencies": {
"@types/lunr": "^2.3.3",
"@types/node": "^14.17.1",
"@types/node-forge": "^0.9.7",
"@types/papaparse": "^5.2.5",
"@types/tldjs": "^2.3.0",
"@types/zxcvbn": "^4.4.1",
"rimraf": "^3.0.2",
"typescript": "4.1.5"
},
"dependencies": {
"@microsoft/signalr": "3.1.13",
"@microsoft/signalr-protocol-msgpack": "3.1.13",
"big-integer": "1.6.48",
"browser-hrtime": "^1.1.8",
"lunr": "^2.3.9",
"node-forge": "^0.10.0",
"papaparse": "^5.3.0",
"tldjs": "^2.3.1",
"zxcvbn": "^4.4.2"
}
}

View File

@@ -0,0 +1,405 @@
import { PolicyType } from '../enums/policyType';
import { EnvironmentUrls } from '../models/domain/environmentUrls';
import { AttachmentRequest } from '../models/request/attachmentRequest';
import { BitPayInvoiceRequest } from '../models/request/bitPayInvoiceRequest';
import { CipherBulkDeleteRequest } from '../models/request/cipherBulkDeleteRequest';
import { CipherBulkMoveRequest } from '../models/request/cipherBulkMoveRequest';
import { CipherBulkRestoreRequest } from '../models/request/cipherBulkRestoreRequest';
import { CipherBulkShareRequest } from '../models/request/cipherBulkShareRequest';
import { CipherCollectionsRequest } from '../models/request/cipherCollectionsRequest';
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 { DeleteRecoverRequest } from '../models/request/deleteRecoverRequest';
import { EmailRequest } from '../models/request/emailRequest';
import { EmailTokenRequest } from '../models/request/emailTokenRequest';
import { EmergencyAccessAcceptRequest } from '../models/request/emergencyAccessAcceptRequest';
import { EmergencyAccessConfirmRequest } from '../models/request/emergencyAccessConfirmRequest';
import { EmergencyAccessInviteRequest } from '../models/request/emergencyAccessInviteRequest';
import { EmergencyAccessPasswordRequest } from '../models/request/emergencyAccessPasswordRequest';
import { EmergencyAccessUpdateRequest } from '../models/request/emergencyAccessUpdateRequest';
import { EventRequest } from '../models/request/eventRequest';
import { FolderRequest } from '../models/request/folderRequest';
import { GroupRequest } from '../models/request/groupRequest';
import { IapCheckRequest } from '../models/request/iapCheckRequest';
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 { KeysRequest } from '../models/request/keysRequest';
import { OrganizationCreateRequest } from '../models/request/organizationCreateRequest';
import { OrganizationImportRequest } from '../models/request/organizationImportRequest';
import { OrganizationKeysRequest } from '../models/request/organizationKeysRequest';
import { OrganizationTaxInfoUpdateRequest } from '../models/request/organizationTaxInfoUpdateRequest';
import { OrganizationUpdateRequest } from '../models/request/organizationUpdateRequest';
import { OrganizationUpgradeRequest } from '../models/request/organizationUpgradeRequest';
import { OrganizationUserAcceptRequest } from '../models/request/organizationUserAcceptRequest';
import { OrganizationUserBulkConfirmRequest } from '../models/request/organizationUserBulkConfirmRequest';
import { OrganizationUserBulkRequest } from '../models/request/organizationUserBulkRequest';
import { OrganizationUserConfirmRequest } from '../models/request/organizationUserConfirmRequest';
import { OrganizationUserInviteRequest } from '../models/request/organizationUserInviteRequest';
import { OrganizationUserResetPasswordEnrollmentRequest } from '../models/request/organizationUserResetPasswordEnrollmentRequest';
import { OrganizationUserResetPasswordRequest } from '../models/request/organizationUserResetPasswordRequest';
import { OrganizationUserUpdateGroupsRequest } from '../models/request/organizationUserUpdateGroupsRequest';
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';
import { RegisterRequest } from '../models/request/registerRequest';
import { SeatRequest } from '../models/request/seatRequest';
import { SelectionReadOnlyRequest } from '../models/request/selectionReadOnlyRequest';
import { SendAccessRequest } from '../models/request/sendAccessRequest';
import { SendRequest } from '../models/request/sendRequest';
import { SetPasswordRequest } from '../models/request/setPasswordRequest';
import { StorageRequest } from '../models/request/storageRequest';
import { TaxInfoUpdateRequest } from '../models/request/taxInfoUpdateRequest';
import { TokenRequest } from '../models/request/tokenRequest';
import { TwoFactorEmailRequest } from '../models/request/twoFactorEmailRequest';
import { TwoFactorProviderRequest } from '../models/request/twoFactorProviderRequest';
import { TwoFactorRecoveryRequest } from '../models/request/twoFactorRecoveryRequest';
import { UpdateDomainsRequest } from '../models/request/updateDomainsRequest';
import { UpdateKeyRequest } from '../models/request/updateKeyRequest';
import { UpdateProfileRequest } from '../models/request/updateProfileRequest';
import { UpdateTwoFactorAuthenticatorRequest } from '../models/request/updateTwoFactorAuthenticatorRequest';
import { UpdateTwoFactorDuoRequest } from '../models/request/updateTwoFactorDuoRequest';
import { UpdateTwoFactorEmailRequest } from '../models/request/updateTwoFactorEmailRequest';
import { UpdateTwoFactorWebAuthnDeleteRequest } from '../models/request/updateTwoFactorWebAuthnDeleteRequest';
import { UpdateTwoFactorWebAuthnRequest } from '../models/request/updateTwoFactorWebAuthnRequest';
import { UpdateTwoFactorYubioOtpRequest } from '../models/request/updateTwoFactorYubioOtpRequest';
import { VerifyBankRequest } from '../models/request/verifyBankRequest';
import { VerifyDeleteRecoverRequest } from '../models/request/verifyDeleteRecoverRequest';
import { VerifyEmailRequest } from '../models/request/verifyEmailRequest';
import { ApiKeyResponse } from '../models/response/apiKeyResponse';
import { AttachmentResponse } from '../models/response/attachmentResponse';
import { AttachmentUploadDataResponse } from '../models/response/attachmentUploadDataResponse';
import { BillingResponse } from '../models/response/billingResponse';
import { BreachAccountResponse } from '../models/response/breachAccountResponse';
import { CipherResponse } from '../models/response/cipherResponse';
import {
CollectionGroupDetailsResponse,
CollectionResponse,
} from '../models/response/collectionResponse';
import { DomainsResponse } from '../models/response/domainsResponse';
import {
EmergencyAccessGranteeDetailsResponse,
EmergencyAccessGrantorDetailsResponse,
EmergencyAccessTakeoverResponse,
EmergencyAccessViewResponse
} from '../models/response/emergencyAccessResponse';
import { EventResponse } from '../models/response/eventResponse';
import { FolderResponse } from '../models/response/folderResponse';
import {
GroupDetailsResponse,
GroupResponse,
} from '../models/response/groupResponse';
import { IdentityTokenResponse } from '../models/response/identityTokenResponse';
import { IdentityTwoFactorResponse } from '../models/response/identityTwoFactorResponse';
import { ListResponse } from '../models/response/listResponse';
import { OrganizationKeysResponse } from '../models/response/organizationKeysResponse';
import { OrganizationResponse } from '../models/response/organizationResponse';
import { OrganizationSubscriptionResponse } from '../models/response/organizationSubscriptionResponse';
import { OrganizationUserBulkPublicKeyResponse } from '../models/response/organizationUserBulkPublicKeyResponse';
import { OrganizationUserBulkResponse } from '../models/response/organizationUserBulkResponse';
import {
OrganizationUserDetailsResponse,
OrganizationUserResetPasswordDetailsReponse,
OrganizationUserUserDetailsResponse,
} from '../models/response/organizationUserResponse';
import { PaymentResponse } from '../models/response/paymentResponse';
import { PlanResponse } from '../models/response/planResponse';
import { PolicyResponse } from '../models/response/policyResponse';
import { PreloginResponse } from '../models/response/preloginResponse';
import { ProfileResponse } from '../models/response/profileResponse';
import { SelectionReadOnlyResponse } from '../models/response/selectionReadOnlyResponse';
import { SendAccessResponse } from '../models/response/sendAccessResponse';
import { SendFileDownloadDataResponse } from '../models/response/sendFileDownloadDataResponse';
import { SendFileUploadDataResponse } from '../models/response/sendFileUploadDataResponse';
import { SendResponse } from '../models/response/sendResponse';
import { SubscriptionResponse } from '../models/response/subscriptionResponse';
import { SyncResponse } from '../models/response/syncResponse';
import { TaxInfoResponse } from '../models/response/taxInfoResponse';
import { TaxRateResponse } from '../models/response/taxRateResponse';
import { TwoFactorAuthenticatorResponse } from '../models/response/twoFactorAuthenticatorResponse';
import { TwoFactorDuoResponse } from '../models/response/twoFactorDuoResponse';
import { TwoFactorEmailResponse } from '../models/response/twoFactorEmailResponse';
import { TwoFactorProviderResponse } from '../models/response/twoFactorProviderResponse';
import { TwoFactorRecoverResponse } from '../models/response/twoFactorRescoverResponse';
import { ChallengeResponse, TwoFactorWebAuthnResponse } from '../models/response/twoFactorWebAuthnResponse';
import { TwoFactorYubiKeyResponse } from '../models/response/twoFactorYubiKeyResponse';
import { UserKeyResponse } from '../models/response/userKeyResponse';
import { SendAccessView } from '../models/view/sendAccessView';
export abstract class ApiService {
urlsSet: boolean;
apiBaseUrl: string;
identityBaseUrl: string;
eventsBaseUrl: string;
setUrls: (urls: EnvironmentUrls) => void;
postIdentityToken: (request: TokenRequest) => Promise<IdentityTokenResponse | IdentityTwoFactorResponse>;
refreshIdentityToken: () => Promise<any>;
getProfile: () => Promise<ProfileResponse>;
getUserBilling: () => Promise<BillingResponse>;
getUserSubscription: () => Promise<SubscriptionResponse>;
getTaxInfo: () => Promise<TaxInfoResponse>;
putProfile: (request: UpdateProfileRequest) => Promise<ProfileResponse>;
putTaxInfo: (request: TaxInfoUpdateRequest) => Promise<any>;
postPrelogin: (request: PreloginRequest) => Promise<PreloginResponse>;
postEmailToken: (request: EmailTokenRequest) => Promise<any>;
postEmail: (request: EmailRequest) => Promise<any>;
postPassword: (request: PasswordRequest) => Promise<any>;
setPassword: (request: SetPasswordRequest) => Promise<any>;
postSecurityStamp: (request: PasswordVerificationRequest) => Promise<any>;
deleteAccount: (request: PasswordVerificationRequest) => Promise<any>;
getAccountRevisionDate: () => Promise<number>;
postPasswordHint: (request: PasswordHintRequest) => Promise<any>;
postRegister: (request: RegisterRequest) => Promise<any>;
postPremium: (data: FormData) => Promise<PaymentResponse>;
postIapCheck: (request: IapCheckRequest) => Promise<any>;
postReinstatePremium: () => Promise<any>;
postCancelPremium: () => Promise<any>;
postAccountStorage: (request: StorageRequest) => Promise<PaymentResponse>;
postAccountPayment: (request: PaymentRequest) => Promise<any>;
postAccountLicense: (data: FormData) => Promise<any>;
postAccountKey: (request: UpdateKeyRequest) => Promise<any>;
postAccountKeys: (request: KeysRequest) => Promise<any>;
postAccountVerifyEmail: () => Promise<any>;
postAccountVerifyEmailToken: (request: VerifyEmailRequest) => Promise<any>;
postAccountVerifyPassword: (request: PasswordVerificationRequest) => Promise<any>;
postAccountRecoverDelete: (request: DeleteRecoverRequest) => Promise<any>;
postAccountRecoverDeleteToken: (request: VerifyDeleteRecoverRequest) => Promise<any>;
postAccountKdf: (request: KdfRequest) => Promise<any>;
getEnterprisePortalSignInToken: () => Promise<string>;
postUserApiKey: (id: string, request: PasswordVerificationRequest) => Promise<ApiKeyResponse>;
postUserRotateApiKey: (id: string, request: PasswordVerificationRequest) => Promise<ApiKeyResponse>;
getFolder: (id: string) => Promise<FolderResponse>;
postFolder: (request: FolderRequest) => Promise<FolderResponse>;
putFolder: (id: string, request: FolderRequest) => Promise<FolderResponse>;
deleteFolder: (id: string) => Promise<any>;
getSend: (id: string) => Promise<SendResponse>;
postSendAccess: (id: string, request: SendAccessRequest, apiUrl?: string) => Promise<SendAccessResponse>;
getSends: () => Promise<ListResponse<SendResponse>>;
postSend: (request: SendRequest) => Promise<SendResponse>;
postFileTypeSend: (request: SendRequest) => Promise<SendFileUploadDataResponse>;
postSendFile: (sendId: string, fileId: string, data: FormData) => Promise<any>;
/**
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
* This method still exists for backward compatibility with old server versions.
*/
postSendFileLegacy: (data: FormData) => Promise<SendResponse>;
putSend: (id: string, request: SendRequest) => Promise<SendResponse>;
putSendRemovePassword: (id: string) => Promise<SendResponse>;
deleteSend: (id: string) => Promise<any>;
getSendFileDownloadData: (send: SendAccessView, request: SendAccessRequest, apiUrl?: string) => Promise<SendFileDownloadDataResponse>;
renewSendFileUploadUrl: (sendId: string, fileId: string) => Promise<SendFileUploadDataResponse>;
getCipher: (id: string) => Promise<CipherResponse>;
getCipherAdmin: (id: string) => Promise<CipherResponse>;
getAttachmentData: (cipherId: string, attachmentId: string, emergencyAccessId?: string) => Promise<AttachmentResponse>;
getCiphersOrganization: (organizationId: string) => Promise<ListResponse<CipherResponse>>;
postCipher: (request: CipherRequest) => Promise<CipherResponse>;
postCipherCreate: (request: CipherCreateRequest) => Promise<CipherResponse>;
postCipherAdmin: (request: CipherCreateRequest) => Promise<CipherResponse>;
putCipher: (id: string, request: CipherRequest) => Promise<CipherResponse>;
putCipherAdmin: (id: string, request: CipherRequest) => Promise<CipherResponse>;
deleteCipher: (id: string) => Promise<any>;
deleteCipherAdmin: (id: string) => Promise<any>;
deleteManyCiphers: (request: CipherBulkDeleteRequest) => Promise<any>;
deleteManyCiphersAdmin: (request: CipherBulkDeleteRequest) => Promise<any>;
putMoveCiphers: (request: CipherBulkMoveRequest) => Promise<any>;
putShareCipher: (id: string, request: CipherShareRequest) => Promise<CipherResponse>;
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>;
postImportCiphers: (request: ImportCiphersRequest) => Promise<any>;
postImportOrganizationCiphers: (organizationId: string, request: ImportOrganizationCiphersRequest) => Promise<any>;
putDeleteCipher: (id: string) => Promise<any>;
putDeleteCipherAdmin: (id: string) => Promise<any>;
putDeleteManyCiphers: (request: CipherBulkDeleteRequest) => Promise<any>;
putDeleteManyCiphersAdmin: (request: CipherBulkDeleteRequest) => Promise<any>;
putRestoreCipher: (id: string) => Promise<CipherResponse>;
putRestoreCipherAdmin: (id: string) => Promise<CipherResponse>;
putRestoreManyCiphers: (request: CipherBulkRestoreRequest) => Promise<ListResponse<CipherResponse>>;
/**
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
* This method still exists for backward compatibility with old server versions.
*/
postCipherAttachmentLegacy: (id: string, data: FormData) => Promise<CipherResponse>;
/**
* @deprecated Mar 25 2021: This method has been deprecated in favor of direct uploads.
* This method still exists for backward compatibility with old server versions.
*/
postCipherAttachmentAdminLegacy: (id: string, data: FormData) => Promise<CipherResponse>;
postCipherAttachment: (id: string, request: AttachmentRequest) => Promise<AttachmentUploadDataResponse>;
deleteCipherAttachment: (id: string, attachmentId: string) => Promise<any>;
deleteCipherAttachmentAdmin: (id: string, attachmentId: string) => Promise<any>;
postShareCipherAttachment: (id: string, attachmentId: string, data: FormData,
organizationId: string) => Promise<any>;
renewAttachmentUploadUrl: (id: string, attachmentId: string) => Promise<AttachmentUploadDataResponse>;
postAttachmentFile: (id: string, attachmentId: string, data: FormData) => Promise<any>;
getCollectionDetails: (organizationId: string, id: string) => Promise<CollectionGroupDetailsResponse>;
getUserCollections: () => Promise<ListResponse<CollectionResponse>>;
getCollections: (organizationId: string) => Promise<ListResponse<CollectionResponse>>;
getCollectionUsers: (organizationId: string, id: string) => Promise<SelectionReadOnlyResponse[]>;
postCollection: (organizationId: string, request: CollectionRequest) => Promise<CollectionResponse>;
putCollectionUsers: (organizationId: string, id: string, request: SelectionReadOnlyRequest[]) => Promise<any>;
putCollection: (organizationId: string, id: string, request: CollectionRequest) => Promise<CollectionResponse>;
deleteCollection: (organizationId: string, id: string) => Promise<any>;
deleteCollectionUser: (organizationId: string, id: string, organizationUserId: string) => Promise<any>;
getGroupDetails: (organizationId: string, id: string) => Promise<GroupDetailsResponse>;
getGroups: (organizationId: string) => Promise<ListResponse<GroupResponse>>;
getGroupUsers: (organizationId: string, id: string) => Promise<string[]>;
postGroup: (organizationId: string, request: GroupRequest) => Promise<GroupResponse>;
putGroup: (organizationId: string, id: string, request: GroupRequest) => Promise<GroupResponse>;
putGroupUsers: (organizationId: string, id: string, request: string[]) => Promise<any>;
deleteGroup: (organizationId: string, id: string) => Promise<any>;
deleteGroupUser: (organizationId: string, id: string, organizationUserId: string) => Promise<any>;
getPolicy: (organizationId: string, type: PolicyType) => Promise<PolicyResponse>;
getPolicies: (organizationId: string) => Promise<ListResponse<PolicyResponse>>;
getPoliciesByToken: (organizationId: string, token: string, email: string, organizationUserId: string) =>
Promise<ListResponse<PolicyResponse>>;
putPolicy: (organizationId: string, type: PolicyType, request: PolicyRequest) => Promise<PolicyResponse>;
getOrganizationUser: (organizationId: string, id: string) => Promise<OrganizationUserDetailsResponse>;
getOrganizationUserGroups: (organizationId: string, id: string) => Promise<string[]>;
getOrganizationUsers: (organizationId: string) => Promise<ListResponse<OrganizationUserUserDetailsResponse>>;
getOrganizationUserResetPasswordDetails: (organizationId: string, id: string)
=> Promise<OrganizationUserResetPasswordDetailsReponse>;
postOrganizationUserInvite: (organizationId: string, request: OrganizationUserInviteRequest) => Promise<any>;
postOrganizationUserReinvite: (organizationId: string, id: string) => Promise<any>;
postManyOrganizationUserReinvite: (organizationId: string, request: OrganizationUserBulkRequest) => Promise<ListResponse<OrganizationUserBulkResponse>>;
postOrganizationUserAccept: (organizationId: string, id: string,
request: OrganizationUserAcceptRequest) => Promise<any>;
postOrganizationUserConfirm: (organizationId: string, id: string,
request: OrganizationUserConfirmRequest) => Promise<any>;
postOrganizationUsersPublicKey: (organizationId: string, request: OrganizationUserBulkRequest) =>
Promise<ListResponse<OrganizationUserBulkPublicKeyResponse>>;
postOrganizationUserBulkConfirm: (organizationId: string, request: OrganizationUserBulkConfirmRequest) => Promise<ListResponse<OrganizationUserBulkResponse>>;
putOrganizationUser: (organizationId: string, id: string, request: OrganizationUserUpdateRequest) => Promise<any>;
putOrganizationUserGroups: (organizationId: string, id: string,
request: OrganizationUserUpdateGroupsRequest) => Promise<any>;
putOrganizationUserResetPasswordEnrollment: (organizationId: string, userId: string,
request: OrganizationUserResetPasswordEnrollmentRequest) => Promise<any>;
putOrganizationUserResetPassword: (organizationId: string, id: string,
request: OrganizationUserResetPasswordRequest) => Promise<any>;
deleteOrganizationUser: (organizationId: string, id: string) => Promise<any>;
deleteManyOrganizationUsers: (organizationId: string, request: OrganizationUserBulkRequest) => Promise<ListResponse<OrganizationUserBulkResponse>>;
getSync: () => Promise<SyncResponse>;
postImportDirectory: (organizationId: string, request: ImportDirectoryRequest) => Promise<any>;
postPublicImportDirectory: (request: OrganizationImportRequest) => Promise<any>;
getSettingsDomains: () => Promise<DomainsResponse>;
putSettingsDomains: (request: UpdateDomainsRequest) => Promise<DomainsResponse>;
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>;
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>;
putTwoFactorAuthenticator: (
request: UpdateTwoFactorAuthenticatorRequest) => Promise<TwoFactorAuthenticatorResponse>;
putTwoFactorEmail: (request: UpdateTwoFactorEmailRequest) => Promise<TwoFactorEmailResponse>;
putTwoFactorDuo: (request: UpdateTwoFactorDuoRequest) => Promise<TwoFactorDuoResponse>;
putTwoFactorOrganizationDuo: (organizationId: string,
request: UpdateTwoFactorDuoRequest) => Promise<TwoFactorDuoResponse>;
putTwoFactorYubiKey: (request: UpdateTwoFactorYubioOtpRequest) => Promise<TwoFactorYubiKeyResponse>;
putTwoFactorWebAuthn: (request: UpdateTwoFactorWebAuthnRequest) => Promise<TwoFactorWebAuthnResponse>;
deleteTwoFactorWebAuthn: (request: UpdateTwoFactorWebAuthnDeleteRequest) => Promise<TwoFactorWebAuthnResponse>;
putTwoFactorDisable: (request: TwoFactorProviderRequest) => Promise<TwoFactorProviderResponse>;
putTwoFactorOrganizationDisable: (organizationId: string,
request: TwoFactorProviderRequest) => Promise<TwoFactorProviderResponse>;
postTwoFactorRecover: (request: TwoFactorRecoveryRequest) => Promise<any>;
postTwoFactorEmailSetup: (request: TwoFactorEmailRequest) => Promise<any>;
postTwoFactorEmail: (request: TwoFactorEmailRequest) => Promise<any>;
getEmergencyAccessTrusted: () => Promise<ListResponse<EmergencyAccessGranteeDetailsResponse>>;
getEmergencyAccessGranted: () => Promise<ListResponse<EmergencyAccessGrantorDetailsResponse>>;
getEmergencyAccess: (id: string) => Promise<EmergencyAccessGranteeDetailsResponse>;
getEmergencyGrantorPolicies: (id: string) => Promise<ListResponse<PolicyResponse>>;
putEmergencyAccess: (id: string, request: EmergencyAccessUpdateRequest) => Promise<any>;
deleteEmergencyAccess: (id: string) => Promise<any>;
postEmergencyAccessInvite: (request: EmergencyAccessInviteRequest) => Promise<any>;
postEmergencyAccessReinvite: (id: string) => Promise<any>;
postEmergencyAccessAccept: (id: string, request: EmergencyAccessAcceptRequest) => Promise<any>;
postEmergencyAccessConfirm: (id: string, request: EmergencyAccessConfirmRequest) => Promise<any>;
postEmergencyAccessInitiate: (id: string) => Promise<any>;
postEmergencyAccessApprove: (id: string) => Promise<any>;
postEmergencyAccessReject: (id: string) => Promise<any>;
postEmergencyAccessTakeover: (id: string) => Promise<EmergencyAccessTakeoverResponse>;
postEmergencyAccessPassword: (id: string, request: EmergencyAccessPasswordRequest) => Promise<any>;
postEmergencyAccessView: (id: string) => Promise<EmergencyAccessViewResponse>;
getOrganization: (id: string) => Promise<OrganizationResponse>;
getOrganizationBilling: (id: string) => Promise<BillingResponse>;
getOrganizationSubscription: (id: string) => Promise<OrganizationSubscriptionResponse>;
getOrganizationLicense: (id: string, installationId: string) => Promise<any>;
getOrganizationTaxInfo: (id: string) => Promise<TaxInfoResponse>;
postOrganization: (request: OrganizationCreateRequest) => Promise<OrganizationResponse>;
putOrganization: (id: string, request: OrganizationUpdateRequest) => Promise<OrganizationResponse>;
putOrganizationTaxInfo: (id: string, request: OrganizationTaxInfoUpdateRequest) => Promise<any>;
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>;
postOrganizationUpgrade: (id: string, request: OrganizationUpgradeRequest) => Promise<PaymentResponse>;
postOrganizationSeat: (id: string, request: SeatRequest) => Promise<PaymentResponse>;
postOrganizationStorage: (id: string, request: StorageRequest) => Promise<any>;
postOrganizationPayment: (id: string, request: PaymentRequest) => Promise<any>;
postOrganizationVerifyBank: (id: string, request: VerifyBankRequest) => Promise<any>;
postOrganizationCancel: (id: string) => Promise<any>;
postOrganizationReinstate: (id: string) => Promise<any>;
deleteOrganization: (id: string, request: PasswordVerificationRequest) => Promise<any>;
getPlans: () => Promise<ListResponse<PlanResponse>>;
getTaxRates: () => Promise<ListResponse<TaxRateResponse>>;
getOrganizationKeys: (id: string) => Promise<OrganizationKeysResponse>;
postOrganizationKeys: (id: string, request: OrganizationKeysRequest) => Promise<OrganizationKeysResponse>;
getEvents: (start: string, end: string, token: string) => Promise<ListResponse<EventResponse>>;
getEventsCipher: (id: string, start: string, end: string, token: string) => Promise<ListResponse<EventResponse>>;
getEventsOrganization: (id: string, start: string, end: string,
token: string) => Promise<ListResponse<EventResponse>>;
getEventsOrganizationUser: (organizationId: string, id: string,
start: string, end: string, token: string) => Promise<ListResponse<EventResponse>>;
postEventsCollect: (request: EventRequest[]) => Promise<any>;
deleteSsoUser: (organizationId: string) => Promise<any>;
getSsoUserIdentifier: () => Promise<string>;
getUserPublicKey: (id: string) => Promise<UserKeyResponse>;
getHibpBreach: (username: string) => Promise<BreachAccountResponse[]>;
postBitPayInvoice: (request: BitPayInvoiceRequest) => Promise<string>;
postSetupPayment: () => Promise<string>;
getActiveBearerToken: () => Promise<string>;
fetch: (request: Request) => Promise<Response>;
nativeFetch: (request: Request) => Promise<Response>;
preValidateSso: (identifier: string) => Promise<boolean>;
}

View File

@@ -0,0 +1,7 @@
export abstract class ApiKeyService {
setInformation: (clientId: string) => Promise<any>;
clear: () => Promise<any>;
getEntityType: () => Promise<string>;
getEntityId: () => Promise<string>;
isAuthenticated: () => Promise<boolean>;
}

View File

@@ -0,0 +1,4 @@
export abstract class AppIdService {
getAppId: () => Promise<string>;
getAnonymousAppId: () => Promise<string>;
}

View File

@@ -0,0 +1,6 @@
import { BreachAccountResponse } from '../models/response/breachAccountResponse';
export abstract class AuditService {
passwordLeaked: (password: string) => Promise<number>;
breachedAccounts: (username: string) => Promise<BreachAccountResponse[]>;
}

View File

@@ -0,0 +1,35 @@
import { TwoFactorProviderType } from '../enums/twoFactorProviderType';
import { AuthResult } from '../models/domain/authResult';
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
export abstract class AuthService {
email: string;
masterPasswordHash: string;
code: string;
codeVerifier: string;
ssoRedirectUrl: string;
clientId: string;
clientSecret: string;
twoFactorProvidersData: Map<TwoFactorProviderType, { [key: string]: string; }>;
selectedTwoFactorProviderType: TwoFactorProviderType;
logIn: (email: string, masterPassword: string) => Promise<AuthResult>;
logInSso: (code: string, codeVerifier: string, redirectUrl: string) => Promise<AuthResult>;
logInApiKey: (clientId: string, clientSecret: string) => Promise<AuthResult>;
logInTwoFactor: (twoFactorProvider: TwoFactorProviderType, twoFactorToken: string,
remember?: boolean) => Promise<AuthResult>;
logInComplete: (email: string, masterPassword: string, twoFactorProvider: TwoFactorProviderType,
twoFactorToken: string, remember?: boolean) => Promise<AuthResult>;
logInSsoComplete: (code: string, codeVerifier: string, redirectUrl: string,
twoFactorProvider: TwoFactorProviderType, twoFactorToken: string, remember?: boolean) => Promise<AuthResult>;
logInApiKeyComplete: (clientId: string, clientSecret: string, twoFactorProvider: TwoFactorProviderType,
twoFactorToken: string, remember?: boolean) => Promise<AuthResult>;
logOut: (callback: Function) => void;
getSupportedTwoFactorProviders: (win: Window) => any[];
getDefaultTwoFactorProvider: (webAuthnSupported: boolean) => TwoFactorProviderType;
makePreloginKey: (masterPassword: string, email: string) => Promise<SymmetricCryptoKey>;
authingWithApiKey: () => boolean;
authingWithSso: () => boolean;
authingWithPassword: () => boolean;
}

View File

@@ -0,0 +1,6 @@
export abstract class BiometricMain {
isError: boolean;
init: () => Promise<void>;
supportsBiometric: () => Promise<boolean>;
requestCreate: () => Promise<boolean>;
}

View File

@@ -0,0 +1,5 @@
export abstract class BroadcasterService {
send: (message: any, id?: string) => void;
subscribe: (id: string, messageCallback: (message: any) => any) => void;
unsubscribe: (id: string) => void;
}

View File

@@ -0,0 +1,59 @@
import { CipherType } from '../enums/cipherType';
import { UriMatchType } from '../enums/uriMatchType';
import { CipherData } from '../models/data/cipherData';
import { Cipher } from '../models/domain/cipher';
import { Field } from '../models/domain/field';
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
import { CipherView } from '../models/view/cipherView';
import { FieldView } from '../models/view/fieldView';
export abstract class CipherService {
decryptedCipherCache: CipherView[];
clearCache: () => void;
encrypt: (model: CipherView, key?: SymmetricCryptoKey, originalCipher?: Cipher) => Promise<Cipher>;
encryptFields: (fieldsModel: FieldView[], key: SymmetricCryptoKey) => Promise<Field[]>;
encryptField: (fieldModel: FieldView, key: SymmetricCryptoKey) => Promise<Field>;
get: (id: string) => Promise<Cipher>;
getAll: () => Promise<Cipher[]>;
getAllDecrypted: () => Promise<CipherView[]>;
getAllDecryptedForGrouping: (groupingId: string, folder?: boolean) => Promise<CipherView[]>;
getAllDecryptedForUrl: (url: string, includeOtherTypes?: CipherType[],
defaultMatch?: UriMatchType) => Promise<CipherView[]>;
getAllFromApiForOrganization: (organizationId: string) => Promise<CipherView[]>;
getLastUsedForUrl: (url: string, autofillOnPageLoad: boolean) => Promise<CipherView>;
getLastLaunchedForUrl: (url: string, autofillOnPageLoad: boolean) => Promise<CipherView>;
getNextCipherForUrl: (url: string) => Promise<CipherView>;
updateLastUsedIndexForUrl: (url: string) => void;
updateLastUsedDate: (id: string) => Promise<void>;
updateLastLaunchedDate: (id: string) => Promise<void>;
saveNeverDomain: (domain: string) => Promise<void>;
saveWithServer: (cipher: Cipher) => Promise<any>;
shareWithServer: (cipher: CipherView, organizationId: string, collectionIds: string[]) => Promise<any>;
shareManyWithServer: (ciphers: CipherView[], organizationId: string, collectionIds: string[]) => Promise<any>;
saveAttachmentWithServer: (cipher: Cipher, unencryptedFile: any, admin?: boolean) => Promise<Cipher>;
saveAttachmentRawWithServer: (cipher: Cipher, filename: string, data: ArrayBuffer,
admin?: boolean) => Promise<Cipher>;
saveCollectionsWithServer: (cipher: Cipher) => Promise<any>;
upsert: (cipher: CipherData | CipherData[]) => Promise<any>;
replace: (ciphers: { [id: string]: CipherData; }) => Promise<any>;
clear: (userId: string) => Promise<any>;
moveManyWithServer: (ids: string[], folderId: string) => Promise<any>;
delete: (id: string | string[]) => Promise<any>;
deleteWithServer: (id: string) => Promise<any>;
deleteManyWithServer: (ids: string[]) => Promise<any>;
deleteAttachment: (id: string, attachmentId: string) => Promise<void>;
deleteAttachmentWithServer: (id: string, attachmentId: string) => Promise<void>;
sortCiphersByLastUsed: (a: any, b: any) => number;
sortCiphersByLastUsedThenName: (a: any, b: any) => number;
getLocaleSortingFunction: () => (a: CipherView, b: CipherView) => number;
softDelete: (id: string | string[]) => Promise<any>;
softDeleteWithServer: (id: string) => Promise<any>;
softDeleteManyWithServer: (ids: string[]) => Promise<any>;
restore: (cipher: { id: string, revisionDate: string; } | { id: string, revisionDate: string; }[]) => Promise<any>;
restoreWithServer: (id: string) => Promise<any>;
restoreManyWithServer: (ids: string[]) => Promise<any>;
}

View File

@@ -0,0 +1,23 @@
import { CollectionData } from '../models/data/collectionData';
import { Collection } from '../models/domain/collection';
import { TreeNode } from '../models/domain/treeNode';
import { CollectionView } from '../models/view/collectionView';
export abstract class CollectionService {
decryptedCollectionCache: CollectionView[];
clearCache: () => void;
encrypt: (model: CollectionView) => Promise<Collection>;
decryptMany: (collections: Collection[]) => Promise<CollectionView[]>;
get: (id: string) => Promise<Collection>;
getAll: () => Promise<Collection[]>;
getAllDecrypted: () => Promise<CollectionView[]>;
getAllNested: (collections?: CollectionView[]) => Promise<TreeNode<CollectionView>[]>;
getNested: (id: string) => Promise<TreeNode<CollectionView>>;
upsert: (collection: CollectionData | CollectionData[]) => Promise<any>;
replace: (collections: { [id: string]: CollectionData; }) => Promise<any>;
clear: (userId: string) => Promise<any>;
delete: (id: string | string[]) => Promise<any>;
}

View File

@@ -0,0 +1,52 @@
import { EncArrayBuffer } from '../models/domain/encArrayBuffer';
import { EncString } from '../models/domain/encString';
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
import { ProfileOrganizationResponse } from '../models/response/profileOrganizationResponse';
import { KdfType } from '../enums/kdfType';
export abstract class CryptoService {
setKey: (key: SymmetricCryptoKey) => Promise<any>;
setKeyHash: (keyHash: string) => Promise<{}>;
setEncKey: (encKey: string) => Promise<{}>;
setEncPrivateKey: (encPrivateKey: string) => Promise<{}>;
setOrgKeys: (orgs: ProfileOrganizationResponse[]) => Promise<{}>;
getKey: () => Promise<SymmetricCryptoKey>;
getKeyHash: () => Promise<string>;
getEncKey: (key?: SymmetricCryptoKey) => Promise<SymmetricCryptoKey>;
getPublicKey: () => Promise<ArrayBuffer>;
getPrivateKey: () => Promise<ArrayBuffer>;
getFingerprint: (userId: string, publicKey?: ArrayBuffer) => Promise<string[]>;
getOrgKeys: () => Promise<Map<string, SymmetricCryptoKey>>;
getOrgKey: (orgId: string) => Promise<SymmetricCryptoKey>;
hasKey: () => Promise<boolean>;
hasEncKey: () => Promise<boolean>;
clearKey: () => Promise<any>;
clearKeyHash: () => Promise<any>;
clearEncKey: (memoryOnly?: boolean) => Promise<any>;
clearKeyPair: (memoryOnly?: boolean) => Promise<any>;
clearOrgKeys: (memoryOnly?: boolean) => Promise<any>;
clearPinProtectedKey: () => Promise<any>;
clearKeys: () => Promise<any>;
toggleKey: () => Promise<any>;
makeKey: (password: string, salt: string, kdf: KdfType, kdfIterations: number) => Promise<SymmetricCryptoKey>;
makeKeyFromPin: (pin: string, salt: string, kdf: KdfType, kdfIterations: number,
protectedKeyCs?: EncString) => Promise<SymmetricCryptoKey>;
makeShareKey: () => Promise<[EncString, SymmetricCryptoKey]>;
makeKeyPair: (key?: SymmetricCryptoKey) => Promise<[string, EncString]>;
makePinKey: (pin: string, salt: string, kdf: KdfType, kdfIterations: number) => Promise<SymmetricCryptoKey>;
makeSendKey: (keyMaterial: ArrayBuffer) => Promise<SymmetricCryptoKey>;
hashPassword: (password: string, key: SymmetricCryptoKey) => Promise<string>;
makeEncKey: (key: SymmetricCryptoKey) => Promise<[SymmetricCryptoKey, EncString]>;
remakeEncKey: (key: SymmetricCryptoKey, encKey?: SymmetricCryptoKey) => Promise<[SymmetricCryptoKey, EncString]>;
encrypt: (plainValue: string | ArrayBuffer, key?: SymmetricCryptoKey) => Promise<EncString>;
encryptToBytes: (plainValue: ArrayBuffer, key?: SymmetricCryptoKey) => Promise<EncArrayBuffer>;
rsaEncrypt: (data: ArrayBuffer, publicKey?: ArrayBuffer) => Promise<EncString>;
rsaDecrypt: (encValue: string, privateKeyValue?: ArrayBuffer) => Promise<ArrayBuffer>;
decryptToBytes: (encString: EncString, key?: SymmetricCryptoKey) => Promise<ArrayBuffer>;
decryptToUtf8: (encString: EncString, key?: SymmetricCryptoKey) => Promise<string>;
decryptFromBytes: (encBuf: ArrayBuffer, key: SymmetricCryptoKey) => Promise<ArrayBuffer>;
randomNumber: (min: number, max: number) => Promise<number>;
validateKey: (key: SymmetricCryptoKey) => Promise<boolean>;
}

View File

@@ -0,0 +1,27 @@
import { DecryptParameters } from '../models/domain/decryptParameters';
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
export abstract class CryptoFunctionService {
pbkdf2: (password: string | ArrayBuffer, salt: string | ArrayBuffer, algorithm: 'sha256' | 'sha512',
iterations: number) => Promise<ArrayBuffer>;
hkdf: (ikm: ArrayBuffer, salt: string | ArrayBuffer, info: string | ArrayBuffer,
outputByteSize: number, algorithm: 'sha256' | 'sha512') => Promise<ArrayBuffer>;
hkdfExpand: (prk: ArrayBuffer, info: string | ArrayBuffer, outputByteSize: number,
algorithm: 'sha256' | 'sha512') => Promise<ArrayBuffer>;
hash: (value: string | ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512' | 'md5') => Promise<ArrayBuffer>;
hmac: (value: ArrayBuffer, key: ArrayBuffer, algorithm: 'sha1' | 'sha256' | 'sha512') => Promise<ArrayBuffer>;
compare: (a: ArrayBuffer, b: ArrayBuffer) => Promise<boolean>;
hmacFast: (value: ArrayBuffer | string, key: ArrayBuffer | string, algorithm: 'sha1' | 'sha256' | 'sha512') =>
Promise<ArrayBuffer | string>;
compareFast: (a: ArrayBuffer | string, b: ArrayBuffer | string) => Promise<boolean>;
aesEncrypt: (data: ArrayBuffer, iv: ArrayBuffer, key: ArrayBuffer) => Promise<ArrayBuffer>;
aesDecryptFastParameters: (data: string, iv: string, mac: string, key: SymmetricCryptoKey) =>
DecryptParameters<ArrayBuffer | string>;
aesDecryptFast: (parameters: DecryptParameters<ArrayBuffer | string>) => Promise<string>;
aesDecrypt: (data: ArrayBuffer, iv: ArrayBuffer, key: ArrayBuffer) => Promise<ArrayBuffer>;
rsaEncrypt: (data: ArrayBuffer, publicKey: ArrayBuffer, algorithm: 'sha1' | 'sha256') => Promise<ArrayBuffer>;
rsaDecrypt: (data: ArrayBuffer, privateKey: ArrayBuffer, algorithm: 'sha1' | 'sha256') => Promise<ArrayBuffer>;
rsaExtractPublicKey: (privateKey: ArrayBuffer) => Promise<ArrayBuffer>;
rsaGenerateKeyPair: (length: 1024 | 2048 | 4096) => Promise<[ArrayBuffer, ArrayBuffer]>;
randomBytes: (length: number) => Promise<ArrayBuffer>;
}

View File

@@ -0,0 +1,14 @@
export abstract class EnvironmentService {
baseUrl: string;
webVaultUrl: string;
apiUrl: string;
identityUrl: string;
iconsUrl: string;
notificationsUrl: string;
eventsUrl: string;
enterpriseUrl: string;
getWebVaultUrl: () => string;
setUrlsFromStorage: () => Promise<void>;
setUrls: (urls: any) => Promise<any>;
}

View File

@@ -0,0 +1,7 @@
import { EventType } from '../enums/eventType';
export abstract class EventService {
collect: (eventType: EventType, cipherId?: string, uploadImmediately?: boolean) => Promise<any>;
uploadEvents: () => Promise<any>;
clearEvents: () => Promise<any>;
}

View File

@@ -0,0 +1,8 @@
import { EventView } from '../models/view/eventView';
export abstract class ExportService {
getExport: (format?: 'csv' | 'json' | 'encrypted_json') => Promise<string>;
getOrganizationExport: (organizationId: string, format?: 'csv' | 'json' | 'encrypted_json') => Promise<string>;
getEventExport: (events: EventView[]) => Promise<string>;
getFileName: (prefix?: string, extension?: string) => string;
}

View File

@@ -0,0 +1,11 @@
import { EncArrayBuffer } from '../models/domain/encArrayBuffer';
import { EncString } from '../models/domain/encString';
import { AttachmentUploadDataResponse } from '../models/response/attachmentUploadDataResponse';
import { SendFileUploadDataResponse } from '../models/response/sendFileUploadDataResponse';
export abstract class FileUploadService {
uploadSendFile: (uploadData: SendFileUploadDataResponse, fileName: EncString,
encryptedFileData: EncArrayBuffer) => Promise<any>;
uploadCipherAttachment: (admin: boolean, uploadData: AttachmentUploadDataResponse, fileName: string,
encryptedFileData: EncArrayBuffer) => Promise<any>;
}

View File

@@ -0,0 +1,25 @@
import { FolderData } from '../models/data/folderData';
import { Folder } from '../models/domain/folder';
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
import { TreeNode } from '../models/domain/treeNode';
import { FolderView } from '../models/view/folderView';
export abstract class FolderService {
decryptedFolderCache: FolderView[];
clearCache: () => void;
encrypt: (model: FolderView, key?: SymmetricCryptoKey) => Promise<Folder>;
get: (id: string) => Promise<Folder>;
getAll: () => Promise<Folder[]>;
getAllDecrypted: () => Promise<FolderView[]>;
getAllNested: () => Promise<TreeNode<FolderView>[]>;
getNested: (id: string) => Promise<TreeNode<FolderView>>;
saveWithServer: (folder: Folder) => Promise<any>;
upsert: (folder: FolderData | FolderData[]) => Promise<any>;
replace: (folders: { [id: string]: FolderData; }) => Promise<any>;
clear: (userId: string) => Promise<any>;
delete: (id: string | string[]) => Promise<any>;
deleteWithServer: (id: string) => Promise<any>;
}

View File

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

View File

@@ -0,0 +1,13 @@
import { Importer } from '../importers/importer';
export interface ImportOption {
id: string;
name: string;
}
export abstract class ImportService {
featuredImportOptions: ImportOption[];
regularImportOptions: ImportOption[];
getImportOptions: () => ImportOption[];
import: (importer: Importer, fileContents: string, organizationId?: string) => Promise<Error>;
getImporter: (format: string, organizationId: string) => Importer;
}

View File

@@ -0,0 +1,24 @@
// Using index.ts is deprecated, please do not extend
export { ApiService } from './api.service';
export { AppIdService } from './appId.service';
export { AuditService } from './audit.service';
export { AuthService } from './auth.service';
export { CipherService } from './cipher.service';
export { CollectionService } from './collection.service';
export { CryptoService } from './crypto.service';
export { EnvironmentService } from './environment.service';
export { FolderService } from './folder.service';
export { I18nService } from './i18n.service';
export { LogService } from './log.service';
export { MessagingService } from './messaging.service';
export { PasswordGenerationService } from './passwordGeneration.service';
export { PlatformUtilsService } from './platformUtils.service';
export { SearchService } from './search.service';
export { SettingsService } from './settings.service';
export { StorageService } from './storage.service';
export { StateService } from './state.service';
export { SyncService } from './sync.service';
export { TokenService } from './token.service';
export { TotpService } from './totp.service';
export { UserService } from './user.service';
export { VaultTimeoutService } from './vaultTimeout.service';

View File

@@ -0,0 +1,11 @@
import { LogLevelType } from '../enums/logLevelType';
export abstract class LogService {
debug: (message: string) => void;
info: (message: string) => void;
warning: (message: string) => void;
error: (message: string) => void;
write: (level: LogLevelType, message: string) => void;
time: (label: string) => void;
timeEnd: (label: string) => [number, number];
}

View File

@@ -0,0 +1,3 @@
export abstract class MessagingService {
send: (subscriber: string, arg?: any) => void;
}

View File

@@ -0,0 +1,8 @@
import { EnvironmentService } from './environment.service';
export abstract class NotificationsService {
init: (environmentService: EnvironmentService) => Promise<void>;
updateConnection: (sync?: boolean) => Promise<void>;
reconnectFromActivity: () => Promise<void>;
disconnectFromInactivity: () => Promise<void>;
}

View File

@@ -0,0 +1,18 @@
import * as zxcvbn from 'zxcvbn';
import { GeneratedPasswordHistory } from '../models/domain/generatedPasswordHistory';
import { PasswordGeneratorPolicyOptions } from '../models/domain/passwordGeneratorPolicyOptions';
export abstract class PasswordGenerationService {
generatePassword: (options: any) => Promise<string>;
generatePassphrase: (options: any) => Promise<string>;
getOptions: () => Promise<[any, PasswordGeneratorPolicyOptions]>;
enforcePasswordGeneratorPoliciesOnOptions: (options: any) => Promise<[any, PasswordGeneratorPolicyOptions]>;
getPasswordGeneratorPolicyOptions: () => Promise<PasswordGeneratorPolicyOptions>;
saveOptions: (options: any) => Promise<any>;
getHistory: () => Promise<GeneratedPasswordHistory[]>;
addHistory: (password: string) => Promise<any>;
clear: () => Promise<any>;
passwordStrength: (password: string, userInputs?: string[]) => zxcvbn.ZXCVBNResult;
normalizeOptions: (options: any, enforcedPolicyOptions: PasswordGeneratorPolicyOptions) => void;
}

View File

@@ -0,0 +1,4 @@
export abstract class PasswordRepromptService {
protectedFields: () => string[];
showPasswordPrompt: () => Promise<boolean>;
}

View File

@@ -0,0 +1,39 @@
import { DeviceType } from '../enums/deviceType';
export abstract class PlatformUtilsService {
identityClientId: string;
getDevice: () => DeviceType;
getDeviceString: () => string;
isFirefox: () => boolean;
isChrome: () => boolean;
isEdge: () => boolean;
isOpera: () => boolean;
isVivaldi: () => boolean;
isSafari: () => boolean;
isIE: () => boolean;
isMacAppStore: () => boolean;
isViewOpen: () => Promise<boolean>;
/**
* @deprecated This only ever returns null. Pull from your platform's storage using ConstantsService.vaultTimeoutKey
*/
lockTimeout: () => number;
launchUri: (uri: string, options?: any) => void;
saveFile: (win: Window, blobData: any, blobOptions: any, fileName: string) => void;
getApplicationVersion: () => Promise<string>;
supportsWebAuthn: (win: Window) => boolean;
supportsDuo: () => boolean;
showToast: (type: 'error' | 'success' | 'warning' | 'info', title: string, text: string | string[],
options?: any) => void;
showDialog: (body: string, title?: string, confirmText?: string, cancelText?: string,
type?: string, bodyIsHtml?: boolean) => Promise<boolean>;
showPasswordDialog: (title: string, body: string, passwordValidation: (value: string) => Promise<boolean>) => Promise<boolean>;
isDev: () => boolean;
isSelfHost: () => boolean;
copyToClipboard: (text: string, options?: any) => void | boolean;
readFromClipboard: (options?: any) => Promise<string>;
supportsBiometric: () => Promise<boolean>;
authenticateBiometric: () => Promise<boolean>;
getDefaultSystemTheme: () => Promise<'light' | 'dark'>;
onDefaultSystemThemeChange: (callback: ((theme: 'light' | 'dark') => unknown)) => unknown;
supportsSecureStorage: () => boolean;
}

View File

@@ -0,0 +1,24 @@
import { PolicyData } from '../models/data/policyData';
import { MasterPasswordPolicyOptions } from '../models/domain/masterPasswordPolicyOptions';
import { Policy } from '../models/domain/policy';
import { ResetPasswordPolicyOptions } from '../models/domain/resetPasswordPolicyOptions';
import { PolicyType } from '../enums/policyType';
import { ListResponse } from '../models/response/listResponse';
import { PolicyResponse } from '../models/response/policyResponse';
export abstract class PolicyService {
policyCache: Policy[];
clearCache: () => void;
getAll: (type?: PolicyType) => Promise<Policy[]>;
replace: (policies: { [id: string]: PolicyData; }) => Promise<any>;
clear: (userId: string) => Promise<any>;
getMasterPasswordPolicyOptions: (policies?: Policy[]) => Promise<MasterPasswordPolicyOptions>;
evaluateMasterPassword: (passwordStrength: number, newPassword: string,
enforcedPolicyOptions?: MasterPasswordPolicyOptions) => boolean;
getResetPasswordPolicyOptions: (policies: Policy[], orgId: string) => [ResetPasswordPolicyOptions, boolean];
mapPoliciesFromToken: (policiesResponse: ListResponse<PolicyResponse>) => Policy[];
}

View File

@@ -0,0 +1,14 @@
import { CipherView } from '../models/view/cipherView';
import { SendView } from '../models/view/sendView';
export abstract class SearchService {
indexedEntityId?: string = null;
clearIndex: () => void;
isSearchable: (query: string) => boolean;
indexCiphers: (indexedEntityGuid?: string, ciphersToIndex?: CipherView[]) => Promise<void>;
searchCiphers: (query: string,
filter?: ((cipher: CipherView) => boolean) | (((cipher: CipherView) => boolean)[]),
ciphers?: CipherView[]) => Promise<CipherView[]>;
searchCiphersBasic: (ciphers: CipherView[], query: string, deleted?: boolean) => CipherView[];
searchSends: (sends: SendView[], query: string) => SendView[];
}

View File

@@ -0,0 +1,24 @@
import { SendData } from '../models/data/sendData';
import { EncArrayBuffer } from '../models/domain/encArrayBuffer';
import { Send } from '../models/domain/send';
import { SymmetricCryptoKey } from '../models/domain/symmetricCryptoKey';
import { SendView } from '../models/view/sendView';
export abstract class SendService {
decryptedSendCache: SendView[];
clearCache: () => void;
encrypt: (model: SendView, file: File | ArrayBuffer, password: string, key?: SymmetricCryptoKey) => Promise<[Send, EncArrayBuffer]>;
get: (id: string) => Promise<Send>;
getAll: () => Promise<Send[]>;
getAllDecrypted: () => Promise<SendView[]>;
saveWithServer: (sendData: [Send, EncArrayBuffer]) => Promise<any>;
upsert: (send: SendData | SendData[]) => Promise<any>;
replace: (sends: { [id: string]: SendData; }) => Promise<any>;
clear: (userId: string) => Promise<any>;
delete: (id: string | string[]) => Promise<any>;
deleteWithServer: (id: string) => Promise<any>;
removePasswordWithServer: (id: string) => Promise<any>;
}

View File

@@ -0,0 +1,6 @@
export abstract class SettingsService {
clearCache: () => void;
getEquivalentDomains: () => Promise<any>;
setEquivalentDomains: (equivalentDomains: string[][]) => Promise<any>;
clear: (userId: string) => Promise<void>;
}

View File

@@ -0,0 +1,6 @@
export abstract class StateService {
get: <T>(key: string) => Promise<T>;
save: (key: string, obj: any) => Promise<any>;
remove: (key: string) => Promise<any>;
purge: () => Promise<any>;
}

View File

@@ -0,0 +1,5 @@
export abstract class StorageService {
get: <T>(key: string) => Promise<T>;
save: (key: string, obj: any) => Promise<any>;
remove: (key: string) => Promise<any>;
}

View File

@@ -0,0 +1,19 @@
import {
SyncCipherNotification,
SyncFolderNotification,
SyncSendNotification,
} from '../models/response/notificationResponse';
export abstract class SyncService {
syncInProgress: boolean;
getLastSync: () => Promise<Date>;
setLastSync: (date: Date) => Promise<any>;
fullSync: (forceSync: boolean, allowThrowOnError?: boolean) => Promise<boolean>;
syncUpsertFolder: (notification: SyncFolderNotification, isEdit: boolean) => Promise<boolean>;
syncDeleteFolder: (notification: SyncFolderNotification) => Promise<boolean>;
syncUpsertCipher: (notification: SyncCipherNotification, isEdit: boolean) => Promise<boolean>;
syncDeleteCipher: (notification: SyncFolderNotification) => Promise<boolean>;
syncUpsertSend: (notification: SyncSendNotification, isEdit: boolean) => Promise<boolean>;
syncDeleteSend: (notification: SyncSendNotification) => Promise<boolean>;
}

View File

@@ -0,0 +1,6 @@
export abstract class SystemService {
startProcessReload: () => void;
cancelProcessReload: () => void;
clearClipboard: (clipboardValue: string, timeoutMs?: number) => void;
clearPendingClipboard: () => Promise<any>;
}

View File

@@ -0,0 +1,25 @@
export abstract class TokenService {
token: string;
decodedToken: any;
refreshToken: string;
setTokens: (accessToken: string, refreshToken: string) => Promise<any>;
setToken: (token: string) => Promise<any>;
getToken: () => Promise<string>;
setRefreshToken: (refreshToken: string) => Promise<any>;
getRefreshToken: () => Promise<string>;
toggleTokens: () => Promise<any>;
setTwoFactorToken: (token: string, email: string) => Promise<any>;
getTwoFactorToken: (email: string) => Promise<string>;
clearTwoFactorToken: (email: string) => Promise<any>;
clearToken: () => Promise<any>;
decodeToken: () => any;
getTokenExpirationDate: () => Date;
tokenSecondsRemaining: (offsetSeconds?: number) => number;
tokenNeedsRefresh: (minutes?: number) => boolean;
getUserId: () => string;
getEmail: () => string;
getEmailVerified: () => boolean;
getName: () => string;
getPremium: () => boolean;
getIssuer: () => string;
}

View File

@@ -0,0 +1,5 @@
export abstract class TotpService {
getCode: (key: string) => Promise<string>;
getTimeInterval: (key: string) => number;
isAutoCopyEnabled: () => Promise<boolean>;
}

View File

@@ -0,0 +1,23 @@
import { OrganizationData } from '../models/data/organizationData';
import { Organization } from '../models/domain/organization';
import { KdfType } from '../enums/kdfType';
export abstract class UserService {
setInformation: (userId: string, email: string, kdf: KdfType, kdfIterations: number) => Promise<any>;
setEmailVerified: (emailVerified: boolean) => Promise<any>;
setSecurityStamp: (stamp: string) => Promise<any>;
getUserId: () => Promise<string>;
getEmail: () => Promise<string>;
getSecurityStamp: () => Promise<string>;
getKdf: () => Promise<KdfType>;
getKdfIterations: () => Promise<number>;
getEmailVerified: () => Promise<boolean>;
clear: () => Promise<any>;
isAuthenticated: () => Promise<boolean>;
canAccessPremium: () => Promise<boolean>;
getOrganization: (id: string) => Promise<Organization>;
getAllOrganizations: () => Promise<Organization[]>;
replaceOrganizations: (organizations: { [id: string]: OrganizationData; }) => Promise<any>;
clearOrganizations: (userId: string) => Promise<any>;
}

View File

@@ -0,0 +1,14 @@
import { EncString } from '../models/domain/encString';
export abstract class VaultTimeoutService {
biometricLocked: boolean;
pinProtectedKey: EncString;
isLocked: () => Promise<boolean>;
checkVaultTimeout: () => Promise<void>;
lock: (allowSoftLock?: boolean) => Promise<void>;
logOut: () => Promise<void>;
setVaultTimeoutOptions: (vaultTimeout: number, vaultTimeoutAction: string) => Promise<void>;
isPinLockSet: () => Promise<[boolean, boolean]>;
isBiometricLockSet: () => Promise<boolean>;
clear: () => Promise<any>;
}

View File

@@ -0,0 +1,4 @@
export enum CipherRepromptType {
None = 0,
Password = 1,
}

View File

@@ -0,0 +1,6 @@
export enum CipherType {
Login = 1,
SecureNote = 2,
Card = 3,
Identity = 4,
}

View File

@@ -0,0 +1,23 @@
export enum DeviceType {
Android = 0,
iOS = 1,
ChromeExtension = 2,
FirefoxExtension = 3,
OperaExtension = 4,
EdgeExtension = 5,
WindowsDesktop = 6,
MacOsDesktop = 7,
LinuxDesktop = 8,
ChromeBrowser = 9,
FirefoxBrowser = 10,
OperaBrowser = 11,
EdgeBrowser = 12,
IEBrowser = 13,
UnknownBrowser = 14,
AndroidAmazon = 15,
UWP = 16,
SafariBrowser = 17,
VivaldiBrowser = 18,
VivaldiExtension = 19,
SafariExtension = 20,
}

View File

@@ -0,0 +1,7 @@
export enum EmergencyAccessStatusType {
Invited = 0,
Accepted = 1,
Confirmed = 2,
RecoveryInitiated = 3,
RecoveryApproved = 4,
}

View File

@@ -0,0 +1,5 @@
export enum EmergencyAccessType
{
View = 0,
Takeover = 1,
}

View File

@@ -0,0 +1,9 @@
export enum EncryptionType {
AesCbc256_B64 = 0,
AesCbc128_HmacSha256_B64 = 1,
AesCbc256_HmacSha256_B64 = 2,
Rsa2048_OaepSha256_B64 = 3,
Rsa2048_OaepSha1_B64 = 4,
Rsa2048_OaepSha256_HmacSha256_B64 = 5,
Rsa2048_OaepSha1_HmacSha256_B64 = 6,
}

View File

@@ -0,0 +1,53 @@
export enum EventType {
User_LoggedIn = 1000,
User_ChangedPassword = 1001,
User_Updated2fa = 1002,
User_Disabled2fa = 1003,
User_Recovered2fa = 1004,
User_FailedLogIn = 1005,
User_FailedLogIn2fa = 1006,
User_ClientExportedVault = 1007,
Cipher_Created = 1100,
Cipher_Updated = 1101,
Cipher_Deleted = 1102,
Cipher_AttachmentCreated = 1103,
Cipher_AttachmentDeleted = 1104,
Cipher_Shared = 1105,
Cipher_UpdatedCollections = 1106,
Cipher_ClientViewed = 1107,
Cipher_ClientToggledPasswordVisible = 1108,
Cipher_ClientToggledHiddenFieldVisible = 1109,
Cipher_ClientToggledCardCodeVisible = 1110,
Cipher_ClientCopiedPassword = 1111,
Cipher_ClientCopiedHiddenField = 1112,
Cipher_ClientCopiedCardCode = 1113,
Cipher_ClientAutofilled = 1114,
Cipher_SoftDeleted = 1115,
Cipher_Restored = 1116,
Cipher_ClientToggledCardNumberVisible = 1117,
Collection_Created = 1300,
Collection_Updated = 1301,
Collection_Deleted = 1302,
Group_Created = 1400,
Group_Updated = 1401,
Group_Deleted = 1402,
OrganizationUser_Invited = 1500,
OrganizationUser_Confirmed = 1501,
OrganizationUser_Updated = 1502,
OrganizationUser_Removed = 1503,
OrganizationUser_UpdatedGroups = 1504,
OrganizationUser_UnlinkedSso = 1505,
OrganizationUser_ResetPassword_Enroll = 1506,
OrganizationUser_ResetPassword_Withdraw = 1507,
OrganizationUser_AdminResetPassword = 1508,
Organization_Updated = 1600,
Organization_PurgedVault = 1601,
// Organization_ClientExportedVault = 1602,
Policy_Updated = 1700,
}

View File

@@ -0,0 +1,5 @@
export enum FieldType {
Text = 0,
Hidden = 1,
Boolean = 2,
}

View File

@@ -0,0 +1,4 @@
export enum FileUploadType {
Direct = 0,
Azure = 1,
}

View File

@@ -0,0 +1,8 @@
export { CipherType } from './cipherType';
export { DeviceType } from './deviceType';
export { EncryptionType } from './encryptionType';
export { FieldType } from './fieldType';
export { LogLevelType } from './logLevelType';
export { SecureNoteType } from './secureNoteType';
export { TwoFactorProviderType } from './twoFactorProviderType';
export { UriMatchType } from './uriMatchType';

View File

@@ -0,0 +1,3 @@
export enum KdfType {
PBKDF2_SHA256 = 0,
}

View File

@@ -0,0 +1,6 @@
export enum LogLevelType {
Debug,
Info,
Warning,
Error,
}

View File

@@ -0,0 +1,20 @@
export enum NotificationType {
SyncCipherUpdate = 0,
SyncCipherCreate = 1,
SyncLoginDelete = 2,
SyncFolderDelete = 3,
SyncCiphers = 4,
SyncVault = 5,
SyncOrgKeys = 6,
SyncFolderCreate = 7,
SyncFolderUpdate = 8,
SyncCipherDelete = 9,
SyncSettings = 10,
LogOut = 11,
SyncSendCreate = 12,
SyncSendUpdate = 13,
SyncSendDelete = 14,
}

View File

@@ -0,0 +1,5 @@
export enum OrganizationUserStatusType {
Invited = 0,
Accepted = 1,
Confirmed = 2,
}

View File

@@ -0,0 +1,7 @@
export enum OrganizationUserType {
Owner = 0,
Admin = 1,
User = 2,
Manager = 3,
Custom = 4,
}

View File

@@ -0,0 +1,11 @@
export enum PaymentMethodType {
Card = 0,
BankAccount = 1,
PayPal = 2,
BitPay = 3,
Credit = 4,
WireTransfer = 5,
AppleInApp = 6,
GoogleInApp = 7,
Check = 8,
}

View File

@@ -0,0 +1,13 @@
export enum Permissions {
AccessBusinessPortal,
AccessEventLogs,
AccessImportExport,
AccessReports,
ManageAllCollections,
ManageAssignedCollections,
ManageGroups,
ManageOrganization,
ManagePolicies,
ManageUsers,
ManageUsersPassword,
}

View File

@@ -0,0 +1,14 @@
export enum PlanType {
Free = 0,
FamiliesAnnually2019 = 1,
TeamsMonthly2019 = 2,
TeamsAnnually2019 = 3,
EnterpriseMonthly2019 = 4,
EnterpriseAnnually2019 = 5,
Custom = 6,
FamiliesAnnually = 7,
TeamsMonthly = 8,
TeamsAnnually = 9,
EnterpriseMonthly = 10,
EnterpriseAnnually = 11,
}

View File

@@ -0,0 +1,11 @@
export enum PolicyType {
TwoFactorAuthentication = 0, // Requires users to have 2fa enabled
MasterPassword = 1, // Sets minimum requirements for master password complexity
PasswordGenerator = 2, // Sets minimum requirements/default type for generated passwords/passphrases
SingleOrg = 3, // Allows users to only be apart of one organization
RequireSso = 4, // Requires users to authenticate with SSO
PersonalOwnership = 5, // Disables personal vault ownership for adding/cloning items
DisableSend = 6, // Disables the ability to create and edit Bitwarden Sends
SendOptions = 7, // Sets restrictions or defaults for Bitwarden Sends
ResetPassword = 8, // Allows orgs to use reset password : also can enable auto-enrollment during invite flow
}

View File

@@ -0,0 +1,6 @@
export enum ProductType {
Free = 0,
Families = 1,
Teams = 2,
Enterprise = 3,
}

View File

@@ -0,0 +1,3 @@
export enum SecureNoteType {
Generic = 0,
}

View File

@@ -0,0 +1,4 @@
export enum SendType {
Text = 0,
File = 1,
}

View File

@@ -0,0 +1,7 @@
export enum TransactionType {
Charge = 0,
Credit = 1,
PromotionalCredit = 2,
ReferralCredit = 3,
Refund = 4,
}

View File

@@ -0,0 +1,10 @@
export enum TwoFactorProviderType {
Authenticator = 0,
Email = 1,
Duo = 2,
Yubikey = 3,
U2f = 4,
Remember = 5,
OrganizationDuo = 6,
WebAuthn = 7,
}

View File

@@ -0,0 +1,8 @@
export enum UriMatchType {
Domain = 0,
Host = 1,
StartsWith = 2,
Exact = 3,
RegularExpression = 4,
Never = 5,
}

2
common/src/globals.d.ts vendored Normal file
View File

@@ -0,0 +1,2 @@
declare function escape(s: string): string;
declare function unescape(s: string): string;

View File

@@ -0,0 +1,55 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
export class AscendoCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, false);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
if (value.length < 2) {
return;
}
const cipher = this.initLoginCipher();
cipher.notes = this.getValueOrDefault(value[value.length - 1]);
cipher.name = this.getValueOrDefault(value[0], '--');
if (value.length > 2 && (value.length % 2) === 0) {
for (let i = 0; i < value.length - 2; i += 2) {
const val: string = value[i + 2];
const field: string = value[i + 1];
if (this.isNullOrWhitespace(val) || this.isNullOrWhitespace(field)) {
continue;
}
const fieldLower = field.toLowerCase();
if (cipher.login.password == null && this.passwordFieldNames.indexOf(fieldLower) > -1) {
cipher.login.password = this.getValueOrDefault(val);
} else if (cipher.login.username == null &&
this.usernameFieldNames.indexOf(fieldLower) > -1) {
cipher.login.username = this.getValueOrDefault(val);
} else if ((cipher.login.uris == null || cipher.login.uris.length === 0) &&
this.uriFieldNames.indexOf(fieldLower) > -1) {
cipher.login.uris = this.makeUriArray(val);
} else {
this.processKvp(cipher, field, val);
}
}
}
this.convertToNoteIfNeeded(cipher);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,28 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
export class AvastCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(value.name);
cipher.login.uris = this.makeUriArray(value.web);
cipher.login.password = this.getValueOrDefault(value.password);
cipher.login.username = this.getValueOrDefault(value.login);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,69 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
import { CipherType } from '../enums/cipherType';
import { SecureNoteType } from '../enums/secureNoteType';
export class AvastJsonImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = JSON.parse(data);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
if (results.logins != null) {
results.logins.forEach((value: any) => {
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(value.custName);
cipher.notes = this.getValueOrDefault(value.note);
cipher.login.uris = this.makeUriArray(value.url);
cipher.login.password = this.getValueOrDefault(value.pwd);
cipher.login.username = this.getValueOrDefault(value.loginName);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
}
if (results.notes != null) {
results.notes.forEach((value: any) => {
const cipher = this.initLoginCipher();
cipher.type = CipherType.SecureNote;
cipher.secureNote.type = SecureNoteType.Generic;
cipher.name = this.getValueOrDefault(value.label);
cipher.notes = this.getValueOrDefault(value.text);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
}
if (results.cards != null) {
results.cards.forEach((value: any) => {
const cipher = this.initLoginCipher();
cipher.type = CipherType.Card;
cipher.name = this.getValueOrDefault(value.custName);
cipher.notes = this.getValueOrDefault(value.note);
cipher.card.cardholderName = this.getValueOrDefault(value.holderName);
cipher.card.number = this.getValueOrDefault(value.cardNumber);
cipher.card.code = this.getValueOrDefault(value.cvv);
cipher.card.brand = this.getCardBrand(cipher.card.number);
if (value.expirationDate != null) {
if (value.expirationDate.month != null) {
cipher.card.expMonth = value.expirationDate.month + '';
}
if (value.expirationDate.year != null) {
cipher.card.expYear = value.expirationDate.year + '';
}
}
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
}
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,36 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
export class AviraCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(value.name,
this.getValueOrDefault(this.nameFromUrl(value.website), '--'));
cipher.login.uris = this.makeUriArray(value.website);
cipher.login.password = this.getValueOrDefault(value.password);
if (this.isNullOrWhitespace(value.username) && !this.isNullOrWhitespace(value.secondary_username)) {
cipher.login.username = value.secondary_username;
} else {
cipher.login.username = this.getValueOrDefault(value.username);
cipher.notes = this.getValueOrDefault(value.secondary_username);
}
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,377 @@
import * as papa from 'papaparse';
import { LogService } from '../abstractions/log.service';
import { ImportResult } from '../models/domain/importResult';
import { CipherView } from '../models/view/cipherView';
import { CollectionView } from '../models/view/collectionView';
import { LoginUriView } from '../models/view/loginUriView';
import { Utils } from '../misc/utils';
import { FieldView } from '../models/view/fieldView';
import { FolderView } from '../models/view/folderView';
import { LoginView } from '../models/view/loginView';
import { SecureNoteView } from '../models/view/secureNoteView';
import { CipherRepromptType } from '../enums/cipherRepromptType';
import { CipherType } from '../enums/cipherType';
import { FieldType } from '../enums/fieldType';
import { SecureNoteType } from '../enums/secureNoteType';
import { ConsoleLogService } from '../services/consoleLog.service';
export abstract class BaseImporter {
organizationId: string = null;
protected logService: LogService = new ConsoleLogService(false);
protected newLineRegex = /(?:\r\n|\r|\n)/;
protected passwordFieldNames = [
'password', 'pass word', 'passphrase', 'pass phrase',
'pass', 'code', 'code word', 'codeword',
'secret', 'secret word', 'personpwd',
'key', 'keyword', 'key word', 'keyphrase', 'key phrase',
'form_pw', 'wppassword', 'pin', 'pwd', 'pw', 'pword', 'passwd',
'p', 'serial', 'serial#', 'license key', 'reg #',
// Non-English names
'passwort',
];
protected usernameFieldNames = [
'user', 'name', 'user name', 'username', 'login name',
'email', 'e-mail', 'id', 'userid', 'user id',
'login', 'form_loginname', 'wpname', 'mail',
'loginid', 'login id', 'log', 'personlogin',
'first name', 'last name', 'card#', 'account #',
'member', 'member #',
// Non-English names
'nom', 'benutzername',
];
protected notesFieldNames = [
'note', 'notes', 'comment', 'comments', 'memo',
'description', 'free form', 'freeform',
'free text', 'freetext', 'free',
// Non-English names
'kommentar',
];
protected uriFieldNames: string[] = [
'url', 'hyper link', 'hyperlink', 'link',
'host', 'hostname', 'host name', 'server', 'address',
'hyper ref', 'href', 'web', 'website', 'web site', 'site',
'web-site', 'uri',
// Non-English names
'ort', 'adresse',
];
protected parseCsvOptions = {
encoding: 'UTF-8',
skipEmptyLines: false,
};
protected get organization() {
return this.organizationId != null;
}
protected parseXml(data: string): Document {
const parser = new DOMParser();
const doc = parser.parseFromString(data, 'application/xml');
return doc != null && doc.querySelector('parsererror') == null ? doc : null;
}
protected parseCsv(data: string, header: boolean, options: any = {}): any[] {
const parseOptions = Object.assign({ header: header }, this.parseCsvOptions, options);
data = this.splitNewLine(data).join('\n').trim();
const result = papa.parse(data, parseOptions);
if (result.errors != null && result.errors.length > 0) {
result.errors.forEach(e => {
if (e.row != null) {
// tslint:disable-next-line
this.logService.warning('Error parsing row ' + e.row + ': ' + e.message);
}
});
}
return result.data && result.data.length > 0 ? result.data : null;
}
protected parseSingleRowCsv(rowData: string) {
if (this.isNullOrWhitespace(rowData)) {
return null;
}
const parsedRow = this.parseCsv(rowData, false);
if (parsedRow != null && parsedRow.length > 0 && parsedRow[0].length > 0) {
return parsedRow[0];
}
return null;
}
protected makeUriArray(uri: string | string[]): LoginUriView[] {
if (uri == null) {
return null;
}
if (typeof uri === 'string') {
const loginUri = new LoginUriView();
loginUri.uri = this.fixUri(uri);
if (this.isNullOrWhitespace(loginUri.uri)) {
return null;
}
loginUri.match = null;
return [loginUri];
}
if (uri.length > 0) {
const returnArr: LoginUriView[] = [];
uri.forEach(u => {
const loginUri = new LoginUriView();
loginUri.uri = this.fixUri(u);
if (this.isNullOrWhitespace(loginUri.uri)) {
return;
}
loginUri.match = null;
returnArr.push(loginUri);
});
return returnArr.length === 0 ? null : returnArr;
}
return null;
}
protected fixUri(uri: string) {
if (uri == null) {
return null;
}
uri = uri.trim();
if (uri.indexOf('://') === -1 && uri.indexOf('.') >= 0) {
uri = 'http://' + uri;
}
if (uri.length > 1000) {
return uri.substring(0, 1000);
}
return uri;
}
protected nameFromUrl(url: string) {
const hostname = Utils.getHostname(url);
if (this.isNullOrWhitespace(hostname)) {
return null;
}
return hostname.startsWith('www.') ? hostname.replace('www.', '') : hostname;
}
protected isNullOrWhitespace(str: string): boolean {
return Utils.isNullOrWhitespace(str);
}
protected getValueOrDefault(str: string, defaultValue: string = null): string {
if (this.isNullOrWhitespace(str)) {
return defaultValue;
}
return str;
}
protected splitNewLine(str: string): string[] {
return str.split(this.newLineRegex);
}
// ref https://stackoverflow.com/a/5911300
protected getCardBrand(cardNum: string) {
if (this.isNullOrWhitespace(cardNum)) {
return null;
}
// Visa
let re = new RegExp('^4');
if (cardNum.match(re) != null) {
return 'Visa';
}
// Mastercard
// Updated for Mastercard 2017 BINs expansion
if (/^(5[1-5][0-9]{14}|2(22[1-9][0-9]{12}|2[3-9][0-9]{13}|[3-6][0-9]{14}|7[0-1][0-9]{13}|720[0-9]{12}))$/
.test(cardNum)) {
return 'Mastercard';
}
// AMEX
re = new RegExp('^3[47]');
if (cardNum.match(re) != null) {
return 'Amex';
}
// Discover
re = new RegExp('^(6011|622(12[6-9]|1[3-9][0-9]|[2-8][0-9]{2}|9[0-1][0-9]|92[0-5]|64[4-9])|65)');
if (cardNum.match(re) != null) {
return 'Discover';
}
// Diners
re = new RegExp('^36');
if (cardNum.match(re) != null) {
return 'Diners Club';
}
// Diners - Carte Blanche
re = new RegExp('^30[0-5]');
if (cardNum.match(re) != null) {
return 'Diners Club';
}
// JCB
re = new RegExp('^35(2[89]|[3-8][0-9])');
if (cardNum.match(re) != null) {
return 'JCB';
}
// Visa Electron
re = new RegExp('^(4026|417500|4508|4844|491(3|7))');
if (cardNum.match(re) != null) {
return 'Visa';
}
return null;
}
protected setCardExpiration(cipher: CipherView, expiration: string): boolean {
if (!this.isNullOrWhitespace(expiration)) {
expiration = expiration.replace(/\s/g, '');
const parts = expiration.split('/');
if (parts.length === 2) {
let month: string = null;
let year: string = null;
if (parts[0].length === 1 || parts[0].length === 2) {
month = parts[0];
if (month.length === 2 && month[0] === '0') {
month = month.substr(1, 1);
}
}
if (parts[1].length === 2 || parts[1].length === 4) {
year = month.length === 2 ? '20' + parts[1] : parts[1];
}
if (month != null && year != null) {
cipher.card.expMonth = month;
cipher.card.expYear = year;
return true;
}
}
}
return false;
}
protected moveFoldersToCollections(result: ImportResult) {
result.folderRelationships.forEach(r => result.collectionRelationships.push(r));
result.collections = result.folders.map(f => {
const collection = new CollectionView();
collection.name = f.name;
return collection;
});
result.folderRelationships = [];
result.folders = [];
}
protected querySelectorDirectChild(parentEl: Element, query: string) {
const els = this.querySelectorAllDirectChild(parentEl, query);
return els.length === 0 ? null : els[0];
}
protected querySelectorAllDirectChild(parentEl: Element, query: string) {
return Array.from(parentEl.querySelectorAll(query)).filter(el => el.parentNode === parentEl);
}
protected initLoginCipher() {
const cipher = new CipherView();
cipher.favorite = false;
cipher.notes = '';
cipher.fields = [];
cipher.login = new LoginView();
cipher.type = CipherType.Login;
return cipher;
}
protected cleanupCipher(cipher: CipherView) {
if (cipher == null) {
return;
}
if (cipher.type !== CipherType.Login) {
cipher.login = null;
}
if (this.isNullOrWhitespace(cipher.name)) {
cipher.name = '--';
}
if (this.isNullOrWhitespace(cipher.notes)) {
cipher.notes = null;
} else {
cipher.notes = cipher.notes.trim();
}
if (cipher.fields != null && cipher.fields.length === 0) {
cipher.fields = null;
}
}
protected processKvp(cipher: CipherView, key: string, value: string, type: FieldType = FieldType.Text) {
if (this.isNullOrWhitespace(value)) {
return;
}
if (this.isNullOrWhitespace(key)) {
key = '';
}
if (value.length > 200 || value.trim().search(this.newLineRegex) > -1) {
if (cipher.notes == null) {
cipher.notes = '';
}
cipher.notes += (key + ': ' + this.splitNewLine(value).join('\n') + '\n');
} else {
if (cipher.fields == null) {
cipher.fields = [];
}
const field = new FieldView();
field.type = type;
field.name = key;
field.value = value;
cipher.fields.push(field);
}
}
protected processFolder(result: ImportResult, folderName: string) {
let folderIndex = result.folders.length;
const hasFolder = !this.isNullOrWhitespace(folderName);
let addFolder = hasFolder;
if (hasFolder) {
for (let i = 0; i < result.folders.length; i++) {
if (result.folders[i].name === folderName) {
addFolder = false;
folderIndex = i;
break;
}
}
}
if (addFolder) {
const f = new FolderView();
f.name = folderName;
result.folders.push(f);
}
if (hasFolder) {
result.folderRelationships.push([result.ciphers.length, folderIndex]);
}
}
protected convertToNoteIfNeeded(cipher: CipherView) {
if (cipher.type === CipherType.Login && this.isNullOrWhitespace(cipher.login.username) &&
this.isNullOrWhitespace(cipher.login.password) &&
(cipher.login.uris == null || cipher.login.uris.length === 0)) {
cipher.type = CipherType.SecureNote;
cipher.secureNote = new SecureNoteView();
cipher.secureNote.type = SecureNoteType.Generic;
}
}
}

View File

@@ -0,0 +1,118 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
import { CipherView } from '../models/view/cipherView';
import { CollectionView } from '../models/view/collectionView';
import { FieldView } from '../models/view/fieldView';
import { FolderView } from '../models/view/folderView';
import { LoginView } from '../models/view/loginView';
import { SecureNoteView } from '../models/view/secureNoteView';
import { CipherRepromptType } from '../enums/cipherRepromptType';
import { CipherType } from '../enums/cipherType';
import { FieldType } from '../enums/fieldType';
import { SecureNoteType } from '../enums/secureNoteType';
export class BitwardenCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
if (this.organization && !this.isNullOrWhitespace(value.collections)) {
const collections = (value.collections as string).split(',');
collections.forEach(col => {
let addCollection = true;
let collectionIndex = result.collections.length;
for (let i = 0; i < result.collections.length; i++) {
if (result.collections[i].name === col) {
addCollection = false;
collectionIndex = i;
break;
}
}
if (addCollection) {
const collection = new CollectionView();
collection.name = col;
result.collections.push(collection);
}
result.collectionRelationships.push([result.ciphers.length, collectionIndex]);
});
} else if (!this.organization) {
this.processFolder(result, value.folder);
}
const cipher = new CipherView();
cipher.favorite = !this.organization && this.getValueOrDefault(value.favorite, '0') !== '0' ? true : false;
cipher.type = CipherType.Login;
cipher.notes = this.getValueOrDefault(value.notes);
cipher.name = this.getValueOrDefault(value.name, '--');
try {
cipher.reprompt = parseInt(this.getValueOrDefault(value.reprompt, CipherRepromptType.None.toString()), 10);
} catch (e) {
// tslint:disable-next-line
console.error('Unable to parse reprompt value', e);
cipher.reprompt = CipherRepromptType.None;
}
if (!this.isNullOrWhitespace(value.fields)) {
const fields = this.splitNewLine(value.fields);
for (let i = 0; i < fields.length; i++) {
if (this.isNullOrWhitespace(fields[i])) {
continue;
}
const delimPosition = fields[i].lastIndexOf(': ');
if (delimPosition === -1) {
continue;
}
if (cipher.fields == null) {
cipher.fields = [];
}
const field = new FieldView();
field.name = fields[i].substr(0, delimPosition);
field.value = null;
field.type = FieldType.Text;
if (fields[i].length > (delimPosition + 2)) {
field.value = fields[i].substr(delimPosition + 2);
}
cipher.fields.push(field);
}
}
const valueType = value.type != null ? value.type.toLowerCase() : null;
switch (valueType) {
case 'note':
cipher.type = CipherType.SecureNote;
cipher.secureNote = new SecureNoteView();
cipher.secureNote.type = SecureNoteType.Generic;
break;
default:
cipher.type = CipherType.Login;
cipher.login = new LoginView();
cipher.login.totp = this.getValueOrDefault(value.login_totp || value.totp);
cipher.login.username = this.getValueOrDefault(value.login_username || value.username);
cipher.login.password = this.getValueOrDefault(value.login_password || value.password);
const uris = this.parseSingleRowCsv(value.login_uri || value.uri);
cipher.login.uris = this.makeUriArray(uris);
break;
}
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,159 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { EncString } from '../models/domain/encString';
import { ImportResult } from '../models/domain/importResult';
import { CipherWithIds } from '../models/export/cipherWithIds';
import { CollectionWithId } from '../models/export/collectionWithId';
import { FolderWithId } from '../models/export/folderWithId';
import { CryptoService } from '../abstractions/crypto.service';
import { I18nService } from '../abstractions/i18n.service';
export class BitwardenJsonImporter extends BaseImporter implements Importer {
private results: any;
private result: ImportResult;
constructor(private cryptoService: CryptoService, private i18nService: I18nService) {
super();
}
async parse(data: string): Promise<ImportResult> {
this.result = new ImportResult();
this.results = JSON.parse(data);
if (this.results == null || this.results.items == null || this.results.items.length === 0) {
this.result.success = false;
return this.result;
}
if (this.results.encrypted) {
await this.parseEncrypted();
} else {
this.parseDecrypted();
}
return this.result;
}
private async parseEncrypted() {
if (this.results.encKeyValidation_DO_NOT_EDIT != null) {
const orgKey = await this.cryptoService.getOrgKey(this.organizationId);
const encKeyValidation = new EncString(this.results.encKeyValidation_DO_NOT_EDIT);
const encKeyValidationDecrypt = await this.cryptoService.decryptToUtf8(encKeyValidation, orgKey);
if (encKeyValidationDecrypt === null) {
this.result.success = false;
this.result.errorMessage = this.i18nService.t('importEncKeyError');
return;
}
}
const groupingsMap = new Map<string, number>();
if (this.organization && this.results.collections != null) {
for (const c of this.results.collections as CollectionWithId[]) {
const collection = CollectionWithId.toDomain(c);
if (collection != null) {
collection.id = null;
collection.organizationId = this.organizationId;
const view = await collection.decrypt();
groupingsMap.set(c.id, this.result.collections.length);
this.result.collections.push(view);
}
}
} else if (!this.organization && this.results.folders != null) {
for (const f of this.results.folders as FolderWithId[]) {
const folder = FolderWithId.toDomain(f);
if (folder != null) {
folder.id = null;
const view = await folder.decrypt();
groupingsMap.set(f.id, this.result.folders.length);
this.result.folders.push(view);
}
}
}
for (const c of this.results.items as CipherWithIds[]) {
const cipher = CipherWithIds.toDomain(c);
// reset ids incase they were set for some reason
cipher.id = null;
cipher.folderId = null;
cipher.organizationId = this.organizationId;
cipher.collectionIds = null;
// make sure password history is limited
if (cipher.passwordHistory != null && cipher.passwordHistory.length > 5) {
cipher.passwordHistory = cipher.passwordHistory.slice(0, 5);
}
if (!this.organization && c.folderId != null && groupingsMap.has(c.folderId)) {
this.result.folderRelationships.push([this.result.ciphers.length, groupingsMap.get(c.folderId)]);
} else if (this.organization && c.collectionIds != null) {
c.collectionIds.forEach(cId => {
if (groupingsMap.has(cId)) {
this.result.collectionRelationships.push([this.result.ciphers.length, groupingsMap.get(cId)]);
}
});
}
const view = await cipher.decrypt();
this.cleanupCipher(view);
this.result.ciphers.push(view);
}
this.result.success = true;
}
private parseDecrypted() {
const groupingsMap = new Map<string, number>();
if (this.organization && this.results.collections != null) {
this.results.collections.forEach((c: CollectionWithId) => {
const collection = CollectionWithId.toView(c);
if (collection != null) {
collection.id = null;
collection.organizationId = null;
groupingsMap.set(c.id, this.result.collections.length);
this.result.collections.push(collection);
}
});
} else if (!this.organization && this.results.folders != null) {
this.results.folders.forEach((f: FolderWithId) => {
const folder = FolderWithId.toView(f);
if (folder != null) {
folder.id = null;
groupingsMap.set(f.id, this.result.folders.length);
this.result.folders.push(folder);
}
});
}
this.results.items.forEach((c: CipherWithIds) => {
const cipher = CipherWithIds.toView(c);
// reset ids incase they were set for some reason
cipher.id = null;
cipher.folderId = null;
cipher.organizationId = null;
cipher.collectionIds = null;
// make sure password history is limited
if (cipher.passwordHistory != null && cipher.passwordHistory.length > 5) {
cipher.passwordHistory = cipher.passwordHistory.slice(0, 5);
}
if (!this.organization && c.folderId != null && groupingsMap.has(c.folderId)) {
this.result.folderRelationships.push([this.result.ciphers.length, groupingsMap.get(c.folderId)]);
} else if (this.organization && c.collectionIds != null) {
c.collectionIds.forEach(cId => {
if (groupingsMap.has(cId)) {
this.result.collectionRelationships.push([this.result.ciphers.length, groupingsMap.get(cId)]);
}
});
}
this.cleanupCipher(cipher);
this.result.ciphers.push(cipher);
});
this.result.success = true;
}
}

View File

@@ -0,0 +1,36 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
export class BlackBerryCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
if (value.grouping === 'list') {
return;
}
const cipher = this.initLoginCipher();
cipher.favorite = value.fav === '1';
cipher.name = this.getValueOrDefault(value.name);
cipher.notes = this.getValueOrDefault(value.extra);
if (value.grouping !== 'note') {
cipher.login.uris = this.makeUriArray(value.url);
cipher.login.password = this.getValueOrDefault(value.password);
cipher.login.username = this.getValueOrDefault(value.username);
}
this.convertToNoteIfNeeded(cipher);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,39 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
export class BlurCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
if (value.label === 'null') {
value.label = null;
}
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(value.label,
this.getValueOrDefault(this.nameFromUrl(value.domain), '--'));
cipher.login.uris = this.makeUriArray(value.domain);
cipher.login.password = this.getValueOrDefault(value.password);
if (this.isNullOrWhitespace(value.email) && !this.isNullOrWhitespace(value.username)) {
cipher.login.username = value.username;
} else {
cipher.login.username = this.getValueOrDefault(value.email);
cipher.notes = this.getValueOrDefault(value.username);
}
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,51 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
const OfficialProps = [
'!group_id', '!group_name', 'title', 'username', 'password', 'URL', 'id',
];
export class ButtercupCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
this.processFolder(result, this.getValueOrDefault(value['!group_name']));
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(value.title, '--');
cipher.login.username = this.getValueOrDefault(value.username);
cipher.login.password = this.getValueOrDefault(value.password);
cipher.login.uris = this.makeUriArray(value.URL);
let processingCustomFields = false;
for (const prop in value) {
if (value.hasOwnProperty(prop)) {
if (!processingCustomFields && OfficialProps.indexOf(prop) === -1) {
processingCustomFields = true;
}
if (processingCustomFields) {
this.processKvp(cipher, prop, value[prop]);
}
}
}
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
if (this.organization) {
this.moveFoldersToCollections(result);
}
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,28 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
export class ChromeCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(value.name, '--');
cipher.login.username = this.getValueOrDefault(value.username);
cipher.login.password = this.getValueOrDefault(value.password);
cipher.login.uris = this.makeUriArray(value.url);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,79 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
export class ClipperzHtmlImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const doc = this.parseXml(data);
if (doc == null) {
result.success = false;
return Promise.resolve(result);
}
const textarea = doc.querySelector('textarea');
if (textarea == null || this.isNullOrWhitespace(textarea.textContent)) {
result.errorMessage = 'Missing textarea.';
result.success = false;
return Promise.resolve(result);
}
const entries = JSON.parse(textarea.textContent);
entries.forEach((entry: any) => {
const cipher = this.initLoginCipher();
if (!this.isNullOrWhitespace(entry.label)) {
cipher.name = entry.label.split(' ')[0];
}
if (entry.data != null && !this.isNullOrWhitespace(entry.data.notes)) {
cipher.notes = entry.data.notes.split('\\n').join('\n');
}
if (entry.currentVersion != null && entry.currentVersion.fields != null) {
for (const property in entry.currentVersion.fields) {
if (!entry.currentVersion.fields.hasOwnProperty(property)) {
continue;
}
const field = entry.currentVersion.fields[property];
const actionType = field.actionType != null ? field.actionType.toLowerCase() : null;
switch (actionType) {
case 'password':
cipher.login.password = this.getValueOrDefault(field.value);
break;
case 'email':
case 'username':
case 'user':
case 'name':
cipher.login.username = this.getValueOrDefault(field.value);
break;
case 'url':
cipher.login.uris = this.makeUriArray(field.value);
break;
default:
const labelLower = field.label != null ? field.label.toLowerCase() : null;
if (cipher.login.password == null && this.passwordFieldNames.indexOf(labelLower) > -1) {
cipher.login.password = this.getValueOrDefault(field.value);
} else if (cipher.login.username == null &&
this.usernameFieldNames.indexOf(labelLower) > -1) {
cipher.login.username = this.getValueOrDefault(field.value);
} else if ((cipher.login.uris == null || cipher.login.uris.length === 0) &&
this.uriFieldNames.indexOf(labelLower) > -1) {
cipher.login.uris = this.makeUriArray(field.value);
} else {
this.processKvp(cipher, field.label, field.value);
}
break;
}
}
}
this.convertToNoteIfNeeded(cipher);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,47 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
export class CodebookCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
this.processFolder(result, this.getValueOrDefault(value.Category));
const cipher = this.initLoginCipher();
cipher.favorite = this.getValueOrDefault(value.Favorite) === 'True';
cipher.name = this.getValueOrDefault(value.Entry, '--');
cipher.notes = this.getValueOrDefault(value.Note);
cipher.login.username = this.getValueOrDefault(value.Username, value.Email);
cipher.login.password = this.getValueOrDefault(value.Password);
cipher.login.totp = this.getValueOrDefault(value.TOTP);
cipher.login.uris = this.makeUriArray(value.Website);
if (!this.isNullOrWhitespace(value.Username)) {
this.processKvp(cipher, 'Email', value.Email);
}
this.processKvp(cipher, 'Phone', value.Phone);
this.processKvp(cipher, 'PIN', value.PIN);
this.processKvp(cipher, 'Account', value.Account);
this.processKvp(cipher, 'Date', value.Date);
this.convertToNoteIfNeeded(cipher);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
if (this.organization) {
this.moveFoldersToCollections(result);
}
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,162 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
import { CardView } from '../models/view/cardView';
import { CipherView } from '../models/view/cipherView';
import { IdentityView } from '../models/view/identityView';
import { SecureNoteView } from '../models/view/secureNoteView';
import { CipherType } from '../enums/cipherType';
import { SecureNoteType } from '../enums/secureNoteType';
const HandledResults = new Set(['ADDRESS', 'AUTHENTIFIANT', 'BANKSTATEMENT', 'IDCARD', 'IDENTITY',
'PAYMENTMEANS_CREDITCARD', 'PAYMENTMEAN_PAYPAL', 'EMAIL']);
export class DashlaneJsonImporter extends BaseImporter implements Importer {
private result: ImportResult;
parse(data: string): Promise<ImportResult> {
this.result = new ImportResult();
const results = JSON.parse(data);
if (results == null || results.length === 0) {
this.result.success = false;
return Promise.resolve(this.result);
}
if (results.ADDRESS != null) {
this.processAddress(results.ADDRESS);
}
if (results.AUTHENTIFIANT != null) {
this.processAuth(results.AUTHENTIFIANT);
}
if (results.BANKSTATEMENT != null) {
this.processNote(results.BANKSTATEMENT, 'BankAccountName');
}
if (results.IDCARD != null) {
this.processNote(results.IDCARD, 'Fullname');
}
if (results.PAYMENTMEANS_CREDITCARD != null) {
this.processCard(results.PAYMENTMEANS_CREDITCARD);
}
if (results.IDENTITY != null) {
this.processIdentity(results.IDENTITY);
}
for (const key in results) {
if (results.hasOwnProperty(key) && !HandledResults.has(key)) {
this.processNote(results[key], null, 'Generic Note');
}
}
this.result.success = true;
return Promise.resolve(this.result);
}
private processAuth(results: any[]) {
results.forEach((credential: any) => {
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(credential.title);
cipher.login.username = this.getValueOrDefault(credential.login,
this.getValueOrDefault(credential.secondaryLogin));
if (this.isNullOrWhitespace(cipher.login.username)) {
cipher.login.username = this.getValueOrDefault(credential.email);
} else if (!this.isNullOrWhitespace(credential.email)) {
cipher.notes = ('Email: ' + credential.email + '\n');
}
cipher.login.password = this.getValueOrDefault(credential.password);
cipher.login.uris = this.makeUriArray(credential.domain);
cipher.notes += this.getValueOrDefault(credential.note, '');
this.convertToNoteIfNeeded(cipher);
this.cleanupCipher(cipher);
this.result.ciphers.push(cipher);
});
}
private processIdentity(results: any[]) {
results.forEach((obj: any) => {
const cipher = new CipherView();
cipher.identity = new IdentityView();
cipher.type = CipherType.Identity;
cipher.name = this.getValueOrDefault(obj.fullName, '');
const nameParts = cipher.name.split(' ');
if (nameParts.length > 0) {
cipher.identity.firstName = this.getValueOrDefault(nameParts[0]);
}
if (nameParts.length === 2) {
cipher.identity.lastName = this.getValueOrDefault(nameParts[1]);
} else if (nameParts.length === 3) {
cipher.identity.middleName = this.getValueOrDefault(nameParts[1]);
cipher.identity.lastName = this.getValueOrDefault(nameParts[2]);
}
cipher.identity.username = this.getValueOrDefault(obj.pseudo);
this.cleanupCipher(cipher);
this.result.ciphers.push(cipher);
});
}
private processAddress(results: any[]) {
results.forEach((obj: any) => {
const cipher = new CipherView();
cipher.identity = new IdentityView();
cipher.type = CipherType.Identity;
cipher.name = this.getValueOrDefault(obj.addressName);
cipher.identity.address1 = this.getValueOrDefault(obj.addressFull);
cipher.identity.city = this.getValueOrDefault(obj.city);
cipher.identity.state = this.getValueOrDefault(obj.state);
cipher.identity.postalCode = this.getValueOrDefault(obj.zipcode);
cipher.identity.country = this.getValueOrDefault(obj.country);
if (cipher.identity.country != null) {
cipher.identity.country = cipher.identity.country.toUpperCase();
}
this.cleanupCipher(cipher);
this.result.ciphers.push(cipher);
});
}
private processCard(results: any[]) {
results.forEach((obj: any) => {
const cipher = new CipherView();
cipher.card = new CardView();
cipher.type = CipherType.Card;
cipher.name = this.getValueOrDefault(obj.bank);
cipher.card.number = this.getValueOrDefault(obj.cardNumber);
cipher.card.brand = this.getCardBrand(cipher.card.number);
cipher.card.cardholderName = this.getValueOrDefault(obj.owner);
if (!this.isNullOrWhitespace(cipher.card.brand)) {
if (this.isNullOrWhitespace(cipher.name)) {
cipher.name = cipher.card.brand;
} else {
cipher.name += (' - ' + cipher.card.brand);
}
}
this.cleanupCipher(cipher);
this.result.ciphers.push(cipher);
});
}
private processNote(results: any[], nameProperty: string, name: string = null) {
results.forEach((obj: any) => {
const cipher = new CipherView();
cipher.secureNote = new SecureNoteView();
cipher.type = CipherType.SecureNote;
cipher.secureNote.type = SecureNoteType.Generic;
if (name != null) {
cipher.name = name;
} else {
cipher.name = this.getValueOrDefault(obj[nameProperty]);
}
for (const key in obj) {
if (obj.hasOwnProperty(key) && key !== nameProperty) {
this.processKvp(cipher, key, obj[key].toString());
}
}
this.cleanupCipher(cipher);
this.result.ciphers.push(cipher);
});
}
}

View File

@@ -0,0 +1,62 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
import { CardView } from '../models/view/cardView';
import { CipherType } from '../enums/cipherType';
export class EncryptrCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(value.Label, '--');
cipher.notes = this.getValueOrDefault(value.Notes);
const text = this.getValueOrDefault(value.Text);
if (!this.isNullOrWhitespace(text)) {
if (this.isNullOrWhitespace(cipher.notes)) {
cipher.notes = text;
} else {
cipher.notes += ('\n\n' + text);
}
}
const type = value['Entry Type'];
if (type === 'Password') {
cipher.login.username = this.getValueOrDefault(value.Username);
cipher.login.password = this.getValueOrDefault(value.Password);
cipher.login.uris = this.makeUriArray(value['Site URL']);
} else if (type === 'Credit Card') {
cipher.type = CipherType.Card;
cipher.card = new CardView();
cipher.card.cardholderName = this.getValueOrDefault(value['Name on card']);
cipher.card.number = this.getValueOrDefault(value['Card Number']);
cipher.card.brand = this.getCardBrand(cipher.card.number);
cipher.card.code = this.getValueOrDefault(value.CVV);
const expiry = this.getValueOrDefault(value.Expiry);
if (!this.isNullOrWhitespace(expiry)) {
const expParts = expiry.split('/');
if (expParts.length > 1) {
cipher.card.expMonth = parseInt(expParts[0], null).toString();
cipher.card.expYear = (2000 + parseInt(expParts[1], null)).toString();
}
}
}
this.convertToNoteIfNeeded(cipher);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,112 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
import { CipherType } from '../enums/cipherType';
import { SecureNoteType } from '../enums/secureNoteType';
import { CardView } from '../models/view/cardView';
import { SecureNoteView } from '../models/view/secureNoteView';
export class EnpassCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, false);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
let firstRow = true;
results.forEach(value => {
if (value.length < 2 || (firstRow && (value[0] === 'Title' || value[0] === 'title'))) {
firstRow = false;
return;
}
const cipher = this.initLoginCipher();
cipher.notes = this.getValueOrDefault(value[value.length - 1]);
cipher.name = this.getValueOrDefault(value[0], '--');
if (value.length === 2 || (!this.containsField(value, 'username') &&
!this.containsField(value, 'password') && !this.containsField(value, 'email') &&
!this.containsField(value, 'url'))) {
cipher.type = CipherType.SecureNote;
cipher.secureNote = new SecureNoteView();
cipher.secureNote.type = SecureNoteType.Generic;
}
if (this.containsField(value, 'cardholder') && this.containsField(value, 'number') &&
this.containsField(value, 'expiry date')) {
cipher.type = CipherType.Card;
cipher.card = new CardView();
}
if (value.length > 2 && (value.length % 2) === 0) {
for (let i = 0; i < value.length - 2; i += 2) {
const fieldValue: string = value[i + 2];
if (this.isNullOrWhitespace(fieldValue)) {
continue;
}
const fieldName: string = value[i + 1];
const fieldNameLower = fieldName.toLowerCase();
if (cipher.type === CipherType.Login) {
if (fieldNameLower === 'url' && (cipher.login.uris == null || cipher.login.uris.length === 0)) {
cipher.login.uris = this.makeUriArray(fieldValue);
continue;
} else if ((fieldNameLower === 'username' || fieldNameLower === 'email') &&
this.isNullOrWhitespace(cipher.login.username)) {
cipher.login.username = fieldValue;
continue;
} else if (fieldNameLower === 'password' && this.isNullOrWhitespace(cipher.login.password)) {
cipher.login.password = fieldValue;
continue;
} else if (fieldNameLower === 'totp' && this.isNullOrWhitespace(cipher.login.totp)) {
cipher.login.totp = fieldValue;
continue;
}
} else if (cipher.type === CipherType.Card) {
if (fieldNameLower === 'cardholder' && this.isNullOrWhitespace(cipher.card.cardholderName)) {
cipher.card.cardholderName = fieldValue;
continue;
} else if (fieldNameLower === 'number' && this.isNullOrWhitespace(cipher.card.number)) {
cipher.card.number = fieldValue;
cipher.card.brand = this.getCardBrand(fieldValue);
continue;
} else if (fieldNameLower === 'cvc' && this.isNullOrWhitespace(cipher.card.code)) {
cipher.card.code = fieldValue;
continue;
} else if (fieldNameLower === 'expiry date' && this.isNullOrWhitespace(cipher.card.expMonth) &&
this.isNullOrWhitespace(cipher.card.expYear)) {
if (this.setCardExpiration(cipher, fieldValue)) {
continue;
}
} else if (fieldNameLower === 'type') {
// Skip since brand was determined from number above
continue;
}
}
this.processKvp(cipher, fieldName, fieldValue);
}
}
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
private containsField(fields: any[], name: string) {
if (fields == null || name == null) {
return false;
}
return fields.filter(f => !this.isNullOrWhitespace(f) &&
f.toLowerCase() === name.toLowerCase()).length > 0;
}
}

View File

@@ -0,0 +1,163 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
import { CardView } from '../models/view/cardView';
import { CipherView } from '../models/view/cipherView';
import { FolderView } from '../models/view/folderView';
import { CipherType } from '../enums/cipherType';
import { FieldType } from '../enums/fieldType';
export class EnpassJsonImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = JSON.parse(data);
if (results == null || results.items == null || results.items.length === 0) {
result.success = false;
return Promise.resolve(result);
}
const foldersMap = new Map<string, string>();
const foldersIndexMap = new Map<string, number>();
const folderTree = this.buildFolderTree(results.folders);
this.flattenFolderTree(null, folderTree, foldersMap);
foldersMap.forEach((val, key) => {
foldersIndexMap.set(key, result.folders.length);
const f = new FolderView();
f.name = val;
result.folders.push(f);
});
results.items.forEach((item: any) => {
if (item.folders != null && item.folders.length > 0 && foldersIndexMap.has(item.folders[0])) {
result.folderRelationships.push([result.ciphers.length, foldersIndexMap.get(item.folders[0])]);
}
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(item.title);
cipher.favorite = item.favorite > 0;
if (item.template_type != null && item.fields != null && item.fields.length > 0) {
if (item.template_type.indexOf('login.') === 0 || item.template_type.indexOf('password.') === 0) {
this.processLogin(cipher, item.fields);
} else if (item.template_type.indexOf('creditcard.') === 0) {
this.processCard(cipher, item.fields);
} else if (item.template_type.indexOf('identity.') < 0 &&
item.fields.some((f: any) => f.type === 'password' && !this.isNullOrWhitespace(f.value))) {
this.processLogin(cipher, item.fields);
} else {
this.processNote(cipher, item.fields);
}
}
cipher.notes += ('\n' + this.getValueOrDefault(item.note, ''));
this.convertToNoteIfNeeded(cipher);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
private processLogin(cipher: CipherView, fields: any[]) {
const urls: string[] = [];
fields.forEach((field: any) => {
if (this.isNullOrWhitespace(field.value) || field.type === 'section') {
return;
}
if ((field.type === 'username' || field.type === 'email') &&
this.isNullOrWhitespace(cipher.login.username)) {
cipher.login.username = field.value;
} else if (field.type === 'password' && this.isNullOrWhitespace(cipher.login.password)) {
cipher.login.password = field.value;
} else if (field.type === 'totp' && this.isNullOrWhitespace(cipher.login.totp)) {
cipher.login.totp = field.value;
} else if (field.type === 'url') {
urls.push(field.value);
} else {
this.processKvp(cipher, field.label, field.value,
field.sensitive === 1 ? FieldType.Hidden : FieldType.Text);
}
});
cipher.login.uris = this.makeUriArray(urls);
}
private processCard(cipher: CipherView, fields: any[]) {
cipher.card = new CardView();
cipher.type = CipherType.Card;
fields.forEach((field: any) => {
if (this.isNullOrWhitespace(field.value) || field.type === 'section' || field.type === 'ccType') {
return;
}
if (field.type === 'ccName' && this.isNullOrWhitespace(cipher.card.cardholderName)) {
cipher.card.cardholderName = field.value;
} else if (field.type === 'ccNumber' && this.isNullOrWhitespace(cipher.card.number)) {
cipher.card.number = field.value;
cipher.card.brand = this.getCardBrand(cipher.card.number);
} else if (field.type === 'ccCvc' && this.isNullOrWhitespace(cipher.card.code)) {
cipher.card.code = field.value;
} else if (field.type === 'ccExpiry' && this.isNullOrWhitespace(cipher.card.expYear)) {
if (!this.setCardExpiration(cipher, field.value)) {
this.processKvp(cipher, field.label, field.value,
field.sensitive === 1 ? FieldType.Hidden : FieldType.Text);
}
} else {
this.processKvp(cipher, field.label, field.value,
field.sensitive === 1 ? FieldType.Hidden : FieldType.Text);
}
});
}
private processNote(cipher: CipherView, fields: any[]) {
fields.forEach((field: any) => {
if (this.isNullOrWhitespace(field.value) || field.type === 'section') {
return;
}
this.processKvp(cipher, field.label, field.value,
field.sensitive === 1 ? FieldType.Hidden : FieldType.Text);
});
}
private buildFolderTree(folders: any[]): any[] {
if (folders == null) {
return [];
}
const folderTree: any[] = [];
const map = new Map<string, any>([]);
folders.forEach((obj: any) => {
map.set(obj.uuid, obj);
obj.children = [];
});
folders.forEach((obj: any) => {
if (obj.parent_uuid != null && obj.parent_uuid !== '' && map.has(obj.parent_uuid)) {
map.get(obj.parent_uuid).children.push(obj);
} else {
folderTree.push(obj);
}
});
return folderTree;
}
private flattenFolderTree(titlePrefix: string, tree: any[], map: Map<string, string>) {
if (tree == null) {
return;
}
tree.forEach((f: any) => {
if (f.title != null && f.title.trim() !== '') {
let title = f.title.trim();
if (titlePrefix != null && titlePrefix.trim() !== '') {
title = titlePrefix + '/' + title;
}
map.set(f.uuid, title);
if (f.children != null && f.children.length !== 0) {
this.flattenFolderTree(title, f.children, map);
}
}
});
}
}

View File

@@ -0,0 +1,31 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
export class FirefoxCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.filter(value => {
return value.url !== 'chrome://FirefoxAccounts';
}).forEach(value => {
const cipher = this.initLoginCipher();
const url = this.getValueOrDefault(value.url, this.getValueOrDefault(value.hostname));
cipher.name = this.getValueOrDefault(this.nameFromUrl(url), '--');
cipher.login.username = this.getValueOrDefault(value.username);
cipher.login.password = this.getValueOrDefault(value.password);
cipher.login.uris = this.makeUriArray(url);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,60 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
import { CardView } from '../models/view/cardView';
import { CipherType } from '../enums/cipherType';
export class FSecureFskImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = JSON.parse(data);
if (results == null || results.data == null) {
result.success = false;
return Promise.resolve(result);
}
for (const key in results.data) {
if (!results.data.hasOwnProperty(key)) {
continue;
}
const value = results.data[key];
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(value.service);
cipher.notes = this.getValueOrDefault(value.notes);
if (value.style === 'website') {
cipher.login.username = this.getValueOrDefault(value.username);
cipher.login.password = this.getValueOrDefault(value.password);
cipher.login.uris = this.makeUriArray(value.url);
} else if (value.style === 'creditcard') {
cipher.type = CipherType.Card;
cipher.card = new CardView();
cipher.card.cardholderName = this.getValueOrDefault(value.username);
cipher.card.number = this.getValueOrDefault(value.creditNumber);
cipher.card.brand = this.getCardBrand(cipher.card.number);
cipher.card.code = this.getValueOrDefault(value.creditCvv);
if (!this.isNullOrWhitespace(value.creditExpiry)) {
if (!this.setCardExpiration(cipher, value.creditExpiry)) {
this.processKvp(cipher, 'Expiration', value.creditExpiry);
}
}
if (!this.isNullOrWhitespace(value.password)) {
this.processKvp(cipher, 'PIN', value.password);
}
} else {
continue;
}
this.convertToNoteIfNeeded(cipher);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
}
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,60 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
export class GnomeJsonImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = JSON.parse(data);
if (results == null || Object.keys(results).length === 0) {
result.success = false;
return Promise.resolve(result);
}
for (const keyRing in results) {
if (!results.hasOwnProperty(keyRing) || this.isNullOrWhitespace(keyRing) ||
results[keyRing].length === 0) {
continue;
}
results[keyRing].forEach((value: any) => {
if (this.isNullOrWhitespace(value.display_name) || value.display_name.indexOf('http') !== 0) {
return;
}
this.processFolder(result, keyRing);
const cipher = this.initLoginCipher();
cipher.name = value.display_name.replace('http://', '').replace('https://', '');
if (cipher.name.length > 30) {
cipher.name = cipher.name.substring(0, 30);
}
cipher.login.password = this.getValueOrDefault(value.secret);
cipher.login.uris = this.makeUriArray(value.display_name);
if (value.attributes != null) {
cipher.login.username = value.attributes != null ?
this.getValueOrDefault(value.attributes.username_value) : null;
for (const attr in value.attributes) {
if (!value.attributes.hasOwnProperty(attr) || attr === 'username_value' ||
attr === 'xdg:schema') {
continue;
}
this.processKvp(cipher, attr, value.attributes[attr]);
}
}
this.convertToNoteIfNeeded(cipher);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
}
if (this.organization) {
this.moveFoldersToCollections(result);
}
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,6 @@
import { ImportResult } from '../models/domain/importResult';
export interface Importer {
organizationId: string;
parse(data: string): Promise<ImportResult>;
}

View File

@@ -0,0 +1,124 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
const NotesHeader = 'Notes\n\n';
const ApplicationsHeader = 'Applications\n\n';
const WebsitesHeader = 'Websites\n\n';
const Delimiter = '\n---\n';
export class KasperskyTxtImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
let notesData: string;
let applicationsData: string;
let websitesData: string;
let workingData = this.splitNewLine(data).join('\n');
if (workingData.indexOf(NotesHeader) !== -1) {
const parts = workingData.split(NotesHeader);
if (parts.length > 1) {
workingData = parts[0];
notesData = parts[1];
}
}
if (workingData.indexOf(ApplicationsHeader) !== -1) {
const parts = workingData.split(ApplicationsHeader);
if (parts.length > 1) {
workingData = parts[0];
applicationsData = parts[1];
}
}
if (workingData.indexOf(WebsitesHeader) === 0) {
const parts = workingData.split(WebsitesHeader);
if (parts.length > 1) {
workingData = parts[0];
websitesData = parts[1];
}
}
const notes = this.parseDataCategory(notesData);
const applications = this.parseDataCategory(applicationsData);
const websites = this.parseDataCategory(websitesData);
notes.forEach(n => {
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(n.get('Name'));
cipher.notes = this.getValueOrDefault(n.get('Text'));
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
websites.concat(applications).forEach(w => {
const cipher = this.initLoginCipher();
const nameKey = w.has('Website name') ? 'Website name' : 'Application';
cipher.name = this.getValueOrDefault(w.get(nameKey), '');
if (!this.isNullOrWhitespace(w.get('Login name'))) {
if (!this.isNullOrWhitespace(cipher.name)) {
cipher.name += ': ';
}
cipher.name += w.get('Login name');
}
cipher.notes = this.getValueOrDefault(w.get('Comment'));
if (w.has('Website URL')) {
cipher.login.uris = this.makeUriArray(w.get('Website URL'));
}
cipher.login.username = this.getValueOrDefault(w.get('Login'));
cipher.login.password = this.getValueOrDefault(w.get('Password'));
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
private parseDataCategory(data: string): Map<string, string>[] {
if (this.isNullOrWhitespace(data) || data.indexOf(Delimiter) === -1) {
return [];
}
const items: Map<string, string>[] = [];
data.split(Delimiter).forEach(p => {
if (p.indexOf('\n') === -1) {
return;
}
const item = new Map<string, string>();
let itemComment: string;
let itemCommentKey: string;
p.split('\n').forEach(l => {
if (itemComment != null) {
itemComment += ('\n' + l);
return;
}
const colonIndex = l.indexOf(':');
let key: string;
let val: string;
if (colonIndex === -1) {
return;
} else {
key = l.substring(0, colonIndex);
if (l.length > colonIndex + 1) {
val = l.substring(colonIndex + 2);
}
}
if (key != null) {
item.set(key, val);
}
if (key === 'Comment' || key === 'Text') {
itemComment = val;
itemCommentKey = key;
}
});
if (itemComment != null && itemCommentKey != null) {
item.set(itemCommentKey, itemComment);
}
if (item.size === 0) {
return;
}
items.push(item);
});
return items;
}
}

View File

@@ -0,0 +1,100 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { FieldType } from '../enums/fieldType';
import { ImportResult } from '../models/domain/importResult';
import { FolderView } from '../models/view/folderView';
export class KeePass2XmlImporter extends BaseImporter implements Importer {
result = new ImportResult();
parse(data: string): Promise<ImportResult> {
const doc = this.parseXml(data);
if (doc == null) {
this.result.success = false;
return Promise.resolve(this.result);
}
const rootGroup = doc.querySelector('KeePassFile > Root > Group');
if (rootGroup == null) {
this.result.errorMessage = 'Missing `KeePassFile > Root > Group` node.';
this.result.success = false;
return Promise.resolve(this.result);
}
this.traverse(rootGroup, true, '');
if (this.organization) {
this.moveFoldersToCollections(this.result);
}
this.result.success = true;
return Promise.resolve(this.result);
}
traverse(node: Element, isRootNode: boolean, groupPrefixName: string) {
const folderIndex = this.result.folders.length;
let groupName = groupPrefixName;
if (!isRootNode) {
if (groupName !== '') {
groupName += '/';
}
const nameEl = this.querySelectorDirectChild(node, 'Name');
groupName += nameEl == null ? '-' : nameEl.textContent;
const folder = new FolderView();
folder.name = groupName;
this.result.folders.push(folder);
}
this.querySelectorAllDirectChild(node, 'Entry').forEach(entry => {
const cipherIndex = this.result.ciphers.length;
const cipher = this.initLoginCipher();
this.querySelectorAllDirectChild(entry, 'String').forEach(entryString => {
const valueEl = this.querySelectorDirectChild(entryString, 'Value');
const value = valueEl != null ? valueEl.textContent : null;
if (this.isNullOrWhitespace(value)) {
return;
}
const keyEl = this.querySelectorDirectChild(entryString, 'Key');
const key = keyEl != null ? keyEl.textContent : null;
if (key === 'URL') {
cipher.login.uris = this.makeUriArray(value);
} else if (key === 'UserName') {
cipher.login.username = value;
} else if (key === 'Password') {
cipher.login.password = value;
} else if (key === 'otp') {
cipher.login.totp = value.replace('key=', '');
} else if (key === 'Title') {
cipher.name = value;
} else if (key === 'Notes') {
cipher.notes += (value + '\n');
} else {
let type = FieldType.Text;
const attrs = (valueEl.attributes as any);
if (attrs.length > 0 && attrs.ProtectInMemory != null &&
attrs.ProtectInMemory.value === 'True') {
type = FieldType.Hidden;
}
this.processKvp(cipher, key, value, type);
}
});
this.cleanupCipher(cipher);
this.result.ciphers.push(cipher);
if (!isRootNode) {
this.result.folderRelationships.push([cipherIndex, folderIndex]);
}
});
this.querySelectorAllDirectChild(node, 'Group').forEach(group => {
this.traverse(group, false, groupName);
});
}
}

View File

@@ -0,0 +1,42 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
export class KeePassXCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
if (this.isNullOrWhitespace(value.Title)) {
return;
}
value.Group = !this.isNullOrWhitespace(value.Group) && value.Group.startsWith('Root/') ?
value.Group.replace('Root/', '') : value.Group;
const groupName = !this.isNullOrWhitespace(value.Group) ? value.Group : null;
this.processFolder(result, groupName);
const cipher = this.initLoginCipher();
cipher.notes = this.getValueOrDefault(value.Notes);
cipher.name = this.getValueOrDefault(value.Title, '--');
cipher.login.username = this.getValueOrDefault(value.Username);
cipher.login.password = this.getValueOrDefault(value.Password);
cipher.login.uris = this.makeUriArray(value.URL);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
if (this.organization) {
this.moveFoldersToCollections(result);
}
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,48 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
import { FolderView } from '../models/view/folderView';
export class KeeperCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, false);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
if (value.length < 6) {
return;
}
this.processFolder(result, value[0]);
const cipher = this.initLoginCipher();
cipher.notes = this.getValueOrDefault(value[5]) + '\n';
cipher.name = this.getValueOrDefault(value[1], '--');
cipher.login.username = this.getValueOrDefault(value[2]);
cipher.login.password = this.getValueOrDefault(value[3]);
cipher.login.uris = this.makeUriArray(value[4]);
if (value.length > 7) {
// we have some custom fields.
for (let i = 7; i < value.length; i = i + 2) {
this.processKvp(cipher, value[i], value[i + 1]);
}
}
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
if (this.organization) {
this.moveFoldersToCollections(result);
}
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,276 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
import { CardView } from '../models/view/cardView';
import { CipherView } from '../models/view/cipherView';
import { FolderView } from '../models/view/folderView';
import { IdentityView } from '../models/view/identityView';
import { LoginView } from '../models/view/loginView';
import { SecureNoteView } from '../models/view/secureNoteView';
import { CipherType } from '../enums/cipherType';
import { SecureNoteType } from '../enums/secureNoteType';
export class LastPassCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach((value, index) => {
const cipherIndex = result.ciphers.length;
let folderIndex = result.folders.length;
let grouping = value.grouping;
if (grouping != null) {
grouping = grouping.replace(/\\/g, '/').replace(/[\x00-\x1F\x7F-\x9F]/g, '');
}
const hasFolder = this.getValueOrDefault(grouping, '(none)') !== '(none)';
let addFolder = hasFolder;
if (hasFolder) {
for (let i = 0; i < result.folders.length; i++) {
if (result.folders[i].name === grouping) {
addFolder = false;
folderIndex = i;
break;
}
}
}
const cipher = this.buildBaseCipher(value);
if (cipher.type === CipherType.Login) {
cipher.notes = this.getValueOrDefault(value.extra);
cipher.login = new LoginView();
cipher.login.uris = this.makeUriArray(value.url);
cipher.login.username = this.getValueOrDefault(value.username);
cipher.login.password = this.getValueOrDefault(value.password);
cipher.login.totp = this.getValueOrDefault(value.totp);
} else if (cipher.type === CipherType.SecureNote) {
this.parseSecureNote(value, cipher);
} else if (cipher.type === CipherType.Card) {
cipher.card = this.parseCard(value);
cipher.notes = this.getValueOrDefault(value.notes);
} else if (cipher.type === CipherType.Identity) {
cipher.identity = this.parseIdentity(value);
cipher.notes = this.getValueOrDefault(value.notes);
if (!this.isNullOrWhitespace(value.ccnum)) {
// there is a card on this identity too
const cardCipher = this.buildBaseCipher(value);
cardCipher.identity = null;
cardCipher.type = CipherType.Card;
cardCipher.card = this.parseCard(value);
result.ciphers.push(cardCipher);
}
}
result.ciphers.push(cipher);
if (addFolder) {
const f = new FolderView();
f.name = grouping;
result.folders.push(f);
}
if (hasFolder) {
result.folderRelationships.push([cipherIndex, folderIndex]);
}
});
if (this.organization) {
this.moveFoldersToCollections(result);
}
result.success = true;
return Promise.resolve(result);
}
private buildBaseCipher(value: any) {
const cipher = new CipherView();
if (value.hasOwnProperty('profilename') && value.hasOwnProperty('profilelanguage')) {
// form fill
cipher.favorite = false;
cipher.name = this.getValueOrDefault(value.profilename, '--');
cipher.type = CipherType.Card;
if (!this.isNullOrWhitespace(value.title) || !this.isNullOrWhitespace(value.firstname) ||
!this.isNullOrWhitespace(value.lastname) || !this.isNullOrWhitespace(value.address1) ||
!this.isNullOrWhitespace(value.phone) || !this.isNullOrWhitespace(value.username) ||
!this.isNullOrWhitespace(value.email)) {
cipher.type = CipherType.Identity;
}
} else {
// site or secure note
cipher.favorite = !this.organization && this.getValueOrDefault(value.fav, '0') === '1';
cipher.name = this.getValueOrDefault(value.name, '--');
cipher.type = value.url === 'http://sn' ? CipherType.SecureNote : CipherType.Login;
}
return cipher;
}
private parseCard(value: any): CardView {
const card = new CardView();
card.cardholderName = this.getValueOrDefault(value.ccname);
card.number = this.getValueOrDefault(value.ccnum);
card.code = this.getValueOrDefault(value.cccsc);
card.brand = this.getCardBrand(value.ccnum);
if (!this.isNullOrWhitespace(value.ccexp) && value.ccexp.indexOf('-') > -1) {
const ccexpParts = (value.ccexp as string).split('-');
if (ccexpParts.length > 1) {
card.expYear = ccexpParts[0];
card.expMonth = ccexpParts[1];
if (card.expMonth.length === 2 && card.expMonth[0] === '0') {
card.expMonth = card.expMonth[1];
}
}
}
return card;
}
private parseIdentity(value: any): IdentityView {
const identity = new IdentityView();
identity.title = this.getValueOrDefault(value.title);
identity.firstName = this.getValueOrDefault(value.firstname);
identity.middleName = this.getValueOrDefault(value.middlename);
identity.lastName = this.getValueOrDefault(value.lastname);
identity.username = this.getValueOrDefault(value.username);
identity.company = this.getValueOrDefault(value.company);
identity.ssn = this.getValueOrDefault(value.ssn);
identity.address1 = this.getValueOrDefault(value.address1);
identity.address2 = this.getValueOrDefault(value.address2);
identity.address3 = this.getValueOrDefault(value.address3);
identity.city = this.getValueOrDefault(value.city);
identity.state = this.getValueOrDefault(value.state);
identity.postalCode = this.getValueOrDefault(value.zip);
identity.country = this.getValueOrDefault(value.country);
identity.email = this.getValueOrDefault(value.email);
identity.phone = this.getValueOrDefault(value.phone);
if (!this.isNullOrWhitespace(identity.title)) {
identity.title = identity.title.charAt(0).toUpperCase() + identity.title.slice(1);
}
return identity;
}
private parseSecureNote(value: any, cipher: CipherView) {
const extraParts = this.splitNewLine(value.extra);
let processedNote = false;
if (extraParts.length) {
const typeParts = extraParts[0].split(':');
if (typeParts.length > 1 && typeParts[0] === 'NoteType' &&
(typeParts[1] === 'Credit Card' || typeParts[1] === 'Address')) {
if (typeParts[1] === 'Credit Card') {
const mappedData = this.parseSecureNoteMapping<CardView>(cipher, extraParts, {
'Number': 'number',
'Name on Card': 'cardholderName',
'Security Code': 'code',
// LP provides date in a format like 'June,2020'
// Store in expMonth, then parse and modify
'Expiration Date': 'expMonth',
});
if (this.isNullOrWhitespace(mappedData.expMonth) || mappedData.expMonth === ',') {
// No expiration data
mappedData.expMonth = undefined;
} else {
const [monthString, year] = mappedData.expMonth.split(',');
// Parse month name into number
if (!this.isNullOrWhitespace(monthString)) {
const month = new Date(Date.parse(monthString.trim() + ' 1, 2012')).getMonth() + 1;
if (isNaN(month)) {
mappedData.expMonth = undefined;
} else {
mappedData.expMonth = month.toString();
}
} else {
mappedData.expMonth = undefined;
}
if (!this.isNullOrWhitespace(year)) {
mappedData.expYear = year;
}
}
cipher.type = CipherType.Card;
cipher.card = mappedData;
} else if (typeParts[1] === 'Address') {
const mappedData = this.parseSecureNoteMapping<IdentityView>(cipher, extraParts, {
'Title': 'title',
'First Name': 'firstName',
'Last Name': 'lastName',
'Middle Name': 'middleName',
'Company': 'company',
'Address 1': 'address1',
'Address 2': 'address2',
'Address 3': 'address3',
'City / Town': 'city',
'State': 'state',
'Zip / Postal Code': 'postalCode',
'Country': 'country',
'Email Address': 'email',
'Username': 'username',
});
cipher.type = CipherType.Identity;
cipher.identity = mappedData;
}
processedNote = true;
}
}
if (!processedNote) {
cipher.secureNote = new SecureNoteView();
cipher.secureNote.type = SecureNoteType.Generic;
cipher.notes = this.getValueOrDefault(value.extra);
}
}
private parseSecureNoteMapping<T>(cipher: CipherView, extraParts: string[], map: any): T {
const dataObj: any = {};
let processingNotes = false;
extraParts.forEach(extraPart => {
let key: string = null;
let val: string = null;
if (!processingNotes) {
if (this.isNullOrWhitespace(extraPart)) {
return;
}
const colonIndex = extraPart.indexOf(':');
if (colonIndex === -1) {
key = extraPart;
} else {
key = extraPart.substring(0, colonIndex);
if (extraPart.length > colonIndex) {
val = extraPart.substring(colonIndex + 1);
}
}
if (this.isNullOrWhitespace(key) || this.isNullOrWhitespace(val) || key === 'NoteType') {
return;
}
}
if (processingNotes) {
cipher.notes += ('\n' + extraPart);
} else if (key === 'Notes') {
if (!this.isNullOrWhitespace(cipher.notes)) {
cipher.notes += ('\n' + val);
} else {
cipher.notes = val;
}
processingNotes = true;
} else if (map.hasOwnProperty(key)) {
dataObj[map[key]] = val;
} else {
this.processKvp(cipher, key, val);
}
});
return dataObj;
}
}

View File

@@ -0,0 +1,31 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
export class LogMeOnceCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, false);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
if (value.length < 4) {
return;
}
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(value[0], '--');
cipher.login.username = this.getValueOrDefault(value[2]);
cipher.login.password = this.getValueOrDefault(value[3]);
cipher.login.uris = this.makeUriArray(value[1]);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,29 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
export class MeldiumCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(value.DisplayName, '--');
cipher.notes = this.getValueOrDefault(value.Notes);
cipher.login.username = this.getValueOrDefault(value.UserName);
cipher.login.password = this.getValueOrDefault(value.Password);
cipher.login.uris = this.makeUriArray(value.Url);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,62 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
import { CipherType } from '../enums/cipherType';
import { SecureNoteType } from '../enums/secureNoteType';
import { SecureNoteView } from '../models/view/secureNoteView';
export class MSecureCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, false);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
if (value.length < 3) {
return;
}
const folderName = this.getValueOrDefault(value[0], 'Unassigned') !== 'Unassigned' ? value[0] : null;
this.processFolder(result, folderName);
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(value[2], '--');
if (value[1] === 'Web Logins' || value[1] === 'Login') {
cipher.login.uris = this.makeUriArray(value[4]);
cipher.login.username = this.getValueOrDefault(value[5]);
cipher.login.password = this.getValueOrDefault(value[6]);
cipher.notes = !this.isNullOrWhitespace(value[3]) ? value[3].split('\\n').join('\n') : null;
} else if (value.length > 3) {
cipher.type = CipherType.SecureNote;
cipher.secureNote = new SecureNoteView();
cipher.secureNote.type = SecureNoteType.Generic;
for (let i = 3; i < value.length; i++) {
if (!this.isNullOrWhitespace(value[i])) {
cipher.notes += (value[i] + '\n');
}
}
}
if (!this.isNullOrWhitespace(value[1]) && cipher.type !== CipherType.Login) {
cipher.name = value[1] + ': ' + cipher.name;
}
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
if (this.organization) {
this.moveFoldersToCollections(result);
}
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,76 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { CipherType } from '../enums/cipherType';
import { SecureNoteType } from '../enums/secureNoteType';
import { CardView } from '../models/view/cardView';
import { IdentityView } from '../models/view/identityView';
import { SecureNoteView } from '../models/view/secureNoteView';
import { ImportResult } from '../models/domain/importResult';
export class MykiCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(value.nickname, '--');
cipher.notes = this.getValueOrDefault(value.additionalInfo);
if (value.url !== undefined) {
// Accounts
cipher.login.uris = this.makeUriArray(value.url);
cipher.login.username = this.getValueOrDefault(value.username);
cipher.login.password = this.getValueOrDefault(value.password);
cipher.login.totp = this.getValueOrDefault(value.twoFactAuthToken);
} else if (value.cardNumber !== undefined) {
// Cards
cipher.card = new CardView();
cipher.type = CipherType.Card;
cipher.card.cardholderName = this.getValueOrDefault(value.cardName);
cipher.card.number = this.getValueOrDefault(value.cardNumber);
cipher.card.brand = this.getCardBrand(cipher.card.number);
cipher.card.expMonth = this.getValueOrDefault(value.exp_month);
cipher.card.expYear = this.getValueOrDefault(value.exp_year);
cipher.card.code = this.getValueOrDefault(value.cvv);
} else if (value.firstName !== undefined) {
// Identities
cipher.identity = new IdentityView();
cipher.type = CipherType.Identity;
cipher.identity.title = this.getValueOrDefault(value.title);
cipher.identity.firstName = this.getValueOrDefault(value.firstName);
cipher.identity.middleName = this.getValueOrDefault(value.middleName);
cipher.identity.lastName = this.getValueOrDefault(value.lastName);
cipher.identity.phone = this.getValueOrDefault(value.number);
cipher.identity.email = this.getValueOrDefault(value.email);
cipher.identity.address1 = this.getValueOrDefault(value.firstAddressLine);
cipher.identity.address2 = this.getValueOrDefault(value.secondAddressLine);
cipher.identity.city = this.getValueOrDefault(value.city);
cipher.identity.country = this.getValueOrDefault(value.country);
cipher.identity.postalCode = this.getValueOrDefault(value.zipCode);
} else if (value.content !== undefined) {
// Notes
cipher.secureNote = new SecureNoteView();
cipher.type = CipherType.SecureNote;
cipher.secureNote.type = SecureNoteType.Generic;
cipher.name = this.getValueOrDefault(value.title, '--');
cipher.notes = this.getValueOrDefault(value.content);
} else {
return;
}
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
}

View File

@@ -0,0 +1,149 @@
import { BaseImporter } from './baseImporter';
import { Importer } from './importer';
import { ImportResult } from '../models/domain/importResult';
import { CipherView } from '../models/view/cipherView';
import { LoginView } from '../models/view/loginView';
import { CipherType } from '../enums/cipherType';
import { SecureNoteType } from '../enums/secureNoteType';
type nodePassCsvParsed = {
name: string;
url: string;
username: string;
password: string;
note: string;
cardholdername: string;
cardnumber: string;
cvc: string;
expirydate: string;
zipcode: string;
folder: string;
full_name: string;
phone_number: string;
email: string;
address1: string;
address2: string;
city: string;
country: string;
state: string;
};
export class NordPassCsvImporter extends BaseImporter implements Importer {
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results: nodePassCsvParsed[] = this.parseCsv(data, true);
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(record => {
const recordType = this.evaluateType(record);
if (recordType === undefined) {
return;
}
if (!this.organization) {
this.processFolder(result, record.folder);
}
const cipher = new CipherView();
cipher.name = this.getValueOrDefault(record.name, '--');
cipher.notes = this.getValueOrDefault(record.note);
switch (recordType) {
case CipherType.Login:
cipher.type = CipherType.Login;
cipher.login = new LoginView();
cipher.login.username = this.getValueOrDefault(record.username);
cipher.login.password = this.getValueOrDefault(record.password);
cipher.login.uris = this.makeUriArray(record.url);
break;
case CipherType.Card:
cipher.type = CipherType.Card;
cipher.card.cardholderName = this.getValueOrDefault(record.cardholdername);
cipher.card.number = this.getValueOrDefault(record.cardnumber);
cipher.card.code = this.getValueOrDefault(record.cvc);
cipher.card.brand = this.getCardBrand(cipher.card.number);
this.setCardExpiration(cipher, record.expirydate);
break;
case CipherType.Identity:
cipher.type = CipherType.Identity;
this.processName(cipher, this.getValueOrDefault(record.full_name));
cipher.identity.address1 = this.getValueOrDefault(record.address1);
cipher.identity.address2 = this.getValueOrDefault(record.address2);
cipher.identity.city = this.getValueOrDefault(record.city);
cipher.identity.state = this.getValueOrDefault(record.state);
cipher.identity.postalCode = this.getValueOrDefault(record.zipcode);
cipher.identity.country = this.getValueOrDefault(record.country);
if (cipher.identity.country != null) {
cipher.identity.country = cipher.identity.country.toUpperCase();
}
cipher.identity.email = this.getValueOrDefault(record.email);
cipher.identity.phone = this.getValueOrDefault(record.phone_number);
break;
case CipherType.SecureNote:
cipher.type = CipherType.SecureNote;
cipher.secureNote.type = SecureNoteType.Generic;
break;
default:
break;
}
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
if (this.organization) {
this.moveFoldersToCollections(result);
}
result.success = true;
return Promise.resolve(result);
}
private evaluateType(record: nodePassCsvParsed): CipherType {
if (!this.isNullOrWhitespace(record.username)) {
return CipherType.Login;
}
if (!this.isNullOrWhitespace(record.cardnumber)) {
return CipherType.Card;
}
if (!this.isNullOrWhitespace(record.full_name)) {
return CipherType.Identity;
}
if (!this.isNullOrWhitespace(record.note)) {
return CipherType.SecureNote;
}
return undefined;
}
private processName(cipher: CipherView, fullName: string) {
if (this.isNullOrWhitespace(fullName)) {
return;
}
const nameParts = fullName.split(' ');
if (nameParts.length > 0) {
cipher.identity.firstName = this.getValueOrDefault(nameParts[0]);
}
if (nameParts.length === 2) {
cipher.identity.lastName = this.getValueOrDefault(nameParts[1]);
} else if (nameParts.length >= 3) {
cipher.identity.middleName = this.getValueOrDefault(nameParts[1]);
cipher.identity.lastName = nameParts.slice(2, nameParts.length).join(' ');
}
}
}

View File

@@ -0,0 +1,8 @@
import { CipherView } from '../../models/view';
export class CipherImportContext {
lowerProperty: string;
constructor(public importRecord: any, public property: string, public cipher: CipherView) {
this.lowerProperty = property.toLowerCase();
}
}

View File

@@ -0,0 +1,248 @@
import { BaseImporter } from '../baseImporter';
import { Importer } from '../importer';
import { ImportResult } from '../../models/domain/importResult';
import { CardView } from '../../models/view/cardView';
import { CipherView } from '../../models/view/cipherView';
import { IdentityView } from '../../models/view/identityView';
import { PasswordHistoryView } from '../../models/view/passwordHistoryView';
import { SecureNoteView } from '../../models/view/secureNoteView';
import { CipherType } from '../../enums/cipherType';
import { FieldType } from '../../enums/fieldType';
import { SecureNoteType } from '../../enums/secureNoteType';
export class OnePassword1PifImporter extends BaseImporter implements Importer {
result = new ImportResult();
parse(data: string): Promise<ImportResult> {
data.split(this.newLineRegex).forEach(line => {
if (this.isNullOrWhitespace(line) || line[0] !== '{') {
return;
}
const item = JSON.parse(line);
if (item.trashed === true) {
return;
}
const cipher = this.initLoginCipher();
if (this.isNullOrWhitespace(item.hmac)) {
this.processStandardItem(item, cipher);
} else {
this.processWinOpVaultItem(item, cipher);
}
this.convertToNoteIfNeeded(cipher);
this.cleanupCipher(cipher);
this.result.ciphers.push(cipher);
});
this.result.success = true;
return Promise.resolve(this.result);
}
private processWinOpVaultItem(item: any, cipher: CipherView) {
if (item.overview != null) {
cipher.name = this.getValueOrDefault(item.overview.title);
if (item.overview.URLs != null) {
const urls: string[] = [];
item.overview.URLs.forEach((url: any) => {
if (!this.isNullOrWhitespace(url.u)) {
urls.push(url.u);
}
});
cipher.login.uris = this.makeUriArray(urls);
}
}
if (item.details != null) {
if (item.details.passwordHistory != null) {
this.parsePasswordHistory(item.details.passwordHistory, cipher);
}
if (!this.isNullOrWhitespace(item.details.ccnum) || !this.isNullOrWhitespace(item.details.cvv)) {
cipher.type = CipherType.Card;
cipher.card = new CardView();
} else if (!this.isNullOrWhitespace(item.details.firstname) ||
!this.isNullOrWhitespace(item.details.address1)) {
cipher.type = CipherType.Identity;
cipher.identity = new IdentityView();
}
if (cipher.type === CipherType.Login && !this.isNullOrWhitespace(item.details.password)) {
cipher.login.password = item.details.password;
}
if (!this.isNullOrWhitespace(item.details.notesPlain)) {
cipher.notes = item.details.notesPlain.split(this.newLineRegex).join('\n') + '\n';
}
if (item.details.fields != null) {
this.parseFields(item.details.fields, cipher, 'designation', 'value', 'name');
}
if (item.details.sections != null) {
item.details.sections.forEach((section: any) => {
if (section.fields != null) {
this.parseFields(section.fields, cipher, 'n', 'v', 't');
}
});
}
}
}
private processStandardItem(item: any, cipher: CipherView) {
cipher.favorite = item.openContents && item.openContents.faveIndex ? true : false;
cipher.name = this.getValueOrDefault(item.title);
if (item.typeName === 'securenotes.SecureNote') {
cipher.type = CipherType.SecureNote;
cipher.secureNote = new SecureNoteView();
cipher.secureNote.type = SecureNoteType.Generic;
} else if (item.typeName === 'wallet.financial.CreditCard') {
cipher.type = CipherType.Card;
cipher.card = new CardView();
} else if (item.typeName === 'identities.Identity') {
cipher.type = CipherType.Identity;
cipher.identity = new IdentityView();
} else {
cipher.login.uris = this.makeUriArray(item.location);
}
if (item.secureContents != null) {
if (item.secureContents.passwordHistory != null) {
this.parsePasswordHistory(item.secureContents.passwordHistory, cipher);
}
if (!this.isNullOrWhitespace(item.secureContents.notesPlain)) {
cipher.notes = item.secureContents.notesPlain.split(this.newLineRegex).join('\n') + '\n';
}
if (cipher.type === CipherType.Login) {
if (!this.isNullOrWhitespace(item.secureContents.password)) {
cipher.login.password = item.secureContents.password;
}
if (item.secureContents.URLs != null) {
const urls: string[] = [];
item.secureContents.URLs.forEach((u: any) => {
if (!this.isNullOrWhitespace(u.url)) {
urls.push(u.url);
}
});
if (urls.length > 0) {
cipher.login.uris = this.makeUriArray(urls);
}
}
}
if (item.secureContents.fields != null) {
this.parseFields(item.secureContents.fields, cipher, 'designation', 'value', 'name');
}
if (item.secureContents.sections != null) {
item.secureContents.sections.forEach((section: any) => {
if (section.fields != null) {
this.parseFields(section.fields, cipher, 'n', 'v', 't');
}
});
}
}
}
private parsePasswordHistory(items: any[], cipher: CipherView) {
const maxSize = items.length > 5 ? 5 : items.length;
cipher.passwordHistory = items
.filter((h: any) => !this.isNullOrWhitespace(h.value) && h.time != null)
.sort((a, b) => b.time - a.time)
.slice(0, maxSize)
.map((h: any) => {
const ph = new PasswordHistoryView();
ph.password = h.value;
ph.lastUsedDate = new Date(('' + h.time).length >= 13 ? h.time : h.time * 1000);
return ph;
});
}
private parseFields(fields: any[], cipher: CipherView, designationKey: string, valueKey: string, nameKey: string) {
fields.forEach((field: any) => {
if (field[valueKey] == null || field[valueKey].toString().trim() === '') {
return;
}
const fieldValue = field[valueKey].toString();
const fieldDesignation = field[designationKey] != null ? field[designationKey].toString() : null;
if (cipher.type === CipherType.Login) {
if (this.isNullOrWhitespace(cipher.login.username) && fieldDesignation === 'username') {
cipher.login.username = fieldValue;
return;
} else if (this.isNullOrWhitespace(cipher.login.password) && fieldDesignation === 'password') {
cipher.login.password = fieldValue;
return;
} else if (this.isNullOrWhitespace(cipher.login.totp) && fieldDesignation != null &&
fieldDesignation.startsWith('TOTP_')) {
cipher.login.totp = fieldValue;
return;
}
} else if (cipher.type === CipherType.Card) {
if (this.isNullOrWhitespace(cipher.card.number) && fieldDesignation === 'ccnum') {
cipher.card.number = fieldValue;
cipher.card.brand = this.getCardBrand(fieldValue);
return;
} else if (this.isNullOrWhitespace(cipher.card.code) && fieldDesignation === 'cvv') {
cipher.card.code = fieldValue;
return;
} else if (this.isNullOrWhitespace(cipher.card.cardholderName) && fieldDesignation === 'cardholder') {
cipher.card.cardholderName = fieldValue;
return;
} else if (this.isNullOrWhitespace(cipher.card.expiration) && fieldDesignation === 'expiry' &&
fieldValue.length === 6) {
cipher.card.expMonth = (fieldValue as string).substr(4, 2);
if (cipher.card.expMonth[0] === '0') {
cipher.card.expMonth = cipher.card.expMonth.substr(1, 1);
}
cipher.card.expYear = (fieldValue as string).substr(0, 4);
return;
} else if (fieldDesignation === 'type') {
// Skip since brand was determined from number above
return;
}
} else if (cipher.type === CipherType.Identity) {
const identity = cipher.identity;
if (this.isNullOrWhitespace(identity.firstName) && fieldDesignation === 'firstname') {
identity.firstName = fieldValue;
return;
} else if (this.isNullOrWhitespace(identity.lastName) && fieldDesignation === 'lastname') {
identity.lastName = fieldValue;
return;
} else if (this.isNullOrWhitespace(identity.middleName) && fieldDesignation === 'initial') {
identity.middleName = fieldValue;
return;
} else if (this.isNullOrWhitespace(identity.phone) && fieldDesignation === 'defphone') {
identity.phone = fieldValue;
return;
} else if (this.isNullOrWhitespace(identity.company) && fieldDesignation === 'company') {
identity.company = fieldValue;
return;
} else if (this.isNullOrWhitespace(identity.email) && fieldDesignation === 'email') {
identity.email = fieldValue;
return;
} else if (this.isNullOrWhitespace(identity.username) && fieldDesignation === 'username') {
identity.username = fieldValue;
return;
} else if (fieldDesignation === 'address') {
// fieldValue is an object casted into a string, so access the plain value instead
const { street, city, country, zip } = field[valueKey];
identity.address1 = this.getValueOrDefault(street);
identity.city = this.getValueOrDefault(city);
if (!this.isNullOrWhitespace(country)) {
identity.country = country.toUpperCase();
}
identity.postalCode = this.getValueOrDefault(zip);
return;
}
}
const fieldName = this.isNullOrWhitespace(field[nameKey]) ? 'no_name' : field[nameKey];
if (fieldName === 'password' && cipher.passwordHistory != null &&
cipher.passwordHistory.some(h => h.password === fieldValue)) {
return;
}
const fieldType = field.k === 'concealed' ? FieldType.Hidden : FieldType.Text;
this.processKvp(cipher, fieldName, fieldValue, fieldType);
});
}
}

View File

@@ -0,0 +1,288 @@
import { ImportResult } from '../../models/domain/importResult';
import { BaseImporter } from '../baseImporter';
import { Importer } from '../importer';
import { CipherType } from '../../enums/cipherType';
import { FieldType } from '../../enums/fieldType';
import { CipherView } from '../../models/view';
import { CipherImportContext } from './cipherImportContext';
export const IgnoredProperties = ['ainfo', 'autosubmit', 'notesplain', 'ps', 'scope', 'tags', 'title', 'uuid', 'notes'];
export abstract class OnePasswordCsvImporter extends BaseImporter implements Importer {
protected loginPropertyParsers = [this.setLoginUsername, this.setLoginPassword, this.setLoginUris];
protected creditCardPropertyParsers = [this.setCreditCardNumber, this.setCreditCardVerification, this.setCreditCardCardholderName, this.setCreditCardExpiry];
protected identityPropertyParsers = [this.setIdentityFirstName, this.setIdentityInitial, this.setIdentityLastName, this.setIdentityUserName, this.setIdentityEmail, this.setIdentityPhone, this.setIdentityCompany];
abstract setCipherType(value: any, cipher: CipherView): void;
parse(data: string): Promise<ImportResult> {
const result = new ImportResult();
const results = this.parseCsv(data, true, {
quoteChar: '"',
escapeChar: '\\',
});
if (results == null) {
result.success = false;
return Promise.resolve(result);
}
results.forEach(value => {
if (this.isNullOrWhitespace(this.getProp(value, 'title'))) {
return;
}
const cipher = this.initLoginCipher();
cipher.name = this.getValueOrDefault(this.getProp(value, 'title'), '--');
this.setNotes(value, cipher);
this.setCipherType(value, cipher);
let altUsername: string = null;
for (const property in value) {
if (!value.hasOwnProperty(property) || this.isNullOrWhitespace(value[property])) {
continue;
}
const context = new CipherImportContext(value, property, cipher);
if (cipher.type === CipherType.Login && this.setKnownLoginValue(context)) {
continue;
} else if (cipher.type === CipherType.Card && this.setKnownCreditCardValue(context)) {
continue;
} else if (cipher.type === CipherType.Identity && this.setKnownIdentityValue(context)) {
continue;
}
altUsername = this.setUnknownValue(context, altUsername);
}
if (cipher.type === CipherType.Login && !this.isNullOrWhitespace(altUsername) &&
this.isNullOrWhitespace(cipher.login.username) && altUsername.indexOf('://') === -1) {
cipher.login.username = altUsername;
}
this.convertToNoteIfNeeded(cipher);
this.cleanupCipher(cipher);
result.ciphers.push(cipher);
});
result.success = true;
return Promise.resolve(result);
}
protected getProp(obj: any, name: string): any {
const lowerObj = Object.entries(obj).reduce((agg: any, entry: [string, any]) => {
agg[entry[0].toLowerCase()] = entry[1];
return agg;
}, {});
return lowerObj[name.toLowerCase()];
}
protected getPropByRegexp(obj: any, regexp: RegExp): any {
const matchingKeys = Object.keys(obj).reduce((agg: string[], key: string) => {
if (key.match(regexp)) {
agg.push(key);
}
return agg;
}, []);
if (matchingKeys.length === 0) {
return null;
} else {
return obj[matchingKeys[0]];
}
}
protected getPropIncluding(obj: any, name: string): any {
const includesMap = Object.keys(obj).reduce((agg: string[], entry: string) => {
if (entry.toLowerCase().includes(name.toLowerCase())) {
agg.push(entry);
}
return agg;
}, []);
if (includesMap.length === 0) {
return null;
} else {
return obj[includesMap[0]];
}
}
protected setNotes(importRecord: any, cipher: CipherView) {
cipher.notes = this.getValueOrDefault(this.getProp(importRecord, 'notesPlain'), '') + '\n' +
this.getValueOrDefault(this.getProp(importRecord, 'notes'), '') + '\n';
cipher.notes.trim();
}
protected setKnownLoginValue(context: CipherImportContext): boolean {
return this.loginPropertyParsers.reduce((agg: boolean, func) => {
if (!agg) {
agg = func.bind(this)(context);
}
return agg;
}, false);
}
protected setKnownCreditCardValue(context: CipherImportContext): boolean {
return this.creditCardPropertyParsers.reduce((agg: boolean, func) => {
if (!agg) {
agg = func.bind(this)(context);
}
return agg;
}, false);
}
protected setKnownIdentityValue(context: CipherImportContext): boolean {
return this.identityPropertyParsers.reduce((agg: boolean, func) => {
if (!agg) {
agg = func.bind(this)(context);
}
return agg;
}, false);
}
protected setUnknownValue(context: CipherImportContext, altUsername: string): string {
if (IgnoredProperties.indexOf(context.lowerProperty) === -1 && !context.lowerProperty.startsWith('section:') &&
!context.lowerProperty.startsWith('section ')) {
if (altUsername == null && context.lowerProperty === 'email') {
return context.importRecord[context.property];
}
else if (context.lowerProperty === 'created date' || context.lowerProperty === 'modified date') {
const readableDate = new Date(parseInt(context.importRecord[context.property], 10) * 1000).toUTCString();
this.processKvp(context.cipher, '1Password ' + context.property, readableDate);
return null;
}
if (context.lowerProperty.includes('password') || context.lowerProperty.includes('key') || context.lowerProperty.includes('secret')) {
this.processKvp(context.cipher, context.property, context.importRecord[context.property], FieldType.Hidden);
} else {
this.processKvp(context.cipher, context.property, context.importRecord[context.property]);
}
}
return null;
}
protected setIdentityFirstName(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.identity.firstName) && context.lowerProperty.includes('first name')) {
context.cipher.identity.firstName = context.importRecord[context.property];
return true;
}
return false;
}
protected setIdentityInitial(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.identity.middleName) && context.lowerProperty.includes('initial')) {
context.cipher.identity.middleName = context.importRecord[context.property];
return true;
}
return false;
}
protected setIdentityLastName(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.identity.lastName) && context.lowerProperty.includes('last name')) {
context.cipher.identity.lastName = context.importRecord[context.property];
return true;
}
return false;
}
protected setIdentityUserName(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.identity.username) && context.lowerProperty.includes('username')) {
context.cipher.identity.username = context.importRecord[context.property];
return true;
}
return false;
}
protected setIdentityCompany(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.identity.company) && context.lowerProperty.includes('company')) {
context.cipher.identity.company = context.importRecord[context.property];
return true;
}
return false;
}
protected setIdentityPhone(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.identity.phone) && context.lowerProperty.includes('default phone')) {
context.cipher.identity.phone = context.importRecord[context.property];
return true;
}
return false;
}
protected setIdentityEmail(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.identity.email) && context.lowerProperty.includes('email')) {
context.cipher.identity.email = context.importRecord[context.property];
return true;
}
return false;
}
protected setCreditCardNumber(context: CipherImportContext): boolean {
if (this.isNullOrWhitespace(context.cipher.card.number) && context.lowerProperty.includes('number')) {
context.cipher.card.number = context.importRecord[context.property];
context.cipher.card.brand = this.getCardBrand(context.cipher.card.number);
return true;
}
return false;
}
protected setCreditCardVerification(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.card.code) && context.lowerProperty.includes('verification number')) {
context.cipher.card.code = context.importRecord[context.property];
return true;
}
return false;
}
protected setCreditCardCardholderName(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.card.cardholderName) && context.lowerProperty.includes('cardholder name')) {
context.cipher.card.cardholderName = context.importRecord[context.property];
return true;
}
return false;
}
protected setCreditCardExpiry(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.card.expiration) && context.lowerProperty.includes('expiry date') &&
context.importRecord[context.property].length === 7) {
context.cipher.card.expMonth = (context.importRecord[context.property] as string).substr(0, 2);
if (context.cipher.card.expMonth[0] === '0') {
context.cipher.card.expMonth = context.cipher.card.expMonth.substr(1, 1);
}
context.cipher.card.expYear = (context.importRecord[context.property] as string).substr(3, 4);
return true;
}
return false;
}
protected setLoginPassword(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.login.password) && context.lowerProperty === 'password') {
context.cipher.login.password = context.importRecord[context.property];
return true;
}
return false;
}
protected setLoginUsername(context: CipherImportContext) {
if (this.isNullOrWhitespace(context.cipher.login.username) && context.lowerProperty === 'username') {
context.cipher.login.username = context.importRecord[context.property];
return true;
}
return false;
}
protected setLoginUris(context: CipherImportContext) {
if ((context.cipher.login.uris == null || context.cipher.login.uris.length === 0) && context.lowerProperty === 'urls') {
const urls = context.importRecord[context.property].split(this.newLineRegex);
context.cipher.login.uris = this.makeUriArray(urls);
return true;
} else if ((context.lowerProperty === 'url')) {
if (context.cipher.login.uris == null) {
context.cipher.login.uris = [];
}
context.cipher.login.uris.concat(this.makeUriArray(context.importRecord[context.property]));
return true;
}
return false;
}
}

View File

@@ -0,0 +1,28 @@
import { Importer } from '../importer';
import { IgnoredProperties, OnePasswordCsvImporter } from './onepasswordCsvImporter';
import { CipherType } from '../../enums/cipherType';
import { CardView, CipherView, IdentityView } from '../../models/view';
export class OnePasswordMacCsvImporter extends OnePasswordCsvImporter implements Importer {
setCipherType(value: any, cipher: CipherView) {
const onePassType = this.getValueOrDefault(this.getProp(value, 'type'), 'Login');
switch (onePassType) {
case 'Credit Card':
cipher.type = CipherType.Card;
cipher.card = new CardView();
IgnoredProperties.push('type');
break;
case 'Identity':
cipher.type = CipherType.Identity;
cipher.identity = new IdentityView();
IgnoredProperties.push('type');
break;
case 'Login':
case 'Secure Note':
IgnoredProperties.push('type');
default:
break;
}
}
}

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