Index: build/chrome/Makefile ================================================================== --- build/chrome/Makefile +++ build/chrome/Makefile @@ -26,11 +26,11 @@ endif export NACL_SDK_ROOT all: cackey.crx -cackey.crx: cackey.pexe cackey.nmf manifest.json cackey.js google-pcsc.js pin.html pin-icon.png +cackey.crx: cackey.pexe cackey.nmf manifest.json cackey.js google-pcsc.js pin.html pin.js pin-icon.png rm -f cackey.crx zip cackey.crx.new $^ mv cackey.crx.new cackey.crx cackey.pexe: cackey-chrome.o cackey-chrome-init.o lib/libcackey.a lib/libpcsc.a lib/libz.a Index: build/chrome/cackey.js ================================================================== --- build/chrome/cackey.js +++ build/chrome/cackey.js @@ -17,10 +17,15 @@ * Handle and ID for outstanding callbacks */ var cackeyOutstandingCallbacks = [] var cackeyOutstandingCallbackCounter = -1; +/* + * Communication with the PIN entry window + */ +var pinWindowDidWork = 0; + /* * Handle a response from the NaCl side regarding certificates available */ function cackeyMessageIncomingListCertificates(message, chromeCallback) { var idx; @@ -86,25 +91,92 @@ console.log("[cackey] Discarding outdated message"); return; } - if (messageEvent.data.status != "success") { - console.error("[cackey] Failed to execute command '" + messageEvent.data.command + "': " + messageEvent.data.error); - - chromeCallback(); - } else { - switch (messageEvent.data.command) { - case "listcertificates": - nextFunction = cackeyMessageIncomingListCertificates; - - break; - case "sign": - nextFunction = cackeyMessageIncomingSignMessage; - - break; - } + switch (messageEvent.data.status) { + case "error": + console.error("[cackey] Failed to execute command '" + messageEvent.data.command + "': " + messageEvent.data.error); + + chromeCallback(); + + break; + case "retry": + pinWindowDidWork = 0; + + chrome.app.window.create("pin.html", { + "id": "cackeyPINEntry", + "resizable": false, + "alwaysOnTop": true, + "focused": true, + "visibleOnAllWorkspaces": true, + "innerBounds": { + "width": 350, + "minWidth": 350, + "height": 135, + "minHeight": 135 + } + }, function(pinWindow) { + if (!pinWindow) { + console.log("[cackey] No window was provided for PIN entry, this will not go well."); + + return; + } + pinWindow.drawAttention(); + pinWindow.focus(); + + /* + * Register a handler to handle the window being closed without + * having sent anything + */ + pinWindow.onClosed.addListener(function() { + if (pinWindowDidWork != 1) { + console.log("[cackey] The PIN dialog was closed without resubmitting the request, treating it as a failure"); + + cackeyMessageIncoming( + { + "data": { + "target": "cackey", + "command": messageEvent.data.command, + "id": messageEvent.data.id, + "status": "error", + "error": "PIN window closed without a PIN being provided" + } + } + ) + + } + return; + }) + + /* + * Pass this message off to the other window so that it may resubmit the request. + */ + pinWindow.contentWindow.parentWindow = window; + pinWindow.contentWindow.messageEvent = messageEvent; + + return; + }); + + /* + * We return here instead of break to avoid deleting the callback + * entry. + */ + return; + case "success": + switch (messageEvent.data.command) { + case "listcertificates": + nextFunction = cackeyMessageIncomingListCertificates; + + break; + case "sign": + nextFunction = cackeyMessageIncomingSignMessage; + + break; + } + + break; } if (nextFunction != null) { nextFunction(messageEvent.data, chromeCallback); } Index: build/chrome/pin.html ================================================================== --- build/chrome/pin.html +++ build/chrome/pin.html @@ -1,8 +1,14 @@