
#ifdef HAVE_CONFIG_H
#include "../../../../ext_config.h"
#endif

#include <php.h>
#include "../../../../php_ext.h"
#include "../../../../ext.h"

#include <Zend/zend_operators.h>
#include <Zend/zend_exceptions.h>
#include <Zend/zend_interfaces.h>

#include "kernel/main.h"
#include "kernel/time.h"
#include "kernel/memory.h"
#include "kernel/operators.h"
#include "kernel/fcall.h"
#include "kernel/object.h"
#include "kernel/array.h"
#include "kernel/concat.h"
#include "kernel/exception.h"


/**
 * This file is part of the Phalcon Framework.
 *
 * (c) Phalcon Team <team@phalcon.io>
 *
 * For the full copyright and license information, please view the LICENSE.txt
 * file that was distributed with this source code.
 */
/**
 * Class Validator
 */
ZEPHIR_INIT_CLASS(Phalcon_Encryption_Security_JWT_Validator)
{
	ZEPHIR_REGISTER_CLASS(Phalcon\\Encryption\\Security\\JWT, Validator, phalcon, encryption_security_jwt_validator, phalcon_encryption_security_jwt_validator_method_entry, 0);

	/**
	 * @var array
	 */
	zend_declare_property_null(phalcon_encryption_security_jwt_validator_ce, SL("claims"), ZEND_ACC_PRIVATE);
	/**
	 * @var array
	 */
	zend_declare_property_null(phalcon_encryption_security_jwt_validator_ce, SL("errors"), ZEND_ACC_PRIVATE);
	/**
	 * @var int
	 */
	zend_declare_property_long(phalcon_encryption_security_jwt_validator_ce, SL("timeShift"), 0, ZEND_ACC_PRIVATE);
	/**
	 * @var Token
	 */
	zend_declare_property_null(phalcon_encryption_security_jwt_validator_ce, SL("token"), ZEND_ACC_PRIVATE);
	phalcon_encryption_security_jwt_validator_ce->create_object = zephir_init_properties_Phalcon_Encryption_Security_JWT_Validator;

	return SUCCESS;
}

/**
 * Validator constructor.
 *
 * @param Token               $token
 * @param int                 $timeShift Legacy clock-skew offset in seconds
 *                                       added to validated timestamps.
 *                                       Prefer injecting a ClockInterface
 *                                       for testable time; retained for BC.
 * @param ClockInterface|null $clock     Clock used to read "now" at
 *                                       construction. Defaults to the
 *                                       system wall clock (time()).
 */
PHP_METHOD(Phalcon_Encryption_Security_JWT_Validator, __construct)
{
	zval _2;
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zend_long timeShift, ZEPHIR_LAST_CALL_STATUS;
	zval *token, token_sub, *timeShift_param = NULL, *clock = NULL, clock_sub, __$null, now, _1, _0$$3;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&token_sub);
	ZVAL_UNDEF(&clock_sub);
	ZVAL_NULL(&__$null);
	ZVAL_UNDEF(&now);
	ZVAL_UNDEF(&_1);
	ZVAL_UNDEF(&_0$$3);
	ZVAL_UNDEF(&_2);
	static zend_string *_zephir_prop_0 = NULL;
	static zend_string *_zephir_prop_1 = NULL;
	static zend_string *_zephir_prop_2 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("token", 5, 1);
	}
	if (UNEXPECTED(!_zephir_prop_1)) {
		_zephir_prop_1 = zend_string_init("timeShift", 9, 1);
	}
	if (UNEXPECTED(!_zephir_prop_2)) {
		_zephir_prop_2 = zend_string_init("claims", 6, 1);
	}

	bool is_null_true = 1;
	ZEND_PARSE_PARAMETERS_START(1, 3)
		Z_PARAM_OBJECT_OF_CLASS(token, phalcon_encryption_security_jwt_token_token_ce)
		Z_PARAM_OPTIONAL
		Z_PARAM_LONG(timeShift)
		Z_PARAM_OBJECT_OF_CLASS_OR_NULL(clock, phalcon_time_clock_clockinterface_ce)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	zephir_fetch_params(1, 1, 2, &token, &timeShift_param, &clock);
	if (!timeShift_param) {
		timeShift = 0;
	} else {
		}
	if (!clock) {
		clock = &clock_sub;
		clock = &__$null;
	}
	ZEPHIR_INIT_VAR(&now);
	zephir_time(&now);
	if (Z_TYPE_P(clock) != IS_NULL) {
		ZEPHIR_CALL_METHOD(&_0$$3, clock, "now", NULL, 0);
		zephir_check_call_status();
		ZEPHIR_CALL_METHOD(&now, &_0$$3, "gettimestamp", NULL, 0);
		zephir_check_call_status();
	}
	zephir_update_property_zval_cached(this_ptr, _zephir_prop_0, 721, token);
	ZVAL_UNDEF(&_1);
	ZVAL_LONG(&_1, timeShift);
	zephir_update_property_zval_cached(this_ptr, _zephir_prop_1, 722, &_1);
	ZEPHIR_INIT_VAR(&_2);
	zephir_create_array(&_2, 7, 0);
	zephir_array_update_string(&_2, SL("aud"), &__$null, PH_COPY | PH_SEPARATE);
	zephir_array_update_string(&_2, SL("exp"), &now, PH_COPY | PH_SEPARATE);
	zephir_array_update_string(&_2, SL("jti"), &__$null, PH_COPY | PH_SEPARATE);
	zephir_array_update_string(&_2, SL("iat"), &now, PH_COPY | PH_SEPARATE);
	zephir_array_update_string(&_2, SL("iss"), &__$null, PH_COPY | PH_SEPARATE);
	zephir_array_update_string(&_2, SL("nbf"), &now, PH_COPY | PH_SEPARATE);
	zephir_array_update_string(&_2, SL("sub"), &__$null, PH_COPY | PH_SEPARATE);
	zephir_update_property_zval_cached(this_ptr, _zephir_prop_2, 723, &_2);
	ZEPHIR_MM_RESTORE();
}

