UrlTrackingService   A
last analyzed

Complexity

Total Complexity 11

Size/Duplication

Total Lines 56
Duplicated Lines 0 %

Importance

Changes 1
Bugs 0 Features 1
Metric Value
wmc 11
eloc 27
c 1
b 0
f 1
dl 0
loc 56
rs 10

2 Methods

Rating   Name   Duplication   Size   Complexity  
B safeRedirect() 0 25 7
A rewriteUrlsForTracking() 0 21 4
1
<?php
2
3
namespace Usamamuneerchaudhary\Notifier\Services;
4
5
use Illuminate\Http\RedirectResponse;
6
7
class UrlTrackingService
8
{
9
    /**
10
     * Safely redirect to URL with validation
11
     */
12
    public function safeRedirect(string $url): RedirectResponse
13
    {
14
        $dangerousProtocols = ['javascript:', 'data:', 'vbscript:', 'file:', 'about:'];
15
        $urlLower = strtolower(trim($url));
16
17
        foreach ($dangerousProtocols as $protocol) {
18
            if (str_starts_with($urlLower, $protocol)) {
19
                return redirect()->to('/');
20
            }
21
        }
22
23
        if (!filter_var($url, FILTER_VALIDATE_URL)) {
24
            if (!str_starts_with($url, '/')) {
25
                $url = '/' . $url;
26
            }
27
            return redirect()->to($url);
28
        }
29
30
        // Only allow http/https protocols
31
        $parsedUrl = parse_url($url);
32
        if (isset($parsedUrl['scheme']) && !in_array(strtolower($parsedUrl['scheme']), ['http', 'https'])) {
33
            return redirect()->to('/');
34
        }
35
36
        return redirect()->away($url);
37
    }
38
39
    /**
40
     * Rewrite URLs in content for click tracking
41
     */
42
    public function rewriteUrlsForTracking(string $content, string $token): string
43
    {
44
        $appUrl = rtrim(config('app.url', ''), '/');
45
        $trackingUrl = "{$appUrl}/notifier/track/click/{$token}";
46
47
        $pattern = '/href=["\']([^"\']+)["\']/i';
48
49
        return preg_replace_callback($pattern, function ($matches) use ($trackingUrl) {
50
            $originalUrl = $matches[1];
51
52
            if (str_contains($originalUrl, '/notifier/track/') ||
53
                str_starts_with($originalUrl, 'mailto:') ||
54
                str_starts_with($originalUrl, 'tel:')) {
55
                return $matches[0];
56
            }
57
58
            $encodedUrl = urlencode($originalUrl);
59
            $newUrl = "{$trackingUrl}?url={$encodedUrl}";
60
61
            return 'href="' . htmlspecialchars($newUrl, ENT_QUOTES, 'UTF-8') . '"';
62
        }, $content);
63
    }
64
}
65