Skip to content

Commit

Permalink
feat: document signing, add setting for the signing certificate & key…
Browse files Browse the repository at this point in the history
…, too (fixes #4123)

The CA chain for the document signing was already a user setting & it
was exposed in the WOPI CheckFileInfo, but the actual signing
certificate & key was missing, so signing was not possible.

These are typically in a similar PEM format using just ASCII characters,
so providing a textarea where the user can paste them sounds like a good
fit.

Add the read/write of this setting and also expose it as part of the
private user info in WOPI CheckFileInfo.

With this, once all 3 are configured, it's possible to sign a document
in Nextcloud Office, using the Signature button on the Home tab of the
notebookbar.

Signed-off-by: Miklos Vajna <vmiklos@collabora.com>
  • Loading branch information
vmiklos committed Oct 16, 2024
1 parent 6ca8071 commit adfb905
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 1 deletion.
8 changes: 8 additions & 0 deletions css/admin.scss
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ input#zoteroAPIKeyField {
width: 300px;
}

textarea#documentSigningCertField {
width: 600px;
}

textarea#documentSigningKeyField {
width: 600px;
}

textarea#documentSigningCaField {
width: 600px;
}
Expand Down
18 changes: 18 additions & 0 deletions lib/Controller/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -237,6 +237,8 @@ public function updateWatermarkSettings($settings = []): JSONResponse {
*/
public function setPersonalSettings($templateFolder,
$zoteroAPIKeyInput,
$documentSigningCertInput,
$documentSigningKeyInput,
$documentSigningCaInput) {
$message = $this->l10n->t('Saved');
$status = 'success';
Expand All @@ -258,6 +260,22 @@ public function setPersonalSettings($templateFolder,
}
}

if ($documentSigningCertInput !== null) {
try {
$this->config->setUserValue($this->userId, 'richdocuments', 'documentSigningCert', $documentSigningCertInput);
} catch (PreConditionNotMetException $e) {
$message = $this->l10n->t('Error when saving');
$status = 'error';
}
}
if ($documentSigningKeyInput !== null) {
try {
$this->config->setUserValue($this->userId, 'richdocuments', 'documentSigningKey', $documentSigningKeyInput);
} catch (PreConditionNotMetException $e) {
$message = $this->l10n->t('Error when saving');
$status = 'error';
}
}
if ($documentSigningCaInput !== null) {
try {
$this->config->setUserValue($this->userId, 'richdocuments', 'documentSigningCa', $documentSigningCaInput);
Expand Down
4 changes: 4 additions & 0 deletions lib/Controller/WopiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,10 @@ public function checkFileInfo(string $fileId, string $access_token): JSONRespons
}
$enableDocumentSigning = $this->config->getAppValue(Application::APPNAME, 'documentSigningEnabled', 'yes') === 'yes';
if (!$isPublic && $enableDocumentSigning) {
$documentSigningCert = $this->config->getUserValue($wopi->getEditorUid(), 'richdocuments', 'documentSigningCert', '');
$response['UserPrivateInfo']['SignatureCert'] = $documentSigningCert;
$documentSigningKey = $this->config->getUserValue($wopi->getEditorUid(), 'richdocuments', 'documentSigningKey', '');
$response['UserPrivateInfo']['SignatureKey'] = $documentSigningKey;
$documentSigningCa = $this->config->getUserValue($wopi->getEditorUid(), 'richdocuments', 'documentSigningCa', '');
$response['UserPrivateInfo']['SignatureCa'] = $documentSigningCa;
}
Expand Down
2 changes: 2 additions & 0 deletions lib/Settings/Personal.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public function getForm() {
[
'templateFolder' => $this->config->getUserValue($this->userId, 'richdocuments', 'templateFolder', ''),
'hasDocumentSigningSupport' => $this->capabilitiesService->hasDocumentSigningSupport(),
'documentSigningCert' => $this->config->getUserValue($this->userId, 'richdocuments', 'documentSigningCert', ''),
'documentSigningKey' => $this->config->getUserValue($this->userId, 'richdocuments', 'documentSigningKey', ''),
'documentSigningCa' => $this->config->getUserValue($this->userId, 'richdocuments', 'documentSigningCa', ''),
'hasZoteroSupport' => $this->capabilitiesService->hasZoteroSupport(),
'zoteroAPIKey' => $this->config->getUserValue($this->userId, 'richdocuments', 'zoteroAPIKey', '')
Expand Down
51 changes: 50 additions & 1 deletion src/personal.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ import { showError } from '@nextcloud/dialogs'
this.zoteroAPIKeySaveButton = document.getElementById('zoteroAPIKeySave')
this.zoteroAPIKeyRemoveButton = document.getElementById('zoteroAPIKeyRemove')

this.documentSigningCertInput = document.getElementById('documentSigningCertField')
this.documentSigningCertSaveButton = document.getElementById('documentSigningCertSave')
this.documentSigningCertRemoveButton = document.getElementById('documentSigningCertRemove')
this.documentSigningKeyInput = document.getElementById('documentSigningKeyField')
this.documentSigningKeySaveButton = document.getElementById('documentSigningKeySave')
this.documentSigningKeyRemoveButton = document.getElementById('documentSigningKeyRemove')
this.documentSigningCaInput = document.getElementById('documentSigningCaField')
this.documentSigningCaSaveButton = document.getElementById('documentSigningCaSave')
this.documentSigningCaRemoveButton = document.getElementById('documentSigningCaRemove')
Expand All @@ -36,10 +42,17 @@ import { showError } from '@nextcloud/dialogs'

this.zoteroAPIKeyRemoveButton.addEventListener('click', this.resetZoteroAPI.bind(this))

this.documentSigningCertSaveButton.addEventListener('click', function() {
self.updateDocumentSigningCert(self.documentSigningCertInput.value)
})
this.documentSigningCertRemoveButton.addEventListener('click', this.resetDocumentSigningCert.bind(this))
this.documentSigningKeySaveButton.addEventListener('click', function() {
self.updateDocumentSigningKey(self.documentSigningKeyInput.value)
})
this.documentSigningKeyRemoveButton.addEventListener('click', this.resetDocumentSigningKey.bind(this))
this.documentSigningCaSaveButton.addEventListener('click', function() {
self.updateDocumentSigningCa(self.documentSigningCaInput.value)
})

this.documentSigningCaRemoveButton.addEventListener('click', this.resetDocumentSigningCa.bind(this))
}

Expand Down Expand Up @@ -79,6 +92,42 @@ import { showError } from '@nextcloud/dialogs'
})
}

