-orig_password +member_id

Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
This commit is contained in:
Maxence Lange 2020-01-08 10:52:12 -01:00
parent 2387bf1b78
commit 9f67aebd45
9 changed files with 143 additions and 86 deletions

View file

@ -40,6 +40,8 @@ use OCP\AppFramework\IAppContainer;
use OCP\AppFramework\QueryException;
use OCP\Util;
require_once __DIR__ . '/../../appinfo/autoload.php';
class Application extends App {

View file

@ -65,9 +65,6 @@ use OCP\Util;
class FileSharingBroadcaster implements IBroadcaster {
use TArrayTools;
/** @var bool */
private $initiated = false;
@ -233,14 +230,14 @@ class FileSharingBroadcaster implements IBroadcaster {
$password = $this->miscService->token(15);
}
$sharesToken = $this->tokensRequest->generateTokenForMember($member, $share->getId());
$sharesToken = $this->tokensRequest->generateTokenForMember($member, $share->getId(), $password);
$mails = [$member->getUserId()];
if ($member->getType() === Member::TYPE_CONTACT) {
$mails = $this->getMailsFromContact($member->getUserId());
}
foreach ($mails as $mail) {
$this->sharedByMail($circle, $share, $mail, $sharesToken);
$this->sharedByMail($circle, $share, $mail, $sharesToken, $password);
}
} catch (Exception $e) {
}
@ -298,7 +295,12 @@ class FileSharingBroadcaster implements IBroadcaster {
$recipient = $member->getUserId();
if ($member->getType() === Member::TYPE_CONTACT) {
$emails = $this->getArray('EMAIL', MiscService::getContactData($member->getUserId()));
$data = MiscService::getContactData($member->getUserId());
if (!array_key_exists('EMAIL', $data)) {
return;
}
$emails = $data['EMAIL'];
if (empty($emails)) {
return;
}
@ -392,8 +394,11 @@ class FileSharingBroadcaster implements IBroadcaster {
* @param IShare $share
* @param string $email
* @param SharesToken $sharesToken
* @param string $password
*/
private function sharedByMail(Circle $circle, IShare $share, $email, SharesToken $sharesToken) {
private function sharedByMail(
Circle $circle, IShare $share, string $email, SharesToken $sharesToken, string $password
) {
// genelink
$link = $this->urlGenerator->linkToRouteAbsolute(
'files_sharing.sharecontroller.showShare',
@ -409,7 +414,7 @@ class FileSharingBroadcaster implements IBroadcaster {
);
$this->sendPasswordByMail(
$share, MiscService::getDisplay($share->getSharedBy(), Member::TYPE_USER),
$email, $sharesToken->getOrigPassword()
$email, $password
);
} catch (Exception $e) {
OC::$server->getLogger()
@ -579,7 +584,6 @@ class FileSharingBroadcaster implements IBroadcaster {
* @param Member $member
* @param string $recipient
* @param string $circleName
* @param string $password
*/
public function sendMailExitingShares(
array $unknownShares, $author, Member $member, $recipient, $circleName
@ -587,11 +591,13 @@ class FileSharingBroadcaster implements IBroadcaster {
$data = [];
$password = '';
if ($this->configService->enforcePasswordProtection()) {
$password = $this->miscService->token(15);
}
foreach ($unknownShares as $share) {
try {
$item = $this->getMailLinkFromShare($share, $member, $password);
$password = $item['password'];
$data[] = $item;
$data[] = $this->getMailLinkFromShare($share, $member, $password);
} catch (TokenDoesNotExistException $e) {
}
}
@ -686,7 +692,6 @@ class FileSharingBroadcaster implements IBroadcaster {
* @param array $share
* @param Member $member
* @param string $password
* @param string $token
*
* @return array
* @throws TokenDoesNotExistException
@ -704,7 +709,6 @@ class FileSharingBroadcaster implements IBroadcaster {
return [
'author' => $author,
'link' => $link,
'password' => $sharesToken->getOrigPassword(),
'filename' => $filename
];
}

View file

@ -28,6 +28,7 @@
namespace OCA\Circles\Db;
use daita\MySmallPhpTools\Traits\TStringTools;
use Doctrine\DBAL\Exception\UniqueConstraintViolationException;
use OCA\Circles\Exceptions\MemberAlreadyExistsException;
use OCA\Circles\Exceptions\MemberDoesNotExistException;
@ -37,6 +38,9 @@ use OCP\IGroup;
class MembersRequest extends MembersRequestBuilder {
use TStringTools;
/**
* Returns information about a member.
*
@ -420,10 +424,16 @@ class MembersRequest extends MembersRequestBuilder {
* @throws MemberAlreadyExistsException
*/
public function createMember(Member $member) {
if ($member->getMemberId() === '') {
$member->setMemberId($this->token());
}
try {
$qb = $this->getMembersInsertSql();
$qb->setValue('circle_id', $qb->createNamedParameter($member->getCircleId()))
->setValue('user_id', $qb->createNamedParameter($member->getUserId()))
->setValue('member_id', $qb->createNamedParameter($member->getMemberId()))
->setValue('user_type', $qb->createNamedParameter($member->getType()))
->setValue('level', $qb->createNamedParameter($member->getLevel()))
->setValue('status', $qb->createNamedParameter($member->getStatus()))

View file

@ -82,6 +82,7 @@ class MembersRequestBuilder extends CoreRequestBuilder {
/** @noinspection PhpMethodParametersCountMismatchInspection */
$qb->select(
'm.user_id', 'm.user_type', 'm.circle_id', 'm.level', 'm.status', 'm.note', 'm.contact_id',
'member_id',
'm.contact_meta', 'm.joined'
)
->from(self::TABLE_MEMBERS, 'm')
@ -209,6 +210,7 @@ class MembersRequestBuilder extends CoreRequestBuilder {
$member = new Member($data['user_id'], $data['user_type'], $data['circle_id']);
$member->setNote($data['note']);
$member->setContactId($data['contact_id']);
$member->setMemberId($data['member_id']);
$contactMeta = json_decode($data['contact_meta'], true);
if (is_array($contactMeta)) {

View file

@ -121,14 +121,8 @@ class TokensRequest extends TokensRequestBuilder {
try {
$token = $this->miscService->token(15);
$orig = '';
if ($password === '' && $this->configService->enforcePasswordProtection()) {
$password = $this->miscService->token(15);
}
if ($password !== '') {
$hasher = \OC::$server->getHasher();
$orig = $this->origPasswordEncrypt($password);
$password = $hasher->hash($password);
}
@ -136,9 +130,9 @@ class TokensRequest extends TokensRequestBuilder {
$qb->setValue('circle_id', $qb->createNamedParameter($member->getCircleId()))
->setValue('user_id', $qb->createNamedParameter($member->getUserId()))
->setValue('share_id', $qb->createNamedParameter($shareId))
->setValue('member_id', $qb->createNamedParameter($member->getMemberId()))
->setValue('token', $qb->createNamedParameter($token))
->setValue('password', $qb->createNamedParameter($password))
->setValue('orig_password', $qb->createNamedParameter($orig));
->setValue('password', $qb->createNamedParameter($password));
$qb->execute();
} catch (UniqueConstraintViolationException $e) {

View file

@ -81,7 +81,7 @@ class TokensRequestBuilder extends CoreRequestBuilder {
$qb = $this->dbConnection->getQueryBuilder();
/** @noinspection PhpMethodParametersCountMismatchInspection */
$qb->select('t.user_id', 't.circle_id', 't.share_id', 't.token', 't.orig_password')
$qb->select('t.user_id', 't.circle_id', 't.share_id', 't.token')
->from(self::TABLE_TOKENS, 't');
$this->default_select_alias = 't';
@ -110,38 +110,9 @@ class TokensRequestBuilder extends CoreRequestBuilder {
*/
protected function parseTokensSelectSql($data) {
$sharesToken = new SharesToken();
$orig = $this->get('orig_password', $data);
$data['orig_password'] = ($orig === '') ? '' : $this->origPasswordDecrypt($orig);
$sharesToken->import($data);
return $sharesToken;
}
protected function origPasswordEncrypt(string $password): string {
$key = $this->configService->getInstanceId();
$ivlen = openssl_cipher_iv_length($cipher = 'AES-128-CBC');
$iv = openssl_random_pseudo_bytes($ivlen);
$raw = openssl_encrypt($password, $cipher, $key, $options = OPENSSL_RAW_DATA, $iv);
$hmac = hash_hmac('sha256', $raw, $key, $as_binary = true);
return base64_encode($iv . $hmac . $raw);
}
protected function origPasswordDecrypt($encoded): string {
$key = $this->configService->getInstanceId();
$c = base64_decode($encoded);
$ivlen = openssl_cipher_iv_length($cipher = 'AES-128-CBC');
$iv = substr($c, 0, $ivlen);
$hmac = substr($c, $ivlen, $sha2len = 32);
$raw = substr($c, $ivlen + $sha2len);
$password = openssl_decrypt($raw, $cipher, $key, $options = OPENSSL_RAW_DATA, $iv);
return $password;
}
}

View file

@ -32,6 +32,7 @@ use Closure;
use Doctrine\DBAL\Schema\SchemaException;
use Doctrine\DBAL\Types\Type;
use OCP\DB\ISchemaWrapper;
use OCP\IDBConnection;
use OCP\Migration\IOutput;
use OCP\Migration\SimpleMigrationStep;
@ -40,6 +41,18 @@ use OCP\Migration\SimpleMigrationStep;
*/
class Version0017Date20191206144441 extends SimpleMigrationStep {
/** @var IDBConnection */
private $connection;
/**
* @param IDBConnection $connection
*/
public function __construct(IDBConnection $connection) {
$this->connection = $connection;
}
/**
* @param IOutput $output
* @param Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
@ -80,6 +93,14 @@ class Version0017Date20191206144441 extends SimpleMigrationStep {
}
$table = $schema->getTable('circles_members');
if (!$table->hasColumn('member_id')) {
$table->addColumn(
'member_id', Type::STRING, [
'notnull' => false,
'length' => 15,
]
);
}
if (!$table->hasColumn('contact_meta')) {
$table->addColumn(
'contact_meta', 'string', [
@ -91,9 +112,9 @@ class Version0017Date20191206144441 extends SimpleMigrationStep {
if (!$table->hasColumn('contact_checked')) {
$table->addColumn(
'contact_checked', Type::SMALLINT, [
'notnull' => false,
'length' => 1,
]
'notnull' => false,
'length' => 1,
]
);
}
if (!$table->hasColumn('contact_id')) {
@ -108,20 +129,20 @@ class Version0017Date20191206144441 extends SimpleMigrationStep {
}
$table = $schema->getTable('circles_tokens');
if (!$table->hasColumn('orig_password')) {
if (!$table->hasColumn('member_id')) {
$table->addColumn(
'orig_password', 'string', [
'notnull' => false,
'length' => 255,
]
'member_id', Type::STRING, [
'notnull' => false,
'length' => 15,
]
);
}
if (!$table->hasColumn('accepted')) {
$table->addColumn(
'accepted', Type::SMALLINT, [
'notnull' => false,
'length' => 1,
]
'notnull' => false,
'length' => 1,
]
);
}
@ -134,5 +155,66 @@ class Version0017Date20191206144441 extends SimpleMigrationStep {
* @param array $options
*/
public function postSchemaChange(IOutput $output, Closure $schemaClosure, array $options) {
$qb = $this->connection->getQueryBuilder();
$expr = $qb->expr();
$orX = $expr->orX();
$orX->add($expr->eq('member_id', $qb->createNamedParameter('')));
$orX->add($expr->isNull('member_id'));
$qb->select('circle_id', 'user_id', 'user_type')
->from('circles_members')
->where($orX);
$result = $qb->execute();
while ($row = $result->fetch()) {
$uniqueId = substr(bin2hex(openssl_random_pseudo_bytes(24)), 0, 15);
$update = $this->connection->getQueryBuilder();
$expru = $update->expr();
$update->update('circles_members')
->set('member_id', $update->createNamedParameter($uniqueId))
->where($expru->eq('circle_id', $update->createNamedParameter($row['circle_id'])))
->andWhere($expru->eq('user_id', $update->createNamedParameter($row['user_id'])))
->andWhere($expru->eq('user_type', $update->createNamedParameter($row['user_type'])));
$update->execute();
}
$qb2 = $this->connection->getQueryBuilder();
$expr2 = $qb2->expr();
$orX = $expr2->orX();
$orX->add($expr2->eq('member_id', $qb2->createNamedParameter('')));
$orX->add($expr2->isNull('member_id'));
$qb2->select('user_id', 'circle_id')
->from('circles_tokens')
->where($orX);
$result = $qb2->execute();
while ($row = $result->fetch()) {
$qbm = $this->connection->getQueryBuilder();
$exprm = $qbm->expr();
$qbm->select('member_id')
->from('circles_members')
->where($exprm->eq('circle_id', $qbm->createNamedParameter($row['circle_id'])))
->andWhere($exprm->eq('user_id', $qbm->createNamedParameter($row['user_id'])))
->andWhere($exprm->neq('user_type', $qbm->createNamedParameter('1')));
$resultm = $qbm->execute();
$member = $resultm->fetch();
$update = $this->connection->getQueryBuilder();
$expru = $update->expr();
$update->update('circles_tokens')
->set('member_id', $update->createNamedParameter($member['member_id']))
->where($expru->eq('circle_id', $update->createNamedParameter($row['circle_id'])))
->andWhere($expru->eq('user_id', $update->createNamedParameter($row['user_id'])));
$update->execute();
}
}
}

View file

@ -62,6 +62,9 @@ class BaseMember implements \JsonSerializable {
/** @var string */
private $userId = '';
/** @var string */
private $memberId = '';
/** @var int */
private $type = self::TYPE_USER;
@ -181,6 +184,18 @@ class BaseMember implements \JsonSerializable {
}
public function setMemberId($memberId) {
$this->memberId = $memberId;
return $this;
}
public function getMemberId() {
return $this->memberId;
}
public function setDisplayName($display) {
$this->displayName = $display;

View file

@ -54,9 +54,6 @@ class SharesToken implements JsonSerializable {
/** @var string */
private $token = '';
/** @var string */
private $origPassword = '';
/**
* SharesToken constructor.
@ -141,25 +138,6 @@ class SharesToken implements JsonSerializable {
}
/**
* @return string
*/
public function getOrigPassword(): string {
return $this->origPassword;
}
/**
* @param string $origPassword
*
* @return SharesToken
*/
public function setOrigPassword(string $origPassword): self {
$this->origPassword = $origPassword;
return $this;
}
/**
* @param array $data
*/
@ -168,7 +146,6 @@ class SharesToken implements JsonSerializable {
$this->setUserId($this->get('user_id', $data, ''));
$this->setShareId($this->get('share_id', $data, ''));
$this->setToken($this->get('token', $data, ''));
$this->setOrigPassword($this->get('orig_password', $data, ''));
}