/**
 * Return an array with validation errors (if any)
 *
 * @return array
 */
PHP_METHOD(Phalcon_Encryption_Security_JWT_Validator, getErrors)
{

	RETURN_MEMBER_TYPED(getThis(), "errors", IS_ARRAY);
}

/**
 * Return the value of a claim
 *
 * @param string $claim
 *
 * @return mixed
 */
PHP_METHOD(Phalcon_Encryption_Security_JWT_Validator, get)
{
	zval claim_zv, _0, _1$$3, _2$$3;
	zend_string *claim = NULL;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&claim_zv);
	ZVAL_UNDEF(&_0);
	ZVAL_UNDEF(&_1$$3);
	ZVAL_UNDEF(&_2$$3);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("claims", 6, 1);
	}

	ZEND_PARSE_PARAMETERS_START(1, 1)
		Z_PARAM_STR(claim)
	ZEND_PARSE_PARAMETERS_END();
	ZVAL_STR(&claim_zv, claim);
	zephir_read_property_cached(&_0, this_ptr, _zephir_prop_0, 723, PH_NOISY_CC | PH_READONLY);
	if (zephir_array_isset_value(&_0, &claim_zv)) {
		zephir_read_property_cached(&_1$$3, this_ptr, _zephir_prop_0, 723, PH_NOISY_CC | PH_READONLY);
		zephir_array_fetch(&_2$$3, &_1$$3, &claim_zv, PH_NOISY | PH_READONLY, "phalcon/Encryption/Security/JWT/Validator.zep", 103);
		RETURN_CTORW(&_2$$3);
	}
	RETURN_NULL();
}

/**
 * Set the value of a claim, for comparison with the token values
 *
 * @param string $claim
 * @param mixed  $value
 *
 * @return static
 */
PHP_METHOD(Phalcon_Encryption_Security_JWT_Validator, set)
{
	zval claim_zv, *value, value_sub;
	zend_string *claim = NULL;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&claim_zv);
	ZVAL_UNDEF(&value_sub);
	ZEND_PARSE_PARAMETERS_START(2, 2)
		Z_PARAM_STR(claim)
		Z_PARAM_ZVAL(value)
	ZEND_PARSE_PARAMETERS_END();
	value = ZEND_CALL_ARG(execute_data, 2);
	ZVAL_STR(&claim_zv, claim);
	zephir_update_property_array(this_ptr, SL("claims"), &claim_zv, value);
	RETURN_THISW();
}

/**
 * Set the token to be validated
 *
 * @param Token $token
 *
 * @return static
 */
PHP_METHOD(Phalcon_Encryption_Security_JWT_Validator, setToken)
{
	zval *token, token_sub;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&token_sub);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("token", 5, 1);
	}

	ZEND_PARSE_PARAMETERS_START(1, 1)
		Z_PARAM_OBJECT_OF_CLASS(token, phalcon_encryption_security_jwt_token_token_ce)
	ZEND_PARSE_PARAMETERS_END();
	zephir_fetch_params_without_memory_grow(1, 0, &token);
	zephir_update_property_zval_cached(this_ptr, _zephir_prop_0, 721, token);
	RETURN_THISW();
}

