Skip to content

Commit

Permalink
cool#9992 doc electronic sign: actually sign the hash in a popup
Browse files Browse the repository at this point in the history
Open an PDF in Draw, Insert -> Electronic signature, the doc hash is
sent to ESignatureBaseUrl, but we don't attempt to sign it.

The actual signing happens using a HTML page provided by eIDEasy, so
open that in a popup.

We can avoid polling for the signature result by listening for
postmessages: the signing popups sends us a postmessage on completion.

This is the same mechanism that's used by the SignatureJS npm library,
developed by eIDEasy (but don't use that here, since it would pull in a
number of dependencies since it doesn't use the fetch() API).

Signed-off-by: Miklos Vajna <vmiklos@collabora.com>
Change-Id: I10902ec6868a64f250fe5afdd0cf9ba36a2f63e6
  • Loading branch information
vmiklos committed Nov 26, 2024
1 parent e729f7e commit a1d81fd
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 7 deletions.
54 changes: 48 additions & 6 deletions browser/src/control/Control.ESignature.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,11 @@ namespace cool {
doc_id: string;
}

export interface SignedResponse {
type: string;
error: string;
}

/**
* Provides electronic signing with document hashes for PDF files.
*/
Expand All @@ -33,14 +38,23 @@ namespace cool {
// <https://docs.eideasy.com/guide/api-credentials.html>
secret: string;
clientId: string;
// This is the specific provider used by eIDEasy, e.g. 'smart-id-signature'
method: string;

// Timestamp of the hash extraction
signatureTime: number;

constructor(url: string, secret: string, clientId: string) {
// Identifier of the document on the eIDEasy side
docId: string;

// The popup window we opened.
popup: Window;

constructor(url: string, secret: string, clientId: string, method: string) {
this.url = url;
this.secret = secret;
this.clientId = clientId;
this.method = method;

app.map.on('commandvalues', this.onCommandValues.bind(this));
}
Expand Down Expand Up @@ -119,11 +133,38 @@ namespace cool {

// Handles the 'send hash' response JSON
handleSendHashJson(response: HashSendResponse): void {
const docId = response.doc_id;
this.docId = response.doc_id;

let url = this.url + '/single-method-signature';
url += '?client_id=' + this.clientId;
url += '&doc_id=' + this.docId;
url += '&method=' + this.method;

let features = 'popup';
features += ', left=' + window.screen.width / 4;
features += ', top=' + window.screen.height / 4;
features += ', width=' + window.screen.width / 2;
features += ', height=' + window.screen.height / 2;

// Step 3: sign the hash.
this.popup = window.open(url, '_blank', features);
}

// Handles the 'sign hash' response
handleSigned(response: SignedResponse): void {
if (response.type != 'SUCCESS') {
app.console.log('failed to sign: ' + response.error);
return;
}

try {
this.popup.close();
} catch (error) {
app.console.log('failed to close the signing popup: ' + error.message);
}

console.log(
'TODO(vmiklos) ESignature::handleSendHashJson: docId is "' +
docId +
'"',
'TODO(vmiklos) ESignature::handleSigned: fetch the signature',
);
}
}
Expand All @@ -135,6 +176,7 @@ L.control.eSignature = function (
url: string,
secret: string,
clientId: string,
method: string,
) {
return new L.Control.ESignature(url, secret, clientId);
return new L.Control.ESignature(url, secret, clientId, method);
};
3 changes: 2 additions & 1 deletion browser/src/control/Control.UIManager.js
Original file line number Diff line number Diff line change
Expand Up @@ -1077,8 +1077,9 @@ L.Control.UIManager = L.Control.extend({
const baseUrl = userPrivateInfo.ESignatureBaseUrl;
const secret = userPrivateInfo.ESignatureSecret;
const clientId = userPrivateInfo.ESignatureClientId;
const method = userPrivateInfo.ESignatureMethod;
if (baseUrl !== undefined && !this.map.eSignature) {
this.map.eSignature = L.control.eSignature(baseUrl, secret, clientId);
this.map.eSignature = L.control.eSignature(baseUrl, secret, clientId, method);
}
}
},
Expand Down
16 changes: 16 additions & 0 deletions browser/src/map/handler/Map.WOPI.js
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,12 @@ L.Map.WOPI = L.Handler.extend({
return true;
}

const eSignature = this._map.eSignature;
if (eSignature && eSignature.url === e.origin) {
// The sender is our esign popup: accept it.
return true;
}

return false;
},

Expand All @@ -277,6 +283,9 @@ L.Map.WOPI = L.Handler.extend({
if (('data' in e) && Object.hasOwnProperty.call(e.data, 'MessageId')) {
// when e.data already contains the right props, but isn't JSON (a blob is passed for ex)
msg = e.data;
} else if (typeof e.data === 'object') {
// E.g. the esign popup sends us an object, no need to JSON-parse it.
msg = e.data;
} else {
try {
msg = JSON.parse(e.data);
Expand Down Expand Up @@ -684,6 +693,13 @@ L.Map.WOPI = L.Handler.extend({
var list = msg.Values.list;
this._map.mention.openMentionPopup(list);
}
else if (msg.sender === 'EIDEASY_SINGLE_METHOD_SIGNATURE') {
// This is produced by the esign popup.
const eSignature = this._map.eSignature;
if (eSignature) {
eSignature.handleSigned(msg);
}
}
},

_postMessage: function(e) {
Expand Down

0 comments on commit a1d81fd

Please sign in to comment.