processwire-issues icon indicating copy to clipboard operation
processwire-issues copied to clipboard

Selector for 'tfa_type' makes no difference between set and activated

Open kixe opened this issue 3 years ago • 4 comments

Short description of the issue

Unable to determine if a user has 2FA activated via Selector

Actual behavior

Search via selector $user->find("tfa_type! = ''"); returns all users for whom the field is set, but no distinction is made whether the field is activated or not (settings column = NULL).

However, after running a loop with the result returned by this selector and check each via function User::hasTfa(), you get finally the desired result. (either false or string)

Unfortunately this function makes no difference between set and activated. It returns false in both cases.

Optional: Screenshots/Links that demonstrate the issue

Bildschirmfoto 2021-12-15 um 18 10 06

Suggestions for possible fixes

  1. The field value of tfa_type (instance of Class TfaTotp) should provide a queryable property/ subfield to determine if 2FA is active via selector. Something like $user->find("tfa_type.enabled=1);
  2. User::hasTfa() could return null if not set and false if not activated
public function hasTfa($getInstance = false) {
	$fieldname = Tfa::userFieldName;
	if (!$this->$fieldname) return null;
	return Tfa::getUserTfaType($this, $getInstance); 
}

Setup/Environment

  • ProcessWire version: 3.0.190 dev
  • (Optional) PHP version:
  • (Optional) MySQL version:
  • (Optional) Any 3rd party modules that are installed and could be related to the issue:

kixe avatar Dec 16 '21 10:12 kixe

@kixe This information is stored in JSON with other TFA data that varies depending on what TFA module is being used. So you cannot query this with a selector. If you aren't dealing with hundreds of users then I would suggest just iterating them and checking the value(s) you need. If you have lots of users then you could potentially query them using MySQL JSON querying functions if supported by your MySQL version.

ryancramerdesign avatar Dec 24 '21 16:12 ryancramerdesign

2. User::hasTfa() could return null if not set and false if not activated

public function hasTfa($getInstance = false) {
	$fieldname = Tfa::userFieldName;
	if (!$this->$fieldname) return null;
	return Tfa::getUserTfaType($this, $getInstance); 
}

@ryancramerdesign Would it be at least possible to get a more differentiated return value from the hasTfa() function? Thanks.

kixe avatar Mar 26 '22 09:03 kixe

@kixe I'm not sure I understand. Can you describe the use case for having it return null rather than false?

ryancramerdesign avatar Jul 17 '23 17:07 ryancramerdesign

We are running a ProcessWire instance with more than 2000 users. I need to know if someone has started the activation of tfa but has not completed the configuration to issue a warning or message.

some tests:

$users->find("tfa_type>0")->count(); // 53 RIGHT
$users->find("tfa_type>0,tfa_type.settings!=''")->count(); // 47 RIGHT

$users->find("tfa_type>0,tfa_type.settings=''")->count(); // 0 WRONG should be 6
$users->find("tfa_type>0")->not("tfa_type>0,tfa_type.settings!=''")->count(); // 0 WRONG should be 6
$users->find("tfa_type>0,tfa_type.settings=0")->count(); // 0 WRONG should be 6

current workaround:

$x = $users->find("tfa_type>0")->getArray();
$y = $users->find("tfa_type>0,tfa_type.settings!=''")->getArray();
$z = array_diff($x, $y);
$result = new PageArray;
$result->import($z);
var_dump($result); // PageArray with 6 items

kixe avatar Nov 27 '23 04:11 kixe