Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
Signed-off-by: Vitor Mattos <[email protected]>
  • Loading branch information
vitormattos committed Apr 24, 2023
1 parent 03b683f commit 9d49cf4
Show file tree
Hide file tree
Showing 9 changed files with 91 additions and 21 deletions.
8 changes: 4 additions & 4 deletions lib/Db/FileUserMapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -346,7 +346,7 @@ private function getFilesAssociatedFilesWithMeStmt(string $userId): Pagination {
->selectAlias($qb->func()->max('fu.signed'), 'status_date')
->from('libresign_file', 'f')
->leftJoin('f', 'libresign_file_user', 'fu', 'fu.file_id = f.id')
->leftJoin('f', 'libresign_identify_method', 'im', $qb->expr()->andX(
->leftJoin('f', 'libresign_identify_method', 'im', $qb->expr()->andX(
$qb->expr()->eq('fu.id', 'im.file_user_id'),
$qb->expr()->eq('im.method', $qb->createNamedParameter('nextcloud')),
$qb->expr()->eq('im.identifier_key', $qb->createNamedParameter('uid'))
Expand Down Expand Up @@ -397,7 +397,7 @@ private function associateAllAndFormat(IUser $user, array $files, array $signers
foreach ($signers as $signerKey => $signer) {
if ($signer->getFileId() === $file['id']) {
$data = [
'email' => array_reduce($identifyMethods[$signer->getId()] ?? [], function(string $carry, IdentifyMethod $identifyMethod): bool {
'email' => array_reduce($identifyMethods[$signer->getId()] ?? [], function (string $carry, IdentifyMethod $identifyMethod): bool {
if ($identifyMethod->getIdentifierKey() === 'uid') {
return $identifyMethod->getIdentifierValue();
} elseif ($identifyMethod->getIdentifierKey() === 'email') {
Expand All @@ -411,14 +411,14 @@ private function associateAllAndFormat(IUser $user, array $files, array $signers
->setTimestamp($signer->getCreatedAt())
->format('Y-m-d H:i:s'),
'sign_date' => null,
'uid' => array_reduce($identifyMethods[$signer->getId()] ?? [], function(string $carry, IdentifyMethod $identifyMethod): bool {
'uid' => array_reduce($identifyMethods[$signer->getId()] ?? [], function (string $carry, IdentifyMethod $identifyMethod): bool {
if ($identifyMethod->getIdentifierKey() === 'uid') {
return $identifyMethod->getIdentifierValue();
}
return $carry;
}, ''),
'fileUserId' => $signer->getId(),
'me' => array_reduce($identifyMethods[$signer->getId()] ?? [], function(bool $carry, IdentifyMethod $identifyMethod) use ($user): bool {
'me' => array_reduce($identifyMethods[$signer->getId()] ?? [], function (bool $carry, IdentifyMethod $identifyMethod) use ($user): bool {
if (!$user->getEMailAddress()) {
return false;
}
Expand Down
26 changes: 26 additions & 0 deletions lib/Service/AccountService.php
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,33 @@ public function createToSign(string $uuid, string $uid, string $password, ?strin
* @psalm-return array{action?: int, user?: array{name: mixed}, sign?: array{pdf: mixed, uuid: mixed, filename: mixed, description: mixed}, errors?: non-empty-list<mixed>, redirect?: mixed, settings: array{accountHash: string, hasSignatureFile: bool}}
*/
public function getConfig(string $typeOfUuid, ?string $uuid, ?IUser $user, string $formatOfPdfOnSign): array {
/**
* @todo WIP, don't merge. Necessary identify how will get this info to send to web client
*/
try {
$this->fsm->setPayload($typeOfUuid, $uuid, $user, $formatOfPdfOnSign);

if (!$this->isValidUrl()) {
// next state: do nothing
// Message: invalid data
return;
}
if ($this->identifyMethodService->haveSession()) {
if (!$this->identifyMethodService->isMyDocument()) {
// next state: do nothing
// Message: haven't access
return;
}
if (!$this->identifyMethodService->iCanSign()) {
// next state: do nothing
// Message: get the reason
return;
}
// next state: show document
return;
}
return $this->identifyMethodService->nextState();

if ($typeOfUuid === 'file_user_uuid') {
$info = $this->signFileService->getInfoOfFileToSignUsingFileUserUuid($uuid, $user, $formatOfPdfOnSign);
} else {
Expand Down
4 changes: 4 additions & 0 deletions lib/Service/IdentifyMethod/AbstractIdentifyMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,10 @@ public function __construct() {
$this->entity = new IdentifyMethod();
}

public function setEntity(IdentifyMethod $entity): void {
$this->entity = $entity;
}

public function getEntity(): IdentifyMethod {
return $this->entity;
}
Expand Down
1 change: 1 addition & 0 deletions lib/Service/IdentifyMethod/IIdentifyMethod.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
use OCA\Libresign\Db\IdentifyMethod;

interface IIdentifyMethod {
public function setEntity(IdentifyMethod $entity): void;
public function getEntity(): IdentifyMethod;
public function notify(bool $isNew, FileUser $fileUser): void;
public function validate(): void;
Expand Down
12 changes: 8 additions & 4 deletions lib/Service/IdentifyMethodService.php
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ public function getDefaultIdentifyMethodName(): string {
?? IdentifyMethodService::IDENTIFY_NEXTCLOUD;
}

public function validateAll(): void {
public function validateToRequestToSign(): void {
if (!array_key_exists($this->getDefaultIdentifyMethodName(), $this->identifyMethod)) {
/**
* @todo check if is necessary to return a more specific message. i.e.: the identification method xpto wasn't found
Expand Down Expand Up @@ -141,11 +141,15 @@ public function getDefaultIdentiyMethod(int $fileUserId): IdentifyMethod {

/**
* @param integer $fileUserId
* @return array<IdentifyMethod>
* @return array<IIdentifyMethod>
*/
public function getIdentifyMethodsFromFileUserId(int $fileUserId): array {
$identifyMethods = $this->identifyMethodMapper->getIdentifyMethodsFromFileUserId($fileUserId);
return $identifyMethods;
$entities = $this->identifyMethodMapper->getIdentifyMethodsFromFileUserId($fileUserId);
foreach ($entities as $entity) {
$identifyMethod = $this->getIdentifyMethod($entity->getMethod());
$identifyMethod->setEntity($entity);
}
return $this->identifyMethod;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion lib/Service/RequestSignatureService.php
Original file line number Diff line number Diff line change
Expand Up @@ -204,7 +204,7 @@ public function validateUsers(array $data): void {
}
foreach ($data['users'] as $user) {
$this->identifyMethod->setAllEntityData($user);
$this->identifyMethod->validateAll($user);
$this->identifyMethod->validateToRequestToSign($user);
}
}

Expand Down
19 changes: 17 additions & 2 deletions lib/Service/SignFileService.php
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,21 @@ private function throwIfAlreadySigned(FileEntity $fileEntity, ?FileUserEntity $f
* @todo validate here if is possible identify the user by identification methods
*/
private function trhowIfCantIdentifyUser(string $uuid, ?IUser $user, ?FileUserEntity $fileUser): void {
$identifyMethods = $this->identifyMethod->getIdentifyMethodsFromFileUserId($fileUser->getId());
$maxAttempts = (int) $this->config->getAppValue(Application::APP_ID, 'max_attempts', 5);
foreach ($identifyMethods as $identifyMethod) {
$entity = $identifyMethod->getEntity();
if ($entity->getIdentifiedAtDate()) {
continue;
}
if ($entity->getAttempts() > $maxAttempts) {
throw new LibresignException(json_encode([
'action' => JSActions::ACTION_DO_NOTHING,
'errors' => [$this->l10n->t('Exceeded identification attempts')],
]));
}
$identifyMethod->validateContextBeforeSign($user, $fileUser);
}
if ($fileUser instanceof FileUserEntity) {
$identifyMethods = $this->identifyMethodMapper->getIdentifyMethodsFromFileUserId($fileUser->getId());
$nextcloudIdentifyMethod = array_filter($identifyMethods, function (IdentifyMethod $identifyMethod): bool {
Expand All @@ -566,7 +581,7 @@ private function trhowIfCantIdentifyUser(string $uuid, ?IUser $user, ?FileUserEn
]));
}
$identifyMethods = $this->identifyMethodMapper->getIdentifyMethodsFromFileUserId($fileUser->getId());
$email = array_reduce($identifyMethods, function(string $carry, IdentifyMethod $identifyMethod): string {
$email = array_reduce($identifyMethods, function (string $carry, IdentifyMethod $identifyMethod): string {
/**
* @todo go-horse to make working with implementation when is necessary to have an email
*/
Expand Down Expand Up @@ -600,7 +615,7 @@ private function trhowIfCantIdentifyUser(string $uuid, ?IUser $user, ?FileUserEn
*/
private function throwIfUserIsNotSigner(?IUser $user, FileUserEntity $fileUser): void {
$identifyMethods = $this->identifyMethodMapper->getIdentifyMethodsFromFileUserId($fileUser->getId());
$uid = array_reduce($identifyMethods, function(string $carry, IdentifyMethod $identifyMethod): string {
$uid = array_reduce($identifyMethods, function (string $carry, IdentifyMethod $identifyMethod): string {
/**
* @todo go-horse to make working with implementation when is necessary to have an email
*/
Expand Down
24 changes: 23 additions & 1 deletion tests/integration/features/bootstrap/FeatureContext.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,20 @@
use Behat\Gherkin\Node\TableNode;
use Libresign\NextcloudBehat\NextcloudApiContext;
use PHPUnit\Framework\Assert;
use rpkamp\Behat\MailhogExtension\Context\OpenedEmailStorageAwareContext;
use rpkamp\Behat\MailhogExtension\Service\OpenedEmailStorage;

/**
* Defines application features from the specific context.
*/
class FeatureContext extends NextcloudApiContext {
class FeatureContext extends NextcloudApiContext implements OpenedEmailStorageAwareContext {
private array $signer = [];
private array $file = [];
private OpenedEmailStorage $openedEmailStorage;

public function setOpenedEmailStorage(OpenedEmailStorage $storage): void {
$this->openedEmailStorage = $storage;
}

/**
* @Then /^the signer "([^"]*)" have a file to sign$/
Expand Down Expand Up @@ -94,4 +101,19 @@ public function theSignerContains(TableNode $table): void {
Assert::assertEquals($value['value'], $actual);
}
}

/**
* @Then follow the link on opened email
*/
public function iDoSomethingWithTheOpenedEmail(): void {
if (!$this->openedEmailStorage->hasOpenedEmail()) {
throw new RuntimeException('No email opened, unable to do something!');
}

/** @var \rpkamp\Mailhog\Message\Message $openedEmail */
$openedEmail = $this->openedEmailStorage->getOpenedEmail();
preg_match('/p\/sign\/(?<uuid>[\w-]+)"/', $openedEmail->body, $matches);

$this->sendRequest('get', '/apps/libresign/p/sign/' . $matches['uuid']);
}
}
16 changes: 7 additions & 9 deletions tests/integration/features/page/sign_identify_email.feature
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
Feature: page/sign_identify_token
Background: Create users
Given user "signer1" exists
And as user "admin"
And set the email of user "signer1" to "[email protected]"
And my inbox is empty
Given as user "admin"
And the following "libresign" app config is set
| identify_method | email |
And my inbox is empty
And sending "post" to "/apps/libresign/api/0.1/request-signature"
| file | {"base64":"data:application/pdf;base64,JVBERi0xLjYKJcOkw7zDtsOfCjIgMCBvYmoKPDwvTGVuZ3RoIDMgMCBSL0ZpbHRlci9GbGF0ZURlY29kZT4+CnN0cmVhbQp4nDPQM1Qo5ypUMFAw0DMwslAwtTTVMzIxV7AwMdSzMDNUKErlCtdSyOMyVADBonQuA4iUhaVCLheKYqBIDlw7xLAcuLEgFlwVVwZXmhZXoAIAI+sZGAplbmRzdHJlYW0KZW5kb2JqCgozIDAgb2JqCjg2CmVuZG9iagoKNSAwIG9iago8PAo+PgplbmRvYmoKCjYgMCBvYmoKPDwvRm9udCA1IDAgUgovUHJvY1NldFsvUERGL1RleHRdCj4+CmVuZG9iagoKMSAwIG9iago8PC9UeXBlL1BhZ2UvUGFyZW50IDQgMCBSL1Jlc291cmNlcyA2IDAgUi9NZWRpYUJveFswIDAgNTk1LjI3NTU5MDU1MTE4MSA4NDEuODg5NzYzNzc5NTI4XS9Hcm91cDw8L1MvVHJhbnNwYXJlbmN5L0NTL0RldmljZVJHQi9JIHRydWU+Pi9Db250ZW50cyAyIDAgUj4+CmVuZG9iagoKNCAwIG9iago8PC9UeXBlL1BhZ2VzCi9SZXNvdXJjZXMgNiAwIFIKL01lZGlhQm94WyAwIDAgNTk1IDg0MSBdCi9LaWRzWyAxIDAgUiBdCi9Db3VudCAxPj4KZW5kb2JqCgo3IDAgb2JqCjw8L1R5cGUvQ2F0YWxvZy9QYWdlcyA0IDAgUgovT3BlbkFjdGlvblsxIDAgUiAvWFlaIG51bGwgbnVsbCAwXQo+PgplbmRvYmoKCjggMCBvYmoKPDwvQ3JlYXRvcjxGRUZGMDA0NDAwNzIwMDYxMDA3Nz4KL1Byb2R1Y2VyPEZFRkYwMDRDMDA2OTAwNjIwMDcyMDA2NTAwNEYwMDY2MDA2NjAwNjkwMDYzMDA2NTAwMjAwMDM3MDAyRTAwMzA+Ci9DcmVhdGlvbkRhdGUoRDoyMDIxMDIyMzExMDgwOS0wMycwMCcpPj4KZW5kb2JqCgp4cmVmCjAgOQowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAyNzAgMDAwMDAgbiAKMDAwMDAwMDAxOSAwMDAwMCBuIAowMDAwMDAwMTc2IDAwMDAwIG4gCjAwMDAwMDA0MzggMDAwMDAgbiAKMDAwMDAwMDE5NSAwMDAwMCBuIAowMDAwMDAwMjE3IDAwMDAwIG4gCjAwMDAwMDA1MzYgMDAwMDAgbiAKMDAwMDAwMDYxOSAwMDAwMCBuIAp0cmFpbGVyCjw8L1NpemUgOS9Sb290IDcgMCBSCi9JbmZvIDggMCBSCi9JRCBbIDw1RkQ4MDlEMTdFODMwQUU5OTRDODkxNDVBMTMwNUQyQz4KPDVGRDgwOUQxN0U4MzBBRTk5NEM4OTE0NUExMzA1RDJDPiBdCi9Eb2NDaGVja3N1bSAvRDZBQThGQTBBQjMwODg2QkQ5ODU0QzYyMTg5QjI2NDQKPj4Kc3RhcnR4cmVmCjc4NQolJUVPRgo="} |
| users | [{"identifyMethods":{"email":"signer1@domain.test"}}] |
| users | [{"identifyMethods":{"email":"signer2@domain.test"}}] |
| name | document |
And the response should have a status code 200
And there should be 1 emails in my inbox
Expand All @@ -18,24 +16,24 @@ Feature: page/sign_identify_token
Scenario: Open sign file with invalid data
# With invalid UUID, need to be the signer UUID
When as user "signer1"
And sending "get" to "/apps/libresign/p/sign/<FILE_UUID>"
And sending "get" to "/apps/libresign/p/sign/invalid"
Then the response should contain the initial state "libresign-config" with the following values:
| key | value |
| action | 200 |
| errors | ["Invalid UUID"] |
| settings | {"identificationDocumentsFlow":false,"certificateOk":false,"hasSignatureFile":false,"phoneNumber":"","isApprover":false} |
# With invalid user
When as user "admin"
And sending "get" to "/apps/libresign/p/sign/<SIGN_UUID>"
And follow the link on opened email
Then the response should contain the initial state "libresign-config" with the following values:
| key | value |
| action | 200 |
| errors | ["Invalid user"] |
| errors | ["This is not your file"] |
| settings | {"identificationDocumentsFlow":false,"certificateOk":false,"hasSignatureFile":false,"phoneNumber":"","isApprover":true} |

Scenario: Open sign file with all data valid
When as user ""
And sending "get" to "/apps/libresign/p/sign/<SIGN_UUID>"
And follow the link on opened email
Then the response should contain the initial state "libresign-config" with the following values:
| key | value |
| action | 250 |
Expand Down

0 comments on commit 9d49cf4

Please sign in to comment.