/**
 * Validate a claim
 *
 * @param string          $name
 * @param bool|int|string $value
 *
 * @return static
 */
PHP_METHOD(Phalcon_Encryption_Security_JWT_Validator, validateClaim)
{
	zval _2$$3;
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zend_long ZEPHIR_LAST_CALL_STATUS;
	zval name_zv, *value, value_sub, claimValue, _0, _1;
	zend_string *name = NULL;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&name_zv);
	ZVAL_UNDEF(&value_sub);
	ZVAL_UNDEF(&claimValue);
	ZVAL_UNDEF(&_0);
	ZVAL_UNDEF(&_1);
	ZVAL_UNDEF(&_2$$3);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("token", 5, 1);
	}

	ZEND_PARSE_PARAMETERS_START(2, 2)
		Z_PARAM_STR(name)
		Z_PARAM_ZVAL(value)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	value = ZEND_CALL_ARG(execute_data, 2);
	zephir_memory_observe(&name_zv);
	ZVAL_STR_COPY(&name_zv, name);
	zephir_read_property_cached(&_0, this_ptr, _zephir_prop_0, 721, PH_NOISY_CC | PH_READONLY);
	ZEPHIR_CALL_METHOD(&_1, &_0, "getclaims", NULL, 0);
	zephir_check_call_status();
	ZEPHIR_CALL_METHOD(&claimValue, &_1, "get", NULL, 0, &name_zv);
	zephir_check_call_status();
	if (!ZEPHIR_IS_IDENTICAL(value, &claimValue)) {
		ZEPHIR_INIT_VAR(&_2$$3);
		ZEPHIR_CONCAT_SV(&_2$$3, "Validation: incorrect ", &name_zv);
		zephir_update_property_array_append(this_ptr, SL("errors"), &_2$$3);
	}
	RETURN_THIS();
}

/**
 * Validate the audience
 *
 * @param string|array $audience
 *
 * @return static
 * @throws ValidatorException
 */
