Skip to content

Commit

Permalink
Merge pull request #2520 from LibreSign/backport/2519/stable28
Browse files Browse the repository at this point in the history
[stable28] Show certificate data
  • Loading branch information
vitormattos authored Mar 13, 2024
2 parents 4aa01fe + 702c0f7 commit 473b096
Show file tree
Hide file tree
Showing 10 changed files with 296 additions and 14 deletions.
1 change: 1 addition & 0 deletions appinfo/routes/routesAccountController.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
['name' => 'account#createToSign', 'url' => '/api/{apiVersion}/account/create/{uuid}', 'verb' => 'POST', 'requirements' => $requirements],
['name' => 'account#me', 'url' => '/api/{apiVersion}/account/me', 'verb' => 'GET', 'requirements' => $requirements],
['name' => 'account#uploadPfx', 'url' => '/api/{apiVersion}/account/pfx', 'verb' => 'POST', 'requirements' => $requirements],
['name' => 'account#readPfxData', 'url' => '/api/{apiVersion}/account/pfx/read', 'verb' => 'POST', 'requirements' => $requirements],
['name' => 'account#updatePfxPassword', 'url' => '/api/{apiVersion}/account/pfx', 'verb' => 'PATCH', 'requirements' => $requirements],
['name' => 'account#deletePfx', 'url' => '/api/{apiVersion}/account/pfx', 'verb' => 'DELETE', 'requirements' => $requirements],
['name' => 'account#updateSettings', 'url' => '/api/{apiVersion}/account/settings', 'verb' => 'PATCH', 'requirements' => $requirements],
Expand Down
19 changes: 19 additions & 0 deletions lib/Controller/AccountController.php
Original file line number Diff line number Diff line change
Expand Up @@ -538,4 +538,23 @@ public function updatePfxPassword($current, $new): JSONResponse {
Http::STATUS_ACCEPTED
);
}

#[NoAdminRequired]
#[NoCSRFRequired]
public function readPfxData(string $password): JSONResponse {
try {
$data = $this->accountService->readPfxData($this->userSession->getUser(), $password);
} catch (LibresignException $e) {
return new JSONResponse(
[
'message' => $e->getMessage()
],
Http::STATUS_BAD_REQUEST
);
}
return new JSONResponse(
$data,
Http::STATUS_ACCEPTED
);
}
}
27 changes: 27 additions & 0 deletions lib/Handler/CertificateEngine/AEngineHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
use OCP\Files\IAppData;
use OCP\Files\SimpleFS\ISimpleFolder;
use OCP\IConfig;
use OCP\IDateTimeFormatter;
use ReflectionClass;

/**
Expand Down Expand Up @@ -76,6 +77,7 @@ public function __construct(
protected IConfig $config,
protected IAppConfig $appConfig,
protected IAppDataFactory $appDataFactory,
protected IDateTimeFormatter $dateTimeFormatter,
) {
$this->appData = $appDataFactory->get('libresign');
}
Expand Down Expand Up @@ -116,6 +118,31 @@ public function updatePassword(string $certificate, string $currentPrivateKey, s
return $certContent;
}

public function readCertificate(string $certificate, string $privateKey): array {
if (empty($certificate) || empty($privateKey)) {
throw new EmptyRootCertificateException();
}
openssl_pkcs12_read($certificate, $certContent, $privateKey);
if (empty($certContent)) {
throw new InvalidPasswordException();
}
$parsed = openssl_x509_parse(openssl_x509_read($certContent['cert']));

$return['name'] = $parsed['name'];
$return['subject'] = $parsed['subject'];
if (is_array($return['subject']['OU']) && !empty($return['subject']['OU'])) {
$return['subject']['OU'] = implode(', ', $return['subject']['OU']);
}
$return['subjectAltName'] = $parsed['extensions']['subjectAltName'];
$return['issuer'] = $parsed['issuer'];
$return['issuerInfoAccess'] = $parsed['extensions']['authorityInfoAccess'];
$return['validate'] = [
'from' => $this->dateTimeFormatter->formatDateTime($parsed['validFrom_time_t']),
'to' => $this->dateTimeFormatter->formatDateTime($parsed['validTo_time_t']),
];
return $return;
}

public function translateToLong($name): string {
switch ($name) {
case 'CN':
Expand Down
4 changes: 3 additions & 1 deletion lib/Handler/CertificateEngine/CfsslHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
use OCP\AppFramework\Services\IAppConfig;
use OCP\Files\AppData\IAppDataFactory;
use OCP\IConfig;
use OCP\IDateTimeFormatter;

/**
* Class CfsslHandler
Expand All @@ -58,8 +59,9 @@ public function __construct(
private SystemConfig $systemConfig,
private CfsslServerHandler $cfsslServerHandler,
protected IAppDataFactory $appDataFactory,
protected IDateTimeFormatter $dateTimeFormatter,
) {
parent::__construct($config, $appConfig, $appDataFactory);
parent::__construct($config, $appConfig, $appDataFactory, $dateTimeFormatter);
}

private function getClient(): Client {
Expand Down
8 changes: 8 additions & 0 deletions lib/Handler/Pkcs12Handler.php
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,14 @@ public function updatePassword(string $uid, string $currentPrivateKey, string $n
return $this->savePfx($uid, $content);
}

public function readCertificate(string $uid, string $privateKey): array {
$pfx = $this->getPfx($uid);
return $this->certificateEngineHandler->getEngine()->readCertificate(
$pfx,
$privateKey
);
}

/**
* Get content of pfx file
*/
Expand Down
11 changes: 11 additions & 0 deletions lib/Service/AccountService.php
Original file line number Diff line number Diff line change
Expand Up @@ -522,4 +522,15 @@ public function updatePfxPassword(IUser $user, string $current, string $new): vo
throw new LibresignException($this->l10n->t('Invalid user or password'));
}
}

