2 Commits
Author SHA1 Message Date
MeghdadFadaee 5f422ac0e4 feat: add configurable role for Mahak-created users
Build plugin release / release (push) Successful in 5s
2026-08-24 10:39:32 +03:30
MeghdadFadaee e7d718cd0e fix: build Gitea release archive without rsync
Build plugin release / release (push) Successful in 4s
2026-08-24 10:09:08 +03:30
8 changed files with 141 additions and 29 deletions
+4
View File
@@ -0,0 +1,4 @@
/.gitattributes export-ignore
/.gitignore export-ignore
/.gitea export-ignore
/test export-ignore
+6 -10
View File
@@ -21,16 +21,12 @@ jobs:
run: |
VERSION="${RELEASE_TAG#v}"
grep -q "Version: ${VERSION}$" dabestaniha-authenticate-bridge.php
mkdir -p build/mahak-authenticate-bridge dist
rsync -a \
--exclude='.git/' \
--exclude='.gitea/' \
--exclude='build/' \
--exclude='dist/' \
--exclude='test/' \
./ build/mahak-authenticate-bridge/
cd build
zip -qr ../dist/mahak-authenticate-bridge.zip mahak-authenticate-bridge
mkdir -p dist
git archive \
--format=zip \
--prefix=mahak-authenticate-bridge/ \
--output=dist/mahak-authenticate-bridge.zip \
HEAD
- name: Publish Gitea release
env:
+4 -1
View File
@@ -9,6 +9,7 @@ Authenticate WordPress user via json web token from Laravel Application.
- Admin settings page
- Custom invalid token page
- Optional debug mode with full exception details and stack traces
- Configurable role for users created through Mahak authentication
Debug mode is disabled by default. An administrator can enable it from **Settings > Mahak Authentication** while troubleshooting. The debug page includes server clock/timezone data, safe JWT timing claims, and a Copy Markdown report. JWT contents, secrets, request parameters, and stack-trace arguments are omitted. Because diagnostic pages still expose server paths and other technical details to visitors of the login URL, disable it again after diagnosing the problem.
@@ -16,7 +17,9 @@ Debug mode is disabled by default. An administrator can enable it from **Setting
Administrators can check for and install published releases from **Settings > Mahak Authentication**. Updates also appear in WordPress's standard **Plugins** and **Updates** screens.
To publish an update, change the plugin `Version` header and `MAHAK_AUTHENTICATE_BRIDGE_VERSION` constant to the same version, commit the change, and push a matching tag such as `v2.3.0` to Mahgit. The Gitea Actions workflow builds and attaches the ZIP required by the WordPress updater.
The **New user role** setting defaults to WordPress Default, using the site's current global new-user role without changing it. Administrators can select a different role only for accounts created by this plugin; existing users keep their current roles.
To publish an update, change the plugin `Version` header and `MAHAK_AUTHENTICATE_BRIDGE_VERSION` constant to the same version, commit the change, and push a matching tag such as `v2.4.0` to Mahgit. The Gitea Actions workflow builds and attaches the ZIP required by the WordPress updater.
## Usage
+2 -2
View File
@@ -4,7 +4,7 @@
* Plugin Name: Mahak Authenticate Bridge
* Plugin URI: https://mahgit.ir/dabestaniha/mahak-authenticate-bridge
* Description: Authenticate WordPress user via json web token from Mahakiha Application.
* Version: 2.2.2
* Version: 2.3.1
* Requires PHP: 7.4
* Update URI: https://mahgit.ir/dabestaniha/mahak-authenticate-bridge
* Author: Dabestaniha
@@ -18,7 +18,7 @@ use Dabestaniha\AuthenticateBridge\App\Http\Controllers\SettingsPageMenuControll
use Dabestaniha\AuthenticateBridge\App\Http\Controllers\SettingsPageFormController;
use Dabestaniha\AuthenticateBridge\App\Support\PluginUpdater;
define('MAHAK_AUTHENTICATE_BRIDGE_VERSION', '2.2.2');
define('MAHAK_AUTHENTICATE_BRIDGE_VERSION', '2.3.1');
define('MAHAK_AUTHENTICATE_BRIDGE_FILE', __FILE__);
require_once __DIR__.'/src/Autoloader.php';
@@ -64,7 +64,20 @@ class AuthenticateController extends InvocableController
$username .= '_'.wp_generate_password(4, false);
}
$user_id = wp_create_user($username, $random_password, $email);
$configured_role = sanitize_key((string) get_configured_option('new-user-role', 'wordpress_default'));
if ($configured_role === 'wordpress_default') {
$configured_role = sanitize_key((string) get_option('default_role', 'subscriber'));
}
$role = get_role($configured_role) === null ? 'subscriber' : $configured_role;
$user_id = wp_insert_user([
'user_login' => $username,
'user_pass' => $random_password,
'user_email' => $email,
'display_name' => $name,
'role' => $role,
]);
if (is_wp_error($user_id)) {
throw new RuntimeException(
@@ -72,16 +85,8 @@ class AuthenticateController extends InvocableController
);
}
$updated_user_id = wp_update_user([
'ID' => $user_id,
'display_name' => $name,
]);
if (is_wp_error($updated_user_id)) {
throw new RuntimeException(
'WordPress could not update the user: '.$updated_user_id->get_error_message()
);
}
// Enforce the configured role after user_register callbacks from other plugins have completed.
(new \WP_User($user_id))->set_role($role);
return $user_id;
}
@@ -14,6 +14,9 @@ class SettingsPageFormController extends InvocableController
return (int) filter_var($value, FILTER_VALIDATE_BOOLEAN);
};
$args['default'] = 0;
} elseif ($configured === 'new-user-role') {
$args['sanitize_callback'] = fn ($value): string => $this->sanitize_new_user_role($value);
$args['default'] = 'wordpress_default';
}
register_setting(config('mahak.settings-group'), $options_key, $args);
@@ -58,6 +61,14 @@ class SettingsPageFormController extends InvocableController
config('mahak.section-id')
);
add_settings_field(
config('mahak.options.new-user-role'),
config('mahak.translations.new-user-role'),
fn () => $this->new_user_role(),
config('mahak.settings-page'),
config('mahak.section-id')
);
add_settings_field(
config('mahak.options.debug-mode'),
config('mahak.translations.debug-mode'),
@@ -130,4 +141,54 @@ class SettingsPageFormController extends InvocableController
echo "<label><input type='checkbox' name='".esc_attr($name)."' value='1' ".checked($enabled, true, false).' /> ';
echo esc_html(config('mahak.translations.debug-mode-description')).'</label>';
}
public function new_user_role(): void
{
$name = config('mahak.options.new-user-role');
$value = sanitize_key((string) get_option($name, 'wordpress_default'));
$roles = wp_roles()->get_names();
if ($value !== 'wordpress_default' && !isset($roles[$value])) {
$value = 'wordpress_default';
}
echo "<select name='".esc_attr($name)."'>";
$defaultRole = sanitize_key((string) get_option('default_role', 'subscriber'));
$defaultRoleLabel = $roles[$defaultRole] ?? $defaultRole;
$translatedDefaultRole = function_exists('translate_user_role')
? translate_user_role($defaultRoleLabel)
: $defaultRoleLabel;
echo "<option value='wordpress_default' ".selected($value, 'wordpress_default', false).'>';
echo esc_html(config('mahak.translations.wordpress-default-role').' — '.$translatedDefaultRole).'</option>';
foreach ($roles as $role => $label) {
$translatedLabel = function_exists('translate_user_role') ? translate_user_role($label) : $label;
echo "<option value='".esc_attr($role)."' ".selected($value, $role, false).'>';
echo esc_html($translatedLabel).'</option>';
}
echo '</select>';
echo '<p class="description">'.esc_html(config('mahak.translations.new-user-role-description')).'</p>';
}
public function sanitize_new_user_role($value): string
{
$role = sanitize_key((string) $value);
if ($role === 'wordpress_default') {
return $role;
}
if (get_role($role) !== null) {
return $role;
}
add_settings_error(
config('mahak.options.new-user-role'),
'mahak_invalid_new_user_role',
'نقش انتخاب‌شده معتبر نیست. نقش پیش‌فرض وردپرس استفاده شد.'
);
return 'wordpress_default';
}
}
+4
View File
@@ -11,6 +11,7 @@ return [
'user-identifier' => 'mahak_user_identifier',
'login-route' => 'mahak_login_route',
'after-login-route' => 'mahak_after_login_route',
'new-user-role' => 'mahak_new_user_role',
'debug-mode' => 'mahak_debug_mode',
],
@@ -38,6 +39,9 @@ return [
'user-identifier' => 'فیلد شناسایی کاربر',
'login-route' => 'مسیر لاگین ماهک',
'after-login-route' => 'مسیر بعد از لاگین',
'new-user-role' => 'نقش کاربر جدید',
'wordpress-default-role' => 'پیش‌فرض وردپرس',
'new-user-role-description' => 'در حالت پیش‌فرض وردپرس، نقش عمومی کاربران جدید استفاده می‌شود. نقش انتخابی دیگر فقط به کاربران ساخته‌شده توسط این افزونه اختصاص می‌یابد.',
'debug-mode' => 'حالت اشکال‌زدایی',
'debug-mode-description' => 'در صورت بروز خطا، جزئیات کامل فنی در صفحه نمایش داده شود. این گزینه را فقط هنگام عیب‌یابی فعال کنید.',
+44 -5
View File
@@ -7,6 +7,7 @@ const TEST_PLUGIN = 'mahak-authenticate-bridge/dabestaniha-authenticate-bridge.p
const TEST_SECRET = 'integration-test-secret';
const TEST_EMAIL = 'mahak-auth-user@example.test';
const TEST_NAME = 'Mahak Auth User';
const TEST_ROLE_EMAIL = 'mahak-role-user@example.test';
function fail(string $message): void
{
@@ -86,6 +87,8 @@ function activate_and_configure_plugin(): void
update_option('mahak_user_identifier', 'email');
update_option('mahak_login_route', 'mahak/login');
update_option('mahak_after_login_route', 'wp-admin/profile.php');
update_option('default_role', 'subscriber');
update_option('mahak_new_user_role', 'wordpress_default');
pass('Plugin activated and configured');
}
@@ -213,6 +216,10 @@ function test_valid_authentication(): void
assert_true($user !== false, 'Authenticated user was not created.');
assert_true($user->display_name === TEST_NAME, 'Authenticated user display name was not saved.');
assert_true(
$user->roles === ['subscriber'],
'New user did not receive the plugin-configured Subscriber role.'
);
$cookieHeader = cookie_header_from_response($response['headers']);
$profileResponse = http_request(TEST_SITE_URL.'/wp-admin/profile.php', $cookieHeader);
@@ -222,7 +229,38 @@ function test_valid_authentication(): void
'Issued cookies did not authenticate a follow-up WordPress admin request.'
);
pass('Valid JWT creates/logs in user and issued cookies authenticate follow-up request');
pass('Valid JWT creates a Subscriber and issued cookies authenticate follow-up requests');
}
function test_configured_new_user_role_is_enforced(): void
{
$smsRoleOverride = function (int $userId): void {
(new WP_User($userId))->set_role('administrator');
};
add_action('user_register', $smsRoleOverride);
$controller = new Dabestaniha\AuthenticateBridge\App\Http\Controllers\AuthenticateController();
$userId = $controller->find_or_create_user('email', TEST_ROLE_EMAIL, 'Role Test User');
remove_action('user_register', $smsRoleOverride);
$user = get_userdata($userId);
assert_true(
$user !== false && $user->roles === ['subscriber'],
'Configured role was not enforced after another plugin changed the role during user_register.'
);
$user->set_role('author');
$existingUserId = $controller->find_or_create_user('email', TEST_ROLE_EMAIL, 'Role Test User');
$existingUser = get_userdata($existingUserId);
assert_true($existingUserId === $userId, 'Existing user was not reused.');
assert_true(
$existingUser !== false && $existingUser->roles === ['author'],
'Existing user role was changed during authentication.'
);
pass('Configured role overrides creation hooks without changing existing users');
}
function test_invalid_authentication(): void
@@ -310,7 +348,7 @@ function test_debug_error_details(): void
function test_plugin_update_discovery(): void
{
$packageUrl = 'https://mahgit.ir/dabestaniha/mahak-authenticate-bridge/releases/download/v2.3.0/mahak-authenticate-bridge.zip';
$packageUrl = 'https://mahgit.ir/dabestaniha/mahak-authenticate-bridge/releases/download/v2.4.0/mahak-authenticate-bridge.zip';
$mockRelease = function ($response, array $request, string $url) use ($packageUrl) {
if ($url !== 'https://mahgit.ir/api/v1/repos/dabestaniha/mahak-authenticate-bridge/releases/latest') {
return $response;
@@ -319,8 +357,8 @@ function test_plugin_update_discovery(): void
return [
'headers' => [],
'body' => json_encode([
'tag_name' => 'v2.3.0',
'html_url' => 'https://mahgit.ir/dabestaniha/mahak-authenticate-bridge/releases/tag/v2.3.0',
'tag_name' => 'v2.4.0',
'html_url' => 'https://mahgit.ir/dabestaniha/mahak-authenticate-bridge/releases/tag/v2.4.0',
'body' => 'Test release',
'draft' => false,
'prerelease' => false,
@@ -346,7 +384,7 @@ function test_plugin_update_discovery(): void
remove_filter('pre_http_request', $mockRelease, 10);
assert_true(isset($updates->response[TEST_PLUGIN]), 'A newer Mahgit release was not offered as a WordPress update.');
assert_true($updates->response[TEST_PLUGIN]->new_version === '2.3.0', 'The offered plugin version was incorrect.');
assert_true($updates->response[TEST_PLUGIN]->new_version === '2.4.0', 'The offered plugin version was incorrect.');
assert_true($updates->response[TEST_PLUGIN]->package === $packageUrl, 'The release package URL was incorrect.');
pass('Published Mahgit releases are discovered by the WordPress updater');
@@ -357,6 +395,7 @@ install_wordpress();
activate_and_configure_plugin();
wait_for_http();
test_valid_authentication();
test_configured_new_user_role_is_enforced();
test_invalid_authentication();
test_debug_error_details();
test_plugin_update_discovery();