// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
function arrayBufferFromByteList(byteList) {
return (new Uint8Array(byteList)).buffer;
}
function byteListFromArrayBuffer(arrayBuffer) {
return Array.from(new Uint8Array(arrayBuffer));
}
// Returns the list of certificateProvider ClientCertificateInfo instances,
// given the parsed JSON value received from the C++ handler.
function clientCertificateInfoListFromJson(parsedCertInfoList) {
return parsedCertInfoList.map(parsedCertInfo => {
const certInfo = Object.assign({}, parsedCertInfo);
certInfo.certificateChain[0] =
arrayBufferFromByteList(parsedCertInfo.certificateChain[0]);
return certInfo;
});
}
// Transforms the certificateProvider signature request instance into a
// JSON-ifiable value that may be sent to the C++ handler.
function jsonifiableFromSignRequest(signRequest) {
const transformedSignRequest = Object.assign({}, signRequest);
transformedSignRequest.input = byteListFromArrayBuffer(signRequest.input);
transformedSignRequest.certificate =
byteListFromArrayBuffer(signRequest.certificate);
return transformedSignRequest;
}
// Listener for the chrome.certificateProvider.onCertificatesUpdateRequested
// event.
function onCertificatesUpdateRequested(request) {
// Request certificates from the C++ side.
chrome.test.sendMessage(
JSON.stringify(['getCertificates']),
onCertificatesResponseFromCpp.bind(null, request.certificatesRequestId));
}
// Calls chrome.certificateProvider.setCertificates with the given certificates.
function onCertificatesResponseFromCpp(certificatesRequestId, response) {
const certInfoList = clientCertificateInfoListFromJson(JSON.parse(response));
let details = {clientCertificates: certInfoList};
if (certificatesRequestId !== null)
details.certificatesRequestId = certificatesRequestId;
chrome.certificateProvider.setCertificates(details);
}
// Listener for the chrome.certificateProvider.onSignatureRequested event.
function onSignatureRequested(request) {
requestSignatureFromCpp(
request, /* pinStatus= */ 'not_requested', /* pin= */ '');
}
function requestSignatureFromCpp(signatureRequest, pinStatus, pin) {
chrome.test.sendMessage(
JSON.stringify([
'onSignatureRequested', jsonifiableFromSignRequest(signatureRequest),
pinStatus, pin
]),
onSignatureResponseFromCpp.bind(null, signatureRequest));
}
function onSignatureResponseFromCpp(signatureRequest, response) {
const parsedResponse = JSON.parse(response);
if (parsedResponse === null) {
// The C++ handler signaled an error.
const details = {
signRequestId: signatureRequest.signRequestId,
error: 'GENERAL_ERROR'
};
chrome.certificateProvider.reportSignature(details);
return;
}
if (parsedResponse.stopPinRequest) {
// The C++ handler asked to stop the PIN request.
chrome.certificateProvider.stopPinRequest(
parsedResponse.stopPinRequest, function() {});
// Note that we're not returning here, since the parsed response may contain
// the signature as well.
}
if (parsedResponse.signature) {
// Forward the signature generated by the C++ handler.
const details = {
signRequestId: signatureRequest.signRequestId,
signature: arrayBufferFromByteList(parsedResponse.signature)
};
chrome.certificateProvider.reportSignature(details);
}
if (parsedResponse.requestPin) {
// The C++ handler asked to request the PIN. After the PIN is obtained,
// we'll request the signature from the C++ handler again.
chrome.certificateProvider.requestPin(
parsedResponse.requestPin, requestPinResponse => {
const pin = (requestPinResponse && requestPinResponse.userInput) ?
requestPinResponse.userInput :
'';
const pinStatus = chrome.runtime.lastError ?
('failed:' + chrome.runtime.lastError) :
(pin ? 'ok' : 'canceled');
requestSignatureFromCpp(signatureRequest, pinStatus, pin);
});
}
}
chrome.certificateProvider.onCertificatesUpdateRequested.addListener(
onCertificatesUpdateRequested);
chrome.certificateProvider.onSignatureRequested.addListener(
onSignatureRequested);
// Listen for messages that are 'setCertificates'.
// When receiving one, call chrome.certificateProvider.setCertificates().
chrome.test.onMessage.addListener((msg) => {
if (msg.name !== 'setCertificates')
return;
chrome.certificateProvider.setCertificates({
clientCertificates:
clientCertificateInfoListFromJson(msg.certificateInfoList)
});
});