/**
* @throws LibresignException when have not a certificate file
*/
public function readPfxData(IUser $user, string $password): array {
try {
return $this->pkcs12Handler->readCertificate($user->getUID(), $password);
} catch (InvalidPasswordException $e) {
throw new LibresignException($this->l10n->t('Invalid user or password'));
}
}
}
7 changes: 7 additions & 0 deletions src/helpers/certification.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,13 @@ export const options = [
value: '',
helperText: t('libresign', 'Two-letter ISO 3166 country code'),
},
{
id: 'CN',
label: 'Name',
min: 1,
value: '',
helperText: t('libresign', 'Name (CN)'),
},
{
id: 'ST',
label: 'State',
Expand Down
27 changes: 20 additions & 7 deletions src/views/Account/Account.vue
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,14 @@
<CloudUploadIcon :size="20" />
</template>
</NcButton>
<NcButton v-if="signMethodsStore.hasSignatureFile()"
:wide="true"
@click="handleModal('readCertificate')">
{{ t('libresign', 'Read certificate') }}
<template #icon>
<LockOpenCheckIcon :size="20" />
</template>
</NcButton>
<NcButton v-if="signMethodsStore.hasSignatureFile()"
:wide="true"
@click="deleteCertificate()">
Expand All @@ -30,25 +38,26 @@
</NcButton>
<NcButton v-if="certificateEngine !== 'none' && !signMethodsStore.hasSignatureFile()"
:wide="true"
@click="handleModal(true)">
@click="handleModal('createPassword')">
{{ t('libresign', 'Create certificate') }}
<template #icon>
<CertificateIcon :size="20" />
</template>
</NcButton>
<NcButton v-else-if="signMethodsStore.hasSignatureFile()"
:wide="true"
@click="handleModal(true)">
@click="handleModal('resetPassword')">
{{ t('librsign', 'Change password') }}
<template #icon>
<FileReplaceIcon :size="20" />
</template>
</NcButton>
</div>
<NcModal v-if="modal"
@close="handleModal(false)">
<CreatePassword v-if="!signMethodsStore.hasSignatureFile()" @close="handleModal(false)" />
<ResetPassword v-if="signMethodsStore.hasSignatureFile()" @close="handleModal(false)" />
<NcModal v-if="modal.length > 0"
@close="handleModal('')">
<CreatePassword v-if="modal === 'createPassword'" @close="handleModal('')" />
<ReadCertificate v-if="modal === 'readCertificate'" @close="handleModal('')" />
<ResetPassword v-if="modal === 'resetPassword'" @close="handleModal('')" />
</NcModal>
</div>
</div>
Expand All @@ -72,10 +81,12 @@ import axios from '@nextcloud/axios'
import { generateOcsUrl } from '@nextcloud/router'
import { showError, showSuccess } from '@nextcloud/dialogs'
import CloudUploadIcon from 'vue-material-design-icons/CloudUpload.vue'
import LockOpenCheckIcon from 'vue-material-design-icons/LockOpenCheck.vue'
import DeleteIcon from 'vue-material-design-icons/Delete.vue'
import FileReplaceIcon from 'vue-material-design-icons/FileReplace.vue'
import CertificateIcon from 'vue-material-design-icons/Certificate.vue'
import CreatePassword from '../CreatePassword.vue'
import ReadCertificate from '../ReadCertificate.vue'
import ResetPassword from '../ResetPassword.vue'
import UserImage from './partials/UserImage.vue'
import Signatures from './partials/Signatures.vue'
Expand All @@ -90,10 +101,12 @@ export default {
NcContent,
NcButton,
CloudUploadIcon,
LockOpenCheckIcon,
DeleteIcon,
FileReplaceIcon,
CertificateIcon,
CreatePassword,
ReadCertificate,
ResetPassword,
Signatures,
UserImage,
Expand All @@ -107,7 +120,7 @@ export default {
data() {
return {
user: getCurrentUser(),
modal: false,
modal: '',
certificateEngine: loadState('libresign', 'certificate_engine', ''),
}
},
Expand Down
7 changes: 1 addition & 6 deletions src/views/CreatePassword.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,10 +49,8 @@ export default {
},
data() {
return {
modal: false,
hasLoading: false,
password: '',
hasPfx: false,
}
},
methods: {
Expand All @@ -64,7 +62,7 @@ export default {
.then(() => {
showSuccess(t('libresign', 'New password to sign documents has been created'))
this.signMethodsStore.setHasSignatureFile(true)
this.clear()
this.password = ''
this.$emit('close', true)
this.$emit('password:created', true)
})
Expand All @@ -79,9 +77,6 @@ export default {
})
this.hasLoading = false
},
clear() {
this.password = ''
},
},
}
</script>
Expand Down
Loading

0 comments on commit 473b096

Please sign in to comment.