Skip to content

Commit

Permalink
Fix support x-forwarded-prefix
Browse files Browse the repository at this point in the history
  • Loading branch information
vtsykun committed Jan 25, 2025
1 parent b413acd commit 3b98103
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 12 deletions.
28 changes: 28 additions & 0 deletions docs/reverse-proxy.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,34 @@ server {
}
```

#### Nginx with a sub-path

In case you already have a site, and you want Packeton to share the domain name,
you can setup Nginx to serve Packeton under a sub-path by adding the following
server section into the http section of nginx.conf:

```
server {
....
location ~ ^/packeton(/?)(.*) {
resolver 1.1.1.1 valid=30s;
set $upstream_pkg pack4.example.com;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Prefix /packeton;
proxy_set_header X-Forwarded-Host portal.example.com;
proxy_pass https://$upstream_pkg/$2$is_args$args;
}
}
```

Where `X-Forwarded-Host` real host and `X-Forwarded-Prefix` site prefix.

Then you MUST set something like `TRUSTED_PROXIES=172.16.0.0/12,127.0.0.1` correctly in your .env vars. 172.16.0.0/12 - IPs of proxy servers

#### Apache

```
Expand Down
4 changes: 3 additions & 1 deletion src/Composer/Cache/MetadataCache.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,15 @@
namespace Packeton\Composer\Cache;

use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\Routing\RequestContext;
use Symfony\Contracts\Cache\CacheInterface;