PHP_METHOD(Phalcon_Encryption_Security_JWT_Validator, validateAudience)
{
	zend_bool _0, _12;
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zephir_fcall_cache_entry *_9 = NULL;
	zend_long ZEPHIR_LAST_CALL_STATUS;
	zval *audience = NULL, audience_sub, __$true, item, tokenAudience, _3, _4, _5, _6, *_7, _11, _1$$3, _2$$4, _8$$5, _10$$6, _13$$7, _14$$8;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&audience_sub);
	ZVAL_BOOL(&__$true, 1);
	ZVAL_UNDEF(&item);
	ZVAL_UNDEF(&tokenAudience);
	ZVAL_UNDEF(&_3);
	ZVAL_UNDEF(&_4);
	ZVAL_UNDEF(&_5);
	ZVAL_UNDEF(&_6);
	ZVAL_UNDEF(&_11);
	ZVAL_UNDEF(&_1$$3);
	ZVAL_UNDEF(&_2$$4);
	ZVAL_UNDEF(&_8$$5);
	ZVAL_UNDEF(&_10$$6);
	ZVAL_UNDEF(&_13$$7);
	ZVAL_UNDEF(&_14$$8);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("token", 5, 1);
	}

	ZEND_PARSE_PARAMETERS_START(1, 1)
		Z_PARAM_ZVAL(audience)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	zephir_fetch_params(1, 1, 0, &audience);
	ZEPHIR_SEPARATE_PARAM(audience);
	_0 = Z_TYPE_P(audience) != IS_STRING;
	if (_0) {
		_0 = Z_TYPE_P(audience) != IS_ARRAY;
	}
	if (_0) {
		ZEPHIR_INIT_VAR(&_1$$3);
		object_init_ex(&_1$$3, phalcon_encryption_security_jwt_exceptions_invalidaudiencetype_ce);
		ZEPHIR_CALL_METHOD(NULL, &_1$$3, "__construct", NULL, 0);
		zephir_check_call_status();
		zephir_throw_exception_debug(&_1$$3, "phalcon/Encryption/Security/JWT/Validator.zep", 172);
		ZEPHIR_MM_RESTORE();
		return;
	}
	if (Z_TYPE_P(audience) == IS_STRING) {
		ZEPHIR_INIT_VAR(&_2$$4);
		zephir_create_array(&_2$$4, 1, 0);
		zephir_array_fast_append(&_2$$4, audience);
		ZEPHIR_CPY_WRT(audience, &_2$$4);
	}
	zephir_read_property_cached(&_3, this_ptr, _zephir_prop_0, 721, PH_NOISY_CC | PH_READONLY);
	ZEPHIR_CALL_METHOD(&_4, &_3, "getclaims", NULL, 0);
	zephir_check_call_status();
	ZEPHIR_INIT_VAR(&_5);
	array_init(&_5);
	ZEPHIR_INIT_VAR(&_6);
	ZVAL_STRING(&_6, "aud");
	ZEPHIR_CALL_METHOD(&tokenAudience, &_4, "get", NULL, 0, &_6, &_5);
	zephir_check_call_status();
	zephir_is_iterable(audience, 0, "phalcon/Encryption/Security/JWT/Validator.zep", 187);
	if (Z_TYPE_P(audience) == IS_ARRAY) {
		ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(audience), _7)
		{
			ZEPHIR_INIT_NVAR(&item);
			ZVAL_COPY(&item, _7);
			ZEPHIR_CALL_FUNCTION(&_8$$5, "in_array", &_9, 89, &item, &tokenAudience, &__$true);
			zephir_check_call_status();
			if (!ZEPHIR_IS_TRUE_IDENTICAL(&_8$$5)) {
				ZVAL_UNDEF(&_10$$6);
				ZEPHIR_INIT_NVAR(&_10$$6);
				ZVAL_STRING(&_10$$6, "Validation: audience not allowed");
				zephir_update_property_array_append(this_ptr, SL("errors"), &_10$$6);
			}
		} ZEND_HASH_FOREACH_END();
	} else {
		ZEPHIR_CALL_METHOD(NULL, audience, "rewind", NULL, 0);
		zephir_check_call_status();
		_12 = 1;
		while (1) {
			if (_12) {
				_12 = 0;
			} else {
				ZEPHIR_CALL_METHOD(NULL, audience, "next", NULL, 0);
				zephir_check_call_status();
			}
			ZEPHIR_CALL_METHOD(&_11, audience, "valid", NULL, 0);
			zephir_check_call_status();
			if (!zend_is_true(&_11)) {
				break;
			}
			ZEPHIR_CALL_METHOD(&item, audience, "current", NULL, 0);
			zephir_check_call_status();
				ZEPHIR_CALL_FUNCTION(&_13$$7, "in_array", &_9, 89, &item, &tokenAudience, &__$true);
				zephir_check_call_status();
				if (!ZEPHIR_IS_TRUE_IDENTICAL(&_13$$7)) {
					ZVAL_UNDEF(&_14$$8);
					ZEPHIR_INIT_NVAR(&_14$$8);
					ZVAL_STRING(&_14$$8, "Validation: audience not allowed");
					zephir_update_property_array_append(this_ptr, SL("errors"), &_14$$8);
				}
		}
	}
	ZEPHIR_INIT_NVAR(&item);
	RETURN_THIS();
}

/**
 * Validate the expiration time of the token
 *
 * @param int $timestamp
 *
 * @return static
 */
PHP_METHOD(Phalcon_Encryption_Security_JWT_Validator, validateExpiration)
{
	zend_bool _7;
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zval *timestamp_param = NULL, _0, _1, _2, _3, _4, _5, _6, _8, _9, _10$$3;
	zend_long timestamp, ZEPHIR_LAST_CALL_STATUS, tokenExpirationTime = 0;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&_0);
	ZVAL_UNDEF(&_1);
	ZVAL_UNDEF(&_2);
	ZVAL_UNDEF(&_3);
	ZVAL_UNDEF(&_4);
	ZVAL_UNDEF(&_5);
	ZVAL_UNDEF(&_6);
	ZVAL_UNDEF(&_8);
	ZVAL_UNDEF(&_9);
	ZVAL_UNDEF(&_10$$3);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("token", 5, 1);
	}

	ZEND_PARSE_PARAMETERS_START(1, 1)
		Z_PARAM_LONG(timestamp)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	zephir_fetch_params(1, 1, 0, &timestamp_param);
	zephir_read_property_cached(&_0, this_ptr, _zephir_prop_0, 721, PH_NOISY_CC | PH_READONLY);
	ZEPHIR_CALL_METHOD(&_1, &_0, "getclaims", NULL, 0);
	zephir_check_call_status();
	ZEPHIR_INIT_VAR(&_3);
	ZVAL_STRING(&_3, "exp");
	ZEPHIR_CALL_METHOD(&_2, &_1, "get", NULL, 0, &_3);
	zephir_check_call_status();
	tokenExpirationTime = zephir_get_intval(&_2);
	zephir_read_property_cached(&_4, this_ptr, _zephir_prop_0, 721, PH_NOISY_CC | PH_READONLY);
	ZEPHIR_CALL_METHOD(&_5, &_4, "getclaims", NULL, 0);
	zephir_check_call_status();
	ZEPHIR_INIT_NVAR(&_3);
	ZVAL_STRING(&_3, "exp");
	ZEPHIR_CALL_METHOD(&_6, &_5, "has", NULL, 0, &_3);
	zephir_check_call_status();
	_7 = zephir_is_true(&_6);
	if (_7) {
		ZVAL_LONG(&_9, timestamp);
		ZEPHIR_CALL_METHOD(&_8, this_ptr, "gettimestamp", NULL, 0, &_9);
		zephir_check_call_status();
		_7 = ZEPHIR_GT_LONG(&_8, tokenExpirationTime);
	}
	if (_7) {
		ZVAL_UNDEF(&_10$$3);
		ZEPHIR_INIT_VAR(&_10$$3);
		ZVAL_STRING(&_10$$3, "Validation: the token has expired");
		zephir_update_property_array_append(this_ptr, SL("errors"), &_10$$3);
	}
	RETURN_THIS();
}

