55 Commits

Author SHA1 Message Date
Marcel Pociot
ff232d9ef4 Merge branch '1.0' of github.com:beyondcode/phunnel into 1.0 2020-12-07 23:31:08 +01:00
Marcel Pociot
5b8cc4d985 Allow specifying server host and port in share command 2020-12-07 23:30:57 +01:00
Marcel Pociot
26a805c552 Merge pull request #164 from beyondcode/analysis-gOmLGw
Apply fixes from StyleCI
2020-12-05 00:34:31 +01:00
Marcel Pociot
28cc353c30 Apply fixes from StyleCI 2020-12-04 23:34:24 +00:00
Marcel Pociot
7bfb618d93 wip 2020-12-05 00:34:01 +01:00
Marcel Pociot
41e6e674e0 wip 2020-07-28 22:34:30 +02:00
Marcel Pociot
3d76b49fea wip 2020-07-28 22:23:31 +02:00
Marcel Pociot
1d5169af07 fix github packages config 2020-07-28 22:08:48 +02:00
Marcel Pociot
0945b1e66b Merge branch 'lukepolo-master' 2020-07-28 21:39:10 +02:00
Marcel Pociot
a2bdf518ab change docker hub namespace 2020-07-28 21:39:03 +02:00
Marcel Pociot
0216948d18 Merge branch 'master' of https://github.com/lukepolo/expose into lukepolo-master 2020-07-28 21:38:00 +02:00
Marcel Pociot
9e31b020b6 Merge pull request #103 from beyondcode/analysis-ZlOyRP
Apply fixes from StyleCI
2020-07-27 22:11:58 +02:00
Marcel Pociot
bf0025979e Apply fixes from StyleCI 2020-07-27 20:11:50 +00:00
Marcel Pociot
dda3cbbae5 Merge pull request #87 from localheinz/feature/normalize
Enhancement: Normalize composer.json
2020-07-27 22:11:29 +02:00
Andreas Möller
6a07859078 Enhancement: Normalize composer.json 2020-07-06 23:18:27 +02:00
Marcel Pociot
e5b2aada2f Bump build for 1.3.0 2020-07-01 18:17:32 +02:00
Marcel Pociot
076da2c0de Use hardcoded version 2020-07-01 18:14:55 +02:00
Marcel Pociot
6410c7eb5e Merge pull request #81 from beyondcode/analysis-GDEdVA
Apply fixes from StyleCI
2020-07-01 18:11:21 +02:00
Marcel Pociot
0d9413dfdf Apply fixes from StyleCI 2020-07-01 16:11:13 +00:00
Marcel Pociot
87a4115c14 Merge pull request #79 from ahmedash95/users-pagination
Add simple pagination to users page
2020-07-01 18:10:58 +02:00
Luke Policinski
096a2b2a70 Simplified based on githubs docs
https://docs.github.com/en/actions/language-and-framework-guides/publishing-docker-images
2020-07-01 11:59:53 -04:00
Marcel Pociot
6d6306b3b2 Add request time to cli output 2020-07-01 17:58:54 +02:00
Marcel Pociot
611a4c617c Add X-Forwarded-Host header. Fixes #63 2020-07-01 17:46:54 +02:00
Marcel Pociot
54bd95c66c Merge pull request #67 from Ayesh/export-ignore
Update .gitattributes to export-ignore tests, docs, and other build files
2020-07-01 17:41:59 +02:00
Luke Policinski
3cb254e1f5 Update starting-the-server.md 2020-06-30 14:32:47 -04:00
Ahmed Ashraf
e960ffb825 Implement simple pagination 2020-06-26 12:20:01 +02:00
Marcel Pociot
459135f286 Merge pull request #74 from okaufmann/fix-remaining-time
fix remaining time calculation
2020-06-26 00:51:01 +02:00
Marcel Pociot
0efb42f989 Merge pull request #76 from riasvdv/patch-1
Don't use underscore in subdomain
2020-06-26 00:49:43 +02:00
Rias
6f04a0dfb6 Don't use underscore in subdomain
Even though it's perfectly valid, some providers (Paddle in our case) don't validate URLs with an underscore in them as valid, an easy fix is just using a dash instead.
2020-06-25 13:11:55 +02:00
Oliver Kaufmann
91f169460e fix remaining time calculation 2020-06-25 02:09:00 +02:00
Marcel Pociot
f8a6b45af7 Merge pull request #73 from clmntgr/patch-1
Update sharing.md with an https example
2020-06-24 11:22:30 +02:00
Clément Aigreault
b48dba1413 Update sharing.md with an https example 2020-06-24 11:18:20 +02:00
Marcel Pociot
8bcc7613d9 Merge pull request #71 from dakira/patch-1
Document missing nginx header config for ssl
2020-06-24 09:59:40 +02:00
Matthias Niess
9158887a60 document missing nginx header config for ssl 2020-06-24 09:54:13 +02:00
Luke Policinski
b3f2edd18c dont copy tests / .git 2020-06-23 13:03:06 -04:00
Luke Policinski
b4379ddf6d Adding action to push docker image 2020-06-23 12:44:56 -04:00
Luke Policinski
70a9666f37 Adding how to run with the readme 2020-06-23 12:37:15 -04:00
Luke Policinski
0b9f860138 adding a docker-compose file for starting a server 2020-06-23 12:28:21 -04:00
Ayesh Karunaratne
dae1851e1d Update .gitattributes to export-ignore tests, docs, and other build files 2020-06-23 04:47:03 +07:00
Marcel Pociot
70d275bb1c wip 2020-06-22 22:58:09 +02:00
Marcel Pociot
8b8c6c8e2e Fix subdomain check 2020-06-22 22:57:29 +02:00
Marcel Pociot
c5b89e1179 Add build 2020-06-22 22:51:21 +02:00
Marcel Pociot
18d67abc3f detect valet secured sites automatically 2020-06-22 22:49:19 +02:00
Marcel Pociot
38efb0b879 Merge branch 'master' of github.com:beyondcode/phunnel 2020-06-22 09:05:49 +02:00
Marcel Pociot
04c881a875 Register chrome-extension as a valid uri scheme. Fixes #50 2020-06-22 09:05:40 +02:00
Marcel Pociot
d98eabe36e Merge pull request #46 from drbyte/patch-1
Fix duplicate config section header
2020-06-19 09:34:38 +02:00
Marcel Pociot
262a1eac4a Use toArray representation of sites for the server. Fixes #44 2020-06-19 09:13:26 +02:00
Chris Brown
979bacb928 Fix config section heading 2020-06-18 12:04:50 -04:00
Chris Brown
732e0aeb3e Fix config section header 2020-06-18 12:02:41 -04:00
Marcel Pociot
2c0c544eeb Merge pull request #41 from beyondcode/analysis-KZpkkj
Apply fixes from StyleCI
2020-06-18 10:22:56 +02:00
Marcel Pociot
528d5d74e0 Apply fixes from StyleCI 2020-06-18 08:22:48 +00:00
Marcel Pociot
68200aedc4 wip 2020-06-18 10:21:28 +02:00
Marcel Pociot
8628a7e1b6 Update build to 1.1.0 2020-06-18 10:18:06 +02:00
Marcel Pociot
5df98c4b91 Update changelog 2020-06-18 10:17:13 +02:00
Marcel Pociot
78fbef90cd Merge pull request #40 from beyondcode/analysis-lKY3aQ
Apply fixes from StyleCI
2020-06-18 10:10:45 +02:00
35 changed files with 387 additions and 678 deletions

