Completed
Branch dev (d5d70c)
by Raffael
11:00
created

Http   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 151
Duplicated Lines 0 %

Coupling/Cohesion

Components 1

Importance

Changes 0
Metric Value
wmc 19
lcom 1
dl 0
loc 151
rs 10
c 0
b 0
f 0

3 Methods

Rating   Name   Duplication   Size   Complexity  
A hp$0 ➔ preAuthentication() 0 6 2
B __construct() 0 39 4
D start() 0 80 13
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * balloon
7
 *
8
 * @copyright   Copryright (c) 2012-2018 gyselroth GmbH (https://gyselroth.com)
9
 * @license     GPL-3.0 https://opensource.org/licenses/GPL-3.0
10
 */
11
12
namespace Balloon\App\Sharelink\Constructor;
13
14
use Balloon\App\Sharelink\Api\v1;
15
use Balloon\App\Sharelink\Api\v2;
16
use Balloon\App\Sharelink\Sharelink as Share;
17
use Balloon\Exception;
18
use Balloon\Filesystem\Node\AttributeDecorator;
19
use Balloon\Filesystem\Node\Collection;
20
use Balloon\Hook;
21
use Balloon\Hook\AbstractHook;
22
use DateTime;
23
use Micro\Auth\Adapter\None as AuthNone;
24
use Micro\Auth\Auth;
25
use Micro\Http\Response;
26
use Micro\Http\Router;
27
use Micro\Http\Router\Route;
28
use Psr\Log\LoggerInterface;
29
30
class Http
31
{
32
    /**
33
     * Sharelink.
34
     *
35
     * @var Share
36
     */
37
    protected $sharelink;
38
39
    /**
40
     * Logger.
41
     *
42
     * @var LoggerInterface
43
     */
44
    protected $logger;
45
46
    /**
47
     * Init.
48
     *
49
     * @param Router             $router
50
     * @param Hook               $hook
51
     * @param Share              $sharelink
52
     * @param AttributeDecorator $decorator
53
     * @param LoggerInterface    $logger
54
     */
55
    public function __construct(Router $router, Hook $hook, Share $sharelink, AttributeDecorator $decorator, LoggerInterface $logger)
56
    {
57
        $router
58
            ->appendRoute(new Route('/share', $this, 'start'))
0 ignored issues
show
Documentation introduced by
$this is of type this<Balloon\App\Sharelink\Constructor\Http>, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
59
            ->prependRoute(new Route('/api/v1/(node|file|collection)/share-link', v1\ShareLink::class))
60
            ->prependRoute(new Route('/api/v1/(node|file|collection)/{id:#([0-9a-z]{24})#}/share-link', v1\ShareLink::class))
61
            ->prependRoute(new Route('/api/v2/(nodes|files|collections)/share-link', v2\ShareLink::class))
62
            ->prependRoute(new Route('/api/v2/(nodes|files|collections)/{id:#([0-9a-z]{24})#}/share-link', v2\ShareLink::class));
63
64
        $hook->injectHook(new class() extends AbstractHook {
65
            public function preAuthentication(Auth $auth): void
66
            {
67
                if (preg_match('#^/index.php/share#', $_SERVER['ORIG_SCRIPT_NAME'])) {
68
                    $auth->injectAdapter(new AuthNone());
69
                }
70
            }
71
        });
72
73
        $decorator->addDecorator('sharelink_token', function ($node) use ($sharelink) {
74
            $attributes = $sharelink->getSharelink($node);
75
76
            if (isset($attributes['token'])) {
77
                return $attributes['token'];
78
            }
79
        });
80
81
        $decorator->addDecorator('sharelink_expire', function ($node) use ($sharelink) {
82
            $attributes = $sharelink->getSharelink($node);
83
84
            if (isset($attributes['expiration'])) {
85
                $ts = (new DateTime())->setTimestamp($attributes['expiration']);
86
87
                return $ts->format('c');
88
            }
89
        });
90
91
        $this->logger = $logger;
92
        $this->sharelink = $sharelink;
93
    }
94
95
    /**
96
     * Start.
97
     *
98
     * @return bool
99
     */
100
    public function start(): bool
101
    {
102
        if (isset($_GET['t']) && !empty($_GET['t'])) {
103
            $token = $_GET['t'];
104
            if (isset($_GET['download'])) {
105
                $download = (bool) $_GET['download'];
106
            } else {
107
                $download = false;
108
            }
109
110
            try {
111
                $node = $this->sharelink->findNodeWithShareToken($token);
112
                $share = $node->getAppAttributes('Balloon\\App\\Sharelink');
113
114
                if (array_key_exists('password', $share)) {
115
                    $valid = false;
116
                    if (isset($_POST['password'])) {
117
                        $valid = hash('sha256', $_POST['password']) === $share['password'];
118
                    }
119
120
                    if (false === $valid) {
121
                        echo "<form method=\"post\">\n";
122
                        echo    "Password: <input type=\"password\" name=\"password\"/>\n";
123
                        echo    "<input type=\"submit\" value=\"Submit\"/>\n";
124
                        echo "</form>\n";
125
                        exit();
126
                    }
127
                }
128
129
                if ($node instanceof Collection) {
130
                    $mime = 'application/zip';
131
                    $stream = $node->getZip();
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $stream is correct as $node->getZip() (which targets Balloon\Filesystem\Node\AbstractNode::getZip()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
132
                    $name = $node->getName().'.zip';
133
                } else {
134
                    $mime = $node->getContentType();
135
                    $stream = $node->get();
136
                    $name = $node->getName();
137
                }
138
139
                if (true === $download || preg_match('#html#', $mime)) {
140
                    header('Content-Disposition: attachment; filename*=UTF-8\'\''.rawurlencode($name));
141
                    header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
142
                    header('Content-Type: application/octet-stream');
143
                    header('Content-Length: '.$node->getSize());
144
                    header('Content-Transfer-Encoding: binary');
145
                } else {
146
                    header('Content-Disposition: inline; filename="'.$name.'"');
147
                    header('Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0');
148
                    header('Content-Type: '.$mime);
149
                }
150
151
                if (null === $stream) {
152
                    exit();
153
                }
154
155
                while (!feof($stream)) {
156
                    echo fread($stream, 8192);
157
                }
158
            } catch (\Exception $e) {
159
                $this->logger->error("failed load node with access token [$token]", [
160
                    'category' => get_class($this),
161
                    'exception' => $e,
162
                ]);
163
164
                (new Response())
165
                    ->setOutputFormat('text')
166
                    ->setCode(404)
167
                    ->setBody('Token is invalid or share link is expired')
168
                    ->send();
169
            }
170
        } else {
171
            (new Response())
172
                ->setOutputFormat('text')
173
                ->setCode(401)
174
                ->setBody('No token submited')
175
                ->send();
176
        }
177
178
        return true;
179
    }
180
}
181