PersonalSettings.prototype.updateDocumentSigningCert = function(ca) {
const self = this
this._updateSetting({ documentSigningCertInput: ca }, function() {
self.documentSigningCertInput.value = ca
}, function() {
showError(t('richdocuments', 'Failed to update the document signing CA chain'))
})
}

PersonalSettings.prototype.resetDocumentSigningCert = function() {
const self = this
this._updateSetting({ documentSigningCertInput: '' }, function() {
self.documentSigningCertInput.value = ''
}, function() {

})
}

PersonalSettings.prototype.updateDocumentSigningKey = function(ca) {
const self = this
this._updateSetting({ documentSigningKeyInput: ca }, function() {
self.documentSigningKeyInput.value = ca
}, function() {
showError(t('richdocuments', 'Failed to update the document signing CA chain'))
})
}

PersonalSettings.prototype.resetDocumentSigningKey = function() {
const self = this
this._updateSetting({ documentSigningKeyInput: '' }, function() {
self.documentSigningKeyInput.value = ''
}, function() {

})
}

PersonalSettings.prototype.updateDocumentSigningCa = function(ca) {
const self = this
this._updateSetting({ documentSigningCaInput: ca }, function() {
Expand Down
10 changes: 10 additions & 0 deletions templates/personal.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,16 @@
<p><strong><?php p($l->t('Document signing')) ?></strong></p>
<?php if ($_['hasDocumentSigningSupport']) { ?>
<div class="input-wrapper">
<p><label for="documentSigningCertField"><?php p($l->t('Enter document signing cert (in PEM format)')); ?></label><br />
<textarea type="text" name="documentSigningCertField" id="documentSigningCertField"><?php p($_['documentSigningCert']); ?></textarea><br />
<button id="documentSigningCertSave"><span title="<?php p($l->t('Save document signing cert')); ?>" data-toggle="tooltip">Save</span></button>
<button id="documentSigningCertRemove"><span class="icon-delete" title="<?php p($l->t('Remove document signing cert')); ?>" data-toggle="tooltip"></span></button>
</p>
<p><label for="documentSigningKeyField"><?php p($l->t('Enter document signing key')); ?></label><br />
<textarea type="text" name="documentSigningKeyField" id="documentSigningKeyField"><?php p($_['documentSigningKey']); ?></textarea><br />
<button id="documentSigningKeySave"><span title="<?php p($l->t('Save document signing key')); ?>" data-toggle="tooltip">Save</span></button>
<button id="documentSigningKeyRemove"><span class="icon-delete" title="<?php p($l->t('Remove document signing key')); ?>" data-toggle="tooltip"></span></button>
</p>
<p><label for="documentSigningCaField"><?php p($l->t('Enter document signing CA chain')); ?></label><br />
<textarea type="text" name="documentSigningCaField" id="documentSigningCaField"><?php p($_['documentSigningCa']); ?></textarea><br />
<button id="documentSigningCaSave"><span title="<?php p($l->t('Save document signing CA chain')); ?>" data-toggle="tooltip">Save</span></button>
Expand Down

0 comments on commit adfb905

Please sign in to comment.