import { generateUUID } from "../tools/uuid" ; import { credentialsAllowsPurpose , getCredentials , setCredentials } from "./channel" ; import { getSharedAppEnv } from "../env/appEnv" ; private const LEGACY_SIGNING_KEY = "b~>buttercup/acreds.v2." ; private const SIGNING_KEY = "bc~3>" ; see SIGNING_KEY private param content returns function signEncryptedContent ( content ) { return `${ SIGNING_KEY }${ content }` ; } private param content returns throws see SIGNING_KEY function unsignEncryptedContent ( content ) { const newIndex = content . indexOf ( SIGNING_KEY ) ; const oldIndex = content . indexOf ( LEGACY_SIGNING_KEY ) ; if ( newIndex === - 1 && oldIndex === - 1 ) { throw new Error ( "Invalid credentials content (unknown signature)" ) ; } return newIndex === 0 ? content . substr ( SIGNING_KEY . length ) : content . substr ( LEGACY_SIGNING_KEY . length ) ; } memberof export default class Credentials { static PURPOSE_DECRYPT_VAULT = "vault-decrypt" ; static PURPOSE_ENCRYPT_VAULT = "vault-encrypt" ; static PURPOSE_SECURE_EXPORT = "secure-export" ; memberof static static allPurposes ( ) { return [ Credentials . PURPOSE_DECRYPT_VAULT , Credentials . PURPOSE_ENCRYPT_VAULT , Credentials . PURPOSE_SECURE_EXPORT ] ; } param credentials param masterPassword memberof static throws throws static fromCredentials ( credentials , masterPassword ) { if ( ! masterPassword ) { throw new Error ( "Master password is required for credentials cloning" ) ; } const credentialsData = getCredentials ( credentials . id ) ; if ( credentialsData . masterPassword !== masterPassword ) { throw new Error ( "Master password does not match that of the credentials to be cloned" ) ; } const newData = JSON . parse ( JSON . stringify ( credentialsData . data ) ) ; return new Credentials ( newData , masterPassword ) ; } param datasourceConfig param masterPassword memberof static static fromDatasource ( datasourceConfig , masterPassword = null ) { return new Credentials ( { datasource : datasourceConfig } , masterPassword ) ; } param password param masterPassword memberof static static fromPassword ( password , masterPassword = null ) { const masterPass = masterPassword || password ; return new Credentials ( { password } , masterPass ) ; } param content param masterPassword returns static memberof static fromSecureString ( content , masterPassword ) { const decrypt = getSharedAppEnv ( ) . getProperty ( "crypto/v1/decryptText" ) ; return decrypt ( unsignEncryptedContent ( content ) , masterPassword ) . then ( ( decryptedContent ) => JSON . parse ( decryptedContent ) ) . then ( ( credentialsData ) => { if ( credentialsData . datasource ) { if ( typeof credentialsData . datasource === "string" ) { credentialsData . datasource = JSON . parse ( credentialsData . datasource ) ; } if ( credentialsData . username ) { credentialsData . datasource . username = credentialsData . username ; delete credentialsData . username ; } if ( credentialsData . password ) { credentialsData . datasource . password = credentialsData . password ; delete credentialsData . password ; } } return new Credentials ( credentialsData , masterPassword ) ; } ) ; } param inst statuc memberof static isCredentials ( inst ) { return ! ! inst && typeof inst === "object" && typeof inst . toSecureString === "function" && ! ! inst . id ; } id : string ; param obj param masterPassword constructor ( obj = { } , masterPassword = null ) { const id = generateUUID ( ) ; Object . defineProperty ( this , "id" , { writable : false , configurable : false , enumerable : true , value : id } ) ; setCredentials ( id , { data : obj , masterPassword , purposes : Credentials . allPurposes ( ) , open : false } ) ; } memberof getData ( ) { const isClosedEnv = getSharedAppEnv ( ) . getProperty ( "env/v1/isClosedEnv" ) ( ) ; const payload = getCredentials ( this . id ) ; if ( isClosedEnv || payload . open === true ) { return payload ; } return null ; } param allowedPurposes returns memberof example restrictPurposes ( allowedPurposes ) { const creds = getCredentials ( this . id ) ; const { purposes } = creds ; const finalPurposes = allowedPurposes . filter ( newPurpose => purposes . includes ( newPurpose ) ) ; setCredentials ( this . id , Object . assign ( creds , { purposes : finalPurposes } ) ) ; return this ; } returns throws throws memberof toSecureString ( ) { if ( credentialsAllowsPurpose ( this . id , Credentials . PURPOSE_SECURE_EXPORT ) !== true ) { return Promise . reject ( new Error ( "Credential purposes don't allow for secure exports" ) ) ; } const encrypt = getSharedAppEnv ( ) . getProperty ( "crypto/v1/encryptText" ) ; const { data , masterPassword } = getCredentials ( this . id ) ; if ( typeof masterPassword !== "string" ) { return Promise . reject ( new Error ( "Cannot convert Credentials to string: master password was not set or is invalid" ) ) ; } return encrypt ( JSON . stringify ( data ) , masterPassword ) . then ( signEncryptedContent ) ; } protected memberof deprecated _getData ( ) { return this . getData ( ) ; } }