class MetadataCache
{
public function __construct(
private readonly RequestStack $requestStack,
private readonly CacheInterface $packagesCachePool,
private readonly RequestContext $requestContext,
private readonly int $maxTtl = 1800 // TTL default / 2
) {
}
Expand All @@ -22,7 +24,7 @@ public function get(string $key, callable $callback, ?int $lastModify = null, ?c
// But for will protection must be used trusted_hosts
$httpKey = $this->requestStack->getMainRequest()?->getSchemeAndHttpHost();

$cacheKey = sha1($key . $httpKey);
$cacheKey = sha1($key . $httpKey . $this->requestContext->getBaseUrl());
$item = $this->packagesCachePool->getItem($cacheKey);
@[$ctime, $data] = $item->get();

Expand Down
7 changes: 6 additions & 1 deletion src/EventListener/PackagistListener.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,18 @@
use Packeton\Model\ProviderManager;
use Packeton\Service\DistConfig;
use Packeton\Service\SubRepositoryHelper;
use Packeton\Trait\RequestContextTrait;
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\EventDispatcher\Attribute\AsEventListener;
use Symfony\Component\Routing\RequestContext;

#[AsEventListener(event: 'formHandler')]
#[AsDoctrineListener(event: 'onFlush')]
#[AsEntityListener(event: 'postLoad', entity: 'Packeton\Entity\Version')]
class PackagistListener
{
use RequestContextTrait;

private static $trackLastModifyClasses = [
GroupAclPermission::class => true,
Group::class => true,
Expand All @@ -40,6 +44,7 @@ public function __construct(
private readonly RequestStack $requestStack,
private readonly ProviderManager $providerManager,
private readonly SubRepositoryHelper $subRepositoryHelper,
private readonly RequestContext $requestContext,
) {
}

Expand All @@ -59,7 +64,7 @@ public function postLoad(Version $version, PostLoadEventArgs $event)
if (isset($dist['url']) && \str_starts_with($dist['url'], DistConfig::HOSTNAME_PLACEHOLDER)) {
$currentHost = $request->getSchemeAndHttpHost();
$slug = $this->subRepositoryHelper->getCurrentSlug();
$replacement = null !== $slug ? $currentHost . '/' . $slug : $currentHost;
$replacement = rtrim($currentHost . $this->generateUrl('/') . $slug . '/', '/');

$dist['url'] = \str_replace(DistConfig::HOSTNAME_PLACEHOLDER, $replacement, $dist['url']);
$version->distNormalized = $dist;
Expand Down
12 changes: 10 additions & 2 deletions src/Integrations/Security/OAuth2Authenticator.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,12 @@
use Packeton\Entity\User;
use Packeton\Integrations\IntegrationRegistry;
use Packeton\Integrations\LoginInterface;
use Packeton\Trait\RequestContextTrait;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpClient\Exception\ClientException;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
Expand All @@ -24,10 +26,13 @@

class OAuth2Authenticator implements InteractiveAuthenticatorInterface
{
use RequestContextTrait;

public function __construct(
protected IntegrationRegistry $integrations,
protected ManagerRegistry $registry,
protected LoggerInterface $logger
protected LoggerInterface $logger,
protected RequestContext $requestContext,
) {
}

Expand Down Expand Up @@ -157,6 +162,9 @@ public function isInteractive(): bool
// Used to remove referral header.
protected function getJSRedirectTemplate($route): string
{
$path = $this->generateUrl('/packeton/js/redirect.js');
$route = $this->generateUrl($route);

$text = <<<TXT
<html lang="en">
<head>
Expand All @@ -167,7 +175,7 @@ protected function getJSRedirectTemplate($route): string
<div>
<p>Processing redirect <a id="route" href="$route">$route</a></p>
</div>
<script src="/packeton/js/redirect.js"></script>
<script src="$path"></script>
</body>
</html>
TXT;
Expand Down
21 changes: 14 additions & 7 deletions src/Package/InMemoryDumper.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,15 @@
use Packeton\Security\Acl\PackagesAclChecker;
use Packeton\Service\DistConfig;
use Packeton\Service\SubRepositoryHelper;
use Packeton\Trait\RequestContextTrait;
use Symfony\Component\Routing\RequestContext;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\User\UserInterface;

class InMemoryDumper
{
use RequestContextTrait;

private MetadataFormat $metadataFormat;
private ?string $infoMessage;

Expand All @@ -31,6 +35,7 @@ public function __construct(
private readonly RouterInterface $router,
private readonly SubRepositoryHelper $subRepositoryHelper,
private readonly DistConfig $distConfig,
private readonly RequestContext $requestContext,
?array $config = null,
) {
$this->infoMessage = $config['info_cmd_message'] ?? null;
Expand Down Expand Up @@ -97,21 +102,23 @@ private function dumpRootPackages(?UserInterface $user = null, ?int $apiVersion
[$providers, $packagesData, $availablePackages] = $this->dumpUserPackages($user, $apiVersion, $subRepo);

$rootFile = ['packages' => []];
$url = $this->router->generate('track_download', ['name' => 'VND/PKG']);

$slug = $subRepo && !$this->subRepositoryHelper->isAutoHost() ? '/'. $subRepo->getSlug() : '';
$slugName = '' === $slug ? null : $subRepo->getSlug();
$url = $this->generateRoute('track_download', $slugName, ['name' => 'VND/PKG']);

$rootFile['notify'] = $slug . str_replace('VND/PKG', '%package%', $url);
$rootFile['notify-batch'] = $slug . $this->router->generate('track_download_batch');
$rootFile['notify'] = str_replace('VND/PKG', '%package%', $url);
$rootFile['notify-batch'] = $this->generateRoute('track_download_batch', $slugName);
$rootFile['metadata-changes-url'] = $this->router->generate('metadata_changes');
$rootFile['providers-url'] = $slug . '/p/%package%$%hash%.json';
$rootFile['providers-url'] = $this->generateUrl($slug . '/p/%package%$%hash%.json');

if ($this->distConfig->mirrorEnabled()) {
$ref = '0000000000000000000000000000000000000000.zip';
$zipball = $slug . $this->router->generate('download_dist_package', ['package' => 'VND/PKG', 'hash' => $ref]);
$zipball = $this->generateRoute('download_dist_package', $slugName, ['package' => 'VND/PKG', 'hash' => $ref]);
$rootFile['mirrors'][] = ['dist-url' => \str_replace(['VND/PKG', $ref], ['%package%', '%reference%.%type%'], $zipball), 'preferred' => true];
}

$rootFile['metadata-url'] = $slug . '/p2/%package%.json';
$rootFile['metadata-url'] = $this->generateUrl($slug . '/p2/%package%.json');
if ($subRepo) {
$rootFile['_comment'] = "Subrepository {$subRepo->getSlug()}";
}
Expand All @@ -129,7 +136,7 @@ private function dumpRootPackages(?UserInterface $user = null, ?int $apiVersion

if ($this->metadataFormat->lazyProviders($apiVersion)) {
unset($rootFile['provider-includes'], $rootFile['providers-url']);
$rootFile['providers-lazy-url'] = $slug . '/p/%package%.json';
$rootFile['providers-lazy-url'] = $this->generateUrl($slug . '/p/%package%.json');
}

if (false === $this->metadataFormat->metadataUrl($apiVersion)) {
Expand Down
20 changes: 20 additions & 0 deletions src/Trait/RequestContextTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

declare(strict_types=1);

namespace Packeton\Trait;

trait RequestContextTrait
{
private function generateUrl(string $path): string
{
return rtrim($this->requestContext->getBaseUrl(), '/') . $path;
}

private function generateRoute(string $name, ?string $slugName, array $params = []): string
{
return $slugName === null ?
$this->router->generate($name, $params)
: $this->router->generate($name . '_slug', $params + ['slug' => $slugName]);
}
}
3 changes: 2 additions & 1 deletion templates/package/package.html.twig
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@
<div class="col-xs-12 col-sm-10">
{% for version in package.versions %}
{%- if (version.dist) and (version.type != 'metapackage') -%}
{% set distURL = version.distNormalized['url'] ?? version.dist['url']|replace({'__host_unset__': ''}) %}

<a href="{{ version.dist['url']|replace({'__host_unset__': ''}) }}" title="dist-reference: {{ version.dist['reference'] }}">
<a href="{{ distURL }}" title="dist-reference: {{ version.dist['reference'] }}">
{{ version.version }}
</a>
{%- else -%}
Expand Down

0 comments on commit 3b98103

Please sign in to comment.