Skip to content

Commit 323c6b5

Browse files
committed
trigger metadata restoration
Signed-off-by: Maxence Lange <maxence@artificial-owl.com>
1 parent 794bafb commit 323c6b5

File tree

4 files changed

+416
-17
lines changed

4 files changed

+416
-17
lines changed

lib/Controller/LocalController.php

Lines changed: 76 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,20 +36,30 @@
3636
use ArtificialOwl\MySmallPhpTools\Traits\Nextcloud\nc23\TNC23Logger;
3737
use Exception;
3838
use OC\AppFramework\Http;
39+
use OC\Files\Node\File;
40+
use OC\Files\Node\Folder;
41+
use OC\User\NoUserException;
3942
use OCA\Backup\Db\EventRequest;
43+
use OCA\Backup\Exceptions\RestoringPointException;
4044
use OCA\Backup\Exceptions\RestoringPointNotFoundException;
4145
use OCA\Backup\Model\BackupEvent;
46+
use OCA\Backup\Model\RestoringPoint;
4247
use OCA\Backup\Service\ConfigService;
4348
use OCA\Backup\Service\CronService;
4449
use OCA\Backup\Service\ExportService;
4550
use OCA\Backup\Service\ExternalFolderService;
4651
use OCA\Backup\Service\FilesService;
4752
use OCA\Backup\Service\PointService;
53+
use OCA\Backup\Service\RestoreService;
4854
use OCP\AppFramework\Http\DataResponse;
4955
use OCP\AppFramework\OCS\OCSException;
5056
use OCP\AppFramework\OCSController;
57+
use OCP\Files\FileInfo;
58+
use OCP\Files\IRootFolder;
59+
use OCP\Files\NotPermittedException;
5160
use OCP\IRequest;
5261
use OCP\IUserSession;
62+
use OCP\Lock\LockedException;
5363

5464
/**
5565
* Class LocalController
@@ -65,6 +75,9 @@ class LocalController extends OcsController {
6575
/** @var IUserSession */
6676
private $userSession;
6777

78+
/** @var IRootFolder */
79+
private $rootFolder;
80+
6881
/** @var EventRequest */
6982
private $eventRequest;
7083

