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 #" , "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 #" , "nom" , "benutzername" , ] ; protected notesFieldNames = [ "note" , "notes" , "comment" , "comments" , "memo" , "description" , "free form" , "freeform" , "free text" , "freetext" , "free" , "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" , "ort" , "adresse" , ] ; protected parseCsvOptions = { encoding : "UTF-8" , skipEmptyLines : false , } ; protected get organization ( ) { return this . organizationId != null ; } protected parseXml ( data ) { const parser = new DOMParser ( ) ; const doc = parser . parseFromString ( data , "application/xml" ) ; return doc != null && doc . querySelector ( "parsererror" ) == null ? doc : null ; } protected parseCsv ( data , header , options = { } ) { 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 ) { this . logService . warning ( "Error parsing row " + e . row + ": " + e . message ) ; } } ) ; } return result . data && result . data . length > 0 ? result . data : null ; } protected parseSingleRowCsv ( rowData ) { 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 ) { 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 = [ ] ; 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 ) { 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 ) { const hostname = Utils . getHostname ( url ) ; if ( this . isNullOrWhitespace ( hostname ) ) { return null ; } return hostname . startsWith ( "www." ) ? hostname . replace ( "www." , "" ) : hostname ; } protected isNullOrWhitespace ( str ) { return Utils . isNullOrWhitespace ( str ) ; } protected getValueOrDefault ( str , defaultValue = null ) { if ( this . isNullOrWhitespace ( str ) ) { return defaultValue ; } return str ; } protected splitNewLine ( str ) { return str . split ( this . newLineRegex ) ; } protected getCardBrand ( cardNum ) { if ( this . isNullOrWhitespace ( cardNum ) ) { return null ; } let re = new RegExp ( "^4" ) ; if ( cardNum . match ( re ) != null ) { return "Visa" ; } 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" ; } re = new RegExp ( "^3[47]" ) ; if ( cardNum . match ( re ) != null ) { return "Amex" ; } 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" ; } re = new RegExp ( "^36" ) ; if ( cardNum . match ( re ) != null ) { return "Diners Club" ; } re = new RegExp ( "^30[0-5]" ) ; if ( cardNum . match ( re ) != null ) { return "Diners Club" ; } re = new RegExp ( "^35(2[89]|[3-8][0-9])" ) ; if ( cardNum . match ( re ) != null ) { return "JCB" ; } re = new RegExp ( "^(4026|417500|4508|4844|491(3|7))" ) ; if ( cardNum . match ( re ) != null ) { return "Visa" ; } return null ; } protected setCardExpiration ( cipher , expiration ) { if ( ! this . isNullOrWhitespace ( expiration ) ) { expiration = expiration . replace ( /\s/g , "" ) ; const parts = expiration . split ( "/" ) ; if ( parts . length === 2 ) { let month = null ; let year = 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 ) { 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 , query ) { const els = this . querySelectorAllDirectChild ( parentEl , query ) ; return els . length === 0 ? null : els [ 0 ] ; } protected querySelectorAllDirectChild ( parentEl , query ) { 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 ) { 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 , key , value , type = 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 , folderName ) { 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 ) { 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 ; } } }