var sentResponse = false;
var queuedSignRequest;
- function sendErrorResponse(u2fCode) {
+ function sendErrorResponse(error) {
sendResponseOnce(sentResponse, queuedSignRequest,
makeWebErrorResponse(request,
- mapErrorCodeToGnubbyCodeType(u2fCode, true /* forSign */)),
+ mapErrorCodeToGnubbyCodeType(error.errorCode, true /* forSign */)),
sendResponse);
}
var sentResponse = false;
var queuedSignRequest;
- function sendErrorResponse(u2fCode) {
+ function sendErrorResponse(error) {
sendResponseOnce(sentResponse, queuedSignRequest,
- makeU2fErrorResponse(request, u2fCode), sendResponse);
+ makeU2fErrorResponse(request, error.errorCode, error.errorMessage),
+ sendResponse);
}
function sendSuccessResponse(challenge, info, browserData) {
* @param {Object} request The web page's sign request.
* @param {string} signChallengesName The name of the sign challenges value in
* the request.
- * @param {function(ErrorCodes)} errorCb Error callback.
+ * @param {function(U2fError)} errorCb Error callback.
* @param {function(SignChallenge, string, string)} successCb Success callback.
* @return {Closeable} Request handler that should be closed when the browser
* message channel is closed.
signChallengesName, errorCb, successCb) {
var origin = getOriginFromUrl(/** @type {string} */ (sender.url));
if (!origin) {
- errorCb(ErrorCodes.BAD_REQUEST);
+ errorCb({errorCode: ErrorCodes.BAD_REQUEST});
return null;
}
// More closure type inference fail.
var nonNullOrigin = /** @type {string} */ (origin);
if (!isValidSignRequest(request, signChallengesName)) {
- errorCb(ErrorCodes.BAD_REQUEST);
+ errorCb({errorCode: ErrorCodes.BAD_REQUEST});
return null;
}
var signChallenges = request[signChallengesName];
- // A valid sign data has at least one challenge, so get the first appId from
- // the first challenge.
- var firstAppId = signChallenges[0]['appId'];
+ var appId;
+ if (request['appId']) {
+ appId = request['appId'];
+ } else {
+ // A valid sign data has at least one challenge, so get the appId from
+ // the first challenge.
+ appId = signChallenges[0]['appId'];
+ }
+ // Sanity check
+ if (!appId) {
+ console.warn(UTIL_fmt('empty sign appId?'));
+ errorCb({errorCode: ErrorCodes.BAD_REQUEST});
+ return null;
+ }
var timer = createTimerForRequest(
FACTORY_REGISTRY.getCountdownFactory(), request);
var logMsgUrl = request['logMsgUrl'];
// Queue sign requests from the same origin, to protect against simultaneous
// sign-out on many tabs resulting in repeated sign-in requests.
var queuedSignRequest = new QueuedSignRequest(signChallenges,
- timer, nonNullOrigin, errorCb, successCb, sender.tlsChannelId,
+ timer, nonNullOrigin, errorCb, successCb, appId, sender.tlsChannelId,
logMsgUrl);
- var requestToken = signRequestQueue.queueRequest(firstAppId, nonNullOrigin,
+ var requestToken = signRequestQueue.queueRequest(appId, nonNullOrigin,
queuedSignRequest.begin.bind(queuedSignRequest), timer);
queuedSignRequest.setToken(requestToken);
return queuedSignRequest;
// be fulfilled. Fail.
if (!signChallenges.length)
return false;
- return isValidSignChallengeArray(signChallenges);
+ var hasAppId = request.hasOwnProperty('appId');
+ return isValidSignChallengeArray(signChallenges, !hasAppId);
}
/**
* @param {!Array.<SignChallenge>} signChallenges The sign challenges.
* @param {Countdown} timer Timeout timer
* @param {string} origin Signature origin
- * @param {function(ErrorCodes)} errorCb Error callback
+ * @param {function(U2fError)} errorCb Error callback
* @param {function(SignChallenge, string, string)} successCb Success callback
+ * @param {string|undefined} opt_appId The app id for the entire request.
* @param {string|undefined} opt_tlsChannelId TLS Channel Id
* @param {string|undefined} opt_logMsgUrl Url to post log messages to
* @constructor
* @implements {Closeable}
*/
function QueuedSignRequest(signChallenges, timer, origin, errorCb,
- successCb, opt_tlsChannelId, opt_logMsgUrl) {
+ successCb, opt_appId, opt_tlsChannelId, opt_logMsgUrl) {
/** @private {!Array.<SignChallenge>} */
this.signChallenges_ = signChallenges;
/** @private {Countdown} */
this.timer_ = timer;
/** @private {string} */
this.origin_ = origin;
- /** @private {function(ErrorCodes)} */
+ /** @private {function(U2fError)} */
this.errorCb_ = errorCb;
/** @private {function(SignChallenge, string, string)} */
this.successCb_ = successCb;
/** @private {string|undefined} */
+ this.appId_ = opt_appId;
+ /** @private {string|undefined} */
this.tlsChannelId_ = opt_tlsChannelId;
/** @private {string|undefined} */
this.logMsgUrl_ = opt_logMsgUrl;
this.signer_ = new Signer(this.timer_, this.origin_,
this.signerFailed_.bind(this), this.signerSucceeded_.bind(this),
this.tlsChannelId_, this.logMsgUrl_);
- if (!this.signer_.setChallenges(this.signChallenges_)) {
+ if (!this.signer_.setChallenges(this.signChallenges_, this.appId_)) {
token.complete();
- this.errorCb_(ErrorCodes.BAD_REQUEST);
+ this.errorCb_({errorCode: ErrorCodes.BAD_REQUEST});
}
};
/**
* Called when this request's signer fails.
- * @param {ErrorCodes} code The failure code reported by the signer.
+ * @param {U2fError} error The failure reported by the signer.
* @private
*/
-QueuedSignRequest.prototype.signerFailed_ = function(code) {
+QueuedSignRequest.prototype.signerFailed_ = function(error) {
this.token_.complete();
- this.errorCb_(code);
+ this.errorCb_(error);
};
/**
* Creates an object to track signing with a gnubby.
* @param {Countdown} timer Timer for sign request.
* @param {string} origin The origin making the request.
- * @param {function(ErrorCodes)} errorCb Called when the sign operation fails.
+ * @param {function(U2fError)} errorCb Called when the sign operation fails.
* @param {function(SignChallenge, string, string)} successCb Called when the
* sign operation succeeds.
* @param {string=} opt_tlsChannelId the TLS channel ID, if any, of the origin
this.timer_ = timer;
/** @private {string} */
this.origin_ = origin;
- /** @private {function(ErrorCodes)} */
+ /** @private {function(U2fError)} */
this.errorCb_ = errorCb;
/** @private {function(SignChallenge, string, string)} */
this.successCb_ = successCb;
/**
* Sets the challenges to be signed.
* @param {Array.<SignChallenge>} signChallenges The challenges to set.
+ * @param {string=} opt_appId The app id for the entire request.
* @return {boolean} Whether the challenges could be set.
*/
-Signer.prototype.setChallenges = function(signChallenges) {
+Signer.prototype.setChallenges = function(signChallenges, opt_appId) {
if (this.challengesSet_ || this.done_)
return false;
/** @private {Array.<SignChallenge>} */
this.signChallenges_ = signChallenges;
+ /** @private {string|undefined} */
+ this.appId_ = opt_appId;
/** @private {boolean} */
this.challengesSet_ = true;
*/
Signer.prototype.checkAppIds_ = function() {
var appIds = getDistinctAppIds(this.signChallenges_);
+ if (this.appId_) {
+ appIds = UTIL_unionArrays([this.appId_], appIds);
+ }
if (!appIds || !appIds.length) {
- this.notifyError_(ErrorCodes.BAD_REQUEST);
+ var error = {
+ errorCode: ErrorCodes.BAD_REQUEST,
+ errorMessage: 'missing appId'
+ };
+ this.notifyError_(error);
return;
}
FACTORY_REGISTRY.getOriginChecker().canClaimAppIds(this.origin_, appIds)
*/
Signer.prototype.originChecked_ = function(appIds, result) {
if (!result) {
- this.notifyError_(ErrorCodes.BAD_REQUEST);
+ var error = {
+ errorCode: ErrorCodes.BAD_REQUEST,
+ errorMessage: 'bad appId'
+ };
+ this.notifyError_(error);
return;
}
/** @private {!AppIdChecker} */
*/
Signer.prototype.appIdChecked_ = function(result) {
if (!result) {
- this.notifyError_(ErrorCodes.BAD_REQUEST);
+ var error = {
+ errorCode: ErrorCodes.BAD_REQUEST,
+ errorMessage: 'bad appId'
+ };
+ this.notifyError_(error);
return;
}
if (!this.doSign_()) {
- this.notifyError_(ErrorCodes.BAD_REQUEST);
+ this.notifyError_({errorCode: ErrorCodes.BAD_REQUEST});
return;
}
};
}
var encodedChallenges = encodeSignChallenges(this.signChallenges_,
- this.getChallengeHash_.bind(this));
+ this.appId_, this.getChallengeHash_.bind(this));
var timeoutSeconds = this.timer_.millisecondsUntilExpired() / 1000.0;
var request = makeSignHelperRequest(encodedChallenges, timeoutSeconds,
};
/**
- * Notifies the caller of error with the given error code.
- * @param {ErrorCodes} code Error code
+ * Notifies the caller of error.
+ * @param {U2fError} error Error.
* @private
*/
-Signer.prototype.notifyError_ = function(code) {
+Signer.prototype.notifyError_ = function(error) {
if (this.done_)
return;
this.close();
this.done_ = true;
- this.errorCb_(code);
+ this.errorCb_(error);
};
/**
*/
Signer.prototype.helperComplete_ = function(helperReply, opt_source) {
if (helperReply.type != 'sign_helper_reply') {
- this.notifyError_(ErrorCodes.OTHER_ERROR);
+ this.notifyError_({errorCode: ErrorCodes.OTHER_ERROR});
return;
}
var reply = /** @type {SignHelperReply} */ (helperReply);
if (reply.code) {
- var reportedError = mapDeviceStatusCodeToErrorCode(reply.code);
+ var reportedError = mapDeviceStatusCodeToU2fError(reply.code);
console.log(UTIL_fmt('helper reported ' + reply.code.toString(16) +
- ', returning ' + reportedError));
+ ', returning ' + reportedError.errorCode));
this.notifyError_(reportedError);
} else {
if (this.logMsgUrl_ && opt_source) {