Version Description
- Fixed the bug with Access Policy access control
- Fixed the bug with Access Policy tab shows only 10 last Policies
- Fixed the bug where AAM was not determining correct max user level
- Fixed the bug where user was able to manage his roles on the profile page
- Fixed the bug with Access Policy "Between" condition
- Optimized AAM to support unusual access capabilities for custom post types https://forum.aamplugin.com/d/99-custom-post-type-does-not-honor-edit-delete-publish-overrides/5
- Enhanced Access Policy with few new features. The complete reference is here https://aamplugin.com/reference/policy
- Enabled 'JWT Authentication' by default
- Significantly improved AAM UI page security
- Added new JWT Tokens feature to the list of AAM features https://aamplugin.com/reference/plugin#jwt-tokens
- Added new capability aam_manage_jwt
- Added "Add New Policies" submenu to fix WordPress core bug with managing access to submenus
- Removed "Role Expiration" feature - it was too confusing to work with
- Removed allow_ajax_calls capability support - it was too confusing for end users
Download this release
Release Info
Developer | vasyltech |
Plugin | Advanced Access Manager |
Version | 5.9.2 |
Comparing to | |
See all releases |
Code changes from version 5.9.1.1 to 5.9.2
- Application/Backend/Feature.php +6 -1
- Application/Backend/Feature/Main/404Redirect.php +2 -1
- Application/Backend/Feature/Main/Capability.php +4 -2
- Application/Backend/Feature/Main/Jwt.php +182 -0
- Application/Backend/Feature/Main/LoginRedirect.php +2 -1
- Application/Backend/Feature/Main/LogoutRedirect.php +2 -1
- Application/Backend/Feature/Main/Menu.php +2 -1
- Application/Backend/Feature/Main/Metabox.php +2 -1
- Application/Backend/Feature/Main/Policy.php +14 -21
- Application/Backend/Feature/Main/Post.php +2 -1
- Application/Backend/Feature/Main/Redirect.php +2 -1
- Application/Backend/Feature/Main/Route.php +2 -1
- Application/Backend/Feature/Main/Toolbar.php +2 -1
- Application/Backend/Feature/Main/Uri.php +3 -2
- Application/Backend/Feature/Settings/Core.php +1 -1
- Application/Backend/Feature/Subject/Role.php +1 -20
- Application/Backend/Feature/Subject/User.php +18 -21
- Application/Backend/Manager.php +24 -47
- Application/Backend/Subject.php +30 -7
- Application/Backend/View.php +1 -0
- Application/Backend/phtml/index.phtml +0 -27
- Application/Backend/phtml/main/jwt.phtml +126 -0
- Application/Backend/phtml/main/menu.phtml +2 -2
- Application/Backend/phtml/main/metabox.phtml +1 -1
- Application/Backend/phtml/main/toolbar.phtml +1 -1
- Application/Backend/phtml/user/multiple-roles.phtml +29 -27
- Application/Core/Compatibility.php +34 -1
- Application/Core/Gateway.php +9 -0
- Application/Core/Jwt/Auth.php +69 -0
- Application/Core/Jwt/Issuer.php +229 -0
- Application/Core/Jwt/Manager.php +356 -0
- Application/Core/JwtAuth.php +0 -347
- Application/Core/Login.php +20 -4
- Application/Core/Object/Post.php +8 -3
- Application/Core/Object/Route.php +5 -4
- Application/Core/Policy/Condition.php +21 -5
- Application/Core/Policy/Token.php +2 -0
- Application/Core/Subject/User.php +160 -81
- Application/Shared/Manager.php +117 -74
- aam.php +22 -14
- media/css/aam.css +15 -6
- media/font/fontello.eot +0 -0
- media/font/fontello.svg +4 -0
- media/font/fontello.ttf +0 -0
- media/font/fontello.woff +0 -0
- media/font/fontello.woff2 +0 -0
- media/js/{aam-5.9.1.js → aam-5.9.2.js} +311 -84
- media/js/vendor.js +9 -1
- readme.txt +18 -1
- vendor/firebase/JWT.php +4 -1
Application/Backend/Feature.php
CHANGED
@@ -40,19 +40,24 @@ class AAM_Backend_Feature {
|
|
40 |
public static function registerFeature(stdClass $feature) {
|
41 |
$response = false;
|
42 |
|
|
|
43 |
if (empty($feature->capability)){
|
44 |
$cap = 'aam_manager';
|
45 |
} else {
|
46 |
$cap = $feature->capability;
|
47 |
}
|
48 |
|
|
|
49 |
if (isset($feature->option)) {
|
50 |
$show = self::isVisible($feature->option);
|
51 |
} else {
|
52 |
$show = true;
|
53 |
}
|
|
|
|
|
|
|
54 |
|
55 |
-
if ($show && current_user_can($cap)) {
|
56 |
self::$_features[] = $feature;
|
57 |
$response = true;
|
58 |
}
|
40 |
public static function registerFeature(stdClass $feature) {
|
41 |
$response = false;
|
42 |
|
43 |
+
// Determine correct AAM UI capability
|
44 |
if (empty($feature->capability)){
|
45 |
$cap = 'aam_manager';
|
46 |
} else {
|
47 |
$cap = $feature->capability;
|
48 |
}
|
49 |
|
50 |
+
// Determine if minimum required options are enabled
|
51 |
if (isset($feature->option)) {
|
52 |
$show = self::isVisible($feature->option);
|
53 |
} else {
|
54 |
$show = true;
|
55 |
}
|
56 |
+
|
57 |
+
// Determine that current user has enough level to manage requested subject
|
58 |
+
$allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
|
59 |
|
60 |
+
if ($show && $allowed && current_user_can($cap)) {
|
61 |
self::$_features[] = $feature;
|
62 |
$response = true;
|
63 |
}
|
Application/Backend/Feature/Main/404Redirect.php
CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_404Redirect extends AAM_Backend_Feature_Abstract
|
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
-
|
|
|
25 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_404_redirect'));
|
26 |
}
|
27 |
}
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
+
$allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
|
25 |
+
if (!$allowed || !current_user_can('aam_manage_404_redirect')) {
|
26 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_404_redirect'));
|
27 |
}
|
28 |
}
|
Application/Backend/Feature/Main/Capability.php
CHANGED
@@ -56,7 +56,8 @@ class AAM_Backend_Feature_Main_Capability extends AAM_Backend_Feature_Abstract {
|
|
56 |
'aam_edit_roles', 'aam_delete_roles', 'aam_toggle_users', 'aam_switch_users',
|
57 |
'aam_manage_configpress', 'aam_manage_api_routes', 'aam_manage_uri', 'aam_manage_policy',
|
58 |
'aam_view_help_btn', 'aam_edit_policy', 'aam_read_policy', 'aam_delete_policy',
|
59 |
-
'aam_delete_policies', 'aam_edit_policies', 'aam_edit_others_policies', 'aam_publish_policies'
|
|
|
60 |
)
|
61 |
);
|
62 |
|
@@ -66,7 +67,8 @@ class AAM_Backend_Feature_Main_Capability extends AAM_Backend_Feature_Abstract {
|
|
66 |
public function __construct() {
|
67 |
parent::__construct();
|
68 |
|
69 |
-
|
|
|
70 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_capabilities'));
|
71 |
}
|
72 |
}
|
56 |
'aam_edit_roles', 'aam_delete_roles', 'aam_toggle_users', 'aam_switch_users',
|
57 |
'aam_manage_configpress', 'aam_manage_api_routes', 'aam_manage_uri', 'aam_manage_policy',
|
58 |
'aam_view_help_btn', 'aam_edit_policy', 'aam_read_policy', 'aam_delete_policy',
|
59 |
+
'aam_delete_policies', 'aam_edit_policies', 'aam_edit_others_policies', 'aam_publish_policies',
|
60 |
+
'aam_manage_jwt'
|
61 |
)
|
62 |
);
|
63 |
|
67 |
public function __construct() {
|
68 |
parent::__construct();
|
69 |
|
70 |
+
$allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
|
71 |
+
if (!$allowed || !current_user_can('aam_manage_capabilities')) {
|
72 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_capabilities'));
|
73 |
}
|
74 |
}
|
Application/Backend/Feature/Main/Jwt.php
ADDED
@@ -0,0 +1,182 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
/**
|
11 |
+
* JWT manager
|
12 |
+
*
|
13 |
+
* @package AAM
|
14 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
15 |
+
*/
|
16 |
+
class AAM_Backend_Feature_Main_Jwt extends AAM_Backend_Feature_Abstract {
|
17 |
+
|
18 |
+
/**
|
19 |
+
* Construct
|
20 |
+
*/
|
21 |
+
public function __construct() {
|
22 |
+
parent::__construct();
|
23 |
+
|
24 |
+
$allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
|
25 |
+
if (!$allowed || !current_user_can('aam_manage_jwt')) {
|
26 |
+
AAM::api()->denyAccess(array('reason' => 'aam_manage_jwt'));
|
27 |
+
}
|
28 |
+
}
|
29 |
+
|
30 |
+
/**
|
31 |
+
*
|
32 |
+
* @return type
|
33 |
+
*/
|
34 |
+
public function getTable() {
|
35 |
+
return wp_json_encode($this->retrieveList());
|
36 |
+
}
|
37 |
+
|
38 |
+
/**
|
39 |
+
*
|
40 |
+
* @return type
|
41 |
+
*/
|
42 |
+
public function generate() {
|
43 |
+
$user = AAM_Backend_Subject::getInstance()->get();
|
44 |
+
$expires = filter_input(INPUT_POST, 'expires');
|
45 |
+
|
46 |
+
try {
|
47 |
+
$max = AAM::getUser()->getMaxLevel();
|
48 |
+
if ($max >= AAM_Core_API::maxLevel($user->allcaps)) {
|
49 |
+
$issuer = new AAM_Core_Jwt_Issuer();
|
50 |
+
$jwt = $issuer->issueToken(
|
51 |
+
array('userId' => $user->ID, 'revocable' => true),
|
52 |
+
$expires
|
53 |
+
);
|
54 |
+
$result = array(
|
55 |
+
'status' => 'success',
|
56 |
+
'jwt' => $jwt->token
|
57 |
+
);
|
58 |
+
} else {
|
59 |
+
throw new Exception('User ID has higher level than current user');
|
60 |
+
}
|
61 |
+
} catch (Exception $ex) {
|
62 |
+
$result = array('status' => 'failure', 'reason' => $ex->getMessage());
|
63 |
+
}
|
64 |
+
|
65 |
+
return wp_json_encode($result);
|
66 |
+
}
|
67 |
+
|
68 |
+
/**
|
69 |
+
*
|
70 |
+
* @return type
|
71 |
+
*/
|
72 |
+
public function save() {
|
73 |
+
$user = AAM_Backend_Subject::getInstance()->get();
|
74 |
+
$token = filter_input(INPUT_POST, 'token');
|
75 |
+
$claims = AAM_Core_Jwt_Issuer::extractTokenClaims($token);
|
76 |
+
|
77 |
+
$result = AAM_Core_Jwt_Manager::getInstance()->registerToken(
|
78 |
+
$user->ID,
|
79 |
+
$token
|
80 |
+
);
|
81 |
+
|
82 |
+
if ($result) {
|
83 |
+
$response = array('status' => 'success');
|
84 |
+
} else {
|
85 |
+
$response = array(
|
86 |
+
'status' => 'failure',
|
87 |
+
'reason' => __('Failed to register JWT token', AAM_KEY)
|
88 |
+
);
|
89 |
+
}
|
90 |
+
|
91 |
+
return wp_json_encode($response);
|
92 |
+
}
|
93 |
+
|
94 |
+
/**
|
95 |
+
*
|
96 |
+
* @return type
|
97 |
+
*/
|
98 |
+
public function delete() {
|
99 |
+
$user = AAM_Backend_Subject::getInstance()->get();
|
100 |
+
$token = filter_input(INPUT_POST, 'token');
|
101 |
+
$result = AAM_Core_Jwt_Manager::getInstance()->revokeToken($user->ID, $token);
|
102 |
+
|
103 |
+
if ($result) {
|
104 |
+
$response = array('status' => 'success');
|
105 |
+
} else {
|
106 |
+
$response = array(
|
107 |
+
'status' => 'failure',
|
108 |
+
'reason' => __('Failed to revoke JWT token', AAM_KEY)
|
109 |
+
);
|
110 |
+
}
|
111 |
+
|
112 |
+
return wp_json_encode($response);
|
113 |
+
}
|
114 |
+
|
115 |
+
/**
|
116 |
+
* @inheritdoc
|
117 |
+
*/
|
118 |
+
public static function getTemplate() {
|
119 |
+
return 'main/jwt.phtml';
|
120 |
+
}
|
121 |
+
|
122 |
+
/**
|
123 |
+
*
|
124 |
+
* @return type
|
125 |
+
*/
|
126 |
+
protected function retrieveList() {
|
127 |
+
$tokens = AAM_Core_Jwt_Manager::getInstance()->getTokenRegistry(
|
128 |
+
AAM_Backend_Subject::getInstance()->get()->ID
|
129 |
+
);
|
130 |
+
|
131 |
+
$response = array(
|
132 |
+
'recordsTotal' => count($tokens),
|
133 |
+
'recordsFiltered' => count($tokens),
|
134 |
+
'draw' => AAM_Core_Request::request('draw'),
|
135 |
+
'data' => array(),
|
136 |
+
);
|
137 |
+
|
138 |
+
$issuer = new AAM_Core_Jwt_Issuer();
|
139 |
+
|
140 |
+
foreach($tokens as $token) {
|
141 |
+
try {
|
142 |
+
$claims = $issuer->validateToken($token);
|
143 |
+
} catch(Exception $e) {
|
144 |
+
$claims = $issuer->extractTokenClaims($token);
|
145 |
+
$claims->status = 'invalid';
|
146 |
+
}
|
147 |
+
|
148 |
+
$response['data'][] = array(
|
149 |
+
$token,
|
150 |
+
add_query_arg('aam-jwt', $token, site_url()),
|
151 |
+
$claims->status,
|
152 |
+
$claims->exp,
|
153 |
+
'view,delete'
|
154 |
+
);
|
155 |
+
}
|
156 |
+
|
157 |
+
return $response;
|
158 |
+
}
|
159 |
+
|
160 |
+
/**
|
161 |
+
* Register Menu feature
|
162 |
+
*
|
163 |
+
* @return void
|
164 |
+
*
|
165 |
+
* @access public
|
166 |
+
*/
|
167 |
+
public static function register() {
|
168 |
+
AAM_Backend_Feature::registerFeature((object) array(
|
169 |
+
'uid' => 'jwt',
|
170 |
+
'position' => 65,
|
171 |
+
'title' => __('JWT Tokens', AAM_KEY) . '<span class="badge">NEW</span>',
|
172 |
+
'capability' => 'aam_manage_jwt',
|
173 |
+
'type' => 'main',
|
174 |
+
'subjects' => array(
|
175 |
+
AAM_Core_Subject_User::UID
|
176 |
+
),
|
177 |
+
'option' => 'core.settings.jwtAuthentication',
|
178 |
+
'view' => __CLASS__
|
179 |
+
));
|
180 |
+
}
|
181 |
+
|
182 |
+
}
|
Application/Backend/Feature/Main/LoginRedirect.php
CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_LoginRedirect extends AAM_Backend_Feature_Abstrac
|
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
-
|
|
|
25 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_login_redirect'));
|
26 |
}
|
27 |
}
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
+
$allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
|
25 |
+
if (!$allowed || !current_user_can('aam_manage_login_redirect')) {
|
26 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_login_redirect'));
|
27 |
}
|
28 |
}
|
Application/Backend/Feature/Main/LogoutRedirect.php
CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_LogoutRedirect extends AAM_Backend_Feature_Abstra
|
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
-
|
|
|
25 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_logout_redirect'));
|
26 |
}
|
27 |
}
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
+
$allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
|
25 |
+
if (!$allowed || !current_user_can('aam_manage_logout_redirect')) {
|
26 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_logout_redirect'));
|
27 |
}
|
28 |
}
|
Application/Backend/Feature/Main/Menu.php
CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_Menu extends AAM_Backend_Feature_Abstract {
|
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
-
|
|
|
25 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_admin_menu'));
|
26 |
}
|
27 |
}
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
+
$allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
|
25 |
+
if (!$allowed || !current_user_can('aam_manage_admin_menu')) {
|
26 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_admin_menu'));
|
27 |
}
|
28 |
}
|
Application/Backend/Feature/Main/Metabox.php
CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_Metabox extends AAM_Backend_Feature_Abstract {
|
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
-
|
|
|
25 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_metaboxes'));
|
26 |
}
|
27 |
}
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
+
$allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
|
25 |
+
if (!$allowed || !current_user_can('aam_manage_metaboxes')) {
|
26 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_metaboxes'));
|
27 |
}
|
28 |
}
|
Application/Backend/Feature/Main/Policy.php
CHANGED
@@ -15,6 +15,18 @@
|
|
15 |
*/
|
16 |
class AAM_Backend_Feature_Main_Policy extends AAM_Backend_Feature_Abstract {
|
17 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
/**
|
19 |
*
|
20 |
* @return type
|
@@ -131,9 +143,8 @@ class AAM_Backend_Feature_Main_Policy extends AAM_Backend_Feature_Abstract {
|
|
131 |
|
132 |
$list = get_posts(array(
|
133 |
'post_type' => 'aam_policy',
|
134 |
-
'numberposts' =>
|
135 |
-
'
|
136 |
-
's' => ($search ? $search . '*' : ''),
|
137 |
));
|
138 |
|
139 |
$response = array(
|
@@ -159,24 +170,6 @@ class AAM_Backend_Feature_Main_Policy extends AAM_Backend_Feature_Abstract {
|
|
159 |
return $response;
|
160 |
}
|
161 |
|
162 |
-
/**
|
163 |
-
*
|
164 |
-
* @global type $wpdb
|
165 |
-
* @param type $type
|
166 |
-
* @param type $search
|
167 |
-
* @return type
|
168 |
-
*/
|
169 |
-
protected function getPolicyCount($type, $search) {
|
170 |
-
global $wpdb;
|
171 |
-
|
172 |
-
$query = "SELECT COUNT(*) AS total FROM {$wpdb->posts} ";
|
173 |
-
$query .= "WHERE (post_type = %s) AND (post_title LIKE %s) AND (post_status = %s)";
|
174 |
-
|
175 |
-
$args = array($type, "{$search}%", 'publish');
|
176 |
-
|
177 |
-
return $wpdb->get_var($wpdb->prepare($query, $args));
|
178 |
-
}
|
179 |
-
|
180 |
/**
|
181 |
*
|
182 |
* @param type $record
|
15 |
*/
|
16 |
class AAM_Backend_Feature_Main_Policy extends AAM_Backend_Feature_Abstract {
|
17 |
|
18 |
+
/**
|
19 |
+
* Construct
|
20 |
+
*/
|
21 |
+
public function __construct() {
|
22 |
+
parent::__construct();
|
23 |
+
|
24 |
+
$allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
|
25 |
+
if (!$allowed || !current_user_can('aam_manage_policy')) {
|
26 |
+
AAM::api()->denyAccess(array('reason' => 'aam_manage_policy'));
|
27 |
+
}
|
28 |
+
}
|
29 |
+
|
30 |
/**
|
31 |
*
|
32 |
* @return type
|
143 |
|
144 |
$list = get_posts(array(
|
145 |
'post_type' => 'aam_policy',
|
146 |
+
'numberposts' => -1,
|
147 |
+
'post_status' => 'publish'
|
|
|
148 |
));
|
149 |
|
150 |
$response = array(
|
170 |
return $response;
|
171 |
}
|
172 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
173 |
/**
|
174 |
*
|
175 |
* @param type $record
|
Application/Backend/Feature/Main/Post.php
CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_Post extends AAM_Backend_Feature_Abstract {
|
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
-
|
|
|
25 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_posts'));
|
26 |
}
|
27 |
}
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
+
$allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
|
25 |
+
if (!$allowed || !current_user_can('aam_manage_posts')) {
|
26 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_posts'));
|
27 |
}
|
28 |
}
|
Application/Backend/Feature/Main/Redirect.php
CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_Redirect extends AAM_Backend_Feature_Abstract {
|
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
-
|
|
|
25 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_access_denied_redirect'));
|
26 |
}
|
27 |
}
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
+
$allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
|
25 |
+
if (!$allowed || !current_user_can('aam_manage_access_denied_redirect')) {
|
26 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_access_denied_redirect'));
|
27 |
}
|
28 |
}
|
Application/Backend/Feature/Main/Route.php
CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_Route extends AAM_Backend_Feature_Abstract {
|
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
-
|
|
|
25 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_api_routes'));
|
26 |
}
|
27 |
}
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
+
$allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
|
25 |
+
if (!$allowed || !current_user_can('aam_manage_api_routes')) {
|
26 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_api_routes'));
|
27 |
}
|
28 |
}
|
Application/Backend/Feature/Main/Toolbar.php
CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_Toolbar extends AAM_Backend_Feature_Abstract {
|
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
-
|
|
|
25 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_admin_toolbar'));
|
26 |
}
|
27 |
}
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
+
$allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
|
25 |
+
if (!$allowed || !current_user_can('aam_manage_admin_toolbar')) {
|
26 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_admin_toolbar'));
|
27 |
}
|
28 |
}
|
Application/Backend/Feature/Main/Uri.php
CHANGED
@@ -21,7 +21,8 @@ class AAM_Backend_Feature_Main_Uri extends AAM_Backend_Feature_Abstract {
|
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
-
|
|
|
25 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_uri'));
|
26 |
}
|
27 |
}
|
@@ -146,7 +147,7 @@ class AAM_Backend_Feature_Main_Uri extends AAM_Backend_Feature_Abstract {
|
|
146 |
AAM_Backend_Feature::registerFeature((object) array(
|
147 |
'uid' => 'uri',
|
148 |
'position' => 55,
|
149 |
-
'title' => __('URI Access', AAM_KEY)
|
150 |
'capability' => 'aam_manage_uri',
|
151 |
'type' => 'main',
|
152 |
'subjects' => array(
|
21 |
public function __construct() {
|
22 |
parent::__construct();
|
23 |
|
24 |
+
$allowed = AAM_Backend_Subject::getInstance()->isAllowedToManage();
|
25 |
+
if (!$allowed || !current_user_can('aam_manage_uri')) {
|
26 |
AAM::api()->denyAccess(array('reason' => 'aam_manage_uri'));
|
27 |
}
|
28 |
}
|
147 |
AAM_Backend_Feature::registerFeature((object) array(
|
148 |
'uid' => 'uri',
|
149 |
'position' => 55,
|
150 |
+
'title' => __('URI Access', AAM_KEY),
|
151 |
'capability' => 'aam_manage_uri',
|
152 |
'type' => 'main',
|
153 |
'subjects' => array(
|
Application/Backend/Feature/Settings/Core.php
CHANGED
@@ -92,7 +92,7 @@ class AAM_Backend_Feature_Settings_Core extends AAM_Backend_Feature_Abstract {
|
|
92 |
'core.settings.jwtAuthentication' => array(
|
93 |
'title' => __('JWT Authentication', AAM_KEY),
|
94 |
'descr' => sprintf(AAM_Backend_View_Helper::preparePhrase('[Note!] PHP 5.4 or higher is required for this feature. Enable the ability to authenticate user with WordPress RESTful API and JWT token. For more information, check %sHow to authenticate WordPress user with JWT token%s article', 'b'), '<a href="https://aamplugin.com/article/how-to-authenticate-wordpress-user-with-jwt-token">', '</a>'),
|
95 |
-
'value' => AAM_Core_Config::get('core.settings.jwtAuthentication',
|
96 |
),
|
97 |
'core.settings.multiSubject' => array(
|
98 |
'title' => __('Multiple Roles Support', AAM_KEY),
|
92 |
'core.settings.jwtAuthentication' => array(
|
93 |
'title' => __('JWT Authentication', AAM_KEY),
|
94 |
'descr' => sprintf(AAM_Backend_View_Helper::preparePhrase('[Note!] PHP 5.4 or higher is required for this feature. Enable the ability to authenticate user with WordPress RESTful API and JWT token. For more information, check %sHow to authenticate WordPress user with JWT token%s article', 'b'), '<a href="https://aamplugin.com/article/how-to-authenticate-wordpress-user-with-jwt-token">', '</a>'),
|
95 |
+
'value' => AAM_Core_Config::get('core.settings.jwtAuthentication', true)
|
96 |
),
|
97 |
'core.settings.multiSubject' => array(
|
98 |
'title' => __('Multiple Roles Support', AAM_KEY),
|
Application/Backend/Feature/Subject/Role.php
CHANGED
@@ -59,8 +59,7 @@ class AAM_Backend_Feature_Subject_Role {
|
|
59 |
implode(',', $this->prepareRowActions($uc, $id)),
|
60 |
$data
|
61 |
),
|
62 |
-
AAM_Core_API::maxLevel($data['capabilities'])
|
63 |
-
AAM_Core_API::getOption("aam-role-{$id}-expiration", '')
|
64 |
);
|
65 |
}
|
66 |
|
@@ -163,7 +162,6 @@ class AAM_Backend_Feature_Subject_Role {
|
|
163 |
|
164 |
if (current_user_can('aam_create_roles')) {
|
165 |
$name = sanitize_text_field(filter_input(INPUT_POST, 'name'));
|
166 |
-
$expire = filter_input(INPUT_POST, 'expire');
|
167 |
$roles = AAM_Core_API::getRoles();
|
168 |
$role_id = sanitize_key(strtolower($name));
|
169 |
|
@@ -185,13 +183,6 @@ class AAM_Backend_Feature_Subject_Role {
|
|
185 |
$this->cloneSettings($role, $parent);
|
186 |
}
|
187 |
|
188 |
-
//save expiration rule if set
|
189 |
-
if ($expire) {
|
190 |
-
AAM_Core_API::updateOption("aam-role-{$role_id}-expiration", $expire);
|
191 |
-
} else {
|
192 |
-
AAM_Core_API::deleteOption("aam-role-{$role_id}-expiration");
|
193 |
-
}
|
194 |
-
|
195 |
do_action('aam-post-add-role-action', $role, $parent);
|
196 |
} else {
|
197 |
$response['reason'] = __("Role with slug [{$role_id}] already exists", AAM_KEY);
|
@@ -246,16 +237,6 @@ class AAM_Backend_Feature_Subject_Role {
|
|
246 |
$role = AAM_Backend_Subject::getInstance();
|
247 |
$role->update(trim(filter_input(INPUT_POST, 'name')));
|
248 |
|
249 |
-
$expire = filter_input(INPUT_POST, 'expire');
|
250 |
-
//save expiration rule if set
|
251 |
-
if ($expire) {
|
252 |
-
AAM_Core_API::updateOption(
|
253 |
-
'aam-role-' . $role->getId() .'-expiration', $expire
|
254 |
-
);
|
255 |
-
} else {
|
256 |
-
AAM_Core_API::deleteOption('aam-role-' . $role->getId() .'-expiration');
|
257 |
-
}
|
258 |
-
|
259 |
do_action('aam-post-update-role-action', $role->get());
|
260 |
|
261 |
$response = array('status' => 'success');
|
59 |
implode(',', $this->prepareRowActions($uc, $id)),
|
60 |
$data
|
61 |
),
|
62 |
+
AAM_Core_API::maxLevel($data['capabilities'])
|
|
|
63 |
);
|
64 |
}
|
65 |
|
162 |
|
163 |
if (current_user_can('aam_create_roles')) {
|
164 |
$name = sanitize_text_field(filter_input(INPUT_POST, 'name'));
|
|
|
165 |
$roles = AAM_Core_API::getRoles();
|
166 |
$role_id = sanitize_key(strtolower($name));
|
167 |
|
183 |
$this->cloneSettings($role, $parent);
|
184 |
}
|
185 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
186 |
do_action('aam-post-add-role-action', $role, $parent);
|
187 |
} else {
|
188 |
$response['reason'] = __("Role with slug [{$role_id}] already exists", AAM_KEY);
|
237 |
$role = AAM_Backend_Subject::getInstance();
|
238 |
$role->update(trim(filter_input(INPUT_POST, 'name')));
|
239 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
240 |
do_action('aam-post-update-role-action', $role->get());
|
241 |
|
242 |
$response = array('status' => 'success');
|
Application/Backend/Feature/Subject/User.php
CHANGED
@@ -98,10 +98,9 @@ class AAM_Backend_Feature_Subject_User {
|
|
98 |
);
|
99 |
|
100 |
if (current_user_can('aam_switch_users')) {
|
101 |
-
$user
|
102 |
-
$max = AAM::getUser()->getMaxLevel();
|
103 |
|
104 |
-
if ($
|
105 |
AAM_Core_API::updateOption(
|
106 |
'aam-user-switch-' . $user->ID, get_current_user_id()
|
107 |
);
|
@@ -137,22 +136,6 @@ class AAM_Backend_Feature_Subject_User {
|
|
137 |
return wp_json_encode($response);
|
138 |
}
|
139 |
|
140 |
-
/**
|
141 |
-
*
|
142 |
-
* @return type
|
143 |
-
*/
|
144 |
-
public function generateJWT() {
|
145 |
-
$userId = filter_input(INPUT_POST, 'user');
|
146 |
-
$expires = filter_input(INPUT_POST, 'expires');
|
147 |
-
|
148 |
-
$jwt = AAM_Core_JwtAuth::generateJWT($userId, $expires);
|
149 |
-
|
150 |
-
return wp_json_encode(array(
|
151 |
-
'status' => 'success',
|
152 |
-
'jwt' => $jwt->token
|
153 |
-
));
|
154 |
-
}
|
155 |
-
|
156 |
/**
|
157 |
* Query database for list of users
|
158 |
*
|
@@ -361,9 +344,23 @@ class AAM_Backend_Feature_Subject_User {
|
|
361 |
* @access protected
|
362 |
*/
|
363 |
protected function isAllowed(AAM_Core_Subject_User $user) {
|
364 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
365 |
|
366 |
-
return $
|
367 |
}
|
368 |
|
369 |
}
|
98 |
);
|
99 |
|
100 |
if (current_user_can('aam_switch_users')) {
|
101 |
+
$user = AAM_Backend_Subject::getInstance()->get();
|
|
|
102 |
|
103 |
+
if ($this->isAllowed($user)) {
|
104 |
AAM_Core_API::updateOption(
|
105 |
'aam-user-switch-' . $user->ID, get_current_user_id()
|
106 |
);
|
136 |
return wp_json_encode($response);
|
137 |
}
|
138 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
/**
|
140 |
* Query database for list of users
|
141 |
*
|
344 |
* @access protected
|
345 |
*/
|
346 |
protected function isAllowed(AAM_Core_Subject_User $user) {
|
347 |
+
$sameLevel = false;
|
348 |
+
if (AAM_Core_API::capabilityExists('manage_same_user_level')) {
|
349 |
+
$sameLevel = current_user_can('manage_same_user_level');
|
350 |
+
} else {
|
351 |
+
$sameLevel = current_user_can('administrator');
|
352 |
+
}
|
353 |
+
|
354 |
+
$userMaxLevel = AAM::api()->getUser()->getMaxLevel();
|
355 |
+
$subjectMaxLevel = $user->getMaxLevel();
|
356 |
+
|
357 |
+
if ($sameLevel) {
|
358 |
+
$allowed = $userMaxLevel >= $subjectMaxLevel;
|
359 |
+
} else {
|
360 |
+
$allowed = $userMaxLevel > $subjectMaxLevel;
|
361 |
+
}
|
362 |
|
363 |
+
return $allowed;
|
364 |
}
|
365 |
|
366 |
}
|
Application/Backend/Manager.php
CHANGED
@@ -46,9 +46,6 @@ class AAM_Backend_Manager {
|
|
46 |
add_action('admin_print_footer_scripts', array($this, 'printFooterJavascript'));
|
47 |
add_action('admin_print_styles', array($this, 'printStylesheet'));
|
48 |
|
49 |
-
//map AAM UI specific capabilities
|
50 |
-
add_filter('map_meta_cap', array($this, 'mapMetaCap'), 10, 4);
|
51 |
-
|
52 |
//user profile update action
|
53 |
add_action('profile_update', array($this, 'profileUpdate'), 10, 2);
|
54 |
|
@@ -74,9 +71,10 @@ class AAM_Backend_Manager {
|
|
74 |
//manager Admin Menu
|
75 |
if (is_multisite() && is_network_admin()) {
|
76 |
//register AAM in the network admin panel
|
77 |
-
add_action('
|
78 |
} else {
|
79 |
-
add_action('
|
|
|
80 |
add_action('all_admin_notices', array($this, 'notification'));
|
81 |
}
|
82 |
|
@@ -314,22 +312,6 @@ class AAM_Backend_Manager {
|
|
314 |
$importer->dispatch();
|
315 |
}
|
316 |
|
317 |
-
/**
|
318 |
-
*
|
319 |
-
* @param type $caps
|
320 |
-
* @param type $cap
|
321 |
-
* @return type
|
322 |
-
*/
|
323 |
-
public function mapMetaCap($caps, $cap) {
|
324 |
-
if (in_array($cap, AAM_Backend_Feature_Main_Capability::$groups['aam'], true)) {
|
325 |
-
if (!AAM_Core_API::capabilityExists($cap)) {
|
326 |
-
$caps = array(AAM_Core_Config::get('page.capability', 'administrator'));
|
327 |
-
}
|
328 |
-
}
|
329 |
-
|
330 |
-
return $caps;
|
331 |
-
}
|
332 |
-
|
333 |
/**
|
334 |
*
|
335 |
* @param string $html
|
@@ -368,7 +350,8 @@ class AAM_Backend_Manager {
|
|
368 |
|
369 |
if (!empty($newRoles)) {
|
370 |
//remove all current roles and then set new
|
371 |
-
$user->set_role(
|
|
|
372 |
foreach($newRoles as $role) {
|
373 |
$user->add_role($role);
|
374 |
}
|
@@ -378,19 +361,6 @@ class AAM_Backend_Manager {
|
|
378 |
//role changed?
|
379 |
if (implode('', $user->roles) !== implode('', $old->roles)) {
|
380 |
AAM_Core_API::clearCache(new AAM_Core_Subject_User($id));
|
381 |
-
|
382 |
-
// check if role has expiration data set
|
383 |
-
// TODO: This supports only the first role and NOT the multi-roles
|
384 |
-
if (is_array($user->roles)) {
|
385 |
-
$roles = array_values($user->roles);
|
386 |
-
$role = array_shift($roles);
|
387 |
-
$expire = AAM_Core_API::getOption("aam-role-{$role}-expiration", '');
|
388 |
-
|
389 |
-
if ($expire) {
|
390 |
-
update_user_option($id, "aam-original-roles", $old->roles);
|
391 |
-
update_user_option($id, "aam-role-expires", strtotime($expire));
|
392 |
-
}
|
393 |
-
}
|
394 |
}
|
395 |
}
|
396 |
|
@@ -514,17 +484,12 @@ class AAM_Backend_Manager {
|
|
514 |
|
515 |
if ($uid && AAM_Core_API::capabilityExists('access_dashboard')) {
|
516 |
$caps = AAM::getUser()->allcaps;
|
517 |
-
|
518 |
-
|
519 |
-
|
520 |
-
|
521 |
-
|
522 |
-
|
523 |
-
} elseif (!defined('DOING_AJAX')) {
|
524 |
-
AAM_Core_API::reject(
|
525 |
-
'backend', array('hook' => 'access_dashboard')
|
526 |
-
);
|
527 |
-
}
|
528 |
}
|
529 |
}
|
530 |
}
|
@@ -833,7 +798,7 @@ class AAM_Backend_Manager {
|
|
833 |
public function printJavascript() {
|
834 |
if (AAM::isAAM()) {
|
835 |
wp_enqueue_script('aam-vendor', AAM_MEDIA . '/js/vendor.js');
|
836 |
-
wp_enqueue_script('aam-main', AAM_MEDIA . '/js/aam-5.9.
|
837 |
|
838 |
//add plugin localization
|
839 |
$this->printLocalization('aam-main');
|
@@ -956,6 +921,18 @@ class AAM_Backend_Manager {
|
|
956 |
AAM_Core_Config::get('policy.capability', 'aam_manage_policy'),
|
957 |
'edit.php?post_type=aam_policy'
|
958 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
959 |
}
|
960 |
|
961 |
/**
|
46 |
add_action('admin_print_footer_scripts', array($this, 'printFooterJavascript'));
|
47 |
add_action('admin_print_styles', array($this, 'printStylesheet'));
|
48 |
|
|
|
|
|
|
|
49 |
//user profile update action
|
50 |
add_action('profile_update', array($this, 'profileUpdate'), 10, 2);
|
51 |
|
71 |
//manager Admin Menu
|
72 |
if (is_multisite() && is_network_admin()) {
|
73 |
//register AAM in the network admin panel
|
74 |
+
add_action('_network_admin_menu', array($this, 'adminMenu'));
|
75 |
} else {
|
76 |
+
add_action('_user_admin_menu', array($this, 'adminMenu'));
|
77 |
+
add_action('_admin_menu', array($this, 'adminMenu'));
|
78 |
add_action('all_admin_notices', array($this, 'notification'));
|
79 |
}
|
80 |
|
312 |
$importer->dispatch();
|
313 |
}
|
314 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
315 |
/**
|
316 |
*
|
317 |
* @param string $html
|
350 |
|
351 |
if (!empty($newRoles)) {
|
352 |
//remove all current roles and then set new
|
353 |
+
$user->set_role('');
|
354 |
+
// TODO: Fix the bug where multiple roles are not removed
|
355 |
foreach($newRoles as $role) {
|
356 |
$user->add_role($role);
|
357 |
}
|
361 |
//role changed?
|
362 |
if (implode('', $user->roles) !== implode('', $old->roles)) {
|
363 |
AAM_Core_API::clearCache(new AAM_Core_Subject_User($id));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
364 |
}
|
365 |
}
|
366 |
|
484 |
|
485 |
if ($uid && AAM_Core_API::capabilityExists('access_dashboard')) {
|
486 |
$caps = AAM::getUser()->allcaps;
|
487 |
+
// If this is the AJAX call, still allow it because it will break a lot
|
488 |
+
// of frontend stuff that depends on it
|
489 |
+
if (empty($caps['access_dashboard']) && !defined('DOING_AJAX')) {
|
490 |
+
AAM_Core_API::reject(
|
491 |
+
'backend', array('hook' => 'access_dashboard')
|
492 |
+
);
|
|
|
|
|
|
|
|
|
|
|
493 |
}
|
494 |
}
|
495 |
}
|
798 |
public function printJavascript() {
|
799 |
if (AAM::isAAM()) {
|
800 |
wp_enqueue_script('aam-vendor', AAM_MEDIA . '/js/vendor.js');
|
801 |
+
wp_enqueue_script('aam-main', AAM_MEDIA . '/js/aam-5.9.2.js');
|
802 |
|
803 |
//add plugin localization
|
804 |
$this->printLocalization('aam-main');
|
921 |
AAM_Core_Config::get('policy.capability', 'aam_manage_policy'),
|
922 |
'edit.php?post_type=aam_policy'
|
923 |
);
|
924 |
+
|
925 |
+
$type = get_post_type_object('aam_policy');
|
926 |
+
if (current_user_can($type->cap->create_posts)) {
|
927 |
+
add_submenu_page(
|
928 |
+
'aam',
|
929 |
+
'Add New Policies',
|
930 |
+
'Add New Policies',
|
931 |
+
$type->cap->create_posts,
|
932 |
+
'post-new.php?post_type=aam_policy'
|
933 |
+
);
|
934 |
+
}
|
935 |
+
|
936 |
}
|
937 |
|
938 |
/**
|
Application/Backend/Subject.php
CHANGED
@@ -51,12 +51,6 @@ class AAM_Backend_Subject {
|
|
51 |
$instance = $this->initRequestedSubject(
|
52 |
$subject, AAM_Core_Request::request('subjectId')
|
53 |
);
|
54 |
-
|
55 |
-
$max = AAM::getUser()->getMaxLevel();
|
56 |
-
|
57 |
-
if ($max < AAM_Core_API::maxLevel($instance->getMaxLevel())) {
|
58 |
-
AAM::api()->denyAccess(array('reason' => 'User Level is too low'));
|
59 |
-
}
|
60 |
} else {
|
61 |
$this->initDefaultSubject();
|
62 |
}
|
@@ -99,7 +93,8 @@ class AAM_Backend_Subject {
|
|
99 |
*/
|
100 |
protected function initDefaultSubject() {
|
101 |
// This cover the scenario when we directly go to user e.g. ?page=aam&user=38
|
102 |
-
|
|
|
103 |
|
104 |
// TODO: The aam_list_roles is legacy and can be removed in Oct 2021
|
105 |
if (!$forceUser && (current_user_can('aam_manage_roles') || current_user_can('aam_list_roles'))) {
|
@@ -129,6 +124,34 @@ class AAM_Backend_Subject {
|
|
129 |
protected function setSubject(AAM_Core_Subject $subject) {
|
130 |
$this->subject = $subject;
|
131 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
132 |
|
133 |
/**
|
134 |
* Get subject property
|
51 |
$instance = $this->initRequestedSubject(
|
52 |
$subject, AAM_Core_Request::request('subjectId')
|
53 |
);
|
|
|
|
|
|
|
|
|
|
|
|
|
54 |
} else {
|
55 |
$this->initDefaultSubject();
|
56 |
}
|
93 |
*/
|
94 |
protected function initDefaultSubject() {
|
95 |
// This cover the scenario when we directly go to user e.g. ?page=aam&user=38
|
96 |
+
// or through AJAX post request with user ID
|
97 |
+
$forceUser = AAM_Core_Request::request('user');
|
98 |
|
99 |
// TODO: The aam_list_roles is legacy and can be removed in Oct 2021
|
100 |
if (!$forceUser && (current_user_can('aam_manage_roles') || current_user_can('aam_list_roles'))) {
|
124 |
protected function setSubject(AAM_Core_Subject $subject) {
|
125 |
$this->subject = $subject;
|
126 |
}
|
127 |
+
|
128 |
+
/**
|
129 |
+
* Check if current subject is allowed to be managed
|
130 |
+
*
|
131 |
+
* @return boolean
|
132 |
+
*
|
133 |
+
* @access public
|
134 |
+
*/
|
135 |
+
public function isAllowedToManage() {
|
136 |
+
// Determine that current user has enough level to manage requested subject
|
137 |
+
$sameLevel = false;
|
138 |
+
if (AAM_Core_API::capabilityExists('manage_same_user_level')) {
|
139 |
+
$sameLevel = current_user_can('manage_same_user_level');
|
140 |
+
} else {
|
141 |
+
$sameLevel = current_user_can('administrator');
|
142 |
+
}
|
143 |
+
|
144 |
+
$userMaxLevel = AAM::api()->getUser()->getMaxLevel();
|
145 |
+
$subjectMaxLevel = $this->subject->getMaxLevel();
|
146 |
+
|
147 |
+
if ($sameLevel) {
|
148 |
+
$allowed = $userMaxLevel >= $subjectMaxLevel;
|
149 |
+
} else {
|
150 |
+
$allowed = $userMaxLevel > $subjectMaxLevel;
|
151 |
+
}
|
152 |
+
|
153 |
+
return $allowed;
|
154 |
+
}
|
155 |
|
156 |
/**
|
157 |
* Get subject property
|
Application/Backend/View.php
CHANGED
@@ -46,6 +46,7 @@ class AAM_Backend_View {
|
|
46 |
AAM_Backend_Feature_Main_LogoutRedirect::register();
|
47 |
AAM_Backend_Feature_Main_404Redirect::register();
|
48 |
AAM_Backend_Feature_Main_Uri::register();
|
|
|
49 |
|
50 |
AAM_Backend_Feature_Settings_Core::register();
|
51 |
AAM_Backend_Feature_Settings_Content::register();
|
46 |
AAM_Backend_Feature_Main_LogoutRedirect::register();
|
47 |
AAM_Backend_Feature_Main_404Redirect::register();
|
48 |
AAM_Backend_Feature_Main_Uri::register();
|
49 |
+
AAM_Backend_Feature_Main_Jwt::register();
|
50 |
|
51 |
AAM_Backend_Feature_Settings_Core::register();
|
52 |
AAM_Backend_Feature_Settings_Content::register();
|
Application/Backend/phtml/index.phtml
CHANGED
@@ -248,7 +248,6 @@
|
|
248 |
<th width="65%"><?php echo __('Role', AAM_KEY); ?></th>
|
249 |
<th><?php echo __('Action', AAM_KEY); ?></th>
|
250 |
<th>Level</th>
|
251 |
-
<th>Expiration</th>
|
252 |
</tr>
|
253 |
</thead>
|
254 |
<tbody></tbody>
|
@@ -266,10 +265,6 @@
|
|
266 |
<label><?php echo __('Role Name', AAM_KEY); ?><span class="aam-asterix">*</span></label>
|
267 |
<input type="text" class="form-control" name="name" placeholder="<?php echo __('Enter Role Name', AAM_KEY); ?>" />
|
268 |
</div>
|
269 |
-
<div class="form-group">
|
270 |
-
<label><?php echo __('Role Expiration', AAM_KEY); ?> <a href="https://aamplugin.com/article/how-to-manage-wordpress-roles" target="_blank" data-toggle="tooltip" title="For how long user can have this role. Click to learn more."><i class="icon-help-circled"></i></a></label>
|
271 |
-
<input type="text" class="form-control" name="expire" placeholder="<?php echo __('Enter Expiration Rule', AAM_KEY); ?>" />
|
272 |
-
</div>
|
273 |
<?php /* TODO: Rethink this filter */ do_action('aam-add-role-ui-action'); ?>
|
274 |
<?php /* TODO: Rethink this filter */ echo apply_filters('aam-add-role-ui-filter', AAM_Backend_View::getInstance()->loadPartial('role-inheritance.phtml')); ?>
|
275 |
</div>
|
@@ -293,10 +288,6 @@
|
|
293 |
<label for="new-role-name"><?php echo __('Role Name', AAM_KEY); ?></label>
|
294 |
<input type="text" class="form-control" id="edit-role-name" placeholder="<?php echo __('Enter Role Name', AAM_KEY); ?>" name="name" />
|
295 |
</div>
|
296 |
-
<div class="form-group">
|
297 |
-
<label><?php echo __('Role Expiration', AAM_KEY); ?> <a href="https://aamplugin.com/article/how-to-manage-wordpress-roles" target="_blank" data-toggle="tooltip" title="For how long user can have this role. Click to learn more."><i class="icon-help-circled"></i></a></label>
|
298 |
-
<input type="text" class="form-control" name="expire" id="edit-role-expiration" placeholder="<?php echo __('Enter Expiration Rule', AAM_KEY); ?>" />
|
299 |
-
</div>
|
300 |
<?php /* TODO: Rethink this filter */ do_action('aam-edit-role-ui-action'); ?>
|
301 |
</div>
|
302 |
<div class="modal-footer">
|
@@ -352,7 +343,6 @@
|
|
352 |
<div class="modal-body">
|
353 |
<ul class="nav nav-tabs" role="tablist">
|
354 |
<li role="presentation" class="active"><a href="#edit-user-expiration" aria-controls="edit-user-expiration" role="tab" data-toggle="tab">Temporary Access</a></li>
|
355 |
-
<li role="presentation"><a href="#edit-user-jwt" aria-controls="edit-user-jwt" role="tab" data-toggle="tab">JWT Auth Token</a></li>
|
356 |
<li role="presentation"><a href="#edit-user-profile" aria-controls="edit-user-profile" role="tab" data-toggle="tab">Edit User</a></li>
|
357 |
</ul>
|
358 |
|
@@ -380,23 +370,6 @@
|
|
380 |
</select>
|
381 |
</div>
|
382 |
</div>
|
383 |
-
<div role="tabpanel" class="tab-pane" id="edit-user-jwt">
|
384 |
-
<div class="form-group">
|
385 |
-
<p class="aam-info"><?php echo sprintf(__('User JWT token to authentication user without a need for entering username/password. To learn more about JWT authentication, please refer to %sHow to authenticate WordPress user with JWT token%s article.', AAM_KEY), '<a href="https://aamplugin.com/article/how-to-authenticate-wordpress-user-with-jwt-token" target="_blank">', '</a>'); ?></p>
|
386 |
-
<div class="form-group">
|
387 |
-
<label for="user-auth-url"><?php echo __('JWT Token (for any API calls)', AAM_KEY); ?></label>
|
388 |
-
<textarea class="form-control" id="user-auth-jwt" readonly rows="5"></textarea>
|
389 |
-
</div>
|
390 |
-
|
391 |
-
<hr/>
|
392 |
-
|
393 |
-
<div class="form-group">
|
394 |
-
<label for="user-auth-url"><?php echo __('User Login URL (with JWT token)', AAM_KEY); ?></label>
|
395 |
-
<textarea class="form-control" id="user-auth-url" data-url="<?php echo add_query_arg('aam-jwt', '%s', site_url()); ?>" readonly rows="5"></textarea>
|
396 |
-
<small><?php echo __('With this URL user will be automatically logged in until the time defined on the "Temporary Access" tab.', AAM_KEY); ?></small>
|
397 |
-
</div>
|
398 |
-
</div>
|
399 |
-
</div>
|
400 |
<div role="tabpanel" class="tab-pane" id="edit-user-profile">
|
401 |
<p class="aam-info"><?php echo __("To manage user profile, click on the button below.", AAM_KEY); ?></p>
|
402 |
<p class="text-center">
|
248 |
<th width="65%"><?php echo __('Role', AAM_KEY); ?></th>
|
249 |
<th><?php echo __('Action', AAM_KEY); ?></th>
|
250 |
<th>Level</th>
|
|
|
251 |
</tr>
|
252 |
</thead>
|
253 |
<tbody></tbody>
|
265 |
<label><?php echo __('Role Name', AAM_KEY); ?><span class="aam-asterix">*</span></label>
|
266 |
<input type="text" class="form-control" name="name" placeholder="<?php echo __('Enter Role Name', AAM_KEY); ?>" />
|
267 |
</div>
|
|
|
|
|
|
|
|
|
268 |
<?php /* TODO: Rethink this filter */ do_action('aam-add-role-ui-action'); ?>
|
269 |
<?php /* TODO: Rethink this filter */ echo apply_filters('aam-add-role-ui-filter', AAM_Backend_View::getInstance()->loadPartial('role-inheritance.phtml')); ?>
|
270 |
</div>
|
288 |
<label for="new-role-name"><?php echo __('Role Name', AAM_KEY); ?></label>
|
289 |
<input type="text" class="form-control" id="edit-role-name" placeholder="<?php echo __('Enter Role Name', AAM_KEY); ?>" name="name" />
|
290 |
</div>
|
|
|
|
|
|
|
|
|
291 |
<?php /* TODO: Rethink this filter */ do_action('aam-edit-role-ui-action'); ?>
|
292 |
</div>
|
293 |
<div class="modal-footer">
|
343 |
<div class="modal-body">
|
344 |
<ul class="nav nav-tabs" role="tablist">
|
345 |
<li role="presentation" class="active"><a href="#edit-user-expiration" aria-controls="edit-user-expiration" role="tab" data-toggle="tab">Temporary Access</a></li>
|
|
|
346 |
<li role="presentation"><a href="#edit-user-profile" aria-controls="edit-user-profile" role="tab" data-toggle="tab">Edit User</a></li>
|
347 |
</ul>
|
348 |
|
370 |
</select>
|
371 |
</div>
|
372 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
373 |
<div role="tabpanel" class="tab-pane" id="edit-user-profile">
|
374 |
<p class="aam-info"><?php echo __("To manage user profile, click on the button below.", AAM_KEY); ?></p>
|
375 |
<p class="text-center">
|
Application/Backend/phtml/main/jwt.phtml
ADDED
@@ -0,0 +1,126 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php if (defined('AAM_KEY')) { ?>
|
2 |
+
<div class="aam-feature" id="jwt-content">
|
3 |
+
<?php $subject = AAM_Backend_Subject::getInstance(); ?>
|
4 |
+
|
5 |
+
<div class="row">
|
6 |
+
<div class="col-xs-12">
|
7 |
+
<p class="aam-info">
|
8 |
+
<?php echo sprintf(AAM_Backend_View_Helper::preparePhrase('Manage list of all valid JWT tokens to the website for [%s] account. For more information about JWT tokens please refer to the %sUltimate guide to WordPress JWT authentication%s article.', 'b'), AAM_Backend_Subject::getInstance()->getName(), '<a href="https://aamplugin.com/article/ultimate-guide-to-wordpress-jwt-authentication" target="_blank">', '</a>'); ?>
|
9 |
+
</p>
|
10 |
+
</div>
|
11 |
+
</div>
|
12 |
+
|
13 |
+
<div class="row">
|
14 |
+
<div class="col-xs-12">
|
15 |
+
<table id="jwt-list" class="table table-striped table-bordered">
|
16 |
+
<thead>
|
17 |
+
<tr>
|
18 |
+
<th>Token</th>
|
19 |
+
<th>URL</th>
|
20 |
+
<th width="8%"> </th>
|
21 |
+
<th width="70%"><?php echo __('Expires', AAM_KEY); ?></th>
|
22 |
+
<th><?php echo __('Actions', AAM_KEY); ?></th>
|
23 |
+
</tr>
|
24 |
+
</thead>
|
25 |
+
<tbody></tbody>
|
26 |
+
</table>
|
27 |
+
</div>
|
28 |
+
</div>
|
29 |
+
|
30 |
+
<div class="modal fade" id="create-jwt-modal" tabindex="-1" role="dialog">
|
31 |
+
<div class="modal-dialog" role="document">
|
32 |
+
<div class="modal-content">
|
33 |
+
<div class="modal-header">
|
34 |
+
<button type="button" class="close" data-dismiss="modal" aria-label="<?php echo __('Close', AAM_KEY); ?>"><span aria-hidden="true">×</span></button>
|
35 |
+
<h4 class="modal-title"><?php echo __('Create JWT Token', AAM_KEY); ?></h4>
|
36 |
+
</div>
|
37 |
+
<div class="modal-body">
|
38 |
+
<div class="form-group aam-bordered">
|
39 |
+
<label for="jwt-expiration-datapicker" class="aam-block">
|
40 |
+
<?php echo __('JWT Expires', AAM_KEY); ?>
|
41 |
+
</label>
|
42 |
+
<div id="jwt-expiration-datapicker"></div>
|
43 |
+
<input type="hidden" id="jwt-expires" />
|
44 |
+
</div>
|
45 |
+
|
46 |
+
<div class="form-group aam-outer-top-xs">
|
47 |
+
<label for="jwt-token-preview" class="aam-block">
|
48 |
+
<?php echo __('JWT Token (for any API calls)', AAM_KEY); ?>
|
49 |
+
<a href="#" class="aam-copy-clipboard" data-clipboard-target="#jwt-token-preview"><?php echo __('Copy to clipboard', AAM_KEY); ?></a>
|
50 |
+
</label>
|
51 |
+
<textarea class="form-control" id="jwt-token-preview" readonly rows="5"></textarea>
|
52 |
+
</div>
|
53 |
+
|
54 |
+
<hr/>
|
55 |
+
|
56 |
+
<div class="form-group">
|
57 |
+
<label for="jwt-url-preview" class="aam-block">
|
58 |
+
<?php echo __('Account Login URL (with JWT token)', AAM_KEY); ?>
|
59 |
+
<a href="#" class="aam-copy-clipboard" data-clipboard-target="#jwt-url-preview"><?php echo __('Copy to clipboard', AAM_KEY); ?></a>
|
60 |
+
</label>
|
61 |
+
<textarea class="form-control" id="jwt-url-preview" data-url="<?php echo add_query_arg('aam-jwt', '%s', site_url()); ?>" readonly rows="5"></textarea>
|
62 |
+
<small><?php echo __('With this URL account will be automatically logged in until the time defined on the "Temporary Access" tab.', AAM_KEY); ?></small>
|
63 |
+
</div>
|
64 |
+
</div>
|
65 |
+
<div class="modal-footer">
|
66 |
+
<button type="button" class="btn btn-success" id="create-jwt-btn"><?php echo __('Create', AAM_KEY); ?></button>
|
67 |
+
<button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
|
68 |
+
</div>
|
69 |
+
</div>
|
70 |
+
</div>
|
71 |
+
</div>
|
72 |
+
|
73 |
+
<div class="modal fade" id="view-jwt-modal" tabindex="-1" role="dialog">
|
74 |
+
<div class="modal-dialog" role="document">
|
75 |
+
<div class="modal-content">
|
76 |
+
<div class="modal-header">
|
77 |
+
<button type="button" class="close" data-dismiss="modal" aria-label="<?php echo __('Close', AAM_KEY); ?>"><span aria-hidden="true">×</span></button>
|
78 |
+
<h4 class="modal-title"><?php echo __('View JWT Token', AAM_KEY); ?></h4>
|
79 |
+
</div>
|
80 |
+
<div class="modal-body">
|
81 |
+
<div class="form-group">
|
82 |
+
<label for="view-jwt-token" class="aam-block">
|
83 |
+
<?php echo __('JWT Token (for any API calls)', AAM_KEY); ?>
|
84 |
+
<a href="#" class="aam-copy-clipboard" data-clipboard-target="#view-jwt-token"><?php echo __('Copy to clipboard', AAM_KEY); ?></a>
|
85 |
+
</label>
|
86 |
+
<textarea class="form-control" id="view-jwt-token" readonly rows="5"></textarea>
|
87 |
+
</div>
|
88 |
+
|
89 |
+
<hr/>
|
90 |
+
|
91 |
+
<div class="form-group">
|
92 |
+
<label for="view-jwt-url" class="aam-block">
|
93 |
+
<?php echo __('Account Login URL (with JWT token)', AAM_KEY); ?>
|
94 |
+
<a href="#" class="aam-copy-clipboard" data-clipboard-target="#view-jwt-url"><?php echo __('Copy to clipboard', AAM_KEY); ?></a>
|
95 |
+
</label>
|
96 |
+
<textarea class="form-control" id="view-jwt-url" readonly rows="5"></textarea>
|
97 |
+
<small><?php echo __('Use this URL to authenticate account without the need to enter username/password.', AAM_KEY); ?></small>
|
98 |
+
</div>
|
99 |
+
</div>
|
100 |
+
<div class="modal-footer">
|
101 |
+
<button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
|
102 |
+
</div>
|
103 |
+
</div>
|
104 |
+
</div>
|
105 |
+
</div>
|
106 |
+
|
107 |
+
<div class="modal fade" id="delete-jwt-modal" tabindex="-1" role="dialog">
|
108 |
+
<div class="modal-dialog" role="document">
|
109 |
+
<div class="modal-content">
|
110 |
+
<div class="modal-header">
|
111 |
+
<button type="button" class="close" data-dismiss="modal" aria-label="<?php echo __('Close', AAM_KEY); ?>"><span aria-hidden="true">×</span></button>
|
112 |
+
<h4 class="modal-title"><?php echo __('Delete JWT Token', AAM_KEY); ?></h4>
|
113 |
+
</div>
|
114 |
+
<div class="modal-body">
|
115 |
+
<p class="alert alert-danger text-larger"><?php echo __('You are about to delete already issued JWT token. Any application or person that has this token, will no longer be able to use it. Please confirm.') ?></p>
|
116 |
+
</div>
|
117 |
+
<div class="modal-footer">
|
118 |
+
<button type="button" class="btn btn-danger" id="jwt-delete-btn"><?php echo __('Delete', AAM_KEY); ?></button>
|
119 |
+
<button type="button" class="btn btn-default" data-dismiss="modal"><?php echo __('Close', AAM_KEY); ?></button>
|
120 |
+
</div>
|
121 |
+
</div>
|
122 |
+
</div>
|
123 |
+
</div>
|
124 |
+
|
125 |
+
</div>
|
126 |
+
<?php }
|
Application/Backend/phtml/main/menu.phtml
CHANGED
@@ -56,13 +56,13 @@
|
|
56 |
<?php if ($submenu['id'] == 'index.php') { ?>
|
57 |
<div class="col-xs-12 col-md-6 aam-submenu-item">
|
58 |
<label for="menu-item-<?php echo $i . $j; ?>">
|
59 |
-
|
60 |
<a href="#dashboard-lockout-modal" data-toggle="modal"><i class="icon-help-circled"></i></a>
|
61 |
</div>
|
62 |
<?php } else { ?>
|
63 |
<div class="col-xs-12 col-md-6 aam-submenu-item">
|
64 |
<label for="menu-item-<?php echo $i . $j; ?>">
|
65 |
-
|
66 |
<small class="aam-menu-capability"><?php echo __('Cap:', AAM_KEY), ' <b>', $submenu['capability']; ?></b></small>
|
67 |
<small class="aam-menu-capability"><?php echo __('ID:', AAM_KEY), ' <b>', $submenu['crc32']; ?></b></small>
|
68 |
</label>
|
56 |
<?php if ($submenu['id'] == 'index.php') { ?>
|
57 |
<div class="col-xs-12 col-md-6 aam-submenu-item">
|
58 |
<label for="menu-item-<?php echo $i . $j; ?>">
|
59 |
+
<?php echo $submenu['name']; ?><small class="aam-menu-capability"><?php echo __('Cap:', AAM_KEY), ' <b>', $submenu['capability']; ?></b></small></label>
|
60 |
<a href="#dashboard-lockout-modal" data-toggle="modal"><i class="icon-help-circled"></i></a>
|
61 |
</div>
|
62 |
<?php } else { ?>
|
63 |
<div class="col-xs-12 col-md-6 aam-submenu-item">
|
64 |
<label for="menu-item-<?php echo $i . $j; ?>">
|
65 |
+
<?php echo $submenu['name']; ?>
|
66 |
<small class="aam-menu-capability"><?php echo __('Cap:', AAM_KEY), ' <b>', $submenu['capability']; ?></b></small>
|
67 |
<small class="aam-menu-capability"><?php echo __('ID:', AAM_KEY), ' <b>', $submenu['crc32']; ?></b></small>
|
68 |
</label>
|
Application/Backend/phtml/main/metabox.phtml
CHANGED
@@ -61,7 +61,7 @@
|
|
61 |
<?php foreach ($metaboxes as $metabox) { ?>
|
62 |
<div class="col-xs-12 col-md-6 aam-submenu-item">
|
63 |
<label for="metabox-<?php echo $screen; ?>-<?php echo $metabox['id']; ?>">
|
64 |
-
|
65 |
<small class="aam-metabox-details"><?php echo __('ID:', AAM_KEY); ?> <b><?php echo crc32($screen . '|' . $metabox['id']); ?></b></small>
|
66 |
</label>
|
67 |
<input type="checkbox" class="aam-checkbox-danger" id="metabox-<?php echo $screen; ?>-<?php echo $metabox['id']; ?>" data-metabox="<?php echo $screen; ?>|<?php echo $metabox['id']; ?>"<?php echo ($object->has($screen, $metabox['id']) ? ' checked="checked"' : ''); ?> />
|
61 |
<?php foreach ($metaboxes as $metabox) { ?>
|
62 |
<div class="col-xs-12 col-md-6 aam-submenu-item">
|
63 |
<label for="metabox-<?php echo $screen; ?>-<?php echo $metabox['id']; ?>">
|
64 |
+
<?php echo $metabox['title']; ?>
|
65 |
<small class="aam-metabox-details"><?php echo __('ID:', AAM_KEY); ?> <b><?php echo crc32($screen . '|' . $metabox['id']); ?></b></small>
|
66 |
</label>
|
67 |
<input type="checkbox" class="aam-checkbox-danger" id="metabox-<?php echo $screen; ?>-<?php echo $metabox['id']; ?>" data-metabox="<?php echo $screen; ?>|<?php echo $metabox['id']; ?>"<?php echo ($object->has($screen, $metabox['id']) ? ' checked="checked"' : ''); ?> />
|
Application/Backend/phtml/main/toolbar.phtml
CHANGED
@@ -51,7 +51,7 @@
|
|
51 |
<?php foreach($this->getAllChildren($branch) as $child) { ?>
|
52 |
<div class="col-xs-12 aam-submenu-item">
|
53 |
<label for="toolbar-<?php echo $child->id; ?>">
|
54 |
-
|
55 |
<small class="aam-menu-capability"><?php echo __('URI:', AAM_KEY); ?> <b><?php echo str_replace(site_url(), '', $child->href); ?></b></small>
|
56 |
<small class="aam-menu-capability"><?php echo __('ID:', AAM_KEY); ?> <b><?php echo esc_js($child->id); ?></b></small>
|
57 |
</label>
|
51 |
<?php foreach($this->getAllChildren($branch) as $child) { ?>
|
52 |
<div class="col-xs-12 aam-submenu-item">
|
53 |
<label for="toolbar-<?php echo $child->id; ?>">
|
54 |
+
<?php echo $this->normalizeTitle($child); ?>
|
55 |
<small class="aam-menu-capability"><?php echo __('URI:', AAM_KEY); ?> <b><?php echo str_replace(site_url(), '', $child->href); ?></b></small>
|
56 |
<small class="aam-menu-capability"><?php echo __('ID:', AAM_KEY); ?> <b><?php echo esc_js($child->id); ?></b></small>
|
57 |
</label>
|
Application/Backend/phtml/user/multiple-roles.phtml
CHANGED
@@ -1,30 +1,32 @@
|
|
1 |
<?php if (defined('AAM_KEY')) { ?>
|
2 |
-
|
3 |
-
<
|
4 |
-
<
|
5 |
-
|
6 |
-
<
|
7 |
-
<
|
8 |
-
|
9 |
-
|
10 |
-
<
|
11 |
-
<
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
|
17 |
-
|
18 |
-
|
19 |
-
|
20 |
-
|
|
|
21 |
|
22 |
-
|
23 |
-
|
24 |
-
|
25 |
-
|
26 |
-
|
27 |
-
|
28 |
-
|
29 |
-
|
|
|
30 |
<?php } ?>
|
1 |
<?php if (defined('AAM_KEY')) { ?>
|
2 |
+
<?php if ( !IS_PROFILE_PAGE && !is_network_admin() && current_user_can('promote_user', $user->ID)) { ?>
|
3 |
+
<table class="form-table">
|
4 |
+
<tr>
|
5 |
+
<th><?php echo esc_html('User Roles', AAM_KEY); ?></th>
|
6 |
+
<td>
|
7 |
+
<div class="wp-tab-panel">
|
8 |
+
<ul>
|
9 |
+
<?php foreach (get_editable_roles() as $id => $role) { ?>
|
10 |
+
<li>
|
11 |
+
<label>
|
12 |
+
<input type="checkbox" name="aam_user_roles[]" value="<?php echo esc_attr($id); ?>" <?php checked(in_array($id, $user->roles)); ?> />
|
13 |
+
<?php echo esc_html(translate_user_role($role['name'])); ?>
|
14 |
+
</label>
|
15 |
+
</li>
|
16 |
+
<?php } ?>
|
17 |
+
</ul>
|
18 |
+
</div>
|
19 |
+
</td>
|
20 |
+
</tr>
|
21 |
+
</table>
|
22 |
|
23 |
+
<!-- Remove standard WordPress roles selector-->
|
24 |
+
<script>
|
25 |
+
(function($) {
|
26 |
+
$(document).ready(function(){
|
27 |
+
$('.user-role-wrap').remove();
|
28 |
+
});
|
29 |
+
})(jQuery);
|
30 |
+
</script>
|
31 |
+
<?php } ?>
|
32 |
<?php } ?>
|
Application/Core/Compatibility.php
CHANGED
@@ -12,10 +12,31 @@
|
|
12 |
*
|
13 |
* @package AAM
|
14 |
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
15 |
-
* @todo Remove Feb 2018
|
16 |
*/
|
17 |
class AAM_Core_Compatibility {
|
18 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
19 |
/**
|
20 |
* Convert config to the Policy Config
|
21 |
*
|
@@ -271,4 +292,16 @@ class AAM_Core_Compatibility {
|
|
271 |
}
|
272 |
}
|
273 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
274 |
}
|
12 |
*
|
13 |
* @package AAM
|
14 |
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
|
|
15 |
*/
|
16 |
class AAM_Core_Compatibility {
|
17 |
|
18 |
+
/**
|
19 |
+
* Undocumented variable
|
20 |
+
*
|
21 |
+
* @var [type]
|
22 |
+
*/
|
23 |
+
protected static $instance = null;
|
24 |
+
|
25 |
+
/**
|
26 |
+
* Compatibility between post actions and policy actions
|
27 |
+
*
|
28 |
+
* @param [type] $action
|
29 |
+
* @param [type] $effect
|
30 |
+
* @return void
|
31 |
+
*/
|
32 |
+
public static function convertPolicyAction($action, $effect) {
|
33 |
+
return array(
|
34 |
+
"frontend.{$action}" => $effect,
|
35 |
+
"backend.{$action}" => $effect,
|
36 |
+
"api.{$action}" => $effect
|
37 |
+
);
|
38 |
+
}
|
39 |
+
|
40 |
/**
|
41 |
* Convert config to the Policy Config
|
42 |
*
|
292 |
}
|
293 |
}
|
294 |
|
295 |
+
/**
|
296 |
+
* Undocumented function
|
297 |
+
*
|
298 |
+
* @return void
|
299 |
+
*/
|
300 |
+
public static function getInstance() {
|
301 |
+
if (is_null(self::$instance)) {
|
302 |
+
self::$instance = new self;
|
303 |
+
}
|
304 |
+
|
305 |
+
return self::$instance;
|
306 |
+
}
|
307 |
}
|
Application/Core/Gateway.php
CHANGED
@@ -123,6 +123,15 @@ final class AAM_Core_Gateway {
|
|
123 |
);
|
124 |
}
|
125 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
126 |
/**
|
127 |
* Redirect request
|
128 |
*
|
123 |
);
|
124 |
}
|
125 |
|
126 |
+
/**
|
127 |
+
* Compatibility manager
|
128 |
+
*
|
129 |
+
* @return AAM_Core_Compatibility
|
130 |
+
*/
|
131 |
+
public function getCompatibilityManager() {
|
132 |
+
return AAM_Core_Compatibility::getInstance();
|
133 |
+
}
|
134 |
+
|
135 |
/**
|
136 |
* Redirect request
|
137 |
*
|
Application/Core/Jwt/Auth.php
ADDED
@@ -0,0 +1,69 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
/**
|
11 |
+
* AAM JWT Authentication handler
|
12 |
+
*
|
13 |
+
* @package AAM
|
14 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
15 |
+
* @since v5.9.2
|
16 |
+
*/
|
17 |
+
class AAM_Core_Jwt_Auth {
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Authenticate user with username and password
|
21 |
+
*
|
22 |
+
* @param string $username
|
23 |
+
* @param string $password
|
24 |
+
*
|
25 |
+
* @return stdClass
|
26 |
+
*
|
27 |
+
* @access public
|
28 |
+
*/
|
29 |
+
public function authenticateWithCredentials($username, $password) {
|
30 |
+
$response = array('error' => true);
|
31 |
+
|
32 |
+
// try to authenticate user with provided credentials
|
33 |
+
try {
|
34 |
+
$result = AAM_Core_Login::getInstance()->execute(
|
35 |
+
array(
|
36 |
+
'user_login' => $username,
|
37 |
+
'user_password' => $password
|
38 |
+
),
|
39 |
+
false
|
40 |
+
);
|
41 |
+
} catch (Exception $ex) {
|
42 |
+
$result = array(
|
43 |
+
'status' => 'failure',
|
44 |
+
'reason' => $ex->getMessage(),
|
45 |
+
);
|
46 |
+
}
|
47 |
+
|
48 |
+
if ($result['status'] === 'success') { // generate token
|
49 |
+
try {
|
50 |
+
$issuer = new AAM_Core_Jwt_Issuer();
|
51 |
+
$token = $issuer->issueToken(
|
52 |
+
array('userId' => $result['user']->ID, 'revocable' => true)
|
53 |
+
);
|
54 |
+
|
55 |
+
$response = array(
|
56 |
+
'jwt' => $token,
|
57 |
+
'user' => $result['user']
|
58 |
+
);
|
59 |
+
} catch (Exception $ex) {
|
60 |
+
$response['reason'] = $ex->getMessage();
|
61 |
+
}
|
62 |
+
} else {
|
63 |
+
$response['reason'] = $result['reason'];
|
64 |
+
}
|
65 |
+
|
66 |
+
return (object) $response;
|
67 |
+
}
|
68 |
+
|
69 |
+
}
|
Application/Core/Jwt/Issuer.php
ADDED
@@ -0,0 +1,229 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
/**
|
11 |
+
* AAM JWT Issuer
|
12 |
+
*
|
13 |
+
* @package AAM
|
14 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
15 |
+
* @since v5.9.2
|
16 |
+
*/
|
17 |
+
class AAM_Core_Jwt_Issuer {
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Just a local cache
|
21 |
+
*
|
22 |
+
* @var array
|
23 |
+
*/
|
24 |
+
protected $cache = array();
|
25 |
+
|
26 |
+
/**
|
27 |
+
* Validate JWT token
|
28 |
+
*
|
29 |
+
* @param string $token
|
30 |
+
*
|
31 |
+
* @return stdClass
|
32 |
+
*
|
33 |
+
* @access public
|
34 |
+
*/
|
35 |
+
public function validateToken($token) {
|
36 |
+
try {
|
37 |
+
$headers = $this->extractTokenHeaders($token);
|
38 |
+
|
39 |
+
if (strpos($headers->alg, 'RS') === 0) {
|
40 |
+
$filepath = AAM_Core_Config::get('authentication.jwt.publicKeyPath');
|
41 |
+
$key = (is_readable($filepath) ? file_get_contents($filepath) : null);
|
42 |
+
} else {
|
43 |
+
$key = AAM_Core_Config::get('authentication.jwt.secret', SECURE_AUTH_KEY);
|
44 |
+
}
|
45 |
+
|
46 |
+
// Step #1. Check if token is actually valid
|
47 |
+
$response = Firebase\JWT\JWT::decode(
|
48 |
+
$token, $key, array_keys(Firebase\JWT\JWT::$supported_algs)
|
49 |
+
);
|
50 |
+
|
51 |
+
// Step #2. If token is "revocable", make sure that claimed user still has
|
52 |
+
// the token in the meta
|
53 |
+
if (!empty($response->revocable)) {
|
54 |
+
$tokens = $this->getUsersTokens($response->userId);
|
55 |
+
if (!in_array($token, $tokens, true)) {
|
56 |
+
throw new Exception(__('Token has been revoked', AAM_KEY));
|
57 |
+
}
|
58 |
+
}
|
59 |
+
|
60 |
+
$response->status = 'valid';
|
61 |
+
} catch (Exception $ex) {
|
62 |
+
$response = array_merge(array(
|
63 |
+
'status' => 'invalid',
|
64 |
+
'reason' => $ex->getMessage()
|
65 |
+
), (array) $this->extractTokenClaims($token));
|
66 |
+
}
|
67 |
+
|
68 |
+
return (object) $response;
|
69 |
+
}
|
70 |
+
|
71 |
+
/**
|
72 |
+
* Issue JWT token
|
73 |
+
*
|
74 |
+
* @param array $args
|
75 |
+
* @param string $expires
|
76 |
+
*
|
77 |
+
* @return stdClass
|
78 |
+
*
|
79 |
+
* @access public
|
80 |
+
* @throws Exception
|
81 |
+
*/
|
82 |
+
public function issueToken($args = array(), $expires = null) {
|
83 |
+
if (!empty($expires)) {
|
84 |
+
$time = DateTime::createFromFormat('m/d/Y, H:i O', $expires);
|
85 |
+
} else {
|
86 |
+
$time = new DateTime(
|
87 |
+
AAM_Core_Config::get('authentication.jwt.expires', '+24 hours')
|
88 |
+
);
|
89 |
+
}
|
90 |
+
|
91 |
+
$claims = apply_filters(
|
92 |
+
'aam-jwt-claims-filter',
|
93 |
+
array_merge(
|
94 |
+
array(
|
95 |
+
"iat" => time(),
|
96 |
+
'iss' => get_site_url(),
|
97 |
+
'exp' => $time->format('m/d/Y, H:i O'),
|
98 |
+
'jti' => $this->generateUuid()
|
99 |
+
),
|
100 |
+
$args
|
101 |
+
)
|
102 |
+
);
|
103 |
+
|
104 |
+
// Determine algorithm and key
|
105 |
+
$attr = $this->getJWTSigningAttributes();
|
106 |
+
|
107 |
+
return (object) array(
|
108 |
+
'token' => Firebase\JWT\JWT::encode($claims, $attr->key, $attr->alg),
|
109 |
+
'claims' => $claims
|
110 |
+
);
|
111 |
+
}
|
112 |
+
|
113 |
+
/**
|
114 |
+
* Extract tokens headers
|
115 |
+
*
|
116 |
+
* @param string $token
|
117 |
+
*
|
118 |
+
* @return object
|
119 |
+
*
|
120 |
+
* @access public
|
121 |
+
*/
|
122 |
+
public static function extractTokenHeaders($token) {
|
123 |
+
$parts = explode('.', $token);
|
124 |
+
|
125 |
+
try {
|
126 |
+
$headers = Firebase\JWT\JWT::jsonDecode(
|
127 |
+
Firebase\JWT\JWT::urlsafeB64Decode($parts[0])
|
128 |
+
);
|
129 |
+
} catch (Exception $ex) {
|
130 |
+
$headers = new stdClass();
|
131 |
+
}
|
132 |
+
|
133 |
+
return $headers;
|
134 |
+
}
|
135 |
+
|
136 |
+
/**
|
137 |
+
* Extract token claims
|
138 |
+
*
|
139 |
+
* @param string $token
|
140 |
+
*
|
141 |
+
* @return object
|
142 |
+
*
|
143 |
+
* @access public
|
144 |
+
*/
|
145 |
+
public static function extractTokenClaims($token) {
|
146 |
+
$parts = explode('.', $token);
|
147 |
+
|
148 |
+
try {
|
149 |
+
$claims = Firebase\JWT\JWT::jsonDecode(
|
150 |
+
Firebase\JWT\JWT::urlsafeB64Decode($parts[1])
|
151 |
+
);
|
152 |
+
} catch (Exception $ex) {
|
153 |
+
$claims = new stdClass();
|
154 |
+
}
|
155 |
+
|
156 |
+
return $claims;
|
157 |
+
}
|
158 |
+
|
159 |
+
/**
|
160 |
+
* Get JWT attributes for signing
|
161 |
+
*
|
162 |
+
* @return object
|
163 |
+
*
|
164 |
+
* @access protected
|
165 |
+
*/
|
166 |
+
protected function getJWTSigningAttributes() {
|
167 |
+
$alg = strtoupper(
|
168 |
+
AAM_Core_Config::get('authentication.jwt.algorithm', 'HS256')
|
169 |
+
);
|
170 |
+
|
171 |
+
if (strpos($alg, 'RS') === 0) {
|
172 |
+
$filepath = AAM_Core_Config::get('authentication.jwt.privateKeyPath');
|
173 |
+
$key = (is_readable($filepath) ? file_get_contents($filepath) : null);
|
174 |
+
} else {
|
175 |
+
$key = AAM_Core_Config::get('authentication.jwt.secret', SECURE_AUTH_KEY);
|
176 |
+
}
|
177 |
+
|
178 |
+
return (object) array(
|
179 |
+
'alg' => $alg,
|
180 |
+
'key' => $key
|
181 |
+
);
|
182 |
+
}
|
183 |
+
|
184 |
+
/**
|
185 |
+
* Get user's tokens
|
186 |
+
*
|
187 |
+
* @param int $userId
|
188 |
+
*
|
189 |
+
* @return array
|
190 |
+
*
|
191 |
+
* @access protected
|
192 |
+
*/
|
193 |
+
protected function getUsersTokens($userId) {
|
194 |
+
if (!isset($this->cache[$userId])) {
|
195 |
+
$list = get_user_meta($userId, 'aam-jwt');
|
196 |
+
$this->cache[$userId] = is_array($list) ? $list : array();
|
197 |
+
}
|
198 |
+
|
199 |
+
return $this->cache[$userId];
|
200 |
+
}
|
201 |
+
|
202 |
+
/**
|
203 |
+
* Generate random uuid
|
204 |
+
*
|
205 |
+
* @return string
|
206 |
+
*/
|
207 |
+
protected function generateUuid() {
|
208 |
+
return sprintf( '%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
|
209 |
+
// 32 bits for "time_low"
|
210 |
+
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ),
|
211 |
+
|
212 |
+
// 16 bits for "time_mid"
|
213 |
+
mt_rand( 0, 0xffff ),
|
214 |
+
|
215 |
+
// 16 bits for "time_hi_and_version",
|
216 |
+
// four most significant bits holds version number 4
|
217 |
+
mt_rand( 0, 0x0fff ) | 0x4000,
|
218 |
+
|
219 |
+
// 16 bits, 8 bits for "clk_seq_hi_res",
|
220 |
+
// 8 bits for "clk_seq_low",
|
221 |
+
// two most significant bits holds zero and one for variant DCE1.1
|
222 |
+
mt_rand( 0, 0x3fff ) | 0x8000,
|
223 |
+
|
224 |
+
// 48 bits for "node"
|
225 |
+
mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff ), mt_rand( 0, 0xffff )
|
226 |
+
);
|
227 |
+
}
|
228 |
+
|
229 |
+
}
|
Application/Core/Jwt/Manager.php
ADDED
@@ -0,0 +1,356 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
/**
|
4 |
+
* ======================================================================
|
5 |
+
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
+
* file 'license.txt', which is part of this source code package. *
|
7 |
+
* ======================================================================
|
8 |
+
*/
|
9 |
+
|
10 |
+
/**
|
11 |
+
* AAM JWT Manager
|
12 |
+
*
|
13 |
+
* @package AAM
|
14 |
+
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
15 |
+
* @since v5.9.2
|
16 |
+
*/
|
17 |
+
class AAM_Core_Jwt_Manager {
|
18 |
+
|
19 |
+
/**
|
20 |
+
* Single instance of itself
|
21 |
+
*
|
22 |
+
* @var AAM_Core_Jwt_Manager
|
23 |
+
*
|
24 |
+
* @access protected
|
25 |
+
* @static
|
26 |
+
*/
|
27 |
+
protected static $instance = null;
|
28 |
+
|
29 |
+
/**
|
30 |
+
* Constructor
|
31 |
+
*
|
32 |
+
* @return void
|
33 |
+
*
|
34 |
+
* @access protected
|
35 |
+
*/
|
36 |
+
protected function __construct() {
|
37 |
+
//register API endpoint
|
38 |
+
add_action('rest_api_init', array($this, 'registerAPI'));
|
39 |
+
|
40 |
+
//register authentication hook
|
41 |
+
add_filter('determine_current_user', array($this, 'determineUser'), 999);
|
42 |
+
}
|
43 |
+
|
44 |
+
/**
|
45 |
+
* Register APIs
|
46 |
+
*
|
47 |
+
* @return void
|
48 |
+
*
|
49 |
+
* @access public
|
50 |
+
*/
|
51 |
+
public function registerAPI() {
|
52 |
+
// Authenticate user
|
53 |
+
register_rest_route('aam/v1', '/authenticate', array(
|
54 |
+
'methods' => 'POST',
|
55 |
+
'callback' => array($this, 'issueToken'),
|
56 |
+
'args' => array(
|
57 |
+
'username' => array(
|
58 |
+
'description' => __('Valid username.', AAM_KEY),
|
59 |
+
'type' => 'string',
|
60 |
+
),
|
61 |
+
'password' => array(
|
62 |
+
'description' => __('Valid password.', AAM_KEY),
|
63 |
+
'type' => 'string',
|
64 |
+
)
|
65 |
+
),
|
66 |
+
));
|
67 |
+
|
68 |
+
// Validate JWT token
|
69 |
+
register_rest_route('aam/v1', '/validate-jwt', array(
|
70 |
+
'methods' => 'POST',
|
71 |
+
'callback' => array($this, 'validateToken'),
|
72 |
+
'args' => array(
|
73 |
+
'jwt' => array(
|
74 |
+
'description' => __('JWT token.', AAM_KEY),
|
75 |
+
'type' => 'string',
|
76 |
+
)
|
77 |
+
),
|
78 |
+
));
|
79 |
+
}
|
80 |
+
|
81 |
+
/**
|
82 |
+
* Authenticate user
|
83 |
+
*
|
84 |
+
* @param WP_REST_Request $request
|
85 |
+
*
|
86 |
+
* @return WP_REST_Response
|
87 |
+
*
|
88 |
+
* @access public
|
89 |
+
*/
|
90 |
+
public function issueToken(WP_REST_Request $request) {
|
91 |
+
$username = $request->get_param('username');
|
92 |
+
$password = $request->get_param('password');
|
93 |
+
$response = new WP_REST_Response();
|
94 |
+
|
95 |
+
$auth = new AAM_Core_Jwt_Auth();
|
96 |
+
$result = $auth->authenticateWithCredentials($username, $password);
|
97 |
+
|
98 |
+
if (!empty($result->error)) {
|
99 |
+
$response->status = 403;
|
100 |
+
$response->data = new WP_Error(
|
101 |
+
'rest_jwt_auth_failure',
|
102 |
+
strip_tags($result->reason)
|
103 |
+
);
|
104 |
+
} else {
|
105 |
+
$response->status = 200;
|
106 |
+
$response->data = array(
|
107 |
+
'token' => $result->jwt->token,
|
108 |
+
'token_expires' => $result->jwt->claims['exp'],
|
109 |
+
'user' => $result->user
|
110 |
+
);
|
111 |
+
|
112 |
+
// Finally register token so it can be revoked
|
113 |
+
$this->registerToken($result->user->ID, $result->jwt->token);
|
114 |
+
}
|
115 |
+
|
116 |
+
return apply_filters('aam-jwt-response-filter', $response);
|
117 |
+
}
|
118 |
+
|
119 |
+
/**
|
120 |
+
* Validate JWT token
|
121 |
+
*
|
122 |
+
* @param WP_REST_Request $request
|
123 |
+
*
|
124 |
+
* @return WP_REST_Response
|
125 |
+
*
|
126 |
+
* @access public
|
127 |
+
*/
|
128 |
+
public function validateToken(WP_REST_Request $request) {
|
129 |
+
$jwt = $request->get_param('jwt');
|
130 |
+
$issuer = new AAM_Core_Jwt_Issuer();
|
131 |
+
$response = new WP_REST_Response();
|
132 |
+
|
133 |
+
$result = $issuer->validateToken($jwt);
|
134 |
+
|
135 |
+
if ($result->status === 'valid') {
|
136 |
+
$response->status = 200;
|
137 |
+
$response->data = $result;
|
138 |
+
} else {
|
139 |
+
$response->status = 400;
|
140 |
+
$response->data = new WP_Error(
|
141 |
+
'rest_jwt_validation_failure',
|
142 |
+
$result->reason
|
143 |
+
);
|
144 |
+
}
|
145 |
+
|
146 |
+
return $response;
|
147 |
+
}
|
148 |
+
|
149 |
+
/**
|
150 |
+
* Determine current user by JWT
|
151 |
+
*
|
152 |
+
* @param int $userId
|
153 |
+
*
|
154 |
+
* @return int
|
155 |
+
*
|
156 |
+
* @access public
|
157 |
+
*/
|
158 |
+
public function determineUser($userId) {
|
159 |
+
if (empty($userId)) {
|
160 |
+
$token = $this->extractJwt();
|
161 |
+
|
162 |
+
if (!empty($token)) {
|
163 |
+
$issuer = new AAM_Core_Jwt_Issuer();
|
164 |
+
$result = $issuer->validateToken($token->jwt);
|
165 |
+
|
166 |
+
if ($result->status === 'valid') {
|
167 |
+
$userId = $result->userId;
|
168 |
+
$this->possiblyLoginUser($token->method, $result);
|
169 |
+
}
|
170 |
+
}
|
171 |
+
}
|
172 |
+
|
173 |
+
return $userId;
|
174 |
+
}
|
175 |
+
|
176 |
+
/**
|
177 |
+
* Register JWT token to user's registry
|
178 |
+
*
|
179 |
+
* @param int $userId
|
180 |
+
* @param string $token
|
181 |
+
* @param array $args
|
182 |
+
*
|
183 |
+
* @return bool
|
184 |
+
*
|
185 |
+
* @access public
|
186 |
+
*/
|
187 |
+
public function registerToken($userId, $token) {
|
188 |
+
$registry = $this->getTokenRegistry($userId);
|
189 |
+
$limit = AAM_Core_Config::get('authentication.jwt.registryLimit', 10);
|
190 |
+
|
191 |
+
// Make sure that we do not overload the user meta
|
192 |
+
if (count($registry) >= $limit) {
|
193 |
+
$this->revokeToken($userId, array_shift($registry));
|
194 |
+
}
|
195 |
+
|
196 |
+
// Save token
|
197 |
+
return add_user_meta($userId, 'aam-jwt', $token);
|
198 |
+
}
|
199 |
+
|
200 |
+
/**
|
201 |
+
* Revoke JWT token
|
202 |
+
*
|
203 |
+
* @param int $userId
|
204 |
+
* @param string $token
|
205 |
+
*
|
206 |
+
* @return bool
|
207 |
+
*
|
208 |
+
* @access public
|
209 |
+
*/
|
210 |
+
public function revokeToken($userId, $token) {
|
211 |
+
$result = false;
|
212 |
+
$registry = $this->getTokenRegistry($userId);
|
213 |
+
|
214 |
+
if (in_array($token, $registry, true)) {
|
215 |
+
$result = delete_user_meta($userId, 'aam-jwt', $token);
|
216 |
+
}
|
217 |
+
|
218 |
+
return $result;
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Get JWT token registry
|
223 |
+
*
|
224 |
+
* @param int $userId
|
225 |
+
*
|
226 |
+
* @return array
|
227 |
+
*
|
228 |
+
* @access public
|
229 |
+
*/
|
230 |
+
public function getTokenRegistry($userId) {
|
231 |
+
$registry = get_user_meta($userId, 'aam-jwt', false);
|
232 |
+
|
233 |
+
return (!empty($registry) ? $registry : array());
|
234 |
+
}
|
235 |
+
|
236 |
+
/**
|
237 |
+
* Extract JWT token from the request
|
238 |
+
*
|
239 |
+
* Based on the `authentication.jwt.container` setting, parse HTTP request and
|
240 |
+
* try to extract the JWT token
|
241 |
+
*
|
242 |
+
* @return object|null
|
243 |
+
*
|
244 |
+
* @access protected
|
245 |
+
*/
|
246 |
+
protected function extractJwt() {
|
247 |
+
$container = explode(',', AAM_Core_Config::get(
|
248 |
+
'authentication.jwt.container', 'header,post,query,cookie'
|
249 |
+
));
|
250 |
+
|
251 |
+
$jwt = null;
|
252 |
+
|
253 |
+
foreach($container as $method) {
|
254 |
+
switch(strtolower(trim($method))) {
|
255 |
+
case 'header':
|
256 |
+
$jwt = AAM_Core_Request::server('HTTP_AUTHENTICATION');
|
257 |
+
break;
|
258 |
+
|
259 |
+
case 'cookie':
|
260 |
+
$jwt = AAM_Core_Request::cookie('aam-jwt');
|
261 |
+
break;
|
262 |
+
|
263 |
+
case 'query':
|
264 |
+
$jwt = AAM_Core_Request::get('aam-jwt');
|
265 |
+
break;
|
266 |
+
|
267 |
+
case 'post':
|
268 |
+
$jwt = AAM_Core_Request::post('aam-jwt');
|
269 |
+
break;
|
270 |
+
|
271 |
+
default:
|
272 |
+
$jwt = apply_filters('aam-get-jwt-filter', null, $method);
|
273 |
+
break;
|
274 |
+
}
|
275 |
+
|
276 |
+
if (!is_null($jwt)) {
|
277 |
+
break;
|
278 |
+
}
|
279 |
+
}
|
280 |
+
|
281 |
+
if (!empty($jwt)) {
|
282 |
+
$response = (object) array(
|
283 |
+
'jwt' => preg_replace('/^Bearer /', '', $jwt),
|
284 |
+
'method' => $method
|
285 |
+
);
|
286 |
+
} else {
|
287 |
+
$response = null;
|
288 |
+
}
|
289 |
+
|
290 |
+
return $response;
|
291 |
+
}
|
292 |
+
|
293 |
+
/**
|
294 |
+
* Also login user if HTTP request is get and JWT was extracted from query params
|
295 |
+
*
|
296 |
+
* @param string $container
|
297 |
+
* @param object $claims
|
298 |
+
*
|
299 |
+
* @return void
|
300 |
+
*
|
301 |
+
* @access protected
|
302 |
+
*/
|
303 |
+
protected function possiblyLoginUser($container, $claims) {
|
304 |
+
// Also login user if REQUEST_METHOD is GET
|
305 |
+
$method = AAM_Core_Request::server('REQUEST_METHOD');
|
306 |
+
|
307 |
+
if ($container === 'query' && ($method === 'GET')) {
|
308 |
+
$exp = get_user_meta($claims->userId, 'aam_user_expiration', true);
|
309 |
+
|
310 |
+
// Do it only once
|
311 |
+
if (empty($exp)) {
|
312 |
+
wp_set_current_user($claims->userId);
|
313 |
+
wp_set_auth_cookie($claims->userId);
|
314 |
+
|
315 |
+
// TODO: Remove June 2020
|
316 |
+
$exp = (is_numeric($claims->exp) ? date('m/d/Y, H:i O', $claims->exp) : $claims->exp);
|
317 |
+
|
318 |
+
update_user_meta(
|
319 |
+
$claims->userId,
|
320 |
+
'aam_user_expiration',
|
321 |
+
$exp . '|logout|'
|
322 |
+
);
|
323 |
+
do_action('wp_login', '', wp_get_current_user());
|
324 |
+
}
|
325 |
+
}
|
326 |
+
}
|
327 |
+
|
328 |
+
/**
|
329 |
+
* Get single instance of itself
|
330 |
+
*
|
331 |
+
* @return AAM_Core_Jwt_Manager
|
332 |
+
*
|
333 |
+
* @access public
|
334 |
+
* @static
|
335 |
+
*/
|
336 |
+
public static function getInstance() {
|
337 |
+
if (is_null(self::$instance)) {
|
338 |
+
self::$instance = new self;
|
339 |
+
}
|
340 |
+
|
341 |
+
return self::$instance;
|
342 |
+
}
|
343 |
+
|
344 |
+
/**
|
345 |
+
* Bootstrap AAM JWT Manager
|
346 |
+
*
|
347 |
+
* @return AAM_Core_Jwt_Manager
|
348 |
+
*
|
349 |
+
* @access public
|
350 |
+
* @static
|
351 |
+
*/
|
352 |
+
public static function bootstrap() {
|
353 |
+
return self::getInstance();
|
354 |
+
}
|
355 |
+
|
356 |
+
}
|
Application/Core/JwtAuth.php
DELETED
@@ -1,347 +0,0 @@
|
|
1 |
-
<?php
|
2 |
-
|
3 |
-
/**
|
4 |
-
* ======================================================================
|
5 |
-
* LICENSE: This file is subject to the terms and conditions defined in *
|
6 |
-
* file 'license.txt', which is part of this source code package. *
|
7 |
-
* ======================================================================
|
8 |
-
*/
|
9 |
-
|
10 |
-
/**
|
11 |
-
* AAM JWT Authentication
|
12 |
-
*
|
13 |
-
* @package AAM
|
14 |
-
* @author Vasyl Martyniuk <vasyl@vasyltech.com>
|
15 |
-
*/
|
16 |
-
class AAM_Core_JwtAuth {
|
17 |
-
|
18 |
-
/**
|
19 |
-
* Single instance of itself
|
20 |
-
*
|
21 |
-
* @var AAM_Core_JwtAuth
|
22 |
-
*
|
23 |
-
* @access protected
|
24 |
-
* @static
|
25 |
-
*/
|
26 |
-
protected static $instance = null;
|
27 |
-
|
28 |
-
/**
|
29 |
-
* Constructor
|
30 |
-
*
|
31 |
-
* @return void
|
32 |
-
*
|
33 |
-
* @access protected
|
34 |
-
*/
|
35 |
-
protected function __construct() {
|
36 |
-
//register API endpoint
|
37 |
-
add_action('rest_api_init', array($this, 'registerAPI'));
|
38 |
-
|
39 |
-
//register authentication hook
|
40 |
-
add_filter('determine_current_user', array($this, 'determineCurrentUser'), 999);
|
41 |
-
}
|
42 |
-
|
43 |
-
/**
|
44 |
-
* Register APIs
|
45 |
-
*
|
46 |
-
* @return void
|
47 |
-
*
|
48 |
-
* @access public
|
49 |
-
*/
|
50 |
-
public function registerAPI() {
|
51 |
-
// Authenticate user
|
52 |
-
register_rest_route('aam/v1', '/authenticate', array(
|
53 |
-
'methods' => 'POST',
|
54 |
-
'callback' => array($this, 'authenticate'),
|
55 |
-
'args' => array(
|
56 |
-
'username' => array(
|
57 |
-
'description' => __('Valid username.', AAM_KEY),
|
58 |
-
'type' => 'string',
|
59 |
-
),
|
60 |
-
'password' => array(
|
61 |
-
'description' => __('Valid password.', AAM_KEY),
|
62 |
-
'type' => 'string',
|
63 |
-
)
|
64 |
-
),
|
65 |
-
));
|
66 |
-
|
67 |
-
// Validate JWT token
|
68 |
-
register_rest_route('aam/v1', '/validate-jwt', array(
|
69 |
-
'methods' => 'POST',
|
70 |
-
'callback' => array($this, 'validateJWT'),
|
71 |
-
'args' => array(
|
72 |
-
'jwt' => array(
|
73 |
-
'description' => __('JWT token.', AAM_KEY),
|
74 |
-
'type' => 'string',
|
75 |
-
)
|
76 |
-
),
|
77 |
-
));
|
78 |
-
}
|
79 |
-
|
80 |
-
/**
|
81 |
-
* Authenticate user
|
82 |
-
*
|
83 |
-
* @param WP_REST_Request $request
|
84 |
-
*
|
85 |
-
* @return WP_REST_Response
|
86 |
-
*
|
87 |
-
* @access public
|
88 |
-
*/
|
89 |
-
public function authenticate(WP_REST_Request $request) {
|
90 |
-
$username = $request->get_param('username');
|
91 |
-
$password = $request->get_param('password');
|
92 |
-
|
93 |
-
// try to authenticate user
|
94 |
-
$result = AAM_Core_Login::getInstance()->execute(array(
|
95 |
-
'user_login' => $username,
|
96 |
-
'user_password' => $password
|
97 |
-
), false);
|
98 |
-
|
99 |
-
$response = new WP_REST_Response();
|
100 |
-
|
101 |
-
if ($result['status'] === 'success') { // generate token
|
102 |
-
try {
|
103 |
-
$token = $this->issueJWT($result['user']->ID);
|
104 |
-
|
105 |
-
$response->status = 200;
|
106 |
-
$response->data = array(
|
107 |
-
'token' => $token->token,
|
108 |
-
'token_expires' => $token->claims['exp'],
|
109 |
-
'user' => $result['user']
|
110 |
-
);
|
111 |
-
} catch (Exception $ex) {
|
112 |
-
$response->status = 400;
|
113 |
-
$response->data = new WP_Error(
|
114 |
-
'rest_jwt_empty_secret_key',
|
115 |
-
$ex->getMessage()
|
116 |
-
);
|
117 |
-
}
|
118 |
-
} else {
|
119 |
-
$response->data = $result['reason'];
|
120 |
-
$response->status = 403;
|
121 |
-
}
|
122 |
-
|
123 |
-
return apply_filters('aam-jwt-response-filter', $response);
|
124 |
-
}
|
125 |
-
|
126 |
-
/**
|
127 |
-
*
|
128 |
-
* @param WP_REST_Request $request
|
129 |
-
*/
|
130 |
-
public function validateJWT(WP_REST_Request $request) {
|
131 |
-
$jwt = $request->get_param('jwt');
|
132 |
-
$key = AAM_Core_Config::get('authentication.jwt.secret', SECURE_AUTH_KEY);
|
133 |
-
|
134 |
-
$response = new WP_REST_Response(array(
|
135 |
-
'status' => 'invalid'
|
136 |
-
), 400);
|
137 |
-
|
138 |
-
if (!empty($jwt)) {
|
139 |
-
try {
|
140 |
-
$claims = Firebase\JWT\JWT::decode(
|
141 |
-
$jwt, $key, array_keys(Firebase\JWT\JWT::$supported_algs)
|
142 |
-
);
|
143 |
-
|
144 |
-
$response->status = 200;
|
145 |
-
$response->data = array(
|
146 |
-
'status' => 'valid',
|
147 |
-
'token_expires' => $claims->exp
|
148 |
-
);
|
149 |
-
} catch (Exception $ex) {
|
150 |
-
$response->data['reason'] = $ex->getMessage();
|
151 |
-
}
|
152 |
-
}
|
153 |
-
|
154 |
-
return $response;
|
155 |
-
}
|
156 |
-
|
157 |
-
/**
|
158 |
-
* Generate JWT token
|
159 |
-
*
|
160 |
-
* @param int $userId
|
161 |
-
*
|
162 |
-
* @return stdClass
|
163 |
-
*
|
164 |
-
* @access public
|
165 |
-
* @throws Exception
|
166 |
-
*/
|
167 |
-
public function issueJWT($userId, $container = 'header') {
|
168 |
-
$container = explode(
|
169 |
-
',', AAM_Core_Config::get('authentication.jwt.container', $container)
|
170 |
-
);
|
171 |
-
|
172 |
-
$token = $this->generateJWT($userId);
|
173 |
-
|
174 |
-
if (in_array('cookie', $container, true)) {
|
175 |
-
setcookie(
|
176 |
-
'aam-jwt',
|
177 |
-
$token->token,
|
178 |
-
$token->claims['exp'],
|
179 |
-
'/',
|
180 |
-
parse_url(get_bloginfo('url'), PHP_URL_HOST),
|
181 |
-
is_ssl(),
|
182 |
-
AAM_Core_Config::get('authentication.jwt.cookie.httpOnly', false)
|
183 |
-
);
|
184 |
-
}
|
185 |
-
|
186 |
-
return $token;
|
187 |
-
}
|
188 |
-
|
189 |
-
/**
|
190 |
-
* Generate the token
|
191 |
-
*
|
192 |
-
* @param int $userId
|
193 |
-
* @param int $expires
|
194 |
-
*
|
195 |
-
* @return stdObject
|
196 |
-
*
|
197 |
-
* @access public
|
198 |
-
* @throws Exception
|
199 |
-
*/
|
200 |
-
public static function generateJWT($userId, $expires = null) {
|
201 |
-
$key = AAM_Core_Config::get('authentication.jwt.secret', SECURE_AUTH_KEY);
|
202 |
-
$expire = AAM_Core_Config::get('authentication.jwt.expires', $expires);
|
203 |
-
$alg = AAM_Core_Config::get('authentication.jwt.algorithm', 'HS256');
|
204 |
-
|
205 |
-
if (!empty($expire)) {
|
206 |
-
$time = DateTime::createFromFormat('m/d/Y, H:i O', $expires);
|
207 |
-
} else {
|
208 |
-
$time = new DateTime('+24 hours');
|
209 |
-
}
|
210 |
-
|
211 |
-
if ($key) {
|
212 |
-
$claims = apply_filters('aam-jwt-claims-filter', array(
|
213 |
-
"iat" => time(),
|
214 |
-
'exp' => $time->format('U'),
|
215 |
-
'userId' => $userId
|
216 |
-
));
|
217 |
-
|
218 |
-
$token = Firebase\JWT\JWT::encode($claims, $key, $alg);
|
219 |
-
} else {
|
220 |
-
Throw new Exception(
|
221 |
-
__('JWT Authentication is enabled but secret key is not defined', AAM_KEY)
|
222 |
-
);
|
223 |
-
}
|
224 |
-
|
225 |
-
return (object) array(
|
226 |
-
'token' => $token,
|
227 |
-
'claims' => $claims
|
228 |
-
);
|
229 |
-
}
|
230 |
-
|
231 |
-
/**
|
232 |
-
*
|
233 |
-
* @param type $result
|
234 |
-
*/
|
235 |
-
public function determineCurrentUser($result) {
|
236 |
-
$token = $this->extractJwt();
|
237 |
-
$key = AAM_Core_Config::get('authentication.jwt.secret', SECURE_AUTH_KEY);
|
238 |
-
|
239 |
-
if (!empty($token['jwt'])) {
|
240 |
-
try {
|
241 |
-
$claims = Firebase\JWT\JWT::decode(
|
242 |
-
$token['jwt'], $key, array_keys(Firebase\JWT\JWT::$supported_algs)
|
243 |
-
);
|
244 |
-
|
245 |
-
if (isset($claims->userId)) {
|
246 |
-
$result = $claims->userId;
|
247 |
-
|
248 |
-
// Also login user if REQUEST_METHOD is GET
|
249 |
-
if ($token['method'] === 'query'
|
250 |
-
&& AAM_Core_Request::server('REQUEST_METHOD') === 'GET') {
|
251 |
-
wp_set_current_user($claims->userId);
|
252 |
-
wp_set_auth_cookie($claims->userId);
|
253 |
-
|
254 |
-
$exp = get_user_meta($claims->userId, 'aam_user_expiration', true);
|
255 |
-
if (empty($exp)) {
|
256 |
-
update_user_meta(
|
257 |
-
$claims->userId,
|
258 |
-
'aam_user_expiration',
|
259 |
-
date('m/d/Y, H:i O', $claims->exp) . '|logout|'
|
260 |
-
);
|
261 |
-
}
|
262 |
-
|
263 |
-
do_action('wp_login', '', wp_get_current_user());
|
264 |
-
}
|
265 |
-
}
|
266 |
-
} catch (Exception $ex) {
|
267 |
-
// Do nothing
|
268 |
-
}
|
269 |
-
}
|
270 |
-
|
271 |
-
return $result;
|
272 |
-
}
|
273 |
-
|
274 |
-
/**
|
275 |
-
*
|
276 |
-
* @return type
|
277 |
-
*/
|
278 |
-
protected function extractJwt() {
|
279 |
-
$container = explode(',', AAM_Core_Config::get(
|
280 |
-
'authentication.jwt.container', 'header,post,query,cookie'
|
281 |
-
));
|
282 |
-
|
283 |
-
$jwt = null;
|
284 |
-
|
285 |
-
foreach($container as $method) {
|
286 |
-
switch(strtolower(trim($method))) {
|
287 |
-
case 'header':
|
288 |
-
$jwt = AAM_Core_Request::server('HTTP_AUTHENTICATION');
|
289 |
-
break;
|
290 |
-
|
291 |
-
case 'cookie':
|
292 |
-
$jwt = AAM_Core_Request::cookie('aam-jwt');
|
293 |
-
break;
|
294 |
-
|
295 |
-
case 'query':
|
296 |
-
$jwt = AAM_Core_Request::get('aam-jwt');
|
297 |
-
break;
|
298 |
-
|
299 |
-
case 'post':
|
300 |
-
$jwt = AAM_Core_Request::post('aam-jwt');
|
301 |
-
break;
|
302 |
-
|
303 |
-
default:
|
304 |
-
$jwt = apply_filters('aam-get-jwt-filter', null, $method);
|
305 |
-
break;
|
306 |
-
}
|
307 |
-
|
308 |
-
if (!is_null($jwt)) {
|
309 |
-
break;
|
310 |
-
}
|
311 |
-
}
|
312 |
-
|
313 |
-
return array(
|
314 |
-
'jwt' => preg_replace('/^Bearer /', '', $jwt),
|
315 |
-
'method' => $method
|
316 |
-
);
|
317 |
-
}
|
318 |
-
|
319 |
-
/**
|
320 |
-
* Get single instance of itself
|
321 |
-
*
|
322 |
-
* @return AAM_Core_JwtAuth
|
323 |
-
*
|
324 |
-
* @access public
|
325 |
-
* @static
|
326 |
-
*/
|
327 |
-
public static function getInstance() {
|
328 |
-
if (is_null(self::$instance)) {
|
329 |
-
self::$instance = new self;
|
330 |
-
}
|
331 |
-
|
332 |
-
return self::$instance;
|
333 |
-
}
|
334 |
-
|
335 |
-
/**
|
336 |
-
* Bootstrap AAM JWT Authentication feature
|
337 |
-
*
|
338 |
-
* @return AAM_Core_JwtAuth
|
339 |
-
*
|
340 |
-
* @access public
|
341 |
-
* @static
|
342 |
-
*/
|
343 |
-
public static function bootstrap() {
|
344 |
-
return self::getInstance();
|
345 |
-
}
|
346 |
-
|
347 |
-
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Application/Core/Login.php
CHANGED
@@ -92,7 +92,17 @@ class AAM_Core_Login {
|
|
92 |
}
|
93 |
|
94 |
if (AAM::api()->getConfig('core.settings.setJwtCookieAfterLogin', false)) {
|
95 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
96 |
}
|
97 |
|
98 |
if ($this->aamLogin === false) {
|
@@ -252,8 +262,14 @@ class AAM_Core_Login {
|
|
252 |
}
|
253 |
|
254 |
if ($attempts >= AAM_Core_Config::get('security.login.attempts', 20)) {
|
255 |
-
|
256 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
257 |
} else {
|
258 |
set_transient('aam_login_attempts', $attempts, $timeout);
|
259 |
}
|
@@ -270,7 +286,7 @@ class AAM_Core_Login {
|
|
270 |
$this->aamLogin = true;
|
271 |
|
272 |
if ($set_cookie === false) {
|
273 |
-
add_filter('send_auth_cookies',
|
274 |
}
|
275 |
|
276 |
$response = array(
|
92 |
}
|
93 |
|
94 |
if (AAM::api()->getConfig('core.settings.setJwtCookieAfterLogin', false)) {
|
95 |
+
$issuer = new AAM_Core_Jwt_Issuer();
|
96 |
+
$token = $issuer->issueToken(array('userId' => $user->ID));
|
97 |
+
setcookie(
|
98 |
+
'aam-jwt',
|
99 |
+
$token->token,
|
100 |
+
$token->claims['exp'],
|
101 |
+
'/',
|
102 |
+
parse_url(get_bloginfo('url'), PHP_URL_HOST),
|
103 |
+
is_ssl(),
|
104 |
+
AAM_Core_Config::get('authentication.jwt.cookie.httpOnly', false)
|
105 |
+
);
|
106 |
}
|
107 |
|
108 |
if ($this->aamLogin === false) {
|
262 |
}
|
263 |
|
264 |
if ($attempts >= AAM_Core_Config::get('security.login.attempts', 20)) {
|
265 |
+
if (AAM_Core_Api_Area::isAPI()) {
|
266 |
+
throw new Exception(
|
267 |
+
'Exceeded maximum number for authentication attempts. Please try later again.'
|
268 |
+
);
|
269 |
+
} else {
|
270 |
+
wp_safe_redirect(site_url('index.php'));
|
271 |
+
exit;
|
272 |
+
}
|
273 |
} else {
|
274 |
set_transient('aam_login_attempts', $attempts, $timeout);
|
275 |
}
|
286 |
$this->aamLogin = true;
|
287 |
|
288 |
if ($set_cookie === false) {
|
289 |
+
add_filter('send_auth_cookies', '__return_false');
|
290 |
}
|
291 |
|
292 |
$response = array(
|
Application/Core/Object/Post.php
CHANGED
@@ -105,9 +105,14 @@ class AAM_Core_Object_Post extends AAM_Core_Object {
|
|
105 |
// TODO: Prepare better conversion from policy Action to AAM
|
106 |
// post & term action. For example listToOthers -> list_others
|
107 |
$chunks = explode(':', $key);
|
108 |
-
|
109 |
-
$option
|
110 |
-
|
|
|
|
|
|
|
|
|
|
|
111 |
}
|
112 |
}
|
113 |
|
105 |
// TODO: Prepare better conversion from policy Action to AAM
|
106 |
// post & term action. For example listToOthers -> list_others
|
107 |
$chunks = explode(':', $key);
|
108 |
+
|
109 |
+
$option = array_merge(
|
110 |
+
$option,
|
111 |
+
AAM_Core_Compatibility::convertPolicyAction(
|
112 |
+
(isset($chunks[3]) ? $chunks[3] : 'read'),
|
113 |
+
$stm['Effect'] === 'deny'
|
114 |
+
)
|
115 |
+
);
|
116 |
}
|
117 |
}
|
118 |
|
Application/Core/Object/Route.php
CHANGED
@@ -34,14 +34,15 @@ class AAM_Core_Object_Route extends AAM_Core_Object {
|
|
34 |
if (!empty($option)) {
|
35 |
$this->setOverwritten(true);
|
36 |
}
|
37 |
-
|
38 |
// Load settings from Access & Security Policy
|
39 |
if (empty($option)) {
|
40 |
$stms = AAM_Core_Policy_Factory::get($subject)->find("/^Route:/i");
|
41 |
-
|
42 |
foreach($stms as $key => $stm) {
|
43 |
$chunks = explode(':', $key);
|
44 |
-
$
|
|
|
45 |
|
46 |
$option[$id] = ($stm['Effect'] === 'deny' ? 1 : 0);
|
47 |
}
|
@@ -68,7 +69,7 @@ class AAM_Core_Object_Route extends AAM_Core_Object {
|
|
68 |
public function has($type, $route, $method = 'POST') {
|
69 |
$options = $this->getOption();
|
70 |
$id = strtolower("{$type}|{$route}|{$method}");
|
71 |
-
|
72 |
return !empty($options[$id]);
|
73 |
}
|
74 |
|
34 |
if (!empty($option)) {
|
35 |
$this->setOverwritten(true);
|
36 |
}
|
37 |
+
|
38 |
// Load settings from Access & Security Policy
|
39 |
if (empty($option)) {
|
40 |
$stms = AAM_Core_Policy_Factory::get($subject)->find("/^Route:/i");
|
41 |
+
|
42 |
foreach($stms as $key => $stm) {
|
43 |
$chunks = explode(':', $key);
|
44 |
+
$method = (isset($chunks[3]) ? $chunks[3] : 'post');
|
45 |
+
$id = "{$chunks[1]}|{$chunks[2]}|{$method}";
|
46 |
|
47 |
$option[$id] = ($stm['Effect'] === 'deny' ? 1 : 0);
|
48 |
}
|
69 |
public function has($type, $route, $method = 'POST') {
|
70 |
$options = $this->getOption();
|
71 |
$id = strtolower("{$type}|{$route}|{$method}");
|
72 |
+
|
73 |
return !empty($options[$id]);
|
74 |
}
|
75 |
|
Application/Core/Policy/Condition.php
CHANGED
@@ -70,18 +70,27 @@ final class AAM_Core_Policy_Condition {
|
|
70 |
*/
|
71 |
public function evaluate($conditions, $args = array()) {
|
72 |
$result = true;
|
73 |
-
|
74 |
foreach($conditions as $type => $conditions) {
|
75 |
$type = strtolower($type);
|
76 |
|
77 |
if (isset($this->map[$type])) {
|
78 |
$callback = array($this, $this->map[$type]);
|
79 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
80 |
} else {
|
81 |
$result = false;
|
82 |
}
|
83 |
}
|
84 |
-
|
85 |
return $result;
|
86 |
}
|
87 |
|
@@ -99,10 +108,17 @@ final class AAM_Core_Policy_Condition {
|
|
99 |
$result = false;
|
100 |
|
101 |
foreach($this->prepareConditions($conditions, $args) as $condition) {
|
102 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
103 |
$min = (is_array($subset) ? array_shift($subset) : $subset);
|
104 |
$max = (is_array($subset) ? end($subset) : $subset);
|
105 |
-
|
106 |
$result = $result || ($condition['left'] >= $min && $condition['left'] <= $max);
|
107 |
}
|
108 |
}
|
70 |
*/
|
71 |
public function evaluate($conditions, $args = array()) {
|
72 |
$result = true;
|
73 |
+
|
74 |
foreach($conditions as $type => $conditions) {
|
75 |
$type = strtolower($type);
|
76 |
|
77 |
if (isset($this->map[$type])) {
|
78 |
$callback = array($this, $this->map[$type]);
|
79 |
+
|
80 |
+
// Since v5.9.2 - if specific condition type is array, then combine
|
81 |
+
// them with AND operation
|
82 |
+
if (isset($conditions[0]) && is_array($conditions[0])) {
|
83 |
+
foreach($conditions as $set) {
|
84 |
+
$result = $result && call_user_func($callback, $set, $args);
|
85 |
+
}
|
86 |
+
} else {
|
87 |
+
$result = $result && call_user_func($callback, $conditions, $args);
|
88 |
+
}
|
89 |
} else {
|
90 |
$result = false;
|
91 |
}
|
92 |
}
|
93 |
+
|
94 |
return $result;
|
95 |
}
|
96 |
|
108 |
$result = false;
|
109 |
|
110 |
foreach($this->prepareConditions($conditions, $args) as $condition) {
|
111 |
+
// Convert the right condition into the array of array to cover more
|
112 |
+
// complex between conditions like [[0,8],[13,15]]
|
113 |
+
if (is_array($condition['right'][0])) {
|
114 |
+
$right = $condition['right'];
|
115 |
+
} else {
|
116 |
+
$right = array($condition['right']);
|
117 |
+
}
|
118 |
+
foreach($right as $subset) {
|
119 |
$min = (is_array($subset) ? array_shift($subset) : $subset);
|
120 |
$max = (is_array($subset) ? end($subset) : $subset);
|
121 |
+
|
122 |
$result = $result || ($condition['left'] >= $min && $condition['left'] <= $max);
|
123 |
}
|
124 |
}
|
Application/Core/Policy/Token.php
CHANGED
@@ -105,10 +105,12 @@ final class AAM_Core_Policy_Token {
|
|
105 |
break;
|
106 |
|
107 |
case 'authenticated':
|
|
|
108 |
$value = $user->isVisitor() ? false : true;
|
109 |
break;
|
110 |
|
111 |
case 'capabilities':
|
|
|
112 |
$value = array();
|
113 |
foreach($user->allcaps as $cap => $effect) {
|
114 |
if (!empty($effect)) {
|
105 |
break;
|
106 |
|
107 |
case 'authenticated':
|
108 |
+
case 'isauthenticated':
|
109 |
$value = $user->isVisitor() ? false : true;
|
110 |
break;
|
111 |
|
112 |
case 'capabilities':
|
113 |
+
case 'caps':
|
114 |
$value = array();
|
115 |
foreach($user->allcaps as $cap => $effect) {
|
116 |
if (!empty($effect)) {
|
Application/Core/Subject/User.php
CHANGED
@@ -19,6 +19,11 @@ class AAM_Core_Subject_User extends AAM_Core_Subject {
|
|
19 |
* Subject UID: USER
|
20 |
*/
|
21 |
const UID = 'user';
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
/**
|
24 |
* AAM Capability Key
|
@@ -55,6 +60,15 @@ class AAM_Core_Subject_User extends AAM_Core_Subject {
|
|
55 |
* @access protected
|
56 |
*/
|
57 |
protected $maxLevel = null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
58 |
|
59 |
/**
|
60 |
* Constructor
|
@@ -176,20 +190,103 @@ class AAM_Core_Subject_User extends AAM_Core_Subject {
|
|
176 |
}
|
177 |
|
178 |
/**
|
|
|
|
|
|
|
179 |
*
|
|
|
180 |
*/
|
181 |
-
public function
|
182 |
-
|
183 |
-
|
184 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
185 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
186 |
|
187 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
188 |
$expired = get_user_meta($this->ID, 'aam_user_expiration', true);
|
189 |
if (!empty($expired)) {
|
190 |
$parts = explode('|', $expired);
|
191 |
|
192 |
-
// Set time
|
193 |
// TODO: Remove in Jan 2020
|
194 |
if (preg_match('/^[\d]{4}-/', $parts[0])) {
|
195 |
$expires = DateTime::createFromFormat('Y-m-d H:i:s', $parts[0]);
|
@@ -197,27 +294,67 @@ class AAM_Core_Subject_User extends AAM_Core_Subject {
|
|
197 |
$expires = DateTime::createFromFormat('m/d/Y, H:i O', $parts[0]);
|
198 |
}
|
199 |
|
200 |
-
|
201 |
-
|
202 |
-
|
203 |
-
|
204 |
-
|
205 |
-
$
|
|
|
|
|
|
|
|
|
|
|
|
|
206 |
}
|
207 |
}
|
208 |
|
209 |
-
|
210 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
211 |
if ($roleExpire && ($roleExpire <= time())) {
|
212 |
-
$
|
213 |
-
|
|
|
|
|
|
|
|
|
|
|
214 |
|
215 |
-
|
216 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
217 |
if (AAM::api()->getConfig('core.session.tracking', false)) {
|
218 |
$ttl = AAM::api()->getConfig(
|
219 |
-
|
220 |
-
|
221 |
);
|
222 |
|
223 |
if (!empty($ttl)) {
|
@@ -227,51 +364,14 @@ class AAM_Core_Subject_User extends AAM_Core_Subject {
|
|
227 |
|
228 |
if ($timestamp && ($timestamp + intval($ttl) <= time())) {
|
229 |
delete_user_meta($this->ID, 'aam-authenticated-timestamp');
|
230 |
-
|
231 |
}
|
232 |
}
|
233 |
}
|
234 |
-
}
|
235 |
-
|
236 |
-
/**
|
237 |
-
* Expire user
|
238 |
-
*
|
239 |
-
* @param array $config
|
240 |
-
*
|
241 |
-
* @return void
|
242 |
-
*
|
243 |
-
* @access
|
244 |
-
*/
|
245 |
-
public function triggerExpiredUserAction($config) {
|
246 |
-
switch($config[1]) {
|
247 |
-
case 'lock':
|
248 |
-
$this->block();
|
249 |
-
break;
|
250 |
-
|
251 |
-
case 'logout':
|
252 |
-
wp_logout();
|
253 |
-
break;
|
254 |
-
|
255 |
-
case 'change-role':
|
256 |
-
if (AAM_Core_API::getRoles()->is_role($config[2])) {
|
257 |
-
$this->getSubject()->set_role($config[2]);
|
258 |
-
delete_user_option($this->getSubject()->ID, 'aam_user_expiration');
|
259 |
-
}
|
260 |
-
break;
|
261 |
-
|
262 |
-
case 'delete':
|
263 |
-
require_once(ABSPATH . 'wp-admin/includes/user.php' );
|
264 |
-
wp_delete_user(
|
265 |
-
$this->getId(), AAM_Core_Config::get('core.reasign.ownership.user')
|
266 |
-
);
|
267 |
-
wp_logout();
|
268 |
-
break;
|
269 |
|
270 |
-
|
271 |
-
break;
|
272 |
-
}
|
273 |
}
|
274 |
-
|
275 |
/**
|
276 |
* Block User
|
277 |
*
|
@@ -298,27 +398,6 @@ class AAM_Core_Subject_User extends AAM_Core_Subject {
|
|
298 |
return $result;
|
299 |
}
|
300 |
|
301 |
-
/**
|
302 |
-
*
|
303 |
-
*/
|
304 |
-
public function restoreRoles() {
|
305 |
-
$roles = get_user_option('aam-original-roles');
|
306 |
-
|
307 |
-
//remove curren roles
|
308 |
-
foreach((array) $this->roles as $role) {
|
309 |
-
$this->remove_role($role);
|
310 |
-
}
|
311 |
-
|
312 |
-
//add original roles
|
313 |
-
foreach(($roles ? $roles : array('subscriber')) as $role) {
|
314 |
-
$this->add_role($role);
|
315 |
-
}
|
316 |
-
|
317 |
-
//delete options
|
318 |
-
delete_user_option($this->getId(), 'aam-role-expires');
|
319 |
-
delete_user_option($this->getId(), 'aam-original-roles');
|
320 |
-
}
|
321 |
-
|
322 |
/**
|
323 |
* Retrieve User based on ID
|
324 |
*
|
19 |
* Subject UID: USER
|
20 |
*/
|
21 |
const UID = 'user';
|
22 |
+
|
23 |
+
/**
|
24 |
+
* User status is BLOCKED
|
25 |
+
*/
|
26 |
+
const STATUS_BLOCKED = 1;
|
27 |
|
28 |
/**
|
29 |
* AAM Capability Key
|
60 |
* @access protected
|
61 |
*/
|
62 |
protected $maxLevel = null;
|
63 |
+
|
64 |
+
/**
|
65 |
+
* Current user status
|
66 |
+
*
|
67 |
+
* @var array
|
68 |
+
*
|
69 |
+
* @access protected
|
70 |
+
*/
|
71 |
+
protected $status = null;
|
72 |
|
73 |
/**
|
74 |
* Constructor
|
190 |
}
|
191 |
|
192 |
/**
|
193 |
+
* Get current user's status
|
194 |
+
*
|
195 |
+
* @return array
|
196 |
*
|
197 |
+
* @access public
|
198 |
*/
|
199 |
+
public function getUserStatus() {
|
200 |
+
if (is_null($this->status)) {
|
201 |
+
$this->status = array('status' => 'active');
|
202 |
+
$steps = array(
|
203 |
+
'UserRecordStatus', // Check if user's record states that it is blocked
|
204 |
+
'UserExpiration', // Check if user's account is expired
|
205 |
+
'RoleExpiration', // Legacy: Check if user's role is expired
|
206 |
+
'UserTtl' // Check if user's session ttl is expired
|
207 |
+
);
|
208 |
+
|
209 |
+
foreach($steps as $step) {
|
210 |
+
$result = call_user_func(array($this, "check{$step}"));
|
211 |
+
if ($result !== true) {
|
212 |
+
$this->status = $result;
|
213 |
+
break;
|
214 |
+
}
|
215 |
+
}
|
216 |
}
|
217 |
+
|
218 |
+
return $this->status;
|
219 |
+
}
|
220 |
+
|
221 |
+
/**
|
222 |
+
* Restrain user account based on status
|
223 |
+
*
|
224 |
+
* @param array $status
|
225 |
+
*
|
226 |
+
* @return void
|
227 |
+
* @see AAM_Core_Subject_User::getUserStatus
|
228 |
+
*
|
229 |
+
* @access public
|
230 |
+
*/
|
231 |
+
public function restrainUserAccount(array $status) {
|
232 |
+
switch($status['action']) {
|
233 |
+
case 'lock':
|
234 |
+
$this->block();
|
235 |
+
break;
|
236 |
|
237 |
+
case 'change-role':
|
238 |
+
$this->getSubject()->set_role(''); // First reset all roles
|
239 |
+
foreach((array)$status['meta'] as $role) {
|
240 |
+
$this->getSubject()->add_role($role);
|
241 |
+
}
|
242 |
+
break;
|
243 |
+
|
244 |
+
case 'delete':
|
245 |
+
require_once(ABSPATH . 'wp-admin/includes/user.php' );
|
246 |
+
$reasign = AAM_Core_Config::get('core.reasign.ownership.user');
|
247 |
+
wp_delete_user($this->getId(), $reasign);
|
248 |
+
// Finally logout user
|
249 |
+
|
250 |
+
default:
|
251 |
+
wp_logout();
|
252 |
+
break;
|
253 |
+
}
|
254 |
+
|
255 |
+
// Delete `aam_user_expiration`
|
256 |
+
delete_user_meta($this->getId(), 'aam_user_expiration');
|
257 |
+
}
|
258 |
+
|
259 |
+
/**
|
260 |
+
* Check if user status is blocked
|
261 |
+
*
|
262 |
+
* @return array|bool
|
263 |
+
*
|
264 |
+
* @access protected
|
265 |
+
*/
|
266 |
+
protected function checkUserRecordStatus() {
|
267 |
+
if (intval($this->user_status) === self::STATUS_BLOCKED) {
|
268 |
+
$status = array('status' => 'inactive', 'action' => 'logout');
|
269 |
+
} else {
|
270 |
+
$status = true;
|
271 |
+
}
|
272 |
+
|
273 |
+
return $status;
|
274 |
+
}
|
275 |
+
|
276 |
+
/**
|
277 |
+
* Check if user account is expired
|
278 |
+
*
|
279 |
+
* @return array|bool
|
280 |
+
*
|
281 |
+
* @access protected
|
282 |
+
*/
|
283 |
+
protected function checkUserExpiration() {
|
284 |
+
$status = true;
|
285 |
+
|
286 |
$expired = get_user_meta($this->ID, 'aam_user_expiration', true);
|
287 |
if (!empty($expired)) {
|
288 |
$parts = explode('|', $expired);
|
289 |
|
|
|
290 |
// TODO: Remove in Jan 2020
|
291 |
if (preg_match('/^[\d]{4}-/', $parts[0])) {
|
292 |
$expires = DateTime::createFromFormat('Y-m-d H:i:s', $parts[0]);
|
294 |
$expires = DateTime::createFromFormat('m/d/Y, H:i O', $parts[0]);
|
295 |
}
|
296 |
|
297 |
+
if ($expires) {
|
298 |
+
$compare = new DateTime();
|
299 |
+
//TODO - PHP Warning: DateTime::setTimezone(): Can only do this for zones with ID for now in
|
300 |
+
@$compare->setTimezone($expires->getTimezone());
|
301 |
+
|
302 |
+
if ($expires->getTimestamp() <= $compare->getTimestamp()) {
|
303 |
+
$status = array(
|
304 |
+
'status' => 'inactive',
|
305 |
+
'action' => $parts[1],
|
306 |
+
'meta' => (isset($parts[2]) ? $parts[2] : null)
|
307 |
+
);
|
308 |
+
}
|
309 |
}
|
310 |
}
|
311 |
|
312 |
+
return $status;
|
313 |
+
}
|
314 |
+
|
315 |
+
/**
|
316 |
+
* Check if role is expired
|
317 |
+
*
|
318 |
+
* @return array|bool
|
319 |
+
*
|
320 |
+
* @access protected
|
321 |
+
* @todo Remove in April 2020
|
322 |
+
*/
|
323 |
+
protected function checkRoleExpiration() {
|
324 |
+
$status = true;
|
325 |
+
|
326 |
+
$roleExpire = get_user_option('aam-role-expires', $this->getId());
|
327 |
if ($roleExpire && ($roleExpire <= time())) {
|
328 |
+
$roles = get_user_option('aam-original-roles');
|
329 |
+
|
330 |
+
$status = array(
|
331 |
+
'status' => 'inactive',
|
332 |
+
'action' => 'change-role',
|
333 |
+
'meta' => ($roles ? $roles : 'subscriber')
|
334 |
+
);
|
335 |
|
336 |
+
//delete options
|
337 |
+
delete_user_option($this->getId(), 'aam-role-expires');
|
338 |
+
delete_user_option($this->getId(), 'aam-original-roles');
|
339 |
+
}
|
340 |
+
|
341 |
+
return $status;
|
342 |
+
}
|
343 |
+
|
344 |
+
/**
|
345 |
+
* Check user TTL
|
346 |
+
*
|
347 |
+
* @return array|bool
|
348 |
+
*
|
349 |
+
* @access protected
|
350 |
+
*/
|
351 |
+
protected function checkUserTtl() {
|
352 |
+
$status = true;
|
353 |
+
|
354 |
if (AAM::api()->getConfig('core.session.tracking', false)) {
|
355 |
$ttl = AAM::api()->getConfig(
|
356 |
+
"core.session.user.{$this->ID}.ttl",
|
357 |
+
AAM::api()->getConfig("core.session.user.ttl", null)
|
358 |
);
|
359 |
|
360 |
if (!empty($ttl)) {
|
364 |
|
365 |
if ($timestamp && ($timestamp + intval($ttl) <= time())) {
|
366 |
delete_user_meta($this->ID, 'aam-authenticated-timestamp');
|
367 |
+
$status = array('status' => 'inactive', 'action' => 'logout');
|
368 |
}
|
369 |
}
|
370 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
371 |
|
372 |
+
return $status;
|
|
|
|
|
373 |
}
|
374 |
+
|
375 |
/**
|
376 |
* Block User
|
377 |
*
|
398 |
return $result;
|
399 |
}
|
400 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
401 |
/**
|
402 |
* Retrieve User based on ID
|
403 |
*
|
Application/Shared/Manager.php
CHANGED
@@ -89,6 +89,9 @@ class AAM_Shared_Manager {
|
|
89 |
);
|
90 |
}
|
91 |
}
|
|
|
|
|
|
|
92 |
|
93 |
// Check if user has ability to perform certain task based on provided
|
94 |
// capability and meta data
|
@@ -110,6 +113,26 @@ class AAM_Shared_Manager {
|
|
110 |
|
111 |
return self::$_instance;
|
112 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
|
114 |
/**
|
115 |
*
|
@@ -180,13 +203,6 @@ class AAM_Shared_Manager {
|
|
180 |
public function userRoleAdded($userId, $role) {
|
181 |
$user = new AAM_Core_Subject_User($userId);
|
182 |
AAM_Core_API::clearCache($user);
|
183 |
-
|
184 |
-
$expire = AAM_Core_API::getOption("aam-role-{$role}-expiration", '');
|
185 |
-
|
186 |
-
if ($expire) {
|
187 |
-
update_user_option($userId, "aam-original-roles", $user->roles);
|
188 |
-
update_user_option($userId, "aam-role-expires", strtotime($expire));
|
189 |
-
}
|
190 |
}
|
191 |
|
192 |
/**
|
@@ -197,12 +213,6 @@ class AAM_Shared_Manager {
|
|
197 |
public function userRoleRemoved($userId, $role) {
|
198 |
$user = new AAM_Core_Subject_User($userId);
|
199 |
AAM_Core_API::clearCache($user);
|
200 |
-
|
201 |
-
$expire = AAM_Core_API::getOption("aam-role-{$role}-expiration", '');
|
202 |
-
|
203 |
-
if ($expire) {
|
204 |
-
delete_user_option($userId, "aam-role-expires");
|
205 |
-
}
|
206 |
}
|
207 |
|
208 |
/**
|
@@ -252,7 +262,6 @@ class AAM_Shared_Manager {
|
|
252 |
*/
|
253 |
public function authorizeXMLRPCRequest($method) {
|
254 |
$object = AAM::api()->getUser(get_current_user_id())->getObject('route');
|
255 |
-
|
256 |
if ($object->has('xmlrpc', $method)) {
|
257 |
AAM_Core_API::getXMLRPCServer()->error(
|
258 |
401,
|
@@ -443,103 +452,137 @@ class AAM_Shared_Manager {
|
|
443 |
* @access public
|
444 |
*/
|
445 |
public function mapMetaCaps($caps, $cap, $user_id, $args) {
|
446 |
-
global $post;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
447 |
|
448 |
switch($cap) {
|
449 |
case 'edit_user':
|
450 |
case 'delete_user':
|
451 |
-
|
452 |
-
|
|
|
|
|
|
|
453 |
}
|
454 |
break;
|
455 |
|
456 |
case 'install_plugins':
|
457 |
-
$caps = $this->checkPluginsAction('install', $caps, $cap);
|
458 |
-
break;
|
459 |
-
|
460 |
case 'delete_plugins':
|
461 |
-
$caps = $this->checkPluginsAction('delete', $caps, $cap);
|
462 |
-
break;
|
463 |
-
|
464 |
case 'edit_plugins':
|
465 |
-
$caps = $this->checkPluginsAction('edit', $caps, $cap);
|
466 |
-
break;
|
467 |
-
|
468 |
case 'update_plugins':
|
469 |
-
$
|
470 |
-
|
471 |
-
|
472 |
-
case 'activate_plugin':
|
473 |
-
$caps = $this->checkPluginAction(
|
474 |
-
(isset($args[0]) ? $args[0] : ''), 'activate', $caps, $cap
|
475 |
-
);
|
476 |
break;
|
477 |
|
|
|
478 |
case 'deactivate_plugin':
|
479 |
-
$
|
480 |
-
|
481 |
-
);
|
482 |
break;
|
483 |
-
|
484 |
-
default:
|
485 |
-
//potentially post type cap
|
486 |
-
$caps = $this->checkPostPermission(
|
487 |
-
$caps, $cap, (isset($args[0]) ? $args[0] : null)
|
488 |
-
);
|
489 |
-
break;
|
490 |
-
}
|
491 |
-
|
492 |
-
return $caps;
|
493 |
-
}
|
494 |
|
495 |
-
|
496 |
-
|
497 |
-
*
|
498 |
-
* @param [type] $caps
|
499 |
-
* @param [type] $cap
|
500 |
-
* @param [type] $id
|
501 |
-
*
|
502 |
-
* @return array
|
503 |
-
*
|
504 |
-
* @access protected
|
505 |
-
*/
|
506 |
-
protected function checkPostPermission($caps, $cap, $id = null) {
|
507 |
-
global $post;
|
508 |
-
|
509 |
-
$postId = (empty($id) && is_a($post, 'WP_Post') ? $post->ID : $id);
|
510 |
-
switch($cap) {
|
511 |
case 'edit_post':
|
512 |
-
|
513 |
-
$caps = $this->authorizePostEdit($caps, $postId);
|
514 |
break;
|
515 |
|
516 |
case 'delete_post':
|
517 |
-
|
518 |
-
$caps = $this->authorizePostDelete($caps, $postId);
|
519 |
break;
|
520 |
|
521 |
case 'read_post':
|
522 |
-
|
523 |
-
case 'aam_read_policy':
|
524 |
-
$caps = $this->authorizePostRead($caps, $postId);
|
525 |
break;
|
526 |
|
527 |
|
528 |
case 'publish_post':
|
529 |
case 'publish_posts':
|
530 |
case 'publish_pages':
|
531 |
-
case 'aam_publish_policies':
|
532 |
// There is a bug in WP core that instead of checking if user has
|
533 |
// ability to publish_post, it checks for edit_post. That is why
|
534 |
// user has to be on the edit
|
535 |
if (is_a($post, 'WP_Post')) {
|
536 |
-
$caps = $this->authorizePublishPost($caps, $
|
537 |
}
|
538 |
break;
|
539 |
-
|
540 |
default:
|
|
|
|
|
|
|
|
|
|
|
541 |
break;
|
542 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
543 |
|
544 |
return $caps;
|
545 |
}
|
@@ -655,7 +698,7 @@ class AAM_Shared_Manager {
|
|
655 |
* @access protected
|
656 |
*/
|
657 |
protected function authorizeUserUpdate($caps, $userId) {
|
658 |
-
$user =
|
659 |
|
660 |
//current user max level
|
661 |
$maxLevel = AAM::getUser()->getMaxLevel();
|
89 |
);
|
90 |
}
|
91 |
}
|
92 |
+
|
93 |
+
// Working with post types
|
94 |
+
add_action('registered_post_type', array(self::$_instance, 'registerPostType'), 999, 2);
|
95 |
|
96 |
// Check if user has ability to perform certain task based on provided
|
97 |
// capability and meta data
|
113 |
|
114 |
return self::$_instance;
|
115 |
}
|
116 |
+
|
117 |
+
/**
|
118 |
+
* Hook into post type registration process
|
119 |
+
*
|
120 |
+
* @param string $type
|
121 |
+
* @param WP_Post_Type $object
|
122 |
+
*
|
123 |
+
* @return void
|
124 |
+
*
|
125 |
+
* @access public
|
126 |
+
*/
|
127 |
+
public function registerPostType($type, $object) {
|
128 |
+
if (is_a($object, 'WP_Post_Type')) { // Work only with WP 4.6.0 or higher
|
129 |
+
foreach($object->cap as $type => $capability) {
|
130 |
+
if (in_array($type, array('edit_post', 'delete_post', 'read_post'), true)) {
|
131 |
+
$object->cap->{$type} = "aam-{$type}-{$capability}";
|
132 |
+
}
|
133 |
+
}
|
134 |
+
}
|
135 |
+
}
|
136 |
|
137 |
/**
|
138 |
*
|
203 |
public function userRoleAdded($userId, $role) {
|
204 |
$user = new AAM_Core_Subject_User($userId);
|
205 |
AAM_Core_API::clearCache($user);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
206 |
}
|
207 |
|
208 |
/**
|
213 |
public function userRoleRemoved($userId, $role) {
|
214 |
$user = new AAM_Core_Subject_User($userId);
|
215 |
AAM_Core_API::clearCache($user);
|
|
|
|
|
|
|
|
|
|
|
|
|
216 |
}
|
217 |
|
218 |
/**
|
262 |
*/
|
263 |
public function authorizeXMLRPCRequest($method) {
|
264 |
$object = AAM::api()->getUser(get_current_user_id())->getObject('route');
|
|
|
265 |
if ($object->has('xmlrpc', $method)) {
|
266 |
AAM_Core_API::getXMLRPCServer()->error(
|
267 |
401,
|
452 |
* @access public
|
453 |
*/
|
454 |
public function mapMetaCaps($caps, $cap, $user_id, $args) {
|
455 |
+
global $post;
|
456 |
+
|
457 |
+
$objectId = (isset($args[0]) ? $args[0] : null);
|
458 |
+
|
459 |
+
// First of all delete all artificial capability from the $caps
|
460 |
+
foreach($caps as $i => $capability) {
|
461 |
+
if (strpos($capability, 'aam-') === 0) {
|
462 |
+
$parts = explode('-', $capability);
|
463 |
+
$capability = $parts[2];
|
464 |
+
}
|
465 |
+
|
466 |
+
if (in_array($capability, AAM_Backend_Feature_Main_Capability::$groups['aam'], true)) {
|
467 |
+
if (!AAM_Core_API::capabilityExists($capability)) {
|
468 |
+
$capability = AAM_Core_Config::get(
|
469 |
+
'page.capability', 'administrator'
|
470 |
+
);
|
471 |
+
}
|
472 |
+
}
|
473 |
+
|
474 |
+
$caps[$i] = $capability;
|
475 |
+
}
|
476 |
|
477 |
switch($cap) {
|
478 |
case 'edit_user':
|
479 |
case 'delete_user':
|
480 |
+
// Some plugins or themes simply do not provide the the user ID for
|
481 |
+
// these capabilities. I did not find in WP core any place were they
|
482 |
+
// violate this rule
|
483 |
+
if (!empty($objectId)) {
|
484 |
+
$caps = $this->authorizeUserUpdate($caps, $objectId);
|
485 |
}
|
486 |
break;
|
487 |
|
488 |
case 'install_plugins':
|
|
|
|
|
|
|
489 |
case 'delete_plugins':
|
|
|
|
|
|
|
490 |
case 'edit_plugins':
|
|
|
|
|
|
|
491 |
case 'update_plugins':
|
492 |
+
$action = explode('_', $cap);
|
493 |
+
$caps = $this->checkPluginsAction($action[0], $caps, $cap);
|
|
|
|
|
|
|
|
|
|
|
494 |
break;
|
495 |
|
496 |
+
case 'activate_plugin':
|
497 |
case 'deactivate_plugin':
|
498 |
+
$action = explode('_', $cap);
|
499 |
+
$caps = $this->checkPluginAction($objectId, $action[0], $caps, $cap);
|
|
|
500 |
break;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
501 |
|
502 |
+
// This part needs to stay to cover scenarios where WP_Post_Type->cap->...
|
503 |
+
// is not used but rather the hardcoded capability
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
504 |
case 'edit_post':
|
505 |
+
$caps = $this->authorizePostEdit($caps, $objectId);
|
|
|
506 |
break;
|
507 |
|
508 |
case 'delete_post':
|
509 |
+
$caps = $this->authorizePostDelete($caps, $objectId);
|
|
|
510 |
break;
|
511 |
|
512 |
case 'read_post':
|
513 |
+
$caps = $this->authorizePostRead($caps, $objectId);
|
|
|
|
|
514 |
break;
|
515 |
|
516 |
|
517 |
case 'publish_post':
|
518 |
case 'publish_posts':
|
519 |
case 'publish_pages':
|
|
|
520 |
// There is a bug in WP core that instead of checking if user has
|
521 |
// ability to publish_post, it checks for edit_post. That is why
|
522 |
// user has to be on the edit
|
523 |
if (is_a($post, 'WP_Post')) {
|
524 |
+
$caps = $this->authorizePublishPost($caps, $post->ID);
|
525 |
}
|
526 |
break;
|
527 |
+
|
528 |
default:
|
529 |
+
if (strpos($cap, 'aam-') === 0) {
|
530 |
+
$caps = $this->checkPostTypePermission($caps, $cap, $objectId);
|
531 |
+
} else {
|
532 |
+
$caps = apply_filters('aam-map-meta-caps-filter', $caps, $cap, $args);
|
533 |
+
}
|
534 |
break;
|
535 |
}
|
536 |
+
|
537 |
+
return $caps;
|
538 |
+
}
|
539 |
+
|
540 |
+
/**
|
541 |
+
* Check Post Permissions
|
542 |
+
*
|
543 |
+
* @param [type] $caps
|
544 |
+
* @param [type] $cap
|
545 |
+
* @param [type] $id
|
546 |
+
*
|
547 |
+
* @return array
|
548 |
+
*
|
549 |
+
* @access protected
|
550 |
+
*/
|
551 |
+
protected function checkPostTypePermission($caps, $cap, $id = null) {
|
552 |
+
// Expecting to have:
|
553 |
+
// [0] === aam
|
554 |
+
// [1] === WP_Post_Type->cap key
|
555 |
+
// [2] === The capability
|
556 |
+
$parts = explode('-', $cap);
|
557 |
+
|
558 |
+
// Build the argument array for the current_user_can
|
559 |
+
$args = array($parts[2]);
|
560 |
+
if (!is_null($id)) {
|
561 |
+
$args[] = $id;
|
562 |
+
}
|
563 |
+
|
564 |
+
// NOTE! DO NOT FORGET TO UPDATE REGISTERED_POST_TYPE if new capability is
|
565 |
+
// added
|
566 |
+
if (call_user_func_array('current_user_can', $args)) {
|
567 |
+
switch($parts[1]) {
|
568 |
+
case 'edit_post':
|
569 |
+
$caps = $this->authorizePostEdit($caps, $id);
|
570 |
+
break;
|
571 |
+
|
572 |
+
case 'read_post':
|
573 |
+
$caps = $this->authorizePostRead($caps, $id);
|
574 |
+
break;
|
575 |
+
|
576 |
+
case 'delete_post':
|
577 |
+
$caps = $this->authorizePostDelete($caps, $id);
|
578 |
+
break;
|
579 |
+
|
580 |
+
default:
|
581 |
+
break;
|
582 |
+
}
|
583 |
+
} else {
|
584 |
+
$caps[] = 'do_not_allow';
|
585 |
+
}
|
586 |
|
587 |
return $caps;
|
588 |
}
|
698 |
* @access protected
|
699 |
*/
|
700 |
protected function authorizeUserUpdate($caps, $userId) {
|
701 |
+
$user = AAM::api()->getUser($userId);
|
702 |
|
703 |
//current user max level
|
704 |
$maxLevel = AAM::getUser()->getMaxLevel();
|
aam.php
CHANGED
@@ -1,17 +1,17 @@
|
|
1 |
<?php
|
2 |
|
3 |
/**
|
4 |
-
|
5 |
-
|
6 |
-
|
7 |
-
|
8 |
-
|
9 |
-
|
10 |
-
-------
|
11 |
-
LICENSE: This file is subject to the terms and conditions defined in
|
12 |
-
file 'license.txt', which is part of Advanced Access Manager source package.
|
13 |
*
|
14 |
-
|
|
|
|
|
|
|
|
|
15 |
|
16 |
/**
|
17 |
* Main plugin's class
|
@@ -121,8 +121,8 @@ class AAM {
|
|
121 |
}
|
122 |
|
123 |
//JWT Authentication
|
124 |
-
if (AAM_Core_Config::get('core.settings.jwtAuthentication',
|
125 |
-
|
126 |
}
|
127 |
|
128 |
// Load AAM
|
@@ -165,12 +165,20 @@ class AAM {
|
|
165 |
public static function getInstance() {
|
166 |
if (is_null(self::$_instance)) {
|
167 |
self::$_instance = new self;
|
|
|
|
|
|
|
168 |
|
169 |
// Load user capabilities
|
170 |
-
|
171 |
|
172 |
// Logout user if he/she is blocked
|
173 |
-
|
|
|
|
|
|
|
|
|
|
|
174 |
|
175 |
load_plugin_textdomain(AAM_KEY, false, 'advanced-access-manager/Lang');
|
176 |
}
|
1 |
<?php
|
2 |
|
3 |
/**
|
4 |
+
* Plugin Name: Advanced Access Manager
|
5 |
+
* Description: All you need to manage access to your WordPress website
|
6 |
+
* Version: 5.9.2
|
7 |
+
* Author: Vasyl Martyniuk <vasyl@vasyltech.com>
|
8 |
+
* Author URI: https://vasyltech.com
|
|
|
|
|
|
|
|
|
9 |
*
|
10 |
+
* -------
|
11 |
+
* LICENSE: This file is subject to the terms and conditions defined in
|
12 |
+
* file 'license.txt', which is part of Advanced Access Manager source package.
|
13 |
+
*
|
14 |
+
**/
|
15 |
|
16 |
/**
|
17 |
* Main plugin's class
|
121 |
}
|
122 |
|
123 |
//JWT Authentication
|
124 |
+
if (AAM_Core_Config::get('core.settings.jwtAuthentication', true)) {
|
125 |
+
AAM_Core_Jwt_Manager::bootstrap();
|
126 |
}
|
127 |
|
128 |
// Load AAM
|
165 |
public static function getInstance() {
|
166 |
if (is_null(self::$_instance)) {
|
167 |
self::$_instance = new self;
|
168 |
+
|
169 |
+
// Get current user
|
170 |
+
$user = self::$_instance->getUser();
|
171 |
|
172 |
// Load user capabilities
|
173 |
+
$user->initialize();
|
174 |
|
175 |
// Logout user if he/she is blocked
|
176 |
+
$status = $user->getUserStatus();
|
177 |
+
|
178 |
+
// If user is not active, then perform rollback on user
|
179 |
+
if ($status['status'] !== 'active') {
|
180 |
+
$user->restrainUserAccount($status);
|
181 |
+
}
|
182 |
|
183 |
load_plugin_textdomain(AAM_KEY, false, 'advanced-access-manager/Lang');
|
184 |
}
|
media/css/aam.css
CHANGED
@@ -103,6 +103,8 @@
|
|
103 |
.icon-cubes:before { content: '\f1b3' !important; } /* 'ï³' */
|
104 |
.icon-cog-alt:before { content: '\e80d' !important; } /* 'î ' */
|
105 |
.icon-wrench:before { content: '\e80e' !important; } /* 'î ' */
|
|
|
|
|
106 |
|
107 |
.animate-spin {
|
108 |
-moz-animation: spin 2s infinite linear;
|
@@ -310,6 +312,18 @@ div.error {
|
|
310 |
font-weight: bold;
|
311 |
}
|
312 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
313 |
.panel-title {
|
314 |
font-size: 13px;
|
315 |
}
|
@@ -594,11 +608,6 @@ input[type=radio]:checked + label:before {
|
|
594 |
margin-top: 30px;
|
595 |
}
|
596 |
|
597 |
-
.aam-block {
|
598 |
-
display: block;
|
599 |
-
letter-spacing: 1.5px;
|
600 |
-
}
|
601 |
-
|
602 |
.aam-highligh-row {
|
603 |
border:3px solid #337ab7;
|
604 |
}
|
@@ -754,7 +763,7 @@ input[type=radio]:checked + label:before {
|
|
754 |
font-weight: 500;
|
755 |
padding: 15px;
|
756 |
text-align: center;
|
757 |
-
z-index:
|
758 |
color: #FFFFFF;
|
759 |
letter-spacing: 1px;
|
760 |
}
|
103 |
.icon-cubes:before { content: '\f1b3' !important; } /* 'ï³' */
|
104 |
.icon-cog-alt:before { content: '\e80d' !important; } /* 'î ' */
|
105 |
.icon-wrench:before { content: '\e80e' !important; } /* 'î ' */
|
106 |
+
.icon-ok-circled:before { content: '\e81c' !important; } /* 'î ' */
|
107 |
+
.icon-cancel-circled:before { content: '\e81d' !important; } /* 'î ' */
|
108 |
|
109 |
.animate-spin {
|
110 |
-moz-animation: spin 2s infinite linear;
|
312 |
font-weight: bold;
|
313 |
}
|
314 |
|
315 |
+
.aam-block {
|
316 |
+
display: block;
|
317 |
+
}
|
318 |
+
|
319 |
+
.aam-block .aam-copy-clipboard{
|
320 |
+
float: right;
|
321 |
+
}
|
322 |
+
|
323 |
+
.aam-block .aam-copy-clipboard:after {
|
324 |
+
clear:both;
|
325 |
+
}
|
326 |
+
|
327 |
.panel-title {
|
328 |
font-size: 13px;
|
329 |
}
|
608 |
margin-top: 30px;
|
609 |
}
|
610 |
|
|
|
|
|
|
|
|
|
|
|
611 |
.aam-highligh-row {
|
612 |
border:3px solid #337ab7;
|
613 |
}
|
763 |
font-weight: 500;
|
764 |
padding: 15px;
|
765 |
text-align: center;
|
766 |
+
z-index: 9999;
|
767 |
color: #FFFFFF;
|
768 |
letter-spacing: 1px;
|
769 |
}
|
media/font/fontello.eot
CHANGED
Binary file
|
media/font/fontello.svg
CHANGED
@@ -62,6 +62,10 @@
|
|
62 |
|
63 |
<glyph glyph-name="users" unicode="" d="M331 350q-90-3-148-71h-75q-45 0-77 22t-31 66q0 197 69 197 4 0 25-11t54-24 66-12q38 0 75 13-3-21-3-37 0-78 45-143z m598-356q0-66-41-105t-108-39h-488q-68 0-108 39t-41 105q0 30 2 58t8 61 14 61 24 54 35 45 48 30 62 11q6 0 24-12t41-26 59-27 76-12 75 12 60 27 41 26 23 12q35 0 63-11t47-30 35-45 24-54 15-61 8-61 2-58z m-572 713q0-59-42-101t-101-42-101 42-42 101 42 101 101 42 101-42 42-101z m393-214q0-89-63-152t-151-62-152 62-63 152 63 151 152 63 151-63 63-151z m321-126q0-43-31-66t-77-22h-75q-57 68-147 71 45 65 45 143 0 16-3 37 37-13 74-13 33 0 67 12t54 24 24 11q69 0 69-197z m-71 340q0-59-42-101t-101-42-101 42-42 101 42 101 101 42 101-42 42-101z" horiz-adv-x="1071.4" />
|
64 |
|
|
|
|
|
|
|
|
|
65 |
<glyph glyph-name="user-plus" unicode="" d="M393 350q-89 0-152 63t-62 151 62 152 152 63 151-63 63-152-63-151-151-63z m536-71h196q7 0 13-6t5-12v-107q0-8-5-13t-13-5h-196v-197q0-7-6-12t-12-6h-107q-8 0-13 6t-5 12v197h-197q-7 0-12 5t-6 13v107q0 7 6 12t12 6h197v196q0 7 5 13t13 5h107q7 0 12-5t6-13v-196z m-411-125q0-29 21-51t50-21h143v-133q-38-28-95-28h-488q-67 0-108 39t-41 106q0 30 2 58t8 61 15 60 24 55 34 45 48 30 62 11q11 0 22-10 44-34 86-51t92-17 92 17 86 51q11 10 22 10 73 0 121-54h-125q-29 0-50-21t-21-50v-107z" horiz-adv-x="1142.9" />
|
66 |
|
67 |
<glyph glyph-name="box" unicode="" d="M607 386q0 14-10 25t-26 10h-142q-15 0-26-10t-10-25 10-25 26-11h142q15 0 26 11t10 25z m322 107v-536q0-14-11-25t-25-11h-786q-14 0-25 11t-11 25v536q0 14 11 25t25 11h786q14 0 25-11t11-25z m35 250v-143q0-15-10-25t-25-11h-858q-14 0-25 11t-10 25v143q0 14 10 25t25 11h858q14 0 25-11t10-25z" horiz-adv-x="1000" />
|
62 |
|
63 |
<glyph glyph-name="users" unicode="" d="M331 350q-90-3-148-71h-75q-45 0-77 22t-31 66q0 197 69 197 4 0 25-11t54-24 66-12q38 0 75 13-3-21-3-37 0-78 45-143z m598-356q0-66-41-105t-108-39h-488q-68 0-108 39t-41 105q0 30 2 58t8 61 14 61 24 54 35 45 48 30 62 11q6 0 24-12t41-26 59-27 76-12 75 12 60 27 41 26 23 12q35 0 63-11t47-30 35-45 24-54 15-61 8-61 2-58z m-572 713q0-59-42-101t-101-42-101 42-42 101 42 101 101 42 101-42 42-101z m393-214q0-89-63-152t-151-62-152 62-63 152 63 151 152 63 151-63 63-151z m321-126q0-43-31-66t-77-22h-75q-57 68-147 71 45 65 45 143 0 16-3 37 37-13 74-13 33 0 67 12t54 24 24 11q69 0 69-197z m-71 340q0-59-42-101t-101-42-101 42-42 101 42 101 101 42 101-42 42-101z" horiz-adv-x="1071.4" />
|
64 |
|
65 |
+
<glyph glyph-name="ok-circled" unicode="" d="M717 440q0 16-10 26l-51 50q-11 11-25 11t-25-11l-228-227-126 126q-11 11-25 11t-25-11l-51-50q-10-10-10-26 0-15 10-25l202-202q10-10 25-10 15 0 26 10l303 303q10 10 10 25z m140-90q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
|
66 |
+
|
67 |
+
<glyph glyph-name="cancel-circled" unicode="" d="M641 224q0 14-10 25l-101 101 101 101q10 11 10 25 0 15-10 26l-51 50q-10 11-25 11-15 0-25-11l-101-101-101 101q-11 11-25 11-16 0-26-11l-50-50q-11-11-11-26 0-14 11-25l101-101-101-101q-11-11-11-25 0-15 11-26l50-50q10-11 26-11 14 0 25 11l101 101 101-101q10-11 25-11 15 0 25 11l51 50q10 11 10 26z m216 126q0-117-57-215t-156-156-215-58-216 58-155 156-58 215 58 215 155 156 216 58 215-58 156-156 57-215z" horiz-adv-x="857.1" />
|
68 |
+
|
69 |
<glyph glyph-name="user-plus" unicode="" d="M393 350q-89 0-152 63t-62 151 62 152 152 63 151-63 63-152-63-151-151-63z m536-71h196q7 0 13-6t5-12v-107q0-8-5-13t-13-5h-196v-197q0-7-6-12t-12-6h-107q-8 0-13 6t-5 12v197h-197q-7 0-12 5t-6 13v107q0 7 6 12t12 6h197v196q0 7 5 13t13 5h107q7 0 12-5t6-13v-196z m-411-125q0-29 21-51t50-21h143v-133q-38-28-95-28h-488q-67 0-108 39t-41 106q0 30 2 58t8 61 15 60 24 55 34 45 48 30 62 11q11 0 22-10 44-34 86-51t92-17 92 17 86 51q11 10 22 10 73 0 121-54h-125q-29 0-50-21t-21-50v-107z" horiz-adv-x="1142.9" />
|
70 |
|
71 |
<glyph glyph-name="box" unicode="" d="M607 386q0 14-10 25t-26 10h-142q-15 0-26-10t-10-25 10-25 26-11h142q15 0 26 11t10 25z m322 107v-536q0-14-11-25t-25-11h-786q-14 0-25 11t-11 25v536q0 14 11 25t25 11h786q14 0 25-11t11-25z m35 250v-143q0-15-10-25t-25-11h-858q-14 0-25 11t-10 25v143q0 14 10 25t25 11h858q14 0 25-11t10-25z" horiz-adv-x="1000" />
|
media/font/fontello.ttf
CHANGED
Binary file
|
media/font/fontello.woff
CHANGED
Binary file
|
media/font/fontello.woff2
CHANGED
Binary file
|
media/js/{aam-5.9.1.js → aam-5.9.2.js}
RENAMED
@@ -110,6 +110,41 @@
|
|
110 |
});
|
111 |
});
|
112 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
113 |
|
114 |
/**
|
115 |
*
|
@@ -171,7 +206,7 @@
|
|
171 |
getAAM().triggerHook('post-get-role-list', {
|
172 |
list : response
|
173 |
});
|
174 |
-
//TODO -
|
175 |
$.aamEditRole = null;
|
176 |
}
|
177 |
});
|
@@ -216,8 +251,8 @@
|
|
216 |
}
|
217 |
},
|
218 |
columnDefs: [
|
219 |
-
{visible: false, targets: [0, 1, 4
|
220 |
-
{orderable: false, targets: [0, 1, 3, 4
|
221 |
],
|
222 |
language: {
|
223 |
search: '_INPUT_',
|
@@ -256,12 +291,11 @@
|
|
256 |
$(row).attr('data-id', data[0]);
|
257 |
|
258 |
//add subtitle
|
259 |
-
var expire = (data[5] ? '; <i class="icon-clock"></i>' : '');
|
260 |
$('td:eq(0)', row).append(
|
261 |
$('<i/>', {'class': 'aam-row-subtitle'}).html(
|
262 |
getAAM().applyFilters(
|
263 |
'role-subtitle',
|
264 |
-
getAAM().__('Users') + ': <b>' + parseInt(data[1]) + '</b>; ID: <b>' + data[0] + '</b>'
|
265 |
data
|
266 |
)
|
267 |
)
|
@@ -319,11 +353,10 @@
|
|
319 |
resetForm('#edit-role-modal .modal-body');
|
320 |
$('#edit-role-btn').data('role', data[0]);
|
321 |
$('#edit-role-name').val(data[2]);
|
322 |
-
$('#edit-role-expiration').val(data[5]);
|
323 |
$('#edit-role-modal').modal('show');
|
324 |
fetchRoleList(data[0]);
|
325 |
|
326 |
-
//TODO -
|
327 |
$.aamEditRole = data;
|
328 |
|
329 |
getAAM().triggerHook('edit-role-modal', data);
|
@@ -347,7 +380,7 @@
|
|
347 |
$(container).append($('<i/>', {
|
348 |
'class': 'aam-row-action icon-clone text-success'
|
349 |
}).bind('click', function () {
|
350 |
-
//TODO -
|
351 |
$.aamEditRole = data;
|
352 |
$('#clone-role').prop('checked', true);
|
353 |
$('#add-role-modal').modal('show');
|
@@ -678,40 +711,6 @@
|
|
678 |
return (subject.type === 'user' && parseInt(subject.id) === id);
|
679 |
}
|
680 |
|
681 |
-
/**
|
682 |
-
*
|
683 |
-
* @param {type} selected
|
684 |
-
* @returns {undefined}
|
685 |
-
*/
|
686 |
-
function loadRoleList(selected) {
|
687 |
-
$.ajax(getLocal().ajaxurl, {
|
688 |
-
type: 'POST',
|
689 |
-
dataType: 'json',
|
690 |
-
data: {
|
691 |
-
action: 'aam',
|
692 |
-
sub_action: 'Subject_Role.getList',
|
693 |
-
_ajax_nonce: getLocal().nonce
|
694 |
-
},
|
695 |
-
beforeSend: function () {
|
696 |
-
$('#expiration-change-role').html(
|
697 |
-
'<option value="">' + getAAM().__('Loading...') + '</option>'
|
698 |
-
);
|
699 |
-
},
|
700 |
-
success: function (response) {
|
701 |
-
$('#expiration-change-role').html(
|
702 |
-
'<option value="">' + getAAM().__('Select Role') + '</option>'
|
703 |
-
);
|
704 |
-
for (var i in response) {
|
705 |
-
$('#expiration-change-role').append(
|
706 |
-
'<option value="' + i + '">' + response[i].name + '</option>'
|
707 |
-
);
|
708 |
-
}
|
709 |
-
|
710 |
-
$('#expiration-change-role').val(selected);
|
711 |
-
}
|
712 |
-
});
|
713 |
-
}
|
714 |
-
|
715 |
/**
|
716 |
*
|
717 |
* @param {type} id
|
@@ -759,44 +758,6 @@
|
|
759 |
});
|
760 |
}
|
761 |
|
762 |
-
/**
|
763 |
-
*
|
764 |
-
* @param {type} id
|
765 |
-
* @param {type} expires
|
766 |
-
* @returns {undefined}
|
767 |
-
*/
|
768 |
-
function generateJWT(id, expires) {
|
769 |
-
$.ajax(getLocal().ajaxurl, {
|
770 |
-
type: 'POST',
|
771 |
-
dataType: 'json',
|
772 |
-
data: {
|
773 |
-
action: 'aam',
|
774 |
-
sub_action: 'Subject_User.generateJWT',
|
775 |
-
_ajax_nonce: getLocal().nonce,
|
776 |
-
user: id,
|
777 |
-
expires: expires
|
778 |
-
},
|
779 |
-
beforeSend: function () {
|
780 |
-
$('#user-auth-jwt').val(getAAM().__('Generating token...'));
|
781 |
-
},
|
782 |
-
success: function (response) {
|
783 |
-
if (response.status === 'success') {
|
784 |
-
$('#user-auth-jwt').val(response.jwt);
|
785 |
-
$('#user-auth-url').val(
|
786 |
-
$('#user-auth-url').data('url').replace('%s', response.jwt)
|
787 |
-
);
|
788 |
-
} else {
|
789 |
-
getAAM().notification(
|
790 |
-
'danger', getAAM().__('Failed to generate JWT token')
|
791 |
-
);
|
792 |
-
}
|
793 |
-
},
|
794 |
-
error: function () {
|
795 |
-
getAAM().notification('danger', getAAM().__('Application error'));
|
796 |
-
}
|
797 |
-
});
|
798 |
-
}
|
799 |
-
|
800 |
//initialize the user list table
|
801 |
$('#user-list').DataTable({
|
802 |
autoWidth: false,
|
@@ -1125,10 +1086,6 @@
|
|
1125 |
$('#user-expires').val(
|
1126 |
res.date.format('MM/DD/YYYY, H:mm Z')
|
1127 |
);
|
1128 |
-
generateJWT(
|
1129 |
-
$('#edit-user-expiration-btn').attr('data-user-id'),
|
1130 |
-
$('#user-expires').val()
|
1131 |
-
);
|
1132 |
});
|
1133 |
|
1134 |
//edit role button
|
@@ -3749,6 +3706,265 @@
|
|
3749 |
|
3750 |
})(jQuery);
|
3751 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3752 |
/**
|
3753 |
* Extensions Interface
|
3754 |
*
|
@@ -4557,6 +4773,17 @@
|
|
4557 |
$('#aam-container').delegate('a[href="#"]', 'click', function(event) {
|
4558 |
event.preventDefault();
|
4559 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4560 |
};
|
4561 |
|
4562 |
/**
|
110 |
});
|
111 |
});
|
112 |
}
|
113 |
+
|
114 |
+
/**
|
115 |
+
*
|
116 |
+
* @param {type} selected
|
117 |
+
* @returns {undefined}
|
118 |
+
*/
|
119 |
+
function loadRoleList(selected, target) {
|
120 |
+
target = (typeof target === 'undefined' ? '#expiration-change-role' : target);
|
121 |
+
$.ajax(getLocal().ajaxurl, {
|
122 |
+
type: 'POST',
|
123 |
+
dataType: 'json',
|
124 |
+
data: {
|
125 |
+
action: 'aam',
|
126 |
+
sub_action: 'Subject_Role.getList',
|
127 |
+
_ajax_nonce: getLocal().nonce
|
128 |
+
},
|
129 |
+
beforeSend: function () {
|
130 |
+
$(target).html(
|
131 |
+
'<option value="">' + getAAM().__('Loading...') + '</option>'
|
132 |
+
);
|
133 |
+
},
|
134 |
+
success: function (response) {
|
135 |
+
$(target).html(
|
136 |
+
'<option value="">' + getAAM().__('Select Role') + '</option>'
|
137 |
+
);
|
138 |
+
for (var i in response) {
|
139 |
+
$(target).append(
|
140 |
+
'<option value="' + i + '">' + response[i].name + '</option>'
|
141 |
+
);
|
142 |
+
}
|
143 |
+
|
144 |
+
$(target).val(selected);
|
145 |
+
}
|
146 |
+
});
|
147 |
+
}
|
148 |
|
149 |
/**
|
150 |
*
|
206 |
getAAM().triggerHook('post-get-role-list', {
|
207 |
list : response
|
208 |
});
|
209 |
+
//TODO - Rewrite JavaScript to support $.aam
|
210 |
$.aamEditRole = null;
|
211 |
}
|
212 |
});
|
251 |
}
|
252 |
},
|
253 |
columnDefs: [
|
254 |
+
{visible: false, targets: [0, 1, 4]},
|
255 |
+
{orderable: false, targets: [0, 1, 3, 4]}
|
256 |
],
|
257 |
language: {
|
258 |
search: '_INPUT_',
|
291 |
$(row).attr('data-id', data[0]);
|
292 |
|
293 |
//add subtitle
|
|
|
294 |
$('td:eq(0)', row).append(
|
295 |
$('<i/>', {'class': 'aam-row-subtitle'}).html(
|
296 |
getAAM().applyFilters(
|
297 |
'role-subtitle',
|
298 |
+
getAAM().__('Users') + ': <b>' + parseInt(data[1]) + '</b>; ID: <b>' + data[0] + '</b>',
|
299 |
data
|
300 |
)
|
301 |
)
|
353 |
resetForm('#edit-role-modal .modal-body');
|
354 |
$('#edit-role-btn').data('role', data[0]);
|
355 |
$('#edit-role-name').val(data[2]);
|
|
|
356 |
$('#edit-role-modal').modal('show');
|
357 |
fetchRoleList(data[0]);
|
358 |
|
359 |
+
//TODO - Rewrite JavaScript to support $.aam
|
360 |
$.aamEditRole = data;
|
361 |
|
362 |
getAAM().triggerHook('edit-role-modal', data);
|
380 |
$(container).append($('<i/>', {
|
381 |
'class': 'aam-row-action icon-clone text-success'
|
382 |
}).bind('click', function () {
|
383 |
+
//TODO - Rewrite JavaScript to support $.aam
|
384 |
$.aamEditRole = data;
|
385 |
$('#clone-role').prop('checked', true);
|
386 |
$('#add-role-modal').modal('show');
|
711 |
return (subject.type === 'user' && parseInt(subject.id) === id);
|
712 |
}
|
713 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
714 |
/**
|
715 |
*
|
716 |
* @param {type} id
|
758 |
});
|
759 |
}
|
760 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
761 |
//initialize the user list table
|
762 |
$('#user-list').DataTable({
|
763 |
autoWidth: false,
|
1086 |
$('#user-expires').val(
|
1087 |
res.date.format('MM/DD/YYYY, H:mm Z')
|
1088 |
);
|
|
|
|
|
|
|
|
|
1089 |
});
|
1090 |
|
1091 |
//edit role button
|
3706 |
|
3707 |
})(jQuery);
|
3708 |
|
3709 |
+
/**
|
3710 |
+
* JWT Interface
|
3711 |
+
*
|
3712 |
+
* @param {jQuery} $
|
3713 |
+
*
|
3714 |
+
* @returns {void}
|
3715 |
+
*/
|
3716 |
+
(function ($) {
|
3717 |
+
|
3718 |
+
/**
|
3719 |
+
*
|
3720 |
+
* @param {type} expires
|
3721 |
+
* @returns {undefined}
|
3722 |
+
*/
|
3723 |
+
function generateJWT(expires) {
|
3724 |
+
$.ajax(getLocal().ajaxurl, {
|
3725 |
+
type: 'POST',
|
3726 |
+
dataType: 'json',
|
3727 |
+
data: {
|
3728 |
+
action: 'aam',
|
3729 |
+
sub_action: 'Main_Jwt.generate',
|
3730 |
+
_ajax_nonce: getLocal().nonce,
|
3731 |
+
subject: getAAM().getSubject().type,
|
3732 |
+
subjectId: getAAM().getSubject().id,
|
3733 |
+
expires: expires
|
3734 |
+
},
|
3735 |
+
beforeSend: function () {
|
3736 |
+
$('#jwt-token-preview').val(getAAM().__('Generating token...'));
|
3737 |
+
$('#jwt-url-preview').val(getAAM().__('Generating URL...'));
|
3738 |
+
},
|
3739 |
+
success: function (response) {
|
3740 |
+
if (response.status === 'success') {
|
3741 |
+
$('#jwt-token-preview').val(response.jwt);
|
3742 |
+
$('#jwt-url-preview').val(
|
3743 |
+
$('#jwt-url-preview').data('url').replace('%s', response.jwt)
|
3744 |
+
);
|
3745 |
+
} else {
|
3746 |
+
getAAM().notification(
|
3747 |
+
'danger', getAAM().__('Failed to generate JWT token')
|
3748 |
+
);
|
3749 |
+
}
|
3750 |
+
},
|
3751 |
+
error: function () {
|
3752 |
+
getAAM().notification('danger', getAAM().__('Application error'));
|
3753 |
+
}
|
3754 |
+
});
|
3755 |
+
}
|
3756 |
+
|
3757 |
+
/**
|
3758 |
+
*
|
3759 |
+
*/
|
3760 |
+
function initialize() {
|
3761 |
+
var container = '#jwt-content';
|
3762 |
+
|
3763 |
+
if ($(container).length) {
|
3764 |
+
$('#jwt-expiration-datapicker').datetimepicker({
|
3765 |
+
icons: {
|
3766 |
+
time: "icon-clock",
|
3767 |
+
date: "icon-calendar",
|
3768 |
+
up: "icon-angle-up",
|
3769 |
+
down: "icon-angle-down",
|
3770 |
+
previous: "icon-angle-left",
|
3771 |
+
next: "icon-angle-right"
|
3772 |
+
},
|
3773 |
+
minDate: new Date(),
|
3774 |
+
inline: true,
|
3775 |
+
sideBySide: true
|
3776 |
+
});
|
3777 |
+
|
3778 |
+
$('#create-jwt-modal').on('show.bs.modal', function() {
|
3779 |
+
try{
|
3780 |
+
var tomorrow = new Date();
|
3781 |
+
tomorrow.setDate(tomorrow.getDate() + 1);
|
3782 |
+
$('#jwt-expiration-datapicker').data('DateTimePicker').defaultDate(
|
3783 |
+
tomorrow
|
3784 |
+
);
|
3785 |
+
$('#jwt-expires').val('');
|
3786 |
+
} catch(e) {
|
3787 |
+
// do nothing. Prevent from any kind of corrupted data
|
3788 |
+
}
|
3789 |
+
});
|
3790 |
+
|
3791 |
+
$('#jwt-expiration-datapicker').on('dp.change', function(res) {
|
3792 |
+
$('#jwt-expires').val(
|
3793 |
+
res.date.format('MM/DD/YYYY, H:mm Z')
|
3794 |
+
);
|
3795 |
+
generateJWT(
|
3796 |
+
$('#jwt-expires').val()
|
3797 |
+
);
|
3798 |
+
});
|
3799 |
+
|
3800 |
+
$('#jwt-list').DataTable({
|
3801 |
+
autoWidth: false,
|
3802 |
+
ordering: true,
|
3803 |
+
dom: 'ftrip',
|
3804 |
+
pagingType: 'simple',
|
3805 |
+
processing: true,
|
3806 |
+
stateSave: false,
|
3807 |
+
serverSide: false,
|
3808 |
+
ajax: {
|
3809 |
+
url: getLocal().ajaxurl,
|
3810 |
+
type: 'POST',
|
3811 |
+
dataType: 'json',
|
3812 |
+
data: {
|
3813 |
+
action: 'aam',
|
3814 |
+
sub_action: 'Main_Jwt.getTable',
|
3815 |
+
_ajax_nonce: getLocal().nonce,
|
3816 |
+
subject: getAAM().getSubject().type,
|
3817 |
+
subjectId: getAAM().getSubject().id
|
3818 |
+
}
|
3819 |
+
},
|
3820 |
+
language: {
|
3821 |
+
search: '_INPUT_',
|
3822 |
+
searchPlaceholder: getAAM().__('Search Tokens'),
|
3823 |
+
info: getAAM().__('_TOTAL_ token(s)'),
|
3824 |
+
infoFiltered: '',
|
3825 |
+
emptyTable: getAAM().__('No JWT tokens have been generated.'),
|
3826 |
+
infoEmpty: getAAM().__('Nothing to show'),
|
3827 |
+
lengthMenu: '_MENU_'
|
3828 |
+
},
|
3829 |
+
columnDefs: [
|
3830 |
+
{visible: false, targets: [0, 1]},
|
3831 |
+
{orderable: false, targets: [0, 1, 2, 4]}
|
3832 |
+
],
|
3833 |
+
initComplete: function () {
|
3834 |
+
var create = $('<a/>', {
|
3835 |
+
'href': '#',
|
3836 |
+
'class': 'btn btn-primary'
|
3837 |
+
}).html('<i class="icon-plus"></i> ' + getAAM().__('Create'))
|
3838 |
+
.bind('click', function () {
|
3839 |
+
$('#create-jwt-modal').modal('show');
|
3840 |
+
});
|
3841 |
+
|
3842 |
+
$('.dataTables_filter', '#jwt-list_wrapper').append(create);
|
3843 |
+
},
|
3844 |
+
createdRow: function (row, data) {
|
3845 |
+
// Render status
|
3846 |
+
if (data[2] === 'valid') {
|
3847 |
+
$('td:eq(0)', row).html(
|
3848 |
+
'<i class="icon-ok-circled text-success"></i>'
|
3849 |
+
);
|
3850 |
+
} else {
|
3851 |
+
$('td:eq(0)', row).html(
|
3852 |
+
'<i class="icon-cancel-circled text-danger"></i>'
|
3853 |
+
);
|
3854 |
+
}
|
3855 |
+
|
3856 |
+
var actions = data[4].split(',');
|
3857 |
+
|
3858 |
+
var container = $('<div/>', {'class': 'aam-row-actions'});
|
3859 |
+
$.each(actions, function (i, action) {
|
3860 |
+
switch (action) {
|
3861 |
+
case 'delete':
|
3862 |
+
$(container).append($('<i/>', {
|
3863 |
+
'class': 'aam-row-action icon-trash-empty text-danger'
|
3864 |
+
}).bind('click', function () {
|
3865 |
+
$('#jwt-delete-btn').attr('data-id', data[0]);
|
3866 |
+
$('#delete-jwt-modal').modal('show');
|
3867 |
+
}).attr({
|
3868 |
+
'data-toggle': "tooltip",
|
3869 |
+
'title': getAAM().__('Delete Token')
|
3870 |
+
}));
|
3871 |
+
break;
|
3872 |
+
|
3873 |
+
case 'view':
|
3874 |
+
$(container).append($('<i/>', {
|
3875 |
+
'class': 'aam-row-action icon-eye text-success'
|
3876 |
+
}).bind('click', function () {
|
3877 |
+
$('#view-jwt-token').val(data[0]);
|
3878 |
+
$('#view-jwt-url').val(data[1]);
|
3879 |
+
$('#view-jwt-modal').modal('show');
|
3880 |
+
}).attr({
|
3881 |
+
'data-toggle': "tooltip",
|
3882 |
+
'title': getAAM().__('View Token')
|
3883 |
+
}));
|
3884 |
+
break;
|
3885 |
+
|
3886 |
+
default:
|
3887 |
+
break;
|
3888 |
+
}
|
3889 |
+
});
|
3890 |
+
$('td:eq(2)', row).html(container);
|
3891 |
+
}
|
3892 |
+
});
|
3893 |
+
|
3894 |
+
$('#create-jwt-btn').bind('click', function() {
|
3895 |
+
$.ajax(getLocal().ajaxurl, {
|
3896 |
+
type: 'POST',
|
3897 |
+
dataType: 'json',
|
3898 |
+
data: {
|
3899 |
+
action: 'aam',
|
3900 |
+
sub_action: 'Main_Jwt.save',
|
3901 |
+
_ajax_nonce: getLocal().nonce,
|
3902 |
+
subject: getAAM().getSubject().type,
|
3903 |
+
subjectId: getAAM().getSubject().id,
|
3904 |
+
token: $('#jwt-token-preview').val()
|
3905 |
+
},
|
3906 |
+
beforeSend: function () {
|
3907 |
+
$('#create-jwt-btn').html(getAAM().__('Creating...'));
|
3908 |
+
},
|
3909 |
+
success: function (response) {
|
3910 |
+
if (response.status === 'success') {
|
3911 |
+
$('#create-jwt-modal').modal('hide');
|
3912 |
+
$('#jwt-list').DataTable().ajax.reload();
|
3913 |
+
} else {
|
3914 |
+
getAAM().notification('danger', response.reason);
|
3915 |
+
}
|
3916 |
+
},
|
3917 |
+
error: function () {
|
3918 |
+
getAAM().notification(
|
3919 |
+
'danger', getAAM().__('Application error')
|
3920 |
+
);
|
3921 |
+
},
|
3922 |
+
complete: function() {
|
3923 |
+
$('#create-jwt-btn').html(getAAM().__('Create'));
|
3924 |
+
}
|
3925 |
+
});
|
3926 |
+
});
|
3927 |
+
|
3928 |
+
$('#jwt-delete-btn').bind('click', function() {
|
3929 |
+
$.ajax(getLocal().ajaxurl, {
|
3930 |
+
type: 'POST',
|
3931 |
+
dataType: 'json',
|
3932 |
+
data: {
|
3933 |
+
action: 'aam',
|
3934 |
+
sub_action: 'Main_Jwt.delete',
|
3935 |
+
_ajax_nonce: getLocal().nonce,
|
3936 |
+
subject: getAAM().getSubject().type,
|
3937 |
+
subjectId: getAAM().getSubject().id,
|
3938 |
+
token: $('#jwt-delete-btn').attr('data-id')
|
3939 |
+
},
|
3940 |
+
beforeSend: function () {
|
3941 |
+
$('#jwt-delete-btn').html(getAAM().__('Deleting...'));
|
3942 |
+
},
|
3943 |
+
success: function (response) {
|
3944 |
+
if (response.status === 'success') {
|
3945 |
+
$('#delete-jwt-modal').modal('hide');
|
3946 |
+
$('#jwt-list').DataTable().ajax.reload();
|
3947 |
+
} else {
|
3948 |
+
getAAM().notification('danger', response.reason);
|
3949 |
+
}
|
3950 |
+
},
|
3951 |
+
error: function () {
|
3952 |
+
getAAM().notification(
|
3953 |
+
'danger', getAAM().__('Application error')
|
3954 |
+
);
|
3955 |
+
},
|
3956 |
+
complete: function() {
|
3957 |
+
$('#jwt-delete-btn').html(getAAM().__('Delete'));
|
3958 |
+
}
|
3959 |
+
});
|
3960 |
+
});
|
3961 |
+
}
|
3962 |
+
}
|
3963 |
+
|
3964 |
+
getAAM().addHook('init', initialize);
|
3965 |
+
|
3966 |
+
})(jQuery);
|
3967 |
+
|
3968 |
/**
|
3969 |
* Extensions Interface
|
3970 |
*
|
4773 |
$('#aam-container').delegate('a[href="#"]', 'click', function(event) {
|
4774 |
event.preventDefault();
|
4775 |
});
|
4776 |
+
|
4777 |
+
// Initialize clipboard
|
4778 |
+
var clipboard = new ClipboardJS('.aam-copy-clipboard');
|
4779 |
+
|
4780 |
+
clipboard.on('success', function(e) {
|
4781 |
+
getAAM().notification('success', 'Data has been saved to clipboard');
|
4782 |
+
});
|
4783 |
+
|
4784 |
+
clipboard.on('error', function(e) {
|
4785 |
+
getAAM().notification('danger', 'Failed to save data to clipboard');
|
4786 |
+
});
|
4787 |
};
|
4788 |
|
4789 |
/**
|
media/js/vendor.js
CHANGED
@@ -602,4 +602,12 @@ jsonldMode:U,jsonMode:G,expressionAllowed:na,skipExpression:function(a){var b=a.
|
|
602 |
// Bootstrap datapicker
|
603 |
// https://eonasdan.github.io/bootstrap-datetimepicker/
|
604 |
!function(a){"use strict";if("function"==typeof define&&define.amd)define(["jquery","moment"],a);else if("object"==typeof exports)module.exports=a(require("jquery"),require("moment"));else{if("undefined"==typeof jQuery)throw"bootstrap-datetimepicker requires jQuery to be loaded first";if("undefined"==typeof moment)throw"bootstrap-datetimepicker requires Moment.js to be loaded first";a(jQuery,moment)}}(function(a,b){"use strict";if(!b)throw new Error("bootstrap-datetimepicker requires Moment.js to be loaded first");var c=function(c,d){var e,f,g,h,i,j,k,l={},m=!0,n=!1,o=!1,p=0,q=[{clsName:"days",navFnc:"M",navStep:1},{clsName:"months",navFnc:"y",navStep:1},{clsName:"years",navFnc:"y",navStep:10},{clsName:"decades",navFnc:"y",navStep:100}],r=["days","months","years","decades"],s=["top","bottom","auto"],t=["left","right","auto"],u=["default","top","bottom"],v={up:38,38:"up",down:40,40:"down",left:37,37:"left",right:39,39:"right",tab:9,9:"tab",escape:27,27:"escape",enter:13,13:"enter",pageUp:33,33:"pageUp",pageDown:34,34:"pageDown",shift:16,16:"shift",control:17,17:"control",space:32,32:"space",t:84,84:"t",delete:46,46:"delete"},w={},x=function(){return void 0!==b.tz&&void 0!==d.timeZone&&null!==d.timeZone&&""!==d.timeZone},y=function(a){var c;return c=void 0===a||null===a?b():b.isDate(a)||b.isMoment(a)?b(a):x()?b.tz(a,j,d.useStrict,d.timeZone):b(a,j,d.useStrict),x()&&c.tz(d.timeZone),c},z=function(a){if("string"!=typeof a||a.length>1)throw new TypeError("isEnabled expects a single character string parameter");switch(a){case"y":return i.indexOf("Y")!==-1;case"M":return i.indexOf("M")!==-1;case"d":return i.toLowerCase().indexOf("d")!==-1;case"h":case"H":return i.toLowerCase().indexOf("h")!==-1;case"m":return i.indexOf("m")!==-1;case"s":return i.indexOf("s")!==-1;default:return!1}},A=function(){return z("h")||z("m")||z("s")},B=function(){return z("y")||z("M")||z("d")},C=function(){var b=a("<thead>").append(a("<tr>").append(a("<th>").addClass("prev").attr("data-action","previous").append(a("<span>").addClass(d.icons.previous))).append(a("<th>").addClass("picker-switch").attr("data-action","pickerSwitch").attr("colspan",d.calendarWeeks?"6":"5")).append(a("<th>").addClass("next").attr("data-action","next").append(a("<span>").addClass(d.icons.next)))),c=a("<tbody>").append(a("<tr>").append(a("<td>").attr("colspan",d.calendarWeeks?"8":"7")));return[a("<div>").addClass("datepicker-days").append(a("<table>").addClass("table-condensed").append(b).append(a("<tbody>"))),a("<div>").addClass("datepicker-months").append(a("<table>").addClass("table-condensed").append(b.clone()).append(c.clone())),a("<div>").addClass("datepicker-years").append(a("<table>").addClass("table-condensed").append(b.clone()).append(c.clone())),a("<div>").addClass("datepicker-decades").append(a("<table>").addClass("table-condensed").append(b.clone()).append(c.clone()))]},D=function(){var b=a("<tr>"),c=a("<tr>"),e=a("<tr>");return z("h")&&(b.append(a("<td>").append(a("<a>").attr({href:"#",tabindex:"-1",title:d.tooltips.incrementHour}).addClass("btn").attr("data-action","incrementHours").append(a("<span>").addClass(d.icons.up)))),c.append(a("<td>").append(a("<span>").addClass("timepicker-hour").attr({"data-time-component":"hours",title:d.tooltips.pickHour}).attr("data-action","showHours"))),e.append(a("<td>").append(a("<a>").attr({href:"#",tabindex:"-1",title:d.tooltips.decrementHour}).addClass("btn").attr("data-action","decrementHours").append(a("<span>").addClass(d.icons.down))))),z("m")&&(z("h")&&(b.append(a("<td>").addClass("separator")),c.append(a("<td>").addClass("separator").html(":")),e.append(a("<td>").addClass("separator"))),b.append(a("<td>").append(a("<a>").attr({href:"#",tabindex:"-1",title:d.tooltips.incrementMinute}).addClass("btn").attr("data-action","incrementMinutes").append(a("<span>").addClass(d.icons.up)))),c.append(a("<td>").append(a("<span>").addClass("timepicker-minute").attr({"data-time-component":"minutes",title:d.tooltips.pickMinute}).attr("data-action","showMinutes"))),e.append(a("<td>").append(a("<a>").attr({href:"#",tabindex:"-1",title:d.tooltips.decrementMinute}).addClass("btn").attr("data-action","decrementMinutes").append(a("<span>").addClass(d.icons.down))))),z("s")&&(z("m")&&(b.append(a("<td>").addClass("separator")),c.append(a("<td>").addClass("separator").html(":")),e.append(a("<td>").addClass("separator"))),b.append(a("<td>").append(a("<a>").attr({href:"#",tabindex:"-1",title:d.tooltips.incrementSecond}).addClass("btn").attr("data-action","incrementSeconds").append(a("<span>").addClass(d.icons.up)))),c.append(a("<td>").append(a("<span>").addClass("timepicker-second").attr({"data-time-component":"seconds",title:d.tooltips.pickSecond}).attr("data-action","showSeconds"))),e.append(a("<td>").append(a("<a>").attr({href:"#",tabindex:"-1",title:d.tooltips.decrementSecond}).addClass("btn").attr("data-action","decrementSeconds").append(a("<span>").addClass(d.icons.down))))),h||(b.append(a("<td>").addClass("separator")),c.append(a("<td>").append(a("<button>").addClass("btn btn-primary").attr({"data-action":"togglePeriod",tabindex:"-1",title:d.tooltips.togglePeriod}))),e.append(a("<td>").addClass("separator"))),a("<div>").addClass("timepicker-picker").append(a("<table>").addClass("table-condensed").append([b,c,e]))},E=function(){var b=a("<div>").addClass("timepicker-hours").append(a("<table>").addClass("table-condensed")),c=a("<div>").addClass("timepicker-minutes").append(a("<table>").addClass("table-condensed")),d=a("<div>").addClass("timepicker-seconds").append(a("<table>").addClass("table-condensed")),e=[D()];return z("h")&&e.push(b),z("m")&&e.push(c),z("s")&&e.push(d),e},F=function(){var b=[];return d.showTodayButton&&b.push(a("<td>").append(a("<a>").attr({"data-action":"today",title:d.tooltips.today}).append(a("<span>").addClass(d.icons.today)))),!d.sideBySide&&B()&&A()&&b.push(a("<td>").append(a("<a>").attr({"data-action":"togglePicker",title:d.tooltips.selectTime}).append(a("<span>").addClass(d.icons.time)))),d.showClear&&b.push(a("<td>").append(a("<a>").attr({"data-action":"clear",title:d.tooltips.clear}).append(a("<span>").addClass(d.icons.clear)))),d.showClose&&b.push(a("<td>").append(a("<a>").attr({"data-action":"close",title:d.tooltips.close}).append(a("<span>").addClass(d.icons.close)))),a("<table>").addClass("table-condensed").append(a("<tbody>").append(a("<tr>").append(b)))},G=function(){var b=a("<div>").addClass("bootstrap-datetimepicker-widget dropdown-menu"),c=a("<div>").addClass("datepicker").append(C()),e=a("<div>").addClass("timepicker").append(E()),f=a("<ul>").addClass("list-unstyled"),g=a("<li>").addClass("picker-switch"+(d.collapse?" accordion-toggle":"")).append(F());return d.inline&&b.removeClass("dropdown-menu"),h&&b.addClass("usetwentyfour"),z("s")&&!h&&b.addClass("wider"),d.sideBySide&&B()&&A()?(b.addClass("timepicker-sbs"),"top"===d.toolbarPlacement&&b.append(g),b.append(a("<div>").addClass("row").append(c.addClass("col-md-6")).append(e.addClass("col-md-6"))),"bottom"===d.toolbarPlacement&&b.append(g),b):("top"===d.toolbarPlacement&&f.append(g),B()&&f.append(a("<li>").addClass(d.collapse&&A()?"collapse in":"").append(c)),"default"===d.toolbarPlacement&&f.append(g),A()&&f.append(a("<li>").addClass(d.collapse&&B()?"collapse":"").append(e)),"bottom"===d.toolbarPlacement&&f.append(g),b.append(f))},H=function(){var b,e={};return b=c.is("input")||d.inline?c.data():c.find("input").data(),b.dateOptions&&b.dateOptions instanceof Object&&(e=a.extend(!0,e,b.dateOptions)),a.each(d,function(a){var c="date"+a.charAt(0).toUpperCase()+a.slice(1);void 0!==b[c]&&(e[a]=b[c])}),e},I=function(){var b,e=(n||c).position(),f=(n||c).offset(),g=d.widgetPositioning.vertical,h=d.widgetPositioning.horizontal;if(d.widgetParent)b=d.widgetParent.append(o);else if(c.is("input"))b=c.after(o).parent();else{if(d.inline)return void(b=c.append(o));b=c,c.children().first().after(o)}if("auto"===g&&(g=f.top+1.5*o.height()>=a(window).height()+a(window).scrollTop()&&o.height()+c.outerHeight()<f.top?"top":"bottom"),"auto"===h&&(h=b.width()<f.left+o.outerWidth()/2&&f.left+o.outerWidth()>a(window).width()?"right":"left"),"top"===g?o.addClass("top").removeClass("bottom"):o.addClass("bottom").removeClass("top"),"right"===h?o.addClass("pull-right"):o.removeClass("pull-right"),"static"===b.css("position")&&(b=b.parents().filter(function(){return"static"!==a(this).css("position")}).first()),0===b.length)throw new Error("datetimepicker component should be placed within a non-static positioned container");o.css({top:"top"===g?"auto":e.top+c.outerHeight(),bottom:"top"===g?b.outerHeight()-(b===c?0:e.top):"auto",left:"left"===h?b===c?0:e.left:"auto",right:"left"===h?"auto":b.outerWidth()-c.outerWidth()-(b===c?0:e.left)})},J=function(a){"dp.change"===a.type&&(a.date&&a.date.isSame(a.oldDate)||!a.date&&!a.oldDate)||c.trigger(a)},K=function(a){"y"===a&&(a="YYYY"),J({type:"dp.update",change:a,viewDate:f.clone()})},L=function(a){o&&(a&&(k=Math.max(p,Math.min(3,k+a))),o.find(".datepicker > div").hide().filter(".datepicker-"+q[k].clsName).show())},M=function(){var b=a("<tr>"),c=f.clone().startOf("w").startOf("d");for(d.calendarWeeks===!0&&b.append(a("<th>").addClass("cw").text("#"));c.isBefore(f.clone().endOf("w"));)b.append(a("<th>").addClass("dow").text(c.format("dd"))),c.add(1,"d");o.find(".datepicker-days thead").append(b)},N=function(a){return d.disabledDates[a.format("YYYY-MM-DD")]===!0},O=function(a){return d.enabledDates[a.format("YYYY-MM-DD")]===!0},P=function(a){return d.disabledHours[a.format("H")]===!0},Q=function(a){return d.enabledHours[a.format("H")]===!0},R=function(b,c){if(!b.isValid())return!1;if(d.disabledDates&&"d"===c&&N(b))return!1;if(d.enabledDates&&"d"===c&&!O(b))return!1;if(d.minDate&&b.isBefore(d.minDate,c))return!1;if(d.maxDate&&b.isAfter(d.maxDate,c))return!1;if(d.daysOfWeekDisabled&&"d"===c&&d.daysOfWeekDisabled.indexOf(b.day())!==-1)return!1;if(d.disabledHours&&("h"===c||"m"===c||"s"===c)&&P(b))return!1;if(d.enabledHours&&("h"===c||"m"===c||"s"===c)&&!Q(b))return!1;if(d.disabledTimeIntervals&&("h"===c||"m"===c||"s"===c)){var e=!1;if(a.each(d.disabledTimeIntervals,function(){if(b.isBetween(this[0],this[1]))return e=!0,!1}),e)return!1}return!0},S=function(){for(var b=[],c=f.clone().startOf("y").startOf("d");c.isSame(f,"y");)b.push(a("<span>").attr("data-action","selectMonth").addClass("month").text(c.format("MMM"))),c.add(1,"M");o.find(".datepicker-months td").empty().append(b)},T=function(){var b=o.find(".datepicker-months"),c=b.find("th"),g=b.find("tbody").find("span");c.eq(0).find("span").attr("title",d.tooltips.prevYear),c.eq(1).attr("title",d.tooltips.selectYear),c.eq(2).find("span").attr("title",d.tooltips.nextYear),b.find(".disabled").removeClass("disabled"),R(f.clone().subtract(1,"y"),"y")||c.eq(0).addClass("disabled"),c.eq(1).text(f.year()),R(f.clone().add(1,"y"),"y")||c.eq(2).addClass("disabled"),g.removeClass("active"),e.isSame(f,"y")&&!m&&g.eq(e.month()).addClass("active"),g.each(function(b){R(f.clone().month(b),"M")||a(this).addClass("disabled")})},U=function(){var a=o.find(".datepicker-years"),b=a.find("th"),c=f.clone().subtract(5,"y"),g=f.clone().add(6,"y"),h="";for(b.eq(0).find("span").attr("title",d.tooltips.prevDecade),b.eq(1).attr("title",d.tooltips.selectDecade),b.eq(2).find("span").attr("title",d.tooltips.nextDecade),a.find(".disabled").removeClass("disabled"),d.minDate&&d.minDate.isAfter(c,"y")&&b.eq(0).addClass("disabled"),b.eq(1).text(c.year()+"-"+g.year()),d.maxDate&&d.maxDate.isBefore(g,"y")&&b.eq(2).addClass("disabled");!c.isAfter(g,"y");)h+='<span data-action="selectYear" class="year'+(c.isSame(e,"y")&&!m?" active":"")+(R(c,"y")?"":" disabled")+'">'+c.year()+"</span>",c.add(1,"y");a.find("td").html(h)},V=function(){var a,c=o.find(".datepicker-decades"),g=c.find("th"),h=b({y:f.year()-f.year()%100-1}),i=h.clone().add(100,"y"),j=h.clone(),k=!1,l=!1,m="";for(g.eq(0).find("span").attr("title",d.tooltips.prevCentury),g.eq(2).find("span").attr("title",d.tooltips.nextCentury),c.find(".disabled").removeClass("disabled"),(h.isSame(b({y:1900}))||d.minDate&&d.minDate.isAfter(h,"y"))&&g.eq(0).addClass("disabled"),g.eq(1).text(h.year()+"-"+i.year()),(h.isSame(b({y:2e3}))||d.maxDate&&d.maxDate.isBefore(i,"y"))&&g.eq(2).addClass("disabled");!h.isAfter(i,"y");)a=h.year()+12,k=d.minDate&&d.minDate.isAfter(h,"y")&&d.minDate.year()<=a,l=d.maxDate&&d.maxDate.isAfter(h,"y")&&d.maxDate.year()<=a,m+='<span data-action="selectDecade" class="decade'+(e.isAfter(h)&&e.year()<=a?" active":"")+(R(h,"y")||k||l?"":" disabled")+'" data-selection="'+(h.year()+6)+'">'+(h.year()+1)+" - "+(h.year()+12)+"</span>",h.add(12,"y");m+="<span></span><span></span><span></span>",c.find("td").html(m),g.eq(1).text(j.year()+1+"-"+h.year())},W=function(){var b,c,g,h=o.find(".datepicker-days"),i=h.find("th"),j=[],k=[];if(B()){for(i.eq(0).find("span").attr("title",d.tooltips.prevMonth),i.eq(1).attr("title",d.tooltips.selectMonth),i.eq(2).find("span").attr("title",d.tooltips.nextMonth),h.find(".disabled").removeClass("disabled"),i.eq(1).text(f.format(d.dayViewHeaderFormat)),R(f.clone().subtract(1,"M"),"M")||i.eq(0).addClass("disabled"),R(f.clone().add(1,"M"),"M")||i.eq(2).addClass("disabled"),b=f.clone().startOf("M").startOf("w").startOf("d"),g=0;g<42;g++)0===b.weekday()&&(c=a("<tr>"),d.calendarWeeks&&c.append('<td class="cw">'+b.week()+"</td>"),j.push(c)),k=["day"],b.isBefore(f,"M")&&k.push("old"),b.isAfter(f,"M")&&k.push("new"),b.isSame(e,"d")&&!m&&k.push("active"),R(b,"d")||k.push("disabled"),b.isSame(y(),"d")&&k.push("today"),0!==b.day()&&6!==b.day()||k.push("weekend"),J({type:"dp.classify",date:b,classNames:k}),c.append('<td data-action="selectDay" data-day="'+b.format("L")+'" class="'+k.join(" ")+'">'+b.date()+"</td>"),b.add(1,"d");h.find("tbody").empty().append(j),T(),U(),V()}},X=function(){var b=o.find(".timepicker-hours table"),c=f.clone().startOf("d"),d=[],e=a("<tr>");for(f.hour()>11&&!h&&c.hour(12);c.isSame(f,"d")&&(h||f.hour()<12&&c.hour()<12||f.hour()>11);)c.hour()%4===0&&(e=a("<tr>"),d.push(e)),e.append('<td data-action="selectHour" class="hour'+(R(c,"h")?"":" disabled")+'">'+c.format(h?"HH":"hh")+"</td>"),c.add(1,"h");b.empty().append(d)},Y=function(){for(var b=o.find(".timepicker-minutes table"),c=f.clone().startOf("h"),e=[],g=a("<tr>"),h=1===d.stepping?5:d.stepping;f.isSame(c,"h");)c.minute()%(4*h)===0&&(g=a("<tr>"),e.push(g)),g.append('<td data-action="selectMinute" class="minute'+(R(c,"m")?"":" disabled")+'">'+c.format("mm")+"</td>"),c.add(h,"m");b.empty().append(e)},Z=function(){for(var b=o.find(".timepicker-seconds table"),c=f.clone().startOf("m"),d=[],e=a("<tr>");f.isSame(c,"m");)c.second()%20===0&&(e=a("<tr>"),d.push(e)),e.append('<td data-action="selectSecond" class="second'+(R(c,"s")?"":" disabled")+'">'+c.format("ss")+"</td>"),c.add(5,"s");b.empty().append(d)},$=function(){var a,b,c=o.find(".timepicker span[data-time-component]");h||(a=o.find(".timepicker [data-action=togglePeriod]"),b=e.clone().add(e.hours()>=12?-12:12,"h"),a.text(e.format("A")),R(b,"h")?a.removeClass("disabled"):a.addClass("disabled")),c.filter("[data-time-component=hours]").text(e.format(h?"HH":"hh")),c.filter("[data-time-component=minutes]").text(e.format("mm")),c.filter("[data-time-component=seconds]").text(e.format("ss")),X(),Y(),Z()},_=function(){o&&(W(),$())},aa=function(a){var b=m?null:e;if(!a)return m=!0,g.val(""),c.data("date",""),J({type:"dp.change",date:!1,oldDate:b}),void _();if(a=a.clone().locale(d.locale),x()&&a.tz(d.timeZone),1!==d.stepping)for(a.minutes(Math.round(a.minutes()/d.stepping)*d.stepping).seconds(0);d.minDate&&a.isBefore(d.minDate);)a.add(d.stepping,"minutes");R(a)?(e=a,f=e.clone(),g.val(e.format(i)),c.data("date",e.format(i)),m=!1,_(),J({type:"dp.change",date:e.clone(),oldDate:b})):(d.keepInvalid?J({type:"dp.change",date:a,oldDate:b}):g.val(m?"":e.format(i)),J({type:"dp.error",date:a,oldDate:b}))},ba=function(){var b=!1;return o?(o.find(".collapse").each(function(){var c=a(this).data("collapse");return!c||!c.transitioning||(b=!0,!1)}),b?l:(n&&n.hasClass("btn")&&n.toggleClass("active"),o.hide(),a(window).off("resize",I),o.off("click","[data-action]"),o.off("mousedown",!1),o.remove(),o=!1,J({type:"dp.hide",date:e.clone()}),g.blur(),f=e.clone(),l)):l},ca=function(){aa(null)},da=function(a){return void 0===d.parseInputDate?(!b.isMoment(a)||a instanceof Date)&&(a=y(a)):a=d.parseInputDate(a),a},ea={next:function(){var a=q[k].navFnc;f.add(q[k].navStep,a),W(),K(a)},previous:function(){var a=q[k].navFnc;f.subtract(q[k].navStep,a),W(),K(a)},pickerSwitch:function(){L(1)},selectMonth:function(b){var c=a(b.target).closest("tbody").find("span").index(a(b.target));f.month(c),k===p?(aa(e.clone().year(f.year()).month(f.month())),d.inline||ba()):(L(-1),W()),K("M")},selectYear:function(b){var c=parseInt(a(b.target).text(),10)||0;f.year(c),k===p?(aa(e.clone().year(f.year())),d.inline||ba()):(L(-1),W()),K("YYYY")},selectDecade:function(b){var c=parseInt(a(b.target).data("selection"),10)||0;f.year(c),k===p?(aa(e.clone().year(f.year())),d.inline||ba()):(L(-1),W()),K("YYYY")},selectDay:function(b){var c=f.clone();a(b.target).is(".old")&&c.subtract(1,"M"),a(b.target).is(".new")&&c.add(1,"M"),aa(c.date(parseInt(a(b.target).text(),10))),A()||d.keepOpen||d.inline||ba()},incrementHours:function(){var a=e.clone().add(1,"h");R(a,"h")&&aa(a)},incrementMinutes:function(){var a=e.clone().add(d.stepping,"m");R(a,"m")&&aa(a)},incrementSeconds:function(){var a=e.clone().add(1,"s");R(a,"s")&&aa(a)},decrementHours:function(){var a=e.clone().subtract(1,"h");R(a,"h")&&aa(a)},decrementMinutes:function(){var a=e.clone().subtract(d.stepping,"m");R(a,"m")&&aa(a)},decrementSeconds:function(){var a=e.clone().subtract(1,"s");R(a,"s")&&aa(a)},togglePeriod:function(){aa(e.clone().add(e.hours()>=12?-12:12,"h"))},togglePicker:function(b){var c,e=a(b.target),f=e.closest("ul"),g=f.find(".in"),h=f.find(".collapse:not(.in)");if(g&&g.length){if(c=g.data("collapse"),c&&c.transitioning)return;g.collapse?(g.collapse("hide"),h.collapse("show")):(g.removeClass("in"),h.addClass("in")),e.is("span")?e.toggleClass(d.icons.time+" "+d.icons.date):e.find("span").toggleClass(d.icons.time+" "+d.icons.date)}},showPicker:function(){o.find(".timepicker > div:not(.timepicker-picker)").hide(),o.find(".timepicker .timepicker-picker").show()},showHours:function(){o.find(".timepicker .timepicker-picker").hide(),o.find(".timepicker .timepicker-hours").show()},showMinutes:function(){o.find(".timepicker .timepicker-picker").hide(),o.find(".timepicker .timepicker-minutes").show()},showSeconds:function(){o.find(".timepicker .timepicker-picker").hide(),o.find(".timepicker .timepicker-seconds").show()},selectHour:function(b){var c=parseInt(a(b.target).text(),10);h||(e.hours()>=12?12!==c&&(c+=12):12===c&&(c=0)),aa(e.clone().hours(c)),ea.showPicker.call(l)},selectMinute:function(b){aa(e.clone().minutes(parseInt(a(b.target).text(),10))),ea.showPicker.call(l)},selectSecond:function(b){aa(e.clone().seconds(parseInt(a(b.target).text(),10))),ea.showPicker.call(l)},clear:ca,today:function(){var a=y();R(a,"d")&&aa(a)},close:ba},fa=function(b){return!a(b.currentTarget).is(".disabled")&&(ea[a(b.currentTarget).data("action")].apply(l,arguments),!1)},ga=function(){var b,c={year:function(a){return a.month(0).date(1).hours(0).seconds(0).minutes(0)},month:function(a){return a.date(1).hours(0).seconds(0).minutes(0)},day:function(a){return a.hours(0).seconds(0).minutes(0)},hour:function(a){return a.seconds(0).minutes(0)},minute:function(a){return a.seconds(0)}};return g.prop("disabled")||!d.ignoreReadonly&&g.prop("readonly")||o?l:(void 0!==g.val()&&0!==g.val().trim().length?aa(da(g.val().trim())):m&&d.useCurrent&&(d.inline||g.is("input")&&0===g.val().trim().length)&&(b=y(),"string"==typeof d.useCurrent&&(b=c[d.useCurrent](b)),aa(b)),o=G(),M(),S(),o.find(".timepicker-hours").hide(),o.find(".timepicker-minutes").hide(),o.find(".timepicker-seconds").hide(),_(),L(),a(window).on("resize",I),o.on("click","[data-action]",fa),o.on("mousedown",!1),n&&n.hasClass("btn")&&n.toggleClass("active"),I(),o.show(),d.focusOnShow&&!g.is(":focus")&&g.focus(),J({type:"dp.show"}),l)},ha=function(){return o?ba():ga()},ia=function(a){var b,c,e,f,g=null,h=[],i={},j=a.which,k="p";w[j]=k;for(b in w)w.hasOwnProperty(b)&&w[b]===k&&(h.push(b),parseInt(b,10)!==j&&(i[b]=!0));for(b in d.keyBinds)if(d.keyBinds.hasOwnProperty(b)&&"function"==typeof d.keyBinds[b]&&(e=b.split(" "),e.length===h.length&&v[j]===e[e.length-1])){for(f=!0,c=e.length-2;c>=0;c--)if(!(v[e[c]]in i)){f=!1;break}if(f){g=d.keyBinds[b];break}}g&&(g.call(l,o),a.stopPropagation(),a.preventDefault())},ja=function(a){w[a.which]="r",a.stopPropagation(),a.preventDefault()},ka=function(b){var c=a(b.target).val().trim(),d=c?da(c):null;return aa(d),b.stopImmediatePropagation(),!1},la=function(){g.on({change:ka,blur:d.debug?"":ba,keydown:ia,keyup:ja,focus:d.allowInputToggle?ga:""}),c.is("input")?g.on({focus:ga}):n&&(n.on("click",ha),n.on("mousedown",!1))},ma=function(){g.off({change:ka,blur:blur,keydown:ia,keyup:ja,focus:d.allowInputToggle?ba:""}),c.is("input")?g.off({focus:ga}):n&&(n.off("click",ha),n.off("mousedown",!1))},na=function(b){var c={};return a.each(b,function(){var a=da(this);a.isValid()&&(c[a.format("YYYY-MM-DD")]=!0)}),!!Object.keys(c).length&&c},oa=function(b){var c={};return a.each(b,function(){c[this]=!0}),!!Object.keys(c).length&&c},pa=function(){var a=d.format||"L LT";i=a.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,function(a){var b=e.localeData().longDateFormat(a)||a;return b.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,function(a){return e.localeData().longDateFormat(a)||a})}),j=d.extraFormats?d.extraFormats.slice():[],j.indexOf(a)<0&&j.indexOf(i)<0&&j.push(i),h=i.toLowerCase().indexOf("a")<1&&i.replace(/\[.*?\]/g,"").indexOf("h")<1,z("y")&&(p=2),z("M")&&(p=1),z("d")&&(p=0),k=Math.max(p,k),m||aa(e)};if(l.destroy=function(){ba(),ma(),c.removeData("DateTimePicker"),c.removeData("date")},l.toggle=ha,l.show=ga,l.hide=ba,l.disable=function(){return ba(),n&&n.hasClass("btn")&&n.addClass("disabled"),g.prop("disabled",!0),l},l.enable=function(){return n&&n.hasClass("btn")&&n.removeClass("disabled"),g.prop("disabled",!1),l},l.ignoreReadonly=function(a){if(0===arguments.length)return d.ignoreReadonly;if("boolean"!=typeof a)throw new TypeError("ignoreReadonly () expects a boolean parameter");return d.ignoreReadonly=a,l},l.options=function(b){if(0===arguments.length)return a.extend(!0,{},d);if(!(b instanceof Object))throw new TypeError("options() options parameter should be an object");return a.extend(!0,d,b),a.each(d,function(a,b){if(void 0===l[a])throw new TypeError("option "+a+" is not recognized!");l[a](b)}),l},l.date=function(a){if(0===arguments.length)return m?null:e.clone();if(!(null===a||"string"==typeof a||b.isMoment(a)||a instanceof Date))throw new TypeError("date() parameter must be one of [null, string, moment or Date]");return aa(null===a?null:da(a)),l},l.format=function(a){if(0===arguments.length)return d.format;if("string"!=typeof a&&("boolean"!=typeof a||a!==!1))throw new TypeError("format() expects a string or boolean:false parameter "+a);return d.format=a,i&&pa(),l},l.timeZone=function(a){if(0===arguments.length)return d.timeZone;if("string"!=typeof a)throw new TypeError("newZone() expects a string parameter");return d.timeZone=a,l},l.dayViewHeaderFormat=function(a){if(0===arguments.length)return d.dayViewHeaderFormat;if("string"!=typeof a)throw new TypeError("dayViewHeaderFormat() expects a string parameter");return d.dayViewHeaderFormat=a,l},l.extraFormats=function(a){if(0===arguments.length)return d.extraFormats;if(a!==!1&&!(a instanceof Array))throw new TypeError("extraFormats() expects an array or false parameter");return d.extraFormats=a,j&&pa(),l},l.disabledDates=function(b){if(0===arguments.length)return d.disabledDates?a.extend({},d.disabledDates):d.disabledDates;if(!b)return d.disabledDates=!1,_(),l;if(!(b instanceof Array))throw new TypeError("disabledDates() expects an array parameter");return d.disabledDates=na(b),d.enabledDates=!1,_(),l},l.enabledDates=function(b){if(0===arguments.length)return d.enabledDates?a.extend({},d.enabledDates):d.enabledDates;if(!b)return d.enabledDates=!1,_(),l;if(!(b instanceof Array))throw new TypeError("enabledDates() expects an array parameter");return d.enabledDates=na(b),d.disabledDates=!1,_(),l},l.daysOfWeekDisabled=function(a){if(0===arguments.length)return d.daysOfWeekDisabled.splice(0);if("boolean"==typeof a&&!a)return d.daysOfWeekDisabled=!1,_(),l;if(!(a instanceof Array))throw new TypeError("daysOfWeekDisabled() expects an array parameter");if(d.daysOfWeekDisabled=a.reduce(function(a,b){return b=parseInt(b,10),b>6||b<0||isNaN(b)?a:(a.indexOf(b)===-1&&a.push(b),a)},[]).sort(),d.useCurrent&&!d.keepInvalid){for(var b=0;!R(e,"d");){if(e.add(1,"d"),31===b)throw"Tried 31 times to find a valid date";b++}aa(e)}return _(),l},l.maxDate=function(a){if(0===arguments.length)return d.maxDate?d.maxDate.clone():d.maxDate;if("boolean"==typeof a&&a===!1)return d.maxDate=!1,_(),l;"string"==typeof a&&("now"!==a&&"moment"!==a||(a=y()));var b=da(a);if(!b.isValid())throw new TypeError("maxDate() Could not parse date parameter: "+a);if(d.minDate&&b.isBefore(d.minDate))throw new TypeError("maxDate() date parameter is before options.minDate: "+b.format(i));return d.maxDate=b,d.useCurrent&&!d.keepInvalid&&e.isAfter(a)&&aa(d.maxDate),f.isAfter(b)&&(f=b.clone().subtract(d.stepping,"m")),_(),l},l.minDate=function(a){if(0===arguments.length)return d.minDate?d.minDate.clone():d.minDate;if("boolean"==typeof a&&a===!1)return d.minDate=!1,_(),l;"string"==typeof a&&("now"!==a&&"moment"!==a||(a=y()));var b=da(a);if(!b.isValid())throw new TypeError("minDate() Could not parse date parameter: "+a);if(d.maxDate&&b.isAfter(d.maxDate))throw new TypeError("minDate() date parameter is after options.maxDate: "+b.format(i));return d.minDate=b,d.useCurrent&&!d.keepInvalid&&e.isBefore(a)&&aa(d.minDate),f.isBefore(b)&&(f=b.clone().add(d.stepping,"m")),_(),l},l.defaultDate=function(a){if(0===arguments.length)return d.defaultDate?d.defaultDate.clone():d.defaultDate;if(!a)return d.defaultDate=!1,l;"string"==typeof a&&(a="now"===a||"moment"===a?y():y(a));var b=da(a);if(!b.isValid())throw new TypeError("defaultDate() Could not parse date parameter: "+a);if(!R(b))throw new TypeError("defaultDate() date passed is invalid according to component setup validations");return d.defaultDate=b,(d.defaultDate&&d.inline||""===g.val().trim())&&aa(d.defaultDate),l},l.locale=function(a){if(0===arguments.length)return d.locale;if(!b.localeData(a))throw new TypeError("locale() locale "+a+" is not loaded from moment locales!");return d.locale=a,e.locale(d.locale),f.locale(d.locale),i&&pa(),o&&(ba(),ga()),l},l.stepping=function(a){return 0===arguments.length?d.stepping:(a=parseInt(a,10),(isNaN(a)||a<1)&&(a=1),d.stepping=a,l)},l.useCurrent=function(a){var b=["year","month","day","hour","minute"];if(0===arguments.length)return d.useCurrent;if("boolean"!=typeof a&&"string"!=typeof a)throw new TypeError("useCurrent() expects a boolean or string parameter");if("string"==typeof a&&b.indexOf(a.toLowerCase())===-1)throw new TypeError("useCurrent() expects a string parameter of "+b.join(", "));return d.useCurrent=a,l},l.collapse=function(a){if(0===arguments.length)return d.collapse;if("boolean"!=typeof a)throw new TypeError("collapse() expects a boolean parameter");return d.collapse===a?l:(d.collapse=a,o&&(ba(),ga()),l)},l.icons=function(b){if(0===arguments.length)return a.extend({},d.icons);if(!(b instanceof Object))throw new TypeError("icons() expects parameter to be an Object");return a.extend(d.icons,b),o&&(ba(),ga()),l},l.tooltips=function(b){if(0===arguments.length)return a.extend({},d.tooltips);if(!(b instanceof Object))throw new TypeError("tooltips() expects parameter to be an Object");return a.extend(d.tooltips,b),o&&(ba(),ga()),l},l.useStrict=function(a){if(0===arguments.length)return d.useStrict;if("boolean"!=typeof a)throw new TypeError("useStrict() expects a boolean parameter");return d.useStrict=a,l},l.sideBySide=function(a){if(0===arguments.length)return d.sideBySide;if("boolean"!=typeof a)throw new TypeError("sideBySide() expects a boolean parameter");return d.sideBySide=a,o&&(ba(),ga()),l},l.viewMode=function(a){if(0===arguments.length)return d.viewMode;if("string"!=typeof a)throw new TypeError("viewMode() expects a string parameter");if(r.indexOf(a)===-1)throw new TypeError("viewMode() parameter must be one of ("+r.join(", ")+") value");return d.viewMode=a,k=Math.max(r.indexOf(a),p),L(),l},l.toolbarPlacement=function(a){if(0===arguments.length)return d.toolbarPlacement;if("string"!=typeof a)throw new TypeError("toolbarPlacement() expects a string parameter");if(u.indexOf(a)===-1)throw new TypeError("toolbarPlacement() parameter must be one of ("+u.join(", ")+") value");return d.toolbarPlacement=a,o&&(ba(),ga()),l},l.widgetPositioning=function(b){if(0===arguments.length)return a.extend({},d.widgetPositioning);if("[object Object]"!=={}.toString.call(b))throw new TypeError("widgetPositioning() expects an object variable");if(b.horizontal){if("string"!=typeof b.horizontal)throw new TypeError("widgetPositioning() horizontal variable must be a string");if(b.horizontal=b.horizontal.toLowerCase(),t.indexOf(b.horizontal)===-1)throw new TypeError("widgetPositioning() expects horizontal parameter to be one of ("+t.join(", ")+")");d.widgetPositioning.horizontal=b.horizontal}if(b.vertical){if("string"!=typeof b.vertical)throw new TypeError("widgetPositioning() vertical variable must be a string");if(b.vertical=b.vertical.toLowerCase(),s.indexOf(b.vertical)===-1)throw new TypeError("widgetPositioning() expects vertical parameter to be one of ("+s.join(", ")+")");d.widgetPositioning.vertical=b.vertical}return _(),l},l.calendarWeeks=function(a){if(0===arguments.length)return d.calendarWeeks;if("boolean"!=typeof a)throw new TypeError("calendarWeeks() expects parameter to be a boolean value");return d.calendarWeeks=a,_(),l},l.showTodayButton=function(a){if(0===arguments.length)return d.showTodayButton;if("boolean"!=typeof a)throw new TypeError("showTodayButton() expects a boolean parameter");return d.showTodayButton=a,o&&(ba(),ga()),l},l.showClear=function(a){if(0===arguments.length)return d.showClear;if("boolean"!=typeof a)throw new TypeError("showClear() expects a boolean parameter");return d.showClear=a,o&&(ba(),ga()),l},l.widgetParent=function(b){if(0===arguments.length)return d.widgetParent;if("string"==typeof b&&(b=a(b)),null!==b&&"string"!=typeof b&&!(b instanceof a))throw new TypeError("widgetParent() expects a string or a jQuery object parameter");return d.widgetParent=b,o&&(ba(),ga()),l},l.keepOpen=function(a){if(0===arguments.length)return d.keepOpen;if("boolean"!=typeof a)throw new TypeError("keepOpen() expects a boolean parameter");return d.keepOpen=a,l},l.focusOnShow=function(a){if(0===arguments.length)return d.focusOnShow;if("boolean"!=typeof a)throw new TypeError("focusOnShow() expects a boolean parameter");return d.focusOnShow=a,l},l.inline=function(a){if(0===arguments.length)return d.inline;if("boolean"!=typeof a)throw new TypeError("inline() expects a boolean parameter");return d.inline=a,l},l.clear=function(){return ca(),l},l.keyBinds=function(a){return 0===arguments.length?d.keyBinds:(d.keyBinds=a,l)},l.getMoment=function(a){return y(a)},l.debug=function(a){if("boolean"!=typeof a)throw new TypeError("debug() expects a boolean parameter");return d.debug=a,l},l.allowInputToggle=function(a){if(0===arguments.length)return d.allowInputToggle;if("boolean"!=typeof a)throw new TypeError("allowInputToggle() expects a boolean parameter");return d.allowInputToggle=a,l},l.showClose=function(a){if(0===arguments.length)return d.showClose;if("boolean"!=typeof a)throw new TypeError("showClose() expects a boolean parameter");return d.showClose=a,l},l.keepInvalid=function(a){if(0===arguments.length)return d.keepInvalid;if("boolean"!=typeof a)throw new TypeError("keepInvalid() expects a boolean parameter");
|
605 |
-
return d.keepInvalid=a,l},l.datepickerInput=function(a){if(0===arguments.length)return d.datepickerInput;if("string"!=typeof a)throw new TypeError("datepickerInput() expects a string parameter");return d.datepickerInput=a,l},l.parseInputDate=function(a){if(0===arguments.length)return d.parseInputDate;if("function"!=typeof a)throw new TypeError("parseInputDate() sholud be as function");return d.parseInputDate=a,l},l.disabledTimeIntervals=function(b){if(0===arguments.length)return d.disabledTimeIntervals?a.extend({},d.disabledTimeIntervals):d.disabledTimeIntervals;if(!b)return d.disabledTimeIntervals=!1,_(),l;if(!(b instanceof Array))throw new TypeError("disabledTimeIntervals() expects an array parameter");return d.disabledTimeIntervals=b,_(),l},l.disabledHours=function(b){if(0===arguments.length)return d.disabledHours?a.extend({},d.disabledHours):d.disabledHours;if(!b)return d.disabledHours=!1,_(),l;if(!(b instanceof Array))throw new TypeError("disabledHours() expects an array parameter");if(d.disabledHours=oa(b),d.enabledHours=!1,d.useCurrent&&!d.keepInvalid){for(var c=0;!R(e,"h");){if(e.add(1,"h"),24===c)throw"Tried 24 times to find a valid date";c++}aa(e)}return _(),l},l.enabledHours=function(b){if(0===arguments.length)return d.enabledHours?a.extend({},d.enabledHours):d.enabledHours;if(!b)return d.enabledHours=!1,_(),l;if(!(b instanceof Array))throw new TypeError("enabledHours() expects an array parameter");if(d.enabledHours=oa(b),d.disabledHours=!1,d.useCurrent&&!d.keepInvalid){for(var c=0;!R(e,"h");){if(e.add(1,"h"),24===c)throw"Tried 24 times to find a valid date";c++}aa(e)}return _(),l},l.viewDate=function(a){if(0===arguments.length)return f.clone();if(!a)return f=e.clone(),l;if(!("string"==typeof a||b.isMoment(a)||a instanceof Date))throw new TypeError("viewDate() parameter must be one of [string, moment or Date]");return f=da(a),K(),l},c.is("input"))g=c;else if(g=c.find(d.datepickerInput),0===g.length)g=c.find("input");else if(!g.is("input"))throw new Error('CSS class "'+d.datepickerInput+'" cannot be applied to non input element');if(c.hasClass("input-group")&&(n=0===c.find(".datepickerbutton").length?c.find(".input-group-addon"):c.find(".datepickerbutton")),!d.inline&&!g.is("input"))throw new Error("Could not initialize DateTimePicker without an input element");return e=y(),f=e.clone(),a.extend(!0,d,H()),l.options(d),pa(),la(),g.prop("disabled")&&l.disable(),g.is("input")&&0!==g.val().trim().length?aa(da(g.val().trim())):d.defaultDate&&void 0===g.attr("placeholder")&&aa(d.defaultDate),d.inline&&ga(),l};return a.fn.datetimepicker=function(b){b=b||{};var d,e=Array.prototype.slice.call(arguments,1),f=!0,g=["destroy","hide","show","toggle"];if("object"==typeof b)return this.each(function(){var d,e=a(this);e.data("DateTimePicker")||(d=a.extend(!0,{},a.fn.datetimepicker.defaults,b),e.data("DateTimePicker",c(e,d)))});if("string"==typeof b)return this.each(function(){var c=a(this),g=c.data("DateTimePicker");if(!g)throw new Error('bootstrap-datetimepicker("'+b+'") method was called on an element that is not using DateTimePicker');d=g[b].apply(g,e),f=d===g}),f||a.inArray(b,g)>-1?this:d;throw new TypeError("Invalid arguments for DateTimePicker: "+b)},a.fn.datetimepicker.defaults={timeZone:"",format:!1,dayViewHeaderFormat:"MMMM YYYY",extraFormats:!1,stepping:1,minDate:!1,maxDate:!1,useCurrent:!0,collapse:!0,locale:b.locale(),defaultDate:!1,disabledDates:!1,enabledDates:!1,icons:{time:"glyphicon glyphicon-time",date:"glyphicon glyphicon-calendar",up:"glyphicon glyphicon-chevron-up",down:"glyphicon glyphicon-chevron-down",previous:"glyphicon glyphicon-chevron-left",next:"glyphicon glyphicon-chevron-right",today:"glyphicon glyphicon-screenshot",clear:"glyphicon glyphicon-trash",close:"glyphicon glyphicon-remove"},tooltips:{today:"Go to today",clear:"Clear selection",close:"Close the picker",selectMonth:"Select Month",prevMonth:"Previous Month",nextMonth:"Next Month",selectYear:"Select Year",prevYear:"Previous Year",nextYear:"Next Year",selectDecade:"Select Decade",prevDecade:"Previous Decade",nextDecade:"Next Decade",prevCentury:"Previous Century",nextCentury:"Next Century",pickHour:"Pick Hour",incrementHour:"Increment Hour",decrementHour:"Decrement Hour",pickMinute:"Pick Minute",incrementMinute:"Increment Minute",decrementMinute:"Decrement Minute",pickSecond:"Pick Second",incrementSecond:"Increment Second",decrementSecond:"Decrement Second",togglePeriod:"Toggle Period",selectTime:"Select Time"},useStrict:!1,sideBySide:!1,daysOfWeekDisabled:!1,calendarWeeks:!1,viewMode:"days",toolbarPlacement:"default",showTodayButton:!1,showClear:!1,showClose:!1,widgetPositioning:{horizontal:"auto",vertical:"auto"},widgetParent:null,ignoreReadonly:!1,keepOpen:!1,focusOnShow:!0,inline:!1,keepInvalid:!1,datepickerInput:".datepickerinput",keyBinds:{up:function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")?this.date(b.clone().subtract(7,"d")):this.date(b.clone().add(this.stepping(),"m"))}},down:function(a){if(!a)return void this.show();var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")?this.date(b.clone().add(7,"d")):this.date(b.clone().subtract(this.stepping(),"m"))},"control up":function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")?this.date(b.clone().subtract(1,"y")):this.date(b.clone().add(1,"h"))}},"control down":function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")?this.date(b.clone().add(1,"y")):this.date(b.clone().subtract(1,"h"))}},left:function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")&&this.date(b.clone().subtract(1,"d"))}},right:function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")&&this.date(b.clone().add(1,"d"))}},pageUp:function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")&&this.date(b.clone().subtract(1,"M"))}},pageDown:function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")&&this.date(b.clone().add(1,"M"))}},enter:function(){this.hide()},escape:function(){this.hide()},"control space":function(a){a&&a.find(".timepicker").is(":visible")&&a.find('.btn[data-action="togglePeriod"]').click()},t:function(){this.date(this.getMoment())},delete:function(){this.clear()}},debug:!1,allowInputToggle:!1,disabledTimeIntervals:!1,disabledHours:!1,enabledHours:!1,viewDate:!1},a.fn.datetimepicker});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
602 |
// Bootstrap datapicker
|
603 |
// https://eonasdan.github.io/bootstrap-datetimepicker/
|
604 |
!function(a){"use strict";if("function"==typeof define&&define.amd)define(["jquery","moment"],a);else if("object"==typeof exports)module.exports=a(require("jquery"),require("moment"));else{if("undefined"==typeof jQuery)throw"bootstrap-datetimepicker requires jQuery to be loaded first";if("undefined"==typeof moment)throw"bootstrap-datetimepicker requires Moment.js to be loaded first";a(jQuery,moment)}}(function(a,b){"use strict";if(!b)throw new Error("bootstrap-datetimepicker requires Moment.js to be loaded first");var c=function(c,d){var e,f,g,h,i,j,k,l={},m=!0,n=!1,o=!1,p=0,q=[{clsName:"days",navFnc:"M",navStep:1},{clsName:"months",navFnc:"y",navStep:1},{clsName:"years",navFnc:"y",navStep:10},{clsName:"decades",navFnc:"y",navStep:100}],r=["days","months","years","decades"],s=["top","bottom","auto"],t=["left","right","auto"],u=["default","top","bottom"],v={up:38,38:"up",down:40,40:"down",left:37,37:"left",right:39,39:"right",tab:9,9:"tab",escape:27,27:"escape",enter:13,13:"enter",pageUp:33,33:"pageUp",pageDown:34,34:"pageDown",shift:16,16:"shift",control:17,17:"control",space:32,32:"space",t:84,84:"t",delete:46,46:"delete"},w={},x=function(){return void 0!==b.tz&&void 0!==d.timeZone&&null!==d.timeZone&&""!==d.timeZone},y=function(a){var c;return c=void 0===a||null===a?b():b.isDate(a)||b.isMoment(a)?b(a):x()?b.tz(a,j,d.useStrict,d.timeZone):b(a,j,d.useStrict),x()&&c.tz(d.timeZone),c},z=function(a){if("string"!=typeof a||a.length>1)throw new TypeError("isEnabled expects a single character string parameter");switch(a){case"y":return i.indexOf("Y")!==-1;case"M":return i.indexOf("M")!==-1;case"d":return i.toLowerCase().indexOf("d")!==-1;case"h":case"H":return i.toLowerCase().indexOf("h")!==-1;case"m":return i.indexOf("m")!==-1;case"s":return i.indexOf("s")!==-1;default:return!1}},A=function(){return z("h")||z("m")||z("s")},B=function(){return z("y")||z("M")||z("d")},C=function(){var b=a("<thead>").append(a("<tr>").append(a("<th>").addClass("prev").attr("data-action","previous").append(a("<span>").addClass(d.icons.previous))).append(a("<th>").addClass("picker-switch").attr("data-action","pickerSwitch").attr("colspan",d.calendarWeeks?"6":"5")).append(a("<th>").addClass("next").attr("data-action","next").append(a("<span>").addClass(d.icons.next)))),c=a("<tbody>").append(a("<tr>").append(a("<td>").attr("colspan",d.calendarWeeks?"8":"7")));return[a("<div>").addClass("datepicker-days").append(a("<table>").addClass("table-condensed").append(b).append(a("<tbody>"))),a("<div>").addClass("datepicker-months").append(a("<table>").addClass("table-condensed").append(b.clone()).append(c.clone())),a("<div>").addClass("datepicker-years").append(a("<table>").addClass("table-condensed").append(b.clone()).append(c.clone())),a("<div>").addClass("datepicker-decades").append(a("<table>").addClass("table-condensed").append(b.clone()).append(c.clone()))]},D=function(){var b=a("<tr>"),c=a("<tr>"),e=a("<tr>");return z("h")&&(b.append(a("<td>").append(a("<a>").attr({href:"#",tabindex:"-1",title:d.tooltips.incrementHour}).addClass("btn").attr("data-action","incrementHours").append(a("<span>").addClass(d.icons.up)))),c.append(a("<td>").append(a("<span>").addClass("timepicker-hour").attr({"data-time-component":"hours",title:d.tooltips.pickHour}).attr("data-action","showHours"))),e.append(a("<td>").append(a("<a>").attr({href:"#",tabindex:"-1",title:d.tooltips.decrementHour}).addClass("btn").attr("data-action","decrementHours").append(a("<span>").addClass(d.icons.down))))),z("m")&&(z("h")&&(b.append(a("<td>").addClass("separator")),c.append(a("<td>").addClass("separator").html(":")),e.append(a("<td>").addClass("separator"))),b.append(a("<td>").append(a("<a>").attr({href:"#",tabindex:"-1",title:d.tooltips.incrementMinute}).addClass("btn").attr("data-action","incrementMinutes").append(a("<span>").addClass(d.icons.up)))),c.append(a("<td>").append(a("<span>").addClass("timepicker-minute").attr({"data-time-component":"minutes",title:d.tooltips.pickMinute}).attr("data-action","showMinutes"))),e.append(a("<td>").append(a("<a>").attr({href:"#",tabindex:"-1",title:d.tooltips.decrementMinute}).addClass("btn").attr("data-action","decrementMinutes").append(a("<span>").addClass(d.icons.down))))),z("s")&&(z("m")&&(b.append(a("<td>").addClass("separator")),c.append(a("<td>").addClass("separator").html(":")),e.append(a("<td>").addClass("separator"))),b.append(a("<td>").append(a("<a>").attr({href:"#",tabindex:"-1",title:d.tooltips.incrementSecond}).addClass("btn").attr("data-action","incrementSeconds").append(a("<span>").addClass(d.icons.up)))),c.append(a("<td>").append(a("<span>").addClass("timepicker-second").attr({"data-time-component":"seconds",title:d.tooltips.pickSecond}).attr("data-action","showSeconds"))),e.append(a("<td>").append(a("<a>").attr({href:"#",tabindex:"-1",title:d.tooltips.decrementSecond}).addClass("btn").attr("data-action","decrementSeconds").append(a("<span>").addClass(d.icons.down))))),h||(b.append(a("<td>").addClass("separator")),c.append(a("<td>").append(a("<button>").addClass("btn btn-primary").attr({"data-action":"togglePeriod",tabindex:"-1",title:d.tooltips.togglePeriod}))),e.append(a("<td>").addClass("separator"))),a("<div>").addClass("timepicker-picker").append(a("<table>").addClass("table-condensed").append([b,c,e]))},E=function(){var b=a("<div>").addClass("timepicker-hours").append(a("<table>").addClass("table-condensed")),c=a("<div>").addClass("timepicker-minutes").append(a("<table>").addClass("table-condensed")),d=a("<div>").addClass("timepicker-seconds").append(a("<table>").addClass("table-condensed")),e=[D()];return z("h")&&e.push(b),z("m")&&e.push(c),z("s")&&e.push(d),e},F=function(){var b=[];return d.showTodayButton&&b.push(a("<td>").append(a("<a>").attr({"data-action":"today",title:d.tooltips.today}).append(a("<span>").addClass(d.icons.today)))),!d.sideBySide&&B()&&A()&&b.push(a("<td>").append(a("<a>").attr({"data-action":"togglePicker",title:d.tooltips.selectTime}).append(a("<span>").addClass(d.icons.time)))),d.showClear&&b.push(a("<td>").append(a("<a>").attr({"data-action":"clear",title:d.tooltips.clear}).append(a("<span>").addClass(d.icons.clear)))),d.showClose&&b.push(a("<td>").append(a("<a>").attr({"data-action":"close",title:d.tooltips.close}).append(a("<span>").addClass(d.icons.close)))),a("<table>").addClass("table-condensed").append(a("<tbody>").append(a("<tr>").append(b)))},G=function(){var b=a("<div>").addClass("bootstrap-datetimepicker-widget dropdown-menu"),c=a("<div>").addClass("datepicker").append(C()),e=a("<div>").addClass("timepicker").append(E()),f=a("<ul>").addClass("list-unstyled"),g=a("<li>").addClass("picker-switch"+(d.collapse?" accordion-toggle":"")).append(F());return d.inline&&b.removeClass("dropdown-menu"),h&&b.addClass("usetwentyfour"),z("s")&&!h&&b.addClass("wider"),d.sideBySide&&B()&&A()?(b.addClass("timepicker-sbs"),"top"===d.toolbarPlacement&&b.append(g),b.append(a("<div>").addClass("row").append(c.addClass("col-md-6")).append(e.addClass("col-md-6"))),"bottom"===d.toolbarPlacement&&b.append(g),b):("top"===d.toolbarPlacement&&f.append(g),B()&&f.append(a("<li>").addClass(d.collapse&&A()?"collapse in":"").append(c)),"default"===d.toolbarPlacement&&f.append(g),A()&&f.append(a("<li>").addClass(d.collapse&&B()?"collapse":"").append(e)),"bottom"===d.toolbarPlacement&&f.append(g),b.append(f))},H=function(){var b,e={};return b=c.is("input")||d.inline?c.data():c.find("input").data(),b.dateOptions&&b.dateOptions instanceof Object&&(e=a.extend(!0,e,b.dateOptions)),a.each(d,function(a){var c="date"+a.charAt(0).toUpperCase()+a.slice(1);void 0!==b[c]&&(e[a]=b[c])}),e},I=function(){var b,e=(n||c).position(),f=(n||c).offset(),g=d.widgetPositioning.vertical,h=d.widgetPositioning.horizontal;if(d.widgetParent)b=d.widgetParent.append(o);else if(c.is("input"))b=c.after(o).parent();else{if(d.inline)return void(b=c.append(o));b=c,c.children().first().after(o)}if("auto"===g&&(g=f.top+1.5*o.height()>=a(window).height()+a(window).scrollTop()&&o.height()+c.outerHeight()<f.top?"top":"bottom"),"auto"===h&&(h=b.width()<f.left+o.outerWidth()/2&&f.left+o.outerWidth()>a(window).width()?"right":"left"),"top"===g?o.addClass("top").removeClass("bottom"):o.addClass("bottom").removeClass("top"),"right"===h?o.addClass("pull-right"):o.removeClass("pull-right"),"static"===b.css("position")&&(b=b.parents().filter(function(){return"static"!==a(this).css("position")}).first()),0===b.length)throw new Error("datetimepicker component should be placed within a non-static positioned container");o.css({top:"top"===g?"auto":e.top+c.outerHeight(),bottom:"top"===g?b.outerHeight()-(b===c?0:e.top):"auto",left:"left"===h?b===c?0:e.left:"auto",right:"left"===h?"auto":b.outerWidth()-c.outerWidth()-(b===c?0:e.left)})},J=function(a){"dp.change"===a.type&&(a.date&&a.date.isSame(a.oldDate)||!a.date&&!a.oldDate)||c.trigger(a)},K=function(a){"y"===a&&(a="YYYY"),J({type:"dp.update",change:a,viewDate:f.clone()})},L=function(a){o&&(a&&(k=Math.max(p,Math.min(3,k+a))),o.find(".datepicker > div").hide().filter(".datepicker-"+q[k].clsName).show())},M=function(){var b=a("<tr>"),c=f.clone().startOf("w").startOf("d");for(d.calendarWeeks===!0&&b.append(a("<th>").addClass("cw").text("#"));c.isBefore(f.clone().endOf("w"));)b.append(a("<th>").addClass("dow").text(c.format("dd"))),c.add(1,"d");o.find(".datepicker-days thead").append(b)},N=function(a){return d.disabledDates[a.format("YYYY-MM-DD")]===!0},O=function(a){return d.enabledDates[a.format("YYYY-MM-DD")]===!0},P=function(a){return d.disabledHours[a.format("H")]===!0},Q=function(a){return d.enabledHours[a.format("H")]===!0},R=function(b,c){if(!b.isValid())return!1;if(d.disabledDates&&"d"===c&&N(b))return!1;if(d.enabledDates&&"d"===c&&!O(b))return!1;if(d.minDate&&b.isBefore(d.minDate,c))return!1;if(d.maxDate&&b.isAfter(d.maxDate,c))return!1;if(d.daysOfWeekDisabled&&"d"===c&&d.daysOfWeekDisabled.indexOf(b.day())!==-1)return!1;if(d.disabledHours&&("h"===c||"m"===c||"s"===c)&&P(b))return!1;if(d.enabledHours&&("h"===c||"m"===c||"s"===c)&&!Q(b))return!1;if(d.disabledTimeIntervals&&("h"===c||"m"===c||"s"===c)){var e=!1;if(a.each(d.disabledTimeIntervals,function(){if(b.isBetween(this[0],this[1]))return e=!0,!1}),e)return!1}return!0},S=function(){for(var b=[],c=f.clone().startOf("y").startOf("d");c.isSame(f,"y");)b.push(a("<span>").attr("data-action","selectMonth").addClass("month").text(c.format("MMM"))),c.add(1,"M");o.find(".datepicker-months td").empty().append(b)},T=function(){var b=o.find(".datepicker-months"),c=b.find("th"),g=b.find("tbody").find("span");c.eq(0).find("span").attr("title",d.tooltips.prevYear),c.eq(1).attr("title",d.tooltips.selectYear),c.eq(2).find("span").attr("title",d.tooltips.nextYear),b.find(".disabled").removeClass("disabled"),R(f.clone().subtract(1,"y"),"y")||c.eq(0).addClass("disabled"),c.eq(1).text(f.year()),R(f.clone().add(1,"y"),"y")||c.eq(2).addClass("disabled"),g.removeClass("active"),e.isSame(f,"y")&&!m&&g.eq(e.month()).addClass("active"),g.each(function(b){R(f.clone().month(b),"M")||a(this).addClass("disabled")})},U=function(){var a=o.find(".datepicker-years"),b=a.find("th"),c=f.clone().subtract(5,"y"),g=f.clone().add(6,"y"),h="";for(b.eq(0).find("span").attr("title",d.tooltips.prevDecade),b.eq(1).attr("title",d.tooltips.selectDecade),b.eq(2).find("span").attr("title",d.tooltips.nextDecade),a.find(".disabled").removeClass("disabled"),d.minDate&&d.minDate.isAfter(c,"y")&&b.eq(0).addClass("disabled"),b.eq(1).text(c.year()+"-"+g.year()),d.maxDate&&d.maxDate.isBefore(g,"y")&&b.eq(2).addClass("disabled");!c.isAfter(g,"y");)h+='<span data-action="selectYear" class="year'+(c.isSame(e,"y")&&!m?" active":"")+(R(c,"y")?"":" disabled")+'">'+c.year()+"</span>",c.add(1,"y");a.find("td").html(h)},V=function(){var a,c=o.find(".datepicker-decades"),g=c.find("th"),h=b({y:f.year()-f.year()%100-1}),i=h.clone().add(100,"y"),j=h.clone(),k=!1,l=!1,m="";for(g.eq(0).find("span").attr("title",d.tooltips.prevCentury),g.eq(2).find("span").attr("title",d.tooltips.nextCentury),c.find(".disabled").removeClass("disabled"),(h.isSame(b({y:1900}))||d.minDate&&d.minDate.isAfter(h,"y"))&&g.eq(0).addClass("disabled"),g.eq(1).text(h.year()+"-"+i.year()),(h.isSame(b({y:2e3}))||d.maxDate&&d.maxDate.isBefore(i,"y"))&&g.eq(2).addClass("disabled");!h.isAfter(i,"y");)a=h.year()+12,k=d.minDate&&d.minDate.isAfter(h,"y")&&d.minDate.year()<=a,l=d.maxDate&&d.maxDate.isAfter(h,"y")&&d.maxDate.year()<=a,m+='<span data-action="selectDecade" class="decade'+(e.isAfter(h)&&e.year()<=a?" active":"")+(R(h,"y")||k||l?"":" disabled")+'" data-selection="'+(h.year()+6)+'">'+(h.year()+1)+" - "+(h.year()+12)+"</span>",h.add(12,"y");m+="<span></span><span></span><span></span>",c.find("td").html(m),g.eq(1).text(j.year()+1+"-"+h.year())},W=function(){var b,c,g,h=o.find(".datepicker-days"),i=h.find("th"),j=[],k=[];if(B()){for(i.eq(0).find("span").attr("title",d.tooltips.prevMonth),i.eq(1).attr("title",d.tooltips.selectMonth),i.eq(2).find("span").attr("title",d.tooltips.nextMonth),h.find(".disabled").removeClass("disabled"),i.eq(1).text(f.format(d.dayViewHeaderFormat)),R(f.clone().subtract(1,"M"),"M")||i.eq(0).addClass("disabled"),R(f.clone().add(1,"M"),"M")||i.eq(2).addClass("disabled"),b=f.clone().startOf("M").startOf("w").startOf("d"),g=0;g<42;g++)0===b.weekday()&&(c=a("<tr>"),d.calendarWeeks&&c.append('<td class="cw">'+b.week()+"</td>"),j.push(c)),k=["day"],b.isBefore(f,"M")&&k.push("old"),b.isAfter(f,"M")&&k.push("new"),b.isSame(e,"d")&&!m&&k.push("active"),R(b,"d")||k.push("disabled"),b.isSame(y(),"d")&&k.push("today"),0!==b.day()&&6!==b.day()||k.push("weekend"),J({type:"dp.classify",date:b,classNames:k}),c.append('<td data-action="selectDay" data-day="'+b.format("L")+'" class="'+k.join(" ")+'">'+b.date()+"</td>"),b.add(1,"d");h.find("tbody").empty().append(j),T(),U(),V()}},X=function(){var b=o.find(".timepicker-hours table"),c=f.clone().startOf("d"),d=[],e=a("<tr>");for(f.hour()>11&&!h&&c.hour(12);c.isSame(f,"d")&&(h||f.hour()<12&&c.hour()<12||f.hour()>11);)c.hour()%4===0&&(e=a("<tr>"),d.push(e)),e.append('<td data-action="selectHour" class="hour'+(R(c,"h")?"":" disabled")+'">'+c.format(h?"HH":"hh")+"</td>"),c.add(1,"h");b.empty().append(d)},Y=function(){for(var b=o.find(".timepicker-minutes table"),c=f.clone().startOf("h"),e=[],g=a("<tr>"),h=1===d.stepping?5:d.stepping;f.isSame(c,"h");)c.minute()%(4*h)===0&&(g=a("<tr>"),e.push(g)),g.append('<td data-action="selectMinute" class="minute'+(R(c,"m")?"":" disabled")+'">'+c.format("mm")+"</td>"),c.add(h,"m");b.empty().append(e)},Z=function(){for(var b=o.find(".timepicker-seconds table"),c=f.clone().startOf("m"),d=[],e=a("<tr>");f.isSame(c,"m");)c.second()%20===0&&(e=a("<tr>"),d.push(e)),e.append('<td data-action="selectSecond" class="second'+(R(c,"s")?"":" disabled")+'">'+c.format("ss")+"</td>"),c.add(5,"s");b.empty().append(d)},$=function(){var a,b,c=o.find(".timepicker span[data-time-component]");h||(a=o.find(".timepicker [data-action=togglePeriod]"),b=e.clone().add(e.hours()>=12?-12:12,"h"),a.text(e.format("A")),R(b,"h")?a.removeClass("disabled"):a.addClass("disabled")),c.filter("[data-time-component=hours]").text(e.format(h?"HH":"hh")),c.filter("[data-time-component=minutes]").text(e.format("mm")),c.filter("[data-time-component=seconds]").text(e.format("ss")),X(),Y(),Z()},_=function(){o&&(W(),$())},aa=function(a){var b=m?null:e;if(!a)return m=!0,g.val(""),c.data("date",""),J({type:"dp.change",date:!1,oldDate:b}),void _();if(a=a.clone().locale(d.locale),x()&&a.tz(d.timeZone),1!==d.stepping)for(a.minutes(Math.round(a.minutes()/d.stepping)*d.stepping).seconds(0);d.minDate&&a.isBefore(d.minDate);)a.add(d.stepping,"minutes");R(a)?(e=a,f=e.clone(),g.val(e.format(i)),c.data("date",e.format(i)),m=!1,_(),J({type:"dp.change",date:e.clone(),oldDate:b})):(d.keepInvalid?J({type:"dp.change",date:a,oldDate:b}):g.val(m?"":e.format(i)),J({type:"dp.error",date:a,oldDate:b}))},ba=function(){var b=!1;return o?(o.find(".collapse").each(function(){var c=a(this).data("collapse");return!c||!c.transitioning||(b=!0,!1)}),b?l:(n&&n.hasClass("btn")&&n.toggleClass("active"),o.hide(),a(window).off("resize",I),o.off("click","[data-action]"),o.off("mousedown",!1),o.remove(),o=!1,J({type:"dp.hide",date:e.clone()}),g.blur(),f=e.clone(),l)):l},ca=function(){aa(null)},da=function(a){return void 0===d.parseInputDate?(!b.isMoment(a)||a instanceof Date)&&(a=y(a)):a=d.parseInputDate(a),a},ea={next:function(){var a=q[k].navFnc;f.add(q[k].navStep,a),W(),K(a)},previous:function(){var a=q[k].navFnc;f.subtract(q[k].navStep,a),W(),K(a)},pickerSwitch:function(){L(1)},selectMonth:function(b){var c=a(b.target).closest("tbody").find("span").index(a(b.target));f.month(c),k===p?(aa(e.clone().year(f.year()).month(f.month())),d.inline||ba()):(L(-1),W()),K("M")},selectYear:function(b){var c=parseInt(a(b.target).text(),10)||0;f.year(c),k===p?(aa(e.clone().year(f.year())),d.inline||ba()):(L(-1),W()),K("YYYY")},selectDecade:function(b){var c=parseInt(a(b.target).data("selection"),10)||0;f.year(c),k===p?(aa(e.clone().year(f.year())),d.inline||ba()):(L(-1),W()),K("YYYY")},selectDay:function(b){var c=f.clone();a(b.target).is(".old")&&c.subtract(1,"M"),a(b.target).is(".new")&&c.add(1,"M"),aa(c.date(parseInt(a(b.target).text(),10))),A()||d.keepOpen||d.inline||ba()},incrementHours:function(){var a=e.clone().add(1,"h");R(a,"h")&&aa(a)},incrementMinutes:function(){var a=e.clone().add(d.stepping,"m");R(a,"m")&&aa(a)},incrementSeconds:function(){var a=e.clone().add(1,"s");R(a,"s")&&aa(a)},decrementHours:function(){var a=e.clone().subtract(1,"h");R(a,"h")&&aa(a)},decrementMinutes:function(){var a=e.clone().subtract(d.stepping,"m");R(a,"m")&&aa(a)},decrementSeconds:function(){var a=e.clone().subtract(1,"s");R(a,"s")&&aa(a)},togglePeriod:function(){aa(e.clone().add(e.hours()>=12?-12:12,"h"))},togglePicker:function(b){var c,e=a(b.target),f=e.closest("ul"),g=f.find(".in"),h=f.find(".collapse:not(.in)");if(g&&g.length){if(c=g.data("collapse"),c&&c.transitioning)return;g.collapse?(g.collapse("hide"),h.collapse("show")):(g.removeClass("in"),h.addClass("in")),e.is("span")?e.toggleClass(d.icons.time+" "+d.icons.date):e.find("span").toggleClass(d.icons.time+" "+d.icons.date)}},showPicker:function(){o.find(".timepicker > div:not(.timepicker-picker)").hide(),o.find(".timepicker .timepicker-picker").show()},showHours:function(){o.find(".timepicker .timepicker-picker").hide(),o.find(".timepicker .timepicker-hours").show()},showMinutes:function(){o.find(".timepicker .timepicker-picker").hide(),o.find(".timepicker .timepicker-minutes").show()},showSeconds:function(){o.find(".timepicker .timepicker-picker").hide(),o.find(".timepicker .timepicker-seconds").show()},selectHour:function(b){var c=parseInt(a(b.target).text(),10);h||(e.hours()>=12?12!==c&&(c+=12):12===c&&(c=0)),aa(e.clone().hours(c)),ea.showPicker.call(l)},selectMinute:function(b){aa(e.clone().minutes(parseInt(a(b.target).text(),10))),ea.showPicker.call(l)},selectSecond:function(b){aa(e.clone().seconds(parseInt(a(b.target).text(),10))),ea.showPicker.call(l)},clear:ca,today:function(){var a=y();R(a,"d")&&aa(a)},close:ba},fa=function(b){return!a(b.currentTarget).is(".disabled")&&(ea[a(b.currentTarget).data("action")].apply(l,arguments),!1)},ga=function(){var b,c={year:function(a){return a.month(0).date(1).hours(0).seconds(0).minutes(0)},month:function(a){return a.date(1).hours(0).seconds(0).minutes(0)},day:function(a){return a.hours(0).seconds(0).minutes(0)},hour:function(a){return a.seconds(0).minutes(0)},minute:function(a){return a.seconds(0)}};return g.prop("disabled")||!d.ignoreReadonly&&g.prop("readonly")||o?l:(void 0!==g.val()&&0!==g.val().trim().length?aa(da(g.val().trim())):m&&d.useCurrent&&(d.inline||g.is("input")&&0===g.val().trim().length)&&(b=y(),"string"==typeof d.useCurrent&&(b=c[d.useCurrent](b)),aa(b)),o=G(),M(),S(),o.find(".timepicker-hours").hide(),o.find(".timepicker-minutes").hide(),o.find(".timepicker-seconds").hide(),_(),L(),a(window).on("resize",I),o.on("click","[data-action]",fa),o.on("mousedown",!1),n&&n.hasClass("btn")&&n.toggleClass("active"),I(),o.show(),d.focusOnShow&&!g.is(":focus")&&g.focus(),J({type:"dp.show"}),l)},ha=function(){return o?ba():ga()},ia=function(a){var b,c,e,f,g=null,h=[],i={},j=a.which,k="p";w[j]=k;for(b in w)w.hasOwnProperty(b)&&w[b]===k&&(h.push(b),parseInt(b,10)!==j&&(i[b]=!0));for(b in d.keyBinds)if(d.keyBinds.hasOwnProperty(b)&&"function"==typeof d.keyBinds[b]&&(e=b.split(" "),e.length===h.length&&v[j]===e[e.length-1])){for(f=!0,c=e.length-2;c>=0;c--)if(!(v[e[c]]in i)){f=!1;break}if(f){g=d.keyBinds[b];break}}g&&(g.call(l,o),a.stopPropagation(),a.preventDefault())},ja=function(a){w[a.which]="r",a.stopPropagation(),a.preventDefault()},ka=function(b){var c=a(b.target).val().trim(),d=c?da(c):null;return aa(d),b.stopImmediatePropagation(),!1},la=function(){g.on({change:ka,blur:d.debug?"":ba,keydown:ia,keyup:ja,focus:d.allowInputToggle?ga:""}),c.is("input")?g.on({focus:ga}):n&&(n.on("click",ha),n.on("mousedown",!1))},ma=function(){g.off({change:ka,blur:blur,keydown:ia,keyup:ja,focus:d.allowInputToggle?ba:""}),c.is("input")?g.off({focus:ga}):n&&(n.off("click",ha),n.off("mousedown",!1))},na=function(b){var c={};return a.each(b,function(){var a=da(this);a.isValid()&&(c[a.format("YYYY-MM-DD")]=!0)}),!!Object.keys(c).length&&c},oa=function(b){var c={};return a.each(b,function(){c[this]=!0}),!!Object.keys(c).length&&c},pa=function(){var a=d.format||"L LT";i=a.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,function(a){var b=e.localeData().longDateFormat(a)||a;return b.replace(/(\[[^\[]*\])|(\\)?(LTS|LT|LL?L?L?|l{1,4})/g,function(a){return e.localeData().longDateFormat(a)||a})}),j=d.extraFormats?d.extraFormats.slice():[],j.indexOf(a)<0&&j.indexOf(i)<0&&j.push(i),h=i.toLowerCase().indexOf("a")<1&&i.replace(/\[.*?\]/g,"").indexOf("h")<1,z("y")&&(p=2),z("M")&&(p=1),z("d")&&(p=0),k=Math.max(p,k),m||aa(e)};if(l.destroy=function(){ba(),ma(),c.removeData("DateTimePicker"),c.removeData("date")},l.toggle=ha,l.show=ga,l.hide=ba,l.disable=function(){return ba(),n&&n.hasClass("btn")&&n.addClass("disabled"),g.prop("disabled",!0),l},l.enable=function(){return n&&n.hasClass("btn")&&n.removeClass("disabled"),g.prop("disabled",!1),l},l.ignoreReadonly=function(a){if(0===arguments.length)return d.ignoreReadonly;if("boolean"!=typeof a)throw new TypeError("ignoreReadonly () expects a boolean parameter");return d.ignoreReadonly=a,l},l.options=function(b){if(0===arguments.length)return a.extend(!0,{},d);if(!(b instanceof Object))throw new TypeError("options() options parameter should be an object");return a.extend(!0,d,b),a.each(d,function(a,b){if(void 0===l[a])throw new TypeError("option "+a+" is not recognized!");l[a](b)}),l},l.date=function(a){if(0===arguments.length)return m?null:e.clone();if(!(null===a||"string"==typeof a||b.isMoment(a)||a instanceof Date))throw new TypeError("date() parameter must be one of [null, string, moment or Date]");return aa(null===a?null:da(a)),l},l.format=function(a){if(0===arguments.length)return d.format;if("string"!=typeof a&&("boolean"!=typeof a||a!==!1))throw new TypeError("format() expects a string or boolean:false parameter "+a);return d.format=a,i&&pa(),l},l.timeZone=function(a){if(0===arguments.length)return d.timeZone;if("string"!=typeof a)throw new TypeError("newZone() expects a string parameter");return d.timeZone=a,l},l.dayViewHeaderFormat=function(a){if(0===arguments.length)return d.dayViewHeaderFormat;if("string"!=typeof a)throw new TypeError("dayViewHeaderFormat() expects a string parameter");return d.dayViewHeaderFormat=a,l},l.extraFormats=function(a){if(0===arguments.length)return d.extraFormats;if(a!==!1&&!(a instanceof Array))throw new TypeError("extraFormats() expects an array or false parameter");return d.extraFormats=a,j&&pa(),l},l.disabledDates=function(b){if(0===arguments.length)return d.disabledDates?a.extend({},d.disabledDates):d.disabledDates;if(!b)return d.disabledDates=!1,_(),l;if(!(b instanceof Array))throw new TypeError("disabledDates() expects an array parameter");return d.disabledDates=na(b),d.enabledDates=!1,_(),l},l.enabledDates=function(b){if(0===arguments.length)return d.enabledDates?a.extend({},d.enabledDates):d.enabledDates;if(!b)return d.enabledDates=!1,_(),l;if(!(b instanceof Array))throw new TypeError("enabledDates() expects an array parameter");return d.enabledDates=na(b),d.disabledDates=!1,_(),l},l.daysOfWeekDisabled=function(a){if(0===arguments.length)return d.daysOfWeekDisabled.splice(0);if("boolean"==typeof a&&!a)return d.daysOfWeekDisabled=!1,_(),l;if(!(a instanceof Array))throw new TypeError("daysOfWeekDisabled() expects an array parameter");if(d.daysOfWeekDisabled=a.reduce(function(a,b){return b=parseInt(b,10),b>6||b<0||isNaN(b)?a:(a.indexOf(b)===-1&&a.push(b),a)},[]).sort(),d.useCurrent&&!d.keepInvalid){for(var b=0;!R(e,"d");){if(e.add(1,"d"),31===b)throw"Tried 31 times to find a valid date";b++}aa(e)}return _(),l},l.maxDate=function(a){if(0===arguments.length)return d.maxDate?d.maxDate.clone():d.maxDate;if("boolean"==typeof a&&a===!1)return d.maxDate=!1,_(),l;"string"==typeof a&&("now"!==a&&"moment"!==a||(a=y()));var b=da(a);if(!b.isValid())throw new TypeError("maxDate() Could not parse date parameter: "+a);if(d.minDate&&b.isBefore(d.minDate))throw new TypeError("maxDate() date parameter is before options.minDate: "+b.format(i));return d.maxDate=b,d.useCurrent&&!d.keepInvalid&&e.isAfter(a)&&aa(d.maxDate),f.isAfter(b)&&(f=b.clone().subtract(d.stepping,"m")),_(),l},l.minDate=function(a){if(0===arguments.length)return d.minDate?d.minDate.clone():d.minDate;if("boolean"==typeof a&&a===!1)return d.minDate=!1,_(),l;"string"==typeof a&&("now"!==a&&"moment"!==a||(a=y()));var b=da(a);if(!b.isValid())throw new TypeError("minDate() Could not parse date parameter: "+a);if(d.maxDate&&b.isAfter(d.maxDate))throw new TypeError("minDate() date parameter is after options.maxDate: "+b.format(i));return d.minDate=b,d.useCurrent&&!d.keepInvalid&&e.isBefore(a)&&aa(d.minDate),f.isBefore(b)&&(f=b.clone().add(d.stepping,"m")),_(),l},l.defaultDate=function(a){if(0===arguments.length)return d.defaultDate?d.defaultDate.clone():d.defaultDate;if(!a)return d.defaultDate=!1,l;"string"==typeof a&&(a="now"===a||"moment"===a?y():y(a));var b=da(a);if(!b.isValid())throw new TypeError("defaultDate() Could not parse date parameter: "+a);if(!R(b))throw new TypeError("defaultDate() date passed is invalid according to component setup validations");return d.defaultDate=b,(d.defaultDate&&d.inline||""===g.val().trim())&&aa(d.defaultDate),l},l.locale=function(a){if(0===arguments.length)return d.locale;if(!b.localeData(a))throw new TypeError("locale() locale "+a+" is not loaded from moment locales!");return d.locale=a,e.locale(d.locale),f.locale(d.locale),i&&pa(),o&&(ba(),ga()),l},l.stepping=function(a){return 0===arguments.length?d.stepping:(a=parseInt(a,10),(isNaN(a)||a<1)&&(a=1),d.stepping=a,l)},l.useCurrent=function(a){var b=["year","month","day","hour","minute"];if(0===arguments.length)return d.useCurrent;if("boolean"!=typeof a&&"string"!=typeof a)throw new TypeError("useCurrent() expects a boolean or string parameter");if("string"==typeof a&&b.indexOf(a.toLowerCase())===-1)throw new TypeError("useCurrent() expects a string parameter of "+b.join(", "));return d.useCurrent=a,l},l.collapse=function(a){if(0===arguments.length)return d.collapse;if("boolean"!=typeof a)throw new TypeError("collapse() expects a boolean parameter");return d.collapse===a?l:(d.collapse=a,o&&(ba(),ga()),l)},l.icons=function(b){if(0===arguments.length)return a.extend({},d.icons);if(!(b instanceof Object))throw new TypeError("icons() expects parameter to be an Object");return a.extend(d.icons,b),o&&(ba(),ga()),l},l.tooltips=function(b){if(0===arguments.length)return a.extend({},d.tooltips);if(!(b instanceof Object))throw new TypeError("tooltips() expects parameter to be an Object");return a.extend(d.tooltips,b),o&&(ba(),ga()),l},l.useStrict=function(a){if(0===arguments.length)return d.useStrict;if("boolean"!=typeof a)throw new TypeError("useStrict() expects a boolean parameter");return d.useStrict=a,l},l.sideBySide=function(a){if(0===arguments.length)return d.sideBySide;if("boolean"!=typeof a)throw new TypeError("sideBySide() expects a boolean parameter");return d.sideBySide=a,o&&(ba(),ga()),l},l.viewMode=function(a){if(0===arguments.length)return d.viewMode;if("string"!=typeof a)throw new TypeError("viewMode() expects a string parameter");if(r.indexOf(a)===-1)throw new TypeError("viewMode() parameter must be one of ("+r.join(", ")+") value");return d.viewMode=a,k=Math.max(r.indexOf(a),p),L(),l},l.toolbarPlacement=function(a){if(0===arguments.length)return d.toolbarPlacement;if("string"!=typeof a)throw new TypeError("toolbarPlacement() expects a string parameter");if(u.indexOf(a)===-1)throw new TypeError("toolbarPlacement() parameter must be one of ("+u.join(", ")+") value");return d.toolbarPlacement=a,o&&(ba(),ga()),l},l.widgetPositioning=function(b){if(0===arguments.length)return a.extend({},d.widgetPositioning);if("[object Object]"!=={}.toString.call(b))throw new TypeError("widgetPositioning() expects an object variable");if(b.horizontal){if("string"!=typeof b.horizontal)throw new TypeError("widgetPositioning() horizontal variable must be a string");if(b.horizontal=b.horizontal.toLowerCase(),t.indexOf(b.horizontal)===-1)throw new TypeError("widgetPositioning() expects horizontal parameter to be one of ("+t.join(", ")+")");d.widgetPositioning.horizontal=b.horizontal}if(b.vertical){if("string"!=typeof b.vertical)throw new TypeError("widgetPositioning() vertical variable must be a string");if(b.vertical=b.vertical.toLowerCase(),s.indexOf(b.vertical)===-1)throw new TypeError("widgetPositioning() expects vertical parameter to be one of ("+s.join(", ")+")");d.widgetPositioning.vertical=b.vertical}return _(),l},l.calendarWeeks=function(a){if(0===arguments.length)return d.calendarWeeks;if("boolean"!=typeof a)throw new TypeError("calendarWeeks() expects parameter to be a boolean value");return d.calendarWeeks=a,_(),l},l.showTodayButton=function(a){if(0===arguments.length)return d.showTodayButton;if("boolean"!=typeof a)throw new TypeError("showTodayButton() expects a boolean parameter");return d.showTodayButton=a,o&&(ba(),ga()),l},l.showClear=function(a){if(0===arguments.length)return d.showClear;if("boolean"!=typeof a)throw new TypeError("showClear() expects a boolean parameter");return d.showClear=a,o&&(ba(),ga()),l},l.widgetParent=function(b){if(0===arguments.length)return d.widgetParent;if("string"==typeof b&&(b=a(b)),null!==b&&"string"!=typeof b&&!(b instanceof a))throw new TypeError("widgetParent() expects a string or a jQuery object parameter");return d.widgetParent=b,o&&(ba(),ga()),l},l.keepOpen=function(a){if(0===arguments.length)return d.keepOpen;if("boolean"!=typeof a)throw new TypeError("keepOpen() expects a boolean parameter");return d.keepOpen=a,l},l.focusOnShow=function(a){if(0===arguments.length)return d.focusOnShow;if("boolean"!=typeof a)throw new TypeError("focusOnShow() expects a boolean parameter");return d.focusOnShow=a,l},l.inline=function(a){if(0===arguments.length)return d.inline;if("boolean"!=typeof a)throw new TypeError("inline() expects a boolean parameter");return d.inline=a,l},l.clear=function(){return ca(),l},l.keyBinds=function(a){return 0===arguments.length?d.keyBinds:(d.keyBinds=a,l)},l.getMoment=function(a){return y(a)},l.debug=function(a){if("boolean"!=typeof a)throw new TypeError("debug() expects a boolean parameter");return d.debug=a,l},l.allowInputToggle=function(a){if(0===arguments.length)return d.allowInputToggle;if("boolean"!=typeof a)throw new TypeError("allowInputToggle() expects a boolean parameter");return d.allowInputToggle=a,l},l.showClose=function(a){if(0===arguments.length)return d.showClose;if("boolean"!=typeof a)throw new TypeError("showClose() expects a boolean parameter");return d.showClose=a,l},l.keepInvalid=function(a){if(0===arguments.length)return d.keepInvalid;if("boolean"!=typeof a)throw new TypeError("keepInvalid() expects a boolean parameter");
|
605 |
+
return d.keepInvalid=a,l},l.datepickerInput=function(a){if(0===arguments.length)return d.datepickerInput;if("string"!=typeof a)throw new TypeError("datepickerInput() expects a string parameter");return d.datepickerInput=a,l},l.parseInputDate=function(a){if(0===arguments.length)return d.parseInputDate;if("function"!=typeof a)throw new TypeError("parseInputDate() sholud be as function");return d.parseInputDate=a,l},l.disabledTimeIntervals=function(b){if(0===arguments.length)return d.disabledTimeIntervals?a.extend({},d.disabledTimeIntervals):d.disabledTimeIntervals;if(!b)return d.disabledTimeIntervals=!1,_(),l;if(!(b instanceof Array))throw new TypeError("disabledTimeIntervals() expects an array parameter");return d.disabledTimeIntervals=b,_(),l},l.disabledHours=function(b){if(0===arguments.length)return d.disabledHours?a.extend({},d.disabledHours):d.disabledHours;if(!b)return d.disabledHours=!1,_(),l;if(!(b instanceof Array))throw new TypeError("disabledHours() expects an array parameter");if(d.disabledHours=oa(b),d.enabledHours=!1,d.useCurrent&&!d.keepInvalid){for(var c=0;!R(e,"h");){if(e.add(1,"h"),24===c)throw"Tried 24 times to find a valid date";c++}aa(e)}return _(),l},l.enabledHours=function(b){if(0===arguments.length)return d.enabledHours?a.extend({},d.enabledHours):d.enabledHours;if(!b)return d.enabledHours=!1,_(),l;if(!(b instanceof Array))throw new TypeError("enabledHours() expects an array parameter");if(d.enabledHours=oa(b),d.disabledHours=!1,d.useCurrent&&!d.keepInvalid){for(var c=0;!R(e,"h");){if(e.add(1,"h"),24===c)throw"Tried 24 times to find a valid date";c++}aa(e)}return _(),l},l.viewDate=function(a){if(0===arguments.length)return f.clone();if(!a)return f=e.clone(),l;if(!("string"==typeof a||b.isMoment(a)||a instanceof Date))throw new TypeError("viewDate() parameter must be one of [string, moment or Date]");return f=da(a),K(),l},c.is("input"))g=c;else if(g=c.find(d.datepickerInput),0===g.length)g=c.find("input");else if(!g.is("input"))throw new Error('CSS class "'+d.datepickerInput+'" cannot be applied to non input element');if(c.hasClass("input-group")&&(n=0===c.find(".datepickerbutton").length?c.find(".input-group-addon"):c.find(".datepickerbutton")),!d.inline&&!g.is("input"))throw new Error("Could not initialize DateTimePicker without an input element");return e=y(),f=e.clone(),a.extend(!0,d,H()),l.options(d),pa(),la(),g.prop("disabled")&&l.disable(),g.is("input")&&0!==g.val().trim().length?aa(da(g.val().trim())):d.defaultDate&&void 0===g.attr("placeholder")&&aa(d.defaultDate),d.inline&&ga(),l};return a.fn.datetimepicker=function(b){b=b||{};var d,e=Array.prototype.slice.call(arguments,1),f=!0,g=["destroy","hide","show","toggle"];if("object"==typeof b)return this.each(function(){var d,e=a(this);e.data("DateTimePicker")||(d=a.extend(!0,{},a.fn.datetimepicker.defaults,b),e.data("DateTimePicker",c(e,d)))});if("string"==typeof b)return this.each(function(){var c=a(this),g=c.data("DateTimePicker");if(!g)throw new Error('bootstrap-datetimepicker("'+b+'") method was called on an element that is not using DateTimePicker');d=g[b].apply(g,e),f=d===g}),f||a.inArray(b,g)>-1?this:d;throw new TypeError("Invalid arguments for DateTimePicker: "+b)},a.fn.datetimepicker.defaults={timeZone:"",format:!1,dayViewHeaderFormat:"MMMM YYYY",extraFormats:!1,stepping:1,minDate:!1,maxDate:!1,useCurrent:!0,collapse:!0,locale:b.locale(),defaultDate:!1,disabledDates:!1,enabledDates:!1,icons:{time:"glyphicon glyphicon-time",date:"glyphicon glyphicon-calendar",up:"glyphicon glyphicon-chevron-up",down:"glyphicon glyphicon-chevron-down",previous:"glyphicon glyphicon-chevron-left",next:"glyphicon glyphicon-chevron-right",today:"glyphicon glyphicon-screenshot",clear:"glyphicon glyphicon-trash",close:"glyphicon glyphicon-remove"},tooltips:{today:"Go to today",clear:"Clear selection",close:"Close the picker",selectMonth:"Select Month",prevMonth:"Previous Month",nextMonth:"Next Month",selectYear:"Select Year",prevYear:"Previous Year",nextYear:"Next Year",selectDecade:"Select Decade",prevDecade:"Previous Decade",nextDecade:"Next Decade",prevCentury:"Previous Century",nextCentury:"Next Century",pickHour:"Pick Hour",incrementHour:"Increment Hour",decrementHour:"Decrement Hour",pickMinute:"Pick Minute",incrementMinute:"Increment Minute",decrementMinute:"Decrement Minute",pickSecond:"Pick Second",incrementSecond:"Increment Second",decrementSecond:"Decrement Second",togglePeriod:"Toggle Period",selectTime:"Select Time"},useStrict:!1,sideBySide:!1,daysOfWeekDisabled:!1,calendarWeeks:!1,viewMode:"days",toolbarPlacement:"default",showTodayButton:!1,showClear:!1,showClose:!1,widgetPositioning:{horizontal:"auto",vertical:"auto"},widgetParent:null,ignoreReadonly:!1,keepOpen:!1,focusOnShow:!0,inline:!1,keepInvalid:!1,datepickerInput:".datepickerinput",keyBinds:{up:function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")?this.date(b.clone().subtract(7,"d")):this.date(b.clone().add(this.stepping(),"m"))}},down:function(a){if(!a)return void this.show();var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")?this.date(b.clone().add(7,"d")):this.date(b.clone().subtract(this.stepping(),"m"))},"control up":function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")?this.date(b.clone().subtract(1,"y")):this.date(b.clone().add(1,"h"))}},"control down":function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")?this.date(b.clone().add(1,"y")):this.date(b.clone().subtract(1,"h"))}},left:function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")&&this.date(b.clone().subtract(1,"d"))}},right:function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")&&this.date(b.clone().add(1,"d"))}},pageUp:function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")&&this.date(b.clone().subtract(1,"M"))}},pageDown:function(a){if(a){var b=this.date()||this.getMoment();a.find(".datepicker").is(":visible")&&this.date(b.clone().add(1,"M"))}},enter:function(){this.hide()},escape:function(){this.hide()},"control space":function(a){a&&a.find(".timepicker").is(":visible")&&a.find('.btn[data-action="togglePeriod"]').click()},t:function(){this.date(this.getMoment())},delete:function(){this.clear()}},debug:!1,allowInputToggle:!1,disabledTimeIntervals:!1,disabledHours:!1,enabledHours:!1,viewDate:!1},a.fn.datetimepicker});
|
606 |
+
|
607 |
+
/*!
|
608 |
+
* clipboard.js v2.0.4
|
609 |
+
* https://zenorocha.github.io/clipboard.js
|
610 |
+
*
|
611 |
+
* Licensed MIT © Zeno Rocha
|
612 |
+
*/
|
613 |
+
!function (t, e) { "object" == typeof exports && "object" == typeof module ? module.exports = e() : "function" == typeof define && define.amd ? define([], e) : "object" == typeof exports ? exports.ClipboardJS = e() : t.ClipboardJS = e() }(this, function () { return function (n) { var o = {}; function r(t) { if (o[t]) return o[t].exports; var e = o[t] = { i: t, l: !1, exports: {} }; return n[t].call(e.exports, e, e.exports, r), e.l = !0, e.exports } return r.m = n, r.c = o, r.d = function (t, e, n) { r.o(t, e) || Object.defineProperty(t, e, { enumerable: !0, get: n }) }, r.r = function (t) { "undefined" != typeof Symbol && Symbol.toStringTag && Object.defineProperty(t, Symbol.toStringTag, { value: "Module" }), Object.defineProperty(t, "__esModule", { value: !0 }) }, r.t = function (e, t) { if (1 & t && (e = r(e)), 8 & t) return e; if (4 & t && "object" == typeof e && e && e.__esModule) return e; var n = Object.create(null); if (r.r(n), Object.defineProperty(n, "default", { enumerable: !0, value: e }), 2 & t && "string" != typeof e) for (var o in e) r.d(n, o, function (t) { return e[t] }.bind(null, o)); return n }, r.n = function (t) { var e = t && t.__esModule ? function () { return t.default } : function () { return t }; return r.d(e, "a", e), e }, r.o = function (t, e) { return Object.prototype.hasOwnProperty.call(t, e) }, r.p = "", r(r.s = 0) }([function (t, e, n) { "use strict"; var r = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (t) { return typeof t } : function (t) { return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t }, i = function () { function o(t, e) { for (var n = 0; n < e.length; n++) { var o = e[n]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(t, o.key, o) } } return function (t, e, n) { return e && o(t.prototype, e), n && o(t, n), t } }(), a = o(n(1)), c = o(n(3)), u = o(n(4)); function o(t) { return t && t.__esModule ? t : { default: t } } var l = function (t) { function o(t, e) { !function (t, e) { if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") }(this, o); var n = function (t, e) { if (!t) throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); return !e || "object" != typeof e && "function" != typeof e ? t : e }(this, (o.__proto__ || Object.getPrototypeOf(o)).call(this)); return n.resolveOptions(e), n.listenClick(t), n } return function (t, e) { if ("function" != typeof e && null !== e) throw new TypeError("Super expression must either be null or a function, not " + typeof e); t.prototype = Object.create(e && e.prototype, { constructor: { value: t, enumerable: !1, writable: !0, configurable: !0 } }), e && (Object.setPrototypeOf ? Object.setPrototypeOf(t, e) : t.__proto__ = e) }(o, c.default), i(o, [{ key: "resolveOptions", value: function () { var t = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : {}; this.action = "function" == typeof t.action ? t.action : this.defaultAction, this.target = "function" == typeof t.target ? t.target : this.defaultTarget, this.text = "function" == typeof t.text ? t.text : this.defaultText, this.container = "object" === r(t.container) ? t.container : document.body } }, { key: "listenClick", value: function (t) { var e = this; this.listener = (0, u.default)(t, "click", function (t) { return e.onClick(t) }) } }, { key: "onClick", value: function (t) { var e = t.delegateTarget || t.currentTarget; this.clipboardAction && (this.clipboardAction = null), this.clipboardAction = new a.default({ action: this.action(e), target: this.target(e), text: this.text(e), container: this.container, trigger: e, emitter: this }) } }, { key: "defaultAction", value: function (t) { return s("action", t) } }, { key: "defaultTarget", value: function (t) { var e = s("target", t); if (e) return document.querySelector(e) } }, { key: "defaultText", value: function (t) { return s("text", t) } }, { key: "destroy", value: function () { this.listener.destroy(), this.clipboardAction && (this.clipboardAction.destroy(), this.clipboardAction = null) } }], [{ key: "isSupported", value: function () { var t = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : ["copy", "cut"], e = "string" == typeof t ? [t] : t, n = !!document.queryCommandSupported; return e.forEach(function (t) { n = n && !!document.queryCommandSupported(t) }), n } }]), o }(); function s(t, e) { var n = "data-clipboard-" + t; if (e.hasAttribute(n)) return e.getAttribute(n) } t.exports = l }, function (t, e, n) { "use strict"; var o, r = "function" == typeof Symbol && "symbol" == typeof Symbol.iterator ? function (t) { return typeof t } : function (t) { return t && "function" == typeof Symbol && t.constructor === Symbol && t !== Symbol.prototype ? "symbol" : typeof t }, i = function () { function o(t, e) { for (var n = 0; n < e.length; n++) { var o = e[n]; o.enumerable = o.enumerable || !1, o.configurable = !0, "value" in o && (o.writable = !0), Object.defineProperty(t, o.key, o) } } return function (t, e, n) { return e && o(t.prototype, e), n && o(t, n), t } }(), a = n(2), c = (o = a) && o.__esModule ? o : { default: o }; var u = function () { function e(t) { !function (t, e) { if (!(t instanceof e)) throw new TypeError("Cannot call a class as a function") }(this, e), this.resolveOptions(t), this.initSelection() } return i(e, [{ key: "resolveOptions", value: function () { var t = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : {}; this.action = t.action, this.container = t.container, this.emitter = t.emitter, this.target = t.target, this.text = t.text, this.trigger = t.trigger, this.selectedText = "" } }, { key: "initSelection", value: function () { this.text ? this.selectFake() : this.target && this.selectTarget() } }, { key: "selectFake", value: function () { var t = this, e = "rtl" == document.documentElement.getAttribute("dir"); this.removeFake(), this.fakeHandlerCallback = function () { return t.removeFake() }, this.fakeHandler = this.container.addEventListener("click", this.fakeHandlerCallback) || !0, this.fakeElem = document.createElement("textarea"), this.fakeElem.style.fontSize = "12pt", this.fakeElem.style.border = "0", this.fakeElem.style.padding = "0", this.fakeElem.style.margin = "0", this.fakeElem.style.position = "absolute", this.fakeElem.style[e ? "right" : "left"] = "-9999px"; var n = window.pageYOffset || document.documentElement.scrollTop; this.fakeElem.style.top = n + "px", this.fakeElem.setAttribute("readonly", ""), this.fakeElem.value = this.text, this.container.appendChild(this.fakeElem), this.selectedText = (0, c.default)(this.fakeElem), this.copyText() } }, { key: "removeFake", value: function () { this.fakeHandler && (this.container.removeEventListener("click", this.fakeHandlerCallback), this.fakeHandler = null, this.fakeHandlerCallback = null), this.fakeElem && (this.container.removeChild(this.fakeElem), this.fakeElem = null) } }, { key: "selectTarget", value: function () { this.selectedText = (0, c.default)(this.target), this.copyText() } }, { key: "copyText", value: function () { var e = void 0; try { e = document.execCommand(this.action) } catch (t) { e = !1 } this.handleResult(e) } }, { key: "handleResult", value: function (t) { this.emitter.emit(t ? "success" : "error", { action: this.action, text: this.selectedText, trigger: this.trigger, clearSelection: this.clearSelection.bind(this) }) } }, { key: "clearSelection", value: function () { this.trigger && this.trigger.focus(), window.getSelection().removeAllRanges() } }, { key: "destroy", value: function () { this.removeFake() } }, { key: "action", set: function () { var t = 0 < arguments.length && void 0 !== arguments[0] ? arguments[0] : "copy"; if (this._action = t, "copy" !== this._action && "cut" !== this._action) throw new Error('Invalid "action" value, use either "copy" or "cut"') }, get: function () { return this._action } }, { key: "target", set: function (t) { if (void 0 !== t) { if (!t || "object" !== (void 0 === t ? "undefined" : r(t)) || 1 !== t.nodeType) throw new Error('Invalid "target" value, use a valid Element'); if ("copy" === this.action && t.hasAttribute("disabled")) throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute'); if ("cut" === this.action && (t.hasAttribute("readonly") || t.hasAttribute("disabled"))) throw new Error('Invalid "target" attribute. You can\'t cut text from elements with "readonly" or "disabled" attributes'); this._target = t } }, get: function () { return this._target } }]), e }(); t.exports = u }, function (t, e) { t.exports = function (t) { var e; if ("SELECT" === t.nodeName) t.focus(), e = t.value; else if ("INPUT" === t.nodeName || "TEXTAREA" === t.nodeName) { var n = t.hasAttribute("readonly"); n || t.setAttribute("readonly", ""), t.select(), t.setSelectionRange(0, t.value.length), n || t.removeAttribute("readonly"), e = t.value } else { t.hasAttribute("contenteditable") && t.focus(); var o = window.getSelection(), r = document.createRange(); r.selectNodeContents(t), o.removeAllRanges(), o.addRange(r), e = o.toString() } return e } }, function (t, e) { function n() { } n.prototype = { on: function (t, e, n) { var o = this.e || (this.e = {}); return (o[t] || (o[t] = [])).push({ fn: e, ctx: n }), this }, once: function (t, e, n) { var o = this; function r() { o.off(t, r), e.apply(n, arguments) } return r._ = e, this.on(t, r, n) }, emit: function (t) { for (var e = [].slice.call(arguments, 1), n = ((this.e || (this.e = {}))[t] || []).slice(), o = 0, r = n.length; o < r; o++)n[o].fn.apply(n[o].ctx, e); return this }, off: function (t, e) { var n = this.e || (this.e = {}), o = n[t], r = []; if (o && e) for (var i = 0, a = o.length; i < a; i++)o[i].fn !== e && o[i].fn._ !== e && r.push(o[i]); return r.length ? n[t] = r : delete n[t], this } }, t.exports = n }, function (t, e, n) { var d = n(5), h = n(6); t.exports = function (t, e, n) { if (!t && !e && !n) throw new Error("Missing required arguments"); if (!d.string(e)) throw new TypeError("Second argument must be a String"); if (!d.fn(n)) throw new TypeError("Third argument must be a Function"); if (d.node(t)) return s = e, f = n, (l = t).addEventListener(s, f), { destroy: function () { l.removeEventListener(s, f) } }; if (d.nodeList(t)) return a = t, c = e, u = n, Array.prototype.forEach.call(a, function (t) { t.addEventListener(c, u) }), { destroy: function () { Array.prototype.forEach.call(a, function (t) { t.removeEventListener(c, u) }) } }; if (d.string(t)) return o = t, r = e, i = n, h(document.body, o, r, i); throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList"); var o, r, i, a, c, u, l, s, f } }, function (t, n) { n.node = function (t) { return void 0 !== t && t instanceof HTMLElement && 1 === t.nodeType }, n.nodeList = function (t) { var e = Object.prototype.toString.call(t); return void 0 !== t && ("[object NodeList]" === e || "[object HTMLCollection]" === e) && "length" in t && (0 === t.length || n.node(t[0])) }, n.string = function (t) { return "string" == typeof t || t instanceof String }, n.fn = function (t) { return "[object Function]" === Object.prototype.toString.call(t) } }, function (t, e, n) { var a = n(7); function i(t, e, n, o, r) { var i = function (e, n, t, o) { return function (t) { t.delegateTarget = a(t.target, n), t.delegateTarget && o.call(e, t) } }.apply(this, arguments); return t.addEventListener(n, i, r), { destroy: function () { t.removeEventListener(n, i, r) } } } t.exports = function (t, e, n, o, r) { return "function" == typeof t.addEventListener ? i.apply(null, arguments) : "function" == typeof n ? i.bind(null, document).apply(null, arguments) : ("string" == typeof t && (t = document.querySelectorAll(t)), Array.prototype.map.call(t, function (t) { return i(t, e, n, o, r) })) } }, function (t, e) { if ("undefined" != typeof Element && !Element.prototype.matches) { var n = Element.prototype; n.matches = n.matchesSelector || n.mozMatchesSelector || n.msMatchesSelector || n.oMatchesSelector || n.webkitMatchesSelector } t.exports = function (t, e) { for (; t && 9 !== t.nodeType;) { if ("function" == typeof t.matches && t.matches(e)) return t; t = t.parentNode } } }]) });
|
readme.txt
CHANGED
@@ -3,7 +3,7 @@ Contributors: vasyltech
|
|
3 |
Tags: access control, membership, backend menu, user role, restricted content, security, jwt
|
4 |
Requires at least: 4.0
|
5 |
Tested up to: 5.1
|
6 |
-
Stable tag: 5.9.
|
7 |
|
8 |
All you need to manage access to you WordPress websites on frontend, backend and API levels for any role, user or visitors.
|
9 |
|
@@ -37,6 +37,7 @@ https://www.youtube.com/watch?v=mj5Xa_Wc16Y
|
|
37 |
|
38 |
* [free] Manage Backend Menu. Manage access to the backend menu for any user or role. Find out more from [How to manage WordPress backend menu](https://aamplugin.com/article/how-to-manage-wordpress-backend-menu) article;
|
39 |
* [free] Manage Roles & Capabilities. Manage all your WordPress role and capabilities.
|
|
|
40 |
* [free] Create temporary user accounts. Create and manage temporary user accounts. Find out more from [How to create temporary WordPress user account](https://aamplugin.com/article/how-to-create-temporary-wordpress-user-account);
|
41 |
* [limited] Content access. Very granular access to unlimited number of post, page or custom post type ([19 different options](https://aamplugin.com/reference/plugin#posts-terms)). With premium [Plus Package](https://aamplugin.com/extension/plus-package) extension also manage access to hierarchical taxonomies or setup the default access to all post types and taxonomies. Find out more from [How to manage access to the WordPress content](https://aamplugin.com/article/how-to-manage-access-to-the-wordpress-content) article;
|
42 |
* [free] Manage Admin Toolbar. Filter out unnecessary items from the top admin toolbar for any role or user.
|
@@ -79,6 +80,22 @@ https://www.youtube.com/watch?v=mj5Xa_Wc16Y
|
|
79 |
|
80 |
== Changelog ==
|
81 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
82 |
= 5.9.1.1 =
|
83 |
* Fixed the bug with saving Metaboxes & Widgets settings
|
84 |
* Fixed the bug with saving Access Policy that has backward slashes in it
|
3 |
Tags: access control, membership, backend menu, user role, restricted content, security, jwt
|
4 |
Requires at least: 4.0
|
5 |
Tested up to: 5.1
|
6 |
+
Stable tag: 5.9.2
|
7 |
|
8 |
All you need to manage access to you WordPress websites on frontend, backend and API levels for any role, user or visitors.
|
9 |
|
37 |
|
38 |
* [free] Manage Backend Menu. Manage access to the backend menu for any user or role. Find out more from [How to manage WordPress backend menu](https://aamplugin.com/article/how-to-manage-wordpress-backend-menu) article;
|
39 |
* [free] Manage Roles & Capabilities. Manage all your WordPress role and capabilities.
|
40 |
+
* [free] All necessary set of tools to manage JWT authentication [Ultimate guide to WordPress JWT Authentication](https://aamplugin.com/article/ultimate-guide-to-wordpress-jwt-authentication)
|
41 |
* [free] Create temporary user accounts. Create and manage temporary user accounts. Find out more from [How to create temporary WordPress user account](https://aamplugin.com/article/how-to-create-temporary-wordpress-user-account);
|
42 |
* [limited] Content access. Very granular access to unlimited number of post, page or custom post type ([19 different options](https://aamplugin.com/reference/plugin#posts-terms)). With premium [Plus Package](https://aamplugin.com/extension/plus-package) extension also manage access to hierarchical taxonomies or setup the default access to all post types and taxonomies. Find out more from [How to manage access to the WordPress content](https://aamplugin.com/article/how-to-manage-access-to-the-wordpress-content) article;
|
43 |
* [free] Manage Admin Toolbar. Filter out unnecessary items from the top admin toolbar for any role or user.
|
80 |
|
81 |
== Changelog ==
|
82 |
|
83 |
+
= 5.9.2 =
|
84 |
+
* Fixed the bug with Access Policy access control
|
85 |
+
* Fixed the bug with Access Policy tab shows only 10 last Policies
|
86 |
+
* Fixed the bug where AAM was not determining correct max user level
|
87 |
+
* Fixed the bug where user was able to manage his roles on the profile page
|
88 |
+
* Fixed the bug with Access Policy "Between" condition
|
89 |
+
* Optimized AAM to support unusual access capabilities for custom post types https://forum.aamplugin.com/d/99-custom-post-type-does-not-honor-edit-delete-publish-overrides/5
|
90 |
+
* Enhanced Access Policy with few new features. The complete reference is here https://aamplugin.com/reference/policy
|
91 |
+
* Enabled 'JWT Authentication' by default
|
92 |
+
* Significantly improved AAM UI page security
|
93 |
+
* Added new JWT Tokens feature to the list of AAM features https://aamplugin.com/reference/plugin#jwt-tokens
|
94 |
+
* Added new capability aam_manage_jwt
|
95 |
+
* Added "Add New Policies" submenu to fix WordPress core bug with managing access to submenus
|
96 |
+
* Removed "Role Expiration" feature - it was too confusing to work with
|
97 |
+
* Removed allow_ajax_calls capability support - it was too confusing for end users
|
98 |
+
|
99 |
= 5.9.1.1 =
|
100 |
* Fixed the bug with saving Metaboxes & Widgets settings
|
101 |
* Fixed the bug with saving Access Policy that has backward slashes in it
|
vendor/firebase/JWT.php
CHANGED
@@ -129,8 +129,11 @@ class JWT
|
|
129 |
);
|
130 |
}
|
131 |
|
|
|
|
|
|
|
132 |
// Check if this token has expired.
|
133 |
-
if (isset($
|
134 |
throw new ExpiredException('Expired token');
|
135 |
}
|
136 |
|
129 |
);
|
130 |
}
|
131 |
|
132 |
+
// The timestamp simply does not take in consideration the timezone
|
133 |
+
$exp = !is_numeric($payload->exp) ? strtotime($payload->exp) : $payload->exp;
|
134 |
+
|
135 |
// Check if this token has expired.
|
136 |
+
if (isset($exp) && ($timestamp - static::$leeway) >= $exp) {
|
137 |
throw new ExpiredException('Expired token');
|
138 |
}
|
139 |
|