Merge branch 'release/v29.0.0.OS'
This commit is contained in:
commit
253b298b0d
103 files changed
+8400
-242
No files matched your search
@@ -17,6 +17,13 @@ if($group == 'admin' || $group == 'modules'){
|
|||||||
$name = str_replace("..","",$name);
|
$name = str_replace("..","",$name);
|
||||||
$name = str_replace("/","",$name);
|
$name = str_replace("/","",$name);
|
||||||
include APP_BASE_PATH.'/'.$group.'/'.$name.'/index.php';
|
include APP_BASE_PATH.'/'.$group.'/'.$name.'/index.php';
|
||||||
|
}else if ($group == 'extension'){
|
||||||
|
$name = str_replace("..","",$name);
|
||||||
|
$name = str_replace("/","",$name);
|
||||||
|
$moduleName = $name;
|
||||||
|
$moduleGroup = 'extensions';
|
||||||
|
$extensionIndex = APP_BASE_PATH.'/../extensions/'.$name.'/web/index.php';
|
||||||
|
include $extensionIndex;
|
||||||
}else{
|
}else{
|
||||||
exit();
|
exit();
|
||||||
}
|
}
|
||||||
@@ -4,48 +4,48 @@
|
|||||||
Developer: Thilina Hasantha (http://lk.linkedin.com/in/thilinah | https://github.com/thilinah)
|
Developer: Thilina Hasantha (http://lk.linkedin.com/in/thilinah | https://github.com/thilinah)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Classes\PermissionManager;
|
||||||
|
use Clients\Common\Model\Client;
|
||||||
|
|
||||||
$moduleName = 'clients';
|
$moduleName = 'clients';
|
||||||
$moduleGroup = 'admin';
|
$moduleGroup = 'admin';
|
||||||
define('MODULE_PATH',dirname(__FILE__));
|
define('MODULE_PATH', dirname(__FILE__));
|
||||||
include APP_BASE_PATH.'header.php';
|
include APP_BASE_PATH . 'header.php';
|
||||||
include APP_BASE_PATH.'modulejslibs.inc.php';
|
include APP_BASE_PATH . 'modulejslibs.inc.php';
|
||||||
?><div class="span9">
|
?><div class="span9">
|
||||||
|
|
||||||
<ul class="nav nav-tabs" id="modTab" style="margin-bottom:0px;margin-left:5px;border-bottom: none;">
|
<ul class="nav nav-tabs" id="modTab" style="margin-bottom:0px;margin-left:5px;border-bottom: none;">
|
||||||
<li class="active"><a id="tabClient" href="#tabPageClient"><?=t('Clients')?></a></li>
|
<li class="active"><a id="tabClient" href="#tabPageClient"><?= t('Clients') ?></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="tab-pane active" id="tabPageClient">
|
<div class="tab-pane active" id="tabPageClient">
|
||||||
<div id="Client" class="reviewBlock" data-content="List" style="padding-left:5px;">
|
<div id="ClientTable" class="reviewBlock" data-content="List" style="padding-left:5px;"></div>
|
||||||
|
<div id="ClientForm"></div>
|
||||||
</div>
|
<div id="ClientFilterForm"></div>
|
||||||
<div id="ClientForm" class="reviewBlock" data-content="Form" style="padding-left:5px;display:none;">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<?php
|
||||||
var modJsList = [];
|
$moduleData = [
|
||||||
|
'user_level' => $user->user_level,
|
||||||
|
'permissions' => [
|
||||||
|
'Client' => PermissionManager::checkGeneralAccess(new Client()),
|
||||||
|
]
|
||||||
|
];
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
var data = <?= json_encode($moduleData) ?>;
|
||||||
|
var modJsList = [];
|
||||||
|
|
||||||
modJsList['tabClient'] = new ClientAdapter('Client','Client');
|
modJsList['tabClient'] = new ClientAdapter('Client');
|
||||||
|
|
||||||
<?php if(isset($modulePermissions['perm']['Add Clients']) && $modulePermissions['perm']['Add Clients'] == "No"){?>
|
modJsList.tabClient.setObjectTypeName('Client');
|
||||||
modJsList['tabClient'].setShowAddNew(false);
|
modJsList.tabClient.setAccess(data.permissions.Client);
|
||||||
<?php }?>
|
modJsList.tabClient.setDataPipe(new IceDataPipe(modJsList.tabClient));
|
||||||
|
modJsList.tabClient.setRemoteTable(true);
|
||||||
|
|
||||||
<?php if(isset($modulePermissions['perm']['Delete Clients']) && $modulePermissions['perm']['Delete Clients'] == "No"){?>
|
var modJs = modJsList['tabClient'];
|
||||||
modJsList['tabClient'].setShowDelete(false);
|
</script>
|
||||||
<?php }?>
|
<?php include APP_BASE_PATH . 'footer.php'; ?>
|
||||||
|
|
||||||
<?php if(isset($modulePermissions['perm']['Edit Clients']) && $modulePermissions['perm']['Edit Clients'] == "No"){?>
|
|
||||||
modJsList['tabClient'].setShowSave(false);
|
|
||||||
<?php }?>
|
|
||||||
|
|
||||||
|
|
||||||
var modJs = modJsList['tabClient'];
|
|
||||||
|
|
||||||
</script>
|
|
||||||
<?php include APP_BASE_PATH.'footer.php';?>
|
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
Developer: Thilina Hasantha (http://lk.linkedin.com/in/thilinah | https://github.com/thilinah)
|
Developer: Thilina Hasantha (http://lk.linkedin.com/in/thilinah | https://github.com/thilinah)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Classes\BaseService;
|
||||||
use Classes\PermissionManager;
|
use Classes\PermissionManager;
|
||||||
use Company\Common\Model\CompanyStructure;
|
use Company\Common\Model\CompanyStructure;
|
||||||
|
|
||||||
@@ -60,6 +61,7 @@ path.link {
|
|||||||
<?php
|
<?php
|
||||||
$moduleData = [
|
$moduleData = [
|
||||||
'user_level' => $user->user_level,
|
'user_level' => $user->user_level,
|
||||||
|
'customFields' => BaseService::getInstance()->getCustomFields("CompanyStructure"),
|
||||||
'permissions' => [
|
'permissions' => [
|
||||||
'CompanyStructure' => PermissionManager::checkGeneralAccess(new CompanyStructure()),
|
'CompanyStructure' => PermissionManager::checkGeneralAccess(new CompanyStructure()),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -0,0 +1,42 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
use Classes\BaseService;
|
||||||
|
use Classes\PermissionManager;
|
||||||
|
use FieldNames\Common\Model\CustomField;
|
||||||
|
|
||||||
|
$moduleName = 'assets';
|
||||||
|
$moduleGroup = 'admin';
|
||||||
|
define('MODULE_PATH',dirname(__FILE__));
|
||||||
|
include APP_BASE_PATH.'header.php';
|
||||||
|
include APP_BASE_PATH.'modulejslibs.inc.php';
|
||||||
|
$modelClasses = BaseService::getInstance()->getCustomFieldClassMap();
|
||||||
|
?><div class="span9">
|
||||||
|
|
||||||
|
<ul class="nav nav-tabs" id="modTab" style="margin-bottom:0px;margin-left:5px;border-bottom: none;">
|
||||||
|
<li class="active"><a id="tabCustomField" href="#tabPageCustomField"><?=t('Custom Fields')?></a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<div class="tab-content">
|
||||||
|
<div class="tab-pane active" id="tabPageCustomField">
|
||||||
|
<div id="CustomFieldTable" class="reviewBlock" data-content="List"></div>
|
||||||
|
<div id="CustomFieldForm"></div>
|
||||||
|
<div id="CustomFieldFilterForm"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
<div id="dataGroup"></div>
|
||||||
|
<?php
|
||||||
|
$moduleData = [
|
||||||
|
'user_level' => $user->user_level,
|
||||||
|
'types' => $modelClasses,
|
||||||
|
'permissions' => [
|
||||||
|
'CustomField' => PermissionManager::checkGeneralAccess(new CustomField()),
|
||||||
|
]
|
||||||
|
];
|
||||||
|
?>
|
||||||
|
<script>
|
||||||
|
initAdminCustomFields(<?=json_encode($moduleData)?>);
|
||||||
|
</script>
|
||||||
|
<?php include APP_BASE_PATH.'footer.php';?>
|
||||||
|
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
{
|
||||||
|
"label": "Custom Fields",
|
||||||
|
"menu": "Admin",
|
||||||
|
"order": "892",
|
||||||
|
"icon": "fa-code",
|
||||||
|
"user_levels": [
|
||||||
|
"Admin"
|
||||||
|
],
|
||||||
|
"permissions": [],
|
||||||
|
"model_namespace": "\\FieldNames\\Common\\Model",
|
||||||
|
"manager": "\\CustomField\\Admin\\Api\\CustomFieldAdminManager"
|
||||||
|
}
|
||||||
@@ -13,41 +13,25 @@ include APP_BASE_PATH.'modulejslibs.inc.php';
|
|||||||
|
|
||||||
<ul class="nav nav-tabs" id="modTab" style="margin-bottom:0px;margin-left:5px;border-bottom: none;">
|
<ul class="nav nav-tabs" id="modTab" style="margin-bottom:0px;margin-left:5px;border-bottom: none;">
|
||||||
<li class="active"><a id="tabEmployeeFieldName" href="#tabPageEmployeeFieldName"><?=t('Employee Field Names')?></a></li>
|
<li class="active"><a id="tabEmployeeFieldName" href="#tabPageEmployeeFieldName"><?=t('Employee Field Names')?></a></li>
|
||||||
<li><a id="tabEmployeeCustomField" href="#tabPageEmployeeCustomField"><?=t('Employee Custom Fields')?></a></li>
|
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="tab-pane active" id="tabPageEmployeeFieldName">
|
<div class="tab-pane active" id="tabPageEmployeeFieldName">
|
||||||
<div id="EmployeeFieldName" class="reviewBlock" data-content="List" style="padding-left:5px;">
|
<div id="EmployeeFieldName" class="reviewBlock" data-content="List" style="padding-left:5px;">
|
||||||
|
|
||||||
</div>
|
|
||||||
<div id="EmployeeFieldNameForm" class="reviewBlock" data-content="Form" style="padding-left:5px;display:none;">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="tab-pane" id="tabPageEmployeeCustomField">
|
|
||||||
<div id="EmployeeCustomField" class="reviewBlock" data-content="List" style="padding-left:5px;">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
<div id="EmployeeCustomFieldForm" class="reviewBlock" data-content="Form" style="padding-left:5px;display:none;">
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<script>
|
<script>
|
||||||
var modJsList = new Array();
|
var modJsList = [];
|
||||||
|
|
||||||
modJsList['tabEmployeeFieldName'] = new FieldNameAdapter('FieldNameMapping','EmployeeFieldName',{"type":"Employee"});
|
modJsList['tabEmployeeFieldName'] = new FieldNameAdapter('FieldNameMapping','EmployeeFieldName',{"type":"Employee"});
|
||||||
modJsList['tabEmployeeFieldName'].setRemoteTable(true);
|
modJsList['tabEmployeeFieldName'].setRemoteTable(true);
|
||||||
modJsList['tabEmployeeFieldName'].setShowDelete(false);
|
modJsList['tabEmployeeFieldName'].setShowDelete(false);
|
||||||
modJsList['tabEmployeeFieldName'].setShowAddNew(false);
|
modJsList['tabEmployeeFieldName'].setShowAddNew(false);
|
||||||
|
|
||||||
modJsList['tabEmployeeCustomField'] = new CustomFieldAdapter('CustomField','EmployeeCustomField',{"type":"Employee"},"display_order desc");
|
|
||||||
modJsList['tabEmployeeCustomField'].setRemoteTable(true);
|
|
||||||
modJsList['tabEmployeeCustomField'].setTableType("Employee");
|
|
||||||
|
|
||||||
|
|
||||||
var modJs = modJsList['tabEmployeeFieldName'];
|
var modJs = modJsList['tabEmployeeFieldName'];
|
||||||
|
|
||||||
|
|||||||
@@ -4,71 +4,65 @@
|
|||||||
Developer: Thilina Hasantha (http://lk.linkedin.com/in/thilinah | https://github.com/thilinah)
|
Developer: Thilina Hasantha (http://lk.linkedin.com/in/thilinah | https://github.com/thilinah)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Classes\PermissionManager;
|
||||||
|
use Projects\Common\Model\Project;
|
||||||
|
use Projects\Common\Model\EmployeeProject;
|
||||||
|
|
||||||
$moduleName = 'projects';
|
$moduleName = 'projects';
|
||||||
$moduleGroup = 'admin';
|
$moduleGroup = 'admin';
|
||||||
define('MODULE_PATH',dirname(__FILE__));
|
define('MODULE_PATH', dirname(__FILE__));
|
||||||
include APP_BASE_PATH.'header.php';
|
include APP_BASE_PATH . 'header.php';
|
||||||
include APP_BASE_PATH.'modulejslibs.inc.php';
|
include APP_BASE_PATH . 'modulejslibs.inc.php';
|
||||||
|
|
||||||
?><div class="span9">
|
?><div class="span9">
|
||||||
|
|
||||||
|
|
||||||
<ul class="nav nav-tabs" id="modTab" style="margin-bottom:0px;margin-left:5px;border-bottom: none;">
|
<ul class="nav nav-tabs" id="modTab" style="margin-bottom:0px;margin-left:5px;border-bottom: none;">
|
||||||
<li class="active"><a id="tabProject" href="#tabPageProject"><?=t('Projects')?></a></li>
|
<li class="active"><a id="tabProject" href="#tabPageProject"><?= t('Projects') ?></a></li>
|
||||||
<li><a id="tabEmployeeProject" href="#tabPageEmployeeProject"><?=t('Employee Projects')?></a></li>
|
<li><a id="tabEmployeeProject" href="#tabPageEmployeeProject"><?= t('Employee Projects') ?></a></li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
<div class="tab-content">
|
<div class="tab-content">
|
||||||
<div class="tab-pane active" id="tabPageProject">
|
<div class="tab-pane active" id="tabPageProject">
|
||||||
<div id="Project" class="reviewBlock" data-content="List" style="padding-left:5px;">
|
<div id="ProjectTable" class="reviewBlock" data-content="List" style="padding-left:5px;"></div>
|
||||||
|
<div id="ProjectForm"></div>
|
||||||
</div>
|
<div id="ProjectFilterForm"></div>
|
||||||
<div id="ProjectForm" class="reviewBlock" data-content="Form" style="padding-left:5px;display:none;">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="tab-pane" id="tabPageEmployeeProject">
|
<div class="tab-pane" id="tabPageEmployeeProject">
|
||||||
<div id="EmployeeProject" class="reviewBlock" data-content="List" style="padding-left:5px;">
|
<div id="EmployeeProjectTable" class="reviewBlock" data-content="List" style="padding-left:5px;"></div>
|
||||||
|
<div id="EmployeeProjectForm"></div>
|
||||||
</div>
|
<div id="EmployeeProjectFilterForm"></div>
|
||||||
<div id="EmployeeProjectForm" class="reviewBlock" data-content="Form" style="padding-left:5px;display:none;">
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<?php
|
||||||
|
$moduleData = [
|
||||||
|
'user_level' => $user->user_level,
|
||||||
|
'permissions' => [
|
||||||
|
'Project' => PermissionManager::checkGeneralAccess(new Project()),
|
||||||
|
'EmployeeProject' => PermissionManager::checkGeneralAccess(new EmployeeProject()),
|
||||||
|
]
|
||||||
|
];
|
||||||
|
?>
|
||||||
<script>
|
<script>
|
||||||
var modJsList = [];
|
var modJsList = [];
|
||||||
|
var data = <?= json_encode($moduleData) ?>;
|
||||||
|
modJsList['tabProject'] = new ProjectAdapter('Project', 'Project');
|
||||||
|
modJsList.tabProject.setObjectTypeName('Project');
|
||||||
|
modJsList.tabProject.setAccess(data.permissions.Project);
|
||||||
|
modJsList.tabProject.setDataPipe(new IceDataPipe(modJsList.tabProject));
|
||||||
|
modJsList.tabProject.setRemoteTable(true);
|
||||||
|
|
||||||
modJsList['tabProject'] = new ProjectAdapter('Project','Project');
|
modJsList['tabEmployeeProject'] = new EmployeeProjectAdapter('EmployeeProject', 'EmployeeProject');
|
||||||
|
|
||||||
<?php if(isset($modulePermissions['perm']['Add Projects']) && $modulePermissions['perm']['Add Projects'] == "No"){?>
|
|
||||||
modJsList['tabProject'].setShowAddNew(false);
|
|
||||||
<?php }?>
|
|
||||||
|
|
||||||
<?php if(isset($modulePermissions['perm']['Delete Projects']) && $modulePermissions['perm']['Delete Projects'] == "No"){?>
|
|
||||||
modJsList['tabProject'].setShowDelete(false);
|
|
||||||
<?php }?>
|
|
||||||
|
|
||||||
<?php if(isset($modulePermissions['perm']['Edit Projects']) && $modulePermissions['perm']['Edit Projects'] == "No"){?>
|
|
||||||
modJsList['tabProject'].setShowSave(false);
|
|
||||||
<?php }?>
|
|
||||||
|
|
||||||
|
|
||||||
modJsList['tabEmployeeProject'] = new EmployeeProjectAdapter('EmployeeProject','EmployeeProject');
|
modJsList.tabEmployeeProject.setObjectTypeName('Employee Project');
|
||||||
modJsList['tabEmployeeProject'].setRemoteTable(true);
|
modJsList.tabEmployeeProject.setAccess(data.permissions.EmployeeProject);
|
||||||
|
modJsList.tabEmployeeProject.setDataPipe(new IceDataPipe(modJsList.tabEmployeeProject));
|
||||||
|
modJsList.tabEmployeeProject.setRemoteTable(true);
|
||||||
|
|
||||||
<?php if(isset($modulePermissions['perm']['Add Projects']) && $modulePermissions['perm']['Add Projects'] == "No"){?>
|
var modJs = modJsList['tabProject'];
|
||||||
modJsList['tabEmployeeProject'].setShowAddNew(false);
|
|
||||||
<?php }?>
|
|
||||||
<?php if(isset($modulePermissions['perm']['Delete Projects']) && $modulePermissions['perm']['Delete Projects'] == "No"){?>
|
|
||||||
modJsList['tabEmployeeProject'].setShowDelete(false);
|
|
||||||
<?php }?>
|
|
||||||
<?php if(isset($modulePermissions['perm']['Edit Projects']) && $modulePermissions['perm']['Edit Projects'] == "No"){?>
|
|
||||||
modJsList['tabEmployeeProject'].setShowEdit(false);
|
|
||||||
<?php }?>
|
|
||||||
|
|
||||||
|
|
||||||
var modJs = modJsList['tabProject'];
|
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
<?php include APP_BASE_PATH.'footer.php';?>
|
<?php include APP_BASE_PATH . 'footer.php'; ?>
|
||||||
@@ -19,28 +19,42 @@ $options1 = array();
|
|||||||
$options1['setShowAddNew'] = 'false';
|
$options1['setShowAddNew'] = 'false';
|
||||||
$options1['setRemoteTable'] = 'true';
|
$options1['setRemoteTable'] = 'true';
|
||||||
|
|
||||||
|
$notCloud = !defined('IS_CLOUD') || IS_CLOUD == false;
|
||||||
|
|
||||||
$moduleBuilder->addModuleOrGroup(new ModuleTab(
|
$moduleBuilder->addModuleOrGroup(new ModuleTab(
|
||||||
'CompanySetting','Setting','Company','SettingAdapter','{"category":"Company"}','name',true,$options1
|
'CompanySetting','Setting','Company','SettingAdapter','{"category":"Company"}','name',true,$options1
|
||||||
));
|
));
|
||||||
$moduleBuilder->addModuleOrGroup(new ModuleTab(
|
$moduleBuilder->addModuleOrGroup(new ModuleTab(
|
||||||
'SystemSetting','Setting','System','SettingAdapter','{"category":"System"}','name',false,$options1
|
'SystemSetting','Setting','System','SettingAdapter','{"category":"System"}','name',false,$options1
|
||||||
));
|
));
|
||||||
if (!defined('CLOUD_INSTALLATION')) {
|
if ( $notCloud ) {
|
||||||
$moduleBuilder->addModuleOrGroup(new ModuleTab(
|
$moduleBuilder->addModuleOrGroup(new ModuleTab(
|
||||||
'EmailSetting', 'Setting', 'Email', 'SettingAdapter', '{"category":"Email"}', 'name', false, $options1
|
'EmailSetting', 'Setting', 'Email', 'SettingAdapter', '{"category":"Email"}', 'name', false, $options1
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
if(!defined('LEAVE_ENABLED') || LDAP_ENABLED == true) {
|
||||||
|
$moduleBuilder->addModuleOrGroup(new ModuleTab(
|
||||||
|
'LeaveSetting', 'Setting', 'Leave', 'SettingAdapter', '{"category":"Leave"}', 'name', false, $options1
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
$moduleBuilder->addModuleOrGroup(new ModuleTab(
|
$moduleBuilder->addModuleOrGroup(new ModuleTab(
|
||||||
'LeaveSetting','Setting','Leave / PTO','SettingAdapter','{"category":"Leave"}','name',false,$options1
|
'AttendanceSetting','Setting','Attendance','SettingAdapter','{"category":"Attendance"}','name',false,$options1
|
||||||
));
|
));
|
||||||
|
|
||||||
if(!defined('LDAP_ENABLED') || LDAP_ENABLED == true){
|
if(!defined('LDAP_ENABLED') || LDAP_ENABLED == true){
|
||||||
$moduleBuilder->addModuleOrGroup(new ModuleTab(
|
$moduleBuilder->addModuleOrGroup(new ModuleTab(
|
||||||
'LDAPSetting','Setting','LDAP','SettingAdapter','{"category":"LDAP"}','name',false,$options1
|
'LDAPSetting','Setting','LDAP','SettingAdapter','{"category":"LDAP"}','name',false,$options1
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
$moduleBuilder->addModuleOrGroup(new ModuleTab(
|
|
||||||
'AttendanceSetting','Setting','Attendance','SettingAdapter','{"category":"Attendance"}','name',false,$options1
|
if(!defined('SAML_ENABLED') || SAML_ENABLED == true){
|
||||||
));
|
$moduleBuilder->addModuleOrGroup(new ModuleTab(
|
||||||
|
'SAMLSetting','Setting','SAML','SettingAdapter','{"category":"SAML"}','name',false,$options1
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$moduleBuilder->addModuleOrGroup(new ModuleTab(
|
$moduleBuilder->addModuleOrGroup(new ModuleTab(
|
||||||
'OtherSetting','Setting','Other','SettingAdapter','{"category":["Projects","Recruitment","Notifications","Expense","Travel","Api","Overtime"]}','name',false,$options1
|
'OtherSetting','Setting','Other','SettingAdapter','{"category":["Projects","Recruitment","Notifications","Expense","Travel","Api","Overtime"]}','name',false,$options1
|
||||||
));
|
));
|
||||||
|
|||||||
@@ -31,22 +31,6 @@ $moduleBuilder->addModuleOrGroup(new \Classes\ModuleBuilder\ModuleTab(
|
|||||||
$travelRequestOptions
|
$travelRequestOptions
|
||||||
));
|
));
|
||||||
|
|
||||||
if ($user->user_level === 'Admin') {
|
|
||||||
$travelCustomFieldOptions = [];
|
|
||||||
$travelCustomFieldOptions['setRemoteTable'] = 'true';
|
|
||||||
$travelCustomFieldOptions['setTableType'] = '\'EmployeeTravelRecord\'';
|
|
||||||
|
|
||||||
$moduleBuilder->addModuleOrGroup(new \Classes\ModuleBuilder\ModuleTab(
|
|
||||||
'TravelCustomField',
|
|
||||||
'CustomField',
|
|
||||||
'Custom Fields',
|
|
||||||
'CustomFieldAdapter',
|
|
||||||
'{"type":"EmployeeTravelRecord"}',
|
|
||||||
'',
|
|
||||||
false,
|
|
||||||
$travelCustomFieldOptions
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
echo \Classes\UIManager::getInstance()->renderModule($moduleBuilder);
|
echo \Classes\UIManager::getInstance()->renderModule($moduleBuilder);
|
||||||
|
|
||||||
|
|||||||
+11
-5
@@ -13,14 +13,13 @@ if(!defined('HOME_LINK_OTHERS')){
|
|||||||
}
|
}
|
||||||
|
|
||||||
//Version
|
//Version
|
||||||
define('VERSION', '28.2.0.OS');
|
define('VERSION', '29.0.0.OS');
|
||||||
define('CACHE_VALUE', '28.2.0.OS.2020-11130243');
|
define('CACHE_VALUE', '29.0.0.OS.2020-04021509');
|
||||||
define('VERSION_NUMBER', '280200');
|
define('VERSION_NUMBER', '290000');
|
||||||
define('VERSION_DATE', '13/11/2020');
|
define('VERSION_DATE', '02/04/2021');
|
||||||
|
|
||||||
if(!defined('CONTACT_EMAIL')){define('CONTACT_EMAIL','icehrm@gamonoid.com');}
|
if(!defined('CONTACT_EMAIL')){define('CONTACT_EMAIL','icehrm@gamonoid.com');}
|
||||||
if(!defined('KEY_PREFIX')){define('KEY_PREFIX','IceHrm');}
|
if(!defined('KEY_PREFIX')){define('KEY_PREFIX','IceHrm');}
|
||||||
if(!defined('APP_SEC')){define('APP_SEC','dbcs234d2saaqw');}
|
|
||||||
|
|
||||||
define('UI_SHOW_SWITCH_PROFILE', true);
|
define('UI_SHOW_SWITCH_PROFILE', true);
|
||||||
define('CRON_LOG', ini_get('error_log'));
|
define('CRON_LOG', ini_get('error_log'));
|
||||||
@@ -33,6 +32,13 @@ if(!defined('WK_HTML_PATH')){
|
|||||||
}
|
}
|
||||||
define('ALL_CLIENT_BASE_PATH', '/var/www/icehrm.app/icehrmapp/');
|
define('ALL_CLIENT_BASE_PATH', '/var/www/icehrm.app/icehrmapp/');
|
||||||
|
|
||||||
|
define('IS_CLOUD', false);
|
||||||
define('LDAP_ENABLED', true);
|
define('LDAP_ENABLED', true);
|
||||||
|
define('SAML_ENABLED', true);
|
||||||
|
define('LEAVE_ENABLED', true);
|
||||||
define('RECRUITMENT_ENABLED', false);
|
define('RECRUITMENT_ENABLED', false);
|
||||||
define('APP_WEB_URL', 'https://icehrm.com');
|
define('APP_WEB_URL', 'https://icehrm.com');
|
||||||
|
|
||||||
|
if (!defined('EXTENSIONS_URL')) {
|
||||||
|
define('EXTENSIONS_URL', str_replace('/web/', '/extensions/', BASE_URL));
|
||||||
|
}
|
||||||
@@ -215,6 +215,26 @@ if (defined('SYM_CLIENT')) {
|
|||||||
|
|
||||||
<?php }?>
|
<?php }?>
|
||||||
|
|
||||||
|
<?php foreach($extensions as $menu){?>
|
||||||
|
<?php if(count($menu['menu']) == 0){continue;}?>
|
||||||
|
<li class="treeview" ref="<?="extension_".str_replace(" ", "_", $menu['name'])?>">
|
||||||
|
<a href="#">
|
||||||
|
<i class="fa <?=!isset($mainIcons[$menu['name']])?"fa-th":$mainIcons[$menu['name']];?>"></i></i> <span><?=\Classes\LanguageManager::tran($menu['name'])?></span>
|
||||||
|
<i class="fa fa-angle-left pull-right"></i>
|
||||||
|
</a>
|
||||||
|
|
||||||
|
<ul class="treeview-menu" id="<?="extension_".str_replace(" ", "_", $menu['name'])?>">
|
||||||
|
<?php foreach ($menu['menu'] as $item){?>
|
||||||
|
<li>
|
||||||
|
<a data-turbolinks="true" href="<?=CLIENT_BASE_URL?>?g=extension&n=<?=$item['name']?>&m=<?="extension_".str_replace(" ", "_", $menu['name'])?>">
|
||||||
|
<i class="fa <?=!isset($item['icon'])?"fa-angle-double-right":$item['icon']?>"></i> <?=\Classes\LanguageManager::tran($item['label'])?>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<?php }?>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
<?php }?>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
if(file_exists(CLIENT_PATH.'/third_party_meta.json')){
|
if(file_exists(CLIENT_PATH.'/third_party_meta.json')){
|
||||||
$tpModules = json_decode(file_get_contents(CLIENT_PATH.'/third_party_meta.json'),true);
|
$tpModules = json_decode(file_get_contents(CLIENT_PATH.'/third_party_meta.json'),true);
|
||||||
|
|||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,185 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
include_once 'Utilities.php';
|
||||||
|
class IDPMetadataReader{
|
||||||
|
|
||||||
|
private $identityProviders;
|
||||||
|
private $serviceProviders;
|
||||||
|
|
||||||
|
public function __construct(DOMNode $xml = NULL){
|
||||||
|
|
||||||
|
$this->identityProviders = array();
|
||||||
|
$this->serviceProviders = array();
|
||||||
|
|
||||||
|
$entitiesDescriptor = Utilities::xpQuery($xml, './saml_metadata:EntitiesDescriptor');
|
||||||
|
|
||||||
|
if(!empty($entitiesDescriptor))
|
||||||
|
$entityDescriptors = Utilities::xpQuery($entitiesDescriptor[0], './saml_metadata:EntityDescriptor');
|
||||||
|
else
|
||||||
|
$entityDescriptors = Utilities::xpQuery($xml, './saml_metadata:EntityDescriptor');
|
||||||
|
|
||||||
|
foreach ($entityDescriptors as $entityDescriptor) {
|
||||||
|
$idpSSODescriptor = Utilities::xpQuery($entityDescriptor, './saml_metadata:IDPSSODescriptor');
|
||||||
|
|
||||||
|
if(isset($idpSSODescriptor) && !empty($idpSSODescriptor)){
|
||||||
|
array_push($this->identityProviders,new IdentityProviders($entityDescriptor));
|
||||||
|
}
|
||||||
|
//TODO: add sp descriptor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIdentityProviders(){
|
||||||
|
return $this->identityProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getServiceProviders(){
|
||||||
|
return $this->serviceProviders;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class IdentityProviders{
|
||||||
|
|
||||||
|
private $idpName;
|
||||||
|
private $entityID;
|
||||||
|
private $loginDetails;
|
||||||
|
private $logoutDetails;
|
||||||
|
private $signingCertificate;
|
||||||
|
private $encryptionCertificate;
|
||||||
|
private $signedRequest;
|
||||||
|
|
||||||
|
public function __construct(DOMElement $xml = NULL){
|
||||||
|
|
||||||
|
$this->idpName = '';
|
||||||
|
$this->loginDetails = array();
|
||||||
|
$this->logoutDetails = array();
|
||||||
|
$this->signingCertificate = array();
|
||||||
|
$this->encryptionCertificate = array();
|
||||||
|
|
||||||
|
if ($xml->hasAttribute('entityID')) {
|
||||||
|
$this->entityID = $xml->getAttribute('entityID');
|
||||||
|
}
|
||||||
|
|
||||||
|
if($xml->hasAttribute('WantAuthnRequestsSigned')){
|
||||||
|
$this->signedRequest = $xml->getAttribute('WantAuthnRequestsSigned');
|
||||||
|
}
|
||||||
|
|
||||||
|
$idpSSODescriptor = Utilities::xpQuery($xml, './saml_metadata:IDPSSODescriptor');
|
||||||
|
|
||||||
|
if (count($idpSSODescriptor) > 1) {
|
||||||
|
throw new Exception('More than one <IDPSSODescriptor> in <EntityDescriptor>.');
|
||||||
|
} elseif (empty($idpSSODescriptor)) {
|
||||||
|
throw new Exception('Missing required <IDPSSODescriptor> in <EntityDescriptor>.');
|
||||||
|
}
|
||||||
|
$idpSSODescriptorEL = $idpSSODescriptor[0];
|
||||||
|
|
||||||
|
$info = Utilities::xpQuery($xml, './saml_metadata:Extensions');
|
||||||
|
|
||||||
|
if($info)
|
||||||
|
$this->parseInfo($idpSSODescriptorEL);
|
||||||
|
$this->parseSSOService($idpSSODescriptorEL);
|
||||||
|
$this->parseSLOService($idpSSODescriptorEL);
|
||||||
|
$this->parsex509Certificate($idpSSODescriptorEL);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseInfo($xml){
|
||||||
|
$displayNames = Utilities::xpQuery($xml, './mdui:UIInfo/mdui:DisplayName');
|
||||||
|
foreach ($displayNames as $name) {
|
||||||
|
if($name->hasAttribute('xml:lang') && $name->getAttribute('xml:lang')=="en"){
|
||||||
|
$this->idpName = $name->textContent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseSSOService($xml){
|
||||||
|
$ssoServices = Utilities::xpQuery($xml, './saml_metadata:SingleSignOnService');
|
||||||
|
foreach ($ssoServices as $ssoService) {
|
||||||
|
$binding = str_replace("urn:oasis:names:tc:SAML:2.0:bindings:","",$ssoService->getAttribute('Binding'));
|
||||||
|
$this->loginDetails = array_merge(
|
||||||
|
$this->loginDetails,
|
||||||
|
array($binding => $ssoService->getAttribute('Location'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseSLOService($xml){
|
||||||
|
$sloServices = Utilities::xpQuery($xml, './saml_metadata:SingleLogoutService');
|
||||||
|
foreach ($sloServices as $sloService) {
|
||||||
|
$binding = str_replace("urn:oasis:names:tc:SAML:2.0:bindings:","",$sloService->getAttribute('Binding'));
|
||||||
|
$this->logoutDetails = array_merge(
|
||||||
|
$this->logoutDetails,
|
||||||
|
array($binding => $sloService->getAttribute('Location'))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parsex509Certificate($xml){
|
||||||
|
foreach ( Utilities::xpQuery($xml, './saml_metadata:KeyDescriptor') as $KeyDescriptorNode ) {
|
||||||
|
if($KeyDescriptorNode->hasAttribute('use')){
|
||||||
|
if($KeyDescriptorNode->getAttribute('use')=='encryption'){
|
||||||
|
$this->parseEncryptionCertificate($KeyDescriptorNode);
|
||||||
|
}else{
|
||||||
|
$this->parseSigningCertificate($KeyDescriptorNode);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
$this->parseSigningCertificate($KeyDescriptorNode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function parseSigningCertificate($xml){
|
||||||
|
$certNode = Utilities::xpQuery($xml, './ds:KeyInfo/ds:X509Data/ds:X509Certificate');
|
||||||
|
$certData = trim($certNode[0]->textContent);
|
||||||
|
$certData = str_replace(array ( "\r", "\n", "\t", ' '), '', $certData);
|
||||||
|
if(!empty($certNode))
|
||||||
|
array_push($this->signingCertificate, Utilities::sanitize_certificate( $certData ));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function parseEncryptionCertificate($xml){
|
||||||
|
$certNode = Utilities::xpQuery($xml, './ds:KeyInfo/ds:X509Data/ds:X509Certificate');
|
||||||
|
$certData = trim($certNode[0]->textContent);
|
||||||
|
$certData = str_replace(array ( "\r", "\n", "\t", ' '), '', $certData);
|
||||||
|
if(!empty($certNode))
|
||||||
|
array_push($this->encryptionCertificate, $certData);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getIdpName(){
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEntityID(){
|
||||||
|
return $this->entityID;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLoginURL($binding){
|
||||||
|
return $this->loginDetails[$binding];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLogoutURL($binding){
|
||||||
|
return $this->logoutDetails[$binding];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLoginDetails(){
|
||||||
|
return $this->loginDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getLogoutDetails(){
|
||||||
|
return $this->logoutDetails;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSigningCertificate(){
|
||||||
|
return $this->signingCertificate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getEncryptionCertificate(){
|
||||||
|
return $this->encryptionCertificate[0];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isRequestSigned(){
|
||||||
|
return $this->signedRequest;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
abstract class MoSAMLBasicEnum {
|
||||||
|
private static $constCacheArray = NULL;
|
||||||
|
|
||||||
|
public static function getConstants() {
|
||||||
|
if (self::$constCacheArray == NULL) {
|
||||||
|
self::$constCacheArray = array();
|
||||||
|
}
|
||||||
|
$calledClass = get_called_class();
|
||||||
|
if (!array_key_exists($calledClass, self::$constCacheArray)) {
|
||||||
|
$reflect = new ReflectionClass($calledClass);
|
||||||
|
self::$constCacheArray[$calledClass] = $reflect->getConstants();
|
||||||
|
}
|
||||||
|
return self::$constCacheArray[$calledClass];
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isValidName($name, $strict = false) {
|
||||||
|
$constants = self::getConstants();
|
||||||
|
|
||||||
|
if ($strict) {
|
||||||
|
return array_key_exists($name, $constants);
|
||||||
|
}
|
||||||
|
|
||||||
|
$keys = array_map('strtolower', array_keys($constants));
|
||||||
|
return in_array(strtolower($name), $keys);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function isValidValue($value, $strict = true) {
|
||||||
|
$values = array_values(self::getConstants());
|
||||||
|
return in_array($value, $values, $strict);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Created by PhpStorm.
|
||||||
|
* User: HP
|
||||||
|
* Date: 9/11/2018
|
||||||
|
* Time: 9:48 AM
|
||||||
|
*/
|
||||||
|
|
||||||
|
class MoSAMLPointer
|
||||||
|
{
|
||||||
|
|
||||||
|
private $content,$anchor_id,$edge,$align,$active,$pointer_name;
|
||||||
|
|
||||||
|
function __construct($header,$body,$anchor_id,$edge,$align,$active,$prefix){
|
||||||
|
|
||||||
|
$this->content = '<h3>'.$header.'</h3>';
|
||||||
|
$this->content .= '<p id="'.$prefix.'" style="font-size: initial;">' .$body . '</p>';
|
||||||
|
$this-> anchor_id = $anchor_id;
|
||||||
|
$this->edge = $edge;
|
||||||
|
$this->align = $align;
|
||||||
|
$this->active = $active;
|
||||||
|
$this->pointer_name = 'miniorange_admin_pointer_'.$prefix;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
function return_array(){
|
||||||
|
return array(
|
||||||
|
// The content needs to point to what we created above in the $new_pointer_content variable
|
||||||
|
'content' => $this->content,
|
||||||
|
|
||||||
|
// In order for the custom pointer to appear in the right location we need to specify the ID
|
||||||
|
// of the element we want it to appear next to
|
||||||
|
'anchor_id' => $this->anchor_id,
|
||||||
|
|
||||||
|
// On what edge do we want the pointer to appear. Options are 'top', 'left', 'right', 'bottom'
|
||||||
|
'edge' => $this->edge,
|
||||||
|
|
||||||
|
// How do we want out custom pointer to align to the element it is attached to. Options are
|
||||||
|
// 'left', 'right', 'center'
|
||||||
|
'align' => $this->align,
|
||||||
|
|
||||||
|
// This is how we tell the pointer to be dismissed or not. Make sure that the 'new_items'
|
||||||
|
// string matches the string at the beginning of the array item
|
||||||
|
'active' => $this->active
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getContent()
|
||||||
|
{
|
||||||
|
return $this->content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $content
|
||||||
|
*/
|
||||||
|
public function setContent($content)
|
||||||
|
{
|
||||||
|
$this->content = $content;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getAnchorId()
|
||||||
|
{
|
||||||
|
return $this->anchor_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getEdge()
|
||||||
|
{
|
||||||
|
return $this->edge;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getActive()
|
||||||
|
{
|
||||||
|
return $this->active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $active
|
||||||
|
*/
|
||||||
|
public function setActive($active)
|
||||||
|
{
|
||||||
|
$this->active = $active;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getPointerName()
|
||||||
|
{
|
||||||
|
return $this->pointer_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
class MoSAMLPointersManager {
|
||||||
|
|
||||||
|
private $pfile;
|
||||||
|
private $version;
|
||||||
|
private $prefix;
|
||||||
|
private $pointers = array();
|
||||||
|
|
||||||
|
public function __construct( $file, $version, $prefix ) {
|
||||||
|
$this->pfile = file_exists( $file ) ? $file : FALSE;
|
||||||
|
$this->version = str_replace( '.', '_', $version );
|
||||||
|
$this->prefix = $prefix;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function parse() {
|
||||||
|
if ( empty( $this->pfile ) ) return;
|
||||||
|
$pointers = (array) require_once $this->pfile;
|
||||||
|
if ( empty($pointers) ) return;
|
||||||
|
foreach ( $pointers as $i => $pointer ) {
|
||||||
|
if(is_array($pointer)){
|
||||||
|
$pointer['id'] = "{$this->prefix}{$this->version}_{$i}";
|
||||||
|
$this->pointers[$pointer['id']] = (object) $pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function filter( $page ) {
|
||||||
|
if ( empty( $this->pointers ) ) return array();
|
||||||
|
$uid = get_current_user_id();
|
||||||
|
$no = explode( ',', (string) get_user_meta( $uid, 'dismissed_wp_pointers', TRUE ) );
|
||||||
|
$active_ids = array_diff( array_keys( $this->pointers ), $no );
|
||||||
|
$good = array();
|
||||||
|
foreach( $this->pointers as $i => $pointer ) {
|
||||||
|
if (
|
||||||
|
in_array( $i, $active_ids, TRUE ) // is active
|
||||||
|
&& isset( $pointer->where ) // has where
|
||||||
|
&& in_array( $page, (array) $pointer->where, TRUE ) // current page is in where
|
||||||
|
) {
|
||||||
|
$good[] = $pointer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$count = count( $good );
|
||||||
|
if ( $good === 0 ) return array();
|
||||||
|
foreach( array_values( $good ) as $i => $pointer ) {
|
||||||
|
$good[$i]->next = $i+1 < $count ? $good[$i+1]->id : '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $good;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is part of miniOrange SAML plugin.
|
||||||
|
*
|
||||||
|
* miniOrange SAML plugin is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* miniOrange SAML plugin is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with miniOrange SAML plugin. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
include 'Assertion.php';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Class for SAML2 Response messages.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
class SAML2_Response
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* The assertions in this response.
|
||||||
|
*/
|
||||||
|
private $assertions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The destination URL in this response.
|
||||||
|
*/
|
||||||
|
private $destination;
|
||||||
|
|
||||||
|
private $certificates;
|
||||||
|
private $signatureData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructor for SAML 2 response messages.
|
||||||
|
*
|
||||||
|
* @param DOMElement|NULL $xml The input message.
|
||||||
|
*/
|
||||||
|
public function __construct(DOMElement $xml = NULL)
|
||||||
|
{
|
||||||
|
//parent::__construct('Response', $xml);
|
||||||
|
|
||||||
|
$this->assertions = array();
|
||||||
|
$this->certificates = array();
|
||||||
|
|
||||||
|
if ($xml === NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sig = Utilities::validateElement($xml);
|
||||||
|
if ($sig !== FALSE) {
|
||||||
|
$this->certificates = $sig['Certificates'];
|
||||||
|
$this->signatureData = $sig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* set the destination from saml response */
|
||||||
|
if ($xml->hasAttribute('Destination')) {
|
||||||
|
$this->destination = $xml->getAttribute('Destination');
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($node = $xml->firstChild; $node !== NULL; $node = $node->nextSibling) {
|
||||||
|
if ($node->namespaceURI !== 'urn:oasis:names:tc:SAML:2.0:assertion') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($node->localName === 'Assertion' || $node->localName === 'EncryptedAssertion') {
|
||||||
|
$this->assertions[] = new SAML2_Assertion($node);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the assertions in this response.
|
||||||
|
*
|
||||||
|
* @return SAML2_Assertion[]|SAML2_EncryptedAssertion[]
|
||||||
|
*/
|
||||||
|
public function getAssertions()
|
||||||
|
{
|
||||||
|
return $this->assertions;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the assertions that should be included in this response.
|
||||||
|
*
|
||||||
|
* @param SAML2_Assertion[]|SAML2_EncryptedAssertion[] The assertions.
|
||||||
|
*/
|
||||||
|
public function setAssertions(array $assertions)
|
||||||
|
{
|
||||||
|
$this->assertions = $assertions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDestination()
|
||||||
|
{
|
||||||
|
return $this->destination;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getCertificates()
|
||||||
|
{
|
||||||
|
return $this->certificates;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getSignatureData()
|
||||||
|
{
|
||||||
|
return $this->signatureData;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,511 @@
|
|||||||
|
<?php
|
||||||
|
namespace RobRichards\XMLSecLibs;
|
||||||
|
|
||||||
|
use DOMDocument;
|
||||||
|
use DOMElement;
|
||||||
|
use DOMNode;
|
||||||
|
use DOMXPath;
|
||||||
|
use Exception;
|
||||||
|
use RobRichards\XMLSecLibs\Utils\MoXPath as XPath;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xmlseclibs.php
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007-2020, Robert Richards <rrichards@cdatazone.org>.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of Robert Richards nor the names of his
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @author Robert Richards <rrichards@cdatazone.org>
|
||||||
|
* @copyright 2007-2020 Robert Richards <rrichards@cdatazone.org>
|
||||||
|
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
|
||||||
|
*/
|
||||||
|
|
||||||
|
class MoXMLSecEnc
|
||||||
|
{
|
||||||
|
const template = "<xenc:EncryptedData xmlns:xenc='http://www.w3.org/2001/04/xmlenc#'>
|
||||||
|
<xenc:CipherData>
|
||||||
|
<xenc:CipherValue></xenc:CipherValue>
|
||||||
|
</xenc:CipherData>
|
||||||
|
</xenc:EncryptedData>";
|
||||||
|
|
||||||
|
const Element = 'http://www.w3.org/2001/04/xmlenc#Element';
|
||||||
|
const Content = 'http://www.w3.org/2001/04/xmlenc#Content';
|
||||||
|
const URI = 3;
|
||||||
|
const XMLENCNS = 'http://www.w3.org/2001/04/xmlenc#';
|
||||||
|
|
||||||
|
/** @var null|DOMDocument */
|
||||||
|
private $encdoc = null;
|
||||||
|
|
||||||
|
/** @var null|DOMNode */
|
||||||
|
private $rawNode = null;
|
||||||
|
|
||||||
|
/** @var null|string */
|
||||||
|
public $type = null;
|
||||||
|
|
||||||
|
/** @var null|DOMElement */
|
||||||
|
public $encKey = null;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
private $references = array();
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$this->_resetTemplate();
|
||||||
|
}
|
||||||
|
|
||||||
|
private function _resetTemplate()
|
||||||
|
{
|
||||||
|
$this->encdoc = new DOMDocument();
|
||||||
|
$this->encdoc->loadXML(self::template);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $name
|
||||||
|
* @param DOMNode $node
|
||||||
|
* @param string $type
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function addReference($name, $node, $type)
|
||||||
|
{
|
||||||
|
if (! $node instanceOf DOMNode) {
|
||||||
|
throw new Exception('$node is not of type DOMNode');
|
||||||
|
}
|
||||||
|
$curencdoc = $this->encdoc;
|
||||||
|
$this->_resetTemplate();
|
||||||
|
$encdoc = $this->encdoc;
|
||||||
|
$this->encdoc = $curencdoc;
|
||||||
|
$refuri = MoXMLSecurityDSig::generateGUID();
|
||||||
|
$element = $encdoc->documentElement;
|
||||||
|
$element->setAttribute("Id", $refuri);
|
||||||
|
$this->references[$name] = array("node" => $node, "type" => $type, "encnode" => $encdoc, "refuri" => $refuri);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param DOMNode $node
|
||||||
|
*/
|
||||||
|
public function setNode($node)
|
||||||
|
{
|
||||||
|
$this->rawNode = $node;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt the selected node with the given key.
|
||||||
|
*
|
||||||
|
* @param MoXMLSecurityKey $objKey The encryption key and algorithm.
|
||||||
|
* @param bool $replace Whether the encrypted node should be replaced in the original tree. Default is true.
|
||||||
|
* @return DOMElement The <xenc:EncryptedData>-element.
|
||||||
|
*@throws Exception
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public function encryptNode($objKey, $replace = true)
|
||||||
|
{
|
||||||
|
$data = '';
|
||||||
|
if (empty($this->rawNode)) {
|
||||||
|
throw new Exception('Node to encrypt has not been set');
|
||||||
|
}
|
||||||
|
if (! $objKey instanceof MoXMLSecurityKey) {
|
||||||
|
throw new Exception('Invalid Key');
|
||||||
|
}
|
||||||
|
$doc = $this->rawNode->ownerDocument;
|
||||||
|
$xPath = new DOMXPath($this->encdoc);
|
||||||
|
$objList = $xPath->query('/xenc:EncryptedData/xenc:CipherData/xenc:CipherValue');
|
||||||
|
$cipherValue = $objList->item(0);
|
||||||
|
if ($cipherValue == null) {
|
||||||
|
throw new Exception('Error locating CipherValue element within template');
|
||||||
|
}
|
||||||
|
switch ($this->type) {
|
||||||
|
case (self::Element):
|
||||||
|
$data = $doc->saveXML($this->rawNode);
|
||||||
|
$this->encdoc->documentElement->setAttribute('Type', self::Element);
|
||||||
|
break;
|
||||||
|
case (self::Content):
|
||||||
|
$children = $this->rawNode->childNodes;
|
||||||
|
foreach ($children AS $child) {
|
||||||
|
$data .= $doc->saveXML($child);
|
||||||
|
}
|
||||||
|
$this->encdoc->documentElement->setAttribute('Type', self::Content);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception('Type is currently not supported');
|
||||||
|
}
|
||||||
|
|
||||||
|
$encMethod = $this->encdoc->documentElement->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:EncryptionMethod'));
|
||||||
|
$encMethod->setAttribute('Algorithm', $objKey->getAlgorithm());
|
||||||
|
$cipherValue->parentNode->parentNode->insertBefore($encMethod, $cipherValue->parentNode->parentNode->firstChild);
|
||||||
|
|
||||||
|
$strEncrypt = base64_encode($objKey->encryptData($data));
|
||||||
|
$value = $this->encdoc->createTextNode($strEncrypt);
|
||||||
|
$cipherValue->appendChild($value);
|
||||||
|
|
||||||
|
if ($replace) {
|
||||||
|
switch ($this->type) {
|
||||||
|
case (self::Element):
|
||||||
|
if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) {
|
||||||
|
return $this->encdoc;
|
||||||
|
}
|
||||||
|
$importEnc = $this->rawNode->ownerDocument->importNode($this->encdoc->documentElement, true);
|
||||||
|
$this->rawNode->parentNode->replaceChild($importEnc, $this->rawNode);
|
||||||
|
return $importEnc;
|
||||||
|
case (self::Content):
|
||||||
|
$importEnc = $this->rawNode->ownerDocument->importNode($this->encdoc->documentElement, true);
|
||||||
|
while ($this->rawNode->firstChild) {
|
||||||
|
$this->rawNode->removeChild($this->rawNode->firstChild);
|
||||||
|
}
|
||||||
|
$this->rawNode->appendChild($importEnc);
|
||||||
|
return $importEnc;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return $this->encdoc->documentElement;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param MoXMLSecurityKey $objKey
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function encryptReferences($objKey)
|
||||||
|
{
|
||||||
|
$curRawNode = $this->rawNode;
|
||||||
|
$curType = $this->type;
|
||||||
|
foreach ($this->references AS $name => $reference) {
|
||||||
|
$this->encdoc = $reference["encnode"];
|
||||||
|
$this->rawNode = $reference["node"];
|
||||||
|
$this->type = $reference["type"];
|
||||||
|
try {
|
||||||
|
$encNode = $this->encryptNode($objKey);
|
||||||
|
$this->references[$name]["encnode"] = $encNode;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$this->rawNode = $curRawNode;
|
||||||
|
$this->type = $curType;
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$this->rawNode = $curRawNode;
|
||||||
|
$this->type = $curType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the CipherValue text from this encrypted node.
|
||||||
|
*
|
||||||
|
* @throws Exception
|
||||||
|
* @return string|null The Ciphervalue text, or null if no CipherValue is found.
|
||||||
|
*/
|
||||||
|
public function getCipherValue()
|
||||||
|
{
|
||||||
|
if (empty($this->rawNode)) {
|
||||||
|
throw new Exception('Node to decrypt has not been set');
|
||||||
|
}
|
||||||
|
|
||||||
|
$doc = $this->rawNode->ownerDocument;
|
||||||
|
$xPath = new DOMXPath($doc);
|
||||||
|
$xPath->registerNamespace('xmlencr', self::XMLENCNS);
|
||||||
|
/* Only handles embedded content right now and not a reference */
|
||||||
|
$query = "./xmlencr:CipherData/xmlencr:CipherValue";
|
||||||
|
$nodeset = $xPath->query($query, $this->rawNode);
|
||||||
|
$node = $nodeset->item(0);
|
||||||
|
|
||||||
|
if (!$node) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return base64_decode($node->nodeValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt this encrypted node.
|
||||||
|
*
|
||||||
|
* The behaviour of this function depends on the value of $replace.
|
||||||
|
* If $replace is false, we will return the decrypted data as a string.
|
||||||
|
* If $replace is true, we will insert the decrypted element(s) into the
|
||||||
|
* document, and return the decrypted element(s).
|
||||||
|
*
|
||||||
|
* @param MoXMLSecurityKey $objKey The decryption key that should be used when decrypting the node.
|
||||||
|
* @param boolean $replace Whether we should replace the encrypted node in the XML document with the decrypted data. The default is true.
|
||||||
|
*
|
||||||
|
* @return string|DOMElement The decrypted data.
|
||||||
|
*/
|
||||||
|
public function decryptNode($objKey, $replace=true)
|
||||||
|
{
|
||||||
|
if (! $objKey instanceof MoXMLSecurityKey) {
|
||||||
|
throw new Exception('Invalid Key');
|
||||||
|
}
|
||||||
|
|
||||||
|
$encryptedData = $this->getCipherValue();
|
||||||
|
if ($encryptedData) {
|
||||||
|
$decrypted = $objKey->decryptData($encryptedData);
|
||||||
|
if ($replace) {
|
||||||
|
switch ($this->type) {
|
||||||
|
case (self::Element):
|
||||||
|
$newdoc = new DOMDocument();
|
||||||
|
$newdoc->loadXML($decrypted);
|
||||||
|
if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) {
|
||||||
|
return $newdoc;
|
||||||
|
}
|
||||||
|
$importEnc = $this->rawNode->ownerDocument->importNode($newdoc->documentElement, true);
|
||||||
|
$this->rawNode->parentNode->replaceChild($importEnc, $this->rawNode);
|
||||||
|
return $importEnc;
|
||||||
|
case (self::Content):
|
||||||
|
if ($this->rawNode->nodeType == XML_DOCUMENT_NODE) {
|
||||||
|
$doc = $this->rawNode;
|
||||||
|
} else {
|
||||||
|
$doc = $this->rawNode->ownerDocument;
|
||||||
|
}
|
||||||
|
$newFrag = $doc->createDocumentFragment();
|
||||||
|
$newFrag->appendXML($decrypted);
|
||||||
|
$parent = $this->rawNode->parentNode;
|
||||||
|
$parent->replaceChild($newFrag, $this->rawNode);
|
||||||
|
return $parent;
|
||||||
|
default:
|
||||||
|
return $decrypted;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return $decrypted;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Exception("Cannot locate encrypted data");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypt the XMLSecurityKey
|
||||||
|
*
|
||||||
|
* @param MoXMLSecurityKey $srcKey
|
||||||
|
* @param MoXMLSecurityKey $rawKey
|
||||||
|
* @param bool $append
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function encryptKey($srcKey, $rawKey, $append=true)
|
||||||
|
{
|
||||||
|
if ((! $srcKey instanceof MoXMLSecurityKey) || (! $rawKey instanceof MoXMLSecurityKey)) {
|
||||||
|
throw new Exception('Invalid Key');
|
||||||
|
}
|
||||||
|
$strEncKey = base64_encode($srcKey->encryptData($rawKey->key));
|
||||||
|
$root = $this->encdoc->documentElement;
|
||||||
|
$encKey = $this->encdoc->createElementNS(self::XMLENCNS, 'xenc:EncryptedKey');
|
||||||
|
if ($append) {
|
||||||
|
$keyInfo = $root->insertBefore($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo'), $root->firstChild);
|
||||||
|
$keyInfo->appendChild($encKey);
|
||||||
|
} else {
|
||||||
|
$this->encKey = $encKey;
|
||||||
|
}
|
||||||
|
$encMethod = $encKey->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:EncryptionMethod'));
|
||||||
|
$encMethod->setAttribute('Algorithm', $srcKey->getAlgorith());
|
||||||
|
if (! empty($srcKey->name)) {
|
||||||
|
$keyInfo = $encKey->appendChild($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyInfo'));
|
||||||
|
$keyInfo->appendChild($this->encdoc->createElementNS('http://www.w3.org/2000/09/xmldsig#', 'dsig:KeyName', $srcKey->name));
|
||||||
|
}
|
||||||
|
$cipherData = $encKey->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:CipherData'));
|
||||||
|
$cipherData->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:CipherValue', $strEncKey));
|
||||||
|
if (is_array($this->references) && count($this->references) > 0) {
|
||||||
|
$refList = $encKey->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:ReferenceList'));
|
||||||
|
foreach ($this->references AS $name => $reference) {
|
||||||
|
$refuri = $reference["refuri"];
|
||||||
|
$dataRef = $refList->appendChild($this->encdoc->createElementNS(self::XMLENCNS, 'xenc:DataReference'));
|
||||||
|
$dataRef->setAttribute("URI", '#' . $refuri);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param MoXMLSecurityKey $encKey
|
||||||
|
* @return DOMElement|string
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function decryptKey($encKey)
|
||||||
|
{
|
||||||
|
if (! $encKey->isEncrypted) {
|
||||||
|
throw new Exception("Key is not Encrypted");
|
||||||
|
}
|
||||||
|
if (empty($encKey->key)) {
|
||||||
|
throw new Exception("Key is missing data to perform the decryption");
|
||||||
|
}
|
||||||
|
return $this->decryptNode($encKey, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param DOMDocument $element
|
||||||
|
* @return DOMNode|null
|
||||||
|
*/
|
||||||
|
public function locateEncryptedData($element)
|
||||||
|
{
|
||||||
|
if ($element instanceof DOMDocument) {
|
||||||
|
$doc = $element;
|
||||||
|
} else {
|
||||||
|
$doc = $element->ownerDocument;
|
||||||
|
}
|
||||||
|
if ($doc) {
|
||||||
|
$xpath = new DOMXPath($doc);
|
||||||
|
$query = "//*[local-name()='EncryptedData' and namespace-uri()='".self::XMLENCNS."']";
|
||||||
|
$nodeset = $xpath->query($query);
|
||||||
|
return $nodeset->item(0);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the key from the DOM
|
||||||
|
* @param null|DOMNode $node
|
||||||
|
* @return null|MoXMLSecurityKey
|
||||||
|
*/
|
||||||
|
public function locateKey($node=null)
|
||||||
|
{
|
||||||
|
if (empty($node)) {
|
||||||
|
$node = $this->rawNode;
|
||||||
|
}
|
||||||
|
if (! $node instanceof DOMNode) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
if ($doc = $node->ownerDocument) {
|
||||||
|
$xpath = new DOMXPath($doc);
|
||||||
|
$xpath->registerNamespace('xmlsecenc', self::XMLENCNS);
|
||||||
|
$query = ".//xmlsecenc:EncryptionMethod";
|
||||||
|
$nodeset = $xpath->query($query, $node);
|
||||||
|
if ($encmeth = $nodeset->item(0)) {
|
||||||
|
$attrAlgorithm = $encmeth->getAttribute("Algorithm");
|
||||||
|
try {
|
||||||
|
$objKey = new MoXMLSecurityKey($attrAlgorithm, array('type' => 'private'));
|
||||||
|
} catch (Exception $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return $objKey;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param null|MoXMLSecurityKey $objBaseKey
|
||||||
|
* @param null|DOMNode $node
|
||||||
|
* @return null|MoXMLSecurityKey
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function staticLocateKeyInfo($objBaseKey=null, $node=null)
|
||||||
|
{
|
||||||
|
if (empty($node) || (! $node instanceof DOMNode)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
$doc = $node->ownerDocument;
|
||||||
|
if (!$doc) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
$xpath = new DOMXPath($doc);
|
||||||
|
$xpath->registerNamespace('xmlsecenc', self::XMLENCNS);
|
||||||
|
$xpath->registerNamespace('xmlsecdsig', MoXMLSecurityDSig::XMLDSIGNS);
|
||||||
|
$query = "./xmlsecdsig:KeyInfo";
|
||||||
|
$nodeset = $xpath->query($query, $node);
|
||||||
|
$encmeth = $nodeset->item(0);
|
||||||
|
if (!$encmeth) {
|
||||||
|
/* No KeyInfo in EncryptedData / EncryptedKey. */
|
||||||
|
return $objBaseKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($encmeth->childNodes AS $child) {
|
||||||
|
switch ($child->localName) {
|
||||||
|
case 'KeyName':
|
||||||
|
if (! empty($objBaseKey)) {
|
||||||
|
$objBaseKey->name = $child->nodeValue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'KeyValue':
|
||||||
|
foreach ($child->childNodes AS $keyval) {
|
||||||
|
switch ($keyval->localName) {
|
||||||
|
case 'DSAKeyValue':
|
||||||
|
throw new Exception("DSAKeyValue currently not supported");
|
||||||
|
case 'RSAKeyValue':
|
||||||
|
$modulus = null;
|
||||||
|
$exponent = null;
|
||||||
|
if ($modulusNode = $keyval->getElementsByTagName('Modulus')->item(0)) {
|
||||||
|
$modulus = base64_decode($modulusNode->nodeValue);
|
||||||
|
}
|
||||||
|
if ($exponentNode = $keyval->getElementsByTagName('Exponent')->item(0)) {
|
||||||
|
$exponent = base64_decode($exponentNode->nodeValue);
|
||||||
|
}
|
||||||
|
if (empty($modulus) || empty($exponent)) {
|
||||||
|
throw new Exception("Missing Modulus or Exponent");
|
||||||
|
}
|
||||||
|
$publicKey = MoXMLSecurityKey::convertRSA($modulus, $exponent);
|
||||||
|
$objBaseKey->loadKey($publicKey);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'RetrievalMethod':
|
||||||
|
$type = $child->getAttribute('Type');
|
||||||
|
if ($type !== 'http://www.w3.org/2001/04/xmlenc#EncryptedKey') {
|
||||||
|
/* Unsupported key type. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$uri = $child->getAttribute('URI');
|
||||||
|
if ($uri[0] !== '#') {
|
||||||
|
/* URI not a reference - unsupported. */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$id = substr($uri, 1);
|
||||||
|
|
||||||
|
$query = '//xmlsecenc:EncryptedKey[@Id="'.MoXPath::filterAttrValue($id, MoXPath::DOUBLE_QUOTE).'"]';
|
||||||
|
$keyElement = $xpath->query($query)->item(0);
|
||||||
|
if (!$keyElement) {
|
||||||
|
throw new Exception("Unable to locate EncryptedKey with @Id='$id'.");
|
||||||
|
}
|
||||||
|
|
||||||
|
return MoXMLSecurityKey::fromEncryptedKeyElement($keyElement);
|
||||||
|
case 'EncryptedKey':
|
||||||
|
return MoXMLSecurityKey::fromEncryptedKeyElement($child);
|
||||||
|
case 'X509Data':
|
||||||
|
if ($x509certNodes = $child->getElementsByTagName('X509Certificate')) {
|
||||||
|
if ($x509certNodes->length > 0) {
|
||||||
|
$x509cert = $x509certNodes->item(0)->textContent;
|
||||||
|
$x509cert = str_replace(array("\r", "\n", " "), "", $x509cert);
|
||||||
|
$x509cert = "-----BEGIN CERTIFICATE-----\n".chunk_split($x509cert, 64, "\n")."-----END CERTIFICATE-----\n";
|
||||||
|
$objBaseKey->loadKey($x509cert, false, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $objBaseKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param null|MoXMLSecurityKey $objBaseKey
|
||||||
|
* @param null|DOMNode $node
|
||||||
|
* @return null|MoXMLSecurityKey
|
||||||
|
*/
|
||||||
|
public function locateKeyInfo($objBaseKey=null, $node=null)
|
||||||
|
{
|
||||||
|
if (empty($node)) {
|
||||||
|
$node = $this->rawNode;
|
||||||
|
}
|
||||||
|
return self::staticLocateKeyInfo($objBaseKey, $node);
|
||||||
|
}
|
||||||
|
}
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,800 @@
|
|||||||
|
<?php
|
||||||
|
namespace RobRichards\XMLSecLibs;
|
||||||
|
|
||||||
|
use DOMElement;
|
||||||
|
use Exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* xmlseclibs.php
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007-2020, Robert Richards <rrichards@cdatazone.org>.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of Robert Richards nor the names of his
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @author Robert Richards <rrichards@cdatazone.org>
|
||||||
|
* @copyright 2007-2020 Robert Richards <rrichards@cdatazone.org>
|
||||||
|
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
|
||||||
|
*/
|
||||||
|
|
||||||
|
class MoXMLSecurityKey
|
||||||
|
{
|
||||||
|
const TRIPLEDES_CBC = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc';
|
||||||
|
const AES128_CBC = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc';
|
||||||
|
const AES192_CBC = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc';
|
||||||
|
const AES256_CBC = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc';
|
||||||
|
const AES128_GCM = 'http://www.w3.org/2009/xmlenc11#aes128-gcm';
|
||||||
|
const AES192_GCM = 'http://www.w3.org/2009/xmlenc11#aes192-gcm';
|
||||||
|
const AES256_GCM = 'http://www.w3.org/2009/xmlenc11#aes256-gcm';
|
||||||
|
const RSA_1_5 = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5';
|
||||||
|
const RSA_OAEP_MGF1P = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p';
|
||||||
|
const DSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#dsa-sha1';
|
||||||
|
const RSA_SHA1 = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
|
||||||
|
const RSA_SHA256 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
|
||||||
|
const RSA_SHA384 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384';
|
||||||
|
const RSA_SHA512 = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512';
|
||||||
|
const HMAC_SHA1 = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1';
|
||||||
|
const AUTHTAG_LENGTH = 16;
|
||||||
|
|
||||||
|
/** @var array */
|
||||||
|
private $cryptParams = array();
|
||||||
|
|
||||||
|
/** @var int|string */
|
||||||
|
public $type = 0;
|
||||||
|
|
||||||
|
/** @var mixed|null */
|
||||||
|
public $key = null;
|
||||||
|
|
||||||
|
/** @var string */
|
||||||
|
public $passphrase = "";
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
public $iv = null;
|
||||||
|
|
||||||
|
/** @var string|null */
|
||||||
|
public $name = null;
|
||||||
|
|
||||||
|
/** @var mixed|null */
|
||||||
|
public $keyChain = null;
|
||||||
|
|
||||||
|
/** @var bool */
|
||||||
|
public $isEncrypted = false;
|
||||||
|
|
||||||
|
/** @var MoXMLSecEnc|null */
|
||||||
|
public $encryptedCtx = null;
|
||||||
|
|
||||||
|
/** @var mixed|null */
|
||||||
|
public $guid = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This variable contains the certificate as a string if this key represents an X509-certificate.
|
||||||
|
* If this key doesn't represent a certificate, this will be null.
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
private $x509Certificate = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This variable contains the certificate thumbprint if we have loaded an X509-certificate.
|
||||||
|
* @var string|null
|
||||||
|
*/
|
||||||
|
private $X509Thumbprint = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $type
|
||||||
|
* @param null|array $params
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function __construct($type, $params=null)
|
||||||
|
{
|
||||||
|
switch ($type) {
|
||||||
|
case (self::TRIPLEDES_CBC):
|
||||||
|
$this->cryptParams['library'] = 'openssl';
|
||||||
|
$this->cryptParams['cipher'] = 'des-ede3-cbc';
|
||||||
|
$this->cryptParams['type'] = 'symmetric';
|
||||||
|
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc';
|
||||||
|
$this->cryptParams['keysize'] = 24;
|
||||||
|
$this->cryptParams['blocksize'] = 8;
|
||||||
|
break;
|
||||||
|
case (self::AES128_CBC):
|
||||||
|
$this->cryptParams['library'] = 'openssl';
|
||||||
|
$this->cryptParams['cipher'] = 'aes-128-cbc';
|
||||||
|
$this->cryptParams['type'] = 'symmetric';
|
||||||
|
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes128-cbc';
|
||||||
|
$this->cryptParams['keysize'] = 16;
|
||||||
|
$this->cryptParams['blocksize'] = 16;
|
||||||
|
break;
|
||||||
|
case (self::AES192_CBC):
|
||||||
|
$this->cryptParams['library'] = 'openssl';
|
||||||
|
$this->cryptParams['cipher'] = 'aes-192-cbc';
|
||||||
|
$this->cryptParams['type'] = 'symmetric';
|
||||||
|
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes192-cbc';
|
||||||
|
$this->cryptParams['keysize'] = 24;
|
||||||
|
$this->cryptParams['blocksize'] = 16;
|
||||||
|
break;
|
||||||
|
case (self::AES256_CBC):
|
||||||
|
$this->cryptParams['library'] = 'openssl';
|
||||||
|
$this->cryptParams['cipher'] = 'aes-256-cbc';
|
||||||
|
$this->cryptParams['type'] = 'symmetric';
|
||||||
|
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#aes256-cbc';
|
||||||
|
$this->cryptParams['keysize'] = 32;
|
||||||
|
$this->cryptParams['blocksize'] = 16;
|
||||||
|
break;
|
||||||
|
case (self::AES128_GCM):
|
||||||
|
$this->cryptParams['library'] = 'openssl';
|
||||||
|
$this->cryptParams['cipher'] = 'aes-128-gcm';
|
||||||
|
$this->cryptParams['type'] = 'symmetric';
|
||||||
|
$this->cryptParams['method'] = 'http://www.w3.org/2009/xmlenc11#aes128-gcm';
|
||||||
|
$this->cryptParams['keysize'] = 32;
|
||||||
|
$this->cryptParams['blocksize'] = 16;
|
||||||
|
break;
|
||||||
|
case (self::AES192_GCM):
|
||||||
|
$this->cryptParams['library'] = 'openssl';
|
||||||
|
$this->cryptParams['cipher'] = 'aes-192-gcm';
|
||||||
|
$this->cryptParams['type'] = 'symmetric';
|
||||||
|
$this->cryptParams['method'] = 'http://www.w3.org/2009/xmlenc11#aes192-gcm';
|
||||||
|
$this->cryptParams['keysize'] = 32;
|
||||||
|
$this->cryptParams['blocksize'] = 16;
|
||||||
|
break;
|
||||||
|
case (self::AES256_GCM):
|
||||||
|
$this->cryptParams['library'] = 'openssl';
|
||||||
|
$this->cryptParams['cipher'] = 'aes-256-gcm';
|
||||||
|
$this->cryptParams['type'] = 'symmetric';
|
||||||
|
$this->cryptParams['method'] = 'http://www.w3.org/2009/xmlenc11#aes256-gcm';
|
||||||
|
$this->cryptParams['keysize'] = 32;
|
||||||
|
$this->cryptParams['blocksize'] = 16;
|
||||||
|
break;
|
||||||
|
case (self::RSA_1_5):
|
||||||
|
$this->cryptParams['library'] = 'openssl';
|
||||||
|
$this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
|
||||||
|
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-1_5';
|
||||||
|
if (is_array($params) && ! empty($params['type'])) {
|
||||||
|
if ($params['type'] == 'public' || $params['type'] == 'private') {
|
||||||
|
$this->cryptParams['type'] = $params['type'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
|
||||||
|
case (self::RSA_OAEP_MGF1P):
|
||||||
|
$this->cryptParams['library'] = 'openssl';
|
||||||
|
$this->cryptParams['padding'] = OPENSSL_PKCS1_OAEP_PADDING;
|
||||||
|
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p';
|
||||||
|
$this->cryptParams['hash'] = null;
|
||||||
|
if (is_array($params) && ! empty($params['type'])) {
|
||||||
|
if ($params['type'] == 'public' || $params['type'] == 'private') {
|
||||||
|
$this->cryptParams['type'] = $params['type'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
|
||||||
|
case (self::RSA_SHA1):
|
||||||
|
$this->cryptParams['library'] = 'openssl';
|
||||||
|
$this->cryptParams['method'] = 'http://www.w3.org/2000/09/xmldsig#rsa-sha1';
|
||||||
|
$this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
|
||||||
|
if (is_array($params) && ! empty($params['type'])) {
|
||||||
|
if ($params['type'] == 'public' || $params['type'] == 'private') {
|
||||||
|
$this->cryptParams['type'] = $params['type'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
|
||||||
|
case (self::RSA_SHA256):
|
||||||
|
$this->cryptParams['library'] = 'openssl';
|
||||||
|
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256';
|
||||||
|
$this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
|
||||||
|
$this->cryptParams['digest'] = 'SHA256';
|
||||||
|
if (is_array($params) && ! empty($params['type'])) {
|
||||||
|
if ($params['type'] == 'public' || $params['type'] == 'private') {
|
||||||
|
$this->cryptParams['type'] = $params['type'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
|
||||||
|
case (self::RSA_SHA384):
|
||||||
|
$this->cryptParams['library'] = 'openssl';
|
||||||
|
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384';
|
||||||
|
$this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
|
||||||
|
$this->cryptParams['digest'] = 'SHA384';
|
||||||
|
if (is_array($params) && ! empty($params['type'])) {
|
||||||
|
if ($params['type'] == 'public' || $params['type'] == 'private') {
|
||||||
|
$this->cryptParams['type'] = $params['type'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
|
||||||
|
case (self::RSA_SHA512):
|
||||||
|
$this->cryptParams['library'] = 'openssl';
|
||||||
|
$this->cryptParams['method'] = 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512';
|
||||||
|
$this->cryptParams['padding'] = OPENSSL_PKCS1_PADDING;
|
||||||
|
$this->cryptParams['digest'] = 'SHA512';
|
||||||
|
if (is_array($params) && ! empty($params['type'])) {
|
||||||
|
if ($params['type'] == 'public' || $params['type'] == 'private') {
|
||||||
|
$this->cryptParams['type'] = $params['type'];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception('Certificate "type" (private/public) must be passed via parameters');
|
||||||
|
case (self::HMAC_SHA1):
|
||||||
|
$this->cryptParams['library'] = $type;
|
||||||
|
$this->cryptParams['method'] = 'http://www.w3.org/2000/09/xmldsig#hmac-sha1';
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Exception('Invalid Key Type');
|
||||||
|
}
|
||||||
|
$this->type = $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the key size for the symmetric encryption algorithm..
|
||||||
|
*
|
||||||
|
* If the key size is unknown, or this isn't a symmetric encryption algorithm,
|
||||||
|
* null is returned.
|
||||||
|
*
|
||||||
|
* @return int|null The number of bytes in the key.
|
||||||
|
*/
|
||||||
|
public function getSymmetricKeySize()
|
||||||
|
{
|
||||||
|
if (! isset($this->cryptParams['keysize'])) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return $this->cryptParams['keysize'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a session key using the openssl-extension.
|
||||||
|
* In case of using DES3-CBC the key is checked for a proper parity bits set.
|
||||||
|
* @return string
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function generateSessionKey()
|
||||||
|
{
|
||||||
|
if (!isset($this->cryptParams['keysize'])) {
|
||||||
|
throw new Exception('Unknown key size for type "' . $this->type . '".');
|
||||||
|
}
|
||||||
|
$keysize = $this->cryptParams['keysize'];
|
||||||
|
|
||||||
|
$key = openssl_random_pseudo_bytes($keysize);
|
||||||
|
|
||||||
|
if ($this->type === self::TRIPLEDES_CBC) {
|
||||||
|
/* Make sure that the generated key has the proper parity bits set.
|
||||||
|
* Mcrypt doesn't care about the parity bits, but others may care.
|
||||||
|
*/
|
||||||
|
for ($i = 0; $i < strlen($key); $i++) {
|
||||||
|
$byte = ord($key[$i]) & 0xfe;
|
||||||
|
$parity = 1;
|
||||||
|
for ($j = 1; $j < 8; $j++) {
|
||||||
|
$parity ^= ($byte >> $j) & 1;
|
||||||
|
}
|
||||||
|
$byte |= $parity;
|
||||||
|
$key[$i] = chr($byte);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->key = $key;
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the raw thumbprint of a certificate
|
||||||
|
*
|
||||||
|
* @param string $cert
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
public static function getRawThumbprint($cert)
|
||||||
|
{
|
||||||
|
|
||||||
|
$arCert = explode("\n", $cert);
|
||||||
|
$data = '';
|
||||||
|
$inData = false;
|
||||||
|
|
||||||
|
foreach ($arCert AS $curData) {
|
||||||
|
if (! $inData) {
|
||||||
|
if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) {
|
||||||
|
$inData = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (strncmp($curData, '-----END CERTIFICATE', 20) == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
$data .= trim($curData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (! empty($data)) {
|
||||||
|
return strtolower(sha1(base64_decode($data)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads the given key, or - with isFile set true - the key from the keyfile.
|
||||||
|
*
|
||||||
|
* @param string $key
|
||||||
|
* @param bool $isFile
|
||||||
|
* @param bool $isCert
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public function loadKey($key, $isFile=false, $isCert = false)
|
||||||
|
{
|
||||||
|
if ($isFile) {
|
||||||
|
$this->key = file_get_contents($key);
|
||||||
|
} else {
|
||||||
|
$this->key = $key;
|
||||||
|
}
|
||||||
|
if ($isCert) {
|
||||||
|
$this->key = openssl_x509_read($this->key);
|
||||||
|
openssl_x509_export($this->key, $str_cert);
|
||||||
|
$this->x509Certificate = $str_cert;
|
||||||
|
$this->key = $str_cert;
|
||||||
|
} else {
|
||||||
|
$this->x509Certificate = null;
|
||||||
|
}
|
||||||
|
if ($this->cryptParams['library'] == 'openssl') {
|
||||||
|
switch ($this->cryptParams['type']) {
|
||||||
|
case 'public':
|
||||||
|
if ($isCert) {
|
||||||
|
/* Load the thumbprint if this is an X509 certificate. */
|
||||||
|
$this->X509Thumbprint = self::getRawThumbprint($this->key);
|
||||||
|
}
|
||||||
|
$this->key = openssl_get_publickey($this->key);
|
||||||
|
if (! $this->key) {
|
||||||
|
throw new Exception('Unable to extract public key');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'private':
|
||||||
|
$this->key = openssl_get_privatekey($this->key, $this->passphrase);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case'symmetric':
|
||||||
|
if (strlen($this->key) < $this->cryptParams['keysize']) {
|
||||||
|
throw new Exception('Key must contain at least 25 characters for this cipher');
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
throw new Exception('Unknown type');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ISO 10126 Padding
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
* @param integer $blockSize
|
||||||
|
* @throws Exception
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function padISO10126($data, $blockSize)
|
||||||
|
{
|
||||||
|
if ($blockSize > 256) {
|
||||||
|
throw new Exception('Block size higher than 256 not allowed');
|
||||||
|
}
|
||||||
|
$padChr = $blockSize - (strlen($data) % $blockSize);
|
||||||
|
$pattern = chr($padChr);
|
||||||
|
return $data . str_repeat($pattern, $padChr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Remove ISO 10126 Padding
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function unpadISO10126($data)
|
||||||
|
{
|
||||||
|
$padChr = substr($data, -1);
|
||||||
|
$padLen = ord($padChr);
|
||||||
|
return substr($data, 0, -$padLen);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts the given data (string) using the openssl-extension
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function encryptSymmetric($data)
|
||||||
|
{
|
||||||
|
$this->iv = openssl_random_pseudo_bytes(openssl_cipher_iv_length($this->cryptParams['cipher']));
|
||||||
|
$authTag = null;
|
||||||
|
if(in_array($this->cryptParams['cipher'], ['aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'])) {
|
||||||
|
if (version_compare(PHP_VERSION, '7.1.0') < 0) {
|
||||||
|
throw new Exception('PHP 7.1.0 is required to use AES GCM algorithms');
|
||||||
|
}
|
||||||
|
$authTag = openssl_random_pseudo_bytes(self::AUTHTAG_LENGTH);
|
||||||
|
$encrypted = openssl_encrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA, $this->iv, $authTag);
|
||||||
|
} else {
|
||||||
|
$data = $this->padISO10126($data, $this->cryptParams['blocksize']);
|
||||||
|
$encrypted = openssl_encrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $encrypted) {
|
||||||
|
throw new Exception('Failure encrypting Data (openssl symmetric) - ' . openssl_error_string());
|
||||||
|
}
|
||||||
|
return $this->iv . $encrypted . $authTag;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts the given data (string) using the openssl-extension
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
private function decryptSymmetric($data)
|
||||||
|
{
|
||||||
|
$iv_length = openssl_cipher_iv_length($this->cryptParams['cipher']);
|
||||||
|
$this->iv = substr($data, 0, $iv_length);
|
||||||
|
$data = substr($data, $iv_length);
|
||||||
|
$authTag = null;
|
||||||
|
if(in_array($this->cryptParams['cipher'], ['aes-128-gcm', 'aes-192-gcm', 'aes-256-gcm'])) {
|
||||||
|
if (version_compare(PHP_VERSION, '7.1.0') < 0) {
|
||||||
|
throw new Exception('PHP 7.1.0 is required to use AES GCM algorithms');
|
||||||
|
}
|
||||||
|
// obtain and remove the authentication tag
|
||||||
|
$offset = 0 - self::AUTHTAG_LENGTH;
|
||||||
|
$authTag = substr($data, $offset);
|
||||||
|
$data = substr($data, 0, $offset);
|
||||||
|
$decrypted = openssl_decrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA, $this->iv, $authTag);
|
||||||
|
} else {
|
||||||
|
$decrypted = openssl_decrypt($data, $this->cryptParams['cipher'], $this->key, OPENSSL_RAW_DATA | OPENSSL_ZERO_PADDING, $this->iv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (false === $decrypted) {
|
||||||
|
throw new Exception('Failure decrypting Data (openssl symmetric) - ' . openssl_error_string());
|
||||||
|
}
|
||||||
|
return null !== $authTag ? $decrypted : $this->unpadISO10126($decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts the given public data (string) using the openssl-extension
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
* @return string
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function encryptPublic($data)
|
||||||
|
{
|
||||||
|
if (! openssl_public_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) {
|
||||||
|
throw new Exception('Failure encrypting Data (openssl public) - ' . openssl_error_string());
|
||||||
|
}
|
||||||
|
return $encrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts the given public data (string) using the openssl-extension
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
* @return string
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function decryptPublic($data)
|
||||||
|
{
|
||||||
|
if (! openssl_public_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) {
|
||||||
|
throw new Exception('Failure decrypting Data (openssl public) - ' . openssl_error_string());
|
||||||
|
}
|
||||||
|
return $decrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts the given private data (string) using the openssl-extension
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
* @return string
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function encryptPrivate($data)
|
||||||
|
{
|
||||||
|
if (! openssl_private_encrypt($data, $encrypted, $this->key, $this->cryptParams['padding'])) {
|
||||||
|
throw new Exception('Failure encrypting Data (openssl private) - ' . openssl_error_string());
|
||||||
|
}
|
||||||
|
return $encrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts the given private data (string) using the openssl-extension
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
* @return string
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function decryptPrivate($data)
|
||||||
|
{
|
||||||
|
if (! openssl_private_decrypt($data, $decrypted, $this->key, $this->cryptParams['padding'])) {
|
||||||
|
throw new Exception('Failure decrypting Data (openssl private) - ' . openssl_error_string());
|
||||||
|
}
|
||||||
|
return $decrypted;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signs the given data (string) using the openssl-extension
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
* @return string
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private function signOpenSSL($data)
|
||||||
|
{
|
||||||
|
$algo = OPENSSL_ALGO_SHA1;
|
||||||
|
if (! empty($this->cryptParams['digest'])) {
|
||||||
|
$algo = $this->cryptParams['digest'];
|
||||||
|
}
|
||||||
|
if (! openssl_sign($data, $signature, $this->key, $algo)) {
|
||||||
|
throw new Exception('Failure Signing Data: ' . openssl_error_string() . ' - ' . $algo);
|
||||||
|
}
|
||||||
|
return $signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies the given data (string) belonging to the given signature using the openssl-extension
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* 1 on succesful signature verification,
|
||||||
|
* 0 when signature verification failed,
|
||||||
|
* -1 if an error occurred during processing.
|
||||||
|
*
|
||||||
|
* NOTE: be very careful when checking the return value, because in PHP,
|
||||||
|
* -1 will be cast to True when in boolean context. So always check the
|
||||||
|
* return value in a strictly typed way, e.g. "$obj->verify(...) === 1".
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
* @param string $signature
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
private function verifyOpenSSL($data, $signature)
|
||||||
|
{
|
||||||
|
$algo = OPENSSL_ALGO_SHA1;
|
||||||
|
if (! empty($this->cryptParams['digest'])) {
|
||||||
|
$algo = $this->cryptParams['digest'];
|
||||||
|
}
|
||||||
|
return openssl_verify($data, $signature, $this->key, $algo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encrypts the given data (string) using the regarding php-extension, depending on the library assigned to algorithm in the contructor.
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
* @return mixed|string
|
||||||
|
*/
|
||||||
|
public function encryptData($data)
|
||||||
|
{
|
||||||
|
if ($this->cryptParams['library'] === 'openssl') {
|
||||||
|
switch ($this->cryptParams['type']) {
|
||||||
|
case 'symmetric':
|
||||||
|
return $this->encryptSymmetric($data);
|
||||||
|
case 'public':
|
||||||
|
return $this->encryptPublic($data);
|
||||||
|
case 'private':
|
||||||
|
return $this->encryptPrivate($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypts the given data (string) using the regarding php-extension, depending on the library assigned to algorithm in the contructor.
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
* @return mixed|string
|
||||||
|
*/
|
||||||
|
public function decryptData($data)
|
||||||
|
{
|
||||||
|
if ($this->cryptParams['library'] === 'openssl') {
|
||||||
|
switch ($this->cryptParams['type']) {
|
||||||
|
case 'symmetric':
|
||||||
|
return $this->decryptSymmetric($data);
|
||||||
|
case 'public':
|
||||||
|
return $this->decryptPublic($data);
|
||||||
|
case 'private':
|
||||||
|
return $this->decryptPrivate($data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Signs the data (string) using the extension assigned to the type in the constructor.
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
* @return mixed|string
|
||||||
|
*/
|
||||||
|
public function signData($data)
|
||||||
|
{
|
||||||
|
switch ($this->cryptParams['library']) {
|
||||||
|
case 'openssl':
|
||||||
|
return $this->signOpenSSL($data);
|
||||||
|
case (self::HMAC_SHA1):
|
||||||
|
return hash_hmac("sha1", $data, $this->key, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies the data (string) against the given signature using the extension assigned to the type in the constructor.
|
||||||
|
*
|
||||||
|
* Returns in case of openSSL:
|
||||||
|
* 1 on succesful signature verification,
|
||||||
|
* 0 when signature verification failed,
|
||||||
|
* -1 if an error occurred during processing.
|
||||||
|
*
|
||||||
|
* NOTE: be very careful when checking the return value, because in PHP,
|
||||||
|
* -1 will be cast to True when in boolean context. So always check the
|
||||||
|
* return value in a strictly typed way, e.g. "$obj->verify(...) === 1".
|
||||||
|
*
|
||||||
|
* @param string $data
|
||||||
|
* @param string $signature
|
||||||
|
* @return bool|int
|
||||||
|
*/
|
||||||
|
public function verifySignature($data, $signature)
|
||||||
|
{
|
||||||
|
switch ($this->cryptParams['library']) {
|
||||||
|
case 'openssl':
|
||||||
|
return $this->verifyOpenSSL($data, $signature);
|
||||||
|
case (self::HMAC_SHA1):
|
||||||
|
$expectedSignature = hash_hmac("sha1", $data, $this->key, true);
|
||||||
|
return strcmp($signature, $expectedSignature) == 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @deprecated
|
||||||
|
* @see getAlgorithm()
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getAlgorith()
|
||||||
|
{
|
||||||
|
return $this->getAlgorithm();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
|
public function getAlgorithm()
|
||||||
|
{
|
||||||
|
return $this->cryptParams['method'];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param int $type
|
||||||
|
* @param string $string
|
||||||
|
* @return null|string
|
||||||
|
*/
|
||||||
|
public static function makeAsnSegment($type, $string)
|
||||||
|
{
|
||||||
|
switch ($type) {
|
||||||
|
case 0x02:
|
||||||
|
if (ord($string) > 0x7f)
|
||||||
|
$string = chr(0).$string;
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
$string = chr(0).$string;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
$length = strlen($string);
|
||||||
|
|
||||||
|
if ($length < 128) {
|
||||||
|
$output = sprintf("%c%c%s", $type, $length, $string);
|
||||||
|
} else if ($length < 0x0100) {
|
||||||
|
$output = sprintf("%c%c%c%s", $type, 0x81, $length, $string);
|
||||||
|
} else if ($length < 0x010000) {
|
||||||
|
$output = sprintf("%c%c%c%c%s", $type, 0x82, $length / 0x0100, $length % 0x0100, $string);
|
||||||
|
} else {
|
||||||
|
$output = null;
|
||||||
|
}
|
||||||
|
return $output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* Hint: Modulus and Exponent must already be base64 decoded
|
||||||
|
* @param string $modulus
|
||||||
|
* @param string $exponent
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function convertRSA($modulus, $exponent)
|
||||||
|
{
|
||||||
|
/* make an ASN publicKeyInfo */
|
||||||
|
$exponentEncoding = self::makeAsnSegment(0x02, $exponent);
|
||||||
|
$modulusEncoding = self::makeAsnSegment(0x02, $modulus);
|
||||||
|
$sequenceEncoding = self::makeAsnSegment(0x30, $modulusEncoding.$exponentEncoding);
|
||||||
|
$bitstringEncoding = self::makeAsnSegment(0x03, $sequenceEncoding);
|
||||||
|
$rsaAlgorithmIdentifier = pack("H*", "300D06092A864886F70D0101010500");
|
||||||
|
$publicKeyInfo = self::makeAsnSegment(0x30, $rsaAlgorithmIdentifier.$bitstringEncoding);
|
||||||
|
|
||||||
|
/* encode the publicKeyInfo in base64 and add PEM brackets */
|
||||||
|
$publicKeyInfoBase64 = base64_encode($publicKeyInfo);
|
||||||
|
$encoding = "-----BEGIN PUBLIC KEY-----\n";
|
||||||
|
$offset = 0;
|
||||||
|
while ($segment = substr($publicKeyInfoBase64, $offset, 64)) {
|
||||||
|
$encoding = $encoding.$segment."\n";
|
||||||
|
$offset += 64;
|
||||||
|
}
|
||||||
|
return $encoding."-----END PUBLIC KEY-----\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param mixed $parent
|
||||||
|
*/
|
||||||
|
public function serializeKey($parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve the X509 certificate this key represents.
|
||||||
|
*
|
||||||
|
* Will return the X509 certificate in PEM-format if this key represents
|
||||||
|
* an X509 certificate.
|
||||||
|
*
|
||||||
|
* @return string The X509 certificate or null if this key doesn't represent an X509-certificate.
|
||||||
|
*/
|
||||||
|
public function getX509Certificate()
|
||||||
|
{
|
||||||
|
return $this->x509Certificate;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the thumbprint of this X509 certificate.
|
||||||
|
*
|
||||||
|
* Returns:
|
||||||
|
* The thumbprint as a lowercase 40-character hexadecimal number, or null
|
||||||
|
* if this isn't a X509 certificate.
|
||||||
|
*
|
||||||
|
* @return string Lowercase 40-character hexadecimal number of thumbprint
|
||||||
|
*/
|
||||||
|
public function getX509Thumbprint()
|
||||||
|
{
|
||||||
|
return $this->X509Thumbprint;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create key from an EncryptedKey-element.
|
||||||
|
*
|
||||||
|
* @param DOMElement $element The EncryptedKey-element.
|
||||||
|
* @return MoXMLSecurityKey The new key.
|
||||||
|
* @throws Exception
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public static function fromEncryptedKeyElement(DOMElement $element)
|
||||||
|
{
|
||||||
|
|
||||||
|
$objenc = new MoXMLSecEnc();
|
||||||
|
$objenc->setNode($element);
|
||||||
|
if (! $objKey = $objenc->locateKey()) {
|
||||||
|
throw new Exception("Unable to locate algorithm for this Encrypted Key");
|
||||||
|
}
|
||||||
|
$objKey->isEncrypted = true;
|
||||||
|
$objKey->encryptedCtx = $objenc;
|
||||||
|
MoXMLSecEnc::staticLocateKeyInfo($objKey, $element);
|
||||||
|
return $objKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace RobRichards\XMLSecLibs\Utils;
|
||||||
|
|
||||||
|
class MoXPath
|
||||||
|
{
|
||||||
|
const ALPHANUMERIC = '\w\d';
|
||||||
|
const NUMERIC = '\d';
|
||||||
|
const LETTERS = '\w';
|
||||||
|
const EXTENDED_ALPHANUMERIC = '\w\d\s\-_:\.';
|
||||||
|
|
||||||
|
const SINGLE_QUOTE = '\'';
|
||||||
|
const DOUBLE_QUOTE = '"';
|
||||||
|
const ALL_QUOTES = '[\'"]';
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter an attribute value for save inclusion in an XPath query.
|
||||||
|
*
|
||||||
|
* @param string $value The value to filter.
|
||||||
|
* @param string $quotes The quotes used to delimit the value in the XPath query.
|
||||||
|
*
|
||||||
|
* @return string The filtered attribute value.
|
||||||
|
*/
|
||||||
|
public static function filterAttrValue($value, $quotes = self::ALL_QUOTES)
|
||||||
|
{
|
||||||
|
return preg_replace('#'.$quotes.'#', '', $value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filter an attribute name for save inclusion in an XPath query.
|
||||||
|
*
|
||||||
|
* @param string $name The attribute name to filter.
|
||||||
|
* @param mixed $allow The set of characters to allow. Can be one of the constants provided by this class, or a
|
||||||
|
* custom regex excluding the '#' character (used as delimiter).
|
||||||
|
*
|
||||||
|
* @return string The filtered attribute name.
|
||||||
|
*/
|
||||||
|
public static function filterAttrName($name, $allow = self::EXTENDED_ALPHANUMERIC)
|
||||||
|
{
|
||||||
|
return preg_replace('#[^'.$allow.']#', '', $name);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,830 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* This file is part of miniOrange SAML plugin.
|
||||||
|
*
|
||||||
|
* miniOrange SAML plugin is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* miniOrange SAML plugin is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with miniOrange SAML plugin. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
include_once 'xmlseclibs.php';
|
||||||
|
use \RobRichards\XMLSecLibs\MoXMLSecurityKey;
|
||||||
|
use \RobRichards\XMLSecLibs\MoXMLSecurityDSig;
|
||||||
|
use \RobRichards\XMLSecLibs\MoXMLSecEnc;
|
||||||
|
|
||||||
|
class Utilities {
|
||||||
|
|
||||||
|
public static function generateID() {
|
||||||
|
return '_' . self::stringToHex(self::generateRandomBytes(21));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function stringToHex($bytes) {
|
||||||
|
$ret = '';
|
||||||
|
for($i = 0; $i < strlen($bytes); $i++) {
|
||||||
|
$ret .= sprintf('%02x', ord($bytes[$i]));
|
||||||
|
}
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function generateRandomBytes($length, $fallback = TRUE) {
|
||||||
|
|
||||||
|
return openssl_random_pseudo_bytes($length);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function createAuthnRequest($acsUrl, $issuer, $force_authn = 'false') {
|
||||||
|
$requestXmlStr = '<?xml version="1.0" encoding="UTF-8"?>' .
|
||||||
|
'<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" ID="' . self::generateID() .
|
||||||
|
'" Version="2.0" IssueInstant="' . self::generateTimestamp() . '"';
|
||||||
|
if( $force_authn == 'true') {
|
||||||
|
$requestXmlStr .= ' ForceAuthn="true"';
|
||||||
|
}
|
||||||
|
$requestXmlStr .= ' ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="' . $acsUrl .
|
||||||
|
'" ><saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">' . $issuer . '</saml:Issuer></samlp:AuthnRequest>';
|
||||||
|
$deflatedStr = gzdeflate($requestXmlStr);
|
||||||
|
$base64EncodedStr = base64_encode($deflatedStr);
|
||||||
|
$urlEncoded = urlencode($base64EncodedStr);
|
||||||
|
update_option('MO_SAML_REQUEST',$base64EncodedStr);
|
||||||
|
|
||||||
|
return $urlEncoded;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function createSAMLRequest($acsUrl, $issuer, $destination, $force_authn = 'false') {
|
||||||
|
|
||||||
|
$requestXmlStr = '<?xml version="1.0" encoding="UTF-8"?>' .
|
||||||
|
'<samlp:AuthnRequest xmlns:samlp="urn:oasis:names:tc:SAML:2.0:protocol" xmlns="urn:oasis:names:tc:SAML:2.0:assertion" ID="' . self::generateID() .
|
||||||
|
'" Version="2.0" IssueInstant="' . self::generateTimestamp() . '"';
|
||||||
|
if( $force_authn == 'true') {
|
||||||
|
$requestXmlStr .= ' ForceAuthn="true"';
|
||||||
|
}
|
||||||
|
$requestXmlStr .= ' ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" AssertionConsumerServiceURL="' . $acsUrl .
|
||||||
|
'" Destination="' . htmlspecialchars($destination) . '"><saml:Issuer xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion">' . $issuer . '</saml:Issuer><samlp:NameIDPolicy AllowCreate="true" Format="urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified"
|
||||||
|
/></samlp:AuthnRequest>';
|
||||||
|
$samlRequest = base64_encode($requestXmlStr);
|
||||||
|
update_option('MO_SAML_REQUEST',$samlRequest);
|
||||||
|
return $requestXmlStr;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function generateTimestamp($instant = NULL) {
|
||||||
|
if($instant === NULL) {
|
||||||
|
$instant = time();
|
||||||
|
}
|
||||||
|
return gmdate('Y-m-d\TH:i:s\Z', $instant);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function xpQuery(DOMNode $node, $query)
|
||||||
|
{
|
||||||
|
|
||||||
|
static $xpCache = NULL;
|
||||||
|
|
||||||
|
if ($node instanceof DOMDocument) {
|
||||||
|
$doc = $node;
|
||||||
|
} else {
|
||||||
|
$doc = $node->ownerDocument;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($xpCache === NULL || !$xpCache->document->isSameNode($doc)) {
|
||||||
|
$xpCache = new DOMXPath($doc);
|
||||||
|
$xpCache->registerNamespace('soap-env', 'http://schemas.xmlsoap.org/soap/envelope/');
|
||||||
|
$xpCache->registerNamespace('saml_protocol', 'urn:oasis:names:tc:SAML:2.0:protocol');
|
||||||
|
$xpCache->registerNamespace('saml_assertion', 'urn:oasis:names:tc:SAML:2.0:assertion');
|
||||||
|
$xpCache->registerNamespace('saml_metadata', 'urn:oasis:names:tc:SAML:2.0:metadata');
|
||||||
|
$xpCache->registerNamespace('ds', 'http://www.w3.org/2000/09/xmldsig#');
|
||||||
|
$xpCache->registerNamespace('xenc', 'http://www.w3.org/2001/04/xmlenc#');
|
||||||
|
}
|
||||||
|
|
||||||
|
$results = $xpCache->query($query, $node);
|
||||||
|
$ret = array();
|
||||||
|
for ($i = 0; $i < $results->length; $i++) {
|
||||||
|
$ret[$i] = $results->item($i);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function parseNameId(DOMElement $xml)
|
||||||
|
{
|
||||||
|
$ret = array('Value' => trim($xml->textContent));
|
||||||
|
|
||||||
|
foreach (array('NameQualifier', 'SPNameQualifier', 'Format') as $attr) {
|
||||||
|
if ($xml->hasAttribute($attr)) {
|
||||||
|
$ret[$attr] = $xml->getAttribute($attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function xsDateTimeToTimestamp($time)
|
||||||
|
{
|
||||||
|
$matches = array();
|
||||||
|
|
||||||
|
// We use a very strict regex to parse the timestamp.
|
||||||
|
$regex = '/^(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)T(\\d\\d):(\\d\\d):(\\d\\d)(?:\\.\\d+)?Z$/D';
|
||||||
|
if (preg_match($regex, $time, $matches) == 0) {
|
||||||
|
echo sprintf("Invalid SAML2 timestamp passed to xsDateTimeToTimestamp: ". htmlspecialchars($time));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Extract the different components of the time from the matches in the regex.
|
||||||
|
// intval will ignore leading zeroes in the string.
|
||||||
|
$year = intval($matches[1]);
|
||||||
|
$month = intval($matches[2]);
|
||||||
|
$day = intval($matches[3]);
|
||||||
|
$hour = intval($matches[4]);
|
||||||
|
$minute = intval($matches[5]);
|
||||||
|
$second = intval($matches[6]);
|
||||||
|
|
||||||
|
// We use gmmktime because the timestamp will always be given
|
||||||
|
//in UTC.
|
||||||
|
$ts = gmmktime($hour, $minute, $second, $month, $day, $year);
|
||||||
|
|
||||||
|
return $ts;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function extractStrings(DOMElement $parent, $namespaceURI, $localName)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
$ret = array();
|
||||||
|
for ($node = $parent->firstChild; $node !== NULL; $node = $node->nextSibling) {
|
||||||
|
if ($node->namespaceURI !== $namespaceURI || $node->localName !== $localName) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$ret[] = trim($node->textContent);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function validateElement(DOMElement $root)
|
||||||
|
{
|
||||||
|
//$data = $root->ownerDocument->saveXML($root);
|
||||||
|
//echo htmlspecialchars($data);
|
||||||
|
|
||||||
|
/* Create an XML security object. */
|
||||||
|
$objXMLSecDSig = new MoXMLSecurityDSig();
|
||||||
|
|
||||||
|
/* Both SAML messages and SAML assertions use the 'ID' attribute. */
|
||||||
|
$objXMLSecDSig->idKeys[] = 'ID';
|
||||||
|
|
||||||
|
|
||||||
|
/* Locate the XMLDSig Signature element to be used. */
|
||||||
|
$signatureElement = self::xpQuery($root, './ds:Signature');
|
||||||
|
//print_r($signatureElement);
|
||||||
|
|
||||||
|
if (count($signatureElement) === 0) {
|
||||||
|
/* We don't have a signature element to validate. */
|
||||||
|
return FALSE;
|
||||||
|
} elseif (count($signatureElement) > 1) {
|
||||||
|
echo sprintf("XMLSec: more than one signature element in root.");
|
||||||
|
exit;
|
||||||
|
}/* elseif ((in_array('Response', $signatureElement) && $ocurrence['Response'] > 1) ||
|
||||||
|
(in_array('Assertion', $signatureElement) && $ocurrence['Assertion'] > 1) ||
|
||||||
|
!in_array('Response', $signatureElement) && !in_array('Assertion', $signatureElement)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
} */
|
||||||
|
|
||||||
|
$signatureElement = $signatureElement[0];
|
||||||
|
$objXMLSecDSig->sigNode = $signatureElement;
|
||||||
|
|
||||||
|
/* Canonicalize the XMLDSig SignedInfo element in the message. */
|
||||||
|
$objXMLSecDSig->canonicalizeSignedInfo();
|
||||||
|
|
||||||
|
/* Validate referenced xml nodes. */
|
||||||
|
if (!$objXMLSecDSig->validateReference()) {
|
||||||
|
echo sprintf("XMLSec: digest validation failed");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check that $root is one of the signed nodes. */
|
||||||
|
$rootSigned = FALSE;
|
||||||
|
/** @var DOMNode $signedNode */
|
||||||
|
foreach ($objXMLSecDSig->getValidatedNodes() as $signedNode) {
|
||||||
|
if ($signedNode->isSameNode($root)) {
|
||||||
|
$rootSigned = TRUE;
|
||||||
|
break;
|
||||||
|
} elseif ($root->parentNode instanceof DOMDocument && $signedNode->isSameNode($root->ownerDocument)) {
|
||||||
|
/* $root is the root element of a signed document. */
|
||||||
|
$rootSigned = TRUE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$rootSigned) {
|
||||||
|
echo sprintf("XMLSec: The root element is not signed.");
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Now we extract all available X509 certificates in the signature element. */
|
||||||
|
$certificates = array();
|
||||||
|
foreach (self::xpQuery($signatureElement, './ds:KeyInfo/ds:X509Data/ds:X509Certificate') as $certNode) {
|
||||||
|
$certData = trim($certNode->textContent);
|
||||||
|
$certData = str_replace(array("\r", "\n", "\t", ' '), '', $certData);
|
||||||
|
$certificates[] = $certData;
|
||||||
|
//echo "CertDate: " . $certData . "<br />";
|
||||||
|
}
|
||||||
|
|
||||||
|
$ret = array(
|
||||||
|
'Signature' => $objXMLSecDSig,
|
||||||
|
'Certificates' => $certificates,
|
||||||
|
);
|
||||||
|
|
||||||
|
//echo "Signature validated";
|
||||||
|
|
||||||
|
|
||||||
|
return $ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static function validateSignature(array $info, MoXMLSecurityKey $key)
|
||||||
|
{
|
||||||
|
|
||||||
|
|
||||||
|
/** @var MoXMLSecurityDSig $objXMLSecDSig */
|
||||||
|
$objXMLSecDSig = $info['Signature'];
|
||||||
|
|
||||||
|
$sigMethod = self::xpQuery($objXMLSecDSig->sigNode, './ds:SignedInfo/ds:SignatureMethod');
|
||||||
|
if (empty($sigMethod)) {
|
||||||
|
echo sprintf('Missing SignatureMethod element');
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
$sigMethod = $sigMethod[0];
|
||||||
|
if (!$sigMethod->hasAttribute('Algorithm')) {
|
||||||
|
echo sprintf('Missing Algorithm-attribute on SignatureMethod element.');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$algo = $sigMethod->getAttribute('Algorithm');
|
||||||
|
|
||||||
|
if ($key->type === MoXMLSecurityKey::RSA_SHA1 && $algo !== $key->type) {
|
||||||
|
$key = self::castKey($key, $algo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Check the signature. */
|
||||||
|
if (! $objXMLSecDSig->verify($key)) {
|
||||||
|
echo sprintf('Unable to validate Signature');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function castKey(MoXMLSecurityKey $key, $algorithm, $type = 'public')
|
||||||
|
{
|
||||||
|
|
||||||
|
// do nothing if algorithm is already the type of the key
|
||||||
|
if ($key->type === $algorithm) {
|
||||||
|
return $key;
|
||||||
|
}
|
||||||
|
|
||||||
|
$keyInfo = openssl_pkey_get_details($key->key);
|
||||||
|
if ($keyInfo === FALSE) {
|
||||||
|
echo sprintf('Unable to get key details from XMLSecurityKey.');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if (!isset($keyInfo['key'])) {
|
||||||
|
echo sprintf('Missing key in public key details.');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$newKey = new MoXMLSecurityKey($algorithm, array('type'=>$type));
|
||||||
|
$newKey->loadKey($keyInfo['key']);
|
||||||
|
|
||||||
|
return $newKey;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function processResponse($currentURL, $certFingerprint, $signatureData,
|
||||||
|
SAML2_Response $response, $certNumber,$relayState) {
|
||||||
|
|
||||||
|
$assertion = current($response->getAssertions());
|
||||||
|
|
||||||
|
$notBefore = $assertion->getNotBefore();
|
||||||
|
if ($notBefore !== NULL && $notBefore > time() + 60) {
|
||||||
|
error_log('Received an assertion that is valid in the future. Check clock synchronization on IdP and SP.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$notOnOrAfter = $assertion->getNotOnOrAfter();
|
||||||
|
if ($notOnOrAfter !== NULL && $notOnOrAfter <= time() - 60) {
|
||||||
|
error_log('Received an assertion that has expired. Check clock synchronization on IdP and SP.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sessionNotOnOrAfter = $assertion->getSessionNotOnOrAfter();
|
||||||
|
if ($sessionNotOnOrAfter !== NULL && $sessionNotOnOrAfter <= time() - 60) {
|
||||||
|
error_log('Received an assertion with a session that has expired. Check clock synchronization on IdP and SP.');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Validate Response-element destination. */
|
||||||
|
$msgDestination = $response->getDestination();
|
||||||
|
if(substr($msgDestination, -1) == '/') {
|
||||||
|
$msgDestination = substr($msgDestination, 0, -1);
|
||||||
|
}
|
||||||
|
if(substr($currentURL, -1) == '/') {
|
||||||
|
$currentURL = substr($currentURL, 0, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($msgDestination !== NULL && $msgDestination !== $currentURL) {
|
||||||
|
echo sprintf('Destination in response doesn\'t match the current URL. Destination is "' .
|
||||||
|
htmlspecialchars($msgDestination) . '", current URL is "' . htmlspecialchars($currentURL) . '".');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$responseSigned = self::checkSign($certFingerprint, $signatureData, $certNumber,$relayState);
|
||||||
|
|
||||||
|
if (!$responseSigned) {
|
||||||
|
error_log('SAML: Responses is not signed');
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Returning boolean $responseSigned */
|
||||||
|
return $responseSigned;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function checkSign($certFingerprint, $signatureData, $certNumber, $relayState) {
|
||||||
|
$certificates = $signatureData['Certificates'];
|
||||||
|
error_log('SAML: certificate count = '.count($certificates));
|
||||||
|
if (count($certificates) === 0) {
|
||||||
|
$storedCerts = maybe_unserialize(get_option('saml_x509_certificate'));
|
||||||
|
$pemCert = $storedCerts[$certNumber];
|
||||||
|
}else{
|
||||||
|
$fpArray = array();
|
||||||
|
$fpArray[] = $certFingerprint;
|
||||||
|
$pemCert = self::findCertificate($fpArray, $certificates, $relayState);
|
||||||
|
if($pemCert==false)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$lastException = NULL;
|
||||||
|
|
||||||
|
$key = new MoXMLSecurityKey(MoXMLSecurityKey::RSA_SHA1, array('type'=>'public'));
|
||||||
|
$key->loadKey($pemCert);
|
||||||
|
|
||||||
|
try {
|
||||||
|
/*
|
||||||
|
* Make sure that we have a valid signature
|
||||||
|
*/
|
||||||
|
self::validateSignature($signatureData, $key);
|
||||||
|
return TRUE;
|
||||||
|
} catch (Exception $e) {
|
||||||
|
$lastException = $e;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* We were unable to validate the signature with any of our keys. */
|
||||||
|
if ($lastException !== NULL) {
|
||||||
|
throw $lastException;
|
||||||
|
} else {
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function validateIssuerAndAudience($samlResponse, $spEntityId, $issuerToValidateAgainst, $relayState) {
|
||||||
|
$issuer = current($samlResponse->getAssertions())->getIssuer();
|
||||||
|
$assertion = current($samlResponse->getAssertions());
|
||||||
|
$audiences = $assertion->getValidAudiences();
|
||||||
|
if(strcmp($issuerToValidateAgainst, $issuer) === 0) {
|
||||||
|
if(!empty($audiences)) {
|
||||||
|
if(in_array($spEntityId, $audiences, TRUE)) {
|
||||||
|
return TRUE;
|
||||||
|
} else {
|
||||||
|
if($relayState=='testValidate'){
|
||||||
|
$Error_message=mo_saml_options_error_constants::Error_invalid_audience;
|
||||||
|
$Cause_message = mo_saml_options_error_constants::Cause_invalid_audience;
|
||||||
|
echo '<div style="font-family:Calibri;padding:0 3%;">';
|
||||||
|
echo '<div style="color: #a94442;background-color: #f2dede;padding: 15px;margin-bottom: 20px;text-align:center;border:1px solid #E6B3B2;font-size:18pt;"> ' . __('ERROR','miniorange-saml-20-single-sign-on') . '</div>
|
||||||
|
<div style="color: #a94442;font-size:14pt; margin-bottom:20px;"><p><strong>' . __('Error','miniorange-saml-20-single-sign-on') . ': </strong>'.$Error_message.'</p>
|
||||||
|
|
||||||
|
<p><strong>' . __('Possible Cause','miniorange-saml-20-single-sign-on'). ': </strong>'.$Cause_message.'</p>
|
||||||
|
<p>' . __('Expected one of the Audiences to be','miniorange-saml-20-single-sign-on'). ': '.$spEntityId.'<p>
|
||||||
|
</div>';
|
||||||
|
mo_saml_download_logs($Error_message,$Cause_message);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wp_die(__("We could not sign you in. Please contact your administrator",'miniorange-saml-20-single-sign-on'),"Error: Invalid Audience URI");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if($relayState=='testValidate'){
|
||||||
|
|
||||||
|
$Error_message=mo_saml_options_error_constants::Error_issuer_not_verfied;
|
||||||
|
$Cause_message = mo_saml_options_error_constants::Cause_issuer_not_verfied;
|
||||||
|
update_option('mo_saml_required_issuer',$issuer);
|
||||||
|
echo '<div style="font-family:Calibri;padding:0 3%;">';
|
||||||
|
echo '<div style="color: #a94442;background-color: #f2dede;padding: 15px;margin-bottom: 20px;text-align:center;border:1px solid #E6B3B2;font-size:18pt;">' . __('ERROR','miniorange-saml-20-single-sign-on') . '</div>
|
||||||
|
<div style="color: #a94442;font-size:14pt; margin-bottom:20px;text-align: justify"><p><strong>' . __('Error','miniorange-saml-20-single-sign-on'). ':'.$Error_message.' </strong></p>
|
||||||
|
|
||||||
|
<p><strong>' . __('Possible Cause','miniorange-saml-20-single-sign-on') . ':'.$Cause_message.' </strong></p>
|
||||||
|
<div>
|
||||||
|
<ol style="text-align: center">
|
||||||
|
<form method="post" action="" name="mo_fix_entityid" id="mo_fix_certificate">';
|
||||||
|
wp_nonce_field('mo_fix_entity_id');
|
||||||
|
echo '<input type="hidden" name="option" value="mo_fix_entity_id" />
|
||||||
|
<input type="submit" class="miniorange-button" style="width: 55%" value="' . __('Fix Issue','miniorange-saml-20-single-sign-on' ) .'">
|
||||||
|
</form>
|
||||||
|
</ol>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>';
|
||||||
|
|
||||||
|
mo_saml_download_logs($Error_message,$Cause_message);
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wp_die(__("We could not sign you in. Please contact your administrator",'miniorange-saml-20-single-sign-on'),"Error: Issuer cannot be verified");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static function findCertificate(array $certFingerprints, array $certificates, $relayState) {
|
||||||
|
|
||||||
|
$candidates = array();
|
||||||
|
|
||||||
|
//foreach ($certificates as $cert) {
|
||||||
|
$fp = strtolower(sha1(base64_decode($certificates[0])));
|
||||||
|
if (!in_array($fp, $certFingerprints, TRUE)) {
|
||||||
|
$candidates[] = $fp;
|
||||||
|
return false;
|
||||||
|
//continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* We have found a matching fingerprint. */
|
||||||
|
$pem = "-----BEGIN CERTIFICATE-----\n" .
|
||||||
|
chunk_split($certificates[0], 64) .
|
||||||
|
"-----END CERTIFICATE-----\n";
|
||||||
|
|
||||||
|
return $pem;
|
||||||
|
// }
|
||||||
|
|
||||||
|
// if($relayState=='testValidate'){
|
||||||
|
// $pem = "-----BEGIN CERTIFICATE-----<br>" .
|
||||||
|
// chunk_split($cert, 64) .
|
||||||
|
// "<br>-----END CERTIFICATE-----";
|
||||||
|
|
||||||
|
// echo '<div style="font-family:Calibri;padding:0 3%;">';
|
||||||
|
// echo '<div style="color: #a94442;background-color: #f2dede;padding: 15px;margin-bottom: 20px;text-align:center;border:1px solid #E6B3B2;font-size:18pt;"> ERROR</div>
|
||||||
|
// <div style="color: #a94442;font-size:14pt; margin-bottom:20px;"><p><strong>Error: </strong>Unable to find a certificate matching the configured fingerprint.</p>
|
||||||
|
// <p>Please contact your administrator and report the following error:</p>
|
||||||
|
// <p><strong>Possible Cause: </strong>Content of \'X.509 Certificate\' field in Service Provider Settings is incorrect. Please replace it with certificate given below.</p>
|
||||||
|
// <p><strong>Certificate found in SAML Response: </strong><br><br>'.$pem.'</p>
|
||||||
|
// </div>
|
||||||
|
// <div style="margin:3%;display:block;text-align:center;">
|
||||||
|
// <form action="index.php">
|
||||||
|
// <div style="margin:3%;display:block;text-align:center;"><input style="padding:1%;width:100px;background: #0091CD none repeat scroll 0% 0%;cursor: pointer;font-size:15px;border-width: 1px;border-style: solid;border-radius: 3px;white-space: nowrap;box-sizing: border-box;border-color: #0073AA;box-shadow: 0px 1px 0px rgba(120, 200, 230, 0.6) inset;color: #FFF;"type="button" value="Done" onClick="self.close();"></div>';
|
||||||
|
|
||||||
|
// exit;
|
||||||
|
// }
|
||||||
|
// else{
|
||||||
|
// wp_die("We could not sign you in. Please contact your administrator","Error: Invalid Certificate");
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decrypt an encrypted element.
|
||||||
|
*
|
||||||
|
* This is an internal helper function.
|
||||||
|
*
|
||||||
|
* @param DOMElement $encryptedData The encrypted data.
|
||||||
|
* @param MoXMLSecurityKey $inputKey The decryption key.
|
||||||
|
* @param array &$blacklist Blacklisted decryption algorithms.
|
||||||
|
* @return DOMElement The decrypted element.
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
private static function doDecryptElement(DOMElement $encryptedData, MoXMLSecurityKey $inputKey, array &$blacklist)
|
||||||
|
{
|
||||||
|
$enc = new MoXMLSecEnc();
|
||||||
|
$enc->setNode($encryptedData);
|
||||||
|
|
||||||
|
$enc->type = $encryptedData->getAttribute("Type");
|
||||||
|
$symmetricKey = $enc->locateKey($encryptedData);
|
||||||
|
if (!$symmetricKey) {
|
||||||
|
echo sprintf(__('Could not locate key algorithm in encrypted data.','miniorange-saml-20-single-sign-on'));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
$symmetricKeyInfo = $enc->locateKeyInfo($symmetricKey);
|
||||||
|
if (!$symmetricKeyInfo) {
|
||||||
|
echo sprintf(__('Could not locate <dsig:KeyInfo> for the encrypted key.','miniorange-saml-20-single-sign-on'));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$inputKeyAlgo = $inputKey->getAlgorith();
|
||||||
|
if ($symmetricKeyInfo->isEncrypted) {
|
||||||
|
$symKeyInfoAlgo = $symmetricKeyInfo->getAlgorith();
|
||||||
|
if (in_array($symKeyInfoAlgo, $blacklist, TRUE)) {
|
||||||
|
echo sprintf('Algorithm disabled: ' . var_export($symKeyInfoAlgo, TRUE));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
if ($symKeyInfoAlgo === MoXMLSecurityKey::RSA_OAEP_MGF1P && $inputKeyAlgo === MoXMLSecurityKey::RSA_1_5) {
|
||||||
|
/*
|
||||||
|
* The RSA key formats are equal, so loading an RSA_1_5 key
|
||||||
|
* into an RSA_OAEP_MGF1P key can be done without problems.
|
||||||
|
* We therefore pretend that the input key is an
|
||||||
|
* RSA_OAEP_MGF1P key.
|
||||||
|
*/
|
||||||
|
$inputKeyAlgo = MoXMLSecurityKey::RSA_OAEP_MGF1P;
|
||||||
|
}
|
||||||
|
/* Make sure that the input key format is the same as the one used to encrypt the key. */
|
||||||
|
if ($inputKeyAlgo !== $symKeyInfoAlgo) {
|
||||||
|
echo sprintf( 'Algorithm mismatch between input key and key used to encrypt ' .
|
||||||
|
' the symmetric key for the message. Key was: ' .
|
||||||
|
var_export($inputKeyAlgo, TRUE) . '; message was: ' .
|
||||||
|
var_export($symKeyInfoAlgo, TRUE));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
/** @var MoXMLSecEnc $encKey */
|
||||||
|
$encKey = $symmetricKeyInfo->encryptedCtx;
|
||||||
|
$symmetricKeyInfo->key = $inputKey->key;
|
||||||
|
$keySize = $symmetricKey->getSymmetricKeySize();
|
||||||
|
if ($keySize === NULL) {
|
||||||
|
/* To protect against "key oracle" attacks, we need to be able to create a
|
||||||
|
* symmetric key, and for that we need to know the key size.
|
||||||
|
*/
|
||||||
|
echo sprintf('Unknown key size for encryption algorithm: ' . var_export($symmetricKey->type, TRUE));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
$key = $encKey->decryptKey($symmetricKeyInfo);
|
||||||
|
if (strlen($key) != $keySize) {
|
||||||
|
echo sprintf('Unexpected key size (' . strlen($key) * 8 . 'bits) for encryption algorithm: ' .
|
||||||
|
var_export($symmetricKey->type, TRUE));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
} catch (Exception $e) {
|
||||||
|
/* We failed to decrypt this key. Log it, and substitute a "random" key. */
|
||||||
|
|
||||||
|
/* Create a replacement key, so that it looks like we fail in the same way as if the key was correctly padded. */
|
||||||
|
/* We base the symmetric key on the encrypted key and private key, so that we always behave the
|
||||||
|
* same way for a given input key.
|
||||||
|
*/
|
||||||
|
$encryptedKey = $encKey->getCipherValue();
|
||||||
|
$pkey = openssl_pkey_get_details($symmetricKeyInfo->key);
|
||||||
|
$pkey = sha1(serialize($pkey), TRUE);
|
||||||
|
$key = sha1($encryptedKey . $pkey, TRUE);
|
||||||
|
/* Make sure that the key has the correct length. */
|
||||||
|
if (strlen($key) > $keySize) {
|
||||||
|
$key = substr($key, 0, $keySize);
|
||||||
|
} elseif (strlen($key) < $keySize) {
|
||||||
|
$key = str_pad($key, $keySize);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$symmetricKey->loadkey($key);
|
||||||
|
} else {
|
||||||
|
$symKeyAlgo = $symmetricKey->getAlgorith();
|
||||||
|
/* Make sure that the input key has the correct format. */
|
||||||
|
if ($inputKeyAlgo !== $symKeyAlgo) {
|
||||||
|
echo sprintf( 'Algorithm mismatch between input key and key in message. ' .
|
||||||
|
'Key was: ' . var_export($inputKeyAlgo, TRUE) . '; message was: ' .
|
||||||
|
var_export($symKeyAlgo, TRUE));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
$symmetricKey = $inputKey;
|
||||||
|
}
|
||||||
|
$algorithm = $symmetricKey->getAlgorith();
|
||||||
|
if (in_array($algorithm, $blacklist, TRUE)) {
|
||||||
|
echo sprintf('Algorithm disabled: ' . var_export($algorithm, TRUE));
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
/** @var string $decrypted */
|
||||||
|
$decrypted = $enc->decryptNode($symmetricKey, FALSE);
|
||||||
|
/*
|
||||||
|
* This is a workaround for the case where only a subset of the XML
|
||||||
|
* tree was serialized for encryption. In that case, we may miss the
|
||||||
|
* namespaces needed to parse the XML.
|
||||||
|
*/
|
||||||
|
$xml = '<root xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" '.
|
||||||
|
'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">' .
|
||||||
|
$decrypted .
|
||||||
|
'</root>';
|
||||||
|
$newDoc = new DOMDocument();
|
||||||
|
if (!@$newDoc->loadXML($xml)) {
|
||||||
|
echo sprintf('Failed to parse decrypted XML. Maybe the wrong sharedkey was used?');
|
||||||
|
throw new Exception('Failed to parse decrypted XML. Maybe the wrong sharedkey was used?');
|
||||||
|
}
|
||||||
|
$decryptedElement = $newDoc->firstChild->firstChild;
|
||||||
|
if ($decryptedElement === NULL) {
|
||||||
|
echo sprintf('Missing encrypted element.');
|
||||||
|
throw new Exception('Missing encrypted element.');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!($decryptedElement instanceof DOMElement)) {
|
||||||
|
echo sprintf('Decrypted element was not actually a DOMElement.');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $decryptedElement;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Decrypt an encrypted element.
|
||||||
|
*
|
||||||
|
* @param DOMElement $encryptedData The encrypted data.
|
||||||
|
* @param MoXMLSecurityKey $inputKey The decryption key.
|
||||||
|
* @param array $blacklist Blacklisted decryption algorithms.
|
||||||
|
* @return DOMElement The decrypted element.
|
||||||
|
* @throws Exception
|
||||||
|
*/
|
||||||
|
public static function decryptElement(DOMElement $encryptedData, MoXMLSecurityKey $inputKey, array $blacklist = array(), MoXMLSecurityKey $alternateKey = NULL)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
return self::doDecryptElement($encryptedData, $inputKey, $blacklist);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
//Try with alternate key
|
||||||
|
try {
|
||||||
|
return self::doDecryptElement($encryptedData, $alternateKey, $blacklist);
|
||||||
|
} catch(Exception $t) {
|
||||||
|
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Something went wrong during decryption, but for security
|
||||||
|
* reasons we cannot tell the user what failed.
|
||||||
|
*/
|
||||||
|
//print_r($e->getMessage());
|
||||||
|
echo sprintf('Failed to decrypt XML element.');
|
||||||
|
exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates the metadata of the SP based on the settings
|
||||||
|
*
|
||||||
|
* @param string $sp The SP data
|
||||||
|
* @param string $authnsign authnRequestsSigned attribute
|
||||||
|
* @param string $wsign wantAssertionsSigned attribute
|
||||||
|
* @param DateTime $validUntil Metadata's valid time
|
||||||
|
* @param Timestamp $cacheDuration Duration of the cache in seconds
|
||||||
|
* @param array $contacts Contacts info
|
||||||
|
* @param array $organization Organization ingo
|
||||||
|
*
|
||||||
|
* @return string SAML Metadata XML
|
||||||
|
*/
|
||||||
|
public static function metadata_builder($siteUrl)
|
||||||
|
{
|
||||||
|
$xml = new DOMDocument();
|
||||||
|
$url = plugins_url().'/miniorange-saml-20-single-sign-on/sp-metadata.xml';
|
||||||
|
|
||||||
|
$xml->load($url);
|
||||||
|
|
||||||
|
$xpath = new DOMXPath($xml);
|
||||||
|
$elements = $xpath->query('//md:EntityDescriptor[@entityID="http://{path-to-your-site}/wp-content/plugins/miniorange-saml-20-single-sign-on/"]');
|
||||||
|
|
||||||
|
if ($elements->length >= 1) {
|
||||||
|
$element = $elements->item(0);
|
||||||
|
$element->setAttribute('entityID', $siteUrl.'/wp-content/plugins/miniorange-saml-20-single-sign-on/');
|
||||||
|
}
|
||||||
|
|
||||||
|
$elements = $xpath->query('//md:AssertionConsumerService[@Location="http://{path-to-your-site}"]');
|
||||||
|
if ($elements->length >= 1) {
|
||||||
|
$element = $elements->item(0);
|
||||||
|
$element->setAttribute('Location', $siteUrl.'/');
|
||||||
|
}
|
||||||
|
|
||||||
|
//re-save
|
||||||
|
$xml->save(plugins_url()."/miniorange-saml-20-single-sign-on/sp-metadata.xml");
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function get_mapped_groups($saml_params, $saml_groups)
|
||||||
|
{
|
||||||
|
$groups = array();
|
||||||
|
|
||||||
|
if (!empty($saml_groups)) {
|
||||||
|
$saml_mapped_groups = array();
|
||||||
|
$i=1;
|
||||||
|
while ($i < 10) {
|
||||||
|
$saml_mapped_groups_value = $saml_params->get('group'.$i.'_map');
|
||||||
|
|
||||||
|
$saml_mapped_groups[$i] = explode(';', $saml_mapped_groups_value);
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($saml_groups as $saml_group) {
|
||||||
|
if (!empty($saml_group)) {
|
||||||
|
$i = 0;
|
||||||
|
$found = false;
|
||||||
|
|
||||||
|
while ($i < 9 && !$found) {
|
||||||
|
if (!empty($saml_mapped_groups[$i]) && in_array($saml_group, $saml_mapped_groups[$i], TRUE)) {
|
||||||
|
$groups[] = $saml_params->get('group'.$i);
|
||||||
|
$found = true;
|
||||||
|
}
|
||||||
|
$i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return array_unique($groups);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static function getEncryptionAlgorithm($method){
|
||||||
|
switch($method){
|
||||||
|
case 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc':
|
||||||
|
return MoXMLSecurityKey::TRIPLEDES_CBC;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'http://www.w3.org/2001/04/xmlenc#aes128-cbc':
|
||||||
|
return MoXMLSecurityKey::AES128_CBC;
|
||||||
|
|
||||||
|
case 'http://www.w3.org/2001/04/xmlenc#aes192-cbc':
|
||||||
|
return MoXMLSecurityKey::AES192_CBC;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'http://www.w3.org/2001/04/xmlenc#aes256-cbc':
|
||||||
|
return MoXMLSecurityKey::AES256_CBC;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'http://www.w3.org/2001/04/xmlenc#rsa-1_5':
|
||||||
|
return MoXMLSecurityKey::RSA_1_5;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p':
|
||||||
|
return MoXMLSecurityKey::RSA_OAEP_MGF1P;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'http://www.w3.org/2000/09/xmldsig#dsa-sha1':
|
||||||
|
return MoXMLSecurityKey::DSA_SHA1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'http://www.w3.org/2000/09/xmldsig#rsa-sha1':
|
||||||
|
return MoXMLSecurityKey::RSA_SHA1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256':
|
||||||
|
return MoXMLSecurityKey::RSA_SHA256;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384':
|
||||||
|
return MoXMLSecurityKey::RSA_SHA384;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512':
|
||||||
|
return MoXMLSecurityKey::RSA_SHA512;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
echo sprintf('Invalid Encryption Method: '. htmlspecialchars($method));
|
||||||
|
exit;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function sanitize_certificate( $certificate ) {
|
||||||
|
$certificate = preg_replace("/[\r\n]+/", "", $certificate);
|
||||||
|
$certificate = str_replace( "-", "", $certificate );
|
||||||
|
$certificate = str_replace( "BEGIN CERTIFICATE", "", $certificate );
|
||||||
|
$certificate = str_replace( "END CERTIFICATE", "", $certificate );
|
||||||
|
$certificate = str_replace( " ", "", $certificate );
|
||||||
|
$certificate = chunk_split($certificate, 64, "\r\n");
|
||||||
|
$certificate = "-----BEGIN CERTIFICATE-----\r\n" . $certificate . "-----END CERTIFICATE-----";
|
||||||
|
return $certificate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function desanitize_certificate( $certificate ) {
|
||||||
|
$certificate = preg_replace("/[\r\n]+/", "", $certificate);
|
||||||
|
//$certificate = str_replace( "-", "", $certificate );
|
||||||
|
$certificate = str_replace( "-----BEGIN CERTIFICATE-----", "", $certificate );
|
||||||
|
$certificate = str_replace( "-----END CERTIFICATE-----", "", $certificate );
|
||||||
|
$certificate = str_replace( " ", "", $certificate );
|
||||||
|
//$certificate = chunk_split($certificate, 64, "\r\n");
|
||||||
|
//$certificate = "-----BEGIN CERTIFICATE-----\r\n" . $certificate . "-----END CERTIFICATE-----";
|
||||||
|
return $certificate;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function mo_saml_wp_remote_post($url, $args = array()){
|
||||||
|
$response = wp_remote_post($url, $args);
|
||||||
|
if(!is_wp_error($response)){
|
||||||
|
return $response;
|
||||||
|
} else {
|
||||||
|
$show_message = new saml_mo_login();
|
||||||
|
update_option('mo_saml_message', __('Unable to connect to the Internet. Please try again.','miniorange-saml-20-single-sign-on'));
|
||||||
|
$show_message->mo_saml_show_error_message();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static function mo_saml_wp_remote_get($url, $args = array()){
|
||||||
|
$response = wp_remote_get($url, $args);
|
||||||
|
if(!is_wp_error($response)){
|
||||||
|
return $response;
|
||||||
|
} else {
|
||||||
|
$show_message = new saml_mo_login();
|
||||||
|
update_option('mo_saml_message', __('Unable to connect to the Internet. Please try again.','miniorange-saml-20-single-sign-on'));
|
||||||
|
$show_message->mo_saml_show_error_message();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @package miniOrange
|
||||||
|
* @author miniOrange Security Software Pvt. Ltd.
|
||||||
|
* @license GNU/GPLv3
|
||||||
|
* @copyright Copyright 2015 miniOrange. All Rights Reserved.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* This file is part of miniOrange SAML plugin.
|
||||||
|
*/
|
||||||
|
|
||||||
|
class AESEncryption {
|
||||||
|
/**
|
||||||
|
* @param string $data - the key=value pairs separated with &
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function encrypt_data($data, $key) {
|
||||||
|
$key = openssl_digest($key, 'sha256');
|
||||||
|
$method = 'AES-128-ECB';
|
||||||
|
$ivSize = openssl_cipher_iv_length($method);
|
||||||
|
$iv = openssl_random_pseudo_bytes($ivSize);
|
||||||
|
$strCrypt = openssl_encrypt ($data, $method, $key,OPENSSL_RAW_DATA||OPENSSL_ZERO_PADDING, $iv);
|
||||||
|
return base64_encode($iv.$strCrypt);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param string $data - crypt response from Sagepay
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public static function decrypt_data($data, $key) {
|
||||||
|
$strIn = base64_decode($data);
|
||||||
|
$key = openssl_digest($key, 'sha256');
|
||||||
|
$method = 'AES-128-ECB';
|
||||||
|
$ivSize = openssl_cipher_iv_length($method);
|
||||||
|
$iv = substr($strIn,0,$ivSize);
|
||||||
|
$data = substr($strIn,$ivSize);
|
||||||
|
$clear = openssl_decrypt ($data, $method, $key, OPENSSL_RAW_DATA||OPENSSL_ZERO_PADDING, $iv);
|
||||||
|
|
||||||
|
return $clear;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
?>
|
||||||
@@ -0,0 +1,640 @@
|
|||||||
|
<?php
|
||||||
|
include "MoSAMLBasicEnum.php";
|
||||||
|
class mo_saml_options_enum_sso_loginMoSAML extends MoSAMLBasicEnum {
|
||||||
|
const Relay_state = 'mo_saml_relay_state';
|
||||||
|
const Redirect_Idp = 'mo_saml_registered_only_access';
|
||||||
|
const Force_authentication = 'mo_saml_force_authentication';
|
||||||
|
const Enable_access_RSS = 'mo_saml_enable_rss_access';
|
||||||
|
const Auto_redirect = 'mo_saml_enable_login_redirect';
|
||||||
|
}
|
||||||
|
|
||||||
|
class mo_saml_options_enum_identity_providerMoSAML extends MoSAMLBasicEnum{
|
||||||
|
const Broker_service ='mo_saml_enable_cloud_broker';
|
||||||
|
const SP_Base_Url='mo_saml_sp_base_url';
|
||||||
|
const SP_Entity_ID = 'mo_saml_sp_entity_id';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class mo_saml_options_tab_names extends MoSAMLBasicEnum{
|
||||||
|
|
||||||
|
const Service_provider_settings = 'service-provider-setup';
|
||||||
|
const Identity_provider_settting = 'identity-provider-setup';
|
||||||
|
const Redirection_sso_links = 'redirection-sso-links';
|
||||||
|
const Entire_plugin_tour = 'entire-plugin-tour';
|
||||||
|
const Attribute_role_mapping = 'attribute-role-mapping';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class mo_saml_options_enum_pointersMoSAML extends MoSAMLBasicEnum{
|
||||||
|
public static
|
||||||
|
$DEFAULT = array(
|
||||||
|
'custom_admin_pointers4_8_52_default-miniorange-sp-metadata-url',
|
||||||
|
'custom_admin_pointers4_8_52_default-miniorange-select-your-idp',
|
||||||
|
'custom_admin_pointers4_8_52_default-miniorange-upload-metadata',
|
||||||
|
'custom_admin_pointers4_8_52_default-miniorange-test-configuration',
|
||||||
|
'custom_admin_pointers4_8_52_default-miniorange-attribute-mapping',
|
||||||
|
'custom_admin_pointers4_8_52_default-miniorange-role-mapping',
|
||||||
|
'custom_admin_pointers4_8_52_default-minorange-use-widget',
|
||||||
|
'custom_admin_pointers4_8_52_default-miniorange-addons',
|
||||||
|
'custom_admin_pointers4_8_52_default-miniorange-support-pointer'
|
||||||
|
);
|
||||||
|
public static $DEFAULT_SKIP = array(
|
||||||
|
'custom_admin_pointers4_8_52_default-miniorange-sp-metadata-url',
|
||||||
|
'custom_admin_pointers4_8_52_default-miniorange-select-your-idp',
|
||||||
|
'custom_admin_pointers4_8_52_default-miniorange-upload-metadata',
|
||||||
|
'custom_admin_pointers4_8_52_default-miniorange-test-configuration',
|
||||||
|
'custom_admin_pointers4_8_52_default-miniorange-attribute-mapping',
|
||||||
|
'custom_admin_pointers4_8_52_default-miniorange-role-mapping',
|
||||||
|
'custom_admin_pointers4_8_52_default-minorange-use-widget',
|
||||||
|
'custom_admin_pointers4_8_52_default-miniorange-addons',
|
||||||
|
);
|
||||||
|
public static $SERVICE_PROVIDER = array(
|
||||||
|
'custom_admin_pointers4_8_52_miniorange-select-your-idp',
|
||||||
|
'custom_admin_pointers4_8_52_miniorange-upload-metadata',
|
||||||
|
'custom_admin_pointers4_8_52_miniorange-test-configuration',
|
||||||
|
'custom_admin_pointers4_8_52_miniorange-import-config',
|
||||||
|
'custom_admin_pointers4_8_52_export-import-config',
|
||||||
|
'custom_admin_pointers4_8_52_configure-service-restart-tour');
|
||||||
|
public static $IDENTITY_PROVIDER = array(
|
||||||
|
'custom_admin_pointers4_8_52_metadata_manual',
|
||||||
|
'custom_admin_pointers4_8_52_miniorange-sp-metadata-url',
|
||||||
|
'custom_admin_pointers4_8_52_identity-provider-restart-tour'
|
||||||
|
);
|
||||||
|
public static $ATTRIBUTE_MAPPING = array(
|
||||||
|
'custom_admin_pointers4_8_52_miniorange-attribute-mapping',
|
||||||
|
'custom_admin_pointers4_8_52_miniorange-role-mapping',
|
||||||
|
'custom_admin_pointers4_8_52_attribute-mapping-restart-tour');
|
||||||
|
public static $REDIRECTION_LINK = array(
|
||||||
|
'custom_admin_pointers4_8_52_minorange-use-widget',
|
||||||
|
'custom_admin_pointers4_8_52_miniorange-auto-redirect',
|
||||||
|
'custom_admin_pointers4_8_52_miniorange-auto-redirect-login-page',
|
||||||
|
'custom_admin_pointers4_8_52_miniorange-short-code',
|
||||||
|
'custom_admin_pointers4_8_52_miniorange-redirection-sso-restart-tour'
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class mo_saml_options_enum_service_providerMoSAML extends MoSAMLBasicEnum{
|
||||||
|
const Identity_name ='saml_identity_name';
|
||||||
|
const Login_binding_type='saml_login_binding_type';
|
||||||
|
const Login_URL = 'saml_login_url';
|
||||||
|
const Logout_binding_type = 'saml_logout_binding_type';
|
||||||
|
const Logout_URL = 'saml_logout_url';
|
||||||
|
const Issuer = 'saml_issuer';
|
||||||
|
const X509_certificate = 'saml_x509_certificate';
|
||||||
|
const Request_signed = 'saml_request_signed';
|
||||||
|
const Guide_name = 'saml_identity_provider_guide_name';
|
||||||
|
const Is_encoding_enabled = 'mo_saml_encoding_enabled';
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class mo_saml_options_test_configuration extends MoSAMLBasicEnum{
|
||||||
|
const SAML_REQUEST = 'MO_SAML_REQUEST';
|
||||||
|
const SAML_RESPONSE = 'MO_SAML_RESPONSE';
|
||||||
|
const TEST_CONFIG_ERROR_LOG = 'MO_SAML_TEST';
|
||||||
|
}
|
||||||
|
|
||||||
|
class mo_saml_options_enum_attribute_mappingMoSAML extends MoSAMLBasicEnum{
|
||||||
|
const Attribute_Username ='saml_am_username';
|
||||||
|
const Attribute_Email = 'saml_am_email';
|
||||||
|
const Attribute_First_name ='saml_am_first_name';
|
||||||
|
const Attribute_Last_name = 'saml_am_last_name';
|
||||||
|
const Attribute_Group_name ='saml_am_group_name';
|
||||||
|
const Attribute_Custom_mapping = 'mo_saml_custom_attrs_mapping';
|
||||||
|
const Attribute_Account_matcher = 'saml_am_account_matcher';
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class mo_saml_options_enum_role_mappingMoSAML extends MoSAMLBasicEnum{
|
||||||
|
const Role_do_not_auto_create_users = 'mo_saml_dont_create_user_if_role_not_mapped';
|
||||||
|
const Role_do_not_assign_role_unlisted = 'saml_am_dont_allow_unlisted_user_role';
|
||||||
|
const Role_do_not_update_existing_user = 'saml_am_dont_update_existing_user_role';
|
||||||
|
const Role_default_role ='saml_am_default_user_role';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class mo_saml_options_error_constants extends MoSAMLBasicEnum{
|
||||||
|
const Error_no_certificate = "Unable to find a certificate .";
|
||||||
|
const Cause_no_certificate = "No signature found in SAML Response or Assertion. Please sign at least one of them.";
|
||||||
|
const Error_wrong_certificate = "Unable to find a certificate matching the configured fingerprint.";
|
||||||
|
const Cause_wrong_certificate = "X.509 Certificate field in plugin does not match the certificate found in SAML Response.";
|
||||||
|
const Error_invalid_audience = "Invalid Audience URI.";
|
||||||
|
const Cause_invalid_audience = "The value of 'Audience URI' field on Identity Provider's side is incorrect";
|
||||||
|
const Error_issuer_not_verfied = "Issuer cannot be verified.";
|
||||||
|
const Cause_issuer_not_verfied = "IdP Entity ID configured and the one found in SAML Response do not match";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class mo_saml_options_plugin_constants extends MoSAMLBasicEnum{
|
||||||
|
const CMS_Name = "WP";
|
||||||
|
const Application_Name = "WP miniOrange SAML 2.0 SSO Plugin";
|
||||||
|
const Application_type = "SAML";
|
||||||
|
const Version = "4.9.05";
|
||||||
|
const HOSTNAME = "https://login.xecurify.com";
|
||||||
|
}
|
||||||
|
|
||||||
|
class mo_saml_options_plugin_idp extends MoSAMLBasicEnum{
|
||||||
|
public static $IDP_GUIDES = array(
|
||||||
|
"Azure AD" => "azure-ad",
|
||||||
|
"Azure B2C" => "azure-b2c",
|
||||||
|
"ADFS" => "adfs",
|
||||||
|
"Okta" => "okta",
|
||||||
|
"SalesForce" => "salesforce",
|
||||||
|
"Google Apps" => "google-apps",
|
||||||
|
"OneLogin" => "onelogin",
|
||||||
|
"MiniOrange" => "miniorange",
|
||||||
|
"Keycloak" => "jboss-keycloak",
|
||||||
|
"AbsorbLMS" => "absorb-lms",
|
||||||
|
"Degreed" => "degreed",
|
||||||
|
"JumpCloud" => "jumpcloud",
|
||||||
|
"PingFederate" => "pingfederate",
|
||||||
|
"PingOne" => "pingone",
|
||||||
|
"Centrify" => "centrify",
|
||||||
|
"Oracle" => "oracle-enterprise-manager",
|
||||||
|
"Bitium" => "bitium",
|
||||||
|
"Shibboleth 2" => "shibboleth2",
|
||||||
|
"Shibboleth 3" => "shibboleth3",
|
||||||
|
"Gluu Server" => "gluu-server",
|
||||||
|
"SimpleSAMLphp" => "simplesaml",
|
||||||
|
"OpenAM" => "openam",
|
||||||
|
"Authanvil"=>"authanvil",
|
||||||
|
"Auth0"=>"auth0",
|
||||||
|
"CA Identity"=>"ca-identity",
|
||||||
|
"WSO2"=>"wso2",
|
||||||
|
"RSA SecureID"=>"rsa-secureid",
|
||||||
|
"Custom IDP"=>"custom-idp"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class mo_saml_options_plugin_idp_videos extends MoSAMLBasicEnum{
|
||||||
|
public static $IDP_VIDEOS = array(
|
||||||
|
"azure-ad"=> "eHen4aiflFU",
|
||||||
|
"azure-b2c"=> "",
|
||||||
|
"adfs"=> "rLBHbRbrY5E",
|
||||||
|
"okta"=> "YHE8iYojUqM",
|
||||||
|
"salesforce"=> "LRQrmgr255Q",
|
||||||
|
"google-apps"=> "5BwzEjgZiu4",
|
||||||
|
"onelogin"=> "_Hsot_RG9YY",
|
||||||
|
"miniorange"=> "eamf9s6JpbA",
|
||||||
|
"jboss-keycloak"=> "Io6x1fTNWHI",
|
||||||
|
"absorb-lms"=> "",
|
||||||
|
"degreed"=> "",
|
||||||
|
"jumpcloud"=> "",
|
||||||
|
"pingfederate"=> "",
|
||||||
|
"pingone"=> "",
|
||||||
|
"centrify"=> "",
|
||||||
|
"oracle-enterprise-manager"=> "",
|
||||||
|
"bitium"=> "",
|
||||||
|
"shibboleth2"=> "",
|
||||||
|
"shibboleth3"=> "",
|
||||||
|
"gluu-server"=> "",
|
||||||
|
"simplesaml"=> "",
|
||||||
|
"openam"=> "",
|
||||||
|
"authanvil"=> "",
|
||||||
|
"auth0"=> "54pz6m5h9mk",
|
||||||
|
"ca-identity" => "",
|
||||||
|
"wso2" => "",
|
||||||
|
"rsa-secureid" => "",
|
||||||
|
"custom-idp" => "gilfhNFYsgc"
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class mo_saml_options_addons extends MoSAMLBasicEnum{
|
||||||
|
|
||||||
|
public static $ADDON_URL = array(
|
||||||
|
|
||||||
|
'scim' => 'https://plugins.miniorange.com/wordpress-user-provisioning',
|
||||||
|
'page_restriction' => 'https://plugins.miniorange.com/wordpress-page-restriction',
|
||||||
|
'file_prevention' => 'https://plugins.miniorange.com/wordpress-media-restriction',
|
||||||
|
'ssologin' => 'https://plugins.miniorange.com/wordpress-sso-login-audit',
|
||||||
|
'buddypress' => 'https://plugins.miniorange.com/wordpress-buddypress-integrator',
|
||||||
|
'learndash' => 'https://plugins.miniorange.com/wordpress-learndash-integrator',
|
||||||
|
'attribute_based_redirection' => 'https://plugins.miniorange.com/wordpress-attribute-based-redirection-restriction',
|
||||||
|
'ssosession' => 'https://plugins.miniorange.com/sso-session-management',
|
||||||
|
'fsso' => 'https://plugins.miniorange.com/incommon-federation-single-sign-on-sso',
|
||||||
|
'paid_mem_pro' => 'https://plugins.miniorange.com/paid-membership-pro-integrator',
|
||||||
|
'memberpress' => 'https://plugins.miniorange.com/wordpress-memberpress-integrator',
|
||||||
|
'wp_members' => 'https://plugins.miniorange.com/wordpress-members-integrator',
|
||||||
|
'woocommerce' => 'https://plugins.miniorange.com/wordpress-woocommerce-integrator',
|
||||||
|
'guest_login' => 'https://plugins.miniorange.com/guest-user-login',
|
||||||
|
'profile_picture_add_on' => 'https://plugins.miniorange.com/wordpress-profile-picture-map'
|
||||||
|
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $WP_ADDON_URL = array(
|
||||||
|
'page-restriction' => 'https://wordpress.org/plugins/page-and-post-restriction/embed/',
|
||||||
|
'scim-user-sync'=> 'https://wordpress.org/plugins/scim-user-provisioning/embed/'
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $ADDON_TITLE = array(
|
||||||
|
|
||||||
|
'scim' => 'SCIM User Provisioning',
|
||||||
|
'page_restriction' => 'Page and Post Restriction',
|
||||||
|
'file_prevention' => 'Prevent File Access',
|
||||||
|
'ssologin' => 'SSO Login Audit',
|
||||||
|
'buddypress' => 'BuddyPress Integrator',
|
||||||
|
'learndash' => 'Learndash Integrator',
|
||||||
|
'attribute_based_redirection' => 'Attribute Based Redirection',
|
||||||
|
'ssosession' => 'SSO Session Management',
|
||||||
|
'fsso' => 'Federation Single Sign-On',
|
||||||
|
'memberpress' => 'MemberPress Integrator',
|
||||||
|
'wp_members' => 'WP-Members Integrator',
|
||||||
|
'woocommerce' => 'WooCommerce Integrator',
|
||||||
|
'guest_login' => 'Guest Login',
|
||||||
|
'profile_picture_add_on' => 'Profile Picture Add-on',
|
||||||
|
'paid_mem_pro' => 'PaidMembership Pro Integrator'
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $RECOMMENDED_ADDONS_PATH = array(
|
||||||
|
|
||||||
|
"learndash" => "sfwd-lms/sfwd_lms.php",
|
||||||
|
"buddypress" => "buddypress/bp-loader.php",
|
||||||
|
"paid_mem_pro" => "paid-memberships-pro/paid-memberships-pro.php",
|
||||||
|
"memberpress" => "memberpress/memberpress.php",
|
||||||
|
"wp_members" => "wp-members/wp-members.php",
|
||||||
|
"woocommerce" => "woocommerce/woocommerce.php"
|
||||||
|
);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
class mo_saml_license_plans extends MoSAMLBasicEnum {
|
||||||
|
|
||||||
|
public static $license_plans = array (
|
||||||
|
'standard' => 'WP SAML SSO Standard Plan',
|
||||||
|
'premium' => 'WP SAML SSO Premium Plan',
|
||||||
|
'enterprise' => 'WP SAML SSO Enterprise Plan',
|
||||||
|
'enterprise-multiple-idp' => 'WP SAML SSO Enterprise Multiple-IDP Plan',
|
||||||
|
'all-inclusive' => 'WP SAML SSO All Inclusive Plan',
|
||||||
|
'premium-multisite' => 'WP SAML SSO Premium Multisite Plan',
|
||||||
|
'enterprise-multisite' => 'WP SAML SSO Enterprise Multisite Plan',
|
||||||
|
'all-inclusive-multisite' => 'WP SAML SSO All Inclusive Multisite Plan',
|
||||||
|
'help' => 'Not Sure'
|
||||||
|
);
|
||||||
|
|
||||||
|
public static $license_plans_slug = array (
|
||||||
|
'standard' => '16.0.2@16.0.2',
|
||||||
|
'premium' => '12.0.2@12.0.2',
|
||||||
|
'enterprise' => '12.0.2@12.0.2',
|
||||||
|
'enterprise-multiple-idp' => '25.0.1@25.0.1',
|
||||||
|
'all-inclusive' => '25.0.1@25.0.1',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
class mo_saml_time_zones extends MoSAMLBasicEnum {
|
||||||
|
|
||||||
|
public static $time_zones = array(
|
||||||
|
"(GMT-11:00) Niue Time" => "Pacific/Niue",
|
||||||
|
"(GMT-11:00) Samoa Standard Time" => "Pacific/Pago_Pago",
|
||||||
|
"(GMT-10:00) Cook Islands Standard Time" => "Pacific/Rarotonga",
|
||||||
|
"(GMT-10:00) Hawaii-Aleutian Standard Time" => "Pacific/Honolulu",
|
||||||
|
"(GMT-10:00) Tahiti Time" => "Pacific/Tahiti",
|
||||||
|
"(GMT-09:30) Marquesas Time" => "Pacific/Marquesas",
|
||||||
|
"(GMT-09:00) Gambier Time" => "Pacific/Gambier",
|
||||||
|
"(GMT-09:00) Hawaii-Aleutian Time (Adak)" => "America/Adak",
|
||||||
|
"(GMT-08:00) Alaska Time - Anchorage" => "America/Anchorage",
|
||||||
|
"(GMT-08:00) Alaska Time - Juneau" => "America/Juneau",
|
||||||
|
"(GMT-08:00) Alaska Time - Metlakatla" => "America/Metlakatla",
|
||||||
|
"(GMT-08:00) Alaska Time - Nome" => "America/Nome",
|
||||||
|
"(GMT-08:00) Alaska Time - Sitka" => "America/Sitka",
|
||||||
|
"(GMT-08:00) Alaska Time - Yakutat" => "America/Yakutat",
|
||||||
|
"(GMT-08:00) Pitcairn Time" => "Pacific/Pitcairn",
|
||||||
|
"(GMT-07:00) Mexican Pacific Standard Time" => "America/Hermosillo",
|
||||||
|
"(GMT-07:00) Mountain Standard Time - Creston" => "America/Creston",
|
||||||
|
"(GMT-07:00) Mountain Standard Time - Dawson" => "America/Dawson",
|
||||||
|
"(GMT-07:00) Mountain Standard Time - Dawson Creek" => "America/Dawson_Creek",
|
||||||
|
"(GMT-07:00) Mountain Standard Time - Fort Nelson" => "America/Fort_Nelson",
|
||||||
|
"(GMT-07:00) Mountain Standard Time - Phoenix" => "America/Phoenix",
|
||||||
|
"(GMT-07:00) Mountain Standard Time - Whitehorse" => "America/Whitehorse",
|
||||||
|
"(GMT-07:00) Pacific Time - Los Angeles" => "America/Los_Angeles",
|
||||||
|
"(GMT-07:00) Pacific Time - Tijuana" => "America/Tijuana",
|
||||||
|
"(GMT-07:00) Pacific Time - Vancouver" => "America/Vancouver",
|
||||||
|
"(GMT-06:00) Central Standard Time - Belize" => "America/Belize",
|
||||||
|
"(GMT-06:00) Central Standard Time - Costa Rica" => "America/Costa_Rica",
|
||||||
|
"(GMT-06:00) Central Standard Time - El Salvador" => "America/El_Salvador",
|
||||||
|
"(GMT-06:00) Central Standard Time - Guatemala" => "America/Guatemala",
|
||||||
|
"(GMT-06:00) Central Standard Time - Managua" => "America/Managua",
|
||||||
|
"(GMT-06:00) Central Standard Time - Regina" => "America/Regina",
|
||||||
|
"(GMT-06:00) Central Standard Time - Swift Current" => "America/Swift_Current",
|
||||||
|
"(GMT-06:00) Central Standard Time - Tegucigalpa" => "America/Tegucigalpa",
|
||||||
|
"(GMT-06:00) Easter Island Time" => "Pacific/Easter",
|
||||||
|
"(GMT-06:00) Galapagos Time" => "Pacific/Galapagos",
|
||||||
|
"(GMT-06:00) Mexican Pacific Time - Chihuahua" => "America/Chihuahua",
|
||||||
|
"(GMT-06:00) Mexican Pacific Time - Mazatlan" => "America/Mazatlan",
|
||||||
|
"(GMT-06:00) Mountain Time - Boise" => "America/Boise",
|
||||||
|
"(GMT-06:00) Mountain Time - Cambridge Bay" => "America/Cambridge_Bay",
|
||||||
|
"(GMT-06:00) Mountain Time - Denver" => "America/Denver",
|
||||||
|
"(GMT-06:00) Mountain Time - Edmonton" => "America/Edmonton",
|
||||||
|
"(GMT-06:00) Mountain Time - Inuvik" => "America/Inuvik",
|
||||||
|
"(GMT-06:00) Mountain Time - Ojinaga" => "America/Ojinaga",
|
||||||
|
"(GMT-06:00) Mountain Time - Yellowknife" => "America/Yellowknife",
|
||||||
|
"(GMT-05:00) Acre Standard Time - Eirunepe" => "America/Eirunepe",
|
||||||
|
"(GMT-05:00) Acre Standard Time - Rio Branco" => "America/Rio_Branco",
|
||||||
|
"(GMT-05:00) Central Time - Bahia Banderas" => "America/Bahia_Banderas",
|
||||||
|
"(GMT-05:00) Central Time - Beulah, North Dakota" => "America/North_Dakota/Beulah",
|
||||||
|
"(GMT-05:00) Central Time - Center, North Dakota" => "America/North_Dakota/Center",
|
||||||
|
"(GMT-05:00) Central Time - Chicago" => "America/Chicago",
|
||||||
|
"(GMT-05:00) Central Time - Knox, Indiana" => "America/Indiana/Knox",
|
||||||
|
"(GMT-05:00) Central Time - Matamoros" => "America/Matamoros",
|
||||||
|
"(GMT-05:00) Central Time - Menominee" => "America/Menominee",
|
||||||
|
"(GMT-05:00) Central Time - Merida" => "America/Merida",
|
||||||
|
"(GMT-05:00) Central Time - Mexico City" => "America/Mexico_City",
|
||||||
|
"(GMT-05:00) Central Time - Monterrey" => "America/Monterrey",
|
||||||
|
"(GMT-05:00) Central Time - New Salem, North Dakota" => "America/North_Dakota/New_Salem",
|
||||||
|
"(GMT-05:00) Central Time - Rainy River" => "America/Rainy_River",
|
||||||
|
"(GMT-05:00) Central Time - Rankin Inlet" => "America/Rankin_Inlet",
|
||||||
|
"(GMT-05:00) Central Time - Resolute" => "America/Resolute",
|
||||||
|
"(GMT-05:00) Central Time - Tell City, Indiana" => "America/Indiana/Tell_City",
|
||||||
|
"(GMT-05:00) Central Time - Winnipeg" => "America/Winnipeg",
|
||||||
|
"(GMT-05:00) Colombia Standard Time" => "America/Bogota",
|
||||||
|
"(GMT-05:00) Eastern Standard Time - Atikokan" => "America/Atikokan",
|
||||||
|
"(GMT-05:00) Eastern Standard Time - Cancun" => "America/Cancun",
|
||||||
|
"(GMT-05:00) Eastern Standard Time - Jamaica" => "America/Jamaica",
|
||||||
|
"(GMT-05:00) Eastern Standard Time - Panama" => "America/Panama",
|
||||||
|
"(GMT-05:00) Ecuador Time" => "America/Guayaquil",
|
||||||
|
"(GMT-05:00) Peru Standard Time" => "America/Lima",
|
||||||
|
"(GMT-04:00) Amazon Standard Time - Boa Vista" => "America/Boa_Vista",
|
||||||
|
"(GMT-04:00) Amazon Standard Time - Campo Grande" => "America/Campo_Grande",
|
||||||
|
"(GMT-04:00) Amazon Standard Time - Cuiaba" => "America/Cuiaba",
|
||||||
|
"(GMT-04:00) Amazon Standard Time - Manaus" => "America/Manaus",
|
||||||
|
"(GMT-04:00) Amazon Standard Time - Porto Velho" => "America/Porto_Velho",
|
||||||
|
"(GMT-04:00) Atlantic Standard Time - Barbados" => "America/Barbados",
|
||||||
|
"(GMT-04:00) Atlantic Standard Time - Blanc-Sablon" => "America/Blanc-Sablon",
|
||||||
|
"(GMT-04:00) Atlantic Standard Time - Curaçao" => "America/Curacao",
|
||||||
|
"(GMT-04:00) Atlantic Standard Time - Martinique" => "America/Martinique",
|
||||||
|
"(GMT-04:00) Atlantic Standard Time - Port of Spain" => "America/Port_of_Spain",
|
||||||
|
"(GMT-04:00) Atlantic Standard Time - Puerto Rico" => "America/Puerto_Rico",
|
||||||
|
"(GMT-04:00) Atlantic Standard Time - Santo Domingo" => "America/Santo_Domingo",
|
||||||
|
"(GMT-04:00) Bolivia Time" => "America/La_Paz",
|
||||||
|
"(GMT-04:00) Chile Time" => "America/Santiago",
|
||||||
|
"(GMT-04:00) Cuba Time" => "America/Havana",
|
||||||
|
"(GMT-04:00) Eastern Time - Detroit" => "America/Detroit",
|
||||||
|
"(GMT-04:00) Eastern Time - Grand Turk" => "America/Grand_Turk",
|
||||||
|
"(GMT-04:00) Eastern Time - Indianapolis" => "America/Indiana/Indianapolis",
|
||||||
|
"(GMT-04:00) Eastern Time - Iqaluit" => "America/Iqaluit",
|
||||||
|
"(GMT-04:00) Eastern Time - Louisville" => "America/Kentucky/Louisville",
|
||||||
|
"(GMT-04:00) Eastern Time - Marengo, Indiana" => "America/Indiana/Marengo",
|
||||||
|
"(GMT-04:00) Eastern Time - Monticello, Kentucky" => "America/Kentucky/Monticello",
|
||||||
|
"(GMT-04:00) Eastern Time - Nassau" => "America/Nassau",
|
||||||
|
"(GMT-04:00) Eastern Time - New York" => "America/New_York",
|
||||||
|
"(GMT-04:00) Eastern Time - Nipigon" => "America/Nipigon",
|
||||||
|
"(GMT-04:00) Eastern Time - Pangnirtung" => "America/Pangnirtung",
|
||||||
|
"(GMT-04:00) Eastern Time - Petersburg, Indiana" => "America/Indiana/Petersburg",
|
||||||
|
"(GMT-04:00) Eastern Time - Port-au-Prince" => "America/Port-au-Prince",
|
||||||
|
"(GMT-04:00) Eastern Time - Thunder Bay" => "America/Thunder_Bay",
|
||||||
|
"(GMT-04:00) Eastern Time - Toronto" => "America/Toronto",
|
||||||
|
"(GMT-04:00) Eastern Time - Vevay, Indiana" => "America/Indiana/Vevay",
|
||||||
|
"(GMT-04:00) Eastern Time - Vincennes, Indiana" => "America/Indiana/Vincennes",
|
||||||
|
"(GMT-04:00) Eastern Time - Winamac, Indiana" => "America/Indiana/Winamac",
|
||||||
|
"(GMT-04:00) Guyana Time" => "America/Guyana",
|
||||||
|
"(GMT-04:00) Paraguay Time" => "America/Asuncion",
|
||||||
|
"(GMT-04:00) Venezuela Time" => "America/Caracas",
|
||||||
|
"(GMT-03:00) Argentina Standard Time - Buenos Aires" => "America/Argentina/Buenos_Aires",
|
||||||
|
"(GMT-03:00) Argentina Standard Time - Catamarca" => "America/Argentina/Catamarca",
|
||||||
|
"(GMT-03:00) Argentina Standard Time - Cordoba" => "America/Argentina/Cordoba",
|
||||||
|
"(GMT-03:00) Argentina Standard Time - Jujuy" => "America/Argentina/Jujuy",
|
||||||
|
"(GMT-03:00) Argentina Standard Time - La Rioja" => "America/Argentina/La_Rioja",
|
||||||
|
"(GMT-03:00) Argentina Standard Time - Mendoza" => "America/Argentina/Mendoza",
|
||||||
|
"(GMT-03:00) Argentina Standard Time - Rio Gallegos" => "America/Argentina/Rio_Gallegos",
|
||||||
|
"(GMT-03:00) Argentina Standard Time - Salta" => "America/Argentina/Salta",
|
||||||
|
"(GMT-03:00) Argentina Standard Time - San Juan" => "America/Argentina/San_Juan",
|
||||||
|
"(GMT-03:00) Argentina Standard Time - San Luis" => "America/Argentina/San_Luis",
|
||||||
|
"(GMT-03:00) Argentina Standard Time - Tucuman" => "America/Argentina/Tucuman",
|
||||||
|
"(GMT-03:00) Argentina Standard Time - Ushuaia" => "America/Argentina/Ushuaia",
|
||||||
|
"(GMT-03:00) Atlantic Time - Bermuda" => "Atlantic/Bermuda",
|
||||||
|
"(GMT-03:00) Atlantic Time - Glace Bay" => "America/Glace_Bay",
|
||||||
|
"(GMT-03:00) Atlantic Time - Goose Bay" => "America/Goose_Bay",
|
||||||
|
"(GMT-03:00) Atlantic Time - Halifax" => "America/Halifax",
|
||||||
|
"(GMT-03:00) Atlantic Time - Moncton" => "America/Moncton",
|
||||||
|
"(GMT-03:00) Atlantic Time - Thule" => "America/Thule",
|
||||||
|
"(GMT-03:00) Brasilia Standard Time - Araguaina" => "America/Araguaina",
|
||||||
|
"(GMT-03:00) Brasilia Standard Time - Bahia" => "America/Bahia",
|
||||||
|
"(GMT-03:00) Brasilia Standard Time - Belem" => "America/Belem",
|
||||||
|
"(GMT-03:00) Brasilia Standard Time - Fortaleza" => "America/Fortaleza",
|
||||||
|
"(GMT-03:00) Brasilia Standard Time - Maceio" => "America/Maceio",
|
||||||
|
"(GMT-03:00) Brasilia Standard Time - Recife" => "America/Recife",
|
||||||
|
"(GMT-03:00) Brasilia Standard Time - Santarem" => "America/Santarem",
|
||||||
|
"(GMT-03:00) Brasilia Standard Time - Sao Paulo" => "America/Sao_Paulo",
|
||||||
|
"(GMT-03:00) Chile Time" => "America/Santiago",
|
||||||
|
"(GMT-03:00) Falkland Islands Standard Time" => "Atlantic/Stanley",
|
||||||
|
"(GMT-03:00) French Guiana Time" => "America/Cayenne",
|
||||||
|
"(GMT-03:00) Palmer Time" => "Antarctica/Palmer",
|
||||||
|
"(GMT-03:00) Punta Arenas Time" => "America/Punta_Arenas",
|
||||||
|
"(GMT-03:00) Rothera Time" => "Antarctica/Rothera",
|
||||||
|
"(GMT-03:00) Suriname Time" => "America/Paramaribo",
|
||||||
|
"(GMT-03:00) Uruguay Standard Time" => "America/Montevideo",
|
||||||
|
"(GMT-02:30) Newfoundland Time" => "America/St_Johns",
|
||||||
|
"(GMT-02:00) Fernando de Noronha Standard Time" => "America/Noronha",
|
||||||
|
"(GMT-02:00) South Georgia Time" => "Atlantic/South_Georgia",
|
||||||
|
"(GMT-02:00) St. Pierre & Miquelon Time" => "America/Miquelon",
|
||||||
|
"(GMT-02:00) West Greenland Time" => "America/Nuuk",
|
||||||
|
"(GMT-01:00) Cape Verde Standard Time" => "Atlantic/Cape_Verde",
|
||||||
|
"(GMT+00:00) Azores Time" => "Atlantic/Azores",
|
||||||
|
"(GMT+00:00) Coordinated Universal Time" => "UTC",
|
||||||
|
"(GMT+00:00) East Greenland Time" => "America/Scoresbysund",
|
||||||
|
"(GMT+00:00) Greenwich Mean Time" => "Etc/GMT",
|
||||||
|
"(GMT+00:00) Greenwich Mean Time - Abidjan" => "Africa/Abidjan",
|
||||||
|
"(GMT+00:00) Greenwich Mean Time - Accra" => "Africa/Accra",
|
||||||
|
"(GMT+00:00) Greenwich Mean Time - Bissau" => "Africa/Bissau",
|
||||||
|
"(GMT+00:00) Greenwich Mean Time - Danmarkshavn" => "America/Danmarkshavn",
|
||||||
|
"(GMT+00:00) Greenwich Mean Time - Monrovia" => "Africa/Monrovia",
|
||||||
|
"(GMT+00:00) Greenwich Mean Time - Reykjavik" => "Atlantic/Reykjavik",
|
||||||
|
"(GMT+00:00) Greenwich Mean Time - São Tomé" => "Africa/Sao_Tome",
|
||||||
|
"(GMT+01:00) Central European Standard Time - Algiers" => "Africa/Algiers",
|
||||||
|
"(GMT+01:00) Central European Standard Time - Tunis" => "Africa/Tunis",
|
||||||
|
"(GMT+01:00) Ireland Time" => "Europe/Dublin",
|
||||||
|
"(GMT+01:00) Morocco Time" => "Africa/Casablanca",
|
||||||
|
"(GMT+01:00) United Kingdom Time" => "Europe/London",
|
||||||
|
"(GMT+01:00) West Africa Standard Time - Lagos" => "Africa/Lagos",
|
||||||
|
"(GMT+01:00) West Africa Standard Time - Ndjamena" => "Africa/Ndjamena",
|
||||||
|
"(GMT+01:00) Western European Time - Canary" => "Atlantic/Canary",
|
||||||
|
"(GMT+01:00) Western European Time - Faroe" => "Atlantic/Faroe",
|
||||||
|
"(GMT+01:00) Western European Time - Lisbon" => "Europe/Lisbon",
|
||||||
|
"(GMT+01:00) Western European Time - Madeira" => "Atlantic/Madeira",
|
||||||
|
"(GMT+01:00) Western Sahara Time" => "Africa/El_Aaiun",
|
||||||
|
"(GMT+02:00) Central Africa Time - Khartoum" => "Africa/Khartoum",
|
||||||
|
"(GMT+02:00) Central Africa Time - Maputo" => "Africa/Maputo",
|
||||||
|
"(GMT+02:00) Central Africa Time - Windhoek" => "Africa/Windhoek",
|
||||||
|
"(GMT+02:00) Central European Time - Amsterdam" => "Europe/Amsterdam",
|
||||||
|
"(GMT+02:00) Central European Time - Andorra" => "Europe/Andorra",
|
||||||
|
"(GMT+02:00) Central European Time - Belgrade" => "Europe/Belgrade",
|
||||||
|
"(GMT+02:00) Central European Time - Berlin" => "Europe/Berlin",
|
||||||
|
"(GMT+02:00) Central European Time - Brussels" => "Europe/Brussels",
|
||||||
|
"(GMT+02:00) Central European Time - Budapest" => "Europe/Budapest",
|
||||||
|
"(GMT+02:00) Central European Time - Ceuta" => "Africa/Ceuta",
|
||||||
|
"(GMT+02:00) Central European Time - Copenhagen" => "Europe/Copenhagen",
|
||||||
|
"(GMT+02:00) Central European Time - Gibraltar" => "Europe/Gibraltar",
|
||||||
|
"(GMT+02:00) Central European Time - Luxembourg" => "Europe/Luxembourg",
|
||||||
|
"(GMT+02:00) Central European Time - Madrid" => "Europe/Madrid",
|
||||||
|
"(GMT+02:00) Central European Time - Malta" => "Europe/Malta",
|
||||||
|
"(GMT+02:00) Central European Time - Monaco" => "Europe/Monaco",
|
||||||
|
"(GMT+02:00) Central European Time - Oslo" => "Europe/Oslo",
|
||||||
|
"(GMT+02:00) Central European Time - Paris" => "Europe/Paris",
|
||||||
|
"(GMT+02:00) Central European Time - Prague" => "Europe/Prague",
|
||||||
|
"(GMT+02:00) Central European Time - Rome" => "Europe/Rome",
|
||||||
|
"(GMT+02:00) Central European Time - Stockholm" => "Europe/Stockholm",
|
||||||
|
"(GMT+02:00) Central European Time - Tirane" => "Europe/Tirane",
|
||||||
|
"(GMT+02:00) Central European Time - Vienna" => "Europe/Vienna",
|
||||||
|
"(GMT+02:00) Central European Time - Warsaw" => "Europe/Warsaw",
|
||||||
|
"(GMT+02:00) Central European Time - Zurich" => "Europe/Zurich",
|
||||||
|
"(GMT+02:00) Eastern European Standard Time - Cairo" => "Africa/Cairo",
|
||||||
|
"(GMT+02:00) Eastern European Standard Time - Kaliningrad" => "Europe/Kaliningrad",
|
||||||
|
"(GMT+02:00) Eastern European Standard Time - Tripoli" => "Africa/Tripoli",
|
||||||
|
"(GMT+02:00) South Africa Standard Time" => "Africa/Johannesburg",
|
||||||
|
"(GMT+02:00) Troll Time" => "Antarctica/Troll",
|
||||||
|
"(GMT+03:00) Arabian Standard Time - Baghdad" => "Asia/Baghdad",
|
||||||
|
"(GMT+03:00) Arabian Standard Time - Qatar" => "Asia/Qatar",
|
||||||
|
"(GMT+03:00) Arabian Standard Time - Riyadh" => "Asia/Riyadh",
|
||||||
|
"(GMT+03:00) East Africa Time - Juba" => "Africa/Juba",
|
||||||
|
"(GMT+03:00) East Africa Time - Nairobi" => "Africa/Nairobi",
|
||||||
|
"(GMT+03:00) Eastern European Time - Amman" => "Asia/Amman",
|
||||||
|
"(GMT+03:00) Eastern European Time - Athens" => "Europe/Athens",
|
||||||
|
"(GMT+03:00) Eastern European Time - Beirut" => "Asia/Beirut",
|
||||||
|
"(GMT+03:00) Eastern European Time - Bucharest" => "Europe/Bucharest",
|
||||||
|
"(GMT+03:00) Eastern European Time - Chisinau" => "Europe/Chisinau",
|
||||||
|
"(GMT+03:00) Eastern European Time - Damascus" => "Asia/Damascus",
|
||||||
|
"(GMT+03:00) Eastern European Time - Gaza" => "Asia/Gaza",
|
||||||
|
"(GMT+03:00) Eastern European Time - Hebron" => "Asia/Hebron",
|
||||||
|
"(GMT+03:00) Eastern European Time - Helsinki" => "Europe/Helsinki",
|
||||||
|
"(GMT+03:00) Eastern European Time - Kiev" => "Europe/Kiev",
|
||||||
|
"(GMT+03:00) Eastern European Time - Nicosia" => "Asia/Nicosia",
|
||||||
|
"(GMT+03:00) Eastern European Time - Riga" => "Europe/Riga",
|
||||||
|
"(GMT+03:00) Eastern European Time - Sofia" => "Europe/Sofia",
|
||||||
|
"(GMT+03:00) Eastern European Time - Tallinn" => "Europe/Tallinn",
|
||||||
|
"(GMT+03:00) Eastern European Time - Uzhhorod" => "Europe/Uzhgorod",
|
||||||
|
"(GMT+03:00) Eastern European Time - Vilnius" => "Europe/Vilnius",
|
||||||
|
"(GMT+03:00) Eastern European Time - Zaporozhye" => "Europe/Zaporozhye",
|
||||||
|
"(GMT+03:00) Famagusta Time" => "Asia/Famagusta",
|
||||||
|
"(GMT+03:00) Israel Time" => "Asia/Jerusalem",
|
||||||
|
"(GMT+03:00) Kirov Time" => "Europe/Kirov",
|
||||||
|
"(GMT+03:00) Moscow Standard Time - Minsk" => "Europe/Minsk",
|
||||||
|
"(GMT+03:00) Moscow Standard Time - Moscow" => "Europe/Moscow",
|
||||||
|
"(GMT+03:00) Moscow Standard Time - Simferopol" => "Europe/Simferopol",
|
||||||
|
"(GMT+03:00) Syowa Time" => "Antarctica/Syowa",
|
||||||
|
"(GMT+03:00) Turkey Time" => "Europe/Istanbul",
|
||||||
|
"(GMT+04:00) Armenia Standard Time" => "Asia/Yerevan",
|
||||||
|
"(GMT+04:00) Astrakhan Time" => "Europe/Astrakhan",
|
||||||
|
"(GMT+04:00) Azerbaijan Standard Time" => "Asia/Baku",
|
||||||
|
"(GMT+04:00) Georgia Standard Time" => "Asia/Tbilisi",
|
||||||
|
"(GMT+04:00) Gulf Standard Time" => "Asia/Dubai",
|
||||||
|
"(GMT+04:00) Mauritius Standard Time" => "Indian/Mauritius",
|
||||||
|
"(GMT+04:00) Réunion Time" => "Indian/Reunion",
|
||||||
|
"(GMT+04:00) Samara Standard Time" => "Europe/Samara",
|
||||||
|
"(GMT+04:00) Saratov Time" => "Europe/Saratov",
|
||||||
|
"(GMT+04:00) Seychelles Time" => "Indian/Mahe",
|
||||||
|
"(GMT+04:00) Ulyanovsk Time" => "Europe/Ulyanovsk",
|
||||||
|
"(GMT+04:00) Volgograd Standard Time" => "Europe/Volgograd",
|
||||||
|
"(GMT+04:30) Afghanistan Time" => "Asia/Kabul",
|
||||||
|
"(GMT+04:30) Iran Time" => "Asia/Tehran",
|
||||||
|
"(GMT+05:00) French Southern & Antarctic Time" => "Indian/Kerguelen",
|
||||||
|
"(GMT+05:00) Maldives Time" => "Indian/Maldives",
|
||||||
|
"(GMT+05:00) Mawson Time" => "Antarctica/Mawson",
|
||||||
|
"(GMT+05:00) Pakistan Standard Time" => "Asia/Karachi",
|
||||||
|
"(GMT+05:00) Tajikistan Time" => "Asia/Dushanbe",
|
||||||
|
"(GMT+05:00) Turkmenistan Standard Time" => "Asia/Ashgabat",
|
||||||
|
"(GMT+05:00) Uzbekistan Standard Time - Samarkand" => "Asia/Samarkand",
|
||||||
|
"(GMT+05:00) Uzbekistan Standard Time - Tashkent" => "Asia/Tashkent",
|
||||||
|
"(GMT+05:00) West Kazakhstan Time - Aqtau" => "Asia/Aqtau",
|
||||||
|
"(GMT+05:00) West Kazakhstan Time - Aqtobe" => "Asia/Aqtobe",
|
||||||
|
"(GMT+05:00) West Kazakhstan Time - Atyrau" => "Asia/Atyrau",
|
||||||
|
"(GMT+05:00) West Kazakhstan Time - Oral" => "Asia/Oral",
|
||||||
|
"(GMT+05:00) West Kazakhstan Time - Qyzylorda" => "Asia/Qyzylorda",
|
||||||
|
"(GMT+05:00) Yekaterinburg Standard Time" => "Asia/Yekaterinburg",
|
||||||
|
"(GMT+05:30) Indian Standard Time - Colombo" => "Asia/Colombo",
|
||||||
|
"(GMT+05:30) Indian Standard Time - Kolkata" => "Asia/Kolkata",
|
||||||
|
"(GMT+05:45) Nepal Time" => "Asia/Kathmandu",
|
||||||
|
"(GMT+06:00) Bangladesh Standard Time" => "Asia/Dhaka",
|
||||||
|
"(GMT+06:00) Bhutan Time" => "Asia/Thimphu",
|
||||||
|
"(GMT+06:00) East Kazakhstan Time - Almaty" => "Asia/Almaty",
|
||||||
|
"(GMT+06:00) East Kazakhstan Time - Kostanay" => "Asia/Qostanay",
|
||||||
|
"(GMT+06:00) Indian Ocean Time" => "Indian/Chagos",
|
||||||
|
"(GMT+06:00) Kyrgyzstan Time" => "Asia/Bishkek",
|
||||||
|
"(GMT+06:00) Omsk Standard Time" => "Asia/Omsk",
|
||||||
|
"(GMT+06:00) Urumqi Time" => "Asia/Urumqi",
|
||||||
|
"(GMT+06:00) Vostok Time" => "Antarctica/Vostok",
|
||||||
|
"(GMT+06:30) Cocos Islands Time" => "Indian/Cocos",
|
||||||
|
"(GMT+06:30) Myanmar Time" => "Asia/Yangon",
|
||||||
|
"(GMT+07:00) Barnaul Time" => "Asia/Barnaul",
|
||||||
|
"(GMT+07:00) Christmas Island Time" => "Indian/Christmas",
|
||||||
|
"(GMT+07:00) Davis Time" => "Antarctica/Davis",
|
||||||
|
"(GMT+07:00) Hovd Standard Time" => "Asia/Hovd",
|
||||||
|
"(GMT+07:00) Indochina Time - Bangkok" => "Asia/Bangkok",
|
||||||
|
"(GMT+07:00) Indochina Time - Ho Chi Minh City" => "Asia/Ho_Chi_Minh",
|
||||||
|
"(GMT+07:00) Krasnoyarsk Standard Time - Krasnoyarsk" => "Asia/Krasnoyarsk",
|
||||||
|
"(GMT+07:00) Krasnoyarsk Standard Time - Novokuznetsk" => "Asia/Novokuznetsk",
|
||||||
|
"(GMT+07:00) Novosibirsk Standard Time" => "Asia/Novosibirsk",
|
||||||
|
"(GMT+07:00) Tomsk Time" => "Asia/Tomsk",
|
||||||
|
"(GMT+07:00) Western Indonesia Time - Jakarta" => "Asia/Jakarta",
|
||||||
|
"(GMT+07:00) Western Indonesia Time - Pontianak" => "Asia/Pontianak",
|
||||||
|
"(GMT+08:00) Australian Western Standard Time - Casey" => "Antarctica/Casey",
|
||||||
|
"(GMT+08:00) Australian Western Standard Time - Perth" => "Australia/Perth",
|
||||||
|
"(GMT+08:00) Brunei Darussalam Time" => "Asia/Brunei",
|
||||||
|
"(GMT+08:00) Central Indonesia Time" => "Asia/Makassar",
|
||||||
|
"(GMT+08:00) China Standard Time - Macao" => "Asia/Macau",
|
||||||
|
"(GMT+08:00) China Standard Time - Shanghai" => "Asia/Shanghai",
|
||||||
|
"(GMT+08:00) Hong Kong Standard Time" => "Asia/Hong_Kong",
|
||||||
|
"(GMT+08:00) Irkutsk Standard Time" => "Asia/Irkutsk",
|
||||||
|
"(GMT+08:00) Malaysia Time - Kuala Lumpur" => "Asia/Kuala_Lumpur",
|
||||||
|
"(GMT+08:00) Malaysia Time - Kuching" => "Asia/Kuching",
|
||||||
|
"(GMT+08:00) Philippine Standard Time" => "Asia/Manila",
|
||||||
|
"(GMT+08:00) Singapore Standard Time" => "Asia/Singapore",
|
||||||
|
"(GMT+08:00) Taipei Standard Time" => "Asia/Taipei",
|
||||||
|
"(GMT+08:00) Ulaanbaatar Standard Time - Choibalsan" => "Asia/Choibalsan",
|
||||||
|
"(GMT+08:00) Ulaanbaatar Standard Time - Ulaanbaatar" => "Asia/Ulaanbaatar",
|
||||||
|
"(GMT+08:45) Australian Central Western Standard Time" => "Australia/Eucla",
|
||||||
|
"(GMT+09:00) East Timor Time" => "Asia/Dili",
|
||||||
|
"(GMT+09:00) Eastern Indonesia Time" => "Asia/Jayapura",
|
||||||
|
"(GMT+09:00) Japan Standard Time" => "Asia/Tokyo",
|
||||||
|
"(GMT+09:00) Korean Standard Time - Pyongyang" => "Asia/Pyongyang",
|
||||||
|
"(GMT+09:00) Korean Standard Time - Seoul" => "Asia/Seoul",
|
||||||
|
"(GMT+09:00) Palau Time" => "Pacific/Palau",
|
||||||
|
"(GMT+09:00) Yakutsk Standard Time - Chita" => "Asia/Chita",
|
||||||
|
"(GMT+09:00) Yakutsk Standard Time - Khandyga" => "Asia/Khandyga",
|
||||||
|
"(GMT+09:00) Yakutsk Standard Time - Yakutsk" => "Asia/Yakutsk",
|
||||||
|
"(GMT+09:30) Australian Central Standard Time" => "Australia/Darwin",
|
||||||
|
"(GMT+09:30) Central Australia Time - Adelaide" => "Australia/Adelaide",
|
||||||
|
"(GMT+09:30) Central Australia Time - Broken Hill" => "Australia/Broken_Hill",
|
||||||
|
"(GMT+10:00) Australian Eastern Standard Time - Brisbane" => "Australia/Brisbane",
|
||||||
|
"(GMT+10:00) Australian Eastern Standard Time - Lindeman" => "Australia/Lindeman",
|
||||||
|
"(GMT+10:00) Chamorro Standard Time" => "Pacific/Guam",
|
||||||
|
"(GMT+10:00) Chuuk Time" => "Pacific/Chuuk",
|
||||||
|
"(GMT+10:00) Dumont-d’Urville Time" => "Antarctica/DumontDUrville",
|
||||||
|
"(GMT+10:00) Eastern Australia Time - Currie" => "Australia/Currie",
|
||||||
|
"(GMT+10:00) Eastern Australia Time - Hobart" => "Australia/Hobart",
|
||||||
|
"(GMT+10:00) Eastern Australia Time - Melbourne" => "Australia/Melbourne",
|
||||||
|
"(GMT+10:00) Eastern Australia Time - Sydney" => "Australia/Sydney",
|
||||||
|
"(GMT+10:00) Papua New Guinea Time" => "Pacific/Port_Moresby",
|
||||||
|
"(GMT+10:00) Vladivostok Standard Time - Ust-Nera" => "Asia/Ust-Nera",
|
||||||
|
"(GMT+10:00) Vladivostok Standard Time - Vladivostok" => "Asia/Vladivostok",
|
||||||
|
"(GMT+10:30) Lord Howe Time" => "Australia/Lord_Howe",
|
||||||
|
"(GMT+11:00) Bougainville Time" => "Pacific/Bougainville",
|
||||||
|
"(GMT+11:00) Kosrae Time" => "Pacific/Kosrae",
|
||||||
|
"(GMT+11:00) Macquarie Island Time" => "Antarctica/Macquarie",
|
||||||
|
"(GMT+11:00) Magadan Standard Time" => "Asia/Magadan",
|
||||||
|
"(GMT+11:00) New Caledonia Standard Time" => "Pacific/Noumea",
|
||||||
|
"(GMT+11:00) Norfolk Island Time" => "Pacific/Norfolk",
|
||||||
|
"(GMT+11:00) Ponape Time" => "Pacific/Pohnpei",
|
||||||
|
"(GMT+11:00) Sakhalin Standard Time" => "Asia/Sakhalin",
|
||||||
|
"(GMT+11:00) Solomon Islands Time" => "Pacific/Guadalcanal",
|
||||||
|
"(GMT+11:00) Srednekolymsk Time" => "Asia/Srednekolymsk",
|
||||||
|
"(GMT+11:00) Vanuatu Standard Time" => "Pacific/Efate",
|
||||||
|
"(GMT+12:00) Anadyr Standard Time" => "Asia/Anadyr",
|
||||||
|
"(GMT+12:00) Fiji Time" => "Pacific/Fiji",
|
||||||
|
"(GMT+12:00) Gilbert Islands Time" => "Pacific/Tarawa",
|
||||||
|
"(GMT+12:00) Marshall Islands Time - Kwajalein" => "Pacific/Kwajalein",
|
||||||
|
"(GMT+12:00) Marshall Islands Time - Majuro" => "Pacific/Majuro",
|
||||||
|
"(GMT+12:00) Nauru Time" => "Pacific/Nauru",
|
||||||
|
"(GMT+12:00) New Zealand Time" => "Pacific/Auckland",
|
||||||
|
"(GMT+12:00) Petropavlovsk-Kamchatski Standard Time" => "Asia/Kamchatka",
|
||||||
|
"(GMT+12:00) Tuvalu Time" => "Pacific/Funafuti",
|
||||||
|
"(GMT+12:00) Wake Island Time" => "Pacific/Wake",
|
||||||
|
"(GMT+12:00) Wallis & Futuna Time" => "Pacific/Wallis",
|
||||||
|
"(GMT+12:45) Chatham Time" => "Pacific/Chatham",
|
||||||
|
"(GMT+13:00) Apia Time" => "Pacific/Apia",
|
||||||
|
"(GMT+13:00) Phoenix Islands Time" => "Pacific/Enderbury",
|
||||||
|
"(GMT+13:00) Tokelau Time" => "Pacific/Fakaofo",
|
||||||
|
"(GMT+13:00) Tonga Standard Time" => "Pacific/Tongatapu",
|
||||||
|
"(GMT+14:00) Line Islands Time" => "Pacific/Kiritimati"
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* xmlseclibs.php
|
||||||
|
*
|
||||||
|
* Copyright (c) 2007-2016, Robert Richards <rrichards@cdatazone.org>.
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions
|
||||||
|
* are met:
|
||||||
|
*
|
||||||
|
* * Redistributions of source code must retain the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* * Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in
|
||||||
|
* the documentation and/or other materials provided with the
|
||||||
|
* distribution.
|
||||||
|
*
|
||||||
|
* * Neither the name of Robert Richards nor the names of his
|
||||||
|
* contributors may be used to endorse or promote products derived
|
||||||
|
* from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
||||||
|
* CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||||||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*
|
||||||
|
* @author Robert Richards <rrichards@cdatazone.org>
|
||||||
|
* @copyright 2007-2017 Robert Richards <rrichards@cdatazone.org>
|
||||||
|
* @license http://www.opensource.org/licenses/bsd-license.php BSD License
|
||||||
|
* @version 3.0.1
|
||||||
|
*/
|
||||||
|
|
||||||
|
$xmlseclibs_srcdir = dirname(__FILE__) . '/SAML2Core';
|
||||||
|
require $xmlseclibs_srcdir . '/MoXMLSecurityKey.php';
|
||||||
|
require $xmlseclibs_srcdir . '/MoXMLSecurityDSig.php';
|
||||||
|
require $xmlseclibs_srcdir . '/MoXMLSecEnc.php';
|
||||||
|
require $xmlseclibs_srcdir . '/Utils/MoXPath.php';
|
||||||
+50
-7
@@ -1,11 +1,14 @@
|
|||||||
<?php
|
<?php
|
||||||
define('CLIENT_PATH', dirname(__FILE__));
|
use Classes\SAMLManager;use Classes\SettingsManager;use Utils\LogManager;define('CLIENT_PATH', dirname(__FILE__));
|
||||||
include("config.base.php");
|
include("config.base.php");
|
||||||
include("include.common.php");
|
include("include.common.php");
|
||||||
include("server.includes.inc.php");
|
include("server.includes.inc.php");
|
||||||
|
|
||||||
$companyName = \Classes\SettingsManager::getInstance()->getSetting('Company: Name');
|
$gsuiteEnabled = SettingsManager::getInstance()->getSetting('System: G Suite Enabled');
|
||||||
$gsuiteEnabled = \Classes\SettingsManager::getInstance()->getSetting('System: G Suite Enabled');
|
$companyName = SettingsManager::getInstance()->getSetting('Company: Name');
|
||||||
|
$SAMLAutoLogin = SettingsManager::getInstance()->getSetting('SAML: Auto Login') === "1";
|
||||||
|
$SAMLEnabled = SettingsManager::getInstance()->getSetting("SAML: Enabled") == "1";
|
||||||
|
$SAMLUserLoaded = false;
|
||||||
|
|
||||||
if (isset($_REQUEST['logout'])) {
|
if (isset($_REQUEST['logout'])) {
|
||||||
\Utils\SessionUtils::unsetClientSession();
|
\Utils\SessionUtils::unsetClientSession();
|
||||||
@@ -14,12 +17,19 @@ if (isset($_REQUEST['logout'])) {
|
|||||||
|
|
||||||
if (empty($user) || empty($user->email)) {
|
if (empty($user) || empty($user->email)) {
|
||||||
|
|
||||||
if (!empty($_REQUEST['username']) && !empty($_REQUEST['password'])) {
|
if (!isset($_REQUEST['logout']) && !isset($_POST['SAMLResponse']) && $SAMLAutoLogin && $SAMLEnabled && !empty(SettingsManager::getInstance()->getSetting("SAML: IDP SSO Url"))) {
|
||||||
|
header("Location:" . SettingsManager::getInstance()->getSetting("SAML: IDP SSO Url"));
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((!empty($_REQUEST['username']) && !empty($_REQUEST['password']))
|
||||||
|
|| isset($_POST['SAMLResponse'])
|
||||||
|
) {
|
||||||
$suser = null;
|
$suser = null;
|
||||||
$ssoUserLoaded = false;
|
$ssoUserLoaded = false;
|
||||||
|
|
||||||
if($_REQUEST['username'] != "admin") {
|
if($_REQUEST['username'] != "admin") {
|
||||||
if (\Classes\SettingsManager::getInstance()->getSetting("LDAP: Enabled") == "1") {
|
if (SettingsManager::getInstance()->getSetting("LDAP: Enabled") === "1") {
|
||||||
$ldapResp = \Classes\LDAPManager::getInstance()->checkLDAPLogin($_REQUEST['username'], $_REQUEST['password']);
|
$ldapResp = \Classes\LDAPManager::getInstance()->checkLDAPLogin($_REQUEST['username'], $_REQUEST['password']);
|
||||||
if ($ldapResp->getStatus() == \Classes\IceResponse::ERROR) {
|
if ($ldapResp->getStatus() == \Classes\IceResponse::ERROR) {
|
||||||
header("Location:" . CLIENT_BASE_URL . "login.php?f=1");
|
header("Location:" . CLIENT_BASE_URL . "login.php?f=1");
|
||||||
@@ -36,6 +46,39 @@ if (empty($user) || empty($user->email)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ($SAMLEnabled && isset($_POST['SAMLResponse'])) {
|
||||||
|
$samlData = $_POST['SAMLResponse'];
|
||||||
|
|
||||||
|
if(array_key_exists('RelayState', $_POST) && !empty( $_POST['RelayState'] ) && $_POST['RelayState'] !== '/') {
|
||||||
|
$relayState = htmlspecialchars($_POST['RelayState']);
|
||||||
|
} else {
|
||||||
|
$relayState = '';
|
||||||
|
}
|
||||||
|
|
||||||
|
$ssoUserEmail = (new SAMLManager())->getSSOEmail($samlData, $relayState);
|
||||||
|
LogManager::getInstance()->info('SSO SAML User Email:'.$ssoUserEmail);
|
||||||
|
if (false === $ssoUserEmail) {
|
||||||
|
header("Location:" . CLIENT_BASE_URL . "login.php?f=1");
|
||||||
|
exit();
|
||||||
|
} else {
|
||||||
|
$mapping = SettingsManager::getInstance()->getSetting('SAML: Name ID Mapping');
|
||||||
|
$suser = new \Users\Common\Model\User();
|
||||||
|
if ($mapping === 'username') {
|
||||||
|
$suser->Load("username = ?", array($ssoUserEmail));
|
||||||
|
} else {
|
||||||
|
$suser->Load("email = ?", array($ssoUserEmail));
|
||||||
|
}
|
||||||
|
|
||||||
|
LogManager::getInstance()->info('SSO SAML User:'.print_r($suser, true));
|
||||||
|
if (empty($suser)) {
|
||||||
|
header("Location:" . CLIENT_BASE_URL . "login.php?f=1");
|
||||||
|
exit();
|
||||||
|
}
|
||||||
|
$ssoUserLoaded = true;
|
||||||
|
$SAMLUserLoaded = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (empty($suser)) {
|
if (empty($suser)) {
|
||||||
$suser = new \Users\Common\Model\User();
|
$suser = new \Users\Common\Model\User();
|
||||||
$suser->Load(
|
$suser->Load(
|
||||||
@@ -59,7 +102,7 @@ if (empty($user) || empty($user->email)) {
|
|||||||
|
|
||||||
$loginCsrf = \Utils\SessionUtils::getSessionObject('csrf-login');
|
$loginCsrf = \Utils\SessionUtils::getSessionObject('csrf-login');
|
||||||
|
|
||||||
if ($_REQUEST['csrf'] != $loginCsrf || empty($_REQUEST['csrf'])) {
|
if (!$SAMLUserLoaded && ($_REQUEST['csrf'] != $loginCsrf || empty($_REQUEST['csrf']))) {
|
||||||
$next = !empty($_REQUEST['next'])?'&next='.$_REQUEST['next']:'';
|
$next = !empty($_REQUEST['next'])?'&next='.$_REQUEST['next']:'';
|
||||||
header("Location:".CLIENT_BASE_URL."login.php?f=1".$next);
|
header("Location:".CLIENT_BASE_URL."login.php?f=1".$next);
|
||||||
exit();
|
exit();
|
||||||
@@ -277,7 +320,7 @@ $csrfToken = sha1(rand(4500, 100000) . time(). CLIENT_BASE_URL);
|
|||||||
<div class="col-lg-6 col-md-8 col-xs-10">
|
<div class="col-lg-6 col-md-8 col-xs-10">
|
||||||
<div class="bg-white-2 h-100 px-11 pt-11 pb-7">
|
<div class="bg-white-2 h-100 px-11 pt-11 pb-7">
|
||||||
<div class="row d-flex justify-content-center">
|
<div class="row d-flex justify-content-center">
|
||||||
<img src="<?=$logoFileUrl?>" style="max-width:100%;max-height:280px;"/>
|
<img style="max-width: 100%;" src="<?=$logoFileUrl?>"/>
|
||||||
</div>
|
</div>
|
||||||
<hr/>
|
<hr/>
|
||||||
<?php if ($gsuiteEnabled) {?>
|
<?php if ($gsuiteEnabled) {?>
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
<?php
|
<?php
|
||||||
$migrationList = [];
|
$migrationList = [];
|
||||||
|
$migrationList[] = 'v20210402_280006_modify_attendance_rep';
|
||||||
|
$migrationList[] = 'v20210327_280005_saml_settings';
|
||||||
|
$migrationList[] = 'v20210228_280003_add_share_with_employee';
|
||||||
|
$migrationList[] = 'v20210228_280004_add_visible_to_document';
|
||||||
$migrationList[] = 'v20201028_280002_update_gender';
|
$migrationList[] = 'v20201028_280002_update_gender';
|
||||||
$migrationList[] = 'v20201028_280001_update_module_names';
|
$migrationList[] = 'v20201028_280001_update_module_names';
|
||||||
$migrationList[] = 'v20201017_271101_switch_off_photo_att';
|
$migrationList[] = 'v20201017_271101_switch_off_photo_att';
|
||||||
|
|||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Classes\Migration;
|
||||||
|
|
||||||
|
class v20210228_280003_add_share_with_employee extends AbstractMigration
|
||||||
|
{
|
||||||
|
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
|
||||||
|
$sql = <<<'SQL'
|
||||||
|
ALTER TABLE `Documents`
|
||||||
|
ADD COLUMN `share_with_employee` enum('Yes','No') NULL DEFAULT 'Yes' AFTER `updated`;
|
||||||
|
SQL;
|
||||||
|
$this->executeQuery($sql);
|
||||||
|
|
||||||
|
return $this->executeQuery($sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Classes\Migration;
|
||||||
|
|
||||||
|
class v20210228_280004_add_visible_to_document extends AbstractMigration
|
||||||
|
{
|
||||||
|
|
||||||
|
public function up()
|
||||||
|
{
|
||||||
|
|
||||||
|
$sql = <<<'SQL'
|
||||||
|
ALTER TABLE `EmployeeDocuments`
|
||||||
|
ADD COLUMN `visible_to` enum('Owner','Manager','Admin') NULL DEFAULT 'Owner' AFTER `expire_notification_last`;
|
||||||
|
SQL;
|
||||||
|
$this->executeQuery($sql);
|
||||||
|
|
||||||
|
return $this->executeQuery($sql);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
namespace Classes\Migration;
|
||||||
|
|
||||||
|
class v20210327_280005_saml_settings extends AbstractMigration {
|
||||||
|
|
||||||
|
public function up(){
|
||||||
|
|
||||||
|
$sql[] = <<<'SQL'
|
||||||
|
REPLACE INTO `Settings` (`name`, `value`, `description`, `meta`, `category`)
|
||||||
|
VALUES (
|
||||||
|
'SAML: Enabled',
|
||||||
|
'0',
|
||||||
|
'Enable SAML Login',
|
||||||
|
'["value", {"label":"Value","type":"select","source":[["1","Yes"],["0","No"]]}]',
|
||||||
|
'SAML'
|
||||||
|
);
|
||||||
|
SQL;
|
||||||
|
$sql[] = <<<'SQL'
|
||||||
|
REPLACE INTO `Settings` (`name`, `value`, `description`, `meta`, `category`)
|
||||||
|
VALUES (
|
||||||
|
'SAML: Auto Login',
|
||||||
|
'0',
|
||||||
|
'Try to login via SAML by redirecting the user to SSO Url',
|
||||||
|
'["value", {"label":"Value","type":"select","source":[["1","Yes"],["0","No"]]}]',
|
||||||
|
'SAML'
|
||||||
|
);
|
||||||
|
SQL;
|
||||||
|
|
||||||
|
$sql[] = <<<'SQL'
|
||||||
|
REPLACE INTO `Settings` (`name`, `value`, `description`, `meta`, `category`)
|
||||||
|
VALUES (
|
||||||
|
'SAML: IDP SSO Url',
|
||||||
|
'',
|
||||||
|
'Identity Provider Single Sign-On URL. Users will be redirected to this URL for authentication',
|
||||||
|
'',
|
||||||
|
'SAML'
|
||||||
|
);
|
||||||
|
SQL;
|
||||||
|
|
||||||
|
$sql[] = <<<'SQL'
|
||||||
|
REPLACE INTO `Settings` (`name`, `value`, `description`, `meta`, `category`)
|
||||||
|
VALUES (
|
||||||
|
'SAML: IDP Issuer',
|
||||||
|
'',
|
||||||
|
'Identity Provider Issuer',
|
||||||
|
'',
|
||||||
|
'SAML'
|
||||||
|
);
|
||||||
|
SQL;
|
||||||
|
|
||||||
|
$sql[] = <<<'SQL'
|
||||||
|
REPLACE INTO `Settings` (`name`, `value`, `description`, `meta`, `category`)
|
||||||
|
VALUES (
|
||||||
|
'SAML: X.509 Certificate',
|
||||||
|
'',
|
||||||
|
'X.509 Certificate provided by the Identity Provider. This certificate will be encrypted',
|
||||||
|
'["value", {"label":"Value","type":"textarea"}]',
|
||||||
|
'SAML'
|
||||||
|
);
|
||||||
|
SQL;
|
||||||
|
|
||||||
|
$sql[] = <<<'SQL'
|
||||||
|
REPLACE INTO `Settings` (`name`, `value`, `description`, `meta`, `category`)
|
||||||
|
VALUES (
|
||||||
|
'SAML: Name ID Mapping',
|
||||||
|
'email',
|
||||||
|
'SAML Name id mapped to can be mapped to icehrm user email or the username',
|
||||||
|
'["value", {"label":"Value","type":"select","source":[["email","Email"],["username","Username"]]}]',
|
||||||
|
'SAML'
|
||||||
|
);
|
||||||
|
SQL;
|
||||||
|
|
||||||
|
$result = true;
|
||||||
|
foreach ($sql as $query) {
|
||||||
|
$result = $result && $this->executeQuery($query);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
<?php
|
||||||
|
namespace Classes\Migration;
|
||||||
|
|
||||||
|
use Model\Report;
|
||||||
|
|
||||||
|
class v20210402_280006_modify_attendance_rep extends AbstractMigration {
|
||||||
|
|
||||||
|
public function up(){
|
||||||
|
|
||||||
|
$report = new Report();
|
||||||
|
$report->Load('name = ?', ['Employee Time Tracking Report']);
|
||||||
|
$report->parameters = <<<'JSON'
|
||||||
|
[
|
||||||
|
[ "employee", {"label":"Employee","type":"select2","allow-null":false,"remote-source":["Employee","id","first_name+last_name"]}],
|
||||||
|
[ "date_start", {"label":"Start Date","type":"date", "validation":"none"}],
|
||||||
|
[ "date_end", {"label":"End Date","type":"date","validation":"none"}],
|
||||||
|
["period", { "label": "Period", "type": "select", "source": [["Current Month", "Current Month"], ["Last Month", "Last Month"], ["Last Week", "Last Week"], ["Last 2 Weeks", "Last 2 Weeks"]], "validation":"none" }]
|
||||||
|
]
|
||||||
|
JSON;
|
||||||
|
$report->paramOrder = <<<'JSON'
|
||||||
|
["employee","date_start","date_end","period"]
|
||||||
|
JSON;
|
||||||
|
|
||||||
|
$report->Save();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function down(){
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
+49
-2
@@ -291,6 +291,12 @@ foreach ($ams as $am) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$extensionManager = new \Classes\ExtensionManager();
|
||||||
|
$extensionData = $extensionManager->setupExtensions();
|
||||||
|
$extensionIcons = $extensionData[0];
|
||||||
|
$extensionTemp = $extensionData[1];
|
||||||
|
$extensionMenus = array_keys($extensionIcons);
|
||||||
|
|
||||||
foreach ($adminModulesTemp as $k => $v) {
|
foreach ($adminModulesTemp as $k => $v) {
|
||||||
ksort($adminModulesTemp[$k]);
|
ksort($adminModulesTemp[$k]);
|
||||||
}
|
}
|
||||||
@@ -299,6 +305,10 @@ foreach ($userModulesTemp as $k => $v) {
|
|||||||
ksort($userModulesTemp[$k]);
|
ksort($userModulesTemp[$k]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($extensionTemp as $k => $v) {
|
||||||
|
ksort($extensionTemp[$k]);
|
||||||
|
}
|
||||||
|
|
||||||
$adminIcons = json_decode(file_get_contents(CLIENT_PATH.'/admin/meta.json'), true);
|
$adminIcons = json_decode(file_get_contents(CLIENT_PATH.'/admin/meta.json'), true);
|
||||||
$adminMenus = array_keys($adminIcons);
|
$adminMenus = array_keys($adminIcons);
|
||||||
|
|
||||||
@@ -332,8 +342,6 @@ foreach ($userMenus as $menu) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$mainIcons = array_merge($adminIcons, $userIcons);
|
|
||||||
|
|
||||||
foreach ($userModulesTemp as $k => $v) {
|
foreach ($userModulesTemp as $k => $v) {
|
||||||
if (!in_array($k, $added)) {
|
if (!in_array($k, $added)) {
|
||||||
$arr = array("name"=>$k,"menu"=>$userModulesTemp[$k]);
|
$arr = array("name"=>$k,"menu"=>$userModulesTemp[$k]);
|
||||||
@@ -341,6 +349,25 @@ foreach ($userModulesTemp as $k => $v) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$extensions = array();
|
||||||
|
foreach ($extensionMenus as $menu) {
|
||||||
|
if (isset($extensionTemp[$menu])) {
|
||||||
|
$arr = array("name"=>$menu,"menu"=>$extensionTemp[$menu]);
|
||||||
|
$extensions[] = $arr;
|
||||||
|
$added[] = $menu;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($extensionTemp as $k => $v) {
|
||||||
|
if (!in_array($k, $added)) {
|
||||||
|
$arr = array("name"=>$k,"menu"=>$extensionTemp[$k]);
|
||||||
|
$extensions[] = $arr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Merge icons
|
||||||
|
$mainIcons = array_merge($adminIcons, $userIcons, $extensionIcons);
|
||||||
|
|
||||||
//Remove modules having no permissions
|
//Remove modules having no permissions
|
||||||
if (!empty($user)) {
|
if (!empty($user)) {
|
||||||
if (!empty($user->user_roles)) {
|
if (!empty($user->user_roles)) {
|
||||||
@@ -393,4 +420,24 @@ if (!empty($user)) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
foreach ($extensions as $fk => $menu) {
|
||||||
|
foreach ($menu['menu'] as $key => $item) {
|
||||||
|
// If the user's once of the user roles are blacklisted for the module
|
||||||
|
$commonRoles = array_intersect($item['user_roles_blacklist'], $userRoles);
|
||||||
|
if (!empty($commonRoles)) {
|
||||||
|
unset($extensions[$fk]['menu'][$key]);
|
||||||
|
}
|
||||||
|
if (!in_array($user->user_level, $item['user_levels'])) {
|
||||||
|
if (!empty($userRoles)) {
|
||||||
|
$commonRoles = array_intersect($item['user_roles'], $userRoles);
|
||||||
|
if (empty($commonRoles)) {
|
||||||
|
unset($extensions[$fk]['menu'][$key]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
unset($extensions[$fk]['menu'][$key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -67,6 +67,8 @@ modJsList['tabEmployeeDocument'].setShowDelete(false);
|
|||||||
modJsList['tabEmployeeDocument'].setShowEdit(false);
|
modJsList['tabEmployeeDocument'].setShowEdit(false);
|
||||||
<?php }?>
|
<?php }?>
|
||||||
|
|
||||||
|
modJsList['tabEmployeeDocument'].setRemoteTable(true);
|
||||||
|
|
||||||
|
|
||||||
modJsList['tabEmployeeCompanyDocument'] = new EmployeeCompanyDocumentAdapter('CompanyDocument','EmployeeCompanyDocument');
|
modJsList['tabEmployeeCompanyDocument'] = new EmployeeCompanyDocumentAdapter('CompanyDocument','EmployeeCompanyDocument');
|
||||||
modJsList['tabEmployeeCompanyDocument'].setLoadMoreButton($("#loadMoreEmployeeCompanyDocument"));
|
modJsList['tabEmployeeCompanyDocument'].setLoadMoreButton($("#loadMoreEmployeeCompanyDocument"));
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use Classes\Migration\MigrationManager;
|
|||||||
use Classes\NotificationManager;
|
use Classes\NotificationManager;
|
||||||
use Classes\ReportHandler;
|
use Classes\ReportHandler;
|
||||||
use Classes\SettingsManager;
|
use Classes\SettingsManager;
|
||||||
|
use Model\BaseModel;
|
||||||
use Utils\LogManager;
|
use Utils\LogManager;
|
||||||
|
|
||||||
if (!defined("AWS_REGION")) {
|
if (!defined("AWS_REGION")) {
|
||||||
@@ -79,6 +80,18 @@ if (defined('REDIS_SERVER_URI')
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$samlEnabled = SettingsManager::getInstance()->getSetting("SAML: Enabled");
|
||||||
|
if ($samlEnabled === '1') {
|
||||||
|
include APP_BASE_PATH . 'lib/saml2/Utilities.php';
|
||||||
|
include APP_BASE_PATH . 'lib/saml2/Response.php';
|
||||||
|
include APP_BASE_PATH . 'lib/saml2/encryption.php';
|
||||||
|
include APP_BASE_PATH . 'lib/saml2/mo-saml-options-enum.php';
|
||||||
|
}
|
||||||
|
|
||||||
|
$instanceId = SettingsManager::getInstance()->getSetting("Instance : ID");
|
||||||
|
$instanceKey = SettingsManager::getInstance()->getSetting("Instance: Key");
|
||||||
|
if(!defined('APP_SEC')){define('APP_SEC',sha1($instanceId.$instanceKey));}
|
||||||
|
|
||||||
$noJSONRequests = SettingsManager::getInstance()->getSetting("System: Do not pass JSON in request");
|
$noJSONRequests = SettingsManager::getInstance()->getSetting("System: Do not pass JSON in request");
|
||||||
|
|
||||||
$debugMode = SettingsManager::getInstance()->getSetting("System: Debug Mode");
|
$debugMode = SettingsManager::getInstance()->getSetting("System: Debug Mode");
|
||||||
@@ -123,10 +136,12 @@ if (defined('CLIENT_PATH')) {
|
|||||||
|
|
||||||
$modelClassList = $moduleManagerObj->getModelClasses();
|
$modelClassList = $moduleManagerObj->getModelClasses();
|
||||||
$metaData = $moduleManagerObj->getModuleObject();
|
$metaData = $moduleManagerObj->getModuleObject();
|
||||||
|
/** @var BaseModel $modelClass */
|
||||||
foreach ($modelClassList as $modelClass) {
|
foreach ($modelClassList as $modelClass) {
|
||||||
$modelClassWithNameSpace = $metaData['model_namespace']."\\".$modelClass;
|
$modelClassWithNameSpace = $metaData['model_namespace']."\\".$modelClass;
|
||||||
$modelClassWithNameSpace::SetDatabaseAdapter($dbLocal);
|
$modelClassWithNameSpace::SetDatabaseAdapter($dbLocal);
|
||||||
$baseService->addModelClass($modelClass, $modelClassWithNameSpace);
|
$baseService->addModelClass($modelClass, $modelClassWithNameSpace);
|
||||||
|
$modelClassObject = new $modelClassWithNameSpace();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,8 +33,7 @@ class AttendanceActionManager extends SubActionManager
|
|||||||
//Find any open punch
|
//Find any open punch
|
||||||
$attendance = new Attendance();
|
$attendance = new Attendance();
|
||||||
$attendance->Load(
|
$attendance->Load(
|
||||||
"employee = ? and DATE_FORMAT( in_time, '%Y-%m-%d' ) = ? and (out_time is NULL
|
"employee = ? and DATE_FORMAT( in_time, '%Y-%m-%d' ) = ? and out_time is NULL",
|
||||||
or out_time = '0000-00-00 00:00:00')",
|
|
||||||
array($employee->id,$date)
|
array($employee->id,$date)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
*/
|
*/
|
||||||
namespace Classes;
|
namespace Classes;
|
||||||
|
|
||||||
|
use Model\BaseModel;
|
||||||
use Utils\LogManager;
|
use Utils\LogManager;
|
||||||
|
|
||||||
abstract class AbstractModuleManager
|
abstract class AbstractModuleManager
|
||||||
@@ -254,7 +255,17 @@ abstract class AbstractModuleManager
|
|||||||
protected function addModelClass($className)
|
protected function addModelClass($className)
|
||||||
{
|
{
|
||||||
$this->modelClasses[] = $className;
|
$this->modelClasses[] = $className;
|
||||||
BaseService::getInstance()->addModelClass($className, $this->moduleObject['model_namespace']."\\".$className);
|
$classWithNamespace = $this->moduleObject['model_namespace']."\\".$className;
|
||||||
|
BaseService::getInstance()->addModelClass($className, $classWithNamespace);
|
||||||
|
/** @var BaseModel $modelClass */
|
||||||
|
$modelClass = new $classWithNamespace();
|
||||||
|
if ($modelClass->isCustomFieldsEnabled()) {
|
||||||
|
$objectName = $modelClass->getObjectName();
|
||||||
|
BaseService::getInstance()->addCustomFieldClass(
|
||||||
|
$className,
|
||||||
|
(null === $objectName)? $className : $objectName
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected function addHistoryGeneric($type, $table, $refName, $refId, $field, $oldValue, $newValue)
|
protected function addHistoryGeneric($type, $table, $refName, $refId, $field, $oldValue, $newValue)
|
||||||
@@ -278,4 +289,12 @@ abstract class AbstractModuleManager
|
|||||||
{
|
{
|
||||||
BaseService::getInstance()->addCalculationHook($code, $name, $class, $method);
|
BaseService::getInstance()->addCalculationHook($code, $name, $class, $method);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function install()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function uninstall()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -19,6 +19,7 @@ use Employees\Common\Model\EmployeeApproval;
|
|||||||
use FieldNames\Common\Model\CustomField;
|
use FieldNames\Common\Model\CustomField;
|
||||||
use FieldNames\Common\Model\FieldNameMapping;
|
use FieldNames\Common\Model\FieldNameMapping;
|
||||||
use Metadata\Common\Model\CalculationHook;
|
use Metadata\Common\Model\CalculationHook;
|
||||||
|
use Model\BaseModel;
|
||||||
use Model\DataEntryBackup;
|
use Model\DataEntryBackup;
|
||||||
use Model\Setting;
|
use Model\Setting;
|
||||||
use Modules\Common\Model\Module;
|
use Modules\Common\Model\Module;
|
||||||
@@ -51,7 +52,8 @@ class BaseService
|
|||||||
public $calculationHooks = array();
|
public $calculationHooks = array();
|
||||||
public $customFieldManager = null;
|
public $customFieldManager = null;
|
||||||
public $migrationManager = null;
|
public $migrationManager = null;
|
||||||
public $modelClassMap = array();
|
public $modelClassMap = [];
|
||||||
|
public $customFieldsClassMap = [];
|
||||||
public $currentProfileId = false;
|
public $currentProfileId = false;
|
||||||
|
|
||||||
protected $cacheService = null;
|
protected $cacheService = null;
|
||||||
@@ -167,6 +169,20 @@ class BaseService
|
|||||||
$this->modelClassMap[$modelClass] = $fullQualifiedName;
|
$this->modelClassMap[$modelClass] = $fullQualifiedName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getCustomFieldClassMap()
|
||||||
|
{
|
||||||
|
$map = [];
|
||||||
|
foreach($this->customFieldsClassMap as $key => $val) {
|
||||||
|
$map[] = [$key, $val];
|
||||||
|
}
|
||||||
|
return $map;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addCustomFieldClass($customFieldsClass, $objectName)
|
||||||
|
{
|
||||||
|
$this->customFieldsClassMap[$customFieldsClass] = $objectName;
|
||||||
|
}
|
||||||
|
|
||||||
public function getModelClassName($name)
|
public function getModelClassName($name)
|
||||||
{
|
{
|
||||||
return $this->getFullQualifiedModelClassName($name);
|
return $this->getFullQualifiedModelClassName($name);
|
||||||
@@ -637,7 +653,10 @@ class BaseService
|
|||||||
|
|
||||||
$processedList = array();
|
$processedList = array();
|
||||||
foreach ($list as $obj) {
|
foreach ($list as $obj) {
|
||||||
$processedList[] = $this->cleanUpAdoDB($obj->postProcessGetData($obj));
|
$processedObj = $this->cleanUpAdoDB($obj->postProcessGetData($obj));
|
||||||
|
if (null !== $processedObj) {
|
||||||
|
$processedList[] = $processedObj;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$list = $processedList;
|
$list = $processedList;
|
||||||
@@ -749,7 +768,7 @@ class BaseService
|
|||||||
$obj = $this->enrichObjectCustomFields($table, $obj);
|
$obj = $this->enrichObjectCustomFields($table, $obj);
|
||||||
|
|
||||||
$obj = $obj->postProcessGetElement($obj);
|
$obj = $obj->postProcessGetElement($obj);
|
||||||
return $this->cleanUpAdoDB($obj->postProcessGetData($obj));
|
return $this->cleanUpAdoDB($obj);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -928,6 +947,7 @@ class BaseService
|
|||||||
{
|
{
|
||||||
$fileFields = $this->fileFields;
|
$fileFields = $this->fileFields;
|
||||||
$nsTable = $this->getFullQualifiedModelClassName($table);
|
$nsTable = $this->getFullQualifiedModelClassName($table);
|
||||||
|
/** @var BaseModel $ele */
|
||||||
$ele = new $nsTable();
|
$ele = new $nsTable();
|
||||||
|
|
||||||
$ele->Load('id = ?', array($id));
|
$ele->Load('id = ?', array($id));
|
||||||
@@ -985,7 +1005,7 @@ class BaseService
|
|||||||
$dataEntryBackup->data = json_encode($newObj);
|
$dataEntryBackup->data = json_encode($newObj);
|
||||||
$dataEntryBackup->Save();
|
$dataEntryBackup->Save();
|
||||||
}
|
}
|
||||||
|
$ele->executePostDeleteActions($ele);
|
||||||
$this->audit(IceConstants::AUDIT_DELETE, "Deleted an object in ".$table." [id:".$ele->id."]");
|
$this->audit(IceConstants::AUDIT_DELETE, "Deleted an object in ".$table." [id:".$ele->id."]");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -998,6 +1018,7 @@ class BaseService
|
|||||||
}
|
}
|
||||||
|
|
||||||
$cfs = $this->customFieldManager->getCustomFields($table, $id);
|
$cfs = $this->customFieldManager->getCustomFields($table, $id);
|
||||||
|
/** @var CustomField $cf */
|
||||||
foreach ($cfs as $cf) {
|
foreach ($cfs as $cf) {
|
||||||
$cf->Delete();
|
$cf->Delete();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,6 +61,7 @@ class DomainAwareInputCleaner
|
|||||||
|
|
||||||
$filterData = json_decode($filters, true);
|
$filterData = json_decode($filters, true);
|
||||||
foreach ($filterData as $name => $value) {
|
foreach ($filterData as $name => $value) {
|
||||||
|
|
||||||
if (!$this->isValidColumnName($name) || !$this->isValidFilterValue($value)) {
|
if (!$this->isValidColumnName($name) || !$this->isValidFilterValue($value)) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
@@ -90,6 +91,14 @@ class DomainAwareInputCleaner
|
|||||||
|
|
||||||
private function isValidFilterValue($input)
|
private function isValidFilterValue($input)
|
||||||
{
|
{
|
||||||
|
if (is_array($input)) {
|
||||||
|
$isValid = true;
|
||||||
|
foreach ($input as $val) {
|
||||||
|
$isValid = $isValid && !!preg_match('/^[-_: \d\p{L}]+$/u', $val);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $isValid;
|
||||||
|
}
|
||||||
return !!preg_match('/^[-_: \d\p{L}]+$/u', $input);
|
return !!preg_match('/^[-_: \d\p{L}]+$/u', $input);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,146 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Classes;
|
||||||
|
|
||||||
|
use Utils\LogManager;
|
||||||
|
|
||||||
|
class ExtensionManager
|
||||||
|
{
|
||||||
|
const GROUP = 'extension';
|
||||||
|
protected function processExtensionInDB()
|
||||||
|
{
|
||||||
|
$dbModule = new \Modules\Common\Model\Module();
|
||||||
|
$extensions = $dbModule->Find("mod_group = ?", array(self::GROUP));
|
||||||
|
|
||||||
|
$extensionsInDB = [];
|
||||||
|
foreach ($extensions as $dbm) {
|
||||||
|
$extensionsInDB[$dbm->name] = $dbm;
|
||||||
|
ModuleAccessService::getInstance()->setModule($dbm->name, self::GROUP, $dbm);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $extensionsInDB;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExtensionsPath()
|
||||||
|
{
|
||||||
|
return APP_BASE_PATH.'../extensions/';
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getExtensionMetaData($extensionName)
|
||||||
|
{
|
||||||
|
return json_decode(file_get_contents($this->getExtensionsPath().$extensionName.'/meta.json'));
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setupExtensions()
|
||||||
|
{
|
||||||
|
$menu = [];
|
||||||
|
$extensions = [];
|
||||||
|
$extensionDirs = scandir($this->getExtensionsPath());
|
||||||
|
$currentLocation = 0;
|
||||||
|
|
||||||
|
$extensionsInDB = $this->processExtensionInDB();
|
||||||
|
|
||||||
|
$needToInstall = false;
|
||||||
|
|
||||||
|
foreach ($extensionDirs as $extensionDir) {
|
||||||
|
if (is_dir($this->getExtensionsPath().$extensionDir) && $extensionDir != '.' && $extensionDir != '..') {
|
||||||
|
$meta = $this->getExtensionMetaData($extensionDir);
|
||||||
|
|
||||||
|
$arr = [];
|
||||||
|
$arr['name'] = $extensionDir;
|
||||||
|
$arr['label'] = $meta->label;
|
||||||
|
$arr['icon'] = $meta->icon;
|
||||||
|
$arr['menu'] = $meta->menu[0];
|
||||||
|
$arr['order'] = 0;
|
||||||
|
$arr['status'] = 'Enabled';
|
||||||
|
$arr['user_levels'] = $meta->user_levels;
|
||||||
|
$arr['user_roles'] = isset($meta->user_roles)?$meta->user_roles:"";
|
||||||
|
$arr['model_namespace'] = $meta->model_namespace;
|
||||||
|
$arr['manager'] = $meta->manager;
|
||||||
|
|
||||||
|
// Add menu
|
||||||
|
$menu[$meta->menu[0]] = $meta->menu[1];
|
||||||
|
|
||||||
|
//Check in admin dbmodules
|
||||||
|
if (isset($extensionsInDB[$arr['name']])) {
|
||||||
|
$dbModule = $extensionsInDB[$arr['name']];
|
||||||
|
|
||||||
|
$arr['name'] = $dbModule->name;
|
||||||
|
$arr['label'] = $dbModule->label;
|
||||||
|
$arr['icon'] = $dbModule->icon;
|
||||||
|
$arr['menu'] = $dbModule->menu;
|
||||||
|
$arr['status'] = $dbModule->status;
|
||||||
|
$arr['user_levels'] = json_decode($dbModule->user_levels);
|
||||||
|
$arr['user_roles'] = empty($dbModule->user_roles)
|
||||||
|
? [] : json_decode($dbModule->user_roles);
|
||||||
|
$arr['user_roles_blacklist'] = empty($dbModule->user_roles_blacklist)
|
||||||
|
? [] : json_decode($dbModule->user_roles_blacklist);
|
||||||
|
} else {
|
||||||
|
$dbModule = new \Modules\Common\Model\Module();
|
||||||
|
$dbModule->menu = $arr['menu'];
|
||||||
|
$dbModule->name = $arr['name'];
|
||||||
|
$dbModule->label = $arr['label'];
|
||||||
|
$dbModule->icon = $arr['icon'];
|
||||||
|
$dbModule->mod_group = self::GROUP;
|
||||||
|
$dbModule->mod_order = $arr['order'];
|
||||||
|
$dbModule->status = "Enabled";
|
||||||
|
$dbModule->version = isset($meta->version)?$meta->version:"";
|
||||||
|
$dbModule->update_path = self::GROUP.">".$extensionDir;
|
||||||
|
$dbModule->user_levels = isset($meta->user_levels)?json_encode($meta->user_levels):"";
|
||||||
|
$dbModule->user_roles = isset($meta->user_roles)?json_encode($meta->user_roles):"";
|
||||||
|
|
||||||
|
$ok = $dbModule->Save();
|
||||||
|
if (!$ok) {
|
||||||
|
LogManager::getInstance()->error('Error saving module: '.$dbModule->name);
|
||||||
|
}
|
||||||
|
$needToInstall = $ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* @var \Classes\AbstractModuleManager */
|
||||||
|
$manager = $this->includeModuleManager($extensionDir, $arr);
|
||||||
|
if ($dbModule->status == 'Disabled') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($needToInstall) {
|
||||||
|
$manager->install();
|
||||||
|
}
|
||||||
|
|
||||||
|
$menuName = $arr['menu'];
|
||||||
|
if (!isset($extensions[$menuName])) {
|
||||||
|
$extensions[$menuName] = array();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$meta->headless) {
|
||||||
|
if ($arr['order'] == '0' || $arr['order'] == '') {
|
||||||
|
$extensions[$menuName]["Z".$currentLocation] = $arr;
|
||||||
|
$currentLocation++;
|
||||||
|
} else {
|
||||||
|
$extensions[$arr['menu']]["A".$arr['order']] = $arr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$initializer = $manager->getInitializer();
|
||||||
|
if ($initializer !== null) {
|
||||||
|
$initializer->setBaseService(BaseService::getInstance());
|
||||||
|
$initializer->init();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return [$menu, $extensions];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function includeModuleManager($name, $data)
|
||||||
|
{
|
||||||
|
include($this->getExtensionsPath().$name.'/'.$name.'.php');
|
||||||
|
$moduleManagerClass = $data['manager'];
|
||||||
|
/* @var \Classes\AbstractModuleManager $moduleManagerObj*/
|
||||||
|
$moduleManagerObj = new $moduleManagerClass();
|
||||||
|
$moduleManagerObj->setModuleObject($data);
|
||||||
|
$moduleManagerObj->setModuleType(self::GROUP);
|
||||||
|
$moduleManagerObj->setModulePath(CLIENT_PATH.'/'.self::GROUP.'/'.$name);
|
||||||
|
\Classes\BaseService::getInstance()->addModuleManager($moduleManagerObj);
|
||||||
|
return $moduleManagerObj;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
<?php
|
||||||
|
namespace Classes;
|
||||||
|
|
||||||
|
abstract class IceExtension extends AbstractModuleManager
|
||||||
|
{
|
||||||
|
public function initializeUserClasses()
|
||||||
|
{
|
||||||
|
// TODO: Implement initializeUserClasses() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initializeFieldMappings()
|
||||||
|
{
|
||||||
|
// TODO: Implement initializeFieldMappings() method.
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initializeDatabaseErrorMappings()
|
||||||
|
{
|
||||||
|
// TODO: Implement initializeDatabaseErrorMappings() method.
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -3,6 +3,7 @@
|
|||||||
namespace Classes;
|
namespace Classes;
|
||||||
|
|
||||||
use Firebase\JWT\JWT;
|
use Firebase\JWT\JWT;
|
||||||
|
use Firebase\JWT\SignatureInvalidException;
|
||||||
|
|
||||||
class JwtTokenService
|
class JwtTokenService
|
||||||
{
|
{
|
||||||
@@ -22,7 +23,11 @@ class JwtTokenService
|
|||||||
public function getBaseToken($jwtToken)
|
public function getBaseToken($jwtToken)
|
||||||
{
|
{
|
||||||
$secret = APP_SEC.APP_PASSWORD;
|
$secret = APP_SEC.APP_PASSWORD;
|
||||||
|
try {
|
||||||
$jwt = JWT::decode($jwtToken, $secret, array('HS256'));
|
$jwt = JWT::decode($jwtToken, $secret, array('HS256'));
|
||||||
|
} catch (SignatureInvalidException $e) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
if (time() > intval($jwt->expire)) {
|
if (time() > intval($jwt->expire)) {
|
||||||
return null;
|
return null;
|
||||||
|
|||||||
@@ -15,6 +15,8 @@ class MemcacheService
|
|||||||
public static $openConnections = array();
|
public static $openConnections = array();
|
||||||
private static $me = null;
|
private static $me = null;
|
||||||
|
|
||||||
|
protected $inMemoryStore = [];
|
||||||
|
|
||||||
private function __construct()
|
private function __construct()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -56,6 +58,15 @@ class MemcacheService
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function set($key, $value, $expiry = 3600)
|
public function set($key, $value, $expiry = 3600)
|
||||||
|
{
|
||||||
|
if (!$this->setInServer($key, $value, $expiry)) {
|
||||||
|
$this->inMemoryStore[$this->compressKey($key)] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setInServer($key, $value, $expiry = 3600)
|
||||||
{
|
{
|
||||||
if (!class_exists('\\Memcached')) {
|
if (!class_exists('\\Memcached')) {
|
||||||
return false;
|
return false;
|
||||||
@@ -74,6 +85,19 @@ class MemcacheService
|
|||||||
}
|
}
|
||||||
|
|
||||||
public function get($key)
|
public function get($key)
|
||||||
|
{
|
||||||
|
$data = $this->getFromServer($key);
|
||||||
|
if ($data) {
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
if (isset($this->inMemoryStore[$this->compressKey($key)])) {
|
||||||
|
return $this->inMemoryStore[$this->compressKey($key)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getFromServer($key)
|
||||||
{
|
{
|
||||||
if (!class_exists('\\Memcached')) {
|
if (!class_exists('\\Memcached')) {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -8,6 +8,8 @@
|
|||||||
|
|
||||||
namespace Classes\Migration;
|
namespace Classes\Migration;
|
||||||
|
|
||||||
|
use Utils\LogManager;
|
||||||
|
|
||||||
abstract class AbstractMigration
|
abstract class AbstractMigration
|
||||||
{
|
{
|
||||||
protected $file;
|
protected $file;
|
||||||
@@ -16,7 +18,7 @@ abstract class AbstractMigration
|
|||||||
|
|
||||||
protected $lastError;
|
protected $lastError;
|
||||||
|
|
||||||
public function __construct($file)
|
public function __construct($file = null)
|
||||||
{
|
{
|
||||||
$this->file = $file;
|
$this->file = $file;
|
||||||
}
|
}
|
||||||
@@ -50,6 +52,7 @@ abstract class AbstractMigration
|
|||||||
$ret = $this->db()->Execute($sql);
|
$ret = $this->db()->Execute($sql);
|
||||||
if (!$ret) {
|
if (!$ret) {
|
||||||
$this->lastError = $this->db()->ErrorMsg();
|
$this->lastError = $this->db()->ErrorMsg();
|
||||||
|
LogManager::getInstance()->error('Error in migration: '.$this->lastError);
|
||||||
}
|
}
|
||||||
return $ret;
|
return $ret;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ class ModuleAccess
|
|||||||
* @param $name
|
* @param $name
|
||||||
* @param $group
|
* @param $group
|
||||||
*/
|
*/
|
||||||
public function __construct($name, $group)
|
public function __construct($name, $group = 'extension')
|
||||||
{
|
{
|
||||||
$this->name = $name;
|
$this->name = $name;
|
||||||
$this->group = $group;
|
$this->group = $group;
|
||||||
|
|||||||
@@ -0,0 +1,98 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Created by PhpStorm.
|
||||||
|
* User: Thilina
|
||||||
|
* Date: 8/20/17
|
||||||
|
* Time: 9:47 AM
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Classes\ModuleBuilderV2;
|
||||||
|
|
||||||
|
use Classes\PermissionManager;
|
||||||
|
|
||||||
|
class ModuleBuilder
|
||||||
|
{
|
||||||
|
public $modules = array();
|
||||||
|
public $user = null;
|
||||||
|
|
||||||
|
function __construct()
|
||||||
|
{
|
||||||
|
$this->user = \Classes\BaseService::getInstance()->getCurrentUser();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param ModuleTab $module
|
||||||
|
*/
|
||||||
|
public function addModuleOrGroup($module)
|
||||||
|
{
|
||||||
|
$this->modules[] = $module;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTabHeadersHTML()
|
||||||
|
{
|
||||||
|
$html = "";
|
||||||
|
foreach ($this->modules as $module) {
|
||||||
|
$html .= $module->getHTML()."\r\n";
|
||||||
|
}
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getTabPagesHTML()
|
||||||
|
{
|
||||||
|
$html = "";
|
||||||
|
/* @var ModuleTab $module */
|
||||||
|
foreach ($this->modules as $module) {
|
||||||
|
if (get_class($module) === ModuleTab::class) {
|
||||||
|
$html .= $module->getPageHTML()."\r\n";
|
||||||
|
} else {
|
||||||
|
/* @var ModuleTab $mod */
|
||||||
|
foreach ($module->modules as $mod) {
|
||||||
|
$html .= $mod->getPageHTML()."\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getModJsHTML()
|
||||||
|
{
|
||||||
|
$moduleData = [
|
||||||
|
'user_level' => $this->user->user_level,
|
||||||
|
'permissions' => [
|
||||||
|
]
|
||||||
|
];
|
||||||
|
|
||||||
|
$html = "var modJsList = new Array();\r\n";
|
||||||
|
$activeModule = "";
|
||||||
|
/* @var ModuleTab $module */
|
||||||
|
foreach ($this->modules as $module) {
|
||||||
|
if (get_class($module) == ModuleTab::class) {
|
||||||
|
$html .= $module->getJSObjectCode()."\r\n";
|
||||||
|
|
||||||
|
$modelClass = $module->modelPath;
|
||||||
|
$moduleData['permissions'][$module->name] = PermissionManager::checkGeneralAccess(new $modelClass());
|
||||||
|
|
||||||
|
if ($module->isActive) {
|
||||||
|
$activeModule = $module->name;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* @var ModuleTab $mod */
|
||||||
|
foreach ($module->modules as $mod) {
|
||||||
|
$modelClass = $mod->modelPath;
|
||||||
|
$moduleData['permissions'][$mod->name] = PermissionManager::checkGeneralAccess(new $modelClass());
|
||||||
|
|
||||||
|
if ($module->isActive && $activeModule == "") {
|
||||||
|
$activeModule = $mod->name;
|
||||||
|
}
|
||||||
|
$html .= $mod->getJSObjectCode()."\r\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= "var modJs = modJsList['tab".$activeModule."'];\r\n";
|
||||||
|
|
||||||
|
$html = "var data = ".json_encode($moduleData).";\r\n".$html;
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,96 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Created by PhpStorm.
|
||||||
|
* User: Thilina
|
||||||
|
* Date: 8/20/17
|
||||||
|
* Time: 9:47 AM
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Classes\ModuleBuilderV2;
|
||||||
|
|
||||||
|
class ModuleTab
|
||||||
|
{
|
||||||
|
public $modelPath;
|
||||||
|
public $name;
|
||||||
|
public $class;
|
||||||
|
public $label;
|
||||||
|
public $adapterName;
|
||||||
|
public $filter;
|
||||||
|
public $orderBy;
|
||||||
|
public $isActive = false;
|
||||||
|
public $isInsideGroup = false;
|
||||||
|
public $options = array();
|
||||||
|
|
||||||
|
public function __construct(
|
||||||
|
$modelPath,
|
||||||
|
$name,
|
||||||
|
$class,
|
||||||
|
$label,
|
||||||
|
$adapterName,
|
||||||
|
$filter,
|
||||||
|
$orderBy,
|
||||||
|
$isActive = false,
|
||||||
|
$options = array()
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$this->modelPath = $modelPath;
|
||||||
|
$this->name = $name;
|
||||||
|
$this->class = $class;
|
||||||
|
$this->label = $label;
|
||||||
|
$this->adapterName = $adapterName;
|
||||||
|
$this->filter = $filter;
|
||||||
|
$this->orderBy = $orderBy;
|
||||||
|
$this->isActive = $isActive;
|
||||||
|
|
||||||
|
$this->options = array_merge(
|
||||||
|
$options, [
|
||||||
|
"setObjectTypeName" => "'{$this->name}'",
|
||||||
|
"setAccess" => "data.permissions.{$this->name} ? data.permissions.{$this->name} : {}",
|
||||||
|
"setDataPipe" => 'new IceDataPipe(modJsList.tab' . $this->name . ')',
|
||||||
|
"setRemoteTable" => true,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHTML()
|
||||||
|
{
|
||||||
|
$active = ($this->isActive)?"active":"";
|
||||||
|
if (!$this->isInsideGroup) {
|
||||||
|
return '<li class="' . $active . '"><a id="tab' . $this->name
|
||||||
|
. '" href="#tabPage' . $this->name . '">' . t($this->label) . '</a></li>';
|
||||||
|
} else {
|
||||||
|
return '<li class="' . $active . '"><a id="tab' . $this->name
|
||||||
|
. '" href="#tabPage' . $this->name . '">' . t($this->label) . '</a></li>';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getPageHTML()
|
||||||
|
{
|
||||||
|
$active = ($this->isActive)?" active":"";
|
||||||
|
$html = '<div class="tab-pane'.$active.'" id="tabPage'.$this->name.'">'.
|
||||||
|
'<div id="'.$this->name.'Table" class="reviewBlock" data-content="List" style="padding-left:5px;"></div>'.
|
||||||
|
'<div id="'.$this->name.'Form"></div>'.
|
||||||
|
'<div id="'.$this->name.'FilterForm"></div>'.
|
||||||
|
'</div>';
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getJSObjectCode()
|
||||||
|
{
|
||||||
|
$js = "";
|
||||||
|
if (empty($this->filter)) {
|
||||||
|
$js.= "modJsList['tab" . $this->name . "'] = new " .
|
||||||
|
$this->adapterName . "('" . $this->class . "','" . $this->name . "','','".$this->orderBy. "');\r\n";
|
||||||
|
} else {
|
||||||
|
$js.= "modJsList['tab" . $this->name . "'] = new " .
|
||||||
|
$this->adapterName . "('" . $this->class . "','" . $this->name . "'," .
|
||||||
|
$this->filter . ",'".$this->orderBy. "');\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach ($this->options as $key => $val) {
|
||||||
|
$js.= "modJsList['tab" . $this->name . "'].".$key."(".$val. ");\r\n";
|
||||||
|
}
|
||||||
|
|
||||||
|
return $js;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Created by PhpStorm.
|
||||||
|
* User: Thilina
|
||||||
|
* Date: 8/20/17
|
||||||
|
* Time: 9:48 AM
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace Classes\ModuleBuilderV2;
|
||||||
|
|
||||||
|
class ModuleTabGroup
|
||||||
|
{
|
||||||
|
public $name;
|
||||||
|
public $label;
|
||||||
|
public $isActive = false;
|
||||||
|
public $modules = array();
|
||||||
|
|
||||||
|
public function __construct($name, $label)
|
||||||
|
{
|
||||||
|
$this->name = $name;
|
||||||
|
$this->label = $label;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function addModuleTab($moduleTab)
|
||||||
|
{
|
||||||
|
if ($moduleTab->isActive) {
|
||||||
|
$this->isActive = true;
|
||||||
|
$moduleTab->isActive = false;
|
||||||
|
}
|
||||||
|
$moduleTab->isInsideGroup = true;
|
||||||
|
$this->modules[] = $moduleTab;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHTML()
|
||||||
|
{
|
||||||
|
$html = "";
|
||||||
|
$active = ($this->isActive)?" active":"";
|
||||||
|
|
||||||
|
$html.= '<li class="dropdown'.$active.'">'."\r\n".
|
||||||
|
'<a href="#" id="'.$this->name.
|
||||||
|
'" class="dropdown-toggle" data-toggle="dropdown" aria-controls="'.$this->name.
|
||||||
|
'-contents">'.$this->label.' <span class="caret"></span></a>'."\r\n".
|
||||||
|
'<ul class="dropdown-menu" role="menu" aria-labelledby="'.$this->name.'" id="'.$this->name.'-contents">';
|
||||||
|
|
||||||
|
foreach ($this->modules as $module) {
|
||||||
|
$html.= $module->getHTML();
|
||||||
|
}
|
||||||
|
|
||||||
|
$html .= "</ul></li>";
|
||||||
|
|
||||||
|
return $html;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -103,7 +103,7 @@ class PasswordManager
|
|||||||
return new IceResponse(IceResponse::ERROR, $error);
|
return new IceResponse(IceResponse::ERROR, $error);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen($password) > 20) {
|
if (strlen($password) > 30) {
|
||||||
$error = "Password too long";
|
$error = "Password too long";
|
||||||
|
|
||||||
return new IceResponse(IceResponse::ERROR, $error);
|
return new IceResponse(IceResponse::ERROR, $error);
|
||||||
|
|||||||
@@ -424,10 +424,8 @@ class RestEndPoint
|
|||||||
$token = $_GET['token'];
|
$token = $_GET['token'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (strlen($token) > 32) {
|
|
||||||
$tokenService = new JwtTokenService();
|
$tokenService = new JwtTokenService();
|
||||||
$token = $tokenService->getBaseToken($token);
|
$token = $tokenService->getBaseToken($token);
|
||||||
}
|
|
||||||
|
|
||||||
return $token;
|
return $token;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,85 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Classes;
|
||||||
|
|
||||||
|
use \RobRichards\XMLSecLibs\MoXMLSecurityKey;
|
||||||
|
use Utils\LogManager;
|
||||||
|
|
||||||
|
class SAMLManager
|
||||||
|
{
|
||||||
|
public function getSSOEmail($samlData, $relayState) {
|
||||||
|
// Service Providers Assertion Consumer Service (ACS) URL
|
||||||
|
$acsUrl = CLIENT_BASE_URL.'login.php';
|
||||||
|
$samlResponse = htmlspecialchars($samlData);
|
||||||
|
|
||||||
|
$samlResponse = base64_decode($samlResponse);
|
||||||
|
|
||||||
|
$document = new \DOMDocument();
|
||||||
|
$document->loadXML($samlResponse);
|
||||||
|
$samlResponseXml = $document->firstChild;
|
||||||
|
|
||||||
|
$doc = $document->documentElement;
|
||||||
|
$xpath = new \DOMXpath($document);
|
||||||
|
$xpath->registerNamespace('samlp', 'urn:oasis:names:tc:SAML:2.0:protocol');
|
||||||
|
$xpath->registerNamespace('saml', 'urn:oasis:names:tc:SAML:2.0:assertion');
|
||||||
|
|
||||||
|
$status = $xpath->query('/samlp:Response/samlp:Status/samlp:StatusCode', $doc);
|
||||||
|
$statusString = $status->item(0)->getAttribute('Value');
|
||||||
|
|
||||||
|
|
||||||
|
$statusArray = explode(':',$statusString);
|
||||||
|
if(array_key_exists(7, $statusArray)){
|
||||||
|
$status = $statusArray[7];
|
||||||
|
}
|
||||||
|
|
||||||
|
if ('Success' !== $status) {
|
||||||
|
$StatusMessage = $xpath->query('/samlp:Response/samlp:Status/samlp:StatusMessage', $doc)->item(0);
|
||||||
|
LogManager::getInstance()->error('SAML login failed: status = '. $status);
|
||||||
|
if(!empty($StatusMessage)) {
|
||||||
|
$StatusMessage = $StatusMessage->nodeValue;
|
||||||
|
LogManager::getInstance()->error('SAML login failed: status message = '. $StatusMessage);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$x509cert = SettingsManager::getInstance()->getSetting('SAML: X.509 Certificate');
|
||||||
|
|
||||||
|
$samlResponse = new \SAML2_Response($samlResponseXml);
|
||||||
|
$responseSignatureData = $samlResponse->getSignatureData();
|
||||||
|
$assertionSignatureData = current($samlResponse->getAssertions())->getSignatureData();
|
||||||
|
|
||||||
|
$certFingerPrint = MoXMLSecurityKey::getRawThumbprint($x509cert);
|
||||||
|
$certFingerPrint = preg_replace('/\s+/', '', $certFingerPrint);
|
||||||
|
$validSignature = false;
|
||||||
|
if(!empty($responseSignatureData)) {
|
||||||
|
$validSignature = \Utilities::processResponse($acsUrl, $certFingerPrint, $responseSignatureData, $samlResponse, 0, $relayState);
|
||||||
|
LogManager::getInstance()->error('SAML: response signature validity :'.$validSignature);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!empty($assertionSignatureData)) {
|
||||||
|
$validSignature = \Utilities::processResponse($acsUrl, $certFingerPrint, $assertionSignatureData, $samlResponse, 0, $relayState);
|
||||||
|
LogManager::getInstance()->error('SAML: response signature validity :'.$validSignature);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!$validSignature) {
|
||||||
|
LogManager::getInstance()->error('Invalid response or assertion signature');
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$issuer = current($samlResponse->getAssertions())->getIssuer();
|
||||||
|
$assertion = current($samlResponse->getAssertions());
|
||||||
|
$audiences = $assertion->getValidAudiences();
|
||||||
|
$expectedIssuer = SettingsManager::getInstance()->getSetting('SAML: IDP Issuer');
|
||||||
|
if ($issuer !== $expectedIssuer) {
|
||||||
|
LogManager::getInstance()->error('SAML Invalid Issuer :'.$issuer.' expected :'.$expectedIssuer);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
$ssoEmail = current(current($samlResponse->getAssertions())->getNameId());
|
||||||
|
if (!$ssoEmail) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ssoEmail;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,15 +1,22 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Classes;
|
namespace Classes;
|
||||||
|
|
||||||
|
use Classes\Crypt\AesCtr;
|
||||||
use Model\Setting;
|
use Model\Setting;
|
||||||
|
|
||||||
class SettingsManager
|
class SettingsManager
|
||||||
{
|
{
|
||||||
|
|
||||||
|
const ENCRYPTED_PREFIX = 'iceenc_';
|
||||||
|
|
||||||
private static $me = null;
|
private static $me = null;
|
||||||
|
|
||||||
|
private $encryptedSettings = [];
|
||||||
|
|
||||||
private function __construct()
|
private function __construct()
|
||||||
{
|
{
|
||||||
|
$this->addEncryptedSetting('SAML: X.509 Certificate');
|
||||||
|
$this->addEncryptedSetting('LDAP: Manager Password');
|
||||||
}
|
}
|
||||||
|
|
||||||
public static function getInstance()
|
public static function getInstance()
|
||||||
@@ -21,9 +28,62 @@ class SettingsManager
|
|||||||
return self::$me;
|
return self::$me;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function addEncryptedSetting($name) {
|
||||||
|
if (!$this->isEncryptedSetting($name)) {
|
||||||
|
$this->encryptedSettings[] = $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isEncryptedSetting($name) {
|
||||||
|
return in_array($name, $this->encryptedSettings);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getInstanceKey() {
|
||||||
|
$settings = new Setting();
|
||||||
|
$settings->Load("name = ?", array("Instance: Key"));
|
||||||
|
if ($settings->name != "Instance: Key") {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return $settings->value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function encrypt($value) {
|
||||||
|
$id = BaseService::getInstance()->getInstanceId();
|
||||||
|
$key = $this->getInstanceKey();
|
||||||
|
return AesCtr::encrypt($value, $id.$key, 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function encryptSetting($name, $value) {
|
||||||
|
// check the existence of prefix and encrypt only if need to avoid double encryption
|
||||||
|
if (
|
||||||
|
$this->isEncryptedSetting($name)
|
||||||
|
&& substr($value, 0, strlen(self::ENCRYPTED_PREFIX)) !== self::ENCRYPTED_PREFIX
|
||||||
|
) {
|
||||||
|
$value = self::ENCRYPTED_PREFIX.$this->encrypt($value);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function decrypt($value) {
|
||||||
|
$id = BaseService::getInstance()->getInstanceId();
|
||||||
|
$key = $this->getInstanceKey();
|
||||||
|
return AesCtr::decrypt($value, $id.$key, 256);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function decryptSetting($name, $value) {
|
||||||
|
if (
|
||||||
|
$this->isEncryptedSetting($name)
|
||||||
|
&& substr($value, 0, strlen(self::ENCRYPTED_PREFIX)) === self::ENCRYPTED_PREFIX
|
||||||
|
) {
|
||||||
|
$value = $this->decrypt(substr($value, strlen(self::ENCRYPTED_PREFIX)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
|
}
|
||||||
|
|
||||||
public function getSetting($name)
|
public function getSetting($name)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (class_exists("\\Classes\\ProVersion")) {
|
if (class_exists("\\Classes\\ProVersion")) {
|
||||||
$pro = new ProVersion();
|
$pro = new ProVersion();
|
||||||
$val = $pro->getSetting($name);
|
$val = $pro->getSetting($name);
|
||||||
@@ -34,20 +94,28 @@ class SettingsManager
|
|||||||
|
|
||||||
$setting = new Setting();
|
$setting = new Setting();
|
||||||
$setting->Load("name = ?", array($name));
|
$setting->Load("name = ?", array($name));
|
||||||
|
$value = null;
|
||||||
if ($setting->name == $name) {
|
if ($setting->name == $name) {
|
||||||
return $setting->value;
|
$value = $setting->value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (null === $value) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return $this->decryptSetting($name, $value);
|
||||||
|
}
|
||||||
|
|
||||||
public function setSetting($name, $value)
|
public function setSetting($name, $value)
|
||||||
{
|
{
|
||||||
$setting = new Setting();
|
$setting = new Setting();
|
||||||
$setting->Load("name = ?", array($name));
|
$setting->Load("name = ?", array($name));
|
||||||
if ($setting->name == $name) {
|
if ($setting->name !== $name) {
|
||||||
$setting->value = $value;
|
return;
|
||||||
$setting->Save();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$setting->value = $this->encryptSetting($name, $value);
|
||||||
|
$setting->Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
public function addSetting($name, $value)
|
public function addSetting($name, $value)
|
||||||
@@ -55,14 +123,21 @@ class SettingsManager
|
|||||||
$setting = new Setting();
|
$setting = new Setting();
|
||||||
$setting->Load("name = ?", array($name));
|
$setting->Load("name = ?", array($name));
|
||||||
if ($setting->name == $name) {
|
if ($setting->name == $name) {
|
||||||
$setting->value = $value;
|
$setting->value = $this->encryptSetting($name, $value);
|
||||||
$setting->Save();
|
$setting->Save();
|
||||||
} else {
|
} else {
|
||||||
$setting->name = $name;
|
$setting->name = $name;
|
||||||
$setting->value = $value;
|
$setting->value = $this->encryptSetting($name, $value);
|
||||||
$setting->description = $value;
|
$setting->description = '';
|
||||||
$setting->meta = '';
|
$setting->meta = '';
|
||||||
$setting->Save();
|
$setting->Save();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDeprecatedSettings() {
|
||||||
|
return [
|
||||||
|
'Attendance: Work Week Start Day',
|
||||||
|
'Attendance: Overtime Calculation Class'
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -5,9 +5,14 @@ use Classes\IceResponse;
|
|||||||
use Classes\ModuleAccess;
|
use Classes\ModuleAccess;
|
||||||
use Employees\Common\Model\Employee;
|
use Employees\Common\Model\Employee;
|
||||||
use Model\BaseModel;
|
use Model\BaseModel;
|
||||||
|
use Model\CustomFieldTrait;
|
||||||
|
|
||||||
class CompanyStructure extends BaseModel
|
class CompanyStructure extends BaseModel
|
||||||
{
|
{
|
||||||
|
use CustomFieldTrait;
|
||||||
|
public $objectName = 'Company Structures';
|
||||||
|
protected $allowCustomFields = true;
|
||||||
|
|
||||||
public $table = 'CompanyStructures';
|
public $table = 'CompanyStructures';
|
||||||
|
|
||||||
public function getAdminAccess()
|
public function getAdminAccess()
|
||||||
|
|||||||
@@ -0,0 +1,25 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace CustomField\Admin\Api;
|
||||||
|
|
||||||
|
use Classes\AbstractModuleManager;
|
||||||
|
|
||||||
|
class CustomFieldAdminManager extends AbstractModuleManager
|
||||||
|
{
|
||||||
|
public function initializeUserClasses()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initializeFieldMappings()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function initializeDatabaseErrorMappings()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public function setupModuleClassDefinitions()
|
||||||
|
{
|
||||||
|
$this->addModelClass('CustomField');
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -45,10 +45,11 @@ class DocumentTaskCreator implements TaskCreator
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = "select count(id) as c from EmployeeDocuments where employee = ? and valid_until < ?";
|
$query = "select count(id) as c from EmployeeDocuments where employee = ? and valid_until < ? and visible_to = ?";
|
||||||
|
|
||||||
$user->DB()->SetFetchMode(ADODB_FETCH_ASSOC);
|
$user->DB()->SetFetchMode(ADODB_FETCH_ASSOC);
|
||||||
$rs = $user->DB()->Execute($query, [$employee->id, date('Y-m-d')]);
|
// TODO - sending notifications only for Owner documents, this need to be extended later
|
||||||
|
$rs = $user->DB()->Execute($query, [$employee->id, date('Y-m-d'), 'Owner']);
|
||||||
$count = $rs->fields['c'];
|
$count = $rs->fields['c'];
|
||||||
|
|
||||||
return $count;
|
return $count;
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
<?php
|
<?php
|
||||||
namespace Documents\Common\Model;
|
namespace Documents\Common\Model;
|
||||||
|
|
||||||
|
use Classes\BaseService;
|
||||||
use Classes\ModuleAccess;
|
use Classes\ModuleAccess;
|
||||||
use Model\BaseModel;
|
use Model\BaseModel;
|
||||||
|
|
||||||
@@ -26,4 +27,23 @@ class Document extends BaseModel
|
|||||||
new ModuleAccess('documents', 'user'),
|
new ModuleAccess('documents', 'user'),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function fieldValueMethods()
|
||||||
|
{
|
||||||
|
return ['getDocumentTypesForUser'];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getDocumentTypesForUser()
|
||||||
|
{
|
||||||
|
$documents = new Document();
|
||||||
|
if (BaseService::getInstance()->currentUser->user_level === 'Employee'
|
||||||
|
|| BaseService::getInstance()->currentUser->user_level === 'Restricted Employee'
|
||||||
|
) {
|
||||||
|
$documents = $documents->Find('share_with_employee = ?', ['Yes']);
|
||||||
|
} else {
|
||||||
|
$documents = $documents->Find('1 = 1');
|
||||||
|
}
|
||||||
|
|
||||||
|
return $documents;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -8,14 +8,65 @@
|
|||||||
|
|
||||||
namespace Documents\Common\Model;
|
namespace Documents\Common\Model;
|
||||||
|
|
||||||
|
use Classes\BaseService;
|
||||||
use Classes\IceResponse;
|
use Classes\IceResponse;
|
||||||
use Classes\ModuleAccess;
|
use Classes\ModuleAccess;
|
||||||
|
use Employees\Common\Model\Employee;
|
||||||
use Model\BaseModel;
|
use Model\BaseModel;
|
||||||
|
|
||||||
class EmployeeDocument extends BaseModel
|
class EmployeeDocument extends BaseModel
|
||||||
{
|
{
|
||||||
public $table = 'EmployeeDocuments';
|
public $table = 'EmployeeDocuments';
|
||||||
|
|
||||||
|
private function getHiddenDocumentTypeIds()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
// @codingStandardsIgnoreStart
|
||||||
|
public function Find($whereOrderBy, $bindarr = false, $cache = false, $pkeysArr = false, $extra = array())
|
||||||
|
{
|
||||||
|
$find = '';
|
||||||
|
$user = BaseService::getInstance()->getCurrentUser();
|
||||||
|
|
||||||
|
if ($user->user_level == 'Employee') {
|
||||||
|
$find = ' visible_to = \'Owner\' AND ';
|
||||||
|
$document = new Document();
|
||||||
|
$hiddenDocumentTypes = $document->Find(
|
||||||
|
"share_with_employee = ?",
|
||||||
|
['No']
|
||||||
|
);
|
||||||
|
|
||||||
|
$hiddenTypeIds = [];
|
||||||
|
foreach ($hiddenDocumentTypes as $hiddenDocumentType) {
|
||||||
|
$hiddenTypeIds[] = $hiddenDocumentType->id;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(count($hiddenTypeIds) > 0) {
|
||||||
|
$find .= ' document NOT IN (\''.implode('\',\'', $hiddenTypeIds).'\') AND ';
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::Find($find.$whereOrderBy, $bindarr, $pkeysArr, $extra);
|
||||||
|
|
||||||
|
} else if ($user->user_level == 'Manager') {
|
||||||
|
// Original $whereOrderBy already contain employee selection
|
||||||
|
// So here if isSubOrdinates is true if the query coming from Employee -> Document Management
|
||||||
|
// In that case we need to show documents from sub ordinates
|
||||||
|
// These docs can can be owner and manager both
|
||||||
|
if (isset($isSubOrdinates) && $isSubOrdinates) {
|
||||||
|
$find .= ' visible_to in (\'Owner\', \'Manager\') AND ';
|
||||||
|
} else {
|
||||||
|
// Here we are showing the documents for the manager
|
||||||
|
// If someone upload a document for this manager and make it visible to manager,
|
||||||
|
// that means only the manager of this manager can see the document
|
||||||
|
// So it should not be visible to this manager
|
||||||
|
$find .= ' visible_to in (\'Owner\') AND ';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return parent::Find($find.$whereOrderBy, $bindarr, $pkeysArr, $extra);
|
||||||
|
}
|
||||||
|
// @codingStandardsIgnoreEnd
|
||||||
|
|
||||||
public function getAdminAccess()
|
public function getAdminAccess()
|
||||||
{
|
{
|
||||||
return array("get","element","save","delete");
|
return array("get","element","save","delete");
|
||||||
@@ -26,6 +77,8 @@ class EmployeeDocument extends BaseModel
|
|||||||
return array("get","element","save","delete");
|
return array("get","element","save","delete");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function getUserAccess()
|
public function getUserAccess()
|
||||||
{
|
{
|
||||||
return array("get");
|
return array("get");
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ use Classes\ModuleAccess;
|
|||||||
use Company\Common\Model\CompanyStructure;
|
use Company\Common\Model\CompanyStructure;
|
||||||
use Metadata\Common\Model\Country;
|
use Metadata\Common\Model\Country;
|
||||||
use Model\BaseModel;
|
use Model\BaseModel;
|
||||||
|
use Model\CustomFieldTrait;
|
||||||
|
|
||||||
class Employee extends BaseModel
|
class Employee extends BaseModel
|
||||||
{
|
{
|
||||||
@@ -90,6 +91,11 @@ class Employee extends BaseModel
|
|||||||
$this->oldObj = BaseService::getInstance()->getElement('Employee', $obj->id, $mapping, true);
|
$this->oldObj = BaseService::getInstance()->getElement('Employee', $obj->id, $mapping, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isCustomFieldsEnabled()
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
private function saveHistory($obj)
|
private function saveHistory($obj)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ use Classes\BaseService;
|
|||||||
use Classes\IceResponse;
|
use Classes\IceResponse;
|
||||||
use Classes\ModuleAccess;
|
use Classes\ModuleAccess;
|
||||||
use Model\BaseModel;
|
use Model\BaseModel;
|
||||||
|
use Utils\LogManager;
|
||||||
|
|
||||||
class CustomField extends BaseModel
|
class CustomField extends BaseModel
|
||||||
{
|
{
|
||||||
@@ -58,6 +59,22 @@ class CustomField extends BaseModel
|
|||||||
return new IceResponse(IceResponse::SUCCESS, "");
|
return new IceResponse(IceResponse::SUCCESS, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param CustomField $obj
|
||||||
|
*/
|
||||||
|
public function executePostDeleteActions($obj)
|
||||||
|
{
|
||||||
|
$ret = $this->DB()->Execute(
|
||||||
|
'DELETE FROM CustomFieldValues where type = ? and name = ?',
|
||||||
|
[$obj->type, $obj->name]
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!$ret) {
|
||||||
|
$this->lastError = $this->db()->ErrorMsg();
|
||||||
|
LogManager::getInstance()->error('Error deleting custom field values: '.$this->DB()->ErrorMsg());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public function getModuleAccess()
|
public function getModuleAccess()
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -11,6 +11,8 @@ use Utils\LogManager;
|
|||||||
|
|
||||||
class BaseModel extends \ADOdb_Active_Record
|
class BaseModel extends \ADOdb_Active_Record
|
||||||
{
|
{
|
||||||
|
public $objectName = null;
|
||||||
|
protected $allowCustomFields = false;
|
||||||
|
|
||||||
public $keysToIgnore = array(
|
public $keysToIgnore = array(
|
||||||
"_table",
|
"_table",
|
||||||
@@ -195,6 +197,16 @@ class BaseModel extends \ADOdb_Active_Record
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function executePostDeleteActions($obj)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* If null is returned the object wont be included in the response
|
||||||
|
*
|
||||||
|
* @param $obj
|
||||||
|
* @return mixed
|
||||||
|
*/
|
||||||
public function postProcessGetData($obj)
|
public function postProcessGetData($obj)
|
||||||
{
|
{
|
||||||
return $obj;
|
return $obj;
|
||||||
@@ -340,4 +352,14 @@ class BaseModel extends \ADOdb_Active_Record
|
|||||||
return $ok;
|
return $ok;
|
||||||
}
|
}
|
||||||
// @codingStandardsIgnoreEnd
|
// @codingStandardsIgnoreEnd
|
||||||
|
|
||||||
|
public function getObjectName()
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isCustomFieldsEnabled()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
namespace Model;
|
||||||
|
|
||||||
|
trait CustomFieldTrait
|
||||||
|
{
|
||||||
|
public function getObjectName()
|
||||||
|
{
|
||||||
|
return $this->objectName;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function isCustomFieldsEnabled()
|
||||||
|
{
|
||||||
|
return $this->allowCustomFields;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,6 +12,7 @@ use Classes\BaseService;
|
|||||||
use Classes\IceResponse;
|
use Classes\IceResponse;
|
||||||
use Classes\ModuleAccess;
|
use Classes\ModuleAccess;
|
||||||
use Classes\RestApiManager;
|
use Classes\RestApiManager;
|
||||||
|
use Classes\SettingsManager;
|
||||||
use Users\Common\Model\User;
|
use Users\Common\Model\User;
|
||||||
|
|
||||||
class Setting extends BaseModel
|
class Setting extends BaseModel
|
||||||
@@ -74,6 +75,12 @@ class Setting extends BaseModel
|
|||||||
return new IceResponse(IceResponse::SUCCESS, "");
|
return new IceResponse(IceResponse::SUCCESS, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function executePreSaveActions($obj)
|
||||||
|
{
|
||||||
|
$obj->value = SettingsManager::getInstance()->encryptSetting($obj->name, $obj->value);
|
||||||
|
return new IceResponse(IceResponse::SUCCESS, $obj);
|
||||||
|
}
|
||||||
|
|
||||||
public function executePreUpdateActions($obj)
|
public function executePreUpdateActions($obj)
|
||||||
{
|
{
|
||||||
return $this->executePreSaveActions($obj);
|
return $this->executePreSaveActions($obj);
|
||||||
@@ -87,5 +94,17 @@ class Setting extends BaseModel
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function postProcessGetData($obj)
|
||||||
|
{
|
||||||
|
if (in_array($obj->name, SettingsManager::getInstance()->getDeprecatedSettings())) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (strlen($obj->value) > 30) {
|
||||||
|
$obj->value = substr($obj->value,0, 30).'...';
|
||||||
|
}
|
||||||
|
return $obj;
|
||||||
|
}
|
||||||
|
|
||||||
public $table = 'Settings';
|
public $table = 'Settings';
|
||||||
}
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
namespace Reports\Admin\Reports;
|
namespace Reports\Admin\Reports;
|
||||||
|
|
||||||
use Attendance\Common\Model\Attendance;
|
use Attendance\Common\Model\Attendance;
|
||||||
|
use Company\Common\Model\CompanyStructure;
|
||||||
use Employees\Common\Model\Employee;
|
use Employees\Common\Model\Employee;
|
||||||
use Reports\Admin\Api\ClassBasedReportBuilder;
|
use Reports\Admin\Api\ClassBasedReportBuilder;
|
||||||
use Reports\Admin\Api\ReportBuilderInterface;
|
use Reports\Admin\Api\ReportBuilderInterface;
|
||||||
@@ -16,6 +17,18 @@ class EmployeeTimeTrackReport extends ClassBasedReportBuilder implements ReportB
|
|||||||
LogManager::getInstance()->info(json_encode($report));
|
LogManager::getInstance()->info(json_encode($report));
|
||||||
LogManager::getInstance()->info(json_encode($req));
|
LogManager::getInstance()->info(json_encode($req));
|
||||||
|
|
||||||
|
if (
|
||||||
|
empty($req['period'])
|
||||||
|
&& (
|
||||||
|
empty($req['date_start'])
|
||||||
|
|| 'NULL' === $req['date_start']
|
||||||
|
|| empty($req['date_end'])
|
||||||
|
|| 'NULL' === $req['date_end']
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
$req['period'] = 'Current Month';
|
||||||
|
}
|
||||||
|
|
||||||
$employeeTimeEntry = new EmployeeTimeEntry();
|
$employeeTimeEntry = new EmployeeTimeEntry();
|
||||||
|
|
||||||
$timeEntryList = $employeeTimeEntry->Find(
|
$timeEntryList = $employeeTimeEntry->Find(
|
||||||
@@ -38,6 +51,8 @@ class EmployeeTimeTrackReport extends ClassBasedReportBuilder implements ReportB
|
|||||||
//$minutes = (int)($seconds/60);
|
//$minutes = (int)($seconds/60);
|
||||||
//Find Attendance Entries
|
//Find Attendance Entries
|
||||||
|
|
||||||
|
$req = $this->setRequestDatesBasedOnThePeriod($req);
|
||||||
|
|
||||||
$attendance = new Attendance();
|
$attendance = new Attendance();
|
||||||
$atteandanceList = $attendance->Find(
|
$atteandanceList = $attendance->Find(
|
||||||
"employee = ? and date(in_time) >= ? and date(out_time) <= ? and in_time < out_time",
|
"employee = ? and date(in_time) >= ? and date(out_time) <= ? and in_time < out_time",
|
||||||
@@ -66,21 +81,34 @@ class EmployeeTimeTrackReport extends ClassBasedReportBuilder implements ReportB
|
|||||||
$employeeObject = new Employee();
|
$employeeObject = new Employee();
|
||||||
$employeeObject->Load("id = ?", array($req['employee']));
|
$employeeObject->Load("id = ?", array($req['employee']));
|
||||||
|
|
||||||
|
$company = new CompanyStructure();
|
||||||
|
$company->Load('id = ?', [$employeeObject->department]);
|
||||||
|
|
||||||
$reportData = array();
|
$reportData = [];
|
||||||
//$reportData[] = array($employeeObject->first_name." ".$employeeObject->last_name,"","","","");
|
$reportData[] = ["Date","First Punch-In Time","Last Punch-Out Time","Time in Attendance (Hours)","Time in Time-sheets (Hours)"];
|
||||||
$reportData[] = array("Date","First Punch-In Time","Last Punch-Out Time","Time in Office","Time in Timesheets");
|
$reportData[] = ["Employee:",$employeeObject->first_name." ".$employeeObject->last_name,"","",""];
|
||||||
|
$reportData[] = ["Department:",$company->title,"","",""];
|
||||||
|
$reportData[] = ["Total Days:","","","",""];
|
||||||
|
|
||||||
|
|
||||||
//Iterate date range
|
//Iterate date range
|
||||||
|
|
||||||
$interval = \DateInterval::createFromDateString('1 day');
|
$interval = \DateInterval::createFromDateString('1 day');
|
||||||
$period = new \DatePeriod(new \DateTime($req['date_start']), $interval, new \DateTime($req['date_end']));
|
$period = new \DatePeriod(new \DateTime($req['date_start']), $interval, (new \DateTime($req['date_end']))->modify('+1 day'));
|
||||||
|
|
||||||
|
$totalHoursOffice = 0;
|
||||||
|
$totalHoursTimeSheets = 0;
|
||||||
|
$totalDaysForThePeriod = 0;
|
||||||
|
|
||||||
foreach ($period as $dt) {
|
foreach ($period as $dt) {
|
||||||
$dataRow = array();
|
$dataRow = array();
|
||||||
$key = $dt->format("Y-m-d");
|
$key = $dt->format("Y-m-d");
|
||||||
|
|
||||||
|
if (!isset($firstTimeInArray[$key])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
$totalDaysForThePeriod++;
|
||||||
$dataRow[] = $key;
|
$dataRow[] = $key;
|
||||||
|
|
||||||
if (isset($firstTimeInArray[$key])) {
|
if (isset($firstTimeInArray[$key])) {
|
||||||
@@ -107,8 +135,44 @@ class EmployeeTimeTrackReport extends ClassBasedReportBuilder implements ReportB
|
|||||||
$dataRow[] = 0;
|
$dataRow[] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$totalHoursOffice += $dataRow[3];
|
||||||
|
$totalHoursTimeSheets += $dataRow[4];
|
||||||
|
|
||||||
|
$dataRow[3] = number_format($dataRow[3], 2, '.', '');
|
||||||
|
$dataRow[4] = number_format($dataRow[4], 2, '.', '');
|
||||||
|
|
||||||
$reportData[] = $dataRow;
|
$reportData[] = $dataRow;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$reportData[3][1] = $totalDaysForThePeriod;
|
||||||
|
|
||||||
|
$totalHoursOffice = number_format($totalHoursOffice, 2, '.', '');
|
||||||
|
$totalHoursTimeSheets = number_format($totalHoursTimeSheets, 2, '.', '');
|
||||||
|
|
||||||
|
$reportData[] = ["Total","","",$totalHoursOffice,$totalHoursTimeSheets];
|
||||||
|
|
||||||
return $reportData;
|
return $reportData;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function setRequestDatesBasedOnThePeriod($req) {
|
||||||
|
if (empty($req['period'])) {
|
||||||
|
return $req;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($req['period'] === 'Current Month') {
|
||||||
|
$req['date_start'] = date('Y-m-01', strtotime('now'));
|
||||||
|
$req['date_end'] = date('Y-m-d', strtotime('now'));
|
||||||
|
} else if ($req['period'] === 'Last Month') {
|
||||||
|
$req['date_start'] = date('Y-m-d', strtotime('first day of last month'));
|
||||||
|
$req['date_end'] = date('Y-m-d', strtotime('last day of last month'));
|
||||||
|
} else if ($req['period'] === 'Last Week') {
|
||||||
|
$req['date_start'] = date("Y-m-d", strtotime("-7 days"));
|
||||||
|
$req['date_end'] = date('Y-m-d', strtotime('now'));
|
||||||
|
} else if ($req['period'] === 'Last 2 Weeks') {
|
||||||
|
$req['date_start'] = date("Y-m-d", strtotime("-14 days"));
|
||||||
|
$req['date_end'] = date('Y-m-d', strtotime('now'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return $req;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -24,10 +24,9 @@ class StaffDirectory extends Employee
|
|||||||
foreach ($res as $entry) {
|
foreach ($res as $entry) {
|
||||||
$emp = new BaseModel();
|
$emp = new BaseModel();
|
||||||
$emp->id = $entry->id;
|
$emp->id = $entry->id;
|
||||||
$emp = FileService::getInstance()->updateProfileImage($emp);
|
|
||||||
//$emp->image = str_replace("_img_",$emp->image,$img);
|
|
||||||
$emp->first_name = $entry->first_name;
|
$emp->first_name = $entry->first_name;
|
||||||
$emp->last_name = $entry->last_name;
|
$emp->last_name = $entry->last_name;
|
||||||
|
$emp = FileService::getInstance()->updateSmallProfileImage($emp);
|
||||||
$emp->job_title = $entry->job_title;
|
$emp->job_title = $entry->job_title;
|
||||||
$emp->department = $entry->department;
|
$emp->department = $entry->department;
|
||||||
$emp->work_phone = $entry->work_phone;
|
$emp->work_phone = $entry->work_phone;
|
||||||
@@ -41,6 +40,11 @@ class StaffDirectory extends Employee
|
|||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function isCustomFieldsEnabled()
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// @codingStandardsIgnoreStart
|
// @codingStandardsIgnoreStart
|
||||||
public function Insert()
|
public function Insert()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -11,10 +11,15 @@ namespace Travel\Common\Model;
|
|||||||
use Classes\ModuleAccess;
|
use Classes\ModuleAccess;
|
||||||
use Classes\SettingsManager;
|
use Classes\SettingsManager;
|
||||||
use Model\ApproveModel;
|
use Model\ApproveModel;
|
||||||
|
use Model\CustomFieldTrait;
|
||||||
|
|
||||||
class EmployeeTravelRecord extends ApproveModel
|
class EmployeeTravelRecord extends ApproveModel
|
||||||
{
|
{
|
||||||
|
use CustomFieldTrait;
|
||||||
|
|
||||||
public $table = 'EmployeeTravelRecords';
|
public $table = 'EmployeeTravelRecords';
|
||||||
|
public $objectName = 'Travel Request';
|
||||||
|
protected $allowCustomFields = true;
|
||||||
|
|
||||||
public $notificationModuleName = "Travel Management";
|
public $notificationModuleName = "Travel Management";
|
||||||
public $notificationUnitName = "TravelRequest";
|
public $notificationUnitName = "TravelRequest";
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ namespace Travel\Common\Model;
|
|||||||
|
|
||||||
class EmployeeTravelRecordApproval extends EmployeeTravelRecord
|
class EmployeeTravelRecordApproval extends EmployeeTravelRecord
|
||||||
{
|
{
|
||||||
|
protected $allowCustomFields = false;
|
||||||
|
|
||||||
// @codingStandardsIgnoreStart
|
// @codingStandardsIgnoreStart
|
||||||
public function Find($whereOrderBy, $bindarr = false, $cache = false, $pkeysArr = false, $extra = array())
|
public function Find($whereOrderBy, $bindarr = false, $cache = false, $pkeysArr = false, $extra = array())
|
||||||
|
|||||||
@@ -243,6 +243,7 @@ gulp.task('admin-js', (done) => {
|
|||||||
const files = [
|
const files = [
|
||||||
'attendance',
|
'attendance',
|
||||||
'company_structure',
|
'company_structure',
|
||||||
|
'custom_fields',
|
||||||
'clients',
|
'clients',
|
||||||
'charts',
|
'charts',
|
||||||
'dashboard',
|
'dashboard',
|
||||||
|
|||||||
@@ -3,13 +3,21 @@
|
|||||||
Developer: Thilina Hasantha (http://lk.linkedin.com/in/thilinah | https://github.com/thilinah)
|
Developer: Thilina Hasantha (http://lk.linkedin.com/in/thilinah | https://github.com/thilinah)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import AdapterBase from '../../../api/AdapterBase';
|
import ReactModalAdapterBase from '../../../api/ReactModalAdapterBase';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ClientAdapter
|
* ClientAdapter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class ClientAdapter extends AdapterBase {
|
class ClientAdapter extends ReactModalAdapterBase {
|
||||||
|
constructor(endPoint, tab, filter, orderBy) {
|
||||||
|
super(endPoint, tab, filter, orderBy);
|
||||||
|
this.fieldNameMap = {};
|
||||||
|
this.hiddenFields = {};
|
||||||
|
this.tableFields = {};
|
||||||
|
this.formOnlyFields = {};
|
||||||
|
}
|
||||||
|
|
||||||
getDataMapping() {
|
getDataMapping() {
|
||||||
return [
|
return [
|
||||||
'id',
|
'id',
|
||||||
@@ -30,6 +38,32 @@ class ClientAdapter extends AdapterBase {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
getTableColumns() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: 'Name',
|
||||||
|
dataIndex: 'name',
|
||||||
|
sorter: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Details',
|
||||||
|
dataIndex: 'details',
|
||||||
|
sorter: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Address',
|
||||||
|
dataIndex: 'address',
|
||||||
|
sorter: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Contact Number',
|
||||||
|
dataIndex: 'contact_number',
|
||||||
|
sorter: true,
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
getFormFields() {
|
getFormFields() {
|
||||||
if (this.showSave) {
|
if (this.showSave) {
|
||||||
return [
|
return [
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { CompanyStructureAdapter, CompanyGraphAdapter } from './lib';
|
import { CompanyStructureAdapter, CompanyGraphAdapter } from './lib';
|
||||||
import IceDataPipe from "../../../api/IceDataPipe";
|
import IceDataPipe from "../../../api/IceDataPipe";
|
||||||
import CustomFieldAdapter from "../../../api/ReactCustomFieldAdapter";
|
|
||||||
|
|
||||||
|
|
||||||
function init(data) {
|
function init(data) {
|
||||||
@@ -9,6 +8,7 @@ function init(data) {
|
|||||||
modJsList.tabCompanyStructure.setObjectTypeName('Company Structure');
|
modJsList.tabCompanyStructure.setObjectTypeName('Company Structure');
|
||||||
modJsList.tabCompanyStructure.setDataPipe(new IceDataPipe(modJsList.tabCompanyStructure));
|
modJsList.tabCompanyStructure.setDataPipe(new IceDataPipe(modJsList.tabCompanyStructure));
|
||||||
modJsList.tabCompanyStructure.setAccess(data.permissions.CompanyStructure);
|
modJsList.tabCompanyStructure.setAccess(data.permissions.CompanyStructure);
|
||||||
|
modJsList.tabCompanyStructure.setCustomFields(data.customFields);
|
||||||
|
|
||||||
modJsList.tabCompanyGraph = new CompanyGraphAdapter('CompanyStructure');
|
modJsList.tabCompanyGraph = new CompanyGraphAdapter('CompanyStructure');
|
||||||
|
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ class CompanyStructureAdapter extends ReactModalAdapterBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getFormFields() {
|
getFormFields() {
|
||||||
return [
|
return this.addCustomFields([
|
||||||
['id', { label: 'ID', type: 'hidden', validation: '' }],
|
['id', { label: 'ID', type: 'hidden', validation: '' }],
|
||||||
['title', { label: 'Name', type: 'text', validation: '' }],
|
['title', { label: 'Name', type: 'text', validation: '' }],
|
||||||
['description', { label: 'Details', type: 'textarea', validation: '' }],
|
['description', { label: 'Details', type: 'textarea', validation: '' }],
|
||||||
@@ -80,7 +80,7 @@ class CompanyStructureAdapter extends ReactModalAdapterBase {
|
|||||||
['heads', {
|
['heads', {
|
||||||
label: 'Heads', type: 'select2multi', 'allow-null': true, 'remote-source': ['Employee', 'id', 'first_name+last_name'],
|
label: 'Heads', type: 'select2multi', 'allow-null': true, 'remote-source': ['Employee', 'id', 'first_name+last_name'],
|
||||||
}],
|
}],
|
||||||
];
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
postRenderForm(object, $tempDomObj) {
|
postRenderForm(object, $tempDomObj) {
|
||||||
|
|||||||
@@ -0,0 +1,18 @@
|
|||||||
|
import { CommonCustomFieldAdapter } from './lib';
|
||||||
|
import IceDataPipe from '../../../api/IceDataPipe';
|
||||||
|
|
||||||
|
function init(data) {
|
||||||
|
const modJsList = {};
|
||||||
|
|
||||||
|
modJsList.tabCustomField = new CommonCustomFieldAdapter('CustomField', 'CustomField', {}, '');
|
||||||
|
modJsList.tabCustomField.setRemoteTable(true);
|
||||||
|
modJsList.tabCustomField.setObjectTypeName('Custom Field');
|
||||||
|
modJsList.tabCustomField.setDataPipe(new IceDataPipe(modJsList.tabCustomField));
|
||||||
|
modJsList.tabCustomField.setAccess(data.permissions.CustomField);
|
||||||
|
modJsList.tabCustomField.setTypes(data.types);
|
||||||
|
|
||||||
|
window.modJs = modJsList.tabCustomField;
|
||||||
|
window.modJsList = modJsList;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.initAdminCustomFields = init;
|
||||||
@@ -0,0 +1,166 @@
|
|||||||
|
/**
|
||||||
|
* Author: Thilina Hasantha
|
||||||
|
*/
|
||||||
|
import ReactCustomFieldAdapter from '../../../api/ReactCustomFieldAdapter';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AssetTypeAdapter
|
||||||
|
*/
|
||||||
|
|
||||||
|
class CommonCustomFieldAdapter extends ReactCustomFieldAdapter {
|
||||||
|
getDataMapping() {
|
||||||
|
return [
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
'type',
|
||||||
|
'field_type',
|
||||||
|
'field_label',
|
||||||
|
'display',
|
||||||
|
'display_order',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
getHeaders() {
|
||||||
|
return [
|
||||||
|
{ sTitle: 'ID', bVisible: false },
|
||||||
|
{ sTitle: 'Name' },
|
||||||
|
{ sTitle: 'Object Type' },
|
||||||
|
{ sTitle: 'Field Type' },
|
||||||
|
{ sTitle: 'Field Label' },
|
||||||
|
{ sTitle: 'Display Status' },
|
||||||
|
{ sTitle: 'Priority' },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
getTableColumns() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: 'Name',
|
||||||
|
dataIndex: 'name',
|
||||||
|
sorter: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Object Type',
|
||||||
|
dataIndex: 'type',
|
||||||
|
sorter: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Field Label',
|
||||||
|
dataIndex: 'field_label',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Field Type',
|
||||||
|
dataIndex: 'field_type',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Display Status',
|
||||||
|
dataIndex: 'display',
|
||||||
|
sorter: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Priority',
|
||||||
|
dataIndex: 'display_order',
|
||||||
|
sorter: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
setTypes(tables) {
|
||||||
|
this.types = tables;
|
||||||
|
}
|
||||||
|
|
||||||
|
getFormFields() {
|
||||||
|
return [
|
||||||
|
['id', { label: 'ID', type: 'hidden' }],
|
||||||
|
['field_label', { label: 'Field Label', type: 'text', validation: '' }],
|
||||||
|
['type',
|
||||||
|
{
|
||||||
|
label: 'Object Type',
|
||||||
|
type: 'select2',
|
||||||
|
source: this.types,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
['field_type', { label: 'Field Type', type: 'select', source: [['text', 'Text Field'], ['textarea', 'Text Area'], ['select', 'Select'], ['select2', 'Select2'], ['select2multi', 'Multi Select'], ['fileupload', 'File Upload'], ['date', 'Date'], ['datetime', 'Date Time'], ['time', 'Time'], ['signature', 'Signature']] }],
|
||||||
|
['field_validation', {
|
||||||
|
label: 'Validation', type: 'select2', validation: 'none', sort: 'none', 'null-label': 'Required', 'allow-null': true, source: [['none', 'None'], ['number', 'Number'], ['numberOrEmpty', 'Number or Empty'], ['float', 'Decimal'], ['email', 'Email'], ['emailOrEmpty', 'Email or Empty']],
|
||||||
|
}],
|
||||||
|
['field_options', {
|
||||||
|
label: 'Field Options',
|
||||||
|
type: 'datagroup',
|
||||||
|
form: [
|
||||||
|
['label', { label: 'Label', type: 'text', validation: '' }],
|
||||||
|
['value', { label: 'Value', type: 'text', validation: 'none' }],
|
||||||
|
],
|
||||||
|
html: '<div id="#_id_#" class="panel panel-default"><div class="panel-body">#_delete_##_edit_#<span style="color:#999;font-size:13px;font-weight:bold">#_label_#</span>:#_value_#</div></div>',
|
||||||
|
columns: [
|
||||||
|
{
|
||||||
|
title: 'Label',
|
||||||
|
dataIndex: 'label',
|
||||||
|
key: 'label',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Option Value',
|
||||||
|
dataIndex: 'value',
|
||||||
|
key: 'value',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
validation: 'none',
|
||||||
|
}],
|
||||||
|
['display_order', { label: 'Priority', type: 'text', validation: 'none' }],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
getFilters() {
|
||||||
|
return [
|
||||||
|
['type',
|
||||||
|
{
|
||||||
|
label: 'Object Type',
|
||||||
|
type: 'select2',
|
||||||
|
'allow-null': true,
|
||||||
|
source: this.types,
|
||||||
|
},
|
||||||
|
],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
forceInjectValuesBeforeSave(params) {
|
||||||
|
const data = ['', {}];
|
||||||
|
const options = [];
|
||||||
|
let optionsData;
|
||||||
|
|
||||||
|
data[1].label = params.field_label;
|
||||||
|
data[1].type = params.field_type;
|
||||||
|
data[1].validation = params.field_validation;
|
||||||
|
if (['select', 'select2', 'select2multi'].indexOf(params.field_type) >= 0) {
|
||||||
|
optionsData = (params.field_options === '' || params.field_options === undefined)
|
||||||
|
? [] : JSON.parse(params.field_options);
|
||||||
|
for (const index in optionsData) {
|
||||||
|
options.push([optionsData[index].value, optionsData[index].label]);
|
||||||
|
}
|
||||||
|
data[1].source = options;
|
||||||
|
}
|
||||||
|
if (params.field_validation == null || params.field_validation === undefined) {
|
||||||
|
params.field_validation = '';
|
||||||
|
}
|
||||||
|
if (this.currentElement == null || this.currentElement.name == null || this.currentElement.name === '') {
|
||||||
|
params.name = this.getNameFromFieldName(params.field_label);
|
||||||
|
} else {
|
||||||
|
params.name = this.currentElement.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
data[0] = params.name;
|
||||||
|
params.data = JSON.stringify(data);
|
||||||
|
|
||||||
|
params.display = 'Form';
|
||||||
|
|
||||||
|
params.display_order = parseInt(params.display_order);
|
||||||
|
if (!Number.isInteger(params.display_order)) {
|
||||||
|
params.display_order = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return params;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
module.exports = { CommonCustomFieldAdapter };
|
||||||
@@ -98,6 +98,7 @@ class DashboardAdapter extends AdapterBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
drawEmployeeDistributionChart() {
|
drawEmployeeDistributionChart() {
|
||||||
|
const that = this;
|
||||||
document.getElementById('EmployeeDistributionChart').style.display = 'none';
|
document.getElementById('EmployeeDistributionChart').style.display = 'none';
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
this.getSpinner(),
|
this.getSpinner(),
|
||||||
@@ -115,7 +116,7 @@ class DashboardAdapter extends AdapterBase {
|
|||||||
forceFit: true,
|
forceFit: true,
|
||||||
title: {
|
title: {
|
||||||
visible: true,
|
visible: true,
|
||||||
text: 'Employee Distribution',
|
text: that.gt('Employee Distribution'),
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
visible: false,
|
visible: false,
|
||||||
@@ -125,7 +126,7 @@ class DashboardAdapter extends AdapterBase {
|
|||||||
visible: true,
|
visible: true,
|
||||||
content: {
|
content: {
|
||||||
value: chartData.reduce((acc, item) => acc + item.value, 0),
|
value: chartData.reduce((acc, item) => acc + item.value, 0),
|
||||||
name: 'Total',
|
name: that.gt('Total'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
@@ -151,6 +152,7 @@ class DashboardAdapter extends AdapterBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
drawOnlineOfflineEmployeeChart() {
|
drawOnlineOfflineEmployeeChart() {
|
||||||
|
const that = this;
|
||||||
document.getElementById('EmployeeOnlineOfflineChart').style.display = 'none';
|
document.getElementById('EmployeeOnlineOfflineChart').style.display = 'none';
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
this.getSpinner(),
|
this.getSpinner(),
|
||||||
@@ -168,7 +170,7 @@ class DashboardAdapter extends AdapterBase {
|
|||||||
forceFit: true,
|
forceFit: true,
|
||||||
title: {
|
title: {
|
||||||
visible: true,
|
visible: true,
|
||||||
text: 'Employee Check-Ins',
|
text: that.gt('Employee Check-Ins'),
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
visible: false,
|
visible: false,
|
||||||
@@ -178,7 +180,7 @@ class DashboardAdapter extends AdapterBase {
|
|||||||
visible: true,
|
visible: true,
|
||||||
content: {
|
content: {
|
||||||
value: chartData.reduce((acc, item) => acc + item.value, 0),
|
value: chartData.reduce((acc, item) => acc + item.value, 0),
|
||||||
name: 'Total',
|
name: that.gt('Total'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
@@ -199,6 +201,7 @@ class DashboardAdapter extends AdapterBase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
drawCompanyLeaveEntitlementChart() {
|
drawCompanyLeaveEntitlementChart() {
|
||||||
|
const that = this;
|
||||||
document.getElementById('CompanyLeaveEntitlementChart').style.display = 'none';
|
document.getElementById('CompanyLeaveEntitlementChart').style.display = 'none';
|
||||||
ReactDOM.render(
|
ReactDOM.render(
|
||||||
this.getSpinner(),
|
this.getSpinner(),
|
||||||
@@ -216,7 +219,7 @@ class DashboardAdapter extends AdapterBase {
|
|||||||
forceFit: true,
|
forceFit: true,
|
||||||
title: {
|
title: {
|
||||||
visible: true,
|
visible: true,
|
||||||
text: 'Company Vacation Usage',
|
text: that.gt('Company Vacation Usage'),
|
||||||
},
|
},
|
||||||
description: {
|
description: {
|
||||||
visible: false,
|
visible: false,
|
||||||
@@ -226,7 +229,7 @@ class DashboardAdapter extends AdapterBase {
|
|||||||
visible: true,
|
visible: true,
|
||||||
content: {
|
content: {
|
||||||
value: chartData.reduce((acc, item) => acc + item.value, 0),
|
value: chartData.reduce((acc, item) => acc + item.value, 0),
|
||||||
name: 'Total',
|
name: that.gt('Total'),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
legend: {
|
legend: {
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ class DocumentAdapter extends AdapterBase {
|
|||||||
['expire_notification_month', { label: 'Notify Expiry Before One Month', type: 'select', source: [['Yes', 'Yes'], ['No', 'No']] }],
|
['expire_notification_month', { label: 'Notify Expiry Before One Month', type: 'select', source: [['Yes', 'Yes'], ['No', 'No']] }],
|
||||||
['expire_notification_week', { label: 'Notify Expiry Before One Week', type: 'select', source: [['Yes', 'Yes'], ['No', 'No']] }],
|
['expire_notification_week', { label: 'Notify Expiry Before One Week', type: 'select', source: [['Yes', 'Yes'], ['No', 'No']] }],
|
||||||
['expire_notification_day', { label: 'Notify Expiry Before One Day', type: 'select', source: [['Yes', 'Yes'], ['No', 'No']] }],
|
['expire_notification_day', { label: 'Notify Expiry Before One Day', type: 'select', source: [['Yes', 'Yes'], ['No', 'No']] }],
|
||||||
|
['share_with_employee', { label: 'Share with Employee', type: 'select', source: [['Yes', 'Yes'], ['No', 'No']] }],
|
||||||
|
// [ "sign", {"label":"Require Signature","type":"select","source":[["Yes","Yes"],["No","No"]]}],
|
||||||
// [ "sign", {"label":"Require Signature","type":"select","source":[["Yes","Yes"],["No","No"]]}],
|
// [ "sign", {"label":"Require Signature","type":"select","source":[["Yes","Yes"],["No","No"]]}],
|
||||||
// [ "sign_label", {"label":"Signature Description","type":"textarea","validation":"none"}],
|
// [ "sign_label", {"label":"Signature Description","type":"textarea","validation":"none"}],
|
||||||
['details', { label: 'Details', type: 'textarea', validation: 'none' }],
|
['details', { label: 'Details', type: 'textarea', validation: 'none' }],
|
||||||
@@ -146,6 +148,7 @@ class EmployeeDocumentAdapter extends AdapterBase {
|
|||||||
['date_added', { label: 'Date Added', type: 'date', validation: '' }],
|
['date_added', { label: 'Date Added', type: 'date', validation: '' }],
|
||||||
['valid_until', { label: 'Valid Until', type: 'date', validation: 'none' }],
|
['valid_until', { label: 'Valid Until', type: 'date', validation: 'none' }],
|
||||||
['status', { label: 'Status', type: 'select', source: [['Active', 'Active'], ['Inactive', 'Inactive'], ['Draft', 'Draft']] }],
|
['status', { label: 'Status', type: 'select', source: [['Active', 'Active'], ['Inactive', 'Inactive'], ['Draft', 'Draft']] }],
|
||||||
|
['visible_to', { label: 'Visible To', type: 'select', source: [['Owner', 'Owner'], ['Manager', 'Manager'], ['Admin', 'Admin']] }],
|
||||||
['details', { label: 'Details', type: 'textarea', validation: 'none' }],
|
['details', { label: 'Details', type: 'textarea', validation: 'none' }],
|
||||||
['attachment', { label: 'Attachment', type: 'fileupload', validation: '' }],
|
['attachment', { label: 'Attachment', type: 'fileupload', validation: '' }],
|
||||||
];
|
];
|
||||||
|
|||||||
@@ -363,28 +363,7 @@ class EmployeeAdapter extends ReactModalAdapterBase {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.addActualFields(steps, fields);
|
return this.addActualFieldsForStepModal(steps, fields);
|
||||||
}
|
|
||||||
|
|
||||||
addActualFields(steps, fields) {
|
|
||||||
return steps.map((item) => {
|
|
||||||
item.fields = item.fields.reduce((acc, fieldName) => {
|
|
||||||
const field = fields.find(([name]) => name === fieldName);
|
|
||||||
if (field) {
|
|
||||||
acc.push(field);
|
|
||||||
}
|
|
||||||
return acc;
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return item;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
getFormOptions() {
|
|
||||||
return {
|
|
||||||
width: 1024,
|
|
||||||
twoColumnLayout: false,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getFilters() {
|
getFilters() {
|
||||||
|
|||||||
@@ -344,7 +344,7 @@ class PayrollColumnAdapter extends AdapterBase {
|
|||||||
['enabled', { label: 'Enabled', type: 'select', source: [['Yes', 'Yes'], ['No', 'No']] }],
|
['enabled', { label: 'Enabled', type: 'select', source: [['Yes', 'Yes'], ['No', 'No']] }],
|
||||||
['default_value', { label: 'Default Value', type: 'text', validation: '' }],
|
['default_value', { label: 'Default Value', type: 'text', validation: '' }],
|
||||||
fucntionColumnList,
|
fucntionColumnList,
|
||||||
['function_type', { label: 'Function Type', type: 'select', source: [['Advanced', 'Advanced'], ['Simple', 'Simple']] }],
|
['function_type', { label: 'Function Type', type: 'select', source: [['Simple', 'Simple']] }],
|
||||||
['calculation_function', { label: 'Function', type: 'code', validation: 'none' }],
|
['calculation_function', { label: 'Function', type: 'code', validation: 'none' }],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,13 +3,21 @@
|
|||||||
Developer: Thilina Hasantha (http://lk.linkedin.com/in/thilinah | https://github.com/thilinah)
|
Developer: Thilina Hasantha (http://lk.linkedin.com/in/thilinah | https://github.com/thilinah)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import AdapterBase from '../../../api/AdapterBase';
|
import ReactModalAdapterBase from '../../../api/ReactModalAdapterBase';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ProjectAdapter
|
* ProjectAdapter
|
||||||
*/
|
*/
|
||||||
|
|
||||||
class ProjectAdapter extends AdapterBase {
|
class ProjectAdapter extends ReactModalAdapterBase {
|
||||||
|
constructor(endPoint, tab, filter, orderBy) {
|
||||||
|
super(endPoint, tab, filter, orderBy);
|
||||||
|
this.fieldNameMap = {};
|
||||||
|
this.hiddenFields = {};
|
||||||
|
this.tableFields = {};
|
||||||
|
this.formOnlyFields = {};
|
||||||
|
}
|
||||||
|
|
||||||
getDataMapping() {
|
getDataMapping() {
|
||||||
return [
|
return [
|
||||||
'id',
|
'id',
|
||||||
@@ -26,6 +34,21 @@ class ProjectAdapter extends AdapterBase {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTableColumns() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: 'Name',
|
||||||
|
dataIndex: 'name',
|
||||||
|
sorter: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Client',
|
||||||
|
dataIndex: 'client',
|
||||||
|
sorter: true,
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
getFormFields() {
|
getFormFields() {
|
||||||
if (this.showSave) {
|
if (this.showSave) {
|
||||||
return [
|
return [
|
||||||
@@ -60,7 +83,15 @@ class ProjectAdapter extends AdapterBase {
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
class EmployeeProjectAdapter extends AdapterBase {
|
class EmployeeProjectAdapter extends ReactModalAdapterBase {
|
||||||
|
constructor(endPoint, tab, filter, orderBy) {
|
||||||
|
super(endPoint, tab, filter, orderBy);
|
||||||
|
this.fieldNameMap = {};
|
||||||
|
this.hiddenFields = {};
|
||||||
|
this.tableFields = {};
|
||||||
|
this.formOnlyFields = {};
|
||||||
|
}
|
||||||
|
|
||||||
getDataMapping() {
|
getDataMapping() {
|
||||||
return [
|
return [
|
||||||
'id',
|
'id',
|
||||||
@@ -77,6 +108,22 @@ class EmployeeProjectAdapter extends AdapterBase {
|
|||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getTableColumns() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: 'Employee',
|
||||||
|
dataIndex: 'employee',
|
||||||
|
sorter: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Project',
|
||||||
|
dataIndex: 'project',
|
||||||
|
sorter: true,
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
getFormFields() {
|
getFormFields() {
|
||||||
return [
|
return [
|
||||||
['id', { label: 'ID', type: 'hidden' }],
|
['id', { label: 'ID', type: 'hidden' }],
|
||||||
|
|||||||
File renamed without changes.
@@ -9,8 +9,6 @@ import TimeUtils from './TimeUtils';
|
|||||||
import RequestCache from './RequestCache';
|
import RequestCache from './RequestCache';
|
||||||
import SocialShare from './SocialShare';
|
import SocialShare from './SocialShare';
|
||||||
|
|
||||||
const Aes = require('./Aes');
|
|
||||||
|
|
||||||
window.RequestCache = RequestCache;
|
window.RequestCache = RequestCache;
|
||||||
window.SocialShare = SocialShare;
|
window.SocialShare = SocialShare;
|
||||||
|
|
||||||
|
|||||||
@@ -104,16 +104,16 @@ class ApproveAdminAdapter extends LogViewAdapter {
|
|||||||
|
|
||||||
getStatusOptionsData(currentStatus) {
|
getStatusOptionsData(currentStatus) {
|
||||||
const data = {};
|
const data = {};
|
||||||
if (currentStatus == 'Approved') {
|
if (currentStatus === 'Approved') {
|
||||||
|
|
||||||
} else if (currentStatus == 'Pending') {
|
} else if (currentStatus === 'Pending') {
|
||||||
data.Approved = 'Approved';
|
data.Approved = 'Approved';
|
||||||
data.Rejected = 'Rejected';
|
data.Rejected = 'Rejected';
|
||||||
} else if (currentStatus == 'Rejected') {
|
} else if (currentStatus === 'Rejected') {
|
||||||
|
|
||||||
} else if (currentStatus == 'Cancelled') {
|
} else if (currentStatus === 'Cancelled') {
|
||||||
|
|
||||||
} else if (currentStatus == 'Processing') {
|
} else if (currentStatus === 'Processing') {
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
data['Cancellation Requested'] = 'Cancellation Requested';
|
data['Cancellation Requested'] = 'Cancellation Requested';
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ class CustomFieldAdapter extends AdapterBase {
|
|||||||
['id', { label: 'ID', type: 'hidden' }],
|
['id', { label: 'ID', type: 'hidden' }],
|
||||||
['name', { label: 'Name', type: 'text', validation: '' }],
|
['name', { label: 'Name', type: 'text', validation: '' }],
|
||||||
['display', { label: 'Display Status', type: 'select', source: [['Form', 'Show'], ['Hidden', 'Hidden']] }],
|
['display', { label: 'Display Status', type: 'select', source: [['Form', 'Show'], ['Hidden', 'Hidden']] }],
|
||||||
['field_type', { label: 'Field Type', type: 'select', source: [['text', 'Text Field'], ['textarea', 'Text Area'], ['select', 'Select'], ['select2', 'Select2'], ['select2multi', 'Multi Select'], ['fileupload', 'File Upload'], ['date', 'Date'], ['datetime', 'Date Time'], ['time', 'Time']] }],
|
['field_type', { label: 'Field Type', type: 'select', source: [['text', 'Text Field'], ['textarea', 'Text Area'], ['select', 'Select'], ['select2', 'Select2'], ['select2multi', 'Multi Select'], ['fileupload', 'File Upload'], ['date', 'Date'], ['datetime', 'Date Time'], ['time', 'Time'], ['signature', 'Signature']] }],
|
||||||
['field_label', { label: 'Field Label', type: 'text', validation: '' }],
|
['field_label', { label: 'Field Label', type: 'text', validation: '' }],
|
||||||
['field_validation', {
|
['field_validation', {
|
||||||
label: 'Validation', type: 'select2', validation: 'none', sort: 'none', 'null-label': 'Required', 'allow-null': true, source: [['none', 'None'], ['number', 'Number'], ['numberOrEmpty', 'Number or Empty'], ['float', 'Decimal'], ['email', 'Email'], ['emailOrEmpty', 'Email or Empty']],
|
label: 'Validation', type: 'select2', validation: 'none', sort: 'none', 'null-label': 'Required', 'allow-null': true, source: [['none', 'None'], ['number', 'Number'], ['numberOrEmpty', 'Number or Empty'], ['float', 'Decimal'], ['email', 'Email'], ['emailOrEmpty', 'Email or Empty']],
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ class ModuleBase {
|
|||||||
|
|
||||||
gt(key) {
|
gt(key) {
|
||||||
if (this.translations[key] === undefined || this.translations[key] === null) {
|
if (this.translations[key] === undefined || this.translations[key] === null) {
|
||||||
|
console.log("Tr:" + key);
|
||||||
return key;
|
return key;
|
||||||
}
|
}
|
||||||
return this.translations[key][0];
|
return this.translations[key][0];
|
||||||
@@ -1057,7 +1058,7 @@ class ModuleBase {
|
|||||||
return this.gt('Password too short');
|
return this.gt('Password too short');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (password.length > 20) {
|
if (password.length > 30) {
|
||||||
return this.gt('Password too long');
|
return this.gt('Password too long');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2018 [Glacies UG, Berlin, Germany] (http://glacies.de)
|
||||||
|
Developer: Thilina Hasantha (http://lk.linkedin.com/in/thilinah | https://github.com/thilinah)
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ReactApproveAdminAdapter
|
||||||
|
*/
|
||||||
|
import React from 'react';
|
||||||
|
import ReactLogViewAdapter from './ReactLogViewAdapter';
|
||||||
|
import {Space, Tag} from "antd";
|
||||||
|
import {CopyOutlined, DeleteOutlined, EditOutlined, MonitorOutlined} from "@ant-design/icons";
|
||||||
|
|
||||||
|
class ReactApproveAdminAdapter extends ReactLogViewAdapter {
|
||||||
|
constructor(endPoint, tab, filter, orderBy) {
|
||||||
|
super(endPoint, tab, filter, orderBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
getStatusFieldPosition() {
|
||||||
|
const dm = this.getDataMapping();
|
||||||
|
return dm.length - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
openStatus(id, status) {
|
||||||
|
$(`#${this.itemNameLower}StatusModel`).modal('show');
|
||||||
|
$(`#${this.itemNameLower}_status`).html(this.getStatusOptions(status));
|
||||||
|
$(`#${this.itemNameLower}_status`).val(status);
|
||||||
|
this.statusChangeId = id;
|
||||||
|
}
|
||||||
|
|
||||||
|
closeDialog() {
|
||||||
|
$(`#${this.itemNameLower}StatusModel`).modal('hide');
|
||||||
|
}
|
||||||
|
|
||||||
|
changeStatus() {
|
||||||
|
const status = $(`#${this.itemNameLower}_status`).val();
|
||||||
|
const reason = $(`#${this.itemNameLower}_reason`).val();
|
||||||
|
|
||||||
|
if (status == undefined || status == null || status == '') {
|
||||||
|
this.showMessage('Error', `Please select ${this.itemNameLower} status`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const object = { id: this.statusChangeId, status, reason };
|
||||||
|
|
||||||
|
const reqJson = JSON.stringify(object);
|
||||||
|
|
||||||
|
const callBackData = [];
|
||||||
|
callBackData.callBackData = [];
|
||||||
|
callBackData.callBackSuccess = 'changeStatusSuccessCallBack';
|
||||||
|
callBackData.callBackFail = 'changeStatusFailCallBack';
|
||||||
|
|
||||||
|
this.customAction('changeStatus', `admin=${this.modulePathName}`, reqJson, callBackData);
|
||||||
|
|
||||||
|
this.closeDialog();
|
||||||
|
this.statusChangeId = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
changeStatusSuccessCallBack(callBackData) {
|
||||||
|
this.showMessage('Successful', `${this.itemName} Request status changed successfully`);
|
||||||
|
this.get([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
changeStatusFailCallBack(callBackData) {
|
||||||
|
this.showMessage('Error', `Error occurred while changing ${this.itemName} request status`);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTableActionButtonJsx(adapter) {
|
||||||
|
return (text, record) => (
|
||||||
|
<Space size="middle">
|
||||||
|
{adapter.hasAccess('save') && adapter.showEdit
|
||||||
|
&& (
|
||||||
|
<Tag color="green" onClick={() => modJs.edit(record.id)} style={{ cursor: 'pointer' }}>
|
||||||
|
<EditOutlined />
|
||||||
|
{` ${adapter.gt('Edit')}`}
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
{adapter.hasAccess('delete') && adapter.showDelete
|
||||||
|
&& (
|
||||||
|
<Tag color="volcano" onClick={() => modJs.deleteRow(record.id)} style={{ cursor: 'pointer' }}>
|
||||||
|
<DeleteOutlined />
|
||||||
|
{` ${adapter.gt('Delete')}`}
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
{Object.keys(this.getStatusOptionsData(record.status)).length > 0
|
||||||
|
&& (
|
||||||
|
<Tag color="blue" onClick={() => modJs.openStatus(record.id, record.status)} style={{ cursor: 'pointer' }}>
|
||||||
|
<MonitorOutlined />
|
||||||
|
{` ${adapter.gt('Change Status')}`}
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
<Tag color="cyan" onClick={() => modJs.getLogs(record.id)} style={{ cursor: 'pointer' }}>
|
||||||
|
<CopyOutlined />
|
||||||
|
{` ${adapter.gt('View Logs')}`}
|
||||||
|
</Tag>
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
hasCustomButtons() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
isSubProfileTable() {
|
||||||
|
return this.user.user_level !== 'Admin' && this.user.user_level !== 'Restricted Admin';
|
||||||
|
}
|
||||||
|
|
||||||
|
getStatusOptionsData(currentStatus) {
|
||||||
|
const data = {};
|
||||||
|
if (currentStatus === 'Approved') {
|
||||||
|
|
||||||
|
} else if (currentStatus === 'Pending') {
|
||||||
|
data.Approved = 'Approved';
|
||||||
|
data.Rejected = 'Rejected';
|
||||||
|
} else if (currentStatus === 'Rejected') {
|
||||||
|
|
||||||
|
} else if (currentStatus === 'Cancelled') {
|
||||||
|
|
||||||
|
} else if (currentStatus === 'Processing') {
|
||||||
|
|
||||||
|
} else {
|
||||||
|
data['Cancellation Requested'] = 'Cancellation Requested';
|
||||||
|
data.Cancelled = 'Cancelled';
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
getStatusOptions(currentStatus) {
|
||||||
|
return this.generateOptions(this.getStatusOptionsData(currentStatus));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ReactApproveAdminAdapter;
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2018 [Glacies UG, Berlin, Germany] (http://glacies.de)
|
||||||
|
Developer: Thilina Hasantha (http://lk.linkedin.com/in/thilinah | https://github.com/thilinah)
|
||||||
|
*/
|
||||||
|
import React from 'react';
|
||||||
|
import { Space, Tag } from 'antd';
|
||||||
|
import {
|
||||||
|
CopyOutlined, DeleteOutlined, EditOutlined, MonitorOutlined,
|
||||||
|
} from '@ant-design/icons';
|
||||||
|
import ReactLogViewAdapter from './ReactLogViewAdapter';
|
||||||
|
|
||||||
|
class ReactApproveModuleAdapter extends ReactLogViewAdapter {
|
||||||
|
cancelRequest(id) {
|
||||||
|
const object = {};
|
||||||
|
object.id = id;
|
||||||
|
|
||||||
|
const reqJson = JSON.stringify(object);
|
||||||
|
|
||||||
|
const callBackData = [];
|
||||||
|
callBackData.callBackData = [];
|
||||||
|
callBackData.callBackSuccess = 'cancelSuccessCallBack';
|
||||||
|
callBackData.callBackFail = 'cancelFailCallBack';
|
||||||
|
|
||||||
|
this.customAction('cancel', `modules=${this.modulePathName}`, reqJson, callBackData);
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
cancelSuccessCallBack(callBackData) {
|
||||||
|
this.showMessage('Successful', `${this.itemName} cancellation request sent`);
|
||||||
|
this.get([]);
|
||||||
|
}
|
||||||
|
|
||||||
|
cancelFailCallBack(callBackData) {
|
||||||
|
this.showMessage(`Error Occurred while cancelling ${this.itemName}`, callBackData);
|
||||||
|
}
|
||||||
|
|
||||||
|
getTableActionButtonJsx(adapter) {
|
||||||
|
return (text, record) => (
|
||||||
|
<Space size="middle">
|
||||||
|
{adapter.hasAccess('save') && adapter.showEdit
|
||||||
|
&& (
|
||||||
|
<Tag color="green" onClick={() => modJs.edit(record.id)} style={{ cursor: 'pointer' }}>
|
||||||
|
<EditOutlined />
|
||||||
|
{` ${adapter.gt('Edit')}`}
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
{adapter.hasAccess('delete') && adapter.showDelete && record.status === 'Approved'
|
||||||
|
&& (
|
||||||
|
<Tag color="volcano" onClick={() => modJs.cancelRequest(record.id)} style={{ cursor: 'pointer' }}>
|
||||||
|
<DeleteOutlined />
|
||||||
|
{` ${adapter.gt('Cancel')}`}
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
{adapter.hasAccess('delete') && adapter.showDelete && record.status === 'Pending'
|
||||||
|
&& this.user.user_level === 'Admin'
|
||||||
|
&& (
|
||||||
|
<Tag color="volcano" onClick={() => modJs.deleteRow(record.id)} style={{ cursor: 'pointer' }}>
|
||||||
|
<DeleteOutlined />
|
||||||
|
{` ${adapter.gt('Delete')}`}
|
||||||
|
</Tag>
|
||||||
|
)}
|
||||||
|
<Tag color="cyan" onClick={() => modJs.getLogs(record.id)} style={{ cursor: 'pointer' }}>
|
||||||
|
<CopyOutlined />
|
||||||
|
{` ${adapter.gt('View Logs')}`}
|
||||||
|
</Tag>
|
||||||
|
</Space>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ReactApproveModuleAdapter;
|
||||||
@@ -20,6 +20,8 @@ class ReactCustomFieldAdapter extends AdapterBase {
|
|||||||
return [
|
return [
|
||||||
'id',
|
'id',
|
||||||
'name',
|
'name',
|
||||||
|
'field_type',
|
||||||
|
'field_label',
|
||||||
'display',
|
'display',
|
||||||
'display_order',
|
'display_order',
|
||||||
];
|
];
|
||||||
@@ -29,6 +31,8 @@ class ReactCustomFieldAdapter extends AdapterBase {
|
|||||||
return [
|
return [
|
||||||
{ sTitle: 'ID', bVisible: false },
|
{ sTitle: 'ID', bVisible: false },
|
||||||
{ sTitle: 'Name' },
|
{ sTitle: 'Name' },
|
||||||
|
{ sTitle: 'Field Type' },
|
||||||
|
{ sTitle: 'Field Label' },
|
||||||
{ sTitle: 'Display Status' },
|
{ sTitle: 'Display Status' },
|
||||||
{ sTitle: 'Priority' },
|
{ sTitle: 'Priority' },
|
||||||
];
|
];
|
||||||
@@ -40,17 +44,24 @@ class ReactCustomFieldAdapter extends AdapterBase {
|
|||||||
title: 'Name',
|
title: 'Name',
|
||||||
dataIndex: 'name',
|
dataIndex: 'name',
|
||||||
sorter: true,
|
sorter: true,
|
||||||
width: '25%',
|
},
|
||||||
|
{
|
||||||
|
title: 'Field Label',
|
||||||
|
dataIndex: 'field_label',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Field Type',
|
||||||
|
dataIndex: 'field_type',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Display Status',
|
title: 'Display Status',
|
||||||
dataIndex: 'display',
|
dataIndex: 'display',
|
||||||
width: '35%',
|
sorter: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: 'Priority',
|
title: 'Priority',
|
||||||
dataIndex: 'display_order',
|
dataIndex: 'display_order',
|
||||||
width: '10%',
|
sorter: true,
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@@ -58,10 +69,8 @@ class ReactCustomFieldAdapter extends AdapterBase {
|
|||||||
getFormFields() {
|
getFormFields() {
|
||||||
return [
|
return [
|
||||||
['id', { label: 'ID', type: 'hidden' }],
|
['id', { label: 'ID', type: 'hidden' }],
|
||||||
['name', { label: 'Name', type: 'text', validation: '' }],
|
|
||||||
['display', { label: 'Display Status', type: 'select', source: [['Form', 'Show'], ['Hidden', 'Hidden']] }],
|
|
||||||
['field_type', { label: 'Field Type', type: 'select', source: [['text', 'Text Field'], ['textarea', 'Text Area'], ['select', 'Select'], ['select2', 'Select2'], ['select2multi', 'Multi Select'], ['fileupload', 'File Upload'], ['date', 'Date'], ['datetime', 'Date Time'], ['time', 'Time']] }],
|
|
||||||
['field_label', { label: 'Field Label', type: 'text', validation: '' }],
|
['field_label', { label: 'Field Label', type: 'text', validation: '' }],
|
||||||
|
['field_type', { label: 'Field Type', type: 'select', source: [['text', 'Text Field'], ['textarea', 'Text Area'], ['select', 'Select'], ['select2', 'Select2'], ['select2multi', 'Multi Select'], ['fileupload', 'File Upload'], ['date', 'Date'], ['datetime', 'Date Time'], ['time', 'Time'], ['signature', 'Signature']] }],
|
||||||
['field_validation', {
|
['field_validation', {
|
||||||
label: 'Validation', type: 'select2', validation: 'none', sort: 'none', 'null-label': 'Required', 'allow-null': true, source: [['none', 'None'], ['number', 'Number'], ['numberOrEmpty', 'Number or Empty'], ['float', 'Decimal'], ['email', 'Email'], ['emailOrEmpty', 'Email or Empty']],
|
label: 'Validation', type: 'select2', validation: 'none', sort: 'none', 'null-label': 'Required', 'allow-null': true, source: [['none', 'None'], ['number', 'Number'], ['numberOrEmpty', 'Number or Empty'], ['float', 'Decimal'], ['email', 'Email'], ['emailOrEmpty', 'Email or Empty']],
|
||||||
}],
|
}],
|
||||||
@@ -87,11 +96,14 @@ class ReactCustomFieldAdapter extends AdapterBase {
|
|||||||
],
|
],
|
||||||
validation: 'none',
|
validation: 'none',
|
||||||
}],
|
}],
|
||||||
['display_order', { label: 'Priority', type: 'text', validation: 'number' }],
|
['display_order', { label: 'Priority', type: 'text', validation: 'none' }],
|
||||||
['display_section', { label: 'Display Section', type: 'text', validation: 'none' }],
|
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getNameFromFieldName(fieldName) {
|
||||||
|
return fieldName.replace(/[^a-z0-9+]+/gi, '').toLowerCase();
|
||||||
|
}
|
||||||
|
|
||||||
setTableType(type) {
|
setTableType(type) {
|
||||||
this.tableType = type;
|
this.tableType = type;
|
||||||
}
|
}
|
||||||
@@ -102,18 +114,26 @@ class ReactCustomFieldAdapter extends AdapterBase {
|
|||||||
return str != null && name.test(str);
|
return str != null && name.test(str);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (this.currentElement == null || this.currentElement.name == null || this.currentElement.name === '') {
|
||||||
|
params.name = this.getNameFromFieldName(params.field_label);
|
||||||
|
if (!validateName(params.name)) {
|
||||||
|
return 'Invalid field label for custom field';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
params.name = this.currentElement.name;
|
||||||
|
}
|
||||||
|
|
||||||
if (!validateName(params.name)) {
|
if (!validateName(params.name)) {
|
||||||
return 'Invalid name for custom field';
|
return 'Invalid name for custom field';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
forceInjectValuesBeforeSave(params) {
|
forceInjectValuesBeforeSave(params) {
|
||||||
const data = [params.name]; const options = []; let
|
const data = ['', {}];
|
||||||
optionsData;
|
const options = [];
|
||||||
data.push({});
|
let optionsData;
|
||||||
|
|
||||||
data[1].label = params.field_label;
|
data[1].label = params.field_label;
|
||||||
data[1].type = params.field_type;
|
data[1].type = params.field_type;
|
||||||
data[1].validation = params.field_validation;
|
data[1].validation = params.field_validation;
|
||||||
@@ -128,8 +148,23 @@ class ReactCustomFieldAdapter extends AdapterBase {
|
|||||||
if (params.field_validation == null || params.field_validation === undefined) {
|
if (params.field_validation == null || params.field_validation === undefined) {
|
||||||
params.field_validation = '';
|
params.field_validation = '';
|
||||||
}
|
}
|
||||||
params.data = JSON.stringify(data);
|
|
||||||
params.type = this.tableType;
|
params.type = this.tableType;
|
||||||
|
if (this.currentElement == null || this.currentElement.name == null || this.currentElement.name === '') {
|
||||||
|
params.name = this.getNameFromFieldName(params.field_label);
|
||||||
|
} else {
|
||||||
|
params.name = this.currentElement.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
data[0] = params.name;
|
||||||
|
params.data = JSON.stringify(data);
|
||||||
|
|
||||||
|
params.display = 'Form';
|
||||||
|
params.display_order = parseInt(params.display_order);
|
||||||
|
if (!Number.isInteger(params.display_order)) {
|
||||||
|
params.display_order = 1;
|
||||||
|
}
|
||||||
|
|
||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,45 @@
|
|||||||
|
import ReactModalAdapterBase from './ReactModalAdapterBase';
|
||||||
|
|
||||||
|
class ReactIdNameAdapter extends ReactModalAdapterBase {
|
||||||
|
constructor(endPoint, tab, filter, orderBy) {
|
||||||
|
super(endPoint, tab, filter, orderBy);
|
||||||
|
}
|
||||||
|
|
||||||
|
getDataMapping() {
|
||||||
|
return [
|
||||||
|
'id',
|
||||||
|
'name',
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
getHeaders() {
|
||||||
|
return [
|
||||||
|
{ sTitle: 'ID', bVisible: false },
|
||||||
|
{ sTitle: 'Name' },
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
getFormFields() {
|
||||||
|
return [
|
||||||
|
['id', { label: 'ID', type: 'hidden' }],
|
||||||
|
['name', { label: 'Name', type: 'text', validation: '' }],
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
getTableColumns() {
|
||||||
|
return [
|
||||||
|
{
|
||||||
|
title: 'Id',
|
||||||
|
dataIndex: 'id',
|
||||||
|
sorter: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
title: 'Name',
|
||||||
|
dataIndex: 'name',
|
||||||
|
sorter: true,
|
||||||
|
},
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ReactIdNameAdapter;
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2018 [Glacies UG, Berlin, Germany] (http://glacies.de)
|
||||||
|
Developer: Thilina Hasantha (http://lk.linkedin.com/in/thilinah | https://github.com/thilinah)
|
||||||
|
*/
|
||||||
|
/* global timeUtils */
|
||||||
|
/**
|
||||||
|
* ReactLogViewAdapter
|
||||||
|
*/
|
||||||
|
|
||||||
|
import ReactModalAdapterBase from './ReactModalAdapterBase';
|
||||||
|
|
||||||
|
class ReactLogViewAdapter extends ReactModalAdapterBase {
|
||||||
|
getLogs(id) {
|
||||||
|
const object = { id };
|
||||||
|
const reqJson = JSON.stringify(object);
|
||||||
|
|
||||||
|
const callBackData = [];
|
||||||
|
callBackData.callBackData = [];
|
||||||
|
callBackData.callBackSuccess = 'getLogsSuccessCallBack';
|
||||||
|
callBackData.callBackFail = 'getLogsFailCallBack';
|
||||||
|
|
||||||
|
this.customAction('getLogs', `admin=${this.modulePathName}`, reqJson, callBackData);
|
||||||
|
}
|
||||||
|
|
||||||
|
getLogsSuccessCallBack(callBackData) {
|
||||||
|
let tableLog = '<table class="table table-condensed table-bordered table-striped" style="font-size:14px;"><thead><tr><th>Notes</th></tr></thead><tbody>_days_</tbody></table> ';
|
||||||
|
const rowLog = '<tr><td><span class="logTime label label-default">_date_</span> <b>_status_</b><br/>_note_</td></tr>';
|
||||||
|
|
||||||
|
const logs = callBackData.data;
|
||||||
|
let html = '';
|
||||||
|
let rowsLogs = '';
|
||||||
|
|
||||||
|
|
||||||
|
for (let i = 0; i < logs.length; i++) {
|
||||||
|
let trow = rowLog;
|
||||||
|
trow = trow.replace(/_date_/g, logs[i].time);
|
||||||
|
trow = trow.replace(/_status_/g, `${logs[i].status_from} -> ${logs[i].status_to}`);
|
||||||
|
trow = trow.replace(/_note_/g, logs[i].note);
|
||||||
|
rowsLogs += trow;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rowsLogs !== '') {
|
||||||
|
tableLog = tableLog.replace('_days_', rowsLogs);
|
||||||
|
html += tableLog;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.showMessage('Logs', html);
|
||||||
|
|
||||||
|
timeUtils.convertToRelativeTime($('.logTime'));
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
getLogsFailCallBack(callBackData) {
|
||||||
|
this.showMessage('Error', 'Error occured while getting data');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ReactLogViewAdapter;
|
||||||
@@ -48,6 +48,10 @@ class ReactModalAdapterBase extends AdapterBase {
|
|||||||
return this.access.indexOf(type) > 0;
|
return this.access.indexOf(type) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasCustomButtons() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
initTable() {
|
initTable() {
|
||||||
if (this.tableInitialized) {
|
if (this.tableInitialized) {
|
||||||
return false;
|
return false;
|
||||||
@@ -56,7 +60,11 @@ class ReactModalAdapterBase extends AdapterBase {
|
|||||||
if (tableDom) {
|
if (tableDom) {
|
||||||
this.tableContainer = React.createRef();
|
this.tableContainer = React.createRef();
|
||||||
let columns = this.getTableColumns();
|
let columns = this.getTableColumns();
|
||||||
if (this.hasAccess('save') || this.hasAccess('delete') || this.hasAccess('element')) {
|
if (this.hasAccess('save')
|
||||||
|
|| this.hasAccess('delete')
|
||||||
|
|| this.hasAccess('element')
|
||||||
|
|| this.hasCustomButtons()
|
||||||
|
) {
|
||||||
columns.push({
|
columns.push({
|
||||||
title: 'Actions',
|
title: 'Actions',
|
||||||
key: 'actions',
|
key: 'actions',
|
||||||
@@ -257,6 +265,27 @@ class ReactModalAdapterBase extends AdapterBase {
|
|||||||
showLoader() {
|
showLoader() {
|
||||||
// $('#iceloader').show();
|
// $('#iceloader').show();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addActualFieldsForStepModal(steps, fields) {
|
||||||
|
return steps.map((item) => {
|
||||||
|
item.fields = item.fields.reduce((acc, fieldName) => {
|
||||||
|
const field = fields.find(([name]) => name === fieldName);
|
||||||
|
if (field) {
|
||||||
|
acc.push(field);
|
||||||
|
}
|
||||||
|
return acc;
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
return item;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getFormOptions() {
|
||||||
|
return {
|
||||||
|
width: 1024,
|
||||||
|
twoColumnLayout: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default ReactModalAdapterBase;
|
export default ReactModalAdapterBase;
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
import React, { useState, useRef, useEffect } from "react";
|
||||||
|
import { SketchPicker } from 'react-color';
|
||||||
|
|
||||||
|
function useComponentVisible(initialIsVisible) {
|
||||||
|
const [isComponentVisible, setIsComponentVisible] = useState(initialIsVisible);
|
||||||
|
const ref = useRef(null);
|
||||||
|
|
||||||
|
const handleClickOutside = (event) => {
|
||||||
|
if (ref.current && !ref.current.contains(event.target)) {
|
||||||
|
setIsComponentVisible(false);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
document.addEventListener('click', handleClickOutside, true);
|
||||||
|
return () => {
|
||||||
|
document.removeEventListener('click', handleClickOutside, true);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
return { ref, isComponentVisible, setIsComponentVisible };
|
||||||
|
}
|
||||||
|
|
||||||
|
function IceColorPick(props) {
|
||||||
|
const { value, onChange, readOnly } = props;
|
||||||
|
|
||||||
|
const { ref, isComponentVisible, setIsComponentVisible } = useComponentVisible(true);
|
||||||
|
|
||||||
|
const [color, setColor] = useState(value || '#FFF');
|
||||||
|
const [showPicker, setShowPicker] = useState(false);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isComponentVisible) {
|
||||||
|
setShowPicker(false);
|
||||||
|
}
|
||||||
|
}, [isComponentVisible])
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (value) {
|
||||||
|
setColor(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
}, [value]);
|
||||||
|
|
||||||
|
return <div className="colorpicker-container">
|
||||||
|
<div
|
||||||
|
className="colorpicker-preview"
|
||||||
|
onClick={() => {
|
||||||
|
if (!showPicker) {
|
||||||
|
setIsComponentVisible(true);
|
||||||
|
}
|
||||||
|
setShowPicker(!showPicker);
|
||||||
|
}}
|
||||||
|
style={ { backgroundColor: color} }
|
||||||
|
/>
|
||||||
|
<div ref={ref} className={`colorpicker-component ${(readOnly || !showPicker) ? 'hidden': ''}` }>
|
||||||
|
<SketchPicker
|
||||||
|
color={color}
|
||||||
|
disableAlpha
|
||||||
|
presetColors={[]}
|
||||||
|
onChangeComplete={({ hex }) => {
|
||||||
|
onChange(hex);
|
||||||
|
setColor(hex);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IceColorPick;
|
||||||
@@ -21,6 +21,7 @@ class IceDataGroup extends React.Component {
|
|||||||
value = this.parseValue(value);
|
value = this.parseValue(value);
|
||||||
value = value.map(item => ({ ...item, key:item.id } ));
|
value = value.map(item => ({ ...item, key:item.id } ));
|
||||||
const columns = JSON.parse(JSON.stringify(field[1].columns));
|
const columns = JSON.parse(JSON.stringify(field[1].columns));
|
||||||
|
|
||||||
if (!this.props.readOnly) {
|
if (!this.props.readOnly) {
|
||||||
columns.push({
|
columns.push({
|
||||||
title: 'Action',
|
title: 'Action',
|
||||||
@@ -30,6 +31,7 @@ class IceDataGroup extends React.Component {
|
|||||||
),
|
),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{!this.props.readOnly &&
|
{!this.props.readOnly &&
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import IceUpload from './IceUpload';
|
|||||||
import IceDataGroup from './IceDataGroup';
|
import IceDataGroup from './IceDataGroup';
|
||||||
import IceSelect from './IceSelect';
|
import IceSelect from './IceSelect';
|
||||||
import IceLabel from './IceLabel';
|
import IceLabel from './IceLabel';
|
||||||
|
import IceColorPick from './IceColorPick';
|
||||||
|
import IceSignature from './IceSignature';
|
||||||
|
|
||||||
|
|
||||||
const ValidationRules = {
|
const ValidationRules = {
|
||||||
@@ -86,24 +88,36 @@ class IceForm extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { fields, twoColumnLayout } = this.props;
|
const { fields, twoColumnLayout, adapter } = this.props;
|
||||||
|
let formInputs = [];
|
||||||
const formInputs1 = [];
|
const formInputs1 = [];
|
||||||
const formInputs2 = [];
|
const formInputs2 = [];
|
||||||
const columns = !twoColumnLayout ? 1 : 2;
|
const columns = !twoColumnLayout ? 1 : 2;
|
||||||
for (let i = 0; i < fields.length; i++) {
|
for (let i = 0; i < fields.length; i++) {
|
||||||
const formInput = this.createFromField(fields[i], this.props.viewOnly);
|
formInputs.push(
|
||||||
if (formInput != null) {
|
adapter.beforeRenderFieldHook(
|
||||||
|
fields[i][0],
|
||||||
|
this.createFromField(fields[i], this.props.viewOnly),
|
||||||
|
fields[i][1]
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
formInputs = formInputs.filter(input => !!input);
|
||||||
|
|
||||||
|
for (let i = 0; i < formInputs.length; i++) {
|
||||||
|
|
||||||
|
if (formInputs[i] != null) {
|
||||||
if (columns === 1) {
|
if (columns === 1) {
|
||||||
formInputs1.push(formInput);
|
formInputs1.push(formInputs[i]);
|
||||||
} else if (i % 2 === 0) {
|
} else if (i % 2 === 0) {
|
||||||
formInputs1.push(formInput);
|
formInputs1.push(formInputs[i]);
|
||||||
} else {
|
} else {
|
||||||
formInputs2.push(formInput);
|
formInputs2.push(formInputs[i]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const onFormLayoutChange = () => {};
|
const onFormLayoutChange = () => { };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Form
|
<Form
|
||||||
@@ -239,6 +253,9 @@ class IceForm extends React.Component {
|
|||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
} if (data.type === 'textarea') {
|
} if (data.type === 'textarea') {
|
||||||
|
if (!data.rows) {
|
||||||
|
data.rows = 4;
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<Form.Item
|
<Form.Item
|
||||||
labelCol={labelSpan}
|
labelCol={labelSpan}
|
||||||
@@ -249,7 +266,7 @@ class IceForm extends React.Component {
|
|||||||
>
|
>
|
||||||
{viewOnly
|
{viewOnly
|
||||||
? <IceLabel />
|
? <IceLabel />
|
||||||
: <Input.TextArea />}
|
: <Input.TextArea rows={data.rows} />}
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
} if (data.type === 'date') {
|
} if (data.type === 'date') {
|
||||||
@@ -355,6 +372,34 @@ class IceForm extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</Form.Item>
|
</Form.Item>
|
||||||
);
|
);
|
||||||
|
} if (data.type === 'colorpick') {
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
labelCol={labelSpan}
|
||||||
|
name={name}
|
||||||
|
key={name}
|
||||||
|
label={data.label}
|
||||||
|
>
|
||||||
|
<IceColorPick
|
||||||
|
adapter={adapter}
|
||||||
|
field={field}
|
||||||
|
title={data.label}
|
||||||
|
readOnly={viewOnly}
|
||||||
|
/>
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
|
} if (data.type === 'signature') {
|
||||||
|
return (
|
||||||
|
<Form.Item
|
||||||
|
labelCol={labelSpan}
|
||||||
|
label={data.label}
|
||||||
|
key={name}
|
||||||
|
name={name}
|
||||||
|
rules={rules}
|
||||||
|
>
|
||||||
|
<IceSignature readOnly={viewOnly} />
|
||||||
|
</Form.Item>
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class IceFormModal extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
show(data) {
|
show(data) {
|
||||||
|
this.props.adapter.beforeRenderFieldHook = this.props.adapter.beforeRenderField ? this.props.adapter.beforeRenderField(data) : (fieldName, field) => field;
|
||||||
if (!data) {
|
if (!data) {
|
||||||
this.setState({ visible: true });
|
this.setState({ visible: true });
|
||||||
if (this.iceFormReference.current) {
|
if (this.iceFormReference.current) {
|
||||||
|
|||||||
@@ -0,0 +1,83 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import SignatureCanvas from 'react-signature-canvas';
|
||||||
|
import { Button, Modal, Tag } from 'antd';
|
||||||
|
import { VerifiedOutlined } from '@ant-design/icons';
|
||||||
|
|
||||||
|
class IceSignature extends React.Component {
|
||||||
|
constructor(props) {
|
||||||
|
super(props);
|
||||||
|
this.onChange = props.onChange;
|
||||||
|
this.state = {
|
||||||
|
visible: false,
|
||||||
|
};
|
||||||
|
this.signature = React.createRef();
|
||||||
|
}
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
}
|
||||||
|
|
||||||
|
show() {
|
||||||
|
this.setState({ visible: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
setSignature(ref) {
|
||||||
|
if (ref == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const { value } = this.props;
|
||||||
|
if (value != null && value.length > 10) {
|
||||||
|
ref.fromDataURL(value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
hide() {
|
||||||
|
this.setState({ visible: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
clear() {
|
||||||
|
this.signature.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
save() {
|
||||||
|
const data = this.signature.toDataURL('image/png');
|
||||||
|
this.onChange(data);
|
||||||
|
this.setState({ visible: false });
|
||||||
|
}
|
||||||
|
|
||||||
|
render() {
|
||||||
|
const { readOnly } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Modal
|
||||||
|
visible={this.state.visible}
|
||||||
|
title="Signature"
|
||||||
|
maskClosable={false}
|
||||||
|
centered
|
||||||
|
width={300}
|
||||||
|
onCancel={() => { this.hide(); }}
|
||||||
|
footer={[
|
||||||
|
<Button key="cancel" onClick={() => { this.hide(); }}>
|
||||||
|
Cancel
|
||||||
|
</Button>,
|
||||||
|
<Button key="clear" disabled={readOnly} type="dashed" onClick={() => { if (!readOnly) { this.clear(); } }}>
|
||||||
|
Clear
|
||||||
|
</Button>,
|
||||||
|
<Button key="ok" disabled={readOnly} type="primary" onClick={() => { if (!readOnly) { this.save(); } }}>
|
||||||
|
Submit
|
||||||
|
</Button>,
|
||||||
|
]}
|
||||||
|
>
|
||||||
|
<SignatureCanvas ref={(ref) => { this.signature = ref; this.setSignature(ref); }} canvasProps={{ width: 250, height: 200, className: 'sigCanvas', ...( readOnly ? { readOnly } : {}), }} />
|
||||||
|
</Modal>
|
||||||
|
<Tag color="blue" style={{ cursor: 'pointer' }} onClick={() => { this.show(); }}>
|
||||||
|
<VerifiedOutlined />
|
||||||
|
{' '}
|
||||||
|
Sign
|
||||||
|
</Tag>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default IceSignature;
|
||||||
@@ -10,6 +10,7 @@ class IceStepFormModal extends IceFormModal {
|
|||||||
}
|
}
|
||||||
|
|
||||||
show(data) {
|
show(data) {
|
||||||
|
this.props.adapter.beforeRenderFieldHook = this.props.adapter.beforeRenderField ? this.props.adapter.beforeRenderField(data) : (fieldName, field) => field;
|
||||||
if (!data) {
|
if (!data) {
|
||||||
this.setState({ visible: true });
|
this.setState({ visible: true });
|
||||||
if (this.iceFormReference.current) {
|
if (this.iceFormReference.current) {
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ class IceTable extends React.Component {
|
|||||||
};
|
};
|
||||||
|
|
||||||
search = (value) => {
|
search = (value) => {
|
||||||
console.log('search table:' + value);
|
|
||||||
this.setState({ search: value });
|
this.setState({ search: value });
|
||||||
const fetchConfig = this.state.fetchConfig;
|
const fetchConfig = this.state.fetchConfig;
|
||||||
console.log(fetchConfig);
|
console.log(fetchConfig);
|
||||||
@@ -105,12 +104,10 @@ class IceTable extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fetch = (params = {}) => {
|
fetch = (params = {}) => {
|
||||||
console.log('params:', params);
|
|
||||||
//this.setState({ loading: this.state.showLoading });
|
//this.setState({ loading: this.state.showLoading });
|
||||||
this.setState({ loading: true });
|
this.setState({ loading: true });
|
||||||
//const hideMessage = message.loading({ content: 'Loading Latest Data ...', key: 'loadingTable', duration: 1});
|
//const hideMessage = message.loading({ content: 'Loading Latest Data ...', key: 'loadingTable', duration: 1});
|
||||||
const pagination = { ...this.state.pagination };
|
const pagination = { ...this.state.pagination };
|
||||||
console.log('pagination:', pagination);
|
|
||||||
|
|
||||||
if (this.props.adapter.localStorageEnabled) {
|
if (this.props.adapter.localStorageEnabled) {
|
||||||
try {
|
try {
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ class UpdatePasswordModal extends React.Component {
|
|||||||
return this.props.adapter.gt('Password too short');
|
return this.props.adapter.gt('Password too short');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (password.length > 20) {
|
if (password.length > 30) {
|
||||||
return this.props.adapter.gt('Password too long');
|
return this.props.adapter.gt('Password too long');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -943,3 +943,73 @@ table.dataTable{
|
|||||||
.table-row-dark {
|
.table-row-dark {
|
||||||
background-color: #fbfbfb;
|
background-color: #fbfbfb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.mod-tab {
|
||||||
|
margin-bottom:0px;margin-left:5px;border-bottom: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.row {
|
||||||
|
margin-right: 0px;
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colorpicker-container {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.colorpicker-preview {
|
||||||
|
display: block;
|
||||||
|
width: 30px;
|
||||||
|
height: 30px;
|
||||||
|
border: 5px #FFF solid;
|
||||||
|
border-radius: 4px;
|
||||||
|
box-shadow: 0 0 6px 1px #c7c7c78f;
|
||||||
|
}
|
||||||
|
|
||||||
|
.colorpicker-component {
|
||||||
|
display: block;
|
||||||
|
position: absolute;
|
||||||
|
bottom: -10px;
|
||||||
|
left: 44px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu>li>a:hover {
|
||||||
|
background-color: #5ca4e7 i !important;
|
||||||
|
}
|
||||||
|
.sigCanvas {
|
||||||
|
border: 1px dashed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sigContainer {
|
||||||
|
width: 80%;
|
||||||
|
height: 80%;
|
||||||
|
margin: 0 auto;
|
||||||
|
background-color: #fff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sigPad {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sigImage {
|
||||||
|
background-size: 200px 50px;
|
||||||
|
width: 200px;
|
||||||
|
height: 50px;
|
||||||
|
background-color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dropdown-menu>li>a:hover {
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ant-form-item-label>label {
|
||||||
|
position: relative;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
height: auto !important;
|
||||||
|
color: rgba(0,0,0,.85);
|
||||||
|
font-size: 14px;
|
||||||
|
word-break: break-word;
|
||||||
|
white-space: break-spaces;
|
||||||
|
}
|
||||||
Vendored
+22
-1
@@ -1 +1,22 @@
|
|||||||
var _0x3a83=['Are\x20you\x20sure\x20you\x20want\x20to\x20delete\x20this\x20item\x20?','Max\x20Salary','#changePasswordBtn','_children','UserRole','<option\x20value=\x22__val__\x22>__text__</option>','DeductionGroupAdapter','showSave','monthly_installment','gracePeriod','Error','tabPayrollData','equals','maxLine','.filterBtn','changePasswordConfirm','httpsAgent','modes','issued','Timeline','_div_inner','./Cancel','saveUsage','page','Date\x20Time','./dispatchRequest','content-type','yellow','nodes','Contact\x20details','marital_status','ProjectAdapter','Payroll\x20Report\x20Column','createRef','gender','attachment3','formId','Shift-','getMappedFields','this','CommonDataImporter','domain=','\x20Courses','Display\x20Status','y-1-2','getElementById','viewFrom','edit','Success','#attendnaceCanvasOutWrapper','aqua','process.binding\x20is\x20not\x20supported','false','styles','ellipsis','isParent','fromCharCode','getSelection','<img\x20src=\x22_img_\x22\x20class=\x22img-circle\x22\x20style=\x22width:45px;height:\x2045px;\x22\x20alt=\x22User\x20Image\x22>','fillForm','ReactNative','sendCellDataUpdates','geekblue','TravelRequest','lowerCondition','type','permissions','dependencies','Time-In','helpers','Driving\x20License\x20No','#tabPageCompanyGraph','stateAfter','EmployeeCompanyLoanAdapter','CompanyLoanAdapter','Cancellation\x20Requested','#numberOfCourses','vendor','18px','./adapters/xhr','localVars','closeModal','png','Certification','rmClass','tooltip','modeGen','period_months','preProcessRemoteTableData','triple','remove','upload','getClientMessage','clearWhenEmpty','rowFieldName','formFieldsToData','unmountComponentAtNode','around','createField','User\x20Level','List','./FormValidation','insertBefore','addActualFields','&ob=','curOp','draggingText','min-width:\x201px','start_time','View','saveUser','Document\x20Id','minHeight','selForContextMenu','fileupload','other_id','cyan','Is\x20ID\x20Field','findWordAt','Authorization','ArchivedEmployee','CodeMirror-wrap','Invalid\x20attempt\x20to\x20spread\x20non-iterable\x20instance.\x0aIn\x20order\x20to\x20be\x20iterable,\x20non-array\x20objects\x20must\x20have\x20a\x20[Symbol.iterator]()\x20method.','addToHistory','#tabPageAttendanceGraph\x20div','componentWillUnmount','./helpers/bind','&sSearch=','undefined','payrollColumn','orderBy','work_station_id','menu+name','phrases','initFieldMasterDataResponse','atomic','getSubHeaderTitle','<canvas\x20id=\x22attendnaceCanvasIn\x22\x20height=\x22156\x22\x20width=\x22208\x22\x20style=\x22border:\x201px\x20#222\x20dotted;\x22></canvas>','AttendanceGraphAdapter','setPermissions','_message','pay_frequency','detachLine','\x20Departments','\x20Employees','\x20Active','px;\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20top:\x20','autofocus','getKey','charCodeAt','fa\x20fa\x20fa-file-code-o','change','<img\x20class=\x22tableActionButton\x22\x20src=\x22_BASE_images/clone.png\x22\x20style=\x22margin-left:15px;cursor:pointer;\x22\x20rel=\x22tooltip\x22\x20title=\x22Copy\x22\x20onclick=\x22modJs.copyRow(_id_);return\x20false;\x22></img>','.dataTables_filter\x20label','OrEmpty','gutterFiller','employee_id','empty','lastAnchorOffset','activeElt','(?:$|\x5cs)','offsetHeight','OvertimeRequest','Male','./AdapterBase','menu','hasOwnProperty','Employee\x20Projects','setPhotoAttendance','tables','pageSize','addClass','_id_','pagination','vardef','getItem','Fragment','#plainMessageModel','payroll_','Calculation\x20Process','format','moveV','Reading','parse','showAll','viewport','contenteditable','admin=users','<div\x20style=\x22width:150px;\x22><img\x20class=\x22tableActionButton\x22\x20src=\x22_BASE_images/edit.png\x22\x20style=\x22margin-left:15px;cursor:pointer;\x22\x20rel=\x22tooltip\x22\x20title=\x22Edit\x22\x20onclick=\x22modJs.edit(_id_);return\x20false;\x22></img><img\x20class=\x22tableActionButton\x22\x20src=\x22_BASE_images/delete.png\x22\x20style=\x22margin-left:15px;cursor:pointer;\x22\x20rel=\x22tooltip\x22\x20title=\x22Delete\x22\x20onclick=\x22modJs.deletePayrollGroup(_id_);return\x20false;\x22></img><img\x20class=\x22tableActionButton\x22\x20src=\x22_BASE_images/clone.png\x22\x20style=\x22margin-left:15px;cursor:pointer;\x22\x20rel=\x22tooltip\x22\x20title=\x22Duplicate\x22\x20onclick=\x22modJs.copyRow(_id_);return\x20false;\x22></img></div>','deleteRow','string-2','.tableActionButton','Show','innerHeight','textarea','initMasterDataReader','.select2Multi','Cancel','setScrollLeft','Restricted\x20Manager','numberOfLeaves','<div\x20style=\x22width:80px;\x22><img\x20class=\x22tableActionButton\x22\x20src=\x22_BASE_images/download.png\x22\x20style=\x22cursor:pointer;\x22\x20rel=\x22tooltip\x22\x20title=\x22Download\x22\x20onclick=\x22download(_name_);return\x20false;\x22></img></div>','#_delete_#','px;','response','defineInitHook','rbottom','Expiry\x20Date','lookAhead','openStatus','loading','toString','filtersContainer','.select2Field','lineNumber','request','currLine truncated
|
var _0xc7a5=['saveUserFailCallBack','setSelection','fillRect','work_station_id','getFormParameters','transparent\x20transparent\x20rgba(0,0,0,.1)\x20transparent','Alt-','\x5c$&','./_isKeyable','reload','overlays','<a\x20href=\x22#\x22\x20class=\x22list-group-item\x22>','goCharLeft','Social\x20Security\x20Number','#7c4dff','ClockCircleOutlined','attendnaceMapCanvasOut','null-label','hidden','Employee\x20contract\x20re-activated.','nic_num','codemirror/addon/edit/closebrackets','008b8b','Employee','DataImportAdapter','left','uid','optimizelegibility','project','currentStyle','inset\x200\x200\x200\x203px\x20','expire_notification_week','origFilter','lineN','replaceChild','#82b1ff','dragLabel','Company\x20Structure\x20is\x20having\x20a\x20cyclic\x20dependency','CodeMirror-vscrollbar','#283593','AAAlarge','touchstart','.modal-backdrop','control2','keys','<div\x20style=\x22width:80px;\x22>_edit__delete__photo_</div>','.datetimefield','DataView','require','borderBottom','compareEndPoints','cachedTextHeight','ea7e5d','./_getSymbolsIn','flex','Number\x20required','5px','autoCloseBrackets','pointerEvents','delGroupBefore','cwd','Item\x20Removed','stateAfter','For\x20this\x20user\x20type,\x20you\x20have\x20to\x20assign\x20an\x20employee\x20when\x20adding\x20or\x20editing\x20the\x20user.<br/>','keyword\x20b','#80deea','clearOnResize','Action','done','Time\x20Zone','Swatches','ASC','form','buffer','__proto__','dependOnField','Calling\x20PropTypes\x20validators\x20directly\x20is\x20not\x20supported\x20by\x20the\x20`prop-types`\x20package.\x20Use\x20`PropTypes.checkPropTypes()`\x20to\x20call\x20them.\x20Read\x20more\x20at\x20http://fb.me/use-check-prop-types','\x20for\x20all\x20ranges','calculation_function','linear-gradient(-180deg,\x20#F0F0F0\x200%,\x20#D4D4D4\x20100%)','./_Promise','employees/','readOnly','every','props','2px\x20#fff\x20solid','#FFF','#attendnaceMapCanvasOut','startGracePeriod','isInteger','setCurrentPayroll','Monthly\x20Installment','#aa00ff','getTableHTMLTemplate','addFailed','°,\x20','_formFileds','38px','.timefield','nl2br','setBaseUrl','#f44336','./_baseIsSet','_div','./IceFormModal','getSuccessCallBack','#000000','`\x20is\x20marked\x20as\x20required\x20in\x20`','service.php','Suspense','handleTaskHover','throwIfRequested','Pos','showEdit','itemNameLower','triangleShadow','setDataPipe','./isArguments','AlphaPointer','local','renderModel','initAdminCustomFields','#plainMessageModel\x20.modal-body','out_ip','Speaking','scale(1)','#B80000','from','execCommand','_lastVelocity','uploaded','14px','./_Map','An\x20email\x20has\x20been\x20sent\x20to\x20','CompactPicker','findNext','head','response','indirect_supervisors','./debounce','getLuminance','.completeBtnTable','556b2f','onBegin','./_root','UploadOutlined','Cache','_applyCombination','extendSelectionsBy','replaceSelections','popupTop','borderRadius','SettingAdapter','markers','./components/twitter/Twitter','#C45100','fun','Reset\x20Filters','Descriptions','masterDataReader','getIconByFileType','./_toSource','length','Child','select2','./_toKey','ops','module_id','TrainingSession','\x20status','addMinutes','Attachment\x203','setLocalDate','mousedown','leave','barMeasure','Address\x20Line\x202','../common','SupportedLanguage','isEmpty','changePassword','DownloadOutlined','0ff','inset\x200\x201px\x200\x200\x20rgba(255,255,255,.2),\x20inset\x200\x20-1px\x200\x200\x20rgba(0,0,0,.02)','../../../api/IdNameAdapter','Body','Authorization','previousView','Hue','false','Mod','value','currentElement','Tr:','react.suspense','dragleave','./eq','EmployeeDistributionChart','viewOffset','data_import_definition','isConcurrentMode','#0d47a1','handleActive','getDataItemByKeyValues','GooglePointerCircle','toggles','wheelStartY','window','EmployeeCertificationAdapter','Component','city','Last\x20Installment\x20Date',',\x200)\x200%,\x0a\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20\x20rgba(','Error\x20saving\x20attendance\x20entry','./adapters/http','image_out','Columns\x20to\x20Add','-16px','NoBtn','#8B572A','handlers','../../../api/FormValidation','maxBodyLength','purple','detachEvent','./isObject','../helpers/isAbsoluteURL','moveOnDrag','commands','gutterClass','fixJSON','maybeUnhiddenMarkers','undo','nodeType','top','listSelections','_mouseButtonDown','Input','travel_date','y-2-1\x20h:s:00','employee_id','bdb76b','./_equalByTag','exports','.signatureField','drag','initForm','87ceeb','toHexString','addClass','isURLSearchParams','_div_inner','Industry','mask','Select','Employee\x20Distribution','onTimeout','2px\x20solid\x20#B3B3B3','extend','Photoshop','translate(-8px,\x20-5px)','updateDataSuccessCallBack','./_safeGet','address1','setHistory','CountryAdapter','indentWithTabs','getShowAddNew','SUCCESS','Max\x20Salary','./Swatch','getRequestKey','Greater\x20than\x20or\x20Equal','#666','./_stackClear','da70d6','-02-29','location','handleMouseDown','Line','small','createDocumentFragment','returnValue','316px','onContextMenu','singleSelection','localStorage','23px','16px','respoLine truncated
|
||||||
|
object-assign
|
||||||
|
(c) Sindre Sorhus
|
||||||
|
@license MIT
|
||||||
|
*/
|
||||||
|
'use strict';var _0x13c4e0=Object[_0x25cb3e('0x5e2')],_0x36daff=Object[_0x25cb3e('0xe02')][_0x25cb3e('0xe9c')],_0xa72e14=Object['prototype'][_0x25cb3e('0x166')];function _0x29f70c(_0x52a334){var _0x35c13f=_0x25cb3e;if(null==_0x52a334)throw new TypeError(_0x35c13f('0xf3f'));return Object(_0x52a334);}_0x6194ed[_0x25cb3e('0x64')]=function(){var _0x57d07e=_0x25cb3e;try{if(!Object['assign'])return!0x1;var _0x587f82=new String(_0x57d07e('0xc57'));if(_0x587f82[0x5]='de','5'===Object[_0x57d07e('0x14a')](_0x587f82)[0x0])return!0x1;for(var _0x36410d={},_0x1d95d7=0x0;_0x1d95d7<0xa;_0x1d95d7++)_0x36410d['_'+String[_0x57d07e('0x1006')](_0x1d95d7)]=_0x1d95d7;if(_0x57d07e('0x41e')!==Object[_0x57d07e('0x14a')](_0x36410d)[_0x57d07e('0xd8e')](function(_0x182254){return _0x36410d[_0x182254];})[_0x57d07e('0x2e2')](''))return!0x1;var _0xc78ca9={};return _0x57d07e('0x1b3')['split']('')[_0x57d07e('0xb77')](function(_0x242daf){_0xc78ca9[_0x242daf]=_0x242daf;}),_0x57d07e('0x1b3')===Object['keys'](Object['assign']({},_0xc78ca9))[_0x57d07e('0x2e2')]('');}catch(_0x860379){return!0x1;}}()?Object['assign']:function(_0x42ab68,_0x1ced37){var _0x600af4=_0x25cb3e;for(var _0x190682,_0x4bc7f5,_0x37f4de=_0x29f70c(_0x42ab68),_0x2187a9=0x1;_0x2187a9<arguments[_0x600af4('0x13')];_0x2187a9++){for(var _0x5657e5 in _0x190682=Object(arguments[_0x2187a9]))_0x36daff[_0x600af4('0xfd2')](_0x190682,_0x5657e5)&&(_0x37f4de[_0x5657e5]=_0x190682[_0x5657e5]);if(_0x13c4e0){_0x4bc7f5=_0x13c4e0(_0x190682);for(var _0x2d854a=0x0;_0x2d854a<_0x4bc7f5[_0x600af4('0x13')];_0x2d854a++)_0xa72e14[_0x600af4('0xfd2')](_0x190682,_0x4bc7f5[_0x2d854a])&&(_0x37f4de[_0x4bc7f5[_0x2d854a]]=_0x190682[_0x4bc7f5[_0x2d854a]]);}}return _0x37f4de;};},{}],0x127:[function(_0x1d7482,_0x1abae6,_0x160137){var _0x4e9a1e=_0x548f48;'use strict';function _0x4dd413(_0x46f686,_0x2023d4,_0x1e939e,_0x2e8c77,_0x26c7aa){}_0x4dd413[_0x4e9a1e('0x408')]=function(){0x0;},_0x1abae6[_0x4e9a1e('0x64')]=_0x4dd413;},{'./lib/ReactPropTypesSecret':0x12b}],0x128:[function(_0x425c52,_0x4d14ba,_0x4a30cc){var _0x542abc=_0x548f48;'use strict';var _0x268009=_0x425c52(_0x542abc('0xcc6'));function _0xe01fd3(){}function _0x452b37(){}_0x452b37[_0x542abc('0x408')]=_0xe01fd3,_0x4d14ba[_0x542abc('0x64')]=function(){function _0x5bc254(_0x3c31d8,_0xf98d0c,_0x5460c2,_0x1ab4b3,_0x51bbbb,_0x2a1254){var _0x2426ae=_0x5376;if(_0x2a1254!==_0x268009){var _0x496244=new Error('Calling\x20PropTypes\x20validators\x20directly\x20is\x20not\x20supported\x20by\x20the\x20`prop-types`\x20package.\x20Use\x20PropTypes.checkPropTypes()\x20to\x20call\x20them.\x20Read\x20more\x20at\x20http://fb.me/use-check-prop-types');throw _0x496244[_0x2426ae('0x3ea')]='Invariant\x20Violation',_0x496244;}}function _0x4d4882(){return _0x5bc254;}_0x5bc254['isRequired']=_0x5bc254;var _0x15d5c3={'array':_0x5bc254,'bool':_0x5bc254,'func':_0x5bc254,'number':_0x5bc254,'object':_0x5bc254,'string':_0x5bc254,'symbol':_0x5bc254,'any':_0x5bc254,'arrayOf':_0x4d4882,'element':_0x5bc254,'elementType':_0x5bc254,'instanceOf':_0x4d4882,'node':_0x5bc254,'objectOf':_0x4d4882,'oneOf':_0x4d4882,'oneOfType':_0x4d4882,'shape':_0x4d4882,'exact':_0x4d4882,'checkPropTypes':_0x452b37,'resetWarningCache':_0xe01fd3};return _0x15d5c3['PropTypes']=_0x15d5c3,_0x15d5c3;};},{'./lib/ReactPropTypesSecret':0x12b}],0x129:[function(_0xd8f4f4,_0x2e526c,_0x4f4c11){var _0x619f1a=_0x548f48;'use strict';var _0x5b2dce=_0xd8f4f4(_0x619f1a('0x3b4')),_0x419a83=_0xd8f4f4(_0x619f1a('0x4dc')),_0x41991a=_0xd8f4f4(_0x619f1a('0xcc6')),_0x28e1f0=_0xd8f4f4(_0x619f1a('0x201')),_0x54b172=Function[_0x619f1a('0xfd2')][_0x619f1a('0x91e')](Object[_0x619f1a('0xe02')][_0x619f1a('0xe9c')]),_0x247e46=function(){};function _0x3d626e(){return null;}_0x2e526c[_0x619f1a('0x64')]=function(_0x440cd7,_0x561984){var _0x36be7f=_0x619f1a,_0x3d9050=_0x36be7f('0x106c')==typeof Symbol&&Symbol[_0x36be7f('0x57b')],_0x58556d={'array':_0x11b374(_0x36be7f('0x6c1')),'bool':_0x11b374(_0x36be7f('0x3a4')),'func':_0x11b374(_0x36be7f('0x106c')),'number':_0x11b374(_0x36be7f('0x67b')),'object':_0x11b374(_0x36be7f('0xb3f')),'string':_0x11b374(_0x36be7f('0x2fd')),'symbol':_0x11b374(_0x36be7f('0x43c')),'any':_0x39a976(_0x3d626e),'arrayOf':function(_0x6aaa33){return _0x39a976(function(_0x6e21e1,_0x5fcd51,_0x5557e4,_0x481ff9,_0x5ef767){var _0x1a2e7d=_0x5376;if(_0x1a2e7d('0x106c')!=typeof _0x6aaa33)return new _0x17c7ca(_0x1a2e7d('0x9e2')+_0x5ef767+_0x1a2e7d('0x880')+_0x5557e4+_0x1a2e7d('0x6cc'));var _0x56503c=_0x6e21e1[_0x5fcd51];if(!Array[_0x1a2e7d('0xb66')](_0x56503c))return new _0x17c7ca(_0x1a2e7d('0xf69')+_0x481ff9+'\x20`'+_0x5ef767+_0x1a2e7d('0xf15')+_0x474215(_0x56503c)+_0x1a2e7d('0x835')+_0x5557e4+_0x1a2e7d('0x205'));for(var _0x59d58a=0x0;_0x59d58a<_0x56503c[_0x1a2e7d('0x13')];_0x59d58a++){var _0x48d01a=_0x6aaa33(_0x56503c,_0x59d58a,_0x5557e4,_0x481ff9,_0x5ef767+'['+_0x59d58a+']',_0x41991a);if(_0x48d01a instanceof Error)return _0x48d01a;}return null;});},'element':_0x39a976(function(_0x504009,_0x5ea1fb,_0x396473,_0x469aca,_0x4b05fc){var _0x5c753d=_0x36bLine truncated
|
||||||
|
* react-is.development.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
'use strict';_0x4e4131('0xcd8')!==_0x193ca5['env'][_0x4e4131('0xa8d')]&&function(){var _0x3a5777=_0x4e4131,_0x49875f=_0x3a5777('0x106c')==typeof Symbol&&Symbol[_0x3a5777('0x80e')],_0x332c65=_0x49875f?Symbol[_0x3a5777('0x80e')](_0x3a5777('0x74f')):0xeac7,_0x37ca6c=_0x49875f?Symbol['for']('react.portal'):0xeaca,_0x1dd293=_0x49875f?Symbol[_0x3a5777('0x80e')](_0x3a5777('0xb04')):0xeacb,_0x59c6b4=_0x49875f?Symbol[_0x3a5777('0x80e')](_0x3a5777('0x7cb')):0xeacc,_0xab42f6=_0x49875f?Symbol[_0x3a5777('0x80e')](_0x3a5777('0xbd3')):0xead2,_0x13c5c6=_0x49875f?Symbol[_0x3a5777('0x80e')](_0x3a5777('0xdb1')):0xeacd,_0x32775b=_0x49875f?Symbol[_0x3a5777('0x80e')](_0x3a5777('0x8b2')):0xeace,_0x3c9cfc=_0x49875f?Symbol[_0x3a5777('0x80e')](_0x3a5777('0x84f')):0xeacf,_0x3f68f2=_0x49875f?Symbol[_0x3a5777('0x80e')](_0x3a5777('0x2b8')):0xeacf,_0x31c925=_0x49875f?Symbol[_0x3a5777('0x80e')](_0x3a5777('0x191')):0xead0,_0x16f4c2=_0x49875f?Symbol['for'](_0x3a5777('0x33')):0xead1,_0x35d026=_0x49875f?Symbol[_0x3a5777('0x80e')]('react.suspense_list'):0xead8,_0x7b45e8=_0x49875f?Symbol[_0x3a5777('0x80e')](_0x3a5777('0xe93')):0xead3,_0xf9c1fa=_0x49875f?Symbol[_0x3a5777('0x80e')](_0x3a5777('0xbbe')):0xead4,_0x2e57cd=_0x49875f?Symbol['for'](_0x3a5777('0x107')):0xead9,_0x2ff060=_0x49875f?Symbol[_0x3a5777('0x80e')](_0x3a5777('0xc06')):0xead5,_0x50dcb9=_0x49875f?Symbol[_0x3a5777('0x80e')](_0x3a5777('0xd7b')):0xead6,_0xf39454=_0x49875f?Symbol['for']('react.scope'):0xead7;function _0x25e3d2(_0xace507){var _0x13a66c=_0x3a5777;if(_0x13a66c('0xb3f')==typeof _0xace507&&null!==_0xace507){var _0x5db670=_0xace507['$$typeof'];switch(_0x5db670){case _0x332c65:var _0x2add06=_0xace507[_0x13a66c('0x921')];switch(_0x2add06){case _0x3c9cfc:case _0x3f68f2:case _0x1dd293:case _0xab42f6:case _0x59c6b4:case _0x16f4c2:return _0x2add06;default:var _0xd03078=_0x2add06&&_0x2add06[_0x13a66c('0x1015')];switch(_0xd03078){case _0x32775b:case _0x31c925:case _0xf9c1fa:case _0x7b45e8:case _0x13c5c6:return _0xd03078;default:return _0x5db670;}}case _0x37ca6c:return _0x5db670;}}}var _0x1d2fce=_0x3c9cfc,_0x2a5436=_0x3f68f2,_0x35c4b6=_0x32775b,_0x37d03d=_0x13c5c6,_0x4b0d7f=_0x332c65,_0x49cc3d=_0x31c925,_0x1c375a=_0x1dd293,_0x46bbf7=_0xf9c1fa,_0x3a8c8e=_0x7b45e8,_0x4595a7=_0x37ca6c,_0x55738a=_0xab42f6,_0x14f728=_0x59c6b4,_0x23afca=_0x16f4c2,_0x26e5e1=!0x1;function _0x21189a(_0x945fcc){return _0x25e3d2(_0x945fcc)===_0x3f68f2;}_0x1b0098[_0x3a5777('0x4ac')]=_0x1d2fce,_0x1b0098[_0x3a5777('0xf8a')]=_0x2a5436,_0x1b0098[_0x3a5777('0x307')]=_0x35c4b6,_0x1b0098['ContextProvider']=_0x37d03d,_0x1b0098[_0x3a5777('0x5b0')]=_0x4b0d7f,_0x1b0098['ForwardRef']=_0x49cc3d,_0x1b0098['Fragment']=_0x1c375a,_0x1b0098[_0x3a5777('0x80b')]=_0x46bbf7,_0x1b0098[_0x3a5777('0x741')]=_0x3a8c8e,_0x1b0098[_0x3a5777('0x813')]=_0x4595a7,_0x1b0098['Profiler']=_0x55738a,_0x1b0098[_0x3a5777('0x10df')]=_0x14f728,_0x1b0098[_0x3a5777('0x114f')]=_0x23afca,_0x1b0098[_0x3a5777('0xa21')]=function(_0x28a1da){var _0x119afe=_0x3a5777;return _0x26e5e1||(_0x26e5e1=!0x0,console[_0x119afe('0x783')](_0x119afe('0x648'))),_0x21189a(_0x28a1da)||_0x25e3d2(_0x28a1da)===_0x3c9cfc;},_0x1b0098[_0x3a5777('0x39')]=_0x21189a,_0x1b0098[_0x3a5777('0x815')]=function(_0x28a019){return _0x25e3d2(_0x28a019)===_0x32775b;},_0x1b0098['isContextProvider']=function(_0x3d841f){return _0x25e3d2(_0x3d841f)===_0x13c5c6;},_0x1b0098[_0x3a5777('0xa95')]=function(_0x4c9008){var _0xc5ad9a=_0x3a5777;return _0xc5ad9a('0xb3f')==typeof _0x4c9008&&null!==_0x4c9008&&_0x4c9008[_0xc5ad9a('0x1015')]===_0x332c65;},_0x1b0098[_0x3a5777('0x193')]=function(_0x2ee539){return _0x25e3d2(_0x2ee539)===_0x31c925;},_0x1b0098[_0x3a5777('0x6d8')]=function(_0x5e2a02){return _0x25e3d2(_0x5e2a02)===_0x1dd293;},_0x1b0098['isLazy']=function(_0x24eabe){return _0x25e3d2(_0x24eabe)===_0xf9c1fa;},_0x1b0098[_0x3a5777('0x3b1')]=function(_0x4adf34){return _0x25e3d2(_0x4adf34)===_0x7b45e8;},_0x1b0098[_0x3a5777('0x9ea')]=function(_0x12e5c6){return _0x25e3d2(_0x12e5c6)===_0x37ca6c;},_0x1b0098[_0x3a5777('0xef')]=function(_0x20e2bb){return _0x25e3d2(_0x20e2bb)===_0xab42f6;},_0x1b0098[_0x3a5777('0xfb9')]=function(_0x139a04){return _0x25e3d2(_0x139a04)===_0x59c6b4;},_0x1b0098[_0x3a5777('0x89f')]=function(_0x1bb899){return _0x25e3d2(_0x1bb899)===_0x16f4c2;},_0x1b0098[_0x3a5777('0xf13')]=function(_0x554a3d){var _0x482918=_0x3a5777;return _0x482918('0x2fd')==typeof _0x554a3d||_0x482918('0x106c')==typeof _0x554a3d||_0x554a3d===_0x1dd293||_0x554a3d===_0x3f68f2||_0x554a3d===_0xab42f6||_0x554a3d===_0x59c6b4||_0x554a3d===_0x16f4c2||_0x554a3d===_0x35d026||_0x482918('0xb3f')==typeof _0x554a3d&&null!==_0x554a3d&&(_0x554a3d[_0x482918('0x1015')]===_0xf9c1fa||_0x554a3d[_0x482918('0x1015')]===_0x7b45e8||_0x554a3d[_0x482918('0x1015')]===_0x13c5c6||_0x554a3d[_0x482918('0x1015')]===_0x32775b||_0x554a3d['$$typeof']===_0x31c925||_0x554a3d[_0x482918('0x1015')]===_0x2ff060||_0x554a3d['$$typeof']===_0x50dcb9||_0x554a3d[_0x482918('0x1015')]===_0xf39454||_0x554a3d[_0x482918('0x1015')]===_0x2e57cd);},_0x1b0098[_0x3a5777('0x30c')]=_0Line truncated
|
||||||
|
* react-is.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
'use strict';var _0x38a1a6=_0x5ee9dc('0x106c')==typeof Symbol&&Symbol[_0x5ee9dc('0x80e')],_0x1b74cf=_0x38a1a6?Symbol['for']('react.element'):0xeac7,_0x1f0aea=_0x38a1a6?Symbol[_0x5ee9dc('0x80e')](_0x5ee9dc('0xe34')):0xeaca,_0x38ddf7=_0x38a1a6?Symbol[_0x5ee9dc('0x80e')](_0x5ee9dc('0xb04')):0xeacb,_0x282002=_0x38a1a6?Symbol['for'](_0x5ee9dc('0x7cb')):0xeacc,_0xde6d68=_0x38a1a6?Symbol[_0x5ee9dc('0x80e')](_0x5ee9dc('0xbd3')):0xead2,_0x499648=_0x38a1a6?Symbol[_0x5ee9dc('0x80e')](_0x5ee9dc('0xdb1')):0xeacd,_0x1224c8=_0x38a1a6?Symbol[_0x5ee9dc('0x80e')](_0x5ee9dc('0x8b2')):0xeace,_0x2d58ff=_0x38a1a6?Symbol['for']('react.async_mode'):0xeacf,_0x69f271=_0x38a1a6?Symbol[_0x5ee9dc('0x80e')](_0x5ee9dc('0x2b8')):0xeacf,_0x2b24e7=_0x38a1a6?Symbol[_0x5ee9dc('0x80e')](_0x5ee9dc('0x191')):0xead0,_0x2b91fb=_0x38a1a6?Symbol[_0x5ee9dc('0x80e')](_0x5ee9dc('0x33')):0xead1,_0xb26cb=_0x38a1a6?Symbol['for'](_0x5ee9dc('0x92b')):0xead8,_0x5dea43=_0x38a1a6?Symbol['for'](_0x5ee9dc('0xe93')):0xead3,_0x2ad335=_0x38a1a6?Symbol[_0x5ee9dc('0x80e')](_0x5ee9dc('0xbbe')):0xead4,_0x4c2a82=_0x38a1a6?Symbol[_0x5ee9dc('0x80e')](_0x5ee9dc('0x107')):0xead9,_0x45b7e5=_0x38a1a6?Symbol[_0x5ee9dc('0x80e')]('react.fundamental'):0xead5,_0x63aa0=_0x38a1a6?Symbol[_0x5ee9dc('0x80e')](_0x5ee9dc('0xd7b')):0xead6,_0xf97f29=_0x38a1a6?Symbol['for']('react.scope'):0xead7;function _0x23b89f(_0x1399ee){var _0x2569dc=_0x5ee9dc;if(_0x2569dc('0xb3f')==typeof _0x1399ee&&null!==_0x1399ee){var _0x3de5f2=_0x1399ee[_0x2569dc('0x1015')];switch(_0x3de5f2){case _0x1b74cf:switch(_0x1399ee=_0x1399ee[_0x2569dc('0x921')]){case _0x2d58ff:case _0x69f271:case _0x38ddf7:case _0xde6d68:case _0x282002:case _0x2b91fb:return _0x1399ee;default:switch(_0x1399ee=_0x1399ee&&_0x1399ee[_0x2569dc('0x1015')]){case _0x1224c8:case _0x2b24e7:case _0x2ad335:case _0x5dea43:case _0x499648:return _0x1399ee;default:return _0x3de5f2;}}case _0x1f0aea:return _0x3de5f2;}}}function _0x2c4eff(_0x361966){return _0x23b89f(_0x361966)===_0x69f271;}_0x52ca0f[_0x5ee9dc('0x4ac')]=_0x2d58ff,_0x52ca0f[_0x5ee9dc('0xf8a')]=_0x69f271,_0x52ca0f[_0x5ee9dc('0x307')]=_0x1224c8,_0x52ca0f['ContextProvider']=_0x499648,_0x52ca0f['Element']=_0x1b74cf,_0x52ca0f[_0x5ee9dc('0xb1a')]=_0x2b24e7,_0x52ca0f[_0x5ee9dc('0x18f')]=_0x38ddf7,_0x52ca0f[_0x5ee9dc('0x80b')]=_0x2ad335,_0x52ca0f[_0x5ee9dc('0x741')]=_0x5dea43,_0x52ca0f[_0x5ee9dc('0x813')]=_0x1f0aea,_0x52ca0f['Profiler']=_0xde6d68,_0x52ca0f['StrictMode']=_0x282002,_0x52ca0f['Suspense']=_0x2b91fb,_0x52ca0f['isAsyncMode']=function(_0xdaffb7){return _0x2c4eff(_0xdaffb7)||_0x23b89f(_0xdaffb7)===_0x2d58ff;},_0x52ca0f[_0x5ee9dc('0x39')]=_0x2c4eff,_0x52ca0f['isContextConsumer']=function(_0x6ded89){return _0x23b89f(_0x6ded89)===_0x1224c8;},_0x52ca0f[_0x5ee9dc('0xfe3')]=function(_0x5d89ea){return _0x23b89f(_0x5d89ea)===_0x499648;},_0x52ca0f[_0x5ee9dc('0xa95')]=function(_0x432089){var _0x27a550=_0x5ee9dc;return _0x27a550('0xb3f')==typeof _0x432089&&null!==_0x432089&&_0x432089['$$typeof']===_0x1b74cf;},_0x52ca0f['isForwardRef']=function(_0x3cb40f){return _0x23b89f(_0x3cb40f)===_0x2b24e7;},_0x52ca0f[_0x5ee9dc('0x6d8')]=function(_0x4dab45){return _0x23b89f(_0x4dab45)===_0x38ddf7;},_0x52ca0f['isLazy']=function(_0x4a2c19){return _0x23b89f(_0x4a2c19)===_0x2ad335;},_0x52ca0f[_0x5ee9dc('0x3b1')]=function(_0x983287){return _0x23b89f(_0x983287)===_0x5dea43;},_0x52ca0f[_0x5ee9dc('0x9ea')]=function(_0x12fe59){return _0x23b89f(_0x12fe59)===_0x1f0aea;},_0x52ca0f[_0x5ee9dc('0xef')]=function(_0x4b1f9a){return _0x23b89f(_0x4b1f9a)===_0xde6d68;},_0x52ca0f[_0x5ee9dc('0xfb9')]=function(_0x1ad003){return _0x23b89f(_0x1ad003)===_0x282002;},_0x52ca0f[_0x5ee9dc('0x89f')]=function(_0x5e7790){return _0x23b89f(_0x5e7790)===_0x2b91fb;},_0x52ca0f[_0x5ee9dc('0xf13')]=function(_0x301d02){var _0x179ba2=_0x5ee9dc;return'string'==typeof _0x301d02||_0x179ba2('0x106c')==typeof _0x301d02||_0x301d02===_0x38ddf7||_0x301d02===_0x69f271||_0x301d02===_0xde6d68||_0x301d02===_0x282002||_0x301d02===_0x2b91fb||_0x301d02===_0xb26cb||'object'==typeof _0x301d02&&null!==_0x301d02&&(_0x301d02[_0x179ba2('0x1015')]===_0x2ad335||_0x301d02[_0x179ba2('0x1015')]===_0x5dea43||_0x301d02[_0x179ba2('0x1015')]===_0x499648||_0x301d02[_0x179ba2('0x1015')]===_0x1224c8||_0x301d02['$$typeof']===_0x2b24e7||_0x301d02[_0x179ba2('0x1015')]===_0x45b7e5||_0x301d02[_0x179ba2('0x1015')]===_0x63aa0||_0x301d02[_0x179ba2('0x1015')]===_0xf97f29||_0x301d02[_0x179ba2('0x1015')]===_0x4c2a82);},_0x52ca0f['typeOf']=_0x23b89f;},{}],0x165:[function(_0x1058c6,_0x3e7675,_0x417bbf){var _0x50501d=_0x548f48;(function(_0x24a836){var _0x1d759b=_0x5376;'use strict';_0x1d759b('0xcd8')===_0x24a836[_0x1d759b('0xdcb')][_0x1d759b('0xa8d')]?_0x3e7675['exports']=_0x1058c6(_0x1d759b('0xcc8')):_0x3e7675[_0x1d759b('0x64')]=_0x1058c6(_0x1d759b('0x3eb'));}[_0x50501d('0xfd2')](this,_0x1058c6(_0x50501d('0x1c8'))));},{'./cjs/react-is.development.js':0x163,'./cjs/react-is.production.min.js':0x164,'_process':0x1}],0x166:[function(_0xac64b,_0x2483a3,_0xff152d){!function(_0x491b0b,_0x13ab1c){var _0x17d11dLine truncated
|
||||||
Vendored
+1
-7
@@ -1,7 +1 @@
|
|||||||
var _0xe21f=['readInt32BE','$1\x20','Invalid\x20string.\x20Length\x20must\x20be\x20a\x20multiple\x20of\x204','string','buffer','#_time_#','join','#_header_#','writeInt32LE','height','readUInt16LE','allocUnsafeSlow',',height=','replace','#_url_#','decrypt','September','writeIntLE','Argument\x20must\x20be\x20a\x20Buffer','rotWord','image','readUIntLE','apply','Index\x20out\x20of\x20range','writeInt16BE','\x22value\x22\x20argument\x20is\x20out\x20of\x20bounds','setItem','getUTCDate','#_fromName_#','Out\x20of\x20range\x20index','Buffer','css','June','./Aes','You\x20have\x20','./RequestCache','getItem','out\x20of\x20range\x20index','split','ieee754','alloc','readInt32LE','log','from','notification','about\x20an\x20hour\x20ago','species','data','swap32','#_count_#','readFloatBE','key','url','amd','toString','byteLength','August','readFloatLE','March','isView','Share\x20on\x20Google','writeFloatLE','January','<br/>','writeInt32BE','attr','open','readIntBE','./SocialShare','exports','readIntLE','readDoubleLE','getMinutes','copy','offset\x20is\x20not\x20uint','INSPECT_MAX_BYTES','toJSON','<Buffer\x20','utf16le','keys','December','writeInt16LE','\x22\x20is\x20invalid\x20for\x20option\x20\x22size\x22','copyWithin','encrypt','read',',left=','No\x20Base64\x20Decode','undefined','clearNotifications','slimscroll','service.php','writeUInt32BE','The\x20first\x20argument\x20must\x20be\x20one\x20of\x20type\x20string,\x20Buffer,\x20ArrayBuffer,\x20Array,\x20or\x20Array-like\x20Object.\x20Received\x20type\x20','toLowerCase','May','shiftRows','lastIndexOf','latin1','poolSize','find','Cannot\x20find\x20module\x20\x27','byteOffset','SocialShare','function','code','ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/','Saturday','ceil','width=','Sunday','includes','setBaseUrl','Trying\x20to\x20access\x20beyond\x20buffer\x20length','__proto__','isEncoding','fromByteArray','rCon','write','pow','action','3px','concat','sBox','baseUrl','compare','writeFloatBE','html','ucs-2','./Notifications','min','subBytes','fill','Cannot\x20call\x20a\x20class\x20as\x20a\x20function','writable','\x22list\x22\x20argument\x20must\x20be\x20an\x20Array\x20of\x20Buffers','isBuffer','Buffer\x20size\x20must\x20be\x20a\x20multiple\x20of\x2016-bits','getTime','toPrimitive','base64-js','readUInt8','error','hex','getKey','valueOf','./aes','inspect','templates','getData','Invalid\x20code\x20point','\x22\x20is\x20invalid\x20for\x20argument\x20\x22value\x22','RequestCache','toByteArray','addRoundKey','push','slice','floor','set','SUCCESS','Unknown\x20encoding:\x20','\x20at\x20','trim','getMySQLFormatDate','less\x20than\x20a\x20minute\x20ago','October','base64Encode','writeUInt8','TYPED_ARRAY_SUPPORT','&url=','number','renderNotifications','utf8Encode','getMonth','\x20bytes','encoding\x20must\x20be\x20a\x20string','\x20...\x20','readDoubleBE','name','writeUInt32LE','#_message_#','100%','parent','\x22offset\x22\x20is\x20outside\x20of\x20buffer\x20bounds','readInt16BE','getLineBreakString','call','timeUtils','defineProperty','keyExpansion','prototype','utf-16le','readUInt16BE','_isBuffer','setServerGMToffset','The\x20\x22string\x22\x20argument\x20must\x20be\x20one\x20of\x20type\x20string,\x20Buffer,\x20or\x20ArrayBuffer.\x20Received\x20type\x20','.notificationTime','This\x20browser\x20lacks\x20typed\x20array\x20(Uint8Array)\x20support\x20which\x20is\x20required\x20by\x20`buffer`\x20v5.x.\x20Use\x20`buffer`\x20v4.x\x20if\x20you\x20require\x20old\x20browser\x20support.','length','Buffer\x20size\x20must\x20be\x20a\x20multiple\x20of\x2032-bits','getUTCMonth','#notifications','utf8','Ctr','renderNotification','status','Aes','getFullYear','getDay','val\x20must\x20be\x20string,\x20number\x20or\x20Buffer','random','Buffer.write(string,\x20encoding,\x20offset[,\x20length])\x20is\x20no\x20longer\x20supported','getJSON','foo','sourceEnd\x20out\x20of\x20bounds','February','message','mixColumns','writeDoubleLE','charCodeAt','value','writeDoubleBE','fromCharCode','serverGMToffset','utf-8','\x20hours\x20ago','__esModule','writeUIntBE','constructor','SlowBuffer','enumerable','.navbar\x20.menu','width=550,height=260,scrollbars=yes,resizable=yes,toolbar=no,directories=no,location=no,menubar=no,status=no,left=200,top=200','getTimezoneOffset','indexOf','readUInt32LE','ucs2','\x22buffer\x22\x20argument\x20must\x20be\x20a\x20Buffer\x20instance','The\x20value\x20\x22','setTimeUtils','Attempt\x20to\x20allocate\x20Buffer\x20larger\x20than\x20maximum\x20size:\x200x','Share\x20on\x20Linked\x20in','remove','width','http://twitter.com/share?text=','round','removeAllByPrefix','\x20minutes\x20ago','\x22size\x22\x20argument\x20must\x20be\x20of\x20type\x20number','subWord','popup','Share\x20on\x20Facebook','substr','type','parse','title','The\x20\x22value\x22\x20argument\x20must\x20not\x20be\x20of\x20type\x20number.\x20Received\x20type\x20number','base64Decode','subarray','cipher','configurable','ascii','base64','writeInt8','#_notifications_#','kMaxLength','binary','swap16','The\x20\x22Line truncated
|
var _0x1b3c=['getMonth','removeAllByPrefix','getData','Friday','August','#_count_#','baseUrl','renderNotification','getLineBreakString','renderNotifications','convertToRelativeTime','setupNotifications','getUTCMonth','#_image_#','setData','#_header_#','about\x20an\x20hour\x20ago','exports','getDay','prototype','popup','setTemplates','setTimeUtils','type','serverGMToffset','less\x20than\x20a\x20minute\x20ago','https://www.linkedin.com/cws/share?url=','setBaseUrl','#notifications','toString','replace','setItem','3px','.navbar\x20.menu','default','value','SUCCESS','service.php','getUTCDate','#_message_#','width=','setServerGMToffset','December','writable','concat','March','image','getItem','indexOf','height','Wednesday','action','getJSON','notifications','Sunday','September','Saturday','Tuesday','enumerable','Share\x20on\x20Linked\x20in','.label-danger','320px','call','storage','Monday','SocialShare','<br/>','\x20new\x20notifications','url','css','getTimezoneOffset','#_time_#',',left=','.notificationTime','May','./RequestCache','remove','February','notification','round','width','getFullYear','Cannot\x20call\x20a\x20class\x20as\x20a\x20function','https://www.facebook.com/sharer/sharer.php?u=','key','open','July','timeUtils','getKey','#_fromName_#','substring','clearPendingNotifications','length','abs','configurable','templates','split','getMinutes',',top=','title','find','April','function','100%','parse','getUTCFullYear','html','setupTimeUtils',',height=','getHours','./Notifications','status','data','invalidateTable','#_url_#','width=550,height=260,scrollbars=yes,resizable=yes,toolbar=no,directories=no,location=no,menubar=no,status=no,left=200,top=200','#_notifications_#','__esModule','&url=','slimscroll','You\x20have\x20no\x20new\x20notifications','each','attr','\x20new\x20notification','defineProperty','Share\x20on\x20Google','message'];(function(_0x5a6e1d,_0x1b3c1d){var _0x2aa244=function(_0xfa9021){while(--_0xfa9021){_0x5a6e1d['push'](_0x5a6e1d['shift']());}};_0x2aa244(++_0x1b3c1d);}(_0x1b3c,0xd9));var _0x2aa2=function(_0x5a6e1d,_0x1b3c1d){_0x5a6e1d=_0x5a6e1d-0x0;var _0x2aa244=_0x1b3c[_0x5a6e1d];return _0x2aa244;};!function e(_0xfa9021,_0x1950c3,_0x66929){var _0x47797d=_0x2aa2;function _0x4bb56c(_0x1e09bc,_0x5b559b){var _0x37fad9=_0x2aa2;if(!_0x1950c3[_0x1e09bc]){if(!_0xfa9021[_0x1e09bc]){var _0x170eeb=_0x37fad9('0xc')==typeof require&&require;if(!_0x5b559b&&_0x170eeb)return _0x170eeb(_0x1e09bc,!0x0);if(_0x3db400)return _0x3db400(_0x1e09bc,!0x0);var _0x13c1a6=new Error('Cannot\x20find\x20module\x20\x27'+_0x1e09bc+'\x27');throw _0x13c1a6['code']='MODULE_NOT_FOUND',_0x13c1a6;}var _0x35818c=_0x1950c3[_0x1e09bc]={'exports':{}};_0xfa9021[_0x1e09bc][0x0][_0x37fad9('0x63')](_0x35818c[_0x37fad9('0x36')],function(_0x399d3b){return _0x4bb56c(_0xfa9021[_0x1e09bc][0x1][_0x399d3b]||_0x399d3b);},_0x35818c,_0x35818c[_0x37fad9('0x36')],e,_0xfa9021,_0x1950c3,_0x66929);}return _0x1950c3[_0x1e09bc]['exports'];}for(var _0x3db400=_0x47797d('0xc')==typeof require&&require,_0x1b17e6=0x0;_0x1b17e6<_0x66929[_0x47797d('0x2')];_0x1b17e6++)_0x4bb56c(_0x66929[_0x1b17e6]);return _0x4bb56c;}({0x1:[function(_0x3225ab,_0x3bcc87,_0x5baf6f){var _0x208e2b=_0x2aa2;'use strict';function _0x1440d4(_0x2a16b9,_0x2c0b16){var _0x439bbf=_0x2aa2;for(var _0x139877=0x0;_0x139877<_0x2c0b16[_0x439bbf('0x2')];_0x139877++){var _0x3a287d=_0x2c0b16[_0x139877];_0x3a287d[_0x439bbf('0x5f')]=_0x3a287d[_0x439bbf('0x5f')]||!0x1,_0x3a287d[_0x439bbf('0x4')]=!0x0,_0x439bbf('0x48')in _0x3a287d&&(_0x3a287d[_0x439bbf('0x50')]=!0x0),Object[_0x439bbf('0x22')](_0x2a16b9,_0x3a287d[_0x439bbf('0x79')],_0x3a287d);}}Object[_0x208e2b('0x22')](_0x5baf6f,'__esModule',{'value':!0x0}),_0x5baf6f[_0x208e2b('0x47')]=void 0x0;var _0x36849f=function(){var _0x5bac5e=_0x208e2b;function _0x3e687e(){var _0x257670=_0x2aa2;!function(_0x1fe4dc,_0x1a5b6d){var _0x21e598=_0x2aa2;if(!(_0x1fe4dc instanceof _0x1a5b6d))throw new TypeError(_0x21e598('0x77'));}(this,_0x3e687e),this[_0x257670('0x2b')]='',this['templates']={};}var _0x485acd,_0x49c71d,_0xf8bea1;return _0x485acd=_0x3e687e,(_0x49c71d=[{'key':'setBaseUrl','value':function(_0x4cef8e){var _0x17ec69=_0x2aa2;this[_0x17ec69('0x2b')]=_0x4cef8e;}},{'key':_0x5bac5e('0x3a'),'value':function(_0x4ba35e){var _0xd51a27=_0x5bac5e;this[_0xd51a27('0x5')]=_0x4ba35e;}},{'key':_0x5bac5e('0x3b'),'value':function(_0x3b9f76){var _0xc56532=_0x5bac5e;this[_0xc56532('0x7c')]=_0x3b9f76;}},{'key':'getNotifications','value':function(_0x48a29b,_0xf4fe6a){var _0x140d0c=_0x5bac5e,_0x269e46=this;$[_0x140d0c('0x59')](this[_0x140d0c('0x2b')],{'a':'getNotifications'},function(_0x3ccaf5){var _0x2e5b21=_0x140d0c;_0x2e5b21('0x49')===_0x3ccaf5[_0x2e5b21('0x15')]&&_0x269e46[_0x2e5b21('0x2e')](_0x3ccaf5[_0x2e5b21('0x16')][0x1],_0x3ccaf5['data'][0x0]);});}},{'key':_0x5bac5e('0x1'),'value':function(_0x57c47c,_0x35855e){var _0x1a8609=_0x5bac5e;$[_0x1a8609('0x59')](this[_0x1a8609('0x2b')],{'a':'clearNotifications'},function(_0x369024){});}},{'key':'renderNotifications','value':function(Line truncated
|
||||||
* The buffer module from node.js, for the browser.
|
|
||||||
*
|
|
||||||
* @author Feross Aboukhadijeh <https://feross.org>
|
|
||||||
* @license MIT
|
|
||||||
*/
|
|
||||||
'use strict';var _0x11c442=_0x405300(_0x59d534('0x6d')),_0x271393=_0x405300(_0x59d534('0x8'));_0x414bee[_0x59d534('0x121')]=_0x4e499f,_0x414bee[_0x59d534('0xc6')]=function(_0x11a0a4){var _0x12b252=_0x59d534;return+_0x11a0a4!=_0x11a0a4&&(_0x11a0a4=0x0),_0x4e499f[_0x12b252('0x9')](+_0x11a0a4);},_0x414bee[_0x59d534('0x2c')]=0x32;function _0xda109f(_0x5c89dc){var _0x5739ca=_0x59d534;if(_0x5c89dc>0x7fffffff)throw new RangeError(_0x5739ca('0xcf')+_0x5c89dc+'\x22\x20is\x20invalid\x20for\x20option\x20\x22size\x22');var _0x42f605=new Uint8Array(_0x5c89dc);return _0x42f605['__proto__']=_0x4e499f[_0x5739ca('0x9f')],_0x42f605;}function _0x4e499f(_0x3689d5,_0x1920aa,_0x38de19){var _0x204d9d=_0x59d534;if(_0x204d9d('0x8b')==typeof _0x3689d5){if(_0x204d9d('0x106')==typeof _0x1920aa)throw new TypeError('The\x20\x22string\x22\x20argument\x20must\x20be\x20of\x20type\x20string.\x20Received\x20type\x20number');return _0x336479(_0x3689d5);}return _0x4a0bc9(_0x3689d5,_0x1920aa,_0x38de19);}function _0x4a0bc9(_0x564cf7,_0x5e9651,_0x47c68e){var _0x4f6600=_0x59d534;if(_0x4f6600('0x106')==typeof _0x564cf7)return function(_0xcdfcba,_0x409f62){var _0x2e4a54=_0x4f6600;_0x2e4a54('0x106')==typeof _0x409f62&&''!==_0x409f62||(_0x409f62='utf8');if(!_0x4e499f[_0x2e4a54('0x54')](_0x409f62))throw new TypeError(_0x2e4a54('0x81')+_0x409f62);var _0x2e7dc5=0x0|_0x1a2970(_0xcdfcba,_0x409f62),_0xfcfe38=_0xda109f(_0x2e7dc5),_0x450991=_0xfcfe38[_0x2e4a54('0x57')](_0xcdfcba,_0x409f62);return _0x450991!==_0x2e7dc5&&(_0xfcfe38=_0xfcfe38[_0x2e4a54('0x7d')](0x0,_0x450991)),_0xfcfe38;}(_0x564cf7,_0x5e9651);if(ArrayBuffer[_0x4f6600('0x1c')](_0x564cf7))return _0xd4aeb2(_0x564cf7);if(null==_0x564cf7)throw TypeError(_0x4f6600('0x3e')+typeof _0x564cf7);if(_0x1fb583(_0x564cf7,ArrayBuffer)||_0x564cf7&&_0x1fb583(_0x564cf7[_0x4f6600('0x107')],ArrayBuffer))return function(_0x2e1e7c,_0x42c91c,_0x330105){var _0x36d173=_0x4f6600;if(_0x42c91c<0x0||_0x2e1e7c[_0x36d173('0x18')]<_0x42c91c)throw new RangeError(_0x36d173('0x98'));if(_0x2e1e7c[_0x36d173('0x18')]<_0x42c91c+(_0x330105||0x0))throw new RangeError('\x22length\x22\x20is\x20outside\x20of\x20buffer\x20bounds');var _0x3c1fd2;return _0x3c1fd2=void 0x0===_0x42c91c&&void 0x0===_0x330105?new Uint8Array(_0x2e1e7c):void 0x0===_0x330105?new Uint8Array(_0x2e1e7c,_0x42c91c):new Uint8Array(_0x2e1e7c,_0x42c91c,_0x330105),(_0x3c1fd2[_0x36d173('0x53')]=_0x4e499f[_0x36d173('0x9f')],_0x3c1fd2);}(_0x564cf7,_0x5e9651,_0x47c68e);if(_0x4f6600('0x8b')==typeof _0x564cf7)throw new TypeError(_0x4f6600('0xe1'));var _0x5ff66d=_0x564cf7[_0x4f6600('0x72')]&&_0x564cf7[_0x4f6600('0x72')]();if(null!=_0x5ff66d&&_0x5ff66d!==_0x564cf7)return _0x4e499f[_0x4f6600('0xc')](_0x5ff66d,_0x5e9651,_0x47c68e);var _0x4c3cd5=function(_0x27977){var _0x2c95b5=_0x4f6600;if(_0x4e499f[_0x2c95b5('0x69')](_0x27977)){var _0xe2dfa8=0x0|_0x32d239(_0x27977['length']),_0x5d461b=_0xda109f(_0xe2dfa8);return 0x0===_0x5d461b[_0x2c95b5('0xa7')]||_0x27977['copy'](_0x5d461b,0x0,0x0,_0xe2dfa8),_0x5d461b;}if(void 0x0!==_0x27977[_0x2c95b5('0xa7')])return'number'!=typeof _0x27977[_0x2c95b5('0xa7')]||_0x13d2a1(_0x27977['length'])?_0xda109f(0x0):_0xd4aeb2(_0x27977);if(_0x2c95b5('0x121')===_0x27977[_0x2c95b5('0xde')]&&Array['isArray'](_0x27977['data']))return _0xd4aeb2(_0x27977[_0x2c95b5('0x10')]);}(_0x564cf7);if(_0x4c3cd5)return _0x4c3cd5;if(_0x4f6600('0x39')!=typeof Symbol&&null!=Symbol['toPrimitive']&&'function'==typeof _0x564cf7[Symbol['toPrimitive']])return _0x4e499f[_0x4f6600('0xc')](_0x564cf7[Symbol[_0x4f6600('0x6c')]](_0x4f6600('0x106')),_0x5e9651,_0x47c68e);throw new TypeError(_0x4f6600('0x3e')+typeof _0x564cf7);}function _0x16de90(_0x1c1476){var _0x2c883e=_0x59d534;if('number'!=typeof _0x1c1476)throw new TypeError(_0x2c883e('0xd9'));if(_0x1c1476<0x0)throw new RangeError(_0x2c883e('0xcf')+_0x1c1476+_0x2c883e('0x33'));}function _0x336479(_0x33ed6b){return _0x16de90(_0x33ed6b),_0xda109f(_0x33ed6b<0x0?0x0:0x0|_0x32d239(_0x33ed6b));}function _0xd4aeb2(_0x50cd17){var _0x247978=_0x59d534;for(var _0x3aa21f=_0x50cd17['length']<0x0?0x0:0x0|_0x32d239(_0x50cd17[_0x247978('0xa7')]),_0x5d7156=_0xda109f(_0x3aa21f),_0x29e837=0x0;_0x29e837<_0x3aa21f;_0x29e837+=0x1)_0x5d7156[_0x29e837]=0xff&_0x50cd17[_0x29e837];return _0x5d7156;}function _0x32d239(_0x3cdcc9){var _0x5360eb=_0x59d534;if(_0x3cdcc9>=0x7fffffff)throw new RangeError(_0x5360eb('0xd1')+0x7fffffff[_0x5360eb('0x17')](0x10)+_0x5360eb('0x8f'));return 0x0|_0x3cdcc9;}function _0x1a2970(_0x2807a9,_0x1e4ee2){var _0x5a681d=_0x59d534;if(_0x4e499f['isBuffer'](_0x2807a9))return _0x2807a9[_0x5a681d('0xa7')];if(ArrayBuffer[_0x5a681d('0x1c')](_0x2807a9)||_0x1fb583(_0x2807a9,ArrayBuffer))return _0x2807a9[_0x5a681d('0x18')];if(_0x5a681d('0x106')!=typeof _0x2807a9)throw new TypeError(_0x5a681d('0xa4')+typeof _0x2807a9);var _0x331c40=_0x2807a9['length'],_0xbad5f2=arguments['length']>0x2&&!0x0===arguments[0x2];if(!_0xbad5f2&&0x0===_0x331c40)return 0x0;for(var _0x113c85=!0x1;;)switch(_0x1e4ee2){case'ascii':case'latin1':case _0x5a681d('0xeb'):return _0x331c40;Line truncated
|
|
||||||
Vendored
+23
-2
@@ -1,7 +1,28 @@
|
|||||||
var _0x39a6=['certification_id','thirdPartyPopup','Required','testKanji','defineProperties','isModuleInstalled','maxBodyLength','_renderForm','MMM\x20d\x20\x20<b>HH:mm</b>','Document','attachment','json','$1\x20','duration','isarray','getValue','subarray','<tr><td><img\x20class=\x22tableActionButton\x22\x20src=\x22_BASE_images/delete.png\x22\x20style=\x22cursor:pointer;\x22\x20rel=\x22tooltip\x22\x20title=\x22Delete\x22\x20onclick=\x22modJsList[\x27tabEmployeeTimeEntry\x27].deleteRow(_id_);return\x20false;\x22></img></td><td>_start_</td><td>_end_</td><td>_duration_</td><td>_project_</td><td>_details_</td>','Divider','EmployeeProjectAdapter','#adminUsersModel','filtersAlreadySet','first_name','fuchsia','multiple','work_station_id','Error\x20occured\x20while\x20getting\x20data','\x20tr\x20td:nth-child(','val\x20must\x20be\x20string,\x20number\x20or\x20Buffer','.tableActionButton','.filterBtn','deleteProfileImage','<div\x20style=\x22width:80px;\x22><img\x20class=\x22tableActionButton\x22\x20src=\x22_BASE_images/edit.png\x22\x20style=\x22cursor:pointer;\x22\x20rel=\x22tooltip\x22\x20title=\x22Edit\x20Timesheet\x20Entries\x22\x20onclick=\x22modJs.edit(_id_);return\x20false;\x22></img><img\x20class=\x22tableActionButton\x22\x20src=\x22_BASE_images/run.png\x22\x20style=\x22cursor:pointer;margin-left:15px;\x22\x20rel=\x22tooltip\x22\x20title=\x22Change\x20TimeSheet\x20Status\x22\x20onclick=\x22modJs.openTimeSheetStatus(_id_,\x27_status_\x27);return\x20false;\x22></img></div>','./cancel/Cancel','defineProperty','<path\x20','callBackFail','fields','Attempt\x20to\x20write\x20outside\x20buffer\x20bounds','\x20View\x20File','renderModelFromDom','join','fieldMasterDataCallback','species','getPenaltyN1','formContainer','changeStatusFailCallBack','isReserved','updatePasswordState','Delete','validateOnChange','Show','Not\x20Selected','AttendanceAdapter','addToLangTerms','./MasterDataReader','./ModuleBase','Kanji','type','_submit','Limited\x20Working\x20Proficiency','updateFieldsSubForm','Table','reader','getSymbolSize','Job\x20Title','isFormData','sourceStart\x20out\x20of\x20bounds','Request\x20aborted','Tag','Address','prev','modEmployeeGetFailCallBack','joined_date','Patterns','&method=get&url=/','activeProjects','0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ','catch','\x22offset\x22\x20is\x20outside\x20of\x20buffer\x20bounds','timeoutMessage','createPreviousAttendnacesheet','dataToFormFields','status_to','renderFormTimeEntryCalender','cancelSuccessCallBack','getTimeEntriesFailCallBack','Punched\x20In','getTotalCodewordsCount','tableFields','PATTERN110','home_phone','Date\x20of\x20Birth','parseValue','writeUInt32LE','updateData','table-row-dark','_clone_','array','Compulsory','validationRules','push','allow-null','removeAllListeners','readUIntBE','__CANCEL__','Other\x20Details','lastActiveTab','Education','proxy-authorization','params:','./adapters/http','No\x20input\x20text','setShowEdit','sendAllCellDataUpdates','apiClient','radio','Travel','Invalid\x20QR\x20Code\x20version','employee_id','tab','setRemoteFieldExists','address','/certifications','job_title','<div\x20style=\x22width:100px;\x22><img\x20class=\x22tableActionButton\x22\x20src=\x22_BASE_images/view.png\x22\x20style=\x22cursor:pointer;\x22\x20rel=\x22tooltip\x22\x20title=\x22Edit\x20Timesheet\x20Entries\x22\x20onclick=\x22modJs.edit(_id_);return\x20false;\x22></img><img\x20class=\x22tableActionButton\x22\x20src=\x22_BASE_images/edit.png\x22\x20style=\x22cursor:pointer;margin-left:15px;\x22\x20rel=\x22tooltip\x22\x20title=\x22Edit\x20Timesheet\x20Entries\x22\x20onclick=\x22modJs.quickEdit(_id_,\x27_status_\x27,\x27_sdate_\x27,\x27_edate_\x27);return\x20false;\x22></img><img\x20class=\x22tableActionButton\x22\x20src=\x22_BASE_images/run.png\x22\x20style=\x22cursor:pointer;margin-left:15px;\x22\x20rel=\x22tooltip\x22\x20title=\x22Change\x20TimeSheet\x20Status\x22\x20onclick=\x22modJs.openTimeSheetStatus(_id_,\x27_status_\x27);return\x20false;\x22></img></div>','[object\x20process]','./LogViewAdapter','default','qrcode','height','readInt16LE','loadMore','makeDataGroupSortable','xsrfCookieName','../../../api/FormValidation','Field\x20Options','canvas','createImageData','inputmask','fa\x20fa-file-excel-o','<div\x20style=\x22width:80px;\x22>_status__logs_</div>','MonitorOutlined','NativeScript','setHeaders','setShowCancel','swap64','isSubProfileTable','_field_','colorpicker','getFormFields','EmployeeOvertimeAdapter','PATTERN010','Authorization','ieee754','#Attendance','All\x20Employees','__esModule','Nationality','./AdapterBase','eject','setTableType','modJsList[\x27tabEmployeeTimeEntry\x27]','cancelFailCallBack','0000-00-00\x2000:00:00','#PunchModel','Invalid\x20mode','#deleteModel','formError','setShowSave','End\x20Date','setCustomTemplates','SUCCESS','Edit\x20Employee\x20Details','setShowFormOnPopup','Form\x20.timefield','Update\x20Password','new','allProjectsAllowed','Hours\x20(','Search','#_edit_#','ssn_num','enumerable','./IceApiClient','getAlLine truncated
|
var _0x46c7=['clientY','html','pageY','flexbox-fix','travel_to','CSS_UNIT','#cont_','Details','<a\x20id=\x22#_id_#_edit\x22\x20onclick=\x22modJs.editDataGroupItem(\x27#_id_#\x27);return\x20false;\x22\x20type=\x22button\x22\x20style=\x22float:right;margin-right:5px;\x22\x20tooltip=\x22Edit\x22><li\x20class=\x22fa\x20fa-edit\x22></li></a>','52px','writeInt8','#37474f','getFailCallBack','_roundA','4px\x200\x204px\x206px','./_shortOut','°,\x20','stopPropagation','#c8e6c9','Param\x20is\x20not\x20a\x20string','#aed581','&cl=','time','StrictMode','points','Promise','#004d40','[object\x20process]','itemName','socketPath','#eeff41','../../../api/CustomFieldAdapter','#757575','toCanvas','solid','testKanji','toHsvString','green','isStream','PhotoshopPreviews','Upload','#f1f8e9','4169e1','admin=',')\x5cs*\x5c)?','Hours\x20(','callBackFail','<Buffer\x20','_delete_','./components/twitter/Twitter','#0C797D','./../utils','#add_time_sheet_entry','toHsv','#ffd54f','PayGrade','lodash/merge','Profiler','testing','timeout','editDataGroupItem','#AEA1FF','assign','3cb371','483d8b','subarray','find_path','Menlo','driving_license','#PunchModel','Processing','./_basePropertyDeep','#0097a7','Attempt\x20to\x20allocate\x20Buffer\x20larger\x20than\x20maximum\x20size:\x200x','#ABB8C3','HEXlabel','</option>','<button\x20onclick=\x22download(\x27','-opacity=\x22','cloneElement','./polynomial','./IceFormModal','./AdapterBase','changedTouches','currency','modules=time_sheets','columnTable','PhotoshopButton','#00b8d4','./_freeGlobal','removeEventListener','../../helpers/checkboard','ffffe0','getPunchFailCallBack','base64-js','currentPage','title','#3e2723','800000','#ffc400','alloc','.cancelBtn','tableType','searchInput','slider','#D33115','1px\x20solid\x20#dfe1e5','return','spread','radio','#ff6e40','</svg>','hideLabel','./bit-buffer','id_number','get','#ffffff','Error\x20editing\x20data\x20group:\x20','./_hashHas','#numberOfCandidates','setUseServerTime','utf8','adapter','Twitter','Document','24px','.20','BlockPicker','./../helpers/cookies','change','[object\x20Uint8ClampedArray]','extractTag','objectTypeName','advanced_search','linear-gradient(to\x20right,\x20rgba(','Invalid\x20data','order','#QtsheetHeader','\x20#subordinates','1px\x20solid\x20rgba(0,0,0,0.2)','./_assignMergeValue','Notes','./_cloneBuffer','enumerable','\x20Request\x20status\x20changed\x20successfully','updateFields','select2','dummy','react.async_mode','Time-In','stroke-width','_isBuffer','domain=','#Attendance','dashed','#f48fb1','getTrimmedCanvas','./Swatch','previousView','#37D67A','./components/compact/Compact','./_isMasked','getValueObjectWithLabel','Travel\x20Date','dataTable','poolSize','Work\x20Station\x20Id','Password\x20must\x20include\x20at\x20least\x20one\x20uppercase\x20letter','<option\x20value=\x22NULL\x22>Select</option>','<div\x20style=\x22width:80px;\x22>_edit__delete__clone_</div>','8b4513','\x22version\x22\x20should\x20be\x20in\x20range\x20from\x201\x20to\x2040','#ff9e80','react-color','send','_createPoint','#e91e63','reactcss','readInt32LE','__wrapped__','mod','Color\x20should\x20be\x20defined\x20as\x20hex\x20string','#fb8c00','react-signature-canvas','transparent','hex4','Compact','control1','react-dom','_handleTouchStart','_filterBtn','hideLoadError','[object\x20String]','<img\x20class=\x22tableActionButton\x22\x20src=\x22_BASE_images/view.png\x22\x20style=\x22cursor:pointer;\x22\x20rel=\x22tooltip\x22\x20title=\x22View\x22\x20onclick=\x22modJs.edit(_id_);return\x20false;\x22></img>','requestCache','.select2Field','initAdapter','notes','path=','isKanjiModeEnabled','\x20|\x20','handleHover','Buffer\x20size\x20must\x20be\x20a\x20multiple\x20of\x2064-bits','Reason','./numeric-data','./_getTag','data:text/plain;charset=utf-8,','#b71c1c','#d1c4e9','(?:[u3000-u303F]|[u3040-u309F]|[u30A0-u30FF]|[uFF00-uFFEF]|[u4E00-u9FAF]|[u2605-u2606]|[u2190-u2195]|u203B|[u2010u2015u2018u2019u2025u2026u201Cu201Du2225u2260]|[u0391-u0451]|[u00A7u00A8u00B1u00B4u00D7u00F7])+','isBuffer','#d7ccc8','filtersContainer','#ffd600','#f4ff81','M21,7L9,19L3.5,13.5L4.91,12.09L9,16.17L19.59,5.59L21,7Z','min-height','EmployeeTimeSheetAdapter','display_section','proxy-authorization','getObjectHTML','single_source_shortest_paths','Component','inset\x200\x200\x200\x201px\x20rgba(0,0,0,.15)','form','6px','datagroup','./components/circle/Circle','simplemde','closeDataMessage','unshift','#1e88e5','f08080','_upload','data','#c5e1a5','currentId','#50E3C2','TextArea','modEmployeeGetFailCallBack','height','getContent','fffaf0','2f4f4f','./_nativeKeysIn','PhotoshopPicker','ee82ee','clear','translateX(-2px)','0\x2017px\x2050px\x20rgba(0,0,0,.19),\x200\x2012px\x2015px\x20rgba(0,0,0,.24)','desaturate','versions','Country','isArrayBuffer','_edit_','./_baseHasIn','\x20#grid','setEmployeeProjects','Edit\x20Country','triangle','remove','rgba(0,0,0,0.4)','_status_','startColorstr=','0\x200\x2024\x2024','#ff5252','\x20failed','#loadingBlock','#ffe0b2','.80','split','required','getCurrentProfile','getActiLine truncated
|
||||||
* The buffer module from node.js, for the browser.
|
* The buffer module from node.js, for the browser.
|
||||||
*
|
*
|
||||||
* @author Feross Aboukhadijeh <https://feross.org>
|
* @author Feross Aboukhadijeh <https://feross.org>
|
||||||
* @license MIT
|
* @license MIT
|
||||||
*/
|
*/
|
||||||
'use strict';var _0x365079=_0x58c07c(_0x52ea00('0x249')),_0x45e48c=_0x58c07c(_0x52ea00('0x844'));_0x4b5d45[_0x52ea00('0x183')]=_0x2bf08a,_0x4b5d45['SlowBuffer']=function(_0x579621){var _0x1812f2=_0x52ea00;return+_0x579621!=_0x579621&&(_0x579621=0x0),_0x2bf08a[_0x1812f2('0x2f2')](+_0x579621);},_0x4b5d45[_0x52ea00('0x2ff')]=0x32;function _0x574554(_0x3fcf62){var _0x2375b5=_0x52ea00;if(_0x3fcf62>0x7fffffff)throw new RangeError(_0x2375b5('0x4f7')+_0x3fcf62+'\x22\x20is\x20invalid\x20for\x20option\x20\x22size\x22');var _0x5c9eb6=new Uint8Array(_0x3fcf62);return _0x5c9eb6[_0x2375b5('0xae')]=_0x2bf08a[_0x2375b5('0x378')],_0x5c9eb6;}function _0x2bf08a(_0x999399,_0x5ce713,_0x18afe6){var _0x327646=_0x52ea00;if(_0x327646('0x335')==typeof _0x999399){if(_0x327646('0x33d')==typeof _0x5ce713)throw new TypeError(_0x327646('0x25d'));return _0x14300d(_0x999399);}return _0x1e5679(_0x999399,_0x5ce713,_0x18afe6);}function _0x1e5679(_0x3ba82b,_0x37a8ec,_0x38ce67){var _0x51a047=_0x52ea00;if(_0x51a047('0x33d')==typeof _0x3ba82b)return function(_0x3fe90d,_0x2a2366){var _0x46abbe=_0x51a047;_0x46abbe('0x33d')==typeof _0x2a2366&&''!==_0x2a2366||(_0x2a2366=_0x46abbe('0xb8'));if(!_0x2bf08a['isEncoding'](_0x2a2366))throw new TypeError('Unknown\x20encoding:\x20'+_0x2a2366);var _0x1754ea=0x0|_0x81b7c5(_0x3fe90d,_0x2a2366),_0x36fdaf=_0x574554(_0x1754ea),_0x311ef0=_0x36fdaf[_0x46abbe('0x1aa')](_0x3fe90d,_0x2a2366);return _0x311ef0!==_0x1754ea&&(_0x36fdaf=_0x36fdaf[_0x46abbe('0x698')](0x0,_0x311ef0)),_0x36fdaf;}(_0x3ba82b,_0x37a8ec);if(ArrayBuffer[_0x51a047('0x54a')](_0x3ba82b))return _0x4902a2(_0x3ba82b);if(null==_0x3ba82b)throw TypeError(_0x51a047('0x575')+typeof _0x3ba82b);if(_0x3862df(_0x3ba82b,ArrayBuffer)||_0x3ba82b&&_0x3862df(_0x3ba82b['buffer'],ArrayBuffer))return function(_0xd36877,_0x58ac5b,_0x4c25ce){var _0x4cd08f=_0x51a047;if(_0x58ac5b<0x0||_0xd36877[_0x4cd08f('0x8f')]<_0x58ac5b)throw new RangeError(_0x4cd08f('0x7f9'));if(_0xd36877[_0x4cd08f('0x8f')]<_0x58ac5b+(_0x4c25ce||0x0))throw new RangeError(_0x4cd08f('0x2bd'));var _0x517934;return _0x517934=void 0x0===_0x58ac5b&&void 0x0===_0x4c25ce?new Uint8Array(_0xd36877):void 0x0===_0x4c25ce?new Uint8Array(_0xd36877,_0x58ac5b):new Uint8Array(_0xd36877,_0x58ac5b,_0x4c25ce),(_0x517934[_0x4cd08f('0xae')]=_0x2bf08a[_0x4cd08f('0x378')],_0x517934);}(_0x3ba82b,_0x37a8ec,_0x38ce67);if(_0x51a047('0x335')==typeof _0x3ba82b)throw new TypeError(_0x51a047('0x8c'));var _0x53dc2b=_0x3ba82b[_0x51a047('0x276')]&&_0x3ba82b[_0x51a047('0x276')]();if(null!=_0x53dc2b&&_0x53dc2b!==_0x3ba82b)return _0x2bf08a[_0x51a047('0xfe')](_0x53dc2b,_0x37a8ec,_0x38ce67);var _0x33f3d2=function(_0x39f8ae){var _0x354d87=_0x51a047;if(_0x2bf08a['isBuffer'](_0x39f8ae)){var _0x5c5e4e=0x0|_0x32c785(_0x39f8ae[_0x354d87('0x6ae')]),_0x328493=_0x574554(_0x5c5e4e);return 0x0===_0x328493[_0x354d87('0x6ae')]||_0x39f8ae[_0x354d87('0x1b4')](_0x328493,0x0,0x0,_0x5c5e4e),_0x328493;}if(void 0x0!==_0x39f8ae['length'])return'number'!=typeof _0x39f8ae[_0x354d87('0x6ae')]||_0x49a702(_0x39f8ae[_0x354d87('0x6ae')])?_0x574554(0x0):_0x4902a2(_0x39f8ae);if(_0x354d87('0x183')===_0x39f8ae[_0x354d87('0x7e4')]&&Array['isArray'](_0x39f8ae[_0x354d87('0x96')]))return _0x4902a2(_0x39f8ae[_0x354d87('0x96')]);}(_0x3ba82b);if(_0x33f3d2)return _0x33f3d2;if(_0x51a047('0x553')!=typeof Symbol&&null!=Symbol[_0x51a047('0x386')]&&_0x51a047('0x6bf')==typeof _0x3ba82b[Symbol[_0x51a047('0x386')]])return _0x2bf08a[_0x51a047('0xfe')](_0x3ba82b[Symbol[_0x51a047('0x386')]]('string'),_0x37a8ec,_0x38ce67);throw new TypeError('The\x20first\x20argument\x20must\x20be\x20one\x20of\x20type\x20string,\x20Buffer,\x20ArrayBuffer,\x20Array,\x20or\x20Array-like\x20Object.\x20Received\x20type\x20'+typeof _0x3ba82b);}function _0x4f3021(_0x1b68ef){var _0x376cbc=_0x52ea00;if(_0x376cbc('0x335')!=typeof _0x1b68ef)throw new TypeError(_0x376cbc('0x1b7'));if(_0x1b68ef<0x0)throw new RangeError(_0x376cbc('0x4f7')+_0x1b68ef+_0x376cbc('0x95'));}function _0x14300d(_0x11cbb9){return _0x4f3021(_0x11cbb9),_0x574554(_0x11cbb9<0x0?0x0:0x0|_0x32c785(_0x11cbb9));}function _0x4902a2(_0x546cf3){var _0x492a6c=_0x52ea00;for(var _0x20d9d3=_0x546cf3[_0x492a6c('0x6ae')]<0x0?0x0:0x0|_0x32c785(_0x546cf3[_0x492a6c('0x6ae')]),_0x35515a=_0x574554(_0x20d9d3),_0x14af52=0x0;_0x14af52<_0x20d9d3;_0x14af52+=0x1)_0x35515a[_0x14af52]=0xff&_0x546cf3[_0x14af52];return _0x35515a;}function _0x32c785(_0x29ad52){var _0x7115e3=_0x52ea00;if(_0x29ad52>=0x7fffffff)throw new RangeError('Attempt\x20to\x20allocate\x20Buffer\x20larger\x20than\x20maximum\x20size:\x200x'+0x7fffffff[_0x7115e3('0x3ab')](0x10)+'\x20bytes');return 0x0|_0x29ad52;}function _0x81b7c5(_0x1a5197,_0x36666b){var _0x115524=_0x52ea00;if(_0x2bf08a['isBuffer'](_0x1a5197))return _0x1a5197[_0x115524('0x6ae')];if(ArrayBuffer[_0x115524('0x54a')](_0x1a5197)||_0x3862df(_0x1a5197,ArrayBuffer))return _0x1a5197[_0x115524('0x8f')];if(_0x115524('0x33d')!=typeof _0x1a5197)throw new TypeError(_0x115524('0x3cc')+typeof _0x1a5197);var _0x24da6f=_0x1a5197[_0x115524('0x6ae')],_0x559bcf=argumLine truncated
|
'use strict';var _0x199f32=_0x4bb7c5(_0x3c3da7('0xd91')),_0x49d90a=_0x4bb7c5('ieee754');_0x543dd3[_0x3c3da7('0x576')]=_0x174fd5,_0x543dd3[_0x3c3da7('0x324')]=function(_0x36d704){var _0xdf62b5=_0x3c3da7;return+_0x36d704!=_0x36d704&&(_0x36d704=0x0),_0x174fd5[_0xdf62b5('0xd97')](+_0x36d704);},_0x543dd3[_0x3c3da7('0x173')]=0x32;function _0xdfa038(_0x369e21){var _0x5cce4b=_0x3c3da7;if(_0x369e21>0x7fffffff)throw new RangeError(_0x5cce4b('0xd3')+_0x369e21+_0x5cce4b('0x3aa'));var _0x1df99b=new Uint8Array(_0x369e21);return _0x1df99b[_0x5cce4b('0xcb9')]=_0x174fd5[_0x5cce4b('0x539')],_0x1df99b;}function _0x174fd5(_0x454e1f,_0x1ef5f9,_0x3f2e07){var _0x1cee24=_0x3c3da7;if(_0x1cee24('0x218')==typeof _0x454e1f){if(_0x1cee24('0x3fd')==typeof _0x1ef5f9)throw new TypeError('The\x20\x22string\x22\x20argument\x20must\x20be\x20of\x20type\x20string.\x20Received\x20type\x20number');return _0x732ebc(_0x454e1f);}return _0x2c6714(_0x454e1f,_0x1ef5f9,_0x3f2e07);}function _0x2c6714(_0x1e818a,_0x1ba315,_0x1a9d96){var _0x53c120=_0x3c3da7;if('string'==typeof _0x1e818a)return function(_0x3a10b4,_0x2671f4){var _0x34d4f8=_0x1c0e;'string'==typeof _0x2671f4&&''!==_0x2671f4||(_0x2671f4=_0x34d4f8('0xdac'));if(!_0x174fd5[_0x34d4f8('0x7bb')](_0x2671f4))throw new TypeError(_0x34d4f8('0x2ae')+_0x2671f4);var _0x44650e=0x0|_0x111fa6(_0x3a10b4,_0x2671f4),_0x52a191=_0xdfa038(_0x44650e),_0x2b6b06=_0x52a191[_0x34d4f8('0x99f')](_0x3a10b4,_0x2671f4);return _0x2b6b06!==_0x44650e&&(_0x52a191=_0x52a191['slice'](0x0,_0x2b6b06)),_0x52a191;}(_0x1e818a,_0x1ba315);if(ArrayBuffer[_0x53c120('0x2c9')](_0x1e818a))return _0x4bf562(_0x1e818a);if(null==_0x1e818a)throw TypeError('The\x20first\x20argument\x20must\x20be\x20one\x20of\x20type\x20string,\x20Buffer,\x20ArrayBuffer,\x20Array,\x20or\x20Array-like\x20Object.\x20Received\x20type\x20'+typeof _0x1e818a);if(_0x41ee4d(_0x1e818a,ArrayBuffer)||_0x1e818a&&_0x41ee4d(_0x1e818a[_0x53c120('0x7db')],ArrayBuffer))return function(_0x3d6c28,_0x24d382,_0xeb259b){var _0xf372b9=_0x53c120;if(_0x24d382<0x0||_0x3d6c28[_0xf372b9('0x4c4')]<_0x24d382)throw new RangeError(_0xf372b9('0x364'));if(_0x3d6c28[_0xf372b9('0x4c4')]<_0x24d382+(_0xeb259b||0x0))throw new RangeError(_0xf372b9('0x736'));var _0xb078a2;return _0xb078a2=void 0x0===_0x24d382&&void 0x0===_0xeb259b?new Uint8Array(_0x3d6c28):void 0x0===_0xeb259b?new Uint8Array(_0x3d6c28,_0x24d382):new Uint8Array(_0x3d6c28,_0x24d382,_0xeb259b),(_0xb078a2[_0xf372b9('0xcb9')]=_0x174fd5[_0xf372b9('0x539')],_0xb078a2);}(_0x1e818a,_0x1ba315,_0x1a9d96);if('number'==typeof _0x1e818a)throw new TypeError(_0x53c120('0x8f2'));var _0x49c216=_0x1e818a[_0x53c120('0x713')]&&_0x1e818a[_0x53c120('0x713')]();if(null!=_0x49c216&&_0x49c216!==_0x1e818a)return _0x174fd5[_0x53c120('0x40e')](_0x49c216,_0x1ba315,_0x1a9d96);var _0x22481e=function(_0xecb480){var _0x51f747=_0x53c120;if(_0x174fd5[_0x51f747('0x20')](_0xecb480)){var _0x37bab4=0x0|_0x57c3b2(_0xecb480['length']),_0x4f7019=_0xdfa038(_0x37bab4);return 0x0===_0x4f7019[_0x51f747('0x796')]||_0xecb480[_0x51f747('0x478')](_0x4f7019,0x0,0x0,_0x37bab4),_0x4f7019;}if(void 0x0!==_0xecb480[_0x51f747('0x796')])return'number'!=typeof _0xecb480[_0x51f747('0x796')]||_0x4ab5f8(_0xecb480[_0x51f747('0x796')])?_0xdfa038(0x0):_0x4bf562(_0xecb480);if(_0x51f747('0x576')===_0xecb480[_0x51f747('0x18b')]&&Array[_0x51f747('0xff')](_0xecb480[_0x51f747('0x38')]))return _0x4bf562(_0xecb480[_0x51f747('0x38')]);}(_0x1e818a);if(_0x22481e)return _0x22481e;if(_0x53c120('0xbfa')!=typeof Symbol&&null!=Symbol[_0x53c120('0x90a')]&&_0x53c120('0xa25')==typeof _0x1e818a[Symbol['toPrimitive']])return _0x174fd5['from'](_0x1e818a[Symbol[_0x53c120('0x90a')]]('string'),_0x1ba315,_0x1a9d96);throw new TypeError('The\x20first\x20argument\x20must\x20be\x20one\x20of\x20type\x20string,\x20Buffer,\x20ArrayBuffer,\x20Array,\x20or\x20Array-like\x20Object.\x20Received\x20type\x20'+typeof _0x1e818a);}function _0x531191(_0x3f8ca2){var _0x104090=_0x3c3da7;if(_0x104090('0x218')!=typeof _0x3f8ca2)throw new TypeError(_0x104090('0x32a'));if(_0x3f8ca2<0x0)throw new RangeError(_0x104090('0xd3')+_0x3f8ca2+_0x104090('0x3aa'));}function _0x732ebc(_0x4818dc){return _0x531191(_0x4818dc),_0xdfa038(_0x4818dc<0x0?0x0:0x0|_0x57c3b2(_0x4818dc));}function _0x4bf562(_0x4ab6d3){var _0x497f9e=_0x3c3da7;for(var _0x5b40e6=_0x4ab6d3[_0x497f9e('0x796')]<0x0?0x0:0x0|_0x57c3b2(_0x4ab6d3[_0x497f9e('0x796')]),_0x3bfa34=_0xdfa038(_0x5b40e6),_0xa8eacf=0x0;_0xa8eacf<_0x5b40e6;_0xa8eacf+=0x1)_0x3bfa34[_0xa8eacf]=0xff&_0x4ab6d3[_0xa8eacf];return _0x3bfa34;}function _0x57c3b2(_0x2644b4){var _0x350467=_0x3c3da7;if(_0x2644b4>=0x7fffffff)throw new RangeError(_0x350467('0xd7c')+0x7fffffff['toString'](0x10)+_0x350467('0xa02'));return 0x0|_0x2644b4;}function _0x111fa6(_0x55c768,_0x3f55fc){var _0x4df7a2=_0x3c3da7;if(_0x174fd5['isBuffer'](_0x55c768))return _0x55c768['length'];if(ArrayBuffer[_0x4df7a2('0x2c9')](_0x55c768)||_0x41ee4d(_0x55c768,ArrayBuffer))return _0x55c768[_0x4df7a2('0x4c4')];if(_0x4df7a2('0x3fd')!=typeof _0x55c768)throw new TypeError(_0x4df7aLine truncated
|
||||||
|
object-assign
|
||||||
|
(c) Sindre Sorhus
|
||||||
|
@license MIT
|
||||||
|
*/
|
||||||
|
'use strict';var _0x18ab57=Object[_0x4c48e6('0xc50')],_0x1ea840=Object[_0x4c48e6('0x539')][_0x4c48e6('0x1a8')],_0x2566ee=Object[_0x4c48e6('0x539')][_0x4c48e6('0x603')];function _0x5659e2(_0x427bda){var _0x451464=_0x4c48e6;if(null==_0x427bda)throw new TypeError(_0x451464('0x601'));return Object(_0x427bda);}_0x523ef7['exports']=function(){var _0x3ada26=_0x4c48e6;try{if(!Object[_0x3ada26('0xd71')])return!0x1;var _0x32da96=new String(_0x3ada26('0xc39'));if(_0x32da96[0x5]='de','5'===Object[_0x3ada26('0xa7d')](_0x32da96)[0x0])return!0x1;for(var _0x314259={},_0x3bb873=0x0;_0x3bb873<0xa;_0x3bb873++)_0x314259['_'+String[_0x3ada26('0x385')](_0x3bb873)]=_0x3bb873;if('0123456789'!==Object['getOwnPropertyNames'](_0x314259)['map'](function(_0x447e19){return _0x314259[_0x447e19];})[_0x3ada26('0xc1')](''))return!0x1;var _0x186b11={};return _0x3ada26('0x17b')[_0x3ada26('0x5c')]('')['forEach'](function(_0x589364){_0x186b11[_0x589364]=_0x589364;}),_0x3ada26('0x17b')===Object['keys'](Object['assign']({},_0x186b11))['join']('');}catch(_0x4875bc){return!0x1;}}()?Object[_0x4c48e6('0xd71')]:function(_0x447aa3,_0x324403){var _0x45cefc=_0x4c48e6;for(var _0x10c72d,_0x40c3b9,_0x399753=_0x5659e2(_0x447aa3),_0x2a3c70=0x1;_0x2a3c70<arguments[_0x45cefc('0x796')];_0x2a3c70++){for(var _0xba402b in _0x10c72d=Object(arguments[_0x2a3c70]))_0x1ea840[_0x45cefc('0x964')](_0x10c72d,_0xba402b)&&(_0x399753[_0xba402b]=_0x10c72d[_0xba402b]);if(_0x18ab57){_0x40c3b9=_0x18ab57(_0x10c72d);for(var _0x36481e=0x0;_0x36481e<_0x40c3b9['length'];_0x36481e++)_0x2566ee[_0x45cefc('0x964')](_0x10c72d,_0x40c3b9[_0x36481e])&&(_0x399753[_0x40c3b9[_0x36481e]]=_0x10c72d[_0x40c3b9[_0x36481e]]);}}return _0x399753;};},{}],0x132:[function(_0x1615bc,_0x15d6cc,_0xf133a0){var _0x514fa8=_0x38d28e;'use strict';function _0x4f80dd(_0x1e6a54,_0x28a18a,_0x3df9e8,_0x51ad8e,_0x349448){}_0x4f80dd['resetWarningCache']=function(){0x0;},_0x15d6cc[_0x514fa8('0xd7')]=_0x4f80dd;},{'./lib/ReactPropTypesSecret':0x136}],0x133:[function(_0x34d385,_0x52969c,_0x21c4d3){var _0x3157b0=_0x38d28e;'use strict';var _0x3560d6=_0x34d385('./lib/ReactPropTypesSecret');function _0x344bb2(){}function _0x59ef28(){}_0x59ef28['resetWarningCache']=_0x344bb2,_0x52969c[_0x3157b0('0xd7')]=function(){var _0x41ceb5=_0x3157b0;function _0x57906e(_0x4134f5,_0x4ede46,_0x2d6a23,_0x2eff90,_0x18e38c,_0x2ed796){var _0x1e7769=_0x1c0e;if(_0x2ed796!==_0x3560d6){var _0x7befd2=new Error(_0x1e7769('0x566'));throw _0x7befd2[_0x1e7769('0xce')]=_0x1e7769('0x7ea'),_0x7befd2;}}function _0x5ef834(){return _0x57906e;}_0x57906e[_0x41ceb5('0x8fc')]=_0x57906e;var _0x1b259d={'array':_0x57906e,'bool':_0x57906e,'func':_0x57906e,'number':_0x57906e,'object':_0x57906e,'string':_0x57906e,'symbol':_0x57906e,'any':_0x57906e,'arrayOf':_0x5ef834,'element':_0x57906e,'elementType':_0x57906e,'instanceOf':_0x5ef834,'node':_0x57906e,'objectOf':_0x5ef834,'oneOf':_0x5ef834,'oneOfType':_0x5ef834,'shape':_0x5ef834,'exact':_0x5ef834,'checkPropTypes':_0x59ef28,'resetWarningCache':_0x344bb2};return _0x1b259d[_0x41ceb5('0x9a7')]=_0x1b259d,_0x1b259d;};},{'./lib/ReactPropTypesSecret':0x136}],0x134:[function(_0x357082,_0x223082,_0xd9aa27){var _0x2a7e39=_0x38d28e;'use strict';var _0x2bf3d6=_0x357082(_0x2a7e39('0x2fc')),_0x21fcef=_0x357082(_0x2a7e39('0x95f')),_0xcde69d=_0x357082(_0x2a7e39('0xb21')),_0x3371f8=_0x357082(_0x2a7e39('0x1ff')),_0x391157=Function[_0x2a7e39('0x964')][_0x2a7e39('0xa59')](Object['prototype'][_0x2a7e39('0x1a8')]),_0x56938c=function(){};function _0x39a478(){return null;}_0x223082[_0x2a7e39('0xd7')]=function(_0x1a16e1,_0x3833dc){var _0x1df1b6=_0x2a7e39,_0x1f53b2=_0x1df1b6('0xa25')==typeof Symbol&&Symbol['iterator'],_0x3439b6={'array':_0x1d7158(_0x1df1b6('0x42d')),'bool':_0x1d7158(_0x1df1b6('0xb5e')),'func':_0x1d7158(_0x1df1b6('0xa25')),'number':_0x1d7158(_0x1df1b6('0x218')),'object':_0x1d7158(_0x1df1b6('0xbfd')),'string':_0x1d7158(_0x1df1b6('0x3fd')),'symbol':_0x1d7158(_0x1df1b6('0xb5')),'any':_0x34f306(_0x39a478),'arrayOf':function(_0x466d50){return _0x34f306(function(_0x39e244,_0x10d117,_0x2309d8,_0x3f9e6e,_0x1b2e43){var _0xab63e=_0x1c0e;if(_0xab63e('0xa25')!=typeof _0x466d50)return new _0x9b39c6(_0xab63e('0x97d')+_0x1b2e43+_0xab63e('0x979')+_0x2309d8+_0xab63e('0xbf'));var _0x12a2a3=_0x39e244[_0x10d117];if(!Array[_0xab63e('0xff')](_0x12a2a3))return new _0x9b39c6(_0xab63e('0xa4')+_0x3f9e6e+'\x20`'+_0x1b2e43+_0xab63e('0xb61')+_0x372371(_0x12a2a3)+'`\x20supplied\x20to\x20`'+_0x2309d8+_0xab63e('0x21c'));for(var _0x5ac3d1=0x0;_0x5ac3d1<_0x12a2a3['length'];_0x5ac3d1++){var _0x5209f2=_0x466d50(_0x12a2a3,_0x5ac3d1,_0x2309d8,_0x3f9e6e,_0x1b2e43+'['+_0x5ac3d1+']',_0xcde69d);if(_0x5209f2 instanceof Error)return _0x5209f2;}return null;});},'element':_0x34f306(function(_0x2a2719,_0xc8ba22,_0x4170c6,_0x2eff3b,_0x250272){var _0x146d07=_0x1df1b6,_0x38d265=_0x2a2719[_0xc8ba22];return _0x1a16e1(_0x38d265)?null:new _0x9b39c6(_0x146d07('0xa4')+_0x2eff3b+'\x20`'+_0x250272+_0x146d07('0xb61')+_0x372371(_0x38d265)+_0x146d07('0x885')+_0x4170c6+'`,\x20expected\x20a\x20sin
Line truncated
|
||||||
|
* react-is.development.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
'use strict';'production'!==_0x3ed62b[_0x7ae7b7('0x68b')]['NODE_ENV']&&function(){var _0x273326=_0x7ae7b7,_0x36e536=_0x273326('0xa25')==typeof Symbol&&Symbol['for'],_0x3b0941=_0x36e536?Symbol['for'](_0x273326('0xbf5')):0xeac7,_0x336bbc=_0x36e536?Symbol[_0x273326('0xce2')]('react.portal'):0xeaca,_0x58db15=_0x36e536?Symbol[_0x273326('0xce2')](_0x273326('0x801')):0xeacb,_0x2a66c8=_0x36e536?Symbol['for'](_0x273326('0x2ef')):0xeacc,_0x48666f=_0x36e536?Symbol[_0x273326('0xce2')](_0x273326('0x414')):0xead2,_0x1a4380=_0x36e536?Symbol['for'](_0x273326('0x854')):0xeacd,_0x413bac=_0x36e536?Symbol[_0x273326('0xce2')]('react.context'):0xeace,_0x4c2e8a=_0x36e536?Symbol[_0x273326('0xce2')](_0x273326('0xdc7')):0xeacf,_0x4ee21f=_0x36e536?Symbol['for'](_0x273326('0x4fc')):0xeacf,_0x404707=_0x36e536?Symbol['for']('react.forward_ref'):0xead0,_0x3c268f=_0x36e536?Symbol[_0x273326('0xce2')](_0x273326('0x241')):0xead1,_0x271916=_0x36e536?Symbol[_0x273326('0xce2')](_0x273326('0xbd8')):0xead8,_0x10d621=_0x36e536?Symbol[_0x273326('0xce2')](_0x273326('0x9c7')):0xead3,_0x538c82=_0x36e536?Symbol['for'](_0x273326('0xa87')):0xead4,_0x144087=_0x36e536?Symbol['for'](_0x273326('0x7a8')):0xead9,_0x5dfcd7=_0x36e536?Symbol['for']('react.fundamental'):0xead5,_0x1d6359=_0x36e536?Symbol['for'](_0x273326('0x762')):0xead6,_0x35d210=_0x36e536?Symbol[_0x273326('0xce2')]('react.scope'):0xead7;function _0x32ab76(_0x4444c3){var _0x3cf6f4=_0x273326;if(_0x3cf6f4('0xbfd')==typeof _0x4444c3&&null!==_0x4444c3){var _0xefe4d1=_0x4444c3[_0x3cf6f4('0x5c0')];switch(_0xefe4d1){case _0x3b0941:var _0x3c1042=_0x4444c3['type'];switch(_0x3c1042){case _0x4c2e8a:case _0x4ee21f:case _0x58db15:case _0x48666f:case _0x2a66c8:case _0x3c268f:return _0x3c1042;default:var _0x4cf005=_0x3c1042&&_0x3c1042['$$typeof'];switch(_0x4cf005){case _0x413bac:case _0x404707:case _0x538c82:case _0x10d621:case _0x1a4380:return _0x4cf005;default:return _0xefe4d1;}}case _0x336bbc:return _0xefe4d1;}}}var _0x3ff0bb=_0x4c2e8a,_0x10ca4f=_0x4ee21f,_0x2b1fed=_0x413bac,_0x2f3480=_0x1a4380,_0x365e72=_0x3b0941,_0x58977e=_0x404707,_0x1312c3=_0x58db15,_0x30e58d=_0x538c82,_0x10ee1c=_0x10d621,_0x41f71b=_0x336bbc,_0x36e242=_0x48666f,_0x173f73=_0x2a66c8,_0x208d04=_0x3c268f,_0x42532e=!0x1;function _0x129a26(_0x539f37){return _0x32ab76(_0x539f37)===_0x4ee21f;}_0x31de6a[_0x273326('0xc5b')]=_0x3ff0bb,_0x31de6a[_0x273326('0x8b0')]=_0x10ca4f,_0x31de6a[_0x273326('0x96e')]=_0x2b1fed,_0x31de6a['ContextProvider']=_0x2f3480,_0x31de6a[_0x273326('0x50a')]=_0x365e72,_0x31de6a[_0x273326('0x5c2')]=_0x58977e,_0x31de6a['Fragment']=_0x1312c3,_0x31de6a['Lazy']=_0x30e58d,_0x31de6a[_0x273326('0x5fa')]=_0x10ee1c,_0x31de6a[_0x273326('0x2da')]=_0x41f71b,_0x31de6a[_0x273326('0xd6c')]=_0x36e242,_0x31de6a[_0x273326('0xd4a')]=_0x173f73,_0x31de6a['Suspense']=_0x208d04,_0x31de6a[_0x273326('0x6a9')]=function(_0x5a0acf){var _0x3168e5=_0x273326;return _0x42532e||(_0x42532e=!0x0,console[_0x3168e5('0xb26')]('The\x20ReactIs.isAsyncMode()\x20alias\x20has\x20been\x20deprecated,\x20and\x20will\x20be\x20removed\x20in\x20React\x2017+.\x20Update\x20your\x20code\x20to\x20use\x20ReactIs.isConcurrentMode()\x20instead.\x20It\x20has\x20the\x20exact\x20same\x20API.')),_0x129a26(_0x5a0acf)||_0x32ab76(_0x5a0acf)===_0x4c2e8a;},_0x31de6a[_0x273326('0x113')]=_0x129a26,_0x31de6a['isContextConsumer']=function(_0x454c6e){return _0x32ab76(_0x454c6e)===_0x413bac;},_0x31de6a[_0x273326('0x57f')]=function(_0x3ff21c){return _0x32ab76(_0x3ff21c)===_0x1a4380;},_0x31de6a[_0x273326('0x282')]=function(_0x322dcc){var _0xbb9084=_0x273326;return'object'==typeof _0x322dcc&&null!==_0x322dcc&&_0x322dcc[_0xbb9084('0x5c0')]===_0x3b0941;},_0x31de6a[_0x273326('0x90e')]=function(_0x8e9e57){return _0x32ab76(_0x8e9e57)===_0x404707;},_0x31de6a[_0x273326('0xc7a')]=function(_0x14de2a){return _0x32ab76(_0x14de2a)===_0x58db15;},_0x31de6a[_0x273326('0x1f3')]=function(_0x1b8a33){return _0x32ab76(_0x1b8a33)===_0x538c82;},_0x31de6a[_0x273326('0x39d')]=function(_0x152ee8){return _0x32ab76(_0x152ee8)===_0x10d621;},_0x31de6a[_0x273326('0xdf')]=function(_0x2b3c51){return _0x32ab76(_0x2b3c51)===_0x336bbc;},_0x31de6a[_0x273326('0x678')]=function(_0x154c8e){return _0x32ab76(_0x154c8e)===_0x48666f;},_0x31de6a[_0x273326('0x441')]=function(_0xfa406a){return _0x32ab76(_0xfa406a)===_0x2a66c8;},_0x31de6a['isSuspense']=function(_0x578cf9){return _0x32ab76(_0x578cf9)===_0x3c268f;},_0x31de6a[_0x273326('0x37e')]=function(_0x9246ac){var _0x4d0a82=_0x273326;return'string'==typeof _0x9246ac||_0x4d0a82('0xa25')==typeof _0x9246ac||_0x9246ac===_0x58db15||_0x9246ac===_0x4ee21f||_0x9246ac===_0x48666f||_0x9246ac===_0x2a66c8||_0x9246ac===_0x3c268f||_0x9246ac===_0x271916||_0x4d0a82('0xbfd')==typeof _0x9246ac&&null!==_0x9246ac&&(_0x9246ac['$$typeof']===_0x538c82||_0x9246ac[_0x4d0a82('0x5c0')]===_0x10d621||_0x9246ac['$$typeof']===_0x1a4380||_0x9246ac['$$typeof']===_0x413bac||_0x9246ac['$$typeof']===_0x404707||_0x9246ac['$$typeof']===_0x5dfcd7||_0x9246ac[_0x4d0a82('0x5c0')]===_0x1d6359||_0x9246ac['$$typeof']===_0x35d210||_0x9246Line truncated
|
||||||
|
* react-is.production.min.js
|
||||||
|
*
|
||||||
|
* Copyright (c) Facebook, Inc. and its affiliates.
|
||||||
|
*
|
||||||
|
* This source code is licensed under the MIT license found in the
|
||||||
|
* LICENSE file in the root directory of this source tree.
|
||||||
|
*/
|
||||||
|
'use strict';var _0x562d9a=_0x2fac0e('0xa25')==typeof Symbol&&Symbol[_0x2fac0e('0xce2')],_0x462133=_0x562d9a?Symbol[_0x2fac0e('0xce2')](_0x2fac0e('0xbf5')):0xeac7,_0x292d4e=_0x562d9a?Symbol[_0x2fac0e('0xce2')](_0x2fac0e('0x845')):0xeaca,_0x330e65=_0x562d9a?Symbol[_0x2fac0e('0xce2')](_0x2fac0e('0x801')):0xeacb,_0x14b0ef=_0x562d9a?Symbol['for'](_0x2fac0e('0x2ef')):0xeacc,_0x1c50d6=_0x562d9a?Symbol[_0x2fac0e('0xce2')](_0x2fac0e('0x414')):0xead2,_0x56649b=_0x562d9a?Symbol[_0x2fac0e('0xce2')](_0x2fac0e('0x854')):0xeacd,_0x15d272=_0x562d9a?Symbol['for'](_0x2fac0e('0x558')):0xeace,_0x3a9d53=_0x562d9a?Symbol[_0x2fac0e('0xce2')](_0x2fac0e('0xdc7')):0xeacf,_0x445862=_0x562d9a?Symbol[_0x2fac0e('0xce2')](_0x2fac0e('0x4fc')):0xeacf,_0x3e4ec8=_0x562d9a?Symbol[_0x2fac0e('0xce2')](_0x2fac0e('0x243')):0xead0,_0x49b6d7=_0x562d9a?Symbol[_0x2fac0e('0xce2')](_0x2fac0e('0x241')):0xead1,_0x5d16b6=_0x562d9a?Symbol[_0x2fac0e('0xce2')](_0x2fac0e('0xbd8')):0xead8,_0x3159ad=_0x562d9a?Symbol[_0x2fac0e('0xce2')](_0x2fac0e('0x9c7')):0xead3,_0x2e6fa0=_0x562d9a?Symbol[_0x2fac0e('0xce2')](_0x2fac0e('0xa87')):0xead4,_0x2dbe8a=_0x562d9a?Symbol[_0x2fac0e('0xce2')]('react.block'):0xead9,_0x270951=_0x562d9a?Symbol[_0x2fac0e('0xce2')](_0x2fac0e('0x8c0')):0xead5,_0x5a562c=_0x562d9a?Symbol[_0x2fac0e('0xce2')](_0x2fac0e('0x762')):0xead6,_0x120eb5=_0x562d9a?Symbol[_0x2fac0e('0xce2')](_0x2fac0e('0x326')):0xead7;function _0x4f08c5(_0x4be75f){var _0x47e168=_0x2fac0e;if(_0x47e168('0xbfd')==typeof _0x4be75f&&null!==_0x4be75f){var _0x188c68=_0x4be75f[_0x47e168('0x5c0')];switch(_0x188c68){case _0x462133:switch(_0x4be75f=_0x4be75f[_0x47e168('0x18b')]){case _0x3a9d53:case _0x445862:case _0x330e65:case _0x1c50d6:case _0x14b0ef:case _0x49b6d7:return _0x4be75f;default:switch(_0x4be75f=_0x4be75f&&_0x4be75f['$$typeof']){case _0x15d272:case _0x3e4ec8:case _0x2e6fa0:case _0x3159ad:case _0x56649b:return _0x4be75f;default:return _0x188c68;}}case _0x292d4e:return _0x188c68;}}}function _0x491a6b(_0x1bbcae){return _0x4f08c5(_0x1bbcae)===_0x445862;}_0x3e79af[_0x2fac0e('0xc5b')]=_0x3a9d53,_0x3e79af[_0x2fac0e('0x8b0')]=_0x445862,_0x3e79af[_0x2fac0e('0x96e')]=_0x15d272,_0x3e79af['ContextProvider']=_0x56649b,_0x3e79af[_0x2fac0e('0x50a')]=_0x462133,_0x3e79af[_0x2fac0e('0x5c2')]=_0x3e4ec8,_0x3e79af['Fragment']=_0x330e65,_0x3e79af[_0x2fac0e('0xbfe')]=_0x2e6fa0,_0x3e79af[_0x2fac0e('0x5fa')]=_0x3159ad,_0x3e79af['Portal']=_0x292d4e,_0x3e79af['Profiler']=_0x1c50d6,_0x3e79af[_0x2fac0e('0xd4a')]=_0x14b0ef,_0x3e79af[_0x2fac0e('0xaee')]=_0x49b6d7,_0x3e79af[_0x2fac0e('0x6a9')]=function(_0x58972a){return _0x491a6b(_0x58972a)||_0x4f08c5(_0x58972a)===_0x3a9d53;},_0x3e79af[_0x2fac0e('0x113')]=_0x491a6b,_0x3e79af['isContextConsumer']=function(_0x13875c){return _0x4f08c5(_0x13875c)===_0x15d272;},_0x3e79af[_0x2fac0e('0x57f')]=function(_0x20c756){return _0x4f08c5(_0x20c756)===_0x56649b;},_0x3e79af[_0x2fac0e('0x282')]=function(_0xaf2607){var _0x365719=_0x2fac0e;return'object'==typeof _0xaf2607&&null!==_0xaf2607&&_0xaf2607[_0x365719('0x5c0')]===_0x462133;},_0x3e79af['isForwardRef']=function(_0x49db5a){return _0x4f08c5(_0x49db5a)===_0x3e4ec8;},_0x3e79af['isFragment']=function(_0x2e20b8){return _0x4f08c5(_0x2e20b8)===_0x330e65;},_0x3e79af[_0x2fac0e('0x1f3')]=function(_0x17ba75){return _0x4f08c5(_0x17ba75)===_0x2e6fa0;},_0x3e79af[_0x2fac0e('0x39d')]=function(_0x3dccbc){return _0x4f08c5(_0x3dccbc)===_0x3159ad;},_0x3e79af[_0x2fac0e('0xdf')]=function(_0x4f6268){return _0x4f08c5(_0x4f6268)===_0x292d4e;},_0x3e79af[_0x2fac0e('0x678')]=function(_0x5b3490){return _0x4f08c5(_0x5b3490)===_0x1c50d6;},_0x3e79af[_0x2fac0e('0x441')]=function(_0x280099){return _0x4f08c5(_0x280099)===_0x14b0ef;},_0x3e79af[_0x2fac0e('0x503')]=function(_0x22244d){return _0x4f08c5(_0x22244d)===_0x49b6d7;},_0x3e79af['isValidElementType']=function(_0x356064){var _0x4511c2=_0x2fac0e;return _0x4511c2('0x3fd')==typeof _0x356064||_0x4511c2('0xa25')==typeof _0x356064||_0x356064===_0x330e65||_0x356064===_0x445862||_0x356064===_0x1c50d6||_0x356064===_0x14b0ef||_0x356064===_0x49b6d7||_0x356064===_0x5d16b6||_0x4511c2('0xbfd')==typeof _0x356064&&null!==_0x356064&&(_0x356064[_0x4511c2('0x5c0')]===_0x2e6fa0||_0x356064[_0x4511c2('0x5c0')]===_0x3159ad||_0x356064['$$typeof']===_0x56649b||_0x356064[_0x4511c2('0x5c0')]===_0x15d272||_0x356064['$$typeof']===_0x3e4ec8||_0x356064[_0x4511c2('0x5c0')]===_0x270951||_0x356064[_0x4511c2('0x5c0')]===_0x5a562c||_0x356064[_0x4511c2('0x5c0')]===_0x120eb5||_0x356064['$$typeof']===_0x2dbe8a);},_0x3e79af[_0x2fac0e('0xb48')]=_0x4f08c5;},{}],0x170:[function(_0x4dd546,_0x5cf7e9,_0x20dfa4){var _0x1a45d4=_0x38d28e;(function(_0x4ca3ae){var _0x5951fe=_0x1c0e;'use strict';_0x5951fe('0x5af')===_0x4ca3ae[_0x5951fe('0x68b')][_0x5951fe('0x9a4')]?_0x5cf7e9['exports']=_0x4dd546(_0x5951fe('0x8ce')):_0x5cf7e9[_0x5951fe('0xd7')]=_0x4dd546(_0x5951fe('0x65'));}[_0x1a45d4('0x964')](this,_0x4dd546('_process')));},{'./cjs/react-is.development.js':0x16e,'./cjs/react-is.production.min.js':0x16f,'_process':0x6}],0x171:[function(_0x69e4ec,_0x34Line truncated
|
||||||
Vendored
+1
-1
@@ -58,7 +58,7 @@ div.dataTables_length label{font-weight:400;float:left;text-align:left}div.dataT
|
|||||||
* https://github.com/l-lin/font-awesome-animation
|
* https://github.com/l-lin/font-awesome-animation
|
||||||
* License: MIT
|
* License: MIT
|
||||||
*/@-webkit-keyframes wrench{0%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}8%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}10%{-webkit-transform:rotate(24deg);transform:rotate(24deg)}18%{-webkit-transform:rotate(-24deg);transform:rotate(-24deg)}20%{-webkit-transform:rotate(-24deg);transform:rotate(-24deg)}28%{-webkit-transform:rotate(24deg);transform:rotate(24deg)}30%{-webkit-transform:rotate(24deg);transform:rotate(24deg)}38%{-webkit-transform:rotate(-24deg);transform:rotate(-24deg)}40%{-webkit-transform:rotate(-24deg);transform:rotate(-24deg)}48%{-webkit-transform:rotate(24deg);transform:rotate(24deg)}50%{-webkit-transform:rotate(24deg);transform:rotate(24deg)}58%{-webkit-transform:rotate(-24deg);transform:rotate(-24deg)}60%{-webkit-transform:rotate(-24deg);transform:rotate(-24deg)}68%{-webkit-transform:rotate(24deg);transform:rotate(24deg)}75%{-webkit-transform:rotate(0);transform:rotate(0)}}@keyframes wrench{0%{-webkit-transform:rotate(-12deg);-ms-transform:rotate(-12deg);transform:rotate(-12deg)}8%{-webkit-transform:rotate(12deg);-ms-transform:rotate(12deg);transform:rotate(12deg)}10%{-webkit-transform:rotate(24deg);-ms-transform:rotate(24deg);transform:rotate(24deg)}18%{-webkit-transform:rotate(-24deg);-ms-transform:rotate(-24deg);transform:rotate(-24deg)}20%{-webkit-transform:rotate(-24deg);-ms-transform:rotate(-24deg);transform:rotate(-24deg)}28%{-webkit-transform:rotate(24deg);-ms-transform:rotate(24deg);transform:rotate(24deg)}30%{-webkit-transform:rotate(24deg);-ms-transform:rotate(24deg);transform:rotate(24deg)}38%{-webkit-transform:rotate(-24deg);-ms-transform:rotate(-24deg);transform:rotate(-24deg)}40%{-webkit-transform:rotate(-24deg);-ms-transform:rotate(-24deg);transform:rotate(-24deg)}48%{-webkit-transform:rotate(24deg);-ms-transform:rotate(24deg);transform:rotate(24deg)}50%{-webkit-transform:rotate(24deg);-ms-transform:rotate(24deg);transform:rotate(24deg)}58%{-webkit-transform:rotate(-24deg);-ms-transform:rotate(-24deg);transform:rotate(-24deg)}60%{-webkit-transform:rotate(-24deg);-ms-transform:rotate(-24deg);transform:rotate(-24deg)}68%{-webkit-transform:rotate(24deg);-ms-transform:rotate(24deg);transform:rotate(24deg)}75%{-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}}.faa-parent.animated-hover:hover>.faa-wrench,.faa-wrench.animated,.faa-wrench.animated-hover:hover{-webkit-animation:wrench 2.5s ease infinite;animation:wrench 2.5s ease infinite;transform-origin-x:90%;transform-origin-y:35%;transform-origin-z:initial}@-webkit-keyframes ring{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}2%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}4%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}6%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}8%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}10%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}12%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}14%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}18%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}20%{-webkit-transform:rotate(0);transform:rotate(0)}}@keyframes ring{0%{-webkit-transform:rotate(-15deg);-ms-transform:rotate(-15deg);transform:rotate(-15deg)}2%{-webkit-transform:rotate(15deg);-ms-transform:rotate(15deg);transform:rotate(15deg)}4%{-webkit-transform:rotate(-18deg);-ms-transform:rotate(-18deg);transform:rotate(-18deg)}6%{-webkit-transform:rotate(18deg);-ms-transform:rotate(18deg);transform:rotate(18deg)}8%{-webkit-transform:rotate(-22deg);-ms-transform:rotate(-22deg);transform:rotate(-22deg)}10%{-webkit-transform:rotate(22deg);-ms-transform:rotate(22deg);transform:rotate(22deg)}12%{-webkit-transform:rotate(-18deg);-ms-transform:rotate(-18deg);transform:rotate(-18deg)}14%{-webkit-transform:rotate(18deg);-ms-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-12deg);-ms-transform:rotate(-12deg);transform:rotate(-12deg)}18%{-webkit-transform:rotate(12deg);-ms-transform:rotate(12deg);transform:rotate(12deg)}20%{-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}}.faa-parent.animated-hover:hover>.faa-ring,.faa-ring.animated,.faa-ring.animated-hover:hover{-webkit-animation:ring 2s ease infinite;animation:ring 2s ease infinite;transform-origin-x:50%;transform-origin-y:0;transform-origin-z:initial}@-webkit-keyframes vertical{0%{-webkit-transform:translate(0,-3px);transform:translate(0,-3px)}4%{-webkit-transform:translate(0,3px);transform:translate(0,3px)}8%{-webkit-transform:translate(0,-3px);transform:translate(0,-3px)}12%{-webkit-transform:translate(0,3px);transform:translate(0,3px)}16%{-webkit-transform:translate(0,-3px);transform:translate(0,-3px)}20%{-webkit-transform:translate(0,3px);transform:translate(0,3px)}22%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes vertical{0%{-webkit-transform:translate(0,-3px);-ms-transform:traLine truncated
|
*/@-webkit-keyframes wrench{0%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}8%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}10%{-webkit-transform:rotate(24deg);transform:rotate(24deg)}18%{-webkit-transform:rotate(-24deg);transform:rotate(-24deg)}20%{-webkit-transform:rotate(-24deg);transform:rotate(-24deg)}28%{-webkit-transform:rotate(24deg);transform:rotate(24deg)}30%{-webkit-transform:rotate(24deg);transform:rotate(24deg)}38%{-webkit-transform:rotate(-24deg);transform:rotate(-24deg)}40%{-webkit-transform:rotate(-24deg);transform:rotate(-24deg)}48%{-webkit-transform:rotate(24deg);transform:rotate(24deg)}50%{-webkit-transform:rotate(24deg);transform:rotate(24deg)}58%{-webkit-transform:rotate(-24deg);transform:rotate(-24deg)}60%{-webkit-transform:rotate(-24deg);transform:rotate(-24deg)}68%{-webkit-transform:rotate(24deg);transform:rotate(24deg)}75%{-webkit-transform:rotate(0);transform:rotate(0)}}@keyframes wrench{0%{-webkit-transform:rotate(-12deg);-ms-transform:rotate(-12deg);transform:rotate(-12deg)}8%{-webkit-transform:rotate(12deg);-ms-transform:rotate(12deg);transform:rotate(12deg)}10%{-webkit-transform:rotate(24deg);-ms-transform:rotate(24deg);transform:rotate(24deg)}18%{-webkit-transform:rotate(-24deg);-ms-transform:rotate(-24deg);transform:rotate(-24deg)}20%{-webkit-transform:rotate(-24deg);-ms-transform:rotate(-24deg);transform:rotate(-24deg)}28%{-webkit-transform:rotate(24deg);-ms-transform:rotate(24deg);transform:rotate(24deg)}30%{-webkit-transform:rotate(24deg);-ms-transform:rotate(24deg);transform:rotate(24deg)}38%{-webkit-transform:rotate(-24deg);-ms-transform:rotate(-24deg);transform:rotate(-24deg)}40%{-webkit-transform:rotate(-24deg);-ms-transform:rotate(-24deg);transform:rotate(-24deg)}48%{-webkit-transform:rotate(24deg);-ms-transform:rotate(24deg);transform:rotate(24deg)}50%{-webkit-transform:rotate(24deg);-ms-transform:rotate(24deg);transform:rotate(24deg)}58%{-webkit-transform:rotate(-24deg);-ms-transform:rotate(-24deg);transform:rotate(-24deg)}60%{-webkit-transform:rotate(-24deg);-ms-transform:rotate(-24deg);transform:rotate(-24deg)}68%{-webkit-transform:rotate(24deg);-ms-transform:rotate(24deg);transform:rotate(24deg)}75%{-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}}.faa-parent.animated-hover:hover>.faa-wrench,.faa-wrench.animated,.faa-wrench.animated-hover:hover{-webkit-animation:wrench 2.5s ease infinite;animation:wrench 2.5s ease infinite;transform-origin-x:90%;transform-origin-y:35%;transform-origin-z:initial}@-webkit-keyframes ring{0%{-webkit-transform:rotate(-15deg);transform:rotate(-15deg)}2%{-webkit-transform:rotate(15deg);transform:rotate(15deg)}4%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}6%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}8%{-webkit-transform:rotate(-22deg);transform:rotate(-22deg)}10%{-webkit-transform:rotate(22deg);transform:rotate(22deg)}12%{-webkit-transform:rotate(-18deg);transform:rotate(-18deg)}14%{-webkit-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-12deg);transform:rotate(-12deg)}18%{-webkit-transform:rotate(12deg);transform:rotate(12deg)}20%{-webkit-transform:rotate(0);transform:rotate(0)}}@keyframes ring{0%{-webkit-transform:rotate(-15deg);-ms-transform:rotate(-15deg);transform:rotate(-15deg)}2%{-webkit-transform:rotate(15deg);-ms-transform:rotate(15deg);transform:rotate(15deg)}4%{-webkit-transform:rotate(-18deg);-ms-transform:rotate(-18deg);transform:rotate(-18deg)}6%{-webkit-transform:rotate(18deg);-ms-transform:rotate(18deg);transform:rotate(18deg)}8%{-webkit-transform:rotate(-22deg);-ms-transform:rotate(-22deg);transform:rotate(-22deg)}10%{-webkit-transform:rotate(22deg);-ms-transform:rotate(22deg);transform:rotate(22deg)}12%{-webkit-transform:rotate(-18deg);-ms-transform:rotate(-18deg);transform:rotate(-18deg)}14%{-webkit-transform:rotate(18deg);-ms-transform:rotate(18deg);transform:rotate(18deg)}16%{-webkit-transform:rotate(-12deg);-ms-transform:rotate(-12deg);transform:rotate(-12deg)}18%{-webkit-transform:rotate(12deg);-ms-transform:rotate(12deg);transform:rotate(12deg)}20%{-webkit-transform:rotate(0);-ms-transform:rotate(0);transform:rotate(0)}}.faa-parent.animated-hover:hover>.faa-ring,.faa-ring.animated,.faa-ring.animated-hover:hover{-webkit-animation:ring 2s ease infinite;animation:ring 2s ease infinite;transform-origin-x:50%;transform-origin-y:0;transform-origin-z:initial}@-webkit-keyframes vertical{0%{-webkit-transform:translate(0,-3px);transform:translate(0,-3px)}4%{-webkit-transform:translate(0,3px);transform:translate(0,3px)}8%{-webkit-transform:translate(0,-3px);transform:translate(0,-3px)}12%{-webkit-transform:translate(0,3px);transform:translate(0,3px)}16%{-webkit-transform:translate(0,-3px);transform:translate(0,-3px)}20%{-webkit-transform:translate(0,3px);transform:translate(0,3px)}22%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes vertical{0%{-webkit-transform:translate(0,-3px);-ms-transform:traLine truncated
|
||||||
.redFont{color:red}.box_ws{background:#fff;border-left:1px solid #ddd;border-right:1px solid #ddd;border-bottom:1px solid #ddd;color:#555}.cal_box_ws{background:#fff;border:1px solid #ddd;color:#555;height:100px}.cal_box_ws .wd_date_full{font-weight:700;font-size:10px;float:right;margin-right:5px}.cal_box_ws .wd_date{font-size:10px;float:right;margin-right:5px}.nav-pills li a:hover{background:#1d64ad;color:#fff}.navbar-inverse .brand,.navbar-inverse .nav>li>a{font-weight:700;font-size:12px}.categoryWrap p{font-size:16px;font-weight:700;padding:3px}.categoryWrap p:hover{font-size:16px;font-weight:700;color:#fff;background:gray;padding:3px;cursor:pointer;border-radius:4px}.resultLogo{text-align:center}.pbar{font-weight:700;font-size:11px}.pbar .progress{height:10px}.bs-docs-sidenav{width:228px;margin:30px 0 0;padding:0;background-color:#fff;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 1px 4px rgba(0,0,0,.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,.065);box-shadow:0 1px 4px rgba(0,0,0,.065)}.bs-docs-sidenav>li>a{display:block;margin:0 0 -1px;padding:8px 14px;border:1px solid #e5e5e5}.bs-docs-sidenav>li:first-child>a{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.bs-docs-sidenav>li:last-child>a{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.bs-docs-sidenav>.active>a{position:relative;z-index:2;padding:9px 15px;border:0;text-shadow:0 1px 0 rgba(0,0,0,.15);-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.1),inset -1px 0 0 rgba(0,0,0,.1);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,.1),inset -1px 0 0 rgba(0,0,0,.1);box-shadow:inset 1px 0 0 rgba(0,0,0,.1),inset -1px 0 0 rgba(0,0,0,.1)}.bs-docs-sidenav .icon-chevron-right{float:right;margin-top:2px;margin-right:-6px;opacity:.25}.bs-docs-sidenav>li>a:hover{background-color:#f5f5f5}.bs-docs-sidenav a:hover .icon-chevron-right{opacity:.5}.bs-docs-sidenav .active .icon-chevron-right,.bs-docs-sidenav .active a:hover .icon-chevron-right{background-image:url(../img/glyphicons-halflings-white.png);opacity:1}.bs-docs-sidenav.affix{top:40px}.bs-docs-sidenav.affix-bottom{position:absolute;top:auto;bottom:270px}@media (min-width:1200px){.bs-docs-container{max-width:970px}.bs-docs-sidenav{width:258px}}.reviewPoints{margin-top:10px}.reviewPoints .star{margin-left:10px}.reviewBlock{position:relative;margin:0 0;padding:39px 19px 14px;background-color:#fff;border:1px solid #ddd;font-size:12px}.box_ws{background:#fff;border-left:1px solid #ddd;border-right:1px solid #ddd;border-bottom:1px solid #ddd;color:#555}.cal_box_ws{background:#fff;border:1px solid #ddd;color:#555;height:100px}.cal_box_ws .wd_date_full{font-weight:700;font-size:10px;float:right;margin-right:5px}.cal_box_ws .wd_date{font-size:10px;float:right;margin-right:5px}.nav-pills li a:hover{background:#1d64ad;color:#fff}.nav-tabs>li>a:hover{color:#555}.topheader{background:-moz-linear-gradient(#829aa8,#405a6a);background:-webkit-linear-gradient(#829aa8,#405a6a);background:linear-gradient(#829aa8,#405a6a);border:1px solid #677c89;border-bottom-color:#6b808d;box-shadow:0 1px 0 rgba(255,255,255,.4),0 0 10px rgba(0,0,0,.1)}.bgbody{background:#fafafa;background:-moz-linear-gradient(#fafafa,#eaeaea);background:-webkit-linear-gradient(#fafafa,#eaeaea);background:linear-gradient(#fafafa,#eaeaea);border-bottom:1px solid #cacaca;box-shadow:0 1px 0 rgba(255,255,255,.4),0 0 10px rgba(0,0,0,.1)}.leftMenu{background-color:#e9f1f4;border-style:solid;border-width:1px 1px 2px;border-color:#e9f1f4 #d8dee2 #d8dee2;border-radius:0 0 5px 5px}.nav>li>a:hover{text-decoration:none;background-color:#f5f5f5;border-radius:5px}a{color:#405a6a;text-decoration:none}.nav-header{display:block;padding:3px 15px;font-size:15px;font-weight:700;line-height:20px;text-shadow:0 1px 0 rgba(255,255,255,.5);text-transform:none;background:-moz-linear-gradient(#829aa8,#405a6a);background:-webkit-linear-gradient(#829aa8,#405a6a);background:linear-gradient(#829aa8,#405a6a);color:#fff;border-radius:2px}.modal-backdrop,.modal-backdrop.fade.in{opacity:.4}.error{color:red}.columnMain{font-weight:700}.borderBox{padding-bottom:10px;padding-left:10px;padding-top:10px;-moz-border-radius:5px;border-radius:5px;-webkit-border-radius:5px;margin-bottom:20px;-moz-box-shadow:1px 3px 3px rgba(0,0,0,.1);-webkit-box-shadow:1px 3px 3px rgba(0,0,0,.1);box-shadow:1px 3px 3px rgba(0,0,0,.1);border:1px solid #eee}.iceicon_edit{background-image:url(../images/edit.png)}.iceicon_delete{background-image:url(../images/delete.png)}.iceicon_user{background-image:url(../images/user.png)}.dropdown-menu{z-index:10000}.dropdown-menu>li>a>h5{margin-top:.7em}.lightface .lightfaceContent .lightfaceTitle{font-size:14px;color:#fff;background-color:#405a6a;border:1px solid #405a6a;font-weight:700;margin:-1px;margin-bottom:0;padding:5px 10px;line-height:30px}.badge-ice,.label-ice{background-color:#405a6a}.dataTables_processing{position:absolute;margin-left:40px;font-weight:700;font-sizLine truncated
|
.redFont{color:red}.box_ws{background:#fff;border-left:1px solid #ddd;border-right:1px solid #ddd;border-bottom:1px solid #ddd;color:#555}.cal_box_ws{background:#fff;border:1px solid #ddd;color:#555;height:100px}.cal_box_ws .wd_date_full{font-weight:700;font-size:10px;float:right;margin-right:5px}.cal_box_ws .wd_date{font-size:10px;float:right;margin-right:5px}.nav-pills li a:hover{background:#1d64ad;color:#fff}.navbar-inverse .brand,.navbar-inverse .nav>li>a{font-weight:700;font-size:12px}.categoryWrap p{font-size:16px;font-weight:700;padding:3px}.categoryWrap p:hover{font-size:16px;font-weight:700;color:#fff;background:gray;padding:3px;cursor:pointer;border-radius:4px}.resultLogo{text-align:center}.pbar{font-weight:700;font-size:11px}.pbar .progress{height:10px}.bs-docs-sidenav{width:228px;margin:30px 0 0;padding:0;background-color:#fff;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 1px 4px rgba(0,0,0,.065);-moz-box-shadow:0 1px 4px rgba(0,0,0,.065);box-shadow:0 1px 4px rgba(0,0,0,.065)}.bs-docs-sidenav>li>a{display:block;margin:0 0 -1px;padding:8px 14px;border:1px solid #e5e5e5}.bs-docs-sidenav>li:first-child>a{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0}.bs-docs-sidenav>li:last-child>a{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px}.bs-docs-sidenav>.active>a{position:relative;z-index:2;padding:9px 15px;border:0;text-shadow:0 1px 0 rgba(0,0,0,.15);-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.1),inset -1px 0 0 rgba(0,0,0,.1);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,.1),inset -1px 0 0 rgba(0,0,0,.1);box-shadow:inset 1px 0 0 rgba(0,0,0,.1),inset -1px 0 0 rgba(0,0,0,.1)}.bs-docs-sidenav .icon-chevron-right{float:right;margin-top:2px;margin-right:-6px;opacity:.25}.bs-docs-sidenav>li>a:hover{background-color:#f5f5f5}.bs-docs-sidenav a:hover .icon-chevron-right{opacity:.5}.bs-docs-sidenav .active .icon-chevron-right,.bs-docs-sidenav .active a:hover .icon-chevron-right{background-image:url(../img/glyphicons-halflings-white.png);opacity:1}.bs-docs-sidenav.affix{top:40px}.bs-docs-sidenav.affix-bottom{position:absolute;top:auto;bottom:270px}@media (min-width:1200px){.bs-docs-container{max-width:970px}.bs-docs-sidenav{width:258px}}.reviewPoints{margin-top:10px}.reviewPoints .star{margin-left:10px}.reviewBlock{position:relative;margin:0 0;padding:39px 19px 14px;background-color:#fff;border:1px solid #ddd;font-size:12px}.box_ws{background:#fff;border-left:1px solid #ddd;border-right:1px solid #ddd;border-bottom:1px solid #ddd;color:#555}.cal_box_ws{background:#fff;border:1px solid #ddd;color:#555;height:100px}.cal_box_ws .wd_date_full{font-weight:700;font-size:10px;float:right;margin-right:5px}.cal_box_ws .wd_date{font-size:10px;float:right;margin-right:5px}.nav-pills li a:hover{background:#1d64ad;color:#fff}.nav-tabs>li>a:hover{color:#555}.topheader{background:-moz-linear-gradient(#829aa8,#405a6a);background:-webkit-linear-gradient(#829aa8,#405a6a);background:linear-gradient(#829aa8,#405a6a);border:1px solid #677c89;border-bottom-color:#6b808d;box-shadow:0 1px 0 rgba(255,255,255,.4),0 0 10px rgba(0,0,0,.1)}.bgbody{background:#fafafa;background:-moz-linear-gradient(#fafafa,#eaeaea);background:-webkit-linear-gradient(#fafafa,#eaeaea);background:linear-gradient(#fafafa,#eaeaea);border-bottom:1px solid #cacaca;box-shadow:0 1px 0 rgba(255,255,255,.4),0 0 10px rgba(0,0,0,.1)}.leftMenu{background-color:#e9f1f4;border-style:solid;border-width:1px 1px 2px;border-color:#e9f1f4 #d8dee2 #d8dee2;border-radius:0 0 5px 5px}.nav>li>a:hover{text-decoration:none;background-color:#f5f5f5;border-radius:5px}a{color:#405a6a;text-decoration:none}.nav-header{display:block;padding:3px 15px;font-size:15px;font-weight:700;line-height:20px;text-shadow:0 1px 0 rgba(255,255,255,.5);text-transform:none;background:-moz-linear-gradient(#829aa8,#405a6a);background:-webkit-linear-gradient(#829aa8,#405a6a);background:linear-gradient(#829aa8,#405a6a);color:#fff;border-radius:2px}.modal-backdrop,.modal-backdrop.fade.in{opacity:.4}.error{color:red}.columnMain{font-weight:700}.borderBox{padding-bottom:10px;padding-left:10px;padding-top:10px;-moz-border-radius:5px;border-radius:5px;-webkit-border-radius:5px;margin-bottom:20px;-moz-box-shadow:1px 3px 3px rgba(0,0,0,.1);-webkit-box-shadow:1px 3px 3px rgba(0,0,0,.1);box-shadow:1px 3px 3px rgba(0,0,0,.1);border:1px solid #eee}.iceicon_edit{background-image:url(../images/edit.png)}.iceicon_delete{background-image:url(../images/delete.png)}.iceicon_user{background-image:url(../images/user.png)}.dropdown-menu{z-index:10000}.dropdown-menu>li>a>h5{margin-top:.7em}.lightface .lightfaceContent .lightfaceTitle{font-size:14px;color:#fff;background-color:#405a6a;border:1px solid #405a6a;font-weight:700;margin:-1px;margin-bottom:0;padding:5px 10px;line-height:30px}.badge-ice,.label-ice{background-color:#405a6a}.dataTables_processing{position:absolute;margin-left:40px;font-weight:700;font-sizLine truncated
|
||||||
.CodeMirror{color:#000}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-ruler{border-left:1px solid #ccc;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta,.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-invalidchar,.cm-s-default .cm-error{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative;border-right:30px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-30px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:none;font-variant-ligatures:none}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;overflow:auto}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}.CodeMirror-focused div.CodeMirror-cursors,div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected,.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirrorLine truncated
|
.CodeMirror{color:#000}.CodeMirror-lines{padding:4px 0}.CodeMirror pre{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-ruler{border-left:1px solid #ccc;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta,.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-invalidchar,.cm-s-default .cm-error{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0f0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#f22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-30px;margin-right:-30px;padding-bottom:30px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative;border-right:30px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-30px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important;-webkit-user-select:none;-moz-user-select:none;user-select:none}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:none;font-variant-ligatures:none}.CodeMirror-wrap pre{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;overflow:auto}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:content-box;box-sizing:content-box}.CodeMirror-measure{position:absolute;width:100%;height:0;overflow:hidden;visibility:hidden}.CodeMirror-cursor{position:absolute}.CodeMirror-measure pre{position:static}div.CodeMirror-cursors{visibility:hidden;position:relative;z-index:3}.CodeMirror-focused div.CodeMirror-cursors,div.CodeMirror-dragcursors{visibility:visible}.CodeMirror-selected{background:#d9d9d9}.CodeMirror-focused .CodeMirror-selected,.CodeMirror-line::selection,.CodeMirror-line>span::selection,.CodeMirror-line>span>span::selection{background:#d7d4f0}.CodeMirror-crosshair{cursor:crosshair}.CodeMirror-line::-moz-selection,.CodeMirror-line>span::-moz-selection,.CodeMirrorLine truncated
|
||||||
.CodeMirror{font-family:monospace;height:300px;color:#000;direction:ltr}.CodeMirror-lines{padding:4px 0}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-fat-cursor-mark{background-color:rgba(20,255,20,.5);-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite}.cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-rulers{position:absolute;left:0;right:0;top:-50px;bottom:0;overflow:hidden}.CodeMirror-ruler{border-left:1px solid #ccc;top:0;bottom:0;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-type,.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta{color:#555}.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-s-default .cm-error{color:red}.cm-invalidchar{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0b0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#a22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-50px;margin-right:-50px;padding-bottom:50px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative;border-right:50px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none;outline:0}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-50px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-gutter-wrapper ::selection{background-color:transparent}.CodeMirror-gutter-wrapper ::-moz-selection{background-color:transparent}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:contextual;font-variant-ligatures:contextual}.CodeMirror-wrap pre.CodeMirror-line,.CodeMirror-wrap pre.CodeMirror-line-like{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;padding:.1px}.CodeMirror-rtl pre{direction:rtl}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:coLine truncated
|
.CodeMirror{font-family:monospace;height:300px;color:#000;direction:ltr}.CodeMirror-lines{padding:4px 0}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{padding:0 4px}.CodeMirror-gutter-filler,.CodeMirror-scrollbar-filler{background-color:#fff}.CodeMirror-gutters{border-right:1px solid #ddd;background-color:#f7f7f7;white-space:nowrap}.CodeMirror-linenumber{padding:0 3px 0 5px;min-width:20px;text-align:right;color:#999;white-space:nowrap}.CodeMirror-guttermarker{color:#000}.CodeMirror-guttermarker-subtle{color:#999}.CodeMirror-cursor{border-left:1px solid #000;border-right:none;width:0}.CodeMirror div.CodeMirror-secondarycursor{border-left:1px solid silver}.cm-fat-cursor .CodeMirror-cursor{width:auto;border:0!important;background:#7e7}.cm-fat-cursor div.CodeMirror-cursors{z-index:1}.cm-fat-cursor-mark{background-color:rgba(20,255,20,.5);-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite}.cm-animate-fat-cursor{width:auto;border:0;-webkit-animation:blink 1.06s steps(1) infinite;-moz-animation:blink 1.06s steps(1) infinite;animation:blink 1.06s steps(1) infinite;background-color:#7e7}@-moz-keyframes blink{50%{background-color:transparent}}@-webkit-keyframes blink{50%{background-color:transparent}}@keyframes blink{50%{background-color:transparent}}.cm-tab{display:inline-block;text-decoration:inherit}.CodeMirror-rulers{position:absolute;left:0;right:0;top:-50px;bottom:0;overflow:hidden}.CodeMirror-ruler{border-left:1px solid #ccc;top:0;bottom:0;position:absolute}.cm-s-default .cm-header{color:#00f}.cm-s-default .cm-quote{color:#090}.cm-negative{color:#d44}.cm-positive{color:#292}.cm-header,.cm-strong{font-weight:700}.cm-em{font-style:italic}.cm-link{text-decoration:underline}.cm-strikethrough{text-decoration:line-through}.cm-s-default .cm-keyword{color:#708}.cm-s-default .cm-atom{color:#219}.cm-s-default .cm-number{color:#164}.cm-s-default .cm-def{color:#00f}.cm-s-default .cm-variable-2{color:#05a}.cm-s-default .cm-type,.cm-s-default .cm-variable-3{color:#085}.cm-s-default .cm-comment{color:#a50}.cm-s-default .cm-string{color:#a11}.cm-s-default .cm-string-2{color:#f50}.cm-s-default .cm-meta{color:#555}.cm-s-default .cm-qualifier{color:#555}.cm-s-default .cm-builtin{color:#30a}.cm-s-default .cm-bracket{color:#997}.cm-s-default .cm-tag{color:#170}.cm-s-default .cm-attribute{color:#00c}.cm-s-default .cm-hr{color:#999}.cm-s-default .cm-link{color:#00c}.cm-s-default .cm-error{color:red}.cm-invalidchar{color:red}.CodeMirror-composing{border-bottom:2px solid}div.CodeMirror span.CodeMirror-matchingbracket{color:#0b0}div.CodeMirror span.CodeMirror-nonmatchingbracket{color:#a22}.CodeMirror-matchingtag{background:rgba(255,150,0,.3)}.CodeMirror-activeline-background{background:#e8f2ff}.CodeMirror{position:relative;overflow:hidden;background:#fff}.CodeMirror-scroll{overflow:scroll!important;margin-bottom:-50px;margin-right:-50px;padding-bottom:50px;height:100%;outline:0;position:relative}.CodeMirror-sizer{position:relative;border-right:50px solid transparent}.CodeMirror-gutter-filler,.CodeMirror-hscrollbar,.CodeMirror-scrollbar-filler,.CodeMirror-vscrollbar{position:absolute;z-index:6;display:none;outline:0}.CodeMirror-vscrollbar{right:0;top:0;overflow-x:hidden;overflow-y:scroll}.CodeMirror-hscrollbar{bottom:0;left:0;overflow-y:hidden;overflow-x:scroll}.CodeMirror-scrollbar-filler{right:0;bottom:0}.CodeMirror-gutter-filler{left:0;bottom:0}.CodeMirror-gutters{position:absolute;left:0;top:0;min-height:100%;z-index:3}.CodeMirror-gutter{white-space:normal;height:100%;display:inline-block;vertical-align:top;margin-bottom:-50px}.CodeMirror-gutter-wrapper{position:absolute;z-index:4;background:0 0!important;border:none!important}.CodeMirror-gutter-background{position:absolute;top:0;bottom:0;z-index:4}.CodeMirror-gutter-elt{position:absolute;cursor:default;z-index:4}.CodeMirror-gutter-wrapper ::selection{background-color:transparent}.CodeMirror-gutter-wrapper ::-moz-selection{background-color:transparent}.CodeMirror-lines{cursor:text;min-height:1px}.CodeMirror pre.CodeMirror-line,.CodeMirror pre.CodeMirror-line-like{-moz-border-radius:0;-webkit-border-radius:0;border-radius:0;border-width:0;background:0 0;font-family:inherit;font-size:inherit;margin:0;white-space:pre;word-wrap:normal;line-height:inherit;color:inherit;z-index:2;position:relative;overflow:visible;-webkit-tap-highlight-color:transparent;-webkit-font-variant-ligatures:contextual;font-variant-ligatures:contextual}.CodeMirror-wrap pre.CodeMirror-line,.CodeMirror-wrap pre.CodeMirror-line-like{word-wrap:break-word;white-space:pre-wrap;word-break:normal}.CodeMirror-linebackground{position:absolute;left:0;right:0;top:0;bottom:0;z-index:0}.CodeMirror-linewidget{position:relative;z-index:2;padding:.1px}.CodeMirror-rtl pre{direction:rtl}.CodeMirror-code{outline:0}.CodeMirror-gutter,.CodeMirror-gutters,.CodeMirror-linenumber,.CodeMirror-scroll,.CodeMirror-sizer{-moz-box-sizing:coLine truncated
|
||||||
.ant-image-preview,.ant-modal{pointer-events:none}.ant-image-preview.zoom-appear,.ant-image-preview.zoom-enter,.ant-modal.zoom-appear,.ant-modal.zoom-enter{transform:none;opacity:0;animation-duration:.3s;user-select:none}.ant-image-preview-mask,.ant-modal-mask{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1000;height:100%;background-color:rgba(0,0,0,.45)}.ant-image-preview-mask-hidden,.ant-modal-mask-hidden{display:none}.ant-image-preview-wrap,.ant-modal-wrap{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;outline:0;-webkit-overflow-scrolling:touch}[class*=ant-] input::-ms-clear,[class*=ant-] input::-ms-reveal,[class*=ant-]::-ms-clear,[class^=ant-] input::-ms-clear,[class^=ant-] input::-ms-reveal,[class^=ant-]::-ms-clear{display:none}[class*=ant-],[class*=ant-] *,[class*=ant-] ::after,[class*=ant-] ::before,[class^=ant-],[class^=ant-] *,[class^=ant-] ::after,[class^=ant-] ::before{box-sizing:border-box}body,html{width:100%;height:100%}input::-ms-clear,input::-ms-reveal{display:none}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}body{margin:0;color:rgba(0,0,0,.85);font-size:14px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,'Noto Sans',sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol','Noto Color Emoji';font-variant:tabular-nums;line-height:1.5715;background-color:#fff;font-feature-settings:'tnum'}[tabindex='-1']:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5em;color:rgba(0,0,0,.85);font-weight:500}p{margin-top:0;margin-bottom:1em}abbr[data-original-title],abbr[title]{text-decoration:underline;text-decoration:underline dotted;border-bottom:0;cursor:help}address{margin-bottom:1em;font-style:normal;line-height:inherit}input[type=number],input[type=password],input[type=text],textarea{-webkit-appearance:none}dl,ol,ul{margin-top:0;margin-bottom:1em}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:500}dd{margin-bottom:.5em;margin-left:0}blockquote{margin:0 0 1em}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#1890ff;text-decoration:none;background-color:transparent;outline:0;cursor:pointer;transition:color .3s;-webkit-text-decoration-skip:objects}a:hover{color:#40a9ff}a:active{color:#096dd9}a:active,a:hover{text-decoration:none;outline:0}a:focus{text-decoration:none;outline:0}a[disabled]{color:rgba(0,0,0,.25);cursor:not-allowed;pointer-events:none}code,kbd,pre,samp{font-size:1em;font-family:SFMono-Regular,Consolas,'Liberation Mono',Menlo,Courier,monospace}pre{margin-top:0;margin-bottom:1em;overflow:auto}figure{margin:0 0 1em}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}[role=button],a,area,button,input:not([type=range]),label,select,summary,textarea{touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75em;padding-bottom:.3em;color:rgba(0,0,0,.45);text-align:left;caption-side:bottom}th{text-align:inherit}button,input,optgroup,select,textarea{margin:0;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;margin:0;padding:0;border:0}legend{display:block;width:100%;max-width:100%;margin-bottom:.5em;padding:0;color:inherit;font-size:1.5em;line-height:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}mark{padding:.2em;background-color:#feffe6}::selection{color:#fff;background:#1890ff}.clearfix::before{display:table;content:''}.clearfix::after{display:table;clear:both;content:''}.anticon{display:inline-block;color:inherit;font-style:normal;line-height:0;text-align:center;text-transform:none;vertical-align:-.125em;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothingLine truncated
|
.ant-image-preview,.ant-modal{pointer-events:none}.ant-image-preview.zoom-appear,.ant-image-preview.zoom-enter,.ant-modal.zoom-appear,.ant-modal.zoom-enter{transform:none;opacity:0;animation-duration:.3s;user-select:none}.ant-image-preview-mask,.ant-modal-mask{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1000;height:100%;background-color:rgba(0,0,0,.45)}.ant-image-preview-mask-hidden,.ant-modal-mask-hidden{display:none}.ant-image-preview-wrap,.ant-modal-wrap{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;outline:0;-webkit-overflow-scrolling:touch}[class*=ant-] input::-ms-clear,[class*=ant-] input::-ms-reveal,[class*=ant-]::-ms-clear,[class^=ant-] input::-ms-clear,[class^=ant-] input::-ms-reveal,[class^=ant-]::-ms-clear{display:none}[class*=ant-],[class*=ant-] *,[class*=ant-] ::after,[class*=ant-] ::before,[class^=ant-],[class^=ant-] *,[class^=ant-] ::after,[class^=ant-] ::before{box-sizing:border-box}body,html{width:100%;height:100%}input::-ms-clear,input::-ms-reveal{display:none}*,::after,::before{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:transparent}@-ms-viewport{width:device-width}body{margin:0;color:rgba(0,0,0,.85);font-size:14px;font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,'Helvetica Neue',Arial,'Noto Sans',sans-serif,'Apple Color Emoji','Segoe UI Emoji','Segoe UI Symbol','Noto Color Emoji';font-variant:tabular-nums;line-height:1.5715;background-color:#fff;font-feature-settings:'tnum'}[tabindex='-1']:focus{outline:0!important}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5em;color:rgba(0,0,0,.85);font-weight:500}p{margin-top:0;margin-bottom:1em}abbr[data-original-title],abbr[title]{text-decoration:underline;text-decoration:underline dotted;border-bottom:0;cursor:help}address{margin-bottom:1em;font-style:normal;line-height:inherit}input[type=number],input[type=password],input[type=text],textarea{-webkit-appearance:none}dl,ol,ul{margin-top:0;margin-bottom:1em}ol ol,ol ul,ul ol,ul ul{margin-bottom:0}dt{font-weight:500}dd{margin-bottom:.5em;margin-left:0}blockquote{margin:0 0 1em}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}a{color:#1890ff;text-decoration:none;background-color:transparent;outline:0;cursor:pointer;transition:color .3s;-webkit-text-decoration-skip:objects}a:hover{color:#40a9ff}a:active{color:#096dd9}a:active,a:hover{text-decoration:none;outline:0}a:focus{text-decoration:none;outline:0}a[disabled]{color:rgba(0,0,0,.25);cursor:not-allowed;pointer-events:none}code,kbd,pre,samp{font-size:1em;font-family:SFMono-Regular,Consolas,'Liberation Mono',Menlo,Courier,monospace}pre{margin-top:0;margin-bottom:1em;overflow:auto}figure{margin:0 0 1em}img{vertical-align:middle;border-style:none}svg:not(:root){overflow:hidden}[role=button],a,area,button,input:not([type=range]),label,select,summary,textarea{touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75em;padding-bottom:.3em;color:rgba(0,0,0,.45);text-align:left;caption-side:bottom}th{text-align:inherit}button,input,optgroup,select,textarea{margin:0;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{padding:0;border-style:none}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=date],input[type=datetime-local],input[type=month],input[type=time]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;margin:0;padding:0;border:0}legend{display:block;width:100%;max-width:100%;margin-bottom:.5em;padding:0;color:inherit;font-size:1.5em;line-height:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}mark{padding:.2em;background-color:#feffe6}::selection{color:#fff;background:#1890ff}.clearfix::before{display:table;content:''}.clearfix::after{display:table;clear:both;content:''}.anticon{display:inline-block;color:inherit;font-style:normal;line-height:0;text-align:center;text-transform:none;vertical-align:-.125em;text-rendering:optimizeLegibility;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothingLine truncated
|
||||||
Loaded 100 of 103 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user