/**
 * Validate the id of the token
 *
 * A null id expresses no expectation and is skipped.
 *
 * @param string|null $id
 *
 * @return static
 */
PHP_METHOD(Phalcon_Encryption_Security_JWT_Validator, validateId)
{
	zval _4;
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zend_long ZEPHIR_LAST_CALL_STATUS;
	zval id_zv, tokenId, _0, _1, _2, _3, _5$$4;
	zend_string *id = NULL;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&id_zv);
	ZVAL_UNDEF(&tokenId);
	ZVAL_UNDEF(&_0);
	ZVAL_UNDEF(&_1);
	ZVAL_UNDEF(&_2);
	ZVAL_UNDEF(&_3);
	ZVAL_UNDEF(&_5$$4);
	ZVAL_UNDEF(&_4);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("token", 5, 1);
	}

	bool is_null_true = 1;
	ZEND_PARSE_PARAMETERS_START(0, 1)
		Z_PARAM_OPTIONAL
		Z_PARAM_STR_OR_NULL(id)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	if (!id) {
		ZEPHIR_INIT_VAR(&id_zv);
	} else {
		zephir_memory_observe(&id_zv);
	ZVAL_STR_COPY(&id_zv, id);
	}
	if (Z_TYPE_P(&id_zv) == IS_NULL) {
		RETURN_THIS();
	}
	zephir_read_property_cached(&_0, this_ptr, _zephir_prop_0, 721, PH_NOISY_CC | PH_READONLY);
	ZEPHIR_CALL_METHOD(&_1, &_0, "getclaims", NULL, 0);
	zephir_check_call_status();
	ZEPHIR_INIT_VAR(&_3);
	ZVAL_STRING(&_3, "jti");
	ZEPHIR_CALL_METHOD(&_2, &_1, "get", NULL, 0, &_3);
	zephir_check_call_status();
	zephir_cast_to_string(&_4, &_2);
	ZEPHIR_CPY_WRT(&tokenId, &_4);
	if (!ZEPHIR_IS_IDENTICAL(&id_zv, &tokenId)) {
		ZVAL_UNDEF(&_5$$4);
		ZEPHIR_INIT_VAR(&_5$$4);
		ZVAL_STRING(&_5$$4, "Validation: incorrect Id");
		zephir_update_property_array_append(this_ptr, SL("errors"), &_5$$4);
	}
	RETURN_THIS();
}

/**
 * Validate the issued at (iat) of the token
 *
 * A token issued at exactly $timestamp is valid. Only a token issued after
 * it, i.e. in the future, is rejected.
 *
 * @param int $timestamp
 *
 * @return static
 */
