diff --git a/app/scripts/comp/app/chal-resp-calculator.js b/app/scripts/comp/app/chal-resp-calculator.js new file mode 100644 index 00000000..44713cf5 --- /dev/null +++ b/app/scripts/comp/app/chal-resp-calculator.js @@ -0,0 +1,41 @@ +import { Logger } from 'util/logger'; +import { YubiKey } from 'comp/app/yubikey'; + +const logger = new Logger('chal-resp'); + +const ChalRespCalculator = { + cache: {}, + + build(params) { + if (!params) { + return null; + } + return challenge => { + return new Promise((resolve, reject) => { + const ts = logger.ts(); + + challenge = Buffer.from(challenge); + const hexChallenge = challenge.toString('hex'); + + const key = `${params.vid}:${params.pid}:${params.serial}:${hexChallenge}`; + if (this.cache[key]) { + logger.debug('Found ChalResp in cache'); + return resolve(Buffer.from(this.cache[key], 'hex')); + } + + logger.debug('Calculating ChalResp using a YubiKey'); + + YubiKey.calculateChalResp(params, challenge, (err, response) => { + if (err) { + return reject(err); + } + this.cache[key] = response.toString('hex'); + logger.info('Calculated ChalResp', logger.ts(ts)); + resolve(response); + }); + }); + }; + } +}; + +export { ChalRespCalculator }; diff --git a/app/scripts/models/file-model.js b/app/scripts/models/file-model.js index 7b42d8c8..b7562c4c 100644 --- a/app/scripts/models/file-model.js +++ b/app/scripts/models/file-model.js @@ -8,7 +8,7 @@ import { GroupModel } from 'models/group-model'; import { IconUrlFormat } from 'util/formatting/icon-url-format'; import { Logger } from 'util/logger'; import { mapObject } from 'util/fn'; -import { YubiKey } from 'comp/app/yubikey'; +import { ChalRespCalculator } from 'comp/app/chal-resp-calculator'; const logger = new Logger('file'); @@ -23,7 +23,7 @@ class FileModel extends Model { open(password, fileData, keyFileData, chalResp, callback) { try { - const challengeResponse = this.makeChallengeResponse(chalResp); + const challengeResponse = ChalRespCalculator.build(chalResp); const credentials = new kdbxweb.Credentials(password, keyFileData, challengeResponse); const ts = logger.ts(); @@ -69,26 +69,6 @@ class FileModel extends Model { } } - makeChallengeResponse(params) { - if (!params) { - return null; - } - return challenge => { - return new Promise((resolve, reject) => { - logger.debug('Calculating ChalResp using a YubiKey'); - const ts = logger.ts(); - challenge = Buffer.from(challenge); - YubiKey.calculateChalResp(params, challenge, (err, response) => { - if (err) { - return reject(err); - } - logger.info('Calculated ChalResp', logger.ts(ts)); - resolve(response); - }); - }); - }; - } - kdfArgsToString(header) { if (header.kdfParameters) { return header.kdfParameters