2
.dockerignore Normal file
View File

@@ -0,0 +1,2 @@
tests
.git

4
.env-example Normal file
View File

@@ -0,0 +1,4 @@
PORT=8080
DOMAIN=example.com
ADMIN_USERNAME=username
ADMIN_PASSWORD=password

17
.gitattributes vendored
View File

@@ -1,7 +1,14 @@
* text=auto
/.github export-ignore
.styleci.yml export-ignore
/.github export-ignore
/tests export-ignore
/docs export-ignore
.gitattributes export-ignore
.gitignore export-ignore
.styleci.yml export-ignore
.scrutinizer.yml export-ignore
BACKERS.md export-ignore
CONTRIBUTING.md export-ignore
CHANGELOG.md export-ignore
BACKERS.md export-ignore
CONTRIBUTING.md export-ignore
CHANGELOG.md export-ignore
nodemod.json export-ignore
phpunit.xml.dist export-ignore

19
.github/workflows/docker-publish.yml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: Publish Docker image
on:
release:
types: [published]
jobs:
push_to_registry:
name: Push Docker image to Docker Hub
runs-on: ubuntu-latest
steps:
- name: Check out the repo
uses: actions/checkout@v2
- name: Push to Docker Hub
uses: docker/build-push-action@v1
with:
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
repository: beyondcodegmbh/expose-server
tag_with_ref: true
tags: latest

