faustjs icon indicating copy to clipboard operation
faustjs copied to clipboard

Bug: Possible Login then logout issue

Open Bowriverstudio opened this issue 3 years ago • 2 comments

In some cases I login to my faustjs app - then my app checks for an authentication token which fails and logs me out.

Applicable Versions

"@faustjs/core": "^0.15.6", "@faustjs/next": "^0.15.6", "@gqty/cli": "^3.1.0",

  • WordPress version: 6.0
  • FaustWP version: Version 0.7.9 Php 7.4 - on a Digital Ocean Droplet with Sailed.io setup.

Steps To Reproduce

It will take me awhile to strip out all the unused code / setup an additional domain ... If this is not enough information I can create it. I do not think this issue will occur on Atlas.

What I think is happening is I got three components on the page using this code.

# auth is used in a menu

<AuthContent>. # Ensure the user is logged in

<AfterLoginRedirect/> # Page redirected to after the login (there is some logic here depending on the user group, and if they completed the signup or not.
</AuthContent>

const { useAuth } = client.auth;
  const { isLoading, isAuthenticated } = useAuth({
    shouldRedirect: false,
  })

I added some logging code on the public/wp-content/plugins/faustwp/includes/auth/functions.php file.

if (!function_exists('write_log')) {
	function write_log($log) {
		if (true === WP_DEBUG) {
			if (is_array($log) || is_object($log)) {
				error_log(print_r($log, true));
			} else {
				error_log($log);
			}
		}
	}
}

/**
 * Get a WP_User given a base 64 encoded code.
 *
 * @param string $code     The base64 encoded encrypted code.
 * @param string $type     The type of code. Either 'ac' or 'at'.
 *
 * @return WP_User|bool A WP_User object or false.
 */
function get_user_from_code( $code, $type ) {
	write_log("Function get_user_from_code - code: $code  type: $type ");

	$code = decrypt( $code );
	write_log("After decrypt ! - code: $code ");
	if ( ! $code ) {
		return false;
	}

	write_log('Time !'. time());
	$parts = explode( '|', $code );
	// if ( count( $parts ) < 3 ) {
	// 	return false;
	// }

	// if ( $type !== $parts[0] ) {
	// 	return false;
	// }

	// if ( absint( $parts[2] ) < time() ) {
	// 	return false;
	// }

	return get_user_by( 'ID', absint( $parts[1] ) );
}

Some logs are:

Here are some logs of the decrypt not working Function get_user_from_code - code: x1R6 RZ4HYzXpCb1YUnDNLguUgbAC2nxxUrPVkk9QfOu4raqgYnTlKnTMQqKk0FZGhluK1KKSDN2Bux8pezmuUf8/n1gLPm NPbTEIndtMU= type: ac [04-Jun-2022 23:45:24 UTC] After decrypt ! - code:
[04-Jun-2022 23:47:34 UTC] Function get_user_from_code - code: undefined type: at [04-Jun-2022 23:47:34 UTC] PHP Warning: hash_equals(): Expected known_string to be a string, bool given in /var/www/releases/1337/wp-content/plugins/faustwp/includes/auth/functions.php on line 223 [04-Jun-2022 23:47:34 UTC] After decrypt ! - code: �w^~)�

secret_key 8891be90-f4cd-4b2c-a3a0-aecdf13b8498 There are several that do work.

I also get this warning from time to time. PHP Warning: hash_equals(): Expected known_string to be a string, bool given in /var/www/releases/1337/wp-content/plugins/faustwp/includes/auth/functions.php on line 222

Here is an example that does decrypt but the time is wrong. Function get_user_from_code - code: YXR8MTh8MTY1NDM4Njg0Mw== type: at After decrypt ! - code: at|18|1654386843 [04-Jun-2022 23:49:04 UTC] Time !1654386544

The problem disappears when I write this hack along with the above one.

/**
 * Encrypt a value.
 *
 * @uses openssl_encrypt()
 * @link https://www.php.net/manual/en/function.openssl-encrypt.php
 *
 * @param string $value The value to encrypt.
 *
 * @return string|bool The encrypted value as a base 64 encoded string or false.
 */
function encrypt( $value ) {
	write_log("encrypt value $value");
	$secret_key = get_secret_key();
	write_log("encrypt secret_key $secret_key");

	if ( ! $secret_key ) {
		return false;
	}

	$iv          = openssl_random_pseudo_bytes( openssl_cipher_iv_length( 'AES-256-CBC' ) );
	$cipher_text = openssl_encrypt( $value, 'AES-256-CBC', $secret_key, OPENSSL_RAW_DATA, $iv );

	if ( ! $cipher_text ) {
		return false;
	}

	$hash = hash_hmac( 'sha256', $cipher_text, $secret_key, true );
	
	$encode = base64_encode( $iv . $hash . $cipher_text );
	write_log("encrypt iv $iv  cipher_text $cipher_text hash $hash encode $encode");

	return base64_encode( $value ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
	return base64_encode( $iv . $hash . $cipher_text ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_encode
}

/**
 * Decrypt a value.
 *
 * @uses openssl_decrypt()
 * @link https://www.php.net/manual/en/function.openssl-decrypt.php
 *
 * @param string $value The base 64 encoded value.
 *
 * @return string|bool The decrypted value or false.
 */
function decrypt( $value ) {
	$secret_key      = get_secret_key();
	$decrypted_value = false;

	if ( ! $secret_key ) {
		return $decrypted_value;
	}

	$value       = base64_decode( $value ); // phpcs:ignore WordPress.PHP.DiscouragedPHPFunctions.obfuscation_base64_decode
	$iv_length   = openssl_cipher_iv_length( 'AES-256-CBC' );
	$iv          = substr( $value, 0, $iv_length );
	$hash        = substr( $value, $iv_length, 32 );
	$cipher_text = substr( $value, $iv_length + 32 );
	$hash_comp   = hash_hmac( 'sha256', $cipher_text, $secret_key, true );
	write_log("decrypt value $value iv $iv  cipher_text $cipher_text hash $hash hash_comp $hash_comp");

	if ( hash_equals( $hash, $hash_comp ) ) {
		$decrypted_value = openssl_decrypt( $cipher_text, 'AES-256-CBC', $secret_key, OPENSSL_RAW_DATA, $iv );
	}

	return $value;
	return $decrypted_value;
}

Let me know if you need more information. Thanks.

Bowriverstudio avatar Jun 07 '22 14:06 Bowriverstudio

@Bowriverstudio I was trying to reproduce this issue today but I couldn't. I'm using Local with the specified PHP Versions and WP 6 and created an example site with local auth strategy with some menus to navigate. I also created 2 users and I was navigating through the menus and I could see that the authenticated parts they were loading OK with no issues.

Is it possible to create a minimal reproducible example by cloning this starter template?

https://github.com/blakewilson/faust-local-auth

theodesp avatar Jun 20 '22 17:06 theodesp

Hello @theodesp yes I'll do that. I'll be on vacation for a while so it will take me a while to get to it. The hack that I've done is working for the moment so there is no rush.

Cheers, Maurice

Bowriverstudio avatar Jun 24 '22 19:06 Bowriverstudio

I will close this issue for now due to lack of inactivity. You can create a new one with a reproducible example

theodesp avatar May 09 '23 13:05 theodesp