@@ -83,6 +96,9 @@ class LocalController extends OcsController {
8396
/** @var ExportService */
8497
private $exportService;
8598

99+
/** @var RestoreService */
100+
private $restoreService;
101+
86102
/** @var ConfigService */
87103
private $configService;
88104

@@ -93,35 +109,41 @@ class LocalController extends OcsController {
93109
* @param string $appName
94110
* @param IRequest $request
95111
* @param IUserSession $userSession
112+
* @param IRootFolder $rootFolder
96113
* @param EventRequest $eventRequest
97114
* @param PointService $pointService
98115
* @param FilesService $filesService
99116
* @param CronService $cronService
100117
* @param ExternalFolderService $externalFolderService
101118
* @param ExportService $exportService
119+
* @param RestoreService $restoreService
102120
* @param ConfigService $configService
103121
*/
104122
public function __construct(
105123
string $appName,
106124
IRequest $request,
107125
IUserSession $userSession,
126+
IRootFolder $rootFolder,
108127
EventRequest $eventRequest,
109128
PointService $pointService,
110129
FilesService $filesService,
111130
CronService $cronService,
112131
ExternalFolderService $externalFolderService,
113132
ExportService $exportService,
133+
RestoreService $restoreService,
114134
ConfigService $configService
115135
) {
116136
parent::__construct($appName, $request);
117137

118138
$this->userSession = $userSession;
139+
$this->rootFolder = $rootFolder;
119140
$this->eventRequest = $eventRequest;
120141
$this->pointService = $pointService;
121142
$this->filesService = $filesService;
122143
$this->cronService = $cronService;
123144
$this->externalFolderService = $externalFolderService;
124145
$this->exportService = $exportService;
146+
$this->restoreService = $restoreService;
125147
$this->configService = $configService;
126148
}
127149

@@ -286,27 +308,77 @@ public function unsetExternalFolder(int $storageId): DataResponse {
286308
* @throws OCSException
287309
*/
288310
private function initActionScanLocalFolder(int $fileId): DataResponse {
311+
$userId = $this->userSession->getUser()->getUID();
312+
289313
try {
290-
$userId = $this->userSession->getUser()->getUID();
291314
$point = $this->filesService->getPointFromFileId($fileId, $userId);
292315
$event = new BackupEvent();
293316
$event->setAuthor($userId);
294317
$event->setData(['fileId' => $fileId]);
295318
$event->setType('ScanLocalFolder');
296319

297320
$this->eventRequest->save($event);
321+
322+
return new DataResponse(
323+
[
324+
'message' => 'The restoring point have been scheduled for a scan. (id: ' . $point->getId()
325+
. ')'
326+
]
327+
);
298328
} catch (RestoringPointNotFoundException $e) {
329+
try {
330+
$point = $this->actionFromFileId($fileId, $userId);
331+
332+
return new DataResponse(
333+
[
334+
'message' => 'The restoring point\'s metadata have been generated. (id: '
335+
. $point->getId() . ')'
336+
]
337+
);
338+
} catch (RestoringPointException $e) {
339+
} catch (Exception $e) {
340+
throw new OcsException($e->getMessage(), Http::STATUS_BAD_REQUEST);
341+
}
342+
299343
throw new OcsException(
300344
'file does not seems to be a valid restoring point',
301345
Http::STATUS_BAD_REQUEST
302346
);
303347
} catch (Exception $e) {
304348
throw new OcsException($e->getMessage(), Http::STATUS_BAD_REQUEST);
305349
}
350+
}
351+
352+
353+
/**
354+
* @param int $fileId
355+
* @param string $owner
356+
* @param Folder|null $folder
357+
*
358+
* @return RestoringPoint
359+
* @throws LockedException
360+
* @throws NoUserException
361+
* @throws NotPermittedException
362+
* @throws RestoringPointException
363+
*/
364+
public function actionFromFileId(int $fileId, string $owner, ?Folder &$folder = null): RestoringPoint {
365+
$storage = $this->rootFolder->getUserFolder($owner);
366+
$nodes = $storage->getById($fileId);
367+
368+
foreach ($nodes as $node) {
369+
if ($node->getType() !== FileInfo::TYPE_FILE) {
370+
continue;
371+
}
372+
373+
/** @var File $node */
374+
$folder = $node->getParent();
375+
$content = json_decode($node->getContent(), true);
376+
if ($this->get('action', $content) === 'generate') {
377+
return $this->restoreService->restoreMetadataFromFolder($folder, $this->get('id', $content));
378+
}
379+
}
306380

307-
return new DataResponse(
308-
['message' => 'The restoring point have been scheduled for a scan. (id: ' . $point->getId() . ')']
309-
);
381+
throw new RestoringPointException();
310382
}
311383

312384

lib/Service/EncryptService.php

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ class EncryptService {
5858
public const AES_CBC_IV = 'aes-256-cbc-iv';
5959

6060
public const CHACHA = 'chacha';
61+
public const NONE = 'none';
6162

6263
public const STRING = 'string';
6364
public const STRING_NONCE = 'string-nonce';
@@ -262,9 +263,28 @@ public function encryptFileChacha(string $input, string $output): void {
262263
* @throws PackDecryptException
263264
* @throws SodiumException
264265
*/
265-
public function decryptFile(string $input, string $output, string $name, string $algorithm = ''): void {
266+
public function decryptFile(string $input, string $output, string $name, string &$algorithm = ''): void {
266267
if ($algorithm === '') {
267-
// TODO: test them all ?
268+
try {
269+
$this->decryptFileGCM($input, $output, $name);
270+
$algorithm = self::AES_GCM;
271+
272+
return;
273+
} catch (Exception $e) {
274+
}
275+
276+
try {
277+
$this->decryptFileCBC($input, $output);
278+
$algorithm = self::AES_CBC;
279+
280+
return;
281+
} catch (Exception $e) {
282+
}
283+
284+
$this->decryptFileNone($input, $output);
285+
$algorithm = self::NONE;
286+
287+
return;
268288
}
269289

270290
switch ($algorithm) {
@@ -277,6 +297,9 @@ public function decryptFile(string $input, string $output, string $name, string
277297
case self::AES_CBC:
278298
$this->decryptFileCBC($input, $output);
279299
break;
300+
case self::NONE:
301+
$this->decryptFileNone($input, $output);
302+
break;
280303
}
281304
}
282305

@@ -373,6 +396,21 @@ public function decryptFileChacha(string $input, string $output): void {
373396
}
374397

375398

399+
/**
400+
* @param string $input
401+
* @param string $output
402+
*/
403+
public function decryptFileNone(string $input, string $output): void {
404+
$read = fopen($input, 'rb');
405+
$write = fopen($output, 'wb');
406+
while (($r = fgets($read, 4096)) !== false) {
407+
fputs($write, $r);
408+
}
409+
fclose($read);
410+
fclose($write);
411+
}
412+
413+
376414
/**
377415
* @param bool $generate
378416
*

lib/Service/PackService.php

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ public function packPoint(RestoringPoint $point, bool $force = false): void {
146146
}
147147
}
148148

149-
$this->o(' > lock and set status to <info>packing</info>');
149+
$this->o(' > lock and set status to <info>processing</info>');
150150
$this->metadataService->isLock($point);
151151
$this->metadataService->lock($point);
152152
$point->addStatus(RestoringPoint::STATUS_PACKING);
@@ -202,7 +202,7 @@ public function packPoint(RestoringPoint $point, bool $force = false): void {
202202

203203
// $this->removeOldChunkFiles($point, $oldChunks);
204204

205-
$this->o(' > removing status <info>packing</info>, adding status <info>packed</info>');
205+
$this->o(' > removing status <info>processing</info>, adding status <info>packed</info>');
206206
$point->removeStatus(RestoringPoint::STATUS_PACKING)
207207
->addStatus(RestoringPoint::STATUS_PACKED)
208208
->getNotes()
@@ -769,7 +769,8 @@ private function putOutParts(RestoringPoint $point, RestoringChunk $chunk): arra
769769
* @throws Throwable
770770
*/
771771
private function wrapPackDecrypt(RestoringPoint $point, RestoringChunk $chunk, array $parts): array {
772-
if ($point->isStatus(RestoringPoint::STATUS_ENCRYPTED)) {
772+
if ($point->isStatus(RestoringPoint::STATUS_ENCRYPTED)
773+
|| $point->isStatus(RestoringPoint::STATUS_UNKNOWN)) {
773774
$this->o(' * decrypting each part');
774775
try {
775776
$encrypted = $this->packDecrypt($parts, $chunk);
@@ -793,14 +794,19 @@ private function wrapPackDecrypt(RestoringPoint $point, RestoringChunk $chunk, a
793794

794795

795796
/**
796-
* @param array $parts
797+
* @param RestoringChunkPart[] $parts
797798
* @param RestoringChunk $chunk
798799
*
799800
* @return RestoringChunkPart[]
800801
*/
801802
private function packDecrypt(array $parts, RestoringChunk $chunk): array {
802803
$decrypted = [];
804+
$algorithm = '';
803805
foreach ($parts as $part) {
806+
if ($part->getAlgorithm() !== '') {
807+
$algorithm = $part->getAlgorithm();
808+
}
809+
804810
$this->o(' - decrypting <info>' . $part->getName() . '</info>: ', false);
805811

806812
$new = clone $part;
@@ -811,10 +817,10 @@ private function packDecrypt(array $parts, RestoringChunk $chunk): array {
811817
$part->getName(),
812818
$new->getName(),
813819
$chunk->getName(),
814-
$part->getAlgorithm()
820+
$algorithm
815821
);
816822

817-
$this->o('<info>' . $new->getName() . '</info>, <info>' . $part->getAlgorithm() . '</info>');
823+
$this->o('<info>' . $new->getName() . '</info>, <info>' . $algorithm . '</info>');
818824

819825
// TODO checksums
820826
// echo '-checksum: ' . $this->getTempChecksum($new->getName()) . "\n";
@@ -830,6 +836,7 @@ private function packDecrypt(array $parts, RestoringChunk $chunk): array {
830836
return $decrypted;
831837
}
832838

839+
833840
/**
834841
* @param RestoringChunkPart[] $parts
835842
*
@@ -894,7 +901,8 @@ private function packImplode(array $parts): string {
894901
* @throws Throwable
895902
*/
896903
private function wrapPackChunkExtract(RestoringPoint $point, string $filename): string {
897-
if ($point->isStatus(RestoringPoint::STATUS_COMPRESSED)) {
904+
if ($point->isStatus(RestoringPoint::STATUS_COMPRESSED)
905+
|| $point->isStatus(RestoringPoint::STATUS_UNKNOWN)) {
898906
$this->o(' * Extracting <info>' . $filename . '</info>: ', false);
899907

900908
try {
@@ -923,7 +931,12 @@ private function packChunkExtract(string $zipName): string {
923931

924932
$zip = new ZipArchive();
925933
$zip->open($zipName);
926-
$read = $zip->getStream(self::CHUNK_ENTRY);
934+
if ($zip->count() === 1 && $zip->getFromName(self::CHUNK_ENTRY) !== false) {
935+
$read = $zip->getStream(self::CHUNK_ENTRY);
936+
} else {
937+
$read = fopen($zipName, 'rb');
938+
}
939+
927940
while (($r = fgets($read, 4096)) !== false) {
928941
fputs($write, $r);
929942
}
@@ -978,6 +991,7 @@ public function getPackFolder(
978991
*
979992
* @throws NotPermittedException
980993
* @throws RestoringPointNotInitiatedException
994+
* @throws Throwable
981995
*/
982996
private function wrapRecreateChunk(RestoringPoint $point, RestoringChunk $chunk, string $temp): void {
983997
try {
@@ -1094,7 +1108,8 @@ public function getChecksum(
10941108
}
10951109
} catch (Exception $e) {
10961110
throw new ArchiveNotFoundException(
1097-
'Part ' . $part->getName() . ' from ' . $chunk->getFilename() . ' not found. path: ' . $path
1111+
'Part ' . $part->getName() . ' from ' . $chunk->getFilename() . ' not found. path: '
1112+
. $path
10981113
);
10991114
}
11001115

@@ -1140,5 +1155,4 @@ public function saveChunkPartContent(
11401155
private function o(string $line, bool $ln = true): void {
11411156
$this->outputService->o($line, $ln);
11421157
}
1143-
11441158
}

0 commit comments

Comments
 (0)