Skip to content

Commit

Permalink
Merge pull request #4129 from vmiklos/sign
Browse files Browse the repository at this point in the history
Digitally sign documents via software certificates
  • Loading branch information
elzody authored Oct 21, 2024
2 parents 5c699f1 + adfb905 commit d09ae22
Show file tree
Hide file tree
Showing 7 changed files with 158 additions and 1 deletion.
12 changes: 12 additions & 0 deletions css/admin.scss
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,18 @@ input#zoteroAPIKeyField {
width: 300px;
}

textarea#documentSigningCertField {
width: 600px;
}

textarea#documentSigningKeyField {
width: 600px;
}

textarea#documentSigningCaField {
width: 600px;
}

#richdocuments,
#richdocuments-templates {
// inline buttons on section headers
Expand Down
30 changes: 29 additions & 1 deletion lib/Controller/SettingsController.php
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,10 @@ public function updateWatermarkSettings($settings = []): JSONResponse {
* @return JSONResponse
*/
public function setPersonalSettings($templateFolder,
$zoteroAPIKeyInput) {
$zoteroAPIKeyInput,
$documentSigningCertInput,
$documentSigningKeyInput,
$documentSigningCaInput) {
$message = $this->l10n->t('Saved');
$status = 'success';

Expand All @@ -257,6 +260,31 @@ 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);
} catch (PreConditionNotMetException $e) {
$message = $this->l10n->t('Error when saving');
$status = 'error';
}
}

$response = [
'status' => $status,
'data' => ['message' => $message]
Expand Down
9 changes: 9 additions & 0 deletions lib/Controller/WopiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,15 @@ public function checkFileInfo(string $fileId, string $access_token): JSONRespons
$zoteroAPIKey = $this->config->getUserValue($wopi->getEditorUid(), 'richdocuments', 'zoteroAPIKey', '');
$response['UserPrivateInfo']['ZoteroAPIKey'] = $zoteroAPIKey;
}
$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;
}
if ($wopi->hasTemplateId()) {
$response['TemplateSource'] = $this->getWopiUrlForTemplate($wopi);
}
Expand Down
4 changes: 4 additions & 0 deletions lib/Service/CapabilitiesService.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ public function hasWASMSupport(): bool {
return $this->getCapabilities()['hasWASMSupport'] ?? false;
}

public function hasDocumentSigningSupport(): bool {
return $this->getCapabilities()['hasDocumentSigningSupport'] ?? false;
}

public function hasFormFilling(): bool {
return $this->isVersionAtLeast('24.04.5.2');
}
Expand Down
4 changes: 4 additions & 0 deletions lib/Settings/Personal.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ public function getForm() {
'personal',
[
'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
77 changes: 77 additions & 0 deletions src/personal.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,16 @@ 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')

const self = this
this.templateSelectButton.addEventListener('click', function() {
OC.dialogs.filepicker(t('richdocuments', 'Select a personal template folder'), function(datapath, returntype) {
Expand All @@ -31,6 +41,19 @@ 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))
}

PersonalSettings.prototype.updateSetting = function(path) {
Expand Down Expand Up @@ -69,6 +92,60 @@ 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() {
self.documentSigningCaInput.value = ca
}, function() {
showError(t('richdocuments', 'Failed to update the document signing CA chain'))
})
}

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

})
}

PersonalSettings.prototype._updateSetting = function(data, successCallback, errorCallback) {
OC.msg.startAction('#documents-admin-msg', t('richdocuments', 'Saving …'))
const request = new XMLHttpRequest()
Expand Down
23 changes: 23 additions & 0 deletions templates/personal.php
Original file line number Diff line number Diff line change
Expand Up @@ -30,5 +30,28 @@
<?php } else { ?>
<p><em><?php p($l->t('This instance does not support Zotero, because the feature is missing or disabled. Please contact the administration.')); ?></em></p>
<?php } ?>
<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>
<button id="documentSigningCaRemove"><span class="icon-delete" title="<?php p($l->t('Remove document signing CA chain')); ?>" data-toggle="tooltip"></span></button>
</p>
<p><em><?php p($l->t('To use document signing, specify your signing certificate, key and CA chain here.')); ?></em></p>
</div>
<?php } else { ?>
<p><em><?php p($l->t('This instance does not support document signing, because the feature is missing or disabled. Please contact the administrator.')); ?></em></p>
<?php } ?>
</div>
</div>

0 comments on commit d09ae22

Please sign in to comment.