Passed
Push — master ( 22b305...33bedb )
by Thomas
02:16
created

EncryptedDBFile::sendDecryptedFile()   A

Complexity

Conditions 5
Paths 8

Size

Total Lines 23
Code Lines 14

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
eloc 14
c 2
b 0
f 0
dl 0
loc 23
rs 9.4888
cc 5
nc 8
nop 0
1
<?php
2
3
namespace LeKoala\Encrypt;
4
5
use Exception;
6
use SilverStripe\Assets\File;
7
use SilverStripe\ORM\DataExtension;
8
use ParagonIE\CipherSweet\CipherSweet;
9
use ParagonIE\CipherSweet\EncryptedFile;
10
use SilverStripe\Control\Director;
11
12
/**
13
 * Safe and encrypted content file
14
 * Also make sure that files are not public assets! => use htaccess
15
 * @property bool $Encrypted
16
 * @property File|EncryptedDBFile $owner
17
 */
18
class EncryptedDBFile extends DataExtension
19
{
20
    private static $db = [
0 ignored issues
show
introduced by
The private property $db is not used, and could be removed.
Loading history...
21
        "Encrypted" => "Boolean",
22
    ];
23
24
    /**
25
     * @return EncryptedFile
26
     */
27
    protected function getEncryptedFileInstance()
28
    {
29
        $engine = EncryptHelper::getCipherSweet();
30
        $encFile = new EncryptedFile($engine);
31
        return $encFile;
32
    }
33
34
    /**
35
     * @return string
36
     */
37
    public function getDecryptionLink()
38
    {
39
        $data = [
40
            "ID" => $this->owner->ID,
0 ignored issues
show
Bug Best Practice introduced by
The property ID does not exist on LeKoala\Encrypt\EncryptedDBFile. Did you maybe forget to declare it?
Loading history...
41
            "Hash" => substr($this->owner->File->Hash, 0, 10),
0 ignored issues
show
Bug Best Practice introduced by
The property File does not exist on LeKoala\Encrypt\EncryptedDBFile. Did you maybe forget to declare it?
Loading history...
42
        ];
43
        $url = "__decrypt/?" . http_build_query($data);
44
        return Director::absoluteURL($url);
45
    }
46
47
    /**
48
     * Check if the actual file on the filesystem is encrypted
49
     * You might also use the Encrypted field that should be accurate
50
     *
51
     * @return boolean
52
     */
53
    public function isEncrypted()
54
    {
55
        $encFile = $this->getEncryptedFileInstance();
56
        $stream = $this->owner->getStream();
0 ignored issues
show
Bug introduced by
The method getStream() does not exist on LeKoala\Encrypt\EncryptedDBFile. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

56
        /** @scrutinizer ignore-call */ 
57
        $stream = $this->owner->getStream();

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
57
        return $encFile->isStreamEncrypted($stream);
58
    }
59
60
    /**
61
     * Output file using regular php
62
     *
63
     * @throws Exception
64
     * @return void
65
     */
66
    public function sendDecryptedFile()
67
    {
68
        if (ob_get_level()) {
69
            ob_end_clean();
70
        }
71
        $stream = $this->owner->getStream();
72
        if ($this->owner->Encrypted) {
73
            $encFile = $this->getEncryptedFileInstance();
74
            $output = fopen('php://temp', 'w+b');
75
76
            // We need to decrypt stream
77
            if ($encFile->isStreamEncrypted($stream)) {
78
                $success = $encFile->decryptStream($stream, $output);
79
                if (!$success) {
80
                    throw new Exception("Failed to decrypt stream");
81
                }
82
83
                // Rewind first
84
                rewind($output);
85
                fpassthru($output);
86
            }
87
        } else {
88
            fpassthru($stream);
89
        }
90
    }
91
92
    /**
93
     * Files are not encrypted automatically
94
     * Calls this method to encrypt them
95
     *
96
     * @throws Exception
97
     * @return void
98
     */
99
    public function encryptFileIfNeeded()
100
    {
101
        $encFile = $this->getEncryptedFileInstance();
102
        if (!$this->owner->exists()) {
0 ignored issues
show
Bug introduced by
The method exists() does not exist on LeKoala\Encrypt\EncryptedDBFile. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

102
        if (!$this->owner->/** @scrutinizer ignore-call */ exists()) {

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
103
            throw new Exception("File does not exist");
104
        }
105
        $stream = $this->owner->getStream();
106
107
        if (!$stream) {
0 ignored issues
show
introduced by
$stream is of type resource, thus it always evaluated to false.
Loading history...
108
            throw new Exception("Failed to get stream");
109
        }
110
111
        if (!$encFile->isStreamEncrypted($stream)) {
112
            // php://temp is not a file path, it's a pseudo protocol that always creates a new random temp file when used.
113
            $output = fopen('php://temp', 'wb');
114
            $success =  $encFile->encryptStream($stream, $output);
115
            if (!$success) {
116
                throw new Exception("Failed to encrypt stream");
117
            }
118
            // dont forget to rewind the stream !
119
            rewind($output);
120
            // Keep the hash ! encrypting file will change it's content and it would update the hash
121
            // This would move the file on the filesystem and mess up FileHash link
122
            $fileResult = $this->owner->setFromStream($output, $this->owner->getFilename(), $this->owner->FileHash);
123
            // Mark as encrypted in db
124
            $this->owner->Encrypted =  true;
125
            $this->owner->write();
126
        } elseif ($this->owner->Encrypted) {
127
            // Stream is not encrypted
128
            if ($this->owner->Encrypted) {
129
                $this->owner->Encrypted = false;
130
                $this->owner->write();
131
            }
132
        }
133
    }
134
}
135