Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Digitally sign documents via software certificates #4129

Merged
merged 3 commits into from
Oct 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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')
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be great if we can rather add this to the vue.js based frontend, but maybe that is something where @elzody can help moving that over

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, I was just tracing how the zotero API key setting does this, and this way seemed to be the way it works. Maybe move the zotero API key handling to the vue.js based frontend, and then I'm happy to do the same for these settings as well? Thanks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, also wouldn't consider this a blocker then especially since zotero is also still there in the legacy part. We can migrate them together afterwards as well

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>
Loading