Completed
Push — master ( 8c9911...54b06b )
by Raffael
26:03 queued 22:08
created

Http::start()   B

Complexity

Conditions 7
Paths 34

Size

Total Lines 46

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 56

Importance

Changes 0
Metric Value
dl 0
loc 46
ccs 0
cts 39
cp 0
rs 8.2448
c 0
b 0
f 0
cc 7
nc 34
nop 3
crap 56
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\Api\Helper;
15
use Balloon\App\Api\v1\AttributeDecorator\NodeDecorator as NodeAttributeDecoratorv1;
16
use Balloon\App\Sharelink\Api\v1;
17
use Balloon\App\Sharelink\Api\v2;
18
use Balloon\App\Sharelink\Sharelink as Share;
19
use Balloon\Filesystem\Node\AttributeDecorator as NodeAttributeDecorator;
20
use Balloon\Filesystem\Node\Collection;
21
use Balloon\Hook;
22
use Balloon\Hook\AbstractHook;
23
use Balloon\Server;
24
use DateTime;
25
use Micro\Auth\Adapter\None as AuthNone;
26
use Micro\Auth\Auth;
27
use Micro\Http\Response;
28
use Micro\Http\Router;
29
use Micro\Http\Router\Route;
30
use Psr\Log\LoggerInterface;
31
32
class Http
33
{
34
    /**
35
     * Sharelink.
36
     *
37
     * @var Share
38
     */
39
    protected $sharelink;
40
41
    /**
42
     * Logger.
43
     *
44
     * @var LoggerInterface
45
     */
46
    protected $logger;
47
48
    /**
49
     * Server.
50
     *
51
     * @var Server
52
     */
53
    protected $server;
54
55
    /**
56
     * Init.
57
     */
58
    public function __construct(Router $router, Server $server, Hook $hook, Share $sharelink, NodeAttributeDecorator $node_decorator_v2, NodeAttributeDecoratorv1 $node_decorator_v1, LoggerInterface $logger)
59
    {
60
        $this->server = $server;
61
62
        $router
63
            ->appendRoute(new Route('/share/{t:#(.*+)#}', $this, 'start'))
64
            ->appendRoute(new Route('/share', $this, 'start'))
65
            ->prependRoute(new Route('/api/v1/(node|file|collection)/share-link', v1\ShareLink::class))
66
            ->prependRoute(new Route('/api/v1/(node|file|collection)/{id:#([0-9a-z]{24})#}/share-link', v1\ShareLink::class))
67
            ->prependRoute(new Route('/api/v2/(nodes|files|collections)/share-link(/|\z)', v2\ShareLink::class))
68
            ->prependRoute(new Route('/api/v2/(nodes|files|collections)/{id:#([0-9a-z]{24})#}/share-link(/|\z)', v2\ShareLink::class));
69
70
        $hook->injectHook(new class() extends AbstractHook {
71
            public function preAuthentication(Auth $auth): void
72
            {
73
                if (preg_match('#^/index.php/share#', $_SERVER['ORIG_SCRIPT_NAME'])) {
74
                    $auth->injectAdapter(new AuthNone());
75
                }
76
            }
77
        });
78
79
        $node_decorator_v2->addDecorator('sharelink_has_password', function ($node) use ($sharelink) {
80
            $attributes = $sharelink->getSharelink($node);
81
82
            return isset($attributes['password']);
83
        });
84
85
        $node_decorator_v2->addDecorator('sharelink_token', function ($node) use ($sharelink) {
86
            $attributes = $sharelink->getSharelink($node);
87
88
            if (isset($attributes['token'])) {
89
                return $attributes['token'];
90
            }
91
        });
92
93
        $node_decorator_v2->addDecorator('sharelink_expire', function ($node) use ($sharelink) {
94
            $attributes = $sharelink->getSharelink($node);
95
96
            if (isset($attributes['expiration'])) {
97
                $ts = (new DateTime())->setTimestamp((int) $attributes['expiration']);
98
99
                return $ts->format('c');
100
            }
101
        });
102
103
        $node_decorator_v1->addDecorator('sharelink', function ($node) use ($sharelink) {
104
            return isset($sharelink->getSharelink($node)['token']);
105
        });
106
107
        $this->logger = $logger;
108
        $this->sharelink = $sharelink;
109
    }
110
111
    /**
112
     * Start.
113
     */
114
    public function start(string $t, bool $download = false, ?string $password = null)
115
    {
116
        try {
117
            $node = $this->sharelink->findNodeWithShareToken($t);
118
            $share = $node->getAppAttributes('Balloon\\App\\Sharelink');
119
            $node->setFilesystem($this->server->getFilesystem($this->server->getUserById($node->getOwner())));
120
121
            if (array_key_exists('password', $share)) {
122
                $valid = false;
123
                if ($password !== null) {
124
                    $valid = hash('sha256', $password) === $share['password'];
125
                }
126
127
                if (false === $valid) {
128
                    echo "<form method=\"post\">\n";
129
                    echo    "Password: <input type=\"password\" name=\"password\"/>\n";
130
                    echo    "<input type=\"submit\" value=\"Submit\"/>\n";
131
                    echo "</form>\n";
132
                    exit();
133
                }
134
            }
135
136
            if ($node instanceof Collection) {
137
                $node->getZip();
138
                exit();
139
            }
140
141
            if (preg_match('#html#', $node->getContentType())) {
142
                $download = true;
143
            }
144
145
            $response = new Response();
146
147
            return Helper::streamContent($response, $node, $download);
148
        } catch (\Exception $e) {
149
            $this->logger->error('failed load node with given access token', [
150
                'category' => get_class($this),
151
                'exception' => $e,
152
            ]);
153
154
            return (new Response())
155
                ->setOutputFormat('text')
156
                ->setCode(404)
157
                ->setBody('Token is invalid or share link is expired');
158
        }
159
    }
160
}
161