Merge pull request #1166 from fraenki/acme_1163

security/acme-client: release 1.21
This commit is contained in:
Frank Wall
2019-02-04 22:11:50 +01:00
committed by GitHub
9 changed files with 77 additions and 609 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
PLUGIN_NAME= acme-client
PLUGIN_VERSION= 1.20
PLUGIN_VERSION= 1.21
PLUGIN_COMMENT= Let's Encrypt client
PLUGIN_MAINTAINER= opnsense@moov.de
PLUGIN_DEPENDS= acme.sh bind912
@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2017 Frank Wall
* Copyright (C) 2017-2019 Frank Wall
* Copyright (C) 2015 Deciso B.V.
*
* All rights reserved.
@@ -29,181 +29,48 @@
*/
namespace OPNsense\AcmeClient\Api;
use \OPNsense\Base\ApiControllerBase;
use \OPNsense\AcmeClient\AcmeClient;
use \OPNsense\Core\Config;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Base\UIModelGrid;
use \OPNsense\Core\Config;
use \OPNsense\AcmeClient\AcmeClient;
/**
* Class AccountsController
* @package OPNsense\AcmeClient
*/
class AccountsController extends ApiControllerBase
class AccountsController extends ApiMutableModelControllerBase
{
/**
* Validate and save model after update or insertion.
* Use the reference node and tag to rename validation output for a specific
* node to a new offset, which makes it easier to reference specific uuids
* without having to use them in the frontend descriptions.
* @param $mdl model reference
* @param $node reference node, to use as relative offset
* @param $reference reference for validation output, used to rename the validation output keys
* @return array result / validation output
*/
private function save($mdl, $node = null, $reference = null)
{
$result = array("result"=>"failed","validations" => array());
// perform validation
$valMsgs = $mdl->performValidation();
foreach ($valMsgs as $field => $msg) {
// replace absolute path to attribute for relative one at uuid.
if ($node != null) {
$fieldnm = str_replace($node->__reference, $reference, $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
} else {
$result["validations"][$msg->getField()] = $msg->getMessage();
}
}
protected static $internalModelName = 'acmeclient';
protected static $internalModelClass = '\OPNsense\AcmeClient\AcmeClient';
// serialize model to config and save when there are no validation errors
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdl->serializeToConfig();
Config::getInstance()->save();
$result = array("result" => "saved");
}
return $result;
}
/**
* retrieve account settings or return defaults
* @param $uuid item unique id
* @return array
*/
public function getAction($uuid = null)
{
$mdlAcme = new AcmeClient();
if ($uuid != null) {
$node = $mdlAcme->getNodeByReference('accounts.account.'.$uuid);
if ($node != null) {
// return node
return array("account" => $node->getNodes());
}
} else {
// generate new node, but don't save to disc
$node = $mdlAcme->accounts->account->add();
return array("account" => $node->getNodes());
}
return array();
$this->sessionClose();
return $this->getBase('account', 'accounts.account', $uuid);
}
/**
* update account with given properties
* @param $uuid item unique id
* @return array
*/
public function setAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost("account")) {
$mdlAcme = new AcmeClient();
if ($uuid != null) {
$node = $mdlAcme->getNodeByReference('accounts.account.'.$uuid);
if ($node != null) {
$node->setNodes($this->request->getPost("account"));
return $this->save($mdlAcme, $node, "account");
}
}
}
return array("result"=>"failed");
}
/**
* add new account and set with attributes from post
* @return array
*/
public function addAction()
{
$result = array("result"=>"failed");
if ($this->request->isPost() && $this->request->hasPost("account")) {
$mdlAcme = new AcmeClient();
$node = $mdlAcme->accounts->account->Add();
$node->setNodes($this->request->getPost("account"));
return $this->save($mdlAcme, $node, "account");
}
return $result;
return $this->addBase('account', 'accounts.account');
}
public function updateAction($uuid)
{
return $this->setBase('account', 'accounts.account', $uuid);
}
/**
* delete account by uuid
* @param $uuid item unique id
* @return array status
*/
public function delAction($uuid)
{
$result = array("result"=>"failed");
if ($this->request->isPost()) {
$mdlAcme = new AcmeClient();
if ($uuid != null) {
if ($mdlAcme->accounts->account->del($uuid)) {
// if item is removed, serialize to config and save
$mdlAcme->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
return $this->delBase('accounts.account', $uuid);
}
/**
* toggle account by uuid (enable/disable)
* @param $uuid item unique id
* @param $enabled desired state enabled(1)/disabled(0), leave empty for toggle
* @return array status
*/
public function toggleAction($uuid, $enabled = null)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$mdlAcme = new AcmeClient();
if ($uuid != null) {
$node = $mdlAcme->getNodeByReference('accounts.account.' . $uuid);
if ($node != null) {
if ($enabled == "0" || $enabled == "1") {
$node->enabled = (string)$enabled;
} elseif ((string)$node->enabled == "1") {
$node->enabled = "0";
} else {
$node->enabled = "1";
}
$result['result'] = $node->enabled;
// if item has toggled, serialize to config and save
$mdlAcme->serializeToConfig();
Config::getInstance()->save();
}
}
}
return $result;
return $this->toggleBase('accounts.account', $uuid);
}
/**
* search accounts
* @return array
*/
public function searchAction()
{
$this->sessionClose();
$mdlAcme = new AcmeClient();
$grid = new UIModelGrid($mdlAcme->accounts->account);
return $grid->fetchBindRequest(
$this->request,
array("enabled", "name", "email"),
"name"
);
return $this->searchBase('accounts.account', array('enabled', 'name', 'email'), 'name');
}
}
@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2017 Frank Wall
* Copyright (C) 2017-2019 Frank Wall
* Copyright (C) 2015 Deciso B.V.
*
* All rights reserved.
@@ -29,181 +29,48 @@
*/
namespace OPNsense\AcmeClient\Api;
use \OPNsense\Base\ApiControllerBase;
use \OPNsense\AcmeClient\AcmeClient;
use \OPNsense\Core\Config;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Base\UIModelGrid;
use \OPNsense\Core\Config;
use \OPNsense\AcmeClient\AcmeClient;
/**
* Class ActionsController
* @package OPNsense\AcmeClient
*/
class ActionsController extends ApiControllerBase
class ActionsController extends ApiMutableModelControllerBase
{
/**
* Validate and save model after update or insertion.
* Use the reference node and tag to rename validation output for a specific
* node to a new offset, which makes it easier to reference specific uuids
* without having to use them in the frontend descriptions.
* @param $mdl model reference
* @param $node reference node, to use as relative offset
* @param $reference reference for validation output, used to rename the validation output keys
* @return array result / validation output
*/
private function save($mdl, $node = null, $reference = null)
{
$result = array("result"=>"failed","validations" => array());
// perform validation
$valMsgs = $mdl->performValidation();
foreach ($valMsgs as $field => $msg) {
// replace absolute path to attribute for relative one at uuid.
if ($node != null) {
$fieldnm = str_replace($node->__reference, $reference, $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
} else {
$result["validations"][$msg->getField()] = $msg->getMessage();
}
}
protected static $internalModelName = 'acmeclient';
protected static $internalModelClass = '\OPNsense\AcmeClient\AcmeClient';
// serialize model to config and save when there are no validation errors
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdl->serializeToConfig();
Config::getInstance()->save();
$result = array("result" => "saved");
}
return $result;
}
/**
* retrieve action settings or return defaults
* @param $uuid item unique id
* @return array
*/
public function getAction($uuid = null)
{
$mdlAcme = new AcmeClient();
if ($uuid != null) {
$node = $mdlAcme->getNodeByReference('actions.action.'.$uuid);
if ($node != null) {
// return node
return array("action" => $node->getNodes());
}
} else {
// generate new node, but don't save to disc
$node = $mdlAcme->actions->action->add();
return array("action" => $node->getNodes());
}
return array();
$this->sessionClose();
return $this->getBase('action', 'actions.action', $uuid);
}
/**
* update action with given properties
* @param $uuid item unique id
* @return array
*/
public function setAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost("action")) {
$mdlAcme = new AcmeClient();
if ($uuid != null) {
$node = $mdlAcme->getNodeByReference('actions.action.'.$uuid);
if ($node != null) {
$node->setNodes($this->request->getPost("action"));
return $this->save($mdlAcme, $node, "action");
}
}
}
return array("result"=>"failed");
}
/**
* add new action and set with attributes from post
* @return array
*/
public function addAction()
{
$result = array("result"=>"failed");
if ($this->request->isPost() && $this->request->hasPost("action")) {
$mdlAcme = new AcmeClient();
$node = $mdlAcme->actions->action->Add();
$node->setNodes($this->request->getPost("action"));
return $this->save($mdlAcme, $node, "action");
}
return $result;
return $this->addBase('action', 'actions.action');
}
public function updateAction($uuid)
{
return $this->setBase('action', 'actions.action', $uuid);
}
/**
* delete action by uuid
* @param $uuid item unique id
* @return array status
*/
public function delAction($uuid)
{
$result = array("result"=>"failed");
if ($this->request->isPost()) {
$mdlAcme = new AcmeClient();
if ($uuid != null) {
if ($mdlAcme->actions->action->del($uuid)) {
// if item is removed, serialize to config and save
$mdlAcme->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
return $this->delBase('actions.action', $uuid);
}
/**
* toggle action by uuid (enable/disable)
* @param $uuid item unique id
* @param $enabled desired state enabled(1)/disabled(0), leave empty for toggle
* @return array status
*/
public function toggleAction($uuid, $enabled = null)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$mdlAcme = new AcmeClient();
if ($uuid != null) {
$node = $mdlAcme->getNodeByReference('actions.action.' . $uuid);
if ($node != null) {
if ($enabled == "0" || $enabled == "1") {
$node->enabled = (string)$enabled;
} elseif ((string)$node->enabled == "1") {
$node->enabled = "0";
} else {
$node->enabled = "1";
}
$result['result'] = $node->enabled;
// if item has toggled, serialize to config and save
$mdlAcme->serializeToConfig();
Config::getInstance()->save();
}
}
}
return $result;
return $this->toggleBase('actions.action', $uuid);
}
/**
* search actions
* @return array
*/
public function searchAction()
{
$this->sessionClose();
$mdlAcme = new AcmeClient();
$grid = new UIModelGrid($mdlAcme->actions->action);
return $grid->fetchBindRequest(
$this->request,
array("enabled", "name", "description"),
"name"
);
return $this->searchBase('actions.action', array('enabled', 'name', 'description'), 'name');
}
}
@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2017 Frank Wall
* Copyright (C) 2017-2019 Frank Wall
* Copyright (C) 2015 Deciso B.V.
*
* All rights reserved.
@@ -29,183 +29,50 @@
*/
namespace OPNsense\AcmeClient\Api;
use \OPNsense\Base\ApiControllerBase;
use \OPNsense\AcmeClient\AcmeClient;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Base\UIModelGrid;
use \OPNsense\Core\Backend;
use \OPNsense\Core\Config;
use \OPNsense\Base\UIModelGrid;
use \OPNsense\AcmeClient\AcmeClient;
/**
* Class CertificatesController
* @package OPNsense\AcmeClient
*/
class CertificatesController extends ApiControllerBase
class CertificatesController extends ApiMutableModelControllerBase
{
/**
* Validate and save model after update or insertion.
* Use the reference node and tag to rename validation output for a specific
* node to a new offset, which makes it easier to reference specific uuids
* without having to use them in the frontend descriptions.
* @param $mdl model reference
* @param $node reference node, to use as relative offset
* @param $reference reference for validation output, used to rename the validation output keys
* @return array result / validation output
*/
private function save($mdl, $node = null, $reference = null)
{
$result = array("result"=>"failed","validations" => array());
// perform validation
$valMsgs = $mdl->performValidation();
foreach ($valMsgs as $field => $msg) {
// replace absolute path to attribute for relative one at uuid.
if ($node != null) {
$fieldnm = str_replace($node->__reference, $reference, $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
} else {
$result["validations"][$msg->getField()] = $msg->getMessage();
}
}
protected static $internalModelName = 'acmeclient';
protected static $internalModelClass = '\OPNsense\AcmeClient\AcmeClient';
// serialize model to config and save when there are no validation errors
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdl->serializeToConfig();
Config::getInstance()->save();
$result = array("result" => "saved");
}
return $result;
}
/**
* retrieve certificate settings or return defaults
* @param $uuid item unique id
* @return array
*/
public function getAction($uuid = null)
{
$mdlAcme = new AcmeClient();
if ($uuid != null) {
$node = $mdlAcme->getNodeByReference('certificates.certificate.'.$uuid);
if ($node != null) {
// return node
return array("certificate" => $node->getNodes());
}
} else {
// generate new node, but don't save to disc
$node = $mdlAcme->certificates->certificate->add();
return array("certificate" => $node->getNodes());
}
return array();
$this->sessionClose();
return $this->getBase('certificate', 'certificates.certificate', $uuid);
}
/**
* update certificate with given properties
* @param $uuid item unique id
* @return array
*/
public function setAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost("certificate")) {
$mdlAcme = new AcmeClient();
if ($uuid != null) {
$node = $mdlAcme->getNodeByReference('certificates.certificate.'.$uuid);
if ($node != null) {
$node->setNodes($this->request->getPost("certificate"));
return $this->save($mdlAcme, $node, "certificate");
}
}
}
return array("result"=>"failed");
}
/**
* add new certificate and set with attributes from post
* @return array
*/
public function addAction()
{
$result = array("result"=>"failed");
if ($this->request->isPost() && $this->request->hasPost("certificate")) {
$mdlAcme = new AcmeClient();
$node = $mdlAcme->certificates->certificate->Add();
$node->setNodes($this->request->getPost("certificate"));
return $this->save($mdlAcme, $node, "certificate");
}
return $result;
return $this->addBase('certificate', 'certificates.certificate');
}
public function updateAction($uuid)
{
return $this->setBase('certificate', 'certificates.certificate', $uuid);
}
/**
* delete certificate by uuid
* @param $uuid item unique id
* @return array status
*/
public function delAction($uuid)
{
$result = array("result"=>"failed");
if ($this->request->isPost()) {
$mdlAcme = new AcmeClient();
if ($uuid != null) {
if ($mdlAcme->certificates->certificate->del($uuid)) {
// if item is removed, serialize to config and save
$mdlAcme->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
return $this->delBase('certificates.certificate', $uuid);
}
/**
* toggle certificate by uuid (enable/disable)
* @param $uuid item unique id
* @param $enabled desired state enabled(1)/disabled(0), leave empty for toggle
* @return array status
*/
public function toggleAction($uuid, $enabled = null)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$mdlAcme = new AcmeClient();
if ($uuid != null) {
$node = $mdlAcme->getNodeByReference('certificates.certificate.' . $uuid);
if ($node != null) {
if ($enabled == "0" || $enabled == "1") {
$node->enabled = (string)$enabled;
} elseif ((string)$node->enabled == "1") {
$node->enabled = "0";
} else {
$node->enabled = "1";
}
$result['result'] = $node->enabled;
// if item has toggled, serialize to config and save
$mdlAcme->serializeToConfig();
Config::getInstance()->save();
}
}
}
return $result;
return $this->toggleBase('certificates.certificate', $uuid);
}
/**
* search certificates
* @return array
*/
public function searchAction()
{
$this->sessionClose();
$mdlAcme = new AcmeClient();
$grid = new UIModelGrid($mdlAcme->certificates->certificate);
return $grid->fetchBindRequest(
$this->request,
array("enabled", "name", "altNames", "description", "lastUpdate", "statusCode", "statusLastUpdate"),
"name"
);
return $this->searchBase('certificates.certificate', array('enabled', 'name', 'altNames', 'description', 'lastUpdate', 'statusCode', 'statusLastUpdate'), 'name');
}
/**
@@ -1,6 +1,6 @@
<?php
/**
* Copyright (C) 2017 Frank Wall
* Copyright (C) 2017-2019 Frank Wall
* Copyright (C) 2015 Deciso B.V.
*
* All rights reserved.
@@ -29,181 +29,48 @@
*/
namespace OPNsense\AcmeClient\Api;
use \OPNsense\Base\ApiControllerBase;
use \OPNsense\AcmeClient\AcmeClient;
use \OPNsense\Core\Config;
use \OPNsense\Base\ApiMutableModelControllerBase;
use \OPNsense\Base\UIModelGrid;
use \OPNsense\Core\Config;
use \OPNsense\AcmeClient\AcmeClient;
/**
* Class ValidationsController
* @package OPNsense\AcmeClient
*/
class ValidationsController extends ApiControllerBase
class ValidationsController extends ApiMutableModelControllerBase
{
/**
* Validate and save model after update or insertion.
* Use the reference node and tag to rename validation output for a specific
* node to a new offset, which makes it easier to reference specific uuids
* without having to use them in the frontend descriptions.
* @param $mdl model reference
* @param $node reference node, to use as relative offset
* @param $reference reference for validation output, used to rename the validation output keys
* @return array result / validation output
*/
private function save($mdl, $node = null, $reference = null)
{
$result = array("result"=>"failed","validations" => array());
// perform validation
$valMsgs = $mdl->performValidation();
foreach ($valMsgs as $field => $msg) {
// replace absolute path to attribute for relative one at uuid.
if ($node != null) {
$fieldnm = str_replace($node->__reference, $reference, $msg->getField());
$result["validations"][$fieldnm] = $msg->getMessage();
} else {
$result["validations"][$msg->getField()] = $msg->getMessage();
}
}
protected static $internalModelName = 'acmeclient';
protected static $internalModelClass = '\OPNsense\AcmeClient\AcmeClient';
// serialize model to config and save when there are no validation errors
if (count($result['validations']) == 0) {
// save config if validated correctly
$mdl->serializeToConfig();
Config::getInstance()->save();
$result = array("result" => "saved");
}
return $result;
}
/**
* retrieve validation settings or return defaults
* @param $uuid item unique id
* @return array
*/
public function getAction($uuid = null)
{
$mdlAcme = new AcmeClient();
if ($uuid != null) {
$node = $mdlAcme->getNodeByReference('validations.validation.'.$uuid);
if ($node != null) {
// return node
return array("validation" => $node->getNodes());
}
} else {
// generate new node, but don't save to disc
$node = $mdlAcme->validations->validation->add();
return array("validation" => $node->getNodes());
}
return array();
$this->sessionClose();
return $this->getBase('validation', 'validations.validation', $uuid);
}
/**
* update validation with given properties
* @param $uuid item unique id
* @return array
*/
public function setAction($uuid)
{
if ($this->request->isPost() && $this->request->hasPost("validation")) {
$mdlAcme = new AcmeClient();
if ($uuid != null) {
$node = $mdlAcme->getNodeByReference('validations.validation.'.$uuid);
if ($node != null) {
$node->setNodes($this->request->getPost("validation"));
return $this->save($mdlAcme, $node, "validation");
}
}
}
return array("result"=>"failed");
}
/**
* add new validation and set with attributes from post
* @return array
*/
public function addAction()
{
$result = array("result"=>"failed");
if ($this->request->isPost() && $this->request->hasPost("validation")) {
$mdlAcme = new AcmeClient();
$node = $mdlAcme->validations->validation->Add();
$node->setNodes($this->request->getPost("validation"));
return $this->save($mdlAcme, $node, "validation");
}
return $result;
return $this->addBase('validation', 'validations.validation');
}
public function updateAction($uuid)
{
return $this->setBase('validation', 'validations.validation', $uuid);
}
/**
* delete validation by uuid
* @param $uuid item unique id
* @return array status
*/
public function delAction($uuid)
{
$result = array("result"=>"failed");
if ($this->request->isPost()) {
$mdlAcme = new AcmeClient();
if ($uuid != null) {
if ($mdlAcme->validations->validation->del($uuid)) {
// if item is removed, serialize to config and save
$mdlAcme->serializeToConfig();
Config::getInstance()->save();
$result['result'] = 'deleted';
} else {
$result['result'] = 'not found';
}
}
}
return $result;
return $this->delBase('validations.validation', $uuid);
}
/**
* toggle validation by uuid (enable/disable)
* @param $uuid item unique id
* @param $enabled desired state enabled(1)/disabled(0), leave empty for toggle
* @return array status
*/
public function toggleAction($uuid, $enabled = null)
{
$result = array("result" => "failed");
if ($this->request->isPost()) {
$mdlAcme = new AcmeClient();
if ($uuid != null) {
$node = $mdlAcme->getNodeByReference('validations.validation.' . $uuid);
if ($node != null) {
if ($enabled == "0" || $enabled == "1") {
$node->enabled = (string)$enabled;
} elseif ((string)$node->enabled == "1") {
$node->enabled = "0";
} else {
$node->enabled = "1";
}
$result['result'] = $node->enabled;
// if item has toggled, serialize to config and save
$mdlAcme->serializeToConfig();
Config::getInstance()->save();
}
}
}
return $result;
return $this->toggleBase('validations.validation', $uuid);
}
/**
* search validations
* @return array
*/
public function searchAction()
{
$this->sessionClose();
$mdlAcme = new AcmeClient();
$grid = new UIModelGrid($mdlAcme->validations->validation);
return $grid->fetchBindRequest(
$this->request,
array("enabled", "name", "description"),
"name"
);
return $this->searchBase('validations.validation', array('enabled', 'name', 'description'), 'name');
}
}
@@ -38,7 +38,7 @@ POSSIBILITY OF SUCH DAMAGE.
$("#grid-accounts").UIBootgrid(
{ search:'/api/acmeclient/accounts/search',
get:'/api/acmeclient/accounts/get/',
set:'/api/acmeclient/accounts/set/',
set:'/api/acmeclient/accounts/update/',
add:'/api/acmeclient/accounts/add/',
del:'/api/acmeclient/accounts/del/',
toggle:'/api/acmeclient/accounts/toggle/',
@@ -38,7 +38,7 @@ POSSIBILITY OF SUCH DAMAGE.
$("#grid-actions").UIBootgrid(
{ search:'/api/acmeclient/actions/search',
get:'/api/acmeclient/actions/get/',
set:'/api/acmeclient/actions/set/',
set:'/api/acmeclient/actions/update/',
add:'/api/acmeclient/actions/add/',
del:'/api/acmeclient/actions/del/',
toggle:'/api/acmeclient/actions/toggle/',
@@ -41,7 +41,7 @@ POSSIBILITY OF SUCH DAMAGE.
var gridParams = {
search:'/api/acmeclient/certificates/search',
get:'/api/acmeclient/certificates/get/',
set:'/api/acmeclient/certificates/set/',
set:'/api/acmeclient/certificates/update/',
add:'/api/acmeclient/certificates/add/',
del:'/api/acmeclient/certificates/del/',
toggle:'/api/acmeclient/certificates/toggle/',
@@ -38,7 +38,7 @@ POSSIBILITY OF SUCH DAMAGE.
$("#grid-validations").UIBootgrid(
{ search:'/api/acmeclient/validations/search',
get:'/api/acmeclient/validations/get/',
set:'/api/acmeclient/validations/set/',
set:'/api/acmeclient/validations/update/',
add:'/api/acmeclient/validations/add/',
del:'/api/acmeclient/validations/del/',
toggle:'/api/acmeclient/validations/toggle/',