function handleU2fEnrollRequest(messageSender, request, sendResponse) {
  var sentResponse = false;
  var closeable = null;

  function sendErrorResponse(error) {
    var response =
        makeU2fErrorResponse(request, error.errorCode, error.errorMessage);
    sendResponseOnce(sentResponse, closeable, response, sendResponse);
  }

  async function getRegistrationData(
      appId, enrollChallenge, registrationData, opt_clientData) {
    var isDirect = true;

    if (conveyancePreference(enrollChallenge) == ConveyancePreference.NONE) {
      isDirect = false;
    } else if (chrome.cryptotokenPrivate != null) {
      isDirect = await(new Promise((resolve, reject) => {
        chrome.cryptotokenPrivate.canAppIdGetAttestation(
            {'appId': appId, 'tabId': messageSender.tab.id}, resolve);
      }));
    }

    if (isDirect) {
      return registrationData;
    }

    const reg = new Registration(
        registrationData, appId, enrollChallenge['challenge'], opt_clientData);
    const keypair = await makeCertAndKey(reg.certificate);
    const signature = await reg.sign(keypair.privateKey);
    return reg.withReplacement(keypair.certDER, signature);
  }

  /**
   * @param {string} u2fVersion
   * @param {string} registrationData Registration data, base64
   * @param {string=} opt_clientData Base64.
   */
  function sendSuccessResponse(u2fVersion, registrationData, opt_clientData) {
    var enrollChallenges = request['registerRequests'];
    var enrollChallengeOrNull =
        findEnrollChallengeOfVersion(enrollChallenges, u2fVersion);
    if (!enrollChallengeOrNull) {
      sendErrorResponse({errorCode: ErrorCodes.OTHER_ERROR});
      return;
    }
    var enrollChallenge = enrollChallengeOrNull;  // Avoids compiler warning.
    var appId = request['appId'];
    if (enrollChallenge.hasOwnProperty('appId')) {
      appId = enrollChallenge['appId'];
    }

    getRegistrationData(
        appId, enrollChallenge, registrationData, opt_clientData)
        .then(
            (registrationData) => {
              var responseData = makeEnrollResponseData(
                  enrollChallenge, u2fVersion, registrationData,
                  opt_clientData);
              var response = makeU2fSuccessResponse(request, responseData);
              sendResponseOnce(sentResponse, closeable, response, sendResponse);
            },
            (err) => {
              console.warn(
                  'attestation certificate replacement failed: ' + err);
              sendErrorResponse({errorCode: ErrorCodes.OTHER_ERROR});
            });
  }

  function timeout() {
    sendErrorResponse({errorCode: ErrorCodes.TIMEOUT});
  }

  var sender = createSenderFromMessageSender(messageSender);
  if (!sender) {
    sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST});
    return null;
  }
  if (sender.origin.indexOf('http://') == 0 && !HTTP_ORIGINS_ALLOWED) {
    sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST});
    return null;
  }

  if (!isValidEnrollRequest(request)) {
    sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST});
    return null;
  }

  var timeoutValueSeconds = getTimeoutValueFromRequest(request);
  // Attenuate watchdog timeout value less than the enroller's timeout, so the
  // watchdog only fires after the enroller could reasonably have called back,
  // not before.
  var watchdogTimeoutValueSeconds = attenuateTimeoutInSeconds(
      timeoutValueSeconds, MINIMUM_TIMEOUT_ATTENUATION_SECONDS / 2);
  var watchdog =
      new WatchdogRequestHandler(watchdogTimeoutValueSeconds, timeout);
  var wrappedErrorCb = watchdog.wrapCallback(sendErrorResponse);
  var wrappedSuccessCb = watchdog.wrapCallback(sendSuccessResponse);
  // TODO: Fix unused; intended to pass wrapped callbacks to Enroller?

  var timer = createAttenuatedTimer(
      FACTORY_REGISTRY.getCountdownFactory(), timeoutValueSeconds);
  var logMsgUrl = request['logMsgUrl'];
  var enroller = new Enroller(
      timer, sender, sendErrorResponse, sendSuccessResponse, logMsgUrl);
  watchdog.setCloseable(/** @type {!Closeable} */ (enroller));
  closeable = watchdog;

  var registerRequests = request['registerRequests'];
  var signRequests = getSignRequestsFromEnrollRequest(request);
  enroller.doEnroll(registerRequests, signRequests, request['appId']);

  return closeable;
}
/**
 * Handles a U2F enroll request.
 * @param {MessageSender} messageSender The message sender.
 * @param {Object} request The web page's enroll request.
 * @param {Function} sendResponse Called back with the result of the enroll.
 * @return {Closeable} A handler object to be closed when the browser channel
 *     closes.
 */