PHP_METHOD(Phalcon_Encryption_Security_JWT_Validator, validateIssuedAt)
{
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zval *timestamp_param = NULL, _0, _1, _2, _3, _4, _5, _6$$3;
	zend_long timestamp, ZEPHIR_LAST_CALL_STATUS, tokenIssuedAt = 0;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&_0);
	ZVAL_UNDEF(&_1);
	ZVAL_UNDEF(&_2);
	ZVAL_UNDEF(&_3);
	ZVAL_UNDEF(&_4);
	ZVAL_UNDEF(&_5);
	ZVAL_UNDEF(&_6$$3);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("token", 5, 1);
	}

	ZEND_PARSE_PARAMETERS_START(1, 1)
		Z_PARAM_LONG(timestamp)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	zephir_fetch_params(1, 1, 0, &timestamp_param);
	zephir_read_property_cached(&_0, this_ptr, _zephir_prop_0, 721, PH_NOISY_CC | PH_READONLY);
	ZEPHIR_CALL_METHOD(&_1, &_0, "getclaims", NULL, 0);
	zephir_check_call_status();
	ZEPHIR_INIT_VAR(&_3);
	ZVAL_STRING(&_3, "iat");
	ZEPHIR_CALL_METHOD(&_2, &_1, "get", NULL, 0, &_3);
	zephir_check_call_status();
	tokenIssuedAt = zephir_get_intval(&_2);
	ZVAL_LONG(&_5, timestamp);
	ZEPHIR_CALL_METHOD(&_4, this_ptr, "gettimestamp", NULL, 0, &_5);
	zephir_check_call_status();
	if (ZEPHIR_LT_LONG(&_4, tokenIssuedAt)) {
		ZVAL_UNDEF(&_6$$3);
		ZEPHIR_INIT_VAR(&_6$$3);
		ZVAL_STRING(&_6$$3, "Validation: the token cannot be used yet (future)");
		zephir_update_property_array_append(this_ptr, SL("errors"), &_6$$3);
	}
	RETURN_THIS();
}

/**
 * Validate the issuer of the token
 *
 * A null issuer expresses no expectation and is skipped.
 *
 * @param string|null $issuer
 *
 * @return static
 */
PHP_METHOD(Phalcon_Encryption_Security_JWT_Validator, validateIssuer)
{
	zval _4;
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zend_long ZEPHIR_LAST_CALL_STATUS;
	zval issuer_zv, tokenIssuer, _0, _1, _2, _3, _5$$4;
	zend_string *issuer = NULL;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&issuer_zv);
	ZVAL_UNDEF(&tokenIssuer);
	ZVAL_UNDEF(&_0);
	ZVAL_UNDEF(&_1);
	ZVAL_UNDEF(&_2);
	ZVAL_UNDEF(&_3);
	ZVAL_UNDEF(&_5$$4);
	ZVAL_UNDEF(&_4);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("token", 5, 1);
	}

	bool is_null_true = 1;
	ZEND_PARSE_PARAMETERS_START(0, 1)
		Z_PARAM_OPTIONAL
		Z_PARAM_STR_OR_NULL(issuer)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	if (!issuer) {
		ZEPHIR_INIT_VAR(&issuer_zv);
	} else {
		zephir_memory_observe(&issuer_zv);
	ZVAL_STR_COPY(&issuer_zv, issuer);
	}
	if (Z_TYPE_P(&issuer_zv) == IS_NULL) {
		RETURN_THIS();
	}
	zephir_read_property_cached(&_0, this_ptr, _zephir_prop_0, 721, PH_NOISY_CC | PH_READONLY);
	ZEPHIR_CALL_METHOD(&_1, &_0, "getclaims", NULL, 0);
	zephir_check_call_status();
	ZEPHIR_INIT_VAR(&_3);
	ZVAL_STRING(&_3, "iss");
	ZEPHIR_CALL_METHOD(&_2, &_1, "get", NULL, 0, &_3);
	zephir_check_call_status();
	zephir_cast_to_string(&_4, &_2);
	ZEPHIR_CPY_WRT(&tokenIssuer, &_4);
	if (!ZEPHIR_IS_IDENTICAL(&issuer_zv, &tokenIssuer)) {
		ZVAL_UNDEF(&_5$$4);
		ZEPHIR_INIT_VAR(&_5$$4);
		ZVAL_STRING(&_5$$4, "Validation: incorrect issuer");
		zephir_update_property_array_append(this_ptr, SL("errors"), &_5$$4);
	}
	RETURN_THIS();
}

/**
 * Validate the notbefore (nbf) of the token
 *
 * A token is valid at exactly $timestamp. Only a timestamp before the
 * "nbf" claim is rejected.
 *
 * @param int $timestamp
 *
 * @return static
 */
