-
-
Notifications
You must be signed in to change notification settings - Fork 95
feat: sign usign twofactor_gateway #5459
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
Open
vitormattos
wants to merge
48
commits into
main
Choose a base branch
from
feat/sign-using-twofactor_gateway
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from 42 commits
Commits
Show all changes
48 commits
Select commit
Hold shift + click to select a range
80e9a7f
chore: stop search early if haven't values to search for
vitormattos 5598b8c
feat: Search by signers
vitormattos 721e7e3
fix: add pendign param
vitormattos 49325a8
chore: update openapi
vitormattos b6a1fc3
fix: remove todo and fix method to use twofactor_gateway
vitormattos 9f31207
chore: remove direct access to property and implement getter
vitormattos 9dee22c
fix: don't return not allowed settings
vitormattos 618feda
chore: add setter and getter to name
vitormattos 6ed2ae4
fix: make more generic
vitormattos c46471c
feat: change way to add a signer, use a modal to be possible split
vitormattos 3da5031
chore: add signal svg
vitormattos 5096129
fix: cs
vitormattos 6e4ae67
feat: send twofactor_gateway notification
vitormattos 939c639
feat: implement gateways
vitormattos ace3a36
fix: psalm
vitormattos 72a4acb
fix: copy paste code, added real code
vitormattos 91d6dd7
fix: psalm update baseline
vitormattos 20ba69d
fix: send code to sign
vitormattos 75cd9ad
fix: linter
vitormattos 9ed9790
chore: add docblock
vitormattos fe0865f
fix: cs
vitormattos 37ead7f
fix: psalm
vitormattos 8cb8f94
fix: typo
vitormattos e671cf5
fix: typo
vitormattos 560bf36
fix: error handler
vitormattos 70680c5
fix: psalm update baseline
vitormattos fd9dc8b
fix: prevent error when class doesn't exists
vitormattos 7c12c0a
fix: revert default method.
vitormattos 49e3bb2
fix: remove unused interface
vitormattos b41bb04
chore: resolve code review comment
vitormattos 501a139
fix: only consider the search item when have a method
vitormattos dcca860
fix: validate the email address when is searching by account
vitormattos aba92b9
chore: indent code
vitormattos 73814be
fix: typo
vitormattos c8c593f
chore: replace shareType by method
vitormattos 08f6dda
fix: filter valid condition
vitormattos b244d4f
fix: code review
vitormattos 548a39a
fix: code review
vitormattos 62e81b9
fix: code review
vitormattos 5a22bd0
fix: previous change was wrong
vitormattos 889003c
fix: openapi
vitormattos 610eb24
fix: prevent warning when haven't an email
vitormattos 4833fbb
fix: the method key was removed and I added back
vitormattos 5fdcf43
fix: the match syntax was incorrect
vitormattos 1160db3
fix: enlarge the dialog size
vitormattos 3e4fcd8
chore: use a more readdable code
vitormattos b7412c0
chore: replace string svg by a real file
vitormattos 81c4ad1
fix: psalm update baseline
vitormattos File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
<?php | ||
|
||
declare(strict_types=1); | ||
/** | ||
* SPDX-FileCopyrightText: 2025 LibreCode coop and contributors | ||
* SPDX-License-Identifier: AGPL-3.0-or-later | ||
*/ | ||
|
||
namespace OCA\Libresign\Collaboration\Collaborators; | ||
|
||
use OCA\Libresign\Db\IdentifyMethodMapper; | ||
use OCP\Collaboration\Collaborators\ISearchPlugin; | ||
use OCP\Collaboration\Collaborators\ISearchResult; | ||
use OCP\Collaboration\Collaborators\SearchResultType; | ||
use OCP\IUserSession; | ||
|
||
class SignerPlugin implements ISearchPlugin { | ||
public const TYPE_SIGNER = 50; // IShare::TYPE_SIGNER = 50; It's a custom share type. Not defined in OCP\Share\IShare | ||
public static string $method = ''; | ||
|
||
public function __construct( | ||
protected IdentifyMethodMapper $identifyMethodMapper, | ||
private IUserSession $userSession, | ||
) { | ||
} | ||
|
||
public static function setMethod(string $method): void { | ||
self::$method = $method; | ||
} | ||
|
||
/** | ||
* {@inheritdoc} | ||
*/ | ||
public function search($search, $limit, $offset, ISearchResult $searchResult): bool { | ||
$user = $this->userSession->getUser()->getUID(); | ||
|
||
$limit++; | ||
$identifiers = $this->identifyMethodMapper->searchByIdentifierValue( | ||
$search, | ||
$user, | ||
self::$method, | ||
$limit, | ||
$offset, | ||
); | ||
|
||
$result = ['wide' => [], 'exact' => []]; | ||
|
||
$hasMore = false; | ||
if (count($identifiers) > $limit) { | ||
$hasMore = true; | ||
array_pop($identifiers); | ||
} | ||
|
||
foreach ($identifiers as $row) { | ||
$item = $this->rowToSearchResultItem($row); | ||
if (strtolower($row['identifier_value']) === strtolower($search) | ||
|| strtolower($row['display_name']) === strtolower($search) | ||
) { | ||
$result['exact'][] = $item; | ||
} else { | ||
$result['wide'][] = $item; | ||
} | ||
} | ||
|
||
if (!count($identifiers) && self::$method && !$this->canValidateMethod()) { | ||
$result['exact'][] = [ | ||
'label' => $search, | ||
'shareWithDisplayNameUnique' => $search, | ||
'method' => self::$method, | ||
'value' => [ | ||
'shareWith' => $search, | ||
'shareType' => self::TYPE_SIGNER, | ||
], | ||
]; | ||
} | ||
|
||
$type = new SearchResultType('signer'); | ||
$searchResult->addResultSet($type, $result['wide'], $result['exact']); | ||
|
||
return $hasMore; | ||
} | ||
|
||
private function canValidateMethod(): bool { | ||
return in_array(self::$method, ['email', 'account'], true); | ||
} | ||
|
||
private function rowToSearchResultItem(array $row): array { | ||
$item = [ | ||
'label' => $row['display_name'], | ||
'shareWithDisplayNameUnique' => $row['identifier_value'], | ||
'method' => $row['identifier_key'], | ||
'value' => [ | ||
'shareWith' => $row['identifier_value'], | ||
'shareType' => self::TYPE_SIGNER, | ||
] | ||
]; | ||
|
||
return $item; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -378,7 +378,7 @@ private function fetchPreview( | |||||
/** | ||||||
* Send a file | ||||||
* | ||||||
* Send a new file to Nextcloud and return the fileId to request to sign usign fileId | ||||||
* Send a new file to Nextcloud and return the fileId to request to signature | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
* | ||||||
* @param LibresignNewFile $file File to save | ||||||
* @param string $name The name of file to sign | ||||||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -9,6 +9,7 @@ | |
namespace OCA\Libresign\Controller; | ||
|
||
use OCA\Libresign\AppInfo\Application; | ||
use OCA\Libresign\Collaboration\Collaborators\SignerPlugin; | ||
use OCA\Libresign\Middleware\Attribute\RequireManager; | ||
use OCA\Libresign\ResponseDefinitions; | ||
use OCA\Libresign\Service\IdentifyMethod\Account; | ||
|
@@ -45,6 +46,7 @@ public function __construct( | |
* Used to identify who can sign the document. The return of this endpoint is related with Administration Settiongs > LibreSign > Identify method. | ||
* | ||
* @param string $search search params | ||
* @param string $method filter by method (email, account, sms, signal, telegram, whatsapp, xmpp) | ||
* @param int $page the number of page to return. Default: 1 | ||
* @param int $limit Total of elements to return. Default: 25 | ||
* @return DataResponse<Http::STATUS_OK, LibresignIdentifyAccount[], array{}> | ||
|
@@ -55,29 +57,43 @@ public function __construct( | |
#[NoAdminRequired] | ||
#[RequireManager] | ||
#[ApiRoute(verb: 'GET', url: '/api/{apiVersion}/identify-account/search', requirements: ['apiVersion' => '(v1)'])] | ||
public function search(string $search = '', int $page = 1, int $limit = 25): DataResponse { | ||
$shareTypes = $this->getShareTypes(); | ||
$lookup = false; | ||
|
||
// only search for string larger than a given threshold | ||
$threshold = 1; | ||
if (strlen($search) < $threshold) { | ||
public function search(string $search = '', string $method = '', int $page = 1, int $limit = 25): DataResponse { | ||
// only search for string larger than a minimum length | ||
if (strlen($search) < 1) { | ||
return new DataResponse(); | ||
} | ||
|
||
$shareTypes = $this->getShareTypes(); | ||
$lookup = false; | ||
|
||
$offset = $limit * ($page - 1); | ||
$this->registerPlugin($method); | ||
[$result] = $this->collaboratorSearch->search($search, $shareTypes, $lookup, $limit, $offset); | ||
$result['exact'] = $this->unifyResult($result['exact']); | ||
$result = $this->unifyResult($result); | ||
$result = $this->excludeEmptyShareWith($result); | ||
$return = $this->formatForNcSelect($result); | ||
$return = $this->addHerselfAccount($return, $search); | ||
$return = $this->addHerselfEmail($return, $search); | ||
$return = $this->replaceShareTypeByMethod($return); | ||
$return = $this->excludeNotAllowed($return); | ||
|
||
return new DataResponse($return); | ||
} | ||
|
||
private function registerPlugin(string $method): void { | ||
SignerPlugin::setMethod($method); | ||
|
||
$refObject = new \ReflectionObject($this->collaboratorSearch); | ||
$refProperty = $refObject->getProperty('pluginList'); | ||
$refProperty->setAccessible(true); | ||
|
||
$plugins = $refProperty->getValue($this->collaboratorSearch); | ||
$plugins[SignerPlugin::TYPE_SIGNER] = [SignerPlugin::class]; | ||
|
||
$refProperty->setValue($this->collaboratorSearch, $plugins); | ||
vitormattos marked this conversation as resolved.
Show resolved
Hide resolved
vitormattos marked this conversation as resolved.
Show resolved
Hide resolved
vitormattos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
private function getShareTypes(): array { | ||
if (count($this->shareTypes) > 0) { | ||
return $this->shareTypes; | ||
|
@@ -90,6 +106,8 @@ private function getShareTypes(): array { | |
if ($settings['enabled']) { | ||
$this->shareTypes[] = IShare::TYPE_USER; | ||
} | ||
|
||
$this->shareTypes[] = SignerPlugin::TYPE_SIGNER; | ||
return $this->shareTypes; | ||
} | ||
|
||
|
@@ -109,21 +127,41 @@ private function unifyResult(array $list): array { | |
} | ||
|
||
private function formatForNcSelect(array $list): array { | ||
$return = []; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. $return doesn't sound very descriptive, maybe $formattedList would be better. |
||
foreach ($list as $key => $item) { | ||
$list[$key] = [ | ||
$return[$key] = [ | ||
'id' => $item['value']['shareWith'], | ||
'isNoUser' => $item['value']['shareType'] !== IShare::TYPE_USER, | ||
'isNoUser' => $item['value']['shareType'] !== IShare::TYPE_USER | ||
&& isset($item['method']) | ||
&& $item['method'] !== 'account', | ||
'displayName' => $item['label'], | ||
'subname' => $item['shareWithDisplayNameUnique'] ?? '', | ||
'shareType' => $item['value']['shareType'], | ||
]; | ||
if ($item['value']['shareType'] === IShare::TYPE_EMAIL) { | ||
$list[$key]['icon'] = 'icon-mail'; | ||
$return[$key]['method'] = 'email'; | ||
$return[$key]['icon'] = 'icon-mail'; | ||
} elseif ($item['value']['shareType'] === IShare::TYPE_USER) { | ||
$list[$key]['icon'] = 'icon-user'; | ||
$return[$key]['method'] = 'account'; | ||
$return[$key]['icon'] = 'icon-user'; | ||
} elseif ($item['value']['shareType'] === SignerPlugin::TYPE_SIGNER) { | ||
if ( | ||
!isset($return[$key]['method']) | ||
&& empty($return[$key]['method']) | ||
&& !empty($item['key']) | ||
) { | ||
$return[$key]['method'] = $item['key']; | ||
} | ||
if ($item['key'] === 'email') { | ||
$return[$key]['icon'] = 'icon-mail'; | ||
} elseif ($item['key'] === 'account') { | ||
$return[$key]['icon'] = 'icon-user'; | ||
} else { | ||
$return[$key]['iconSvg'] = 'svg' . ucfirst($item['key']); | ||
$return[$key]['iconName'] = $item['key']; | ||
} | ||
} | ||
} | ||
return $list; | ||
return $return; | ||
} | ||
|
||
private function addHerselfAccount(array $return, string $search): array { | ||
|
@@ -132,7 +170,14 @@ private function addHerselfAccount(array $return, string $search): array { | |
return $return; | ||
} | ||
$user = $this->userSession->getUser(); | ||
if (!str_contains($user->getUID(), $search) && !str_contains(strtolower($user->getDisplayName()), $search)) { | ||
$search = strtolower($search); | ||
if (!str_contains($user->getUID(), $search) | ||
&& !str_contains(strtolower($user->getDisplayName()), $search) | ||
&& ( | ||
$user->getEMailAddress() === null | ||
|| ($user->getEMailAddress() !== null && !str_contains($user->getEMailAddress(), $search)) | ||
) | ||
) { | ||
return $return; | ||
} | ||
$filtered = array_filter($return, fn ($i) => $i['id'] === $user->getUID()); | ||
|
@@ -145,7 +190,7 @@ private function addHerselfAccount(array $return, string $search): array { | |
'displayName' => $user->getDisplayName(), | ||
'subname' => $user->getEMailAddress(), | ||
'icon' => 'icon-user', | ||
'shareType' => IShare::TYPE_USER, | ||
'method' => 'account', | ||
]; | ||
return $return; | ||
} | ||
|
@@ -159,7 +204,9 @@ private function addHerselfEmail(array $return, string $search): array { | |
if (empty($user->getEMailAddress())) { | ||
return $return; | ||
} | ||
if (!str_contains($user->getEMailAddress(), $search) && !str_contains($user->getDisplayName(), $search)) { | ||
if (!str_contains($user->getEMailAddress(), $search) | ||
&& !str_contains($user->getDisplayName(), $search) | ||
) { | ||
return $return; | ||
} | ||
$filtered = array_filter($return, fn ($i) => $i['id'] === $user->getUID()); | ||
|
@@ -172,7 +219,7 @@ private function addHerselfEmail(array $return, string $search): array { | |
'displayName' => $user->getDisplayName(), | ||
'subname' => $user->getEMailAddress(), | ||
'icon' => 'icon-mail', | ||
'shareType' => IShare::TYPE_EMAIL, | ||
'method' => 'email', | ||
]; | ||
return $return; | ||
} | ||
|
@@ -182,7 +229,21 @@ private function excludeEmptyShareWith(array $list): array { | |
} | ||
|
||
private function excludeNotAllowed(array $list): array { | ||
$shareTypes = $this->getShareTypes(); | ||
return array_filter($list, fn ($result) => in_array($result['shareType'], $shareTypes)); | ||
return array_filter($list, fn ($result) => isset($result['method']) && !empty($result['method'])); | ||
} | ||
|
||
private function replaceShareTypeByMethod(array $list): array { | ||
foreach ($list as $key => $item) { | ||
if (isset($item['method']) && !empty($item['method'])) { | ||
continue; | ||
} | ||
$list[$key]['method'] = match ($item['shareType']) { | ||
IShare::TYPE_EMAIL => $item['method'] = 'email', | ||
IShare::TYPE_USER => $item['method'] = 'account', | ||
default => $item['method'] = '', | ||
vitormattos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
vitormattos marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
}; | ||
unset($list[$key]['shareType']); | ||
vitormattos marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
return $list; | ||
} | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.