Handles a U2F enroll request.
@param {MessageSender} messageSender The message sender.
@param {Object} request The web page's enroll request.
@param {Function} sendResponse Called back with the result of the enroll.
@return {Closeable} A handler object to be closed when the browser channel
closes.
Handles a U2F enroll request . @param { MessageSender } messageSender The message sender . @param { Object } request The web page ' s enroll request . @param { Function } sendResponse Called back with the result of the enroll . @return { Closeable } A handler object to be closed when the browser channel closes .
function handleU2fEnrollRequest(messageSender, request, sendResponse) {
  var sentResponse = false;
  var closeable = null;
  function sendErrorResponse(error) {
    var response =
        makeU2fErrorResponse(request, error.errorCode, error.errorMessage);
    sendResponseOnce(sentResponse, closeable, response, sendResponse);
  }
  async function getRegistrationData(
      appId, enrollChallenge, registrationData, opt_clientData) {
    var isDirect = true;
    if (conveyancePreference(enrollChallenge) == ConveyancePreference.NONE) {
      isDirect = false;
    } else if (chrome.cryptotokenPrivate != null) {
      isDirect = await(new Promise((resolve, reject) => {
        chrome.cryptotokenPrivate.canAppIdGetAttestation(
            {'appId': appId, 'tabId': messageSender.tab.id}, resolve);
      }));
    }
    if (isDirect) {
      return registrationData;
    }
    const reg = new Registration(
        registrationData, appId, enrollChallenge['challenge'], opt_clientData);
    const keypair = await makeCertAndKey(reg.certificate);
    const signature = await reg.sign(keypair.privateKey);
    return reg.withReplacement(keypair.certDER, signature);
  }
  function sendSuccessResponse(u2fVersion, registrationData, opt_clientData) {
    var enrollChallenges = request['registerRequests'];
    var enrollChallengeOrNull =
        findEnrollChallengeOfVersion(enrollChallenges, u2fVersion);
    if (!enrollChallengeOrNull) {
      sendErrorResponse({errorCode: ErrorCodes.OTHER_ERROR});
      return;
    }
    var enrollChallenge = enrollChallengeOrNull;  
    var appId = request['appId'];
    if (enrollChallenge.hasOwnProperty('appId')) {
      appId = enrollChallenge['appId'];
    }
    getRegistrationData(
        appId, enrollChallenge, registrationData, opt_clientData)
        .then(
            (registrationData) => {
              var responseData = makeEnrollResponseData(
                  enrollChallenge, u2fVersion, registrationData,
                  opt_clientData);
              var response = makeU2fSuccessResponse(request, responseData);
              sendResponseOnce(sentResponse, closeable, response, sendResponse);
            },
            (err) => {
              console.warn(
                  'attestation certificate replacement failed: ' + err);
              sendErrorResponse({errorCode: ErrorCodes.OTHER_ERROR});
            });
  }
  function timeout() {
    sendErrorResponse({errorCode: ErrorCodes.TIMEOUT});
  }
  var sender = createSenderFromMessageSender(messageSender);
  if (!sender) {
    sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST});
    return null;
  }
  if (sender.origin.indexOf('http://') == 0 && !HTTP_ORIGINS_ALLOWED) {
    sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST});
    return null;
  }
  if (!isValidEnrollRequest(request)) {
    sendErrorResponse({errorCode: ErrorCodes.BAD_REQUEST});
    return null;
  }
  var timeoutValueSeconds = getTimeoutValueFromRequest(request);
  var watchdogTimeoutValueSeconds = attenuateTimeoutInSeconds(
      timeoutValueSeconds, MINIMUM_TIMEOUT_ATTENUATION_SECONDS / 2);
  var watchdog =
      new WatchdogRequestHandler(watchdogTimeoutValueSeconds, timeout);
  var wrappedErrorCb = watchdog.wrapCallback(sendErrorResponse);
  var wrappedSuccessCb = watchdog.wrapCallback(sendSuccessResponse);
  var timer = createAttenuatedTimer(
      FACTORY_REGISTRY.getCountdownFactory(), timeoutValueSeconds);
  var logMsgUrl = request['logMsgUrl'];
  var enroller = new Enroller(
      timer, sender, sendErrorResponse, sendSuccessResponse, logMsgUrl);
  watchdog.setCloseable( (enroller));
  closeable = watchdog;
  var registerRequests = request['registerRequests'];
  var signRequests = getSignRequestsFromEnrollRequest(request);
  enroller.doEnroll(registerRequests, signRequests, request['appId']);
  return closeable;
}
function handleU2fEnrollRequest ( messageSender , request , sendResponse ) { var sentResponse = false ; var closeable = null ; function sendErrorResponse ( error ) { var response = makeU2fErrorResponse ( request , error . errorCode , error . errorMessage ) ; sendResponseOnce ( sentResponse , closeable , response , sendResponse ) ; } async function getRegistrationData ( appId , enrollChallenge , registrationData , opt_clientData ) { var isDirect = true ; if ( conveyancePreference ( enrollChallenge ) == ConveyancePreference . NONE ) { isDirect = false ; } else if ( chrome . cryptotokenPrivate != null ) { isDirect = await ( new Promise ( ( resolve , reject ) => { chrome . cryptotokenPrivate . canAppIdGetAttestation ( { 'appId' : appId , 'tabId' : messageSender . tab . id } , resolve ) ; } ) ) ; } if ( isDirect ) { return registrationData ; } const reg = new Registration ( registrationData , appId , enrollChallenge [ 'challenge' ] , opt_clientData ) ; const keypair = await makeCertAndKey ( reg . certificate ) ; const signature = await reg . sign ( keypair . privateKey ) ; return reg . withReplacement ( keypair . certDER , signature ) ; } function sendSuccessResponse ( u2fVersion , registrationData , opt_clientData ) { var enrollChallenges = request [ 'registerRequests' ] ; var enrollChallengeOrNull = findEnrollChallengeOfVersion ( enrollChallenges , u2fVersion ) ; if ( ! enrollChallengeOrNull ) { sendErrorResponse ( { errorCode : ErrorCodes . OTHER_ERROR } ) ; return ; } var enrollChallenge = enrollChallengeOrNull ; var appId = request [ 'appId' ] ; if ( enrollChallenge . hasOwnProperty ( 'appId' ) ) { appId = enrollChallenge [ 'appId' ] ; } getRegistrationData ( appId , enrollChallenge , registrationData , opt_clientData ) . then ( ( registrationData ) => { var responseData = makeEnrollResponseData ( enrollChallenge , u2fVersion , registrationData , opt_clientData ) ; var response = makeU2fSuccessResponse ( request , responseData ) ; sendResponseOnce ( sentResponse , closeable , response , sendResponse ) ; } , ( err ) => { console . warn ( 'attestation certificate replacement failed: ' + err ) ; sendErrorResponse ( { errorCode : ErrorCodes . OTHER_ERROR } ) ; } ) ; } function timeout ( ) { sendErrorResponse ( { errorCode : ErrorCodes . TIMEOUT } ) ; } var sender = createSenderFromMessageSender ( messageSender ) ; if ( ! sender ) { sendErrorResponse ( { errorCode : ErrorCodes . BAD_REQUEST } ) ; return null ; } if ( sender . origin . indexOf ( 'http://' ) == 0 && ! HTTP_ORIGINS_ALLOWED ) { sendErrorResponse ( { errorCode : ErrorCodes . BAD_REQUEST } ) ; return null ; } if ( ! isValidEnrollRequest ( request ) ) { sendErrorResponse ( { errorCode : ErrorCodes . BAD_REQUEST } ) ; return null ; } var timeoutValueSeconds = getTimeoutValueFromRequest ( request ) ; var watchdogTimeoutValueSeconds = attenuateTimeoutInSeconds ( timeoutValueSeconds , MINIMUM_TIMEOUT_ATTENUATION_SECONDS / 2 ) ; var watchdog = new WatchdogRequestHandler ( watchdogTimeoutValueSeconds , timeout ) ; var wrappedErrorCb = watchdog . wrapCallback ( sendErrorResponse ) ; var wrappedSuccessCb = watchdog . wrapCallback ( sendSuccessResponse ) ; var timer = createAttenuatedTimer ( FACTORY_REGISTRY . getCountdownFactory ( ) , timeoutValueSeconds ) ; var logMsgUrl = request [ 'logMsgUrl' ] ; var enroller = new Enroller ( timer , sender , sendErrorResponse , sendSuccessResponse , logMsgUrl ) ; watchdog . setCloseable ( ( enroller ) ) ; closeable = watchdog ; var registerRequests = request [ 'registerRequests' ] ; var signRequests = getSignRequestsFromEnrollRequest ( request ) ; enroller . doEnroll ( registerRequests , signRequests , request [ 'appId' ] ) ; return closeable ; }
Handles a U2F enroll request.
Handles a U2F enroll request .
/**
   * @param {string} u2fVersion
   * @param {string} registrationData Registration data, base64
   * @param {string=} opt_clientData Base64.
   */ // Avoids compiler warning. // Attenuate watchdog timeout value less than the enroller's timeout, so the // watchdog only fires after the enroller could reasonably have called back, // not before. // TODO: Fix unused; intended to pass wrapped callbacks to Enroller? /** @type {!Closeable} */