add shop controllers
This commit is contained in:
commit
b5b3117fec
46
composer.json
Normal file
46
composer.json
Normal file
@ -0,0 +1,46 @@
|
||||
{
|
||||
"name": "d3/oxwebauthn",
|
||||
"description": "Webauthn / FIDO2 module for OXID eShop.",
|
||||
"type": "oxideshop-module",
|
||||
"keywords": [
|
||||
"oxid",
|
||||
"modules",
|
||||
"eShop",
|
||||
"d3",
|
||||
"webauthn",
|
||||
"FIDO2",
|
||||
"CTAP",
|
||||
"public key"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "D3 Data Development (Inh. Thomas Dartsch)",
|
||||
"email": "info@shopmodule.com",
|
||||
"homepage": "https://www.d3data.de",
|
||||
"role": "Owner"
|
||||
}
|
||||
],
|
||||
"homepage": "https://www.oxidmodule.com/",
|
||||
"license": [
|
||||
"GPL-3.0-or-later"
|
||||
],
|
||||
"extra": {
|
||||
"oxideshop": {
|
||||
"source-directory": "/src",
|
||||
"target-directory": "d3/oxwebauthn"
|
||||
}
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.6",
|
||||
"oxid-esales/oxideshop-ce": "6.10 - 6.12",
|
||||
"web-auth/webauthn-lib": "^3.3",
|
||||
"ext-json": "*",
|
||||
"ext-soap": "*",
|
||||
"ext-PDO": "*"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"D3\\Webauthn\\": "../../../source/modules/d3/oxwebauthn"
|
||||
}
|
||||
}
|
||||
}
|
174
src/Application/Controller/Admin/d3user_webauthn.php
Executable file
174
src/Application/Controller/Admin/d3user_webauthn.php
Executable file
@ -0,0 +1,174 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Application\Controller\Admin;
|
||||
|
||||
use D3\Webauthn\Application\Model\Credential\d3PublicKeyCredentialList;
|
||||
use D3\Webauthn\Application\Model\d3webauthn;
|
||||
use D3\Webauthn\Application\Model\Webauthn\d3PublicKeyCredentialUserEntity;
|
||||
use D3\Webauthn\Modules\Application\Model\d3_User_Webauthn;
|
||||
use Exception;
|
||||
use OxidEsales\Eshop\Application\Controller\Admin\AdminDetailsController;
|
||||
use OxidEsales\Eshop\Application\Model\User;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
|
||||
use OxidEsales\Eshop\Core\Registry;
|
||||
use OxidEsales\Eshop\Core\UtilsView;
|
||||
|
||||
class d3user_webauthn extends AdminDetailsController
|
||||
{
|
||||
protected $_sSaveError = null;
|
||||
|
||||
protected $_sThisTemplate = 'd3user_webauthn.tpl';
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
parent::render();
|
||||
|
||||
$soxId = $this->getEditObjectId();
|
||||
|
||||
if (isset($soxId) && $soxId != "-1") {
|
||||
/** @var d3_User_Webauthn $oUser */
|
||||
$oUser = $this->getUserObject();
|
||||
if ($oUser->load($soxId)) {
|
||||
$this->addTplParam("oxid", $oUser->getId());
|
||||
} else {
|
||||
$this->addTplParam("oxid", '-1');
|
||||
}
|
||||
$this->addTplParam("edit", $oUser);
|
||||
}
|
||||
|
||||
if ($this->_sSaveError) {
|
||||
$this->addTplParam("sSaveError", $this->_sSaveError);
|
||||
}
|
||||
|
||||
$this->setAuthnRegister();
|
||||
|
||||
return $this->_sThisTemplate;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function setAuthnRegister()
|
||||
{
|
||||
$publicKeyCredentialCreationOptions = $this->getWebauthnObject()->setAuthnRegister($this->getEditObjectId());
|
||||
$this->addTplParam(
|
||||
'webauthn_publickey_register',
|
||||
json_encode($publicKeyCredentialCreationOptions, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $userId
|
||||
* @return d3PublicKeyCredentialList|object
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function getCredentialList($userId)
|
||||
{
|
||||
$credentialList = oxNew(d3PublicKeyCredentialList::class);
|
||||
|
||||
$oUser = $this->getUserObject();
|
||||
$oUser->load($userId);
|
||||
if ($oUser && $oUser->getId()) {
|
||||
/** @var d3PublicKeyCredentialUserEntity $userEntity */
|
||||
$userEntity = oxNew(d3PublicKeyCredentialUserEntity::class, $oUser);
|
||||
$credentialList->loadAllForUserEntity($userEntity);
|
||||
}
|
||||
|
||||
return $credentialList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User
|
||||
*/
|
||||
public function getUserObject()
|
||||
{
|
||||
return oxNew(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return d3webauthn
|
||||
*/
|
||||
public function getWebauthnObject()
|
||||
{
|
||||
return oxNew(d3webauthn::class);
|
||||
}
|
||||
|
||||
public function registerNewKey()
|
||||
{
|
||||
$this->getWebauthnObject()->registerNewKey(Registry::getRequest()->getRequestParameter('authn'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
parent::save();
|
||||
|
||||
$aParams = Registry::getRequest()->getRequestEscapedParameter("editval");
|
||||
|
||||
try {
|
||||
/** @var d3webauthn $oWebauthn */
|
||||
$oWebauthn = $this->getWebauthnObject();
|
||||
/*
|
||||
if ($oWebauthn->checkIfAlreadyExist($this->getEditObjectId())) {
|
||||
$oException = oxNew(StandardException::class, 'D3_TOTP_ALREADY_EXIST');
|
||||
throw $oException;
|
||||
};
|
||||
|
||||
if ($aParams['d3totp__oxid']) {
|
||||
$oWebauthn->load($aParams['d3totp__oxid']);
|
||||
} else {
|
||||
$aParams['d3totp__usetotp'] = 1;
|
||||
$seed = Registry::getRequest()->getRequestEscapedParameter("secret");
|
||||
$otp = Registry::getRequest()->getRequestEscapedParameter("otp");
|
||||
|
||||
$oWebauthn->saveSecret($seed);
|
||||
$oWebauthn->assign($aParams);
|
||||
$oWebauthn->verify($otp, $seed);
|
||||
$oWebauthn->setId();
|
||||
}
|
||||
$oWebauthn->save();
|
||||
*/
|
||||
} catch (Exception $oExcp) {
|
||||
$this->_sSaveError = $oExcp->getMessage();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseConnectionException
|
||||
*/
|
||||
public function delete()
|
||||
{
|
||||
$aParams = Registry::getRequest()->getRequestEscapedParameter("editval");
|
||||
|
||||
/** @var d3webauthn $oWebauthn */
|
||||
$oWebauthn = $this->getWebauthnObject();
|
||||
if ($aParams['d3totp__oxid']) {
|
||||
$oWebauthn->load($aParams['d3totp__oxid']);
|
||||
$oWebauthn->delete();
|
||||
Registry::get(UtilsView::class)->addErrorToDisplay('D3_TOTP_REGISTERDELETED');
|
||||
}
|
||||
}
|
||||
}
|
105
src/Application/Controller/d3_account_webauthn.php
Executable file
105
src/Application/Controller/d3_account_webauthn.php
Executable file
@ -0,0 +1,105 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Application\Controller;
|
||||
|
||||
use D3\Webauthn\Application\Model\Credential\d3PublicKeyCredential;
|
||||
use D3\Webauthn\Application\Model\Credential\d3PublicKeyCredentialList;
|
||||
use D3\Webauthn\Application\Model\d3webauthn;
|
||||
use D3\Webauthn\Application\Model\Webauthn\d3PublicKeyCredentialUserEntity;
|
||||
use OxidEsales\Eshop\Application\Controller\AccountController;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
|
||||
use OxidEsales\Eshop\Core\Registry;
|
||||
|
||||
class d3_account_webauthn extends AccountController
|
||||
{
|
||||
protected $_sThisTemplate = 'd3_account_webauthn.tpl';
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
if (Registry::getRequest()->getRequestEscapedParameter('error')) {
|
||||
dumpvar(Registry::getRequest()->getRequestEscapedParameter('error'));
|
||||
Registry::getUtilsView()->addErrorToDisplay('error occured');
|
||||
}
|
||||
|
||||
$sRet = parent::render();
|
||||
|
||||
// is logged in ?
|
||||
$oUser = $this->getUser();
|
||||
if (!$oUser) {
|
||||
return $this->_sThisTemplate = $this->_sThisLoginTemplate;
|
||||
}
|
||||
|
||||
$this->addTplParam('user', $this->getUser());
|
||||
|
||||
$this->setAuthnRegister();
|
||||
|
||||
return $sRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return d3PublicKeyCredentialList|object
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function getCredentialList()
|
||||
{
|
||||
$credentialList = oxNew(d3PublicKeyCredentialList::class);
|
||||
|
||||
$oUser = $this->getUser();
|
||||
if ($oUser) {
|
||||
/** @var d3PublicKeyCredentialUserEntity $userEntity */
|
||||
$userEntity = oxNew(d3PublicKeyCredentialUserEntity::class, $oUser);
|
||||
$credentialList->loadAllForUserEntity($userEntity);
|
||||
}
|
||||
|
||||
return $credentialList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function setAuthnRegister()
|
||||
{
|
||||
$webauthn = oxNew(d3webauthn::class);
|
||||
$publicKeyCredentialCreationOptions = $webauthn->setAuthnRegister('36944b76d6e583fe2.12734046');
|
||||
|
||||
$this->addTplParam(
|
||||
'webauthn_publickey_register',
|
||||
json_encode($publicKeyCredentialCreationOptions, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
|
||||
);
|
||||
}
|
||||
|
||||
public function registerNewKey()
|
||||
{
|
||||
$webauthn = oxNew(d3webauthn::class);
|
||||
$webauthn->registerNewKey(Registry::getRequest()->getRequestParameter('authn'));
|
||||
}
|
||||
|
||||
public function deleteKey()
|
||||
{
|
||||
if (Registry::getRequest()->getRequestEscapedParameter('oxid')) {
|
||||
$credential = oxNew(d3PublicKeyCredential::class);
|
||||
$credential->delete(Registry::getRequest()->getRequestEscapedParameter('oxid'));
|
||||
}
|
||||
}
|
||||
}
|
121
src/Application/Controller/d3webauthnlogin.php
Executable file
121
src/Application/Controller/d3webauthnlogin.php
Executable file
@ -0,0 +1,121 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Application\Controller;
|
||||
|
||||
use D3\Webauthn\Application\Model\d3webauthn;
|
||||
use D3\Webauthn\Application\Model\d3webauthn_conf;
|
||||
use OxidEsales\Eshop\Application\Controller\FrontendController;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
|
||||
use OxidEsales\Eshop\Core\Registry;
|
||||
use OxidEsales\Eshop\Core\Utils;
|
||||
|
||||
class d3webauthnlogin extends FrontendController
|
||||
{
|
||||
protected $_sThisTemplate = 'd3webauthnlogin.tpl';
|
||||
|
||||
/**
|
||||
* @return null
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
|
||||
if (Registry::getSession()->hasVariable(d3webauthn_conf::WEBAUTHN_SESSION_AUTH) ||
|
||||
false == Registry::getSession()->hasVariable(d3webauthn_conf::WEBAUTHN_SESSION_CURRENTUSER)
|
||||
) {
|
||||
$this->getUtils()->redirect('index.php?cl=start', true, 302);
|
||||
if (false == defined('OXID_PHP_UNIT')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
exit;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
$this->generateCredentialRequest();
|
||||
|
||||
$this->addTplParam('navFormParams', Registry::getSession()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_NAVFORMPARAMS));
|
||||
|
||||
return parent::render();
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function generateCredentialRequest()
|
||||
{
|
||||
$auth = Registry::getSession()->getSession()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_CURRENTUSER);
|
||||
$webauthn = oxNew(d3webauthn::class);
|
||||
$publicKeyCredentialRequestOptions = $webauthn->getCredentialRequestOptions($auth);
|
||||
|
||||
$this->addTplParam(
|
||||
'webauthn_publickey_login',
|
||||
$publicKeyCredentialRequestOptions
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Utils
|
||||
*/
|
||||
public function getUtils()
|
||||
{
|
||||
return Registry::getUtils();
|
||||
}
|
||||
|
||||
public function getPreviousClass()
|
||||
{
|
||||
return Registry::getSession()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_CURRENTCLASS);
|
||||
}
|
||||
|
||||
public function previousClassIsOrderStep()
|
||||
{
|
||||
$sClassKey = Registry::getSession()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_CURRENTCLASS);
|
||||
$resolvedClass = Registry::getControllerClassNameResolver()->getClassNameById($sClassKey);
|
||||
$resolvedClass = $resolvedClass ? $resolvedClass : 'start';
|
||||
|
||||
/** @var FrontendController $oController */
|
||||
$oController = oxNew($resolvedClass);
|
||||
return $oController->getIsOrderStep();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function getIsOrderStep()
|
||||
{
|
||||
return $this->previousClassIsOrderStep();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Bread Crumb - you are here page1/page2/page3...
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getBreadCrumb()
|
||||
{
|
||||
$aPaths = [];
|
||||
$aPath = [];
|
||||
$iBaseLanguage = Registry::getLang()->getBaseLanguage();
|
||||
$aPath['title'] = Registry::getLang()->translateString('D3_WEBAUTHN_BREADCRUMB', $iBaseLanguage, false);
|
||||
$aPath['link'] = $this->getLink();
|
||||
|
||||
$aPaths[] = $aPath;
|
||||
|
||||
return $aPaths;
|
||||
}
|
||||
}
|
29
src/Application/Model/Credential/d3MetadataStatementRepository.php
Executable file
29
src/Application/Model/Credential/d3MetadataStatementRepository.php
Executable file
@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
*
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
*
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Application\Model\Credential;
|
||||
|
||||
use Webauthn\MetadataService\MetadataStatement;
|
||||
use Webauthn\MetadataService\MetadataStatementRepository;
|
||||
|
||||
class d3MetadataStatementRepository implements MetadataStatementRepository
|
||||
{
|
||||
public function findOneByAAGUID(string $aaguid): ?MetadataStatement
|
||||
{
|
||||
return new MetadataStatement();
|
||||
}
|
||||
}
|
153
src/Application/Model/Credential/d3PublicKeyCredential.php
Executable file
153
src/Application/Model/Credential/d3PublicKeyCredential.php
Executable file
@ -0,0 +1,153 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
*
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
*
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Application\Model\Credential;
|
||||
|
||||
use OxidEsales\Eshop\Core\DatabaseProvider;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
|
||||
use OxidEsales\Eshop\Core\Model\BaseModel;
|
||||
use OxidEsales\Eshop\Core\Registry;
|
||||
|
||||
class d3PublicKeyCredential extends BaseModel
|
||||
{
|
||||
protected $_sCoreTable = 'd3PublicKeyCredential';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->init($this->getCoreTableName());
|
||||
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function d3SetName($name)
|
||||
{
|
||||
$this->assign(['name' => $name]);
|
||||
}
|
||||
|
||||
public function d3GetName()
|
||||
{
|
||||
return $this->getFieldData('name');
|
||||
}
|
||||
|
||||
public function d3SetCredentialId($credentialId)
|
||||
{
|
||||
$this->assign(['credentialid' => $credentialId]);
|
||||
}
|
||||
|
||||
public function d3GetCredentialId()
|
||||
{
|
||||
return $this->__get($this->_getFieldLongName('credentialid'))->rawValue;
|
||||
}
|
||||
|
||||
public function d3SetType($type)
|
||||
{
|
||||
$this->assign(['Type' => $type]);
|
||||
}
|
||||
|
||||
public function d3GetType()
|
||||
{
|
||||
return $this->getFieldData('Type');
|
||||
}
|
||||
|
||||
public function d3SetTransports($transports)
|
||||
{
|
||||
$this->assign(['Transports' => base64_encode(serialize($transports))]);
|
||||
}
|
||||
|
||||
public function d3GetTransports()
|
||||
{
|
||||
return unserialize(base64_decode($this->getFieldData('Transports')));
|
||||
}
|
||||
|
||||
public function d3SetAttestationType($attestationType)
|
||||
{
|
||||
$this->assign(['AttestationType' => $attestationType]);
|
||||
}
|
||||
|
||||
public function d3GetAttestationType()
|
||||
{
|
||||
return $this->getFieldData('AttestationType');
|
||||
}
|
||||
|
||||
public function d3SetTrustPath($trustPath)
|
||||
{
|
||||
$this->assign(['TrustPath' => base64_encode(serialize($trustPath))]);
|
||||
}
|
||||
|
||||
public function d3GetTrustPath()
|
||||
{
|
||||
return unserialize(base64_decode($this->getFieldData('TrustPath')));
|
||||
}
|
||||
|
||||
public function d3SetAaguid($aaguid)
|
||||
{
|
||||
$this->assign(['Aaguid' => base64_encode(serialize($aaguid))]);
|
||||
}
|
||||
|
||||
public function d3GetAaguid()
|
||||
{
|
||||
return unserialize(base64_decode($this->getFieldData('Aaguid')));
|
||||
}
|
||||
|
||||
public function d3SetPublicKey($publicKey)
|
||||
{
|
||||
$this->assign(['PublicKey' => $publicKey]);
|
||||
}
|
||||
|
||||
public function d3GetPublicKey()
|
||||
{
|
||||
return $this->__get($this->_getFieldLongName('PublicKey'))->rawValue;
|
||||
}
|
||||
|
||||
public function d3SetUserHandle($userHandle)
|
||||
{
|
||||
$this->assign(['UserHandle' => $userHandle]);
|
||||
}
|
||||
|
||||
public function d3GetUserHandle()
|
||||
{
|
||||
return $this->getFieldData('UserHandle');
|
||||
}
|
||||
|
||||
public function d3SetCounter($count)
|
||||
{
|
||||
$this->assign(['Counter' => $count]);
|
||||
}
|
||||
|
||||
public function d3GetCounter()
|
||||
{
|
||||
return $this->getFieldData('Counter');
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $publicKeyCredentialId
|
||||
* @return |null
|
||||
* @throws DatabaseConnectionException
|
||||
*/
|
||||
public function loadByCredentialId(string $publicKeyCredentialId)
|
||||
{
|
||||
if (Registry::getRequest()->getRequestEscapedParameter('fnc') == 'checkregister') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$oDb = DatabaseProvider::getDb(DatabaseProvider::FETCH_MODE_ASSOC);
|
||||
$q = "SELECT oxid FROM ".$this->getViewName()." WHERE CredentialId = ".$oDb->quote($publicKeyCredentialId);
|
||||
$id = $oDb->getOne($q);
|
||||
$this->load($id);
|
||||
}
|
||||
|
||||
}
|
53
src/Application/Model/Credential/d3PublicKeyCredentialList.php
Executable file
53
src/Application/Model/Credential/d3PublicKeyCredentialList.php
Executable file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
*
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
*
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Application\Model\Credential;
|
||||
|
||||
use OxidEsales\Eshop\Core\DatabaseProvider;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
|
||||
use OxidEsales\Eshop\Core\Model\ListModel;
|
||||
use Webauthn\PublicKeyCredentialUserEntity;
|
||||
|
||||
class d3PublicKeyCredentialList extends ListModel
|
||||
{
|
||||
protected $_sObjectsInListName = d3PublicKeyCredential::class;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(d3PublicKeyCredential::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PublicKeyCredentialUserEntity $publicKeyCredentialUserEntity
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function loadAllForUserEntity(PublicKeyCredentialUserEntity $publicKeyCredentialUserEntity)
|
||||
{
|
||||
$q = "SELECT oxid FROM ".$this->getBaseObject()->getViewName()." WHERE UserHandle = ".DatabaseProvider::getDb(DatabaseProvider::FETCH_MODE_ASSOC)->quote($publicKeyCredentialUserEntity->getId());
|
||||
$idList = DatabaseProvider::getDb(DatabaseProvider::FETCH_MODE_ASSOC)->getAll($q);
|
||||
|
||||
if ($idList && is_iterable($idList)) {
|
||||
foreach ($idList as $id) {
|
||||
$credential = oxNew($this->_sObjectsInListName);
|
||||
$credential->load($id['oxid']);
|
||||
$this->offsetSet($credential->getId(), $credential);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
25
src/Application/Model/Exceptions/d3webauthnExceptionAbstract.php
Executable file
25
src/Application/Model/Exceptions/d3webauthnExceptionAbstract.php
Executable file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
*
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
*
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Application\Model\Exceptions;
|
||||
|
||||
use OxidEsales\Eshop\Core\Exception\StandardException;
|
||||
|
||||
abstract class d3webauthnExceptionAbstract extends StandardException
|
||||
{
|
||||
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
*
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
*
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Application\Model\Exceptions;
|
||||
|
||||
use Exception;
|
||||
use OxidEsales\Eshop\Core\Exception\StandardException;
|
||||
|
||||
class d3webauthnMissingPublicKeyCredentialRequestOptions extends d3webauthnExceptionAbstract
|
||||
{
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param string $sMessage exception message
|
||||
* @param integer $iCode exception code
|
||||
* @param Exception|null $previous previous exception
|
||||
*/
|
||||
public function __construct($sMessage = "D3_WEBAUTHN_ERROR_MISSINGPKC", $iCode = 0, Exception $previous = null)
|
||||
{
|
||||
parent::__construct($sMessage, $iCode, $previous);
|
||||
}
|
||||
}
|
35
src/Application/Model/Exceptions/d3webauthnWrongAuthException.php
Executable file
35
src/Application/Model/Exceptions/d3webauthnWrongAuthException.php
Executable file
@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
*
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
*
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Application\Model\Exceptions;
|
||||
|
||||
use Exception;
|
||||
|
||||
class d3webauthnWrongAuthException extends d3webauthnExceptionAbstract
|
||||
{
|
||||
/**
|
||||
* Default constructor
|
||||
*
|
||||
* @param string $sMessage exception message
|
||||
* @param integer $iCode exception code
|
||||
* @param Exception|null $previous previous exception
|
||||
*/
|
||||
public function __construct($sMessage = "D3_WEBAUTHN_ERROR_UNVALID", $iCode = 0, Exception $previous = null)
|
||||
{
|
||||
parent::__construct($sMessage, $iCode, $previous);
|
||||
}
|
||||
}
|
34
src/Application/Model/Webauthn/d3PublicKeyCredentialRpEntity.php
Executable file
34
src/Application/Model/Webauthn/d3PublicKeyCredentialRpEntity.php
Executable file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
*
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
*
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\Webauthn\Application\Model\Webauthn;
|
||||
|
||||
use OxidEsales\Eshop\Application\Model\Shop;
|
||||
use Webauthn\PublicKeyCredentialRpEntity;
|
||||
|
||||
class d3PublicKeyCredentialRpEntity extends PublicKeyCredentialRpEntity
|
||||
{
|
||||
public function __construct(Shop $shop)
|
||||
{
|
||||
parent::__construct(
|
||||
$shop->getFieldData('oxname'),
|
||||
$_SERVER['HTTP_HOST']
|
||||
);
|
||||
}
|
||||
}
|
74
src/Application/Model/Webauthn/d3PublicKeyCredentialSource.php
Executable file
74
src/Application/Model/Webauthn/d3PublicKeyCredentialSource.php
Executable file
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
*
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
*
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Application\Model\Webauthn;
|
||||
|
||||
use D3\Webauthn\Application\Model\Credential\d3PublicKeyCredential;
|
||||
use Webauthn\PublicKeyCredentialSource;
|
||||
|
||||
class d3PublicKeyCredentialSource extends PublicKeyCredentialSource
|
||||
{
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function saveCredential()
|
||||
{
|
||||
$credential = oxNew(d3PublicKeyCredential::class);
|
||||
$credential->d3SetName(date('Y-m-d H:i:s'));
|
||||
$credential->d3SetCredentialId($this->getPublicKeyCredentialId());
|
||||
$credential->d3SetType($this->getType());
|
||||
$credential->d3SetTransports($this->getTransports());
|
||||
$credential->d3SetAttestationType($this->getAttestationType());
|
||||
$credential->d3SetTrustPath($this->getTrustPath());
|
||||
$credential->d3SetAaguid($this->getAaguid());
|
||||
$credential->d3SetPublicKey($this->getCredentialPublicKey());
|
||||
$credential->d3SetUserHandle($this->getUserHandle());
|
||||
$credential->d3SetCounter($this->getCounter());
|
||||
|
||||
$credential->save();
|
||||
}
|
||||
|
||||
public static function createFromd3PublicKeyCredential(d3PublicKeyCredential $publicKeyCredential): self
|
||||
{
|
||||
return new self(
|
||||
$publicKeyCredential->d3GetCredentialId(),
|
||||
$publicKeyCredential->d3GetType(),
|
||||
$publicKeyCredential->d3GetTransports(),
|
||||
$publicKeyCredential->d3GetAttestationType(),
|
||||
$publicKeyCredential->d3GetTrustPath(),
|
||||
$publicKeyCredential->d3GetAaguid(),
|
||||
$publicKeyCredential->d3GetPublicKey(),
|
||||
$publicKeyCredential->d3GetUserHandle(),
|
||||
$publicKeyCredential->d3GetCounter()
|
||||
);
|
||||
}
|
||||
|
||||
public static function createFromPublicKeyCredentialSource(publicKeyCredentialSource $publicKeyCredential): self
|
||||
{
|
||||
return new self(
|
||||
$publicKeyCredential->getPublicKeyCredentialId(),
|
||||
$publicKeyCredential->getType(),
|
||||
$publicKeyCredential->getTransports(),
|
||||
$publicKeyCredential->getAttestationType(),
|
||||
$publicKeyCredential->getTrustPath(),
|
||||
$publicKeyCredential->getAaguid(),
|
||||
$publicKeyCredential->getCredentialPublicKey(),
|
||||
$publicKeyCredential->getUserHandle(),
|
||||
$publicKeyCredential->getCounter()
|
||||
);
|
||||
}
|
||||
}
|
88
src/Application/Model/Webauthn/d3PublicKeyCredentialSourceRepository.php
Executable file
88
src/Application/Model/Webauthn/d3PublicKeyCredentialSourceRepository.php
Executable file
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
*
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
*
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace D3\Webauthn\Application\Model\Webauthn;
|
||||
|
||||
use D3\Webauthn\Application\Model\Credential\d3PublicKeyCredential;
|
||||
use D3\Webauthn\Application\Model\Credential\d3PublicKeyCredentialList;
|
||||
use Exception;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
|
||||
use OxidEsales\Eshop\Core\Registry;
|
||||
use Webauthn\PublicKeyCredentialSource;
|
||||
use Webauthn\PublicKeyCredentialSourceRepository;
|
||||
use Webauthn\PublicKeyCredentialUserEntity;
|
||||
|
||||
class d3PublicKeyCredentialSourceRepository implements PublicKeyCredentialSourceRepository
|
||||
{
|
||||
/**
|
||||
* @param string $publicKeyCredentialId
|
||||
* @return PublicKeyCredentialSource|null
|
||||
* @throws DatabaseConnectionException
|
||||
*/
|
||||
public function findOneByCredentialId(string $publicKeyCredentialId): ?PublicKeyCredentialSource
|
||||
{
|
||||
if (Registry::getRequest()->getRequestEscapedParameter('fnc') == 'checkregister') {
|
||||
return null;
|
||||
}
|
||||
|
||||
$credential = oxNew(d3PublicKeyCredential::class);
|
||||
$credential->loadByCredentialId($publicKeyCredentialId);
|
||||
|
||||
return $credential->getId() ?
|
||||
d3PublicKeyCredentialSource::createFromd3PublicKeyCredential($credential) :
|
||||
null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PublicKeyCredentialUserEntity $publicKeyCredentialUserEntity
|
||||
* @return array
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function findAllForUserEntity(PublicKeyCredentialUserEntity $publicKeyCredentialUserEntity): array
|
||||
{
|
||||
$sourceList = [];
|
||||
|
||||
$credentialList = oxNew(d3PublicKeyCredentialList::class);
|
||||
$credentialList->loadAllForUserEntity($publicKeyCredentialUserEntity);
|
||||
|
||||
/** @var d3PublicKeyCredential $credential */
|
||||
foreach ($credentialList->getArray() as $credential) {
|
||||
$sourceList[$credential->getId()] = d3PublicKeyCredentialSource::createFromd3PublicKeyCredential($credential);
|
||||
};
|
||||
|
||||
return $sourceList;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param PublicKeyCredentialSource $publicKeyCredentialSource
|
||||
* @throws Exception
|
||||
*/
|
||||
public function saveCredentialSource(PublicKeyCredentialSource $publicKeyCredentialSource): void
|
||||
{
|
||||
$publicKeyCredentialSource = d3PublicKeyCredentialSource::createFromPublicKeyCredentialSource($publicKeyCredentialSource);
|
||||
|
||||
if ($this->findOneByCredentialId($publicKeyCredentialSource->getPublicKeyCredentialId())) {
|
||||
// increase counter
|
||||
} else {
|
||||
$publicKeyCredentialSource->saveCredential();
|
||||
}
|
||||
}
|
||||
}
|
33
src/Application/Model/Webauthn/d3PublicKeyCredentialUserEntity.php
Executable file
33
src/Application/Model/Webauthn/d3PublicKeyCredentialUserEntity.php
Executable file
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
*
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
*
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Application\Model\Webauthn;
|
||||
|
||||
use OxidEsales\Eshop\Application\Model\User;
|
||||
use Webauthn\PublicKeyCredentialUserEntity;
|
||||
|
||||
class d3PublicKeyCredentialUserEntity extends publicKeyCredentialUserEntity
|
||||
{
|
||||
public function __construct(User $user)
|
||||
{
|
||||
parent::__construct(
|
||||
strtolower($user->getFieldData('oxfname').'.'.$user->getFieldData('oxlname')),
|
||||
$user->getId(),
|
||||
$user->getFieldData('oxfname').', '.$user->getFieldData('oxlname')
|
||||
);
|
||||
}
|
||||
}
|
334
src/Application/Model/d3webauthn.php
Executable file
334
src/Application/Model/d3webauthn.php
Executable file
@ -0,0 +1,334 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Application\Model;
|
||||
|
||||
use Assert\InvalidArgumentException;
|
||||
use D3\Webauthn\Application\Model\Credential\d3MetadataStatementRepository;
|
||||
use D3\Webauthn\Application\Model\Exceptions\d3webauthnWrongAuthException;
|
||||
use D3\Webauthn\Application\Model\Exceptions\d3webauthnMissingPublicKeyCredentialRequestOptions;
|
||||
use D3\Webauthn\Application\Model\Webauthn\d3PublicKeyCredentialRpEntity;
|
||||
use D3\Webauthn\Application\Model\Webauthn\d3PublicKeyCredentialSourceRepository;
|
||||
use D3\Webauthn\Application\Model\Webauthn\d3PublicKeyCredentialUserEntity;
|
||||
use Nyholm\Psr7\Factory\Psr17Factory;
|
||||
use Nyholm\Psr7Server\ServerRequestCreator;
|
||||
use OxidEsales\Eshop\Application\Model\User;
|
||||
use OxidEsales\Eshop\Core\Database\Adapter\DatabaseInterface;
|
||||
use OxidEsales\Eshop\Core\DatabaseProvider;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
|
||||
use OxidEsales\Eshop\Core\Model\BaseModel;
|
||||
use OxidEsales\Eshop\Core\Registry;
|
||||
use Webauthn\PublicKeyCredentialCreationOptions;
|
||||
use Webauthn\PublicKeyCredentialRequestOptions;
|
||||
use Webauthn\Server;
|
||||
|
||||
class d3webauthn extends BaseModel
|
||||
{
|
||||
public $tableName = 'd3PublicKeyCredential';
|
||||
protected $_sCoreTable = 'd3PublicKeyCredential';
|
||||
public $userId;
|
||||
|
||||
/**
|
||||
* d3webauthn constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->init($this->tableName);
|
||||
|
||||
return parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $userId
|
||||
* @throws DatabaseConnectionException
|
||||
*/
|
||||
public function loadByUserId($userId)
|
||||
{
|
||||
$this->userId = $userId;
|
||||
$oDb = $this->d3GetDb();
|
||||
|
||||
if ($userId && $oDb->getOne("SHOW TABLES LIKE '".$this->tableName."'")) {
|
||||
$query = "SELECT oxid FROM ".$this->getViewName().' WHERE UserHandle = '.$oDb->quote($userId).' LIMIT 1';
|
||||
$this->load($oDb->getOne($query));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return DatabaseInterface
|
||||
* @throws DatabaseConnectionException
|
||||
*/
|
||||
public function d3GetDb()
|
||||
{
|
||||
return DatabaseProvider::getDb(DatabaseProvider::FETCH_MODE_ASSOC);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
$userId = $this->userId ? $this->userId : $this->getFieldData('UserHandle');
|
||||
|
||||
$user = $this->d3GetUser();
|
||||
$user->load($userId);
|
||||
return $user;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User
|
||||
*/
|
||||
public function d3GetUser()
|
||||
{
|
||||
return oxNew(User::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function isActive()
|
||||
{
|
||||
return false == Registry::getConfig()->getConfigParam('blDisableWebauthnGlobally')
|
||||
&& $this->UserUseWebauthn();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function UserUseWebauthn()
|
||||
{
|
||||
return strlen($this->getId())
|
||||
&& strlen($this->__get($this->_getFieldLongName('publickey'))->rawValue);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $auth
|
||||
* @return false|string|null
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function getCredentialRequestOptions($auth)
|
||||
{
|
||||
$this->loadByUserId($auth);
|
||||
|
||||
$requestOptions = null;
|
||||
|
||||
if ($auth
|
||||
&& $this->isActive()
|
||||
&& false == Registry::getSession()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_AUTH)
|
||||
) {
|
||||
/** @var d3PublicKeyCredentialRpEntity $rpEntity */
|
||||
$rpEntity = oxNew(d3PublicKeyCredentialRpEntity::class, Registry::getConfig()->getActiveShop());
|
||||
|
||||
$publicKeyCredentialSourceRepository = oxNew(d3PublicKeyCredentialSourceRepository::class);
|
||||
|
||||
$server = new Server(
|
||||
$rpEntity,
|
||||
$publicKeyCredentialSourceRepository,
|
||||
new d3MetadataStatementRepository()
|
||||
);
|
||||
|
||||
$user = $this->getUser();
|
||||
$userEntity = new d3PublicKeyCredentialUserEntity($user);
|
||||
dumpvar($userEntity);
|
||||
$allowedCredentials = [];
|
||||
$credentialSourceRepository = oxNew(d3PublicKeyCredentialSourceRepository::class);
|
||||
/** @var d3PublicKeyCredentialSource $credentialSource */
|
||||
foreach ($credentialSourceRepository->findAllForUserEntity($userEntity) as $credentialSource) {
|
||||
$allowedCredentials[] = $credentialSource->getPublicKeyCredentialDescriptor();
|
||||
}
|
||||
|
||||
// We generate the set of options.
|
||||
$publicKeyCredentialRequestOptions = $server->generatePublicKeyCredentialRequestOptions(
|
||||
PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_PREFERRED, // Default value
|
||||
$allowedCredentials
|
||||
);
|
||||
dumpvar($publicKeyCredentialRequestOptions);
|
||||
$requestOptions = json_encode($publicKeyCredentialRequestOptions, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
|
||||
|
||||
Registry::getSession()->setVariable(d3webauthn_conf::WEBAUTHN_LOGIN_OBJECT, $publicKeyCredentialRequestOptions);
|
||||
|
||||
// set auth as secured parameter;
|
||||
Registry::getSession()->setVariable("auth", $auth);
|
||||
}
|
||||
|
||||
return $requestOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $webauth
|
||||
* @return bool
|
||||
* @throws d3webauthnWrongAuthException
|
||||
* @throws d3webauthnMissingPublicKeyCredentialRequestOptions
|
||||
*/
|
||||
public function verify($webauth)
|
||||
{
|
||||
$blVerify = false;
|
||||
// Retrieve the Options passed to the device
|
||||
$publicKeyCredentialRequestOptions = Registry::getSession()->getVariable(d3webauthn_conf::WEBAUTHN_LOGIN_OBJECT);
|
||||
|
||||
if (!$publicKeyCredentialRequestOptions) {
|
||||
$oException = oxNew(d3webauthnMissingPublicKeyCredentialRequestOptions::class);
|
||||
throw $oException;
|
||||
}
|
||||
|
||||
$psr17Factory = new Psr17Factory();
|
||||
$creator = new ServerRequestCreator(
|
||||
$psr17Factory, // ServerRequestFactory
|
||||
$psr17Factory, // UriFactory
|
||||
$psr17Factory, // UploadedFileFactory
|
||||
$psr17Factory // StreamFactory
|
||||
);
|
||||
|
||||
$serverRequest = $creator->fromGlobals();
|
||||
|
||||
$publicKeyCredentialSourceRepository = oxNew(d3PublicKeyCredentialSourceRepository::class);
|
||||
|
||||
$server = new Server(
|
||||
new d3PublicKeyCredentialRpEntity(Registry::getConfig()->getActiveShop()),
|
||||
$publicKeyCredentialSourceRepository,
|
||||
new d3MetadataStatementRepository()
|
||||
);
|
||||
|
||||
$user = $this->getUser();
|
||||
$userEntity = new d3PublicKeyCredentialUserEntity($user);
|
||||
|
||||
try {
|
||||
$server->loadAndCheckAssertionResponse(
|
||||
$webauth,
|
||||
$publicKeyCredentialRequestOptions, // The options you stored during the previous step
|
||||
$userEntity, // The user entity
|
||||
$serverRequest // The PSR-7 request
|
||||
);
|
||||
$blVerify = true;
|
||||
|
||||
Registry::getSession()->deleteVariable(d3webauthn_conf::WEBAUTHN_LOGIN_OBJECT);
|
||||
//If everything is fine, this means the user has correctly been authenticated using the
|
||||
// authenticator defined in $publicKeyCredentialSource
|
||||
} catch(InvalidArgumentException $exception) {
|
||||
// ToDo
|
||||
$oException = oxNew(d3webauthnWrongAuthException::class);
|
||||
Registry::getUtilsView()->addErrorToDisplay($oException);
|
||||
// write to log
|
||||
//dumpvar(openssl_error_string());
|
||||
//dumpvar($exception);
|
||||
}
|
||||
|
||||
if (false == $blVerify) {
|
||||
$oException = oxNew(d3webauthnWrongAuthException::class);
|
||||
throw $oException;
|
||||
}
|
||||
|
||||
return $blVerify;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $sUserId
|
||||
* @return PublicKeyCredentialCreationOptions
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function setAuthnRegister($sUserId)
|
||||
{
|
||||
$rpEntity = oxNew(d3PublicKeyCredentialRpEntity::class, Registry::getConfig()->getActiveShop());
|
||||
|
||||
$publicKeyCredentialSourceRepository = oxNew(d3PublicKeyCredentialSourceRepository::class);
|
||||
|
||||
$server = new Server(
|
||||
$rpEntity,
|
||||
$publicKeyCredentialSourceRepository,
|
||||
new d3MetadataStatementRepository()
|
||||
);
|
||||
/*
|
||||
if (!($user = Registry::getSession()->getUser())) {
|
||||
$e = oxNew(\Exception::class, 'no user loaded');
|
||||
throw $e;
|
||||
}
|
||||
*/
|
||||
$user = oxNew(User::class);
|
||||
$user->load($sUserId);
|
||||
|
||||
$userEntity = new d3PublicKeyCredentialUserEntity($user);
|
||||
|
||||
$excludedCredentials = [];
|
||||
$credentialSourceRepository = oxNew(d3PublicKeyCredentialSourceRepository::class);
|
||||
foreach ($credentialSourceRepository->findAllForUserEntity($userEntity) as $credentialSource) {
|
||||
$excludedCredentials[] = $credentialSource->getPublicKeyCredentialDescriptor();
|
||||
}
|
||||
|
||||
$publicKeyCredentialCreationOptions = $server->generatePublicKeyCredentialCreationOptions(
|
||||
$userEntity,
|
||||
PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE,
|
||||
$excludedCredentials
|
||||
);
|
||||
|
||||
if (!Registry::getSession()->isSessionStarted()) {
|
||||
Registry::getSession()->start();
|
||||
}
|
||||
Registry::getSession()->setVariable('authnobject', $publicKeyCredentialCreationOptions);
|
||||
|
||||
return $publicKeyCredentialCreationOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $request
|
||||
*/
|
||||
public function registerNewKey($request)
|
||||
{
|
||||
/** @var PublicKeyCredentialCreationOptions $publicKeyCredentialCreationOptions */
|
||||
$publicKeyCredentialCreationOptions = Registry::getSession()->getVariable('authnobject');
|
||||
|
||||
// Retrieve de data sent by the device
|
||||
$data = base64_decode($request, true);
|
||||
|
||||
$psr17Factory = new Psr17Factory();
|
||||
$creator = new ServerRequestCreator(
|
||||
$psr17Factory, // ServerRequestFactory
|
||||
$psr17Factory, // UriFactory
|
||||
$psr17Factory, // UploadedFileFactory
|
||||
$psr17Factory // StreamFactory
|
||||
);
|
||||
|
||||
$serverRequest = $creator->fromGlobals();
|
||||
|
||||
/*** register ***/
|
||||
$rpEntity = oxNew(d3PublicKeyCredentialRpEntity::class, Registry::getConfig()->getActiveShop());
|
||||
|
||||
$publicKeyCredentialSourceRepository = oxNew(d3PublicKeyCredentialSourceRepository::class);
|
||||
|
||||
$server = new Server(
|
||||
$rpEntity,
|
||||
$publicKeyCredentialSourceRepository,
|
||||
new d3MetadataStatementRepository()
|
||||
);
|
||||
|
||||
try {
|
||||
$publicKeyCredentialSource = $server->loadAndCheckAttestationResponse(
|
||||
$data,
|
||||
$publicKeyCredentialCreationOptions, // The options you stored during the previous step
|
||||
$serverRequest // The PSR-7 request
|
||||
);
|
||||
|
||||
// The user entity and the public key credential source can now be stored using their repository
|
||||
// The Public Key Credential Source repository must implement Webauthn\PublicKeyCredentialSourceRepository
|
||||
// ToDo: is counter set and why will not save in case of login?
|
||||
$publicKeyCredentialSourceRepository->saveCredentialSource($publicKeyCredentialSource);
|
||||
|
||||
} catch(\Exception $exception) {
|
||||
dumpvar($exception);
|
||||
}
|
||||
dumpvar('registered');
|
||||
}
|
||||
}
|
25
src/Application/Model/d3webauthn_conf.php
Executable file
25
src/Application/Model/d3webauthn_conf.php
Executable file
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Application\Model;
|
||||
|
||||
class d3webauthn_conf
|
||||
{
|
||||
const WEBAUTHN_SESSION_AUTH = 'webauthn_auth';
|
||||
const WEBAUTHN_LOGIN_OBJECT = 'authnloginobject';
|
||||
const WEBAUTHN_SESSION_CURRENTUSER = 'd3webauthnCurrentUser';
|
||||
const WEBAUTHN_SESSION_CURRENTCLASS = 'd3webauthnCurrentClass';
|
||||
const WEBAUTHN_SESSION_NAVFORMPARAMS = 'd3webauthnNavFormParams';
|
||||
}
|
20
src/Application/translations/de/d3webauthn_lang.php
Executable file
20
src/Application/translations/de/d3webauthn_lang.php
Executable file
@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
$sLangName = 'Deutsch';
|
||||
|
||||
// -------------------------------
|
||||
// RESOURCE IDENTIFIER = STRING
|
||||
// -------------------------------
|
||||
$aLang = array(
|
||||
'charset' => 'UTF-8',
|
||||
'D3_WEBAUTHN_ACCOUNT' => 'd3 Webauthn',
|
||||
|
||||
'WEBAUTHN_INPUT_HELP' => 'Bitte mit Hardwareschlüssel authentisieren.',
|
||||
'WEBAUTHN_CANCEL_LOGIN' => 'Anmeldung abbrechen',
|
||||
'D3_WEBAUTHN_BREADCRUMB' => 'Passwortloses Anmelden',
|
||||
|
||||
'D3_WEBAUTHN_ACCOUNT_TYPE0' => 'nur Passwort',
|
||||
'D3_WEBAUTHN_ACCOUNT_TYPE1' => 'nur Auth-Stick',
|
||||
'D3_WEBAUTHN_ACCOUNT_TYPE2' => 'nur Auth-Stick, Passwort als Alternative',
|
||||
'D3_WEBAUTHN_ACCOUNT_TYPE3' => 'Auth-Stick und Passwort in Kombination',
|
||||
);
|
85
src/Application/views/admin/blocks/d3webauthn_login_admin_login_form.tpl
Executable file
85
src/Application/views/admin/blocks/d3webauthn_login_admin_login_form.tpl
Executable file
@ -0,0 +1,85 @@
|
||||
[{if $request_webauthn}]
|
||||
[{$oViewConf->getHiddenSid()}]
|
||||
|
||||
<input type="hidden" name="fnc" value="checklogin">
|
||||
<input type="hidden" name="cl" value="login">
|
||||
<input type="hidden" id="keyauth" name="keyauth" value="">
|
||||
|
||||
[{if $Errors.default|@count}]
|
||||
[{include file="inc_error.tpl" Errorlist=$Errors.default}]
|
||||
[{/if}]
|
||||
|
||||
<div class="d3webauthn_icon">
|
||||
<div class="svg-container">
|
||||
[{include file=$oViewConf->getModulePath('d3webauthn', 'out/img/fingerprint.svg')}]
|
||||
</div>
|
||||
<div class="message">[{oxmultilang ident="WEBAUTHN_INPUT_HELP"}]</div>
|
||||
</div>
|
||||
|
||||
[{* prevent cancel button (1st button) action when form is sent via Enter key *}]
|
||||
<input type="submit" style="display:none !important;">
|
||||
|
||||
<input class="btn btn_cancel" value="[{oxmultilang ident="WEBAUTHN_CANCEL_LOGIN"}]" type="submit"
|
||||
onclick="document.getElementById('login').fnc.value='d3WebauthnCancelLogin'; document.getElementById('login').submit();"
|
||||
>
|
||||
|
||||
[{capture name="webauthn_login"}]
|
||||
function arrayToBase64String(a) {
|
||||
return btoa(String.fromCharCode(...a));
|
||||
}
|
||||
|
||||
function base64url2base64(input) {
|
||||
input = input
|
||||
.replace(/=/g, "")
|
||||
.replace(/-/g, '+')
|
||||
.replace(/_/g, '/');
|
||||
|
||||
const pad = input.length % 4;
|
||||
if(pad) {
|
||||
if(pad === 1) {
|
||||
throw new Error('InvalidLengthError: Input base64url string is the wrong length to determine padding');
|
||||
}
|
||||
input += new Array(5-pad).join('=');
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
let publicKey = [{$webauthn_publickey_login}];
|
||||
|
||||
publicKey.challenge = Uint8Array.from(window.atob(base64url2base64(publicKey.challenge)), function(c){return c.charCodeAt(0);});
|
||||
if (publicKey.allowCredentials) {
|
||||
publicKey.allowCredentials = publicKey.allowCredentials.map(function(data) {
|
||||
data.id = Uint8Array.from(window.atob(base64url2base64(data.id)), function(c){return c.charCodeAt(0);});
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
navigator.credentials.get({ 'publicKey': publicKey }).then(function(data){
|
||||
let publicKeyCredential = {
|
||||
id: data.id,
|
||||
type: data.type,
|
||||
rawId: arrayToBase64String(new Uint8Array(data.rawId)),
|
||||
response: {
|
||||
authenticatorData: arrayToBase64String(new Uint8Array(data.response.authenticatorData)),
|
||||
clientDataJSON: arrayToBase64String(new Uint8Array(data.response.clientDataJSON)),
|
||||
signature: arrayToBase64String(new Uint8Array(data.response.signature)),
|
||||
userHandle: data.response.userHandle ? arrayToBase64String(new Uint8Array(data.response.userHandle)) : null
|
||||
}
|
||||
};
|
||||
document.getElementById('keyauth').value = btoa(JSON.stringify(publicKeyCredential));
|
||||
document.getElementById('login').submit();
|
||||
})
|
||||
.catch(function(error){
|
||||
// alert('Open your browser console!');
|
||||
console.log('FAIL', error);
|
||||
});
|
||||
[{/capture}]
|
||||
[{oxscript add=$smarty.capture.webauthn_login}]
|
||||
[{oxscript}]
|
||||
|
||||
[{oxstyle include=$oViewConf->getModuleUrl('d3webauthn', 'out/admin/src/css/d3webauthnlogin.css')}]
|
||||
[{oxstyle}]
|
||||
[{else}]
|
||||
[{$smarty.block.parent}]
|
||||
[{/if}]
|
53
src/Application/views/admin/de/d3webauthn_lang.php
Executable file
53
src/Application/views/admin/de/d3webauthn_lang.php
Executable file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
*
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
*
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
$sLangName = "Deutsch";
|
||||
|
||||
$aLang = [
|
||||
'charset' => 'UTF-8',
|
||||
|
||||
'D3_WEBAUTHN_ERROR_UNVALID' => 'Der verwendete Schlüssel ist ungültig oder kann nicht geprüft werden.',
|
||||
'D3_WEBAUTHN_ERROR_MISSINGPKC' => 'Keine prüfbaren Anfrageoptionen gespeichert. Bitte führen Sie die Anmeldung noch einmal durch bzw. wenden sich an den Betreiber.',
|
||||
'WEBAUTHN_INPUT_HELP' => 'Bitte mit Hardwareschlüssel authentisieren.',
|
||||
'WEBAUTHN_CANCEL_LOGIN' => 'Anmeldung abbrechen',
|
||||
/*
|
||||
'd3mxuser_totp' => '2-Faktor-Authentisierung',
|
||||
|
||||
'D3_TOTP_REGISTERNEW' => 'neue Registrierung erstellen',
|
||||
'D3_TOTP_QRCODE' => 'QR-Code',
|
||||
'D3_TOTP_QRCODE_HELP' => 'Scannen Sie diesen QR-Code mit Ihrer Authentisierungs-App, um dieses Benutzerkonto dort zu hinterlegen.',
|
||||
'D3_TOTP_SECRET' => 'QR-Code kann nicht gescannt werden?',
|
||||
'D3_TOTP_SECRET_HELP' => 'Setzen Sie keine App ein, die den QR-Code scannen kann, können Sie diese Zeichenkette auch in Ihr Authentisierungstool kopieren. Stellen Sie bitte die Passwortlänge auf 6 Zeichen und das Zeitinterval auf 30 Sekunden ein.',
|
||||
'D3_TOTP_CURROTP' => 'Bestätigung mit Einmalpasswort',
|
||||
'D3_TOTP_CURROTP_HELP' => 'Haben Sie dieses Kundenkonto in Ihrer Authentisierungs-App registriert, generieren Sie damit ein Einmalpasswort, tragen Sie es hier ein und senden das Formular direkt darauf hin ab.',
|
||||
|
||||
'D3_TOTP_REGISTEREXIST' => 'vorhandene Registrierung',
|
||||
'D3_TOTP_REGISTERDELETE' => 'Registrierung löschen',
|
||||
'D3_TOTP_REGISTERDELETE_DESC' => 'Um die Registrierung zu ändern, löschen Sie diese bitte vorerst. Sie können sofort im Anschluss eine neue Registrierung anlegen.<br>Wenn Sie die Registrierung löschen, ist das Konto nicht mehr durch die Zwei-Faktor-Authentisierung geschützt.',
|
||||
'D3_TOTP_REGISTERDELETED' => 'Die Registrierung wurde gelöscht.',
|
||||
|
||||
'D3_TOTP_BACKUPCODES' => 'Backupcodes',
|
||||
'D3_TOTP_BACKUPCODES_DESC' => 'Mit diesen Backupcodes können Sie sich anmelden, wenn die Generierung des Einmalpasswortes nicht möglich ist (z.B. Gerät verloren oder neu installiert). Sie können dann die Einstellungen zur Verwendung der 2-Faktor-Authentisierung ändern oder einen neuen Zugang erstellen. Speichern Sie sich diese Codes bitte in diesem Moment sicher ab. Nach Verlassen dieser Seite können diese Codes nicht erneut angezeigt werden.',
|
||||
'D3_TOTP_AVAILBACKUPCODECOUNT' => 'noch %1$s Backupcode(s) verfügbar',
|
||||
'D3_TOTP_AVAILBACKUPCODECOUNT_DESC' => 'Um neue Backupcodes zu erstellen, löschen Sie die bestehende Registrierung und legen diese bitte neu an.',
|
||||
|
||||
'D3_TOTP_SAVE' => 'Speichern',
|
||||
|
||||
'D3_TOTP_ERROR_UNVALID' => 'Das Einmalpasswort ist ungültig.',
|
||||
'D3_TOTP_ALREADY_EXIST' => 'Die Registrierung wurde schon gespeichert.',
|
||||
*/
|
||||
];
|
53
src/Application/views/admin/en/d3webauthn_lang.php
Executable file
53
src/Application/views/admin/en/d3webauthn_lang.php
Executable file
@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
*
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
*
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
$sLangName = "English";
|
||||
|
||||
$aLang = [
|
||||
'charset' => 'UTF-8',
|
||||
|
||||
'D3_WEBAUTHN_ERROR_UNVALID' => 'Der verwendete Schlüssel ist ungültig oder kann nicht geprüft werden.',
|
||||
'D3_WEBAUTHN_ERROR_MISSINGPKC' => 'Keine prüfbaren Anfrageoptionen gespeichert. Bitte führen Sie die Anmeldung noch einmal durch bzw. wenden sich an den Betreiber.',
|
||||
'WEBAUTHN_INPUT_HELP' => 'Please authenticate with hardware key.',
|
||||
'WEBAUTHN_CANCEL_LOGIN' => 'Anmeldung abbrechen',
|
||||
/*
|
||||
'd3mxuser_totp' => '2-Faktor-Authentisierung',
|
||||
|
||||
'D3_TOTP_REGISTERNEW' => 'neue Registrierung erstellen',
|
||||
'D3_TOTP_QRCODE' => 'QR-Code',
|
||||
'D3_TOTP_QRCODE_HELP' => 'Scannen Sie diesen QR-Code mit Ihrer Authentisierungs-App, um dieses Benutzerkonto dort zu hinterlegen.',
|
||||
'D3_TOTP_SECRET' => 'QR-Code kann nicht gescannt werden?',
|
||||
'D3_TOTP_SECRET_HELP' => 'Setzen Sie keine App ein, die den QR-Code scannen kann, können Sie diese Zeichenkette auch in Ihr Authentisierungstool kopieren. Stellen Sie bitte die Passwortlänge auf 6 Zeichen und das Zeitinterval auf 30 Sekunden ein.',
|
||||
'D3_TOTP_CURROTP' => 'Bestätigung mit Einmalpasswort',
|
||||
'D3_TOTP_CURROTP_HELP' => 'Haben Sie dieses Kundenkonto in Ihrer Authentisierungs-App registriert, generieren Sie damit ein Einmalpasswort, tragen Sie es hier ein und senden das Formular direkt darauf hin ab.',
|
||||
|
||||
'D3_TOTP_REGISTEREXIST' => 'vorhandene Registrierung',
|
||||
'D3_TOTP_REGISTERDELETE' => 'Registrierung löschen',
|
||||
'D3_TOTP_REGISTERDELETE_DESC' => 'Um die Registrierung zu ändern, löschen Sie diese bitte vorerst. Sie können sofort im Anschluss eine neue Registrierung anlegen.<br>Wenn Sie die Registrierung löschen, ist das Konto nicht mehr durch die Zwei-Faktor-Authentisierung geschützt.',
|
||||
'D3_TOTP_REGISTERDELETED' => 'Die Registrierung wurde gelöscht.',
|
||||
|
||||
'D3_TOTP_BACKUPCODES' => 'Backupcodes',
|
||||
'D3_TOTP_BACKUPCODES_DESC' => 'Mit diesen Backupcodes können Sie sich anmelden, wenn die Generierung des Einmalpasswortes nicht möglich ist (z.B. Gerät verloren oder neu installiert). Sie können dann die Einstellungen zur Verwendung der 2-Faktor-Authentisierung ändern oder einen neuen Zugang erstellen. Speichern Sie sich diese Codes bitte in diesem Moment sicher ab. Nach Verlassen dieser Seite können diese Codes nicht erneut angezeigt werden.',
|
||||
'D3_TOTP_AVAILBACKUPCODECOUNT' => 'noch %1$s Backupcode(s) verfügbar',
|
||||
'D3_TOTP_AVAILBACKUPCODECOUNT_DESC' => 'Um neue Backupcodes zu erstellen, löschen Sie die bestehende Registrierung und legen diese bitte neu an.',
|
||||
|
||||
'D3_TOTP_SAVE' => 'Speichern',
|
||||
|
||||
'D3_TOTP_ERROR_UNVALID' => 'Das Einmalpasswort ist ungültig.',
|
||||
'D3_TOTP_ALREADY_EXIST' => 'Die Registrierung wurde schon gespeichert.',
|
||||
*/
|
||||
];
|
179
src/Application/views/admin/tpl/d3user_webauthn.tpl
Executable file
179
src/Application/views/admin/tpl/d3user_webauthn.tpl
Executable file
@ -0,0 +1,179 @@
|
||||
[{include file="headitem.tpl" title="GENERAL_ADMIN_TITLE"|oxmultilangassign}]
|
||||
|
||||
[{*assign var="webauthn" value=$edit->d3GetWebauthn()}]*}]
|
||||
[{assign var="userid" value=$edit->getId()}]
|
||||
[{*$webauthn->loadByUserId($userid)*}]
|
||||
|
||||
[{if $readonly}]
|
||||
[{assign var="readonly" value="readonly disabled"}]
|
||||
[{else}]
|
||||
[{assign var="readonly" value=""}]
|
||||
[{/if}]
|
||||
|
||||
<style type="text/css">
|
||||
td.edittext {
|
||||
white-space: normal;
|
||||
}
|
||||
</style>
|
||||
|
||||
<form name="transfer" id="transfer" action="[{$oViewConf->getSelfLink()}]" method="post">
|
||||
[{$oViewConf->getHiddenSid()}]
|
||||
<input type="hidden" name="oxid" value="[{$oxid}]">
|
||||
<input type="hidden" name="cl" value="[{$oViewConf->getActiveClassName()}]">
|
||||
</form>
|
||||
|
||||
<form name="myedit" id="myedit" action="[{$oViewConf->getSelfLink()}]" method="post" style="padding: 0;margin: 0;height:0;">
|
||||
[{$oViewConf->getHiddenSid()}]
|
||||
<input type="hidden" name="cl" value="[{$oViewConf->getActiveClassName()}]">
|
||||
<input type="hidden" id="fncname" name="fnc" value="">
|
||||
<input type="hidden" id="authnvalue" name="authnvalue" value="">
|
||||
<input type="hidden" id="errorvalue" name="errorvalue" value="">
|
||||
<input type="hidden" name="oxid" value="[{$oxid}]">
|
||||
<button type="submit" style="display: none;"></button>
|
||||
[{* <input type="hidden" name="editval[d3totp__oxid]" value="[{$webauthn->getId()}]">
|
||||
<input type="hidden" name="editval[d3totp__oxuserid]" value="[{$oxid}]">
|
||||
*}]
|
||||
|
||||
[{if $sSaveError}]
|
||||
<table style="padding:0; border:0; width:98%;">
|
||||
<tr>
|
||||
<td></td>
|
||||
<td class="errorbox">[{oxmultilang ident=$sSaveError}]</td>
|
||||
</tr>
|
||||
</table>
|
||||
[{/if}]
|
||||
|
||||
[{capture name="javascripts"}]
|
||||
function arrayToBase64String(a) {
|
||||
return btoa(String.fromCharCode(...a));
|
||||
}
|
||||
|
||||
function base64url2base64(input) {
|
||||
input = input
|
||||
.replace(/=/g, "")
|
||||
.replace(/-/g, '+')
|
||||
.replace(/_/g, '/');
|
||||
|
||||
const pad = input.length % 4;
|
||||
if(pad) {
|
||||
if(pad === 1) {
|
||||
throw new Error('InvalidLengthError: Input base64url string is the wrong length to determine padding');
|
||||
}
|
||||
input += new Array(5-pad).join('=');
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
function authnregister() {
|
||||
|
||||
try {
|
||||
let publicKey = [{$webauthn_publickey_register}];
|
||||
console.log('71');
|
||||
publicKey.challenge = Uint8Array.from(window.atob(base64url2base64(publicKey.challenge)), function(c){return c.charCodeAt(0);});
|
||||
publicKey.user.id = Uint8Array.from(window.atob(publicKey.user.id), function(c){return c.charCodeAt(0);});
|
||||
console.log('74');
|
||||
if (publicKey.excludeCredentials) {
|
||||
publicKey.excludeCredentials = publicKey.excludeCredentials.map(function(data) {
|
||||
data.id = Uint8Array.from(window.atob(base64url2base64(data.id)), function(c){return c.charCodeAt(0);});
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
console.log('81');
|
||||
navigator.credentials.create({ 'publicKey': publicKey }).then(function(data){
|
||||
console.log('83');
|
||||
let publicKeyCredential = {
|
||||
id: data.id,
|
||||
type: data.type,
|
||||
rawId: arrayToBase64String(new Uint8Array(data.rawId)),
|
||||
response: {
|
||||
clientDataJSON: arrayToBase64String(new Uint8Array(data.response.clientDataJSON)),
|
||||
attestationObject: arrayToBase64String(new Uint8Array(data.response.attestationObject))
|
||||
}
|
||||
};
|
||||
console.log('92');
|
||||
document.getElementById('fncname').value = 'registerNewKey';
|
||||
console.log('94');
|
||||
document.getElementById('authnvalue').value = btoa(JSON.stringify(publicKeyCredential));
|
||||
console.log('96');
|
||||
}).catch(function(error){
|
||||
console.log(error);
|
||||
// document.getElementById('errorvalue').value = btoa(JSON.stringify(error));
|
||||
// document.getElementById('myedit').submit();
|
||||
});
|
||||
|
||||
}
|
||||
catch (e) {
|
||||
console.log(e);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function deleteItem(id) {
|
||||
document.getElementById('fncname').value = 'deleteKey';
|
||||
document.getElementById('oxidvalue').value = id;
|
||||
document.getElementById('actionform').submit();
|
||||
}
|
||||
|
||||
function toggle(elementId) {
|
||||
$("#" + elementId).toggle();
|
||||
}
|
||||
[{/capture}]
|
||||
[{oxscript add=$smarty.capture.javascripts}]
|
||||
|
||||
|
||||
[{if $oxid && $oxid != '-1'}]
|
||||
<table style="padding:0; border:0; width:98%;">
|
||||
<tr>
|
||||
<td class="edittext" style="vertical-align: top; padding-top:10px;padding-left:10px; width: 50%;">
|
||||
<table style="padding:0; border:0">
|
||||
[{block name="user_d3user_totp_form1"}]
|
||||
<tr>
|
||||
<td class="edittext">
|
||||
<h4>[{oxmultilang ident="D3_TOTP_REGISTERNEW"}]</h4>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="edittext">
|
||||
<button onclick="authnregister();">Register</button>
|
||||
</td>
|
||||
</tr>
|
||||
[{/block}]
|
||||
</table>
|
||||
</td>
|
||||
<!-- Anfang rechte Seite -->
|
||||
<td class="edittext" style="text-align: left; vertical-align: top; height:99%;padding-left:5px;padding-bottom:30px;padding-top:10px; width: 50%;">
|
||||
<table style="padding:0; border:0">
|
||||
[{block name="user_d3user_totp_form2"}]
|
||||
<tr>
|
||||
<td class="edittext" colspan="2">
|
||||
<h4>registered keys</h4>
|
||||
</td>
|
||||
</tr>
|
||||
[{foreach from=$oView->getCredentialList($userid) item="credential"}]
|
||||
<tr>
|
||||
<td class="edittext">
|
||||
<label for="secret">[{$credential->d3GetName()}]</label>
|
||||
</td>
|
||||
<td class="edittext">
|
||||
<a href="#" onclick="toggle('keydetails_[{$credential->getId()}]'); return false;" class="list-group-item">
|
||||
[{$credential->d3GetName()}] (last used: XX)
|
||||
</a>
|
||||
<div class="list-group-item" id="keydetails_[{$credential->getId()}]" style="display: none">
|
||||
<a onclick="deleteItem('[{$credential->getId()}]'); return false;"><span class="glyphicon glyphicon-pencil">delete</span></a>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
[{/foreach}]
|
||||
[{/block}]
|
||||
</table>
|
||||
</td>
|
||||
<!-- Ende rechte Seite -->
|
||||
</tr>
|
||||
</table>
|
||||
[{/if}]
|
||||
</form>
|
||||
|
||||
[{include file="bottomnaviitem.tpl"}]
|
||||
[{include file="bottomitem.tpl"}]
|
4
src/Application/views/blocks/page/account/inc/account_menu.tpl
Executable file
4
src/Application/views/blocks/page/account/inc/account_menu.tpl
Executable file
@ -0,0 +1,4 @@
|
||||
[{$smarty.block.parent}]
|
||||
<li class="list-group-item[{if $active_link == "d3webauthn"}] active[{/if}]">
|
||||
<a class="[{* wave *}] list-group-link" href="[{oxgetseourl ident=$oViewConf->getSelfLink()|cat:"cl=d3_account_webauthn"}]" title="[{oxmultilang ident="D3_WEBAUTHN_ACCOUNT"}]">[{oxmultilang ident="D3_WEBAUTHN_ACCOUNT"}]</a>
|
||||
</li>
|
95
src/Application/views/blocks/page/shop/start_welcome_text.tpl
Executable file
95
src/Application/views/blocks/page/shop/start_welcome_text.tpl
Executable file
@ -0,0 +1,95 @@
|
||||
[{if $webauthn_publickey_register}]
|
||||
[{capture name="webauthn_register"}]
|
||||
function arrayToBase64String(a) {
|
||||
return btoa(String.fromCharCode(...a));
|
||||
}
|
||||
|
||||
function base64url2base64(input) {
|
||||
input = input
|
||||
.replace(/=/g, "")
|
||||
.replace(/-/g, '+')
|
||||
.replace(/_/g, '/');
|
||||
|
||||
const pad = input.length % 4;
|
||||
if(pad) {
|
||||
if(pad === 1) {
|
||||
throw new Error('InvalidLengthError: Input base64url string is the wrong length to determine padding');
|
||||
}
|
||||
input += new Array(5-pad).join('=');
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
function authnregister() {
|
||||
let publicKey = [{$webauthn_publickey_register}];
|
||||
|
||||
publicKey.challenge = Uint8Array.from(window.atob(base64url2base64(publicKey.challenge)), function(c){return c.charCodeAt(0);});
|
||||
publicKey.user.id = Uint8Array.from(window.atob(publicKey.user.id), function(c){return c.charCodeAt(0);});
|
||||
if (publicKey.excludeCredentials) {
|
||||
publicKey.excludeCredentials = publicKey.excludeCredentials.map(function(data) {
|
||||
data.id = Uint8Array.from(window.atob(base64url2base64(data.id)), function(c){return c.charCodeAt(0);});
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
navigator.credentials.create({ 'publicKey': publicKey })
|
||||
.then(function(data){
|
||||
let publicKeyCredential = {
|
||||
id: data.id,
|
||||
type: data.type,
|
||||
rawId: arrayToBase64String(new Uint8Array(data.rawId)),
|
||||
response: {
|
||||
clientDataJSON: arrayToBase64String(new Uint8Array(data.response.clientDataJSON)),
|
||||
attestationObject: arrayToBase64String(new Uint8Array(data.response.attestationObject))
|
||||
}
|
||||
};
|
||||
window.location = 'index.php?cl=start&fnc=checkregister&authn='+btoa(JSON.stringify(publicKeyCredential));
|
||||
}).catch(function(error){
|
||||
//alert('Open your browser console!');
|
||||
console.log('FAIL', error);
|
||||
}
|
||||
);
|
||||
}
|
||||
[{/capture}]
|
||||
[{oxscript add=$smarty.capture.webauthn_register}]
|
||||
<button onclick="authnregister();">Fido2 Register</button>
|
||||
|
||||
[{capture name="webauthn_login"}]
|
||||
function authnlogin() {
|
||||
let publicKey = [{$webauthn_publickey_login}];
|
||||
|
||||
publicKey.challenge = Uint8Array.from(window.atob(base64url2base64(publicKey.challenge)), function(c){return c.charCodeAt(0);});
|
||||
if (publicKey.allowCredentials) {
|
||||
publicKey.allowCredentials = publicKey.allowCredentials.map(function(data) {
|
||||
data.id = Uint8Array.from(window.atob(base64url2base64(data.id)), function(c){return c.charCodeAt(0);});
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
navigator.credentials.get({ 'publicKey': publicKey })
|
||||
.then(function(data){
|
||||
let publicKeyCredential = {
|
||||
id: data.id,
|
||||
type: data.type,
|
||||
rawId: arrayToBase64String(new Uint8Array(data.rawId)),
|
||||
response: {
|
||||
authenticatorData: arrayToBase64String(new Uint8Array(data.response.authenticatorData)),
|
||||
clientDataJSON: arrayToBase64String(new Uint8Array(data.response.clientDataJSON)),
|
||||
signature: arrayToBase64String(new Uint8Array(data.response.signature)),
|
||||
userHandle: data.response.userHandle ? arrayToBase64String(new Uint8Array(data.response.userHandle)) : null
|
||||
}
|
||||
};
|
||||
window.location = 'index.php?cl=start&fnc=checklogin&authn='+btoa(JSON.stringify(publicKeyCredential));
|
||||
})
|
||||
.catch(function(error){
|
||||
// alert('Open your browser console!');
|
||||
console.log('FAIL', error);
|
||||
});
|
||||
}
|
||||
[{/capture}]
|
||||
[{oxscript add=$smarty.capture.webauthn_login}]
|
||||
<button onclick="authnlogin();">Fido2 Login</button>
|
||||
[{/if}]
|
||||
|
||||
[{$smarty.block.parent}]
|
256
src/Application/views/tpl/d3_account_webauthn.tpl
Executable file
256
src/Application/views/tpl/d3_account_webauthn.tpl
Executable file
@ -0,0 +1,256 @@
|
||||
[{capture append="oxidBlock_content"}]
|
||||
|
||||
[{capture name="javascripts"}]
|
||||
function arrayToBase64String(a) {
|
||||
return btoa(String.fromCharCode(...a));
|
||||
}
|
||||
|
||||
function base64url2base64(input) {
|
||||
input = input
|
||||
.replace(/=/g, "")
|
||||
.replace(/-/g, '+')
|
||||
.replace(/_/g, '/');
|
||||
|
||||
const pad = input.length % 4;
|
||||
if(pad) {
|
||||
if(pad === 1) {
|
||||
throw new Error('InvalidLengthError: Input base64url string is the wrong length to determine padding');
|
||||
}
|
||||
input += new Array(5-pad).join('=');
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
function authnregister() {
|
||||
let publicKey = [{$webauthn_publickey_register}];
|
||||
|
||||
publicKey.challenge = Uint8Array.from(window.atob(base64url2base64(publicKey.challenge)), function(c){return c.charCodeAt(0);});
|
||||
publicKey.user.id = Uint8Array.from(window.atob(publicKey.user.id), function(c){return c.charCodeAt(0);});
|
||||
if (publicKey.excludeCredentials) {
|
||||
publicKey.excludeCredentials = publicKey.excludeCredentials.map(function(data) {
|
||||
data.id = Uint8Array.from(window.atob(base64url2base64(data.id)), function(c){return c.charCodeAt(0);});
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
navigator.credentials.create({ 'publicKey': publicKey }).then(function(data){
|
||||
let publicKeyCredential = {
|
||||
id: data.id,
|
||||
type: data.type,
|
||||
rawId: arrayToBase64String(new Uint8Array(data.rawId)),
|
||||
response: {
|
||||
clientDataJSON: arrayToBase64String(new Uint8Array(data.response.clientDataJSON)),
|
||||
attestationObject: arrayToBase64String(new Uint8Array(data.response.attestationObject))
|
||||
}
|
||||
};
|
||||
document.getElementById('fncname').value = 'registerNewKey';
|
||||
document.getElementById('authnvalue').value = btoa(JSON.stringify(publicKeyCredential));
|
||||
document.getElementById('actionform').submit();
|
||||
}).catch(function(error){
|
||||
document.getElementById('errorvalue').value = btoa(JSON.stringify(error));
|
||||
document.getElementById('actionform').submit();
|
||||
});
|
||||
}
|
||||
|
||||
function deleteItem(id) {
|
||||
document.getElementById('fncname').value = 'deleteKey';
|
||||
document.getElementById('oxidvalue').value = id;
|
||||
document.getElementById('actionform').submit();
|
||||
}
|
||||
|
||||
function toggle(elementId) {
|
||||
$("#" + elementId).toggle();
|
||||
}
|
||||
[{/capture}]
|
||||
[{oxscript add=$smarty.capture.javascripts}]
|
||||
|
||||
<h1 class="page-header">[{oxmultilang ident="D3_WEBAUTHN_ACCOUNT"}]</h1>
|
||||
|
||||
<form action="[{$oViewConf->getSelfActionLink()}]" id="actionform" name="d3webauthnform" class="form-horizontal" method="post">
|
||||
<div class="hidden">
|
||||
[{$oViewConf->getHiddenSid()}]
|
||||
[{$oViewConf->getNavFormParams()}]
|
||||
<input type="hidden" id="fncname" name="fnc" value="">
|
||||
<input type="hidden" name="cl" value="[{$oViewConf->getActiveClassName()}]">
|
||||
<input type="hidden" id="oxidvalue" name="oxid" value="">
|
||||
<input type="hidden" id="authnvalue" name="authn" value="">
|
||||
<input type="hidden" id="errorvalue" name="error" value="">
|
||||
</div>
|
||||
</form>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">settings</div>
|
||||
<div class="panel-body">
|
||||
<div class="row" style="margin-right: 0">
|
||||
<div class="col-xs-12 col-md-9">
|
||||
<input id="authtype_0" type="radio" name="authtype" value="0"> <label for="authtype_0">[{oxmultilang ident="D3_WEBAUTHN_ACCOUNT_TYPE0"}]</label>
|
||||
</div>
|
||||
<div class="col-xs-8 col-md-3 progress pull-right" style="padding: 0; margin-bottom: 0">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="20" aria-valuemin="0" aria-valuemax="100" style="width:70%">
|
||||
Sicherheit
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-right: 0">
|
||||
<div class="col-xs-12 col-md-9">
|
||||
<input id="authtype_1" type="radio" name="authtype" value="1"> <label for="authtype_1">[{oxmultilang ident="D3_WEBAUTHN_ACCOUNT_TYPE1"}]</label>
|
||||
</div>
|
||||
<div class="col-xs-8 col-md-3 progress pull-right" style="padding: 0; margin-bottom: 0">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="80" aria-valuemin="0" aria-valuemax="100" style="width:70%">
|
||||
Sicherheit
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-right: 0">
|
||||
<div class="col-xs-12 col-md-9">
|
||||
<input id="authtype_2" type="radio" name="authtype" value="2"> <label for="authtype_2">[{oxmultilang ident="D3_WEBAUTHN_ACCOUNT_TYPE2"}]</label>
|
||||
</div>
|
||||
<div class="col-xs-8 col-md-3 progress pull-right" style="padding: 0; margin-bottom: 0">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="30" aria-valuemin="0" aria-valuemax="100" style="width:70%">
|
||||
Sicherheit
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" style="margin-right: 0">
|
||||
<div class="col-xs-12 col-md-9">
|
||||
<input id="authtype_3" type="radio" name="authtype" value="3"> <label for="authtype_3">[{oxmultilang ident="D3_WEBAUTHN_ACCOUNT_TYPE3"}]</label>
|
||||
</div>
|
||||
<div class="col-xs-8 col-md-3 progress pull-right" style="padding: 0; margin-bottom: 0">
|
||||
<div class="progress-bar" role="progressbar" aria-valuenow="85" aria-valuemin="0" aria-valuemax="100" style="width:70%">
|
||||
Sicherheit
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">registration</div>
|
||||
<div class="panel-body">
|
||||
<button onclick="authnregister();">Register</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading">registered keys</div>
|
||||
<div class="panel-body">
|
||||
<div class="list-group">
|
||||
[{foreach from=$oView->getCredentialList() item="credential"}]
|
||||
<a href="#" onclick="toggle('keydetails_[{$credential->getId()}]'); return false;" class="list-group-item">
|
||||
[{$credential->d3GetName()}] (last used: XX)
|
||||
</a>
|
||||
<div class="list-group-item" id="keydetails_[{$credential->getId()}]" style="display: none">
|
||||
<a onclick="deleteItem('[{$credential->getId()}]'); return false;"><span class="glyphicon glyphicon-pencil">delete</span></a>
|
||||
</div>
|
||||
[{/foreach}]
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
[{if 1 == 0 && false == $totp->getId()}]
|
||||
<div class="registerNew [{* flow *}] panel panel-default [{* wave *}] card">
|
||||
<div class="[{* flow *}] panel-heading [{* wave *}] card-header">
|
||||
[{oxmultilang ident="D3_TOTP_REGISTERNEW"}]
|
||||
</div>
|
||||
<div class="[{* flow *}] panel-body [{* wave *}] card-body">
|
||||
<dl>
|
||||
<dt>
|
||||
[{oxmultilang ident="D3_TOTP_QRCODE"}]
|
||||
</dt>
|
||||
<dd>
|
||||
[{$totp->getQrCodeElement()}]
|
||||
</dd>
|
||||
</dl>
|
||||
<p>
|
||||
[{oxmultilang ident="D3_TOTP_QRCODE_HELP"}]
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<dl>
|
||||
<dt>
|
||||
<label for="secret">[{oxmultilang ident="D3_TOTP_SECRET"}]</label>
|
||||
</dt>
|
||||
<dd>
|
||||
<textarea rows="3" cols="50" id="secret" name="secret" class="editinput" readonly="readonly">[{$totp->getSecret()}]</textarea>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>
|
||||
[{oxmultilang ident="D3_TOTP_SECRET_HELP"}]
|
||||
</p>
|
||||
|
||||
<hr>
|
||||
|
||||
<dl>
|
||||
<dt>
|
||||
<label for="otp">[{oxmultilang ident="D3_TOTP_CURROTP"}]</label>
|
||||
</dt>
|
||||
<dd>
|
||||
<input type="text" class="editinput" size="6" maxlength="6" id="otp" name="otp" value="" [{$readonly}]>
|
||||
</dd>
|
||||
</dl>
|
||||
<p>
|
||||
[{oxmultilang ident="D3_TOTP_CURROTP_HELP"}]
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
[{/if}]
|
||||
|
||||
[{if 1 == 0 && $totp->getId()}]
|
||||
[{block name="d3_account_totp_deletenotes"}]
|
||||
<div class="[{* flow *}] panel panel-default [{* wave *}] card">
|
||||
<div class="[{* flow *}] panel-heading [{* wave *}] card-header">
|
||||
[{oxmultilang ident="D3_TOTP_REGISTEREXIST"}]
|
||||
</div>
|
||||
<div class="[{* flow *}] panel-body [{* wave *}] card-body">
|
||||
[{oxmultilang ident="D3_TOTP_REGISTERDELETE_DESC"}]
|
||||
</div>
|
||||
</div>
|
||||
[{/block}]
|
||||
|
||||
[{block name="d3_account_totp_backupcodes"}]
|
||||
<div class="[{* flow *}] panel panel-default [{* wave *}] card">
|
||||
<div class="[{* flow *}] panel-heading [{* wave *}] card-header">
|
||||
[{oxmultilang ident="D3_TOTP_BACKUPCODES"}]
|
||||
</div>
|
||||
<div class="[{* flow *}] panel-body [{* wave *}] card-body">
|
||||
[{if $oView->getBackupCodes()}]
|
||||
[{block name="d3_account_totp_backupcodes_list"}]
|
||||
<label for="backupcodes">[{oxmultilang ident="D3_TOTP_BACKUPCODES_DESC"}]</label>
|
||||
<textarea id="backupcodes" rows="10" cols="20">[{$oView->getBackupCodes()}]</textarea>
|
||||
[{/block}]
|
||||
[{else}]
|
||||
[{block name="d3_account_totp_backupcodes_info"}]
|
||||
[{oxmultilang ident="D3_TOTP_AVAILBACKUPCODECOUNT" args=$oView->getAvailableBackupCodeCount()}]<br>
|
||||
[{oxmultilang ident="D3_TOTP_AVAILBACKUPCODECOUNT_DESC"}]
|
||||
[{/block}]
|
||||
[{/if}]
|
||||
</div>
|
||||
</div>
|
||||
[{/block}]
|
||||
[{/if}]
|
||||
[{*
|
||||
<p class="submitBtn">
|
||||
<button type="submit" class="btn btn-primary"
|
||||
[{if $totp->getId()}]
|
||||
onclick="
|
||||
if(false === document.getElementById('totp_use').checked && false === confirm('[{oxmultilang ident="D3_TOTP_REGISTERDELETE_CONFIRM"}]')) {return false;}
|
||||
document.getElementById('fncname').value = 'delete';
|
||||
"
|
||||
[{else}]
|
||||
onclick="document.getElementById('fncname').value = 'create';"
|
||||
[{/if}]
|
||||
>
|
||||
[{oxmultilang ident="D3_TOTP_ACCOUNT_SAVE"}]
|
||||
</button>
|
||||
</p>
|
||||
</form>
|
||||
[{/block}]
|
||||
*}]
|
||||
[{/capture}]
|
||||
|
||||
[{capture append="oxidBlock_sidebar"}]
|
||||
[{include file="page/account/inc/account_menu.tpl" active_link="d3webauthn"}]
|
||||
[{/capture}]
|
||||
[{include file="layout/page.tpl" sidebar="Left"}]
|
112
src/Application/views/tpl/d3webauthnlogin.tpl
Executable file
112
src/Application/views/tpl/d3webauthnlogin.tpl
Executable file
@ -0,0 +1,112 @@
|
||||
[{capture append="oxidBlock_content"}]
|
||||
[{assign var="template_title" value=""}]
|
||||
|
||||
[{if $oView->previousClassIsOrderStep()}]
|
||||
[{* ordering steps *}]
|
||||
[{include file="page/checkout/inc/steps.tpl" active=2}]
|
||||
[{/if}]
|
||||
|
||||
<div class="row">
|
||||
<div class="webauthncol col-xs-12 col-sm-10 col-md-6 [{* flow *}] col-sm-offset-1 col-md-offset-3 [{* wave *}] offset-sm-1 offset-md-3 mainforms">
|
||||
<form action="[{$oViewConf->getSelfActionLink()}]" method="post" name="webauthnlogin" id="webauthnlogin">
|
||||
[{$oViewConf->getHiddenSid()}]
|
||||
|
||||
<input type="hidden" name="fnc" value="checkWebauthnlogin">
|
||||
<input type="hidden" name="cl" value="[{$oView->getPreviousClass()}]">
|
||||
<input type="hidden" name="keyauth" id="keyauth" value="">
|
||||
[{$navFormParams}]
|
||||
|
||||
[{if $Errors.default|@count}]
|
||||
[{include file="inc_error.tpl" Errorlist=$Errors.default}]
|
||||
[{/if}]
|
||||
|
||||
<div class="d3webauthn_icon">
|
||||
<div class="svg-container">
|
||||
[{include file=$oViewConf->getModulePath('d3webauthn', 'out/img/fingerprint.svg')}]
|
||||
</div>
|
||||
<div class="message">[{oxmultilang ident="WEBAUTHN_INPUT_HELP"}]</div>
|
||||
</div>
|
||||
|
||||
[{* prevent cancel button (1st button) action when form is sent via Enter key *}]
|
||||
<input type="submit" style="display:none !important;">
|
||||
|
||||
</form>
|
||||
<form action="[{$oViewConf->getSelfActionLink()}]" method="post" name="webauthnlogout" id="webauthnlogout">
|
||||
[{$oViewConf->getHiddenSid()}]
|
||||
|
||||
<input type="hidden" name="fnc" value="cancelWebauthnlogin">
|
||||
<input type="hidden" name="cl" value="[{$oView->getPreviousClass()}]">
|
||||
[{$navFormParams}]
|
||||
|
||||
<button class="btn btn_cancel" type="submit">
|
||||
[{oxmultilang ident="WEBAUTHN_CANCEL_LOGIN"}]
|
||||
</button>
|
||||
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
[{if $webauthn_publickey_login}]
|
||||
[{capture name="webauthn_login"}]
|
||||
function arrayToBase64String(a) {
|
||||
return btoa(String.fromCharCode(...a));
|
||||
}
|
||||
|
||||
function base64url2base64(input) {
|
||||
input = input
|
||||
.replace(/=/g, "")
|
||||
.replace(/-/g, '+')
|
||||
.replace(/_/g, '/');
|
||||
|
||||
const pad = input.length % 4;
|
||||
if(pad) {
|
||||
if(pad === 1) {
|
||||
throw new Error('InvalidLengthError: Input base64url string is the wrong length to determine padding');
|
||||
}
|
||||
input += new Array(5-pad).join('=');
|
||||
}
|
||||
|
||||
return input;
|
||||
}
|
||||
|
||||
let publicKey = [{$webauthn_publickey_login}];
|
||||
|
||||
publicKey.challenge = Uint8Array.from(window.atob(base64url2base64(publicKey.challenge)), function(c){return c.charCodeAt(0);});
|
||||
if (publicKey.allowCredentials) {
|
||||
publicKey.allowCredentials = publicKey.allowCredentials.map(function(data) {
|
||||
data.id = Uint8Array.from(window.atob(base64url2base64(data.id)), function(c){return c.charCodeAt(0);});
|
||||
return data;
|
||||
});
|
||||
}
|
||||
|
||||
navigator.credentials.get({ 'publicKey': publicKey }).then(function(data){
|
||||
let publicKeyCredential = {
|
||||
id: data.id,
|
||||
type: data.type,
|
||||
rawId: arrayToBase64String(new Uint8Array(data.rawId)),
|
||||
response: {
|
||||
authenticatorData: arrayToBase64String(new Uint8Array(data.response.authenticatorData)),
|
||||
clientDataJSON: arrayToBase64String(new Uint8Array(data.response.clientDataJSON)),
|
||||
signature: arrayToBase64String(new Uint8Array(data.response.signature)),
|
||||
userHandle: data.response.userHandle ? arrayToBase64String(new Uint8Array(data.response.userHandle)) : null
|
||||
}
|
||||
};
|
||||
document.getElementById('keyauth').value = btoa(JSON.stringify(publicKeyCredential));
|
||||
document.getElementById('webauthnlogin').submit();
|
||||
})
|
||||
.catch(function(error){
|
||||
// alert('Open your browser console!');
|
||||
console.log('FAIL', error);
|
||||
});
|
||||
[{/capture}]
|
||||
[{oxscript add=$smarty.capture.webauthn_login}]
|
||||
[{oxscript}]
|
||||
[{/if}]
|
||||
|
||||
[{oxstyle include=$oViewConf->getModuleUrl('d3webauthn', 'out/flow/src/css/d3webauthnlogin.css')}]
|
||||
[{oxstyle}]
|
||||
|
||||
[{insert name="oxid_tracker" title=$template_title}]
|
||||
[{/capture}]
|
||||
|
||||
[{include file="layout/page.tpl"}]
|
61
src/IntelliSenseHelper.php
Executable file
61
src/IntelliSenseHelper.php
Executable file
@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
*
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
*
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Modules\Application\Component
|
||||
{
|
||||
use OxidEsales\Eshop\Application\Component\UserComponent;
|
||||
|
||||
class d3_webauthn_UserComponent_parent extends UserComponent {}
|
||||
}
|
||||
|
||||
namespace D3\Webauthn\Modules\Application\Controller
|
||||
{
|
||||
|
||||
use OxidEsales\Eshop\Application\Controller\OrderController;
|
||||
use OxidEsales\Eshop\Application\Controller\PaymentController;
|
||||
use OxidEsales\Eshop\Application\Controller\StartController;
|
||||
use OxidEsales\Eshop\Application\Controller\UserController;
|
||||
|
||||
class d3_StartController_Webauthn_parent extends StartController {}
|
||||
|
||||
class d3_webauthn_UserController_parent extends UserController {}
|
||||
|
||||
class d3_webauthn_OrderController_parent extends OrderController {}
|
||||
|
||||
class d3_webauthn_PaymentController_parent extends PaymentController {}
|
||||
}
|
||||
|
||||
namespace D3\Webauthn\Modules\Application\Controller\Admin
|
||||
{
|
||||
use OxidEsales\Eshop\Application\Controller\Admin\LoginController;
|
||||
|
||||
class d3_LoginController_Webauthn_parent extends LoginController {}
|
||||
}
|
||||
|
||||
namespace D3\Webauthn\Modules\Application\Model
|
||||
{
|
||||
use OxidEsales\Eshop\Application\Model\User;
|
||||
|
||||
class d3_User_Webauthn_parent extends User {}
|
||||
}
|
||||
|
||||
namespace D3\Webauthn\Modules\Core
|
||||
{
|
||||
use OxidEsales\Eshop\Core\Utils;
|
||||
|
||||
class d3_webauthn_utils_parent extends Utils {}
|
||||
}
|
204
src/Modules/Application/Component/d3_webauthn_UserComponent.php
Executable file
204
src/Modules/Application/Component/d3_webauthn_UserComponent.php
Executable file
@ -0,0 +1,204 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Modules\Application\Component;
|
||||
|
||||
use D3\Webauthn\Application\Model\d3webauthn;
|
||||
use D3\Webauthn\Application\Model\d3webauthn_conf;
|
||||
use D3\Webauthn\Application\Model\Exceptions\d3webauthnMissingPublicKeyCredentialRequestOptions;
|
||||
use D3\Webauthn\Application\Model\Exceptions\d3webauthnWrongAuthException;
|
||||
use D3\Webauthn\Modules\Application\Model\d3_User_Webauthn;
|
||||
use Doctrine\DBAL\DBALException;
|
||||
use OxidEsales\Eshop\Application\Model\User;
|
||||
use OxidEsales\Eshop\Core\DatabaseProvider;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
|
||||
use OxidEsales\Eshop\Core\Registry;
|
||||
use OxidEsales\Eshop\Core\Session;
|
||||
use OxidEsales\Eshop\Core\UtilsView;
|
||||
|
||||
class d3_webauthn_UserComponent extends d3_webauthn_UserComponent_parent
|
||||
{
|
||||
/**
|
||||
* @return string|void
|
||||
* @throws DBALException
|
||||
* @throws DatabaseConnectionException
|
||||
*/
|
||||
public function login_noredirect()
|
||||
{
|
||||
$sUser = Registry::getRequest()->getRequestParameter('lgn_usr');
|
||||
$oUser = oxNew(User::class);
|
||||
$q = "SELECT * FROM ".$oUser->getViewName()." WHERE oxusername = ? and oxshopid = ?";
|
||||
$userId = DatabaseProvider::getDb()->getOne(
|
||||
$q,
|
||||
array($sUser, Registry::getConfig()->getActiveShop()->getId())
|
||||
);
|
||||
|
||||
if ($sUser) {
|
||||
$webauthn = $this->d3GetWebauthnObject();
|
||||
$webauthn->loadByUserId($userId);
|
||||
if ($webauthn->isActive()
|
||||
&& false == Registry::getSession()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_AUTH)
|
||||
) {
|
||||
Registry::getSession()->setVariable(
|
||||
d3webauthn_conf::WEBAUTHN_SESSION_CURRENTCLASS,
|
||||
$this->getParent()->getClassKey() != 'd3webauthnlogin' ? $this->getParent()->getClassKey() : 'start');
|
||||
Registry::getSession()->setVariable(d3webauthn_conf::WEBAUTHN_SESSION_CURRENTUSER, $oUser->getId());
|
||||
Registry::getSession()->setVariable(
|
||||
d3webauthn_conf::WEBAUTHN_SESSION_NAVFORMPARAMS,
|
||||
$this->getParent()->getViewConfig()->getNavFormParams()
|
||||
);
|
||||
|
||||
//$oUser->d3templogout();
|
||||
|
||||
return "d3webauthnlogin";
|
||||
}
|
||||
}
|
||||
|
||||
parent::login_noredirect();
|
||||
|
||||
/** @var d3_User_Webauthn $oUser */
|
||||
/*
|
||||
$oUser = $this->getUser();
|
||||
|
||||
if ($oUser && $oUser->getId()) {
|
||||
$webauthn = $this->d3GetWebauthnObject();
|
||||
$webauthn->loadByUserId($oUser->getId());
|
||||
|
||||
if ($webauthn->isActive()
|
||||
&& false == Registry::getSession()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_AUTH)
|
||||
) {
|
||||
Registry::getSession()->setVariable(
|
||||
d3webauthn_conf::WEBAUTHN_SESSION_CURRENTCLASS,
|
||||
$this->getParent()->getClassKey() != 'd3webauthnlogin' ? $this->getParent()->getClassKey() : 'start');
|
||||
Registry::getSession()->setVariable(d3webauthn_conf::WEBAUTHN_SESSION_CURRENTUSER, $oUser->getId());
|
||||
Registry::getSession()->setVariable(
|
||||
d3webauthn_conf::WEBAUTHN_SESSION_NAVFORMPARAMS,
|
||||
$this->getParent()->getViewConfig()->getNavFormParams()
|
||||
);
|
||||
|
||||
$oUser->d3templogout();
|
||||
|
||||
return "d3webauthnlogin";
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* @return d3webauthn
|
||||
*/
|
||||
public function d3GetWebauthnObject()
|
||||
{
|
||||
return oxNew(d3webauthn::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool|string
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws d3webauthnMissingPublicKeyCredentialRequestOptions
|
||||
*/
|
||||
public function checkWebauthnlogin()
|
||||
{
|
||||
$sWebauth = base64_decode(Registry::getRequest()->getRequestParameter('keyauth'));
|
||||
|
||||
$sUserId = Registry::getSession()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_CURRENTUSER);
|
||||
$oUser = oxNew(User::class);
|
||||
$oUser->load($sUserId);
|
||||
|
||||
$webauthn = $this->d3GetWebauthnObject();
|
||||
$webauthn->loadByUserId($sUserId);
|
||||
|
||||
try {
|
||||
if (false == $this->isNoWebauthnOrNoLogin($webauthn) && $this->hasValidWebauthn($sWebauth, $webauthn)) {
|
||||
$this->d3WebauthnRelogin($oUser, $sWebauth);
|
||||
$this->d3WebauthnClearSessionVariables();
|
||||
|
||||
return false;
|
||||
}
|
||||
} catch (d3webauthnWrongAuthException $oEx) {
|
||||
$this->d3GetUtilsView()->addErrorToDisplay($oEx, false, false, "", 'd3webauthnlogin');
|
||||
}
|
||||
|
||||
return 'd3webauthnlogin';
|
||||
}
|
||||
|
||||
/**
|
||||
* @return UtilsView
|
||||
*/
|
||||
public function d3GetUtilsView()
|
||||
{
|
||||
return Registry::getUtilsView();
|
||||
}
|
||||
|
||||
public function cancelWebauthnLogin()
|
||||
{
|
||||
$this->d3WebauthnClearSessionVariables();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param d3webauthn $webauthn
|
||||
* @return bool
|
||||
*/
|
||||
public function isNoWebauthnOrNoLogin($webauthn)
|
||||
{
|
||||
return false == $this->d3GetSession()->getVariable("auth")
|
||||
|| false == $webauthn->isActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sWebauth
|
||||
* @param d3webauthn $webauthn
|
||||
* @return bool
|
||||
* @throws d3webauthnMissingPublicKeyCredentialRequestOptions
|
||||
* @throws d3webauthnWrongAuthException
|
||||
*/
|
||||
public function hasValidWebauthn($sWebauth, $webauthn)
|
||||
{
|
||||
return Registry::getSession()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_AUTH) ||
|
||||
(
|
||||
$sWebauth && $webauthn->verify($sWebauth)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param User $oUser
|
||||
* @param $sWebauthn
|
||||
*/
|
||||
public function d3WebauthnRelogin(User $oUser, $sWebauthn)
|
||||
{
|
||||
$this->d3GetSession()->setVariable(d3webauthn_conf::WEBAUTHN_SESSION_AUTH, $sWebauthn);
|
||||
$this->d3GetSession()->setVariable('usr', $oUser->getId());
|
||||
$this->setUser(null);
|
||||
$this->setLoginStatus(USER_LOGIN_SUCCESS);
|
||||
$this->_afterLogin($oUser);
|
||||
}
|
||||
|
||||
public function d3WebauthnClearSessionVariables()
|
||||
{
|
||||
$this->d3GetSession()->deleteVariable(d3webauthn_conf::WEBAUTHN_SESSION_CURRENTCLASS);
|
||||
$this->d3GetSession()->deleteVariable(d3webauthn_conf::WEBAUTHN_SESSION_CURRENTUSER);
|
||||
$this->d3GetSession()->deleteVariable(d3webauthn_conf::WEBAUTHN_SESSION_NAVFORMPARAMS);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Session
|
||||
*/
|
||||
public function d3GetSession()
|
||||
{
|
||||
return Registry::getSession();
|
||||
}
|
||||
}
|
148
src/Modules/Application/Controller/Admin/d3_LoginController_Webauthn.php
Executable file
148
src/Modules/Application/Controller/Admin/d3_LoginController_Webauthn.php
Executable file
@ -0,0 +1,148 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Modules\Application\Controller\Admin;
|
||||
|
||||
use D3\Webauthn\Application\Model\d3webauthn;
|
||||
use D3\Webauthn\Application\Model\d3webauthn_conf;
|
||||
use D3\Webauthn\Application\Model\Exceptions\d3WebauthnExceptionAbstract;
|
||||
use D3\Webauthn\Application\Model\Exceptions\d3webauthnMissingPublicKeyCredentialRequestOptions;
|
||||
use D3\Webauthn\Application\Model\Exceptions\d3webauthnWrongAuthException;
|
||||
use OxidEsales\Eshop\Application\Model\User;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
|
||||
use OxidEsales\Eshop\Core\Registry;
|
||||
use OxidEsales\Eshop\Core\Session;
|
||||
use OxidEsales\Eshop\Core\UtilsView;
|
||||
|
||||
class d3_LoginController_Webauthn extends d3_LoginController_Webauthn_parent
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
$auth = $this->d3GetSession()->getVariable("auth");
|
||||
|
||||
$return = parent::render();
|
||||
|
||||
if ($auth) {
|
||||
$webauthn = $this->d3GetWebauthnObject();
|
||||
$publicKeyCredentialRequestOptions = $webauthn->getCredentialRequestOptions($auth);
|
||||
|
||||
$this->addTplParam(
|
||||
'webauthn_publickey_login',
|
||||
$publicKeyCredentialRequestOptions
|
||||
);
|
||||
|
||||
$this->addTplParam('request_webauthn', true);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return d3webauthn
|
||||
*/
|
||||
public function d3GetWebauthnObject()
|
||||
{
|
||||
return oxNew(d3webauthn::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return UtilsView
|
||||
*/
|
||||
public function d3GetUtilsView()
|
||||
{
|
||||
return Registry::getUtilsView();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Session
|
||||
*/
|
||||
public function d3GetSession()
|
||||
{
|
||||
return Registry::getSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return mixed|string
|
||||
* @throws DatabaseConnectionException
|
||||
*/
|
||||
public function checklogin()
|
||||
{
|
||||
//$sWebauth = Registry::getRequest()->getRequestEscapedParameter('keyauth');
|
||||
$sWebauth = base64_decode(Registry::getRequest()->getRequestParameter('keyauth'));
|
||||
|
||||
$webauthn = $this->d3GetWebauthnObject();
|
||||
$webauthn->loadByUserId(Registry::getSession()->getVariable("auth"));
|
||||
|
||||
$return = 'login';
|
||||
|
||||
try {
|
||||
if ($this->isNoWebauthnOrNoLogin($webauthn)) {
|
||||
$return = parent::checklogin();
|
||||
} elseif ($this->hasValidWebauthn($sWebauth, $webauthn)) {
|
||||
$this->d3GetSession()->setVariable(d3webauthn_conf::WEBAUTHN_SESSION_AUTH, $sWebauth);
|
||||
$return = "admin_start";
|
||||
}
|
||||
} catch (d3webauthnExceptionAbstract $oEx) {
|
||||
$this->d3GetUtilsView()->addErrorToDisplay($oEx);
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param d3webauthn $webauthn
|
||||
* @return bool
|
||||
*/
|
||||
public function isNoWebauthnOrNoLogin($webauthn)
|
||||
{
|
||||
return false == $this->d3GetSession()->getVariable("auth")
|
||||
|| false == $webauthn->isActive();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $sWebauth
|
||||
* @param d3webauthn $webauthn
|
||||
* @return bool
|
||||
* @throws d3webauthnMissingPublicKeyCredentialRequestOptions
|
||||
* @throws d3webauthnWrongAuthException
|
||||
*/
|
||||
public function hasValidWebauthn($sWebauth, $webauthn)
|
||||
{
|
||||
return Registry::getSession()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_AUTH) ||
|
||||
(
|
||||
$sWebauth && $webauthn->verify($sWebauth)
|
||||
);
|
||||
}
|
||||
|
||||
public function d3WebauthnCancelLogin()
|
||||
{
|
||||
$oUser = $this->d3GetUserObject();
|
||||
$oUser->logout();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return User
|
||||
*/
|
||||
public function d3GetUserObject()
|
||||
{
|
||||
return oxNew(User::class);
|
||||
}
|
||||
}
|
214
src/Modules/Application/Controller/d3_StartController_Webauthn.php
Executable file
214
src/Modules/Application/Controller/d3_StartController_Webauthn.php
Executable file
@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Modules\Application\Controller;
|
||||
|
||||
use D3\Webauthn\Application\Model\Credential\d3MetadataStatementRepository;
|
||||
use D3\Webauthn\Application\Model\Webauthn\d3PublicKeyCredentialRpEntity;
|
||||
use D3\Webauthn\Application\Model\Webauthn\d3PublicKeyCredentialSourceRepository;
|
||||
use D3\Webauthn\Application\Model\Webauthn\d3PublicKeyCredentialUserEntity;
|
||||
use Nyholm\Psr7\Factory\Psr17Factory;
|
||||
use Nyholm\Psr7Server\ServerRequestCreator;
|
||||
use OxidEsales\Eshop\Application\Model\User;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
|
||||
use OxidEsales\Eshop\Core\Registry;
|
||||
use Webauthn\PublicKeyCredentialCreationOptions;
|
||||
use Webauthn\PublicKeyCredentialRequestOptions;
|
||||
use Webauthn\Server;
|
||||
|
||||
class d3_StartController_Webauthn extends d3_StartController_Webauthn_parent
|
||||
{
|
||||
/**
|
||||
* @return string
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function render()
|
||||
{
|
||||
if (!Registry::getRequest()->getRequestEscapedParameter('authn')) {
|
||||
/*** register ***/
|
||||
$rpEntity = oxNew(d3PublicKeyCredentialRpEntity::class, Registry::getConfig()->getActiveShop());
|
||||
|
||||
$publicKeyCredentialSourceRepository = oxNew(d3PublicKeyCredentialSourceRepository::class);
|
||||
|
||||
$server = new Server(
|
||||
$rpEntity,
|
||||
$publicKeyCredentialSourceRepository,
|
||||
new d3MetadataStatementRepository()
|
||||
);
|
||||
/*
|
||||
if (!($user = Registry::getSession()->getUser())) {
|
||||
$e = oxNew(\Exception::class, 'no user loaded');
|
||||
throw $e;
|
||||
}
|
||||
*/
|
||||
$user = oxNew(User::class);
|
||||
//$user->load('oxdefaultadmin');
|
||||
$user->load('36944b76d6e583fe2.12734046');
|
||||
|
||||
$userEntity = new d3PublicKeyCredentialUserEntity($user);
|
||||
|
||||
$excludedCredentials = [];
|
||||
$credentialSourceRepository = oxNew(d3PublicKeyCredentialSourceRepository::class);
|
||||
foreach ($credentialSourceRepository->findAllForUserEntity($userEntity) as $credentialSource) {
|
||||
$excludedCredentials[] = $credentialSource->getPublicKeyCredentialDescriptor();
|
||||
}
|
||||
|
||||
$publicKeyCredentialCreationOptions = $server->generatePublicKeyCredentialCreationOptions(
|
||||
$userEntity,
|
||||
PublicKeyCredentialCreationOptions::ATTESTATION_CONVEYANCE_PREFERENCE_NONE,
|
||||
$excludedCredentials
|
||||
);
|
||||
|
||||
$this->addTplParam(
|
||||
'webauthn_publickey_register',
|
||||
json_encode($publicKeyCredentialCreationOptions, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
|
||||
);
|
||||
|
||||
if (!Registry::getSession()->isSessionStarted()) {
|
||||
Registry::getSession()->start();
|
||||
}
|
||||
Registry::getSession()->setVariable('authnobject', $publicKeyCredentialCreationOptions);
|
||||
|
||||
/*** login ***/
|
||||
|
||||
$allowedCredentials = [];
|
||||
$credentialSourceRepository = oxNew(d3PublicKeyCredentialSourceRepository::class);
|
||||
foreach ($credentialSourceRepository->findAllForUserEntity($userEntity) as $credentialSource) {
|
||||
$allowedCredentials[] = $credentialSource->getPublicKeyCredentialDescriptor();
|
||||
}
|
||||
|
||||
// We generate the set of options.
|
||||
$publicKeyCredentialRequestOptions = $server->generatePublicKeyCredentialRequestOptions(
|
||||
PublicKeyCredentialRequestOptions::USER_VERIFICATION_REQUIREMENT_PREFERRED, // Default value
|
||||
$allowedCredentials
|
||||
);
|
||||
|
||||
$this->addTplParam(
|
||||
'webauthn_publickey_login',
|
||||
json_encode($publicKeyCredentialRequestOptions, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE)
|
||||
);
|
||||
|
||||
Registry::getSession()->setVariable('authnloginobject', $publicKeyCredentialRequestOptions);
|
||||
}
|
||||
|
||||
$return = parent::render();
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function checkregister()
|
||||
{
|
||||
// Retrieve the PublicKeyCredentialCreationOptions object created earlier
|
||||
/** @var PublicKeyCredentialCreationOptions $publicKeyCredentialCreationOptions */
|
||||
$publicKeyCredentialCreationOptions = Registry::getSession()->getVariable('authnobject');
|
||||
|
||||
// Retrieve de data sent by the device
|
||||
$data = base64_decode(Registry::getRequest()->getRequestParameter('authn'), true);
|
||||
|
||||
$psr17Factory = new Psr17Factory();
|
||||
$creator = new ServerRequestCreator(
|
||||
$psr17Factory, // ServerRequestFactory
|
||||
$psr17Factory, // UriFactory
|
||||
$psr17Factory, // UploadedFileFactory
|
||||
$psr17Factory // StreamFactory
|
||||
);
|
||||
|
||||
$serverRequest = $creator->fromGlobals();
|
||||
|
||||
/*** register ***/
|
||||
$rpEntity = oxNew(d3PublicKeyCredentialRpEntity::class, Registry::getConfig()->getActiveShop());
|
||||
|
||||
$publicKeyCredentialSourceRepository = oxNew(d3PublicKeyCredentialSourceRepository::class);
|
||||
|
||||
$server = new Server(
|
||||
$rpEntity,
|
||||
$publicKeyCredentialSourceRepository,
|
||||
new d3MetadataStatementRepository()
|
||||
);
|
||||
|
||||
try {
|
||||
$publicKeyCredentialSource = $server->loadAndCheckAttestationResponse(
|
||||
$data,
|
||||
$publicKeyCredentialCreationOptions, // The options you stored during the previous step
|
||||
$serverRequest // The PSR-7 request
|
||||
);
|
||||
|
||||
// The user entity and the public key credential source can now be stored using their repository
|
||||
// The Public Key Credential Source repository must implement Webauthn\PublicKeyCredentialSourceRepository
|
||||
$publicKeyCredentialSourceRepository->saveCredentialSource($publicKeyCredentialSource);
|
||||
|
||||
} catch(\Exception $exception) {
|
||||
dumpvar($exception);
|
||||
}
|
||||
dumpvar('registered');
|
||||
}
|
||||
|
||||
public function checklogin()
|
||||
{
|
||||
// Retrieve the Options passed to the device
|
||||
$publicKeyCredentialRequestOptions = Registry::getSession()->getVariable('authnloginobject');
|
||||
|
||||
if (!$publicKeyCredentialRequestOptions) {
|
||||
return;
|
||||
}
|
||||
|
||||
$psr17Factory = new Psr17Factory();
|
||||
$creator = new ServerRequestCreator(
|
||||
$psr17Factory, // ServerRequestFactory
|
||||
$psr17Factory, // UriFactory
|
||||
$psr17Factory, // UploadedFileFactory
|
||||
$psr17Factory // StreamFactory
|
||||
);
|
||||
|
||||
$serverRequest = $creator->fromGlobals();
|
||||
|
||||
// Retrieve de data sent by the device
|
||||
$data = base64_decode(Registry::getRequest()->getRequestParameter('authn'));
|
||||
|
||||
$publicKeyCredentialSourceRepository = oxNew(d3PublicKeyCredentialSourceRepository::class);
|
||||
|
||||
$server = new Server(
|
||||
new d3PublicKeyCredentialRpEntity(Registry::getConfig()->getActiveShop()),
|
||||
$publicKeyCredentialSourceRepository,
|
||||
new d3MetadataStatementRepository()
|
||||
);
|
||||
|
||||
$user = oxNew(User::class);
|
||||
//$user->load('oxdefaultadmin');
|
||||
$user->load('36944b76d6e583fe2.12734046');
|
||||
|
||||
$userEntity = new d3PublicKeyCredentialUserEntity($user);
|
||||
|
||||
try {
|
||||
$publicKeyCredentialSource = $server->loadAndCheckAssertionResponse(
|
||||
$data,
|
||||
$publicKeyCredentialRequestOptions, // The options you stored during the previous step
|
||||
$userEntity, // The user entity
|
||||
$serverRequest // The PSR-7 request
|
||||
);
|
||||
|
||||
//If everything is fine, this means the user has correctly been authenticated using the
|
||||
// authenticator defined in $publicKeyCredentialSource
|
||||
} catch(\Throwable $exception) {
|
||||
dumpvar(openssl_error_string());
|
||||
dumpvar($exception);
|
||||
}
|
||||
|
||||
dumpvar('logged in');
|
||||
|
||||
}
|
||||
}
|
22
src/Modules/Application/Controller/d3_webauthn_OrderController.php
Executable file
22
src/Modules/Application/Controller/d3_webauthn_OrderController.php
Executable file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Modules\Application\Controller;
|
||||
|
||||
|
||||
class d3_webauthn_OrderController extends d3_webauthn_OrderController_parent
|
||||
{
|
||||
use d3_webauthn_getUserTrait;
|
||||
}
|
22
src/Modules/Application/Controller/d3_webauthn_PaymentController.php
Executable file
22
src/Modules/Application/Controller/d3_webauthn_PaymentController.php
Executable file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Modules\Application\Controller;
|
||||
|
||||
|
||||
class d3_webauthn_PaymentController extends d3_webauthn_PaymentController_parent
|
||||
{
|
||||
use d3_webauthn_getUserTrait;
|
||||
}
|
22
src/Modules/Application/Controller/d3_webauthn_UserController.php
Executable file
22
src/Modules/Application/Controller/d3_webauthn_UserController.php
Executable file
@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Modules\Application\Controller;
|
||||
|
||||
|
||||
class d3_webauthn_UserController extends d3_webauthn_UserController_parent
|
||||
{
|
||||
use d3_webauthn_getUserTrait;
|
||||
}
|
66
src/Modules/Application/Controller/d3_webauthn_getUserTrait.php
Executable file
66
src/Modules/Application/Controller/d3_webauthn_getUserTrait.php
Executable file
@ -0,0 +1,66 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Modules\Application\Controller;
|
||||
|
||||
use D3\Webauthn\Application\Model\d3webauthn;
|
||||
use D3\Webauthn\Application\Model\d3webauthn_conf;
|
||||
use Doctrine\DBAL\DBALException;
|
||||
use OxidEsales\Eshop\Application\Model\User;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
|
||||
use OxidEsales\Eshop\Core\Registry;
|
||||
use OxidEsales\Eshop\Core\Session;
|
||||
|
||||
trait d3_webauthn_getUserTrait
|
||||
{
|
||||
/**
|
||||
* @return bool|object|User
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DBALException
|
||||
*/
|
||||
public function getUser()
|
||||
{
|
||||
$oUser = parent::getUser();
|
||||
|
||||
if ($oUser && $oUser->getId()) {
|
||||
$webauthn = $this->d3GetWebauthnpObject();
|
||||
$webauthn->loadByUserId($oUser->getId());
|
||||
|
||||
if ($webauthn->isActive()
|
||||
&& false == $this->d3GetSessionObject()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_AUTH)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return $oUser;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return d3webauthn
|
||||
*/
|
||||
public function d3GetWebauthnpObject()
|
||||
{
|
||||
return oxNew(d3webauthn::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Session
|
||||
*/
|
||||
public function d3GetSessionObject()
|
||||
{
|
||||
return Registry::getSession();
|
||||
}
|
||||
}
|
63
src/Modules/Application/Model/d3_User_Webauthn.php
Executable file
63
src/Modules/Application/Model/d3_User_Webauthn.php
Executable file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Modules\Application\Model;
|
||||
|
||||
use D3\Webauthn\Application\Model\d3webauthn;
|
||||
use D3\Webauthn\Application\Model\d3webauthn_conf;
|
||||
use OxidEsales\Eshop\Core\Registry;
|
||||
|
||||
class d3_User_Webauthn extends d3_User_Webauthn_parent
|
||||
{
|
||||
public function logout()
|
||||
{
|
||||
$return = parent::logout();
|
||||
|
||||
Registry::getSession()->deleteVariable(d3webauthn_conf::WEBAUTHN_SESSION_AUTH);
|
||||
Registry::getSession()->deleteVariable(d3webauthn_conf::WEBAUTHN_LOGIN_OBJECT);
|
||||
Registry::getSession()->deleteVariable(d3webauthn_conf::WEBAUTHN_SESSION_CURRENTUSER);
|
||||
Registry::getSession()->deleteVariable(d3webauthn_conf::WEBAUTHN_SESSION_CURRENTCLASS);
|
||||
Registry::getSession()->deleteVariable(d3webauthn_conf::WEBAUTHN_SESSION_NAVFORMPARAMS);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
public function d3templogout()
|
||||
{
|
||||
$varname = Registry::getSession()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_AUTH);
|
||||
$object = Registry::getSession()->getVariable(d3webauthn_conf::WEBAUTHN_LOGIN_OBJECT);
|
||||
$currentUser = Registry::getSession()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_CURRENTUSER);
|
||||
$currentClass = Registry::getSession()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_CURRENTCLASS);
|
||||
$navFormParams = Registry::getSession()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_NAVFORMPARAMS);
|
||||
|
||||
$return = $this->logout();
|
||||
|
||||
Registry::getSession()->setVariable(d3webauthn_conf::WEBAUTHN_SESSION_AUTH, $varname);
|
||||
Registry::getSession()->setVariable(d3webauthn_conf::WEBAUTHN_LOGIN_OBJECT, $object);
|
||||
Registry::getSession()->setVariable(d3webauthn_conf::WEBAUTHN_SESSION_CURRENTUSER, $currentUser);
|
||||
Registry::getSession()->setVariable(d3webauthn_conf::WEBAUTHN_SESSION_CURRENTCLASS, $currentClass);
|
||||
Registry::getSession()->setVariable(d3webauthn_conf::WEBAUTHN_SESSION_NAVFORMPARAMS, $navFormParams);
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return d3webauthn
|
||||
*/
|
||||
public function d3getWebauthn()
|
||||
{
|
||||
return oxNew(d3webauthn::class);
|
||||
}
|
||||
}
|
69
src/Modules/Core/d3_webauthn_utils.php
Executable file
69
src/Modules/Core/d3_webauthn_utils.php
Executable file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Modules\Core;
|
||||
|
||||
use D3\Webauthn\Application\Model\d3webauthn;
|
||||
use D3\Webauthn\Application\Model\d3webauthn_conf;
|
||||
use Doctrine\DBAL\DBALException;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
|
||||
use OxidEsales\Eshop\Core\Registry;
|
||||
use OxidEsales\Eshop\Core\Session;
|
||||
|
||||
class d3_webauthn_utils extends d3_webauthn_utils_parent
|
||||
{
|
||||
/**
|
||||
* @return bool
|
||||
* @throws DBALException
|
||||
* @throws DatabaseConnectionException
|
||||
*/
|
||||
public function checkAccessRights()
|
||||
{
|
||||
$blAuth = parent::checkAccessRights();
|
||||
|
||||
$userID = $this->d3GetSessionObject()->getVariable("auth");
|
||||
$webauthnAuth = (bool) $this->d3GetSessionObject()->getVariable(d3webauthn_conf::WEBAUTHN_SESSION_AUTH);
|
||||
/** @var d3webauthn $webauthn */
|
||||
$webauthn = $this->d3GetWebauthnObject();
|
||||
$webauthn->loadByUserId($userID);
|
||||
|
||||
if ($blAuth && $webauthn->isActive() && false === $webauthnAuth) {
|
||||
$this->redirect('index.php?cl=login', true, 302);
|
||||
if (false == defined('OXID_PHP_UNIT')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
exit;
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
return $blAuth;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Session
|
||||
*/
|
||||
public function d3GetSessionObject()
|
||||
{
|
||||
return Registry::getSession();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return d3webauthn
|
||||
*/
|
||||
public function d3GetWebauthnObject()
|
||||
{
|
||||
return oxNew(d3webauthn::class);
|
||||
}
|
||||
}
|
48
src/Setup/Events.php
Executable file
48
src/Setup/Events.php
Executable file
@ -0,0 +1,48 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
*
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
*
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Setup;
|
||||
|
||||
use D3\ModCfg\Application\Model\Exception\d3ShopCompatibilityAdapterException;
|
||||
use D3\ModCfg\Application\Model\Install\d3install;
|
||||
use Doctrine\DBAL\DBALException;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
|
||||
use OxidEsales\Eshop\Core\Exception\StandardException;
|
||||
use OxidEsales\Eshop\Core\Exception\SystemComponentException;
|
||||
|
||||
class Events
|
||||
{
|
||||
/**
|
||||
* @throws d3ShopCompatibilityAdapterException
|
||||
* @throws DBALException
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
* @throws StandardException
|
||||
* @throws SystemComponentException
|
||||
*/
|
||||
public static function onActivate()
|
||||
{
|
||||
if (class_exists(d3install::class)) {
|
||||
d3install::checkUpdateStart();
|
||||
}
|
||||
}
|
||||
|
||||
public static function onDeactivate()
|
||||
{
|
||||
}
|
||||
}
|
246
src/Setup/Installation.php
Executable file
246
src/Setup/Installation.php
Executable file
@ -0,0 +1,246 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
namespace D3\Webauthn\Setup;
|
||||
|
||||
use D3\ModCfg\Application\Model\d3database;
|
||||
use D3\ModCfg\Application\Model\Install\d3install_updatebase;
|
||||
use Doctrine\DBAL\DBALException;
|
||||
use OxidEsales\Eshop\Core\DatabaseProvider;
|
||||
use OxidEsales\Eshop\Core\Exception\ConnectionException;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseConnectionException;
|
||||
use OxidEsales\Eshop\Core\Exception\DatabaseErrorException;
|
||||
|
||||
class Installation extends d3install_updatebase
|
||||
{
|
||||
protected $_aUpdateMethods = array(
|
||||
array('check' => 'doesPublicKeyCredentialTableNotExist',
|
||||
'do' => 'addPublicKeyCredentialTable'),
|
||||
array('check' => 'checkFields',
|
||||
'do' => 'fixFields'),
|
||||
array('check' => 'checkIndizes',
|
||||
'do' => 'fixIndizes'),
|
||||
array('check' => 'checkSEONotExists',
|
||||
'do' => 'addSEO'),
|
||||
);
|
||||
|
||||
public $aMultiLangTables = array();
|
||||
|
||||
public $aFields = array(
|
||||
'OXID' => array(
|
||||
'sTableName' => 'd3PublicKeyCredential',
|
||||
'sFieldName' => 'OXID',
|
||||
'sType' => 'CHAR(32)',
|
||||
'blNull' => false,
|
||||
'sDefault' => false,
|
||||
'sComment' => '',
|
||||
'sExtra' => '',
|
||||
'blMultilang' => false,
|
||||
),
|
||||
'NAME' => array(
|
||||
'sTableName' => 'd3PublicKeyCredential',
|
||||
'sFieldName' => 'Name',
|
||||
'sType' => 'VARCHAR(255)',
|
||||
'blNull' => false,
|
||||
'sDefault' => false,
|
||||
'sComment' => '',
|
||||
'sExtra' => '',
|
||||
'blMultilang' => false,
|
||||
),
|
||||
'CREDENTIALID' => array(
|
||||
'sTableName' => 'd3PublicKeyCredential',
|
||||
'sFieldName' => 'CredentialId',
|
||||
'sType' => 'BINARY(48)',
|
||||
'blNull' => false,
|
||||
'sDefault' => false,
|
||||
'sComment' => '',
|
||||
'sExtra' => '',
|
||||
'blMultilang' => false,
|
||||
),
|
||||
'TYPE' => array(
|
||||
'sTableName' => 'd3PublicKeyCredential',
|
||||
'sFieldName' => 'Type',
|
||||
'sType' => 'CHAR(20)',
|
||||
'blNull' => false,
|
||||
'sDefault' => false,
|
||||
'sComment' => '',
|
||||
'sExtra' => '',
|
||||
'blMultilang' => false,
|
||||
),
|
||||
'TRANSPORTS' => array(
|
||||
'sTableName' => 'd3PublicKeyCredential',
|
||||
'sFieldName' => 'Transports',
|
||||
'sType' => 'VARCHAR(255)',
|
||||
'blNull' => false,
|
||||
'sDefault' => false,
|
||||
'sComment' => '',
|
||||
'sExtra' => '',
|
||||
'blMultilang' => false,
|
||||
),
|
||||
'ATTESTATIONTYPE' => array(
|
||||
'sTableName' => 'd3PublicKeyCredential',
|
||||
'sFieldName' => 'AttestationType',
|
||||
'sType' => 'CHAR(100)',
|
||||
'blNull' => false,
|
||||
'sDefault' => false,
|
||||
'sComment' => '',
|
||||
'sExtra' => '',
|
||||
'blMultilang' => false,
|
||||
),
|
||||
'TRUSTPATH' => array(
|
||||
'sTableName' => 'd3PublicKeyCredential',
|
||||
'sFieldName' => 'TrustPath',
|
||||
'sType' => 'VARCHAR(255)',
|
||||
'blNull' => false,
|
||||
'sDefault' => false,
|
||||
'sComment' => '',
|
||||
'sExtra' => '',
|
||||
'blMultilang' => false,
|
||||
),
|
||||
'AAGUID' => array(
|
||||
'sTableName' => 'd3PublicKeyCredential',
|
||||
'sFieldName' => 'Aaguid',
|
||||
'sType' => 'VARCHAR(255)',
|
||||
'blNull' => false,
|
||||
'sDefault' => false,
|
||||
'sComment' => '',
|
||||
'sExtra' => '',
|
||||
'blMultilang' => false,
|
||||
),
|
||||
'PUBLICKEY' => array(
|
||||
'sTableName' => 'd3PublicKeyCredential',
|
||||
'sFieldName' => 'PublicKey',
|
||||
'sType' => 'BINARY(77)',
|
||||
'blNull' => false,
|
||||
'sDefault' => false,
|
||||
'sComment' => '',
|
||||
'sExtra' => '',
|
||||
'blMultilang' => false,
|
||||
),
|
||||
'USERHANDLE' => array(
|
||||
'sTableName' => 'd3PublicKeyCredential',
|
||||
'sFieldName' => 'UserHandle',
|
||||
'sType' => 'CHAR(36)',
|
||||
'blNull' => false,
|
||||
'sDefault' => false,
|
||||
'sComment' => '',
|
||||
'sExtra' => '',
|
||||
'blMultilang' => false,
|
||||
),
|
||||
'COUNTER' => array(
|
||||
'sTableName' => 'd3PublicKeyCredential',
|
||||
'sFieldName' => 'Counter',
|
||||
'sType' => 'INT(5)',
|
||||
'blNull' => false,
|
||||
'sDefault' => false,
|
||||
'sComment' => '',
|
||||
'sExtra' => '',
|
||||
'blMultilang' => false,
|
||||
),
|
||||
'OXTIMESTAMP' => array(
|
||||
'sTableName' => 'd3PublicKeyCredential',
|
||||
'sFieldName' => 'oxtimestamp',
|
||||
'sType' => 'TIMESTAMP',
|
||||
'blNull' => false,
|
||||
'sDefault' => 'CURRENT_TIMESTAMP',
|
||||
'sComment' => 'Timestamp',
|
||||
'sExtra' => '',
|
||||
'blMultilang' => false,
|
||||
)
|
||||
);
|
||||
|
||||
public $aIndizes = array(
|
||||
'OXID' => array(
|
||||
'sTableName' => 'd3PublicKeyCredential',
|
||||
'sType' => d3database::INDEX_TYPE_PRIMARY,
|
||||
'sName' => 'PRIMARY',
|
||||
'aFields' => array(
|
||||
'OXID' => 'OXID',
|
||||
),
|
||||
),
|
||||
'OXUSERID' => array(
|
||||
'sTableName' => 'd3PublicKeyCredential',
|
||||
'sType' => d3database::INDEX_TYPE_UNIQUE,
|
||||
'sName' => 'CredentialId',
|
||||
'aFields' => array(
|
||||
'CredentialId' => 'CredentialId',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
protected $_aRefreshMetaModuleIds = array('d3webauthn');
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws DBALException
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function doesPublicKeyCredentialTableNotExist()
|
||||
{
|
||||
return $this->_checkTableNotExist('d3PublicKeyCredential');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws ConnectionException
|
||||
* @throws DBALException
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function addPublicKeyCredentialTable()
|
||||
{
|
||||
$blRet = false;
|
||||
if ($this->doesPublicKeyCredentialTableNotExist()) {
|
||||
$this->setInitialExecMethod(__METHOD__);
|
||||
$blRet = $this->_addTable2(
|
||||
'd3PublicKeyCredential',
|
||||
$this->aFields,
|
||||
$this->aIndizes,
|
||||
'key credentials',
|
||||
'InnoDB'
|
||||
);
|
||||
}
|
||||
|
||||
return $blRet;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws DatabaseConnectionException
|
||||
*/
|
||||
public function checkSEONotExists()
|
||||
{
|
||||
$query = "SELECT 1 FROM " . getViewName('oxseo') . " WHERE oxstdurl = 'index.php?cl=d3_account_webauthn'";
|
||||
|
||||
return !DatabaseProvider::getDb()->getOne($query);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* @throws DatabaseConnectionException
|
||||
* @throws DatabaseErrorException
|
||||
*/
|
||||
public function addSEO()
|
||||
{
|
||||
$query = [
|
||||
"INSERT INTO `oxseo` (`OXOBJECTID`, `OXIDENT`, `OXSHOPID`, `OXLANG`, `OXSTDURL`, `OXSEOURL`, `OXTYPE`, `OXFIXED`, `OXEXPIRED`, `OXPARAMS`, `OXTIMESTAMP`) VALUES
|
||||
('ff57646b47249ee33c6b672741ac371a', 'be07f06fe03a4d5d7936f2eac5e3a87b', 1, 1, 'index.php?cl=d3_account_webauthn', 'en/key-authintication/', 'static', 0, 0, '', NOW()),
|
||||
('ff57646b47249ee33c6b672741ac371a', '220a1af77362196789eeed4741dda184', 1, 0, 'index.php?cl=d3_account_webauthn', 'key-authentisierung/', 'static', 0, 0, '', NOW());"
|
||||
];
|
||||
|
||||
return $this->_executeMultipleQueries($query);
|
||||
}
|
||||
}
|
10
src/menu.xml
Executable file
10
src/menu.xml
Executable file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<OX>
|
||||
<OXMENU id="NAVIGATION_ESHOPADMIN">
|
||||
<MAINMENU id="mxuadmin">
|
||||
<SUBMENU id="mxusers" cl="admin_user" list="user_list">
|
||||
<TAB id="d3mxuser_webauthn" cl="d3user_webauthn" />
|
||||
</SUBMENU>
|
||||
</MAINMENU>
|
||||
</OXMENU>
|
||||
</OX>
|
107
src/metadata.php
Executable file
107
src/metadata.php
Executable file
@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* This Software is the property of Data Development and is protected
|
||||
* by copyright law - it is NOT Freeware.
|
||||
*
|
||||
* Any unauthorized use of this software without a valid license
|
||||
* is a violation of the license agreement and will be prosecuted by
|
||||
* civil and criminal law.
|
||||
*
|
||||
* http://www.shopmodule.com
|
||||
*
|
||||
* @copyright (C) D3 Data Development (Inh. Thomas Dartsch)
|
||||
* @author D3 Data Development - Daniel Seifert <support@shopmodule.com>
|
||||
* @link http://www.oxidmodule.com
|
||||
*/
|
||||
|
||||
// https://github.com/web-auth/webauthn-framework/tree/master/doc
|
||||
// https://webauthn-doc.spomky-labs.com/
|
||||
// https://docs.solokeys.io/solo/
|
||||
|
||||
use D3\Webauthn\Application\Controller\Admin\d3user_webauthn;
|
||||
use D3\Webauthn\Application\Controller\d3_account_webauthn;
|
||||
use D3\Webauthn\Application\Controller\d3webauthnlogin;
|
||||
use D3\Webauthn\Modules\Application\Component\d3_webauthn_UserComponent;
|
||||
use D3\Webauthn\Modules\Application\Controller\Admin\d3_LoginController_Webauthn;
|
||||
use D3\Webauthn\Modules\Application\Controller\d3_StartController_Webauthn;
|
||||
use D3\Webauthn\Modules\Application\Controller\d3_webauthn_OrderController;
|
||||
use D3\Webauthn\Modules\Application\Controller\d3_webauthn_PaymentController;
|
||||
use D3\Webauthn\Modules\Application\Controller\d3_webauthn_UserController;
|
||||
use D3\Webauthn\Modules\Application\Model\d3_User_Webauthn;
|
||||
use D3\Webauthn\Modules\Core\d3_webauthn_utils;
|
||||
use D3\Webauthn\Setup as ModuleSetup;
|
||||
use D3\ModCfg\Application\Model\d3utils;
|
||||
use OxidEsales\Eshop\Application\Component\UserComponent;
|
||||
use OxidEsales\Eshop\Application\Controller\Admin\LoginController;
|
||||
use OxidEsales\Eshop\Application\Controller\OrderController;
|
||||
use OxidEsales\Eshop\Application\Controller\PaymentController;
|
||||
use OxidEsales\Eshop\Application\Controller\StartController;
|
||||
use OxidEsales\Eshop\Application\Controller\UserController;
|
||||
use OxidEsales\Eshop\Core\Utils;
|
||||
use OxidEsales\Eshop\Application\Model as OxidModel;
|
||||
|
||||
/**
|
||||
* Metadata version
|
||||
*/
|
||||
$sMetadataVersion = '2.1';
|
||||
|
||||
$sModuleId = 'd3webauthn';
|
||||
$logo = '<img src="https://logos.oxidmodule.com/d3logo.svg" alt="(D3)" style="height:1em;width:1em">';
|
||||
|
||||
/**
|
||||
* Module information
|
||||
*/
|
||||
$aModule = array(
|
||||
'id' => $sModuleId,
|
||||
'title' => $logo.' Webauthn / FIDO2 Login',
|
||||
'description' => [
|
||||
'de' => 'Webauthn für OXID eSales Shop',
|
||||
'en' => 'Webauthn for OXID eSales shop',
|
||||
],
|
||||
'version' => '0.0.1',
|
||||
'author' => 'D³ Data Development (Inh.: Thomas Dartsch)',
|
||||
'email' => 'support@shopmodule.com',
|
||||
'url' => 'http://www.oxidmodule.com/',
|
||||
'extend' => [
|
||||
UserController::class => d3_webauthn_UserController::class,
|
||||
PaymentController::class => d3_webauthn_PaymentController::class,
|
||||
OrderController::class => d3_webauthn_OrderController::class,
|
||||
OxidModel\User::class => d3_User_Webauthn::class,
|
||||
StartController::class => d3_StartController_Webauthn::class,
|
||||
LoginController::class => d3_LoginController_Webauthn::class,
|
||||
Utils::class => d3_webauthn_utils::class,
|
||||
UserComponent::class => d3_webauthn_UserComponent::class,
|
||||
],
|
||||
'controllers' => [
|
||||
'd3user_webauthn' => d3user_webauthn::class,
|
||||
'd3webauthnlogin' => d3webauthnlogin::class,
|
||||
'd3_account_webauthn' => d3_account_webauthn::class
|
||||
],
|
||||
'templates' => [
|
||||
'd3user_webauthn.tpl' => 'd3/webauthn/Application/views/admin/tpl/d3user_webauthn.tpl',
|
||||
'd3webauthnlogin.tpl' => 'd3/webauthn/Application/views/tpl/d3webauthnlogin.tpl',
|
||||
'd3_account_webauthn.tpl' => 'd3/webauthn/Application/views/tpl/d3_account_webauthn.tpl',
|
||||
],
|
||||
'events' => [
|
||||
'onActivate' => '\D3\Webauthn\Setup\Events::onActivate',
|
||||
'onDeactivate' => '\D3\Webauthn\Setup\Events::onDeactivate',
|
||||
],
|
||||
'blocks' => [
|
||||
[
|
||||
'template' => 'page/account/inc/account_menu.tpl',
|
||||
'block' => 'account_menu',
|
||||
'file' => 'Application/views/blocks/page/account/inc/account_menu.tpl',
|
||||
],
|
||||
[
|
||||
'template' => 'page/shop/start.tpl',
|
||||
'block' => 'start_welcome_text',
|
||||
'file' => 'Application/views/blocks/page/shop/start_welcome_text.tpl',
|
||||
],
|
||||
[
|
||||
'template' => 'login.tpl',
|
||||
'block' => 'admin_login_form',
|
||||
'file' => 'Application/views/admin/blocks/d3webauthn_login_admin_login_form.tpl',
|
||||
]
|
||||
]
|
||||
);
|
28
src/out/admin/src/css/d3webauthnlogin.css
Executable file
28
src/out/admin/src/css/d3webauthnlogin.css
Executable file
@ -0,0 +1,28 @@
|
||||
.d3webauthn_icon {
|
||||
background-color: transparent;
|
||||
height: 175px;
|
||||
width: 278px;
|
||||
}
|
||||
|
||||
.d3webauthn_icon .svg-container {
|
||||
position: relative;
|
||||
height:0;
|
||||
width: 100%;
|
||||
padding: 0 0 50% 0;
|
||||
}
|
||||
|
||||
.d3webauthn_icon .svg-container svg {
|
||||
fill: darkgrey;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.d3webauthn_icon .message {
|
||||
color: darkgrey;
|
||||
margin-top: 12px;
|
||||
text-align: center;
|
||||
font-size: 105%;
|
||||
}
|
45
src/out/flow/src/css/d3webauthnlogin.css
Executable file
45
src/out/flow/src/css/d3webauthnlogin.css
Executable file
@ -0,0 +1,45 @@
|
||||
#login {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
}
|
||||
#login .btn.btn_cancel {
|
||||
background: silver;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.d3webauthn_icon {
|
||||
background-color: transparent;
|
||||
height: 185px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.d3webauthn_icon .svg-container {
|
||||
position: relative;
|
||||
height:0;
|
||||
width: 100%;
|
||||
padding: 0 0 25% 0;
|
||||
}
|
||||
|
||||
.d3webauthn_icon .svg-container svg {
|
||||
fill: darkgrey;
|
||||
position: absolute;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.d3webauthn_icon .message {
|
||||
color: darkgrey;
|
||||
margin-top: 12px;
|
||||
text-align: center;
|
||||
font-size: 105%;
|
||||
}
|
||||
|
||||
#webauthnlogout {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
body.cl-d3webauthnlogin .webauthncol {
|
||||
margin-bottom: 20px;
|
||||
}
|
66
src/out/img/fingerprint.svg
Executable file
66
src/out/img/fingerprint.svg
Executable file
@ -0,0 +1,66 @@
|
||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Capa_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
width="366.541px" height="366.541px" viewBox="0 0 366.541 366.541" style="enable-background:new 0 0 366.541 366.541;"
|
||||
xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path d="M267.833,0H98.698c-11.225,0-20.35,8.79-20.35,19.597v327.349c0,10.807,9.125,19.595,20.35,19.595h169.135
|
||||
c11.225,0,20.358-8.788,20.358-19.595V19.597C288.189,8.79,279.058,0,267.833,0z M183.267,346.021
|
||||
c-6.276,0-11.382-5.099-11.382-11.382c0-6.256,5.106-11.361,11.382-11.361c6.281,0,11.38,5.105,11.38,11.361
|
||||
C194.647,340.922,189.548,346.021,183.267,346.021z M274.294,303.443H92.265V58.178h182.03V303.443z"/>
|
||||
</g>
|
||||
<g>
|
||||
<path d="M255.658,204.864c-8.323-8.329-21.875-8.322-30.197,0c-5.756,5.757-7.525,14.011-5.325,21.307l-11.525,11.526
|
||||
c-0.37,0.376-0.521,0.924-0.384,1.437l1.602,6.133l-6.218-1.54c-0.51-0.13-1.044,0.021-1.41,0.391l-2.707,2.71
|
||||
c-0.366,0.362-0.513,0.883-0.403,1.376l0.773,3.497l-4.306-0.239c-0.417-0.021-0.835,0.13-1.129,0.431l-3.717,3.72
|
||||
c-0.273,0.271-0.424,0.637-0.438,1.021l-0.267,12.371c-0.014,0.438,0.171,0.862,0.499,1.149c0.335,0.288,0.773,0.418,1.212,0.359
|
||||
l11.204-1.704c0.314-0.048,0.602-0.191,0.828-0.414l28.685-28.688c7.733,3.165,16.96,1.629,23.229-4.641
|
||||
C263.98,226.732,263.98,213.187,255.658,204.864z M251.161,231.612l-0.523,0.527l-22.261-22.258l0.526-0.521
|
||||
c6.133-6.14,16.118-6.14,22.258,0C257.293,215.494,257.293,225.479,251.161,231.612z"/>
|
||||
<path d="M124.163,144.762c1.179,0.253,2.264,0.231,5.625-2.34c1.494-1.148,3.698-3.08,5.73-5.768l0.896-1.184
|
||||
c7.62-10.138,25.462-33.873,51.238-32.579c21.249,1.552,36.323,17.602,43.564,46.418c0.254,0.977,0.404,1.579,0.568,2.046
|
||||
c1.108,4.709,2.964,10.582,5.64,12.517c0.66,0.481,1.427,0.705,2.197,0.705c1.163,0,2.313-0.541,3.046-1.554
|
||||
c1.17-1.622,0.852-3.869-0.678-5.112c-0.746-0.957-2.136-4.969-2.964-8.554c-0.052-0.214-0.116-0.418-0.209-0.623
|
||||
c-0.071-0.24-0.209-0.775-0.325-1.252c-1.146-4.572-4.199-16.707-11.601-28.115c-9.562-14.734-22.594-22.799-38.746-23.962
|
||||
c-0.027-0.007-0.055-0.007-0.082-0.007c-29.771-1.521-49.312,24.467-57.655,35.562l-0.876,1.17
|
||||
c-2.285,3.019-4.983,4.899-5.916,5.443c-0.314,0.121-0.625,0.294-0.903,0.508c-1.164,0.883-1.738,2.396-1.424,3.826
|
||||
C121.62,143.327,122.734,144.451,124.163,144.762z"/>
|
||||
<path d="M218.151,159.151c2.837-7.079,2.901-14.382,0.185-20.054c-2.412-5.058-6.927-8.72-13.038-10.586
|
||||
c-8.98-2.745-19.854,2.238-29.821,13.653c-0.128,0.137-14.311,15.057-29.211,24.179c-0.108,0.07-11.021,6.604-22.403,9.71
|
||||
c-1.997,0.539-3.181,2.607-2.635,4.601c0.541,2.004,2.607,3.182,4.604,2.637c12.388-3.369,23.833-10.233,24.332-10.535
|
||||
c16.158-9.897,30.813-25.487,30.935-25.637c6.059-6.928,15.008-13.572,21.989-11.438c4.113,1.258,6.968,3.497,8.474,6.658
|
||||
c1.807,3.778,1.67,8.891-0.384,14.024c-3.826,9.557-15.725,21.089-33.52,32.486c-8.925,5.716-31.388,19.746-47.258,26.525
|
||||
c-1.91,0.814-2.792,3.019-1.977,4.928c0.609,1.421,1.997,2.276,3.448,2.276c0.494,0,0.992-0.093,1.478-0.302
|
||||
c16.387-7.009,39.28-21.292,48.357-27.106C195.215,186.521,212.511,173.242,218.151,159.151z"/>
|
||||
<path d="M157.713,131.139c-1.702,1.874-3.23,3.886-4.881,5.809c-2.154,2.527-4.511,4.875-6.973,7.096
|
||||
c-2.527,2.286-4.574,3.915-7.556,5.631c-3.167,1.816-6.391,3.657-9.671,5.25c-1.129,0.548-2.103,0.912-3.368,1.294
|
||||
c-1.959,0.582-3.169,2.601-2.622,4.611c0.532,1.938,2.656,3.21,4.611,2.621c3.84-1.156,7.317-3.136,10.778-5.099
|
||||
c2.931-1.663,5.832-3.161,8.523-5.207c5.243-3.983,9.753-8.638,13.902-13.729c1.682-2.061,3.475-4.023,5.351-5.916
|
||||
c1.02-1.026,2.081-2.019,3.161-2.993c0.568-0.508,1.136-0.999,1.718-1.485c0.294-0.246,0.589-0.487,0.89-0.732
|
||||
c0.074-0.063,0.659-0.52,0.806-0.645c2.607-1.999,5.393-3.778,8.323-5.286c2.765-1.422,5.544-2.415,8.911-3.121
|
||||
c1.115-0.233,1.362-0.26,2.197-0.344c2.032-0.214,3.75-1.545,3.75-3.749c0-1.889-1.711-3.972-3.75-3.758
|
||||
C178.255,112.808,166.652,121.288,157.713,131.139z"/>
|
||||
<path d="M128.512,202.989c8.152-2.8,50.01-18.425,73.444-51.284c1.209-1.682,0.814-4.023-0.876-5.228
|
||||
c-1.68-1.207-4.027-0.813-5.229,0.876c-22.112,30.991-62.006,45.869-69.774,48.549c-0.173,0.055-0.274,0.085-0.31,0.099
|
||||
c-1.937,0.732-2.914,2.902-2.175,4.839c0.566,1.503,1.99,2.423,3.511,2.423c0.424,0,0.854-0.068,1.278-0.222L128.512,202.989z"/>
|
||||
<path d="M191.3,211.326c3.183-0.545,10.985,5.006,17.248,9.465c0.835,0.596,1.677,1.198,2.519,1.787
|
||||
c-0.075-2.857,0.308-5.695,1.108-8.416c-8.604-6.125-16.057-11.282-22.154-10.231c-4.711,0.811-12.943,6.074-25.94,14.646
|
||||
c-9.37,6.177-19.992,13.179-24.604,14.414c-2.004,0.544-3.188,2.598-2.656,4.603c0.458,1.681,1.973,2.786,3.627,2.786
|
||||
c0.322,0,0.65-0.052,0.97-0.13c5.789-1.567,15.994-8.289,26.794-15.406C176.934,219.086,187.79,211.934,191.3,211.326z"/>
|
||||
<path d="M200.061,239.715c0.205-1.595,0.931-3.121,2.108-4.298l1.649-1.646c-7.386-4.441-12.484-6.971-16.297-6.311
|
||||
c-4.637,0.805-14.383,7.426-30.741,19.366c-2.004,1.458-3.729,2.724-4.933,3.576c-1.689,1.201-2.096,3.535-0.898,5.229
|
||||
c0.732,1.033,1.889,1.588,3.066,1.588c0.754,0,1.507-0.227,2.163-0.691c1.244-0.883,2.996-2.163,5.025-3.642
|
||||
c6.514-4.746,23.811-17.378,27.553-18.031c1.646-0.106,6.27,2.413,10.63,5C199.609,239.811,199.829,239.75,200.061,239.715z"/>
|
||||
<path d="M166.277,264.834c-1.442,1.491-1.401,3.866,0.081,5.311c0.732,0.705,1.672,1.062,2.608,1.062
|
||||
c0.985,0,1.966-0.38,2.702-1.146c3.153-3.262,7.146-6.797,10.362-9.1l0.063-2.547c0.034-1.923,0.812-3.736,2.184-5.099
|
||||
l2.354-2.361c-0.431,0.027-0.869,0.062-1.307,0.144C178.76,252.227,168.303,262.747,166.277,264.834z"/>
|
||||
<path d="M237.787,191.388c1.883,0.801,3.997,0.588,5.134-1.349c0.938-1.588,0.54-4.333-1.349-5.134
|
||||
c-3.128-1.32-6.399-2.71-9.027-4.9c-2.896-2.411-4.25-5.578-4.853-9.233c-0.78-4.764-8.015-2.738-7.234,1.99
|
||||
C222.059,182.503,229.225,187.774,237.787,191.388z"/>
|
||||
<path d="M213.49,186.884c-0.773-1.896-2.471-3.217-4.616-2.621c-1.804,0.492-3.392,2.717-2.622,4.619
|
||||
c2.413,5.928,6.499,11.067,11.52,15.105c0.407-0.472,0.804-0.958,1.249-1.41c1.396-1.393,2.923-2.597,4.552-3.647
|
||||
C219.246,195.85,215.488,191.819,213.49,186.884z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 6.1 KiB |
Loading…
x
Reference in New Issue
Block a user