feat: add mx login mode selection
This commit is contained in:
@@ -44,7 +44,7 @@ final class RemoteLoginUrlClient
|
||||
*/
|
||||
public static function buildCommand(Settings $settings, LoginUrlRequest $request): array
|
||||
{
|
||||
return [
|
||||
$base = [
|
||||
'ssh',
|
||||
'-o',
|
||||
'BatchMode=yes',
|
||||
@@ -59,6 +59,23 @@ final class RemoteLoginUrlClient
|
||||
'-p',
|
||||
(string)$settings->sshPort(),
|
||||
$settings->sshUser() . '@' . $settings->sshHost(),
|
||||
];
|
||||
|
||||
if ($settings->mxLoginMode() === 1) {
|
||||
$command = array_merge($base, [
|
||||
'/usr/bin/da',
|
||||
'login-url',
|
||||
'--user=' . $request->username,
|
||||
'--redirect-url=' . $request->redirectPath,
|
||||
'--expiry=' . $request->ttl . 's',
|
||||
]);
|
||||
if ($request->userIpBound) {
|
||||
$command[] = '--ip=' . $request->clientIp;
|
||||
}
|
||||
return $command;
|
||||
}
|
||||
|
||||
return array_merge($base, [
|
||||
'mail-login-create-url',
|
||||
$request->username,
|
||||
$request->sourceHost,
|
||||
@@ -68,7 +85,7 @@ final class RemoteLoginUrlClient
|
||||
$request->clientIp,
|
||||
$request->redirectPath,
|
||||
(string)$request->createdAt,
|
||||
];
|
||||
]);
|
||||
}
|
||||
|
||||
public function create(Settings $settings, LoginUrlRequest $request): string
|
||||
|
||||
@@ -58,6 +58,7 @@ final class Settings
|
||||
return [
|
||||
'DEFAULT_ENABLE' => 'true',
|
||||
'MAIL_LOGIN_METHOD' => 'login_url',
|
||||
'MX_LOGIN_MODE' => '1',
|
||||
'MAIL_LOGIN_TARGET_NAME' => 'mx1',
|
||||
'MAIL_LOGIN_TARGET_BASE_URL' => 'https://mx1.mojserwer.pl:2222',
|
||||
'MAIL_LOGIN_REDIRECT_URL' => '/',
|
||||
@@ -115,6 +116,11 @@ final class Settings
|
||||
return $this->getString('MAIL_LOGIN_METHOD', 'login_url');
|
||||
}
|
||||
|
||||
public function mxLoginMode(): int
|
||||
{
|
||||
return (int)$this->getString('MX_LOGIN_MODE', '1');
|
||||
}
|
||||
|
||||
public function redirectUrl(): string
|
||||
{
|
||||
return $this->getString('MAIL_LOGIN_REDIRECT_URL', '/');
|
||||
@@ -275,6 +281,9 @@ final class Settings
|
||||
if ($this->method() !== 'login_url') {
|
||||
throw new InvalidArgumentException('MAIL_LOGIN_METHOD must be login_url');
|
||||
}
|
||||
if (!in_array($this->getString('MX_LOGIN_MODE', '1'), ['1', '2'], true)) {
|
||||
throw new InvalidArgumentException('MX_LOGIN_MODE must be 1 or 2');
|
||||
}
|
||||
if (!in_array($this->clientIpMode(), ['direct', 'trusted_proxy'], true)) {
|
||||
throw new InvalidArgumentException('MAIL_LOGIN_CLIENT_IP_MODE must be direct or trusted_proxy');
|
||||
}
|
||||
|
||||
@@ -4,6 +4,11 @@ DEFAULT_ENABLE=true
|
||||
# Metoda produkcyjna. Wersja 1 używa jednorazowego DirectAdmin login URL generowanego na MX.
|
||||
MAIL_LOGIN_METHOD=login_url
|
||||
|
||||
# Tryb tworzenia login URL na MX:
|
||||
# 1 = direct SSH command: serwer źródłowy łączy się po SSH do MX i uruchamia bezpośrednio /usr/bin/da login-url; nie wymaga instalowania helpera na MX.
|
||||
# 2 = helper: serwer źródłowy łączy się po SSH do ograniczonego helpera na MX; lepsza walidacja/audyt/cleanup, ale wymaga instalacji helpera.
|
||||
MX_LOGIN_MODE=1
|
||||
|
||||
# Nazwa i adres docelowego panelu poczty.
|
||||
MAIL_LOGIN_TARGET_NAME=mx1
|
||||
MAIL_LOGIN_TARGET_BASE_URL=https://mx1.mojserwer.pl:2222
|
||||
@@ -25,7 +30,7 @@ MAIL_LOGIN_SOURCE_SERVER_NAME=
|
||||
MAIL_LOGIN_CLIENT_IP_MODE=direct
|
||||
MAIL_LOGIN_TRUSTED_PROXIES=
|
||||
|
||||
# Serwerowy kanał SSH do helpera na MX. Klucz jest root-owned i nigdy nie trafia do użytkownika.
|
||||
# Serwerowy kanał SSH do MX. Klucz jest root-owned i nigdy nie trafia do użytkownika.
|
||||
MAIL_LOGIN_REMOTE_TRANSPORT=ssh
|
||||
MAIL_LOGIN_SSH_HOST=mx1.mojserwer.pl
|
||||
MAIL_LOGIN_SSH_PORT=22
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@ name=mail-login
|
||||
id=mail-login
|
||||
type=user
|
||||
author=HITME.PL
|
||||
version=1.0.1
|
||||
version=1.0.2
|
||||
active=no
|
||||
installed=no
|
||||
user_run_as=root
|
||||
|
||||
@@ -8,7 +8,7 @@ test('plugin metadata and packaging docs match project rules', function (): void
|
||||
assert_contains('name=mail-login', $conf);
|
||||
assert_contains('id=mail-login', $conf);
|
||||
assert_contains('type=user', $conf);
|
||||
assert_contains('version=1.0.1', $conf);
|
||||
assert_contains('version=1.0.2', $conf);
|
||||
assert_contains('user_run_as=root', $conf);
|
||||
assert_contains('/Users/marek/GPT/ChatGPT/da_plugins/mail-login/src', $packing);
|
||||
assert_contains('/Users/marek/GPT/ChatGPT/da_plugins/mail-login/archives/X.Y.Z/mail-login.tar.gz', $packing);
|
||||
@@ -37,4 +37,3 @@ test('package source excludes local-only files and dangerous placeholders', func
|
||||
}
|
||||
assert_same([], $bad);
|
||||
});
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
require_once PLUGIN_ROOT . '/exec/lib/Settings.php';
|
||||
require_once PLUGIN_ROOT . '/exec/lib/RemoteLoginUrlClient.php';
|
||||
|
||||
test('remote login url client builds fixed ssh command with positional arguments', function (): void {
|
||||
test('remote login url client builds direct ssh command by default', function (): void {
|
||||
$settings = Settings::fromArray([
|
||||
'MAIL_LOGIN_TARGET_BASE_URL' => 'https://mx1.domena.pl:2222',
|
||||
'MAIL_LOGIN_SSH_HOST' => 'mx1.domena.pl',
|
||||
@@ -21,6 +21,29 @@ test('remote login url client builds fixed ssh command with positional arguments
|
||||
assert_same('ssh', $command[0]);
|
||||
assert_contains('UserKnownHostsFile=/secure/known_hosts', implode(' ', $command));
|
||||
assert_contains('root@mx1.domena.pl', implode(' ', $command));
|
||||
assert_not_contains('mail-login-create-url', implode(' ', $command));
|
||||
assert_contains('/usr/bin/da login-url', implode(' ', $command));
|
||||
assert_contains('--user=mxtest', implode(' ', $command));
|
||||
assert_contains('--expiry=30s', implode(' ', $command));
|
||||
assert_contains('--ip=198.51.100.10', implode(' ', $command));
|
||||
});
|
||||
|
||||
test('remote login url client builds helper ssh command when mode is helper', function (): void {
|
||||
$settings = Settings::fromArray([
|
||||
'MAIL_LOGIN_TARGET_BASE_URL' => 'https://mx1.domena.pl:2222',
|
||||
'MAIL_LOGIN_SSH_HOST' => 'mx1.domena.pl',
|
||||
'MAIL_LOGIN_SSH_PORT' => '222',
|
||||
'MAIL_LOGIN_SSH_USER' => 'root',
|
||||
'MAIL_LOGIN_SSH_IDENTITY' => '/secure/key',
|
||||
'MAIL_LOGIN_SSH_KNOWN_HOSTS' => '/secure/known_hosts',
|
||||
'LOGIN_KEY_TTL' => '30',
|
||||
'USER_IP_BOUND' => '1',
|
||||
'MX_LOGIN_MODE' => '2',
|
||||
]);
|
||||
$request = new LoginUrlRequest('mxtest', 'h4.domena.pl', 'h4', 30, true, '198.51.100.10', '/', 1782810000);
|
||||
$command = RemoteLoginUrlClient::buildCommand($settings, $request);
|
||||
|
||||
assert_same('ssh', $command[0]);
|
||||
$pos = array_search('mail-login-create-url', $command, true);
|
||||
assert_true(is_int($pos), 'Command marker missing');
|
||||
assert_same('mxtest', $command[$pos + 1]);
|
||||
|
||||
@@ -10,6 +10,7 @@ test('settings expose secure defaults from plugin-settings.conf', function (): v
|
||||
assert_true($settings->userIpBound());
|
||||
assert_true($settings->defaultEnable());
|
||||
assert_same('login_url', $settings->method());
|
||||
assert_same(1, $settings->mxLoginMode());
|
||||
assert_same('root', $settings->sshUser());
|
||||
assert_same('https://mx1.mojserwer.pl:2222', $settings->targetBaseUrl());
|
||||
});
|
||||
@@ -29,10 +30,23 @@ test('settings accept explicit ttl and user ip binding toggle', function (): voi
|
||||
$settings = Settings::fromArray([
|
||||
'LOGIN_KEY_TTL' => '5',
|
||||
'USER_IP_BOUND' => '0',
|
||||
'MX_LOGIN_MODE' => '2',
|
||||
]);
|
||||
|
||||
assert_same(5, $settings->loginKeyTtl());
|
||||
assert_false($settings->userIpBound());
|
||||
assert_same(2, $settings->mxLoginMode());
|
||||
});
|
||||
|
||||
test('settings reject unsupported mx login mode values', function (): void {
|
||||
foreach (['0', '3', 'helper', ''] as $mode) {
|
||||
try {
|
||||
Settings::fromArray(['MX_LOGIN_MODE' => $mode]);
|
||||
throw new RuntimeException('Expected invalid MX_LOGIN_MODE to fail: ' . $mode);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
assert_contains('MX_LOGIN_MODE', $e->getMessage());
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
test('settings parse allowed source hosts as normalized hostnames', function (): void {
|
||||
|
||||
Reference in New Issue
Block a user