1
.gitignore vendored
View File

@@ -7,3 +7,4 @@
expose.php
database/expose.db
.expose.php
.env

22
CHANGELOG.md Normal file
View File

@@ -0,0 +1,22 @@
# Changelog
## 1.3.0 (2020-07-01)
* Feature: Add pagination to admin user interface
* Feature: Add request time to CLI output
* Feature: Add `X-Forwarded-Host` header
* Fix: Fix remaining time calculation
* Fix: Don't use underscores for automatic subdomain generation
## 1.1.0 (2020-06-18)
* Feature: Allow overriding the subdomain when using `expose` without specifying `expose share` explicitly
* Show badges in the local dashboard for 3xx response statuses
* Fix: Updated minimum PHP dependency
* Fix: Added support for detecting the Windows user home path
* Fix: Use minified VueJS versions
* Various spelling fixes
## 1.0.1 (2020-06-17)
* Fixes an issue when setting the auth token
## 1.0.0 (2020-06-17)
* Initial release

24
Dockerfile Normal file
View File

@@ -0,0 +1,24 @@
FROM php:7.4-cli
RUN apt-get update
RUN apt-get install -y git libzip-dev zip
RUN docker-php-ext-install zip
# Get latest Composer
COPY --from=composer:latest /usr/bin/composer /usr/bin/composer
COPY . /src
WORKDIR /src
# install the dependencies
RUN composer install -o --prefer-dist && chmod a+x expose
ENV port=8080
ENV domain=localhost
ENV username=username
ENV password=password
ENV exposeConfigPath=/src/config/expose.php
CMD sed -i "s|username|${username}|g" ${exposeConfigPath} && sed -i "s|password|${password}|g" ${exposeConfigPath} && php expose serve ${domain} --port ${port} --validateAuthTokens
ENTRYPOINT ["/src/expose"]

View File

