Skip to content

Commit 39f9c1f

Browse files
authored
update: Add custom domain support with automatic fallback validation (#73)
* Add custom domain support with automatic fallback validation * Add PHPStan type hint for getCustomDomainOptions
1 parent c2ca0f6 commit 39f9c1f

6 files changed

Lines changed: 148 additions & 12 deletions

File tree

pastefox-share/README.md

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ Share console logs via [pastefox.com](https://pastefox.com) with one click.
1010
- Visual effects (Matrix, Confetti, Glitch, etc.)
1111
- Theme selection (Light/Dark)
1212
- Password protection support
13+
- Custom domain support
1314
- Fetches up to 5000 log lines
1415

1516
## Configuration
@@ -18,13 +19,14 @@ Share console logs via [pastefox.com](https://pastefox.com) with one click.
1819
2. Find **PasteFox Share** and click the **Settings** (gear icon) button
1920
3. Configure the following settings:
2021

21-
| Setting | Description |
22-
|------------|----------------------------------------------------|
23-
| API Key | Optional - Get from https://pastefox.com/dashboard |
24-
| Visibility | PUBLIC or PRIVATE (requires API key) |
25-
| Effect | Visual effect for the paste |
26-
| Theme | Light or Dark theme |
27-
| Password | Optional password protection |
22+
| Setting | Description |
23+
|---------------|----------------------------------------------------|
24+
| API Key | Optional - Get from https://pastefox.com/dashboard |
25+
| Visibility | PUBLIC or PRIVATE (requires API key) |
26+
| Effect | Visual effect for the paste |
27+
| Theme | Light or Dark theme |
28+
| Password | Optional password protection |
29+
| Custom Domain | Use your own domain for paste URLs |
2830

2931
### Without API Key
3032
- Pastes expire after 7 days
@@ -33,7 +35,19 @@ Share console logs via [pastefox.com](https://pastefox.com) with one click.
3335
### With API Key
3436
- No expiration limit
3537
- Private pastes available
38+
- Effects
3639
- Password protection
40+
- Custom domain support
41+
42+
## Custom Domains
43+
44+
Use your own domain (e.g., `logs.yourdomain.com`) for sharing pastes.
45+
46+
1. Add and verify your domain at [PasteFox Dashboard → Custom Domains](https://pastefox.com/dashboard/domains)
47+
2. Verify & Activate the domain in the PasteFox dashboard
48+
3. Select the domain in the plugin settings
49+
50+
The plugin automatically falls back to `pastefox.com` if the configured domain becomes unavailable or inactive.
3751

3852
## Usage
3953

pastefox-share/config/pastefox-share.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@
66
'effect' => env('PASTEFOX_EFFECT', 'NONE'),
77
'theme' => env('PASTEFOX_THEME', 'dark'),
88
'password' => env('PASTEFOX_PASSWORD'),
9+
'custom_domain' => env('PASTEFOX_CUSTOM_DOMAIN'),
910
];

pastefox-share/lang/en/messages.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,14 @@
3737
'theme_light' => 'Light',
3838
'password' => 'Password Protection',
3939
'password_helper' => 'Optional - 4-100 characters',
40+
41+
// Custom Domain
42+
'section_custom_domain' => 'Custom Domain',
43+
'section_custom_domain_description' => 'Use your own domain for sharing pastes. Requires API key. Manage domains at Dashboard → Custom Domains.',
44+
'custom_domain' => 'Custom Domain',
45+
'custom_domain_none' => 'None (use pastefox.com)',
46+
'custom_domain_helper' => 'Select a verified domain to use for paste URLs',
47+
'custom_domain_no_api_key' => 'API key required for custom domains',
48+
'custom_domain_fetch_error' => 'Could not fetch domains',
49+
'custom_domain_inactive' => 'inactive',
4050
];

pastefox-share/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"id": "pastefox-share",
33
"name": "PasteFox Share",
44
"author": "FlexKleks",
5-
"version": "1.0.0",
5+
"version": "1.1.0",
66
"description": "Share console logs via pastefox.com",
77
"category": "plugin",
88
"url": "https://github.com/pelican-dev/plugins/tree/main/pastefox-share",

pastefox-share/src/Filament/Components/Actions/UploadLogsAction.php

Lines changed: 58 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ protected function setUp(): void
5151
$logs = is_array($logs) ? implode(PHP_EOL, $logs) : $logs;
5252

5353
$apiKey = config('pastefox-share.api_key');
54-
$hasApiKey = filled($apiKey);
54+
$validApiKey = $this->isApiKeyValid($apiKey);
5555

5656
$headers = ['Content-Type' => 'application/json'];
5757

@@ -63,7 +63,7 @@ protected function setUp(): void
6363
'theme' => config('pastefox-share.theme'),
6464
];
6565

66-
if ($hasApiKey) {
66+
if ($validApiKey) {
6767
$headers['X-API-Key'] = $apiKey;
6868
$payload['visibility'] = config('pastefox-share.visibility');
6969

@@ -81,10 +81,12 @@ protected function setUp(): void
8181
->json();
8282

8383
if ($response['success']) {
84-
$url = 'https://pastefox.com/'.$response['data']['slug'];
84+
$customDomain = $validApiKey ? $this->getActiveCustomDomain($apiKey) : null;
85+
$baseUrl = filled($customDomain) ? "https://{$customDomain}" : 'https://pastefox.com';
86+
$url = $baseUrl . '/' . $response['data']['slug'];
8587

8688
$body = $url;
87-
if (!$hasApiKey) {
89+
if (!$validApiKey) {
8890
$body .= "\n".trans('pastefox-share::messages.expires_7_days');
8991
}
9092

@@ -112,4 +114,56 @@ protected function setUp(): void
112114
}
113115
});
114116
}
117+
118+
protected function getActiveCustomDomain(?string $apiKey): ?string
119+
{
120+
$configuredDomain = config('pastefox-share.custom_domain');
121+
122+
if (blank($configuredDomain) || blank($apiKey)) {
123+
return null;
124+
}
125+
126+
try {
127+
$response = Http::withHeaders([
128+
'X-API-Key' => $apiKey,
129+
'Content-Type' => 'application/json',
130+
])
131+
->timeout(5)
132+
->get('https://pastefox.com/api/domains')
133+
->json();
134+
135+
if ($response['success'] ?? false) {
136+
foreach ($response['domains'] ?? [] as $domain) {
137+
if ($domain['domain'] === $configuredDomain && ($domain['isActive'] ?? false)) {
138+
return $configuredDomain;
139+
}
140+
}
141+
}
142+
} catch (\Exception $e) {
143+
// Silently fail, fall back to default
144+
}
145+
146+
return null;
147+
}
148+
149+
protected function isApiKeyValid(?string $apiKey): bool
150+
{
151+
if (blank($apiKey)) {
152+
return false;
153+
}
154+
155+
try {
156+
$response = Http::withHeaders([
157+
'X-API-Key' => $apiKey,
158+
'Content-Type' => 'application/json',
159+
])
160+
->timeout(5)
161+
->get('https://pastefox.com/api/domains')
162+
->json();
163+
164+
return $response['success'] ?? false;
165+
} catch (\Exception $e) {
166+
return false;
167+
}
168+
}
115169
}

pastefox-share/src/PasteFoxSharePlugin.php

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Filament\Notifications\Notification;
1111
use Filament\Panel;
1212
use Filament\Schemas\Components\Section;
13+
use Illuminate\Support\Facades\Http;
1314

1415
class PasteFoxSharePlugin implements HasPluginSettings, Plugin
1516
{
@@ -83,9 +84,64 @@ public function getSettingsForm(): array
8384
->helperText(trans('pastefox-share::messages.password_helper'))
8485
->default(fn () => config('pastefox-share.password')),
8586
]),
87+
88+
Section::make(trans('pastefox-share::messages.section_custom_domain'))
89+
->description(trans('pastefox-share::messages.section_custom_domain_description'))
90+
->schema([
91+
Select::make('custom_domain')
92+
->label(trans('pastefox-share::messages.custom_domain'))
93+
->options(fn () => $this->getCustomDomainOptions())
94+
->disableOptionWhen(fn (string $value): bool => str_ends_with($value, ':disabled'))
95+
->default(fn () => config('pastefox-share.custom_domain'))
96+
->helperText(fn () => filled(config('pastefox-share.api_key'))
97+
? trans('pastefox-share::messages.custom_domain_helper')
98+
: trans('pastefox-share::messages.custom_domain_no_api_key'))
99+
->disabled(fn () => blank(config('pastefox-share.api_key'))),
100+
]),
86101
];
87102
}
88103