PHP_METHOD(Phalcon_Encryption_Security_JWT_Validator, validateNotBefore)
{
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zval *timestamp_param = NULL, _0, _1, _2, _3, _4, _5, _6$$3;
	zend_long timestamp, ZEPHIR_LAST_CALL_STATUS, tokenNotBefore = 0;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&_0);
	ZVAL_UNDEF(&_1);
	ZVAL_UNDEF(&_2);
	ZVAL_UNDEF(&_3);
	ZVAL_UNDEF(&_4);
	ZVAL_UNDEF(&_5);
	ZVAL_UNDEF(&_6$$3);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("token", 5, 1);
	}

	ZEND_PARSE_PARAMETERS_START(1, 1)
		Z_PARAM_LONG(timestamp)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	zephir_fetch_params(1, 1, 0, &timestamp_param);
	zephir_read_property_cached(&_0, this_ptr, _zephir_prop_0, 721, PH_NOISY_CC | PH_READONLY);
	ZEPHIR_CALL_METHOD(&_1, &_0, "getclaims", NULL, 0);
	zephir_check_call_status();
	ZEPHIR_INIT_VAR(&_3);
	ZVAL_STRING(&_3, "nbf");
	ZEPHIR_CALL_METHOD(&_2, &_1, "get", NULL, 0, &_3);
	zephir_check_call_status();
	tokenNotBefore = zephir_get_intval(&_2);
	ZVAL_LONG(&_5, timestamp);
	ZEPHIR_CALL_METHOD(&_4, this_ptr, "gettimestamp", NULL, 0, &_5);
	zephir_check_call_status();
	if (ZEPHIR_LT_LONG(&_4, tokenNotBefore)) {
		ZVAL_UNDEF(&_6$$3);
		ZEPHIR_INIT_VAR(&_6$$3);
		ZVAL_STRING(&_6$$3, "Validation: the token cannot be used yet (not before)");
		zephir_update_property_array_append(this_ptr, SL("errors"), &_6$$3);
	}
	RETURN_THIS();
}

/**
 * Validate the signature of the token
 *
 * @param SignerInterface $signer
 * @param string          $passphrase
 *
 * @return static
 */
PHP_METHOD(Phalcon_Encryption_Security_JWT_Validator, validateSignature)
{
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zend_long ZEPHIR_LAST_CALL_STATUS;
	zend_string *passphrase = NULL;
	zval *signer, signer_sub, passphrase_zv, _0, _1, _2, _3, _4, _5, _6$$3;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&signer_sub);
	ZVAL_UNDEF(&passphrase_zv);
	ZVAL_UNDEF(&_0);
	ZVAL_UNDEF(&_1);
	ZVAL_UNDEF(&_2);
	ZVAL_UNDEF(&_3);
	ZVAL_UNDEF(&_4);
	ZVAL_UNDEF(&_5);
	ZVAL_UNDEF(&_6$$3);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("token", 5, 1);
	}

	ZEND_PARSE_PARAMETERS_START(2, 2)
		Z_PARAM_OBJECT_OF_CLASS(signer, phalcon_encryption_security_jwt_signer_signerinterface_ce)
		Z_PARAM_STR(passphrase)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	signer = ZEND_CALL_ARG(execute_data, 1);
	zephir_memory_observe(&passphrase_zv);
	ZVAL_STR_COPY(&passphrase_zv, passphrase);
	zephir_read_property_cached(&_1, this_ptr, _zephir_prop_0, 721, PH_NOISY_CC | PH_READONLY);
	ZEPHIR_CALL_METHOD(&_2, &_1, "getsignature", NULL, 0);
	zephir_check_call_status();
	ZEPHIR_CALL_METHOD(&_3, &_2, "gethash", NULL, 0);
	zephir_check_call_status();
	zephir_read_property_cached(&_4, this_ptr, _zephir_prop_0, 721, PH_NOISY_CC | PH_READONLY);
	ZEPHIR_CALL_METHOD(&_5, &_4, "getpayload", NULL, 0);
	zephir_check_call_status();
	ZEPHIR_CALL_METHOD(&_0, signer, "verify", NULL, 0, &_3, &_5, &passphrase_zv);
	zephir_check_call_status();
	if (!ZEPHIR_IS_TRUE_IDENTICAL(&_0)) {
		ZVAL_UNDEF(&_6$$3);
		ZEPHIR_INIT_VAR(&_6$$3);
		ZVAL_STRING(&_6$$3, "Validation: the signature does not match");
		zephir_update_property_array_append(this_ptr, SL("errors"), &_6$$3);
	}
	RETURN_THIS();
}

/**
 * Validate the subject of the token
 *
 * A null subject expresses no expectation and is skipped.
 *
 * @param string|null $subject
 *
 * @return static
 */
