kolab_2fa: Bump spomky-labs/otphp to version 10
Fixes various PHP8 warnings
This commit is contained in:
parent
84f10a366b
commit
70810e1f88
9 changed files with 84 additions and 274 deletions
|
@ -26,7 +26,7 @@
|
|||
"require": {
|
||||
"php": ">=5.3.0",
|
||||
"roundcube/plugin-installer": ">=0.1.3",
|
||||
"spomky-labs/otphp": "~5.0.0",
|
||||
"spomky-labs/otphp": "~10.0.3",
|
||||
"endroid/qr-code": "~1.6.5",
|
||||
"enygma/yubikey": "~3.2"
|
||||
}
|
||||
|
|
|
@ -193,7 +193,7 @@ class kolab_2fa extends rcube_plugin
|
|||
$_POST['_host'] = $_SESSION['host'];
|
||||
$_POST['_pass'] = $rcmail->decrypt($_SESSION['password']);
|
||||
|
||||
if ($_SESSION['kolab_auth_admin']) {
|
||||
if (!empty($_SESSION['kolab_auth_admin'])) {
|
||||
$_POST['_user'] = $_SESSION['kolab_auth_admin'];
|
||||
$_POST['_loginas'] = $_SESSION['username'];
|
||||
}
|
||||
|
@ -553,10 +553,11 @@ class kolab_2fa extends rcube_plugin
|
|||
|
||||
// add row for displaying the QR code
|
||||
if (method_exists($driver, 'get_provisioning_uri')) {
|
||||
$gif = 'data:image/gif;base64,R0lGODlhDwAPAIAAAMDAwAAAACH5BAEAAAAALAAAAAAPAA8AQAINhI+py+0Po5y02otnAQA7';
|
||||
$table->add('title', $this->gettext('qrcode'));
|
||||
$table->add(null,
|
||||
$table->add('pl-3 pr-3',
|
||||
html::div('explain form-text', $this->gettext("qrcodeexplain$method"))
|
||||
. html::tag('img', array('src' => 'data:image/gif;base64,R0lGODlhDwAPAIAAAMDAwAAAACH5BAEAAAAALAAAAAAPAA8AQAINhI+py+0Po5y02otnAQA7', 'class' => 'qrcode', 'rel' => $method))
|
||||
. html::tag('img', array('src' => $gif, 'class' => 'qrcode mt-2', 'rel' => $method))
|
||||
);
|
||||
|
||||
// add row for testing the factor
|
||||
|
@ -566,7 +567,6 @@ class kolab_2fa extends rcube_plugin
|
|||
html::tag('input', array('type' => 'text', 'name' => '_verify_code', 'id' => $field_id, 'class' => 'k2fa-verify', 'size' => 20, 'required' => true)) .
|
||||
html::div('explain form-text', $this->gettext("verifycodeexplain$method"))
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
$input_id = new html_hiddenfield(array('name' => '_prop[id]', 'value' => ''));
|
||||
|
|
|
@ -112,9 +112,10 @@ abstract class Base
|
|||
/**
|
||||
* Verify the submitted authentication code
|
||||
*
|
||||
* @param string $code The 2nd authentication factor to verify
|
||||
* @param int $timestamp Timestamp of authentication process (window start)
|
||||
* @return boolean True if valid, false otherwise
|
||||
* @param string $code The 2nd authentication factor to verify
|
||||
* @param int $timestamp Timestamp of authentication process (window start)
|
||||
*
|
||||
* @return bool True if valid, false otherwise
|
||||
*/
|
||||
abstract function verify($code, $timestamp = null);
|
||||
|
||||
|
@ -160,7 +161,7 @@ abstract class Base
|
|||
}
|
||||
|
||||
/**
|
||||
* Implement this method if the driver can be prpvisioned via QR code
|
||||
* Implement this method if the driver can be provisioned via QR code
|
||||
*/
|
||||
/* abstract function get_provisioning_uri(); */
|
||||
|
||||
|
@ -181,6 +182,7 @@ abstract class Base
|
|||
for ($i = 0; $i < $length; $i++) {
|
||||
$secret .= $chars[array_rand($chars)];
|
||||
}
|
||||
|
||||
return $secret;
|
||||
}
|
||||
|
||||
|
@ -291,6 +293,14 @@ abstract class Base
|
|||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a string contains a semicolon
|
||||
*/
|
||||
protected function hasSemicolon($value)
|
||||
{
|
||||
return preg_match('/(:|%3A)/i', (string) $value) > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Getter for per-user properties for this method
|
||||
*/
|
||||
|
|
|
@ -57,13 +57,28 @@ class HOTP extends Base
|
|||
),
|
||||
);
|
||||
|
||||
if (!in_array($this->config['digest'], array('md5', 'sha1', 'sha256', 'sha512'))) {
|
||||
throw new \Exception("'{$this->config['digest']}' digest is not supported.");
|
||||
}
|
||||
|
||||
if (!is_numeric($this->config['digits']) || $this->config['digits'] < 1) {
|
||||
throw new \Exception('Digits must be at least 1.');
|
||||
}
|
||||
|
||||
if ($this->hasSemicolon($this->config['issuer'])) {
|
||||
throw new \Exception('Issuer must not contain a semi-colon.');
|
||||
}
|
||||
|
||||
// copy config options
|
||||
$this->backend = new \Kolab2FA\OTP\HOTP();
|
||||
$this->backend
|
||||
->setDigits($this->config['digits'])
|
||||
->setDigest($this->config['digest'])
|
||||
->setIssuer($this->config['issuer'])
|
||||
->setIssuerIncludedAsParameter(true);
|
||||
$this->backend = \OTPHP\HOTP::create(
|
||||
null, // secret
|
||||
0, // counter
|
||||
$this->config['digest'], // digest
|
||||
$this->config['digits'] // digits
|
||||
);
|
||||
|
||||
$this->backend->setIssuer($this->config['issuer']);
|
||||
$this->backend->setIssuerIncludedAsParameter(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -82,8 +97,11 @@ class HOTP extends Base
|
|||
}
|
||||
|
||||
try {
|
||||
$this->backend->setLabel($this->username)->setSecret($secret)->setCounter(intval($this->get('counter')));
|
||||
$pass = $this->backend->verify($code, $counter, $this->config['window']);
|
||||
$this->backend->setLabel($this->username);
|
||||
$this->backend->setSecret($secret);
|
||||
$this->backend->setCounter(intval($this->get('counter')));
|
||||
|
||||
$pass = $this->backend->verify($code, $counter, (int) $this->config['window']);
|
||||
|
||||
// store incremented counter value
|
||||
$this->set('counter', $this->backend->getCounter());
|
||||
|
@ -100,7 +118,7 @@ class HOTP extends Base
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the provisioning URI.
|
||||
*/
|
||||
public function get_provisioning_uri()
|
||||
{
|
||||
|
@ -114,7 +132,10 @@ class HOTP extends Base
|
|||
|
||||
// TODO: deny call if already active?
|
||||
|
||||
$this->backend->setLabel($this->username)->setSecret($this->secret)->setCounter(intval($this->get('counter')));
|
||||
$this->backend->setLabel($this->username);
|
||||
$this->backend->setSecret($this->secret);
|
||||
$this->backend->setCounter(intval($this->get('counter')));
|
||||
|
||||
return $this->backend->getProvisioningUri();
|
||||
}
|
||||
|
||||
|
|
|
@ -51,14 +51,32 @@ class TOTP extends Base
|
|||
),
|
||||
);
|
||||
|
||||
if (!in_array($this->config['digest'], array('md5', 'sha1', 'sha256', 'sha512'))) {
|
||||
throw new \Exception("'{$this->config['digest']}' digest is not supported.");
|
||||
}
|
||||
|
||||
if (!is_numeric($this->config['digits']) || $this->config['digits'] < 1) {
|
||||
throw new \Exception('Digits must be at least 1.');
|
||||
}
|
||||
|
||||
if (!is_numeric($this->config['interval']) || $this->config['interval'] < 1) {
|
||||
throw new \Exception('Interval must be at least 1.');
|
||||
}
|
||||
|
||||
if ($this->hasSemicolon($this->config['issuer'])) {
|
||||
throw new \Exception('Issuer must not contain a semi-colon.');
|
||||
}
|
||||
|
||||
// copy config options
|
||||
$this->backend = new \Kolab2FA\OTP\TOTP();
|
||||
$this->backend
|
||||
->setDigits($this->config['digits'])
|
||||
->setInterval($this->config['interval'])
|
||||
->setDigest($this->config['digest'])
|
||||
->setIssuer($this->config['issuer'])
|
||||
->setIssuerIncludedAsParameter(true);
|
||||
$this->backend = \OTPHP\TOTP::create(
|
||||
null, //secret
|
||||
$this->config['interval'], // period
|
||||
$this->config['digest'], // digest
|
||||
$this->config['digits'] // digits
|
||||
);
|
||||
|
||||
$this->backend->setIssuer($this->config['issuer']);
|
||||
$this->backend->setIssuerIncludedAsParameter(true);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -75,11 +93,12 @@ class TOTP extends Base
|
|||
return false;
|
||||
}
|
||||
|
||||
$this->backend->setLabel($this->username)->setSecret($secret);
|
||||
$this->backend->setLabel($this->username);
|
||||
$this->backend->setSecret($secret);
|
||||
|
||||
// Pass a window to indicate the maximum timeslip between client (mobile
|
||||
// device) and server.
|
||||
$pass = $this->backend->verify($code, $timestamp, 150);
|
||||
$pass = $this->backend->verify($code, (int) $timestamp, 150);
|
||||
|
||||
// try all codes from $timestamp till now
|
||||
if (!$pass && $timestamp) {
|
||||
|
@ -95,7 +114,7 @@ class TOTP extends Base
|
|||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* Get the provisioning URI.
|
||||
*/
|
||||
public function get_provisioning_uri()
|
||||
{
|
||||
|
@ -110,8 +129,9 @@ class TOTP extends Base
|
|||
|
||||
// TODO: deny call if already active?
|
||||
|
||||
$this->backend->setLabel($this->username)->setSecret($this->secret);
|
||||
$this->backend->setLabel($this->username);
|
||||
$this->backend->setSecret($this->secret);
|
||||
|
||||
return $this->backend->getProvisioningUri();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,58 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Kolab HOTP implementation based on Spomky-Labs/otphp
|
||||
*
|
||||
* This basically follows the exmaple implementation from
|
||||
* https://github.com/Spomky-Labs/otphp/tree/master/examples
|
||||
*
|
||||
* @author Thomas Bruederli <bruederli@kolabsys.com>
|
||||
*
|
||||
* Copyright (C) 2015, Kolab Systems AG <contact@kolabsys.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
|
||||
namespace Kolab2FA\OTP;
|
||||
|
||||
use OTPHP\HOTP as Base;
|
||||
|
||||
class HOTP extends Base
|
||||
{
|
||||
use OTP;
|
||||
protected $counter = 0;
|
||||
|
||||
public function setCounter($counter)
|
||||
{
|
||||
if (!is_integer($counter) || $counter < 0) {
|
||||
throw new \Exception('Counter must be at least 0.');
|
||||
}
|
||||
$this->counter = $counter;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCounter()
|
||||
{
|
||||
return $this->counter;
|
||||
}
|
||||
|
||||
public function updateCounter($counter)
|
||||
{
|
||||
$this->counter = $counter;
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Kolab OTP trait based on Spomky-Labs/otphp
|
||||
*
|
||||
* This basically follows the exmaple implementation from
|
||||
* https://github.com/Spomky-Labs/otphp/tree/master/examples
|
||||
*
|
||||
* @author Thomas Bruederli <bruederli@kolabsys.com>
|
||||
*
|
||||
* Copyright (C) 2015, Kolab Systems AG <contact@kolabsys.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Kolab2FA\OTP;
|
||||
|
||||
trait OTP
|
||||
{
|
||||
protected $secret = null;
|
||||
protected $issuer = null;
|
||||
protected $issuer_included_as_parameter = false;
|
||||
protected $label = null;
|
||||
protected $digest = 'sha1';
|
||||
protected $digits = 6;
|
||||
|
||||
public function setSecret($secret)
|
||||
{
|
||||
$this->secret = $secret;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getSecret()
|
||||
{
|
||||
return $this->secret;
|
||||
}
|
||||
|
||||
public function setLabel($label)
|
||||
{
|
||||
if ($this->hasSemicolon($label)) {
|
||||
throw new \Exception('Label must not contain a semi-colon.');
|
||||
}
|
||||
$this->label = $label;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getLabel()
|
||||
{
|
||||
return $this->label;
|
||||
}
|
||||
|
||||
public function setIssuer($issuer)
|
||||
{
|
||||
if ($this->hasSemicolon($issuer)) {
|
||||
throw new \Exception('Issuer must not contain a semi-colon.');
|
||||
}
|
||||
$this->issuer = $issuer;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getIssuer()
|
||||
{
|
||||
return $this->issuer;
|
||||
}
|
||||
|
||||
public function isIssuerIncludedAsParameter()
|
||||
{
|
||||
return $this->issuer_included_as_parameter;
|
||||
}
|
||||
|
||||
public function setIssuerIncludedAsParameter($issuer_included_as_parameter)
|
||||
{
|
||||
$this->issuer_included_as_parameter = $issuer_included_as_parameter;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setDigits($digits)
|
||||
{
|
||||
if (!is_numeric($digits) || $digits < 1) {
|
||||
throw new \Exception('Digits must be at least 1.');
|
||||
}
|
||||
$this->digits = $digits;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDigits()
|
||||
{
|
||||
return $this->digits;
|
||||
}
|
||||
|
||||
public function setDigest($digest)
|
||||
{
|
||||
if (!in_array($digest, array('md5', 'sha1', 'sha256', 'sha512'))) {
|
||||
throw new \Exception("'$digest' digest is not supported.");
|
||||
}
|
||||
$this->digest = $digest;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getDigest()
|
||||
{
|
||||
return $this->digest;
|
||||
}
|
||||
|
||||
private function hasSemicolon($value)
|
||||
{
|
||||
$semicolons = array(':', '%3A', '%3a');
|
||||
foreach ($semicolons as $semicolon) {
|
||||
if (false !== strpos($value, $semicolon)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
<?php
|
||||
|
||||
/**
|
||||
* Kolab TOTP implementation based on Spomky-Labs/otphp
|
||||
*
|
||||
* This basically follows the exmaple implementation from
|
||||
* https://github.com/Spomky-Labs/otphp/tree/master/examples
|
||||
*
|
||||
* @author Thomas Bruederli <bruederli@kolabsys.com>
|
||||
*
|
||||
* Copyright (C) 2015, Kolab Systems AG <contact@kolabsys.com>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU Affero General Public License as
|
||||
* published by the Free Software Foundation, either version 3 of the
|
||||
* License, or (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU Affero General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
namespace Kolab2FA\OTP;
|
||||
|
||||
use OTPHP\TOTP as Base;
|
||||
|
||||
class TOTP extends Base
|
||||
{
|
||||
use OTP;
|
||||
protected $interval = 30;
|
||||
|
||||
public function setInterval($interval)
|
||||
{
|
||||
if (!is_integer($interval) || $interval < 1) {
|
||||
throw new \Exception('Interval must be at least 1.');
|
||||
}
|
||||
$this->interval = $interval;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getInterval()
|
||||
{
|
||||
return $this->interval;
|
||||
}
|
||||
}
|
|
@ -65,7 +65,7 @@ class RcubeUser extends Base
|
|||
{
|
||||
if (!isset($this->cache[$key])) {
|
||||
$factors = $this->get_factors();
|
||||
$this->log(LOG_DEBUG, 'RcubeUser::read() ' . $key);
|
||||
$this->log(LOG_DEBUG, "RcubeUser::read({$key})");
|
||||
$this->cache[$key] = $factors[$key];
|
||||
}
|
||||
|
||||
|
@ -77,7 +77,7 @@ class RcubeUser extends Base
|
|||
*/
|
||||
public function write($key, $value)
|
||||
{
|
||||
$this->log(LOG_DEBUG, 'RcubeUser::write() ' . @json_encode($value));
|
||||
$this->log(LOG_DEBUG, "RcubeUser::write({$key}) " . @json_encode($value));
|
||||
|
||||
if ($user = $this->get_user($this->username)) {
|
||||
$this->cache[$key] = $value;
|
||||
|
|
Loading…
Add table
Reference in a new issue