104+
/**
105+
* @return array<string, string>
106+
*/
107+
protected function getCustomDomainOptions(): array
108+
{
109+
$options = ['' => trans('pastefox-share::messages.custom_domain_none')];
110+
111+
$apiKey = config('pastefox-share.api_key');
112+
if (blank($apiKey)) {
113+
return $options;
114+
}
115+
116+
try {
117+
$response = Http::withHeaders([
118+
'X-API-Key' => $apiKey,
119+
'Content-Type' => 'application/json',
120+
])
121+
->timeout(10)
122+
->get('https://pastefox.com/api/domains')
123+
->json();
124+
125+
if ($response['success'] ?? false) {
126+
foreach ($response['domains'] ?? [] as $domain) {
127+
if ($domain['status'] !== 'ACTIVE') {
128+
continue;
129+
}
130+
131+
if ($domain['isActive'] ?? false) {
132+
$options[$domain['domain']] = $domain['domain'];
133+
} else {
134+
$options[$domain['domain'] . ':disabled'] = $domain['domain'] . ' (' . trans('pastefox-share::messages.custom_domain_inactive') . ')';
135+
}
136+
}
137+
}
138+
} catch (\Exception $e) {
139+
// Silently fail, just return default options
140+
}
141+
142+
return $options;
143+
}
144+
89145
public function saveSettings(array $data): void
90146
{
91147
$this->writeToEnvironment([
@@ -94,6 +150,7 @@ public function saveSettings(array $data): void
94150
'PASTEFOX_EFFECT' => $data['effect'] ?? 'NONE',
95151
'PASTEFOX_THEME' => $data['theme'] ?? 'dark',
96152
'PASTEFOX_PASSWORD' => $data['password'] ?? '',
153+
'PASTEFOX_CUSTOM_DOMAIN' => $data['custom_domain'] ?? '',
97154
]);
98155

99156
Notification::make()

0 commit comments

Comments
 (0)