@@ -45,7 +45,7 @@ class Client
$sharedUrl = $this->prepareSharedUrl($sharedUrl);
foreach ($subdomains as $subdomain) {
$this->connectToServer($sharedUrl, $subdomain, config('expose.auth_token'));
$this->connectToServer($sharedUrl, $subdomain, $this->configuration->auth());
}
}
@@ -84,7 +84,7 @@ class Client
$connection->authenticate($sharedUrl, $subdomain);
$clientConnection->on('close', function () use ($deferred, $sharedUrl, $subdomain, $authToken) {
$clientConnection->on('close', function () use ($sharedUrl, $subdomain, $authToken) {
$this->logger->error('Connection to server closed.');
$this->retryConnectionOrExit($sharedUrl, $subdomain, $authToken);
@@ -108,10 +108,11 @@ class Client
$this->loop->addPeriodicTimer(1, function () use ($data, $timeoutSection) {
$this->timeConnected++;
$carbon = Carbon::createFromFormat('s', str_pad($data->length * 60 - $this->timeConnected, 2, 0, STR_PAD_LEFT));
$secondsRemaining = $data->length * 60 - $this->timeConnected;
$remaining = Carbon::now()->diff(Carbon::now()->addSeconds($secondsRemaining));
$timeoutSection->clear();
$timeoutSection->writeln('Remaining time: '.$carbon->format('H:i:s'));
$timeoutSection->writeln('Remaining time: '.$remaining->format('%H:%I:%S'));
});
});

View File

@@ -66,7 +66,6 @@ class HttpClient
protected function createConnector(): Connector
{
return new Connector($this->loop, [
'dns' => '127.0.0.1',
'tls' => [
'verify_peer' => false,
'verify_peer_name' => false,

View File

@@ -10,7 +10,7 @@ use Symfony\Component\Console\Output\ConsoleOutput;
class ShareCommand extends Command
{
protected $signature = 'share {host} {--subdomain=} {--auth=}';
protected $signature = 'share {host} {--subdomain=} {--auth=} {--server-host=} {--server-port=}';
protected $description = 'Share a local url with a remote expose server';
@@ -27,11 +27,15 @@ class ShareCommand extends Command
{
$this->configureConnectionLogger();
$serverHost = $this->option('server-host') ?? config('expose.host', 'localhost');
$serverPort = $this->option('server-port') ?? config('expose.port', 8080);
$auth = $this->option('auth') ?? config('expose.auth_token', '');
(new Factory())
->setLoop(app(LoopInterface::class))
->setHost(config('expose.host', 'localhost'))
->setPort(config('expose.port', 8080))
->setAuth($this->option('auth'))
->setHost($serverHost)
->setPort($serverPort)
->setAuth($auth)
->createClient()
->share($this->argument('host'), explode(',', $this->option('subdomain')))
->createHttpServer()

View File

@@ -8,10 +8,12 @@ class ShareCurrentWorkingDirectoryCommand extends ShareCommand
public function handle()
{
$this->input->setArgument('host', basename(getcwd()).'.'.$this->detectTld());
$host = $this->prepareSharedHost(basename(getcwd()).'.'.$this->detectTld());
if (! $this->hasOption('subdomain')) {
$subdomain = str_replace('.', '_', basename(getcwd()));
$this->input->setArgument('host', $host);
if (! $this->option('subdomain')) {
$subdomain = str_replace('.', '-', basename(getcwd()));
$this->input->setOption('subdomain', $subdomain);
}
@@ -20,7 +22,7 @@ class ShareCurrentWorkingDirectoryCommand extends ShareCommand
protected function detectTld(): string
{
$valetConfigFile = $_SERVER['HOME'] ?? $_SERVER['USERPROFILE'].DIRECTORY_SEPARATOR.'.config'.DIRECTORY_SEPARATOR.'valet'.DIRECTORY_SEPARATOR.'config.json';
$valetConfigFile = ($_SERVER['HOME'] ?? $_SERVER['USERPROFILE']).DIRECTORY_SEPARATOR.'.config'.DIRECTORY_SEPARATOR.'valet'.DIRECTORY_SEPARATOR.'config.json';
if (file_exists($valetConfigFile)) {
$valetConfig = json_decode(file_get_contents($valetConfigFile));
@@ -30,4 +32,15 @@ class ShareCurrentWorkingDirectoryCommand extends ShareCommand
return config('expose.default_tld', 'test');
}
protected function prepareSharedHost($host): string
{
$certificateFile = ($_SERVER['HOME'] ?? $_SERVER['USERPROFILE']).DIRECTORY_SEPARATOR.'.config'.DIRECTORY_SEPARATOR.'valet'.DIRECTORY_SEPARATOR.'Certificates'.DIRECTORY_SEPARATOR.$host.'.crt';
if (file_exists($certificateFile)) {
return 'https://'.$host;
}
return $host;
}
}

View File

@@ -10,6 +10,8 @@ interface UserRepository
public function getUserById($id): PromiseInterface;
public function paginateUsers(int $perPage, int $currentPage): PromiseInterface;
public function getUserByToken(string $authToken): PromiseInterface;
public function storeUser(array $data): PromiseInterface;

View File

@@ -24,7 +24,7 @@ class CliRequestLogger extends Logger
$this->section = $this->output->section();
$this->table = new Table($this->section);
$this->table->setHeaders(['Method', 'URI', 'Response', 'Duration']);
$this->table->setHeaders(['Method', 'URI', 'Response', 'Time', 'Duration']);
$this->requests = new Collection();
}
@@ -53,6 +53,7 @@ class CliRequestLogger extends Logger
$loggedRequest->getRequest()->getMethod(),
$loggedRequest->getRequest()->getUri(),
optional($loggedRequest->getResponse())->getStatusCode().' '.optional($loggedRequest->getResponse())->getReasonPhrase(),
$loggedRequest->getStartTime()->toDateTimeString(),
$loggedRequest->getDuration().'ms',
];
})->toArray());

View File

@@ -296,6 +296,11 @@ class LoggedRequest implements \JsonSerializable
})->get('x-expose-request-id', (string) Str::uuid());
}
public function getStartTime()
{
return $this->startTime;
}
public function getDuration()
{
return $this->startTime->diffInMilliseconds($this->stopTime, false);

View File

@@ -6,6 +6,8 @@ use App\Logger\CliRequestLogger;
use App\Logger\RequestLogger;
use Clue\React\Buzz\Browser;
use Illuminate\Support\ServiceProvider;
use Laminas\Uri\Uri;
use Laminas\Uri\UriFactory;
use React\EventLoop\Factory as LoopFactory;
use React\EventLoop\LoopInterface;
@@ -13,7 +15,7 @@ class AppServiceProvider extends ServiceProvider
{
public function boot()
{
//
UriFactory::registerScheme('chrome-extension', Uri::class);
}
public function register()

View File

@@ -21,10 +21,10 @@ class GetUsersController extends AdminController
public function handle(Request $request, ConnectionInterface $httpConnection)
{
$this->userRepository
->getUsers()
->then(function ($users) use ($httpConnection) {
->paginateUsers(20, (int) $request->get('page', 1))
->then(function ($paginated) use ($httpConnection) {
$httpConnection->send(
respond_json(['users' => $users])
respond_json(['paginated' => $paginated])
);
$httpConnection->close();

View File

@@ -25,7 +25,12 @@ class ListSitesController extends AdminController
$sites = $this->getView($httpConnection, 'server.sites.index', [
'scheme' => $this->configuration->port() === 443 ? 'https' : 'http',
'configuration' => $this->configuration,
'sites' => $this->connectionManager->getConnections(),
'sites' => collect($this->connectionManager->getConnections())->map(function ($site, $siteId) {
$site = $site->toArray();
$site['id'] = $siteId;
return $site;
})->values(),
]);
$httpConnection->send(

View File

@@ -21,10 +21,10 @@ class ListUsersController extends AdminController
public function handle(Request $request, ConnectionInterface $httpConnection)
{
$this->userRepository
->getUsers()
->then(function ($users) use ($httpConnection) {
->paginateUsers(20, (int) $request->get('page', 1))
->then(function ($paginated) use ($httpConnection) {
$httpConnection->send(
respond_html($this->getView($httpConnection, 'server.users.index', ['users' => $users]))
respond_html($this->getView($httpConnection, 'server.users.index', ['paginated' => $paginated]))
);
$httpConnection->close();

View File

@@ -136,7 +136,7 @@ class ControlMessageController implements MessageComponentInterface
$this->userRepository
->getUserByToken($authToken)
->then(function ($user) use ($connection, $deferred) {
->then(function ($user) use ($deferred) {
if (is_null($user)) {
$deferred->reject();
} else {

View File

@@ -75,7 +75,7 @@ class TunnelMessageController extends Controller
$httpConnection = $this->connectionManager->storeHttpConnection($httpConnection, $requestId);
transform($this->passRequestThroughModifiers($request, $httpConnection), function (Request $request) use ($controlConnection, $httpConnection, $requestId) {
transform($this->passRequestThroughModifiers($request, $httpConnection), function (Request $request) use ($controlConnection, $requestId) {
$controlConnection->once('proxy_ready_'.$requestId, function (ConnectionInterface $proxy) use ($request) {
// Convert the Laravel request into a PSR7 request
$psr17Factory = new Psr17Factory();
@@ -119,6 +119,7 @@ class TunnelMessageController extends Controller
$request->headers->set('Upgrade-Insecure-Requests', 1);
$request->headers->set('X-Exposed-By', config('app.name').' '.config('app.version'));
$request->headers->set('X-Original-Host', "{$controlConnection->subdomain}.{$host}");
$request->headers->set('X-Forwarded-Host', "{$controlConnection->subdomain}.{$host}");
return $request;
}

View File

@@ -31,6 +31,35 @@ class DatabaseUserRepository implements UserRepository
return $deferred->promise();
}
public function paginateUsers(int $perPage, int $currentPage): PromiseInterface
{
$deferred = new Deferred();
$this->database
->query('SELECT * FROM users ORDER by created_at DESC LIMIT :limit OFFSET :offset', [
'limit' => $perPage + 1,
'offset' => $currentPage < 2 ? 0 : ($currentPage - 1) * $perPage,
])
->then(function (Result $result) use ($deferred, $perPage, $currentPage) {
if (count($result->rows) == $perPage + 1) {
array_pop($result->rows);
$nextPage = $currentPage + 1;
}
$paginated = [
'users' => $result->rows,
'current_page' => $currentPage,
'per_page' => $perPage,
'next_page' => $nextPage ?? null,
'previous_page' => $currentPage > 1 ? $currentPage - 1 : null,
];
$deferred->resolve($paginated);
});
return $deferred->promise();
}
public function getUserById($id): PromiseInterface
{
$deferred = new Deferred();

Binary file not shown.

View File

@@ -1,9 +1,13 @@
{
"name": "beyondcode/expose",
"description": "Expose",
"keywords": ["expose", "tunnel", "ngrok"],
"homepage": "https://sharedwithexpose.com",
"type": "project",
"description": "Expose",
"keywords": [
"expose",
"tunnel",
"ngrok"
],
"homepage": "https://sharedwithexpose.com",
"license": "MIT",
"authors": [
{
@@ -11,44 +15,43 @@
"email": "marcel@beyondco.de"
}
],
"repositories": [
{
"type": "vcs",
"url": "https://github.com/seankndy/reactphp-sqlite"
}
],
"require": {
"php": "^7.3.0",
"ext-json": "*",
"padraic/phar-updater": "^1.0.6"
},
"require-dev": {
"nikic/php-parser": "^4.4",
"cboden/ratchet": "^0.4.2",
"clue/block-react": "^1.3",
"clue/buzz-react": "^2.7",
"clue/reactphp-sqlite": "dev-modular-worker-for-phar-support",
"guzzlehttp/guzzle": "^6.5",
"guzzlehttp/psr7": "dev-master as 1.6.1",
"illuminate/http": "5.8.*|^6.0|^7.0",
"illuminate/http": "5.8.* || ^6.0 || ^7.0",
"illuminate/pipeline": "^7.6",
"illuminate/validation": "^7.7",
"laminas/laminas-http": "^2.11",
"laravel-zero/framework": "^7.0",
"mockery/mockery": "^1.3",
"namshi/cuzzle": "^2.0",
"nikic/php-parser": "^4.4",
"nyholm/psr7": "^1.2",
"phpunit/phpunit": "^8.5",
"ratchet/pawl": "^0.3.4",
"react/http": "^0.8.6",
"react/socket": "dev-master as 1.1",
"react/stream": "^1.1.1",
"react/socket": "^1.4",
"riverline/multipart-parser": "^2.0",
"symfony/expression-language": "^5.0",
"symfony/http-kernel": "^4.0|^5.0",
"symfony/http-kernel": "^4.0 || ^5.0",
"symfony/psr-http-message-bridge": "^2.0",
"twig/twig": "^3.0"
},
"config": {
"optimize-autoloader": true,
"preferred-install": "dist",
"sort-packages": true
},
"autoload": {
"psr-4": {
"App\\": "app/"
@@ -62,17 +65,20 @@
"Tests\\": "tests/"
}
},
"config": {
"preferred-install": "dist",
"sort-packages": true,
"optimize-autoloader": true
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/seankndy/reactphp-sqlite"
}
],
"minimum-stability": "dev",
"prefer-stable": true,
"bin": [
"builds/expose"
],
"scripts": {
"post-create-project-cmd": [
"@php application app:rename"
]
},
"minimum-stability": "dev",
"prefer-stable": true,
"bin": ["builds/expose"]
}
}

710
composer.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -26,7 +26,7 @@ return [
|
*/
'version' => app('git.version'),
'version' => '1.3.0',
/*
|--------------------------------------------------------------------------

View File

@@ -8,7 +8,7 @@ return [
|--------------------------------------------------------------------------
|
| The expose server to connect to. By default, expose is using the free
| expose.dev server, offered by Beyond Code. You will need a free
| sharedwithexpose.com server, offered by Beyond Code. You will need a free
| Beyond Code account in order to authenticate with the server.
| Feel free to host your own server and change this value.
|
@@ -78,7 +78,7 @@ return [
/*
|--------------------------------------------------------------------------
| Maximum Allowed Memory
| Skip Response Logging
|--------------------------------------------------------------------------
|
| Sometimes, some responses don't need to be logged. Some are too big,

14
docker-compose.yml Normal file
View File

@@ -0,0 +1,14 @@
version: "3.7"
services:
expose:
image: beyondcodegmbh/expose-server:latest
ports:
- 127.0.0.1:8080:${PORT}
environment:
port: ${PORT}
domain: ${DOMAIN}
username: ${ADMIN_USERNAME}
password: ${ADMIN_PASSWORD}
restart: always
volumes:
- ./database/expose.db:/root/.expose

View File

@@ -16,7 +16,7 @@ The result looks like this:
```json
{
"configuration":{
"hostname": "expose.dev",
"hostname": "sharedwithexpose.com",
"port": 8080,
"database": "/home/forge/expose/database/expose.db",
"validate_auth_tokens": false,

View File

@@ -28,7 +28,7 @@ return [
|--------------------------------------------------------------------------
|
| The expose server to connect to. By default, expose is using the free
| expose.dev server, offered by Beyond Code. You will need a free
| sharedwithexpose.com server, offered by Beyond Code. You will need a free
| Beyond Code account in order to authenticate with the server.
| Feel free to host your own server and change this value.
|
@@ -98,7 +98,7 @@ return [
/*
|--------------------------------------------------------------------------
| Maximum Allowed Memory
| Skip Response Logging
|--------------------------------------------------------------------------
|
| Sometimes, some responses don't need to be logged. Some are too big,

View File

@@ -41,6 +41,9 @@ expose share http://192.168.2.100
# Will share access to http://my-local-site.dev using a randomly generated subdomain
expose share my-local-site.dev
# Will share access to https://my-local-site.dev using a randomly generated subdomain (note the https)
expose share https://my-local-site.dev
```
## Share a local site with a given subdomain

View File

@@ -15,11 +15,11 @@ cd ~/Sites/my-awesome-project/
expose
```
This will connect to the provided server at expose.dev and give you a tunnel that you can immediately start using.
This will connect to the provided server at sharedwithexpose.com and give you a tunnel that you can immediately start using.
To learn more about how you can share your local sites, check out the [sharing local sites](/docs/expose/client/sharing) documentation.
## Using the provided server at expose.dev
## Using the provided server at sharedwithexpose.com
A big advantage of Expose over other alternatives such as ngrok, is the ability to host your own server. To make sharing your sites as easy as possible, we provide and host a custom expose server on our own - so getting started with expose is a breeze.

View File

@@ -32,6 +32,9 @@ server {
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
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 https;
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}

View File

@@ -98,7 +98,7 @@ return [
|--------------------------------------------------------------------------
|
| The expose server to connect to. By default, expose is using the free
| expose.dev server, offered by Beyond Code. You will need a free
| sharedwithexpose.com server, offered by Beyond Code. You will need a free
| Beyond Code account in order to authenticate with the server.
| Feel free to host your own server and change this value.
|
@@ -122,4 +122,21 @@ return [
// ...
```
## Running With Docker
To run Expose with docker use the included `docker-compose.yaml`. Copy `.env-example` to `.env` and update the configuration.
```
PORT=8080
DOMAIN=example.com
ADMIN_USERNAME=username
ADMIN_PASSWORD=password
```
After updating the environment variables you can start the server:
```bash
docker-compose up -d
```
Now that your basic expose server is running, let's take a look at how you can add SSL support.

View File

@@ -75,6 +75,27 @@
</tr>
</tbody>
</table>
<div class="flex items-center justify-end text-gray-900 p-4" v-if="paginated.current_page > 0">
<button
:disabled="paginated.previous_page == null"
v-on:click="getUsers(paginated.previous_page)"
type="button"
:class="(paginated.previous_page == null ? 'opacity-50 cursor-not-allowed' : '') + ' mr-3 py-2 px-4 border border-gray-300 rounded-md text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800 transition duration-150 ease-in-out'"
>
Previous
</button>
<button
:disabled="paginated.next_page == null"
v-on:click="getUsers(paginated.next_page)"
type="button"
:class="(paginated.next_page == null ? 'opacity-50 cursor-not-allowed' : '') + ' py-2 px-4 border border-gray-300 rounded-md text-sm leading-5 font-medium text-gray-700 hover:text-gray-500 focus:outline-none focus:border-blue-300 focus:shadow-outline-blue active:bg-gray-50 active:text-gray-800 transition duration-150 ease-in-out'"
>
Next
</button>
</div>
<div class="flex items-center justify-center text-gray-900 p-4" v-else>
<span class="text-xl">The expose server does not have any users yet.</span>
</div>
@@ -94,10 +115,25 @@
name: '',
errors: {},
},
users: {{ users|json_encode|raw }}
paginated: {{ paginated|json_encode|raw }}
},
computed: {
users : function() {
return this.paginated.users;
}
},
methods: {
getUsers(page) {
fetch('/api/users?page=' + page)
.then((response) => {
return response.json();
}).then((data) => {
this.paginated = data.paginated;
});
},
deleteUser(user) {
fetch('/api/users/' + user.id, {
method: 'DELETE',

View File

@@ -22,6 +22,19 @@ class LoggedRequestTest extends TestCase
$this->assertSame('example-request', $loggedRequest->id());
}
/** @test */
public function it_retrieves_the_request_for_chrome_extensions()
{
$rawRequest = str(new Request(200, '/expose', [
'Origin' => 'chrome-extension://expose',
'X-Expose-Request-ID' => 'example-request',
]));
$parsedRequest = LaminasRequest::fromString($rawRequest);
$loggedRequest = new LoggedRequest($rawRequest, $parsedRequest);
$this->assertSame('example-request', $loggedRequest->id());
}
/** @test */
public function it_returns_post_data_for_json_payloads()
{