PHP_METHOD(Phalcon_Encryption_Security_JWT_Validator, validateSubject)
{
	zval _4;
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
	zend_long ZEPHIR_LAST_CALL_STATUS;
	zval subject_zv, tokenSubject, _0, _1, _2, _3, _5$$4;
	zend_string *subject = NULL;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&subject_zv);
	ZVAL_UNDEF(&tokenSubject);
	ZVAL_UNDEF(&_0);
	ZVAL_UNDEF(&_1);
	ZVAL_UNDEF(&_2);
	ZVAL_UNDEF(&_3);
	ZVAL_UNDEF(&_5$$4);
	ZVAL_UNDEF(&_4);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("token", 5, 1);
	}

	bool is_null_true = 1;
	ZEND_PARSE_PARAMETERS_START(0, 1)
		Z_PARAM_OPTIONAL
		Z_PARAM_STR_OR_NULL(subject)
	ZEND_PARSE_PARAMETERS_END();
	ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
	zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	if (!subject) {
		ZEPHIR_INIT_VAR(&subject_zv);
	} else {
		zephir_memory_observe(&subject_zv);
	ZVAL_STR_COPY(&subject_zv, subject);
	}
	if (Z_TYPE_P(&subject_zv) == IS_NULL) {
		RETURN_THIS();
	}
	zephir_read_property_cached(&_0, this_ptr, _zephir_prop_0, 721, PH_NOISY_CC | PH_READONLY);
	ZEPHIR_CALL_METHOD(&_1, &_0, "getclaims", NULL, 0);
	zephir_check_call_status();
	ZEPHIR_INIT_VAR(&_3);
	ZVAL_STRING(&_3, "sub");
	ZEPHIR_CALL_METHOD(&_2, &_1, "get", NULL, 0, &_3);
	zephir_check_call_status();
	zephir_cast_to_string(&_4, &_2);
	ZEPHIR_CPY_WRT(&tokenSubject, &_4);
	if (!ZEPHIR_IS_IDENTICAL(&subject_zv, &tokenSubject)) {
		ZVAL_UNDEF(&_5$$4);
		ZEPHIR_INIT_VAR(&_5$$4);
		ZVAL_STRING(&_5$$4, "Validation: incorrect subject");
		zephir_update_property_array_append(this_ptr, SL("errors"), &_5$$4);
	}
	RETURN_THIS();
}

/**
 * @param int $timestamp
 *
 * @return int
 */
PHP_METHOD(Phalcon_Encryption_Security_JWT_Validator, getTimestamp)
{
	zval *timestamp_param = NULL, _0;
	zend_long timestamp;
	zval *this_ptr = getThis();

	ZVAL_UNDEF(&_0);
	static zend_string *_zephir_prop_0 = NULL;
	if (UNEXPECTED(!_zephir_prop_0)) {
		_zephir_prop_0 = zend_string_init("timeShift", 9, 1);
	}

	ZEND_PARSE_PARAMETERS_START(1, 1)
		Z_PARAM_LONG(timestamp)
	ZEND_PARSE_PARAMETERS_END();
	zephir_fetch_params_without_memory_grow(1, 0, &timestamp_param);
	zephir_read_property_cached(&_0, this_ptr, _zephir_prop_0, 722, PH_NOISY_CC | PH_READONLY);
	RETURN_LONG((timestamp + (zend_long) zephir_get_numberval(&_0)));
}

zend_object *zephir_init_properties_Phalcon_Encryption_Security_JWT_Validator(zend_class_entry *class_type)
{
		zval _0, _2, _1$$3, _3$$4;
	zephir_method_globals *ZEPHIR_METHOD_GLOBALS_PTR = NULL;
		ZVAL_UNDEF(&_0);
	ZVAL_UNDEF(&_2);
	ZVAL_UNDEF(&_1$$3);
	ZVAL_UNDEF(&_3$$4);
	

		ZEPHIR_METHOD_GLOBALS_PTR = pecalloc(1, sizeof(zephir_method_globals), 0);
		zephir_memory_grow_stack(ZEPHIR_METHOD_GLOBALS_PTR, __func__);
	
	{
		zval local_this_ptr, *this_ptr = &local_this_ptr;
		ZEPHIR_CREATE_OBJECT(this_ptr, class_type);
		zephir_read_property_ex(&_0, this_ptr, ZEND_STRL("errors"), PH_NOISY_CC | PH_READONLY);
		if (Z_TYPE_P(&_0) == IS_NULL) {
			ZEPHIR_INIT_VAR(&_1$$3);
			array_init(&_1$$3);
			zephir_update_property_zval_ex(this_ptr, ZEND_STRL("errors"), &_1$$3);
		}
		zephir_read_property_ex(&_2, this_ptr, ZEND_STRL("claims"), PH_NOISY_CC | PH_READONLY);
		if (Z_TYPE_P(&_2) == IS_NULL) {
			ZEPHIR_INIT_VAR(&_3$$4);
			array_init(&_3$$4);
			zephir_update_property_zval_ex(this_ptr, ZEND_STRL("claims"), &_3$$4);
		}
		ZEPHIR_MM_RESTORE();
		return Z_OBJ_P(this_ptr);
	}
}

